diff --git a/flake.nix b/flake.nix index e3cfcc0..d8e945f 100644 --- a/flake.nix +++ b/flake.nix @@ -114,6 +114,12 @@ libclc # crocus + hasvk (with_driver_using_cl) libclc'ye hard-dependency, # rusticl/opencl kapalı olsa bile gerekiyor + + # rusticl 32-bit: meson rustc'yi bir dil olarak istiyor, yoksa + # "Unknown compiler(s): [['rustc']]" ile yapılandırma düşüyor. + rustc + cargo + rust-bindgen ]; # Build araçları (meson/ninja/python/bison/flex/pkg-config vs.) i686'da @@ -185,6 +191,16 @@ shellHook = '' export MESA_VK_DEVICE_SELECT="${pciId}" + # meson'un find_library'si clang'i llvm'in libdir'inde ariyor, + # nixpkgs'te ise clang ayri bir turev. 64-bit shell bunu + # commonShellVars'ta LIBRARY_PATH ile cozuyor; i686'da eksikti ve + # rusticl "clangBasic not found" ile yapilandirmayi dusuruyordu. + export LIBRARY_PATH=${pkgs32.llvmPackages_21.clang-unwrapped.lib}/lib''${LIBRARY_PATH:+:$LIBRARY_PATH} + + # rust-bindgen (rusticl) libclang'i calisma zamaninda dlopen ediyor + export LIBCLANG_PATH=${pkgs32.llvmPackages_21.libclang.lib}/lib + export BINDGEN_EXTRA_CLANG_ARGS="-I${pkgs32.llvmPackages_21.clang-unwrapped}/lib/clang/21/include" + echo "=== intel-hard-graphics (i686 / 32-bit) ===" echo "CC=$CC" echo "meson setup build32 --buildtype=debugoptimized \\" diff --git a/include/D3D9/.editorconfig b/include/D3D9/.editorconfig new file mode 100644 index 0000000..0dcc752 --- /dev/null +++ b/include/D3D9/.editorconfig @@ -0,0 +1,2 @@ +[*.h] +indent_style = tab diff --git a/include/D3D9/d3d9.h b/include/D3D9/d3d9.h new file mode 100644 index 0000000..4467e5c --- /dev/null +++ b/include/D3D9/d3d9.h @@ -0,0 +1,1868 @@ +/* + * Copyright 2011 Joakim Sindholt + * + * 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) = 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; +}; + +struct IDirect3DVolumeTexture9 : public IDirect3DBaseTexture9 +{ + virtual HRESULT WINAPI GetLevelDesc(UINT Level, D3DVOLUME_DESC *pDesc) = 0; + virtual HRESULT WINAPI GetVolumeLevel(UINT Level, IDirect3DVolume9 **ppVolumeLevel) = 0; + virtual HRESULT WINAPI LockBox(UINT Level, D3DLOCKED_BOX *pLockedVolume, const D3DBOX *pBox, DWORD Flags) = 0; + virtual HRESULT WINAPI UnlockBox(UINT Level) = 0; + virtual HRESULT WINAPI AddDirtyBox(const D3DBOX *pDirtyBox) = 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); + 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) (p)->lpVtbl->GetIndices(p,a) +#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); + 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) (p)->lpVtbl->GetIndices(p,a) +#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 index 0000000..70f9919 --- /dev/null +++ b/include/D3D9/d3d9caps.h @@ -0,0 +1,390 @@ +/* + * Copyright 2011 Joakim Sindholt + * + * 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 D3DCAPS_OVERLAY 0x00000800 +#define D3DCAPS_READ_SCANLINE 0x00020000 + +#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 index 0000000..88f22b9 --- /dev/null +++ b/include/D3D9/d3d9types.h @@ -0,0 +1,1816 @@ +/* + * Copyright 2011 Joakim Sindholt + * + * 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 +#else /* _WIN32 */ +#include + +#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 E_FAIL MAKE_HRESULT(1, 0x000, 0x4005) + +#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 + +/* Windows calling convention */ +#ifndef WINAPI + #if defined(__x86_64__) && !defined(__ILP32__) + #define WINAPI __attribute__((ms_abi)) + #elif defined(__i386__) + #define WINAPI __attribute__((__stdcall__)) + #else /* neither amd64 nor i386 */ + #define WINAPI + #endif +#endif /* WINAPI */ + +/* 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) +#define D3DERR_DEVICEREMOVED MAKE_D3DHRESULT(2160) +#define D3DERR_DEVICEHUNG MAKE_D3DHRESULT(2164) +#define S_PRESENT_OCCLUDED MAKE_D3DSTATUS(2168) + +/******************************************************** + * 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 D3DPRESENT_RATE_DEFAULT 0 + +#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) + +/* D3DRS_COLORWRITEENABLE */ +#define D3DCOLORWRITEENABLE_RED (1L << 0) +#define D3DCOLORWRITEENABLE_GREEN (1L << 1) +#define D3DCOLORWRITEENABLE_BLUE (1L << 2) +#define D3DCOLORWRITEENABLE_ALPHA (1L << 3) + + +/******************************************************** + * 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_ZERO = 0, //Needed to avoid warnings + 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_SOLID_ZERO = 0, + 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_ATI1 = MAKEFOURCC('A', 'T', 'I', '1'), + D3DFMT_ATI2 = MAKEFOURCC('A', 'T', 'I', '2'), + D3DFMT_ATOC = MAKEFOURCC('A', 'T', 'O', 'C'), + 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_NVDB = MAKEFOURCC('N', 'V', 'D', 'B'), + D3DFMT_NV11 = MAKEFOURCC('N', 'V', '1', '1'), + D3DFMT_NV12 = MAKEFOURCC('N', 'V', '1', '2'), + D3DFMT_RESZ = MAKEFOURCC('R', 'E', 'S', 'Z'), + 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/.editorconfig b/include/d3dadapter/.editorconfig new file mode 100644 index 0000000..bdbea00 --- /dev/null +++ b/include/d3dadapter/.editorconfig @@ -0,0 +1,3 @@ +[*.h] +indent_style = space +indent_size = 4 diff --git a/include/d3dadapter/d3dadapter9.h b/include/d3dadapter/d3dadapter9.h new file mode 100644 index 0000000..76ad3d4 --- /dev/null +++ b/include/d3dadapter/d3dadapter9.h @@ -0,0 +1,101 @@ +/* + * Copyright 2011 Joakim Sindholt + * + * 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 index 0000000..6939dd4 --- /dev/null +++ b/include/d3dadapter/drm.h @@ -0,0 +1,51 @@ +/* + * Copyright 2011 Joakim Sindholt + * + * 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 2 + +/* version 0.0: Initial release + * 0.1: All IDirect3D objects can be assumed to have a pointer to the + * internal vtable in second position of the structure + * 0.2: IDirect3DDevice9_SetCursorPosition always calls + * ID3DPresent_SetCursorPos for hardware cursors + */ + +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 index 0000000..0325ebc --- /dev/null +++ b/include/d3dadapter/present.h @@ -0,0 +1,173 @@ +/* + * Copyright 2011 Joakim Sindholt + * + * 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 + +#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; + +/* Available since version 1.3 */ +typedef struct _D3DPRESENT_PARAMETERS2_ { + /* Whether D3DSWAPEFFECT_DISCARD is allowed to release the + * D3DWindowBuffers in any order, and eventually with a delay. + * FALSE (Default): buffers should be released as soon as possible. + * TRUE: it is allowed to release some buffers with a delay, and in + * a random order. */ + BOOL AllowDISCARDDelayedRelease; + /* User preference for D3DSWAPEFFECT_DISCARD with D3DPRESENT_INTERVAL_IMMEDIATE. + * FALSE (Default): User prefers presentation to occur as soon as possible, + * with potential tearings. + * TRUE: User prefers presentation to be tear free. Requires + * AllowDISCARDDelayedRelease to have any effect. */ + BOOL TearFreeDISCARD; +} D3DPRESENT_PARAMETERS2, *PD3DPRESENT_PARAMETERS2, *LPD3DPRESENT_PARAMETERS2; + +/* 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. + * Note: This function waits as well that the buffer content was displayed (this + * can be after the release of the buffer if the window system decided to make + * an internal copy and release early. */ + 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); + /* Available since version 1.1 */ + BOOL (WINAPI *GetWindowOccluded)(ID3DPresent *This); + /* Available since version 1.2 */ + BOOL (WINAPI *ResolutionMismatch)(ID3DPresent *This); + HANDLE (WINAPI *CreateThread)(ID3DPresent *This, void *pThreadfunc, void *pParam); + BOOL (WINAPI *WaitForThread)(ID3DPresent *This, HANDLE thread); + /* Available since version 1.3 */ + HRESULT (WINAPI *SetPresentParameters2)(ID3DPresent *This, D3DPRESENT_PARAMETERS2 *pParameters); + BOOL (WINAPI *IsBufferReleased)(ID3DPresent *This, D3DWindowBuffer *buffer); + /* Wait a buffer gets released. */ + HRESULT (WINAPI *WaitBufferReleaseEvent)(ID3DPresent *This); +} 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->GetWindowInfo(p,a,b,c,d) +#define ID3DPresent_GetWindowOccluded(p) (p)->lpVtbl->GetWindowOccluded(p) +#define ID3DPresent_ResolutionMismatch(p) (p)->lpVtbl->ResolutionMismatch(p) +#define ID3DPresent_CreateThread(p,a,b) (p)->lpVtbl->CreateThread(p,a,b) +#define ID3DPresent_WaitForThread(p,a) (p)->lpVtbl->WaitForThread(p,a) +#define ID3DPresent_SetPresentParameters2(p,a) (p)->lpVtbl->SetPresentParameters2(p,a) +#define ID3DPresent_IsBufferReleased(p,a) (p)->lpVtbl->IsBufferReleased(p,a) +#define ID3DPresent_WaitBufferReleaseEvent(p) (p)->lpVtbl->WaitBufferReleaseEvent(p) + +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_ */ diff --git a/include/meson.build b/include/meson.build index 397d4b4..5f7194f 100644 --- a/include/meson.build +++ b/include/meson.build @@ -2,6 +2,7 @@ # SPDX-License-Identifier: MIT inc_include = [include_directories('.')] +inc_d3d9 = include_directories('D3D9') inc_winddk = include_directories('winddk') # Most things assume that Android headers are in the default include @@ -82,6 +83,13 @@ if with_dri install_headers('GL/internal/dri_interface.h', subdir : 'GL/internal') endif +if with_gallium_st_nine + install_headers( + 'd3dadapter/d3dadapter9.h', 'd3dadapter/drm.h', 'd3dadapter/present.h', + subdir : 'd3dadapter', + ) +endif + opencl_headers = files( 'CL/cl.h', 'CL/cl_d3d10.h', diff --git a/meson.build b/meson.build index 7d9ef58..4034668 100644 --- a/meson.build +++ b/meson.build @@ -795,6 +795,26 @@ if d3d_drivers_path == '' d3d_drivers_path = join_paths(get_option('prefix'), get_option('libdir'), 'd3d') endif +with_gallium_st_nine = get_option('gallium-nine') +if with_gallium_st_nine + if not with_gallium_swrast + error('The nine state tracker requires gallium softpipe/llvmpipe.') + elif not [ + with_gallium_crocus, + with_gallium_freedreno, + with_gallium_i915, + with_gallium_iris, + with_gallium_nouveau, + with_gallium_panfrost, + with_gallium_r300, + with_gallium_r600, + with_gallium_radeonsi, + with_gallium_svga, + with_gallium_zink, + ].contains(true) + error('The nine state tracker requires at least one non-swrast gallium driver.') + endif +endif with_gallium_st_d3d10umd = get_option('gallium-d3d10umd') if with_gallium_st_d3d10umd if not with_gallium_swrast @@ -2600,6 +2620,9 @@ if with_gallium if with_gallium_mediafoundation gallium_frontends += 'mediafoundation' endif + if with_gallium_st_nine + gallium_frontends += 'nine' + endif if with_gallium_rusticl gallium_frontends += 'rusticl' endif diff --git a/meson.options b/meson.options index 51c97a3..b9f9f25 100644 --- a/meson.options +++ b/meson.options @@ -130,6 +130,13 @@ option( description : 'path to put va libraries. defaults to $libdir/dri.' ) +option( + 'gallium-nine', + type : 'boolean', + value : false, + description : 'build gallium "nine" Direct3D 9.x frontend.', +) + option( 'gallium-d3d10umd', type : 'boolean', diff --git a/src/compiler/nir/meson.build b/src/compiler/nir/meson.build index 6d9ac95..ca76e2b 100644 --- a/src/compiler/nir/meson.build +++ b/src/compiler/nir/meson.build @@ -84,6 +84,7 @@ with_nir_headers_only = not with_gfx_compute or ( not [ with_gallium_va, with_any_vk, + with_gallium_st_nine, with_gallium_st_d3d10umd, with_gallium_rusticl, with_microsoft_clc, diff --git a/src/gallium/auxiliary/nir/tgsi_to_nir.c b/src/gallium/auxiliary/nir/tgsi_to_nir.c index fc917f2..622a664 100644 --- a/src/gallium/auxiliary/nir/tgsi_to_nir.c +++ b/src/gallium/auxiliary/nir/tgsi_to_nir.c @@ -1344,13 +1344,21 @@ ttn_tex(struct ttn_compile *c, nir_def **src) } if (tgsi_inst->Instruction.Opcode == TGSI_OPCODE_TXD) { - instr->src[src_number] = - nir_tex_src_for_ssa(nir_tex_src_ddx, - nir_trim_vector(b, src[1], nir_tex_instr_src_size(instr, src_number))); + /* nir_tex_instr_src_size() switches on src[i].src_type, so the type has + * to be assigned before asking for the size. Building the whole + * nir_tex_src in one expression queries the size while the slot is + * still zero-initialised, which yields the wrong component count and + * makes nir_trim_vector() truncate the derivatives to one component. + */ + instr->src[src_number].src_type = nir_tex_src_ddx; + instr->src[src_number].src = + nir_src_for_ssa(nir_trim_vector(b, src[1], + nir_tex_instr_src_size(instr, src_number))); src_number++; - instr->src[src_number] = - nir_tex_src_for_ssa(nir_tex_src_ddy, - nir_trim_vector(b, src[2], nir_tex_instr_src_size(instr, src_number))); + instr->src[src_number].src_type = nir_tex_src_ddy; + instr->src[src_number].src = + nir_src_for_ssa(nir_trim_vector(b, src[2], + nir_tex_instr_src_size(instr, src_number))); src_number++; } diff --git a/src/gallium/drivers/crocus/crocus_clear.c b/src/gallium/drivers/crocus/crocus_clear.c index cf13f01..5f3cff5 100644 --- a/src/gallium/drivers/crocus/crocus_clear.c +++ b/src/gallium/drivers/crocus/crocus_clear.c @@ -20,7 +20,6 @@ * DEALINGS IN THE SOFTWARE. */ -#include #include #include "pipe/p_defines.h" #include "pipe/p_state.h" @@ -759,7 +758,8 @@ crocus_clear_render_target(struct pipe_context *ctx, bool render_condition_enabled) { struct crocus_context *ice = (void *) ctx; - struct crocus_surface *isurf = (void *) psurf; + struct crocus_screen *screen = (struct crocus_screen *) ctx->screen; + const struct intel_device_info *devinfo = &screen->devinfo; struct pipe_box box = { .x = dst_x, .y = dst_y, @@ -772,9 +772,20 @@ crocus_clear_render_target(struct pipe_context *ctx, /* pipe_color_union and isl_color_value are interchangeable */ union isl_color_value *color = (void *) p_color; + /* psurf is owned by the frontend, not by us: since pipe_surface was + * de-pointerized there is no pipe_context::create_surface() hook any more + * and frontends fill in pipe_surface values themselves (lavapipe even + * passes one off the stack). Casting it to crocus_surface and reading + * ->view reads past the end of the caller's struct. Derive the format + * from pipe_surface::format instead; crocus_create_surface() would have + * used exactly this format with an identity swizzle. */ + const struct crocus_format_info fmt = + crocus_format_for_usage(devinfo, psurf->format, + ISL_SURF_USAGE_RENDER_TARGET_BIT); + clear_color(ice, psurf->texture, psurf->level, &box, render_condition_enabled, - isurf->view.format, isurf->view.swizzle, *color); + fmt.fmt, ISL_SWIZZLE_IDENTITY, *color); } /** diff --git a/src/gallium/drivers/crocus/crocus_query.c b/src/gallium/drivers/crocus/crocus_query.c index ee7f4d3..601058c 100644 --- a/src/gallium/drivers/crocus/crocus_query.c +++ b/src/gallium/drivers/crocus/crocus_query.c @@ -667,6 +667,14 @@ crocus_get_query_result(struct pipe_context *ctx, return true; } + if (q->type == PIPE_QUERY_GPU_FINISHED) { + struct pipe_screen *pscreen = ctx->screen; + + result->b = pscreen->fence_finish(pscreen, ctx, q->fence, + wait ? OS_TIMEOUT_INFINITE : 0); + return result->b; + } + if (!q->ready) { struct crocus_batch *batch = &ice->batches[q->batch_idx]; if (q->syncobj == crocus_batch_get_signal_syncobj(batch)) diff --git a/src/gallium/frontends/nine/.editorconfig b/src/gallium/frontends/nine/.editorconfig new file mode 100644 index 0000000..7b12a40 --- /dev/null +++ b/src/gallium/frontends/nine/.editorconfig @@ -0,0 +1,3 @@ +[*.{c,h}] +indent_style = space +indent_size = 4 diff --git a/src/gallium/frontends/nine/adapter9.c b/src/gallium/frontends/nine/adapter9.c new file mode 100644 index 0000000..c1a284c --- /dev/null +++ b/src/gallium/frontends/nine/adapter9.c @@ -0,0 +1,1119 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#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/format/u_format.h" +#include "util/u_dump.h" +#include "nir.h" + +#include "pipe/p_screen.h" + +#define DBG_CHANNEL DBG_ADAPTER + +static bool +has_sm3(struct pipe_screen *hal) +{ + return hal->caps.fragment_shader_texture_lod && + hal->caps.fragment_shader_derivatives; +} + +HRESULT +NineAdapter9_ctor( struct NineAdapter9 *This, + struct NineUnknownParams *pParams, + struct d3dadapter9_context *pCTX ) +{ + struct pipe_screen *hal = pCTX->hal; + 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 (!hal->caps.clip_halfz) { + WARN_ONCE("Driver doesn't natively support d3d9 coordinates\n"); + /* Mesa 26.x: pipe_screen::get_compiler_options() was replaced by the + * pipe_screen::nir_options[] array. */ + const nir_shader_compiler_options *options = hal->nir_options[MESA_SHADER_VERTEX]; + if(!options->compact_arrays){ + ERR("Driver doesn't support emulating d3d9 coordinates\n"); + return D3DERR_DRIVERINTERNALERROR; + } + } + /* Old cards had tricks to bypass some restrictions to implement + * everything and fit tight the requirements: number of constants, + * number of temp registers, special behaviours, etc. Since we don't + * have access to all this, we need a bit more than what dx9 required. + * For example we have to use more than 32 temp registers to emulate + * behaviours, while some dx9 hw don't have more. As for sm2 hardware, + * we could support vs2 / ps2 for them but it needs some more care, and + * as these are very old, we choose to drop support for them */ + + /* checks minimum requirements, most are vs3/ps3 strict requirements */ + if (!has_sm3(hal) || + hal->shader_caps[MESA_SHADER_VERTEX].max_const_buffer0_size < 256 * sizeof(float[4]) || + hal->shader_caps[MESA_SHADER_FRAGMENT].max_const_buffer0_size < 244 * sizeof(float[4]) || + hal->shader_caps[MESA_SHADER_VERTEX].max_temps < 32 || + hal->shader_caps[MESA_SHADER_FRAGMENT].max_temps < 32 || + hal->shader_caps[MESA_SHADER_VERTEX].max_inputs < 16 || + hal->shader_caps[MESA_SHADER_FRAGMENT].max_inputs < 10 || + hal->shader_caps[MESA_SHADER_FRAGMENT].max_texture_samplers < 16) { + ERR("Your device is not supported by Gallium Nine. Minimum requirement " + "is >= r500, >= nv50, >= i965\n"); + return D3DERR_DRIVERINTERNALERROR; + } + /* for r500 */ + if (hal->shader_caps[MESA_SHADER_VERTEX].max_const_buffer0_size < 276 * sizeof(float[4]) || /* we put bool and int constants with float constants */ + hal->shader_caps[MESA_SHADER_VERTEX].max_temps < 40 || /* we use some more temp registers */ + hal->shader_caps[MESA_SHADER_FRAGMENT].max_temps < 40 || + hal->shader_caps[MESA_SHADER_FRAGMENT].max_inputs < 20) /* we don't pack inputs as much as we could */ + WARN_ONCE("Your device is at the limit of Gallium Nine requirements. Some games " + "may run into issues because requirements are too tight\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 NINE_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 bool +backbuffer_format( D3DFORMAT dfmt, + D3DFORMAT bfmt, + bool 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 NINE_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; } + + /* The display format is not handled in Nine. We always present an XRGB8888 + * buffer (and the display server will eventually do the conversion). We probably + * don't need to check for anything for the adapter format support, since if the + * display server advertise support, it will likely be able to do the conversion. + * We do the approximation that a format is available in the display server if + * the format passes with NINE_BIND_BACKBUFFER_FLAGS */ + dfmt = d3d9_to_pipe_format_checked(screen, AdapterFormat, PIPE_TEXTURE_2D, + 1, + NINE_BIND_BACKBUFFER_FLAGS, false, false); + bfmt = d3d9_to_pipe_format_checked(screen, BackBufferFormat, PIPE_TEXTURE_2D, + 1, + NINE_BIND_BACKBUFFER_FLAGS, false, false); + if (dfmt == PIPE_FORMAT_NONE || bfmt == PIPE_FORMAT_NONE) { + DBG("Unsupported Adapter/BackBufferFormat.\n"); + return D3DERR_NOTAVAILABLE; + } + + return D3D_OK; +} + +static inline bool +display_format( D3DFORMAT fmt, + bool 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; +} + +static inline bool +adapter_format( D3DFORMAT fmt ) +{ + /* Formats that are compatible to display_format (modulo alpha bits) */ + static const D3DFORMAT allowed[] = { + D3DFMT_A2R10G10B10, + D3DFMT_X8R8G8B8, + D3DFMT_A8R8G8B8, + D3DFMT_X1R5G5B5, + D3DFMT_A1R5G5B5, + D3DFMT_R5G6B5, + }; + unsigned i; + + for (i = 0; i < sizeof(allowed)/sizeof(D3DFORMAT); i++) { + if (fmt == allowed[i]) { return true; } + } + return false; +} + +HRESULT NINE_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; + bool srgb; + + /* Check adapter format. */ + + DBG("This=%p DeviceType=%s AdapterFormat=%s\n", This, + nine_D3DDEVTYPE_to_str(DeviceType), d3dformat_to_string(AdapterFormat)); + DBG("Usage=%x RType=%u CheckFormat=%s\n", Usage, RType, + d3dformat_to_string(CheckFormat)); + + /* Wine tests, but suspicious. Needs more tests. */ + user_assert(adapter_format(AdapterFormat), D3DERR_INVALIDCALL); + user_assert(display_format(AdapterFormat, false), D3DERR_NOTAVAILABLE); + + hr = NineAdapter9_GetScreen(This, DeviceType, &screen); + if (FAILED(hr)) + return hr; + pf = d3d9_to_pipe_format_checked(screen, AdapterFormat, PIPE_TEXTURE_2D, 0, + PIPE_BIND_DISPLAY_TARGET | + PIPE_BIND_SHARED, false, false); + if (pf == PIPE_FORMAT_NONE) { + 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) { + if (depth_stencil_format(CheckFormat)) + return D3DERR_NOTAVAILABLE; + bind |= PIPE_BIND_RENDER_TARGET; + } + if (Usage & D3DUSAGE_DEPTHSTENCIL) { + if (!depth_stencil_format(CheckFormat)) + return D3DERR_NOTAVAILABLE; + bind |= d3d9_get_pipe_depth_format_bindings(CheckFormat); + } + + if ((Usage & D3DUSAGE_QUERY_VERTEXTEXTURE) && + !screen->shader_caps[MESA_SHADER_VERTEX].max_texture_samplers) + return D3DERR_NOTAVAILABLE; + + /* 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; + + /* RESZ hack */ + if (CheckFormat == D3DFMT_RESZ && bind == PIPE_BIND_RENDER_TARGET && + RType == D3DRTYPE_SURFACE) + return screen->caps.multisample_z_resolve ? + D3D_OK : D3DERR_NOTAVAILABLE; + + /* ATOC hack */ + if (CheckFormat == D3DFMT_ATOC && RType == D3DRTYPE_SURFACE) + return D3D_OK; + + if ((Usage & D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING) && + (Usage & D3DUSAGE_RENDERTARGET)) + 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; + case D3DRTYPE_SURFACE: + if (!(Usage & D3DUSAGE_DEPTHSTENCIL)) + bind |= PIPE_BIND_SAMPLER_VIEW; /* StretchRect */ + /* Offscreen surface support: Usage = 0. + * In practice drivers are very restrictive on the formats supported. + * Basically a few common formats + YUV and compressed formats. The + * reason is that offscreen surface are useful only for directdraw + * compatibility (a WONTIMPL of nine) + format conversion (useful in + * particular for YUV because the format was not advertised for textures + * on NV chips). */ + if (Usage == 0) + bind |= PIPE_BIND_RENDER_TARGET; /* A current requirement of our impl, which we should get rid of. */ + break; + default: + break; + } + + + srgb = (Usage & (D3DUSAGE_QUERY_SRGBREAD | D3DUSAGE_QUERY_SRGBWRITE)) != 0; + pf = d3d9_to_pipe_format_checked(screen, CheckFormat, target, + 0, bind, srgb, false); + if (pf == PIPE_FORMAT_NONE) { + DBG("NOT AVAILABLE\n"); + return D3DERR_NOTAVAILABLE; + } + + /* we support ATI1 and ATI2 hack only for 2D and Cube textures */ + if (RType != D3DRTYPE_TEXTURE && RType != D3DRTYPE_CUBETEXTURE && + (CheckFormat == D3DFMT_ATI1 || CheckFormat == D3DFMT_ATI2)) + 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 NINE_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); + + if (pQualityLevels) { + /* In error cases return only 1 quality level supported */ + *pQualityLevels = 1; + } + user_assert(MultiSampleType <= D3DMULTISAMPLE_16_SAMPLES, D3DERR_INVALIDCALL); + + hr = NineAdapter9_GetScreen(This, DeviceType, &screen); + if (FAILED(hr)) + return hr; + + if (depth_stencil_format(SurfaceFormat)) + bind = d3d9_get_pipe_depth_format_bindings(SurfaceFormat); + else /* render-target */ + bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET; + + pf = d3d9_to_pipe_format_checked(screen, SurfaceFormat, PIPE_TEXTURE_2D, + 0, PIPE_BIND_SAMPLER_VIEW, false, false); + + if (pf == PIPE_FORMAT_NONE && SurfaceFormat != D3DFMT_NULL) { + DBG("%s not available.\n", d3dformat_to_string(SurfaceFormat)); + return D3DERR_INVALIDCALL; + } + + pf = d3d9_to_pipe_format_checked(screen, SurfaceFormat, PIPE_TEXTURE_2D, + MultiSampleType, bind, false, false); + + if (pf == PIPE_FORMAT_NONE && SurfaceFormat != D3DFMT_NULL) { + DBG("%s with %u samples not available.\n", + d3dformat_to_string(SurfaceFormat), MultiSampleType); + return D3DERR_NOTAVAILABLE; + } + + if (pQualityLevels) { + /* NONMASKABLE MultiSampleType might have more than one quality level, + * while MASKABLE MultiSampleTypes have only one level. + * Advertise quality levels and map each level to a sample count. */ + (void ) d3dmultisample_type_check(screen, SurfaceFormat, + &MultiSampleType, D3DMULTISAMPLE_16_SAMPLES, pQualityLevels); + DBG("advertising %u quality levels\n", *pQualityLevels); + } + + return D3D_OK; +} + +HRESULT NINE_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)); + + /* TODO: does it check AdapterFormat at all ? + * It seems to need to pass at least for A8R8G8B8: + * https://github.com/iXit/Mesa-3D/issues/317 */ + user_assert(adapter_format(AdapterFormat), 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_checked(screen, AdapterFormat, PIPE_TEXTURE_2D, 0, + NINE_BIND_BACKBUFFER_FLAGS, false, false); + bfmt = d3d9_to_pipe_format_checked(screen, RenderTargetFormat, + PIPE_TEXTURE_2D, 0, + NINE_BIND_BACKBUFFER_FLAGS, false, false); + if (RenderTargetFormat == D3DFMT_NULL) + bfmt = dfmt; + zsfmt = d3d9_to_pipe_format_checked(screen, DepthStencilFormat, + PIPE_TEXTURE_2D, 0, + d3d9_get_pipe_depth_format_bindings(DepthStencilFormat), + false, false); + if (dfmt == PIPE_FORMAT_NONE || + bfmt == PIPE_FORMAT_NONE || + zsfmt == PIPE_FORMAT_NONE) { + return D3DERR_NOTAVAILABLE; + } + + return D3D_OK; +} + +HRESULT NINE_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_checked(screen, TargetFormat, PIPE_TEXTURE_2D, 1, + NINE_BIND_BACKBUFFER_FLAGS, false, false); + bfmt = d3d9_to_pipe_format_checked(screen, SourceFormat, PIPE_TEXTURE_2D, 1, + NINE_BIND_BACKBUFFER_FLAGS, false, false); + + if (dfmt == PIPE_FORMAT_NONE || bfmt == PIPE_FORMAT_NONE) { + DBG("%s to %s not supported.\n", + d3dformat_to_string(SourceFormat), + d3dformat_to_string(TargetFormat)); + return D3DERR_NOTAVAILABLE; + } + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineAdapter9_GetDeviceCaps( struct NineAdapter9 *This, + D3DDEVTYPE DeviceType, + D3DCAPS9 *pCaps ) +{ + struct pipe_screen *screen; + 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->caps.pcap ? (d3dcap) : 0) + +#define D3DNPIPECAP(pcap, d3dcap) \ + (screen->caps.pcap ? 0 : (d3dcap)) + + pCaps->DeviceType = DeviceType; + + pCaps->AdapterOrdinal = 0; + + pCaps->Caps = D3DCAPS_READ_SCANLINE; + + 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: advertise if Ex and dx10 able card */ + D3DPMISCCAPS_FOGANDSPECULARALPHA | /* Note: documentation of the flag is wrong */ + D3DPIPECAP(blend_equation_separate, D3DPMISCCAPS_SEPARATEALPHABLEND) | + D3DPIPECAP(mixed_colorbuffer_formats, D3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS) | + D3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING | + D3DPMISCCAPS_FOGVERTEXCLAMPED; + if (!screen->caps.vs_window_space_position && + !screen->caps.depth_clip_disable) + pCaps->PrimitiveMiscCaps |= D3DPMISCCAPS_CLIPTLVERTS; + + 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_NEVER | + 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_size, 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->caps.max_line_width_aa > 0.0) { + pCaps->LineCaps |= D3DLINECAPS_ANTIALIAS; + } + + pCaps->MaxTextureWidth =screen->caps.max_texture_2d_size; + pCaps->MaxTextureHeight = pCaps->MaxTextureWidth; + pCaps->MaxVolumeExtent = + 1 << (screen->caps.max_texture_3d_levels - 1); + /* XXX values from wine */ + pCaps->MaxTextureRepeat = 32768; + pCaps->MaxTextureAspectRatio = pCaps->MaxTextureWidth; + + pCaps->MaxAnisotropy = + (DWORD)screen->caps.max_texture_anisotropy; + + /* Values for GeForce 9600 GT */ + pCaps->MaxVertexW = 1e10f; + pCaps->GuardBandLeft = -1e9f; + pCaps->GuardBandTop = -1e9f; + pCaps->GuardBandRight = 1e9f; + pCaps->GuardBandBottom = 1e9f; + pCaps->ExtentsAdjust = 0.0f; + + pCaps->StencilCaps = + D3DSTENCILCAPS_KEEP | + D3DSTENCILCAPS_ZERO | + D3DSTENCILCAPS_REPLACE | + D3DSTENCILCAPS_INCRSAT | + D3DSTENCILCAPS_DECRSAT | + D3DSTENCILCAPS_INVERT | + D3DSTENCILCAPS_INCR | + D3DSTENCILCAPS_DECR | + D3DSTENCILCAPS_TWOSIDED; + + pCaps->FVFCaps = + 8 | /* 8 textures max */ + /*D3DFVFCAPS_DONOTSTRIPELEMENTS |*/ + D3DFVFCAPS_PSIZE; + + 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 */ + pCaps->MaxSimultaneousTextures = 8; + + 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 = 8; /* D3DTS_WORLDMATRIX(0..8) */ + + pCaps->MaxPointSize = screen->caps.max_point_size; + + pCaps->MaxPrimitiveCount = 0x555555; /* <- wine, really 0xFFFFFFFF; */ + pCaps->MaxVertexIndex = 0xFFFFFF; /* <- wine, really 0xFFFFFFFF */ + pCaps->MaxStreams = + _min(screen->shader_caps[MESA_SHADER_VERTEX].max_inputs, + 16); + + pCaps->MaxStreamStride = screen->caps.max_vertex_attrib_stride; + + pCaps->VertexShaderVersion = D3DVS_VERSION(3,0); + + /* VS 2 as well as 3.0 supports a minimum of 256 consts. + * Wine and d3d9 drivers for dx1x hw advertise 256. Just as them, + * advertise 256. Problem is with hw that can only do 256, because + * we need take a few slots for boolean and integer constants. For these + * we'll have to fail later if they use complex shaders. */ + pCaps->MaxVertexShaderConst = NINE_MAX_CONST_F; + + pCaps->PixelShaderVersion = D3DPS_VERSION(3,0); + /* Value for GeForce 9600 GT */ + pCaps->PixelShader1xMaxValue = 65504.f; + + 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->caps.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->shader_caps[MESA_SHADER_VERTEX].max_control_flow_depth; + pCaps->VS20Caps.NumTemps = + screen->shader_caps[MESA_SHADER_VERTEX].max_temps; + pCaps->VS20Caps.StaticFlowControlDepth = /* XXX is this static ? */ + screen->shader_caps[MESA_SHADER_VERTEX].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->shader_caps[MESA_SHADER_FRAGMENT].max_tex_instructions == + screen->shader_caps[MESA_SHADER_FRAGMENT].max_instructions) + pCaps->PS20Caps.Caps |= D3DPS20CAPS_NOTEXINSTRUCTIONLIMIT; + if (screen->shader_caps[MESA_SHADER_FRAGMENT].max_tex_instructions == + screen->shader_caps[MESA_SHADER_FRAGMENT].max_tex_indirections) + pCaps->PS20Caps.Caps |= D3DPS20CAPS_NODEPENDENTREADLIMIT; + pCaps->PS20Caps.DynamicFlowControlDepth = /* XXX is this dynamic ? */ + screen->shader_caps[MESA_SHADER_FRAGMENT].max_control_flow_depth; + pCaps->PS20Caps.NumTemps = + screen->shader_caps[MESA_SHADER_FRAGMENT].max_temps; + pCaps->PS20Caps.StaticFlowControlDepth = /* XXX is this static ? */ + screen->shader_caps[MESA_SHADER_FRAGMENT].max_control_flow_depth; + pCaps->PS20Caps.NumInstructionSlots = + screen->shader_caps[MESA_SHADER_FRAGMENT].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->shader_caps[MESA_SHADER_VERTEX].max_texture_samplers) + pCaps->VertexTextureFilterCaps = pCaps->TextureFilterCaps & + ~(D3DPTFILTERCAPS_MIPFPOINT | + D3DPTFILTERCAPS_MIPFPOINT); /* XXX */ + else + pCaps->VertexTextureFilterCaps = 0; + + pCaps->MaxVertexShader30InstructionSlots = + screen->shader_caps[MESA_SHADER_VERTEX].max_instructions; + pCaps->MaxPixelShader30InstructionSlots = + screen->shader_caps[MESA_SHADER_FRAGMENT].max_instructions; + if (pCaps->MaxVertexShader30InstructionSlots > D3DMAX30SHADERINSTRUCTIONS) + pCaps->MaxVertexShader30InstructionSlots = D3DMAX30SHADERINSTRUCTIONS; + if (pCaps->MaxPixelShader30InstructionSlots > D3DMAX30SHADERINSTRUCTIONS) + pCaps->MaxPixelShader30InstructionSlots = D3DMAX30SHADERINSTRUCTIONS; + assert(pCaps->MaxVertexShader30InstructionSlots >= D3DMIN30SHADERINSTRUCTIONS); + assert(pCaps->MaxPixelShader30InstructionSlots >= D3DMIN30SHADERINSTRUCTIONS); + + /* 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 NINE_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, ¶ms, &caps, pPresentationParameters, + pD3D9, pPresentationGroup, This->ctx, false, NULL, + (struct NineDevice9 **)ppReturnedDeviceInterface, + minor); + if (FAILED(hr)) { + DBG("Failed to create device.\n"); + return hr; + } + DBG("NineDevice9 created successfully.\n"); + + return D3D_OK; +} + +HRESULT NINE_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, ¶ms, &caps, pPresentationParameters, + pFullscreenDisplayMode, + pD3D9Ex, pPresentationGroup, This->ctx, + (struct NineDevice9Ex **)ppReturnedDeviceInterface, + minor); + 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/frontends/nine/adapter9.h b/src/gallium/frontends/nine/adapter9.h new file mode 100644 index 0000000..156afdf --- /dev/null +++ b/src/gallium/frontends/nine/adapter9.h @@ -0,0 +1,130 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#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; + int vblank_mode; + BOOL thread_submit; + BOOL discard_delayed_release; + BOOL tearfree_discard; + int csmt_force; + BOOL dynamic_texture_workaround; + BOOL shader_inline_constants; + int memfd_virtualsizelimit; + int override_vram_size; + BOOL force_emulation; + + 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 NINE_WINAPI +NineAdapter9_GetAdapterIdentifier( struct NineAdapter9 *This, + DWORD Flags, + D3DADAPTER_IDENTIFIER9 *pIdentifier ); + +HRESULT NINE_WINAPI +NineAdapter9_CheckDeviceType( struct NineAdapter9 *This, + D3DDEVTYPE DevType, + D3DFORMAT AdapterFormat, + D3DFORMAT BackBufferFormat, + BOOL bWindowed ); + +HRESULT NINE_WINAPI +NineAdapter9_CheckDeviceFormat( struct NineAdapter9 *This, + D3DDEVTYPE DeviceType, + D3DFORMAT AdapterFormat, + DWORD Usage, + D3DRESOURCETYPE RType, + D3DFORMAT CheckFormat ); + +HRESULT NINE_WINAPI +NineAdapter9_CheckDeviceMultiSampleType( struct NineAdapter9 *This, + D3DDEVTYPE DeviceType, + D3DFORMAT SurfaceFormat, + BOOL Windowed, + D3DMULTISAMPLE_TYPE MultiSampleType, + DWORD *pQualityLevels ); + +HRESULT NINE_WINAPI +NineAdapter9_CheckDepthStencilMatch( struct NineAdapter9 *This, + D3DDEVTYPE DeviceType, + D3DFORMAT AdapterFormat, + D3DFORMAT RenderTargetFormat, + D3DFORMAT DepthStencilFormat ); + +HRESULT NINE_WINAPI +NineAdapter9_CheckDeviceFormatConversion( struct NineAdapter9 *This, + D3DDEVTYPE DeviceType, + D3DFORMAT SourceFormat, + D3DFORMAT TargetFormat ); + +HRESULT NINE_WINAPI +NineAdapter9_GetDeviceCaps( struct NineAdapter9 *This, + D3DDEVTYPE DeviceType, + D3DCAPS9 *pCaps ); + +HRESULT NINE_WINAPI +NineAdapter9_CreateDevice( struct NineAdapter9 *This, + UINT RealAdapter, + D3DDEVTYPE DeviceType, + HWND hFocusWindow, + DWORD BehaviorFlags, + D3DPRESENT_PARAMETERS *pPresentationParameters, + IDirect3D9 *pD3D9, + ID3DPresentGroup *pPresentationGroup, + IDirect3DDevice9 **ppReturnedDeviceInterface ); + +HRESULT NINE_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/frontends/nine/authenticatedchannel9.c b/src/gallium/frontends/nine/authenticatedchannel9.c new file mode 100644 index 0000000..a90d711 --- /dev/null +++ b/src/gallium/frontends/nine/authenticatedchannel9.c @@ -0,0 +1,61 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#include "authenticatedchannel9.h" + +#define DBG_CHANNEL DBG_AUTHENTICATEDCHANNEL + +HRESULT NINE_WINAPI +NineAuthenticatedChannel9_GetCertificateSize( struct NineAuthenticatedChannel9 *This, + UINT *pCertificateSize ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT NINE_WINAPI +NineAuthenticatedChannel9_GetCertificate( struct NineAuthenticatedChannel9 *This, + UINT CertifacteSize, + BYTE *ppCertificate ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT NINE_WINAPI +NineAuthenticatedChannel9_NegotiateKeyExchange( struct NineAuthenticatedChannel9 *This, + UINT DataSize, + void *pData ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT NINE_WINAPI +NineAuthenticatedChannel9_Query( struct NineAuthenticatedChannel9 *This, + UINT InputSize, + const void *pInput, + UINT OutputSize, + void *pOutput ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT NINE_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/frontends/nine/authenticatedchannel9.h b/src/gallium/frontends/nine/authenticatedchannel9.h new file mode 100644 index 0000000..1294b12 --- /dev/null +++ b/src/gallium/frontends/nine/authenticatedchannel9.h @@ -0,0 +1,48 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#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 NINE_WINAPI +NineAuthenticatedChannel9_GetCertificateSize( struct NineAuthenticatedChannel9 *This, + UINT *pCertificateSize ); + +HRESULT NINE_WINAPI +NineAuthenticatedChannel9_GetCertificate( struct NineAuthenticatedChannel9 *This, + UINT CertifacteSize, + BYTE *ppCertificate ); + +HRESULT NINE_WINAPI +NineAuthenticatedChannel9_NegotiateKeyExchange( struct NineAuthenticatedChannel9 *This, + UINT DataSize, + void *pData ); + +HRESULT NINE_WINAPI +NineAuthenticatedChannel9_Query( struct NineAuthenticatedChannel9 *This, + UINT InputSize, + const void *pInput, + UINT OutputSize, + void *pOutput ); + +HRESULT NINE_WINAPI +NineAuthenticatedChannel9_Configure( struct NineAuthenticatedChannel9 *This, + UINT InputSize, + const void *pInput, + D3DAUTHENTICATEDCHANNEL_CONFIGURE_OUTPUT *pOutput ); + +#endif /* _NINE_AUTHENTICATEDCHANNEL9_H_ */ diff --git a/src/gallium/frontends/nine/basetexture9.c b/src/gallium/frontends/nine/basetexture9.c new file mode 100644 index 0000000..ba3cdd4 --- /dev/null +++ b/src/gallium/frontends/nine/basetexture9.c @@ -0,0 +1,612 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#include "basetexture9.h" +#include "device9.h" + +/* For UploadSelf: */ +#include "texture9.h" +#include "cubetexture9.h" +#include "volumetexture9.h" +#include "nine_pipe.h" + +#if MESA_DEBUG || !defined(NDEBUG) +#include "nine_dump.h" +#endif + +#include "util/format/u_format.h" + +#define DBG_CHANNEL DBG_BASETEXTURE + +HRESULT +NineBaseTexture9_ctor( struct NineBaseTexture9 *This, + struct NineUnknownParams *pParams, + struct pipe_resource *initResource, + D3DRESOURCETYPE Type, + D3DFORMAT format, + D3DPOOL Pool, + DWORD Usage) +{ + BOOL alloc = (Pool == D3DPOOL_DEFAULT) && !initResource && + (format != D3DFMT_NULL); + HRESULT hr; + + DBG("This=%p, pParams=%p initResource=%p Type=%d format=%d Pool=%d Usage=%d\n", + This, pParams, initResource, Type, format, Pool, Usage); + + user_assert(!(Usage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) || + Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL); + user_assert(!(Usage & D3DUSAGE_DYNAMIC) || + !(Pool == D3DPOOL_MANAGED || + Pool == D3DPOOL_SCRATCH), D3DERR_INVALIDCALL); + + hr = NineResource9_ctor(&This->base, pParams, initResource, alloc, Type, Pool, Usage); + if (FAILED(hr)) + return hr; + + This->format = format; + This->mipfilter = (Usage & D3DUSAGE_AUTOGENMIPMAP) ? + D3DTEXF_LINEAR : D3DTEXF_NONE; + /* In the case of D3DUSAGE_AUTOGENMIPMAP, only the first level is accessible, + * and thus needs a surface created. */ + This->level_count = (Usage & D3DUSAGE_AUTOGENMIPMAP) ? 1 : (This->base.info.last_level+1); + This->managed.lod = 0; + This->managed.lod_resident = -1; + /* Mark the texture as dirty to trigger first upload when we need the texture, + * even if it wasn't set by the application */ + if (Pool == D3DPOOL_MANAGED) + This->managed.dirty = true; + /* When a depth buffer is sampled, it is for shadow mapping, except for + * D3DFMT_INTZ, D3DFMT_DF16 and D3DFMT_DF24. + * In addition D3DFMT_INTZ can be used for both texturing and depth buffering + * if z write is disabled. This particular feature may not work for us in + * practice because OGL doesn't have that. However apparently it is known + * some cards have performance issues with this feature, so real apps + * shouldn't use it. */ + This->shadow = (This->format != D3DFMT_INTZ && This->format != D3DFMT_DF16 && + This->format != D3DFMT_DF24) && + util_format_has_depth(util_format_description(This->base.info.format)); + This->fetch4_compatible = fetch4_compatible_format(This->format); + + list_inithead(&This->list); + list_inithead(&This->list2); + if (Pool == D3DPOOL_MANAGED) + list_add(&This->list2, &This->base.base.device->managed_textures); + + return D3D_OK; +} + +void +NineBaseTexture9_dtor( struct NineBaseTexture9 *This ) +{ + DBG("This=%p\n", This); + + nine_context_get_pipe_acquire(This->base.base.device); + pipe_sampler_view_release_ptr(&This->view[0]); + pipe_sampler_view_release_ptr(&This->view[1]); + nine_context_get_pipe_release(This->base.base.device); + + if (list_is_linked(&This->list)) + list_del(&This->list); + if (list_is_linked(&This->list2)) + list_del(&This->list2); + + NineResource9_dtor(&This->base); +} + +DWORD NINE_WINAPI +NineBaseTexture9_SetLOD( struct NineBaseTexture9 *This, + DWORD LODNew ) +{ + DWORD old = This->managed.lod; + + DBG("This=%p LODNew=%d\n", This, LODNew); + + user_assert(This->base.pool == D3DPOOL_MANAGED, 0); + + This->managed.lod = MIN2(LODNew, This->level_count-1); + + if (This->managed.lod != old && This->bind_count && list_is_empty(&This->list)) + list_add(&This->list, &This->base.base.device->update_textures); + + return old; +} + +DWORD NINE_WINAPI +NineBaseTexture9_GetLOD( struct NineBaseTexture9 *This ) +{ + DBG("This=%p\n", This); + + return This->managed.lod; +} + +DWORD NINE_WINAPI +NineBaseTexture9_GetLevelCount( struct NineBaseTexture9 *This ) +{ + DBG("This=%p\n", This); + + return This->level_count; +} + +HRESULT NINE_WINAPI +NineBaseTexture9_SetAutoGenFilterType( struct NineBaseTexture9 *This, + D3DTEXTUREFILTERTYPE FilterType ) +{ + DBG("This=%p FilterType=%d\n", This, FilterType); + + if (!(This->base.usage & D3DUSAGE_AUTOGENMIPMAP)) + return D3D_OK; + user_assert(FilterType != D3DTEXF_NONE, D3DERR_INVALIDCALL); + + This->mipfilter = FilterType; + This->dirty_mip = true; + NineBaseTexture9_GenerateMipSubLevels(This); + + return D3D_OK; +} + +D3DTEXTUREFILTERTYPE NINE_WINAPI +NineBaseTexture9_GetAutoGenFilterType( struct NineBaseTexture9 *This ) +{ + DBG("This=%p\n", This); + + return This->mipfilter; +} + +HRESULT +NineBaseTexture9_UploadSelf( struct NineBaseTexture9 *This ) +{ + HRESULT hr; + unsigned l, min_level_dirty = This->managed.lod; + BOOL update_lod; + + DBG("This=%p dirty=%i type=%s\n", This, This->managed.dirty, + nine_D3DRTYPE_to_str(This->base.type)); + + assert(This->base.pool == D3DPOOL_MANAGED); + + update_lod = This->managed.lod_resident != This->managed.lod; + if (!update_lod && !This->managed.dirty) + return D3D_OK; + + /* Allocate a new resource with the correct number of levels, + * Mark states for update, and tell the nine surfaces/volumes + * their new resource. */ + if (update_lod) { + struct pipe_resource *res; + + DBG("updating LOD from %u to %u ...\n", This->managed.lod_resident, This->managed.lod); + + nine_context_get_pipe_acquire(This->base.base.device); + pipe_sampler_view_release_ptr(&This->view[0]); + pipe_sampler_view_release_ptr(&This->view[1]); + nine_context_get_pipe_release(This->base.base.device); + + /* Allocate a new resource */ + hr = NineBaseTexture9_CreatePipeResource(This, This->managed.lod_resident != -1); + if (FAILED(hr)) + return hr; + res = This->base.resource; + + if (This->managed.lod_resident == -1) {/* no levels were resident */ + This->managed.dirty = false; /* We are going to upload everything. */ + This->managed.lod_resident = This->level_count; + } + + if (This->base.type == D3DRTYPE_TEXTURE) { + struct NineTexture9 *tex = NineTexture9(This); + + /* last content (if apply) has been copied to the new resource. + * Note: We cannot render to surfaces of managed textures. + * Note2: the level argument passed is to get the level offset + * right when the texture is uploaded (the texture first level + * corresponds to This->managed.lod). + * Note3: We don't care about the value passed for the surfaces + * before This->managed.lod, negative with this implementation. */ + for (l = 0; l < This->level_count; ++l) + NineSurface9_SetResource(tex->surfaces[l], res, l - This->managed.lod); + } else + if (This->base.type == D3DRTYPE_CUBETEXTURE) { + struct NineCubeTexture9 *tex = NineCubeTexture9(This); + unsigned z; + + for (l = 0; l < This->level_count; ++l) { + for (z = 0; z < 6; ++z) + NineSurface9_SetResource(tex->surfaces[l * 6 + z], + res, l - This->managed.lod); + } + } else + if (This->base.type == D3DRTYPE_VOLUMETEXTURE) { + struct NineVolumeTexture9 *tex = NineVolumeTexture9(This); + + for (l = 0; l < This->level_count; ++l) + NineVolume9_SetResource(tex->volumes[l], res, l - This->managed.lod); + } else { + assert(!"invalid texture type"); + } + + /* We are going to fully upload the new levels, + * no need to update dirty parts of the texture for these */ + min_level_dirty = MAX2(This->managed.lod, This->managed.lod_resident); + } + + /* Update dirty parts of the texture */ + if (This->managed.dirty) { + 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); + + /* Note: for l < min_level_dirty, the resource is + * either non-existing (and thus will be entirely re-uploaded + * if the lod changes) or going to have a full upload */ + if (tex->dirty_rect.width) { + for (l = min_level_dirty; l < This->level_count; ++l) { + u_box_minify_2d(&box, &tex->dirty_rect, l); + NineSurface9_UploadSelf(tex->surfaces[l], &box); + } + memset(&tex->dirty_rect, 0, sizeof(tex->dirty_rect)); + tex->dirty_rect.depth = 1; + } + } 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 = min_level_dirty; l < This->level_count; ++l) { + u_box_minify_2d(&box, &tex->dirty_rect[z], l); + NineSurface9_UploadSelf(tex->surfaces[l * 6 + z], &box); + } + memset(&tex->dirty_rect[z], 0, sizeof(tex->dirty_rect[z])); + tex->dirty_rect[z].depth = 1; + } + } + } 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 = min_level_dirty; l < This->level_count; ++l) { + u_box_minify_3d(&box, &tex->dirty_box, l); + NineVolume9_UploadSelf(tex->volumes[l], &box); + } + memset(&tex->dirty_box, 0, sizeof(tex->dirty_box)); + } + } else { + assert(!"invalid texture type"); + } + This->managed.dirty = false; + } + + /* Upload the new levels */ + if (update_lod) { + if (This->base.type == D3DRTYPE_TEXTURE) { + struct NineTexture9 *tex = NineTexture9(This); + struct pipe_box box; + + box.x = box.y = box.z = 0; + box.depth = 1; + for (l = This->managed.lod; l < This->managed.lod_resident; ++l) { + box.width = u_minify(This->base.info.width0, l); + box.height = u_minify(This->base.info.height0, l); + NineSurface9_UploadSelf(tex->surfaces[l], &box); + } + } else + if (This->base.type == D3DRTYPE_CUBETEXTURE) { + struct NineCubeTexture9 *tex = NineCubeTexture9(This); + struct pipe_box box; + unsigned z; + + box.x = box.y = box.z = 0; + box.depth = 1; + for (l = This->managed.lod; l < This->managed.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_UploadSelf(tex->surfaces[l * 6 + z], &box); + } + } else + if (This->base.type == D3DRTYPE_VOLUMETEXTURE) { + struct NineVolumeTexture9 *tex = NineVolumeTexture9(This); + struct pipe_box box; + + box.x = box.y = box.z = 0; + for (l = This->managed.lod; l < This->managed.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_UploadSelf(tex->volumes[l], &box); + } + } else { + assert(!"invalid texture type"); + } + + This->managed.lod_resident = This->managed.lod; + } + + if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP) + This->dirty_mip = true; + + /* Set again the textures currently bound to update the texture data */ + if (This->bind_count) { + struct nine_state *state = &This->base.base.device->state; + unsigned s; + for (s = 0; s < NINE_MAX_SAMPLERS; ++s) + /* Dirty tracking is done in device9 state, not nine_context. */ + if (state->texture[s] == This) + nine_context_set_texture(This->base.base.device, s, This); + } + + DBG("DONE, generate mip maps = %i\n", This->dirty_mip); + return D3D_OK; +} + +void NINE_WINAPI +NineBaseTexture9_GenerateMipSubLevels( struct NineBaseTexture9 *This ) +{ + unsigned base_level = 0; + unsigned last_level = This->base.info.last_level - This->managed.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->managed.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); + + nine_context_gen_mipmap(This->base.base.device, (struct NineUnknown *)This, + This->base.resource, + base_level, last_level, + first_layer, last_layer, filter); + + This->dirty_mip = false; +} + +HRESULT +NineBaseTexture9_CreatePipeResource( struct NineBaseTexture9 *This, + BOOL CopyData ) +{ + struct pipe_context *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->managed.lod, This->base.info.last_level); + + assert(This->base.pool == D3DPOOL_MANAGED); + + templ = This->base.info; + + if (This->managed.lod) { + templ.width0 = u_minify(templ.width0, This->managed.lod); + templ.height0 = u_minify(templ.height0, This->managed.lod); + templ.depth0 = u_minify(templ.depth0, This->managed.lod); + } + templ.last_level = This->base.info.last_level - This->managed.lod; + + if (old) { + /* LOD might have changed. */ + if (old->width0 == templ.width0 && + old->height0 == templ.height0 && + old->depth0 == templ.depth0) + return D3D_OK; + } + + res = nine_resource_create_with_retry(This->base.base.device, 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->managed.lod < This->managed.lod_resident) ? This->managed.lod_resident - This->managed.lod : 0; + m = (This->managed.lod < This->managed.lod_resident) ? 0 : This->managed.lod - This->managed.lod_resident; + + box.width = u_minify(templ.width0, l); + box.height = u_minify(templ.height0, l); + box.depth = u_minify(templ.depth0, l); + + pipe = nine_context_get_pipe_acquire(This->base.base.device); + + 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); + } + + nine_context_get_pipe_release(This->base.base.device); + } + pipe_resource_reference(&old, NULL); + + return D3D_OK; +} + +#define SWIZZLE_TO_REPLACE(s) (s == PIPE_SWIZZLE_0 || \ + s == PIPE_SWIZZLE_1 || \ + s == PIPE_SWIZZLE_NONE) + +HRESULT +NineBaseTexture9_UpdateSamplerView( struct NineBaseTexture9 *This, + const int sRGB ) +{ + const struct util_format_description *desc; + struct pipe_context *pipe; + struct pipe_screen *screen = NineDevice9_GetScreen(This->base.base.device); + struct pipe_resource *resource = This->base.resource; + struct pipe_sampler_view templ; + enum pipe_format srgb_format; + unsigned i; + uint8_t swizzle[4]; + memset(&templ, 0, sizeof(templ)); + + DBG("This=%p sRGB=%d\n", This, sRGB); + + if (unlikely(!resource)) { + if (unlikely(This->format == D3DFMT_NULL)) + return D3D_OK; + NineBaseTexture9_Dump(This); + } + assert(resource); + + pipe = nine_context_get_pipe_acquire(This->base.base.device); + pipe->sampler_view_release(pipe, This->view[sRGB]); + This->view[sRGB] = NULL; + nine_context_get_pipe_release(This->base.base.device); + + swizzle[0] = PIPE_SWIZZLE_X; + swizzle[1] = PIPE_SWIZZLE_Y; + swizzle[2] = PIPE_SWIZZLE_Z; + swizzle[3] = PIPE_SWIZZLE_W; + desc = util_format_description(resource->format); + if (desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) { + /* msdn doc is incomplete here and wrong. + * The only formats that can be read directly here + * are DF16, DF24 and INTZ. + * Tested on win the swizzle is + * R = depth, G = B = 0, A = 1 for DF16 and DF24 + * R = G = B = A = depth for INTZ + * For the other ZS formats that can't be read directly + * but can be used as shadow map, the result is duplicated on + * all channel */ + if (This->format == D3DFMT_DF16 || + This->format == D3DFMT_DF24) { + swizzle[1] = PIPE_SWIZZLE_0; + swizzle[2] = PIPE_SWIZZLE_0; + swizzle[3] = PIPE_SWIZZLE_1; + } else { + swizzle[1] = PIPE_SWIZZLE_X; + swizzle[2] = PIPE_SWIZZLE_X; + swizzle[3] = PIPE_SWIZZLE_X; + } + } else if (resource->format == PIPE_FORMAT_RGTC2_UNORM) { + swizzle[0] = PIPE_SWIZZLE_Y; + swizzle[1] = PIPE_SWIZZLE_X; + swizzle[2] = PIPE_SWIZZLE_1; + swizzle[3] = PIPE_SWIZZLE_1; + } else if (resource->format != PIPE_FORMAT_A8_UNORM && + resource->format != PIPE_FORMAT_RGTC1_UNORM) { + /* exceptions: + * A8 should have 0.0 as default values for RGB. + * ATI1/RGTC1 should be r 0 0 1 (tested on windows). + * It is already what gallium does. All the other ones + * should have 1.0 for non-defined values */ + for (i = 0; i < 4; i++) { + if (SWIZZLE_TO_REPLACE(desc->swizzle[i])) + swizzle[i] = PIPE_SWIZZLE_1; + } + } + + /* if requested and supported, convert to the sRGB format */ + srgb_format = util_format_srgb(resource->format); + if (sRGB && srgb_format != PIPE_FORMAT_NONE && + screen->is_format_supported(screen, srgb_format, + resource->target, 0, 0, resource->bind)) + templ.format = srgb_format; + else + templ.format = resource->format; + templ.u.tex.first_layer = 0; + templ.u.tex.last_layer = resource->target == PIPE_TEXTURE_3D ? + 0 : resource->array_size - 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; + + pipe = nine_context_get_pipe_acquire(This->base.base.device); + This->view[sRGB] = pipe->create_sampler_view(pipe, resource, &templ); + nine_context_get_pipe_release(This->base.base.device); + + DBG("sampler view = %p(resource = %p)\n", This->view[sRGB], resource); + + return This->view[sRGB] ? D3D_OK : D3DERR_DRIVERINTERNALERROR; +} + +void NINE_WINAPI +NineBaseTexture9_PreLoad( struct NineBaseTexture9 *This ) +{ + DBG("This=%p\n", This); + + if (This->base.pool == D3DPOOL_MANAGED) + NineBaseTexture9_UploadSelf(This); +} + +void +NineBaseTexture9_UnLoad( struct NineBaseTexture9 *This ) +{ + DBG("This=%p\n", This); + + if (This->base.pool != D3DPOOL_MANAGED || + This->managed.lod_resident == -1) + return; + + DBG("This=%p, releasing resource\n", This); + pipe_resource_reference(&This->base.resource, NULL); + This->managed.lod_resident = -1; + This->managed.dirty = true; + + /* If the texture is bound, we have to re-upload it */ + BASETEX_REGISTER_UPDATE(This); +} + +#if MESA_DEBUG || !defined(NDEBUG) +void +NineBaseTexture9_Dump( struct NineBaseTexture9 *This ) +{ + DBG("\nNineBaseTexture9(%p->NULL/%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, + 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->managed.lod, This->managed.lod_resident); +} +#endif /* MESA_DEBUG || !NDEBUG */ diff --git a/src/gallium/frontends/nine/basetexture9.h b/src/gallium/frontends/nine/basetexture9.h new file mode 100644 index 0000000..0614bfa --- /dev/null +++ b/src/gallium/frontends/nine/basetexture9.h @@ -0,0 +1,156 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#ifndef _NINE_BASETEXTURE9_H_ +#define _NINE_BASETEXTURE9_H_ + +#include "device9.h" +#include "resource9.h" +#include "util/u_inlines.h" +#include "util/list.h" + +struct NineBaseTexture9 +{ + struct NineResource9 base; + struct list_head list; /* for update_textures */ + struct list_head list2; /* for managed_textures */ + + /* g3d */ + struct pipe_sampler_view *view[2]; /* linear and sRGB */ + + D3DFORMAT format; + + int16_t bind_count; /* to Device9->state.texture */ + + bool shadow; + bool fetch4_compatible; + uint8_t pstype; /* 0: 2D, 1: 1D, 2: CUBE, 3: 3D */ + + bool dirty_mip; + D3DTEXTUREFILTERTYPE mipfilter; + + unsigned level_count; + + /* Specific to managed textures */ + struct { + bool dirty; + DWORD lod; + DWORD lod_resident; + } managed; +}; +static inline struct NineBaseTexture9 * +NineBaseTexture9( void *data ) +{ + return (struct NineBaseTexture9 *)data; +} + +HRESULT +NineBaseTexture9_ctor( struct NineBaseTexture9 *This, + struct NineUnknownParams *pParams, + struct pipe_resource *initResource, + D3DRESOURCETYPE Type, + D3DFORMAT format, + D3DPOOL Pool, + DWORD Usage); + +void +NineBaseTexture9_dtor( struct NineBaseTexture9 *This ); + +DWORD NINE_WINAPI +NineBaseTexture9_SetLOD( struct NineBaseTexture9 *This, + DWORD LODNew ); + +DWORD NINE_WINAPI +NineBaseTexture9_GetLOD( struct NineBaseTexture9 *This ); + +DWORD NINE_WINAPI +NineBaseTexture9_GetLevelCount( struct NineBaseTexture9 *This ); + +HRESULT NINE_WINAPI +NineBaseTexture9_SetAutoGenFilterType( struct NineBaseTexture9 *This, + D3DTEXTUREFILTERTYPE FilterType ); + +D3DTEXTUREFILTERTYPE NINE_WINAPI +NineBaseTexture9_GetAutoGenFilterType( struct NineBaseTexture9 *This ); + +void NINE_WINAPI +NineBaseTexture9_GenerateMipSubLevels( struct NineBaseTexture9 *This ); + +void NINE_WINAPI +NineBaseTexture9_PreLoad( struct NineBaseTexture9 *This ); + +void +NineBaseTexture9_UnLoad( 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->managed.dirty, This->dirty_mip, This->managed.lod, This->managed.lod_resident); + if ((This->base.pool == D3DPOOL_MANAGED) && + (This->managed.dirty || This->managed.lod != This->managed.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]; +} + +static void inline +NineBindTextureToDevice( struct NineDevice9 *device, + struct NineBaseTexture9 **slot, + struct NineBaseTexture9 *tex ) +{ + struct NineBaseTexture9 *old = *slot; + + if (tex) { + if ((tex->managed.dirty | tex->dirty_mip) && list_is_empty(&tex->list)) + list_add(&tex->list, &device->update_textures); + + tex->bind_count++; + } + if (old) { + old->bind_count--; + if (!old->bind_count) + list_delinit(&old->list); + } + + nine_bind(slot, tex); +} + +#if MESA_DEBUG || !defined(NDEBUG) +void +NineBaseTexture9_Dump( struct NineBaseTexture9 *This ); +#else +static inline void +NineBaseTexture9_Dump( struct NineBaseTexture9 *This ) { } +#endif + +#define BASETEX_REGISTER_UPDATE(t) do { \ + if (((t)->managed.dirty | ((t)->dirty_mip)) && (t)->bind_count) \ + 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/frontends/nine/buffer9.c b/src/gallium/frontends/nine/buffer9.c new file mode 100644 index 0000000..e3cbe89 --- /dev/null +++ b/src/gallium/frontends/nine/buffer9.c @@ -0,0 +1,699 @@ +/* + * Copyright 2011 Joakim Sindholt + * Copyright 2015 Patrick Rudolph + * SPDX-License-Identifier: MIT + */ + +#include "buffer9.h" +#include "device9.h" +#include "indexbuffer9.h" +#include "nine_buffer_upload.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 "util/format/u_formats.h" +#include "util/box.h" +#include "util/u_inlines.h" + +#define DBG_CHANNEL (DBG_INDEXBUFFER|DBG_VERTEXBUFFER) + +HRESULT +NineBuffer9_ctor( struct NineBuffer9 *This, + struct NineUnknownParams *pParams, + D3DRESOURCETYPE Type, + DWORD Usage, + UINT Size, + D3DPOOL Pool ) +{ + struct pipe_resource *info = &This->base.info; + HRESULT hr; + + DBG("This=%p Size=0x%x Usage=%x Pool=%u\n", This, Size, Usage, Pool); + + user_assert(Pool != D3DPOOL_SCRATCH, D3DERR_INVALIDCALL); + + This->maps = MALLOC(sizeof(struct NineTransfer)); + if (!This->maps) + return E_OUTOFMEMORY; + This->nlocks = 0; + This->nmaps = 0; + This->maxmaps = 1; + This->size = Size; + + info->screen = pParams->device->screen; + info->target = PIPE_BUFFER; + info->format = PIPE_FORMAT_R8_UNORM; + info->width0 = Size; + info->flags = 0; + + /* Note: WRITEONLY is just tip for resource placement, the resource + * can still be read (but slower). */ + info->bind = (Type == D3DRTYPE_INDEXBUFFER) ? PIPE_BIND_INDEX_BUFFER : PIPE_BIND_VERTEX_BUFFER; + + /* Software vertex processing: + * If the device is full software vertex processing, + * then the buffer is supposed to be used only for sw processing. + * For mixed vertex processing, buffers with D3DUSAGE_SOFTWAREPROCESSING + * can be used for both sw and hw processing. + * These buffers are expected to be stored in RAM. + * Apps expect locking the full buffer with no flags, then + * render a a few primitive, then locking again, etc + * to be a fast pattern. Only the SYSTEMMEM DYNAMIC path + * will give that pattern ok performance in our case. + * An alternative would be when sw processing is detected to + * convert Draw* calls to Draw*Up calls. */ + if (Usage & D3DUSAGE_SOFTWAREPROCESSING || + pParams->device->params.BehaviorFlags & D3DCREATE_SOFTWARE_VERTEXPROCESSING) { + Pool = D3DPOOL_SYSTEMMEM; + Usage |= D3DUSAGE_DYNAMIC; + /* Note: the application cannot retrieve Pool and Usage */ + } + + /* Always use the DYNAMIC path for SYSTEMMEM. + * If the app uses the vertex buffer is a dynamic fashion, + * this is going to be very significantly faster that way. + * If the app uses the vertex buffer in a static fashion, + * instead of being filled all at once, the buffer will be filled + * little per little, until it is fully filled, thus the perf hit + * will be very small. */ + if (Pool == D3DPOOL_SYSTEMMEM) + Usage |= D3DUSAGE_DYNAMIC; + + /* It is hard to find clear information on where to place the buffer in + * memory depending on the flag. + * MSDN: resources are static, except for those with DYNAMIC, thus why you + * can only use DISCARD on them. + * ATI doc: The driver has the liberty it wants for having things static + * or not. + * MANAGED: Ram + uploads to Vram copy at unlock (msdn and nvidia doc say + * at first draw call using the buffer) + * DEFAULT + Usage = 0 => System memory backing for easy read access + * (That doc is very unclear on the details, like whether some copies to + * vram copy are involved or not). + * DEFAULT + WRITEONLY => Vram + * DEFAULT + WRITEONLY + DYNAMIC => Either Vram buffer or GTT_WC, depending on what the driver wants. + * SYSTEMMEM: Same as MANAGED, but handled by the driver instead of the runtime (which means + * some small behavior differences between vendors). Implementing exactly as MANAGED should + * be fine. + */ + if (Pool == D3DPOOL_SYSTEMMEM && Usage & D3DUSAGE_DYNAMIC) + info->usage = PIPE_USAGE_STREAM; + else if (Pool != D3DPOOL_DEFAULT) + info->usage = PIPE_USAGE_DEFAULT; + else if (Usage & D3DUSAGE_DYNAMIC && Usage & D3DUSAGE_WRITEONLY) + info->usage = PIPE_USAGE_STREAM; + else if (Usage & D3DUSAGE_WRITEONLY) + info->usage = PIPE_USAGE_DEFAULT; + /* For the remaining two, PIPE_USAGE_STAGING would probably be + * a good fit according to the doc. However it seems rather a mistake + * from apps to use these (mistakes that do really happen). Try + * to put the flags that are the best compromise between the real + * behaviour and what buggy apps should get for better performance. */ + else if (Usage & D3DUSAGE_DYNAMIC) + info->usage = PIPE_USAGE_STREAM; + else + info->usage = PIPE_USAGE_DYNAMIC; + + /* When Writeonly is not set, we don't want to enable the + * optimizations */ + This->discard_nooverwrite_only = !!(Usage & D3DUSAGE_WRITEONLY) && + pParams->device->buffer_upload; + /* 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_TEXTAPI) { } */ + + info->height0 = 1; + info->depth0 = 1; + info->array_size = 1; + info->last_level = 0; + info->nr_samples = 0; + info->nr_storage_samples = 0; + + hr = NineResource9_ctor(&This->base, pParams, NULL, true, + Type, Pool, Usage); + + if (FAILED(hr)) + return hr; + + if (Pool != D3DPOOL_DEFAULT) { + This->managed.data = align_calloc( + nine_format_get_level_alloc_size(This->base.info.format, + Size, 1, 0), 32); + if (!This->managed.data) + return E_OUTOFMEMORY; + This->managed.dirty = true; + u_box_1d(0, Size, &This->managed.dirty_box); + u_box_1d(0, 0, &This->managed.valid_region); + u_box_1d(0, 0, &This->managed.required_valid_region); + u_box_1d(0, 0, &This->managed.filled_region); + This->managed.can_unsynchronized = true; + This->managed.num_worker_thread_syncs = 0; + list_inithead(&This->managed.list); + list_inithead(&This->managed.list2); + list_add(&This->managed.list2, &pParams->device->managed_buffers); + } + + return D3D_OK; +} + +void +NineBuffer9_dtor( struct NineBuffer9 *This ) +{ + DBG("This=%p\n", This); + + if (This->maps) { + while (This->nlocks) { + NineBuffer9_Unlock(This); + } + assert(!This->nmaps); + FREE(This->maps); + } + + if (This->base.pool != D3DPOOL_DEFAULT) { + if (This->managed.data) + align_free(This->managed.data); + if (list_is_linked(&This->managed.list)) + list_del(&This->managed.list); + if (list_is_linked(&This->managed.list2)) + list_del(&This->managed.list2); + } + + if (This->buf) + nine_upload_release_buffer(This->base.base.device->buffer_upload, This->buf); + + NineResource9_dtor(&This->base); +} + +struct pipe_resource * +NineBuffer9_GetResource( struct NineBuffer9 *This, unsigned *offset ) +{ + if (This->buf) + return nine_upload_buffer_resource_and_offset(This->buf, offset); + *offset = 0; + return NineResource9_GetResource(&This->base); +} + +static void +NineBuffer9_RebindIfRequired( struct NineBuffer9 *This, + struct NineDevice9 *device, + struct pipe_resource *resource, + unsigned offset ) +{ + int i; + + if (!This->bind_count) + return; + for (i = 0; i < device->caps.MaxStreams; i++) { + if (device->state.stream[i] == (struct NineVertexBuffer9 *)This) + nine_context_set_stream_source_apply(device, i, + resource, + device->state.vtxbuf[i].buffer_offset + offset, + device->state.vtxstride[i]); + } + if (device->state.idxbuf == (struct NineIndexBuffer9 *)This) + nine_context_set_indices_apply(device, resource, + ((struct NineIndexBuffer9 *)This)->index_size, + offset); +} + +HRESULT NINE_WINAPI +NineBuffer9_Lock( struct NineBuffer9 *This, + UINT OffsetToLock, + UINT SizeToLock, + void **ppbData, + DWORD Flags ) +{ + struct NineDevice9 *device = This->base.base.device; + struct pipe_box box; + struct pipe_context *pipe; + void *data; + unsigned usage; + + 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); + + if (SizeToLock == 0) { + SizeToLock = This->size - OffsetToLock; + user_warn(OffsetToLock != 0); + } + + /* Write out of bound seems to have to be taken into account for these. + * TODO: Do more tests (is it only at buffer first lock ? etc). + * Since these buffers are supposed to be locked once and never + * written again (MANAGED or DYNAMIC is used for the other uses cases), + * performance should be unaffected. */ + if (!(This->base.usage & D3DUSAGE_DYNAMIC) && This->base.pool == D3DPOOL_DEFAULT) + SizeToLock = This->size - OffsetToLock; + + SizeToLock = MIN2(SizeToLock, This->size - OffsetToLock); /* Do not read or track out of the buffer */ + u_box_1d(OffsetToLock, SizeToLock, &box); + + if (This->base.pool != D3DPOOL_DEFAULT) { + /* MANAGED: READONLY doesn't dirty the buffer, nor + * wait the upload in the worker thread + * SYSTEMMEM: AMD/NVidia: All locks dirty the full buffer. Not on Intel + * For Nvidia, SYSTEMMEM behaves are if there is no worker thread. + * On AMD, READONLY and NOOVERWRITE do dirty the buffer, but do not sync the previous uploads + * in the worker thread. On Intel only NOOVERWRITE has that effect. + * We implement the AMD behaviour. */ + if (This->base.pool == D3DPOOL_MANAGED) { + if (!(Flags & D3DLOCK_READONLY)) { + if (!This->managed.dirty) { + assert(list_is_empty(&This->managed.list)); + This->managed.dirty = true; + This->managed.dirty_box = box; + /* Flush if regions pending to be uploaded would be dirtied */ + if (p_atomic_read(&This->managed.pending_upload)) { + u_box_intersect_1d(&box, &box, &This->managed.upload_pending_regions); + if (box.width != 0) + nine_csmt_process(This->base.base.device); + } + } else + u_box_union_1d(&This->managed.dirty_box, &This->managed.dirty_box, &box); + /* Tests trying to draw while the buffer is locked show that + * SYSTEMMEM/MANAGED buffers are made dirty at Lock time */ + BASEBUF_REGISTER_UPDATE(This); + } + } else { + if (!(Flags & (D3DLOCK_READONLY|D3DLOCK_NOOVERWRITE)) && + p_atomic_read(&This->managed.pending_upload)) { + This->managed.num_worker_thread_syncs++; + /* If we sync too often, pick the vertex_uploader path */ + if (This->managed.num_worker_thread_syncs >= 3) + This->managed.can_unsynchronized = false; + nine_csmt_process(This->base.base.device); + /* Note: AS DISCARD is not relevant for SYSTEMMEM, + * NOOVERWRITE might have a similar meaning as what is + * in D3D7 doc. Basically that data from previous draws + * OF THIS FRAME are unaffected. As we flush csmt in Present(), + * we should be correct. In some parts of the doc, the notion + * of frame is implied to be related to Begin/EndScene(), + * but tests show NOOVERWRITE after EndScene() doesn't flush + * the csmt thread. */ + } + This->managed.dirty = true; + u_box_1d(0, This->size, &This->managed.dirty_box); /* systemmem non-dynamic */ + u_box_1d(0, 0, &This->managed.valid_region); /* systemmem dynamic */ + BASEBUF_REGISTER_UPDATE(This); + } + + *ppbData = (int8_t *)This->managed.data + OffsetToLock; + DBG("returning pointer %p\n", *ppbData); + This->nlocks++; + return D3D_OK; + } + + /* Driver ddi doc: READONLY is never passed to the device. So it can only + * have effect on things handled by the driver (MANAGED pool for example). + * Msdn doc: DISCARD and NOOVERWRITE are only for DYNAMIC. + * ATI doc: You can use DISCARD and NOOVERWRITE without DYNAMIC. + * Msdn doc: D3DLOCK_DONOTWAIT is not among the valid flags for buffers. + * Our tests: On win 7 nvidia, D3DLOCK_DONOTWAIT does return + * D3DERR_WASSTILLDRAWING if the resource is in use, except for DYNAMIC. + * Our tests: some apps do use both DISCARD and NOOVERWRITE at the same + * time. On windows it seems to return different pointer in some conditions, + * creation flags and drivers. However these tests indicate having + * NOOVERWRITE win is a valid behaviour (NVidia). + */ + + /* Have NOOVERWRITE win over DISCARD. This is allowed (see above) and + * it prevents overconsuming buffers if apps do use both at the same time. */ + if ((Flags & (D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE)) == (D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE)) + Flags &= ~D3DLOCK_DISCARD; + + if (Flags & D3DLOCK_DISCARD) + usage = PIPE_MAP_WRITE | PIPE_MAP_DISCARD_WHOLE_RESOURCE; + else if (Flags & D3DLOCK_NOOVERWRITE) + usage = PIPE_MAP_WRITE | PIPE_MAP_UNSYNCHRONIZED; + else + /* Do not ask for READ if writeonly and default pool (should be safe enough, + * as the doc says app shouldn't expect reading to work with writeonly). */ + usage = (This->base.usage & D3DUSAGE_WRITEONLY) ? + PIPE_MAP_WRITE : + PIPE_MAP_READ_WRITE; + if (Flags & D3DLOCK_DONOTWAIT && !(This->base.usage & D3DUSAGE_DYNAMIC)) + usage |= PIPE_MAP_DONTBLOCK; + + This->discard_nooverwrite_only &= !!(Flags & (D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE)); + + if (This->nmaps == This->maxmaps) { + struct NineTransfer *newmaps = + REALLOC(This->maps, sizeof(struct NineTransfer)*This->maxmaps, + sizeof(struct NineTransfer)*(This->maxmaps << 1)); + if (newmaps == NULL) + return E_OUTOFMEMORY; + + This->maxmaps <<= 1; + This->maps = newmaps; + } + + if (This->buf && !This->discard_nooverwrite_only) { + struct pipe_box src_box; + unsigned offset; + struct pipe_resource *src_res; + DBG("Disabling nine_subbuffer for a buffer having" + "used a nine_subbuffer buffer\n"); + /* Copy buffer content to the buffer resource, which + * we will now use. + * Note: The behaviour may be different from what is expected + * with double lock. However applications can't really make expectations + * about double locks, and don't really use them, so that's ok. */ + src_res = nine_upload_buffer_resource_and_offset(This->buf, &offset); + u_box_1d(offset, This->size, &src_box); + + pipe = NineDevice9_GetPipe(device); + pipe->resource_copy_region(pipe, This->base.resource, 0, 0, 0, 0, + src_res, 0, &src_box); + /* Release previous resource */ + if (This->nmaps >= 1) + This->maps[This->nmaps-1].should_destroy_buf = true; + else + nine_upload_release_buffer(device->buffer_upload, This->buf); + This->buf = NULL; + /* Rebind buffer */ + NineBuffer9_RebindIfRequired(This, device, This->base.resource, 0); + } + + This->maps[This->nmaps].transfer = NULL; + This->maps[This->nmaps].is_pipe_secondary = false; + This->maps[This->nmaps].buf = NULL; + This->maps[This->nmaps].should_destroy_buf = false; + + if (This->discard_nooverwrite_only) { + if (This->buf && (Flags & D3DLOCK_DISCARD)) { + /* Release previous buffer */ + if (This->nmaps >= 1) + This->maps[This->nmaps-1].should_destroy_buf = true; + else + nine_upload_release_buffer(device->buffer_upload, This->buf); + This->buf = NULL; + } + + if (!This->buf) { + unsigned offset; + struct pipe_resource *res; + This->buf = nine_upload_create_buffer(device->buffer_upload, This->base.info.width0); + res = nine_upload_buffer_resource_and_offset(This->buf, &offset); + NineBuffer9_RebindIfRequired(This, device, res, offset); + } + + if (This->buf) { + This->maps[This->nmaps].buf = This->buf; + This->nmaps++; + This->nlocks++; + DBG("Returning %p\n", nine_upload_buffer_get_map(This->buf) + OffsetToLock); + *ppbData = nine_upload_buffer_get_map(This->buf) + OffsetToLock; + return D3D_OK; + } else { + /* Fallback to normal path, and don't try again */ + This->discard_nooverwrite_only = false; + } + } + + /* Previous mappings may need pending commands to write to the + * buffer (staging buffer for example). Before a NOOVERWRITE, + * we thus need a finish, to guarantee any upload is finished. + * Note for discard_nooverwrite_only we don't need to do this + * check as neither discard nor nooverwrite have issues there */ + if (This->need_sync_if_nooverwrite && !(Flags & D3DLOCK_DISCARD) && + (Flags & D3DLOCK_NOOVERWRITE)) { + struct pipe_screen *screen = NineDevice9_GetScreen(device); + struct pipe_fence_handle *fence = NULL; + + pipe = NineDevice9_GetPipe(device); + pipe->flush(pipe, &fence, 0); + (void) screen->fence_finish(screen, NULL, fence, OS_TIMEOUT_INFINITE); + screen->fence_reference(screen, &fence, NULL); + } + This->need_sync_if_nooverwrite = !(Flags & (D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE)); + + /* When csmt is active, we want to avoid stalls as much as possible, + * and thus we want to create a new resource on discard and map it + * with the secondary pipe, instead of waiting on the main pipe. */ + if (Flags & D3DLOCK_DISCARD && device->csmt_active) { + struct pipe_screen *screen = NineDevice9_GetScreen(device); + struct pipe_resource *new_res = nine_resource_create_with_retry(device, screen, &This->base.info); + if (new_res) { + /* Use the new resource */ + pipe_resource_reference(&This->base.resource, new_res); + pipe_resource_reference(&new_res, NULL); + usage = PIPE_MAP_WRITE | PIPE_MAP_UNSYNCHRONIZED; + NineBuffer9_RebindIfRequired(This, device, This->base.resource, 0); + This->maps[This->nmaps].is_pipe_secondary = true; + } + } else if (Flags & D3DLOCK_NOOVERWRITE && device->csmt_active) + This->maps[This->nmaps].is_pipe_secondary = true; + + if (This->maps[This->nmaps].is_pipe_secondary) + pipe = device->pipe_secondary; + else + pipe = NineDevice9_GetPipe(device); + + data = pipe->buffer_map(pipe, This->base.resource, 0, + usage, &box, &This->maps[This->nmaps].transfer); + + if (!data) { + DBG("pipe::buffer_map failed\n" + " usage = %x\n" + " box.x = %u\n" + " box.width = %u\n", + usage, box.x, box.width); + + if (Flags & D3DLOCK_DONOTWAIT) + return D3DERR_WASSTILLDRAWING; + return D3DERR_INVALIDCALL; + } + + DBG("returning pointer %p\n", data); + This->nmaps++; + This->nlocks++; + *ppbData = data; + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineBuffer9_Unlock( struct NineBuffer9 *This ) +{ + struct NineDevice9 *device = This->base.base.device; + struct pipe_context *pipe; + int i; + DBG("This=%p\n", This); + + user_assert(This->nlocks > 0, D3DERR_INVALIDCALL); + This->nlocks--; + if (This->nlocks > 0) + return D3D_OK; /* Pending unlocks. Wait all unlocks before unmapping */ + + if (This->base.pool == D3DPOOL_DEFAULT) { + for (i = 0; i < This->nmaps; i++) { + if (!This->maps[i].buf) { + pipe = This->maps[i].is_pipe_secondary ? + device->pipe_secondary : + nine_context_get_pipe_acquire(device); + pipe->buffer_unmap(pipe, This->maps[i].transfer); + /* We need to flush in case the driver does implicit copies */ + if (This->maps[i].is_pipe_secondary) + pipe->flush(pipe, NULL, 0); + else + nine_context_get_pipe_release(device); + } else if (This->maps[i].should_destroy_buf) + nine_upload_release_buffer(device->buffer_upload, This->maps[i].buf); + } + This->nmaps = 0; + } + return D3D_OK; +} + +void +NineBuffer9_SetDirty( struct NineBuffer9 *This ) +{ + assert(This->base.pool != D3DPOOL_DEFAULT); + + This->managed.dirty = true; + u_box_1d(0, This->size, &This->managed.dirty_box); + BASEBUF_REGISTER_UPDATE(This); +} + +/* Try to remove b from a, supposed to include b */ +static void u_box_try_remove_region_1d(struct pipe_box *dst, + const struct pipe_box *a, + const struct pipe_box *b) +{ + int x, width; + if (a->x == b->x) { + x = a->x + b->width; + width = a->width - b->width; + } else if ((a->x + a->width) == (b->x + b->width)) { + x = a->x; + width = a->width - b->width; + } else { + x = a->x; + width = a->width; + } + dst->x = x; + dst->width = width; +} + +void +NineBuffer9_Upload( struct NineBuffer9 *This ) +{ + struct NineDevice9 *device = This->base.base.device; + unsigned upload_flags = 0; + struct pipe_box box_upload; + + assert(This->base.pool != D3DPOOL_DEFAULT && This->managed.dirty); + + if (This->base.pool == D3DPOOL_SYSTEMMEM && This->base.usage & D3DUSAGE_DYNAMIC) { + struct pipe_box region_already_valid; + struct pipe_box conflicting_region; + struct pipe_box *valid_region = &This->managed.valid_region; + struct pipe_box *required_valid_region = &This->managed.required_valid_region; + struct pipe_box *filled_region = &This->managed.filled_region; + /* Try to upload SYSTEMMEM DYNAMIC in an efficient fashion. + * Unlike non-dynamic for which we upload the whole dirty region, try to + * only upload the data needed for the draw. The draw call preparation + * fills This->managed.required_valid_region for that */ + u_box_intersect_1d(®ion_already_valid, + valid_region, + required_valid_region); + /* If the required valid region is already valid, nothing to do */ + if (region_already_valid.x == required_valid_region->x && + region_already_valid.width == required_valid_region->width) { + /* Rebind if the region happens to be valid in the original buffer + * but we have since used vertex_uploader */ + if (!This->managed.can_unsynchronized) + NineBuffer9_RebindIfRequired(This, device, This->base.resource, 0); + u_box_1d(0, 0, required_valid_region); + return; + } + /* (Try to) Remove valid areas from the region to upload */ + u_box_try_remove_region_1d(&box_upload, + required_valid_region, + ®ion_already_valid); + assert(box_upload.width > 0); + /* To maintain correctly the valid region, as we will do union later with + * box_upload, we must ensure box_upload is consecutive with valid_region */ + if (box_upload.x > valid_region->x + valid_region->width && valid_region->width > 0) { + box_upload.width = box_upload.x + box_upload.width - (valid_region->x + valid_region->width); + box_upload.x = valid_region->x + valid_region->width; + } else if (box_upload.x + box_upload.width < valid_region->x && valid_region->width > 0) { + box_upload.width = valid_region->x - box_upload.x; + } + /* There is conflict if some areas, that are not valid but are filled for previous draw calls, + * intersect with the region we plan to upload. Note by construction valid_region IS + * included in filled_region, thus so is region_already_valid. */ + u_box_intersect_1d(&conflicting_region, &box_upload, filled_region); + /* As box_upload could still contain region_already_valid, check the intersection + * doesn't happen to be exactly region_already_valid (it cannot be smaller, see above) */ + if (This->managed.can_unsynchronized && (conflicting_region.width == 0 || + (conflicting_region.x == region_already_valid.x && + conflicting_region.width == region_already_valid.width))) { + /* No conflicts. */ + upload_flags |= PIPE_MAP_UNSYNCHRONIZED; + } else { + /* We cannot use PIPE_MAP_UNSYNCHRONIZED. We must choose between no flag and DISCARD. + * Criteria to discard: + * . Most of the resource was filled (but some apps do allocate a big buffer + * to only use a small part in a round fashion) + * . The region to upload is very small compared to the filled region and + * at the start of the buffer (hints at round usage starting again) + * . The region to upload is very big compared to the required region + * . We have not discarded yet this frame + * If the buffer use pattern seems to sync the worker thread too often, + * revert to the vertex_uploader */ + if (This->managed.num_worker_thread_syncs < 3 && + (filled_region->width > (This->size / 2) || + (10 * box_upload.width < filled_region->width && + box_upload.x < (filled_region->x + filled_region->width)/2) || + box_upload.width > 2 * required_valid_region->width || + This->managed.frame_count_last_discard != device->frame_count)) { + /* Avoid DISCARDING too much by discarding only if most of the buffer + * has been used */ + DBG_FLAG(DBG_INDEXBUFFER|DBG_VERTEXBUFFER, + "Uploading %p DISCARD: valid %d %d, filled %d %d, required %d %d, box_upload %d %d, required already_valid %d %d, conflicting %d %d\n", + This, valid_region->x, valid_region->width, filled_region->x, filled_region->width, + required_valid_region->x, required_valid_region->width, box_upload.x, box_upload.width, + region_already_valid.x, region_already_valid.width, conflicting_region.x, conflicting_region.width + ); + upload_flags |= PIPE_MAP_DISCARD_WHOLE_RESOURCE; + u_box_1d(0, 0, filled_region); + u_box_1d(0, 0, valid_region); + box_upload = This->managed.required_valid_region; + /* Rebind the buffer if we used intermediate alternative buffer */ + if (!This->managed.can_unsynchronized) + NineBuffer9_RebindIfRequired(This, device, This->base.resource, 0); + This->managed.can_unsynchronized = true; + This->managed.frame_count_last_discard = device->frame_count; + } else { + /* Once we use without UNSYNCHRONIZED, we cannot use it anymore. + * Use a different buffer. */ + unsigned buffer_offset = 0; + struct pipe_resource *resource = NULL; + This->managed.can_unsynchronized = false; + u_upload_data_ref(device->vertex_uploader, + required_valid_region->x, + required_valid_region->width, + 64, + This->managed.data + required_valid_region->x, + &buffer_offset, + &resource); + buffer_offset -= required_valid_region->x; + u_upload_unmap(device->vertex_uploader); + if (resource) { + NineBuffer9_RebindIfRequired(This, device, resource, buffer_offset); + /* Note: This only works because for these types of buffers this function + * is called before every draw call. Else it wouldn't work when the app + * rebinds buffers. In addition it needs this function to be called only + * once per buffers even if bound several times, which we do. */ + u_box_1d(0, 0, required_valid_region); + pipe_resource_reference(&resource, NULL); + return; + } + } + } + + u_box_union_1d(filled_region, + filled_region, + &box_upload); + u_box_union_1d(valid_region, + valid_region, + &box_upload); + u_box_1d(0, 0, required_valid_region); + } else + box_upload = This->managed.dirty_box; + + if (box_upload.x == 0 && box_upload.width == This->size) { + upload_flags |= PIPE_MAP_DISCARD_WHOLE_RESOURCE; + } + + if (This->managed.pending_upload) { + u_box_union_1d(&This->managed.upload_pending_regions, + &This->managed.upload_pending_regions, + &box_upload); + } else { + This->managed.upload_pending_regions = box_upload; + } + + DBG_FLAG(DBG_INDEXBUFFER|DBG_VERTEXBUFFER, + "Uploading %p, offset=%d, size=%d, Flags=0x%x\n", + This, box_upload.x, box_upload.width, upload_flags); + nine_context_range_upload(device, &This->managed.pending_upload, + (struct NineUnknown *)This, + This->base.resource, + box_upload.x, + box_upload.width, + upload_flags, + (int8_t *)This->managed.data + box_upload.x); + This->managed.dirty = false; +} diff --git a/src/gallium/frontends/nine/buffer9.h b/src/gallium/frontends/nine/buffer9.h new file mode 100644 index 0000000..a783550 --- /dev/null +++ b/src/gallium/frontends/nine/buffer9.h @@ -0,0 +1,129 @@ +/* + * Copyright 2011 Joakim Sindholt + * Copyright 2015 Patrick Rudolph + * SPDX-License-Identifier: MIT + */ + +#ifndef _NINE_BUFFER9_H_ +#define _NINE_BUFFER9_H_ + +#include "device9.h" +#include "nine_buffer_upload.h" +#include "nine_state.h" +#include "resource9.h" +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_state.h" +#include "util/list.h" +#include "util/box.h" +#include "util/u_upload_mgr.h" + +struct pipe_screen; +struct pipe_context; +struct pipe_transfer; + +struct NineTransfer { + struct pipe_transfer *transfer; + bool is_pipe_secondary; + struct nine_subbuffer *buf; /* NULL unless subbuffer are used */ + bool should_destroy_buf; /* If the subbuffer should be destroyed */ +}; + +struct NineBuffer9 +{ + struct NineResource9 base; + + /* G3D */ + struct NineTransfer *maps; + int nlocks, nmaps, maxmaps; + UINT size; + + int16_t bind_count; /* to Device9->state.stream */ + /* Whether only discard and nooverwrite were used so far + * for this buffer. Allows some optimization. */ + bool discard_nooverwrite_only; + bool need_sync_if_nooverwrite; + struct nine_subbuffer *buf; + + /* Specific to managed buffers */ + struct { + void *data; + bool dirty; + struct pipe_box dirty_box; /* region in the resource to update */ + struct pipe_box upload_pending_regions; /* region with uploads pending */ + struct list_head list; /* for update_buffers */ + struct list_head list2; /* for managed_buffers */ + unsigned pending_upload; /* for uploads */ + /* SYSTEMMEM DYNAMIC */ + bool can_unsynchronized; /* Whether the upload can use nooverwrite */ + struct pipe_box valid_region; /* Region in the GPU buffer with valid content */ + struct pipe_box required_valid_region; /* Region that needs to be valid right now. */ + struct pipe_box filled_region; /* Region in the GPU buffer filled since last discard */ + unsigned num_worker_thread_syncs; + unsigned frame_count_last_discard; + } managed; +}; +static inline struct NineBuffer9 * +NineBuffer9( void *data ) +{ + return (struct NineBuffer9 *)data; +} + +HRESULT +NineBuffer9_ctor( struct NineBuffer9 *This, + struct NineUnknownParams *pParams, + D3DRESOURCETYPE Type, + DWORD Usage, + UINT Size, + D3DPOOL Pool ); + +void +NineBuffer9_dtor( struct NineBuffer9 *This ); + +struct pipe_resource * +NineBuffer9_GetResource( struct NineBuffer9 *This, unsigned *offset ); + +HRESULT NINE_WINAPI +NineBuffer9_Lock( struct NineBuffer9 *This, + UINT OffsetToLock, + UINT SizeToLock, + void **ppbData, + DWORD Flags ); + +HRESULT NINE_WINAPI +NineBuffer9_Unlock( struct NineBuffer9 *This ); + +void +NineBuffer9_Upload( struct NineBuffer9 *This ); + +static void inline +NineBindBufferToDevice( struct NineDevice9 *device, + struct NineBuffer9 **slot, + struct NineBuffer9 *buf ) +{ + struct NineBuffer9 *old = *slot; + + if (buf) { + if ((buf->managed.dirty) && list_is_empty(&buf->managed.list)) + list_add(&buf->managed.list, &device->update_buffers); + buf->bind_count++; + } + if (old) { + old->bind_count--; + if (!old->bind_count && old->managed.dirty) + list_delinit(&old->managed.list); + } + + nine_bind(slot, buf); +} + +void +NineBuffer9_SetDirty( struct NineBuffer9 *This ); + +#define BASEBUF_REGISTER_UPDATE(b) { \ + if ((b)->managed.dirty && (b)->bind_count) \ + if (list_is_empty(&(b)->managed.list)) \ + list_add(&(b)->managed.list, &(b)->base.base.device->update_buffers); \ + } + +#endif /* _NINE_BUFFER9_H_ */ diff --git a/src/gallium/frontends/nine/cryptosession9.c b/src/gallium/frontends/nine/cryptosession9.c new file mode 100644 index 0000000..3c043ae --- /dev/null +++ b/src/gallium/frontends/nine/cryptosession9.c @@ -0,0 +1,98 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#include "cryptosession9.h" + +#define DBG_CHANNEL DBG_CRYPTOSESSION + +HRESULT NINE_WINAPI +NineCryptoSession9_GetCertificateSize( struct NineCryptoSession9 *This, + UINT *pCertificateSize ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT NINE_WINAPI +NineCryptoSession9_GetCertificate( struct NineCryptoSession9 *This, + UINT CertifacteSize, + BYTE *ppCertificate ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT NINE_WINAPI +NineCryptoSession9_NegotiateKeyExchange( struct NineCryptoSession9 *This, + UINT DataSize, + void *pData ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT NINE_WINAPI +NineCryptoSession9_EncryptionBlt( struct NineCryptoSession9 *This, + IDirect3DSurface9 *pSrcSurface, + IDirect3DSurface9 *pDstSurface, + UINT DstSurfaceSize, + void *pIV ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT NINE_WINAPI +NineCryptoSession9_DecryptionBlt( struct NineCryptoSession9 *This, + IDirect3DSurface9 *pSrcSurface, + IDirect3DSurface9 *pDstSurface, + UINT SrcSurfaceSize, + D3DENCRYPTED_BLOCK_INFO *pEncryptedBlockInfo, + void *pContentKey, + void *pIV ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT NINE_WINAPI +NineCryptoSession9_GetSurfacePitch( struct NineCryptoSession9 *This, + IDirect3DSurface9 *pSrcSurface, + UINT *pSurfacePitch ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT NINE_WINAPI +NineCryptoSession9_StartSessionKeyRefresh( struct NineCryptoSession9 *This, + void *pRandomNumber, + UINT RandomNumberSize ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT NINE_WINAPI +NineCryptoSession9_FinishSessionKeyRefresh( struct NineCryptoSession9 *This ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT NINE_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/frontends/nine/cryptosession9.h b/src/gallium/frontends/nine/cryptosession9.h new file mode 100644 index 0000000..4b6f932 --- /dev/null +++ b/src/gallium/frontends/nine/cryptosession9.h @@ -0,0 +1,69 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#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 NINE_WINAPI +NineCryptoSession9_GetCertificateSize( struct NineCryptoSession9 *This, + UINT *pCertificateSize ); + +HRESULT NINE_WINAPI +NineCryptoSession9_GetCertificate( struct NineCryptoSession9 *This, + UINT CertifacteSize, + BYTE *ppCertificate ); + +HRESULT NINE_WINAPI +NineCryptoSession9_NegotiateKeyExchange( struct NineCryptoSession9 *This, + UINT DataSize, + void *pData ); + +HRESULT NINE_WINAPI +NineCryptoSession9_EncryptionBlt( struct NineCryptoSession9 *This, + IDirect3DSurface9 *pSrcSurface, + IDirect3DSurface9 *pDstSurface, + UINT DstSurfaceSize, + void *pIV ); + +HRESULT NINE_WINAPI +NineCryptoSession9_DecryptionBlt( struct NineCryptoSession9 *This, + IDirect3DSurface9 *pSrcSurface, + IDirect3DSurface9 *pDstSurface, + UINT SrcSurfaceSize, + D3DENCRYPTED_BLOCK_INFO *pEncryptedBlockInfo, + void *pContentKey, + void *pIV ); + +HRESULT NINE_WINAPI +NineCryptoSession9_GetSurfacePitch( struct NineCryptoSession9 *This, + IDirect3DSurface9 *pSrcSurface, + UINT *pSurfacePitch ); + +HRESULT NINE_WINAPI +NineCryptoSession9_StartSessionKeyRefresh( struct NineCryptoSession9 *This, + void *pRandomNumber, + UINT RandomNumberSize ); + +HRESULT NINE_WINAPI +NineCryptoSession9_FinishSessionKeyRefresh( struct NineCryptoSession9 *This ); + +HRESULT NINE_WINAPI +NineCryptoSession9_GetEncryptionBltKey( struct NineCryptoSession9 *This, + void *pReadbackKey, + UINT KeySize ); + +#endif /* _NINE_CRYPTOSESSION9_H_ */ diff --git a/src/gallium/frontends/nine/cubetexture9.c b/src/gallium/frontends/nine/cubetexture9.c new file mode 100644 index 0000000..9bf4eac --- /dev/null +++ b/src/gallium/frontends/nine/cubetexture9.c @@ -0,0 +1,336 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#include "c99_alloca.h" + +#include "device9.h" +#include "cubetexture9.h" +#include "nine_memory_helper.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; + struct pipe_screen *screen = pParams->device->screen; + enum pipe_format pf; + unsigned i, l, f, offset, face_size = 0; + unsigned *level_offsets = NULL; + D3DSURFACE_DESC sfdesc; + struct nine_allocation *p; + HRESULT hr; + + DBG("This=%p pParams=%p EdgeLength=%u Levels=%u Usage=%d " + "Format=%d Pool=%d pSharedHandle=%p\n", + This, pParams, EdgeLength, Levels, Usage, + Format, Pool, pSharedHandle); + + This->base.base.base.device = pParams->device; /* Early fill this field in case of failure */ + + user_assert(EdgeLength, D3DERR_INVALIDCALL); + + /* user_assert(!pSharedHandle || Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL); */ + user_assert(!pSharedHandle, D3DERR_INVALIDCALL); /* TODO */ + + user_assert(!(Usage & D3DUSAGE_AUTOGENMIPMAP) || + (Pool != D3DPOOL_SYSTEMMEM && Levels <= 1), D3DERR_INVALIDCALL); + + if (Usage & D3DUSAGE_AUTOGENMIPMAP) + Levels = 0; + + pf = d3d9_to_pipe_format_checked(screen, Format, PIPE_TEXTURE_CUBE, 0, + PIPE_BIND_SAMPLER_VIEW, false, + Pool == D3DPOOL_SCRATCH); + + if (pf == PIPE_FORMAT_NONE) + return D3DERR_INVALIDCALL; + + if (compressed_format(Format)) { + const unsigned w = util_format_get_blockwidth(pf); + const unsigned h = util_format_get_blockheight(pf); + + user_assert(!(EdgeLength % w) && !(EdgeLength % h), D3DERR_INVALIDCALL); + } + + info->screen = pParams->device->screen; + info->target = PIPE_TEXTURE_CUBE; + info->format = pf; + 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->nr_storage_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; + } + if (Usage & D3DUSAGE_SOFTWAREPROCESSING) + DBG("Application asked for Software Vertex Processing, " + "but this is unimplemented\n"); + + hr = NineBaseTexture9_ctor(&This->base, pParams, NULL, D3DRTYPE_CUBETEXTURE, + Format, Pool, Usage); + if (FAILED(hr)) + return hr; + This->base.pstype = 2; + + if (Pool != D3DPOOL_DEFAULT) { + level_offsets = alloca(sizeof(unsigned) * This->base.level_count); + face_size = nine_format_get_size_and_offsets(pf, level_offsets, + EdgeLength, EdgeLength, + This->base.level_count-1); + This->managed_buffer = nine_allocate(pParams->device->allocator, 6 * face_size); + if (!This->managed_buffer) + return E_OUTOFMEMORY; + } + + This->surfaces = CALLOC(6 * This->base.level_count, sizeof(*This->surfaces)); + if (!This->surfaces) + return E_OUTOFMEMORY; + + /* 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; + /* We allocate the memory for the surfaces as continuous blocks. + * This is the expected behaviour, however we haven't tested for + * cube textures in which order the faces/levels should be in memory + */ + for (f = 0; f < 6; f++) { + offset = f * face_size; + for (l = 0; l < This->base.level_count; l++) { + sfdesc.Width = sfdesc.Height = u_minify(EdgeLength, l); + p = This->managed_buffer ? + nine_suballocate(pParams->device->allocator, This->managed_buffer, offset + level_offsets[l]) : NULL; + + hr = NineSurface9_new(This->base.base.base.device, NineUnknown(This), + This->base.base.resource, p, D3DRTYPE_CUBETEXTURE, + l, f, &sfdesc, &This->surfaces[f + 6 * l]); + if (FAILED(hr)) + return hr; + } + } + + for (i = 0; i < 6; ++i) { + /* Textures start initially dirty */ + This->dirty_rect[i].width = EdgeLength; + This->dirty_rect[i].height = EdgeLength; + This->dirty_rect[i].depth = 1; + } + + return D3D_OK; +} + +static void +NineCubeTexture9_dtor( struct NineCubeTexture9 *This ) +{ + unsigned i; + bool is_worker = nine_context_is_worker(This->base.base.base.device); + + DBG("This=%p\n", This); + + if (This->surfaces) { + for (i = 0; i < This->base.level_count * 6; ++i) + if (This->surfaces[i]) + NineUnknown_Destroy(&This->surfaces[i]->base.base); + FREE(This->surfaces); + } + + if (This->managed_buffer) { + if (is_worker) + nine_free_worker(This->base.base.base.device->allocator, This->managed_buffer); + else + nine_free(This->base.base.base.device->allocator, This->managed_buffer); + } + + NineBaseTexture9_dtor(&This->base); +} + +HRESULT NINE_WINAPI +NineCubeTexture9_GetLevelDesc( struct NineCubeTexture9 *This, + UINT Level, + D3DSURFACE_DESC *pDesc ) +{ + DBG("This=%p Level=%u pDesc=%p\n", This, Level, pDesc); + + user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL); + + *pDesc = This->surfaces[Level * 6]->desc; + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineCubeTexture9_GetCubeMapSurface( struct NineCubeTexture9 *This, + D3DCUBEMAP_FACES FaceType, + UINT Level, + IDirect3DSurface9 **ppCubeMapSurface ) +{ + const unsigned s = Level * 6 + FaceType; + + DBG("This=%p FaceType=%d Level=%u ppCubeMapSurface=%p\n", + This, FaceType, Level, ppCubeMapSurface); + + user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL); + user_assert(FaceType < 6, D3DERR_INVALIDCALL); + + NineUnknown_AddRef(NineUnknown(This->surfaces[s])); + *ppCubeMapSurface = (IDirect3DSurface9 *)This->surfaces[s]; + + return D3D_OK; +} + +HRESULT NINE_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; + + DBG("This=%p FaceType=%d Level=%u pLockedRect=%p pRect=%p Flags=%d\n", + This, FaceType, Level, pLockedRect, pRect, Flags); + + user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL); + user_assert(FaceType < 6, D3DERR_INVALIDCALL); + + return NineSurface9_LockRect(This->surfaces[s], pLockedRect, pRect, Flags); +} + +HRESULT NINE_WINAPI +NineCubeTexture9_UnlockRect( struct NineCubeTexture9 *This, + D3DCUBEMAP_FACES FaceType, + UINT Level ) +{ + const unsigned s = Level * 6 + FaceType; + + DBG("This=%p FaceType=%d Level=%u\n", This, FaceType, Level); + + user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL); + user_assert(FaceType < 6, D3DERR_INVALIDCALL); + + return NineSurface9_UnlockRect(This->surfaces[s]); +} + +HRESULT NINE_WINAPI +NineCubeTexture9_AddDirtyRect( struct NineCubeTexture9 *This, + D3DCUBEMAP_FACES FaceType, + const RECT *pDirtyRect ) +{ + DBG("This=%p FaceType=%d pDirtyRect=%p\n", This, FaceType, 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; + BASETEX_REGISTER_UPDATE(&This->base); + } + return D3D_OK; + } + + if (This->base.base.pool == D3DPOOL_MANAGED) { + This->base.managed.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 { + if (This->dirty_rect[FaceType].width == 0) { + rect_to_pipe_box_clamp(&This->dirty_rect[FaceType], pDirtyRect); + } 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); + } + (void) u_box_clip_2d(&This->dirty_rect[FaceType], + &This->dirty_rect[FaceType], + This->base.base.info.width0, + This->base.base.info.height0); + } + return D3D_OK; +} + +IDirect3DCubeTexture9Vtbl NineCubeTexture9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */ + (void *)NineUnknown_SetPrivateData, + (void *)NineUnknown_GetPrivateData, + (void *)NineUnknown_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/frontends/nine/cubetexture9.h b/src/gallium/frontends/nine/cubetexture9.h new file mode 100644 index 0000000..d15ca42 --- /dev/null +++ b/src/gallium/frontends/nine/cubetexture9.h @@ -0,0 +1,64 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#ifndef _NINE_CUBETEXTURE9_H_ +#define _NINE_CUBETEXTURE9_H_ + +#include "basetexture9.h" +#include "nine_memory_helper.h" +#include "surface9.h" + +struct NineCubeTexture9 +{ + struct NineBaseTexture9 base; + struct NineSurface9 **surfaces; + struct pipe_box dirty_rect[6]; /* covers all mip levels */ + struct nine_allocation *managed_buffer; +}; +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 NINE_WINAPI +NineCubeTexture9_GetLevelDesc( struct NineCubeTexture9 *This, + UINT Level, + D3DSURFACE_DESC *pDesc ); + +HRESULT NINE_WINAPI +NineCubeTexture9_GetCubeMapSurface( struct NineCubeTexture9 *This, + D3DCUBEMAP_FACES FaceType, + UINT Level, + IDirect3DSurface9 **ppCubeMapSurface ); + +HRESULT NINE_WINAPI +NineCubeTexture9_LockRect( struct NineCubeTexture9 *This, + D3DCUBEMAP_FACES FaceType, + UINT Level, + D3DLOCKED_RECT *pLockedRect, + const RECT *pRect, + DWORD Flags ); + +HRESULT NINE_WINAPI +NineCubeTexture9_UnlockRect( struct NineCubeTexture9 *This, + D3DCUBEMAP_FACES FaceType, + UINT Level ); + +HRESULT NINE_WINAPI +NineCubeTexture9_AddDirtyRect( struct NineCubeTexture9 *This, + D3DCUBEMAP_FACES FaceType, + const RECT *pDirtyRect ); + +#endif /* _NINE_CUBETEXTURE9_H_ */ diff --git a/src/gallium/frontends/nine/device9.c b/src/gallium/frontends/nine/device9.c new file mode 100644 index 0000000..b16eb3c --- /dev/null +++ b/src/gallium/frontends/nine/device9.c @@ -0,0 +1,4342 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#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_buffer_upload.h" +#include "nine_helpers.h" +#include "nine_memory_helper.h" +#include "nine_pipe.h" +#include "nine_ff.h" +#include "nine_dump.h" +#include "nine_limits.h" + +#include "pipe/p_screen.h" +#include "pipe/p_context.h" +#include "util/detect.h" +#include "util/macros.h" +#include "util/u_math.h" +#include "util/u_inlines.h" +#include "util/u_hash_table.h" +#include "util/format/u_format.h" +#include "util/u_surface.h" +#include "util/u_upload_mgr.h" +#include "hud/hud_context.h" +#include "compiler/glsl_types.h" + +#include "cso_cache/cso_context.h" + +#define DBG_CHANNEL DBG_DEVICE + +#if DETECT_CC_GCC && (DETECT_ARCH_X86 || DETECT_ARCH_X86_64) + +static void nine_setup_fpu() +{ + uint16_t c; + + __asm__ __volatile__ ("fnstcw %0" : "=m" (*&c)); + + /* clear the control word */ + c &= 0xF0C0; + /* d3d9 doc/wine tests: mask all exceptions, use single-precision + * and round to nearest */ + c |= 0x003F; + + __asm__ __volatile__ ("fldcw %0" : : "m" (*&c)); +} + +static void nine_setup_set_fpu(uint16_t val) +{ + __asm__ __volatile__ ("fldcw %0" : : "m" (*&val)); +} + +static uint16_t nine_setup_get_fpu() +{ + uint16_t c; + + __asm__ __volatile__ ("fnstcw %0" : "=m" (*&c)); + return c; +} + +#else + +static void nine_setup_fpu(void) +{ + WARN_ONCE("FPU setup not supported on non-x86 platforms\n"); +} + +static void nine_setup_set_fpu(UNUSED uint16_t val) +{ + WARN_ONCE("FPU setup not supported on non-x86 platforms\n"); +} + +static uint16_t nine_setup_get_fpu() +{ + WARN_ONCE("FPU setup not supported on non-x86 platforms\n"); + return 0; +} + +#endif + +struct pipe_resource * +nine_resource_create_with_retry( struct NineDevice9 *This, + struct pipe_screen *screen, + const struct pipe_resource *templat ) +{ + struct pipe_resource *res; + res = screen->resource_create(screen, templat); + if (res) + return res; + /* Allocation failed, retry after freeing some resources + * Note: Shouldn't be called from the worker thread */ + if (!This) + return NULL; + /* Evict resources we can evict */ + NineDevice9_EvictManagedResourcesInternal(This); + /* Execute anything pending, such that some + * deleted resources can be actually freed */ + nine_csmt_process(This); + /* We could also finish the context, if needed */ + return screen->resource_create(screen, templat); +} + +void +NineDevice9_SetDefaultState( struct NineDevice9 *This, bool is_reset ) +{ + struct NineSurface9 *refSurf = NULL; + + DBG("This=%p is_reset=%d\n", This, (int) is_reset); + + assert(!This->is_recording); + + nine_state_set_defaults(This, &This->caps, is_reset); + + refSurf = This->swapchains[0]->buffers[0]; + assert(refSurf); + + This->state.viewport.X = 0; + This->state.viewport.Y = 0; + This->state.viewport.Width = refSurf->desc.Width; + This->state.viewport.Height = refSurf->desc.Height; + + nine_context_set_viewport(This, &This->state.viewport); + + This->state.scissor.minx = 0; + This->state.scissor.miny = 0; + This->state.scissor.maxx = refSurf->desc.Width; + This->state.scissor.maxy = refSurf->desc.Height; + + nine_context_set_scissor(This, &This->state.scissor); + + if (This->nswapchains && This->swapchains[0]->params.EnableAutoDepthStencil) { + nine_context_set_render_state(This, D3DRS_ZENABLE, true); + This->state.rs_advertised[D3DRS_ZENABLE] = true; + } + if (This->state.rs_advertised[D3DRS_ZENABLE]) + NineDevice9_SetDepthStencilSurface( + This, (IDirect3DSurface9 *)This->swapchains[0]->zsbuf); +} + +#define GET_PCAP(n) pScreen->caps.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, + bool ex, + D3DDISPLAYMODEEX *pFullscreenDisplayMode, + int minorVersionNum ) +{ + unsigned i; + uint16_t fpu_cw = 0; + HRESULT hr = NineUnknown_ctor(&This->base, pParams); + + DBG("This=%p pParams=%p pScreen=%p pCreationParameters=%p pCaps=%p pPresentationParameters=%p " + "pD3D9=%p pPresentationGroup=%p pCTX=%p ex=%d pFullscreenDisplayMode=%p\n", + This, pParams, pScreen, pCreationParameters, pCaps, pPresentationParameters, pD3D9, + pPresentationGroup, pCTX, (int) ex, pFullscreenDisplayMode); + + if (FAILED(hr)) { return hr; } + + /* NIR shaders need to use GLSL types so let's initialize them here */ + glsl_type_singleton_init_or_ref(); + + list_inithead(&This->update_buffers); + list_inithead(&This->update_textures); + list_inithead(&This->managed_buffers); + list_inithead(&This->managed_textures); + + This->screen = pScreen; + This->screen_sw = pCTX->ref; + This->caps = *pCaps; + This->d3d9 = pD3D9; + This->params = *pCreationParameters; + This->ex = ex; + This->present = pPresentationGroup; + This->minor_version_num = minorVersionNum; + + /* Ex */ + This->gpu_priority = 0; + This->max_frame_latency = 3; + + IDirect3D9_AddRef(This->d3d9); + ID3DPresentGroup_AddRef(This->present); + + if (!(This->params.BehaviorFlags & D3DCREATE_FPU_PRESERVE)) { + nine_setup_fpu(); + } else { + /* Software renderer initialization needs exceptions masked */ + fpu_cw = nine_setup_get_fpu(); + nine_setup_set_fpu(fpu_cw | 0x007f); + } + + if (This->params.BehaviorFlags & D3DCREATE_SOFTWARE_VERTEXPROCESSING) { + DBG("Application asked full Software Vertex Processing.\n"); + This->swvp = true; + This->may_swvp = true; + } else + This->swvp = false; + if (This->params.BehaviorFlags & D3DCREATE_MIXED_VERTEXPROCESSING) { + DBG("Application asked mixed Software Vertex Processing.\n"); + This->may_swvp = true; + } + This->context.swvp = This->swvp; + /* TODO: check if swvp is reset by device Resets */ + + if (This->may_swvp && + (This->screen->shader_caps[MESA_SHADER_VERTEX].max_const_buffer0_size + < (NINE_MAX_CONST_F_SWVP/2) * sizeof(float[4]) || + This->screen->shader_caps[MESA_SHADER_VERTEX].max_const_buffers < 5)) { + /* Note: We just go on, some apps never use the abilities of + * swvp, and just set more constants than allowed at init. + * Only cards we support that are affected are the r500 */ + WARN("Card unable to handle Software Vertex Processing. Game may fail\n"); + } + + /* When may_swvp, SetConstant* limits are different */ + if (This->may_swvp) + This->caps.MaxVertexShaderConst = NINE_MAX_CONST_F_SWVP; + + This->pure = !!(This->params.BehaviorFlags & D3DCREATE_PUREDEVICE); + + This->context.pipe = This->screen->context_create(This->screen, NULL, PIPE_CONTEXT_PREFER_THREADED); + This->pipe_secondary = This->screen->context_create(This->screen, NULL, 0); + if (!This->context.pipe || !This->pipe_secondary) { return E_OUTOFMEMORY; } /* guess */ + This->pipe_sw = This->screen_sw->context_create(This->screen_sw, NULL, PIPE_CONTEXT_PREFER_THREADED); + if (!This->pipe_sw) { return E_OUTOFMEMORY; } + + This->context.cso = cso_create_context(This->context.pipe, CSO_NO_USER_VERTEX_BUFFERS); + if (!This->context.cso) { return E_OUTOFMEMORY; } /* also a guess */ + This->cso_sw = cso_create_context(This->pipe_sw, 0); + if (!This->cso_sw) { return E_OUTOFMEMORY; } + + /* Create first, it messes up our state. */ + This->hud = hud_create(This->context.cso, NULL, NULL, NULL); /* NULL result is fine */ + + This->allocator = nine_allocator_create(This, pCTX->memfd_virtualsizelimit); + + /* Available memory counter. Updated only for allocations with this device + * instance. This is the Win 7 behavior. + * Win XP shares this counter across multiple devices. */ + This->available_texture_mem = This->screen->caps.video_memory; + This->available_texture_mem = (pCTX->override_vram_size >= 0) ? + (long long)pCTX->override_vram_size : This->available_texture_mem; + This->available_texture_mem <<= 20; + + /* We cap texture memory usage to 95% of what is reported free initially + * This helps get closer Win behaviour. For example VertexBuffer allocation + * still succeeds when texture allocation fails. */ + This->available_texture_limit = This->available_texture_mem * 5LL / 100LL; + + This->frame_count = 0; /* Used to check if events occur the same frame */ + + /* 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 (ex) { + D3DDISPLAYMODEEX *mode = NULL; + struct NineSwapChain9Ex **ret = + (struct NineSwapChain9Ex **)&This->swapchains[i]; + + if (pFullscreenDisplayMode) mode = &(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])); + nine_bind(&This->context.rt[i], This->state.rt[i]); + } + + /* Initialize CSMT */ + /* r600, radeonsi and iris are thread safe. */ + if (pCTX->csmt_force == 1) + This->csmt_active = true; + else if (pCTX->csmt_force == 0) + This->csmt_active = false; + else if (strstr(pScreen->get_name(pScreen), "AMD") != NULL) + This->csmt_active = true; + else if (strstr(pScreen->get_name(pScreen), "Intel") != NULL) + This->csmt_active = true; + + /* We rely on u_upload_mgr using persistent coherent buffers (which don't + * require flush to work in multi-pipe_context scenario) for vertex and + * index buffers */ + if (!GET_PCAP(buffer_map_persistent_coherent)) + This->csmt_active = false; + + if (This->csmt_active) { + This->csmt_ctx = nine_csmt_create(This); + if (!This->csmt_ctx) + return E_OUTOFMEMORY; + } + + if (This->csmt_active) + DBG("\033[1;32mCSMT is active\033[0m\n"); + + This->workarounds.dynamic_texture_workaround = pCTX->dynamic_texture_workaround; + + /* Due to the pb_cache, in some cases the buffer_upload path can increase GTT usage/virtual memory. + * As the performance gain is negligible when csmt is off, disable it in this case. + * That way csmt_force=0 can be used as a workaround to reduce GTT usage/virtual memory. */ + This->buffer_upload = This->csmt_active ? nine_upload_create(This->pipe_secondary, 4 * 1024 * 1024, 4) : NULL; + + /* Initialize a dummy VBO to be used when a vertex declaration does not + * specify all the inputs needed by vertex shader, on win default behavior + * is to pass 0,0,0,0 to the shader */ + { + struct pipe_transfer *transfer; + struct pipe_resource tmpl; + struct pipe_box box; + unsigned char *data; + + memset(&tmpl, 0, sizeof(tmpl)); + tmpl.target = PIPE_BUFFER; + tmpl.format = PIPE_FORMAT_R8_UNORM; + tmpl.width0 = 16; /* 4 floats */ + tmpl.height0 = 1; + tmpl.depth0 = 1; + tmpl.array_size = 1; + tmpl.last_level = 0; + tmpl.nr_samples = 0; + tmpl.usage = PIPE_USAGE_DEFAULT; + tmpl.bind = PIPE_BIND_VERTEX_BUFFER; + tmpl.flags = 0; + This->dummy_vbo = pScreen->resource_create(pScreen, &tmpl); + + if (!This->dummy_vbo) + return D3DERR_OUTOFVIDEOMEMORY; + + u_box_1d(0, 16, &box); + data = This->context.pipe->buffer_map(This->context.pipe, This->dummy_vbo, 0, + PIPE_MAP_WRITE | + PIPE_MAP_DISCARD_WHOLE_RESOURCE, + &box, &transfer); + assert(data); + assert(transfer); + memset(data, 0, 16); + This->context.pipe->buffer_unmap(This->context.pipe, transfer); + + /* initialize dummy_vbo_sw */ + if (pScreen != This->screen_sw) { + + This->dummy_vbo_sw = This->screen_sw->resource_create(This->screen_sw, &tmpl); + if (!This->dummy_vbo_sw) + return D3DERR_OUTOFVIDEOMEMORY; + + u_box_1d(0, 16, &box); + data = This->pipe_sw->buffer_map(This->pipe_sw, This->dummy_vbo_sw, 0, + PIPE_MAP_WRITE | + PIPE_MAP_DISCARD_WHOLE_RESOURCE, + &box, &transfer); + assert(data); + assert(transfer); + memset(data, 0, 16); + This->pipe_sw->buffer_unmap(This->pipe_sw, transfer); + } else { + This->dummy_vbo_sw = This->dummy_vbo; + } + } + + This->cursor.software = false; + This->cursor.hotspot.x = -1; + This->cursor.hotspot.y = -1; + This->cursor.w = This->cursor.h = 0; + This->cursor.visible = false; + if (ID3DPresent_GetCursorPos(This->swapchains[0]->present, &This->cursor.pos) != S_OK) { + This->cursor.pos.x = 0; + This->cursor.pos.y = 0; + } + + { + struct pipe_resource tmpl; + memset(&tmpl, 0, sizeof(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; + + /* For uploading 32x32 (argb) cursor */ + This->cursor.hw_upload_temp = MALLOC(32 * 4 * 32); + if (!This->cursor.hw_upload_temp) + return D3DERR_OUTOFVIDEOMEMORY; + } + + /* Create constant buffers. */ + { + unsigned max_const_vs; + + /* vs 3.0: >= 256 float constants, but for cards with exactly 256 slots, + * we have to take in some more slots for int and bool*/ + max_const_vs = _min(pScreen->shader_caps[MESA_SHADER_VERTEX].max_const_buffer0_size / + sizeof(float[4]), + NINE_MAX_CONST_ALL_VS); + /* ps 3.0: 224 float constants. All cards supported support at least + * 256 constants for ps */ + + if (max_const_vs == NINE_MAX_CONST_ALL_VS) + This->max_vs_const_f = NINE_MAX_CONST_F; + else /* Do not count SPE constants as we won't use them */ + This->max_vs_const_f = max_const_vs - + (NINE_MAX_CONST_I + NINE_MAX_CONST_B / 4); + + This->vs_const_size = max_const_vs * sizeof(float[4]); + This->ps_const_size = NINE_MAX_CONST_ALL_PS * sizeof(float[4]); + /* Include space for I,B constants for user constbuf. */ + if (This->may_swvp) { + This->state.vs_const_f = CALLOC(NINE_MAX_CONST_F_SWVP * sizeof(float[4]),1); + This->context.vs_const_f_swvp = CALLOC(NINE_MAX_CONST_F_SWVP * sizeof(float[4]),1); + if (!This->context.vs_const_f_swvp) + return E_OUTOFMEMORY; + This->state.vs_lconstf_temp = CALLOC(NINE_MAX_CONST_F_SWVP * sizeof(float[4]),1); + This->context.vs_lconstf_temp = CALLOC(NINE_MAX_CONST_F_SWVP * sizeof(float[4]),1); + This->state.vs_const_i = CALLOC(NINE_MAX_CONST_I_SWVP * sizeof(int[4]), 1); + This->context.vs_const_i = CALLOC(NINE_MAX_CONST_I_SWVP * sizeof(int[4]), 1); + This->state.vs_const_b = CALLOC(NINE_MAX_CONST_B_SWVP * sizeof(BOOL), 1); + This->context.vs_const_b = CALLOC(NINE_MAX_CONST_B_SWVP * sizeof(BOOL), 1); + } else { + This->state.vs_const_f = CALLOC(NINE_MAX_CONST_F * sizeof(float[4]), 1); + This->context.vs_const_f_swvp = NULL; + This->state.vs_lconstf_temp = CALLOC(This->vs_const_size,1); + This->context.vs_lconstf_temp = CALLOC(This->vs_const_size,1); + This->state.vs_const_i = CALLOC(NINE_MAX_CONST_I * sizeof(int[4]), 1); + This->context.vs_const_i = CALLOC(NINE_MAX_CONST_I * sizeof(int[4]), 1); + This->state.vs_const_b = CALLOC(NINE_MAX_CONST_B * sizeof(BOOL), 1); + This->context.vs_const_b = CALLOC(NINE_MAX_CONST_B * sizeof(BOOL), 1); + } + This->context.vs_const_f = CALLOC(This->vs_const_size, 1); + This->state.ps_const_f = CALLOC(This->ps_const_size, 1); + This->context.ps_const_f = CALLOC(This->ps_const_size, 1); + if (!This->state.vs_const_f || !This->context.vs_const_f || + !This->state.ps_const_f || !This->context.ps_const_f || + !This->state.vs_lconstf_temp || !This->context.vs_lconstf_temp || + !This->state.vs_const_i || !This->context.vs_const_i || + !This->state.vs_const_b || !This->context.vs_const_b) + return E_OUTOFMEMORY; + + if (strstr(pScreen->get_name(pScreen), "AMD") || + strstr(pScreen->get_name(pScreen), "ATI")) { + This->driver_bugs.buggy_barycentrics = true; + } + } + + /* allocate dummy texture/sampler for when there are missing ones bound */ + { + struct pipe_resource tmplt; + struct pipe_sampler_view templ; + struct pipe_sampler_state samp; + memset(&tmplt, 0, sizeof(tmplt)); + memset(&samp, 0, sizeof(samp)); + + tmplt.target = PIPE_TEXTURE_2D; + tmplt.width0 = 1; + tmplt.height0 = 1; + tmplt.depth0 = 1; + tmplt.last_level = 0; + tmplt.array_size = 1; + tmplt.usage = PIPE_USAGE_DEFAULT; + tmplt.flags = 0; + tmplt.format = PIPE_FORMAT_B8G8R8A8_UNORM; + tmplt.bind = PIPE_BIND_SAMPLER_VIEW; + tmplt.nr_samples = 0; + + This->dummy_texture = This->screen->resource_create(This->screen, &tmplt); + if (!This->dummy_texture) + return D3DERR_DRIVERINTERNALERROR; + + templ.format = PIPE_FORMAT_B8G8R8A8_UNORM; + templ.u.tex.first_layer = 0; + templ.u.tex.last_layer = 0; + templ.u.tex.first_level = 0; + templ.u.tex.last_level = 0; + templ.swizzle_r = PIPE_SWIZZLE_0; + templ.swizzle_g = PIPE_SWIZZLE_0; + templ.swizzle_b = PIPE_SWIZZLE_0; + templ.swizzle_a = PIPE_SWIZZLE_1; + templ.target = This->dummy_texture->target; + + This->dummy_sampler_view = This->context.pipe->create_sampler_view(This->context.pipe, This->dummy_texture, &templ); + if (!This->dummy_sampler_view) + return D3DERR_DRIVERINTERNALERROR; + + samp.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; + samp.max_lod = 15.0f; + samp.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + samp.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + samp.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + samp.min_img_filter = PIPE_TEX_FILTER_NEAREST; + samp.mag_img_filter = PIPE_TEX_FILTER_NEAREST; + samp.compare_mode = PIPE_TEX_COMPARE_NONE; + samp.compare_func = PIPE_FUNC_LEQUAL; + samp.unnormalized_coords = 0; + samp.seamless_cube_map = 0; + This->dummy_sampler_state = samp; + } + + /* Allocate upload helper for drivers that suck (from st pov ;). */ + + This->driver_caps.user_sw_vbufs = This->screen_sw->caps.user_vertex_buffers; + This->vertex_uploader = This->csmt_active ? This->pipe_secondary->stream_uploader : This->context.pipe->stream_uploader; + This->driver_caps.window_space_position_support = GET_PCAP(vs_window_space_position); + This->driver_caps.disabling_depth_clipping_support = GET_PCAP(depth_clip_disable); + This->driver_caps.vs_integer = pScreen->shader_caps[MESA_SHADER_VERTEX].integers; + This->driver_caps.ps_integer = pScreen->shader_caps[MESA_SHADER_FRAGMENT].integers; + /* Mesa 26.x: the polygon_offset_units_unscaled screen cap was removed + * (it had no user left besides nine), while pipe_rasterizer_state's + * offset_units_unscaled field stayed. No driver advertised the cap on the + * hardware we target -- crocus never did -- so keep the scaled GL/D3D1X + * path, which is what nine already used there. Revisit if a driver that + * wants the unscaled rules is ever targeted. */ + This->driver_caps.offset_units_unscaled = false; + This->driver_caps.alpha_test_emulation = !GET_PCAP(alpha_test); + /* Always write pointsize output when the driver doesn't support point_size_per_vertex = 0. + * TODO: Only generate pointsize for draw calls that need it */ + This->driver_caps.always_output_pointsize = !GET_PCAP(point_size_fixed); + This->driver_caps.emulate_ucp = !(GET_PCAP(clip_planes) == 1 || GET_PCAP(clip_planes) >= 8); + This->driver_caps.shader_emulate_features = pCTX->force_emulation; + + if (pCTX->force_emulation) { + This->driver_caps.user_sw_vbufs = false; + This->driver_caps.window_space_position_support = false; + This->driver_caps.alpha_test_emulation = true; + This->driver_caps.always_output_pointsize = true; + This->driver_caps.emulate_ucp = true; + } + + /* Disable SPE constants if there is no room for them */ + if (This->max_vs_const_f != NINE_MAX_CONST_F) { + This->driver_caps.always_output_pointsize = false; + This->driver_caps.emulate_ucp = false; + } + + This->context.inline_constants = pCTX->shader_inline_constants; + /* Code would be needed when integers are not available to correctly + * handle the conversion of integer constants */ + This->context.inline_constants &= This->driver_caps.vs_integer && This->driver_caps.ps_integer; + + nine_ff_init(This); /* initialize fixed function code */ + + NineDevice9_SetDefaultState(This, false); + + { + struct pipe_poly_stipple stipple; + memset(&stipple, ~0, sizeof(stipple)); + This->context.pipe->set_polygon_stipple(This->context.pipe, &stipple); + } + + This->update = &This->state; + + nine_state_init_sw(This); + + ID3DPresentGroup_Release(This->present); + nine_context_update_state(This); /* Some drivers needs states to be initialized */ + nine_csmt_process(This); + + if (This->params.BehaviorFlags & D3DCREATE_FPU_PRESERVE) + nine_setup_set_fpu(fpu_cw); + + return D3D_OK; +} +#undef GET_PCAP + +void +NineDevice9_dtor( struct NineDevice9 *This ) +{ + unsigned i; + + DBG("This=%p\n", This); + + /* Flush all pending commands to get refcount right, + * and properly release bound objects. It is ok to still + * execute commands while we are in device dtor, because + * we haven't released anything yet. Note that no pending + * command can increase the device refcount. */ + if (This->csmt_active && This->csmt_ctx) { + nine_csmt_process(This); + nine_csmt_destroy(This, This->csmt_ctx); + This->csmt_active = false; + This->csmt_ctx = NULL; + } + + nine_ff_fini(This); + nine_state_destroy_sw(This); + nine_device_state_clear(This); + nine_context_clear(This); + + nine_bind(&This->record, NULL); + + This->context.pipe->sampler_view_release(This->context.pipe, This->dummy_sampler_view); + pipe_resource_reference(&This->dummy_texture, NULL); + pipe_resource_reference(&This->dummy_vbo, NULL); + if (This->screen != This->screen_sw) + pipe_resource_reference(&This->dummy_vbo_sw, NULL); + FREE(This->state.vs_const_f); + FREE(This->context.vs_const_f); + FREE(This->state.ps_const_f); + FREE(This->context.ps_const_f); + FREE(This->state.vs_lconstf_temp); + FREE(This->context.vs_lconstf_temp); + FREE(This->state.vs_const_i); + FREE(This->context.vs_const_i); + FREE(This->state.vs_const_b); + FREE(This->context.vs_const_b); + FREE(This->context.vs_const_f_swvp); + + pipe_resource_reference(&This->cursor.image, NULL); + FREE(This->cursor.hw_upload_temp); + + if (This->swapchains) { + for (i = 0; i < This->nswapchains; ++i) + if (This->swapchains[i]) + NineUnknown_Unbind(NineUnknown(This->swapchains[i])); + FREE(This->swapchains); + } + + if (This->buffer_upload) + nine_upload_destroy(This->buffer_upload); + + if (This->allocator) + nine_allocator_destroy(This->allocator); + + /* Destroy cso first */ + if (This->context.cso) { cso_destroy_context(This->context.cso); } + if (This->cso_sw) { cso_destroy_context(This->cso_sw); } + if (This->context.pipe && This->context.pipe->destroy) { This->context.pipe->destroy(This->context.pipe); } + if (This->pipe_secondary && This->pipe_secondary->destroy) { This->pipe_secondary->destroy(This->pipe_secondary); } + if (This->pipe_sw && This->pipe_sw->destroy) { This->pipe_sw->destroy(This->pipe_sw); } + + if (This->present) { ID3DPresentGroup_Release(This->present); } + if (This->d3d9) { IDirect3D9_Release(This->d3d9); } + + NineUnknown_dtor(&This->base); + glsl_type_singleton_decref(); +} + +struct pipe_screen * +NineDevice9_GetScreen( struct NineDevice9 *This ) +{ + return This->screen; +} + +struct pipe_context * +NineDevice9_GetPipe( struct NineDevice9 *This ) +{ + return nine_context_get_pipe(This); +} + +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 NINE_WINAPI +NineDevice9_TestCooperativeLevel( struct NineDevice9 *This ) +{ + if (NineSwapChain9_GetOccluded(This->swapchains[0])) { + This->device_needs_reset = true; + return D3DERR_DEVICELOST; + } else if (NineSwapChain9_ResolutionMismatch(This->swapchains[0])) { + This->device_needs_reset = true; + return D3DERR_DEVICENOTRESET; + } else if (This->device_needs_reset) { + return D3DERR_DEVICENOTRESET; + } + + return D3D_OK; +} + +UINT NINE_WINAPI +NineDevice9_GetAvailableTextureMem( struct NineDevice9 *This ) +{ + /* To prevent overflows - Not sure how this should be handled */ + return (UINT)MIN2(This->available_texture_mem, (long long)(UINT_MAX - (64 << 20))); /* 64 MB margin */ +} + +void +NineDevice9_EvictManagedResourcesInternal( struct NineDevice9 *This ) +{ + struct NineBaseTexture9 *tex; + + DBG("This=%p\n", This); + + /* This function is called internally when an allocation fails. + * We are supposed to release old unused managed textures/buffers, + * until we have enough space for the allocation. + * For now just release everything, except the bound textures, + * as this function can be called when uploading bound textures. + */ + LIST_FOR_EACH_ENTRY(tex, &This->managed_textures, list2) { + if (!tex->bind_count) + NineBaseTexture9_UnLoad(tex); + } +} + +HRESULT NINE_WINAPI +NineDevice9_EvictManagedResources( struct NineDevice9 *This ) +{ + struct NineBaseTexture9 *tex; + struct NineBuffer9 *buf; + + DBG("This=%p\n", This); + LIST_FOR_EACH_ENTRY(tex, &This->managed_textures, list2) { + NineBaseTexture9_UnLoad(tex); + } + /* Vertex/index buffers don't take a lot of space and aren't accounted + * for d3d memory usage. Instead of actually freeing from memory, + * just mark the buffer dirty to trigger a re-upload later. We + * could just ignore, but some bad behaving apps could rely on it (if + * they write outside the locked regions typically). */ + LIST_FOR_EACH_ENTRY(buf, &This->managed_buffers, managed.list2) { + NineBuffer9_SetDirty(buf); + } + + return D3D_OK; +} + +HRESULT NINE_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 NINE_WINAPI +NineDevice9_GetDeviceCaps( struct NineDevice9 *This, + D3DCAPS9 *pCaps ) +{ + user_assert(pCaps != NULL, D3DERR_INVALIDCALL); + *pCaps = This->caps; + return D3D_OK; +} + +HRESULT NINE_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 NINE_WINAPI +NineDevice9_GetCreationParameters( struct NineDevice9 *This, + D3DDEVICE_CREATION_PARAMETERS *pParameters ) +{ + user_assert(pParameters != NULL, D3DERR_INVALIDCALL); + *pParameters = This->params; + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_SetCursorProperties( struct NineDevice9 *This, + UINT XHotSpot, + UINT YHotSpot, + IDirect3DSurface9 *pCursorBitmap ) +{ + struct NineSurface9 *surf = NineSurface9(pCursorBitmap); + struct pipe_context *pipe = NineDevice9_GetPipe(This); + struct pipe_box box; + struct pipe_transfer *transfer; + BOOL hw_cursor; + void *ptr; + + DBG_FLAG(DBG_SWAPCHAIN, "This=%p XHotSpot=%u YHotSpot=%u " + "pCursorBitmap=%p\n", This, XHotSpot, YHotSpot, pCursorBitmap); + + user_assert(pCursorBitmap, D3DERR_INVALIDCALL); + user_assert(surf->desc.Format == D3DFMT_A8R8G8B8, D3DERR_INVALIDCALL); + + if (This->swapchains[0]->params.Windowed) { + This->cursor.w = MIN2(surf->desc.Width, 32); + This->cursor.h = MIN2(surf->desc.Height, 32); + hw_cursor = 1; /* always use hw cursor for windowed mode */ + } else { + This->cursor.w = MIN2(surf->desc.Width, This->cursor.image->width0); + This->cursor.h = MIN2(surf->desc.Height, This->cursor.image->height0); + hw_cursor = This->cursor.w == 32 && This->cursor.h == 32; + } + + u_box_origin_2d(This->cursor.w, This->cursor.h, &box); + + ptr = pipe->texture_map(pipe, This->cursor.image, 0, + PIPE_MAP_WRITE | + PIPE_MAP_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; + + hr = NineSurface9_LockRect(surf, &lock, NULL, D3DLOCK_READONLY); + if (FAILED(hr)) + ret_err("Failed to map cursor source image.\n", + D3DERR_DRIVERINTERNALERROR); + + util_format_unpack_rgba_8unorm_rect(surf->base.info.format, ptr, transfer->stride, + lock.pBits, lock.Pitch, + This->cursor.w, This->cursor.h); + + if (hw_cursor) { + void *data = lock.pBits; + /* SetCursor assumes 32x32 argb with pitch 128 */ + if (lock.Pitch != 128) { + util_format_unpack_rgba_8unorm_rect(surf->base.info.format, + This->cursor.hw_upload_temp, 128, + lock.pBits, lock.Pitch, + 32, 32); + data = This->cursor.hw_upload_temp; + } + hw_cursor = ID3DPresent_SetCursor(This->swapchains[0]->present, + data, + &This->cursor.hotspot, + This->cursor.visible) == D3D_OK; + } + + NineSurface9_UnlockRect(surf); + } + pipe->texture_unmap(pipe, transfer); + + /* hide cursor if we emulate it */ + if (!hw_cursor) + ID3DPresent_SetCursor(This->swapchains[0]->present, NULL, NULL, false); + This->cursor.software = !hw_cursor; + + return D3D_OK; +} + +void NINE_WINAPI +NineDevice9_SetCursorPosition( struct NineDevice9 *This, + int X, + int Y, + DWORD Flags ) +{ + struct NineSwapChain9 *swap = This->swapchains[0]; + + DBG("This=%p X=%d Y=%d Flags=%d\n", This, X, Y, Flags); + + /* present >= v1.4 handles this itself */ + if (This->minor_version_num < 4) { + if (This->cursor.pos.x == X && This->cursor.pos.y == Y) + return; + } + + This->cursor.pos.x = X; + This->cursor.pos.y = Y; + + if (!This->cursor.software) + This->cursor.software = ID3DPresent_SetCursorPos(swap->present, &This->cursor.pos) != D3D_OK; +} + +BOOL NINE_WINAPI +NineDevice9_ShowCursor( struct NineDevice9 *This, + BOOL bShow ) +{ + BOOL old = This->cursor.visible; + + DBG("This=%p bShow=%d\n", This, (int) bShow); + + /* No-op until a cursor is set in d3d */ + if (This->cursor.hotspot.x == -1) + return old; + + This->cursor.visible = bShow; + /* Note: Don't optimize by avoiding the call if This->cursor.visible + * hasn't changed. One has to keep in mind the app may do SetCursor + * calls outside d3d, thus such an optimization affects behaviour. */ + if (!This->cursor.software) + This->cursor.software = ID3DPresent_SetCursor(This->swapchains[0]->present, NULL, NULL, bShow) != D3D_OK; + + return old; +} + +HRESULT NINE_WINAPI +NineDevice9_CreateAdditionalSwapChain( struct NineDevice9 *This, + D3DPRESENT_PARAMETERS *pPresentationParameters, + IDirect3DSwapChain9 **pSwapChain ) +{ + struct NineSwapChain9 *swapchain, *tmplt = This->swapchains[0]; + ID3DPresent *present; + HRESULT hr; + + DBG("This=%p pPresentationParameters=%p pSwapChain=%p\n", + This, pPresentationParameters, pSwapChain); + + user_assert(pPresentationParameters, D3DERR_INVALIDCALL); + user_assert(pSwapChain != NULL, D3DERR_INVALIDCALL); + user_assert(tmplt->params.Windowed && pPresentationParameters->Windowed, D3DERR_INVALIDCALL); + + /* TODO: this deserves more tests */ + if (!pPresentationParameters->hDeviceWindow) + pPresentationParameters->hDeviceWindow = This->params.hFocusWindow; + + 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 NINE_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 NINE_WINAPI +NineDevice9_GetNumberOfSwapChains( struct NineDevice9 *This ) +{ + return This->nswapchains; +} + +HRESULT NINE_WINAPI +NineDevice9_Reset( struct NineDevice9 *This, + D3DPRESENT_PARAMETERS *pPresentationParameters ) +{ + HRESULT hr = D3D_OK; + unsigned i; + + DBG("This=%p pPresentationParameters=%p\n", This, pPresentationParameters); + + user_assert(pPresentationParameters != NULL, D3DERR_INVALIDCALL); + + if (NineSwapChain9_GetOccluded(This->swapchains[0])) { + This->device_needs_reset = true; + return D3DERR_DEVICELOST; + } + + for (i = 0; i < This->nswapchains; ++i) { + D3DPRESENT_PARAMETERS *params = &pPresentationParameters[i]; + hr = NineSwapChain9_Resize(This->swapchains[i], params, NULL); + if (hr != D3D_OK) + break; + } + + nine_csmt_process(This); + nine_device_state_clear(This); + nine_context_clear(This); + + NineDevice9_SetDefaultState(This, true); + NineDevice9_SetRenderTarget( + This, 0, (IDirect3DSurface9 *)This->swapchains[0]->buffers[0]); + /* XXX: better use GetBackBuffer here ? */ + + This->device_needs_reset = (hr != D3D_OK); + This->in_scene = FALSE; /* Not sure if should be done also for ResetEx */ + return hr; +} + +HRESULT NINE_WINAPI +NineDevice9_Present( struct NineDevice9 *This, + const RECT *pSourceRect, + const RECT *pDestRect, + HWND hDestWindowOverride, + const RGNDATA *pDirtyRegion ) +{ + unsigned i; + HRESULT hr; + + DBG("This=%p pSourceRect=%p pDestRect=%p hDestWindowOverride=%p pDirtyRegion=%p\n", + This, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion); + + /* 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 NINE_WINAPI +NineDevice9_GetBackBuffer( struct NineDevice9 *This, + UINT iSwapChain, + UINT iBackBuffer, + D3DBACKBUFFER_TYPE Type, + IDirect3DSurface9 **ppBackBuffer ) +{ + user_assert(ppBackBuffer != NULL, D3DERR_INVALIDCALL); + /* return NULL on error */ + *ppBackBuffer = NULL; + user_assert(iSwapChain < This->nswapchains, D3DERR_INVALIDCALL); + + return NineSwapChain9_GetBackBuffer(This->swapchains[iSwapChain], + iBackBuffer, Type, ppBackBuffer); +} + +HRESULT NINE_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 NINE_WINAPI +NineDevice9_SetDialogBoxMode( struct NineDevice9 *This, + BOOL bEnableDialogs ) +{ + STUB(D3DERR_INVALIDCALL); +} + +void NINE_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 NINE_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 NINE_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); + + user_assert(ppTexture != NULL, D3DERR_INVALIDCALL); + + Usage &= D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_DMAP | + D3DUSAGE_DYNAMIC | D3DUSAGE_NONSECURE | D3DUSAGE_RENDERTARGET | + D3DUSAGE_SOFTWAREPROCESSING | D3DUSAGE_TEXTAPI; + + *ppTexture = NULL; + + hr = NineTexture9_new(This, Width, Height, Levels, Usage, Format, Pool, + &tex, pSharedHandle); + if (SUCCEEDED(hr)) + *ppTexture = (IDirect3DTexture9 *)tex; + + return hr; +} + +HRESULT NINE_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); + + user_assert(ppVolumeTexture != NULL, D3DERR_INVALIDCALL); + + Usage &= D3DUSAGE_DYNAMIC | D3DUSAGE_NONSECURE | + D3DUSAGE_SOFTWAREPROCESSING; + + *ppVolumeTexture = NULL; + + hr = NineVolumeTexture9_new(This, Width, Height, Depth, Levels, + Usage, Format, Pool, &tex, pSharedHandle); + if (SUCCEEDED(hr)) + *ppVolumeTexture = (IDirect3DVolumeTexture9 *)tex; + + return hr; +} + +HRESULT NINE_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); + + user_assert(ppCubeTexture != NULL, D3DERR_INVALIDCALL); + + Usage &= D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_DYNAMIC | + D3DUSAGE_NONSECURE | D3DUSAGE_RENDERTARGET | + D3DUSAGE_SOFTWAREPROCESSING; + + *ppCubeTexture = NULL; + + hr = NineCubeTexture9_new(This, EdgeLength, Levels, Usage, Format, Pool, + &tex, pSharedHandle); + if (SUCCEEDED(hr)) + *ppCubeTexture = (IDirect3DCubeTexture9 *)tex; + + return hr; +} + +HRESULT NINE_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(ppVertexBuffer != NULL, D3DERR_INVALIDCALL); + 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 NINE_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(ppIndexBuffer != NULL, D3DERR_INVALIDCALL); + 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; + HRESULT hr; + D3DSURFACE_DESC desc; + + 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); + + 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: assert(type == 2); break; + } + + hr = NineSurface9_new(This, NULL, NULL, NULL, 0, 0, 0, &desc, &surface); + if (SUCCEEDED(hr)) { + *ppSurface = (IDirect3DSurface9 *)surface; + + if (surface->base.resource && Discard_or_Lockable && (type != 1)) + surface->base.resource->flags |= NINE_RESOURCE_FLAG_LOCKABLE; + } + + return hr; +} + +HRESULT NINE_WINAPI +NineDevice9_CreateRenderTarget( struct NineDevice9 *This, + UINT Width, + UINT Height, + D3DFORMAT Format, + D3DMULTISAMPLE_TYPE MultiSample, + DWORD MultisampleQuality, + BOOL Lockable, + IDirect3DSurface9 **ppSurface, + HANDLE *pSharedHandle ) +{ + user_assert(ppSurface != NULL, D3DERR_INVALIDCALL); + *ppSurface = NULL; + return create_zs_or_rt_surface(This, 0, D3DPOOL_DEFAULT, + Width, Height, Format, + MultiSample, MultisampleQuality, + Lockable, ppSurface, pSharedHandle); +} + +HRESULT NINE_WINAPI +NineDevice9_CreateDepthStencilSurface( struct NineDevice9 *This, + UINT Width, + UINT Height, + D3DFORMAT Format, + D3DMULTISAMPLE_TYPE MultiSample, + DWORD MultisampleQuality, + BOOL Discard, + IDirect3DSurface9 **ppSurface, + HANDLE *pSharedHandle ) +{ + user_assert(ppSurface != NULL, D3DERR_INVALIDCALL); + *ppSurface = NULL; + if (!depth_stencil_format(Format)) + return D3DERR_NOTAVAILABLE; + return create_zs_or_rt_surface(This, 1, D3DPOOL_DEFAULT, + Width, Height, Format, + MultiSample, MultisampleQuality, + Discard, ppSurface, pSharedHandle); +} + +HRESULT NINE_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); + int copy_width, copy_height; + RECT destRect; + + 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 && src, D3DERR_INVALIDCALL); + + 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); + + user_assert(!src->lock_count, D3DERR_INVALIDCALL); + user_assert(!dst->lock_count, D3DERR_INVALIDCALL); + + user_assert(dst->desc.Format == src->desc.Format, D3DERR_INVALIDCALL); + user_assert(!depth_stencil_format(dst->desc.Format), D3DERR_INVALIDCALL); + + if (pSourceRect) { + copy_width = pSourceRect->right - pSourceRect->left; + copy_height = pSourceRect->bottom - pSourceRect->top; + + user_assert(pSourceRect->left >= 0 && + copy_width > 0 && + pSourceRect->right <= src->desc.Width && + pSourceRect->top >= 0 && + copy_height > 0 && + pSourceRect->bottom <= src->desc.Height, + D3DERR_INVALIDCALL); + } else { + copy_width = src->desc.Width; + copy_height = src->desc.Height; + } + + destRect.right = copy_width; + destRect.bottom = copy_height; + + if (pDestPoint) { + user_assert(pDestPoint->x >= 0 && pDestPoint->y >= 0, + D3DERR_INVALIDCALL); + destRect.right += pDestPoint->x; + destRect.bottom += pDestPoint->y; + } + + user_assert(destRect.right <= dst->desc.Width && + destRect.bottom <= dst->desc.Height, + D3DERR_INVALIDCALL); + + if (compressed_format(dst->desc.Format)) { + const unsigned w = util_format_get_blockwidth(dst->base.info.format); + const unsigned h = util_format_get_blockheight(dst->base.info.format); + + if (pDestPoint) { + user_assert(!(pDestPoint->x % w) && !(pDestPoint->y % h), + D3DERR_INVALIDCALL); + } + + if (pSourceRect) { + user_assert(!(pSourceRect->left % w) && !(pSourceRect->top % h), + D3DERR_INVALIDCALL); + } + if (!(copy_width == src->desc.Width && + copy_width == dst->desc.Width && + copy_height == src->desc.Height && + copy_height == dst->desc.Height)) { + user_assert(!(copy_width % w) && !(copy_height % h), + D3DERR_INVALIDCALL); + } + } + + NineSurface9_CopyMemToDefault(dst, src, pDestPoint, pSourceRect); + + return D3D_OK; +} + +HRESULT NINE_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_src_level, last_dst_level; + RECT rect; + + DBG("This=%p pSourceTexture=%p pDestinationTexture=%p\n", This, + pSourceTexture, pDestinationTexture); + + user_assert(pSourceTexture && pDestinationTexture, D3DERR_INVALIDCALL); + user_assert(pSourceTexture != pDestinationTexture, D3DERR_INVALIDCALL); + + user_assert(dstb->base.pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL); + user_assert(srcb->base.pool == D3DPOOL_SYSTEMMEM, D3DERR_INVALIDCALL); + user_assert(dstb->base.type == srcb->base.type, D3DERR_INVALIDCALL); + user_assert(!(srcb->base.usage & D3DUSAGE_AUTOGENMIPMAP) || + dstb->base.usage & D3DUSAGE_AUTOGENMIPMAP, D3DERR_INVALIDCALL); + + /* Spec: Failure if + * . Different formats + * . Fewer src levels than dst levels (if the opposite, only matching levels + * are supposed to be copied) + * . Levels do not match + * DDI: Actually the above should pass because of legacy applications + * Do what you want about these, but you shouldn't crash. + * However driver can expect that the top dimension is greater for src than dst. + * Wine tests: Every combination that passes the initial checks should pass. + * . Different formats => conversion driver and format dependent. + * . 1 level, but size not matching => copy is done (and even crash if src bigger + * than dst. For the case where dst bigger, wine doesn't test if a stretch is applied + * or if a subrect is copied). + * . 8x8 4 sublevels -> 7x7 2 sublevels => driver dependent, On NV seems to be 4x4 subrect + * copied to 7x7. + * + * From these, the proposal is: + * . Different formats -> use util_format_translate to translate if possible for surfaces. + * Accept ARGB/XRGB for Volumes. Do nothing for the other combinations + * . First level copied -> the first level such that src is smaller or equal to dst first level + * . number of levels copied -> as long as it fits and textures have levels + * That should satisfy the constraints (and instead of crashing for some cases we return D3D_OK) + */ + + last_src_level = srcb->level_count-1; + last_dst_level = dstb->level_count-1; + + for (m = 0; m <= last_src_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 <= last_src_level, D3D_OK); + + last_dst_level = MIN2(srcb->base.info.last_level - m, last_dst_level); + + if (dstb->base.type == D3DRTYPE_TEXTURE) { + struct NineTexture9 *dst = NineTexture9(dstb); + struct NineTexture9 *src = NineTexture9(srcb); + + if (src->dirty_rect.width == 0) + return D3D_OK; + + pipe_box_to_rect(&rect, &src->dirty_rect); + for (l = 0; l < m; ++l) + rect_minify_inclusive(&rect); + + for (l = 0; l <= last_dst_level; ++l, ++m) { + fit_rect_format_inclusive(dst->base.base.info.format, + &rect, + dst->surfaces[l]->desc.Width, + dst->surfaces[l]->desc.Height); + NineSurface9_CopyMemToDefault(dst->surfaces[l], + src->surfaces[m], + (POINT *)&rect, + &rect); + rect_minify_inclusive(&rect); + } + u_box_origin_2d(0, 0, &src->dirty_rect); + } 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) { + if (src->dirty_rect[z].width == 0) + continue; + + pipe_box_to_rect(&rect, &src->dirty_rect[z]); + for (l = 0; l < m; ++l) + rect_minify_inclusive(&rect); + + for (l = 0; l <= last_dst_level; ++l, ++m) { + fit_rect_format_inclusive(dst->base.base.info.format, + &rect, + dst->surfaces[l * 6 + z]->desc.Width, + dst->surfaces[l * 6 + z]->desc.Height); + NineSurface9_CopyMemToDefault(dst->surfaces[l * 6 + z], + src->surfaces[m * 6 + z], + (POINT *)&rect, + &rect); + rect_minify_inclusive(&rect); + } + u_box_origin_2d(0, 0, &src->dirty_rect[z]); + m -= l; + } + } else + if (dstb->base.type == D3DRTYPE_VOLUMETEXTURE) { + struct NineVolumeTexture9 *dst = NineVolumeTexture9(dstb); + struct NineVolumeTexture9 *src = NineVolumeTexture9(srcb); + + if (src->dirty_box.width == 0) + return D3D_OK; + for (l = 0; l <= last_dst_level; ++l, ++m) + NineVolume9_CopyMemToDefault(dst->volumes[l], + src->volumes[m], 0, 0, 0, NULL); + u_box_3d(0, 0, 0, 0, 0, 0, &src->dirty_box); + } else{ + assert(!"invalid texture type"); + } + + if (dstb->base.usage & D3DUSAGE_AUTOGENMIPMAP) { + dstb->dirty_mip = true; + NineBaseTexture9_GenerateMipSubLevels(dstb); + } + + return D3D_OK; +} + +HRESULT NINE_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(pRenderTarget && pDestSurface, D3DERR_INVALIDCALL); + + 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); + + user_assert(src->desc.Width == dst->desc.Width, D3DERR_INVALIDCALL); + user_assert(src->desc.Height == dst->desc.Height, D3DERR_INVALIDCALL); + + user_assert(src->desc.Format != D3DFMT_NULL, D3DERR_INVALIDCALL); + + NineSurface9_CopyDefaultToMem(dst, src); + + return D3D_OK; +} + +HRESULT NINE_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 NINE_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 NineSurface9 *dst = NineSurface9(pDestSurface); + struct NineSurface9 *src = NineSurface9(pSourceSurface); + struct pipe_resource *dst_res, *src_res; + bool zs; + struct pipe_blit_info blit; + bool 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("pDestRect=(%u,%u)-(%u,%u)\n", pDestRect->left, pDestRect->top, + pDestRect->right, pDestRect->bottom); + + user_assert(pSourceSurface && pDestSurface, D3DERR_INVALIDCALL); + user_assert(dst->base.pool == D3DPOOL_DEFAULT && + src->base.pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL); + + dst_res = NineSurface9_GetResource(dst); + src_res = NineSurface9_GetResource(src); + zs = util_format_is_depth_or_stencil(dst_res->format); + 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, + src_res->nr_storage_samples, + PIPE_BIND_SAMPLER_VIEW), + 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); + + memset(&blit, 0, sizeof(blit)); + 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; + blit.alpha_blend = 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), D3DERR_INVALIDCALL); + user_assert(!NineSurface9_IsOffscreenPlain(dst) || + NineSurface9_IsOffscreenPlain(src), D3DERR_INVALIDCALL); + user_assert(NineSurface9_IsOffscreenPlain(dst) || + dst->desc.Usage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL), + 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 != src->desc.MultiSampleType) || + (dst->desc.MultiSampleQuality != src->desc.MultiSampleQuality); + + 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, + dst_res->nr_storage_samples, + zs ? PIPE_BIND_DEPTH_STENCIL : + PIPE_BIND_RENDER_TARGET), + D3DERR_INVALIDCALL); + + nine_context_blit(This, (struct NineUnknown *)dst, + (struct NineUnknown *)src, &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"); + nine_context_resource_copy_region(This, (struct NineUnknown *)dst, + (struct NineUnknown *)src, + blit.dst.resource, blit.dst.level, + &blit.dst.box, + blit.src.resource, blit.src.level, + &blit.src.box); + } + + /* Communicate the container it needs to update sublevels - if apply */ + NineSurface9_MarkContainerDirty(dst); + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_ColorFill( struct NineDevice9 *This, + IDirect3DSurface9 *pSurface, + const RECT *pRect, + D3DCOLOR color ) +{ + struct NineSurface9 *surf = NineSurface9(pSurface); + unsigned x, y, w, h; + + 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(pSurface != NULL, D3DERR_INVALIDCALL); + + user_assert(surf->base.pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL); + + user_assert((surf->base.usage & D3DUSAGE_RENDERTARGET) || + NineSurface9_IsOffscreenPlain(surf), D3DERR_INVALIDCALL); + + user_assert(surf->desc.Format != D3DFMT_NULL, D3D_OK); + + if (pRect) { + x = pRect->left; + y = pRect->top; + w = pRect->right - pRect->left; + h = pRect->bottom - pRect->top; + /* Wine tests: */ + if (compressed_format(surf->desc.Format)) { + const unsigned bw = util_format_get_blockwidth(surf->base.info.format); + const unsigned bh = util_format_get_blockheight(surf->base.info.format); + + user_assert(!(x % bw) && !(y % bh) && !(w % bw) && !(h % bh), + D3DERR_INVALIDCALL); + } + } else{ + x = 0; + y = 0; + w = surf->desc.Width; + h = surf->desc.Height; + } + + if (surf->base.info.bind & PIPE_BIND_RENDER_TARGET) { + nine_context_clear_render_target(This, surf, color, 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, pRect ? 0 : D3DLOCK_DISCARD); + 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 NINE_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(ppSurface != NULL, D3DERR_INVALIDCALL); + *ppSurface = NULL; + 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 NINE_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; + nine_context_set_viewport(This, &This->state.viewport); + nine_context_set_scissor(This, &This->state.scissor); + } + + if (This->state.rt[i] != NineSurface9(pRenderTarget)) + nine_bind(&This->state.rt[i], pRenderTarget); + + nine_context_set_render_target(This, i, rt); + return D3D_OK; +} + +HRESULT NINE_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 NINE_WINAPI +NineDevice9_SetDepthStencilSurface( struct NineDevice9 *This, + IDirect3DSurface9 *pNewZStencil ) +{ + struct NineSurface9 *ds = NineSurface9(pNewZStencil); + DBG("This=%p pNewZStencil=%p\n", This, pNewZStencil); + + user_assert(!ds || util_format_is_depth_or_stencil(ds->base.info.format), + D3DERR_INVALIDCALL); + + if (This->state.ds != ds) { + nine_bind(&This->state.ds, ds); + nine_context_set_depth_stencil(This, ds); + } + return D3D_OK; +} + +HRESULT NINE_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 NINE_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 NINE_WINAPI +NineDevice9_EndScene( struct NineDevice9 *This ) +{ + DBG("This=%p\n", This); + user_assert(This->in_scene, D3DERR_INVALIDCALL); + This->in_scene = false; + This->end_scene_since_present++; + /* EndScene() is supposed to flush the GPU commands. + * The idea is to flush ahead of the Present() call. + * (Apps could take advantage of this by inserting CPU + * work between EndScene() and Present()). + * Most apps will have one EndScene per frame. + * Some will have 2 or 3. + * Some bad behaving apps do a lot of them. + * As flushing has a cost, do it only once. */ + if (This->end_scene_since_present <= 1) { + nine_context_pipe_flush(This); + nine_csmt_flush(This); + } + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_Clear( struct NineDevice9 *This, + DWORD Count, + const D3DRECT *pRects, + DWORD Flags, + D3DCOLOR Color, + float Z, + DWORD Stencil ) +{ + struct NineSurface9 *zsbuf_surf = This->state.ds; + + 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_surf && + util_format_is_depth_and_stencil(zsbuf_surf->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 + + nine_context_clear_fb(This, Count, pRects, Flags, Color, Z, Stencil); + return D3D_OK; +} + +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]); +} + +HRESULT NINE_WINAPI +NineDevice9_SetTransform( struct NineDevice9 *This, + D3DTRANSFORMSTATETYPE State, + const D3DMATRIX *pMatrix ) +{ + struct nine_state *state = This->update; + D3DMATRIX *M = nine_state_access_transform(&state->ff, State, true); + + DBG("This=%p State=%d pMatrix=%p\n", This, State, pMatrix); + + user_assert(pMatrix, D3DERR_INVALIDCALL); + user_assert(M, D3DERR_INVALIDCALL); + nine_D3DMATRIX_print(pMatrix); + + *M = *pMatrix; + if (unlikely(This->is_recording)) { + state->ff.changed.transform[State / 32] |= 1 << (State % 32); + state->changed.group |= NINE_STATE_FF_VSTRANSF; + } else + nine_context_set_transform(This, State, pMatrix); + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_GetTransform( struct NineDevice9 *This, + D3DTRANSFORMSTATETYPE State, + D3DMATRIX *pMatrix ) +{ + D3DMATRIX *M; + + user_assert(!This->pure, D3DERR_INVALIDCALL); + M = nine_state_access_transform(&This->state.ff, State, false); + user_assert(pMatrix, D3DERR_INVALIDCALL); + user_assert(M, D3DERR_INVALIDCALL); + *pMatrix = *M; + return D3D_OK; +} + +HRESULT NINE_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->ff, State, true); + + DBG("This=%p State=%d pMatrix=%p\n", This, State, pMatrix); + + user_assert(pMatrix, D3DERR_INVALIDCALL); + user_assert(M, D3DERR_INVALIDCALL); + + nine_d3d_matrix_matrix_mul(&T, pMatrix, M); + return NineDevice9_SetTransform(This, State, &T); +} + +HRESULT NINE_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); + + user_assert(pViewport != NULL, D3DERR_INVALIDCALL); + state->viewport = *pViewport; + nine_context_set_viewport(This, pViewport); + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_GetViewport( struct NineDevice9 *This, + D3DVIEWPORT9 *pViewport ) +{ + user_assert(pViewport != NULL, D3DERR_INVALIDCALL); + *pViewport = This->state.viewport; + return D3D_OK; +} + +HRESULT NINE_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; + if (unlikely(This->is_recording)) + state->changed.group |= NINE_STATE_FF_MATERIAL; + else + nine_context_set_material(This, pMaterial); + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_GetMaterial( struct NineDevice9 *This, + D3DMATERIAL9 *pMaterial ) +{ + user_assert(!This->pure, D3DERR_INVALIDCALL); + user_assert(pMaterial, E_POINTER); + *pMaterial = This->state.ff.material; + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_SetLight( struct NineDevice9 *This, + DWORD Index, + const D3DLIGHT9 *pLight ) +{ + struct nine_state *state = This->update; + HRESULT hr; + + 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 */ + + hr = nine_state_set_light(&state->ff, Index, pLight); + if (hr != D3D_OK) + return hr; + + 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"); + } + + if (unlikely(This->is_recording)) + state->changed.group |= NINE_STATE_FF_LIGHTING; + else + nine_context_set_light(This, Index, pLight); + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_GetLight( struct NineDevice9 *This, + DWORD Index, + D3DLIGHT9 *pLight ) +{ + const struct nine_state *state = &This->state; + + user_assert(!This->pure, D3DERR_INVALIDCALL); + 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 NINE_WINAPI +NineDevice9_LightEnable( struct NineDevice9 *This, + DWORD Index, + BOOL Enable ) +{ + struct nine_state *state = This->update; + + 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); + } + + nine_state_light_enable(&state->ff, Index, Enable); + if (likely(!This->is_recording)) + nine_context_light_enable(This, Index, Enable); + else + state->changed.group |= NINE_STATE_FF_LIGHTING; + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_GetLightEnable( struct NineDevice9 *This, + DWORD Index, + BOOL *pEnable ) +{ + const struct nine_state *state = &This->state; + unsigned i; + + user_assert(!This->pure, D3DERR_INVALIDCALL); + user_assert(pEnable != NULL, D3DERR_INVALIDCALL); + 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 ? 128 : 0; // Taken from wine + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_SetClipPlane( struct NineDevice9 *This, + DWORD Index, + const float *pPlane ) +{ + struct nine_state *state = This->update; + + user_assert(pPlane, D3DERR_INVALIDCALL); + + DBG("This=%p Index=%u pPlane=%f %f %f %f\n", This, Index, + pPlane[0], pPlane[1], + pPlane[2], pPlane[3]); + + user_assert(Index < PIPE_MAX_CLIP_PLANES, D3DERR_INVALIDCALL); + + memcpy(&state->clip.ucp[Index][0], pPlane, sizeof(state->clip.ucp[0])); + if (unlikely(This->is_recording)) + state->changed.ucp |= 1 << Index; + else + nine_context_set_clip_plane(This, Index, (struct nine_clipplane *)pPlane); + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_GetClipPlane( struct NineDevice9 *This, + DWORD Index, + float *pPlane ) +{ + const struct nine_state *state = &This->state; + + user_assert(!This->pure, D3DERR_INVALIDCALL); + user_assert(pPlane != NULL, D3DERR_INVALIDCALL); + 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 NINE_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 < D3DRS_COUNT, D3D_OK); + + if (unlikely(This->is_recording)) { + state->rs_advertised[State] = Value; + /* only need to record changed render states for stateblocks */ + state->changed.rs[State / 32] |= 1 << (State % 32); + return D3D_OK; + } + + if (state->rs_advertised[State] == Value) + return D3D_OK; + + state->rs_advertised[State] = Value; + nine_context_set_render_state(This, State, Value); + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_GetRenderState( struct NineDevice9 *This, + D3DRENDERSTATETYPE State, + DWORD *pValue ) +{ + user_assert(!This->pure, D3DERR_INVALIDCALL); + user_assert(pValue != NULL, D3DERR_INVALIDCALL); + /* TODO: This needs tests */ + if (State >= D3DRS_COUNT) { + *pValue = 0; + return D3D_OK; + } + + *pValue = This->state.rs_advertised[State]; + return D3D_OK; +} + +HRESULT NINE_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(ppSB != NULL, D3DERR_INVALIDCALL); + 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_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->may_swvp ? NINE_MAX_CONST_F_SWVP : This->max_vs_const_f, + &This->range_pool); + nine_ranges_insert(&dst->changed.vs_const_i, 0, This->may_swvp ? NINE_MAX_CONST_I_SWVP : NINE_MAX_CONST_I, + &This->range_pool); + nine_ranges_insert(&dst->changed.vs_const_b, 0, This->may_swvp ? NINE_MAX_CONST_B_SWVP : NINE_MAX_CONST_B, + &This->range_pool); + 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 | NINE_STATE_FF_PS_CONSTS; + memcpy(dst->changed.rs, + nine_render_states_pixel, sizeof(dst->changed.rs)); + nine_ranges_insert(&dst->changed.ps_const_f, 0, NINE_MAX_CONST_F_PS3, + &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; + for (s = 0; s < NINE_MAX_TEXTURE_STAGES; ++s) { + dst->ff.changed.tex_stage[s][0] |= 0xffffffff; + dst->ff.changed.tex_stage[s][1] |= 0xffffffff; + } + } + if (Type == D3DSBT_ALL) { + dst->changed.group |= + NINE_STATE_VIEWPORT | + NINE_STATE_SCISSOR | + NINE_STATE_IDXBUF | + NINE_STATE_FF_MATERIAL | + NINE_STATE_FF_VSTRANSF; + 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; + /* The doc says the projection, world, view and texture matrices + * are saved, which would translate to: + * dst->ff.changed.transform[0] = 0x00FF000C; + * dst->ff.changed.transform[D3DTS_WORLD / 32] |= 1 << (D3DTS_WORLD % 32); + * However we assume they meant save everything (which is basically just the + * above plus the other world matrices). + */ + dst->ff.changed.transform[0] = 0x00FF000C; + for (s = 0; s < 8; s++) + dst->ff.changed.transform[8+s] = ~0; + } + NineStateBlock9_Capture(NineStateBlock9(*ppSB)); + + /* TODO: fixed function state */ + + return D3D_OK; +} + +HRESULT NINE_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 NINE_WINAPI +NineDevice9_EndStateBlock( struct NineDevice9 *This, + IDirect3DStateBlock9 **ppSB ) +{ + DBG("This=%p ppSB=%p\n", This, ppSB); + + user_assert(This->record, D3DERR_INVALIDCALL); + user_assert(ppSB != NULL, 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 NINE_WINAPI +NineDevice9_SetClipStatus( struct NineDevice9 *This, + const D3DCLIPSTATUS9 *pClipStatus ) +{ + user_assert(pClipStatus, D3DERR_INVALIDCALL); + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_GetClipStatus( struct NineDevice9 *This, + D3DCLIPSTATUS9 *pClipStatus ) +{ + user_assert(pClipStatus, D3DERR_INVALIDCALL); + /* Set/GetClipStatus is supposed to get the app some infos + * about vertices being clipped if it is using the software + * vertex rendering. It would be too complicated to implement. + * Probably the info is for developers when working on their + * applications. Else it could be for apps to know if it is worth + * drawing some elements. In that case it makes sense to send + * 0 for ClipUnion and 0xFFFFFFFF for ClipIntersection (basically + * means not all vertices are clipped). Those values are known to + * be the default if SetClipStatus is not set. Else we could return + * what was set with SetClipStatus unchanged. */ + pClipStatus->ClipUnion = 0; + pClipStatus->ClipIntersection = 0xFFFFFFFF; + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_GetTexture( struct NineDevice9 *This, + DWORD Stage, + IDirect3DBaseTexture9 **ppTexture ) +{ + user_assert(Stage < NINE_MAX_SAMPLERS_PS || + 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 NINE_WINAPI +NineDevice9_SetTexture( struct NineDevice9 *This, + DWORD Stage, + IDirect3DBaseTexture9 *pTexture ) +{ + struct nine_state *state = This->update; + struct NineBaseTexture9 *tex = NineBaseTexture9(pTexture); + struct NineBaseTexture9 *old; + + DBG("This=%p Stage=%u pTexture=%p\n", This, Stage, pTexture); + + user_assert(Stage < NINE_MAX_SAMPLERS_PS || + Stage == D3DDMAPSAMPLER || + (Stage >= D3DVERTEXTEXTURESAMPLER0 && + Stage <= D3DVERTEXTEXTURESAMPLER3), D3DERR_INVALIDCALL); + user_assert(!tex || (tex->base.pool != D3DPOOL_SCRATCH && + tex->base.pool != D3DPOOL_SYSTEMMEM), D3DERR_INVALIDCALL); + + if (Stage >= D3DDMAPSAMPLER) + Stage = Stage - D3DDMAPSAMPLER + NINE_MAX_SAMPLERS_PS; + + if (This->is_recording) { + state->changed.texture |= 1 << Stage; + nine_bind(&state->texture[Stage], pTexture); + return D3D_OK; + } + + old = state->texture[Stage]; + if (old == tex) + return D3D_OK; + + NineBindTextureToDevice(This, &state->texture[Stage], tex); + + nine_context_set_texture(This, Stage, tex); + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_GetTextureStageState( struct NineDevice9 *This, + DWORD Stage, + D3DTEXTURESTAGESTATETYPE Type, + DWORD *pValue ) +{ + const struct nine_state *state = &This->state; + + user_assert(!This->pure, D3DERR_INVALIDCALL); + user_assert(pValue != NULL, D3DERR_INVALIDCALL); + user_assert(Stage < ARRAY_SIZE(state->ff.tex_stage), D3DERR_INVALIDCALL); + user_assert(Type < ARRAY_SIZE(state->ff.tex_stage[0]), D3DERR_INVALIDCALL); + + *pValue = state->ff.tex_stage[Stage][Type]; + + return D3D_OK; +} + +HRESULT NINE_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 < ARRAY_SIZE(state->ff.tex_stage), D3DERR_INVALIDCALL); + user_assert(Type < ARRAY_SIZE(state->ff.tex_stage[0]), D3DERR_INVALIDCALL); + + state->ff.tex_stage[Stage][Type] = Value; + + if (unlikely(This->is_recording)) { + state->changed.group |= NINE_STATE_FF_PS_CONSTS; + state->ff.changed.tex_stage[Stage][Type / 32] |= 1 << (Type % 32); + } else + nine_context_set_texture_stage_state(This, Stage, Type, Value); + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_GetSamplerState( struct NineDevice9 *This, + DWORD Sampler, + D3DSAMPLERSTATETYPE Type, + DWORD *pValue ) +{ + user_assert(!This->pure, D3DERR_INVALIDCALL); + user_assert(pValue != NULL, D3DERR_INVALIDCALL); + user_assert(Sampler < NINE_MAX_SAMPLERS_PS || + Sampler == D3DDMAPSAMPLER || + (Sampler >= D3DVERTEXTEXTURESAMPLER0 && + Sampler <= D3DVERTEXTEXTURESAMPLER3), D3DERR_INVALIDCALL); + + if (Sampler >= D3DDMAPSAMPLER) + Sampler = Sampler - D3DDMAPSAMPLER + NINE_MAX_SAMPLERS_PS; + + *pValue = This->state.samp_advertised[Sampler][Type]; + return D3D_OK; +} + +HRESULT NINE_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 < NINE_MAX_SAMPLERS_PS || + Sampler == D3DDMAPSAMPLER || + (Sampler >= D3DVERTEXTEXTURESAMPLER0 && + Sampler <= D3DVERTEXTEXTURESAMPLER3), D3DERR_INVALIDCALL); + + if (Sampler >= D3DDMAPSAMPLER) + Sampler = Sampler - D3DDMAPSAMPLER + NINE_MAX_SAMPLERS_PS; + + if (unlikely(This->is_recording)) { + state->samp_advertised[Sampler][Type] = Value; + state->changed.group |= NINE_STATE_SAMPLER; + state->changed.sampler[Sampler] |= 1 << Type; + return D3D_OK; + } + + if (state->samp_advertised[Sampler][Type] == Value) + return D3D_OK; + + state->samp_advertised[Sampler][Type] = Value; + nine_context_set_sampler_state(This, Sampler, Type, Value); + + return D3D_OK; +} + +HRESULT NINE_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 < ARRAY_SIZE(state->samp_advertised); ++i) { + if (state->samp_advertised[i][D3DSAMP_MINFILTER] == D3DTEXF_NONE || + state->samp_advertised[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_advertised[D3DRS_ZENABLE] || state->rs_advertised[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 NINE_WINAPI +NineDevice9_SetPaletteEntries( struct NineDevice9 *This, + UINT PaletteNumber, + const PALETTEENTRY *pEntries ) +{ + STUB(D3D_OK); /* like wine */ +} + +HRESULT NINE_WINAPI +NineDevice9_GetPaletteEntries( struct NineDevice9 *This, + UINT PaletteNumber, + PALETTEENTRY *pEntries ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT NINE_WINAPI +NineDevice9_SetCurrentTexturePalette( struct NineDevice9 *This, + UINT PaletteNumber ) +{ + STUB(D3D_OK); /* like wine */ +} + +HRESULT NINE_WINAPI +NineDevice9_GetCurrentTexturePalette( struct NineDevice9 *This, + UINT *PaletteNumber ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT NINE_WINAPI +NineDevice9_SetScissorRect( struct NineDevice9 *This, + const RECT *pRect ) +{ + struct nine_state *state = This->update; + + user_assert(pRect != NULL, D3DERR_INVALIDCALL); + + 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; + + if (unlikely(This->is_recording)) + state->changed.group |= NINE_STATE_SCISSOR; + else + nine_context_set_scissor(This, &state->scissor); + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_GetScissorRect( struct NineDevice9 *This, + RECT *pRect ) +{ + user_assert(pRect != NULL, D3DERR_INVALIDCALL); + + 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 NINE_WINAPI +NineDevice9_SetSoftwareVertexProcessing( struct NineDevice9 *This, + BOOL bSoftware ) +{ + if (This->params.BehaviorFlags & D3DCREATE_MIXED_VERTEXPROCESSING) { + This->swvp = bSoftware; + nine_context_set_swvp(This, bSoftware); + return D3D_OK; + } else + return D3D_OK; /* msdn seems to indicate INVALIDCALL, but at least Halo expects OK */ +} + +BOOL NINE_WINAPI +NineDevice9_GetSoftwareVertexProcessing( struct NineDevice9 *This ) +{ + return This->swvp; +} + +HRESULT NINE_WINAPI +NineDevice9_SetNPatchMode( struct NineDevice9 *This, + float nSegments ) +{ + return D3D_OK; /* Nothing to do because we don't advertise NPatch support */ +} + +float NINE_WINAPI +NineDevice9_GetNPatchMode( struct NineDevice9 *This ) +{ + STUB(0); +} + +/* 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 void +update_managed_buffers(struct NineDevice9 *device) +{ + struct NineBuffer9 *buf, *ptr; + LIST_FOR_EACH_ENTRY_SAFE(buf, ptr, &device->update_buffers, managed.list) { + list_delinit(&buf->managed.list); + NineBuffer9_Upload(buf); + } +} + +static void +NineBeforeDraw( struct NineDevice9 *This ) +{ + /* Upload Managed dirty content */ + validate_textures(This); /* may clobber state */ + update_managed_buffers(This); +} + +static void +NineAfterDraw( struct NineDevice9 *This ) +{ + unsigned i; + struct nine_state *state = &This->state; + unsigned ps_mask = state->ps ? state->ps->rt_mask : 1; + + /* Flag render-targets with autogenmipmap for mipmap regeneration */ + for (i = 0; i < This->caps.NumSimultaneousRTs; ++i) { + struct NineSurface9 *rt = state->rt[i]; + + if (rt && rt->desc.Format != D3DFMT_NULL && (ps_mask & (1 << i)) && + rt->desc.Usage & D3DUSAGE_AUTOGENMIPMAP) { + assert(rt->texture == D3DRTYPE_TEXTURE || + rt->texture == D3DRTYPE_CUBETEXTURE); + NineBaseTexture9(rt->base.base.container)->dirty_mip = true; + } + } +} + +#define IS_SYSTEMMEM_DYNAMIC(t) ((t) && (t)->base.pool == D3DPOOL_SYSTEMMEM && (t)->base.usage & D3DUSAGE_DYNAMIC) + +/* Indicates the region needed right now for these buffers and add them to the list + * of buffers to process in NineBeforeDraw. + * The reason we don't call the upload right now is to generate smaller code (no + * duplication of the NineBuffer9_Upload inline) and to have one upload (of the correct size) + * if a vertex buffer is twice input of the draw call. */ +static void +NineTrackSystemmemDynamic( struct NineBuffer9 *This, unsigned start, unsigned width ) +{ + struct pipe_box box; + + if (start >= This->size) + return; /* outside bounds, nothing to do */ + u_box_1d(start, MIN2(width, This->size-start), &box); + u_box_union_1d(&This->managed.required_valid_region, + &This->managed.required_valid_region, + &box); + This->managed.dirty = true; + BASEBUF_REGISTER_UPDATE(This); +} + +HRESULT NINE_WINAPI +NineDevice9_DrawPrimitive( struct NineDevice9 *This, + D3DPRIMITIVETYPE PrimitiveType, + UINT StartVertex, + UINT PrimitiveCount ) +{ + unsigned i; + DBG("iface %p, PrimitiveType %u, StartVertex %u, PrimitiveCount %u\n", + This, PrimitiveType, StartVertex, PrimitiveCount); + + /* Tracking for dynamic SYSTEMMEM */ + for (i = 0; i < This->caps.MaxStreams; i++) { + unsigned stride = This->state.vtxstride[i]; + if (IS_SYSTEMMEM_DYNAMIC((struct NineBuffer9*)This->state.stream[i])) { + unsigned start = This->state.vtxbuf[i].buffer_offset + StartVertex * stride; + unsigned full_size = This->state.stream[i]->base.size; + unsigned num_vertices = prim_count_to_vertex_count(PrimitiveType, PrimitiveCount); + unsigned size = MIN2(full_size-start, num_vertices * stride); + if (!stride) /* Instancing. Not sure what to do. Require all */ + size = full_size; + NineTrackSystemmemDynamic(&This->state.stream[i]->base, start, size); + } + } + + NineBeforeDraw(This); + nine_context_draw_primitive(This, PrimitiveType, StartVertex, PrimitiveCount); + NineAfterDraw(This); + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_DrawIndexedPrimitive( struct NineDevice9 *This, + D3DPRIMITIVETYPE PrimitiveType, + INT BaseVertexIndex, + UINT MinVertexIndex, + UINT NumVertices, + UINT StartIndex, + UINT PrimitiveCount ) +{ + unsigned i, num_indices; + 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); + + num_indices = prim_count_to_vertex_count(PrimitiveType, PrimitiveCount); + + /* Tracking for dynamic SYSTEMMEM */ + if (IS_SYSTEMMEM_DYNAMIC(&This->state.idxbuf->base)) + NineTrackSystemmemDynamic(&This->state.idxbuf->base, + StartIndex * This->state.idxbuf->index_size, + num_indices * This->state.idxbuf->index_size); + + for (i = 0; i < This->caps.MaxStreams; i++) { + if (IS_SYSTEMMEM_DYNAMIC((struct NineBuffer9*)This->state.stream[i])) { + uint32_t stride = This->state.vtxstride[i]; + uint32_t full_size = This->state.stream[i]->base.size; + uint32_t start, stop; + + start = MAX2(0, This->state.vtxbuf[i].buffer_offset+(MinVertexIndex+BaseVertexIndex)*stride); + stop = This->state.vtxbuf[i].buffer_offset+(MinVertexIndex+NumVertices+BaseVertexIndex)*stride; + stop = MIN2(stop, full_size); + NineTrackSystemmemDynamic(&This->state.stream[i]->base, + start, stop-start); + } + } + + NineBeforeDraw(This); + nine_context_draw_indexed_primitive(This, PrimitiveType, BaseVertexIndex, + MinVertexIndex, NumVertices, StartIndex, + PrimitiveCount); + NineAfterDraw(This); + + return D3D_OK; +} + +static void +NineDevice9_SetStreamSourceNULL( struct NineDevice9 *This ); + +HRESULT NINE_WINAPI +NineDevice9_DrawPrimitiveUP( struct NineDevice9 *This, + D3DPRIMITIVETYPE PrimitiveType, + UINT PrimitiveCount, + const void *pVertexStreamZeroData, + UINT VertexStreamZeroStride ) +{ + struct pipe_resource *resource = NULL; + unsigned buffer_offset; + unsigned StartVertex = 0; + + DBG("iface %p, PrimitiveType %u, PrimitiveCount %u, data %p, stride %u\n", + This, PrimitiveType, PrimitiveCount, + pVertexStreamZeroData, VertexStreamZeroStride); + + user_assert(pVertexStreamZeroData && VertexStreamZeroStride, + D3DERR_INVALIDCALL); + user_assert(PrimitiveCount, D3D_OK); + + u_upload_data_ref(This->vertex_uploader, + 0, + (prim_count_to_vertex_count(PrimitiveType, PrimitiveCount)) * VertexStreamZeroStride, + 1, + pVertexStreamZeroData, + &buffer_offset, + &resource); + u_upload_unmap(This->vertex_uploader); + + /* Optimization to skip changing the bound vertex buffer data + * for consecutive DrawPrimitiveUp with identical VertexStreamZeroStride */ + if (VertexStreamZeroStride > 0) { + StartVertex = buffer_offset / VertexStreamZeroStride; + buffer_offset -= StartVertex * VertexStreamZeroStride; + } + + nine_context_set_stream_source_apply(This, 0, resource, + buffer_offset, VertexStreamZeroStride); + pipe_resource_reference(&resource, NULL); + + NineBeforeDraw(This); + nine_context_draw_primitive(This, PrimitiveType, StartVertex, PrimitiveCount); + NineAfterDraw(This); + + NineDevice9_PauseRecording(This); + NineDevice9_SetStreamSourceNULL(This); + NineDevice9_ResumeRecording(This); + + return D3D_OK; +} + +HRESULT NINE_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_vertex_buffer vbuf; + unsigned index_size = (IndexDataFormat == D3DFMT_INDEX16) ? 2 : 4; + struct pipe_resource *ibuf = NULL; + unsigned base; + + 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); + user_assert(PrimitiveCount, D3D_OK); + + base = MinVertexIndex * VertexStreamZeroStride; + vbuf.is_user_buffer = false; + vbuf.buffer.resource = NULL; + u_upload_data_ref(This->vertex_uploader, + base, + NumVertices * VertexStreamZeroStride, /* XXX */ + 64, + (const uint8_t *)pVertexStreamZeroData + base, + &vbuf.buffer_offset, + &vbuf.buffer.resource); + u_upload_unmap(This->vertex_uploader); + /* Won't be used: */ + vbuf.buffer_offset -= base; + + unsigned index_offset = 0; + u_upload_data_ref(This->pipe_secondary->stream_uploader, + 0, + (prim_count_to_vertex_count(PrimitiveType, PrimitiveCount)) * index_size, + 64, + pIndexData, + &index_offset, + &ibuf); + u_upload_unmap(This->pipe_secondary->stream_uploader); + + NineBeforeDraw(This); + nine_context_draw_indexed_primitive_from_vtxbuf_idxbuf(This, PrimitiveType, + MinVertexIndex, + NumVertices, + PrimitiveCount, + VertexStreamZeroStride, + &vbuf, + ibuf, + ibuf ? NULL : (void*)pIndexData, + index_offset, + index_size); + NineAfterDraw(This); + + pipe_vertex_buffer_unreference(&vbuf); + pipe_resource_reference(&ibuf, NULL); + + NineDevice9_PauseRecording(This); + NineDevice9_SetIndices(This, NULL); + NineDevice9_SetStreamSourceNULL(This); + NineDevice9_ResumeRecording(This); + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_ProcessVertices( struct NineDevice9 *This, + UINT SrcStartIndex, + UINT DestIndex, + UINT VertexCount, + IDirect3DVertexBuffer9 *pDestBuffer, + IDirect3DVertexDeclaration9 *pVertexDecl, + DWORD Flags ) +{ + struct pipe_screen *screen_sw = This->screen_sw; + struct pipe_context *pipe_sw = This->pipe_sw; + struct NineVertexDeclaration9 *vdecl = NineVertexDeclaration9(pVertexDecl); + struct NineVertexBuffer9 *dst = NineVertexBuffer9(pDestBuffer); + struct NineVertexShader9 *vs; + struct pipe_resource *resource; + struct pipe_transfer *transfer = NULL; + struct pipe_stream_output_info so; + struct pipe_stream_output_target *target; + struct pipe_draw_info draw; + struct pipe_draw_start_count_bias sc; + struct pipe_box box; + bool programmable_vs = This->state.vs && !(This->state.vdecl && This->state.vdecl->position_t); + unsigned offsets[1] = {0}; + HRESULT hr; + unsigned buffer_size; + void *map; + + DBG("This=%p SrcStartIndex=%u DestIndex=%u VertexCount=%u " + "pDestBuffer=%p pVertexDecl=%p Flags=%d\n", + This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, + pVertexDecl, Flags); + + user_assert(pDestBuffer && pVertexDecl, D3DERR_INVALIDCALL); + + if (!screen_sw->caps.max_stream_output_buffers) { + DBG("ProcessVertices not supported\n"); + return D3DERR_INVALIDCALL; + } + + + vs = programmable_vs ? This->state.vs : This->ff.vs; + /* Note: version is 0 for ff */ + user_assert(vdecl || (vs->byte_code.version < 0x30 && dst->desc.FVF), + D3DERR_INVALIDCALL); + if (!vdecl) { + DWORD FVF = dst->desc.FVF; + 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; + _mesa_hash_table_insert(This->ff.ht_fvf, &vdecl->fvf, vdecl); + NineUnknown_ConvertRefToBind(NineUnknown(vdecl)); + } + } + + /* Flags: Can be 0 or D3DPV_DONOTCOPYDATA, and/or lock flags + * D3DPV_DONOTCOPYDATA -> Has effect only for ff. In particular + * if not set, everything from src will be used, and dst + * must match exactly the ff vs outputs. + * TODO: Handle all the checks, etc for ff */ + user_assert(vdecl->position_t || programmable_vs, + D3DERR_INVALIDCALL); + + /* TODO: Support vs < 3 and ff */ + user_assert(vs->byte_code.version == 0x30, + D3DERR_INVALIDCALL); + /* TODO: Not hardcode the constant buffers for swvp */ + user_assert(This->may_swvp, + D3DERR_INVALIDCALL); + + nine_state_prepare_draw_sw(This, vdecl, SrcStartIndex, VertexCount, &so); + + buffer_size = VertexCount * so.stride[0] * 4; + { + struct pipe_resource templ; + + memset(&templ, 0, sizeof(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 = templ.nr_storage_samples = 0; + + resource = screen_sw->resource_create(screen_sw, &templ); + if (!resource) + return E_OUTOFMEMORY; + } + target = pipe_sw->create_stream_output_target(pipe_sw, resource, + 0, buffer_size); + if (!target) { + pipe_resource_reference(&resource, NULL); + return D3DERR_DRIVERINTERNALERROR; + } + + draw.mode = MESA_PRIM_POINTS; + sc.count = VertexCount; + draw.start_instance = 0; + draw.primitive_restart = false; + draw.restart_index = 0; + draw.instance_count = 1; + draw.index_size = 0; + sc.start = 0; + sc.index_bias = 0; + draw.min_index = 0; + draw.max_index = VertexCount - 1; + + + pipe_sw->set_stream_output_targets(pipe_sw, 1, &target, offsets, draw.mode); + + pipe_sw->draw_vbo(pipe_sw, &draw, 0, NULL, &sc, 1); + + pipe_sw->set_stream_output_targets(pipe_sw, 0, NULL, NULL, 0); + pipe_sw->stream_output_target_destroy(pipe_sw, target); + + u_box_1d(0, VertexCount * so.stride[0] * 4, &box); + map = pipe_sw->buffer_map(pipe_sw, resource, 0, PIPE_MAP_READ, &box, + &transfer); + if (!map) { + hr = D3DERR_DRIVERINTERNALERROR; + goto out; + } + + hr = NineVertexDeclaration9_ConvertStreamOutput(vdecl, + dst, DestIndex, VertexCount, + map, &so); + if (transfer) + pipe_sw->buffer_unmap(pipe_sw, transfer); + +out: + nine_state_after_draw_sw(This); + pipe_resource_reference(&resource, NULL); + return hr; +} + +HRESULT NINE_WINAPI +NineDevice9_CreateVertexDeclaration( struct NineDevice9 *This, + const D3DVERTEXELEMENT9 *pVertexElements, + IDirect3DVertexDeclaration9 **ppDecl ) +{ + struct NineVertexDeclaration9 *vdecl; + + DBG("This=%p pVertexElements=%p ppDecl=%p\n", + This, pVertexElements, ppDecl); + + user_assert(pVertexElements && ppDecl, D3DERR_INVALIDCALL); + + HRESULT hr = NineVertexDeclaration9_new(This, pVertexElements, &vdecl); + if (SUCCEEDED(hr)) + *ppDecl = (IDirect3DVertexDeclaration9 *)vdecl; + + return hr; +} + +HRESULT NINE_WINAPI +NineDevice9_SetVertexDeclaration( struct NineDevice9 *This, + IDirect3DVertexDeclaration9 *pDecl ) +{ + struct nine_state *state = This->update; + struct NineVertexDeclaration9 *vdecl = NineVertexDeclaration9(pDecl); + + DBG("This=%p pDecl=%p\n", This, pDecl); + + if (unlikely(This->is_recording)) { + nine_bind(&state->vdecl, vdecl); + state->changed.group |= NINE_STATE_VDECL; + return D3D_OK; + } + + if (state->vdecl == vdecl) + return D3D_OK; + + nine_bind(&state->vdecl, vdecl); + + nine_context_set_vertex_declaration(This, vdecl); + + return D3D_OK; +} + +HRESULT NINE_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 NINE_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; + _mesa_hash_table_insert(This->ff.ht_fvf, &vdecl->fvf, vdecl); + NineUnknown_ConvertRefToBind(NineUnknown(vdecl)); + } + return NineDevice9_SetVertexDeclaration( + This, (IDirect3DVertexDeclaration9 *)vdecl); +} + +HRESULT NINE_WINAPI +NineDevice9_GetFVF( struct NineDevice9 *This, + DWORD *pFVF ) +{ + user_assert(pFVF != NULL, D3DERR_INVALIDCALL); + *pFVF = This->state.vdecl ? This->state.vdecl->fvf : 0; + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_CreateVertexShader( struct NineDevice9 *This, + const DWORD *pFunction, + IDirect3DVertexShader9 **ppShader ) +{ + struct NineVertexShader9 *vs; + HRESULT hr; + + DBG("This=%p pFunction=%p ppShader=%p\n", This, pFunction, ppShader); + + user_assert(pFunction && ppShader, D3DERR_INVALIDCALL); + + hr = NineVertexShader9_new(This, &vs, pFunction, NULL); + if (FAILED(hr)) + return hr; + *ppShader = (IDirect3DVertexShader9 *)vs; + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_SetVertexShader( struct NineDevice9 *This, + IDirect3DVertexShader9 *pShader ) +{ + struct nine_state *state = This->update; + struct NineVertexShader9 *vs_shader = (struct NineVertexShader9*)pShader; + + DBG("This=%p pShader=%p\n", This, pShader); + + if (unlikely(This->is_recording)) { + nine_bind(&state->vs, vs_shader); + state->changed.group |= NINE_STATE_VS; + return D3D_OK; + } + + if (state->vs == vs_shader) + return D3D_OK; + + nine_bind(&state->vs, vs_shader); + + nine_context_set_vertex_shader(This, vs_shader); + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_GetVertexShader( struct NineDevice9 *This, + IDirect3DVertexShader9 **ppShader ) +{ + user_assert(ppShader, D3DERR_INVALIDCALL); + nine_reference_set(ppShader, This->state.vs); + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_SetVertexShaderConstantF( struct NineDevice9 *This, + UINT StartRegister, + const float *pConstantData, + UINT Vector4fCount ) +{ + struct nine_state *state = This->update; + float *vs_const_f = state->vs_const_f; + + 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); + + if (unlikely(This->is_recording)) { + memcpy(&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; + } + + if (!memcmp(&vs_const_f[StartRegister * 4], pConstantData, + Vector4fCount * 4 * sizeof(state->vs_const_f[0]))) + return D3D_OK; + + memcpy(&vs_const_f[StartRegister * 4], + pConstantData, + Vector4fCount * 4 * sizeof(state->vs_const_f[0])); + + nine_context_set_vertex_shader_constant_f(This, StartRegister, pConstantData, + Vector4fCount * 4 * sizeof(state->vs_const_f[0]), + Vector4fCount); + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_GetVertexShaderConstantF( struct NineDevice9 *This, + UINT StartRegister, + float *pConstantData, + UINT Vector4fCount ) +{ + const struct nine_state *state = &This->state; + + user_assert(!This->pure, D3DERR_INVALIDCALL); + 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 NINE_WINAPI +NineDevice9_SetVertexShaderConstantI( struct NineDevice9 *This, + UINT StartRegister, + const int *pConstantData, + UINT Vector4iCount ) +{ + struct nine_state *state = This->update; + int i; + + DBG("This=%p StartRegister=%u pConstantData=%p Vector4iCount=%u\n", + This, StartRegister, pConstantData, Vector4iCount); + + user_assert(StartRegister < (This->may_swvp ? NINE_MAX_CONST_I_SWVP : NINE_MAX_CONST_I), + D3DERR_INVALIDCALL); + user_assert(StartRegister + Vector4iCount <= (This->may_swvp ? NINE_MAX_CONST_I_SWVP : NINE_MAX_CONST_I), + D3DERR_INVALIDCALL); + user_assert(pConstantData, D3DERR_INVALIDCALL); + + if (This->driver_caps.vs_integer) { + if (!This->is_recording) { + if (!memcmp(&state->vs_const_i[4 * StartRegister], pConstantData, + Vector4iCount * sizeof(int[4]))) + return D3D_OK; + } + memcpy(&state->vs_const_i[4 * StartRegister], + pConstantData, + Vector4iCount * sizeof(int[4])); + } else { + for (i = 0; i < Vector4iCount; i++) { + state->vs_const_i[4 * (StartRegister + i)] = fui((float)(pConstantData[4 * i])); + state->vs_const_i[4 * (StartRegister + i) + 1] = fui((float)(pConstantData[4 * i + 1])); + state->vs_const_i[4 * (StartRegister + i) + 2] = fui((float)(pConstantData[4 * i + 2])); + state->vs_const_i[4 * (StartRegister + i) + 3] = fui((float)(pConstantData[4 * i + 3])); + } + } + + if (unlikely(This->is_recording)) { + nine_ranges_insert(&state->changed.vs_const_i, + StartRegister, StartRegister + Vector4iCount, + &This->range_pool); + state->changed.group |= NINE_STATE_VS_CONST; + } else + nine_context_set_vertex_shader_constant_i(This, StartRegister, pConstantData, + Vector4iCount * sizeof(int[4]), Vector4iCount); + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_GetVertexShaderConstantI( struct NineDevice9 *This, + UINT StartRegister, + int *pConstantData, + UINT Vector4iCount ) +{ + const struct nine_state *state = &This->state; + int i; + + user_assert(!This->pure, D3DERR_INVALIDCALL); + user_assert(StartRegister < (This->may_swvp ? NINE_MAX_CONST_I_SWVP : NINE_MAX_CONST_I), + D3DERR_INVALIDCALL); + user_assert(StartRegister + Vector4iCount <= (This->may_swvp ? NINE_MAX_CONST_I_SWVP : NINE_MAX_CONST_I), + D3DERR_INVALIDCALL); + user_assert(pConstantData, D3DERR_INVALIDCALL); + + if (This->driver_caps.vs_integer) { + memcpy(pConstantData, + &state->vs_const_i[4 * StartRegister], + Vector4iCount * sizeof(int[4])); + } else { + for (i = 0; i < Vector4iCount; i++) { + pConstantData[4 * i] = (int32_t) uif(state->vs_const_i[4 * (StartRegister + i)]); + pConstantData[4 * i + 1] = (int32_t) uif(state->vs_const_i[4 * (StartRegister + i) + 1]); + pConstantData[4 * i + 2] = (int32_t) uif(state->vs_const_i[4 * (StartRegister + i) + 2]); + pConstantData[4 * i + 3] = (int32_t) uif(state->vs_const_i[4 * (StartRegister + i) + 3]); + } + } + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_SetVertexShaderConstantB( struct NineDevice9 *This, + UINT StartRegister, + const BOOL *pConstantData, + UINT BoolCount ) +{ + struct nine_state *state = This->update; + int i; + uint32_t bool_true = This->driver_caps.vs_integer ? 0xFFFFFFFF : fui(1.0f); + + DBG("This=%p StartRegister=%u pConstantData=%p BoolCount=%u\n", + This, StartRegister, pConstantData, BoolCount); + + user_assert(StartRegister < (This->may_swvp ? NINE_MAX_CONST_B_SWVP : NINE_MAX_CONST_B), + D3DERR_INVALIDCALL); + user_assert(StartRegister + BoolCount <= (This->may_swvp ? NINE_MAX_CONST_B_SWVP : NINE_MAX_CONST_B), + D3DERR_INVALIDCALL); + user_assert(pConstantData, D3DERR_INVALIDCALL); + + if (!This->is_recording) { + bool noChange = true; + for (i = 0; i < BoolCount; i++) { + if (!!state->vs_const_b[StartRegister + i] != !!pConstantData[i]) + noChange = false; + } + if (noChange) + return D3D_OK; + } + + for (i = 0; i < BoolCount; i++) + state->vs_const_b[StartRegister + i] = pConstantData[i] ? bool_true : 0; + + if (unlikely(This->is_recording)) { + nine_ranges_insert(&state->changed.vs_const_b, + StartRegister, StartRegister + BoolCount, + &This->range_pool); + state->changed.group |= NINE_STATE_VS_CONST; + } else + nine_context_set_vertex_shader_constant_b(This, StartRegister, pConstantData, + sizeof(BOOL) * BoolCount, BoolCount); + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_GetVertexShaderConstantB( struct NineDevice9 *This, + UINT StartRegister, + BOOL *pConstantData, + UINT BoolCount ) +{ + const struct nine_state *state = &This->state; + int i; + + user_assert(!This->pure, D3DERR_INVALIDCALL); + user_assert(StartRegister < (This->may_swvp ? NINE_MAX_CONST_B_SWVP : NINE_MAX_CONST_B), + D3DERR_INVALIDCALL); + user_assert(StartRegister + BoolCount <= (This->may_swvp ? NINE_MAX_CONST_B_SWVP : NINE_MAX_CONST_B), + D3DERR_INVALIDCALL); + user_assert(pConstantData, D3DERR_INVALIDCALL); + + for (i = 0; i < BoolCount; i++) + pConstantData[i] = state->vs_const_b[StartRegister + i] != 0 ? true : false; + + return D3D_OK; +} + +HRESULT NINE_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; + + DBG("This=%p StreamNumber=%u pStreamData=%p OffsetInBytes=%u Stride=%u\n", + This, StreamNumber, pStreamData, OffsetInBytes, Stride); + + user_assert(StreamNumber < This->caps.MaxStreams, D3DERR_INVALIDCALL); + user_assert(Stride <= This->caps.MaxStreamStride, D3DERR_INVALIDCALL); + + if (unlikely(This->is_recording)) { + nine_bind(&state->stream[i], pStreamData); + state->changed.vtxbuf |= 1 << StreamNumber; + state->vtxstride[i] = Stride; + state->vtxbuf[i].buffer_offset = OffsetInBytes; + return D3D_OK; + } + + if (state->stream[i] == NineVertexBuffer9(pStreamData) && + state->vtxstride[i] == Stride && + state->vtxbuf[i].buffer_offset == OffsetInBytes) + return D3D_OK; + + state->vtxstride[i] = Stride; + state->vtxbuf[i].buffer_offset = OffsetInBytes; + + NineBindBufferToDevice(This, + (struct NineBuffer9 **)&state->stream[i], + (struct NineBuffer9 *)pVBuf9); + + nine_context_set_stream_source(This, + StreamNumber, + pVBuf9, + OffsetInBytes, + Stride); + + return D3D_OK; +} + +static void +NineDevice9_SetStreamSourceNULL( struct NineDevice9 *This ) +{ + struct nine_state *state = This->update; + + DBG("This=%p\n", This); + + state->vtxstride[0] = 0; + state->vtxbuf[0].buffer_offset = 0; + + if (!state->stream[0]) + return; + + NineBindBufferToDevice(This, + (struct NineBuffer9 **)&state->stream[0], + NULL); +} + +HRESULT NINE_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 && pOffsetInBytes && pStride, D3DERR_INVALIDCALL); + + nine_reference_set(ppStreamData, state->stream[i]); + *pStride = state->vtxstride[i]; + *pOffsetInBytes = state->vtxbuf[i].buffer_offset; + + return D3D_OK; +} + +HRESULT NINE_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); + + if (unlikely(This->is_recording)) { + state->stream_freq[StreamNumber] = Setting; + state->changed.stream_freq |= 1 << StreamNumber; + return D3D_OK; + } + + if (state->stream_freq[StreamNumber] == Setting) + return D3D_OK; + + state->stream_freq[StreamNumber] = Setting; + + nine_context_set_stream_source_freq(This, StreamNumber, Setting); + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_GetStreamSourceFreq( struct NineDevice9 *This, + UINT StreamNumber, + UINT *pSetting ) +{ + user_assert(pSetting != NULL, D3DERR_INVALIDCALL); + user_assert(StreamNumber < This->caps.MaxStreams, D3DERR_INVALIDCALL); + *pSetting = This->state.stream_freq[StreamNumber]; + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_SetIndices( struct NineDevice9 *This, + IDirect3DIndexBuffer9 *pIndexData ) +{ + struct nine_state *state = This->update; + struct NineIndexBuffer9 *idxbuf = NineIndexBuffer9(pIndexData); + + DBG("This=%p pIndexData=%p\n", This, pIndexData); + + if (unlikely(This->is_recording)) { + nine_bind(&state->idxbuf, idxbuf); + state->changed.group |= NINE_STATE_IDXBUF; + return D3D_OK; + } + + if (state->idxbuf == idxbuf) + return D3D_OK; + + NineBindBufferToDevice(This, + (struct NineBuffer9 **)&state->idxbuf, + (struct NineBuffer9 *)idxbuf); + + nine_context_set_indices(This, 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 NINE_WINAPI +NineDevice9_GetIndices( struct NineDevice9 *This, + IDirect3DIndexBuffer9 **ppIndexData) +{ + user_assert(ppIndexData, D3DERR_INVALIDCALL); + nine_reference_set(ppIndexData, This->state.idxbuf); + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_CreatePixelShader( struct NineDevice9 *This, + const DWORD *pFunction, + IDirect3DPixelShader9 **ppShader ) +{ + struct NinePixelShader9 *ps; + HRESULT hr; + + DBG("This=%p pFunction=%p ppShader=%p\n", This, pFunction, ppShader); + + user_assert(pFunction && ppShader, D3DERR_INVALIDCALL); + + hr = NinePixelShader9_new(This, &ps, pFunction, NULL); + if (FAILED(hr)) + return hr; + *ppShader = (IDirect3DPixelShader9 *)ps; + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_SetPixelShader( struct NineDevice9 *This, + IDirect3DPixelShader9 *pShader ) +{ + struct nine_state *state = This->update; + struct NinePixelShader9 *ps = (struct NinePixelShader9*)pShader; + + DBG("This=%p pShader=%p\n", This, pShader); + + if (unlikely(This->is_recording)) { + nine_bind(&state->ps, pShader); + state->changed.group |= NINE_STATE_PS; + return D3D_OK; + } + + if (state->ps == ps) + return D3D_OK; + + nine_bind(&state->ps, ps); + + nine_context_set_pixel_shader(This, ps); + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_GetPixelShader( struct NineDevice9 *This, + IDirect3DPixelShader9 **ppShader ) +{ + user_assert(ppShader, D3DERR_INVALIDCALL); + nine_reference_set(ppShader, This->state.ps); + return D3D_OK; +} + +HRESULT NINE_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_PS3, D3DERR_INVALIDCALL); + user_assert(StartRegister + Vector4fCount <= NINE_MAX_CONST_F_PS3, D3DERR_INVALIDCALL); + + if (!Vector4fCount) + return D3D_OK; + user_assert(pConstantData, D3DERR_INVALIDCALL); + + if (unlikely(This->is_recording)) { + 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; + } + + if (!memcmp(&state->ps_const_f[StartRegister * 4], pConstantData, + Vector4fCount * 4 * sizeof(state->ps_const_f[0]))) + return D3D_OK; + + memcpy(&state->ps_const_f[StartRegister * 4], + pConstantData, + Vector4fCount * 4 * sizeof(state->ps_const_f[0])); + + nine_context_set_pixel_shader_constant_f(This, StartRegister, pConstantData, + Vector4fCount * 4 * sizeof(state->ps_const_f[0]), + Vector4fCount); + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_GetPixelShaderConstantF( struct NineDevice9 *This, + UINT StartRegister, + float *pConstantData, + UINT Vector4fCount ) +{ + const struct nine_state *state = &This->state; + + user_assert(!This->pure, D3DERR_INVALIDCALL); + user_assert(StartRegister < NINE_MAX_CONST_F_PS3, D3DERR_INVALIDCALL); + user_assert(StartRegister + Vector4fCount <= NINE_MAX_CONST_F_PS3, 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 NINE_WINAPI +NineDevice9_SetPixelShaderConstantI( struct NineDevice9 *This, + UINT StartRegister, + const int *pConstantData, + UINT Vector4iCount ) +{ + struct nine_state *state = This->update; + int i; + + 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); + + if (This->driver_caps.ps_integer) { + if (!This->is_recording) { + if (!memcmp(&state->ps_const_i[StartRegister][0], pConstantData, + Vector4iCount * sizeof(state->ps_const_i[0]))) + return D3D_OK; + } + memcpy(&state->ps_const_i[StartRegister][0], + pConstantData, + Vector4iCount * sizeof(state->ps_const_i[0])); + } else { + for (i = 0; i < Vector4iCount; i++) { + state->ps_const_i[StartRegister+i][0] = fui((float)(pConstantData[4*i])); + state->ps_const_i[StartRegister+i][1] = fui((float)(pConstantData[4*i+1])); + state->ps_const_i[StartRegister+i][2] = fui((float)(pConstantData[4*i+2])); + state->ps_const_i[StartRegister+i][3] = fui((float)(pConstantData[4*i+3])); + } + } + + if (unlikely(This->is_recording)) { + state->changed.ps_const_i |= ((1 << Vector4iCount) - 1) << StartRegister; + state->changed.group |= NINE_STATE_PS_CONST; + } else + nine_context_set_pixel_shader_constant_i(This, StartRegister, pConstantData, + sizeof(state->ps_const_i[0]) * Vector4iCount, Vector4iCount); + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_GetPixelShaderConstantI( struct NineDevice9 *This, + UINT StartRegister, + int *pConstantData, + UINT Vector4iCount ) +{ + const struct nine_state *state = &This->state; + int i; + + user_assert(!This->pure, D3DERR_INVALIDCALL); + user_assert(StartRegister < NINE_MAX_CONST_I, D3DERR_INVALIDCALL); + user_assert(StartRegister + Vector4iCount <= NINE_MAX_CONST_I, D3DERR_INVALIDCALL); + user_assert(pConstantData, D3DERR_INVALIDCALL); + + if (This->driver_caps.ps_integer) { + memcpy(pConstantData, + &state->ps_const_i[StartRegister][0], + Vector4iCount * sizeof(state->ps_const_i[0])); + } else { + for (i = 0; i < Vector4iCount; i++) { + pConstantData[4*i] = (int32_t) uif(state->ps_const_i[StartRegister+i][0]); + pConstantData[4*i+1] = (int32_t) uif(state->ps_const_i[StartRegister+i][1]); + pConstantData[4*i+2] = (int32_t) uif(state->ps_const_i[StartRegister+i][2]); + pConstantData[4*i+3] = (int32_t) uif(state->ps_const_i[StartRegister+i][3]); + } + } + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_SetPixelShaderConstantB( struct NineDevice9 *This, + UINT StartRegister, + const BOOL *pConstantData, + UINT BoolCount ) +{ + struct nine_state *state = This->update; + int i; + uint32_t bool_true = This->driver_caps.ps_integer ? 0xFFFFFFFF : fui(1.0f); + + 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); + + if (!This->is_recording) { + bool noChange = true; + for (i = 0; i < BoolCount; i++) { + if (!!state->ps_const_b[StartRegister + i] != !!pConstantData[i]) + noChange = false; + } + if (noChange) + return D3D_OK; + } + + for (i = 0; i < BoolCount; i++) + state->ps_const_b[StartRegister + i] = pConstantData[i] ? bool_true : 0; + + if (unlikely(This->is_recording)) { + state->changed.ps_const_b |= ((1 << BoolCount) - 1) << StartRegister; + state->changed.group |= NINE_STATE_PS_CONST; + } else + nine_context_set_pixel_shader_constant_b(This, StartRegister, pConstantData, + sizeof(BOOL) * BoolCount, BoolCount); + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_GetPixelShaderConstantB( struct NineDevice9 *This, + UINT StartRegister, + BOOL *pConstantData, + UINT BoolCount ) +{ + const struct nine_state *state = &This->state; + int i; + + user_assert(!This->pure, D3DERR_INVALIDCALL); + user_assert(StartRegister < NINE_MAX_CONST_B, D3DERR_INVALIDCALL); + user_assert(StartRegister + BoolCount <= NINE_MAX_CONST_B, D3DERR_INVALIDCALL); + user_assert(pConstantData, D3DERR_INVALIDCALL); + + for (i = 0; i < BoolCount; i++) + pConstantData[i] = state->ps_const_b[StartRegister + i] ? true : false; + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9_DrawRectPatch( struct NineDevice9 *This, + UINT Handle, + const float *pNumSegs, + const D3DRECTPATCH_INFO *pRectPatchInfo ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT NINE_WINAPI +NineDevice9_DrawTriPatch( struct NineDevice9 *This, + UINT Handle, + const float *pNumSegs, + const D3DTRIPATCH_INFO *pTriPatchInfo ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT NINE_WINAPI +NineDevice9_DeletePatch( struct NineDevice9 *This, + UINT Handle ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT NINE_WINAPI +NineDevice9_CreateQuery( struct NineDevice9 *This, + D3DQUERYTYPE Type, + IDirect3DQuery9 **ppQuery ) +{ + struct NineQuery9 *query; + HRESULT hr; + + DBG("This=%p Type=%d ppQuery=%p\n", This, Type, ppQuery); + + hr = nine_is_query_supported(This->screen, Type); + if (!ppQuery || hr != D3D_OK) + return hr; + + 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, + bool ex, + D3DDISPLAYMODEEX *pFullscreenDisplayMode, + struct NineDevice9 **ppOut, + int minorVersionNum ) +{ + BOOL lock; + lock = !!(pCreationParameters->BehaviorFlags & D3DCREATE_MULTITHREADED); + + NINE_NEW(Device9, ppOut, lock, /* args */ + pScreen, pCreationParameters, pCaps, + pPresentationParameters, pD3D9, pPresentationGroup, pCTX, + ex, pFullscreenDisplayMode, minorVersionNum ); +} diff --git a/src/gallium/frontends/nine/device9.h b/src/gallium/frontends/nine/device9.h new file mode 100644 index 0000000..e6a736f --- /dev/null +++ b/src/gallium/frontends/nine/device9.h @@ -0,0 +1,848 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#ifndef _NINE_DEVICE9_H_ +#define _NINE_DEVICE9_H_ + +#include "d3dadapter/d3dadapter9.h" + +#include "iunknown.h" +#include "adapter9.h" + +#include "nine_helpers.h" +#include "nine_memory_helper.h" +#include "nine_state.h" + +struct gen_mipmap_state; +struct hash_table; +struct pipe_screen; +struct pipe_context; +struct cso_context; +struct hud_context; +struct u_upload_mgr; +struct csmt_context; + +struct NineSwapChain9; +struct NineStateBlock9; + +#include "util/list.h" + +struct NineDevice9 +{ + struct NineUnknown base; + bool ex; + bool may_swvp; + + /* G3D context */ + struct pipe_screen *screen; + /* For first time upload. No Sync with rendering thread */ + struct pipe_context *pipe_secondary; + struct pipe_screen *screen_sw; + struct pipe_context *pipe_sw; + struct cso_context *cso_sw; + + /* CSMT context */ + struct csmt_context *csmt_ctx; + BOOL csmt_active; + + /* For DISCARD/NOOVERWRITE */ + struct nine_buffer_upload *buffer_upload; + + /* 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 nine_context context; + struct nine_state_sw_internal state_sw_internal; + + struct list_head update_buffers; + struct list_head update_textures; + struct list_head managed_buffers; + struct list_head managed_textures; + + bool is_recording; + bool in_scene; + unsigned end_scene_since_present; + + uint16_t vs_const_size; + uint16_t ps_const_size; + uint16_t max_vs_const_f; + + struct pipe_resource *dummy_texture; + struct pipe_sampler_view *dummy_sampler_view; + struct pipe_sampler_state dummy_sampler_state; + + struct gen_mipmap_state *gen_mipmap; + + struct { + struct hash_table *ht_vs; + struct hash_table *ht_ps; + struct NineVertexShader9 *vs; + struct NinePixelShader9 *ps; + unsigned num_vs; + unsigned num_ps; + float *vs_const; + float *ps_const; + + struct 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; + bool software; + void *hw_upload_temp; + } cursor; + + struct { + bool user_sw_vbufs; + bool window_space_position_support; + bool disabling_depth_clipping_support; + bool vs_integer; + bool ps_integer; + bool offset_units_unscaled; + bool alpha_test_emulation; + bool always_output_pointsize; + bool emulate_ucp; + bool shader_emulate_features; + } driver_caps; + + struct { + bool buggy_barycentrics; + } driver_bugs; + + struct { + bool dynamic_texture_workaround; + } workarounds; + + struct u_upload_mgr *vertex_uploader; + + struct nine_range_pool range_pool; + + struct hud_context *hud; /* NULL if hud is disabled */ + + struct nine_allocator *allocator; + + /* dummy vbo (containing 0 0 0 0) to bind if vertex shader input + * is not bound to anything by the vertex declaration */ + struct pipe_resource *dummy_vbo; + struct pipe_resource *dummy_vbo_sw; + BOOL device_needs_reset; + int minor_version_num; + long long available_texture_mem; + long long available_texture_limit; + + /* software vertex processing */ + bool swvp; + /* pure device */ + bool pure; + + unsigned frame_count; /* It's ok if we overflow */ + + /* Ex */ + int gpu_priority; + unsigned max_frame_latency; +}; +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, + bool ex, + D3DDISPLAYMODEEX *pFullscreenDisplayMode, + struct NineDevice9 **ppOut, + int minorVersionNum ); + +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, + bool ex, + D3DDISPLAYMODEEX *pFullscreenDisplayMode, + int minorVersionNum ); + +void +NineDevice9_dtor( struct NineDevice9 *This ); + +/*** Nine private ***/ +struct pipe_resource * +nine_resource_create_with_retry( struct NineDevice9 *This, + struct pipe_screen *screen, + const struct pipe_resource *templat ); + +void +NineDevice9_SetDefaultState( struct NineDevice9 *This, bool is_reset ); + +struct pipe_screen * +NineDevice9_GetScreen( struct NineDevice9 *This ); + +struct pipe_context * +NineDevice9_GetPipe( struct NineDevice9 *This ); + +const D3DCAPS9 * +NineDevice9_GetCaps( struct NineDevice9 *This ); + +void +NineDevice9_EvictManagedResourcesInternal( struct NineDevice9 *This ); + +/*** Direct3D public ***/ + +HRESULT NINE_WINAPI +NineDevice9_TestCooperativeLevel( struct NineDevice9 *This ); + +UINT NINE_WINAPI +NineDevice9_GetAvailableTextureMem( struct NineDevice9 *This ); + +HRESULT NINE_WINAPI +NineDevice9_EvictManagedResources( struct NineDevice9 *This ); + +HRESULT NINE_WINAPI +NineDevice9_GetDirect3D( struct NineDevice9 *This, + IDirect3D9 **ppD3D9 ); + +HRESULT NINE_WINAPI +NineDevice9_GetDeviceCaps( struct NineDevice9 *This, + D3DCAPS9 *pCaps ); + +HRESULT NINE_WINAPI +NineDevice9_GetDisplayMode( struct NineDevice9 *This, + UINT iSwapChain, + D3DDISPLAYMODE *pMode ); + +HRESULT NINE_WINAPI +NineDevice9_GetCreationParameters( struct NineDevice9 *This, + D3DDEVICE_CREATION_PARAMETERS *pParameters ); + +HRESULT NINE_WINAPI +NineDevice9_SetCursorProperties( struct NineDevice9 *This, + UINT XHotSpot, + UINT YHotSpot, + IDirect3DSurface9 *pCursorBitmap ); + +void NINE_WINAPI +NineDevice9_SetCursorPosition( struct NineDevice9 *This, + int X, + int Y, + DWORD Flags ); + +BOOL NINE_WINAPI +NineDevice9_ShowCursor( struct NineDevice9 *This, + BOOL bShow ); + +HRESULT NINE_WINAPI +NineDevice9_CreateAdditionalSwapChain( struct NineDevice9 *This, + D3DPRESENT_PARAMETERS *pPresentationParameters, + IDirect3DSwapChain9 **pSwapChain ); + +HRESULT NINE_WINAPI +NineDevice9_GetSwapChain( struct NineDevice9 *This, + UINT iSwapChain, + IDirect3DSwapChain9 **pSwapChain ); + +UINT NINE_WINAPI +NineDevice9_GetNumberOfSwapChains( struct NineDevice9 *This ); + +HRESULT NINE_WINAPI +NineDevice9_Reset( struct NineDevice9 *This, + D3DPRESENT_PARAMETERS *pPresentationParameters ); + +HRESULT NINE_WINAPI +NineDevice9_Present( struct NineDevice9 *This, + const RECT *pSourceRect, + const RECT *pDestRect, + HWND hDestWindowOverride, + const RGNDATA *pDirtyRegion ); + +HRESULT NINE_WINAPI +NineDevice9_GetBackBuffer( struct NineDevice9 *This, + UINT iSwapChain, + UINT iBackBuffer, + D3DBACKBUFFER_TYPE Type, + IDirect3DSurface9 **ppBackBuffer ); + +HRESULT NINE_WINAPI +NineDevice9_GetRasterStatus( struct NineDevice9 *This, + UINT iSwapChain, + D3DRASTER_STATUS *pRasterStatus ); + +HRESULT NINE_WINAPI +NineDevice9_SetDialogBoxMode( struct NineDevice9 *This, + BOOL bEnableDialogs ); + +void NINE_WINAPI +NineDevice9_SetGammaRamp( struct NineDevice9 *This, + UINT iSwapChain, + DWORD Flags, + const D3DGAMMARAMP *pRamp ); + +void NINE_WINAPI +NineDevice9_GetGammaRamp( struct NineDevice9 *This, + UINT iSwapChain, + D3DGAMMARAMP *pRamp ); + +HRESULT NINE_WINAPI +NineDevice9_CreateTexture( struct NineDevice9 *This, + UINT Width, + UINT Height, + UINT Levels, + DWORD Usage, + D3DFORMAT Format, + D3DPOOL Pool, + IDirect3DTexture9 **ppTexture, + HANDLE *pSharedHandle ); + +HRESULT NINE_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 NINE_WINAPI +NineDevice9_CreateCubeTexture( struct NineDevice9 *This, + UINT EdgeLength, + UINT Levels, + DWORD Usage, + D3DFORMAT Format, + D3DPOOL Pool, + IDirect3DCubeTexture9 **ppCubeTexture, + HANDLE *pSharedHandle ); + +HRESULT NINE_WINAPI +NineDevice9_CreateVertexBuffer( struct NineDevice9 *This, + UINT Length, + DWORD Usage, + DWORD FVF, + D3DPOOL Pool, + IDirect3DVertexBuffer9 **ppVertexBuffer, + HANDLE *pSharedHandle ); + +HRESULT NINE_WINAPI +NineDevice9_CreateIndexBuffer( struct NineDevice9 *This, + UINT Length, + DWORD Usage, + D3DFORMAT Format, + D3DPOOL Pool, + IDirect3DIndexBuffer9 **ppIndexBuffer, + HANDLE *pSharedHandle ); + +HRESULT NINE_WINAPI +NineDevice9_CreateRenderTarget( struct NineDevice9 *This, + UINT Width, + UINT Height, + D3DFORMAT Format, + D3DMULTISAMPLE_TYPE MultiSample, + DWORD MultisampleQuality, + BOOL Lockable, + IDirect3DSurface9 **ppSurface, + HANDLE *pSharedHandle ); + +HRESULT NINE_WINAPI +NineDevice9_CreateDepthStencilSurface( struct NineDevice9 *This, + UINT Width, + UINT Height, + D3DFORMAT Format, + D3DMULTISAMPLE_TYPE MultiSample, + DWORD MultisampleQuality, + BOOL Discard, + IDirect3DSurface9 **ppSurface, + HANDLE *pSharedHandle ); + +HRESULT NINE_WINAPI +NineDevice9_UpdateSurface( struct NineDevice9 *This, + IDirect3DSurface9 *pSourceSurface, + const RECT *pSourceRect, + IDirect3DSurface9 *pDestinationSurface, + const POINT *pDestPoint ); + +HRESULT NINE_WINAPI +NineDevice9_UpdateTexture( struct NineDevice9 *This, + IDirect3DBaseTexture9 *pSourceTexture, + IDirect3DBaseTexture9 *pDestinationTexture ); + +HRESULT NINE_WINAPI +NineDevice9_GetRenderTargetData( struct NineDevice9 *This, + IDirect3DSurface9 *pRenderTarget, + IDirect3DSurface9 *pDestSurface ); + +HRESULT NINE_WINAPI +NineDevice9_GetFrontBufferData( struct NineDevice9 *This, + UINT iSwapChain, + IDirect3DSurface9 *pDestSurface ); + +HRESULT NINE_WINAPI +NineDevice9_StretchRect( struct NineDevice9 *This, + IDirect3DSurface9 *pSourceSurface, + const RECT *pSourceRect, + IDirect3DSurface9 *pDestSurface, + const RECT *pDestRect, + D3DTEXTUREFILTERTYPE Filter ); + +HRESULT NINE_WINAPI +NineDevice9_ColorFill( struct NineDevice9 *This, + IDirect3DSurface9 *pSurface, + const RECT *pRect, + D3DCOLOR color ); + +HRESULT NINE_WINAPI +NineDevice9_CreateOffscreenPlainSurface( struct NineDevice9 *This, + UINT Width, + UINT Height, + D3DFORMAT Format, + D3DPOOL Pool, + IDirect3DSurface9 **ppSurface, + HANDLE *pSharedHandle ); + +HRESULT NINE_WINAPI +NineDevice9_SetRenderTarget( struct NineDevice9 *This, + DWORD RenderTargetIndex, + IDirect3DSurface9 *pRenderTarget ); + +HRESULT NINE_WINAPI +NineDevice9_GetRenderTarget( struct NineDevice9 *This, + DWORD RenderTargetIndex, + IDirect3DSurface9 **ppRenderTarget ); + +HRESULT NINE_WINAPI +NineDevice9_SetDepthStencilSurface( struct NineDevice9 *This, + IDirect3DSurface9 *pNewZStencil ); + +HRESULT NINE_WINAPI +NineDevice9_GetDepthStencilSurface( struct NineDevice9 *This, + IDirect3DSurface9 **ppZStencilSurface ); + +HRESULT NINE_WINAPI +NineDevice9_BeginScene( struct NineDevice9 *This ); + +HRESULT NINE_WINAPI +NineDevice9_EndScene( struct NineDevice9 *This ); + +HRESULT NINE_WINAPI +NineDevice9_Clear( struct NineDevice9 *This, + DWORD Count, + const D3DRECT *pRects, + DWORD Flags, + D3DCOLOR Color, + float Z, + DWORD Stencil ); + +HRESULT NINE_WINAPI +NineDevice9_SetTransform( struct NineDevice9 *This, + D3DTRANSFORMSTATETYPE State, + const D3DMATRIX *pMatrix ); + +HRESULT NINE_WINAPI +NineDevice9_GetTransform( struct NineDevice9 *This, + D3DTRANSFORMSTATETYPE State, + D3DMATRIX *pMatrix ); + +HRESULT NINE_WINAPI +NineDevice9_MultiplyTransform( struct NineDevice9 *This, + D3DTRANSFORMSTATETYPE State, + const D3DMATRIX *pMatrix ); + +HRESULT NINE_WINAPI +NineDevice9_SetViewport( struct NineDevice9 *This, + const D3DVIEWPORT9 *pViewport ); + +HRESULT NINE_WINAPI +NineDevice9_GetViewport( struct NineDevice9 *This, + D3DVIEWPORT9 *pViewport ); + +HRESULT NINE_WINAPI +NineDevice9_SetMaterial( struct NineDevice9 *This, + const D3DMATERIAL9 *pMaterial ); + +HRESULT NINE_WINAPI +NineDevice9_GetMaterial( struct NineDevice9 *This, + D3DMATERIAL9 *pMaterial ); + +HRESULT NINE_WINAPI +NineDevice9_SetLight( struct NineDevice9 *This, + DWORD Index, + const D3DLIGHT9 *pLight ); + +HRESULT NINE_WINAPI +NineDevice9_GetLight( struct NineDevice9 *This, + DWORD Index, + D3DLIGHT9 *pLight ); + +HRESULT NINE_WINAPI +NineDevice9_LightEnable( struct NineDevice9 *This, + DWORD Index, + BOOL Enable ); + +HRESULT NINE_WINAPI +NineDevice9_GetLightEnable( struct NineDevice9 *This, + DWORD Index, + BOOL *pEnable ); + +HRESULT NINE_WINAPI +NineDevice9_SetClipPlane( struct NineDevice9 *This, + DWORD Index, + const float *pPlane ); + +HRESULT NINE_WINAPI +NineDevice9_GetClipPlane( struct NineDevice9 *This, + DWORD Index, + float *pPlane ); + +HRESULT NINE_WINAPI +NineDevice9_SetRenderState( struct NineDevice9 *This, + D3DRENDERSTATETYPE State, + DWORD Value ); + +HRESULT NINE_WINAPI +NineDevice9_GetRenderState( struct NineDevice9 *This, + D3DRENDERSTATETYPE State, + DWORD *pValue ); + +HRESULT NINE_WINAPI +NineDevice9_CreateStateBlock( struct NineDevice9 *This, + D3DSTATEBLOCKTYPE Type, + IDirect3DStateBlock9 **ppSB ); + +HRESULT NINE_WINAPI +NineDevice9_BeginStateBlock( struct NineDevice9 *This ); + +HRESULT NINE_WINAPI +NineDevice9_EndStateBlock( struct NineDevice9 *This, + IDirect3DStateBlock9 **ppSB ); + +HRESULT NINE_WINAPI +NineDevice9_SetClipStatus( struct NineDevice9 *This, + const D3DCLIPSTATUS9 *pClipStatus ); + +HRESULT NINE_WINAPI +NineDevice9_GetClipStatus( struct NineDevice9 *This, + D3DCLIPSTATUS9 *pClipStatus ); + +HRESULT NINE_WINAPI +NineDevice9_GetTexture( struct NineDevice9 *This, + DWORD Stage, + IDirect3DBaseTexture9 **ppTexture ); + +HRESULT NINE_WINAPI +NineDevice9_SetTexture( struct NineDevice9 *This, + DWORD Stage, + IDirect3DBaseTexture9 *pTexture ); + +HRESULT NINE_WINAPI +NineDevice9_GetTextureStageState( struct NineDevice9 *This, + DWORD Stage, + D3DTEXTURESTAGESTATETYPE Type, + DWORD *pValue ); + +HRESULT NINE_WINAPI +NineDevice9_SetTextureStageState( struct NineDevice9 *This, + DWORD Stage, + D3DTEXTURESTAGESTATETYPE Type, + DWORD Value ); + +HRESULT NINE_WINAPI +NineDevice9_GetSamplerState( struct NineDevice9 *This, + DWORD Sampler, + D3DSAMPLERSTATETYPE Type, + DWORD *pValue ); + +HRESULT NINE_WINAPI +NineDevice9_SetSamplerState( struct NineDevice9 *This, + DWORD Sampler, + D3DSAMPLERSTATETYPE Type, + DWORD Value ); + +HRESULT NINE_WINAPI +NineDevice9_ValidateDevice( struct NineDevice9 *This, + DWORD *pNumPasses ); + +HRESULT NINE_WINAPI +NineDevice9_SetPaletteEntries( struct NineDevice9 *This, + UINT PaletteNumber, + const PALETTEENTRY *pEntries ); + +HRESULT NINE_WINAPI +NineDevice9_GetPaletteEntries( struct NineDevice9 *This, + UINT PaletteNumber, + PALETTEENTRY *pEntries ); + +HRESULT NINE_WINAPI +NineDevice9_SetCurrentTexturePalette( struct NineDevice9 *This, + UINT PaletteNumber ); + +HRESULT NINE_WINAPI +NineDevice9_GetCurrentTexturePalette( struct NineDevice9 *This, + UINT *PaletteNumber ); + +HRESULT NINE_WINAPI +NineDevice9_SetScissorRect( struct NineDevice9 *This, + const RECT *pRect ); + +HRESULT NINE_WINAPI +NineDevice9_GetScissorRect( struct NineDevice9 *This, + RECT *pRect ); + +HRESULT NINE_WINAPI +NineDevice9_SetSoftwareVertexProcessing( struct NineDevice9 *This, + BOOL bSoftware ); + +BOOL NINE_WINAPI +NineDevice9_GetSoftwareVertexProcessing( struct NineDevice9 *This ); + +HRESULT NINE_WINAPI +NineDevice9_SetNPatchMode( struct NineDevice9 *This, + float nSegments ); + +float NINE_WINAPI +NineDevice9_GetNPatchMode( struct NineDevice9 *This ); + +HRESULT NINE_WINAPI +NineDevice9_DrawPrimitive( struct NineDevice9 *This, + D3DPRIMITIVETYPE PrimitiveType, + UINT StartVertex, + UINT PrimitiveCount ); + +HRESULT NINE_WINAPI +NineDevice9_DrawIndexedPrimitive( struct NineDevice9 *This, + D3DPRIMITIVETYPE PrimitiveType, + INT BaseVertexIndex, + UINT MinVertexIndex, + UINT NumVertices, + UINT startIndex, + UINT primCount ); + +HRESULT NINE_WINAPI +NineDevice9_DrawPrimitiveUP( struct NineDevice9 *This, + D3DPRIMITIVETYPE PrimitiveType, + UINT PrimitiveCount, + const void *pVertexStreamZeroData, + UINT VertexStreamZeroStride ); + +HRESULT NINE_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 NINE_WINAPI +NineDevice9_ProcessVertices( struct NineDevice9 *This, + UINT SrcStartIndex, + UINT DestIndex, + UINT VertexCount, + IDirect3DVertexBuffer9 *pDestBuffer, + IDirect3DVertexDeclaration9 *pVertexDecl, + DWORD Flags ); + +HRESULT NINE_WINAPI +NineDevice9_CreateVertexDeclaration( struct NineDevice9 *This, + const D3DVERTEXELEMENT9 *pVertexElements, + IDirect3DVertexDeclaration9 **ppDecl ); + +HRESULT NINE_WINAPI +NineDevice9_SetVertexDeclaration( struct NineDevice9 *This, + IDirect3DVertexDeclaration9 *pDecl ); + +HRESULT NINE_WINAPI +NineDevice9_GetVertexDeclaration( struct NineDevice9 *This, + IDirect3DVertexDeclaration9 **ppDecl ); + +HRESULT NINE_WINAPI +NineDevice9_SetFVF( struct NineDevice9 *This, + DWORD FVF ); + +HRESULT NINE_WINAPI +NineDevice9_GetFVF( struct NineDevice9 *This, + DWORD *pFVF ); + +HRESULT NINE_WINAPI +NineDevice9_CreateVertexShader( struct NineDevice9 *This, + const DWORD *pFunction, + IDirect3DVertexShader9 **ppShader ); + +HRESULT NINE_WINAPI +NineDevice9_SetVertexShader( struct NineDevice9 *This, + IDirect3DVertexShader9 *pShader ); + +HRESULT NINE_WINAPI +NineDevice9_GetVertexShader( struct NineDevice9 *This, + IDirect3DVertexShader9 **ppShader ); + +HRESULT NINE_WINAPI +NineDevice9_SetVertexShaderConstantF( struct NineDevice9 *This, + UINT StartRegister, + const float *pConstantData, + UINT Vector4fCount ); + +HRESULT NINE_WINAPI +NineDevice9_GetVertexShaderConstantF( struct NineDevice9 *This, + UINT StartRegister, + float *pConstantData, + UINT Vector4fCount ); + +HRESULT NINE_WINAPI +NineDevice9_SetVertexShaderConstantI( struct NineDevice9 *This, + UINT StartRegister, + const int *pConstantData, + UINT Vector4iCount ); + +HRESULT NINE_WINAPI +NineDevice9_GetVertexShaderConstantI( struct NineDevice9 *This, + UINT StartRegister, + int *pConstantData, + UINT Vector4iCount ); + +HRESULT NINE_WINAPI +NineDevice9_SetVertexShaderConstantB( struct NineDevice9 *This, + UINT StartRegister, + const BOOL *pConstantData, + UINT BoolCount ); + +HRESULT NINE_WINAPI +NineDevice9_GetVertexShaderConstantB( struct NineDevice9 *This, + UINT StartRegister, + BOOL *pConstantData, + UINT BoolCount ); + +HRESULT NINE_WINAPI +NineDevice9_SetStreamSource( struct NineDevice9 *This, + UINT StreamNumber, + IDirect3DVertexBuffer9 *pStreamData, + UINT OffsetInBytes, + UINT Stride ); + +HRESULT NINE_WINAPI +NineDevice9_GetStreamSource( struct NineDevice9 *This, + UINT StreamNumber, + IDirect3DVertexBuffer9 **ppStreamData, + UINT *pOffsetInBytes, + UINT *pStride ); + +HRESULT NINE_WINAPI +NineDevice9_SetStreamSourceFreq( struct NineDevice9 *This, + UINT StreamNumber, + UINT Setting ); + +HRESULT NINE_WINAPI +NineDevice9_GetStreamSourceFreq( struct NineDevice9 *This, + UINT StreamNumber, + UINT *pSetting ); + +HRESULT NINE_WINAPI +NineDevice9_SetIndices( struct NineDevice9 *This, + IDirect3DIndexBuffer9 *pIndexData ); + +HRESULT NINE_WINAPI +NineDevice9_GetIndices( struct NineDevice9 *This, + IDirect3DIndexBuffer9 **ppIndexData /*, + UINT *pBaseVertexIndex */ ); + +HRESULT NINE_WINAPI +NineDevice9_CreatePixelShader( struct NineDevice9 *This, + const DWORD *pFunction, + IDirect3DPixelShader9 **ppShader ); + +HRESULT NINE_WINAPI +NineDevice9_SetPixelShader( struct NineDevice9 *This, + IDirect3DPixelShader9 *pShader ); + +HRESULT NINE_WINAPI +NineDevice9_GetPixelShader( struct NineDevice9 *This, + IDirect3DPixelShader9 **ppShader ); + +HRESULT NINE_WINAPI +NineDevice9_SetPixelShaderConstantF( struct NineDevice9 *This, + UINT StartRegister, + const float *pConstantData, + UINT Vector4fCount ); + +HRESULT NINE_WINAPI +NineDevice9_GetPixelShaderConstantF( struct NineDevice9 *This, + UINT StartRegister, + float *pConstantData, + UINT Vector4fCount ); + +HRESULT NINE_WINAPI +NineDevice9_SetPixelShaderConstantI( struct NineDevice9 *This, + UINT StartRegister, + const int *pConstantData, + UINT Vector4iCount ); + +HRESULT NINE_WINAPI +NineDevice9_GetPixelShaderConstantI( struct NineDevice9 *This, + UINT StartRegister, + int *pConstantData, + UINT Vector4iCount ); + +HRESULT NINE_WINAPI +NineDevice9_SetPixelShaderConstantB( struct NineDevice9 *This, + UINT StartRegister, + const BOOL *pConstantData, + UINT BoolCount ); + +HRESULT NINE_WINAPI +NineDevice9_GetPixelShaderConstantB( struct NineDevice9 *This, + UINT StartRegister, + BOOL *pConstantData, + UINT BoolCount ); + +HRESULT NINE_WINAPI +NineDevice9_DrawRectPatch( struct NineDevice9 *This, + UINT Handle, + const float *pNumSegs, + const D3DRECTPATCH_INFO *pRectPatchInfo ); + +HRESULT NINE_WINAPI +NineDevice9_DrawTriPatch( struct NineDevice9 *This, + UINT Handle, + const float *pNumSegs, + const D3DTRIPATCH_INFO *pTriPatchInfo ); + +HRESULT NINE_WINAPI +NineDevice9_DeletePatch( struct NineDevice9 *This, + UINT Handle ); + +HRESULT NINE_WINAPI +NineDevice9_CreateQuery( struct NineDevice9 *This, + D3DQUERYTYPE Type, + IDirect3DQuery9 **ppQuery ); + +#endif /* _NINE_DEVICE9_H_ */ diff --git a/src/gallium/frontends/nine/device9ex.c b/src/gallium/frontends/nine/device9ex.c new file mode 100644 index 0000000..06f0c3f --- /dev/null +++ b/src/gallium/frontends/nine/device9ex.c @@ -0,0 +1,517 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#include "device9.h" +#include "device9ex.h" +#include "nine_pipe.h" +#include "swapchain9ex.h" + +#include "nine_helpers.h" + +#include "util/macros.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, + int minorVersionNum ) +{ + DBG("This=%p pParams=%p pScreen=%p pCreationParameters=%p pCaps=%p " + "pPresentationParameters=%p pFullscreenDisplayMode=%p " + "pD3D9Ex=%p pPresentationGroup=%p pCTX=%p\n", + This, pParams, pScreen, pCreationParameters, pCaps, + pPresentationParameters, pFullscreenDisplayMode, + pD3D9Ex, pPresentationGroup, pCTX); + + return NineDevice9_ctor(&This->base, pParams, + pScreen, pCreationParameters, pCaps, + pPresentationParameters, + (IDirect3D9 *)pD3D9Ex, pPresentationGroup, pCTX, + true, pFullscreenDisplayMode, minorVersionNum); +} + +static void +NineDevice9Ex_dtor( struct NineDevice9Ex *This ) +{ + NineDevice9_dtor(&This->base); +} + +HRESULT NINE_WINAPI +NineDevice9Ex_SetConvolutionMonoKernel( UNUSED struct NineDevice9Ex *This, + UNUSED UINT width, + UNUSED UINT height, + UNUSED float *rows, + UNUSED float *columns ) +{ + DBG("This\n"); + STUB(D3D_OK); +} + +HRESULT NINE_WINAPI +NineDevice9Ex_ComposeRects( UNUSED struct NineDevice9Ex *This, + UNUSED IDirect3DSurface9 *pSrc, + UNUSED IDirect3DSurface9 *pDst, + UNUSED IDirect3DVertexBuffer9 *pSrcRectDescs, + UNUSED UINT NumRects, + UNUSED IDirect3DVertexBuffer9 *pDstRectDescs, + UNUSED D3DCOMPOSERECTSOP Operation, + UNUSED int Xoffset, + UNUSED int Yoffset ) +{ + DBG("This\n"); + STUB(D3D_OK); +} + +HRESULT NINE_WINAPI +NineDevice9Ex_PresentEx( struct NineDevice9Ex *This, + const RECT *pSourceRect, + const RECT *pDestRect, + HWND hDestWindowOverride, + const RGNDATA *pDirtyRegion, + DWORD dwFlags ) +{ + unsigned i; + HRESULT hr; + + DBG("This=%p pSourceRect=%p pDestRect=%p hDestWindowOverride=%p " + "pDirtyRegion=%p dwFlags=%d\n", + This, pSourceRect, pDestRect, hDestWindowOverride, + pDirtyRegion, dwFlags); + + 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 NINE_WINAPI +NineDevice9Ex_GetGPUThreadPriority( struct NineDevice9Ex *This, + INT *pPriority ) +{ + DBG("This\n"); + user_assert(pPriority != NULL, D3DERR_INVALIDCALL); + *pPriority = This->base.gpu_priority; + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9Ex_SetGPUThreadPriority( struct NineDevice9Ex *This, + INT Priority ) +{ + DBG("This\n"); + user_assert(Priority >= -7 && Priority <= 7, D3DERR_INVALIDCALL); + This->base.gpu_priority = Priority; + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9Ex_WaitForVBlank( UNUSED struct NineDevice9Ex *This, + UNUSED UINT iSwapChain ) +{ + DBG("This\n"); + STUB(D3D_OK); +} + +HRESULT NINE_WINAPI +NineDevice9Ex_CheckResourceResidency( UNUSED struct NineDevice9Ex *This, + UNUSED IDirect3DResource9 **pResourceArray, + UNUSED UINT32 NumResources ) +{ + DBG("This\n"); + STUB(D3D_OK); +} + +HRESULT NINE_WINAPI +NineDevice9Ex_SetMaximumFrameLatency( struct NineDevice9Ex *This, + UINT MaxLatency ) +{ + DBG("This\n"); + This->base.max_frame_latency = MaxLatency; + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9Ex_GetMaximumFrameLatency( struct NineDevice9Ex *This, + UINT *pMaxLatency ) +{ + DBG("This\n"); + user_assert(pMaxLatency != NULL, D3DERR_INVALIDCALL); + *pMaxLatency = This->base.max_frame_latency; + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9Ex_CheckDeviceState( struct NineDevice9Ex *This, + HWND hDestinationWindow ) +{ + DBG("This=%p hDestinationWindow=%p\n", + This, hDestinationWindow); + + user_assert(!This->base.swapchains[0]->params.Windowed, D3D_OK); + + if (This->base.params.hFocusWindow == hDestinationWindow) { + if (NineSwapChain9_GetOccluded(This->base.swapchains[0])) + return S_PRESENT_OCCLUDED; + } else if(!NineSwapChain9_GetOccluded(This->base.swapchains[0])) { + return S_PRESENT_OCCLUDED; + } + /* TODO: handle the other return values */ + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineDevice9Ex_CreateRenderTargetEx( struct NineDevice9Ex *This, + UINT Width, + UINT Height, + D3DFORMAT Format, + D3DMULTISAMPLE_TYPE MultiSample, + DWORD MultisampleQuality, + BOOL Lockable, + IDirect3DSurface9 **ppSurface, + HANDLE *pSharedHandle, + UNUSED DWORD Usage ) +{ + DBG("This\n"); + /* The Create*Ex functions only purpose seem to introduce the + * Usage field, to pass the new d3d9ex flags on secure/restricted + * content. + * TODO: Return error on invalid Usage. + * TODO: Store Usage in the surface descriptor, in case the + * app checks */ + return NineDevice9_CreateRenderTarget(&This->base, + Width, + Height, + Format, + MultiSample, + MultisampleQuality, + Lockable, + ppSurface, + pSharedHandle); +} + +HRESULT NINE_WINAPI +NineDevice9Ex_CreateOffscreenPlainSurfaceEx( struct NineDevice9Ex *This, + UINT Width, + UINT Height, + D3DFORMAT Format, + D3DPOOL Pool, + IDirect3DSurface9 **ppSurface, + HANDLE *pSharedHandle, + UNUSED DWORD Usage ) +{ + DBG("This\n"); + /* The Create*Ex functions only purpose seem to introduce the + * Usage field, to pass the new d3d9ex flags on secure/restricted + * content. + * TODO: Return error on invalid Usage. + * TODO: Store Usage in the surface descriptor, in case the + * app checks */ + return NineDevice9_CreateOffscreenPlainSurface(&This->base, + Width, + Height, + Format, + Pool, + ppSurface, + pSharedHandle); +} + +HRESULT NINE_WINAPI +NineDevice9Ex_CreateDepthStencilSurfaceEx( struct NineDevice9Ex *This, + UINT Width, + UINT Height, + D3DFORMAT Format, + D3DMULTISAMPLE_TYPE MultiSample, + DWORD MultisampleQuality, + BOOL Discard, + IDirect3DSurface9 **ppSurface, + HANDLE *pSharedHandle, + UNUSED DWORD Usage ) +{ + DBG("This\n"); + /* The Create*Ex functions only purpose seem to introduce the + * Usage field, to pass the new d3d9ex flags on secure/restricted + * content. + * TODO: Return error on invalid Usage. + * TODO: Store Usage in the surface descriptor, in case the + * app checks */ + return NineDevice9_CreateDepthStencilSurface(&This->base, + Width, + Height, + Format, + MultiSample, + MultisampleQuality, + Discard, + ppSurface, + pSharedHandle); +} + +HRESULT NINE_WINAPI +NineDevice9Ex_ResetEx( struct NineDevice9Ex *This, + D3DPRESENT_PARAMETERS *pPresentationParameters, + D3DDISPLAYMODEEX *pFullscreenDisplayMode ) +{ + HRESULT hr = D3D_OK; + float MinZ, MaxZ; + 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)) + break; + } + + MinZ = This->base.state.viewport.MinZ; /* These are preserved */ + MaxZ = This->base.state.viewport.MaxZ; + NineDevice9_SetRenderTarget( + (struct NineDevice9 *)This, 0, (IDirect3DSurface9 *)This->base.swapchains[0]->buffers[0]); + This->base.state.viewport.MinZ = MinZ; + This->base.state.viewport.MaxZ = MaxZ; + nine_context_set_viewport(&This->base, &This->base.state.viewport); + + if (This->base.nswapchains && This->base.swapchains[0]->params.EnableAutoDepthStencil) + NineDevice9_SetDepthStencilSurface( + &This->base, (IDirect3DSurface9 *)This->base.swapchains[0]->zsbuf); + + return hr; +} + +HRESULT NINE_WINAPI +NineDevice9Ex_Reset( struct NineDevice9Ex *This, + D3DPRESENT_PARAMETERS *pPresentationParameters ) +{ + HRESULT hr = D3D_OK; + float MinZ, MaxZ; + unsigned i; + + DBG("This=%p pPresentationParameters=%p\n", This, pPresentationParameters); + + for (i = 0; i < This->base.nswapchains; ++i) { + D3DPRESENT_PARAMETERS *params = &pPresentationParameters[i]; + hr = NineSwapChain9_Resize(This->base.swapchains[i], params, NULL); + if (FAILED(hr)) + break; + } + + MinZ = This->base.state.viewport.MinZ; /* These are preserved */ + MaxZ = This->base.state.viewport.MaxZ; + NineDevice9_SetRenderTarget( + (struct NineDevice9 *)This, 0, (IDirect3DSurface9 *)This->base.swapchains[0]->buffers[0]); + This->base.state.viewport.MinZ = MinZ; + This->base.state.viewport.MaxZ = MaxZ; + nine_context_set_viewport(&This->base, &This->base.state.viewport); + + if (This->base.nswapchains && This->base.swapchains[0]->params.EnableAutoDepthStencil) + NineDevice9_SetDepthStencilSurface( + &This->base, (IDirect3DSurface9 *)This->base.swapchains[0]->zsbuf); + + return hr; +} + +HRESULT NINE_WINAPI +NineDevice9Ex_GetDisplayModeEx( struct NineDevice9Ex *This, + UINT iSwapChain, + D3DDISPLAYMODEEX *pMode, + D3DDISPLAYROTATION *pRotation ) +{ + struct NineSwapChain9Ex *swapchain; + + DBG("This=%p iSwapChain=%u pMode=%p pRotation=%p\n", + This, iSwapChain, pMode, pRotation); + + user_assert(iSwapChain < This->base.nswapchains, D3DERR_INVALIDCALL); + + swapchain = NineSwapChain9Ex(This->base.swapchains[iSwapChain]); + return NineSwapChain9Ex_GetDisplayModeEx(swapchain, pMode, pRotation); +} + +HRESULT NINE_WINAPI +NineDevice9Ex_TestCooperativeLevel( UNUSED struct NineDevice9Ex *This ) +{ + DBG("This\n"); + return D3D_OK; +} + + +IDirect3DDevice9ExVtbl NineDevice9Ex_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineDevice9Ex_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 *)NineDevice9Ex_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, + int minorVersionNum ) +{ + BOOL lock; + lock = !!(pCreationParameters->BehaviorFlags & D3DCREATE_MULTITHREADED); + + NINE_NEW(Device9Ex, ppOut, lock, + pScreen, pCreationParameters, pCaps, pPresentationParameters, + pFullscreenDisplayMode, pD3D9Ex, pPresentationGroup, pCTX, minorVersionNum ); +} + diff --git a/src/gallium/frontends/nine/device9ex.h b/src/gallium/frontends/nine/device9ex.h new file mode 100644 index 0000000..9fd1f22 --- /dev/null +++ b/src/gallium/frontends/nine/device9ex.h @@ -0,0 +1,147 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#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, + int minorVersionNum ); + +HRESULT NINE_WINAPI +NineDevice9Ex_SetConvolutionMonoKernel( struct NineDevice9Ex *This, + UINT width, + UINT height, + float *rows, + float *columns ); + +HRESULT NINE_WINAPI +NineDevice9Ex_ComposeRects( struct NineDevice9Ex *This, + IDirect3DSurface9 *pSrc, + IDirect3DSurface9 *pDst, + IDirect3DVertexBuffer9 *pSrcRectDescs, + UINT NumRects, + IDirect3DVertexBuffer9 *pDstRectDescs, + D3DCOMPOSERECTSOP Operation, + int Xoffset, + int Yoffset ); + +HRESULT NINE_WINAPI +NineDevice9Ex_PresentEx( struct NineDevice9Ex *This, + const RECT *pSourceRect, + const RECT *pDestRect, + HWND hDestWindowOverride, + const RGNDATA *pDirtyRegion, + DWORD dwFlags ); + +HRESULT NINE_WINAPI +NineDevice9Ex_Present( struct NineDevice9Ex *This, + const RECT *pSourceRect, + const RECT *pDestRect, + HWND hDestWindowOverride, + const RGNDATA *pDirtyRegion ); + +HRESULT NINE_WINAPI +NineDevice9Ex_GetGPUThreadPriority( struct NineDevice9Ex *This, + INT *pPriority ); + +HRESULT NINE_WINAPI +NineDevice9Ex_SetGPUThreadPriority( struct NineDevice9Ex *This, + INT Priority ); + +HRESULT NINE_WINAPI +NineDevice9Ex_WaitForVBlank( struct NineDevice9Ex *This, + UINT iSwapChain ); + +HRESULT NINE_WINAPI +NineDevice9Ex_CheckResourceResidency( struct NineDevice9Ex *This, + IDirect3DResource9 **pResourceArray, + UINT32 NumResources ); + +HRESULT NINE_WINAPI +NineDevice9Ex_SetMaximumFrameLatency( struct NineDevice9Ex *This, + UINT MaxLatency ); + +HRESULT NINE_WINAPI +NineDevice9Ex_GetMaximumFrameLatency( struct NineDevice9Ex *This, + UINT *pMaxLatency ); + +HRESULT NINE_WINAPI +NineDevice9Ex_CheckDeviceState( struct NineDevice9Ex *This, + HWND hDestinationWindow ); + +HRESULT NINE_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 NINE_WINAPI +NineDevice9Ex_CreateOffscreenPlainSurfaceEx( struct NineDevice9Ex *This, + UINT Width, + UINT Height, + D3DFORMAT Format, + D3DPOOL Pool, + IDirect3DSurface9 **ppSurface, + HANDLE *pSharedHandle, + DWORD Usage ); + +HRESULT NINE_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 NINE_WINAPI +NineDevice9Ex_ResetEx( struct NineDevice9Ex *This, + D3DPRESENT_PARAMETERS *pPresentationParameters, + D3DDISPLAYMODEEX *pFullscreenDisplayMode ); + +HRESULT NINE_WINAPI +NineDevice9Ex_Reset( struct NineDevice9Ex *This, + D3DPRESENT_PARAMETERS *pPresentationParameters ); + +HRESULT NINE_WINAPI +NineDevice9Ex_GetDisplayModeEx( struct NineDevice9Ex *This, + UINT iSwapChain, + D3DDISPLAYMODEEX *pMode, + D3DDISPLAYROTATION *pRotation ); + +HRESULT NINE_WINAPI +NineDevice9Ex_TestCooperativeLevel( struct NineDevice9Ex *This ); + +#endif /* _NINE_DEVICE9EX_H_ */ diff --git a/src/gallium/frontends/nine/device9video.c b/src/gallium/frontends/nine/device9video.c new file mode 100644 index 0000000..73668b5 --- /dev/null +++ b/src/gallium/frontends/nine/device9video.c @@ -0,0 +1,45 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#include "device9video.h" + +#define DBG_CHANNEL DBG_DEVICEVIDEO + +HRESULT NINE_WINAPI +NineDevice9Video_GetContentProtectionCaps( struct NineDevice9Video *This, + const GUID *pCryptoType, + const GUID *pDecodeProfile, + D3DCONTENTPROTECTIONCAPS *pCaps ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT NINE_WINAPI +NineDevice9Video_CreateAuthenticatedChannel( struct NineDevice9Video *This, + D3DAUTHENTICATEDCHANNELTYPE ChannelType, + IDirect3DAuthenticatedChannel9 **ppAuthenticatedChannel, + HANDLE *pChannelHandle ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT NINE_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/frontends/nine/device9video.h b/src/gallium/frontends/nine/device9video.h new file mode 100644 index 0000000..5280e97 --- /dev/null +++ b/src/gallium/frontends/nine/device9video.h @@ -0,0 +1,40 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#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 NINE_WINAPI +NineDevice9Video_GetContentProtectionCaps( struct NineDevice9Video *This, + const GUID *pCryptoType, + const GUID *pDecodeProfile, + D3DCONTENTPROTECTIONCAPS *pCaps ); + +HRESULT NINE_WINAPI +NineDevice9Video_CreateAuthenticatedChannel( struct NineDevice9Video *This, + D3DAUTHENTICATEDCHANNELTYPE ChannelType, + IDirect3DAuthenticatedChannel9 **ppAuthenticatedChannel, + HANDLE *pChannelHandle ); + +HRESULT NINE_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/frontends/nine/guid.c b/src/gallium/frontends/nine/guid.c new file mode 100644 index 0000000..bd865a7 --- /dev/null +++ b/src/gallium/frontends/nine/guid.c @@ -0,0 +1,67 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#include +#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 } }; + +bool +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; +} + +char* GUID_sprintf(char *guid_str, REFGUID id) { + sprintf( guid_str, + "{%08X,%04X,%04X,%02X%02X%02X%02X%02X%02X%02X%02X}", + id->Data1, + id->Data2, + id->Data3, + id->Data4[0], + id->Data4[1], + id->Data4[2], + id->Data4[3], + id->Data4[4], + id->Data4[5], + id->Data4[6], + id->Data4[7]); + return guid_str; +} diff --git a/src/gallium/frontends/nine/guid.h b/src/gallium/frontends/nine/guid.h new file mode 100644 index 0000000..361dd5e --- /dev/null +++ b/src/gallium/frontends/nine/guid.h @@ -0,0 +1,23 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#ifndef _NINE_GUID_H_ +#define _NINE_GUID_H_ + +#include "util/compiler.h" + +#include "d3d9types.h" + +extern const GUID IID_ID3D9Adapter; + +bool +GUID_equal( const GUID *a, + const GUID *b ); + +char* +GUID_sprintf( char *guid_str, + REFGUID id ); + +#endif /* _NINE_GUID_H_ */ diff --git a/src/gallium/frontends/nine/indexbuffer9.c b/src/gallium/frontends/nine/indexbuffer9.c new file mode 100644 index 0000000..e4c5005 --- /dev/null +++ b/src/gallium/frontends/nine/indexbuffer9.c @@ -0,0 +1,117 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#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 "util/format/u_formats.h" +#include "util/box.h" + +#define DBG_CHANNEL DBG_INDEXBUFFER + +HRESULT +NineIndexBuffer9_ctor( struct NineIndexBuffer9 *This, + struct NineUnknownParams *pParams, + D3DINDEXBUFFER_DESC *pDesc ) +{ + HRESULT hr; + DBG("This=%p pParams=%p pDesc=%p Usage=%s\n", + This, pParams, pDesc, nine_D3DUSAGE_to_str(pDesc->Usage)); + + hr = NineBuffer9_ctor(&This->base, pParams, D3DRTYPE_INDEXBUFFER, + pDesc->Usage, pDesc->Size, pDesc->Pool); + if (FAILED(hr)) + return hr; + + switch (pDesc->Format) { + case D3DFMT_INDEX16: This->index_size = 2; break; + case D3DFMT_INDEX32: This->index_size = 4; break; + default: + user_assert(!"Invalid index format.", D3DERR_INVALIDCALL); + break; + } + + pDesc->Type = D3DRTYPE_INDEXBUFFER; + This->desc = *pDesc; + + return D3D_OK; +} + +void +NineIndexBuffer9_dtor( struct NineIndexBuffer9 *This ) +{ + NineBuffer9_dtor(&This->base); +} + +struct pipe_resource * +NineIndexBuffer9_GetBuffer( struct NineIndexBuffer9 *This, unsigned *offset ) +{ + /* The resource may change */ + return NineBuffer9_GetResource(&This->base, offset); +} + +HRESULT NINE_WINAPI +NineIndexBuffer9_Lock( struct NineIndexBuffer9 *This, + UINT OffsetToLock, + UINT SizeToLock, + void **ppbData, + DWORD Flags ) +{ + return NineBuffer9_Lock(&This->base, OffsetToLock, SizeToLock, ppbData, Flags); +} + +HRESULT NINE_WINAPI +NineIndexBuffer9_Unlock( struct NineIndexBuffer9 *This ) +{ + return NineBuffer9_Unlock(&This->base); +} + +HRESULT NINE_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 *)NineUnknown_SetPrivateData, + (void *)NineUnknown_GetPrivateData, + (void *)NineUnknown_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/frontends/nine/indexbuffer9.h b/src/gallium/frontends/nine/indexbuffer9.h new file mode 100644 index 0000000..1b72cbd --- /dev/null +++ b/src/gallium/frontends/nine/indexbuffer9.h @@ -0,0 +1,68 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#ifndef _NINE_INDEXBUFFER9_H_ +#define _NINE_INDEXBUFFER9_H_ + +#include "resource9.h" +#include "buffer9.h" +#include "pipe/p_state.h" + +struct pipe_screen; +struct pipe_context; +struct pipe_transfer; +struct NineDevice9; + +struct NineIndexBuffer9 +{ + struct NineBuffer9 base; + + /* g3d stuff */ + unsigned index_size; + + 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 ***/ + +struct pipe_resource * +NineIndexBuffer9_GetBuffer( struct NineIndexBuffer9 *This, + unsigned *offset ); + +/*** Direct3D public ***/ + +HRESULT NINE_WINAPI +NineIndexBuffer9_Lock( struct NineIndexBuffer9 *This, + UINT OffsetToLock, + UINT SizeToLock, + void **ppbData, + DWORD Flags ); + +HRESULT NINE_WINAPI +NineIndexBuffer9_Unlock( struct NineIndexBuffer9 *This ); + +HRESULT NINE_WINAPI +NineIndexBuffer9_GetDesc( struct NineIndexBuffer9 *This, + D3DINDEXBUFFER_DESC *pDesc ); + +#endif /* _NINE_INDEXBUFFER9_H_ */ diff --git a/src/gallium/frontends/nine/iunknown.c b/src/gallium/frontends/nine/iunknown.c new file mode 100644 index 0000000..25a86f0 --- /dev/null +++ b/src/gallium/frontends/nine/iunknown.c @@ -0,0 +1,293 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#include "iunknown.h" +#include "util/u_atomic.h" +#include "util/hash_table.h" + +#include "nine_helpers.h" +#include "nine_pdata.h" +#include "nine_lock.h" + +#define DBG_CHANNEL DBG_UNKNOWN + +HRESULT +NineUnknown_ctor( struct NineUnknown *This, + struct NineUnknownParams *pParams ) +{ + if (pParams->container) { + This->refs = 0; + This->forward = true; + This->bind = 0; + assert(!pParams->start_with_bind_not_ref); + } else if (pParams->start_with_bind_not_ref) { + This->refs = 0; + This->forward = false; + This->bind = 1; + } else { + This->refs = 1; + This->forward = false; + This->bind = 0; + } + This->has_bind_or_refs = This->bind + 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->vtable_internal = pParams->vtable; + This->guids = pParams->guids; + This->dtor = pParams->dtor; + + This->pdata = _mesa_hash_table_create(NULL, ht_guid_hash, ht_guid_compare); + if (!This->pdata) + return E_OUTOFMEMORY; + + return D3D_OK; +} + +void +NineUnknown_dtor( struct NineUnknown *This ) +{ + if (This->refs && This->device) /* Possible only if early exit after a ctor failed */ + (void) NineUnknown_Release(NineUnknown(This->device)); + + if (This->pdata) + _mesa_hash_table_destroy(This->pdata, ht_guid_delete); + + FREE(This); +} + +HRESULT NINE_WINAPI +NineUnknown_QueryInterface( struct NineUnknown *This, + REFIID riid, + void **ppvObject ) +{ + unsigned i = 0; + char guid_str[64]; + + DBG("This=%p riid=%p id=%s ppvObject=%p\n", + This, riid, riid ? GUID_sprintf(guid_str, riid) : "", ppvObject); + + (void)guid_str; + + if (!ppvObject) return E_POINTER; + + do { + if (GUID_equal(This->guids[i], riid)) { + *ppvObject = This; + /* Tests showed that this call succeeds even on objects with + * zero refcount. This can happen if the app released all references + * but the resource is still bound. + */ + NineUnknown_AddRef(This); + return S_OK; + } + } while (This->guids[++i]); + + *ppvObject = NULL; + return E_NOINTERFACE; +} + +ULONG NINE_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) { + p_atomic_inc(&This->has_bind_or_refs); + if (This->device) + NineUnknown_AddRef(NineUnknown(This->device)); + } + return r; +} + +ULONG NINE_WINAPI +NineUnknown_Release( struct NineUnknown *This ) +{ + if (This->forward) + return NineUnknown_Release(This->container); + + /* Cannot decrease lower than 0. This is a thing + * according to wine tests. It's not just clamping + * the result as AddRef after Release while refs is 0 + * will give 1 */ + if (!p_atomic_read(&This->refs)) + return 0; + + ULONG r = p_atomic_dec_return(&This->refs); + + if (r == 0) { + struct NineDevice9 *device = This->device; + UINT b_or_ref = p_atomic_dec_return(&This->has_bind_or_refs); + /* Containers (here with !forward) take care of item destruction */ + + if (!This->container && b_or_ref == 0) { + assert(p_atomic_read(&This->bind) == 0); + This->dtor(This); + } + if (device) { + NineUnknown_Release(NineUnknown(device)); + } + } + return r; +} + +/* No need to lock the mutex protecting nine (when D3DCREATE_MULTITHREADED) + * for AddRef and Release, except for dtor as some of the dtors require it. */ +ULONG NINE_WINAPI +NineUnknown_ReleaseWithDtorLock( struct NineUnknown *This ) +{ + if (This->forward) + return NineUnknown_ReleaseWithDtorLock(This->container); + + ULONG r = p_atomic_dec_return(&This->refs); + + if (r == 0) { + struct NineDevice9 *device = This->device; + UINT b_or_ref = p_atomic_dec_return(&This->has_bind_or_refs); + /* Containers (here with !forward) take care of item destruction */ + if (!This->container && b_or_ref == 0) { + assert(p_atomic_read(&This->bind) == 0); + NineLockGlobalMutex(); + This->dtor(This); + NineUnlockGlobalMutex(); + } + if (device) { + NineUnknown_ReleaseWithDtorLock(NineUnknown(device)); + } + } + return r; +} + +HRESULT NINE_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; +} + +HRESULT NINE_WINAPI +NineUnknown_SetPrivateData( struct NineUnknown *This, + REFGUID refguid, + const void *pData, + DWORD SizeOfData, + DWORD Flags ) +{ + struct pheader *header; + const void *user_data = pData; + char guid_str[64]; + void *header_data; + + DBG("This=%p GUID=%s pData=%p SizeOfData=%u Flags=%x\n", + This, GUID_sprintf(guid_str, refguid), pData, SizeOfData, Flags); + + (void)guid_str; + + 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); + if (!header) { DBG("Returning E_OUTOFMEMORY\n"); return E_OUTOFMEMORY; } + header->unknown = (Flags & D3DSPD_IUNKNOWN) ? true : false; + + /* if the refguid already exists, delete it */ + NineUnknown_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; + header_data = (void *)header + sizeof(*header); + memcpy(header_data, user_data, header->size); + memcpy(&header->guid, refguid, sizeof(header->guid)); + + DBG("New header %p, size %d\n", header, (int)header->size); + _mesa_hash_table_insert(This->pdata, &header->guid, header); + if (header->unknown) { IUnknown_AddRef(*(IUnknown **)header_data); } + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineUnknown_GetPrivateData( struct NineUnknown *This, + REFGUID refguid, + void *pData, + DWORD *pSizeOfData ) +{ + struct hash_entry *entry; + struct pheader *header; + DWORD sizeofdata; + char guid_str[64]; + void *header_data; + + DBG("This=%p GUID=%s pData=%p pSizeOfData=%p\n", + This, GUID_sprintf(guid_str, refguid), pData, pSizeOfData); + + (void)guid_str; + + entry = _mesa_hash_table_search(This->pdata, refguid); + if (!entry) { DBG("Returning D3DERR_NOTFOUND\n"); return D3DERR_NOTFOUND; } + + header = entry->data; + + user_assert(pSizeOfData, E_POINTER); + sizeofdata = *pSizeOfData; + *pSizeOfData = header->size; + DBG("Found header %p, size %d. Requested max %d\n", header, (int)header->size, (int)sizeofdata); + + if (!pData) { + DBG("Returning early D3D_OK\n"); + return D3D_OK; + } + if (sizeofdata < header->size) { + DBG("Returning D3DERR_MOREDATA\n"); + return D3DERR_MOREDATA; + } + + header_data = (void *)header + sizeof(*header); + if (header->unknown) { IUnknown_AddRef(*(IUnknown **)header_data); } + memcpy(pData, header_data, header->size); + DBG("Returning D3D_OK\n"); + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineUnknown_FreePrivateData( struct NineUnknown *This, + REFGUID refguid ) +{ + struct hash_entry *entry; + char guid_str[64]; + + DBG("This=%p GUID=%s\n", This, GUID_sprintf(guid_str, refguid)); + + (void)guid_str; + + entry = _mesa_hash_table_search(This->pdata, refguid); + if (!entry) { + DBG("Nothing to free\n"); + return D3DERR_NOTFOUND; + } + + DBG("Freeing %p\n", entry->data); + ht_guid_delete(entry); + _mesa_hash_table_remove(This->pdata, entry); + + return D3D_OK; +} diff --git a/src/gallium/frontends/nine/iunknown.h b/src/gallium/frontends/nine/iunknown.h new file mode 100644 index 0000000..01448a4 --- /dev/null +++ b/src/gallium/frontends/nine/iunknown.h @@ -0,0 +1,169 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#ifndef _NINE_IUNKNOWN_H_ +#define _NINE_IUNKNOWN_H_ + +#include "util/compiler.h" + +#include "util/u_atomic.h" +#include "util/u_memory.h" + +#include "guid.h" +#include "nine_flags.h" +#include "nine_debug.h" +#include "nine_quirk.h" + +#include "d3d9.h" + +struct Nine9; +struct NineDevice9; + +struct NineUnknown +{ + /* pointer to vtable (can be overridden outside gallium nine) */ + void *vtable; + /* pointer to internal vtable */ + void *vtable_internal; + + int32_t refs; /* external reference count */ + int32_t bind; /* internal bind count */ + int32_t has_bind_or_refs; /* 0 if no ref, 1 if bind or ref, 2 if both */ + bool forward; /* whether to forward references to the container */ + + /* container: for surfaces and volumes only. + * Can be a texture, a volume texture or a swapchain. + * forward is set to false for the swapchain case. + * If forward is set, refs are passed to the container if forward is set + * and the container has bind increased if the object has non null bind. */ + struct NineUnknown *container; + struct NineDevice9 *device; /* referenced if (refs) */ + + const GUID **guids; /* for QueryInterface */ + + /* for [GS]etPrivateData/FreePrivateData */ + struct hash_table *pdata; + + 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; + bool start_with_bind_not_ref; +}; + +HRESULT +NineUnknown_ctor( struct NineUnknown *This, + struct NineUnknownParams *pParams ); + +void +NineUnknown_dtor( struct NineUnknown *This ); + +/*** Direct3D public methods ***/ + +HRESULT NINE_WINAPI +NineUnknown_QueryInterface( struct NineUnknown *This, + REFIID riid, + void **ppvObject ); + +ULONG NINE_WINAPI +NineUnknown_AddRef( struct NineUnknown *This ); + +ULONG NINE_WINAPI +NineUnknown_Release( struct NineUnknown *This ); + +ULONG NINE_WINAPI +NineUnknown_ReleaseWithDtorLock( struct NineUnknown *This ); + +HRESULT NINE_WINAPI +NineUnknown_GetDevice( struct NineUnknown *This, + IDirect3DDevice9 **ppDevice ); + +HRESULT NINE_WINAPI +NineUnknown_SetPrivateData( struct NineUnknown *This, + REFGUID refguid, + const void *pData, + DWORD SizeOfData, + DWORD Flags ); + +HRESULT NINE_WINAPI +NineUnknown_GetPrivateData( struct NineUnknown *This, + REFGUID refguid, + void *pData, + DWORD *pSizeOfData ); + +HRESULT NINE_WINAPI +NineUnknown_FreePrivateData( struct NineUnknown *This, + REFGUID refguid ); + +/*** Nine private methods ***/ + +static inline void +NineUnknown_Destroy( struct NineUnknown *This ) +{ + assert(!(This->refs | This->bind) && !This->has_bind_or_refs); + This->dtor(This); +} + +static inline UINT +NineUnknown_Bind( struct NineUnknown *This ) +{ + UINT b = p_atomic_inc_return(&This->bind); + assert(b); + + if (b == 1) + p_atomic_inc(&This->has_bind_or_refs); + if (b == 1 && This->forward) + NineUnknown_Bind(This->container); + + return b; +} + +static inline UINT +NineUnknown_Unbind( struct NineUnknown *This ) +{ + UINT b = p_atomic_dec_return(&This->bind); + UINT b_or_ref = 1; + + if (b == 0) + b_or_ref = p_atomic_dec_return(&This->has_bind_or_refs); + if (b == 0 && This->forward) + NineUnknown_Unbind(This->container); + else if (b_or_ref == 0 && !This->container) + 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); + + This->container = NULL; + if (!(This->has_bind_or_refs)) + This->dtor(This); +} + +#endif /* _NINE_IUNKNOWN_H_ */ diff --git a/src/gallium/frontends/nine/meson.build b/src/gallium/frontends/nine/meson.build new file mode 100644 index 0000000..8352a2e --- /dev/null +++ b/src/gallium/frontends/nine/meson.build @@ -0,0 +1,59 @@ +# Copyright © 2017 Intel Corporation +# SPDX-License-Identifier: MIT + +nine_st_files = files( + 'adapter9.c', + 'authenticatedchannel9.c', + 'basetexture9.c', + 'buffer9.c', + 'cryptosession9.c', + 'cubetexture9.c', + 'device9.c', + 'device9ex.c', + 'device9video.c', + 'guid.c', + 'indexbuffer9.c', + 'iunknown.c', + 'nine_buffer_upload.c', + 'nine_debug.c', + 'nine_dump.c', + 'nineexoverlayextension.c', + 'nine_ff.c', + 'nine_helpers.c', + 'nine_lock.c', + 'nine_memory_helper.c', + 'nine_pipe.c', + 'nine_quirk.c', + 'nine_queue.c', + 'nine_shader.c', + 'nine_state.c', + 'pixelshader9.c', + 'query9.c', + 'resource9.c', + 'stateblock9.c', + 'surface9.c', + 'swapchain9.c', + 'swapchain9ex.c', + 'texture9.c', + 'threadpool.c', + 'vertexbuffer9.c', + 'vertexdeclaration9.c', + 'vertexshader9.c', + 'volume9.c', + 'volumetexture9.c', +) + +libnine_st = static_library( + 'nine_st', + nine_st_files, + gnu_symbol_visibility : 'hidden', + include_directories : [ + inc_d3d9, inc_gallium, inc_include, inc_src, inc_gallium_aux, + ], + dependencies : [ + dep_thread, idep_nir, idep_nir_headers + ], + link_with : [ + libmesa + ] +) diff --git a/src/gallium/frontends/nine/nine_buffer_upload.c b/src/gallium/frontends/nine/nine_buffer_upload.c new file mode 100644 index 0000000..ff624a1 --- /dev/null +++ b/src/gallium/frontends/nine/nine_buffer_upload.c @@ -0,0 +1,284 @@ +/* + * + * Copyright 2009 VMware, Inc. + * Copyright 2016 Axel Davy + * All Rights Reserved. + * + * SPDX-License-Identifier: MIT + */ + +/* Adapted from u_upload_mgr. + * Makes suballocations from bigger allocations, + * while enabling fast mapping. */ + +#include "pipe/p_defines.h" +#include "util/u_inlines.h" +#include "pipe/p_context.h" +#include "util/u_memory.h" +#include "util/u_math.h" +#include "util/slab.h" + +#include "nine_buffer_upload.h" + +#include "nine_debug.h" + +#define DBG_CHANNEL (DBG_INDEXBUFFER|DBG_VERTEXBUFFER) + +struct nine_buffer_group { + unsigned refcount; /* How many sub-buffers live inside the buffer */ + struct pipe_resource *resource; + struct pipe_transfer *transfer; + uint8_t *map; + unsigned free_offset; /* Aligned offset to the upload buffer, pointing + * at the first unused byte. */ +}; + +struct nine_subbuffer { + struct nine_buffer_group *parent; /* Can be NULL */ + struct pipe_resource *resource; /* The parent resource if apply */ + unsigned offset; /* Offset inside the resource */ + /* If there is no parent, the resource map. Else NULL. */ + struct pipe_transfer *transfer; + uint8_t *map; +}; + +struct nine_buffer_upload { + struct pipe_context *pipe; + struct slab_mempool buffer_pool; + + unsigned buffers_size; /* Size of the big allocated buffers */ + unsigned num_buffers; + struct nine_buffer_group *buffers; +}; + +static void +nine_upload_create_buffer_group(struct nine_buffer_upload *upload, + struct nine_buffer_group *group) +{ + struct pipe_resource resource; + struct pipe_screen *screen = upload->pipe->screen; + DBG("Allocating %p %p\n", upload, group); + + memset(&resource, 0, sizeof(resource)); + resource.target = PIPE_BUFFER; + resource.format = PIPE_FORMAT_R8_UNORM; + resource.bind = PIPE_BIND_VERTEX_BUFFER; + resource.usage = PIPE_USAGE_STREAM; + resource.width0 = upload->buffers_size; + resource.height0 = 1; + resource.depth0 = 1; + resource.array_size = 1; + resource.flags = PIPE_RESOURCE_FLAG_MAP_PERSISTENT | + PIPE_RESOURCE_FLAG_MAP_COHERENT; + + group->refcount = 0; + group->resource = screen->resource_create(screen, &resource); + if (group->resource == NULL) + return; + + group->map = pipe_buffer_map_range(upload->pipe, group->resource, + 0, upload->buffers_size, + PIPE_MAP_WRITE | +#if DETECT_ARCH_X86 + PIPE_MAP_ONCE | +#endif + PIPE_MAP_PERSISTENT | + PIPE_MAP_COHERENT, + &group->transfer); + if (group->map == NULL) { + group->transfer = NULL; + pipe_resource_reference(&group->resource, NULL); + return; + } + + group->free_offset = 0; + DBG("Success: %p %p\n", group->map, group->map+upload->buffers_size); +} + +static void +nine_upload_destroy_buffer_group(struct nine_buffer_upload *upload, + struct nine_buffer_group *group) +{ + DBG("%p %p\n", upload, group); + DBG("Release: %p %p\n", group->map, group->map+upload->buffers_size); + assert(group->refcount == 0); + + if (group->transfer) + pipe_buffer_unmap(upload->pipe, group->transfer); + if (group->resource) + pipe_resource_reference(&group->resource, NULL); + group->transfer = NULL; + group->map = NULL; +} + +struct nine_buffer_upload * +nine_upload_create(struct pipe_context *pipe, unsigned buffers_size, + unsigned num_buffers) +{ + struct nine_buffer_upload *upload; + int i; + + DBG("\n"); + + if (!pipe->screen->caps.buffer_map_persistent_coherent) + return NULL; + + upload = CALLOC_STRUCT(nine_buffer_upload); + + if (!upload) + return NULL; + + slab_create(&upload->buffer_pool, sizeof(struct nine_subbuffer), 4096); + + upload->pipe = pipe; + upload->buffers_size = align(buffers_size, 4096); + upload->num_buffers = num_buffers; + + upload->buffers = CALLOC(num_buffers, sizeof(struct nine_buffer_group)); + if (!upload->buffers) + goto buffers_fail; + + for (i = 0; i < num_buffers; i++) + nine_upload_create_buffer_group(upload, &upload->buffers[i]); + + return upload; + +buffers_fail: + slab_destroy(&upload->buffer_pool); + FREE(upload); + return NULL; +} + +void +nine_upload_destroy(struct nine_buffer_upload *upload) +{ + int i; + + DBG("%p\n", upload); + + for (i = 0; i < upload->num_buffers; i++) + nine_upload_destroy_buffer_group(upload, &upload->buffers[i]); + slab_destroy(&upload->buffer_pool); + FREE(upload); +} + +struct nine_subbuffer * +nine_upload_create_buffer(struct nine_buffer_upload *upload, + unsigned buffer_size) +{ + struct nine_subbuffer *buf = slab_alloc_st(&upload->buffer_pool); + struct nine_buffer_group *group = NULL; + unsigned size = align(buffer_size, 4096); + int i = 0; + + DBG("%p %d\n", upload, buffer_size); + + if (!buf) + return NULL; + + for (i = 0; i < upload->num_buffers; i++) { + group = &upload->buffers[i]; + if (group->resource && + group->free_offset + size <= upload->buffers_size) + break; + } + + if (i == upload->num_buffers) { + /* Allocate lonely buffer */ + struct pipe_resource resource; + struct pipe_screen *screen = upload->pipe->screen; + + DBG("Allocating buffer\n"); + buf->parent = NULL; + + memset(&resource, 0, sizeof(resource)); + resource.target = PIPE_BUFFER; + resource.format = PIPE_FORMAT_R8_UNORM; + resource.bind = PIPE_BIND_VERTEX_BUFFER; + resource.usage = PIPE_USAGE_STREAM; + resource.width0 = buffer_size; + resource.height0 = 1; + resource.depth0 = 1; + resource.array_size = 1; + resource.flags = PIPE_RESOURCE_FLAG_MAP_PERSISTENT | + PIPE_RESOURCE_FLAG_MAP_COHERENT; + + buf->resource = screen->resource_create(screen, &resource); + if (buf->resource == NULL) { + slab_free_st(&upload->buffer_pool, buf); + return NULL; + } + + buf->map = pipe_buffer_map_range(upload->pipe, buf->resource, + 0, buffer_size, + PIPE_MAP_WRITE | +#if DETECT_ARCH_X86 + PIPE_MAP_ONCE | +#endif + PIPE_MAP_PERSISTENT | + PIPE_MAP_COHERENT, + &buf->transfer); + if (buf->map == NULL) { + pipe_resource_reference(&buf->resource, NULL); + slab_free_st(&upload->buffer_pool, buf); + return NULL; + } + buf->offset = 0; + return buf; + } + + DBG("Using buffer group %d\n", i); + + buf->parent = group; + buf->resource = NULL; + pipe_resource_reference(&buf->resource, group->resource); + buf->offset = group->free_offset; + + group->free_offset += size; + group->refcount += 1; + + return buf; +} + +void +nine_upload_release_buffer(struct nine_buffer_upload *upload, + struct nine_subbuffer *buf) +{ + DBG("%p %p %p\n", upload, buf, buf->parent); + + if (buf->parent) { + pipe_resource_reference(&buf->resource, NULL); + buf->parent->refcount--; + if (buf->parent->refcount == 0) { + /* Allocate new buffer */ + nine_upload_destroy_buffer_group(upload, buf->parent); + nine_upload_create_buffer_group(upload, buf->parent); + } + } else { + /* lonely buffer */ + if (buf->transfer) + pipe_buffer_unmap(upload->pipe, buf->transfer); + pipe_resource_reference(&buf->resource, NULL); + } + + slab_free_st(&upload->buffer_pool, buf); +} + +uint8_t * +nine_upload_buffer_get_map(struct nine_subbuffer *buf) +{ + if (buf->parent) { + DBG("%d\n", buf->parent->refcount); + return buf->parent->map + buf->offset; + } + /* lonely buffer */ + return buf->map; +} + +struct pipe_resource * +nine_upload_buffer_resource_and_offset(struct nine_subbuffer *buf, + unsigned *offset) +{ + *offset = buf->offset; + return buf->resource; +} diff --git a/src/gallium/frontends/nine/nine_buffer_upload.h b/src/gallium/frontends/nine/nine_buffer_upload.h new file mode 100644 index 0000000..61debc6 --- /dev/null +++ b/src/gallium/frontends/nine/nine_buffer_upload.h @@ -0,0 +1,39 @@ +/* + * Copyright 2009 VMware, Inc. + * Copyright 2016 Axel Davy + * All Rights Reserved. + * + * SPDX-License-Identifier: MIT + */ + +#ifndef _NINE_BUFFER_UPLOAD_H_ +#define _NINE_BUFFER_UPLOAD_H_ + +#include "pipe/p_defines.h" + +struct nine_buffer_upload; +struct nine_subbuffer; + +struct nine_buffer_upload * +nine_upload_create(struct pipe_context *pipe, unsigned buffers_size, + unsigned num_buffers); + +void +nine_upload_destroy(struct nine_buffer_upload *upload); + +struct nine_subbuffer * +nine_upload_create_buffer(struct nine_buffer_upload *upload, + unsigned buffer_size); + +void +nine_upload_release_buffer(struct nine_buffer_upload *upload, + struct nine_subbuffer *buf); + +uint8_t * +nine_upload_buffer_get_map(struct nine_subbuffer *buf); + +struct pipe_resource * +nine_upload_buffer_resource_and_offset(struct nine_subbuffer *buf, + unsigned *offset); + +#endif /* _NINE_BUFFER_UPLOAD_H_ */ diff --git a/src/gallium/frontends/nine/nine_csmt_helper.h b/src/gallium/frontends/nine/nine_csmt_helper.h new file mode 100644 index 0000000..503e906 --- /dev/null +++ b/src/gallium/frontends/nine/nine_csmt_helper.h @@ -0,0 +1,427 @@ +/* + * Copyright 2016 Patrick Rudolph + * SPDX-License-Identifier: MIT + */ + +/* get number of arguments with __NARG__ */ +#define __NARG__(...) __NARG_I_(__VA_ARGS__,__RSEQ_N()) +#define __NARG_I_(...) __ARG_N(__VA_ARGS__) +#define __ARG_N( \ + _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \ + _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \ + _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \ + _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \ + _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \ + _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \ + _61,_62,_63,_64,_65,_66,_67,_68,_69,_70,N,...) N +#define __RSEQ_N() \ + 70,69,68,67,66,65,64,63,62,61,60, \ + 59,58,57,56,55,54,53,52,51,50, \ + 49,48,47,46,45,44,43,42,41,40, \ + 39,38,37,36,35,34,33,32,31,30, \ + 29,28,27,26,25,24,23,22,21,20, \ + 19,18,17,16,15,14,13,12,11,10, \ + 9,8,7,6,5,4,3,2,1,0 + + +#define _args_for_bypass_1(a) a +#define _args_for_bypass_7(a, b, c, d, e, f, g) ,g +#define _args_for_bypass_14(a, b, c, d, e, f, g, ...) ,g _args_for_bypass_7(__VA_ARGS__) +#define _args_for_bypass_21(a, b, c, d, e, f, g, ...) ,g _args_for_bypass_14(__VA_ARGS__) +#define _args_for_bypass_28(a, b, c, d, e, f, g, ...) ,g _args_for_bypass_21(__VA_ARGS__) +#define _args_for_bypass_35(a, b, c, d, e, f, g, ...) ,g _args_for_bypass_28(__VA_ARGS__) +#define _args_for_bypass_42(a, b, c, d, e, f, g, ...) ,g _args_for_bypass_35(__VA_ARGS__) +#define _args_for_bypass_49(a, b, c, d, e, f, g, ...) ,g _args_for_bypass_42(__VA_ARGS__) +#define _args_for_bypass_56(a, b, c, d, e, f, g, ...) ,g _args_for_bypass_49(__VA_ARGS__) +#define _args_for_bypass_63(a, b, c, d, e, f, g, ...) ,g _args_for_bypass_56(__VA_ARGS__) +#define _args_for_bypass_70(a, b, c, d, e, f, g, ...) ,g _args_for_bypass_63(__VA_ARGS__) +#define _args_for_bypass_77(a, b, c, d, e, f, g, ...) ,g _args_for_bypass_70(__VA_ARGS__) + +#define _GFUNC_(n) _args_for_bypass_##n +#define _GFUNC(n) _GFUNC_(n) + +#define ARGS_FOR_BYPASS(...) _GFUNC(__NARG__(__VA_ARGS__)) (__VA_ARGS__) + +#define _args_for_mem_1(a) a; +#define _args_for_mem_7(a, b, c, d, e, f, g) f; +#define _args_for_mem_14(a, b, c, d, e, f, g, ...) f; _args_for_mem_7(__VA_ARGS__) +#define _args_for_mem_21(a, b, c, d, e, f, g, ...) f; _args_for_mem_14(__VA_ARGS__) +#define _args_for_mem_28(a, b, c, d, e, f, g, ...) f; _args_for_mem_21(__VA_ARGS__) +#define _args_for_mem_35(a, b, c, d, e, f, g, ...) f; _args_for_mem_28(__VA_ARGS__) +#define _args_for_mem_42(a, b, c, d, e, f, g, ...) f; _args_for_mem_35(__VA_ARGS__) +#define _args_for_mem_49(a, b, c, d, e, f, g, ...) f; _args_for_mem_42(__VA_ARGS__) +#define _args_for_mem_56(a, b, c, d, e, f, g, ...) f; _args_for_mem_49(__VA_ARGS__) +#define _args_for_mem_63(a, b, c, d, e, f, g, ...) f; _args_for_mem_56(__VA_ARGS__) +#define _args_for_mem_70(a, b, c, d, e, f, g, ...) f; _args_for_mem_63(__VA_ARGS__) +#define _args_for_mem_77(a, b, c, d, e, f, g, ...) f; _args_for_mem_70(__VA_ARGS__) + +#define _FFUNC_(n) _args_for_mem_##n +#define _FFUNC(n) _FFUNC_(n) + +#define ARGS_FOR_MEM(...) _FFUNC(__NARG__(__VA_ARGS__)) (__VA_ARGS__) + +#define _args_for_unbind_1(a) a; +#define _args_for_unbind_7(a, b, c, d, e, f, g) e; +#define _args_for_unbind_14(a, b, c, d, e, f, g, ...) e; _args_for_unbind_7(__VA_ARGS__) +#define _args_for_unbind_21(a, b, c, d, e, f, g, ...) e; _args_for_unbind_14(__VA_ARGS__) +#define _args_for_unbind_28(a, b, c, d, e, f, g, ...) e; _args_for_unbind_21(__VA_ARGS__) +#define _args_for_unbind_35(a, b, c, d, e, f, g, ...) e; _args_for_unbind_28(__VA_ARGS__) +#define _args_for_unbind_42(a, b, c, d, e, f, g, ...) e; _args_for_unbind_35(__VA_ARGS__) +#define _args_for_unbind_49(a, b, c, d, e, f, g, ...) e; _args_for_unbind_42(__VA_ARGS__) +#define _args_for_unbind_56(a, b, c, d, e, f, g, ...) e; _args_for_unbind_49(__VA_ARGS__) +#define _args_for_unbind_63(a, b, c, d, e, f, g, ...) e; _args_for_unbind_56(__VA_ARGS__) +#define _args_for_unbind_70(a, b, c, d, e, f, g, ...) e; _args_for_unbind_63(__VA_ARGS__) +#define _args_for_unbind_77(a, b, c, d, e, f, g, ...) e; _args_for_unbind_70(__VA_ARGS__) + +#define _EFUNC_(n) _args_for_unbind_##n +#define _EFUNC(n) _EFUNC_(n) + +#define ARGS_FOR_UNBIND(...) _EFUNC(__NARG__(__VA_ARGS__)) (__VA_ARGS__) + +#define _args_for_call_1(a) a +#define _args_for_call_7(a, b, c, d, e, f, g) ,d +#define _args_for_call_14(a, b, c, d, e, f, g, ...) ,d _args_for_call_7(__VA_ARGS__) +#define _args_for_call_21(a, b, c, d, e, f, g, ...) ,d _args_for_call_14(__VA_ARGS__) +#define _args_for_call_28(a, b, c, d, e, f, g, ...) ,d _args_for_call_21(__VA_ARGS__) +#define _args_for_call_35(a, b, c, d, e, f, g, ...) ,d _args_for_call_28(__VA_ARGS__) +#define _args_for_call_42(a, b, c, d, e, f, g, ...) ,d _args_for_call_35(__VA_ARGS__) +#define _args_for_call_49(a, b, c, d, e, f, g, ...) ,d _args_for_call_42(__VA_ARGS__) +#define _args_for_call_56(a, b, c, d, e, f, g, ...) ,d _args_for_call_49(__VA_ARGS__) +#define _args_for_call_63(a, b, c, d, e, f, g, ...) ,d _args_for_call_56(__VA_ARGS__) +#define _args_for_call_70(a, b, c, d, e, f, g, ...) ,d _args_for_call_63(__VA_ARGS__) +#define _args_for_call_77(a, b, c, d, e, f, g, ...) ,d _args_for_call_70(__VA_ARGS__) + +#define _DFUNC_(n) _args_for_call_##n +#define _DFUNC(n) _DFUNC_(n) + +#define ARGS_FOR_CALL(...) _DFUNC(__NARG__(__VA_ARGS__)) (__VA_ARGS__) + +#define _args_for_decl_1(a) a +#define _args_for_decl_7(a, b, c, d, e, f, g) ,c +#define _args_for_decl_14(a, b, c, d, e, f, g, ...) ,c _args_for_decl_7(__VA_ARGS__) +#define _args_for_decl_21(a, b, c, d, e, f, g, ...) ,c _args_for_decl_14(__VA_ARGS__) +#define _args_for_decl_28(a, b, c, d, e, f, g, ...) ,c _args_for_decl_21(__VA_ARGS__) +#define _args_for_decl_35(a, b, c, d, e, f, g, ...) ,c _args_for_decl_28(__VA_ARGS__) +#define _args_for_decl_42(a, b, c, d, e, f, g, ...) ,c _args_for_decl_35(__VA_ARGS__) +#define _args_for_decl_49(a, b, c, d, e, f, g, ...) ,c _args_for_decl_42(__VA_ARGS__) +#define _args_for_decl_56(a, b, c, d, e, f, g, ...) ,c _args_for_decl_49(__VA_ARGS__) +#define _args_for_decl_63(a, b, c, d, e, f, g, ...) ,c _args_for_decl_56(__VA_ARGS__) +#define _args_for_decl_70(a, b, c, d, e, f, g, ...) ,c _args_for_decl_63(__VA_ARGS__) +#define _args_for_decl_77(a, b, c, d, e, f, g, ...) ,c _args_for_decl_70(__VA_ARGS__) + +#define _CFUNC_(n) _args_for_decl_##n +#define _CFUNC(n) _CFUNC_(n) + +#define ARGS_FOR_DECLARATION(...) _CFUNC(__NARG__(__VA_ARGS__)) (__VA_ARGS__) + +#define _args_for_assign_1(a) a +#define _args_for_assign_7(a, b, c, d, e, f, g) b; +#define _args_for_assign_14(a, b, c, d, e, f, g, ...) b; _args_for_assign_7(__VA_ARGS__) +#define _args_for_assign_21(a, b, c, d, e, f, g, ...) b; _args_for_assign_14(__VA_ARGS__) +#define _args_for_assign_28(a, b, c, d, e, f, g, ...) b; _args_for_assign_21(__VA_ARGS__) +#define _args_for_assign_35(a, b, c, d, e, f, g, ...) b; _args_for_assign_28(__VA_ARGS__) +#define _args_for_assign_42(a, b, c, d, e, f, g, ...) b; _args_for_assign_35(__VA_ARGS__) +#define _args_for_assign_49(a, b, c, d, e, f, g, ...) b; _args_for_assign_42(__VA_ARGS__) +#define _args_for_assign_56(a, b, c, d, e, f, g, ...) b; _args_for_assign_49(__VA_ARGS__) +#define _args_for_assign_63(a, b, c, d, e, f, g, ...) b; _args_for_assign_56(__VA_ARGS__) +#define _args_for_assign_70(a, b, c, d, e, f, g, ...) b; _args_for_assign_63(__VA_ARGS__) +#define _args_for_assign_77(a, b, c, d, e, f, g, ...) b; _args_for_assign_70(__VA_ARGS__) + +#define _BFUNC_(n) _args_for_assign_##n +#define _BFUNC(n) _BFUNC_(n) + +#define ARGS_FOR_ASSIGN(...) _BFUNC(__NARG__(__VA_ARGS__)) (__VA_ARGS__) + +#define _args_for_struct_1(a) a; +#define _args_for_struct_7(a, b, c, d, e, f, g) a; +#define _args_for_struct_14(a, b, c, d, e, f, g, ...) a; _args_for_struct_7(__VA_ARGS__) +#define _args_for_struct_21(a, b, c, d, e, f, g, ...) a; _args_for_struct_14(__VA_ARGS__) +#define _args_for_struct_28(a, b, c, d, e, f, g, ...) a; _args_for_struct_21(__VA_ARGS__) +#define _args_for_struct_35(a, b, c, d, e, f, g, ...) a; _args_for_struct_28(__VA_ARGS__) +#define _args_for_struct_42(a, b, c, d, e, f, g, ...) a; _args_for_struct_35(__VA_ARGS__) +#define _args_for_struct_49(a, b, c, d, e, f, g, ...) a; _args_for_struct_42(__VA_ARGS__) +#define _args_for_struct_56(a, b, c, d, e, f, g, ...) a; _args_for_struct_49(__VA_ARGS__) +#define _args_for_struct_63(a, b, c, d, e, f, g, ...) a; _args_for_struct_56(__VA_ARGS__) +#define _args_for_struct_70(a, b, c, d, e, f, g, ...) a; _args_for_struct_63(__VA_ARGS__) +#define _args_for_struct_77(a, b, c, d, e, f, g, ...) a; _args_for_struct_70(__VA_ARGS__) + +#define _AFUNC_(n) _args_for_struct_##n +#define _AFUNC(n) _AFUNC_(n) + +#define ARGS_FOR_STRUCT(...) _AFUNC(__NARG__(__VA_ARGS__)) (__VA_ARGS__) + +/* Serialization and deserialization */ + +#define CSMT_ITEM_NO_WAIT(name, ...) \ +\ +struct s_##name##_private { \ + struct csmt_instruction instr; \ + ARGS_FOR_STRUCT( __VA_ARGS__ ) \ +}; \ +\ +static void \ +name##_priv( struct NineDevice9 *device ARGS_FOR_DECLARATION( __VA_ARGS__ ) ); \ +\ +static int \ +name##_rx( struct NineDevice9 *device, struct csmt_instruction *instr ) \ +{ \ + struct csmt_context *ctx = device->csmt_ctx; \ + struct s_##name##_private *args = (struct s_##name##_private *)instr; \ + \ + (void) args; \ + (void) ctx; \ + name##_priv( \ + device ARGS_FOR_CALL( __VA_ARGS__ ) \ + ); \ + ARGS_FOR_UNBIND( __VA_ARGS__ ) \ + return 0; \ +} \ +\ +void \ +name( struct NineDevice9 *device ARGS_FOR_DECLARATION( __VA_ARGS__ ) ) \ +{ \ + struct csmt_context *ctx = device->csmt_ctx; \ + struct s_##name##_private *args; \ + unsigned memsize = sizeof(struct s_##name##_private); \ + unsigned memsize2 = 0; \ + \ + if (!device->csmt_active) { \ + name##_priv( \ + device ARGS_FOR_BYPASS( __VA_ARGS__ ) \ + ); \ + return; \ + } \ + ARGS_FOR_MEM ( __VA_ARGS__ ) \ + args = nine_queue_alloc(ctx->pool, memsize + memsize2); \ + assert(args); \ + args->instr.func = &name##_rx; \ + ARGS_FOR_ASSIGN( __VA_ARGS__ ) \ +} \ +\ +static void \ +name##_priv( struct NineDevice9 *device ARGS_FOR_DECLARATION( __VA_ARGS__ ) ) + +#define CSMT_ITEM_NO_WAIT_WITH_COUNTER(name, ...) \ +\ +struct s_##name##_private { \ + struct csmt_instruction instr; \ + unsigned *counter; \ + ARGS_FOR_STRUCT( __VA_ARGS__ ) \ +}; \ +\ +static void \ +name##_priv( struct NineDevice9 *device ARGS_FOR_DECLARATION( __VA_ARGS__ ) ); \ +\ +static int \ +name##_rx( struct NineDevice9 *device, struct csmt_instruction *instr ) \ +{ \ + struct csmt_context *ctx = device->csmt_ctx; \ + struct s_##name##_private *args = (struct s_##name##_private *)instr; \ + \ + (void) args; \ + (void) ctx; \ + name##_priv( \ + device ARGS_FOR_CALL( __VA_ARGS__ ) \ + ); \ + p_atomic_dec(args->counter); \ + ARGS_FOR_UNBIND( __VA_ARGS__ ) \ + return 0; \ +} \ +\ +void \ +name( struct NineDevice9 *device, unsigned *counter ARGS_FOR_DECLARATION( __VA_ARGS__ ) ) \ +{ \ + struct csmt_context *ctx = device->csmt_ctx; \ + struct s_##name##_private *args; \ + unsigned memsize = sizeof(struct s_##name##_private); \ + unsigned memsize2 = 0; \ + \ + if (!device->csmt_active) { \ + name##_priv( \ + device ARGS_FOR_BYPASS( __VA_ARGS__ ) \ + ); \ + return; \ + } \ + assert(counter); \ + p_atomic_inc(counter); \ + ARGS_FOR_MEM ( __VA_ARGS__ ) \ + args = nine_queue_alloc(ctx->pool, memsize + memsize2); \ + assert(args); \ + args->instr.func = &name##_rx; \ + args->counter = counter; \ + ARGS_FOR_ASSIGN( __VA_ARGS__ ) \ +} \ +\ +static void \ +name##_priv( struct NineDevice9 *device ARGS_FOR_DECLARATION( __VA_ARGS__ ) ) + +#define CSMT_ITEM_DO_WAIT(name, ...) \ +\ +struct s_##name##_private { \ + struct csmt_instruction instr; \ + ARGS_FOR_STRUCT( __VA_ARGS__ ) \ +}; \ +static void \ +name##_priv( struct NineDevice9 *device ARGS_FOR_DECLARATION( __VA_ARGS__ ) ); \ +\ +static int \ +name##_rx( struct NineDevice9 *device, struct csmt_instruction *instr) \ +{ \ + struct csmt_context *ctx = device->csmt_ctx; \ + struct s_##name##_private *args = (struct s_##name##_private *)instr; \ + \ + (void) args; \ + (void) ctx; \ + name##_priv( \ + device ARGS_FOR_CALL( __VA_ARGS__ ) \ + ); \ + ARGS_FOR_UNBIND( __VA_ARGS__ ) \ + return 1; \ +} \ +\ +void \ +name( struct NineDevice9 *device ARGS_FOR_DECLARATION( __VA_ARGS__ ) ) \ +{ \ + struct csmt_context *ctx = device->csmt_ctx; \ + struct s_##name##_private *args; \ + unsigned memsize = sizeof(struct s_##name##_private); \ + unsigned memsize2 = 0; \ + \ + if (!device->csmt_active) { \ + name##_priv( \ + device ARGS_FOR_BYPASS( __VA_ARGS__ ) \ + ); \ + return; \ + } \ + ARGS_FOR_MEM ( __VA_ARGS__ ) \ + args = nine_queue_alloc(ctx->pool, memsize + memsize2); \ + assert(args); \ + args->instr.func = &name##_rx; \ + ARGS_FOR_ASSIGN( __VA_ARGS__ ) \ + ctx->processed = false; \ + nine_queue_flush(ctx->pool); \ + nine_csmt_wait_processed(ctx); \ +} \ +\ +static void \ +name##_priv( struct NineDevice9 *device ARGS_FOR_DECLARATION( __VA_ARGS__ ) ) + +/* ARGS_FOR_STRUCT, ARGS_FOR_ASSIGN, ARGS_FOR_DECLARATION, ARGS_FOR_CALL, ARGS_FOR_UNBIND, ARGS_FOR_MEM, ARGS_FOR_BYPASS */ +#define ARG_VAL(x, y) \ + x _##y ; ,\ + args->_##y = y ; ,\ + x y ,\ + args->_##y ,\ + ,\ + ,\ + y + +#define ARG_REF(x, y) \ + x* _##y ; ,\ + args->_##y = y; ,\ + x *y ,\ + args->_##y ,\ + ,\ + ,\ + y + +#define ARG_COPY_REF(x, y) \ + x * _##y ; x __##y ; ,\ + if ( y ) { args->_##y = &args->__##y ; args->__##y = *y ; } else { args->_##y = NULL; } ,\ + const x *y ,\ + (const x *)args->_##y ,\ + ,\ + ,\ + (const x *)y + +#define ARG_BIND_REF(x, y) \ + x * _##y ,\ + if ( y ) \ + NineUnknown_Bind( (void *)y ); \ + args->_##y = y ; ,\ + x *y ,\ + args->_##y,\ + if (args->_##y) \ + NineUnknown_Unbind((void *)(args->_##y)); \ + args->_##y = NULL; ,\ + ,\ + y + +#define ARG_BIND_RES(x, y) \ + x * _##y ,\ + args->_##y = NULL; \ + if (y) \ + pipe_resource_reference(&args->_##y, y); ,\ + x *y ,\ + args->_##y ,\ + if (args->_##y) \ + pipe_resource_reference(&args->_##y, NULL); ,\ + ,\ + y + +#define ARG_MEM(x, y) \ + x * _##y ,\ + args->_##y = (void *)args + memsize;\ + memcpy(args->_##y, y, memsize2); ,\ + const x *y ,\ + (const x *)args->_##y ,\ + ,\ + ,\ + (const x *)y + +#define ARG_MEM_SIZE(x, y) \ + x _##y ,\ + args->_##y = y; ,\ + x y ,\ + args->_##y ,\ + ,\ + memsize2 = y, \ + y + +#define ARG_BIND_BLIT(x, y) \ + x _##y ,\ + memcpy(&args->_##y , y, sizeof(x)); \ + args->_##y.src.resource = NULL; \ + args->_##y.dst.resource = NULL; \ + pipe_resource_reference(&args->_##y.src.resource, y->src.resource); \ + pipe_resource_reference(&args->_##y.dst.resource, y->dst.resource);,\ + x *y ,\ + &args->_##y ,\ + pipe_resource_reference(&args->_##y.src.resource, NULL); \ + pipe_resource_reference(&args->_##y.dst.resource, NULL);,\ + ,\ + y + +#define ARG_BIND_VBUF(x, y) \ + x _##y ,\ + memcpy(&args->_##y , y, sizeof(x)); \ + args->_##y.buffer.resource = NULL; \ + pipe_resource_reference(&args->_##y.buffer.resource, y->buffer.resource); ,\ + x *y ,\ + &args->_##y ,\ + pipe_resource_reference(&args->_##y.buffer.resource, NULL); ,\ + ,\ + y + +#define ARG_BIND_IBUF(x, y) \ + x _##y ,\ + memcpy(&args->_##y , y, sizeof(x)); \ + args->_##y.buffer = NULL; \ + pipe_resource_reference(&args->_##y.buffer, y->buffer); ,\ + x *y ,\ + &args->_##y ,\ + pipe_resource_reference(&args->_##y.buffer, NULL); ,\ + ,\ + y + +#define ARG_BIND_VIEW(x, y) \ + x * _##y ,\ + args->_##y = NULL; \ + if (y) \ + args->_##y = y;,\ + x *y ,\ + args->_##y ,\ + if (args->_##y) \ + args->_##y = NULL;,\ + ,\ + y diff --git a/src/gallium/frontends/nine/nine_debug.c b/src/gallium/frontends/nine/nine_debug.c new file mode 100644 index 0000000..b99986d --- /dev/null +++ b/src/gallium/frontends/nine/nine_debug.c @@ -0,0 +1,100 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#include "nine_debug.h" + +#include +#include "c11/threads.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." }, + { "tid", DBG_TID, "Display thread-ids." }, + DEBUG_NAMED_VALUE_END +}; + +void +_nine_debug_printf( unsigned long flag, + const char *func, + const char *fmt, + ... ) +{ + static bool first = true; + static unsigned long dbg_flags = DBG_ERROR | DBG_WARN; + unsigned long tid = 0; + + if (first) { + first = false; + dbg_flags |= debug_get_flags_option("NINE_DEBUG", nine_debug_flags, 0); + } + +#if defined(HAVE_PTHREAD) + if (dbg_flags & DBG_TID) + tid = (unsigned long)pthread_self(); +#endif + + if (dbg_flags & flag) { + const char *f = func ? strrchr(func, '_') : NULL; + va_list ap; + /* inside a class this will print nine:tid:classinlowercase:func: while + * outside a class (rarely used) it will just print nine:tid: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'; + if (tid) + _debug_printf("nine:0x%08lx:%s:%s: ", tid, klass, ++f); + else + _debug_printf("nine:%s:%s: ", klass, ++f); + } else if (func) { + if (tid) + _debug_printf("nine:0x%08lx:%s ", tid, func); + else + _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/frontends/nine/nine_debug.h b/src/gallium/frontends/nine/nine_debug.h new file mode 100644 index 0000000..826c23a --- /dev/null +++ b/src/gallium/frontends/nine/nine_debug.h @@ -0,0 +1,120 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#ifndef _NINE_DEBUG_H_ +#define _NINE_DEBUG_H_ + +#include "util/u_debug.h" +#include "util/compiler.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, __func__, fmt, ## __VA_ARGS__) + +#if MESA_DEBUG || !defined(NDEBUG) +#define WARN(fmt, ...) _nine_debug_printf(DBG_WARN, __func__, fmt, ## __VA_ARGS__) +#define WARN_ONCE(fmt, ...) \ + do { \ + static bool once = true; \ + if (once) { \ + once = false; \ + _nine_debug_printf(DBG_WARN, __func__, fmt, ## __VA_ARGS__); \ + } \ + } while(0) +#else +#define WARN(fmt, ...) do {} while(0) +#define WARN_ONCE(fmt, ...) do {} while(0) +#endif + +#if MESA_DEBUG || !defined(NDEBUG) +#define DBG_FLAG(flag, fmt, ...) \ + _nine_debug_printf(flag, __func__, fmt, ## __VA_ARGS__) +#else +#define DBG_FLAG(flag, fmt, ...) do {} while(0) +#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) +#define DBG_TID (1<<27) + +void +_nine_stub( const char *file, + const char *func, + unsigned line ); + +#if MESA_DEBUG || !defined(NDEBUG) +#define STUB(ret) \ + do { \ + _nine_stub(__FILE__, __func__, __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. */ +#if MESA_DEBUG || !defined(NDEBUG) +#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 + +#if MESA_DEBUG || !defined(NDEBUG) +#define user_warn(x) \ + if ((x)) { DBG_FLAG(DBG_USER, "User warning: `%s'\n", #x); } +#else +#define user_warn(x) do {} while(0) +#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/frontends/nine/nine_defines.h b/src/gallium/frontends/nine/nine_defines.h new file mode 100644 index 0000000..0731cd6 --- /dev/null +++ b/src/gallium/frontends/nine/nine_defines.h @@ -0,0 +1,48 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#ifndef _NINE_DEFINES_H_ +#define _NINE_DEFINES_H_ + +#include "pipe/p_defines.h" + + +#define NINE_RESOURCE_FLAG_LOCKABLE (PIPE_RESOURCE_FLAG_FRONTEND_PRIV << 1) +#define NINE_RESOURCE_FLAG_DUMMY (PIPE_RESOURCE_FLAG_FRONTEND_PRIV << 2) + +/* vertexdeclaration9.c */ +uint16_t nine_d3d9_to_nine_declusage(unsigned usage, unsigned index); + +#define NINE_DECLUSAGE_POSITION 0 +#define NINE_DECLUSAGE_BLENDWEIGHT 1 +#define NINE_DECLUSAGE_BLENDINDICES 2 +#define NINE_DECLUSAGE_NORMAL 3 +#define NINE_DECLUSAGE_TEXCOORD 4 +#define NINE_DECLUSAGE_TANGENT 5 +#define NINE_DECLUSAGE_BINORMAL 6 +#define NINE_DECLUSAGE_COLOR 7 +#define NINE_DECLUSAGE_POSITIONT 8 + +#define NINE_DECLUSAGE_PSIZE 9 +#define NINE_DECLUSAGE_TESSFACTOR 10 +#define NINE_DECLUSAGE_DEPTH 11 +#define NINE_DECLUSAGE_FOG 12 +#define NINE_DECLUSAGE_SAMPLE 13 +#define NINE_DECLUSAGE_NONE 14 +#define NINE_DECLUSAGE_COUNT (NINE_DECLUSAGE_NONE + 1) + +#define NINE_DECLUSAGE_i(declusage, n) NINE_DECLUSAGE_##declusage + n * NINE_DECLUSAGE_COUNT + +#define NINED3DCLEAR_DEPTHSTENCIL (D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL) + +#define NINE_BIND_BACKBUFFER_FLAGS (PIPE_BIND_RENDER_TARGET |\ + PIPE_BIND_SAMPLER_VIEW) + +#define NINE_BIND_PRESENTBUFFER_FLAGS (PIPE_BIND_RENDER_TARGET |\ + PIPE_BIND_DISPLAY_TARGET |\ + PIPE_BIND_SCANOUT |\ + PIPE_BIND_SHARED) + +#endif /* _NINE_DEFINES_H_ */ diff --git a/src/gallium/frontends/nine/nine_dump.c b/src/gallium/frontends/nine/nine_dump.c new file mode 100644 index 0000000..cfa65b8 --- /dev/null +++ b/src/gallium/frontends/nine/nine_dump.c @@ -0,0 +1,818 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#include "nine_debug.h" +#include "nine_pipe.h" + +#include +#include "c11/threads.h" +#include "util/u_memory.h" +#include "util/u_math.h" + +#include "nine_dump.h" + +#if MESA_DEBUG || !defined(NDEBUG) + +static char thread_local 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 /* MESA_DEBUG || !NDEBUG */ diff --git a/src/gallium/frontends/nine/nine_dump.h b/src/gallium/frontends/nine/nine_dump.h new file mode 100644 index 0000000..19bc8d3 --- /dev/null +++ b/src/gallium/frontends/nine/nine_dump.h @@ -0,0 +1,56 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#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); + +#if MESA_DEBUG || !defined(NDEBUG) + +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 /* !(MESA_DEBUG || !NDEBUG) */ + +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 /* MESA_DEBUG || !NDEBUG */ + +#endif /* _NINE_DUMP_H_H_ */ diff --git a/src/gallium/frontends/nine/nine_ff.c b/src/gallium/frontends/nine/nine_ff.c new file mode 100644 index 0000000..65f151c --- /dev/null +++ b/src/gallium/frontends/nine/nine_ff.c @@ -0,0 +1,2536 @@ +/* + * Copyright 2011 Joakim Sindholt + * Copyright Axel Davy + * SPDX-License-Identifier: MIT + */ + +#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/bitscan.h" +#include "util/box.h" +#include "util/u_hash_table.h" +#include "util/u_upload_mgr.h" + +#define DBG_CHANNEL DBG_FF + +#define NINE_FF_NUM_VS_CONST 204 +#define NINE_FF_NUM_PS_CONST 24 + +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_zero : 1; + uint32_t has_normal : 1; + uint32_t fog : 1; + uint32_t normalizenormals : 1; + uint32_t ucp : 1; + uint32_t pad1 : 4; + uint32_t tc_dim_input: 16; /* 8 * 2 bits */ + uint32_t pad2 : 16; + uint32_t tc_dim_output: 24; /* 8 * 3 bits */ + uint32_t pad3 : 8; + uint32_t tc_gen : 24; /* 8 * 3 bits */ + uint32_t pad4 : 8; + uint32_t tc_idx : 24; + uint32_t clipplane_emulate : 8; + uint32_t passthrough; + }; + uint64_t value64[3]; /* don't forget to resize VertexShader9.ff_key */ + uint32_t value32[6]; + }; +}; + +/* 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 pad : 1; + /* that's 32 bit exactly */ + } ts[8]; + uint32_t projected : 16; + uint32_t fog : 1; /* for vFog coming from VS */ + uint32_t fog_mode : 2; + uint32_t fog_source : 1; /* 0: Z, 1: W */ + uint32_t specular : 1; + uint32_t alpha_test_emulation : 3; + uint32_t flatshade : 1; + uint32_t pad1 : 7; /* 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 */ + uint8_t pad2[3]; + }; + uint64_t value64[6]; /* don't forget to resize PixelShader9.ff_key */ + uint32_t value32[12]; + }; +}; + +static uint32_t nine_ff_vs_key_hash(const void *key) +{ + const struct nine_ff_vs_key *vs = key; + unsigned i; + uint32_t hash = vs->value32[0]; + for (i = 1; i < ARRAY_SIZE(vs->value32); ++i) + hash ^= vs->value32[i]; + return hash; +} +static bool nine_ff_vs_key_comp(const void *key1, const 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)) == 0; +} +static uint32_t nine_ff_ps_key_hash(const void *key) +{ + const struct nine_ff_ps_key *ps = key; + unsigned i; + uint32_t hash = ps->value32[0]; + for (i = 1; i < ARRAY_SIZE(ps->value32); ++i) + hash ^= ps->value32[i]; + return hash; +} +static bool nine_ff_ps_key_comp(const void *key1, const 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)) == 0; +} +static uint32_t nine_ff_fvf_key_hash(const void *key) +{ + return *(DWORD *)key; +} +static bool nine_ff_fvf_key_comp(const void *key1, const 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, bool override) +{ + if (debug_get_bool_option("NINE_FF_DUMP", false) || override) { + const struct tgsi_token *toks = ureg_get_tokens(ureg, NULL); + 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_DECL_constant(ureg, i), _X(AL)) + +#define MATERIAL_CONST(i) \ + ureg_DECL_constant(ureg, 19 + (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_PROJECTION + * CONST[12..15] D3DTS_VIEW^(-1) + * CONST[16..18] Normal matrix + * + * CONST[19].xyz 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[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[100].___w Viewport width + * 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[160] D3DTS_WORLDMATRIX[0] * D3DTS_VIEW + * CONST[164] D3DTS_WORLDMATRIX[1] * D3DTS_VIEW + * ... + * CONST[192] D3DTS_WORLDMATRIX[8] * D3DTS_VIEW + * CONST[196] UCP0 + ... + * CONST[203] UCP7 + */ +struct vs_build_ctx +{ + struct ureg_program *ureg; + const struct nine_ff_vs_key *key; + + uint16_t 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->caps.tgsi_texcoord) + return TGSI_SEMANTIC_TEXCOORD; + return TGSI_SEMANTIC_GENERIC; +} + +static inline struct ureg_src +build_vs_add_input(struct vs_build_ctx *vs, uint16_t 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 = ureg_DECL_temporary(ureg); + 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)); + ureg_release_temporary(ureg, tmp); +} + +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(MESA_SHADER_VERTEX); + struct ureg_dst oPos, oCol[2], oPsz, oFog; + struct ureg_dst AR; + unsigned i, c; + unsigned label[32], l = 0; + bool need_aNrm = key->lighting || key->passthrough & (1 << NINE_DECLUSAGE_NORMAL); + bool has_aNrm; + bool need_aVtx = key->lighting || key->fog_mode || key->pointscale || key->ucp; + 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) & 0x7) { + case NINED3DTSS_TCI_CAMERASPACENORMAL: + need_aNrm = true; + break; + case NINED3DTSS_TCI_CAMERASPACEPOSITION: + need_aVtx = true; + break; + case NINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR: + need_aVtx = need_aNrm = true; + break; + case NINED3DTSS_TCI_SPHEREMAP: + need_aVtx = need_aNrm = true; + break; + default: + break; + } + } + + has_aNrm = need_aNrm && key->has_normal; + + /* 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); + + vs->aNrm = ureg_imm1f(ureg, 0.0f); + if (has_aNrm) + vs->aNrm = build_vs_add_input(vs, NINE_DECLUSAGE_NORMAL); + + vs->aCol[0] = ureg_imm1f(ureg, 1.0f); + vs->aCol[1] = ureg_imm1f(ureg, 0.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_i(COLOR, 0)); + if ((mask & 0x2) && !key->color1in_zero) + vs->aCol[1] = build_vs_add_input(vs, NINE_DECLUSAGE_i(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_i(COLOR, 0)); + if (!key->color1in_zero) vs->aCol[1] = build_vs_add_input(vs, NINE_DECLUSAGE_i(COLOR, 1)); + } + + if (key->vertexpointsize) + vs->aPsz = build_vs_add_input(vs, NINE_DECLUSAGE_PSIZE); + + if (key->vertexblend_indexed || key->passthrough & (1 << NINE_DECLUSAGE_BLENDINDICES)) + vs->aInd = build_vs_add_input(vs, NINE_DECLUSAGE_BLENDINDICES); + if (key->vertexblend || key->passthrough & (1 << NINE_DECLUSAGE_BLENDWEIGHT)) + vs->aWgt = build_vs_add_input(vs, NINE_DECLUSAGE_BLENDWEIGHT); + if (key->vertextween) { + vs->aVtx1 = build_vs_add_input(vs, NINE_DECLUSAGE_i(POSITION,1)); + vs->aNrm1 = build_vs_add_input(vs, NINE_DECLUSAGE_i(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->fog || key->passthrough & (1 << NINE_DECLUSAGE_FOG)) { + oFog = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 16); + oFog = ureg_writemask(oFog, TGSI_WRITEMASK_X); + } + + if (key->vertexpointsize || key->pointscale || device->driver_caps.always_output_pointsize) { + oPsz = ureg_DECL_output_masked(ureg, TGSI_SEMANTIC_PSIZE, 0, + TGSI_WRITEMASK_X, 0, 1); + oPsz = ureg_writemask(oPsz, TGSI_WRITEMASK_X); + } + + if (key->lighting || key->vertexblend) + AR = ureg_DECL_address(ureg); + + /* === Vertex transformation / vertex blending: + */ + + if (key->position_t) { + if (device->driver_caps.window_space_position_support) { + ureg_MOV(ureg, oPos, vs->aVtx); + } else { + struct ureg_dst tmp = ureg_DECL_temporary(ureg); + /* 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_ADD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_XYZ), ureg_src(tmp), ureg_negate(_CONST(101))); + ureg_MUL(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_XYZ), ureg_src(tmp), _CONST(100)); + ureg_ADD(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))); + /* Replace w by 1 if it equals to 0 */ + ureg_CMP(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_W), ureg_negate(ureg_abs(ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_W))), + ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_W), ureg_imm1f(ureg, 1.0f)); + /* 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)); + ureg_release_temporary(ureg, tmp); + } + } else if (key->vertexblend) { + struct ureg_dst tmp = ureg_DECL_temporary(ureg); + struct ureg_dst tmp2 = ureg_DECL_temporary(ureg); + struct ureg_dst aVtx_dst = ureg_DECL_temporary(ureg); + struct ureg_dst aNrm_dst = ureg_DECL_temporary(ureg); + struct ureg_dst sum_blendweights = ureg_DECL_temporary(ureg); + struct ureg_src cWM[4]; + + for (i = 160; i <= 195; ++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, 160.0f)); + ureg_ARL(ureg, AR, ureg_src(tmp)); + } + + ureg_MOV(ureg, aVtx_dst, ureg_imm4f(ureg, 0.0f, 0.0f, 0.0f, 0.0f)); + ureg_MOV(ureg, aNrm_dst, ureg_imm4f(ureg, 0.0f, 0.0f, 0.0f, 0.0f)); + ureg_MOV(ureg, sum_blendweights, ureg_imm4f(ureg, 1.0f, 1.0f, 1.0f, 1.0f)); + + for (i = 0; i < key->vertexblend; ++i) { + for (c = 0; c < 4; ++c) { + cWM[c] = ureg_src_dimension(ureg_src_register(TGSI_FILE_CONSTANT, (160 + i * 4) * !key->vertexblend_indexed + c), 0); + if (key->vertexblend_indexed) + cWM[c] = ureg_src_indirect(cWM[c], ureg_scalar(ureg_src(AR), i)); + } + + /* multiply by WORLD(index) */ + ureg_MUL(ureg, tmp, _XXXX(vs->aVtx), cWM[0]); + ureg_MAD(ureg, tmp, _YYYY(vs->aVtx), cWM[1], ureg_src(tmp)); + ureg_MAD(ureg, tmp, _ZZZZ(vs->aVtx), cWM[2], ureg_src(tmp)); + ureg_MAD(ureg, tmp, _WWWW(vs->aVtx), cWM[3], ureg_src(tmp)); + + if (has_aNrm) { + /* Note: the spec says the transpose of the inverse of the + * WorldView matrices should be used, but all tests show + * otherwise. + * Only case unknown: D3DVBF_0WEIGHTS */ + ureg_MUL(ureg, tmp2, _XXXX(vs->aNrm), cWM[0]); + ureg_MAD(ureg, tmp2, _YYYY(vs->aNrm), cWM[1], ureg_src(tmp2)); + ureg_MAD(ureg, tmp2, _ZZZZ(vs->aNrm), cWM[2], ureg_src(tmp2)); + } + + if (i < (key->vertexblend - 1)) { + /* accumulate weighted position value */ + ureg_MAD(ureg, aVtx_dst, ureg_src(tmp), ureg_scalar(vs->aWgt, i), ureg_src(aVtx_dst)); + if (has_aNrm) + ureg_MAD(ureg, aNrm_dst, ureg_src(tmp2), ureg_scalar(vs->aWgt, i), ureg_src(aNrm_dst)); + /* subtract weighted position value for last value */ + ureg_ADD(ureg, sum_blendweights, ureg_src(sum_blendweights), ureg_negate(ureg_scalar(vs->aWgt, i))); + } + } + + /* the last weighted position is always 1 - sum_of_previous_weights */ + ureg_MAD(ureg, aVtx_dst, ureg_src(tmp), ureg_scalar(ureg_src(sum_blendweights), key->vertexblend - 1), ureg_src(aVtx_dst)); + if (has_aNrm) + ureg_MAD(ureg, aNrm_dst, ureg_src(tmp2), ureg_scalar(ureg_src(sum_blendweights), key->vertexblend - 1), ureg_src(aNrm_dst)); + + /* multiply by VIEW_PROJ */ + ureg_MUL(ureg, tmp, _X(aVtx_dst), _CONST(8)); + ureg_MAD(ureg, tmp, _Y(aVtx_dst), _CONST(9), ureg_src(tmp)); + ureg_MAD(ureg, tmp, _Z(aVtx_dst), _CONST(10), ureg_src(tmp)); + ureg_MAD(ureg, oPos, _W(aVtx_dst), _CONST(11), ureg_src(tmp)); + + if (need_aVtx) + vs->aVtx = ureg_src(aVtx_dst); + + ureg_release_temporary(ureg, tmp); + ureg_release_temporary(ureg, tmp2); + ureg_release_temporary(ureg, sum_blendweights); + if (!need_aVtx) + ureg_release_temporary(ureg, aVtx_dst); + + if (has_aNrm) { + if (key->normalizenormals) + ureg_normalize3(ureg, aNrm_dst, ureg_src(aNrm_dst)); + vs->aNrm = ureg_src(aNrm_dst); + } else + ureg_release_temporary(ureg, aNrm_dst); + } else { + struct ureg_dst tmp = ureg_DECL_temporary(ureg); + + if (key->vertextween) { + struct ureg_dst aVtx_dst = ureg_DECL_temporary(ureg); + ureg_LRP(ureg, aVtx_dst, _XXXX(_CONST(30)), vs->aVtx1, vs->aVtx); + vs->aVtx = ureg_src(aVtx_dst); + if (has_aNrm) { + struct ureg_dst aNrm_dst = ureg_DECL_temporary(ureg); + ureg_LRP(ureg, aNrm_dst, _XXXX(_CONST(30)), vs->aNrm1, vs->aNrm); + vs->aNrm = ureg_src(aNrm_dst); + } + } + + /* position = vertex * WORLD_VIEW_PROJ */ + ureg_MUL(ureg, tmp, _XXXX(vs->aVtx), _CONST(0)); + ureg_MAD(ureg, tmp, _YYYY(vs->aVtx), _CONST(1), ureg_src(tmp)); + ureg_MAD(ureg, tmp, _ZZZZ(vs->aVtx), _CONST(2), ureg_src(tmp)); + ureg_MAD(ureg, oPos, _WWWW(vs->aVtx), _CONST(3), ureg_src(tmp)); + ureg_release_temporary(ureg, tmp); + + if (need_aVtx) { + struct ureg_dst aVtx_dst = ureg_writemask(ureg_DECL_temporary(ureg), TGSI_WRITEMASK_XYZ); + ureg_MUL(ureg, aVtx_dst, _XXXX(vs->aVtx), _CONST(4)); + ureg_MAD(ureg, aVtx_dst, _YYYY(vs->aVtx), _CONST(5), ureg_src(aVtx_dst)); + ureg_MAD(ureg, aVtx_dst, _ZZZZ(vs->aVtx), _CONST(6), ureg_src(aVtx_dst)); + ureg_MAD(ureg, aVtx_dst, _WWWW(vs->aVtx), _CONST(7), ureg_src(aVtx_dst)); + vs->aVtx = ureg_src(aVtx_dst); + } + if (has_aNrm) { + struct ureg_dst aNrm_dst = ureg_writemask(ureg_DECL_temporary(ureg), TGSI_WRITEMASK_XYZ); + ureg_MUL(ureg, aNrm_dst, _XXXX(vs->aNrm), _CONST(16)); + ureg_MAD(ureg, aNrm_dst, _YYYY(vs->aNrm), _CONST(17), ureg_src(aNrm_dst)); + ureg_MAD(ureg, aNrm_dst, _ZZZZ(vs->aNrm), _CONST(18), ureg_src(aNrm_dst)); + if (key->normalizenormals) + ureg_normalize3(ureg, aNrm_dst, ureg_src(aNrm_dst)); + vs->aNrm = ureg_src(aNrm_dst); + } + } + + /* === Process point size: + */ + if (key->vertexpointsize || key->pointscale || device->driver_caps.always_output_pointsize) { + struct ureg_dst tmp = ureg_DECL_temporary(ureg); + struct ureg_dst tmp_x = ureg_writemask(tmp, TGSI_WRITEMASK_X); + struct ureg_dst tmp_y = ureg_writemask(tmp, TGSI_WRITEMASK_Y); + struct ureg_dst tmp_z = ureg_writemask(tmp, TGSI_WRITEMASK_Z); + if (key->vertexpointsize) { + struct ureg_src cPsz1 = ureg_DECL_constant(ureg, 26); + ureg_MAX(ureg, tmp_z, _XXXX(vs->aPsz), _XXXX(cPsz1)); + ureg_MIN(ureg, tmp_z, _Z(tmp), _YYYY(cPsz1)); + } else { + struct ureg_src cPsz1 = ureg_DECL_constant(ureg, 26); + ureg_MOV(ureg, tmp_z, _ZZZZ(cPsz1)); + } + + if (key->pointscale) { + struct ureg_src cPsz1 = ureg_DECL_constant(ureg, 26); + struct ureg_src cPsz2 = ureg_DECL_constant(ureg, 27); + + ureg_DP3(ureg, tmp_x, vs->aVtx, vs->aVtx); + ureg_RSQ(ureg, tmp_y, _X(tmp)); + ureg_MUL(ureg, tmp_y, _Y(tmp), _X(tmp)); + ureg_CMP(ureg, tmp_y, ureg_negate(_Y(tmp)), _Y(tmp), ureg_imm1f(ureg, 0.0f)); + ureg_MAD(ureg, tmp_x, _Y(tmp), _YYYY(cPsz2), _XXXX(cPsz2)); + ureg_MAD(ureg, tmp_x, _Y(tmp), _X(tmp), _WWWW(cPsz1)); + ureg_RSQ(ureg, tmp_x, _X(tmp)); + ureg_MUL(ureg, tmp_x, _X(tmp), _Z(tmp)); + ureg_MUL(ureg, tmp_x, _X(tmp), _WWWW(_CONST(100))); + ureg_MAX(ureg, tmp_x, _X(tmp), _XXXX(cPsz1)); + ureg_MIN(ureg, tmp_z, _X(tmp), _YYYY(cPsz1)); + } + + ureg_MOV(ureg, oPsz, _Z(tmp)); + ureg_release_temporary(ureg, tmp); + } + + for (i = 0; i < 8; ++i) { + struct ureg_dst tmp, tmp_x, tmp2; + struct ureg_dst oTex, input_coord, transformed, t, aVtx_normed; + unsigned c, writemask; + const unsigned tci = (key->tc_gen >> (i * 3)) & 0x7; + const unsigned idx = (key->tc_idx >> (i * 3)) & 0x7; + unsigned dim_input = 1 + ((key->tc_dim_input >> (i * 2)) & 0x3); + const unsigned dim_output = (key->tc_dim_output >> (i * 3)) & 0x7; + + /* No texture output of index s */ + if (tci == NINED3DTSS_TCI_DISABLE) + continue; + oTex = ureg_DECL_output(ureg, texcoord_sn, i); + tmp = ureg_DECL_temporary(ureg); + tmp_x = ureg_writemask(tmp, TGSI_WRITEMASK_X); + input_coord = ureg_DECL_temporary(ureg); + transformed = ureg_DECL_temporary(ureg); + + /* Get the coordinate */ + switch (tci) { + case NINED3DTSS_TCI_PASSTHRU: + /* NINED3DTSS_TCI_PASSTHRU => Use texcoord coming from index idx * + * Else the idx is used only to determine wrapping mode. */ + vs->aTex[idx] = build_vs_add_input(vs, NINE_DECLUSAGE_i(TEXCOORD,idx)); + ureg_MOV(ureg, input_coord, vs->aTex[idx]); + break; + case NINED3DTSS_TCI_CAMERASPACENORMAL: + ureg_MOV(ureg, ureg_writemask(input_coord, TGSI_WRITEMASK_XYZ), vs->aNrm); + ureg_MOV(ureg, ureg_writemask(input_coord, TGSI_WRITEMASK_W), ureg_imm1f(ureg, 1.0f)); + dim_input = 4; + break; + case NINED3DTSS_TCI_CAMERASPACEPOSITION: + ureg_MOV(ureg, ureg_writemask(input_coord, TGSI_WRITEMASK_XYZ), vs->aVtx); + ureg_MOV(ureg, ureg_writemask(input_coord, TGSI_WRITEMASK_W), ureg_imm1f(ureg, 1.0f)); + dim_input = 4; + break; + case NINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR: + tmp.WriteMask = TGSI_WRITEMASK_XYZ; + aVtx_normed = ureg_DECL_temporary(ureg); + ureg_normalize3(ureg, aVtx_normed, vs->aVtx); + ureg_DP3(ureg, tmp_x, ureg_src(aVtx_normed), vs->aNrm); + ureg_MUL(ureg, tmp, vs->aNrm, _X(tmp)); + ureg_ADD(ureg, tmp, ureg_src(tmp), ureg_src(tmp)); + ureg_ADD(ureg, ureg_writemask(input_coord, TGSI_WRITEMASK_XYZ), ureg_src(aVtx_normed), ureg_negate(ureg_src(tmp))); + ureg_MOV(ureg, ureg_writemask(input_coord, TGSI_WRITEMASK_W), ureg_imm1f(ureg, 1.0f)); + ureg_release_temporary(ureg, aVtx_normed); + dim_input = 4; + tmp.WriteMask = TGSI_WRITEMASK_XYZW; + break; + case NINED3DTSS_TCI_SPHEREMAP: + /* Implement the formula of GL_SPHERE_MAP */ + tmp.WriteMask = TGSI_WRITEMASK_XYZ; + aVtx_normed = ureg_DECL_temporary(ureg); + tmp2 = ureg_DECL_temporary(ureg); + ureg_normalize3(ureg, aVtx_normed, vs->aVtx); + ureg_DP3(ureg, tmp_x, ureg_src(aVtx_normed), vs->aNrm); + ureg_MUL(ureg, tmp, vs->aNrm, _X(tmp)); + ureg_ADD(ureg, tmp, ureg_src(tmp), ureg_src(tmp)); + ureg_ADD(ureg, tmp, ureg_src(aVtx_normed), ureg_negate(ureg_src(tmp))); + /* now tmp = normed(Vtx) - 2 dot3(normed(Vtx), Nrm) Nrm */ + ureg_MOV(ureg, ureg_writemask(tmp2, TGSI_WRITEMASK_XYZ), ureg_src(tmp)); + ureg_MUL(ureg, tmp2, ureg_src(tmp2), ureg_src(tmp2)); + ureg_DP3(ureg, ureg_writemask(tmp2, TGSI_WRITEMASK_X), ureg_src(tmp2), ureg_src(tmp2)); + ureg_RSQ(ureg, ureg_writemask(tmp2, TGSI_WRITEMASK_X), ureg_src(tmp2)); + ureg_MUL(ureg, ureg_writemask(tmp2, TGSI_WRITEMASK_X), ureg_src(tmp2), ureg_imm1f(ureg, 0.5f)); + /* tmp2 = 0.5 / sqrt(tmp.x^2 + tmp.y^2 + (tmp.z+1)^2) + * TODO: z coordinates are a bit different gl vs d3d, should the formula be adapted ? */ + ureg_MUL(ureg, tmp, ureg_src(tmp), _X(tmp2)); + ureg_ADD(ureg, ureg_writemask(input_coord, TGSI_WRITEMASK_XY), ureg_src(tmp), ureg_imm1f(ureg, 0.5f)); + ureg_MOV(ureg, ureg_writemask(input_coord, TGSI_WRITEMASK_ZW), ureg_imm4f(ureg, 0.0f, 0.0f, 0.0f, 1.0f)); + ureg_release_temporary(ureg, aVtx_normed); + ureg_release_temporary(ureg, tmp2); + dim_input = 4; + tmp.WriteMask = TGSI_WRITEMASK_XYZW; + break; + default: + assert(0); + break; + } + + /* Apply the transformation */ + /* dim_output == 0 => do not transform the components. + * XYZRHW also disables transformation */ + if (!dim_output || key->position_t) { + ureg_release_temporary(ureg, transformed); + transformed = input_coord; + writemask = TGSI_WRITEMASK_XYZW; + } else { + for (c = 0; c < dim_output; c++) { + t = ureg_writemask(transformed, 1 << c); + switch (dim_input) { + /* dim_input = 1 2 3: -> we add trailing 1 to input*/ + case 1: ureg_MAD(ureg, t, _X(input_coord), _XXXX(_CONST(128 + i * 4 + c)), _YYYY(_CONST(128 + i * 4 + c))); + break; + case 2: ureg_DP2(ureg, t, ureg_src(input_coord), _CONST(128 + i * 4 + c)); + ureg_ADD(ureg, t, ureg_src(transformed), _ZZZZ(_CONST(128 + i * 4 + c))); + break; + case 3: ureg_DP3(ureg, t, ureg_src(input_coord), _CONST(128 + i * 4 + c)); + ureg_ADD(ureg, t, ureg_src(transformed), _WWWW(_CONST(128 + i * 4 + c))); + break; + case 4: ureg_DP4(ureg, t, ureg_src(input_coord), _CONST(128 + i * 4 + c)); break; + default: + assert(0); + } + } + writemask = (1 << dim_output) - 1; + ureg_release_temporary(ureg, input_coord); + } + + ureg_MOV(ureg, ureg_writemask(oTex, writemask), ureg_src(transformed)); + ureg_release_temporary(ureg, transformed); + ureg_release_temporary(ureg, 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 = ureg_DECL_temporary(ureg); + struct ureg_dst tmp_x = ureg_writemask(tmp, TGSI_WRITEMASK_X); + struct ureg_dst tmp_y = ureg_writemask(tmp, TGSI_WRITEMASK_Y); + struct ureg_dst tmp_z = ureg_writemask(tmp, TGSI_WRITEMASK_Z); + struct ureg_dst rAtt = ureg_writemask(ureg_DECL_temporary(ureg), TGSI_WRITEMASK_W); + struct ureg_dst rHit = ureg_writemask(ureg_DECL_temporary(ureg), TGSI_WRITEMASK_XYZ); + struct ureg_dst rMid = ureg_writemask(ureg_DECL_temporary(ureg), TGSI_WRITEMASK_XYZ); + + struct ureg_dst rCtr = ureg_writemask(ureg_DECL_temporary(ureg), TGSI_WRITEMASK_W); + + struct ureg_dst AL = ureg_writemask(AR, TGSI_WRITEMASK_X); + + /* Light.*.Alpha is not used. */ + struct ureg_dst rD = ureg_writemask(ureg_DECL_temporary(ureg), TGSI_WRITEMASK_XYZ); + struct ureg_dst rA = ureg_writemask(ureg_DECL_temporary(ureg), TGSI_WRITEMASK_XYZ); + struct ureg_dst rS = ureg_DECL_temporary(ureg); + + 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++; + + /* Declare all light constants to allow indirect addressing */ + for (i = 32; i < 96; i++) + ureg_DECL_constant(ureg, i); + + 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)); + + /* 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) + */ + ureg_ADD(ureg, rHit, cLPos, ureg_negate(vs->aVtx)); + ureg_DP3(ureg, tmp_x, ureg_src(rHit), ureg_src(rHit)); + ureg_RSQ(ureg, tmp_y, _X(tmp)); + 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); + + /* normalize hitDir */ + ureg_normalize3(ureg, rHit, ureg_src(rHit)); + + /* 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_ADD(ureg, tmp_x, _Y(tmp), ureg_negate(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 */ + + if (has_aNrm) { + if (key->localviewer) { + ureg_normalize3(ureg, rMid, vs->aVtx); + 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)); + ureg_DP3(ureg, ureg_saturate(tmp_x), vs->aNrm, ureg_src(rHit)); + ureg_DP3(ureg, ureg_saturate(tmp_y), vs->aNrm, ureg_src(rMid)); + ureg_MUL(ureg, tmp_z, _X(tmp), _Y(tmp)); + /* Tests show that specular is computed only if (dp3(normal,hitDir) > 0). + * For front facing, it is more restrictive than test (dp3(normal,mid) > 0). + * No tests were made for backfacing, so add the two conditions */ + ureg_IF(ureg, _Z(tmp), &label[l++]); + { + ureg_DP3(ureg, ureg_saturate(tmp_y), vs->aNrm, ureg_src(rMid)); + ureg_POW(ureg, tmp_y, _Y(tmp), mtlP); + ureg_MUL(ureg, tmp_y, _W(rAtt), _Y(tmp)); /* power factor * att */ + 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_MUL(ureg, tmp_x, _W(rAtt), _X(tmp)); /* dp3(normal,hitDir) * att */ + ureg_MAD(ureg, rD, cLColD, _X(tmp), ureg_src(rD)); /* accumulate diffuse */ + } + + 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]); + + /* 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_MAD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_XYZ), 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_MAD(ureg, ureg_writemask(oCol[0], TGSI_WRITEMASK_XYZ), ureg_src(rD), vs->mtlD, ureg_src(tmp)); + ureg_MOV(ureg, ureg_writemask(oCol[0], TGSI_WRITEMASK_W), vs->mtlD); + ureg_MUL(ureg, oCol[1], ureg_src(rS), vs->mtlS); + ureg_release_temporary(ureg, rAtt); + ureg_release_temporary(ureg, rHit); + ureg_release_temporary(ureg, rMid); + ureg_release_temporary(ureg, rCtr); + ureg_release_temporary(ureg, rD); + ureg_release_temporary(ureg, rA); + ureg_release_temporary(ureg, rS); + ureg_release_temporary(ureg, rAtt); + ureg_release_temporary(ureg, tmp); + } else + /* COLOR */ + if (key->darkness) { + if (key->mtl_emissive == 0 && key->mtl_ambient == 0) + ureg_MOV(ureg, ureg_writemask(oCol[0], TGSI_WRITEMASK_XYZ), _CONST(19)); + else + ureg_MAD(ureg, ureg_writemask(oCol[0], TGSI_WRITEMASK_XYZ), vs->mtlA, _CONST(25), vs->mtlE); + ureg_MOV(ureg, ureg_writemask(oCol[0], TGSI_WRITEMASK_W), vs->mtlD); + ureg_MOV(ureg, oCol[1], ureg_imm1f(ureg, 0.0f)); + } else { + ureg_MOV(ureg, oCol[0], vs->aCol[0]); + ureg_MOV(ureg, oCol[1], vs->aCol[1]); + } + + /* === Process fog. + * + * exp(x) = ex2(log2(e) * x) + */ + if (key->fog_mode) { + struct ureg_dst tmp = ureg_DECL_temporary(ureg); + struct ureg_dst tmp_x = ureg_writemask(tmp, TGSI_WRITEMASK_X); + struct ureg_dst tmp_z = ureg_writemask(tmp, TGSI_WRITEMASK_Z); + if (key->fog_range) { + ureg_DP3(ureg, tmp_x, vs->aVtx, vs->aVtx); + ureg_RSQ(ureg, tmp_z, _X(tmp)); + ureg_MUL(ureg, tmp_z, _Z(tmp), _X(tmp)); + } else { + ureg_MOV(ureg, tmp_z, ureg_abs(_ZZZZ(vs->aVtx))); + } + + 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) { + ureg_ADD(ureg, tmp_x, _XXXX(_CONST(28)), ureg_negate(_Z(tmp))); + ureg_MUL(ureg, ureg_saturate(tmp_x), _X(tmp), _YYYY(_CONST(28))); + } + ureg_MOV(ureg, oFog, _X(tmp)); + ureg_release_temporary(ureg, tmp); + } else if (key->fog && !(key->passthrough & (1 << NINE_DECLUSAGE_FOG))) { + ureg_MOV(ureg, oFog, ureg_scalar(vs->aCol[1], TGSI_SWIZZLE_W)); + } + + if (key->passthrough & (1 << NINE_DECLUSAGE_BLENDWEIGHT)) { + struct ureg_src input; + struct ureg_dst output; + input = vs->aWgt; + output = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 19); + ureg_MOV(ureg, output, input); + } + if (key->passthrough & (1 << NINE_DECLUSAGE_BLENDINDICES)) { + struct ureg_src input; + struct ureg_dst output; + input = vs->aInd; + output = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 20); + ureg_MOV(ureg, output, input); + } + if (key->passthrough & (1 << NINE_DECLUSAGE_NORMAL)) { + struct ureg_src input; + struct ureg_dst output; + input = vs->aNrm; + output = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 21); + ureg_MOV(ureg, output, input); + } + if (key->passthrough & (1 << NINE_DECLUSAGE_TANGENT)) { + struct ureg_src input; + struct ureg_dst output; + input = build_vs_add_input(vs, NINE_DECLUSAGE_TANGENT); + output = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 22); + ureg_MOV(ureg, output, input); + } + if (key->passthrough & (1 << NINE_DECLUSAGE_BINORMAL)) { + struct ureg_src input; + struct ureg_dst output; + input = build_vs_add_input(vs, NINE_DECLUSAGE_BINORMAL); + output = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 23); + ureg_MOV(ureg, output, input); + } + if (key->passthrough & (1 << NINE_DECLUSAGE_FOG)) { + struct ureg_src input; + struct ureg_dst output; + input = build_vs_add_input(vs, NINE_DECLUSAGE_FOG); + input = ureg_scalar(input, TGSI_SWIZZLE_X); + output = oFog; + ureg_MOV(ureg, output, input); + } + if (key->passthrough & (1 << NINE_DECLUSAGE_DEPTH)) { + (void) 0; /* TODO: replace z of position output ? */ + } + + /* ucp for ff applies on world coordinates. + * aVtx is in worldview coordinates. */ + if (key->ucp) { + struct ureg_dst tmp = ureg_DECL_temporary(ureg); + ureg_MUL(ureg, tmp, _XXXX(vs->aVtx), _CONST(12)); + ureg_MAD(ureg, tmp, _YYYY(vs->aVtx), _CONST(13), ureg_src(tmp)); + ureg_MAD(ureg, tmp, _ZZZZ(vs->aVtx), _CONST(14), ureg_src(tmp)); + if (!key->clipplane_emulate) { + struct ureg_dst clipVect = ureg_DECL_output(ureg, TGSI_SEMANTIC_CLIPVERTEX, 0); + ureg_ADD(ureg, clipVect, _CONST(15), ureg_src(tmp)); + } else { + struct ureg_dst clipdist[2] = {ureg_dst_undef(), ureg_dst_undef()}; + int num_clipdist = ffs(key->clipplane_emulate); + ureg_ADD(ureg, tmp, _CONST(15), ureg_src(tmp)); + clipdist[0] = ureg_DECL_output_masked(ureg, TGSI_SEMANTIC_CLIPDIST, 0, + ((1 << num_clipdist) - 1) & 0xf, 0, 1); + if (num_clipdist >= 5) + clipdist[1] = ureg_DECL_output_masked(ureg, TGSI_SEMANTIC_CLIPDIST, 1, + ((1 << (num_clipdist - 4)) - 1) & 0xf, 0, 1); + ureg_property(ureg, TGSI_PROPERTY_NUM_CLIPDIST_ENABLED, num_clipdist); + for (i = 0; i < num_clipdist; i++) { + assert(!ureg_dst_is_undef(clipdist[i>>2])); + if (!(key->clipplane_emulate & (1 << i))) + ureg_MOV(ureg, ureg_writemask(clipdist[i>>2], 1 << (i & 0x2)), ureg_imm1f(ureg, 0.f)); + else + ureg_DP4(ureg, ureg_writemask(clipdist[i>>2], 1 << (i & 0x2)), + ureg_src(tmp), _CONST(196+i)); + } + } + ureg_release_temporary(ureg, tmp); + } + + 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 nine_create_shader_with_so_and_destroy(ureg, device->context.pipe, NULL); +} + +/* 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 + * CONST[22].___w Alpha ref + */ +struct ps_build_ctx +{ + struct ureg_program *ureg; + unsigned color_interpolate_flag; + + struct ureg_src vC[2]; /* DIFFUSE, SPECULAR */ + struct ureg_src vT[8]; /* TEXCOORD[i] */ + 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; + } 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, ps->color_interpolate_flag); + break; + case D3DTA_SPECULAR: + reg = ureg_DECL_fs_input(ps->ureg, TGSI_SEMANTIC_COLOR, 1, ps->color_interpolate_flag); + 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 = ureg_DECL_temporary(ps->ureg); + ureg_ADD(ps->ureg, dst, ureg_imm1f(ps->ureg, 1.0f), ureg_negate(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 bool +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 = ureg_DECL_temporary(ureg); + struct ureg_dst tmp2 = ureg_DECL_temporary(ureg); + 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_ADD(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_ADD(ureg, dst, arg[1], ureg_negate(arg[2])); + break; + case D3DTOP_ADDSMOOTH: + ureg_ADD(ureg, tmp, ureg_imm1f(ureg, 1.0f), ureg_negate(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_ADD(ureg, tmp_x, ureg_imm1f(ureg, 1.0f), ureg_negate(_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_ADD(ureg, tmp_x, ureg_imm1f(ureg, 1.0f), ureg_negate(_WWWW(arg[1]))); + ureg_MAD(ureg, dst, _X(tmp), arg[2], arg[1]); + break; + case D3DTOP_MODULATEINVCOLOR_ADDALPHA: + ureg_ADD(ureg, tmp, ureg_imm1f(ureg, 1.0f), ureg_negate(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_ADD(ureg, tmp, arg[1], ureg_imm4f(ureg,-0.5,-0.5,-0.5,-0.5)); + ureg_ADD(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[1], arg[2], arg[0]); + break; + case D3DTOP_LERP: + ureg_LRP(ureg, dst, arg[0], arg[1], arg[2]); + break; + case D3DTOP_DISABLE: + /* no-op ? */ + break; + default: + assert(!"invalid D3DTOP"); + break; + } + ureg_release_temporary(ureg, tmp); + ureg_release_temporary(ureg, tmp2); +} + +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(MESA_SHADER_FRAGMENT); + struct ureg_dst oCol; + unsigned s; + const unsigned texcoord_sn = get_texcoord_sn(device->screen); + + memset(&ps, 0, sizeof(ps)); + ps.ureg = ureg; + ps.color_interpolate_flag = key->flatshade ? TGSI_INTERPOLATE_CONSTANT : TGSI_INTERPOLATE_PERSPECTIVE; + ps.stage.index_pre_mod = -1; + + ps.vC[0] = ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_COLOR, 0, ps.color_interpolate_flag); + + ps.rCur = ureg_DECL_temporary(ureg); + ps.rTmp = ureg_DECL_temporary(ureg); + ps.rTex = ureg_DECL_temporary(ureg); + ps.rCurSrc = ureg_src(ps.rCur); + ps.rTmpSrc = ureg_src(ps.rTmp); + ps.rTexSrc = ureg_src(ps.rTex); + + /* Initial values */ + ureg_MOV(ureg, ps.rCur, ps.vC[0]); + ureg_MOV(ureg, ps.rTmp, ureg_imm1f(ureg, 0.0f)); + ureg_MOV(ureg, ps.rTex, ureg_imm1f(ureg, 0.0f)); + + 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, ps.color_interpolate_flag); + + if (key->ts[s].colorarg0 == D3DTA_TEXTURE || + key->ts[s].colorarg1 == D3DTA_TEXTURE || + key->ts[s].colorarg2 == D3DTA_TEXTURE || + key->ts[s].colorop == D3DTOP_BLENDTEXTUREALPHA || + key->ts[s].colorop == D3DTOP_BLENDTEXTUREALPHAPM) { + 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, ps.color_interpolate_flag); + + if (key->ts[s].alphaarg0 == D3DTA_TEXTURE || + key->ts[s].alphaarg1 == D3DTA_TEXTURE || + key->ts[s].alphaarg2 == D3DTA_TEXTURE || + key->ts[s].colorop == D3DTOP_BLENDTEXTUREALPHA || + key->ts[s].colorop == D3DTOP_BLENDTEXTUREALPHAPM) { + 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, ps.color_interpolate_flag); + + oCol = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0); + + /* 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) { + assert (key->ts[s].alphaop == D3DTOP_DISABLE); + continue; + } + ps.stage.index = s; + + 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; + struct ureg_src texture_coord = ps.vT[s]; + struct ureg_dst delta; + 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 ? */ + } + + /* Modify coordinates */ + if (s >= 1 && + (key->ts[s-1].colorop == D3DTOP_BUMPENVMAP || + key->ts[s-1].colorop == D3DTOP_BUMPENVMAPLUMINANCE)) { + delta = ureg_DECL_temporary(ureg); + /* Du' = D3DTSS_BUMPENVMAT00(stage s-1)*t(s-1)R + D3DTSS_BUMPENVMAT10(stage s-1)*t(s-1)G */ + ureg_MUL(ureg, ureg_writemask(delta, TGSI_WRITEMASK_X), _X(ps.rTex), _XXXX(_CONST(8 + s - 1))); + ureg_MAD(ureg, ureg_writemask(delta, TGSI_WRITEMASK_X), _Y(ps.rTex), _ZZZZ(_CONST(8 + s - 1)), ureg_src(delta)); + /* Dv' = D3DTSS_BUMPENVMAT01(stage s-1)*t(s-1)R + D3DTSS_BUMPENVMAT11(stage s-1)*t(s-1)G */ + ureg_MUL(ureg, ureg_writemask(delta, TGSI_WRITEMASK_Y), _X(ps.rTex), _YYYY(_CONST(8 + s - 1))); + ureg_MAD(ureg, ureg_writemask(delta, TGSI_WRITEMASK_Y), _Y(ps.rTex), _WWWW(_CONST(8 + s - 1)), ureg_src(delta)); + texture_coord = ureg_src(ureg_DECL_temporary(ureg)); + ureg_MOV(ureg, ureg_writemask(ureg_dst(texture_coord), ureg_dst(ps.vT[s]).WriteMask), ps.vT[s]); + ureg_ADD(ureg, ureg_writemask(ureg_dst(texture_coord), TGSI_WRITEMASK_XY), texture_coord, ureg_src(delta)); + /* Prepare luminance multiplier + * t(s)RGBA = t(s)RGBA * clamp[(t(s-1)B * D3DTSS_BUMPENVLSCALE(stage s-1)) + D3DTSS_BUMPENVLOFFSET(stage s-1)] */ + if (key->ts[s-1].colorop == D3DTOP_BUMPENVMAPLUMINANCE) { + struct ureg_src bumpenvlscale = ((s-1) & 1) ? _ZZZZ(_CONST(16 + (s-1) / 2)) : _XXXX(_CONST(16 + (s-1) / 2)); + struct ureg_src bumpenvloffset = ((s-1) & 1) ? _WWWW(_CONST(16 + (s-1) / 2)) : _YYYY(_CONST(16 + (s-1) / 2)); + + ureg_MAD(ureg, ureg_saturate(ureg_writemask(delta, TGSI_WRITEMASK_X)), _Z(ps.rTex), bumpenvlscale, bumpenvloffset); + } + } + if (key->projected & (3 << (s *2))) { + unsigned dim = 1 + ((key->projected >> (2 * s)) & 3); + if (dim == 4) + ureg_TXP(ureg, ps.rTex, target, texture_coord, ps.s[s]); + else { + struct ureg_dst tmp = ureg_DECL_temporary(ureg); + ureg_RCP(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), ureg_scalar(texture_coord, dim-1)); + ureg_MUL(ureg, ps.rTmp, _X(tmp), texture_coord); + ureg_TEX(ureg, ps.rTex, target, ps.rTmpSrc, ps.s[s]); + ureg_release_temporary(ureg, tmp); + } + } else { + ureg_TEX(ureg, ps.rTex, target, texture_coord, ps.s[s]); + } + if (s >= 1 && key->ts[s-1].colorop == D3DTOP_BUMPENVMAPLUMINANCE) + ureg_MUL(ureg, ps.rTex, ureg_src(ps.rTex), _X(delta)); + } + + if (key->ts[s].colorop == D3DTOP_BUMPENVMAP || + key->ts[s].colorop == D3DTOP_BUMPENVMAPLUMINANCE) + continue; + + 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 = ureg_DECL_temporary(ureg); + ureg_MUL(ureg, ps.rMod, ps.rCurSrc, ps.rTexSrc); + } + + colorarg[0] = (key->ts[s].colorarg0 | (((key->colorarg_b4[0] >> s) & 0x1) << 4) | ((key->colorarg_b5[0] >> s) << 5)) & 0x3f; + colorarg[1] = (key->ts[s].colorarg1 | (((key->colorarg_b4[1] >> s) & 0x1) << 4) | ((key->colorarg_b5[1] >> s) << 5)) & 0x3f; + colorarg[2] = (key->ts[s].colorarg2 | (((key->colorarg_b4[2] >> s) & 0x1) << 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; + + /* Special DOTPRODUCT behaviour (see wine tests) */ + if (key->ts[s].colorop == D3DTOP_DOTPRODUCT3) + dst.WriteMask = TGSI_WRITEMASK_XYZW; + + 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, ureg_writemask(ps.rCur, TGSI_WRITEMASK_XYZ), ps.rCurSrc, ps.vC[1]); + + if (key->alpha_test_emulation == PIPE_FUNC_NEVER) { + ureg_KILL(ureg); + } else if (key->alpha_test_emulation != PIPE_FUNC_ALWAYS) { + unsigned cmp_op; + struct ureg_src src[2]; + struct ureg_dst tmp = ps.rTmp; + cmp_op = pipe_comp_to_tgsi_opposite(key->alpha_test_emulation); + src[0] = ureg_scalar(ps.rCurSrc, TGSI_SWIZZLE_W); /* Read color alpha channel */ + src[1] = _WWWW(_CONST(22)); /* Read alpha ref */ + ureg_insn(ureg, cmp_op, &tmp, 1, src, 2, 0); + ureg_KILL_IF(ureg, ureg_negate(ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X))); /* if opposite test passes, discard */ + } + + /* Fog. + */ + if (key->fog_mode) { + struct ureg_dst rFog = ureg_writemask(ps.rTmp, TGSI_WRITEMASK_X); + struct ureg_src vPos; + if (device->screen->caps.fs_position_is_sysval) { + vPos = ureg_DECL_system_value(ureg, TGSI_SEMANTIC_POSITION, 0); + } else { + vPos = ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_POSITION, 0, + TGSI_INTERPOLATE_LINEAR); + } + + /* Source is either W or Z. + * Z is when an orthogonal projection matrix is detected, + * W (WFOG) else. + */ + if (!key->fog_source) + ureg_MOV(ureg, rFog, _ZZZZ(vPos)); + else + /* Position's w is 1/w */ + ureg_RCP(ureg, rFog, _WWWW(vPos)); + + if (key->fog_mode == D3DFOG_EXP) { + ureg_MUL(ureg, rFog, _X(rFog), _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, _X(rFog), _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_ADD(ureg, rFog, _XXXX(_CONST(22)), ureg_negate(_X(rFog))); + 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_GENERIC, 16, 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 nine_create_shader_with_so_and_destroy(ureg, device->context.pipe, NULL); +} + +static struct NineVertexShader9 * +nine_ff_get_vs(struct NineDevice9 *device) +{ + const struct nine_context *context = &device->context; + struct NineVertexShader9 *vs; + struct vs_build_ctx bld; + struct nine_ff_vs_key key; + unsigned s, i; + bool has_indexes = false; + bool has_weights = false; + int8_t input_texture_coord[8]; + + assert(sizeof(key) <= sizeof(key.value32)); + + memset(&key, 0, sizeof(key)); + memset(&bld, 0, sizeof(bld)); + memset(&input_texture_coord, 0, sizeof(input_texture_coord)); + + bld.key = &key; + + /* FIXME: this shouldn't be NULL, but it is on init */ + if (context->vdecl) { + key.color0in_one = 1; + key.color1in_zero = 1; + for (i = 0; i < context->vdecl->nelems; i++) { + uint16_t usage = context->vdecl->usage_map[i]; + if (usage == NINE_DECLUSAGE_POSITIONT) + key.position_t = 1; + else if (usage == NINE_DECLUSAGE_i(COLOR, 0)) + key.color0in_one = 0; + else if (usage == NINE_DECLUSAGE_i(COLOR, 1)) + key.color1in_zero = 0; + else if (usage == NINE_DECLUSAGE_i(BLENDINDICES, 0)) { + has_indexes = true; + key.passthrough |= 1 << usage; + } else if (usage == NINE_DECLUSAGE_i(BLENDWEIGHT, 0)) { + has_weights = true; + key.passthrough |= 1 << usage; + } else if (usage == NINE_DECLUSAGE_i(NORMAL, 0)) { + key.has_normal = 1; + key.passthrough |= 1 << usage; + } else if (usage == NINE_DECLUSAGE_PSIZE) + key.vertexpointsize = 1; + else if (usage % NINE_DECLUSAGE_COUNT == NINE_DECLUSAGE_TEXCOORD) { + s = usage / NINE_DECLUSAGE_COUNT; + if (s < 8) + input_texture_coord[s] = nine_decltype_get_dim(context->vdecl->decls[i].Type); + else + DBG("FF given texture coordinate >= 8. Ignoring\n"); + } else if (usage < NINE_DECLUSAGE_NONE) + key.passthrough |= 1 << usage; + } + } + /* ff vs + ps 3.0: some elements are passed to the ps (wine test). + * We do restrict to indices 0 */ + key.passthrough &= ~((1 << NINE_DECLUSAGE_POSITION) | (1 << NINE_DECLUSAGE_PSIZE) | + (1 << NINE_DECLUSAGE_TEXCOORD) | (1 << NINE_DECLUSAGE_POSITIONT) | + (1 << NINE_DECLUSAGE_TESSFACTOR) | (1 << NINE_DECLUSAGE_SAMPLE)); + if (!key.position_t) + key.passthrough = 0; + key.pointscale = !!context->rs[D3DRS_POINTSCALEENABLE]; + + key.lighting = !!context->rs[D3DRS_LIGHTING] && context->ff.num_lights_active; + key.darkness = !!context->rs[D3DRS_LIGHTING] && !context->ff.num_lights_active; + if (key.position_t) { + key.darkness = 0; /* |= key.lighting; */ /* XXX ? */ + key.lighting = 0; + } + if ((key.lighting | key.darkness) && context->rs[D3DRS_COLORVERTEX]) { + uint32_t mask = (key.color0in_one ? 0 : 1) | (key.color1in_zero ? 0 : 2); + key.mtl_diffuse = context->rs[D3DRS_DIFFUSEMATERIALSOURCE] & mask; + key.mtl_ambient = context->rs[D3DRS_AMBIENTMATERIALSOURCE] & mask; + key.mtl_specular = context->rs[D3DRS_SPECULARMATERIALSOURCE] & mask; + key.mtl_emissive = context->rs[D3DRS_EMISSIVEMATERIALSOURCE] & mask; + } + key.fog = !!context->rs[D3DRS_FOGENABLE]; + key.fog_mode = (!key.position_t && context->rs[D3DRS_FOGENABLE]) ? context->rs[D3DRS_FOGVERTEXMODE] : 0; + if (key.fog_mode) + key.fog_range = context->rs[D3DRS_RANGEFOGENABLE]; + + key.localviewer = !!context->rs[D3DRS_LOCALVIEWER]; + key.normalizenormals = !!context->rs[D3DRS_NORMALIZENORMALS]; + key.ucp = !!context->rs[D3DRS_CLIPPLANEENABLE]; + key.clipplane_emulate = device->driver_caps.emulate_ucp ? (context->rs[D3DRS_CLIPPLANEENABLE] & 0xff) : 0; + + if (context->rs[D3DRS_VERTEXBLEND] != D3DVBF_DISABLE) { + key.vertexblend_indexed = !!context->rs[D3DRS_INDEXEDVERTEXBLENDENABLE] && has_indexes; + + switch (context->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; + } + if (!has_weights && context->rs[D3DRS_VERTEXBLEND] != D3DVBF_0WEIGHTS) + key.vertexblend = 0; /* TODO: if key.vertexblend_indexed, perhaps it should use 1.0 as weight, or revert to D3DVBF_0WEIGHTS */ + } + + for (s = 0; s < 8; ++s) { + unsigned gen = (context->ff.tex_stage[s][D3DTSS_TEXCOORDINDEX] >> 16) + 1; + unsigned idx = context->ff.tex_stage[s][D3DTSS_TEXCOORDINDEX] & 7; + unsigned dim; + + if (key.position_t && gen > NINED3DTSS_TCI_PASSTHRU) + gen = NINED3DTSS_TCI_PASSTHRU; + + if (!input_texture_coord[idx] && gen == NINED3DTSS_TCI_PASSTHRU) + gen = NINED3DTSS_TCI_DISABLE; + + key.tc_gen |= gen << (s * 3); + key.tc_idx |= idx << (s * 3); + key.tc_dim_input |= ((input_texture_coord[idx]-1) & 0x3) << (s * 2); + + dim = context->ff.tex_stage[s][D3DTSS_TEXTURETRANSFORMFLAGS] & 0x7; + if (dim > 4) + dim = input_texture_coord[idx]; + if (dim == 1) /* NV behaviour */ + dim = 0; + key.tc_dim_output |= dim << (s * 3); + } + + DBG("VS ff key hash: %x\n", nine_ff_vs_key_hash(&key)); + 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)); + + _mesa_hash_table_insert(device->ff.ht_vs, &vs->ff_key, vs); + device->ff.num_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 | device->driver_caps.always_output_pointsize; + } + return vs; +} + +#define GET_D3DTS(n) nine_state_access_transform(&context->ff, D3DTS_##n, FALSE) +#define IS_D3DTS_DIRTY(s,n) ((s)->ff.changed.transform[(D3DTS_##n) / 32] & (1 << ((D3DTS_##n) % 32))) + +static struct NinePixelShader9 * +nine_ff_get_ps(struct NineDevice9 *device) +{ + struct nine_context *context = &device->context; + struct NinePixelShader9 *ps; + struct nine_ff_ps_key key; + unsigned s; + uint8_t sampler_mask = 0; + + assert(sizeof(key) <= sizeof(key.value32)); + + memset(&key, 0, sizeof(key)); + for (s = 0; s < 8; ++s) { + key.ts[s].colorop = context->ff.tex_stage[s][D3DTSS_COLOROP]; + key.ts[s].alphaop = context->ff.tex_stage[s][D3DTSS_ALPHAOP]; + 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); + /* MSDN says D3DTOP_DISABLE disables this and all subsequent stages. + * ALPHAOP cannot be enabled if COLOROP is disabled. + * Verified on Windows. */ + if (key.ts[s].colorop == D3DTOP_DISABLE) { + key.ts[s].alphaop = D3DTOP_DISABLE; /* DISABLE == 1, avoid degenerate keys */ + break; + } + + if (!context->texture[s].enabled && + ((context->ff.tex_stage[s][D3DTSS_COLORARG0] == D3DTA_TEXTURE && + used_c & 0x1) || + (context->ff.tex_stage[s][D3DTSS_COLORARG1] == D3DTA_TEXTURE && + used_c & 0x2) || + (context->ff.tex_stage[s][D3DTSS_COLORARG2] == D3DTA_TEXTURE && + used_c & 0x4))) { + /* Tested on Windows: Invalid texture read disables the stage + * and the subsequent ones, but only for colorop. For alpha, + * it's as if the texture had alpha of 1.0, which is what + * has our dummy texture in that case. Invalid color also + * disabled the following alpha stages. */ + key.ts[s].colorop = key.ts[s].alphaop = D3DTOP_DISABLE; + break; + } + + if (context->ff.tex_stage[s][D3DTSS_COLORARG0] == D3DTA_TEXTURE || + context->ff.tex_stage[s][D3DTSS_COLORARG1] == D3DTA_TEXTURE || + context->ff.tex_stage[s][D3DTSS_COLORARG2] == D3DTA_TEXTURE || + context->ff.tex_stage[s][D3DTSS_ALPHAARG0] == D3DTA_TEXTURE || + context->ff.tex_stage[s][D3DTSS_ALPHAARG1] == D3DTA_TEXTURE || + context->ff.tex_stage[s][D3DTSS_ALPHAARG2] == D3DTA_TEXTURE) + sampler_mask |= (1 << s); + + if (key.ts[s].colorop != D3DTOP_DISABLE) { + if (used_c & 0x1) key.ts[s].colorarg0 = context->ff.tex_stage[s][D3DTSS_COLORARG0] & 0x7; + if (used_c & 0x2) key.ts[s].colorarg1 = context->ff.tex_stage[s][D3DTSS_COLORARG1] & 0x7; + if (used_c & 0x4) key.ts[s].colorarg2 = context->ff.tex_stage[s][D3DTSS_COLORARG2] & 0x7; + if (used_c & 0x1) key.colorarg_b4[0] |= ((context->ff.tex_stage[s][D3DTSS_COLORARG0] >> 4) & 0x1) << s; + if (used_c & 0x1) key.colorarg_b5[0] |= ((context->ff.tex_stage[s][D3DTSS_COLORARG0] >> 5) & 0x1) << s; + if (used_c & 0x2) key.colorarg_b4[1] |= ((context->ff.tex_stage[s][D3DTSS_COLORARG1] >> 4) & 0x1) << s; + if (used_c & 0x2) key.colorarg_b5[1] |= ((context->ff.tex_stage[s][D3DTSS_COLORARG1] >> 5) & 0x1) << s; + if (used_c & 0x4) key.colorarg_b4[2] |= ((context->ff.tex_stage[s][D3DTSS_COLORARG2] >> 4) & 0x1) << s; + if (used_c & 0x4) key.colorarg_b5[2] |= ((context->ff.tex_stage[s][D3DTSS_COLORARG2] >> 5) & 0x1) << s; + } + if (key.ts[s].alphaop != D3DTOP_DISABLE) { + if (used_a & 0x1) key.ts[s].alphaarg0 = context->ff.tex_stage[s][D3DTSS_ALPHAARG0] & 0x7; + if (used_a & 0x2) key.ts[s].alphaarg1 = context->ff.tex_stage[s][D3DTSS_ALPHAARG1] & 0x7; + if (used_a & 0x4) key.ts[s].alphaarg2 = context->ff.tex_stage[s][D3DTSS_ALPHAARG2] & 0x7; + if (used_a & 0x1) key.alphaarg_b4[0] |= ((context->ff.tex_stage[s][D3DTSS_ALPHAARG0] >> 4) & 0x1) << s; + if (used_a & 0x2) key.alphaarg_b4[1] |= ((context->ff.tex_stage[s][D3DTSS_ALPHAARG1] >> 4) & 0x1) << s; + if (used_a & 0x4) key.alphaarg_b4[2] |= ((context->ff.tex_stage[s][D3DTSS_ALPHAARG2] >> 4) & 0x1) << s; + } + key.ts[s].resultarg = context->ff.tex_stage[s][D3DTSS_RESULTARG] == D3DTA_TEMP; + + if (context->texture[s].enabled) { + switch (context->texture[s].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; + } + } + + /* Note: If colorop is D3DTOP_DISABLE for the first stage + * (which implies alphaop is too), nothing particular happens, + * that is, current is equal to diffuse (which is the case anyway, + * because it is how it is initialized). + * Special case seems if alphaop is D3DTOP_DISABLE and not colorop, + * because then if the resultarg is TEMP, then diffuse alpha is written + * to it. */ + if (key.ts[0].colorop != D3DTOP_DISABLE && + key.ts[0].alphaop == D3DTOP_DISABLE && + key.ts[0].resultarg != 0) { + key.ts[0].alphaop = D3DTOP_SELECTARG1; + key.ts[0].alphaarg1 = D3DTA_DIFFUSE; + } + /* When no alpha stage writes to current, diffuse alpha is taken. + * Since we initialize current to diffuse, we have the behaviour. */ + + /* Last stage always writes to Current */ + if (s >= 1) + key.ts[s-1].resultarg = 0; + + key.projected = nine_ff_get_projected_key_ff(context); + key.specular = !!context->rs[D3DRS_SPECULARENABLE]; + key.flatshade = context->rs[D3DRS_SHADEMODE] == D3DSHADE_FLAT; + + for (; s < 8; ++s) + key.ts[s].colorop = key.ts[s].alphaop = D3DTOP_DISABLE; + if (context->rs[D3DRS_FOGENABLE]) + key.fog_mode = context->rs[D3DRS_FOGTABLEMODE]; + key.fog = !!context->rs[D3DRS_FOGENABLE]; + if (key.fog_mode && key.fog) + key.fog_source = !context->zfog; + key.alpha_test_emulation = context->rs[NINED3DRS_EMULATED_ALPHATEST] & 0x7; + + DBG("PS ff key hash: %x\n", nine_ff_ps_key_hash(&key)); + 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)); + + _mesa_hash_table_insert(device->ff.ht_ps, &ps->ff_key, ps); + device->ff.num_ps++; + + ps->rt_mask = 0x1; + ps->sampler_mask = sampler_mask; + } + return ps; +} + +static void +nine_ff_load_vs_transforms(struct NineDevice9 *device) +{ + struct nine_context *context = &device->context; + 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(context, WORLD) || + IS_D3DTS_DIRTY(context, VIEW) || + IS_D3DTS_DIRTY(context, 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(&T, &M[1]); + nine_d3d_matrix_transpose(&M[4], &T); + + /* P matrix */ + M[2] = *GET_D3DTS(PROJECTION); + + /* V and W matrix */ + nine_d3d_matrix_inverse(&M[3], GET_D3DTS(VIEW)); + M[40] = M[1]; + } + + if (context->rs[D3DRS_VERTEXBLEND] != D3DVBF_DISABLE) { + /* load other world matrices */ + for (i = 1; i <= 8; ++i) { + nine_d3d_matrix_matrix_mul(&M[40 + i], GET_D3DTS(WORLDMATRIX(i)), GET_D3DTS(VIEW)); + } + } + + device->ff.vs_const[30 * 4] = asfloat(context->rs[D3DRS_TWEENFACTOR]); +} + +static void +nine_ff_load_lights(struct NineDevice9 *device) +{ + struct nine_context *context = &device->context; + struct fvec4 *dst = (struct fvec4 *)device->ff.vs_const; + unsigned l; + + if (context->changed.group & NINE_STATE_FF_MATERIAL) { + const D3DMATERIAL9 *mtl = &context->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, context->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; + } + + if (!(context->changed.group & NINE_STATE_FF_LIGHTING) && !IS_D3DTS_DIRTY(context, VIEW)) + return; + + for (l = 0; l < context->ff.num_lights_active; ++l) { + const D3DLIGHT9 *light = &context->ff.light[context->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 = (float)((l + 1) == context->ff.num_lights_active); + } +} + +static void +nine_ff_load_point_and_fog_params(struct NineDevice9 *device) +{ + struct nine_context *context = &device->context; + struct fvec4 *dst = (struct fvec4 *)device->ff.vs_const; + + if (!(context->changed.group & NINE_STATE_FF_VS_OTHER)) + return; + dst[26].x = asfloat(context->rs[D3DRS_POINTSIZE_MIN]); + dst[26].y = asfloat(context->rs[D3DRS_POINTSIZE_MAX]); + dst[26].z = CLAMP(asfloat(context->rs[D3DRS_POINTSIZE]), + asfloat(context->rs[D3DRS_POINTSIZE_MIN]), + asfloat(context->rs[D3DRS_POINTSIZE_MAX])); + dst[26].w = asfloat(context->rs[D3DRS_POINTSCALE_A]); + dst[27].x = asfloat(context->rs[D3DRS_POINTSCALE_B]); + dst[27].y = asfloat(context->rs[D3DRS_POINTSCALE_C]); + dst[28].x = asfloat(context->rs[D3DRS_FOGEND]); + dst[28].y = 1.0f / (asfloat(context->rs[D3DRS_FOGEND]) - asfloat(context->rs[D3DRS_FOGSTART])); + if (isinf(dst[28].y)) + dst[28].y = 0.0f; + dst[28].z = asfloat(context->rs[D3DRS_FOGDENSITY]); + if (device->driver_caps.emulate_ucp) + memcpy(&dst[196], &context->clip.ucp, sizeof(context->clip)); +} + +static void +nine_ff_load_tex_matrices(struct NineDevice9 *device) +{ + struct nine_context *context = &device->context; + D3DMATRIX *M = (D3DMATRIX *)device->ff.vs_const; + unsigned s; + + if (!(context->ff.changed.transform[0] & 0xff0000)) + return; + for (s = 0; s < 8; ++s) { + if (IS_D3DTS_DIRTY(context, TEXTURE0 + s)) + nine_d3d_matrix_transpose(&M[32 + s], nine_state_access_transform(&context->ff, D3DTS_TEXTURE0 + s, false)); + } +} + +static void +nine_ff_load_ps_params(struct NineDevice9 *device) +{ + struct nine_context *context = &device->context; + struct fvec4 *dst = (struct fvec4 *)device->ff.ps_const; + unsigned s; + + if (!(context->changed.group & NINE_STATE_FF_PS_CONSTS)) + return; + + for (s = 0; s < 8; ++s) + d3dcolor_to_rgba(&dst[s].x, context->ff.tex_stage[s][D3DTSS_CONSTANT]); + + for (s = 0; s < 8; ++s) { + dst[8 + s].x = asfloat(context->ff.tex_stage[s][D3DTSS_BUMPENVMAT00]); + dst[8 + s].y = asfloat(context->ff.tex_stage[s][D3DTSS_BUMPENVMAT01]); + dst[8 + s].z = asfloat(context->ff.tex_stage[s][D3DTSS_BUMPENVMAT10]); + dst[8 + s].w = asfloat(context->ff.tex_stage[s][D3DTSS_BUMPENVMAT11]); + if (s & 1) { + dst[16 + s / 2].z = asfloat(context->ff.tex_stage[s][D3DTSS_BUMPENVLSCALE]); + dst[16 + s / 2].w = asfloat(context->ff.tex_stage[s][D3DTSS_BUMPENVLOFFSET]); + } else { + dst[16 + s / 2].x = asfloat(context->ff.tex_stage[s][D3DTSS_BUMPENVLSCALE]); + dst[16 + s / 2].y = asfloat(context->ff.tex_stage[s][D3DTSS_BUMPENVLOFFSET]); + } + } + + d3dcolor_to_rgba(&dst[20].x, context->rs[D3DRS_TEXTUREFACTOR]); + d3dcolor_to_rgba(&dst[21].x, context->rs[D3DRS_FOGCOLOR]); + dst[22].x = asfloat(context->rs[D3DRS_FOGEND]); + dst[22].y = 1.0f / (asfloat(context->rs[D3DRS_FOGEND]) - asfloat(context->rs[D3DRS_FOGSTART])); + dst[22].z = asfloat(context->rs[D3DRS_FOGDENSITY]); + dst[22].w = (float)context->rs[D3DRS_ALPHAREF] / 255.f; +} + +static void +nine_ff_load_viewport_info(struct NineDevice9 *device) +{ + D3DVIEWPORT9 *viewport = &device->context.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[100].w = (float)(viewport->Width); + 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 nine_context *context = &device->context; + struct pipe_constant_buffer cb; + + DBG("vs=%p ps=%p\n", context->vs, context->ps); + + /* NOTE: the only reference belongs to the hash table */ + if (!context->programmable_vs) { + device->ff.vs = nine_ff_get_vs(device); + context->changed.group |= NINE_STATE_VS; + } + if (!context->ps) { + device->ff.ps = nine_ff_get_ps(device); + context->changed.group |= NINE_STATE_PS; + } + + if (!context->programmable_vs) { + 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(context->ff.changed.transform, 0, sizeof(context->ff.changed.transform)); + + nine_upload_constant_buffer(context, &context->pipe_data.cb_vs_ff, + device->ff.vs_const, + NINE_FF_NUM_VS_CONST * 4 * sizeof(float)); + context->commit |= NINE_STATE_COMMIT_CONST_VS; + + context->changed.group &= ~NINE_STATE_FF_VS; + } + + if (!context->ps) { + nine_ff_load_ps_params(device); + + nine_upload_constant_buffer(context, &context->pipe_data.cb_ps_ff, + device->ff.ps_const, + NINE_FF_NUM_PS_CONST * 4 * sizeof(float)); + context->commit |= NINE_STATE_COMMIT_CONST_PS; + + context->changed.group &= ~NINE_STATE_FF_PS; + } +} + + +bool +nine_ff_init(struct NineDevice9 *device) +{ + device->ff.ht_vs = _mesa_hash_table_create(NULL, nine_ff_vs_key_hash, + nine_ff_vs_key_comp); + device->ff.ht_ps = _mesa_hash_table_create(NULL, nine_ff_ps_key_hash, + nine_ff_ps_key_comp); + + device->ff.ht_fvf = _mesa_hash_table_create(NULL, 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); + _mesa_hash_table_destroy(device->ff.ht_vs, NULL); + } + if (device->ff.ht_ps) { + util_hash_table_foreach(device->ff.ht_ps, nine_ff_ht_delete_cb, NULL); + _mesa_hash_table_destroy(device->ff.ht_ps, NULL); + } + if (device->ff.ht_fvf) { + util_hash_table_foreach(device->ff.ht_fvf, nine_ff_ht_delete_cb, NULL); + _mesa_hash_table_destroy(device->ff.ht_fvf, NULL); + } + 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) +{ + struct nine_context *context = &device->context; + + if (device->ff.num_vs > 1024) { + /* could destroy the bound one here, so unbind */ + context->pipe->bind_vs_state(context->pipe, NULL); + util_hash_table_foreach(device->ff.ht_vs, nine_ff_ht_delete_cb, NULL); + _mesa_hash_table_clear(device->ff.ht_vs, NULL); + device->ff.num_vs = 0; + context->changed.group |= NINE_STATE_VS; + } +} +static void +nine_ff_prune_ps(struct NineDevice9 *device) +{ + struct nine_context *context = &device->context; + + if (device->ff.num_ps > 1024) { + /* could destroy the bound one here, so unbind */ + context->pipe->bind_fs_state(context->pipe, NULL); + util_hash_table_foreach(device->ff.ht_ps, nine_ff_ht_delete_cb, NULL); + _mesa_hash_table_clear(device->ff.ht_ps, NULL); + device->ff.num_ps = 0; + context->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]; + + if (fabsf(det) < 1e-30) {/* non inversible */ + *D = *M; /* wine tests */ + return; + } + + det = 1.0 / det; + + for (i = 0; i < 4; i++) + for (k = 0; k < 4; k++) + D->m[i][k] *= det; + +#if MESA_DEBUG || !defined(NDEBUG) + { + 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 +} diff --git a/src/gallium/frontends/nine/nine_ff.h b/src/gallium/frontends/nine/nine_ff.h new file mode 100644 index 0000000..d41cb9f --- /dev/null +++ b/src/gallium/frontends/nine/nine_ff.h @@ -0,0 +1,132 @@ +/* + * Copyright 2011 Joakim Sindholt + * Copyright Axel Davy + * SPDX-License-Identifier: MIT + */ + +#ifndef _NINE_FF_H_ +#define _NINE_FF_H_ + +#include "device9.h" +#include "vertexdeclaration9.h" + +bool 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_transpose(D3DMATRIX *, const D3DMATRIX *); + +#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 + +static inline unsigned +nine_decltype_get_dim(BYTE type) +{ + switch (type) { + case D3DDECLTYPE_FLOAT1: return 1; + case D3DDECLTYPE_FLOAT2: return 2; + case D3DDECLTYPE_FLOAT3: return 3; + case D3DDECLTYPE_FLOAT4: return 4; + case D3DDECLTYPE_D3DCOLOR: return 1; + case D3DDECLTYPE_UBYTE4: return 4; + case D3DDECLTYPE_SHORT2: return 2; + case D3DDECLTYPE_SHORT4: return 4; + case D3DDECLTYPE_UBYTE4N: return 4; + case D3DDECLTYPE_SHORT2N: return 2; + case D3DDECLTYPE_SHORT4N: return 4; + case D3DDECLTYPE_USHORT2N: return 2; + case D3DDECLTYPE_USHORT4N: return 4; + case D3DDECLTYPE_UDEC3: return 3; + case D3DDECLTYPE_DEC3N: return 3; + case D3DDECLTYPE_FLOAT16_2: return 2; + case D3DDECLTYPE_FLOAT16_4: return 4; + default: + assert(!"Implementation error !"); + } + return 0; +} + +static inline uint16_t +nine_ff_get_projected_key(struct nine_context *context, unsigned num_stages) +{ + unsigned s, i; + uint16_t projected = 0; + int8_t input_texture_coord[num_stages]; + memset(&input_texture_coord, 0, sizeof(input_texture_coord)); + + if (context->vdecl) { + for (i = 0; i < context->vdecl->nelems; i++) { + uint16_t usage = context->vdecl->usage_map[i]; + if (usage % NINE_DECLUSAGE_COUNT == NINE_DECLUSAGE_TEXCOORD) { + s = usage / NINE_DECLUSAGE_COUNT; + if (s < num_stages) + input_texture_coord[s] = nine_decltype_get_dim(context->vdecl->decls[i].Type); + } + } + } + + for (s = 0; s < num_stages; ++s) { + unsigned gen = (context->ff.tex_stage[s][D3DTSS_TEXCOORDINDEX] >> 16) + 1; + unsigned dim = context->ff.tex_stage[s][D3DTSS_TEXTURETRANSFORMFLAGS] & 0x7; + unsigned idx = context->ff.tex_stage[s][D3DTSS_TEXCOORDINDEX] & 7; + unsigned proj = !!(context->ff.tex_stage[s][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED); + + if (!context->programmable_vs) { + if (dim > 4) + dim = input_texture_coord[idx]; + + if (!dim && gen == NINED3DTSS_TCI_PASSTHRU) + dim = input_texture_coord[idx]; + else if (!dim) + dim = 4; + + if (dim == 1) /* NV behaviour */ + proj = 0; + if (dim > input_texture_coord[idx] && gen == NINED3DTSS_TCI_PASSTHRU) + proj = 0; + } else { + dim = 4; + } + if (proj) + projected |= (dim-1) << (2 * s); + } + return projected; +} + +static inline uint16_t +nine_ff_get_projected_key_ff(struct nine_context *context) +{ + /* 8 stages */ + return nine_ff_get_projected_key(context, 8); +} + +static inline uint8_t +nine_ff_get_projected_key_programmable(struct nine_context *context) +{ + /* We only look at the 4 stages because this function + * is used only for ps 1.1-3, where only the first four + * slots are available */ + return (uint8_t)nine_ff_get_projected_key(context, 4); +} + +#endif /* _NINE_FF_H_ */ diff --git a/src/gallium/frontends/nine/nine_flags.h b/src/gallium/frontends/nine/nine_flags.h new file mode 100644 index 0000000..985e37c --- /dev/null +++ b/src/gallium/frontends/nine/nine_flags.h @@ -0,0 +1,17 @@ +/* + * Copyright Axel Davy + * SPDX-License-Identifier: MIT + */ + +#ifndef _NINE_FLAGS_H_ +#define _NINE_FLAGS_H_ + +#include "util/compiler.h" + +/* Incoming 32 bits calls are 4-byte aligned. + * We need to realign them to be able to use + * SSE and to work with other libraries (llvm, etc) + */ +#define NINE_WINAPI WINAPI UTIL_ALIGN_STACK + +#endif /* _NINE_FLAGS_H_ */ diff --git a/src/gallium/frontends/nine/nine_helpers.c b/src/gallium/frontends/nine/nine_helpers.c new file mode 100644 index 0000000..9f297a0 --- /dev/null +++ b/src/gallium/frontends/nine/nine_helpers.c @@ -0,0 +1,83 @@ +/* + * Copyright 2013 Christoph Bumiller + * SPDX-License-Identifier: MIT + */ + +#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/frontends/nine/nine_helpers.h b/src/gallium/frontends/nine/nine_helpers.h new file mode 100644 index 0000000..7b32db6 --- /dev/null +++ b/src/gallium/frontends/nine/nine_helpers.h @@ -0,0 +1,183 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#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; \ + __params.start_with_bind_not_ref = false; \ + { \ + 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_DEVICE_CHILD_BIND_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; \ + __params.start_with_bind_not_ref = true; \ + { \ + 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; \ + __params.start_with_bind_not_ref = false; \ + { \ + 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; +} + +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/frontends/nine/nine_limits.h b/src/gallium/frontends/nine/nine_limits.h new file mode 100644 index 0000000..7d00ced --- /dev/null +++ b/src/gallium/frontends/nine/nine_limits.h @@ -0,0 +1,230 @@ +/* + * Copyright 2015 Axel Davy + * SPDX-License-Identifier: MIT + */ + +#ifndef _NINE_LIMITS_H_ +#define _NINE_LIMITS_H_ + +#include "assert.h" +#include "d3d9types.h" + +// state can be any value +#define NINE_STATE_NO_LIMIT 0 +// value is clamped if below min or max +#define NINE_STATE_CLAMP 1 +// boolean: 0 -> false; any other value -> true +#define NINE_STATE_BOOL 2 +// a mask is applied on the value +#define NINE_STATE_MASK 3 +// if outside a range, state value is changed to a default value +#define NINE_STATE_RANGE_DEF_VAL 4 + +struct nine_state_behaviour { + unsigned state_value_behaviour; + union { + struct { + unsigned min; + unsigned max; + } clamp; + unsigned mask; + struct { + unsigned min; + unsigned max; + unsigned default_val; + } range_def_val; + } u; +}; + +#define __NO_LIMIT_RS(o) \ + [D3DRS_##o] = {NINE_STATE_NO_LIMIT} + +#define __CLAMP_RS(o, m, M) \ + [D3DRS_##o] = {NINE_STATE_CLAMP, {.clamp = {m, M}}} + +#define __BOOLEAN_RS(o) \ + [D3DRS_##o] = {NINE_STATE_BOOL} + +#define __MASK_RS(o, m) \ + [D3DRS_##o] = {NINE_STATE_MASK, {.mask = m}} + +#define __RANGE_DEF_VAL_RS(o, m, M, d) \ + [D3DRS_##o] = {NINE_STATE_RANGE_DEF_VAL, {.range_def_val = {m, M, d}}} + +#define __TO_DETERMINE_RS(o, m, M) \ + [D3DRS_##o] = {NINE_STATE_NO_LIMIT} + +static const struct nine_state_behaviour +render_state_limits_table[D3DRS_BLENDOPALPHA + 1] = { + __TO_DETERMINE_RS(ZENABLE, 0, 3), + __TO_DETERMINE_RS(FILLMODE, 1, 3), + __CLAMP_RS(SHADEMODE, 1, 3), + __BOOLEAN_RS(ZWRITEENABLE), + __BOOLEAN_RS(ALPHATESTENABLE), + __BOOLEAN_RS(LASTPIXEL), + __RANGE_DEF_VAL_RS(SRCBLEND, 1, 17, D3DBLEND_ZERO), + __RANGE_DEF_VAL_RS(DESTBLEND, 1, 17, D3DBLEND_ZERO), + __CLAMP_RS(CULLMODE, 1, 3), + __CLAMP_RS(ZFUNC, 1, 8), + __MASK_RS(ALPHAREF, 0x000000FF), + __CLAMP_RS(ALPHAFUNC, 1, 8), + __BOOLEAN_RS(DITHERENABLE), + __BOOLEAN_RS(ALPHABLENDENABLE), + __BOOLEAN_RS(FOGENABLE), + __BOOLEAN_RS(SPECULARENABLE), + __NO_LIMIT_RS(FOGCOLOR), + __MASK_RS(FOGTABLEMODE, 0x00000003), + __NO_LIMIT_RS(FOGSTART), /* a bit more complex than that, lets ignore */ + __NO_LIMIT_RS(FOGEND), + __NO_LIMIT_RS(FOGDENSITY), /* actually should be between 0.0 and 1.0 */ + __BOOLEAN_RS(RANGEFOGENABLE), + __BOOLEAN_RS(STENCILENABLE), + __CLAMP_RS(STENCILFAIL, 1, 8), + __CLAMP_RS(STENCILZFAIL, 1, 8), + __CLAMP_RS(STENCILPASS, 1, 8), + __CLAMP_RS(STENCILFUNC, 1, 8), + __NO_LIMIT_RS(STENCILREF), + __NO_LIMIT_RS(STENCILMASK), + __NO_LIMIT_RS(STENCILWRITEMASK), + __NO_LIMIT_RS(TEXTUREFACTOR), + __TO_DETERMINE_RS(WRAP0, 0, 15), + __TO_DETERMINE_RS(WRAP1, 0, 15), + __TO_DETERMINE_RS(WRAP2, 0, 15), + __TO_DETERMINE_RS(WRAP3, 0, 15), + __TO_DETERMINE_RS(WRAP4, 0, 15), + __TO_DETERMINE_RS(WRAP5, 0, 15), + __TO_DETERMINE_RS(WRAP6, 0, 15), + __TO_DETERMINE_RS(WRAP7, 0, 15), + __BOOLEAN_RS(CLIPPING), + __BOOLEAN_RS(LIGHTING), + __NO_LIMIT_RS(AMBIENT), + __MASK_RS(FOGVERTEXMODE, 0x00000003), + __BOOLEAN_RS(COLORVERTEX), + __BOOLEAN_RS(LOCALVIEWER), + __BOOLEAN_RS(NORMALIZENORMALS), + __TO_DETERMINE_RS(DIFFUSEMATERIALSOURCE, 0, 2), + __TO_DETERMINE_RS(SPECULARMATERIALSOURCE, 0, 2), + __TO_DETERMINE_RS(AMBIENTMATERIALSOURCE, 0, 2), + __TO_DETERMINE_RS(EMISSIVEMATERIALSOURCE, 0, 2), + __TO_DETERMINE_RS(VERTEXBLEND, 0, 256), /* values between 4 and 254 -both included- are forbidden too */ + __NO_LIMIT_RS(CLIPPLANEENABLE), /* expected check seems complex */ + __TO_DETERMINE_RS(POINTSIZE, 0, 0xFFFFFFFF), + __TO_DETERMINE_RS(POINTSIZE_MIN, 0, 0x7FFFFFFF), /* float >= 0.0 */ + __BOOLEAN_RS(POINTSPRITEENABLE), + __BOOLEAN_RS(POINTSCALEENABLE), + __TO_DETERMINE_RS(POINTSCALE_A, 0, 0x7FFFFFFF), /* float >= 0.0 */ + __TO_DETERMINE_RS(POINTSCALE_B, 0, 0x7FFFFFFF), /* float >= 0.0 */ + __TO_DETERMINE_RS(POINTSCALE_C, 0, 0x7FFFFFFF), /* float >= 0.0 */ + __BOOLEAN_RS(MULTISAMPLEANTIALIAS), + __NO_LIMIT_RS(MULTISAMPLEMASK), + __TO_DETERMINE_RS(PATCHEDGESTYLE, 0, 1), + __TO_DETERMINE_RS(DEBUGMONITORTOKEN, 0, 1), + __TO_DETERMINE_RS(POINTSIZE_MAX, 0, 0x7FFFFFFF), /* check more complex than that */ + __BOOLEAN_RS(INDEXEDVERTEXBLENDENABLE), + __TO_DETERMINE_RS(COLORWRITEENABLE, 0, 15), + __NO_LIMIT_RS(TWEENFACTOR), + __CLAMP_RS(BLENDOP, 1, 5), + __TO_DETERMINE_RS(POSITIONDEGREE, 1, 5), /* can actually be only 1 or 5 */ + __TO_DETERMINE_RS(NORMALDEGREE, 1, 2), + __BOOLEAN_RS(SCISSORTESTENABLE), + __NO_LIMIT_RS(SLOPESCALEDEPTHBIAS), + __BOOLEAN_RS(ANTIALIASEDLINEENABLE), + __NO_LIMIT_RS(MINTESSELLATIONLEVEL), + __NO_LIMIT_RS(MAXTESSELLATIONLEVEL), + __NO_LIMIT_RS(ADAPTIVETESS_X), + __NO_LIMIT_RS(ADAPTIVETESS_Y), + __NO_LIMIT_RS(ADAPTIVETESS_Z), + __NO_LIMIT_RS(ADAPTIVETESS_W), + __BOOLEAN_RS(ENABLEADAPTIVETESSELLATION), + __BOOLEAN_RS(TWOSIDEDSTENCILMODE), + __CLAMP_RS(CCW_STENCILFAIL, 1, 8), + __CLAMP_RS(CCW_STENCILZFAIL, 1, 8), + __CLAMP_RS(CCW_STENCILPASS, 1, 8), + __CLAMP_RS(CCW_STENCILFUNC, 1, 8), + __TO_DETERMINE_RS(COLORWRITEENABLE1, 0, 15), + __TO_DETERMINE_RS(COLORWRITEENABLE2, 0, 15), + __TO_DETERMINE_RS(COLORWRITEENABLE3, 0, 15), + __NO_LIMIT_RS(BLENDFACTOR), + __BOOLEAN_RS(SRGBWRITEENABLE), + __NO_LIMIT_RS(DEPTHBIAS), + __TO_DETERMINE_RS(WRAP8, 0, 15), + __TO_DETERMINE_RS(WRAP9, 0, 15), + __TO_DETERMINE_RS(WRAP10, 0, 15), + __TO_DETERMINE_RS(WRAP11, 0, 15), + __TO_DETERMINE_RS(WRAP12, 0, 15), + __TO_DETERMINE_RS(WRAP13, 0, 15), + __TO_DETERMINE_RS(WRAP14, 0, 15), + __TO_DETERMINE_RS(WRAP15, 0, 15), + __BOOLEAN_RS(SEPARATEALPHABLENDENABLE), + __RANGE_DEF_VAL_RS(SRCBLENDALPHA, 1, 17, D3DBLEND_ZERO), + __RANGE_DEF_VAL_RS(DESTBLENDALPHA, 1, 17, D3DBLEND_ZERO), + __CLAMP_RS(BLENDOPALPHA, 1, 5) +}; + +static DWORD inline +nine_fix_render_state_value(D3DRENDERSTATETYPE State, + DWORD Value) +{ + struct nine_state_behaviour behaviour = render_state_limits_table[State]; + + switch (behaviour.state_value_behaviour) { + case NINE_STATE_NO_LIMIT: + break; + case NINE_STATE_CLAMP: + if (Value < behaviour.u.clamp.min) + Value = behaviour.u.clamp.min; + else if (Value > behaviour.u.clamp.max) + Value = behaviour.u.clamp.max; + break; + case NINE_STATE_BOOL: + Value = Value ? 1 : 0; + break; + case NINE_STATE_MASK: + Value = Value & behaviour.u.mask; + break; + case NINE_STATE_RANGE_DEF_VAL: + if (Value < behaviour.u.range_def_val.min || Value > behaviour.u.range_def_val.max) + Value = behaviour.u.range_def_val.default_val; + break; + } + + return Value; +} + +struct nine_limits +{ + unsigned min; + unsigned max; +}; + +#define __VALUE_SAMP(o, m, M) \ + [D3DSAMP_##o] = {m, M} + +static const struct nine_limits +sampler_state_limits_table[D3DRS_BLENDOPALPHA + 1] = { + __VALUE_SAMP(ADDRESSU, 1, 5), + __VALUE_SAMP(ADDRESSV, 1, 5), + __VALUE_SAMP(ADDRESSW, 1, 5), + __VALUE_SAMP(BORDERCOLOR, 0, 0xFFFFFFFF), + __VALUE_SAMP(MAGFILTER, 0, 8), /* 4-5 should be forbidden */ + __VALUE_SAMP(MINFILTER, 0, 8), /* same */ + __VALUE_SAMP(MIPFILTER, 0, 8), /* same */ + __VALUE_SAMP(MIPMAPLODBIAS, 0, 0xFFFFFFFF), + __VALUE_SAMP(MAXMIPLEVEL, 0, 0xFFFFFFFF), + __VALUE_SAMP(MAXANISOTROPY, 1, 0xFFFFFFFF), /* Max value should be pCaps->MaxAnisotropy */ + __VALUE_SAMP(SRGBTEXTURE, 0, 1), + __VALUE_SAMP(ELEMENTINDEX, 0, 0xFFFFFFFF), + __VALUE_SAMP(DMAPOFFSET, 0, 0xFFFFFFFF) +}; + +static BOOL inline +nine_check_sampler_state_value(D3DSAMPLERSTATETYPE State, + DWORD Value) +{ + struct nine_limits limit; + + limit = sampler_state_limits_table[State]; + return (limit.min <= Value && Value <= limit.max); +} + +#endif /* _NINE_HELPERS_H_ */ diff --git a/src/gallium/frontends/nine/nine_lock.c b/src/gallium/frontends/nine/nine_lock.c new file mode 100644 index 0000000..8259aaa --- /dev/null +++ b/src/gallium/frontends/nine/nine_lock.c @@ -0,0 +1,3278 @@ +/* + * Copyright 2013 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#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 "nine_lock.h" + +#include "util/simple_mtx.h" +#include "util/u_thread.h" + +/* Global mutex as described by MSDN */ +static simple_mtx_t d3dlock_global = SIMPLE_MTX_INITIALIZER; + +void +NineLockGlobalMutex() +{ + simple_mtx_lock(&d3dlock_global); +} + +void +NineUnlockGlobalMutex() +{ + simple_mtx_unlock(&d3dlock_global); +} + +static HRESULT NINE_WINAPI +LockAuthenticatedChannel9_GetCertificateSize( struct NineAuthenticatedChannel9 *This, + UINT *pCertificateSize ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineAuthenticatedChannel9_GetCertificateSize(This, pCertificateSize); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockAuthenticatedChannel9_GetCertificate( struct NineAuthenticatedChannel9 *This, + UINT CertifacteSize, + BYTE *ppCertificate ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineAuthenticatedChannel9_GetCertificate(This, CertifacteSize, ppCertificate); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockAuthenticatedChannel9_NegotiateKeyExchange( struct NineAuthenticatedChannel9 *This, + UINT DataSize, + void *pData ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineAuthenticatedChannel9_NegotiateKeyExchange(This, DataSize, pData); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockAuthenticatedChannel9_Query( struct NineAuthenticatedChannel9 *This, + UINT InputSize, + const void *pInput, + UINT OutputSize, + void *pOutput ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineAuthenticatedChannel9_Query(This, InputSize, pInput, OutputSize, pOutput); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockAuthenticatedChannel9_Configure( struct NineAuthenticatedChannel9 *This, + UINT InputSize, + const void *pInput, + D3DAUTHENTICATEDCHANNEL_CONFIGURE_OUTPUT *pOutput ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineAuthenticatedChannel9_Configure(This, InputSize, pInput, pOutput); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +IDirect3DAuthenticatedChannel9Vtbl LockAuthenticatedChannel9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_ReleaseWithDtorLock, + (void *)LockAuthenticatedChannel9_GetCertificateSize, + (void *)LockAuthenticatedChannel9_GetCertificate, + (void *)LockAuthenticatedChannel9_NegotiateKeyExchange, + (void *)LockAuthenticatedChannel9_Query, + (void *)LockAuthenticatedChannel9_Configure +}; + +static HRESULT NINE_WINAPI +LockUnknown_SetPrivateData( struct NineUnknown *This, + REFGUID refguid, + const void *pData, + DWORD SizeOfData, + DWORD Flags ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineUnknown_SetPrivateData(This, refguid, pData, SizeOfData, Flags); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockUnknown_GetPrivateData( struct NineUnknown *This, + REFGUID refguid, + void *pData, + DWORD *pSizeOfData ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineUnknown_GetPrivateData(This, refguid, pData, pSizeOfData); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockUnknown_FreePrivateData( struct NineUnknown *This, + REFGUID refguid ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineUnknown_FreePrivateData(This, refguid); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +#if 0 +static HRESULT NINE_WINAPI +LockResource9_GetDevice( struct NineResource9 *This, + IDirect3DDevice9 **ppDevice ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineUnknown_GetDevice(NineUnknown(This), ppDevice); + simple_mtx_unlock(&d3dlock_global); + return r; +} +#endif + +static DWORD NINE_WINAPI +LockResource9_SetPriority( struct NineResource9 *This, + DWORD PriorityNew ) +{ + DWORD r; + simple_mtx_lock(&d3dlock_global); + r = NineResource9_SetPriority(This, PriorityNew); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static DWORD NINE_WINAPI +LockResource9_GetPriority( struct NineResource9 *This ) +{ + DWORD r; + simple_mtx_lock(&d3dlock_global); + r = NineResource9_GetPriority(This); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +#if 0 +static void NINE_WINAPI +LockResource9_PreLoad( struct NineResource9 *This ) +{ + simple_mtx_lock(&d3dlock_global); + NineResource9_PreLoad(This); + simple_mtx_unlock(&d3dlock_global); +} +#endif + +#if 0 +static D3DRESOURCETYPE NINE_WINAPI +LockResource9_GetType( struct NineResource9 *This ) +{ + D3DRESOURCETYPE r; + simple_mtx_lock(&d3dlock_global); + r = NineResource9_GetType(This); + simple_mtx_unlock(&d3dlock_global); + return r; +} +#endif + +static DWORD NINE_WINAPI +LockBaseTexture9_SetLOD( struct NineBaseTexture9 *This, + DWORD LODNew ) +{ + DWORD r; + simple_mtx_lock(&d3dlock_global); + r = NineBaseTexture9_SetLOD(This, LODNew); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static DWORD NINE_WINAPI +LockBaseTexture9_GetLOD( struct NineBaseTexture9 *This ) +{ + DWORD r; + simple_mtx_lock(&d3dlock_global); + r = NineBaseTexture9_GetLOD(This); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static DWORD NINE_WINAPI +LockBaseTexture9_GetLevelCount( struct NineBaseTexture9 *This ) +{ + DWORD r; + simple_mtx_lock(&d3dlock_global); + r = NineBaseTexture9_GetLevelCount(This); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockBaseTexture9_SetAutoGenFilterType( struct NineBaseTexture9 *This, + D3DTEXTUREFILTERTYPE FilterType ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineBaseTexture9_SetAutoGenFilterType(This, FilterType); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static D3DTEXTUREFILTERTYPE NINE_WINAPI +LockBaseTexture9_GetAutoGenFilterType( struct NineBaseTexture9 *This ) +{ + D3DTEXTUREFILTERTYPE r; + simple_mtx_lock(&d3dlock_global); + r = NineBaseTexture9_GetAutoGenFilterType(This); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static void NINE_WINAPI +LockBaseTexture9_PreLoad( struct NineBaseTexture9 *This ) +{ + simple_mtx_lock(&d3dlock_global); + NineBaseTexture9_PreLoad(This); + simple_mtx_unlock(&d3dlock_global); +} + +static void NINE_WINAPI +LockBaseTexture9_GenerateMipSubLevels( struct NineBaseTexture9 *This ) +{ + simple_mtx_lock(&d3dlock_global); + NineBaseTexture9_GenerateMipSubLevels(This); + simple_mtx_unlock(&d3dlock_global); +} + +static HRESULT NINE_WINAPI +LockCryptoSession9_GetCertificateSize( struct NineCryptoSession9 *This, + UINT *pCertificateSize ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineCryptoSession9_GetCertificateSize(This, pCertificateSize); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockCryptoSession9_GetCertificate( struct NineCryptoSession9 *This, + UINT CertifacteSize, + BYTE *ppCertificate ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineCryptoSession9_GetCertificate(This, CertifacteSize, ppCertificate); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockCryptoSession9_NegotiateKeyExchange( struct NineCryptoSession9 *This, + UINT DataSize, + void *pData ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineCryptoSession9_NegotiateKeyExchange(This, DataSize, pData); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockCryptoSession9_EncryptionBlt( struct NineCryptoSession9 *This, + IDirect3DSurface9 *pSrcSurface, + IDirect3DSurface9 *pDstSurface, + UINT DstSurfaceSize, + void *pIV ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineCryptoSession9_EncryptionBlt(This, pSrcSurface, pDstSurface, DstSurfaceSize, pIV); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockCryptoSession9_DecryptionBlt( struct NineCryptoSession9 *This, + IDirect3DSurface9 *pSrcSurface, + IDirect3DSurface9 *pDstSurface, + UINT SrcSurfaceSize, + D3DENCRYPTED_BLOCK_INFO *pEncryptedBlockInfo, + void *pContentKey, + void *pIV ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineCryptoSession9_DecryptionBlt(This, pSrcSurface, pDstSurface, SrcSurfaceSize, pEncryptedBlockInfo, pContentKey, pIV); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockCryptoSession9_GetSurfacePitch( struct NineCryptoSession9 *This, + IDirect3DSurface9 *pSrcSurface, + UINT *pSurfacePitch ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineCryptoSession9_GetSurfacePitch(This, pSrcSurface, pSurfacePitch); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockCryptoSession9_StartSessionKeyRefresh( struct NineCryptoSession9 *This, + void *pRandomNumber, + UINT RandomNumberSize ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineCryptoSession9_StartSessionKeyRefresh(This, pRandomNumber, RandomNumberSize); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockCryptoSession9_FinishSessionKeyRefresh( struct NineCryptoSession9 *This ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineCryptoSession9_FinishSessionKeyRefresh(This); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockCryptoSession9_GetEncryptionBltKey( struct NineCryptoSession9 *This, + void *pReadbackKey, + UINT KeySize ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineCryptoSession9_GetEncryptionBltKey(This, pReadbackKey, KeySize); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +IDirect3DCryptoSession9Vtbl LockCryptoSession9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_ReleaseWithDtorLock, + (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 NINE_WINAPI +LockCubeTexture9_GetLevelDesc( struct NineCubeTexture9 *This, + UINT Level, + D3DSURFACE_DESC *pDesc ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineCubeTexture9_GetLevelDesc(This, Level, pDesc); + simple_mtx_unlock(&d3dlock_global); + return r; +} +#endif + +#if 0 +static HRESULT NINE_WINAPI +LockCubeTexture9_GetCubeMapSurface( struct NineCubeTexture9 *This, + D3DCUBEMAP_FACES FaceType, + UINT Level, + IDirect3DSurface9 **ppCubeMapSurface ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineCubeTexture9_GetCubeMapSurface(This, FaceType, Level, ppCubeMapSurface); + simple_mtx_unlock(&d3dlock_global); + return r; +} +#endif + +static HRESULT NINE_WINAPI +LockCubeTexture9_LockRect( struct NineCubeTexture9 *This, + D3DCUBEMAP_FACES FaceType, + UINT Level, + D3DLOCKED_RECT *pLockedRect, + const RECT *pRect, + DWORD Flags ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineCubeTexture9_LockRect(This, FaceType, Level, pLockedRect, pRect, Flags); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockCubeTexture9_UnlockRect( struct NineCubeTexture9 *This, + D3DCUBEMAP_FACES FaceType, + UINT Level ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineCubeTexture9_UnlockRect(This, FaceType, Level); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockCubeTexture9_AddDirtyRect( struct NineCubeTexture9 *This, + D3DCUBEMAP_FACES FaceType, + const RECT *pDirtyRect ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineCubeTexture9_AddDirtyRect(This, FaceType, pDirtyRect); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +IDirect3DCubeTexture9Vtbl LockCubeTexture9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_ReleaseWithDtorLock, + (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */ + (void *)LockUnknown_SetPrivateData, + (void *)LockUnknown_GetPrivateData, + (void *)LockUnknown_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 NINE_WINAPI +LockDevice9_TestCooperativeLevel( struct NineDevice9 *This ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_TestCooperativeLevel(This); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static UINT NINE_WINAPI +LockDevice9_GetAvailableTextureMem( struct NineDevice9 *This ) +{ + UINT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetAvailableTextureMem(This); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_EvictManagedResources( struct NineDevice9 *This ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_EvictManagedResources(This); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetDirect3D( struct NineDevice9 *This, + IDirect3D9 **ppD3D9 ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetDirect3D(This, ppD3D9); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +#if 0 +static HRESULT NINE_WINAPI +LockDevice9_GetDeviceCaps( struct NineDevice9 *This, + D3DCAPS9 *pCaps ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetDeviceCaps(This, pCaps); + simple_mtx_unlock(&d3dlock_global); + return r; +} +#endif + +static HRESULT NINE_WINAPI +LockDevice9_GetDisplayMode( struct NineDevice9 *This, + UINT iSwapChain, + D3DDISPLAYMODE *pMode ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetDisplayMode(This, iSwapChain, pMode); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +#if 0 +static HRESULT NINE_WINAPI +LockDevice9_GetCreationParameters( struct NineDevice9 *This, + D3DDEVICE_CREATION_PARAMETERS *pParameters ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetCreationParameters(This, pParameters); + simple_mtx_unlock(&d3dlock_global); + return r; +} +#endif + +static HRESULT NINE_WINAPI +LockDevice9_SetCursorProperties( struct NineDevice9 *This, + UINT XHotSpot, + UINT YHotSpot, + IDirect3DSurface9 *pCursorBitmap ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetCursorProperties(This, XHotSpot, YHotSpot, pCursorBitmap); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static void NINE_WINAPI +LockDevice9_SetCursorPosition( struct NineDevice9 *This, + int X, + int Y, + DWORD Flags ) +{ + simple_mtx_lock(&d3dlock_global); + NineDevice9_SetCursorPosition(This, X, Y, Flags); + simple_mtx_unlock(&d3dlock_global); +} + +static BOOL NINE_WINAPI +LockDevice9_ShowCursor( struct NineDevice9 *This, + BOOL bShow ) +{ + BOOL r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_ShowCursor(This, bShow); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_CreateAdditionalSwapChain( struct NineDevice9 *This, + D3DPRESENT_PARAMETERS *pPresentationParameters, + IDirect3DSwapChain9 **pSwapChain ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_CreateAdditionalSwapChain(This, pPresentationParameters, pSwapChain); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetSwapChain( struct NineDevice9 *This, + UINT iSwapChain, + IDirect3DSwapChain9 **pSwapChain ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetSwapChain(This, iSwapChain, pSwapChain); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static UINT NINE_WINAPI +LockDevice9_GetNumberOfSwapChains( struct NineDevice9 *This ) +{ + UINT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetNumberOfSwapChains(This); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_Reset( struct NineDevice9 *This, + D3DPRESENT_PARAMETERS *pPresentationParameters ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_Reset(This, pPresentationParameters); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_Present( struct NineDevice9 *This, + const RECT *pSourceRect, + const RECT *pDestRect, + HWND hDestWindowOverride, + const RGNDATA *pDirtyRegion ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_Present(This, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetBackBuffer( struct NineDevice9 *This, + UINT iSwapChain, + UINT iBackBuffer, + D3DBACKBUFFER_TYPE Type, + IDirect3DSurface9 **ppBackBuffer ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetBackBuffer(This, iSwapChain, iBackBuffer, Type, ppBackBuffer); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetRasterStatus( struct NineDevice9 *This, + UINT iSwapChain, + D3DRASTER_STATUS *pRasterStatus ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetRasterStatus(This, iSwapChain, pRasterStatus); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_SetDialogBoxMode( struct NineDevice9 *This, + BOOL bEnableDialogs ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetDialogBoxMode(This, bEnableDialogs); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static void NINE_WINAPI +LockDevice9_SetGammaRamp( struct NineDevice9 *This, + UINT iSwapChain, + DWORD Flags, + const D3DGAMMARAMP *pRamp ) +{ + simple_mtx_lock(&d3dlock_global); + NineDevice9_SetGammaRamp(This, iSwapChain, Flags, pRamp); + simple_mtx_unlock(&d3dlock_global); +} + +static void NINE_WINAPI +LockDevice9_GetGammaRamp( struct NineDevice9 *This, + UINT iSwapChain, + D3DGAMMARAMP *pRamp ) +{ + simple_mtx_lock(&d3dlock_global); + NineDevice9_GetGammaRamp(This, iSwapChain, pRamp); + simple_mtx_unlock(&d3dlock_global); +} + +static HRESULT NINE_WINAPI +LockDevice9_CreateTexture( struct NineDevice9 *This, + UINT Width, + UINT Height, + UINT Levels, + DWORD Usage, + D3DFORMAT Format, + D3DPOOL Pool, + IDirect3DTexture9 **ppTexture, + HANDLE *pSharedHandle ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_CreateTexture(This, Width, Height, Levels, Usage, Format, Pool, ppTexture, pSharedHandle); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_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; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_CreateVolumeTexture(This, Width, Height, Depth, Levels, Usage, Format, Pool, ppVolumeTexture, pSharedHandle); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_CreateCubeTexture( struct NineDevice9 *This, + UINT EdgeLength, + UINT Levels, + DWORD Usage, + D3DFORMAT Format, + D3DPOOL Pool, + IDirect3DCubeTexture9 **ppCubeTexture, + HANDLE *pSharedHandle ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_CreateCubeTexture(This, EdgeLength, Levels, Usage, Format, Pool, ppCubeTexture, pSharedHandle); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_CreateVertexBuffer( struct NineDevice9 *This, + UINT Length, + DWORD Usage, + DWORD FVF, + D3DPOOL Pool, + IDirect3DVertexBuffer9 **ppVertexBuffer, + HANDLE *pSharedHandle ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_CreateVertexBuffer(This, Length, Usage, FVF, Pool, ppVertexBuffer, pSharedHandle); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_CreateIndexBuffer( struct NineDevice9 *This, + UINT Length, + DWORD Usage, + D3DFORMAT Format, + D3DPOOL Pool, + IDirect3DIndexBuffer9 **ppIndexBuffer, + HANDLE *pSharedHandle ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_CreateIndexBuffer(This, Length, Usage, Format, Pool, ppIndexBuffer, pSharedHandle); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_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; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_CreateRenderTarget(This, Width, Height, Format, MultiSample, MultisampleQuality, Lockable, ppSurface, pSharedHandle); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_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; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_CreateDepthStencilSurface(This, Width, Height, Format, MultiSample, MultisampleQuality, Discard, ppSurface, pSharedHandle); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_UpdateSurface( struct NineDevice9 *This, + IDirect3DSurface9 *pSourceSurface, + const RECT *pSourceRect, + IDirect3DSurface9 *pDestinationSurface, + const POINT *pDestPoint ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_UpdateSurface(This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_UpdateTexture( struct NineDevice9 *This, + IDirect3DBaseTexture9 *pSourceTexture, + IDirect3DBaseTexture9 *pDestinationTexture ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_UpdateTexture(This, pSourceTexture, pDestinationTexture); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetRenderTargetData( struct NineDevice9 *This, + IDirect3DSurface9 *pRenderTarget, + IDirect3DSurface9 *pDestSurface ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetRenderTargetData(This, pRenderTarget, pDestSurface); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetFrontBufferData( struct NineDevice9 *This, + UINT iSwapChain, + IDirect3DSurface9 *pDestSurface ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetFrontBufferData(This, iSwapChain, pDestSurface); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_StretchRect( struct NineDevice9 *This, + IDirect3DSurface9 *pSourceSurface, + const RECT *pSourceRect, + IDirect3DSurface9 *pDestSurface, + const RECT *pDestRect, + D3DTEXTUREFILTERTYPE Filter ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_StretchRect(This, pSourceSurface, pSourceRect, pDestSurface, pDestRect, Filter); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_ColorFill( struct NineDevice9 *This, + IDirect3DSurface9 *pSurface, + const RECT *pRect, + D3DCOLOR color ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_ColorFill(This, pSurface, pRect, color); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_CreateOffscreenPlainSurface( struct NineDevice9 *This, + UINT Width, + UINT Height, + D3DFORMAT Format, + D3DPOOL Pool, + IDirect3DSurface9 **ppSurface, + HANDLE *pSharedHandle ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_CreateOffscreenPlainSurface(This, Width, Height, Format, Pool, ppSurface, pSharedHandle); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_SetRenderTarget( struct NineDevice9 *This, + DWORD RenderTargetIndex, + IDirect3DSurface9 *pRenderTarget ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetRenderTarget(This, RenderTargetIndex, pRenderTarget); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetRenderTarget( struct NineDevice9 *This, + DWORD RenderTargetIndex, + IDirect3DSurface9 **ppRenderTarget ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetRenderTarget(This, RenderTargetIndex, ppRenderTarget); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_SetDepthStencilSurface( struct NineDevice9 *This, + IDirect3DSurface9 *pNewZStencil ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetDepthStencilSurface(This, pNewZStencil); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetDepthStencilSurface( struct NineDevice9 *This, + IDirect3DSurface9 **ppZStencilSurface ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetDepthStencilSurface(This, ppZStencilSurface); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_BeginScene( struct NineDevice9 *This ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_BeginScene(This); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_EndScene( struct NineDevice9 *This ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_EndScene(This); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_Clear( struct NineDevice9 *This, + DWORD Count, + const D3DRECT *pRects, + DWORD Flags, + D3DCOLOR Color, + float Z, + DWORD Stencil ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_Clear(This, Count, pRects, Flags, Color, Z, Stencil); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_SetTransform( struct NineDevice9 *This, + D3DTRANSFORMSTATETYPE State, + const D3DMATRIX *pMatrix ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetTransform(This, State, pMatrix); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetTransform( struct NineDevice9 *This, + D3DTRANSFORMSTATETYPE State, + D3DMATRIX *pMatrix ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetTransform(This, State, pMatrix); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_MultiplyTransform( struct NineDevice9 *This, + D3DTRANSFORMSTATETYPE State, + const D3DMATRIX *pMatrix ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_MultiplyTransform(This, State, pMatrix); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_SetViewport( struct NineDevice9 *This, + const D3DVIEWPORT9 *pViewport ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetViewport(This, pViewport); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetViewport( struct NineDevice9 *This, + D3DVIEWPORT9 *pViewport ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetViewport(This, pViewport); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_SetMaterial( struct NineDevice9 *This, + const D3DMATERIAL9 *pMaterial ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetMaterial(This, pMaterial); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetMaterial( struct NineDevice9 *This, + D3DMATERIAL9 *pMaterial ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetMaterial(This, pMaterial); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_SetLight( struct NineDevice9 *This, + DWORD Index, + const D3DLIGHT9 *pLight ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetLight(This, Index, pLight); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetLight( struct NineDevice9 *This, + DWORD Index, + D3DLIGHT9 *pLight ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetLight(This, Index, pLight); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_LightEnable( struct NineDevice9 *This, + DWORD Index, + BOOL Enable ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_LightEnable(This, Index, Enable); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetLightEnable( struct NineDevice9 *This, + DWORD Index, + BOOL *pEnable ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetLightEnable(This, Index, pEnable); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_SetClipPlane( struct NineDevice9 *This, + DWORD Index, + const float *pPlane ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetClipPlane(This, Index, pPlane); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetClipPlane( struct NineDevice9 *This, + DWORD Index, + float *pPlane ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetClipPlane(This, Index, pPlane); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_SetRenderState( struct NineDevice9 *This, + D3DRENDERSTATETYPE State, + DWORD Value ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetRenderState(This, State, Value); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetRenderState( struct NineDevice9 *This, + D3DRENDERSTATETYPE State, + DWORD *pValue ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetRenderState(This, State, pValue); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_CreateStateBlock( struct NineDevice9 *This, + D3DSTATEBLOCKTYPE Type, + IDirect3DStateBlock9 **ppSB ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_CreateStateBlock(This, Type, ppSB); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_BeginStateBlock( struct NineDevice9 *This ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_BeginStateBlock(This); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_EndStateBlock( struct NineDevice9 *This, + IDirect3DStateBlock9 **ppSB ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_EndStateBlock(This, ppSB); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_SetClipStatus( struct NineDevice9 *This, + const D3DCLIPSTATUS9 *pClipStatus ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetClipStatus(This, pClipStatus); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetClipStatus( struct NineDevice9 *This, + D3DCLIPSTATUS9 *pClipStatus ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetClipStatus(This, pClipStatus); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetTexture( struct NineDevice9 *This, + DWORD Stage, + IDirect3DBaseTexture9 **ppTexture ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetTexture(This, Stage, ppTexture); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_SetTexture( struct NineDevice9 *This, + DWORD Stage, + IDirect3DBaseTexture9 *pTexture ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetTexture(This, Stage, pTexture); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetTextureStageState( struct NineDevice9 *This, + DWORD Stage, + D3DTEXTURESTAGESTATETYPE Type, + DWORD *pValue ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetTextureStageState(This, Stage, Type, pValue); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_SetTextureStageState( struct NineDevice9 *This, + DWORD Stage, + D3DTEXTURESTAGESTATETYPE Type, + DWORD Value ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetTextureStageState(This, Stage, Type, Value); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetSamplerState( struct NineDevice9 *This, + DWORD Sampler, + D3DSAMPLERSTATETYPE Type, + DWORD *pValue ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetSamplerState(This, Sampler, Type, pValue); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_SetSamplerState( struct NineDevice9 *This, + DWORD Sampler, + D3DSAMPLERSTATETYPE Type, + DWORD Value ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetSamplerState(This, Sampler, Type, Value); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_ValidateDevice( struct NineDevice9 *This, + DWORD *pNumPasses ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_ValidateDevice(This, pNumPasses); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_SetPaletteEntries( struct NineDevice9 *This, + UINT PaletteNumber, + const PALETTEENTRY *pEntries ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetPaletteEntries(This, PaletteNumber, pEntries); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetPaletteEntries( struct NineDevice9 *This, + UINT PaletteNumber, + PALETTEENTRY *pEntries ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetPaletteEntries(This, PaletteNumber, pEntries); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_SetCurrentTexturePalette( struct NineDevice9 *This, + UINT PaletteNumber ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetCurrentTexturePalette(This, PaletteNumber); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetCurrentTexturePalette( struct NineDevice9 *This, + UINT *PaletteNumber ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetCurrentTexturePalette(This, PaletteNumber); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_SetScissorRect( struct NineDevice9 *This, + const RECT *pRect ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetScissorRect(This, pRect); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetScissorRect( struct NineDevice9 *This, + RECT *pRect ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetScissorRect(This, pRect); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_SetSoftwareVertexProcessing( struct NineDevice9 *This, + BOOL bSoftware ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetSoftwareVertexProcessing(This, bSoftware); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static BOOL NINE_WINAPI +LockDevice9_GetSoftwareVertexProcessing( struct NineDevice9 *This ) +{ + BOOL r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetSoftwareVertexProcessing(This); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_SetNPatchMode( struct NineDevice9 *This, + float nSegments ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetNPatchMode(This, nSegments); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static float NINE_WINAPI +LockDevice9_GetNPatchMode( struct NineDevice9 *This ) +{ + float r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetNPatchMode(This); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_DrawPrimitive( struct NineDevice9 *This, + D3DPRIMITIVETYPE PrimitiveType, + UINT StartVertex, + UINT PrimitiveCount ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_DrawPrimitive(This, PrimitiveType, StartVertex, PrimitiveCount); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_DrawIndexedPrimitive( struct NineDevice9 *This, + D3DPRIMITIVETYPE PrimitiveType, + INT BaseVertexIndex, + UINT MinVertexIndex, + UINT NumVertices, + UINT startIndex, + UINT primCount ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_DrawIndexedPrimitive(This, PrimitiveType, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_DrawPrimitiveUP( struct NineDevice9 *This, + D3DPRIMITIVETYPE PrimitiveType, + UINT PrimitiveCount, + const void *pVertexStreamZeroData, + UINT VertexStreamZeroStride ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_DrawPrimitiveUP(This, PrimitiveType, PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_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; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_DrawIndexedPrimitiveUP(This, PrimitiveType, MinVertexIndex, NumVertices, PrimitiveCount, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_ProcessVertices( struct NineDevice9 *This, + UINT SrcStartIndex, + UINT DestIndex, + UINT VertexCount, + IDirect3DVertexBuffer9 *pDestBuffer, + IDirect3DVertexDeclaration9 *pVertexDecl, + DWORD Flags ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_ProcessVertices(This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_CreateVertexDeclaration( struct NineDevice9 *This, + const D3DVERTEXELEMENT9 *pVertexElements, + IDirect3DVertexDeclaration9 **ppDecl ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_CreateVertexDeclaration(This, pVertexElements, ppDecl); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_SetVertexDeclaration( struct NineDevice9 *This, + IDirect3DVertexDeclaration9 *pDecl ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetVertexDeclaration(This, pDecl); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetVertexDeclaration( struct NineDevice9 *This, + IDirect3DVertexDeclaration9 **ppDecl ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetVertexDeclaration(This, ppDecl); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_SetFVF( struct NineDevice9 *This, + DWORD FVF ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetFVF(This, FVF); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetFVF( struct NineDevice9 *This, + DWORD *pFVF ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetFVF(This, pFVF); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_CreateVertexShader( struct NineDevice9 *This, + const DWORD *pFunction, + IDirect3DVertexShader9 **ppShader ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_CreateVertexShader(This, pFunction, ppShader); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_SetVertexShader( struct NineDevice9 *This, + IDirect3DVertexShader9 *pShader ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetVertexShader(This, pShader); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetVertexShader( struct NineDevice9 *This, + IDirect3DVertexShader9 **ppShader ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetVertexShader(This, ppShader); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_SetVertexShaderConstantF( struct NineDevice9 *This, + UINT StartRegister, + const float *pConstantData, + UINT Vector4fCount ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetVertexShaderConstantF(This, StartRegister, pConstantData, Vector4fCount); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetVertexShaderConstantF( struct NineDevice9 *This, + UINT StartRegister, + float *pConstantData, + UINT Vector4fCount ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetVertexShaderConstantF(This, StartRegister, pConstantData, Vector4fCount); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_SetVertexShaderConstantI( struct NineDevice9 *This, + UINT StartRegister, + const int *pConstantData, + UINT Vector4iCount ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetVertexShaderConstantI(This, StartRegister, pConstantData, Vector4iCount); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetVertexShaderConstantI( struct NineDevice9 *This, + UINT StartRegister, + int *pConstantData, + UINT Vector4iCount ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetVertexShaderConstantI(This, StartRegister, pConstantData, Vector4iCount); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_SetVertexShaderConstantB( struct NineDevice9 *This, + UINT StartRegister, + const BOOL *pConstantData, + UINT BoolCount ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetVertexShaderConstantB(This, StartRegister, pConstantData, BoolCount); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetVertexShaderConstantB( struct NineDevice9 *This, + UINT StartRegister, + BOOL *pConstantData, + UINT BoolCount ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetVertexShaderConstantB(This, StartRegister, pConstantData, BoolCount); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_SetStreamSource( struct NineDevice9 *This, + UINT StreamNumber, + IDirect3DVertexBuffer9 *pStreamData, + UINT OffsetInBytes, + UINT Stride ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetStreamSource(This, StreamNumber, pStreamData, OffsetInBytes, Stride); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetStreamSource( struct NineDevice9 *This, + UINT StreamNumber, + IDirect3DVertexBuffer9 **ppStreamData, + UINT *pOffsetInBytes, + UINT *pStride ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetStreamSource(This, StreamNumber, ppStreamData, pOffsetInBytes, pStride); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_SetStreamSourceFreq( struct NineDevice9 *This, + UINT StreamNumber, + UINT Setting ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetStreamSourceFreq(This, StreamNumber, Setting); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetStreamSourceFreq( struct NineDevice9 *This, + UINT StreamNumber, + UINT *pSetting ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetStreamSourceFreq(This, StreamNumber, pSetting); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_SetIndices( struct NineDevice9 *This, + IDirect3DIndexBuffer9 *pIndexData ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetIndices(This, pIndexData); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetIndices( struct NineDevice9 *This, + IDirect3DIndexBuffer9 **ppIndexData ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetIndices(This, ppIndexData); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_CreatePixelShader( struct NineDevice9 *This, + const DWORD *pFunction, + IDirect3DPixelShader9 **ppShader ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_CreatePixelShader(This, pFunction, ppShader); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_SetPixelShader( struct NineDevice9 *This, + IDirect3DPixelShader9 *pShader ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetPixelShader(This, pShader); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetPixelShader( struct NineDevice9 *This, + IDirect3DPixelShader9 **ppShader ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetPixelShader(This, ppShader); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_SetPixelShaderConstantF( struct NineDevice9 *This, + UINT StartRegister, + const float *pConstantData, + UINT Vector4fCount ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetPixelShaderConstantF(This, StartRegister, pConstantData, Vector4fCount); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetPixelShaderConstantF( struct NineDevice9 *This, + UINT StartRegister, + float *pConstantData, + UINT Vector4fCount ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetPixelShaderConstantF(This, StartRegister, pConstantData, Vector4fCount); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_SetPixelShaderConstantI( struct NineDevice9 *This, + UINT StartRegister, + const int *pConstantData, + UINT Vector4iCount ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetPixelShaderConstantI(This, StartRegister, pConstantData, Vector4iCount); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetPixelShaderConstantI( struct NineDevice9 *This, + UINT StartRegister, + int *pConstantData, + UINT Vector4iCount ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetPixelShaderConstantI(This, StartRegister, pConstantData, Vector4iCount); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_SetPixelShaderConstantB( struct NineDevice9 *This, + UINT StartRegister, + const BOOL *pConstantData, + UINT BoolCount ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_SetPixelShaderConstantB(This, StartRegister, pConstantData, BoolCount); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_GetPixelShaderConstantB( struct NineDevice9 *This, + UINT StartRegister, + BOOL *pConstantData, + UINT BoolCount ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_GetPixelShaderConstantB(This, StartRegister, pConstantData, BoolCount); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_DrawRectPatch( struct NineDevice9 *This, + UINT Handle, + const float *pNumSegs, + const D3DRECTPATCH_INFO *pRectPatchInfo ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_DrawRectPatch(This, Handle, pNumSegs, pRectPatchInfo); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_DrawTriPatch( struct NineDevice9 *This, + UINT Handle, + const float *pNumSegs, + const D3DTRIPATCH_INFO *pTriPatchInfo ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_DrawTriPatch(This, Handle, pNumSegs, pTriPatchInfo); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_DeletePatch( struct NineDevice9 *This, + UINT Handle ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_DeletePatch(This, Handle); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9_CreateQuery( struct NineDevice9 *This, + D3DQUERYTYPE Type, + IDirect3DQuery9 **ppQuery ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9_CreateQuery(This, Type, ppQuery); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +IDirect3DDevice9Vtbl LockDevice9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_ReleaseWithDtorLock, + (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 NINE_WINAPI +LockDevice9Ex_SetConvolutionMonoKernel( struct NineDevice9Ex *This, + UINT width, + UINT height, + float *rows, + float *columns ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9Ex_SetConvolutionMonoKernel(This, width, height, rows, columns); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9Ex_ComposeRects( struct NineDevice9Ex *This, + IDirect3DSurface9 *pSrc, + IDirect3DSurface9 *pDst, + IDirect3DVertexBuffer9 *pSrcRectDescs, + UINT NumRects, + IDirect3DVertexBuffer9 *pDstRectDescs, + D3DCOMPOSERECTSOP Operation, + int Xoffset, + int Yoffset ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9Ex_ComposeRects(This, pSrc, pDst, pSrcRectDescs, NumRects, pDstRectDescs, Operation, Xoffset, Yoffset); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9Ex_PresentEx( struct NineDevice9Ex *This, + const RECT *pSourceRect, + const RECT *pDestRect, + HWND hDestWindowOverride, + const RGNDATA *pDirtyRegion, + DWORD dwFlags ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9Ex_PresentEx(This, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9Ex_GetGPUThreadPriority( struct NineDevice9Ex *This, + INT *pPriority ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9Ex_GetGPUThreadPriority(This, pPriority); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9Ex_SetGPUThreadPriority( struct NineDevice9Ex *This, + INT Priority ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9Ex_SetGPUThreadPriority(This, Priority); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9Ex_WaitForVBlank( struct NineDevice9Ex *This, + UINT iSwapChain ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9Ex_WaitForVBlank(This, iSwapChain); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9Ex_CheckResourceResidency( struct NineDevice9Ex *This, + IDirect3DResource9 **pResourceArray, + UINT32 NumResources ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9Ex_CheckResourceResidency(This, pResourceArray, NumResources); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9Ex_SetMaximumFrameLatency( struct NineDevice9Ex *This, + UINT MaxLatency ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9Ex_SetMaximumFrameLatency(This, MaxLatency); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9Ex_GetMaximumFrameLatency( struct NineDevice9Ex *This, + UINT *pMaxLatency ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9Ex_GetMaximumFrameLatency(This, pMaxLatency); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9Ex_CheckDeviceState( struct NineDevice9Ex *This, + HWND hDestinationWindow ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9Ex_CheckDeviceState(This, hDestinationWindow); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_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; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9Ex_CreateRenderTargetEx(This, Width, Height, Format, MultiSample, MultisampleQuality, Lockable, ppSurface, pSharedHandle, Usage); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9Ex_CreateOffscreenPlainSurfaceEx( struct NineDevice9Ex *This, + UINT Width, + UINT Height, + D3DFORMAT Format, + D3DPOOL Pool, + IDirect3DSurface9 **ppSurface, + HANDLE *pSharedHandle, + DWORD Usage ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9Ex_CreateOffscreenPlainSurfaceEx(This, Width, Height, Format, Pool, ppSurface, pSharedHandle, Usage); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_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; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9Ex_CreateDepthStencilSurfaceEx(This, Width, Height, Format, MultiSample, MultisampleQuality, Discard, ppSurface, pSharedHandle, Usage); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9Ex_ResetEx( struct NineDevice9Ex *This, + D3DPRESENT_PARAMETERS *pPresentationParameters, + D3DDISPLAYMODEEX *pFullscreenDisplayMode ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9Ex_ResetEx(This, pPresentationParameters, pFullscreenDisplayMode); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9Ex_GetDisplayModeEx( struct NineDevice9Ex *This, + UINT iSwapChain, + D3DDISPLAYMODEEX *pMode, + D3DDISPLAYROTATION *pRotation ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9Ex_GetDisplayModeEx(This, iSwapChain, pMode, pRotation); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +IDirect3DDevice9ExVtbl LockDevice9Ex_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_ReleaseWithDtorLock, + (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 NINE_WINAPI +LockDevice9Video_GetContentProtectionCaps( struct NineDevice9Video *This, + const GUID *pCryptoType, + const GUID *pDecodeProfile, + D3DCONTENTPROTECTIONCAPS *pCaps ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9Video_GetContentProtectionCaps(This, pCryptoType, pDecodeProfile, pCaps); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9Video_CreateAuthenticatedChannel( struct NineDevice9Video *This, + D3DAUTHENTICATEDCHANNELTYPE ChannelType, + IDirect3DAuthenticatedChannel9 **ppAuthenticatedChannel, + HANDLE *pChannelHandle ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9Video_CreateAuthenticatedChannel(This, ChannelType, ppAuthenticatedChannel, pChannelHandle); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockDevice9Video_CreateCryptoSession( struct NineDevice9Video *This, + const GUID *pCryptoType, + const GUID *pDecodeProfile, + IDirect3DCryptoSession9 **ppCryptoSession, + HANDLE *pCryptoHandle ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineDevice9Video_CreateCryptoSession(This, pCryptoType, pDecodeProfile, ppCryptoSession, pCryptoHandle); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +IDirect3DDevice9VideoVtbl LockDevice9Video_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_ReleaseWithDtorLock, + (void *)LockDevice9Video_GetContentProtectionCaps, + (void *)LockDevice9Video_CreateAuthenticatedChannel, + (void *)LockDevice9Video_CreateCryptoSession +}; + +static HRESULT NINE_WINAPI +LockIndexBuffer9_Lock( struct NineIndexBuffer9 *This, + UINT OffsetToLock, + UINT SizeToLock, + void **ppbData, + DWORD Flags ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineIndexBuffer9_Lock(This, OffsetToLock, SizeToLock, ppbData, Flags); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockIndexBuffer9_Unlock( struct NineIndexBuffer9 *This ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineIndexBuffer9_Unlock(This); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +#if 0 +static HRESULT NINE_WINAPI +LockIndexBuffer9_GetDesc( struct NineIndexBuffer9 *This, + D3DINDEXBUFFER_DESC *pDesc ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineIndexBuffer9_GetDesc(This, pDesc); + simple_mtx_unlock(&d3dlock_global); + return r; +} +#endif + +IDirect3DIndexBuffer9Vtbl LockIndexBuffer9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_ReleaseWithDtorLock, + (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */ + (void *)LockUnknown_SetPrivateData, + (void *)LockUnknown_GetPrivateData, + (void *)LockUnknown_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 NINE_WINAPI +LockPixelShader9_GetDevice( struct NinePixelShader9 *This, + IDirect3DDevice9 **ppDevice ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineUnknown_GetDevice(NineUnknown(This), ppDevice); + simple_mtx_unlock(&d3dlock_global); + return r; +} +#endif + +static HRESULT NINE_WINAPI +LockPixelShader9_GetFunction( struct NinePixelShader9 *This, + void *pData, + UINT *pSizeOfData ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NinePixelShader9_GetFunction(This, pData, pSizeOfData); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +IDirect3DPixelShader9Vtbl LockPixelShader9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_ReleaseWithDtorLock, + (void *)NineUnknown_GetDevice, + (void *)LockPixelShader9_GetFunction +}; + +#if 0 +static HRESULT NINE_WINAPI +LockQuery9_GetDevice( struct NineQuery9 *This, + IDirect3DDevice9 **ppDevice ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineUnknown_GetDevice(NineUnknown(This), ppDevice); + simple_mtx_unlock(&d3dlock_global); + return r; +} +#endif + +#if 0 +static D3DQUERYTYPE NINE_WINAPI +LockQuery9_GetType( struct NineQuery9 *This ) +{ + D3DQUERYTYPE r; + simple_mtx_lock(&d3dlock_global); + r = NineQuery9_GetType(This); + simple_mtx_unlock(&d3dlock_global); + return r; +} +#endif + +#if 0 +static DWORD NINE_WINAPI +LockQuery9_GetDataSize( struct NineQuery9 *This ) +{ + DWORD r; + simple_mtx_lock(&d3dlock_global); + r = NineQuery9_GetDataSize(This); + simple_mtx_unlock(&d3dlock_global); + return r; +} +#endif + +static HRESULT NINE_WINAPI +LockQuery9_Issue( struct NineQuery9 *This, + DWORD dwIssueFlags ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineQuery9_Issue(This, dwIssueFlags); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockQuery9_GetData( struct NineQuery9 *This, + void *pData, + DWORD dwSize, + DWORD dwGetDataFlags ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineQuery9_GetData(This, pData, dwSize, dwGetDataFlags); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +IDirect3DQuery9Vtbl LockQuery9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_ReleaseWithDtorLock, + (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 NINE_WINAPI +LockStateBlock9_GetDevice( struct NineStateBlock9 *This, + IDirect3DDevice9 **ppDevice ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineUnknown_GetDevice(NineUnknown(This), ppDevice); + simple_mtx_unlock(&d3dlock_global); + return r; +} +#endif + +static HRESULT NINE_WINAPI +LockStateBlock9_Capture( struct NineStateBlock9 *This ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineStateBlock9_Capture(This); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockStateBlock9_Apply( struct NineStateBlock9 *This ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineStateBlock9_Apply(This); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +IDirect3DStateBlock9Vtbl LockStateBlock9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_ReleaseWithDtorLock, + (void *)NineUnknown_GetDevice, /* actually part of StateBlock9 iface */ + (void *)LockStateBlock9_Capture, + (void *)LockStateBlock9_Apply +}; + +static HRESULT NINE_WINAPI +LockSurface9_GetContainer( struct NineSurface9 *This, + REFIID riid, + void **ppContainer ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineSurface9_GetContainer(This, riid, ppContainer); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +#if 0 +static HRESULT NINE_WINAPI +LockSurface9_GetDesc( struct NineSurface9 *This, + D3DSURFACE_DESC *pDesc ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineSurface9_GetDesc(This, pDesc); + simple_mtx_unlock(&d3dlock_global); + return r; +} +#endif + +static HRESULT NINE_WINAPI +LockSurface9_LockRect( struct NineSurface9 *This, + D3DLOCKED_RECT *pLockedRect, + const RECT *pRect, + DWORD Flags ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineSurface9_LockRect(This, pLockedRect, pRect, Flags); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockSurface9_UnlockRect( struct NineSurface9 *This ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineSurface9_UnlockRect(This); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockSurface9_GetDC( struct NineSurface9 *This, + HDC *phdc ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineSurface9_GetDC(This, phdc); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockSurface9_ReleaseDC( struct NineSurface9 *This, + HDC hdc ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineSurface9_ReleaseDC(This, hdc); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +IDirect3DSurface9Vtbl LockSurface9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_ReleaseWithDtorLock, + (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */ + (void *)LockUnknown_SetPrivateData, + (void *)LockUnknown_GetPrivateData, + (void *)LockUnknown_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 NINE_WINAPI +LockSwapChain9_Present( struct NineSwapChain9 *This, + const RECT *pSourceRect, + const RECT *pDestRect, + HWND hDestWindowOverride, + const RGNDATA *pDirtyRegion, + DWORD dwFlags ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineSwapChain9_Present(This, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockSwapChain9_GetFrontBufferData( struct NineSwapChain9 *This, + IDirect3DSurface9 *pDestSurface ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineSwapChain9_GetFrontBufferData(This, pDestSurface); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockSwapChain9_GetBackBuffer( struct NineSwapChain9 *This, + UINT iBackBuffer, + D3DBACKBUFFER_TYPE Type, + IDirect3DSurface9 **ppBackBuffer ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineSwapChain9_GetBackBuffer(This, iBackBuffer, Type, ppBackBuffer); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockSwapChain9_GetRasterStatus( struct NineSwapChain9 *This, + D3DRASTER_STATUS *pRasterStatus ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineSwapChain9_GetRasterStatus(This, pRasterStatus); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockSwapChain9_GetDisplayMode( struct NineSwapChain9 *This, + D3DDISPLAYMODE *pMode ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineSwapChain9_GetDisplayMode(This, pMode); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +#if 0 +static HRESULT NINE_WINAPI +LockSwapChain9_GetDevice( struct NineSwapChain9 *This, + IDirect3DDevice9 **ppDevice ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineUnknown_GetDevice(NineUnknown(This), ppDevice); + simple_mtx_unlock(&d3dlock_global); + return r; +} +#endif + +static HRESULT NINE_WINAPI +LockSwapChain9_GetPresentParameters( struct NineSwapChain9 *This, + D3DPRESENT_PARAMETERS *pPresentationParameters ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineSwapChain9_GetPresentParameters(This, pPresentationParameters); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +IDirect3DSwapChain9Vtbl LockSwapChain9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_ReleaseWithDtorLock, + (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 NINE_WINAPI +LockSwapChain9Ex_GetLastPresentCount( struct NineSwapChain9Ex *This, + UINT *pLastPresentCount ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineSwapChain9Ex_GetLastPresentCount(This, pLastPresentCount); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockSwapChain9Ex_GetPresentStats( struct NineSwapChain9Ex *This, + D3DPRESENTSTATS *pPresentationStatistics ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineSwapChain9Ex_GetPresentStats(This, pPresentationStatistics); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockSwapChain9Ex_GetDisplayModeEx( struct NineSwapChain9Ex *This, + D3DDISPLAYMODEEX *pMode, + D3DDISPLAYROTATION *pRotation ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineSwapChain9Ex_GetDisplayModeEx(This, pMode, pRotation); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +IDirect3DSwapChain9ExVtbl LockSwapChain9Ex_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_ReleaseWithDtorLock, + (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 NINE_WINAPI +LockTexture9_GetLevelDesc( struct NineTexture9 *This, + UINT Level, + D3DSURFACE_DESC *pDesc ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineTexture9_GetLevelDesc(This, Level, pDesc); + simple_mtx_unlock(&d3dlock_global); + return r; +} +#endif + +#if 0 +static HRESULT NINE_WINAPI +LockTexture9_GetSurfaceLevel( struct NineTexture9 *This, + UINT Level, + IDirect3DSurface9 **ppSurfaceLevel ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineTexture9_GetSurfaceLevel(This, Level, ppSurfaceLevel); + simple_mtx_unlock(&d3dlock_global); + return r; +} +#endif + +static HRESULT NINE_WINAPI +LockTexture9_LockRect( struct NineTexture9 *This, + UINT Level, + D3DLOCKED_RECT *pLockedRect, + const RECT *pRect, + DWORD Flags ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineTexture9_LockRect(This, Level, pLockedRect, pRect, Flags); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockTexture9_UnlockRect( struct NineTexture9 *This, + UINT Level ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineTexture9_UnlockRect(This, Level); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockTexture9_AddDirtyRect( struct NineTexture9 *This, + const RECT *pDirtyRect ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineTexture9_AddDirtyRect(This, pDirtyRect); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +IDirect3DTexture9Vtbl LockTexture9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_ReleaseWithDtorLock, + (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */ + (void *)LockUnknown_SetPrivateData, + (void *)LockUnknown_GetPrivateData, + (void *)LockUnknown_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 NINE_WINAPI +LockVertexBuffer9_Lock( struct NineVertexBuffer9 *This, + UINT OffsetToLock, + UINT SizeToLock, + void **ppbData, + DWORD Flags ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineVertexBuffer9_Lock(This, OffsetToLock, SizeToLock, ppbData, Flags); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockVertexBuffer9_Unlock( struct NineVertexBuffer9 *This ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineVertexBuffer9_Unlock(This); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +#if 0 +static HRESULT NINE_WINAPI +LockVertexBuffer9_GetDesc( struct NineVertexBuffer9 *This, + D3DVERTEXBUFFER_DESC *pDesc ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineVertexBuffer9_GetDesc(This, pDesc); + simple_mtx_unlock(&d3dlock_global); + return r; +} +#endif + +IDirect3DVertexBuffer9Vtbl LockVertexBuffer9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_ReleaseWithDtorLock, + (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */ + (void *)LockUnknown_SetPrivateData, + (void *)LockUnknown_GetPrivateData, + (void *)LockUnknown_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 NINE_WINAPI +LockVertexDeclaration9_GetDevice( struct NineVertexDeclaration9 *This, + IDirect3DDevice9 **ppDevice ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineUnknown_GetDevice(NineUnknown(This), ppDevice); + simple_mtx_unlock(&d3dlock_global); + return r; +} +#endif + +static HRESULT NINE_WINAPI +LockVertexDeclaration9_GetDeclaration( struct NineVertexDeclaration9 *This, + D3DVERTEXELEMENT9 *pElement, + UINT *pNumElements ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineVertexDeclaration9_GetDeclaration(This, pElement, pNumElements); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +IDirect3DVertexDeclaration9Vtbl LockVertexDeclaration9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_ReleaseWithDtorLock, + (void *)NineUnknown_GetDevice, /* actually part of VertexDecl9 iface */ + (void *)LockVertexDeclaration9_GetDeclaration +}; + +#if 0 +static HRESULT NINE_WINAPI +LockVertexShader9_GetDevice( struct NineVertexShader9 *This, + IDirect3DDevice9 **ppDevice ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineUnknown_GetDevice(NineUnknown(This), ppDevice); + simple_mtx_unlock(&d3dlock_global); + return r; +} +#endif + +static HRESULT NINE_WINAPI +LockVertexShader9_GetFunction( struct NineVertexShader9 *This, + void *pData, + UINT *pSizeOfData ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineVertexShader9_GetFunction(This, pData, pSizeOfData); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +IDirect3DVertexShader9Vtbl LockVertexShader9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_ReleaseWithDtorLock, + (void *)NineUnknown_GetDevice, + (void *)LockVertexShader9_GetFunction +}; + +#if 0 +static HRESULT NINE_WINAPI +LockVolume9_GetDevice( struct NineVolume9 *This, + IDirect3DDevice9 **ppDevice ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineUnknown_GetDevice(NineUnknown(This), ppDevice); + simple_mtx_unlock(&d3dlock_global); + return r; +} +#endif + +static HRESULT NINE_WINAPI +LockVolume9_GetContainer( struct NineVolume9 *This, + REFIID riid, + void **ppContainer ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineVolume9_GetContainer(This, riid, ppContainer); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +#if 0 +static HRESULT NINE_WINAPI +LockVolume9_GetDesc( struct NineVolume9 *This, + D3DVOLUME_DESC *pDesc ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineVolume9_GetDesc(This, pDesc); + simple_mtx_unlock(&d3dlock_global); + return r; +} +#endif + +static HRESULT NINE_WINAPI +LockVolume9_LockBox( struct NineVolume9 *This, + D3DLOCKED_BOX *pLockedVolume, + const D3DBOX *pBox, + DWORD Flags ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineVolume9_LockBox(This, pLockedVolume, pBox, Flags); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockVolume9_UnlockBox( struct NineVolume9 *This ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineVolume9_UnlockBox(This); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +IDirect3DVolume9Vtbl LockVolume9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_ReleaseWithDtorLock, + (void *)NineUnknown_GetDevice, /* actually part of Volume9 iface */ + (void *)LockUnknown_SetPrivateData, + (void *)LockUnknown_GetPrivateData, + (void *)LockUnknown_FreePrivateData, + (void *)LockVolume9_GetContainer, + (void *)NineVolume9_GetDesc, /* immutable */ + (void *)LockVolume9_LockBox, + (void *)LockVolume9_UnlockBox +}; + +#if 0 +static HRESULT NINE_WINAPI +LockVolumeTexture9_GetLevelDesc( struct NineVolumeTexture9 *This, + UINT Level, + D3DVOLUME_DESC *pDesc ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineVolumeTexture9_GetLevelDesc(This, Level, pDesc); + simple_mtx_unlock(&d3dlock_global); + return r; +} +#endif + +#if 0 +static HRESULT NINE_WINAPI +LockVolumeTexture9_GetVolumeLevel( struct NineVolumeTexture9 *This, + UINT Level, + IDirect3DVolume9 **ppVolumeLevel ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineVolumeTexture9_GetVolumeLevel(This, Level, ppVolumeLevel); + simple_mtx_unlock(&d3dlock_global); + return r; +} +#endif + +static HRESULT NINE_WINAPI +LockVolumeTexture9_LockBox( struct NineVolumeTexture9 *This, + UINT Level, + D3DLOCKED_BOX *pLockedVolume, + const D3DBOX *pBox, + DWORD Flags ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineVolumeTexture9_LockBox(This, Level, pLockedVolume, pBox, Flags); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockVolumeTexture9_UnlockBox( struct NineVolumeTexture9 *This, + UINT Level ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineVolumeTexture9_UnlockBox(This, Level); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +static HRESULT NINE_WINAPI +LockVolumeTexture9_AddDirtyBox( struct NineVolumeTexture9 *This, + const D3DBOX *pDirtyBox ) +{ + HRESULT r; + simple_mtx_lock(&d3dlock_global); + r = NineVolumeTexture9_AddDirtyBox(This, pDirtyBox); + simple_mtx_unlock(&d3dlock_global); + return r; +} + +IDirect3DVolumeTexture9Vtbl LockVolumeTexture9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_ReleaseWithDtorLock, + (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */ + (void *)LockUnknown_SetPrivateData, + (void *)LockUnknown_GetPrivateData, + (void *)LockUnknown_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/frontends/nine/nine_lock.h b/src/gallium/frontends/nine/nine_lock.h new file mode 100644 index 0000000..f39e498 --- /dev/null +++ b/src/gallium/frontends/nine/nine_lock.h @@ -0,0 +1,37 @@ +/* + * Copyright 2013 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#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; + +void NineLockGlobalMutex(void); +void NineUnlockGlobalMutex(void); + +#endif /* _NINE_LOCK_H_ */ diff --git a/src/gallium/frontends/nine/nine_memory_helper.c b/src/gallium/frontends/nine/nine_memory_helper.c new file mode 100644 index 0000000..67febdd --- /dev/null +++ b/src/gallium/frontends/nine/nine_memory_helper.c @@ -0,0 +1,1159 @@ +/* + * Copyright 2020 Axel Davy + * SPDX-License-Identifier: MIT + */ + +/* + * Memory util function to allocate RAM backing for textures. + * DEFAULT textures are stored on GPU + * MANAGED textures have a RAM backing and upload the content to a GPU texture for use + * SYSTEMMEM textures are stored in RAM and are meant to be uploaded to DEFAULT textures. + * Basically SYSTEMMEM + DEFAULT enables to do manually what MANAGED does automatically. + * + * Once the GPU texture is created, the RAM backing of MANAGED textures can be used in + * two occasions: + * . Recreating the GPU texture (for example lod change, or GPU memory eviction) + * . Reading the texture content (some games do that to fill higher res versions of the texture) + * + * When a lot of textures are used, the amount of addressing space (virtual memory) taken by MANAGED + * and SYSTEMMEM textures can be significant and cause virtual memory exhaustion for 32 bits programs. + * + * One way to reduce the virtual memory taken is to ignore lod and delete the RAM backing of + * MANAGED textures once it is uploaded. If the texture is read, or evicted from GPU memory, the RAM + * backing would be recreated (Note that mapping the GPU memory is not acceptable as RAM memory is supposed + * to have smaller (fixed) stride constraints). + * + * Instead the approach taken here is to keep the RAM backing alive, but free its addressing space. + * In other words virtual memory usage is reduced, but the RAM usage of the app is the same. + * To do so, we use the memfd feature of the linux kernel. It enables to allocate a file + * stored in RAM and visible only to the app. We can map/unmap portions of the file as we need. + * When a portion is mapped, it takes virtual memory space. When it is not, it doesn't. + * The file is stored in RAM, and thus the access speed is the same as normal RAM. Using such + * file to allocate data enables to use more than 4GB RAM on 32 bits. + * + * This approach adds some overhead: when accessing mapped content the first time, pages are allocated + * by the system. This has a lot of overhead (several times the time to memset the area). + * Releasing these pages (when unmapping) has overhead too, though significantly less. + * + * This overhead however is much less significant than the overhead of downloading the GPU content. + * In addition, we reduce significantly the overhead spent in Gallium nine for new allocations by + * using the fact new contents of the file are zero-allocated. By not calling memset in Gallium nine, + * the overhead of page allocation happens client side, thus outside the d3d mutex. This should give + * a performance boost for multithreaded applications. As malloc also has this overhead (at least for + * large enough allocations which use mmap internally), allocating ends up faster than with the standard + * allocation path. + * By far the overhead induced by page allocation/deallocation is the biggest overhead involved in this + * code. It is reduced significantly with huge pages, but it is too complex to configure for the user + * to use it (and it has some memory management downsides too). The memset trick enables to move most of + * the overhead outside Nine anyway. + * + * To prevent useless unmappings quickly followed by mapping again, we do not unmap right away allocations + * that are not locked for access anymore. Indeed it is likely the allocation will be accessed several times + * in a row, for example first to fill it, then to upload it. + * We keep everything mapped until we reach a threshold of memory allocated. Then we use hints to prioritize + * which regions to unmap first. Thus virtual memory usage is only reduced when the threshold is reached. + * + * Multiple memfd files are used, each of 100MB. Thus memory usage (but not virtual memory usage) increases + * by amounts of 100MB. When not on x86 32 bits, we do use the standard malloc. + * + * Finally, for ease of use, we do not implement packing of allocation inside page-aligned regions. + * One allocation is given one page-aligned region inside a memfd file. + * Allocations smaller than a page (4KB on x86) go through malloc. + * As texture sizes are usually multiples of powers of two, allocations above the page size are typically + * multiples of the page size, thus space is not wasted in practice. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util/list.h" +#include "util/u_memory.h" +#include "util/slab.h" + +#include "nine_debug.h" +#include "nine_memory_helper.h" +#include "nine_state.h" + + +#define DIVUP(a,b) (((a)+(b)-1)/(b)) + +/* Required alignment for allocations */ +#define NINE_ALLOCATION_ALIGNMENT 32 + +#define DBG_CHANNEL (DBG_BASETEXTURE|DBG_SURFACE|DBG_VOLUME|DBG_TEXTURE|DBG_CUBETEXTURE) + +/* Use memfd only for 32 bits. Check for memfd_create support */ +#if DETECT_ARCH_X86 && defined(HAVE_MEMFD_CREATE) +#define NINE_ENABLE_MEMFD +#endif + +#ifdef NINE_ENABLE_MEMFD + +struct nine_memfd_file_region { + unsigned offset; + unsigned size; + void *map; /* pointer to the mapped content of the file. Can be NULL */ + int num_locks; /* Total number of locks blocking the munmap */ + int num_weak_unlocks; /* Number of users which weakly block the munmap */ + bool zero_filled; + struct list_head list; +}; + +struct nine_memfd_file { + int fd; + int filesize; /* Size of the file */ + struct list_head free_regions; /* This list is sorted by the offset, and consecutive regions are merged */ + struct list_head unmapped_allocated_regions; /* This list and the following ones are not sorted */ + struct list_head locked_mapped_allocated_regions; + struct list_head weak_unlocked_mapped_allocated_regions; + struct list_head unlocked_mapped_allocated_regions; +}; + +/* The allocation is stored inside a memfd */ +#define NINE_MEMFD_ALLOC 1 +/* The allocation is part of another allocation, which is stored inside a memfd */ +#define NINE_MEMFD_SUBALLOC 2 +/* The allocation was allocated with malloc and will have to be freed */ +#define NINE_MALLOC_ALLOC 3 +/* The pointer doesn't need memory management */ +#define NINE_EXTERNAL_ALLOC 4 + +struct nine_memfd_allocation { + struct nine_memfd_file *file; /* File in which the data is allocated */ + struct nine_memfd_file_region *region; /* Corresponding file memory region. Max 1 allocation per region */ +}; + +/* 'Suballocations' are used to represent subregions of an allocation. + * For example a given layer of a texture. These are not allocations, + * but can be accessed separately. To correctly handle accessing them, + * we encapsulate them into this structure. */ +struct nine_memfd_suballocation { + struct nine_memfd_allocation *parent; /* Parent allocation */ + int relative_offset; /* Offset relative to the parent */ +}; + +/* A standard allocation with malloc */ +struct nine_malloc_allocation { + void *buf; + unsigned allocation_size; +}; + +/* A pointer with no need of memory management. + * For example a pointer passed by the application, + * or a 'suballocation' inside a malloc-ed allocation. */ +struct nine_external_allocation { + void *buf; +}; + +/* Encapsulates all allocations */ +struct nine_allocation { + unsigned allocation_type; /* Type of allocation */ + union { + struct nine_memfd_allocation memfd; + struct nine_memfd_suballocation submemfd; + struct nine_malloc_allocation malloc; + struct nine_external_allocation external; + } memory; + struct list_head list_free; /* for pending frees */ + /* The fields below are only used for memfd/submemfd allocations */ + struct list_head list_release; /* for pending releases */ + /* Handling of the CSMT thread: + * API calls are singled thread (global mutex protection). + * However we multithreading internally (CSMT worker thread). + * To handle this thread, we map/lock the allocation in the + * main thread and increase pending_counter. When the worker thread + * is done with the scheduled function, the pending_counter is decreased. + * If pending_counter is 0, locks_on_counter can be subtracted from + * active_locks (in the main thread). */ + unsigned locks_on_counter; + unsigned *pending_counter; + /* Hint from the last unlock indicating the data might be locked again soon */ + bool weak_unlock; +}; + +struct nine_allocator { + struct NineDevice9 *device; + int page_size; /* Page size */ + int num_fd_max; /* Max number of memfd files */ + int min_file_size; /* Minimum memfd file size */ + /* Tracking of all allocations */ + long long total_allocations; /* Amount of memory allocated */ + long long total_locked_memory; /* TODO */ /* Amount of memory blocked by a lock */ + long long total_virtual_memory; /* Current virtual memory used by our allocations */ + long long total_virtual_memory_limit; /* Target maximum virtual memory used. Above that, tries to unmap memfd files whenever possible. */ + + int num_fd; /* Number of memfd files */ /* TODO release unused memfd files */ + struct slab_mempool allocation_pool; + struct slab_mempool region_pool; + struct nine_memfd_file *memfd_pool; /* Table (of size num_fd) of memfd files */ + struct list_head pending_releases; /* List of allocations with unlocks depending on pending_counter */ /* TODO: Elements seem removed only on flush. Destruction ? */ + + pthread_mutex_t mutex_pending_frees; + struct list_head pending_frees; +}; + +#if MESA_DEBUG + +static void +debug_dump_memfd_state(struct nine_memfd_file *memfd_file, bool details) +{ + struct nine_memfd_file_region *region; + + DBG("fd: %d, filesize: %d\n", memfd_file->fd, memfd_file->filesize); + if (!details) + return; + LIST_FOR_EACH_ENTRY(region, &memfd_file->free_regions, list) { + DBG("FREE block: offset %d, size %d, map=%p, locks=%d, weak=%d, z=%d\n", + region->offset, region->size, region->map, + region->num_locks, region->num_weak_unlocks, (int)region->zero_filled); + } + LIST_FOR_EACH_ENTRY(region, &memfd_file->unmapped_allocated_regions, list) { + DBG("UNMAPPED ALLOCATED block: offset %d, size %d, map=%p, locks=%d, weak=%d, z=%d\n", + region->offset, region->size, region->map, + region->num_locks, region->num_weak_unlocks, (int)region->zero_filled); + } + LIST_FOR_EACH_ENTRY(region, &memfd_file->locked_mapped_allocated_regions, list) { + DBG("LOCKED MAPPED ALLOCATED block: offset %d, size %d, map=%p, locks=%d, weak=%d, z=%d\n", + region->offset, region->size, region->map, + region->num_locks, region->num_weak_unlocks, (int)region->zero_filled); + } + LIST_FOR_EACH_ENTRY(region, &memfd_file->unlocked_mapped_allocated_regions, list) { + DBG("UNLOCKED MAPPED ALLOCATED block: offset %d, size %d, map=%p, locks=%d, weak=%d, z=%d\n", + region->offset, region->size, region->map, + region->num_locks, region->num_weak_unlocks, (int)region->zero_filled); + } + LIST_FOR_EACH_ENTRY(region, &memfd_file->weak_unlocked_mapped_allocated_regions, list) { + DBG("WEAK UNLOCKED MAPPED ALLOCATED block: offset %d, size %d, map=%p, locks=%d, weak=%d, z=%d\n", + region->offset, region->size, region->map, + region->num_locks, region->num_weak_unlocks, (int)region->zero_filled); + } +} + +static void +debug_dump_allocation_state(struct nine_allocation *allocation) +{ + switch(allocation->allocation_type) { + case NINE_MEMFD_ALLOC: + DBG("Allocation is stored in this memfd file:\n"); + debug_dump_memfd_state(allocation->memory.memfd.file, true); + DBG("Allocation is offset: %d, size: %d\n", + allocation->memory.memfd.region->offset, allocation->memory.memfd.region->size); + break; + case NINE_MEMFD_SUBALLOC: + DBG("Allocation is suballocation at relative offset %d of this allocation:\n", + allocation->memory.submemfd.relative_offset); + DBG("Parent allocation is stored in this memfd file:\n"); + debug_dump_memfd_state(allocation->memory.submemfd.parent->file, false); + DBG("Parent allocation is offset: %d, size: %d\n", + allocation->memory.submemfd.parent->region->offset, + allocation->memory.submemfd.parent->region->size); + break; + case NINE_MALLOC_ALLOC: + DBG("Allocation is a standard malloc\n"); + break; + case NINE_EXTERNAL_ALLOC: + DBG("Allocation is a suballocation of a standard malloc or an external allocation\n"); + break; + default: + assert(false); + } +} + +#else + +static void +debug_dump_memfd_state(struct nine_memfd_file *memfd_file, bool details) +{ + (void)memfd_file; + (void)details; +} + +static void +debug_dump_allocation_state(struct nine_allocation *allocation) +{ + (void)allocation; +} + +#endif + +static void +debug_dump_allocator_state(struct nine_allocator *allocator) +{ + DBG("SURFACE ALLOCATOR STATUS:\n"); + DBG("Total allocated: %lld\n", allocator->total_allocations); + DBG("Total virtual memory locked: %lld\n", allocator->total_locked_memory); + DBG("Virtual memory used: %lld / %lld\n", allocator->total_virtual_memory, allocator->total_virtual_memory_limit); + DBG("Num memfd files: %d / %d\n", allocator->num_fd, allocator->num_fd_max); +} + + +/* Retrieve file used for the storage of the content of this allocation. + * NULL if not using memfd */ +static struct nine_memfd_file * +nine_get_memfd_file_backing(struct nine_allocation *allocation) +{ + if (allocation->allocation_type > NINE_MEMFD_SUBALLOC) + return NULL; + if (allocation->allocation_type == NINE_MEMFD_ALLOC) + return allocation->memory.memfd.file; + return allocation->memory.submemfd.parent->file; +} + +/* Retrieve region used for the storage of the content of this allocation. + * NULL if not using memfd */ +static struct nine_memfd_file_region * +nine_get_memfd_region_backing(struct nine_allocation *allocation) +{ + if (allocation->allocation_type > NINE_MEMFD_SUBALLOC) + return NULL; + if (allocation->allocation_type == NINE_MEMFD_ALLOC) + return allocation->memory.memfd.region; + return allocation->memory.submemfd.parent->region; +} + +static void move_region(struct list_head *tail, struct nine_memfd_file_region *region) +{ + /* Remove from previous list (if any) */ + list_delinit(®ion->list); + /* Insert in new list (last) */ + list_addtail(®ion->list, tail); +} + +#if 0 +static void move_region_ordered(struct list_head *tail, struct nine_memfd_file_region *region) +{ + struct nine_memfd_file_region *cur_region; + struct list_head *insertion_point = tail; + + /* Remove from previous list (if any) */ + list_delinit(®ion->list); + + LIST_FOR_EACH_ENTRY(cur_region, tail, list) { + if (cur_region->offset > region->offset) + break; + insertion_point = &cur_region->list; + } + /* Insert just before cur_region */ + list_add(®ion->list, insertion_point); +} +#endif + +static void move_region_ordered_merge(struct nine_allocator *allocator, struct list_head *tail, struct nine_memfd_file_region *region) +{ + struct nine_memfd_file_region *p, *cur_region = NULL, *prev_region = NULL; + + /* Remove from previous list (if any) */ + list_delinit(®ion->list); + + LIST_FOR_EACH_ENTRY(p, tail, list) { + cur_region = p; + if (cur_region->offset > region->offset) + break; + prev_region = cur_region; + } + + /* Insert after prev_region and before cur_region. Try to merge */ + if (prev_region && ((prev_region->offset + prev_region->size) == region->offset)) { + if (cur_region && (cur_region->offset == (region->offset + region->size))) { + /* Merge all three regions */ + prev_region->size += region->size + cur_region->size; + prev_region->zero_filled = prev_region->zero_filled && region->zero_filled && cur_region->zero_filled; + list_del(&cur_region->list); + slab_free_st(&allocator->region_pool, region); + slab_free_st(&allocator->region_pool, cur_region); + } else { + prev_region->size += region->size; + prev_region->zero_filled = prev_region->zero_filled && region->zero_filled; + slab_free_st(&allocator->region_pool, region); + } + } else if (cur_region && (cur_region->offset == (region->offset + region->size))) { + cur_region->offset = region->offset; + cur_region->size += region->size; + cur_region->zero_filled = region->zero_filled && cur_region->zero_filled; + slab_free_st(&allocator->region_pool, region); + } else { + list_add(®ion->list, prev_region ? &prev_region->list : tail); + } +} + +static struct nine_memfd_file_region *allocate_region(struct nine_allocator *allocator, unsigned offset, unsigned size) { + struct nine_memfd_file_region *region = slab_alloc_st(&allocator->allocation_pool); + if (!region) + return NULL; + region->offset = offset; + region->size = size; + region->num_locks = 0; + region->num_weak_unlocks = 0; + region->map = NULL; + region->zero_filled = false; + list_inithead(®ion->list); + return region; +} + +/* Go through memfd allocated files, and try to use unused memory for the requested allocation. + * Returns whether it succeeded */ +static bool +insert_new_allocation(struct nine_allocator *allocator, struct nine_allocation *new_allocation, unsigned allocation_size) +{ + int memfd_index; + struct nine_memfd_file *memfd_file, *best_memfd_file; + struct nine_memfd_file_region *region, *best_region, *new_region; + + + /* Find the smallest - but bigger than the requested size - unused memory + * region inside the memfd files. */ + int min_blocksize = INT_MAX; + + for (memfd_index = 0; memfd_index < allocator->num_fd; memfd_index++) { + memfd_file = (void*)allocator->memfd_pool + memfd_index*sizeof(struct nine_memfd_file); + + LIST_FOR_EACH_ENTRY(region, &memfd_file->free_regions, list) { + if (region->size <= min_blocksize && region->size >= allocation_size) { + min_blocksize = region->size; + best_region = region; + best_memfd_file = memfd_file; + } + } + if (min_blocksize == allocation_size) + break; + } + + /* The allocation doesn't fit in any memfd file */ + if (min_blocksize == INT_MAX) + return false; + + /* Target region found */ + /* Move from free to unmapped allocated */ + best_region->size = DIVUP(allocation_size, allocator->page_size) * allocator->page_size; + assert(min_blocksize >= best_region->size); + move_region(&best_memfd_file->unmapped_allocated_regions, best_region); + new_allocation->memory.memfd.region = best_region; + new_allocation->memory.memfd.file = best_memfd_file; + + /* If the original region is bigger than needed, add new region with remaining space */ + min_blocksize -= best_region->size; + if (min_blocksize > 0) { + new_region = allocate_region(allocator, best_region->offset + best_region->size, min_blocksize); + new_region->zero_filled = best_region->zero_filled; + move_region_ordered_merge(allocator, &best_memfd_file->free_regions, new_region); + } + allocator->total_allocations += best_region->size; + return true; +} + +/* Go through allocations with unlocks waiting on pending_counter being 0. + * If 0 is indeed reached, update the allocation status */ +static void +nine_flush_pending_releases(struct nine_allocator *allocator) +{ + struct nine_allocation *allocation, *ptr; + LIST_FOR_EACH_ENTRY_SAFE(allocation, ptr, &allocator->pending_releases, list_release) { + assert(allocation->locks_on_counter > 0); + /* If pending_releases reached 0, remove from the list and update the status */ + if (*allocation->pending_counter == 0) { + struct nine_memfd_file *memfd_file = nine_get_memfd_file_backing(allocation); + struct nine_memfd_file_region *region = nine_get_memfd_region_backing(allocation); + region->num_locks -= allocation->locks_on_counter; + allocation->locks_on_counter = 0; + list_delinit(&allocation->list_release); + if (region->num_locks == 0) { + /* Move to the correct list */ + if (region->num_weak_unlocks) + move_region(&memfd_file->weak_unlocked_mapped_allocated_regions, region); + else + move_region(&memfd_file->unlocked_mapped_allocated_regions, region); + allocator->total_locked_memory -= region->size; + } + } + } +} + +static void +nine_free_internal(struct nine_allocator *allocator, struct nine_allocation *allocation); + +static void +nine_flush_pending_frees(struct nine_allocator *allocator) +{ + struct nine_allocation *allocation, *ptr; + + pthread_mutex_lock(&allocator->mutex_pending_frees); + /* The order of release matters as suballocations are supposed to be released first */ + LIST_FOR_EACH_ENTRY_SAFE(allocation, ptr, &allocator->pending_frees, list_free) { + /* Set the allocation in an unlocked state, and then free it */ + if (allocation->allocation_type == NINE_MEMFD_ALLOC || + allocation->allocation_type == NINE_MEMFD_SUBALLOC) { + struct nine_memfd_file *memfd_file = nine_get_memfd_file_backing(allocation); + struct nine_memfd_file_region *region = nine_get_memfd_region_backing(allocation); + if (region->num_locks != 0) { + region->num_locks = 0; + allocator->total_locked_memory -= region->size; + /* Useless, but to keep consistency */ + move_region(&memfd_file->unlocked_mapped_allocated_regions, region); + } + region->num_weak_unlocks = 0; + allocation->weak_unlock = false; + allocation->locks_on_counter = 0; + list_delinit(&allocation->list_release); + } + list_delinit(&allocation->list_free); + nine_free_internal(allocator, allocation); + } + pthread_mutex_unlock(&allocator->mutex_pending_frees); +} + +/* Try to unmap the memfd_index-th file if not already unmapped. + * If even_if_weak is False, will not unmap if there are weak unlocks */ +static void +nine_memfd_unmap_region(struct nine_allocator *allocator, + struct nine_memfd_file *memfd_file, + struct nine_memfd_file_region *region) +{ + DBG("Unmapping memfd mapped region at %d: size: %d, map=%p, locks=%d, weak=%d\n", + region->offset, region->size, region->map, + region->num_locks, region->num_weak_unlocks); + assert(region->map != NULL); + + if (munmap(region->map, region->size) != 0) + fprintf(stderr, "Error on unmapping, errno=%d\n", (int)errno); + + region->map = NULL; + /* Move from one of the mapped region list to the unmapped one */ + move_region(&memfd_file->unmapped_allocated_regions, region); + allocator->total_virtual_memory -= region->size; +} + +/* Unallocate a region of a memfd file */ +static void +remove_allocation(struct nine_allocator *allocator, struct nine_memfd_file *memfd_file, struct nine_memfd_file_region *region) +{ + assert(region->num_locks == 0); + region->num_weak_unlocks = 0; + /* Move from mapped region to unmapped region */ + if (region->map) { + if (likely(!region->zero_filled)) { + /* As the region is mapped, it is likely the pages are allocated. + * Do the memset now for when we allocate again. It is much faster now, + * as the pages are allocated. */ + DBG("memset on data=%p, size %d\n", region->map, region->size); + memset(region->map, 0, region->size); + region->zero_filled = true; + } + nine_memfd_unmap_region(allocator, memfd_file, region); + } + /* Move from unmapped region to free region */ + allocator->total_allocations -= region->size; + move_region_ordered_merge(allocator, &memfd_file->free_regions, region); +} + +/* Try to unmap the regions of the memfd_index-th file if not already unmapped. + * If even_if_weak is False, will not unmap if there are weak unlocks */ +static void +nine_memfd_try_unmap_file(struct nine_allocator *allocator, + int memfd_index, + bool weak) +{ + struct nine_memfd_file *memfd_file = (void*)allocator->memfd_pool + memfd_index*sizeof(struct nine_memfd_file); + struct nine_memfd_file_region *region, *ptr; + DBG("memfd file at %d: fd: %d, filesize: %d\n", + memfd_index, memfd_file->fd, memfd_file->filesize); + debug_dump_memfd_state(memfd_file, true); + LIST_FOR_EACH_ENTRY_SAFE(region, ptr, + weak ? + &memfd_file->weak_unlocked_mapped_allocated_regions : + &memfd_file->unlocked_mapped_allocated_regions, + list) { + nine_memfd_unmap_region(allocator, memfd_file, region); + } +} + +/* Unmap files until we are below the virtual memory target limit. + * If unmap_everything_possible is set, ignore the limit and unmap + * all that can be unmapped. */ +static void +nine_memfd_files_unmap(struct nine_allocator *allocator, + bool unmap_everything_possible) +{ + long long memory_limit = unmap_everything_possible ? + 0 : allocator->total_virtual_memory_limit; + int i; + + /* We are below the limit. Do nothing */ + if (memory_limit >= allocator->total_virtual_memory) + return; + + /* Update allocations with pending releases */ + nine_flush_pending_releases(allocator); + + DBG("Trying to unmap files with no weak unlock (%lld / %lld)\n", + allocator->total_virtual_memory, memory_limit); + + /* Try to release everything with no weak releases. + * Those have data not needed for a long time (and + * possibly ever). */ + for (i = 0; i < allocator->num_fd; i++) { + nine_memfd_try_unmap_file(allocator, i, false); + if (memory_limit >= allocator->total_virtual_memory) { + return;} + } + + DBG("Trying to unmap files even with weak unlocks (%lld / %lld)\n", + allocator->total_virtual_memory, memory_limit); + + /* This wasn't enough. Also release files with weak releases */ + for (i = 0; i < allocator->num_fd; i++) { + nine_memfd_try_unmap_file(allocator, i, true); + /* Stop if the target is reached */ + if (memory_limit >= allocator->total_virtual_memory) { + return;} + } + + if (!unmap_everything_possible) + return; + + /* If there are some pending uploads, execute them, + * and retry. */ + if (list_is_empty(&allocator->pending_releases)) { + return;} + nine_csmt_process(allocator->device); + nine_flush_pending_releases(allocator); + + DBG("Retrying after flushing (%lld / %lld)\n", + allocator->total_virtual_memory, memory_limit); + + for (i = 0; i < allocator->num_fd; i++) { + nine_memfd_try_unmap_file(allocator, i, false); + nine_memfd_try_unmap_file(allocator, i, true); + } + /* We have done all we could */ +} + +/* Map a given memfd file */ +static bool +nine_memfd_region_map(struct nine_allocator *allocator, struct nine_memfd_file *memfd_file, struct nine_memfd_file_region *region) +{ + if (region->map != NULL) + return true; + + debug_dump_memfd_state(memfd_file, true); + nine_memfd_files_unmap(allocator, false); + + void *buf = mmap(NULL, region->size, PROT_READ | PROT_WRITE, MAP_SHARED, memfd_file->fd, region->offset); + + if (buf == MAP_FAILED && errno == ENOMEM) { + DBG("Failed to mmap a memfd file - trying to unmap other files\n"); + nine_memfd_files_unmap(allocator, true); + buf = mmap(NULL, region->size, PROT_READ | PROT_WRITE, MAP_SHARED, memfd_file->fd, region->offset); + } + if (buf == MAP_FAILED) { + DBG("Failed to mmap a memfd file, errno=%d\n", (int)errno); + return false; + } + region->map = buf; + /* no need to move to an unlocked mapped regions list, the caller will handle the list */ + allocator->total_virtual_memory += region->size; + assert((uintptr_t)buf % NINE_ALLOCATION_ALIGNMENT == 0); /* mmap should be page_size aligned, so it should be fine */ + + return true; +} + +/* Allocate with memfd some memory. Returns True if successful. */ +static bool +nine_memfd_allocator(struct nine_allocator *allocator, + struct nine_allocation *new_allocation, + unsigned allocation_size) +{ + struct nine_memfd_file *memfd_file; + struct nine_memfd_file_region *region; + + allocation_size = DIVUP(allocation_size, allocator->page_size) * allocator->page_size; + new_allocation->allocation_type = NINE_MEMFD_ALLOC; + new_allocation->locks_on_counter = 0; + new_allocation->pending_counter = NULL; + new_allocation->weak_unlock = false; + list_inithead(&new_allocation->list_free); + list_inithead(&new_allocation->list_release); + + /* Try to find free space in a file already allocated */ + if (insert_new_allocation(allocator, new_allocation, allocation_size)) + return true; + + /* No - allocate new memfd file */ + + if (allocator->num_fd == allocator->num_fd_max) + return false; /* Too many memfd files */ + + allocator->num_fd++; + memfd_file = (void*)allocator->memfd_pool + (allocator->num_fd-1)*sizeof(struct nine_memfd_file); + /* If the allocation size is above the memfd file default size, use a bigger size */ + memfd_file->filesize = MAX2(allocation_size, allocator->min_file_size); + + memfd_file->fd = memfd_create("gallium_nine_ram", 0); + if (memfd_file->fd == -1) { + DBG("Failed to created a memfd file, errno=%d\n", (int)errno); + allocator->num_fd--; + return false; + } + + if (ftruncate(memfd_file->fd, memfd_file->filesize) != 0) { + DBG("Failed to resize a memfd file, errno=%d\n", (int)errno); + close(memfd_file->fd); + allocator->num_fd--; + return false; + } + + list_inithead(&memfd_file->free_regions); + list_inithead(&memfd_file->unmapped_allocated_regions); + list_inithead(&memfd_file->locked_mapped_allocated_regions); + list_inithead(&memfd_file->unlocked_mapped_allocated_regions); + list_inithead(&memfd_file->weak_unlocked_mapped_allocated_regions); + + /* Initialize the memfd file with empty region and the allocation */ + region = allocate_region(allocator, 0, allocation_size); + region->zero_filled = true; /* ftruncate does zero-fill the new data */ + list_add(®ion->list, &memfd_file->unmapped_allocated_regions); + new_allocation->memory.memfd.file = memfd_file; + new_allocation->memory.memfd.region = region; + allocator->total_allocations += allocation_size; + + if (allocation_size == memfd_file->filesize) + return true; + + /* Add empty region */ + region = allocate_region(allocator, allocation_size, memfd_file->filesize - allocation_size); + region->zero_filled = true; /* ftruncate does zero-fill the new data */ + list_add(®ion->list, &memfd_file->free_regions); + + return true; +} + +/* Allocate memory */ +struct nine_allocation * +nine_allocate(struct nine_allocator *allocator, unsigned size) +{ + + struct nine_allocation *new_allocation = slab_alloc_st(&allocator->allocation_pool); + debug_dump_allocator_state(allocator); + if (!new_allocation) + return NULL; + + nine_flush_pending_frees(allocator); + + /* Restrict to >= page_size to prevent having too much fragmentation, as the size of + * allocations is rounded to the next page_size multiple. */ + if (size >= allocator->page_size && allocator->total_virtual_memory_limit >= 0 && + nine_memfd_allocator(allocator, new_allocation, size)) { + struct nine_memfd_file_region *region = new_allocation->memory.memfd.region; + if (!region->zero_filled) { + void *data = nine_get_pointer(allocator, new_allocation); + if (!data) { + ERR("INTERNAL MMAP FOR NEW ALLOCATION FAILED\n"); + nine_free(allocator, new_allocation); + return NULL; + } + DBG("memset on data=%p, size %d\n", data, region->size); + memset(data, 0, region->size); + region->zero_filled = true; + /* Even though the user usually fills afterward, we don't weakrelease. + * The reason is suballocations don't affect the weakrelease state of their + * parents. Thus if only suballocations are accessed, the release would stay + * weak forever. */ + nine_pointer_strongrelease(allocator, new_allocation); + } + DBG("ALLOCATION SUCCESSFUL\n"); + debug_dump_allocation_state(new_allocation); + return new_allocation; + } + + void *data = align_calloc(size, NINE_ALLOCATION_ALIGNMENT); + if (!data) { + DBG("ALLOCATION FAILED\n"); + return NULL; + } + + new_allocation->allocation_type = NINE_MALLOC_ALLOC; + new_allocation->memory.malloc.buf = data; + new_allocation->memory.malloc.allocation_size = size; + list_inithead(&new_allocation->list_free); + allocator->total_allocations += size; + allocator->total_locked_memory += size; + allocator->total_virtual_memory += size; + DBG("ALLOCATION SUCCESSFUL\n"); + debug_dump_allocation_state(new_allocation); + return new_allocation; +} + +/* Release memory */ +static void +nine_free_internal(struct nine_allocator *allocator, struct nine_allocation *allocation) +{ + DBG("RELEASING ALLOCATION\n"); + debug_dump_allocation_state(allocation); + if (allocation->allocation_type == NINE_MALLOC_ALLOC) { + allocator->total_allocations -= allocation->memory.malloc.allocation_size; + allocator->total_locked_memory -= allocation->memory.malloc.allocation_size; + allocator->total_virtual_memory -= allocation->memory.malloc.allocation_size; + align_free(allocation->memory.malloc.buf); + } else if (allocation->allocation_type == NINE_MEMFD_ALLOC || + allocation->allocation_type == NINE_MEMFD_SUBALLOC) { + struct nine_memfd_file *memfd_file = nine_get_memfd_file_backing(allocation); + struct nine_memfd_file_region *region = nine_get_memfd_region_backing(allocation); + if (allocation->weak_unlock) + region->num_weak_unlocks--; + if (allocation->allocation_type == NINE_MEMFD_ALLOC) + remove_allocation(allocator, memfd_file, region); + } + + slab_free_st(&allocator->allocation_pool, allocation); + debug_dump_allocator_state(allocator); +} + + +void +nine_free(struct nine_allocator *allocator, struct nine_allocation *allocation) +{ + nine_flush_pending_frees(allocator); + nine_flush_pending_releases(allocator); + nine_free_internal(allocator, allocation); +} + +/* Called from the worker thread. Similar to nine_free except we are not in the main thread, thus + * we are disallowed to change the allocator structures except the fields reserved + * for the worker. In addition, the allocation is allowed to not being unlocked (the release + * will unlock it) */ +void nine_free_worker(struct nine_allocator *allocator, struct nine_allocation *allocation) +{ + /* Add the allocation to the list of pending allocations to free */ + pthread_mutex_lock(&allocator->mutex_pending_frees); + /* The order of free matters as suballocations are supposed to be released first */ + list_addtail(&allocation->list_free, &allocator->pending_frees); + pthread_mutex_unlock(&allocator->mutex_pending_frees); +} + +/* Lock an allocation, and retrieve the pointer */ +void * +nine_get_pointer(struct nine_allocator *allocator, struct nine_allocation *allocation) +{ + struct nine_memfd_file *memfd_file; + struct nine_memfd_file_region *region; + + nine_flush_pending_releases(allocator); + DBG("allocation_type: %d\n", allocation->allocation_type); + + if (allocation->allocation_type == NINE_MALLOC_ALLOC) + return allocation->memory.malloc.buf; + if (allocation->allocation_type == NINE_EXTERNAL_ALLOC) + return allocation->memory.external.buf; + + memfd_file = nine_get_memfd_file_backing(allocation); + region = nine_get_memfd_region_backing(allocation); + if (!nine_memfd_region_map(allocator, memfd_file, region)) { + DBG("Couldn't map memfd region for get_pointer\n"); + return NULL; + } + + move_region(&memfd_file->locked_mapped_allocated_regions, region); /* Note: redundant if region->num_locks */ + region->num_locks++; + + if (region->num_locks == 1) + allocator->total_locked_memory += region->size; + if (allocation->weak_unlock) + region->num_weak_unlocks--; + allocation->weak_unlock = false; + region->zero_filled = false; + + + if (allocation->allocation_type == NINE_MEMFD_ALLOC) + return region->map; + if (allocation->allocation_type == NINE_MEMFD_SUBALLOC) + return region->map + allocation->memory.submemfd.relative_offset; + + assert(false); + return NULL; +} + +/* Unlock an allocation, but with hint that we might lock again soon */ +void +nine_pointer_weakrelease(struct nine_allocator *allocator, struct nine_allocation *allocation) +{ + struct nine_memfd_file_region *region; + if (allocation->allocation_type > NINE_MEMFD_SUBALLOC) + return; + + region = nine_get_memfd_region_backing(allocation); + if (!allocation->weak_unlock) + region->num_weak_unlocks++; + allocation->weak_unlock = true; + region->num_locks--; + if (region->num_locks == 0) { + struct nine_memfd_file *memfd_file = nine_get_memfd_file_backing(allocation); + allocator->total_locked_memory -= region->size; + move_region(&memfd_file->weak_unlocked_mapped_allocated_regions, region); + } +} + +/* Unlock an allocation */ +void +nine_pointer_strongrelease(struct nine_allocator *allocator, struct nine_allocation *allocation) +{ + struct nine_memfd_file_region *region; + if (allocation->allocation_type > NINE_MEMFD_SUBALLOC) + return; + + region = nine_get_memfd_region_backing(allocation); + region->num_locks--; + if (region->num_locks == 0) { + struct nine_memfd_file *memfd_file = nine_get_memfd_file_backing(allocation); + allocator->total_locked_memory -= region->size; + if (region->num_weak_unlocks) + move_region(&memfd_file->weak_unlocked_mapped_allocated_regions, region); + else + move_region(&memfd_file->unlocked_mapped_allocated_regions, region); + } +} + +/* Delay a release to when a given counter becomes zero */ +void +nine_pointer_delayedstrongrelease(struct nine_allocator *allocator, struct nine_allocation *allocation, unsigned *counter) +{ + if (allocation->allocation_type > NINE_MEMFD_SUBALLOC) + return; + + assert(allocation->pending_counter == NULL || allocation->pending_counter == counter); + allocation->pending_counter = counter; + allocation->locks_on_counter++; + + if (list_is_empty(&allocation->list_release)) + list_add(&allocation->list_release, &allocator->pending_releases); +} + +/* Create a suballocation of an allocation */ +struct nine_allocation * +nine_suballocate(struct nine_allocator* allocator, struct nine_allocation *allocation, int offset) +{ + struct nine_allocation *new_allocation = slab_alloc_st(&allocator->allocation_pool); + if (!new_allocation) + return NULL; + + DBG("Suballocate allocation at offset: %d\n", offset); + assert(allocation->allocation_type != NINE_MEMFD_SUBALLOC); + list_inithead(&new_allocation->list_free); + + if (allocation->allocation_type != NINE_MEMFD_ALLOC) { + new_allocation->allocation_type = NINE_EXTERNAL_ALLOC; + if (allocation->allocation_type == NINE_MALLOC_ALLOC) + new_allocation->memory.external.buf = allocation->memory.malloc.buf + offset; + else + new_allocation->memory.external.buf = allocation->memory.external.buf + offset; + return new_allocation; + } + new_allocation->allocation_type = NINE_MEMFD_SUBALLOC; + new_allocation->memory.submemfd.parent = &allocation->memory.memfd; + new_allocation->memory.submemfd.relative_offset = offset; + new_allocation->locks_on_counter = 0; + new_allocation->pending_counter = NULL; + new_allocation->weak_unlock = false; + list_inithead(&new_allocation->list_release); + debug_dump_allocation_state(new_allocation); + return new_allocation; +} + +/* Wrap an external pointer as an allocation */ +struct nine_allocation * +nine_wrap_external_pointer(struct nine_allocator* allocator, void* data) +{ + struct nine_allocation *new_allocation = slab_alloc_st(&allocator->allocation_pool); + if (!new_allocation) + return NULL; + DBG("Wrapping external pointer: %p\n", data); + new_allocation->allocation_type = NINE_EXTERNAL_ALLOC; + new_allocation->memory.external.buf = data; + list_inithead(&new_allocation->list_free); + return new_allocation; +} + +struct nine_allocator * +nine_allocator_create(struct NineDevice9 *device, int memfd_virtualsizelimit) +{ + struct nine_allocator* allocator = MALLOC(sizeof(struct nine_allocator)); + + if (!allocator) + return NULL; + + allocator->device = device; + allocator->page_size = sysconf(_SC_PAGESIZE); + assert(allocator->page_size == 4 << 10); + allocator->num_fd_max = (memfd_virtualsizelimit >= 0) ? MIN2(128, sysconf(_SC_OPEN_MAX)) : 0; + allocator->min_file_size = DIVUP(100 * (1 << 20), allocator->page_size) * allocator->page_size; /* 100MB files */ + allocator->total_allocations = 0; + allocator->total_locked_memory = 0; + allocator->total_virtual_memory = 0; + allocator->total_virtual_memory_limit = memfd_virtualsizelimit * (1 << 20); + allocator->num_fd = 0; + + DBG("Allocator created (ps: %d; fm: %d)\n", allocator->page_size, allocator->num_fd_max); + + slab_create(&allocator->allocation_pool, sizeof(struct nine_allocation), 4096); + slab_create(&allocator->region_pool, sizeof(struct nine_memfd_file_region), 4096); + allocator->memfd_pool = CALLOC(allocator->num_fd_max, sizeof(struct nine_memfd_file)); + list_inithead(&allocator->pending_releases); + list_inithead(&allocator->pending_frees); + pthread_mutex_init(&allocator->mutex_pending_frees, NULL); + return allocator; +} + +void +nine_allocator_destroy(struct nine_allocator* allocator) +{ + int i; + DBG("DESTROYING ALLOCATOR\n"); + debug_dump_allocator_state(allocator); + nine_flush_pending_releases(allocator); + nine_flush_pending_frees(allocator); + nine_memfd_files_unmap(allocator, true); + pthread_mutex_destroy(&allocator->mutex_pending_frees); + + assert(list_is_empty(&allocator->pending_frees)); + assert(list_is_empty(&allocator->pending_releases)); + for (i = 0; i < allocator->num_fd; i++) { + debug_dump_memfd_state(&allocator->memfd_pool[i], true); + assert(list_is_empty(&allocator->memfd_pool[i].locked_mapped_allocated_regions)); + assert(list_is_empty(&allocator->memfd_pool[i].weak_unlocked_mapped_allocated_regions)); + assert(list_is_empty(&allocator->memfd_pool[i].unlocked_mapped_allocated_regions)); + assert(list_is_singular(&allocator->memfd_pool[i].free_regions)); + slab_free_st(&allocator->region_pool, + list_first_entry(&allocator->memfd_pool[i].free_regions, + struct nine_memfd_file_region, list)); + close(allocator->memfd_pool[i].fd); + } + slab_destroy(&allocator->allocation_pool); + slab_destroy(&allocator->region_pool); + FREE(allocator->memfd_pool); + FREE(allocator); +} + +#else + +struct nine_allocation { + unsigned is_external; + void *external; +}; + +struct nine_allocator { + struct slab_mempool external_allocation_pool; + pthread_mutex_t mutex_slab; +}; + +struct nine_allocation * +nine_allocate(struct nine_allocator *allocator, unsigned size) +{ + struct nine_allocation *allocation; + (void)allocator; + assert(sizeof(struct nine_allocation) <= NINE_ALLOCATION_ALIGNMENT); + allocation = align_calloc(size + NINE_ALLOCATION_ALIGNMENT, NINE_ALLOCATION_ALIGNMENT); + allocation->is_external = false; + return allocation; +} + + +void nine_free(struct nine_allocator *allocator, struct nine_allocation *allocation) +{ + if (allocation->is_external) { + pthread_mutex_lock(&allocator->mutex_slab); + slab_free_st(&allocator->external_allocation_pool, allocation); + pthread_mutex_unlock(&allocator->mutex_slab); + } else + align_free(allocation); +} + +void nine_free_worker(struct nine_allocator *allocator, struct nine_allocation *allocation) +{ + nine_free(allocator, allocation); +} + +void *nine_get_pointer(struct nine_allocator *allocator, struct nine_allocation *allocation) +{ + (void)allocator; + if (allocation->is_external) + return allocation->external; + return (uint8_t *)allocation + NINE_ALLOCATION_ALIGNMENT; +} + +void nine_pointer_weakrelease(struct nine_allocator *allocator, struct nine_allocation *allocation) +{ + (void)allocator; + (void)allocation; +} + +void nine_pointer_strongrelease(struct nine_allocator *allocator, struct nine_allocation *allocation) +{ + (void)allocator; + (void)allocation; +} + +void nine_pointer_delayedstrongrelease(struct nine_allocator *allocator, + struct nine_allocation *allocation, + unsigned *counter) +{ + (void)allocator; + (void)allocation; + (void)counter; +} + +struct nine_allocation * +nine_suballocate(struct nine_allocator* allocator, struct nine_allocation *allocation, int offset) +{ + struct nine_allocation *new_allocation; + pthread_mutex_lock(&allocator->mutex_slab); + new_allocation = slab_alloc_st(&allocator->external_allocation_pool); + pthread_mutex_unlock(&allocator->mutex_slab); + new_allocation->is_external = true; + new_allocation->external = (uint8_t *)allocation + NINE_ALLOCATION_ALIGNMENT + offset; + return new_allocation; +} + +struct nine_allocation * +nine_wrap_external_pointer(struct nine_allocator* allocator, void* data) +{ + struct nine_allocation *new_allocation; + pthread_mutex_lock(&allocator->mutex_slab); + new_allocation = slab_alloc_st(&allocator->external_allocation_pool); + pthread_mutex_unlock(&allocator->mutex_slab); + new_allocation->is_external = true; + new_allocation->external = data; + return new_allocation; +} + +struct nine_allocator * +nine_allocator_create(struct NineDevice9 *device, int memfd_virtualsizelimit) +{ + struct nine_allocator* allocator = MALLOC(sizeof(struct nine_allocator)); + (void)device; + (void)memfd_virtualsizelimit; + + if (!allocator) + return NULL; + + slab_create(&allocator->external_allocation_pool, sizeof(struct nine_allocation), 4096); + pthread_mutex_init(&allocator->mutex_slab, NULL); + + return allocator; +} + +void +nine_allocator_destroy(struct nine_allocator *allocator) +{ + slab_destroy(&allocator->external_allocation_pool); + pthread_mutex_destroy(&allocator->mutex_slab); +} + +#endif /* NINE_ENABLE_MEMFD */ diff --git a/src/gallium/frontends/nine/nine_memory_helper.h b/src/gallium/frontends/nine/nine_memory_helper.h new file mode 100644 index 0000000..7c08931 --- /dev/null +++ b/src/gallium/frontends/nine/nine_memory_helper.h @@ -0,0 +1,58 @@ +/* + * Copyright 2020 Axel Davy + * SPDX-License-Identifier: MIT + */ + +#ifndef _NINE_MEMORY_HELPER_H_ +#define _NINE_MEMORY_HELPER_H_ + + +struct NineDevice9; + +struct nine_allocator; +struct nine_allocation; + +/* Note: None of these functions are thread safe, thus the worker thread is disallowed + * to call any of them. Only exception is nine_free_worker reserved for it. */ + +struct nine_allocation * +nine_allocate(struct nine_allocator *allocator, unsigned size); + +/* Note: Suballocations MUST be freed before their parent */ +void nine_free(struct nine_allocator *allocator, struct nine_allocation *allocation); +void nine_free_worker(struct nine_allocator *allocator, struct nine_allocation *allocation); + +void *nine_get_pointer(struct nine_allocator *allocator, struct nine_allocation *allocation); + +/* We don't need the pointer anymore, but we are likely to need it again soon */ +void nine_pointer_weakrelease(struct nine_allocator *allocator, struct nine_allocation *allocation); + +/* We don't need the pointer anymore, probably for a long time */ +void nine_pointer_strongrelease(struct nine_allocator *allocator, struct nine_allocation *allocation); + +/* You can strong release when counter becomes 0. + * Once a counter is used for a given allocation, the same must keep being used */ +void nine_pointer_delayedstrongrelease(struct nine_allocator *allocator, + struct nine_allocation *allocation, + unsigned *counter); + +/* Note: It is disallowed to release a suballocation before its parent. + * It is disallowed to suballocate on a suballocation. */ +struct nine_allocation * +nine_suballocate(struct nine_allocator* allocator, struct nine_allocation *allocation, int offset); + +/* Won't be freed - but at least we can use the same interface */ +struct nine_allocation * +nine_wrap_external_pointer(struct nine_allocator* allocator, void* data); + + +/* memfd_virtualsizelimit: Limit for the virtual memory usage (in MB) + * above which memfd files are unmapped (to reduce virtual memory usage). + * If negative, disables memfd usage. */ +struct nine_allocator * +nine_allocator_create(struct NineDevice9 *device, int memfd_virtualsizelimit); + +void +nine_allocator_destroy(struct nine_allocator *allocator); + +#endif /* _NINE_MEMORY_HELPER_H_ */ diff --git a/src/gallium/frontends/nine/nine_pdata.h b/src/gallium/frontends/nine/nine_pdata.h new file mode 100644 index 0000000..c0a5b47 --- /dev/null +++ b/src/gallium/frontends/nine/nine_pdata.h @@ -0,0 +1,48 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#ifndef _NINE_PDATA_H_ +#define _NINE_PDATA_H_ + +#include "util/hash_table.h" + +struct pheader +{ + bool unknown; + GUID guid; + DWORD size; +}; + +static bool +ht_guid_compare( const void *a, + const void *b ) +{ + return GUID_equal(a, b); +} + +static uint32_t +ht_guid_hash( const 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 void +ht_guid_delete( struct hash_entry *entry ) +{ + struct pheader *header = entry->data; + void *header_data = (void *)header + sizeof(*header); + + if (header->unknown) { IUnknown_Release(*(IUnknown **)header_data); } + FREE(header); +} + +#endif /* _NINE_PDATA_H_ */ diff --git a/src/gallium/frontends/nine/nine_pipe.c b/src/gallium/frontends/nine/nine_pipe.c new file mode 100644 index 0000000..559b4e0 --- /dev/null +++ b/src/gallium/frontends/nine/nine_pipe.c @@ -0,0 +1,382 @@ +/* + * Copyright 2011 Joakim Sindholt + * Copyright 2013 Christoph Bumiller + * SPDX-License-Identifier: MIT + */ + +#include "device9.h" +#include "nine_pipe.h" + +#include "cso_cache/cso_context.h" + +void +nine_convert_dsa_state(struct pipe_depth_stencil_alpha_state *dsa_state, + 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_func = d3dcmpfunc_to_pipe_func(rs[D3DRS_ZFUNC]); + /* Disable depth write if no change can occur */ + dsa.depth_writemask = !!rs[D3DRS_ZWRITEENABLE] && + dsa.depth_func != PIPE_FUNC_EQUAL && + dsa.depth_func != PIPE_FUNC_NEVER; + } + + 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] && rs[NINED3DRS_EMULATED_ALPHATEST] == 7 && rs[D3DRS_ALPHAFUNC] != D3DCMP_ALWAYS) { + dsa.alpha_enabled = 1; + dsa.alpha_func = d3dcmpfunc_to_pipe_func(rs[D3DRS_ALPHAFUNC]); + dsa.alpha_ref_value = (float)rs[D3DRS_ALPHAREF] / 255.0f; + } + + *dsa_state = dsa; +} + +void +nine_convert_rasterizer_state(struct NineDevice9 *device, + struct pipe_rasterizer_state *rast_state, + const DWORD *rs) +{ + struct pipe_rasterizer_state rast; + + memset(&rast, 0, sizeof(rast)); + + 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 = 1; + rast.point_size_per_vertex = rs[NINED3DRS_VSPOINTSIZE]; + rast.multisample = rs[NINED3DRS_MULTISAMPLE]; + 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; */ + if (rs[NINED3DRS_POSITIONT] && + !device->driver_caps.window_space_position_support && + device->driver_caps.disabling_depth_clipping_support) { + /* rast.depth_clip_near = 0; */ + /* rast.depth_clip_far = 0; */ + rast.depth_clamp = 1; + } else { + rast.depth_clip_near = 1; + rast.depth_clip_far = 1; + /* rast.depth_clamp = 0; */ + } + 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.line_rectangular = 0; + if (rs[NINED3DRS_VSPOINTSIZE]) { + rast.point_size = 1.0f; + } else { + rast.point_size = CLAMP(asfloat(rs[D3DRS_POINTSIZE]), + asfloat(rs[D3DRS_POINTSIZE_MIN]), + asfloat(rs[D3DRS_POINTSIZE_MAX])); + } + /* offset_units has the ogl/d3d11 meaning. + * d3d9: offset = scale * dz + bias + * ogl/d3d11: offset = scale * dz + r * bias + * with r implementation dependent (+ different formula for float depth + * buffers). r=2^-23 is often the right value for gallium drivers. + * If possible, use offset_units_unscaled, which gives the d3d9 + * behaviour, else scale by 1 << 23 */ + rast.offset_units = asfloat(rs[D3DRS_DEPTHBIAS]) * (device->driver_caps.offset_units_unscaled ? 1.0f : (float)(1 << 23)); + rast.offset_units_unscaled = device->driver_caps.offset_units_unscaled; + rast.offset_scale = asfloat(rs[D3DRS_SLOPESCALEDEPTHBIAS]); + /* rast.offset_clamp = 0.0f; */ + + *rast_state = 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 pipe_blend_state *blend_state, 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 = !!(rs[NINED3DRS_ALPHACOVERAGE] & 5); + + 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.max_rt = 3; /* Upper bound. Could be optimized to fb->nr_cbufs for example */ + 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]; */ + + *blend_state = 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)); + + 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_lod = 0.0; + samp.lod_bias = 0.0; + samp.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; + } + samp.max_lod = 15.0f; + + if (ss[NINED3DSAMP_CUBETEX]) { + /* Cube textures are always clamped to edge on D3D */ + samp.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + samp.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + samp.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + } else { + 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 && !ss[NINED3DSAMP_SHADOW]) ? PIPE_TEX_FILTER_NEAREST : PIPE_TEX_FILTER_LINEAR; + samp.mag_img_filter = (ss[D3DSAMP_MAGFILTER] == D3DTEXF_POINT && !ss[NINED3DSAMP_SHADOW]) ? PIPE_TEX_FILTER_NEAREST : PIPE_TEX_FILTER_LINEAR; + if (ss[D3DSAMP_MINFILTER] == D3DTEXF_ANISOTROPIC || + ss[D3DSAMP_MAGFILTER] == D3DTEXF_ANISOTROPIC) + samp.max_anisotropy = MIN2(16, ss[D3DSAMP_MAXANISOTROPY]); + else + samp.max_anisotropy = 0; + samp.compare_mode = ss[NINED3DSAMP_SHADOW] ? PIPE_TEX_COMPARE_R_TO_TEXTURE : PIPE_TEX_COMPARE_NONE; + samp.compare_func = PIPE_FUNC_LEQUAL; + samp.unnormalized_coords = 0; + samp.seamless_cube_map = 0; + samp.border_color_is_integer = 0; + samp.reduction_mode = 0; + samp.pad = 0; + samp.border_color_format = PIPE_FORMAT_NONE; + 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, MESA_SHADER_FRAGMENT, idx - NINE_SAMPLER_PS(0), &samp); + else + cso_single_sampler(ctx, MESA_SHADER_VERTEX, idx - NINE_SAMPLER_VS(0), &samp); +} + +const enum pipe_format nine_d3d9_to_pipe_format_map[120] = +{ + [D3DFMT_UNKNOWN] = PIPE_FORMAT_NONE, + [D3DFMT_R8G8B8] = PIPE_FORMAT_R8G8B8_UNORM, + [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_R3G3B2] = PIPE_FORMAT_B2G3R3_UNORM, + [D3DFMT_A8] = PIPE_FORMAT_A8_UNORM, + [D3DFMT_A8R3G3B2] = PIPE_FORMAT_NONE, + [D3DFMT_X4R4G4B4] = PIPE_FORMAT_B4G4R4X4_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, + [D3DFMT_A8P8] = PIPE_FORMAT_NONE, + [D3DFMT_P8] = 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_L6V5U5] = PIPE_FORMAT_NONE, /* Should be PIPE_FORMAT_R5SG5SB6U_NORM, but interpretation of the data differs a bit. */ + [D3DFMT_X8L8V8U8] = PIPE_FORMAT_R8SG8SB8UX8U_NORM, + [D3DFMT_Q8W8V8U8] = PIPE_FORMAT_R8G8B8A8_SNORM, + [D3DFMT_V16U16] = PIPE_FORMAT_R16G16_SNORM, + [D3DFMT_A2W10V10U10] = PIPE_FORMAT_R10SG10SB10SA2U_NORM, + [D3DFMT_D16_LOCKABLE] = PIPE_FORMAT_Z16_UNORM, + [D3DFMT_D32] = PIPE_FORMAT_Z32_UNORM, + [D3DFMT_D15S1] = PIPE_FORMAT_NONE, + [D3DFMT_D24S8] = PIPE_FORMAT_S8_UINT_Z24_UNORM, + [D3DFMT_D24X8] = PIPE_FORMAT_X8Z24_UNORM, + [D3DFMT_D24X4S4] = PIPE_FORMAT_NONE, + [D3DFMT_D16] = PIPE_FORMAT_Z16_UNORM, + [D3DFMT_D32F_LOCKABLE] = PIPE_FORMAT_Z32_FLOAT, + [D3DFMT_D24FS8] = PIPE_FORMAT_Z32_FLOAT_S8X24_UINT, + [D3DFMT_D32_LOCKABLE] = PIPE_FORMAT_NONE, + [D3DFMT_S8_LOCKABLE] = PIPE_FORMAT_NONE, + [D3DFMT_L16] = PIPE_FORMAT_L16_UNORM, + [D3DFMT_VERTEXDATA] = PIPE_FORMAT_NONE, + [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_G16R16F] = PIPE_FORMAT_R16G16_FLOAT, + [D3DFMT_A16B16G16R16F] = PIPE_FORMAT_R16G16B16A16_FLOAT, + [D3DFMT_R32F] = PIPE_FORMAT_R32_FLOAT, + [D3DFMT_G32R32F] = PIPE_FORMAT_R32G32_FLOAT, + [D3DFMT_A32B32G32R32F] = PIPE_FORMAT_R32G32B32A32_FLOAT, + [D3DFMT_CxV8U8] = PIPE_FORMAT_NONE, + [D3DFMT_A1] = PIPE_FORMAT_NONE, + [D3DFMT_A2B10G10R10_XR_BIAS] = PIPE_FORMAT_NONE, +}; + +const D3DFORMAT nine_pipe_to_d3d9_format_map[PIPE_FORMAT_COUNT] = +{ + [PIPE_FORMAT_NONE] = D3DFMT_UNKNOWN, + /* TODO: rename PIPE_FORMAT_R8G8B8_UNORM to PIPE_FORMAT_B8G8R8_UNORM */ + [PIPE_FORMAT_R8G8B8_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/frontends/nine/nine_pipe.h b/src/gallium/frontends/nine/nine_pipe.h new file mode 100644 index 0000000..740e559 --- /dev/null +++ b/src/gallium/frontends/nine/nine_pipe.h @@ -0,0 +1,853 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#ifndef _NINE_PIPE_H_ +#define _NINE_PIPE_H_ + +#include "d3d9.h" +#include "util/format/u_formats.h" +#include "pipe/p_screen.h" +#include "pipe/p_state.h" /* pipe_box */ +#include "util/macros.h" +#include "util/u_rect.h" +#include "util/format/u_format.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 pipe_depth_stencil_alpha_state *, const DWORD *); +void nine_convert_rasterizer_state(struct NineDevice9 *, struct pipe_rasterizer_state *, const DWORD *); +void nine_convert_blend_state(struct pipe_blend_state *, const DWORD *); +void nine_convert_sampler_state(struct cso_context *, int idx, const DWORD *); + +#define is_ATI1_ATI2(format) (format == PIPE_FORMAT_RGTC1_UNORM || format == PIPE_FORMAT_RGTC2_UNORM) + +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 void +pipe_box_to_rect(RECT *dst, const struct pipe_box *src) +{ + dst->left = src->x; + dst->right = src->x + src->width; + dst->top = src->y; + dst->bottom = src->y + src->height; +} + +static inline void +rect_minify_inclusive(RECT *rect) +{ + rect->left = rect->left >> 2; + rect->top = rect->top >> 2; + rect->right = DIV_ROUND_UP(rect->right, 2); + rect->bottom = DIV_ROUND_UP(rect->bottom, 2); +} + +/* We suppose: + * 0 <= rect->left < rect->right + * 0 <= rect->top < rect->bottom + */ +static inline void +fit_rect_format_inclusive(enum pipe_format format, RECT *rect, int width, int height) +{ + const unsigned w = util_format_get_blockwidth(format); + const unsigned h = util_format_get_blockheight(format); + + if (util_format_is_compressed(format)) { + rect->left = rect->left - rect->left % w; + rect->top = rect->top - rect->top % h; + rect->right = (rect->right % w) == 0 ? + rect->right : + rect->right - (rect->right % w) + w; + rect->bottom = (rect->bottom % h) == 0 ? + rect->bottom : + rect->bottom - (rect->bottom % h) + h; + } + + rect->right = MIN2(rect->right, width); + rect->bottom = MIN2(rect->bottom, height); +} + +static inline bool +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 bool +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 +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 bool +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 bool +fetch4_compatible_format( D3DFORMAT fmt ) +{ + /* Basically formats with only red channel are allowed (with some exceptions) */ + static const D3DFORMAT allowed[] = { /* TODO: list incomplete */ + D3DFMT_L8, + D3DFMT_L16, + D3DFMT_R16F, + D3DFMT_R32F, + D3DFMT_A8, + D3DFMT_DF16, + D3DFMT_DF24, + D3DFMT_INTZ + }; + unsigned i; + + for (i = 0; i < sizeof(allowed)/sizeof(D3DFORMAT); i++) { + if (fmt == allowed[i]) { return true; } + } + return false; +} + +/* ATI1 and ATI2 are not officially compressed in d3d9 */ +static inline bool +compressed_format( D3DFORMAT fmt ) +{ + switch (fmt) { + case D3DFMT_DXT1: + case D3DFMT_DXT2: + case D3DFMT_DXT3: + case D3DFMT_DXT4: + case D3DFMT_DXT5: + return true; + default: + break; + } + return false; +} + +static inline bool +depth_stencil_format( D3DFORMAT fmt ) +{ + static const 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, + D3DFMT_DF16, + D3DFMT_DF24, + D3DFMT_INTZ + }; + unsigned i; + + for (i = 0; i < sizeof(allowed)/sizeof(D3DFORMAT); i++) { + if (fmt == allowed[i]) { return true; } + } + return false; +} + +static inline unsigned +d3d9_get_pipe_depth_format_bindings(D3DFORMAT format) +{ + switch (format) { + case D3DFMT_D32: + case D3DFMT_D15S1: + case D3DFMT_D24S8: + case D3DFMT_D24X8: + case D3DFMT_D24X4S4: + case D3DFMT_D16: + case D3DFMT_D24FS8: + return PIPE_BIND_DEPTH_STENCIL; + case D3DFMT_D32F_LOCKABLE: + case D3DFMT_D16_LOCKABLE: + case D3DFMT_D32_LOCKABLE: + return PIPE_BIND_DEPTH_STENCIL; + case D3DFMT_DF16: + case D3DFMT_DF24: + case D3DFMT_INTZ: + return PIPE_BIND_DEPTH_STENCIL | PIPE_BIND_SAMPLER_VIEW; + default: UNREACHABLE("Unexpected format"); + } +} + +static inline enum pipe_format +d3d9_to_pipe_format_internal(D3DFORMAT format) +{ + if (format <= D3DFMT_A2B10G10R10_XR_BIAS) + return nine_d3d9_to_pipe_format_map[format]; + switch (format) { + case D3DFMT_INTZ: return PIPE_FORMAT_S8_UINT_Z24_UNORM; + case D3DFMT_DF16: return PIPE_FORMAT_Z16_UNORM; + case D3DFMT_DF24: return PIPE_FORMAT_X8Z24_UNORM; + 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_ATI1: return PIPE_FORMAT_RGTC1_UNORM; + case D3DFMT_ATI2: return PIPE_FORMAT_RGTC2_UNORM; + 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_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; + } +} + +#define format_check_internal(pipe_format) \ + screen->is_format_supported(screen, pipe_format, target, \ + sample_count, sample_count, bindings) + +static inline enum pipe_format +d3d9_to_pipe_format_checked(struct pipe_screen *screen, + D3DFORMAT format, + enum pipe_texture_target target, + unsigned sample_count, + unsigned bindings, + bool srgb, + bool bypass_check) +{ + enum pipe_format result; + + /* We cannot render to depth textures as a render target */ + if (depth_stencil_format(format) && (bindings & PIPE_BIND_RENDER_TARGET)) + return PIPE_FORMAT_NONE; + + result = d3d9_to_pipe_format_internal(format); + if (result == PIPE_FORMAT_NONE) + return PIPE_FORMAT_NONE; + + if (srgb) + result = util_format_srgb(result); + + /* bypass_check: Used for D3DPOOL_SCRATCH, which + * isn't limited to the formats supported by the + * device, and to check we are not using a format + * fallback. */ + if (bypass_check || format_check_internal(result)) + return result; + + /* fallback to another format for formats + * that match several pipe_format */ + switch(format) { + /* depth buffer formats are not lockable (except those for which it + * is precised in the name), so it is ok to match to another similar + * format. In all cases, if the app reads the texture with a shader, + * it gets depth on r and doesn't get stencil.*/ + case D3DFMT_D16: + /* D16 support is a requirement, but as it cannot be locked, + * it is ok to revert to D24 */ + if (format_check_internal(PIPE_FORMAT_Z24X8_UNORM)) + return PIPE_FORMAT_Z24X8_UNORM; + if (format_check_internal(PIPE_FORMAT_X8Z24_UNORM)) + return PIPE_FORMAT_X8Z24_UNORM; + break; + case D3DFMT_INTZ: + case D3DFMT_D24S8: + if (format_check_internal(PIPE_FORMAT_Z24_UNORM_S8_UINT)) + return PIPE_FORMAT_Z24_UNORM_S8_UINT; + break; + case D3DFMT_DF24: + case D3DFMT_D24X8: + if (format_check_internal(PIPE_FORMAT_Z24X8_UNORM)) + return PIPE_FORMAT_Z24X8_UNORM; + break; + /* Support for X8L8V8U8 bumpenvmap format with lighting bits. + * X8L8V8U8 is commonly supported among dx9 cards. + * To avoid precision loss, we use PIPE_FORMAT_R32G32B32X32_FLOAT, + * however using PIPE_FORMAT_R8G8B8A8_SNORM should be ok */ + case D3DFMT_X8L8V8U8: + if (bindings & PIPE_BIND_RENDER_TARGET) + return PIPE_FORMAT_NONE; + if (format_check_internal(PIPE_FORMAT_R32G32B32X32_FLOAT)) + return PIPE_FORMAT_R32G32B32X32_FLOAT; + break; + /* Fallback for YUV formats */ + case D3DFMT_UYVY: + case D3DFMT_YUY2: + case D3DFMT_NV12: + if (bindings & PIPE_BIND_RENDER_TARGET) + return PIPE_FORMAT_NONE; + if (format_check_internal(PIPE_FORMAT_R8G8B8X8_UNORM)) + return PIPE_FORMAT_R8G8B8X8_UNORM; + break; + default: + break; + } + return PIPE_FORMAT_NONE; +} + +/* The quality levels are vendor dependent, so we set our own. + * Every quality level has its own sample count and sample + * position matrix. + * The exact mapping might differ from system to system but that's OK, + * as there's no way to gather more information about quality levels + * in D3D9. + * In case of NONMASKABLE multisample map every quality-level + * to a MASKABLE MultiSampleType: + * 0: no MSAA + * 1: 2x MSAA + * 2: 4x MSAA + * ... + * If the requested quality level is not available to nearest + * matching quality level is used. + * If no multisample is available the function sets + * multisample to D3DMULTISAMPLE_NONE and returns zero. + */ +static inline HRESULT +d3dmultisample_type_check(struct pipe_screen *screen, + D3DFORMAT format, + D3DMULTISAMPLE_TYPE *multisample, + DWORD multisamplequality, + DWORD *levels) +{ + unsigned bind, i; + + assert(multisample); + + if (levels) + *levels = 1; + + /* Ignores multisamplequality */ + if (*multisample == D3DMULTISAMPLE_NONE) + return D3D_OK; + + if (*multisample == D3DMULTISAMPLE_NONMASKABLE) { + if (depth_stencil_format(format)) + bind = d3d9_get_pipe_depth_format_bindings(format); + else /* render-target */ + bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET; + + *multisample = 0; + for (i = D3DMULTISAMPLE_2_SAMPLES; i < D3DMULTISAMPLE_16_SAMPLES && + multisamplequality; ++i) { + if (d3d9_to_pipe_format_checked(screen, format, PIPE_TEXTURE_2D, + i, bind, false, false) != PIPE_FORMAT_NONE) { + multisamplequality--; + if (levels) + (*levels)++; + *multisample = i; + } + } + } + /* Make sure to get an exact match */ + if (multisamplequality) + return D3DERR_INVALIDCALL; + return D3D_OK; +} + +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_ATI1: return "D3DFMT_ATI1"; + case D3DFMT_ATI2: return "D3DFMT_ATI2"; + 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_NVDB: return "D3DFMT_NVDB"; + case D3DFMT_RESZ: return "D3DFMT_RESZ"; + case D3DFMT_NULL: return "D3DFMT_NULL"; + case D3DFMT_ATOC: return "D3DFMT_ATOC"; + 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 MESA_PRIM_POINTS; + case D3DPT_LINELIST: return MESA_PRIM_LINES; + case D3DPT_LINESTRIP: return MESA_PRIM_LINE_STRIP; + case D3DPT_TRIANGLELIST: return MESA_PRIM_TRIANGLES; + case D3DPT_TRIANGLESTRIP: return MESA_PRIM_TRIANGLE_STRIP; + case D3DPT_TRIANGLEFAN: return MESA_PRIM_TRIANGLE_FAN; + default: + assert(0); + return MESA_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; + case D3DCMP_NEVER_ZERO: return PIPE_FUNC_NEVER; // Tested on windows + ATI HD5770 + 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; + case D3DFILL_SOLID_ZERO: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; + } +} + +static inline unsigned nine_format_get_stride(enum pipe_format format, + unsigned width) +{ + unsigned stride = util_format_get_stride(format, width); + + return align(stride, 4); +} + +static inline unsigned nine_format_get_level_alloc_size(enum pipe_format format, + unsigned width, + unsigned height, + unsigned level) +{ + unsigned w, h, size; + + w = u_minify(width, level); + h = u_minify(height, level); + if (is_ATI1_ATI2(format)) { + /* For "unknown" formats like ATIx use width * height bytes */ + size = w * h; + } else if (format == PIPE_FORMAT_NONE) { /* D3DFMT_NULL */ + size = w * h * 4; + } else { + size = nine_format_get_stride(format, w) * + util_format_get_nblocksy(format, h); + } + + return size; +} + +static inline unsigned nine_format_get_size_and_offsets(enum pipe_format format, + unsigned *offsets, + unsigned width, + unsigned height, + unsigned last_level) +{ + unsigned l, w, h, size = 0; + + for (l = 0; l <= last_level; ++l) { + w = u_minify(width, l); + h = u_minify(height, l); + offsets[l] = size; + if (is_ATI1_ATI2(format)) { + /* For "unknown" formats like ATIx use width * height bytes */ + size += w * h; + } else { + size += nine_format_get_stride(format, w) * + util_format_get_nblocksy(format, h); + } + } + + return size; +} + +#endif /* _NINE_PIPE_H_ */ diff --git a/src/gallium/frontends/nine/nine_queue.c b/src/gallium/frontends/nine/nine_queue.c new file mode 100644 index 0000000..cd73516 --- /dev/null +++ b/src/gallium/frontends/nine/nine_queue.c @@ -0,0 +1,262 @@ +/* + * Copyright 2016 Patrick Rudolph + * SPDX-License-Identifier: MIT + */ + +#include "nine_queue.h" +#include "util/u_thread.h" +#include "util/macros.h" +#include "nine_helpers.h" + +#define NINE_CMD_BUF_INSTR (256) + +#define NINE_CMD_BUFS (32) +#define NINE_CMD_BUFS_MASK (NINE_CMD_BUFS - 1) + +#define NINE_QUEUE_SIZE (8192 * 16 + 128) + +#define DBG_CHANNEL DBG_DEVICE + +/* + * Single producer - single consumer pool queue + * + * Producer: + * Calls nine_queue_alloc to get a slice of memory in current cmdbuf. + * Calls nine_queue_flush to flush the queue by request. + * The queue is flushed automatically on insufficient space or once the + * cmdbuf contains NINE_CMD_BUF_INSTR instructions. + * + * nine_queue_flush does block, while nine_queue_alloc doesn't block. + * + * nine_queue_alloc returns NULL on insufficient space. + * + * Consumer: + * Calls nine_queue_wait_flush to wait for a cmdbuf. + * After waiting for a cmdbuf it calls nine_queue_get until NULL is returned. + * + * nine_queue_wait_flush does block, while nine_queue_get doesn't block. + * + * Constrains: + * Only a single consumer and a single producer are supported. + * + */ + +struct nine_cmdbuf { + unsigned instr_size[NINE_CMD_BUF_INSTR]; + unsigned num_instr; + unsigned offset; + void *mem_pool; + BOOL full; +}; + +struct nine_queue_pool { + struct nine_cmdbuf pool[NINE_CMD_BUFS]; + unsigned head; + unsigned tail; + unsigned cur_instr; + BOOL worker_wait; + cnd_t event_pop; + cnd_t event_push; + mtx_t mutex_pop; + mtx_t mutex_push; +}; + +/* Consumer functions: */ +void +nine_queue_wait_flush(struct nine_queue_pool* ctx) +{ + struct nine_cmdbuf *cmdbuf = &ctx->pool[ctx->tail]; + + /* wait for cmdbuf full */ + mtx_lock(&ctx->mutex_push); + while (!cmdbuf->full) + { + DBG("waiting for full cmdbuf\n"); + cnd_wait(&ctx->event_push, &ctx->mutex_push); + } + DBG("got cmdbuf=%p\n", cmdbuf); + mtx_unlock(&ctx->mutex_push); + + cmdbuf->offset = 0; + ctx->cur_instr = 0; +} + +/* Gets a pointer to the next memory slice. + * Does not block. + * Returns NULL on empty cmdbuf. */ +void * +nine_queue_get(struct nine_queue_pool* ctx) +{ + struct nine_cmdbuf *cmdbuf = &ctx->pool[ctx->tail]; + unsigned offset; + + /* At this pointer there's always a cmdbuf. */ + + if (ctx->cur_instr == cmdbuf->num_instr) { + /* signal waiting producer */ + mtx_lock(&ctx->mutex_pop); + DBG("freeing cmdbuf=%p\n", cmdbuf); + cmdbuf->full = 0; + cnd_signal(&ctx->event_pop); + mtx_unlock(&ctx->mutex_pop); + + ctx->tail = (ctx->tail + 1) & NINE_CMD_BUFS_MASK; + + return NULL; + } + + /* At this pointer there's always a cmdbuf with instruction to process. */ + offset = cmdbuf->offset; + cmdbuf->offset += cmdbuf->instr_size[ctx->cur_instr]; + ctx->cur_instr ++; + + return cmdbuf->mem_pool + offset; +} + +/* Producer functions: */ + +/* Flushes the queue. + * Moves the current cmdbuf to worker thread. + * Blocks until next cmdbuf is free. */ +void +nine_queue_flush(struct nine_queue_pool* ctx) +{ + struct nine_cmdbuf *cmdbuf = &ctx->pool[ctx->head]; + + DBG("flushing cmdbuf=%p instr=%d size=%d\n", + cmdbuf, cmdbuf->num_instr, cmdbuf->offset); + + /* Nothing to flush */ + if (!cmdbuf->num_instr) + return; + + /* signal waiting worker */ + mtx_lock(&ctx->mutex_push); + cmdbuf->full = 1; + cnd_signal(&ctx->event_push); + mtx_unlock(&ctx->mutex_push); + + ctx->head = (ctx->head + 1) & NINE_CMD_BUFS_MASK; + + cmdbuf = &ctx->pool[ctx->head]; + + /* wait for queue empty */ + mtx_lock(&ctx->mutex_pop); + while (cmdbuf->full) + { + DBG("waiting for empty cmdbuf\n"); + cnd_wait(&ctx->event_pop, &ctx->mutex_pop); + } + DBG("got empty cmdbuf=%p\n", cmdbuf); + mtx_unlock(&ctx->mutex_pop); + cmdbuf->offset = 0; + cmdbuf->num_instr = 0; +} + +/* Gets a a pointer to slice of memory with size @space. + * Does block if queue is full. + * Returns NULL on @space > NINE_QUEUE_SIZE. */ +void * +nine_queue_alloc(struct nine_queue_pool* ctx, unsigned space) +{ + unsigned offset; + struct nine_cmdbuf *cmdbuf = &ctx->pool[ctx->head]; + + if (space > NINE_QUEUE_SIZE) + return NULL; + + /* at this pointer there's always a free queue available */ + + if ((cmdbuf->offset + space > NINE_QUEUE_SIZE) || + (cmdbuf->num_instr == NINE_CMD_BUF_INSTR)) { + + nine_queue_flush(ctx); + + cmdbuf = &ctx->pool[ctx->head]; + } + + DBG("cmdbuf=%p space=%d\n", cmdbuf, space); + + /* at this pointer there's always a free queue with sufficient space available */ + + offset = cmdbuf->offset; + cmdbuf->offset += space; + cmdbuf->instr_size[cmdbuf->num_instr] = space; + cmdbuf->num_instr ++; + + return cmdbuf->mem_pool + offset; +} + +/* Returns the current queue flush state. + * TRUE nothing flushed + * FALSE one or more instructions queued flushed. */ +bool +nine_queue_no_flushed_work(struct nine_queue_pool* ctx) +{ + return (ctx->tail == ctx->head); +} + +/* Returns the current queue empty state. + * TRUE no instructions queued. + * FALSE one or more instructions queued. */ +bool +nine_queue_isempty(struct nine_queue_pool* ctx) +{ + struct nine_cmdbuf *cmdbuf = &ctx->pool[ctx->head]; + + return (ctx->tail == ctx->head) && !cmdbuf->num_instr; +} + +struct nine_queue_pool* +nine_queue_create(void) +{ + unsigned i; + struct nine_queue_pool *ctx; + + ctx = CALLOC_STRUCT(nine_queue_pool); + if (!ctx) + goto failed; + + for (i = 0; i < NINE_CMD_BUFS; i++) { + ctx->pool[i].mem_pool = MALLOC(NINE_QUEUE_SIZE); + if (!ctx->pool[i].mem_pool) + goto failed; + } + + cnd_init(&ctx->event_pop); + (void) mtx_init(&ctx->mutex_pop, mtx_plain); + + cnd_init(&ctx->event_push); + (void) mtx_init(&ctx->mutex_push, mtx_plain); + + /* Block until first cmdbuf has been flushed. */ + ctx->worker_wait = true; + + return ctx; +failed: + if (ctx) { + for (i = 0; i < NINE_CMD_BUFS; i++) { + if (ctx->pool[i].mem_pool) + FREE(ctx->pool[i].mem_pool); + } + FREE(ctx); + } + return NULL; +} + +void +nine_queue_delete(struct nine_queue_pool *ctx) +{ + unsigned i; + + mtx_destroy(&ctx->mutex_pop); + cnd_destroy(&ctx->event_pop); + + mtx_destroy(&ctx->mutex_push); + cnd_destroy(&ctx->event_push); + + for (i = 0; i < NINE_CMD_BUFS; i++) + FREE(ctx->pool[i].mem_pool); + + FREE(ctx); +} diff --git a/src/gallium/frontends/nine/nine_queue.h b/src/gallium/frontends/nine/nine_queue.h new file mode 100644 index 0000000..c93eef5 --- /dev/null +++ b/src/gallium/frontends/nine/nine_queue.h @@ -0,0 +1,37 @@ +/* + * Copyright 2016 Patrick Rudolph + * SPDX-License-Identifier: MIT + */ + +#ifndef _NINE_QUEUE_H_ +#define _NINE_QUEUE_H_ + +#include "util/compiler.h" + +struct nine_queue_pool; + +void +nine_queue_wait_flush(struct nine_queue_pool* ctx); + +void * +nine_queue_get(struct nine_queue_pool* ctx); + +void +nine_queue_flush(struct nine_queue_pool* ctx); + +void * +nine_queue_alloc(struct nine_queue_pool* ctx, unsigned space); + +bool +nine_queue_no_flushed_work(struct nine_queue_pool* ctx); + +bool +nine_queue_isempty(struct nine_queue_pool* ctx); + +struct nine_queue_pool* +nine_queue_create(void); + +void +nine_queue_delete(struct nine_queue_pool *ctx); + +#endif /* _NINE_QUEUE_H_ */ diff --git a/src/gallium/frontends/nine/nine_quirk.c b/src/gallium/frontends/nine/nine_quirk.c new file mode 100644 index 0000000..4132a7a --- /dev/null +++ b/src/gallium/frontends/nine/nine_quirk.c @@ -0,0 +1,32 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#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 +}; + +bool +_nine_get_quirk( unsigned quirk ) +{ + static bool 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/frontends/nine/nine_quirk.h b/src/gallium/frontends/nine/nine_quirk.h new file mode 100644 index 0000000..2464391 --- /dev/null +++ b/src/gallium/frontends/nine/nine_quirk.h @@ -0,0 +1,19 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#ifndef _NINE_QUIRK_H_ +#define _NINE_QUIRK_H_ + +#include "util/compiler.h" + +bool +_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/frontends/nine/nine_shader.c b/src/gallium/frontends/nine/nine_shader.c new file mode 100644 index 0000000..4f2ef4a --- /dev/null +++ b/src/gallium/frontends/nine/nine_shader.c @@ -0,0 +1,4275 @@ +/* + * Copyright 2011 Joakim Sindholt + * Copyright 2013 Christoph Bumiller + * SPDX-License-Identifier: MIT + */ + +#include "nine_shader.h" + +#include "device9.h" +#include "nine_debug.h" +#include "nine_state.h" +#include "vertexdeclaration9.h" + +#include "util/bitscan.h" +#include "util/macros.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" +#include "nir/tgsi_to_nir.h" +#include "nir.h" + +#define DBG_CHANNEL DBG_SHADER + +#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 NINE_APPLY_SWIZZLE(src, s) \ + ureg_swizzle(src, NINE_SWIZZLE4(s, s, s, s)) + +#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; + int8_t 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]; + + const 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 < ARRAY_SIZE(insn->dst); ++i) { + sm1_dump_dst_param(&insn->dst[i]); + DUMP(" "); + } + + for (i = 0; i < insn->nsrc && i < ARRAY_SIZE(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; + float f[4]; /* for indirect addressing of float constants */ +}; + +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; /* MESA_SHADER_VERTEX/FRAMGENT */ + unsigned num_constf_allowed; + unsigned num_consti_allowed; + unsigned num_constb_allowed; + + bool native_integers; + bool inline_subroutines; + bool want_texcoord; + bool shift_wpos; + bool wpos_is_sysval; + bool face_is_sysval_integer; + bool mul_zero_wins; + bool always_output_pointsize; + bool no_vs_window_space; + unsigned texcoord_sn; + + struct sm1_instruction insn; /* current instruction */ + + struct { + struct ureg_dst *r; + struct ureg_dst oPos; + struct ureg_dst oPos_out; /* the real output when doing streamout or clipplane emulation */ + 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 v_consecutive; /* copy in temp array of ps inputs for rel addressing */ + struct ureg_src vPos; + struct ureg_src vFace; + struct ureg_src s; + struct ureg_dst p; + struct ureg_dst address; + struct ureg_dst a0; + struct ureg_dst predicate; + struct ureg_dst predicate_tmp; + struct ureg_dst predicate_dst; + struct ureg_dst tS[8]; /* texture stage registers */ + struct ureg_dst tdst; /* scratch dst if we need extra modifiers */ + struct ureg_dst t[8]; /* 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/rep ctr */ + struct ureg_dst aL[NINE_MAX_LOOP_DEPTH]; /* aL emulation */ + } regs; + unsigned num_temp; /* ARRAY_SIZE(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]; + bool loop_or_rep[NINE_MAX_LOOP_DEPTH]; /* true: loop, false: rep */ + bool predicated_activated; + + 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; + unsigned num_lconsti; + struct sm1_local_const *lconstb; + unsigned num_lconstb; + + bool slots_used[NINE_MAX_CONST_ALL_VS]; + unsigned *slot_map; + unsigned num_slots; + + bool indirect_const_access; + bool failure; + + struct nine_vs_output_info output_info[16]; + int num_outputs; + + struct nine_shader_info *info; + + int16_t op_info_map[D3DSIO_BREAKP + 1]; +}; + +#define IS_VS (tx->processor == MESA_SHADER_VERTEX) +#define IS_PS (tx->processor == MESA_SHADER_FRAGMENT) + +#define FAILURE_VOID(cond) if ((cond)) {tx->failure=1;return;} + +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 void +nine_record_outputs(struct shader_translator *tx, BYTE Usage, BYTE UsageIndex, + int mask, int output_index) +{ + tx->output_info[tx->num_outputs].output_semantic = Usage; + tx->output_info[tx->num_outputs].output_semantic_index = UsageIndex; + tx->output_info[tx->num_outputs].mask = mask; + tx->output_info[tx->num_outputs].output_index = output_index; + tx->num_outputs++; +} + +static struct ureg_src nine_float_constant_src(struct shader_translator *tx, int idx) +{ + struct ureg_src src; + + if (tx->slot_map) + idx = tx->slot_map[idx]; + /* vswp constant handling: we use two buffers + * to fit all the float constants. The special handling + * doesn't need to be elsewhere, because all the instructions + * accessing the constants directly are VS1, and swvp + * is VS >= 2 */ + if (tx->info->swvp_on && idx >= 4096) { + /* TODO: swvp rel is broken if many constants are used */ + src = ureg_src_register(TGSI_FILE_CONSTANT, idx - 4096); + src = ureg_src_dimension(src, 1); + } else { + src = ureg_src_register(TGSI_FILE_CONSTANT, idx); + src = ureg_src_dimension(src, 0); + } + + if (!tx->info->swvp_on) + tx->slots_used[idx] = true; + if (tx->info->const_float_slots < (idx + 1)) + tx->info->const_float_slots = idx + 1; + if (tx->num_slots < (idx + 1)) + tx->num_slots = idx + 1; + + return src; +} + +static struct ureg_src nine_integer_constant_src(struct shader_translator *tx, int idx) +{ + struct ureg_src src; + + if (tx->info->swvp_on) { + src = ureg_src_register(TGSI_FILE_CONSTANT, idx); + src = ureg_src_dimension(src, 2); + } else { + unsigned slot_idx = tx->info->const_i_base + idx; + if (tx->slot_map) + slot_idx = tx->slot_map[slot_idx]; + src = ureg_src_register(TGSI_FILE_CONSTANT, slot_idx); + src = ureg_src_dimension(src, 0); + tx->slots_used[slot_idx] = true; + tx->info->int_slots_used[idx] = true; + if (tx->num_slots < (slot_idx + 1)) + tx->num_slots = slot_idx + 1; + } + + if (tx->info->const_int_slots < (idx + 1)) + tx->info->const_int_slots = idx + 1; + + return src; +} + +static struct ureg_src nine_boolean_constant_src(struct shader_translator *tx, int idx) +{ + struct ureg_src src; + + char r = idx / 4; + char s = idx & 3; + + if (tx->info->swvp_on) { + src = ureg_src_register(TGSI_FILE_CONSTANT, r); + src = ureg_src_dimension(src, 3); + } else { + unsigned slot_idx = tx->info->const_b_base + r; + if (tx->slot_map) + slot_idx = tx->slot_map[slot_idx]; + src = ureg_src_register(TGSI_FILE_CONSTANT, slot_idx); + src = ureg_src_dimension(src, 0); + tx->slots_used[slot_idx] = true; + tx->info->bool_slots_used[idx] = true; + if (tx->num_slots < (slot_idx + 1)) + tx->num_slots = slot_idx + 1; + } + src = ureg_swizzle(src, s, s, s, s); + + if (tx->info->const_bool_slots < (idx + 1)) + tx->info->const_bool_slots = idx + 1; + + return src; +} + +static struct ureg_src nine_special_constant_src(struct shader_translator *tx, int idx) +{ + struct ureg_src src; + + unsigned slot_idx = idx + (IS_PS ? NINE_MAX_CONST_PS_SPE_OFFSET : + (tx->info->swvp_on ? NINE_MAX_CONST_SWVP_SPE_OFFSET : NINE_MAX_CONST_VS_SPE_OFFSET)); + + if (!tx->info->swvp_on && tx->slot_map) + slot_idx = tx->slot_map[slot_idx]; + src = ureg_src_register(TGSI_FILE_CONSTANT, slot_idx); + src = ureg_src_dimension(src, 0); + + if (!tx->info->swvp_on) + tx->slots_used[slot_idx] = true; + if (tx->num_slots < (slot_idx + 1)) + tx->num_slots = slot_idx + 1; + + return src; +} + +static bool +tx_lconstf(struct shader_translator *tx, struct ureg_src *src, INT index) +{ + INT i; + + if (index < 0 || index >= tx->num_constf_allowed) { + tx->failure = true; + return false; + } + for (i = 0; i < tx->num_lconstf; ++i) { + if (tx->lconstf[i].idx == index) { + *src = tx->lconstf[i].reg; + return true; + } + } + return false; +} +static bool +tx_lconsti(struct shader_translator *tx, struct ureg_src *src, INT index) +{ + int i; + + if (index < 0 || index >= tx->num_consti_allowed) { + tx->failure = true; + return false; + } + for (i = 0; i < tx->num_lconsti; ++i) { + if (tx->lconsti[i].idx == index) { + *src = tx->lconsti[i].reg; + return true; + } + } + return false; +} +static bool +tx_lconstb(struct shader_translator *tx, struct ureg_src *src, INT index) +{ + int i; + + if (index < 0 || index >= tx->num_constb_allowed) { + tx->failure = true; + return false; + } + for (i = 0; i < tx->num_lconstb; ++i) { + if (tx->lconstb[i].idx == index) { + *src = tx->lconstb[i].reg; + return true; + } + } + return false; +} + +static void +tx_set_lconstf(struct shader_translator *tx, INT index, float f[4]) +{ + unsigned n; + + FAILURE_VOID(index < 0 || index >= tx->num_constf_allowed) + + 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].f, f, sizeof(tx->lconstf[n].f)); +} +static void +tx_set_lconsti(struct shader_translator *tx, INT index, int i[4]) +{ + unsigned n; + + FAILURE_VOID(index < 0 || index >= tx->num_consti_allowed) + + for (n = 0; n < tx->num_lconsti; ++n) + if (tx->lconsti[n].idx == index) + break; + if (n == tx->num_lconsti) { + if ((n % 8) == 0) { + tx->lconsti = REALLOC(tx->lconsti, + (n + 0) * sizeof(tx->lconsti[0]), + (n + 8) * sizeof(tx->lconsti[0])); + assert(tx->lconsti); + } + tx->num_lconsti++; + } + + tx->lconsti[n].idx = index; + tx->lconsti[n].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) +{ + unsigned n; + + FAILURE_VOID(index < 0 || index >= tx->num_constb_allowed) + + for (n = 0; n < tx->num_lconstb; ++n) + if (tx->lconstb[n].idx == index) + break; + if (n == tx->num_lconstb) { + if ((n % 8) == 0) { + tx->lconstb = REALLOC(tx->lconstb, + (n + 0) * sizeof(tx->lconstb[0]), + (n + 8) * sizeof(tx->lconstb[0])); + assert(tx->lconstb); + } + tx->num_lconstb++; + } + + tx->lconstb[n].idx = index; + tx->lconstb[n].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) +{ + if (tx->num_scratch >= ARRAY_SIZE(tx->regs.t)) { + tx->failure = true; + return tx->regs.t[0]; + } + 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; +} + +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.address)) + tx->regs.address = ureg_DECL_address(tx->ureg); + if (ureg_dst_is_undef(tx->regs.a0)) + tx->regs.a0 = ureg_DECL_temporary(tx->ureg); +} + +static inline bool +TEX_if_fetch4(struct shader_translator *tx, struct ureg_dst dst, + unsigned target, struct ureg_src src0, + struct ureg_src src1, INT idx) +{ + struct ureg_dst tmp; + struct ureg_src src_tg4[3] = {src0, ureg_imm1f(tx->ureg, 0.f), src1}; + + if (!(tx->info->fetch4 & (1 << idx))) + return false; + + /* TODO: needs more tests, but this feature is not much used at all */ + + tmp = tx_scratch(tx); + /* Mesa 26.x: ureg_tex_insn() lost its tgsi_return_type argument. */ + ureg_tex_insn(tx->ureg, TGSI_OPCODE_TG4, &tmp, 1, target, + NULL, 0, src_tg4, 3); + ureg_MOV(tx->ureg, dst, ureg_swizzle(ureg_src(tmp), NINE_SWIZZLE4(Z, X, Y, W))); + return true; +} + +/* NOTE: It's not very clear on which ps1.1-ps1.3 instructions + * the projection should be applied on the texture. It doesn't + * apply on texkill. + * The doc is very imprecise here (it says the projection is done + * before rasterization, thus in vs, which seems wrong since ps instructions + * are affected differently) + * For now we only apply to the ps TEX instruction and TEXBEM. + * Perhaps some other instructions would need it */ +static inline void +apply_ps1x_projection(struct shader_translator *tx, struct ureg_dst dst, + struct ureg_src src, INT idx) +{ + struct ureg_dst tmp; + unsigned dim = 1 + ((tx->info->projected >> (2 * idx)) & 3); + + /* no projection */ + if (dim == 1) { + ureg_MOV(tx->ureg, dst, src); + } else { + tmp = tx_scratch_scalar(tx); + ureg_RCP(tx->ureg, tmp, ureg_scalar(src, dim-1)); + ureg_MUL(tx->ureg, dst, tx_src_scalar(tmp), src); + } +} + +static inline void +TEX_with_ps1x_projection(struct shader_translator *tx, struct ureg_dst dst, + unsigned target, struct ureg_src src0, + struct ureg_src src1, INT idx) +{ + unsigned dim = 1 + ((tx->info->projected >> (2 * idx)) & 3); + struct ureg_dst tmp; + bool shadow = !!(tx->info->sampler_mask_shadow & (1 << idx)); + + /* dim == 1: no projection + * Looks like must be disabled when it makes no + * sense according the texture dimensions + */ + if (dim == 1 || (dim <= target && !shadow)) { + ureg_TEX(tx->ureg, dst, target, src0, src1); + } else if (dim == 4) { + ureg_TXP(tx->ureg, dst, target, src0, src1); + } else { + tmp = tx_scratch(tx); + apply_ps1x_projection(tx, tmp, src0, idx); + ureg_TEX(tx->ureg, dst, target, ureg_src(tmp), src1); + } +} + +static inline void +tx_texcoord_alloc(struct shader_translator *tx, INT idx) +{ + assert(IS_PS); + assert(idx >= 0 && idx < ARRAY_SIZE(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, bool loop_or_rep) +{ + 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.rL[l])) { + /* loop or rep ctr creation */ + tx->regs.rL[l] = ureg_DECL_local_temporary(tx->ureg); + if (loop_or_rep) + tx->regs.aL[l] = ureg_DECL_local_temporary(tx->ureg); + tx->loop_or_rep[l] = loop_or_rep; + } + /* loop - rep - endloop - endrep not allowed */ + assert(tx->loop_or_rep[l] == loop_or_rep); + + return tx->regs.rL[l]; +} + +static struct ureg_dst +tx_get_loopal(struct shader_translator *tx) +{ + int loop_level = tx->loop_depth - 1; + + while (loop_level >= 0) { + /* handle loop - rep - endrep - endloop case */ + if (tx->loop_or_rep[loop_level]) + /* the aL value is in the Y component (nine implementation) */ + return tx->regs.aL[loop_level]; + loop_level--; + } + + DBG("aL counter requested outside of loop\n"); + 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 inline struct ureg_src +nine_get_position_input(struct shader_translator *tx) +{ + struct ureg_program *ureg = tx->ureg; + + if (tx->wpos_is_sysval) + return ureg_DECL_system_value(ureg, TGSI_SEMANTIC_POSITION, 0); + else + return ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_POSITION, + 0, TGSI_INTERPOLATE_LINEAR); +} + +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; + + assert(!param->rel || (IS_VS && param->file == D3DSPR_CONST) || + (param->file == D3DSPR_INPUT && tx->version.major == 3)); + + switch (param->file) + { + case D3DSPR_TEMP: + tx_temp_alloc(tx, param->idx); + src = ureg_src(tx->regs.r[param->idx]); + break; + /* case D3DSPR_TEXTURE: == D3DSPR_ADDR */ + case D3DSPR_ADDR: + if (IS_VS) { + assert(param->idx == 0); + /* the address register (vs only) must be + * assigned before use */ + assert(!ureg_dst_is_undef(tx->regs.a0)); + /* Round to lowest for vs1.1 (contrary to the doc), else + * round to nearest */ + if (tx->version.major < 2 && tx->version.minor < 2) + ureg_ARL(ureg, tx->regs.address, ureg_src(tx->regs.a0)); + else + ureg_ARR(ureg, tx->regs.address, ureg_src(tx->regs.a0)); + src = ureg_src(tx->regs.address); + } 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) { + src = ureg_DECL_fs_input_centroid( + ureg, TGSI_SEMANTIC_COLOR, param->idx, + tx->info->color_flatshade ? TGSI_INTERPOLATE_CONSTANT : TGSI_INTERPOLATE_PERSPECTIVE, + tx->info->force_color_in_centroid ? + TGSI_INTERPOLATE_LOC_CENTROID : 0, + 0, 1); + } else { + if(param->rel) { + /* Copy all inputs (non consecutive) + * to temp array (consecutive). + * This is not good for performance. + * A better way would be to have inputs + * consecutive (would need implement alternative + * way to match vs outputs and ps inputs). + * However even with the better way, the temp array + * copy would need to be used if some inputs + * are not GENERIC or if they have different + * interpolation flag. */ + if (ureg_src_is_undef(tx->regs.v_consecutive)) { + int i; + tx->regs.v_consecutive = ureg_src(ureg_DECL_array_temporary(ureg, 10, 0)); + for (i = 0; i < 10; i++) { + if (!ureg_src_is_undef(tx->regs.v[i])) + ureg_MOV(ureg, ureg_dst_array_offset(ureg_dst(tx->regs.v_consecutive), i), tx->regs.v[i]); + else + ureg_MOV(ureg, ureg_dst_array_offset(ureg_dst(tx->regs.v_consecutive), i), ureg_imm4f(ureg, 0.0f, 0.0f, 0.0f, 1.0f)); + } + } + src = ureg_src_array_offset(tx->regs.v_consecutive, param->idx); + } else { + assert(param->idx < ARRAY_SIZE(tx->regs.v)); + src = tx->regs.v[param->idx]; + } + } + } + if (param->rel) + src = ureg_src_indirect(src, tx_src_param(tx, param->rel)); + break; + case D3DSPR_PREDICATE: + if (ureg_dst_is_undef(tx->regs.predicate)) { + /* Forbidden to use the predicate register before being set */ + tx->failure = true; + tx->regs.predicate = ureg_DECL_temporary(tx->ureg); + } + src = ureg_src(tx->regs.predicate); + break; + case D3DSPR_SAMPLER: + assert(param->mod == NINED3DSPSM_NONE); + /* assert(param->swizzle == NINED3DSP_NOSWIZZLE); Passed by wine tests */ + src = ureg_DECL_sampler(ureg, param->idx); + break; + case D3DSPR_CONST: + if (param->rel || !tx_lconstf(tx, &src, param->idx)) { + src = nine_float_constant_src(tx, param->idx); + if (param->rel) { + tx->indirect_const_access = true; + src = ureg_src_indirect(src, tx_src_param(tx, param->rel)); + } + } + if (!IS_VS && tx->version.major < 2) { + /* ps 1.X clamps constants */ + tmp = tx_scratch(tx); + ureg_MIN(ureg, tmp, src, ureg_imm1f(ureg, 1.0f)); + ureg_MAX(ureg, tmp, ureg_src(tmp), ureg_imm1f(ureg, -1.0f)); + src = ureg_src(tmp); + } + 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: + /* relative addressing only possible for float constants in vs */ + if (!tx_lconsti(tx, &src, param->idx)) + src = nine_integer_constant_src(tx, param->idx); + break; + case D3DSPR_CONSTBOOL: + if (!tx_lconstb(tx, &src, param->idx)) + src = nine_boolean_constant_src(tx, param->idx); + break; + case D3DSPR_LOOP: + if (ureg_dst_is_undef(tx->regs.address)) + tx->regs.address = ureg_DECL_address(ureg); + if (!tx->native_integers) + ureg_ARR(ureg, tx->regs.address, + ureg_scalar(ureg_src(tx_get_loopal(tx)), TGSI_SWIZZLE_Y)); + else + ureg_UARL(ureg, tx->regs.address, + ureg_scalar(ureg_src(tx_get_loopal(tx)), TGSI_SWIZZLE_Y)); + src = ureg_src(tx->regs.address); + break; + case D3DSPR_MISCTYPE: + switch (param->idx) { + case D3DSMO_POSITION: + if (ureg_src_is_undef(tx->regs.vPos)) + tx->regs.vPos = nine_get_position_input(tx); + if (tx->shift_wpos) { + /* TODO: do this only once */ + struct ureg_dst wpos = tx_scratch(tx); + ureg_ADD(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)) { + if (tx->face_is_sysval_integer) { + tmp = ureg_DECL_temporary(ureg); + tx->regs.vFace = + ureg_DECL_system_value(ureg, TGSI_SEMANTIC_FACE, 0); + + /* convert bool to float */ + ureg_UCMP(ureg, tmp, ureg_scalar(tx->regs.vFace, TGSI_SWIZZLE_X), + ureg_imm1f(ureg, 1), ureg_imm1f(ureg, -1)); + tx->regs.vFace = ureg_src(tmp); + } else { + 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; + } + break; + case D3DSPR_TEMPFLOAT16: + break; + default: + assert(!"invalid src D3DSPR"); + } + + switch (param->mod) { + case NINED3DSPSM_DW: + tmp = tx_scratch(tx); + /* NOTE: app is not allowed to read w with this modifier */ + ureg_RCP(ureg, ureg_writemask(tmp, NINED3DSP_WRITEMASK_3), ureg_scalar(src, TGSI_SWIZZLE_W)); + ureg_MUL(ureg, tmp, src, ureg_swizzle(ureg_src(tmp), NINE_SWIZZLE4(W,W,W,W))); + src = ureg_src(tmp); + break; + case NINED3DSPSM_DZ: + tmp = tx_scratch(tx); + /* NOTE: app is not allowed to read z with this modifier */ + ureg_RCP(ureg, ureg_writemask(tmp, NINED3DSP_WRITEMASK_2), ureg_scalar(src, TGSI_SWIZZLE_Z)); + ureg_MUL(ureg, tmp, src, ureg_swizzle(ureg_src(tmp), NINE_SWIZZLE4(Z,Z,Z,Z))); + src = ureg_src(tmp); + break; + default: + break; + } + + if (param->swizzle != NINED3DSP_NOSWIZZLE && param->file != D3DSPR_SAMPLER) + 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_ADD(ureg, tmp, src, ureg_imm1f(ureg, -0.5f)); + src = ureg_src(tmp); + break; + case NINED3DSPSM_BIASNEG: + tmp = tx_scratch(tx); + ureg_ADD(ureg, tmp, ureg_imm1f(ureg, 0.5f), ureg_negate(src)); + src = ureg_src(tmp); + break; + case NINED3DSPSM_NOT: + if (tx->native_integers && param->file == D3DSPR_CONSTBOOL) { + tmp = tx_scratch(tx); + ureg_NOT(ureg, tmp, src); + src = ureg_src(tmp); + break; + } else { /* predicate */ + tmp = tx_scratch(tx); + ureg_ADD(ureg, tmp, ureg_imm1f(ureg, 1.0f), ureg_negate(src)); + src = ureg_src(tmp); + } + FALLTHROUGH; + case NINED3DSPSM_COMP: + tmp = tx_scratch(tx); + ureg_ADD(ureg, tmp, ureg_imm1f(ureg, 1.0f), ureg_negate(src)); + src = ureg_src(tmp); + break; + case NINED3DSPSM_DZ: + case NINED3DSPSM_DW: + /* Already handled*/ + 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.a0; + } + break; + case D3DSPR_RASTOUT: + assert(!param->rel); + switch (param->idx) { + case 0: + if (ureg_dst_is_undef(tx->regs.oPos)) { + if (tx->info->clip_plane_emulation > 0) { + tx->regs.oPos = ureg_DECL_temporary(tx->ureg); + } else { + tx->regs.oPos = tx->regs.oPos_out; + } + } + dst = tx->regs.oPos; + break; + case 1: + if (ureg_dst_is_undef(tx->regs.oFog)) + tx->regs.oFog = + ureg_saturate(ureg_DECL_output(tx->ureg, TGSI_SEMANTIC_GENERIC, 16)); + dst = tx->regs.oFog; + break; + case 2: + if (ureg_dst_is_undef(tx->regs.oPts)) + tx->regs.oPts = ureg_DECL_temporary(tx->ureg); + 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 < ARRAY_SIZE(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])) { + /* ps < 3: oCol[0] will have fog blending afterward + * ps: oCol[0] might have alphatest afterward */ + if (!IS_VS && param->idx == 0) { + tx->regs.oCol[0] = ureg_DECL_temporary(tx->ureg); + } else { + 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, 0, 1); + dst = tx->regs.oDepth; /* XXX: must write .z component */ + break; + case D3DSPR_PREDICATE: + if (ureg_dst_is_undef(tx->regs.predicate)) + tx->regs.predicate = ureg_DECL_temporary(tx->ureg); + dst = tx->regs.predicate; + 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); + + if (tx->predicated_activated) { + tx->regs.predicate_dst = dst; + dst = tx->regs.predicate_tmp; + } + + 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 < ARRAY_SIZE(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]; + struct sm1_src_param *src_mat = &tx->insn.src[1]; + unsigned i; + + dst = tx_dst_param(tx, &tx->insn.dst[0]); + src[0] = tx_src_param(tx, &tx->insn.src[0]); + + for (i = 0; i < n; i++) + { + const unsigned m = (1 << i); + + src[1] = tx_src_param(tx, src_mat); + src_mat->idx++; + + 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 < ARRAY_SIZE(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(NOP) +{ + /* Nothing to do. NOP was used to avoid hangs + * with very old d3d drivers. */ + return D3D_OK; +} + +DECL_SPECIAL(SUB) +{ + struct ureg_program *ureg = tx->ureg; + struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]); + struct ureg_src src0 = tx_src_param(tx, &tx->insn.src[0]); + struct ureg_src src1 = tx_src_param(tx, &tx->insn.src[1]); + + ureg_ADD(ureg, dst, src0, ureg_negate(src1)); + return D3D_OK; +} + +DECL_SPECIAL(ABS) +{ + 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]); + + ureg_MOV(ureg, dst, ureg_abs(src)); + return D3D_OK; +} + +DECL_SPECIAL(XPD) +{ + struct ureg_program *ureg = tx->ureg; + struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]); + struct ureg_src src0 = tx_src_param(tx, &tx->insn.src[0]); + struct ureg_src src1 = tx_src_param(tx, &tx->insn.src[1]); + + ureg_MUL(ureg, ureg_writemask(dst, TGSI_WRITEMASK_XYZ), + ureg_swizzle(src0, TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Z, + TGSI_SWIZZLE_X, 0), + ureg_swizzle(src1, TGSI_SWIZZLE_Z, TGSI_SWIZZLE_X, + TGSI_SWIZZLE_Y, 0)); + ureg_MAD(ureg, ureg_writemask(dst, TGSI_WRITEMASK_XYZ), + ureg_swizzle(src0, TGSI_SWIZZLE_Z, TGSI_SWIZZLE_X, + TGSI_SWIZZLE_Y, 0), + ureg_negate(ureg_swizzle(src1, TGSI_SWIZZLE_Y, + TGSI_SWIZZLE_Z, TGSI_SWIZZLE_X, 0)), + ureg_src(dst)); + ureg_MOV(ureg, ureg_writemask(dst, TGSI_WRITEMASK_W), + ureg_imm1f(ureg, 1)); + return D3D_OK; +} + +DECL_SPECIAL(M4x4) +{ + return NineTranslateInstruction_Mkxn(tx, 4, 4); +} + +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; + + /* the coissue flag was a tip for compilers to advise to + * execute two operations at the same time, in cases + * the two executions had the same dst with different channels. + * It has no effect on current hw. However it seems CND + * is affected. The handling of this very specific case + * handled below mimic wine behaviour */ + if (tx->insn.coissue && tx->version.major == 1 && tx->version.minor < 4 && tx->insn.dst[0].mask != NINED3DSP_WRITEMASK_3) { + 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]); + cgt = tx_scratch(tx); + + if (tx->version.major == 1 && tx->version.minor < 4) + cnd = ureg_scalar(cnd, TGSI_SWIZZLE_W); + + ureg_SGT(tx->ureg, cgt, cnd, ureg_imm1f(tx->ureg, 0.5f)); + + ureg_CMP(tx->ureg, dst, ureg_negate(ureg_src(cgt)), + tx_src_param(tx, &tx->insn.src[1]), + tx_src_param(tx, &tx->insn.src[2])); + 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_src src = tx_src_param(tx, &tx->insn.src[1]); + + if (!tx->native_integers) + ureg_IF(ureg, src, tx_cond(tx)); + else + ureg_UIF(ureg, src, 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(LOOP) +{ + struct ureg_program *ureg = tx->ureg; + unsigned *label; + struct ureg_src src = tx_src_param(tx, &tx->insn.src[1]); + struct ureg_dst ctr; + struct ureg_dst aL; + struct ureg_dst tmp; + struct ureg_src ctrx; + + label = tx_bgnloop(tx); + ctr = tx_get_loopctr(tx, true); + aL = tx_get_loopal(tx); + ctrx = ureg_scalar(ureg_src(ctr), TGSI_SWIZZLE_X); + + /* src: num_iterations*/ + ureg_MOV(ureg, ureg_writemask(ctr, NINED3DSP_WRITEMASK_0), + ureg_scalar(src, TGSI_SWIZZLE_X)); + /* al: unused - start_value of al - step for al - unused */ + ureg_MOV(ureg, aL, src); + ureg_BGNLOOP(tx->ureg, label); + tmp = tx_scratch_scalar(tx); + /* Initially ctr.x contains the number of iterations. + * ctr.y will contain the updated value of al. + * We decrease ctr.x at the end of every iteration, + * and stop when it reaches 0. */ + + if (!tx->native_integers) { + /* case src and ctr contain floats */ + /* to avoid precision issue, we stop when ctr <= 0.5 */ + ureg_SGE(ureg, tmp, ureg_imm1f(ureg, 0.5f), ctrx); + ureg_IF(ureg, tx_src_scalar(tmp), tx_cond(tx)); + } else { + /* case src and ctr contain integers */ + ureg_ISGE(ureg, tmp, ureg_imm1i(ureg, 0), ctrx); + ureg_UIF(ureg, tx_src_scalar(tmp), tx_cond(tx)); + } + ureg_BRK(ureg); + tx_endcond(tx); + ureg_ENDIF(ureg); + return D3D_OK; +} + +DECL_SPECIAL(RET) +{ + /* RET as a last instruction could be safely ignored. + * Remove it to prevent crashes/warnings in case underlying + * driver doesn't implement arbitrary returns. + */ + if (*(tx->parse_next) != NINED3DSP_END) { + ureg_RET(tx->ureg); + } + return D3D_OK; +} + +DECL_SPECIAL(ENDLOOP) +{ + struct ureg_program *ureg = tx->ureg; + struct ureg_dst ctr = tx_get_loopctr(tx, true); + struct ureg_dst al = tx_get_loopal(tx); + struct ureg_dst dst_ctrx, dst_al; + struct ureg_src src_ctr, al_counter; + + dst_ctrx = ureg_writemask(ctr, NINED3DSP_WRITEMASK_0); + dst_al = ureg_writemask(al, NINED3DSP_WRITEMASK_1); + src_ctr = ureg_src(ctr); + al_counter = ureg_scalar(ureg_src(al), TGSI_SWIZZLE_Z); + + /* ctr.x -= 1 + * al.y (aL) += step */ + if (!tx->native_integers) { + ureg_ADD(ureg, dst_ctrx, src_ctr, ureg_imm1f(ureg, -1.0f)); + ureg_ADD(ureg, dst_al, ureg_src(al), al_counter); + } else { + ureg_UADD(ureg, dst_ctrx, src_ctr, ureg_imm1i(ureg, -1)); + ureg_UADD(ureg, dst_al, ureg_src(al), al_counter); + } + 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_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]); + struct ureg_dst tmp = tx_scratch_scalar(tx); + + assert(!(dst.WriteMask & 0xc)); + + /* Copying to a temporary register avoids src/dst aliasing. + * src is supposed to have replicated swizzle. */ + ureg_MOV(ureg, tmp, src); + + /* z undefined, w untouched */ + ureg_COS(ureg, ureg_writemask(dst, TGSI_WRITEMASK_X), + tx_src_scalar(tmp)); + ureg_SIN(ureg, ureg_writemask(dst, TGSI_WRITEMASK_Y), + tx_src_scalar(tmp)); + 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; + struct ureg_src ctrx; + + label = tx_bgnloop(tx); + ctr = ureg_writemask(tx_get_loopctr(tx, false), NINED3DSP_WRITEMASK_0); + ctrx = ureg_scalar(ureg_src(ctr), TGSI_SWIZZLE_X); + + /* 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); + + /* rep: num_iterations - 0 - 0 - 0 */ + ureg_MOV(ureg, ctr, rep); + ureg_BGNLOOP(ureg, label); + tmp = tx_scratch_scalar(tx); + /* Initially ctr.x contains the number of iterations. + * We decrease ctr.x at the end of every iteration, + * and stop when it reaches 0. */ + + if (!tx->native_integers) { + /* case src and ctr contain floats */ + /* to avoid precision issue, we stop when ctr <= 0.5 */ + ureg_SGE(ureg, tmp, ureg_imm1f(ureg, 0.5f), ctrx); + ureg_IF(ureg, tx_src_scalar(tmp), tx_cond(tx)); + } else { + /* case src and ctr contain integers */ + ureg_ISGE(ureg, tmp, ureg_imm1i(ureg, 0), ctrx); + ureg_UIF(ureg, tx_src_scalar(tmp), tx_cond(tx)); + } + ureg_BRK(ureg); + tx_endcond(tx); + ureg_ENDIF(ureg); + + return D3D_OK; +} + +DECL_SPECIAL(ENDREP) +{ + struct ureg_program *ureg = tx->ureg; + struct ureg_dst ctr = tx_get_loopctr(tx, false); + struct ureg_dst dst_ctrx = ureg_writemask(ctr, NINED3DSP_WRITEMASK_0); + struct ureg_src src_ctr = ureg_src(ctr); + + /* ctr.x -= 1 */ + if (!tx->native_integers) + ureg_ADD(ureg, dst_ctrx, src_ctr, ureg_imm1f(ureg, -1.0f)); + else + ureg_UADD(ureg, dst_ctrx, src_ctr, ureg_imm1i(ureg, -1)); + + 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_SGT; + } +} + +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, 0); + 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, 0); + 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); + 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, + bool tc, + struct sm1_semantic *dcl) +{ + BYTE index = dcl->usage_idx; + + /* For everything that is not matching to a TGSI_SEMANTIC_****, + * we match to a TGSI_SEMANTIC_GENERIC with index. + * + * The index can be anything UINT16 and usage_idx is BYTE, + * so we can fit everything. It doesn't matter if indices + * are close together or low. + * + * + * POSITION >= 1: 10 * index + 7 + * COLOR >= 2: 10 * (index-1) + 8 + * FOG: 16 + * TEXCOORD[0..15]: index + * BLENDWEIGHT: 10 * index + 19 + * BLENDINDICES: 10 * index + 20 + * NORMAL: 10 * index + 21 + * TANGENT: 10 * index + 22 + * BINORMAL: 10 * index + 23 + * TESSFACTOR: 10 * index + 24 + */ + + switch (dcl->usage) { + case D3DDECLUSAGE_POSITION: + case D3DDECLUSAGE_POSITIONT: + case D3DDECLUSAGE_DEPTH: + if (index == 0) { + sem->Name = TGSI_SEMANTIC_POSITION; + sem->Index = 0; + } else { + sem->Name = TGSI_SEMANTIC_GENERIC; + sem->Index = 10 * index + 7; + } + break; + case D3DDECLUSAGE_COLOR: + if (index < 2) { + sem->Name = TGSI_SEMANTIC_COLOR; + sem->Index = index; + } else { + sem->Name = TGSI_SEMANTIC_GENERIC; + sem->Index = 10 * (index-1) + 8; + } + break; + case D3DDECLUSAGE_FOG: + assert(index == 0); + sem->Name = TGSI_SEMANTIC_GENERIC; + sem->Index = 16; + break; + case D3DDECLUSAGE_PSIZE: + assert(index == 0); + sem->Name = TGSI_SEMANTIC_PSIZE; + sem->Index = 0; + break; + case D3DDECLUSAGE_TEXCOORD: + assert(index < 16); + if (index < 8 && tc) + sem->Name = TGSI_SEMANTIC_TEXCOORD; + else + sem->Name = TGSI_SEMANTIC_GENERIC; + sem->Index = index; + break; + case D3DDECLUSAGE_BLENDWEIGHT: + sem->Name = TGSI_SEMANTIC_GENERIC; + sem->Index = 10 * index + 19; + break; + case D3DDECLUSAGE_BLENDINDICES: + sem->Name = TGSI_SEMANTIC_GENERIC; + sem->Index = 10 * index + 20; + break; + case D3DDECLUSAGE_NORMAL: + sem->Name = TGSI_SEMANTIC_GENERIC; + sem->Index = 10 * index + 21; + break; + case D3DDECLUSAGE_TANGENT: + sem->Name = TGSI_SEMANTIC_GENERIC; + sem->Index = 10 * index + 22; + break; + case D3DDECLUSAGE_BINORMAL: + sem->Name = TGSI_SEMANTIC_GENERIC; + sem->Index = 10 * index + 23; + break; + case D3DDECLUSAGE_TESSFACTOR: + sem->Name = TGSI_SEMANTIC_GENERIC; + sem->Index = 10 * index + 24; + break; + case D3DDECLUSAGE_SAMPLE: + sem->Name = TGSI_SEMANTIC_COUNT; + sem->Index = 0; + break; + default: + UNREACHABLE("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) +{ + bool shadow = !!(info->sampler_mask_shadow & (1 << stage)); + switch ((info->sampler_ps1xtypes >> (stage * 2)) & 0x3) { + case 1: return shadow ? TGSI_TEXTURE_SHADOW1D : TGSI_TEXTURE_1D; + case 0: return shadow ? TGSI_TEXTURE_SHADOW2D : 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: + return TGSI_INTERPOLATE_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; + bool is_input; + bool 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 < ARRAY_SIZE(tx->info->input_map)); + tx->info->input_map[sem.reg.idx] = sm1_to_nine_declusage(&sem); + tx->info->num_inputs = MAX2(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 < ARRAY_SIZE(tx->regs.o)); + assert(ureg_dst_is_undef(tx->regs.o[sem.reg.idx]) && "Nine doesn't support yet packing"); + tx->regs.o[sem.reg.idx] = ureg_DECL_output_masked( + ureg, tgsi.Name, tgsi.Index, sem.reg.mask, 0, 1); + nine_record_outputs(tx, sem.usage, sem.usage_idx, sem.reg.mask, sem.reg.idx); + if ((tx->info->process_vertices || tx->info->clip_plane_emulation > 0) && + sem.usage == D3DDECLUSAGE_POSITION && sem.usage_idx == 0) { + tx->regs.oPos_out = tx->regs.o[sem.reg.idx]; /* TODO: probably not good declare it twice */ + tx->regs.o[sem.reg.idx] = ureg_DECL_temporary(ureg); + tx->regs.oPos = tx->regs.o[sem.reg.idx]; + } + + if (tgsi.Name == TGSI_SEMANTIC_PSIZE) { + tx->regs.o[sem.reg.idx] = ureg_DECL_temporary(ureg); + tx->regs.oPts = tx->regs.o[sem.reg.idx]; + } + } + } else { + if (is_input && tx->version.major >= 3) { + unsigned interp_flag; + unsigned interp_location = 0; + /* SM3 only, SM2 input semantic determined by file */ + assert(sem.reg.idx < ARRAY_SIZE(tx->regs.v)); + assert(ureg_src_is_undef(tx->regs.v[sem.reg.idx]) && "Nine doesn't support yet packing"); + /* PositionT and tessfactor forbidden */ + if (sem.usage == D3DDECLUSAGE_POSITIONT || sem.usage == D3DDECLUSAGE_TESSFACTOR) + return D3DERR_INVALIDCALL; + + if (tgsi.Name == TGSI_SEMANTIC_POSITION) { + /* Position0 is forbidden (likely because vPos already does that) */ + if (sem.usage == D3DDECLUSAGE_POSITION) + return D3DERR_INVALIDCALL; + /* Following code is for depth */ + tx->regs.v[sem.reg.idx] = nine_get_position_input(tx); + return D3D_OK; + } + + if (sem.reg.mod & NINED3DSPDM_CENTROID || + (tgsi.Name == TGSI_SEMANTIC_COLOR && tx->info->force_color_in_centroid)) + interp_location = TGSI_INTERPOLATE_LOC_CENTROID; + interp_flag = nine_tgsi_to_interp_mode(&tgsi); + /* We replace TGSI_INTERPOLATE_COLOR because some drivers don't support it, + * and those who support it do the same replacement we do */ + if (interp_flag == TGSI_INTERPOLATE_COLOR) + interp_flag = tx->info->color_flatshade ? TGSI_INTERPOLATE_CONSTANT : TGSI_INTERPOLATE_PERSPECTIVE; + + tx->regs.v[sem.reg.idx] = ureg_DECL_fs_input_centroid( + ureg, tgsi.Name, tgsi.Index, + interp_flag, + interp_location, 0, 1); + } 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, + 0, 1); + } + } + 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(POW) +{ + 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]) + }; + /* Anything^0 is 1, including 0^0. + * Assume mul_zero_wins drivers already have + * this behaviour. Emulate for the others. */ + if (tx->mul_zero_wins) { + ureg_POW(tx->ureg, dst, ureg_abs(src[0]), src[1]); + } else { + struct ureg_dst tmp = tx_scratch_scalar(tx); + ureg_POW(tx->ureg, tmp, ureg_abs(src[0]), src[1]); + ureg_CMP(tx->ureg, dst, + ureg_negate(ureg_abs(ureg_scalar(src[1], TGSI_SWIZZLE_X))), + tx_src_scalar(tmp), ureg_imm1f(tx->ureg, 1.0f)); + } + return D3D_OK; +} + +/* Tests results on Win 10: + * NV (NVIDIA GeForce GT 635M) + * AMD (AMD Radeon HD 7730M) + * INTEL (Intel(R) HD Graphics 4000) + * PS2 and PS3: + * RCP and RSQ can generate inf on NV and AMD. + * RCP and RSQ are clamped on INTEL (+- FLT_MAX), + * NV: log not clamped + * AMD: log(0) is -FLT_MAX (but log(inf) is inf) + * INTEL: log(0) is -FLT_MAX and log(inf) is 127 + * All devices have 0*anything = 0 + * + * INTEL VS2 and VS3: same behaviour. + * Some differences VS2 and VS3 for constants defined with inf/NaN. + * While PS3, VS3 and PS2 keep NaN and Inf shader constants without change, + * VS2 seems to clamp to zero (may be test failure). + * AMD VS2: unknown, VS3: very likely behaviour of PS3 + * NV VS2 and VS3: very likely behaviour of PS3 + * For both, Inf in VS becomes NaN is PS + * "Very likely" because the test was less extensive. + * + * Thus all clamping can be removed for shaders 2 and 3, + * as long as 0*anything = 0. + * Else clamps to enforce 0*anything = 0 (anything being then + * neither inf or NaN, the user being unlikely to pass them + * as constant). + * The status for VS1 and PS1 is unknown. + */ + +DECL_SPECIAL(RCP) +{ + 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]); + struct ureg_dst tmp = tx->mul_zero_wins ? dst : tx_scratch(tx); + ureg_RCP(ureg, tmp, src); + if (!tx->mul_zero_wins) { + /* FLT_MAX has issues with Rayman */ + ureg_MIN(ureg, tmp, ureg_imm1f(ureg, FLT_MAX/2.f), ureg_src(tmp)); + ureg_MAX(ureg, dst, ureg_imm1f(ureg, -FLT_MAX/2.f), ureg_src(tmp)); + } + return D3D_OK; +} + +DECL_SPECIAL(RSQ) +{ + 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]); + struct ureg_dst tmp = tx->mul_zero_wins ? dst : tx_scratch(tx); + ureg_RSQ(ureg, tmp, ureg_abs(src)); + if (!tx->mul_zero_wins) + ureg_MIN(ureg, dst, ureg_imm1f(ureg, FLT_MAX), ureg_src(tmp)); + return D3D_OK; +} + +DECL_SPECIAL(LOG) +{ + struct ureg_program *ureg = tx->ureg; + struct ureg_dst tmp = tx_scratch_scalar(tx); + struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]); + struct ureg_src src = tx_src_param(tx, &tx->insn.src[0]); + ureg_LG2(ureg, tmp, ureg_abs(src)); + if (tx->mul_zero_wins) { + ureg_MOV(ureg, dst, tx_src_scalar(tmp)); + } else { + ureg_MAX(ureg, dst, ureg_imm1f(ureg, -FLT_MAX), tx_src_scalar(tmp)); + } + return D3D_OK; +} + +DECL_SPECIAL(LIT) +{ + struct ureg_program *ureg = tx->ureg; + struct ureg_dst tmp = tx_scratch(tx); + struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]); + struct ureg_src src = tx_src_param(tx, &tx->insn.src[0]); + ureg_LIT(ureg, tmp, src); + /* d3d9 LIT is the same than gallium LIT. One difference is that d3d9 + * states that dst.z is 0 when src.y <= 0. Gallium definition can assign + * it 0^0 if src.w=0, which value is driver dependent. */ + ureg_CMP(ureg, ureg_writemask(dst, TGSI_WRITEMASK_Z), + ureg_negate(ureg_scalar(src, TGSI_SWIZZLE_Y)), + ureg_src(tmp), ureg_imm1f(ureg, 0.0f)); + ureg_MOV(ureg, ureg_writemask(dst, TGSI_WRITEMASK_XYW), ureg_src(tmp)); + 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_dst dst = tx_dst_param(tx, &tx->insn.dst[0]); + struct ureg_src src = tx_src_param(tx, &tx->insn.src[0]); + ureg_DP3(ureg, tmp, src, src); + ureg_RSQ(ureg, tmp, nrm); + if (!tx->mul_zero_wins) + ureg_MIN(ureg, tmp, ureg_imm1f(ureg, FLT_MAX), nrm); + ureg_MUL(ureg, dst, src, nrm); + return D3D_OK; +} + +DECL_SPECIAL(DP2ADD) +{ + 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; +} + +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]); + + tx_texcoord_alloc(tx, s); + ureg_MOV(ureg, ureg_writemask(ureg_saturate(dst), TGSI_WRITEMASK_XYZ), tx->regs.vT[s]); + ureg_MOV(ureg, ureg_writemask(dst, TGSI_WRITEMASK_W), ureg_imm1f(tx->ureg, 1.0f)); + + return D3D_OK; +} + +DECL_SPECIAL(TEXCOORD_ps14) +{ + struct ureg_program *ureg = tx->ureg; + struct ureg_src src = tx_src_param(tx, &tx->insn.src[0]); + struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]); + + assert(tx->insn.src[0].file == D3DSPR_TEXTURE); + + ureg_MOV(ureg, dst, src); + + 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) +{ + 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]); /* t[n] */ + struct ureg_dst tmp, tmp2, texcoord; + struct ureg_src sample, m00, m01, m10, m11, c8m, c16m2; + struct ureg_src bumpenvlscale, bumpenvloffset; + const int m = tx->insn.dst[0].idx; + + assert(tx->version.major == 1); + + sample = ureg_DECL_sampler(ureg, m); + tx->info->sampler_mask |= 1 << m; + + tx_texcoord_alloc(tx, m); + + tmp = tx_scratch(tx); + tmp2 = tx_scratch(tx); + texcoord = tx_scratch(tx); + /* + * Bump-env-matrix: + * 00 is X + * 01 is Y + * 10 is Z + * 11 is W + */ + c8m = nine_special_constant_src(tx, m); + c16m2 = nine_special_constant_src(tx, 8+m/2); + + m00 = NINE_APPLY_SWIZZLE(c8m, X); + m01 = NINE_APPLY_SWIZZLE(c8m, Y); + m10 = NINE_APPLY_SWIZZLE(c8m, Z); + m11 = NINE_APPLY_SWIZZLE(c8m, W); + + /* These two attributes are packed as X=scale0 Y=offset0 Z=scale1 W=offset1 etc */ + if (m % 2 == 0) { + bumpenvlscale = NINE_APPLY_SWIZZLE(c16m2, X); + bumpenvloffset = NINE_APPLY_SWIZZLE(c16m2, Y); + } else { + bumpenvlscale = NINE_APPLY_SWIZZLE(c16m2, Z); + bumpenvloffset = NINE_APPLY_SWIZZLE(c16m2, W); + } + + apply_ps1x_projection(tx, texcoord, tx->regs.vT[m], m); + + /* u' = TextureCoordinates(stage m)u + D3DTSS_BUMPENVMAT00(stage m)*t(n)R */ + ureg_MAD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), m00, + NINE_APPLY_SWIZZLE(src, X), ureg_src(texcoord)); + /* u' = u' + D3DTSS_BUMPENVMAT10(stage m)*t(n)G */ + ureg_MAD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), m10, + NINE_APPLY_SWIZZLE(src, Y), + NINE_APPLY_SWIZZLE(ureg_src(tmp), X)); + + /* v' = TextureCoordinates(stage m)v + D3DTSS_BUMPENVMAT01(stage m)*t(n)R */ + ureg_MAD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_Y), m01, + NINE_APPLY_SWIZZLE(src, X), ureg_src(texcoord)); + /* v' = v' + D3DTSS_BUMPENVMAT11(stage m)*t(n)G*/ + ureg_MAD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_Y), m11, + NINE_APPLY_SWIZZLE(src, Y), + NINE_APPLY_SWIZZLE(ureg_src(tmp), Y)); + + /* Now the texture coordinates are in tmp.xy */ + + if (tx->insn.opcode == D3DSIO_TEXBEM) { + ureg_TEX(ureg, dst, ps1x_sampler_type(tx->info, m), ureg_src(tmp), sample); + } else if (tx->insn.opcode == D3DSIO_TEXBEML) { + /* t(m)RGBA = t(m)RGBA * [(t(n)B * D3DTSS_BUMPENVLSCALE(stage m)) + D3DTSS_BUMPENVLOFFSET(stage m)] */ + ureg_TEX(ureg, tmp, ps1x_sampler_type(tx->info, m), ureg_src(tmp), sample); + ureg_MAD(ureg, tmp2, NINE_APPLY_SWIZZLE(src, Z), + bumpenvlscale, bumpenvloffset); + ureg_MUL(ureg, dst, ureg_src(tmp), ureg_src(tmp2)); + } + + tx->info->bumpenvmat_needed = 1; + + return D3D_OK; +} + +DECL_SPECIAL(TEXREG2AR) +{ + 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]); /* t[n] */ + struct ureg_src sample; + const int m = tx->insn.dst[0].idx; + ASSERTED const int n = tx->insn.src[0].idx; + assert(m >= 0 && m > n); + + sample = ureg_DECL_sampler(ureg, m); + tx->info->sampler_mask |= 1 << m; + ureg_TEX(ureg, dst, ps1x_sampler_type(tx->info, m), ureg_swizzle(src, NINE_SWIZZLE4(W,X,X,X)), sample); + + return D3D_OK; +} + +DECL_SPECIAL(TEXREG2GB) +{ + 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]); /* t[n] */ + struct ureg_src sample; + const int m = tx->insn.dst[0].idx; + ASSERTED const int n = tx->insn.src[0].idx; + assert(m >= 0 && m > n); + + sample = ureg_DECL_sampler(ureg, m); + tx->info->sampler_mask |= 1 << m; + ureg_TEX(ureg, dst, ps1x_sampler_type(tx->info, m), ureg_swizzle(src, NINE_SWIZZLE4(Y,Z,Z,Z)), sample); + + return D3D_OK; +} + +DECL_SPECIAL(TEXM3x2PAD) +{ + return D3D_OK; /* this is just padding */ +} + +DECL_SPECIAL(TEXM3x2TEX) +{ + 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]); /* t[n] */ + struct ureg_src sample; + const int m = tx->insn.dst[0].idx - 1; + ASSERTED const int n = tx->insn.src[0].idx; + assert(m >= 0 && m > n); + + tx_texcoord_alloc(tx, m); + tx_texcoord_alloc(tx, m+1); + + /* performs the matrix multiplication */ + ureg_DP3(ureg, ureg_writemask(dst, TGSI_WRITEMASK_X), tx->regs.vT[m], src); + ureg_DP3(ureg, ureg_writemask(dst, TGSI_WRITEMASK_Y), tx->regs.vT[m+1], src); + + sample = ureg_DECL_sampler(ureg, m + 1); + tx->info->sampler_mask |= 1 << (m + 1); + ureg_TEX(ureg, dst, ps1x_sampler_type(tx->info, m + 1), ureg_src(dst), sample); + + return D3D_OK; +} + +DECL_SPECIAL(TEXM3x3PAD) +{ + return D3D_OK; /* this is just padding */ +} + +DECL_SPECIAL(TEXM3x3SPEC) +{ + 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]); /* t[n] */ + struct ureg_src E = tx_src_param(tx, &tx->insn.src[1]); + struct ureg_src sample; + struct ureg_dst tmp; + const int m = tx->insn.dst[0].idx - 2; + ASSERTED const int n = tx->insn.src[0].idx; + assert(m >= 0 && m > n); + + tx_texcoord_alloc(tx, m); + tx_texcoord_alloc(tx, m+1); + tx_texcoord_alloc(tx, m+2); + + ureg_DP3(ureg, ureg_writemask(dst, TGSI_WRITEMASK_X), tx->regs.vT[m], src); + ureg_DP3(ureg, ureg_writemask(dst, TGSI_WRITEMASK_Y), tx->regs.vT[m+1], src); + ureg_DP3(ureg, ureg_writemask(dst, TGSI_WRITEMASK_Z), tx->regs.vT[m+2], src); + + sample = ureg_DECL_sampler(ureg, m + 2); + tx->info->sampler_mask |= 1 << (m + 2); + tmp = ureg_writemask(tx_scratch(tx), TGSI_WRITEMASK_XYZ); + + /* At this step, dst = N = (u', w', z'). + * We want dst to be the texture sampled at (u'', w'', z''), with + * (u'', w'', z'') = 2 * (N.E / N.N) * N - E */ + ureg_DP3(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), ureg_src(dst), ureg_src(dst)); + ureg_RCP(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X)); + /* at this step tmp.x = 1/N.N */ + ureg_DP3(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_Y), ureg_src(dst), E); + /* at this step tmp.y = N.E */ + ureg_MUL(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X), ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_Y)); + /* at this step tmp.x = N.E/N.N */ + ureg_MUL(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X), ureg_imm1f(ureg, 2.0f)); + ureg_MUL(ureg, tmp, ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X), ureg_src(dst)); + /* at this step tmp.xyz = 2 * (N.E / N.N) * N */ + ureg_ADD(ureg, tmp, ureg_src(tmp), ureg_negate(E)); + ureg_TEX(ureg, dst, ps1x_sampler_type(tx->info, m + 2), ureg_src(tmp), sample); + + return D3D_OK; +} + +DECL_SPECIAL(TEXREG2RGB) +{ + 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]); /* t[n] */ + struct ureg_src sample; + const int m = tx->insn.dst[0].idx; + ASSERTED const int n = tx->insn.src[0].idx; + assert(m >= 0 && m > n); + + sample = ureg_DECL_sampler(ureg, m); + tx->info->sampler_mask |= 1 << m; + ureg_TEX(ureg, dst, ps1x_sampler_type(tx->info, m), src, sample); + + return D3D_OK; +} + +DECL_SPECIAL(TEXDP3TEX) +{ + 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]); /* t[n] */ + struct ureg_dst tmp; + struct ureg_src sample; + const int m = tx->insn.dst[0].idx; + ASSERTED const int n = tx->insn.src[0].idx; + assert(m >= 0 && m > n); + + tx_texcoord_alloc(tx, m); + + tmp = tx_scratch(tx); + ureg_DP3(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), tx->regs.vT[m], src); + ureg_MOV(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_YZ), ureg_imm1f(ureg, 0.0f)); + + sample = ureg_DECL_sampler(ureg, m); + tx->info->sampler_mask |= 1 << m; + ureg_TEX(ureg, dst, ps1x_sampler_type(tx->info, m), ureg_src(tmp), sample); + + return D3D_OK; +} + +DECL_SPECIAL(TEXM3x2DEPTH) +{ + struct ureg_program *ureg = tx->ureg; + struct ureg_src src = tx_src_param(tx, &tx->insn.src[0]); /* t[n] */ + struct ureg_dst tmp; + const int m = tx->insn.dst[0].idx - 1; + ASSERTED const int n = tx->insn.src[0].idx; + assert(m >= 0 && m > n); + + tx_texcoord_alloc(tx, m); + tx_texcoord_alloc(tx, m+1); + + tmp = tx_scratch(tx); + + /* performs the matrix multiplication */ + ureg_DP3(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), tx->regs.vT[m], src); + ureg_DP3(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_Y), tx->regs.vT[m+1], src); + + ureg_RCP(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_Z), ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_Y)); + /* tmp.x = 'z', tmp.y = 'w', tmp.z = 1/'w'. */ + ureg_MUL(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X), ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_Z)); + /* res = 'w' == 0 ? 1.0 : z/w */ + ureg_CMP(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), ureg_negate(ureg_abs(ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_Y))), + ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X), ureg_imm1f(ureg, 1.0f)); + /* replace the depth for depth testing with the result */ + tx->regs.oDepth = ureg_DECL_output_masked(ureg, TGSI_SEMANTIC_POSITION, 0, + TGSI_WRITEMASK_Z, 0, 1); + ureg_MOV(ureg, tx->regs.oDepth, ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X)); + /* note that we write nothing to the destination, since it's disallowed to use it afterward */ + return D3D_OK; +} + +DECL_SPECIAL(TEXDP3) +{ + 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]); /* t[n] */ + const int m = tx->insn.dst[0].idx; + ASSERTED const int n = tx->insn.src[0].idx; + assert(m >= 0 && m > n); + + tx_texcoord_alloc(tx, m); + + ureg_DP3(ureg, dst, tx->regs.vT[m], src); + + return D3D_OK; +} + +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 = tx_src_param(tx, &tx->insn.src[0]); /* t[n] */ + struct ureg_src sample; + struct ureg_dst E, tmp; + const int m = tx->insn.dst[0].idx - 2; + ASSERTED const int n = tx->insn.src[0].idx; + assert(m >= 0 && m > n); + + tx_texcoord_alloc(tx, m); + tx_texcoord_alloc(tx, m+1); + tx_texcoord_alloc(tx, m+2); + + ureg_DP3(ureg, ureg_writemask(dst, TGSI_WRITEMASK_X), tx->regs.vT[m], src); + ureg_DP3(ureg, ureg_writemask(dst, TGSI_WRITEMASK_Y), tx->regs.vT[m+1], src); + ureg_DP3(ureg, ureg_writemask(dst, TGSI_WRITEMASK_Z), tx->regs.vT[m+2], src); + + 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: + sample = 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), sample); + break; + case D3DSIO_TEXM3x3VSPEC: + sample = ureg_DECL_sampler(ureg, m + 2); + tx->info->sampler_mask |= 1 << (m + 2); + E = tx_scratch(tx); + tmp = ureg_writemask(tx_scratch(tx), TGSI_WRITEMASK_XYZ); + ureg_MOV(ureg, ureg_writemask(E, TGSI_WRITEMASK_X), ureg_scalar(tx->regs.vT[m], TGSI_SWIZZLE_W)); + ureg_MOV(ureg, ureg_writemask(E, TGSI_WRITEMASK_Y), ureg_scalar(tx->regs.vT[m+1], TGSI_SWIZZLE_W)); + ureg_MOV(ureg, ureg_writemask(E, TGSI_WRITEMASK_Z), ureg_scalar(tx->regs.vT[m+2], TGSI_SWIZZLE_W)); + /* At this step, dst = N = (u', w', z'). + * We want dst to be the texture sampled at (u'', w'', z''), with + * (u'', w'', z'') = 2 * (N.E / N.N) * N - E */ + ureg_DP3(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), ureg_src(dst), ureg_src(dst)); + ureg_RCP(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X)); + /* at this step tmp.x = 1/N.N */ + ureg_DP3(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_Y), ureg_src(dst), ureg_src(E)); + /* at this step tmp.y = N.E */ + ureg_MUL(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X), ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_Y)); + /* at this step tmp.x = N.E/N.N */ + ureg_MUL(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X), ureg_imm1f(ureg, 2.0f)); + ureg_MUL(ureg, tmp, ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X), ureg_src(dst)); + /* at this step tmp.xyz = 2 * (N.E / N.N) * N */ + ureg_ADD(ureg, tmp, ureg_src(tmp), ureg_negate(ureg_src(E))); + ureg_TEX(ureg, dst, ps1x_sampler_type(tx->info, m + 2), ureg_src(tmp), sample); + break; + default: + return D3DERR_INVALIDCALL; + } + return D3D_OK; +} + +DECL_SPECIAL(TEXDEPTH) +{ + struct ureg_program *ureg = tx->ureg; + struct ureg_dst r5; + struct ureg_src r5r, r5g; + + assert(tx->insn.dst[0].idx == 5); /* instruction must get r5 here */ + + /* we must replace the depth by r5.g == 0 ? 1.0f : r5.r/r5.g. + * r5 won't be used afterward, thus we can use r5.ba */ + r5 = tx->regs.r[5]; + r5r = ureg_scalar(ureg_src(r5), TGSI_SWIZZLE_X); + r5g = ureg_scalar(ureg_src(r5), TGSI_SWIZZLE_Y); + + ureg_RCP(ureg, ureg_writemask(r5, TGSI_WRITEMASK_Z), r5g); + ureg_MUL(ureg, ureg_writemask(r5, TGSI_WRITEMASK_X), r5r, ureg_scalar(ureg_src(r5), TGSI_SWIZZLE_Z)); + /* r5.r = r/g */ + ureg_CMP(ureg, ureg_writemask(r5, TGSI_WRITEMASK_X), ureg_negate(ureg_abs(r5g)), + r5r, ureg_imm1f(ureg, 1.0f)); + /* replace the depth for depth testing with the result */ + tx->regs.oDepth = ureg_DECL_output_masked(ureg, TGSI_SEMANTIC_POSITION, 0, + TGSI_WRITEMASK_Z, 0, 1); + ureg_MOV(ureg, tx->regs.oDepth, r5r); + + return D3D_OK; +} + +DECL_SPECIAL(BEM) +{ + struct ureg_program *ureg = tx->ureg; + struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]); + struct ureg_src src0 = tx_src_param(tx, &tx->insn.src[0]); + struct ureg_src src1 = tx_src_param(tx, &tx->insn.src[1]); + struct ureg_src m00, m01, m10, m11, c8m; + const int m = tx->insn.dst[0].idx; + struct ureg_dst tmp = tx_scratch(tx); + /* + * Bump-env-matrix: + * 00 is X + * 01 is Y + * 10 is Z + * 11 is W + */ + c8m = nine_special_constant_src(tx, m); + m00 = NINE_APPLY_SWIZZLE(c8m, X); + m01 = NINE_APPLY_SWIZZLE(c8m, Y); + m10 = NINE_APPLY_SWIZZLE(c8m, Z); + m11 = NINE_APPLY_SWIZZLE(c8m, W); + /* dest.r = src0.r + D3DTSS_BUMPENVMAT00(stage n) * src1.r */ + ureg_MAD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), m00, + NINE_APPLY_SWIZZLE(src1, X), NINE_APPLY_SWIZZLE(src0, X)); + /* dest.r = dest.r + D3DTSS_BUMPENVMAT10(stage n) * src1.g; */ + ureg_MAD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), m10, + NINE_APPLY_SWIZZLE(src1, Y), NINE_APPLY_SWIZZLE(ureg_src(tmp), X)); + + /* dest.g = src0.g + D3DTSS_BUMPENVMAT01(stage n) * src1.r */ + ureg_MAD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_Y), m01, + NINE_APPLY_SWIZZLE(src1, X), src0); + /* dest.g = dest.g + D3DTSS_BUMPENVMAT11(stage n) * src1.g */ + ureg_MAD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_Y), m11, + NINE_APPLY_SWIZZLE(src1, Y), NINE_APPLY_SWIZZLE(ureg_src(tmp), Y)); + ureg_MOV(ureg, ureg_writemask(dst, TGSI_WRITEMASK_XY), ureg_src(tmp)); + + tx->info->bumpenvmat_needed = 1; + + return D3D_OK; +} + +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 < ARRAY_SIZE(tx->sampler_targets)); + target = tx->sampler_targets[tx->insn.src[1].idx]; + + if (TEX_if_fetch4(tx, dst, target, src[0], src[1], tx->insn.src[1].idx)) + return D3D_OK; + + 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]; + + tx_texcoord_alloc(tx, s); + + src[0] = tx->regs.vT[s]; + src[1] = ureg_DECL_sampler(ureg, s); + tx->info->sampler_mask |= 1 << s; + + TEX_with_ps1x_projection(tx, dst, t, src[0], src[1], s); + + 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[1].idx >= 0 && + tx->insn.src[1].idx < ARRAY_SIZE(tx->sampler_targets)); + target = tx->sampler_targets[tx->insn.src[1].idx]; + + if (TEX_if_fetch4(tx, dst, target, src[0], src[1], tx->insn.src[1].idx)) + return D3D_OK; + + 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[1].idx >= 0 && + tx->insn.src[1].idx < ARRAY_SIZE(tx->sampler_targets)); + target = tx->sampler_targets[tx->insn.src[1].idx]; + + if (TEX_if_fetch4(tx, dst, target, src[0], src[1], tx->insn.src[1].idx)) + return D3D_OK; + + ureg_TXL(tx->ureg, dst, target, src[0], src[1]); + return D3D_OK; +} + +DECL_SPECIAL(SETP) +{ + const unsigned cmp_op = sm1_insn_flags_to_tgsi_setop(tx->insn.flags); + 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]) + }; + ureg_insn(tx->ureg, cmp_op, &dst, 1, src, 2, 0); + return D3D_OK; +} + +DECL_SPECIAL(BREAKP) +{ + struct ureg_src src = tx_src_param(tx, &tx->insn.src[0]); + ureg_IF(tx->ureg, src, tx_cond(tx)); + ureg_BRK(tx->ureg); + tx_endcond(tx); + ureg_ENDIF(tx->ureg); + return D3D_OK; +} + +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 } + +static const struct sm1_op_info inst_table[] = +{ + _OPI(NOP, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 0, 0, SPECIAL(NOP)), /* 0 */ + _OPI(MOV, MOV, V(0,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, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, SPECIAL(SUB)), /* 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, SPECIAL(RCP)), /* 6 */ + _OPI(RSQ, RSQ, V(0,0), V(3,0), V(0,0), V(3,0), 1, 1, SPECIAL(RSQ)), /* 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, SPECIAL(LOG)), /* 15 */ + _OPI(LIT, LIT, V(0,0), V(3,0), V(0,0), V(0,0), 1, 1, SPECIAL(LIT)), /* 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, 1, SPECIAL(CALL)), + _OPI(CALLNZ, CAL, V(2,0), V(3,0), V(2,1), V(3,0), 0, 2, 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, 1, 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, SPECIAL(POW)), + _OPI(CRS, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, SPECIAL(XPD)), /* 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, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 1, 1, SPECIAL(ABS)), + _OPI(NRM, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 1, 1, SPECIAL(NRM)), /* NRM doesn't fit */ + + _OPI(SINCOS, NOP, V(2,0), V(2,1), V(2,0), V(2,1), 1, 3, SPECIAL(SINCOS)), + _OPI(SINCOS, NOP, 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, NOP, V(2,1), V(3,0), V(2,1), V(3,0), 0, 2, SPECIAL(BREAKC)), + /* we don't write to the address register, but a normal register (copied + * when needed to the address register), thus we don't use ARR */ + _OPI(MOVA, MOV, 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), 1, 1, SPECIAL(TEXBEM)), + _OPI(TEXBEML, TEX, V(0,0), V(0,0), V(0,0), V(1,3), 1, 1, SPECIAL(TEXBEM)), + _OPI(TEXREG2AR, TEX, V(0,0), V(0,0), V(0,0), V(1,3), 1, 1, SPECIAL(TEXREG2AR)), + _OPI(TEXREG2GB, TEX, V(0,0), V(0,0), V(0,0), V(1,3), 1, 1, SPECIAL(TEXREG2GB)), + _OPI(TEXM3x2PAD, TEX, V(0,0), V(0,0), V(0,0), V(1,3), 1, 1, SPECIAL(TEXM3x2PAD)), + _OPI(TEXM3x2TEX, TEX, V(0,0), V(0,0), V(0,0), V(1,3), 1, 1, SPECIAL(TEXM3x2TEX)), + _OPI(TEXM3x3PAD, TEX, V(0,0), V(0,0), V(0,0), V(1,3), 1, 1, SPECIAL(TEXM3x3PAD)), + _OPI(TEXM3x3TEX, TEX, V(0,0), V(0,0), V(0,0), V(1,3), 1, 1, SPECIAL(TEXM3x3)), + _OPI(TEXM3x3SPEC, TEX, V(0,0), V(0,0), V(0,0), V(1,3), 1, 2, SPECIAL(TEXM3x3SPEC)), + _OPI(TEXM3x3VSPEC, TEX, V(0,0), V(0,0), V(0,0), V(1,3), 1, 1, SPECIAL(TEXM3x3)), + + _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, SPECIAL(LOG)), + _OPI(CND, NOP, 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), 1, 1, SPECIAL(TEXREG2RGB)), + _OPI(TEXDP3TEX, TEX, V(0,0), V(0,0), V(1,2), V(1,3), 1, 1, SPECIAL(TEXDP3TEX)), + _OPI(TEXM3x2DEPTH, TEX, V(0,0), V(0,0), V(1,3), V(1,3), 1, 1, SPECIAL(TEXM3x2DEPTH)), + _OPI(TEXDP3, TEX, V(0,0), V(0,0), V(1,2), V(1,3), 1, 1, SPECIAL(TEXDP3)), + _OPI(TEXM3x3, TEX, V(0,0), V(0,0), V(1,2), V(1,3), 1, 1, SPECIAL(TEXM3x3)), + _OPI(TEXDEPTH, TEX, V(0,0), V(0,0), V(1,4), V(1,4), 1, 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), 1, 2, SPECIAL(BEM)), + _OPI(DP2ADD, NOP, V(0,0), V(0,0), V(2,0), V(3,0), 1, 3, SPECIAL(DP2ADD)), + _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), 1, 2, 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, 1, SPECIAL(BREAKP)) +}; + +static const 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)); + +static const 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 < ARRAY_SIZE(tx->op_info_map); ++i) + tx->op_info_map[i] = -1; + + if (tx->processor == MESA_SHADER_VERTEX) { + for (i = 0; i < ARRAY_SIZE(inst_table); ++i) { + assert(inst_table[i].sio < ARRAY_SIZE(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 < ARRAY_SIZE(inst_table); ++i) { + assert(inst_table[i].sio < ARRAY_SIZE(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 < ARRAY_SIZE(dst); ++i) + dst[i] = tx_dst_param(tx, &tx->insn.dst[i]); + for (i = 0; i < tx->insn.nsrc && i < ARRAY_SIZE(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, 0); + 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 bool +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 = MESA_SHADER_VERTEX; break; + case NINED3D_SM1_PS: tx->processor = MESA_SHADER_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; + else + *rel = TOKEN_NEXT(tx); + } +} + +static void +sm1_parse_dst_param(struct sm1_dst_param *dst, DWORD tok) +{ + int8_t shift; + 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; + shift = (tok & D3DSP_DSTSHIFT_MASK) >> D3DSP_DSTSHIFT_SHIFT; + dst->shift = (shift & 0x7) - (shift & 0x8); +} + +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; + HRESULT hr; + DWORD tok; + const 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 < ARRAY_SIZE(tx->op_info_map)) { + int k = tx->op_info_map[insn->opcode]; + if (k >= 0) { + assert(k < ARRAY_SIZE(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; + + /* 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 (insn->predicated) { + tx->predicated_activated = true; + if (ureg_dst_is_undef(tx->regs.predicate_tmp)) { + tx->regs.predicate_tmp = ureg_DECL_temporary(tx->ureg); + tx->regs.predicate_dst = ureg_DECL_temporary(tx->ureg); + } + } + + if (info->handler) + hr = info->handler(tx); + else + hr = NineTranslateInstruction_Generic(tx); + tx_apply_dst0_modifiers(tx); + + if (insn->predicated) { + tx->predicated_activated = false; + /* TODO: predicate might be allowed on outputs, + * which cannot be src. Workaround it. */ + ureg_CMP(tx->ureg, tx->regs.predicate_dst, + ureg_negate(tx_src_param(tx, &insn->pred)), + ureg_src(tx->regs.predicate_tmp), + ureg_src(tx->regs.predicate_dst)); + } + + if (hr != D3D_OK) + tx->failure = true; + tx->num_scratch = 0; /* reset */ + + TOKEN_JUMP(tx); +} + +#define GET_CAP(n) screen->caps.n +#define GET_SHADER_CAP(n) screen->shader_caps[info->type].n + +static HRESULT +tx_ctor(struct shader_translator *tx, struct pipe_screen *screen, struct nine_shader_info *info) +{ + unsigned i; + + memset(tx, 0, sizeof(*tx)); + + tx->info = info; + + tx->byte_code = info->byte_code; + tx->parse = info->byte_code; + + for (i = 0; i < ARRAY_SIZE(info->input_map); ++i) + info->input_map[i] = NINE_DECLUSAGE_NONE; + info->num_inputs = 0; + + info->position_t = false; + info->point_size = false; + + memset(tx->slots_used, 0, sizeof(tx->slots_used)); + memset(info->int_slots_used, 0, sizeof(info->int_slots_used)); + memset(info->bool_slots_used, 0, sizeof(info->bool_slots_used)); + + tx->info->const_float_slots = 0; + tx->info->const_int_slots = 0; + tx->info->const_bool_slots = 0; + + info->sampler_mask = 0x0; + info->rt_mask = 0x0; + + info->lconstf.data = NULL; + info->lconstf.ranges = NULL; + + info->bumpenvmat_needed = 0; + + for (i = 0; i < ARRAY_SIZE(tx->regs.rL); ++i) { + tx->regs.rL[i] = ureg_dst_undef(); + } + tx->regs.address = ureg_dst_undef(); + tx->regs.a0 = 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 < ARRAY_SIZE(tx->regs.o); ++i) + tx->regs.o[i] = ureg_dst_undef(); + for (i = 0; i < ARRAY_SIZE(tx->regs.oCol); ++i) + tx->regs.oCol[i] = ureg_dst_undef(); + for (i = 0; i < ARRAY_SIZE(tx->regs.vC); ++i) + tx->regs.vC[i] = ureg_src_undef(); + for (i = 0; i < ARRAY_SIZE(tx->regs.vT); ++i) + tx->regs.vT[i] = ureg_src_undef(); + + sm1_read_version(tx); + + info->version = (tx->version.major << 4) | tx->version.minor; + + tx->num_outputs = 0; + + create_op_info_map(tx); + + tx->ureg = ureg_create(info->type); + if (!tx->ureg) { + return E_OUTOFMEMORY; + } + + tx->native_integers = GET_SHADER_CAP(integers); + tx->inline_subroutines = !GET_SHADER_CAP(subroutines); + tx->want_texcoord = GET_CAP(tgsi_texcoord); + tx->shift_wpos = !GET_CAP(fs_coord_pixel_center_integer); + tx->texcoord_sn = tx->want_texcoord ? + TGSI_SEMANTIC_TEXCOORD : TGSI_SEMANTIC_GENERIC; + tx->wpos_is_sysval = GET_CAP(fs_position_is_sysval); + tx->face_is_sysval_integer = GET_CAP(fs_face_is_integer_sysval); + tx->no_vs_window_space = !GET_CAP(vs_window_space_position); + tx->mul_zero_wins = GET_CAP(legacy_math_rules); + + if (info->emulate_features) { + tx->shift_wpos = true; + tx->no_vs_window_space = true; + tx->mul_zero_wins = false; + } + + if (IS_VS) { + tx->num_constf_allowed = NINE_MAX_CONST_F; + } else if (tx->version.major < 2) {/* IS_PS v1 */ + tx->num_constf_allowed = 8; + } else if (tx->version.major == 2) {/* IS_PS v2 */ + tx->num_constf_allowed = 32; + } else {/* IS_PS v3 */ + tx->num_constf_allowed = NINE_MAX_CONST_F_PS3; + } + + if (tx->version.major < 2) { + tx->num_consti_allowed = 0; + tx->num_constb_allowed = 0; + } else { + tx->num_consti_allowed = NINE_MAX_CONST_I; + tx->num_constb_allowed = NINE_MAX_CONST_B; + } + + if (info->swvp_on) { + /* TODO: The values tx->version.major == 1 */ + tx->num_constf_allowed = 8192; + tx->num_consti_allowed = 2048; + tx->num_constb_allowed = 2048; + } + + /* 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_out = 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 (tx->mul_zero_wins) + ureg_property(tx->ureg, TGSI_PROPERTY_LEGACY_MATH_RULES, 1); + + /* Add additional definition of constants */ + if (info->add_constants_defs.c_combination) { + unsigned i; + + assert(info->add_constants_defs.int_const_added); + assert(info->add_constants_defs.bool_const_added); + /* We only add constants that are used by the shader + * and that are not defined in the shader */ + for (i = 0; i < NINE_MAX_CONST_I; ++i) { + if ((*info->add_constants_defs.int_const_added)[i]) { + DBG("Defining const i%i : { %i %i %i %i }\n", i, + info->add_constants_defs.c_combination->const_i[i][0], + info->add_constants_defs.c_combination->const_i[i][1], + info->add_constants_defs.c_combination->const_i[i][2], + info->add_constants_defs.c_combination->const_i[i][3]); + tx_set_lconsti(tx, i, info->add_constants_defs.c_combination->const_i[i]); + } + } + for (i = 0; i < NINE_MAX_CONST_B; ++i) { + if ((*info->add_constants_defs.bool_const_added)[i]) { + DBG("Defining const b%i : %i\n", i, (int)(info->add_constants_defs.c_combination->const_b[i] != 0)); + tx_set_lconstb(tx, i, info->add_constants_defs.c_combination->const_b[i]); + } + } + } + return D3D_OK; +} + +static void +tx_dtor(struct shader_translator *tx) +{ + if (tx->slot_map) + FREE(tx->slot_map); + if (tx->num_inst_labels) + FREE(tx->inst_labels); + FREE(tx->lconstf); + FREE(tx->regs.r); + FREE(tx); +} + +/* CONST[0].xyz = width/2, -height/2, zmax-zmin + * CONST[1].xyz = x+width/2, y+height/2, zmin */ +static void +shader_add_vs_viewport_transform(struct shader_translator *tx) +{ + struct ureg_program *ureg = tx->ureg; + struct ureg_src c0 = ureg_src_register(TGSI_FILE_CONSTANT, 0); + struct ureg_src c1 = ureg_src_register(TGSI_FILE_CONSTANT, 1); + /* struct ureg_dst pos_tmp = ureg_DECL_temporary(ureg);*/ + + c0 = ureg_src_dimension(c0, 4); + c1 = ureg_src_dimension(c1, 4); + /* TODO: find out when we need to apply the viewport transformation or not. + * Likely will be XYZ vs XYZRHW in vdecl_out + * ureg_MUL(ureg, ureg_writemask(pos_tmp, TGSI_WRITEMASK_XYZ), ureg_src(tx->regs.oPos), c0); + * ureg_ADD(ureg, ureg_writemask(tx->regs.oPos_out, TGSI_WRITEMASK_XYZ), ureg_src(pos_tmp), c1); + */ + ureg_MOV(ureg, ureg_writemask(tx->regs.oPos_out, TGSI_WRITEMASK_XYZ), ureg_src(tx->regs.oPos)); +} + +static void +shader_add_ps_fog_stage(struct shader_translator *tx, struct ureg_dst dst_col, struct ureg_src src_col) +{ + struct ureg_program *ureg = tx->ureg; + struct ureg_src fog_end, fog_coeff, fog_density, fog_params; + struct ureg_src fog_vs, fog_color; + struct ureg_dst fog_factor, depth; + + if (!tx->info->fog_enable) { + ureg_MOV(ureg, dst_col, src_col); + return; + } + + if (tx->info->fog_mode != D3DFOG_NONE) { + depth = tx_scratch_scalar(tx); + if (tx->info->zfog) + ureg_MOV(ureg, depth, ureg_scalar(nine_get_position_input(tx), TGSI_SWIZZLE_Z)); + else /* wfog: use w. position's w contains 1/w */ + ureg_RCP(ureg, depth, ureg_scalar(nine_get_position_input(tx), TGSI_SWIZZLE_W)); + } + + fog_color = nine_special_constant_src(tx, 12); + fog_params = nine_special_constant_src(tx, 13); + fog_factor = tx_scratch_scalar(tx); + + if (tx->info->fog_mode == D3DFOG_LINEAR) { + fog_end = NINE_APPLY_SWIZZLE(fog_params, X); + fog_coeff = NINE_APPLY_SWIZZLE(fog_params, Y); + ureg_ADD(ureg, fog_factor, fog_end, ureg_negate(ureg_src(depth))); + ureg_MUL(ureg, ureg_saturate(fog_factor), tx_src_scalar(fog_factor), fog_coeff); + } else if (tx->info->fog_mode == D3DFOG_EXP) { + fog_density = NINE_APPLY_SWIZZLE(fog_params, X); + ureg_MUL(ureg, fog_factor, ureg_src(depth), fog_density); + ureg_MUL(ureg, fog_factor, tx_src_scalar(fog_factor), ureg_imm1f(ureg, -1.442695f)); + ureg_EX2(ureg, fog_factor, tx_src_scalar(fog_factor)); + } else if (tx->info->fog_mode == D3DFOG_EXP2) { + fog_density = NINE_APPLY_SWIZZLE(fog_params, X); + ureg_MUL(ureg, fog_factor, ureg_src(depth), fog_density); + ureg_MUL(ureg, fog_factor, tx_src_scalar(fog_factor), tx_src_scalar(fog_factor)); + ureg_MUL(ureg, fog_factor, tx_src_scalar(fog_factor), ureg_imm1f(ureg, -1.442695f)); + ureg_EX2(ureg, fog_factor, tx_src_scalar(fog_factor)); + } else { + fog_vs = ureg_scalar(ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_GENERIC, 16, + TGSI_INTERPOLATE_PERSPECTIVE), + TGSI_SWIZZLE_X); + ureg_MOV(ureg, fog_factor, fog_vs); + } + + ureg_LRP(ureg, ureg_writemask(dst_col, TGSI_WRITEMASK_XYZ), + tx_src_scalar(fog_factor), src_col, fog_color); + ureg_MOV(ureg, ureg_writemask(dst_col, TGSI_WRITEMASK_W), src_col); +} + +static void +shader_add_ps_alpha_test_stage(struct shader_translator *tx, struct ureg_src src_color) +{ + struct ureg_program *ureg = tx->ureg; + unsigned cmp_op; + struct ureg_src src[2]; + struct ureg_dst tmp = tx_scratch(tx); + if (tx->info->alpha_test_emulation == PIPE_FUNC_ALWAYS) + return; + if (tx->info->alpha_test_emulation == PIPE_FUNC_NEVER) { + ureg_KILL(ureg); + return; + } + cmp_op = pipe_comp_to_tgsi_opposite(tx->info->alpha_test_emulation); + src[0] = ureg_scalar(src_color, TGSI_SWIZZLE_W); /* Read color alpha channel */ + src[1] = ureg_scalar(nine_special_constant_src(tx, 14), TGSI_SWIZZLE_X); /* Read alphatest */ + ureg_insn(tx->ureg, cmp_op, &tmp, 1, src, 2, 0); + ureg_KILL_IF(tx->ureg, ureg_negate(ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X))); /* if opposite test passes, discard */ +} + +static void parse_shader(struct shader_translator *tx) +{ + struct nine_shader_info *info = tx->info; + + while (!sm1_parse_eof(tx) && !tx->failure) + sm1_parse_instruction(tx); + tx->parse++; /* for byte_size */ + + if (tx->failure) + return; + + if (IS_PS) { + struct ureg_dst oCol0 = ureg_DECL_output(tx->ureg, TGSI_SEMANTIC_COLOR, 0); + struct ureg_dst tmp_oCol0; + if (tx->version.major < 3) { + tmp_oCol0 = ureg_DECL_temporary(tx->ureg); + if (tx->version.major < 2) { + assert(tx->num_temp); /* there must be color output */ + info->rt_mask |= 0x1; + shader_add_ps_fog_stage(tx, tmp_oCol0, ureg_src(tx->regs.r[0])); + } else { + shader_add_ps_fog_stage(tx, tmp_oCol0, ureg_src(tx->regs.oCol[0])); + } + } else { + assert(!ureg_dst_is_undef(tx->regs.oCol[0])); + tmp_oCol0 = tx->regs.oCol[0]; + } + shader_add_ps_alpha_test_stage(tx, ureg_src(tmp_oCol0)); + ureg_MOV(tx->ureg, oCol0, ureg_src(tmp_oCol0)); + } + + if (IS_VS && tx->version.major < 3 && ureg_dst_is_undef(tx->regs.oFog) && info->fog_enable) { + tx->regs.oFog = ureg_DECL_output(tx->ureg, TGSI_SEMANTIC_GENERIC, 16); + ureg_MOV(tx->ureg, ureg_writemask(tx->regs.oFog, TGSI_WRITEMASK_X), ureg_imm1f(tx->ureg, 0.0f)); + } + + if (info->position_t) { + if (tx->no_vs_window_space) { + ERR("POSITIONT is not yet implemented for your device.\n"); + } else { + ureg_property(tx->ureg, TGSI_PROPERTY_VS_WINDOW_SPACE_POSITION, true); + } + } + + if (IS_VS && !ureg_dst_is_undef(tx->regs.oPts)) { + struct ureg_dst oPts = ureg_DECL_output(tx->ureg, TGSI_SEMANTIC_PSIZE, 0); + ureg_MAX(tx->ureg, ureg_writemask(tx->regs.oPts, TGSI_WRITEMASK_X), ureg_src(tx->regs.oPts), ureg_imm1f(tx->ureg, info->point_size_min)); + ureg_MIN(tx->ureg, ureg_writemask(oPts, TGSI_WRITEMASK_X), ureg_src(tx->regs.oPts), ureg_imm1f(tx->ureg, info->point_size_max)); + info->point_size = true; + } else if (IS_VS && tx->always_output_pointsize) { + struct ureg_dst oPts = ureg_DECL_output(tx->ureg, TGSI_SEMANTIC_PSIZE, 0); + ureg_MOV(tx->ureg, ureg_writemask(oPts, TGSI_WRITEMASK_X), nine_special_constant_src(tx, 8)); + info->point_size = true; + } + + if (IS_VS && tx->info->clip_plane_emulation > 0) { + struct ureg_dst clipdist[2] = {ureg_dst_undef(), ureg_dst_undef()}; + int num_clipdist = ffs(tx->info->clip_plane_emulation); + int i; + /* TODO: handle undefined channels of oPos (w is not always written to I think. default is 1) * + * Note in d3d9 it's not possible to output clipvert, so we don't need to check + * for its existence */ + clipdist[0] = ureg_DECL_output_masked(tx->ureg, TGSI_SEMANTIC_CLIPDIST, 0, ((1 << num_clipdist) - 1) & 0xf, 0, 1); + if (num_clipdist >= 5) + clipdist[1] = ureg_DECL_output_masked(tx->ureg, TGSI_SEMANTIC_CLIPDIST, 1, ((1 << (num_clipdist - 4)) - 1) & 0xf, 0, 1); + ureg_property(tx->ureg, TGSI_PROPERTY_NUM_CLIPDIST_ENABLED, num_clipdist); + for (i = 0; i < num_clipdist; i++) { + assert(!ureg_dst_is_undef(clipdist[i>>2])); + if (!(tx->info->clip_plane_emulation & (1 << i))) + ureg_MOV(tx->ureg, ureg_writemask(clipdist[i>>2], 1 << (i & 0x2)), ureg_imm1f(tx->ureg, 0.f)); + else + ureg_DP4(tx->ureg, ureg_writemask(clipdist[i>>2], 1 << (i & 0x2)), + ureg_src(tx->regs.oPos), nine_special_constant_src(tx, i)); + } + + ureg_MOV(tx->ureg, tx->regs.oPos_out, ureg_src(tx->regs.oPos)); + } + + if (info->process_vertices) + shader_add_vs_viewport_transform(tx); + + ureg_END(tx->ureg); +} + +#define NINE_SHADER_DEBUG_OPTION_NO_NIR_VS (1 << 2) +#define NINE_SHADER_DEBUG_OPTION_NO_NIR_PS (1 << 3) +#define NINE_SHADER_DEBUG_OPTION_DUMP_NIR (1 << 4) +#define NINE_SHADER_DEBUG_OPTION_DUMP_TGSI (1 << 5) + +static const struct debug_named_value nine_shader_debug_options[] = { + { "no_nir_vs", NINE_SHADER_DEBUG_OPTION_NO_NIR_VS, "Never use NIR for vertex shaders even if the driver prefers it." }, + { "no_nir_ps", NINE_SHADER_DEBUG_OPTION_NO_NIR_PS, "Never use NIR for pixel shaders even if the driver prefers it." }, + { "dump_nir", NINE_SHADER_DEBUG_OPTION_DUMP_NIR, "Print translated NIR shaders." }, + { "dump_tgsi", NINE_SHADER_DEBUG_OPTION_DUMP_TGSI, "Print TGSI shaders." }, + DEBUG_NAMED_VALUE_END /* must be last */ +}; + +static inline bool +nine_shader_get_debug_flag(uint64_t flag) +{ + static uint64_t flags = 0; + static bool first_run = true; + + if (unlikely(first_run)) { + first_run = false; + flags = debug_get_flags_option("NINE_SHADER", nine_shader_debug_options, 0); + + // Check old TGSI dump envvar too + if (debug_get_bool_option("NINE_TGSI_DUMP", false)) { + flags |= NINE_SHADER_DEBUG_OPTION_DUMP_TGSI; + } + } + + return !!(flags & flag); +} + +static void +nine_pipe_nir_shader_state_from_tgsi(struct pipe_shader_state *state, const struct tgsi_token *tgsi_tokens, + struct pipe_screen *screen) +{ + struct nir_shader *nir = tgsi_to_nir(tgsi_tokens, screen, screen->get_disk_shader_cache != NULL); + + if (unlikely(nine_shader_get_debug_flag(NINE_SHADER_DEBUG_OPTION_DUMP_NIR))) { + nir_print_shader(nir, stdout); + } + + state->type = PIPE_SHADER_IR_NIR; + state->tokens = NULL; + state->ir.nir = nir; + memset(&state->stream_output, 0, sizeof(state->stream_output)); +} + +static void * +nine_ureg_create_shader(struct ureg_program *ureg, + struct pipe_context *pipe, + const struct pipe_stream_output_info *so) +{ + struct pipe_shader_state state; + const struct tgsi_token *tgsi_tokens; + struct pipe_screen *screen = pipe->screen; + + tgsi_tokens = ureg_finalize(ureg); + if (!tgsi_tokens) + return NULL; + + assert(((struct tgsi_header *) &tgsi_tokens[0])->HeaderSize >= 2); + mesa_shader_stage shader_type = ((struct tgsi_processor *) &tgsi_tokens[1])->Processor; + + bool use_nir = true; + + /* Allow user to override preferred IR, this is very useful for debugging */ + if (unlikely(shader_type == MESA_SHADER_VERTEX && nine_shader_get_debug_flag(NINE_SHADER_DEBUG_OPTION_NO_NIR_VS))) + use_nir = false; + if (unlikely(shader_type == MESA_SHADER_FRAGMENT && nine_shader_get_debug_flag(NINE_SHADER_DEBUG_OPTION_NO_NIR_PS))) + use_nir = false; + + DUMP("shader type: %s, selected IR: %s\n", + shader_type == MESA_SHADER_VERTEX ? "VS" : "PS", + use_nir ? "NIR" : "TGSI"); + + if (use_nir) { + nine_pipe_nir_shader_state_from_tgsi(&state, tgsi_tokens, screen); + } else { + pipe_shader_state_from_tgsi(&state, tgsi_tokens); + } + + assert(state.tokens || state.ir.nir); + + if (so) + state.stream_output = *so; + + state.report_compile_error = false; + + switch (shader_type) { + case MESA_SHADER_VERTEX: + return pipe->create_vs_state(pipe, &state); + case MESA_SHADER_FRAGMENT: + return pipe->create_fs_state(pipe, &state); + default: + UNREACHABLE("unsupported shader type"); + } +} + + +void * +nine_create_shader_with_so_and_destroy(struct ureg_program *p, + struct pipe_context *pipe, + const struct pipe_stream_output_info *so) +{ + void *result = nine_ureg_create_shader(p, pipe, so); + ureg_destroy(p); + return result; +} + +HRESULT +nine_translate_shader(struct NineDevice9 *device, struct nine_shader_info *info, struct pipe_context *pipe) +{ + struct shader_translator *tx; + HRESULT hr = D3D_OK; + const unsigned processor = info->type; + struct pipe_screen *screen = info->process_vertices ? device->screen_sw : device->screen; + unsigned *const_ranges = NULL; + + user_assert(processor != ~0, D3DERR_INVALIDCALL); + + tx = MALLOC_STRUCT(shader_translator); + if (!tx) + return E_OUTOFMEMORY; + + info->emulate_features = device->driver_caps.shader_emulate_features; + + if (tx_ctor(tx, screen, info) == E_OUTOFMEMORY) { + hr = E_OUTOFMEMORY; + goto out; + } + tx->always_output_pointsize = device->driver_caps.always_output_pointsize; + + assert(IS_VS || !info->swvp_on); + + 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 == MESA_SHADER_VERTEX ? "VS" : "PS", + tx->version.major, tx->version.minor); + + parse_shader(tx); + + if (tx->failure) { + /* For VS shaders, we print the warning later, + * we first try with swvp. */ + if (IS_PS) + ERR("Encountered buggy shader\n"); + ureg_destroy(tx->ureg); + hr = D3DERR_INVALIDCALL; + goto out; + } + + /* Recompile after compacting constant slots if possible */ + if (!tx->indirect_const_access && !info->swvp_on && tx->num_slots > 0) { + unsigned *slot_map; + unsigned c; + int i, j, num_ranges, prev; + + DBG("Recompiling shader for constant compaction\n"); + ureg_destroy(tx->ureg); + + if (tx->num_inst_labels) + FREE(tx->inst_labels); + FREE(tx->lconstf); + FREE(tx->regs.r); + + num_ranges = 0; + prev = -2; + for (i = 0; i < NINE_MAX_CONST_ALL_VS; i++) { + if (tx->slots_used[i]) { + if (prev != i - 1) + num_ranges++; + prev = i; + } + } + slot_map = MALLOC(NINE_MAX_CONST_ALL_VS * sizeof(unsigned)); + const_ranges = CALLOC(num_ranges + 1, 2 * sizeof(unsigned)); /* ranges stop when last is of size 0 */ + if (!slot_map || !const_ranges) { + hr = E_OUTOFMEMORY; + goto out; + } + c = 0; + j = -1; + prev = -2; + for (i = 0; i < NINE_MAX_CONST_ALL_VS; i++) { + if (tx->slots_used[i]) { + if (prev != i - 1) + j++; + /* Initialize first slot of the range */ + if (!const_ranges[2*j+1]) + const_ranges[2*j] = i; + const_ranges[2*j+1]++; + prev = i; + slot_map[i] = c++; + } + } + + if (tx_ctor(tx, screen, info) == E_OUTOFMEMORY) { + hr = E_OUTOFMEMORY; + goto out; + } + tx->always_output_pointsize = device->driver_caps.always_output_pointsize; + tx->slot_map = slot_map; + parse_shader(tx); + assert(!tx->failure); +#if !defined(NDEBUG) + i = 0; + j = 0; + while (const_ranges[i*2+1] != 0) { + j += const_ranges[i*2+1]; + i++; + } + assert(j == tx->num_slots); +#endif + } + + /* 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].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; + } + + /* r500 */ + if (info->const_float_slots > device->max_vs_const_f && + (info->const_int_slots || info->const_bool_slots) && + !info->swvp_on) + ERR("Overlapping constant slots. The shader is likely to be buggy\n"); + + + if (tx->indirect_const_access) { /* vs only */ + info->const_float_slots = device->max_vs_const_f; + tx->num_slots = MAX2(tx->num_slots, device->max_vs_const_f); + } + + if (!info->swvp_on) { + info->const_used_size = sizeof(float[4]) * tx->num_slots; + if (tx->num_slots) + ureg_DECL_constant2D(tx->ureg, 0, tx->num_slots-1, 0); + } else { + ureg_DECL_constant2D(tx->ureg, 0, 4095, 0); + ureg_DECL_constant2D(tx->ureg, 0, 4095, 1); + ureg_DECL_constant2D(tx->ureg, 0, 2047, 2); + ureg_DECL_constant2D(tx->ureg, 0, 511, 3); + } + + if (info->process_vertices) + ureg_DECL_constant2D(tx->ureg, 0, 2, 4); /* Viewport data */ + + if (unlikely(nine_shader_get_debug_flag(NINE_SHADER_DEBUG_OPTION_DUMP_TGSI))) { + const struct tgsi_token *toks = ureg_get_tokens(tx->ureg, NULL); + tgsi_dump(toks, 0); + ureg_free_tokens(toks); + } + + if (info->process_vertices) { + NineVertexDeclaration9_FillStreamOutputInfo(info->vdecl_out, + tx->output_info, + tx->num_outputs, + &(info->so)); + info->cso = nine_create_shader_with_so_and_destroy(tx->ureg, pipe, &(info->so)); + } else + info->cso = nine_create_shader_with_so_and_destroy(tx->ureg, pipe, NULL); + if (!info->cso) { + hr = D3DERR_DRIVERINTERNALERROR; + FREE(info->lconstf.data); + FREE(info->lconstf.ranges); + goto out; + } + + info->const_ranges = const_ranges; + const_ranges = NULL; + info->byte_size = (tx->parse - tx->byte_code) * sizeof(DWORD); +out: + if (const_ranges) + FREE(const_ranges); + tx_dtor(tx); + return hr; +} diff --git a/src/gallium/frontends/nine/nine_shader.h b/src/gallium/frontends/nine/nine_shader.h new file mode 100644 index 0000000..62d4527 --- /dev/null +++ b/src/gallium/frontends/nine/nine_shader.h @@ -0,0 +1,334 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#ifndef _NINE_SHADER_H_ +#define _NINE_SHADER_H_ + +#include "d3d9types.h" +#include "d3d9caps.h" +#include "nine_defines.h" +#include "nine_helpers.h" +#include "nine_state.h" +#include "pipe/p_state.h" /* PIPE_MAX_ATTRIBS */ +#include "util/u_memory.h" +#include "tgsi/tgsi_ureg.h" + +struct NineDevice9; +struct NineVertexDeclaration9; +struct ureg_program; + +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_constant_combination; + +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 */ + + uint16_t input_map[PIPE_MAX_ATTRIBS]; /* VS input -> NINE_DECLUSAGE_x */ + uint8_t num_inputs; /* there may be unused inputs (NINE_DECLUSAGE_NONE) */ + + bool position_t; /* out, true if VP writes pre-transformed position */ + bool point_size; /* out, true if VP writes point size */ + float point_size_min; + float point_size_max; + + 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 */ + + uint8_t fog_enable; + uint8_t fog_mode; + uint8_t zfog; + uint8_t force_color_in_centroid; + uint8_t color_flatshade; + uint8_t projected; /* ps 1.1 to 1.3 */ + uint16_t fetch4; + uint8_t alpha_test_emulation; + uint8_t clip_plane_emulation; + bool emulate_features; + + unsigned const_i_base; /* in vec4 (16 byte) units */ + unsigned const_b_base; /* in vec4 (16 byte) units */ + unsigned const_used_size; + + bool int_slots_used[NINE_MAX_CONST_I]; + bool bool_slots_used[NINE_MAX_CONST_B]; + + unsigned const_float_slots; + unsigned const_int_slots; + unsigned const_bool_slots; + + unsigned *const_ranges; + + struct nine_lconstf lconstf; /* out, NOTE: members to be free'd by user */ + uint8_t bumpenvmat_needed; + + struct { + struct nine_shader_constant_combination* c_combination; + bool (*int_const_added)[NINE_MAX_CONST_I]; + bool (*bool_const_added)[NINE_MAX_CONST_B]; + } add_constants_defs; + + bool swvp_on; + + bool process_vertices; + struct NineVertexDeclaration9 *vdecl_out; + struct pipe_stream_output_info so; +}; + +struct nine_vs_output_info +{ + BYTE output_semantic; + int output_semantic_index; + int mask; + int output_index; +}; + +void * +nine_create_shader_with_so_and_destroy(struct ureg_program *p, + struct pipe_context *pipe, + const struct pipe_stream_output_info *so); + +HRESULT +nine_translate_shader(struct NineDevice9 *device, + struct nine_shader_info *, + struct pipe_context *); + + +struct nine_shader_variant +{ + struct nine_shader_variant *next; + void *cso; + unsigned *const_ranges; + unsigned const_used_size; + uint64_t key; +}; + +static inline void * +nine_shader_variant_get(struct nine_shader_variant *list, + unsigned **const_ranges, + unsigned *const_used_size, + uint64_t key) +{ + while (list->key != key && list->next) + list = list->next; + if (list->key == key) { + *const_ranges = list->const_ranges; + *const_used_size = list->const_used_size; + return list->cso; + } + return NULL; +} + +static inline bool +nine_shader_variant_add(struct nine_shader_variant *list, + uint64_t key, void *cso, + unsigned *const_ranges, + unsigned const_used_size) +{ + 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; + list->next->const_ranges = const_ranges; + list->next->const_used_size = const_used_size; + 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); + } +} + +struct nine_shader_variant_so +{ + struct nine_shader_variant_so *next; + struct NineVertexDeclaration9 *vdecl; + struct pipe_stream_output_info so; + void *cso; +}; + +static inline void * +nine_shader_variant_so_get(struct nine_shader_variant_so *list, + struct NineVertexDeclaration9 *vdecl, + struct pipe_stream_output_info *so) +{ + while (list->vdecl != vdecl && list->next) + list = list->next; + if (list->vdecl == vdecl) { + *so = list->so; + return list->cso; + } + return NULL; +} + +static inline bool +nine_shader_variant_so_add(struct nine_shader_variant_so *list, + struct NineVertexDeclaration9 *vdecl, + struct pipe_stream_output_info *so, void *cso) +{ + if (list->vdecl == NULL) { /* first shader */ + list->next = NULL; + nine_bind(&list->vdecl, vdecl); + list->so = *so; + list->cso = cso; + return true; + } + while (list->next) { + assert(list->vdecl != vdecl); + list = list->next; + } + list->next = MALLOC_STRUCT(nine_shader_variant_so); + if (!list->next) + return false; + list->next->next = NULL; + nine_bind(&list->vdecl, vdecl); + list->next->so = *so; + list->next->cso = cso; + return true; +} + +static inline void +nine_shader_variants_so_free(struct nine_shader_variant_so *list) +{ + while (list->next) { + struct nine_shader_variant_so *ptr = list->next; + list->next = ptr->next; + nine_bind(&ptr->vdecl, NULL); + FREE(ptr); + } + if (list->vdecl) + nine_bind(&list->vdecl, NULL); +} + +struct nine_shader_constant_combination +{ + struct nine_shader_constant_combination *next; + int const_i[NINE_MAX_CONST_I][4]; + BOOL const_b[NINE_MAX_CONST_B]; +}; + +#define NINE_MAX_CONSTANT_COMBINATION_VARIANTS 32 + +static inline uint8_t +nine_shader_constant_combination_key(struct nine_shader_constant_combination **list, + bool *int_slots_used, + bool *bool_slots_used, + int *const_i, + BOOL *const_b) +{ + int i; + uint8_t index = 0; + bool match; + struct nine_shader_constant_combination **next_allocate = list, *current = *list; + + assert(int_slots_used); + assert(bool_slots_used); + assert(const_i); + assert(const_b); + + while (current) { + index++; /* start at 1. 0 is for the variant without constant replacement */ + match = true; + for (i = 0; i < NINE_MAX_CONST_I; ++i) { + if (int_slots_used[i]) + match &= !memcmp(const_i + 4*i, current->const_i[i], sizeof(current->const_i[0])); + } + for (i = 0; i < NINE_MAX_CONST_B; ++i) { + if (bool_slots_used[i]) + match &= const_b[i] == current->const_b[i]; + } + if (match) + return index; + next_allocate = ¤t->next; + current = current->next; + } + + if (index < NINE_MAX_CONSTANT_COMBINATION_VARIANTS) { + *next_allocate = MALLOC_STRUCT(nine_shader_constant_combination); + current = *next_allocate; + index++; + current->next = NULL; + memcpy(current->const_i, const_i, sizeof(current->const_i)); + memcpy(current->const_b, const_b, sizeof(current->const_b)); + return index; + } + + return 0; /* Too many variants, revert to no replacement */ +} + +static inline struct nine_shader_constant_combination * +nine_shader_constant_combination_get(struct nine_shader_constant_combination *list, uint8_t index) +{ + if (index == 0) + return NULL; + while (index) { + assert(list != NULL); + index--; + if (index == 0) + return list; + list = list->next; + } + assert(false); + return NULL; +} + +static inline void +nine_shader_constant_combination_free(struct nine_shader_constant_combination *list) +{ + if (!list) + return; + + while (list->next) { + struct nine_shader_constant_combination *ptr = list->next; + list->next = ptr->next; + FREE(ptr); + } + + FREE(list); +} + +/* Returns corresponding opposite test */ +static inline unsigned +pipe_comp_to_tgsi_opposite(BYTE flags) +{ + switch (flags) { + case PIPE_FUNC_GREATER: return TGSI_OPCODE_SLE; + case PIPE_FUNC_EQUAL: return TGSI_OPCODE_SNE; + case PIPE_FUNC_GEQUAL: return TGSI_OPCODE_SLT; + case PIPE_FUNC_LESS: return TGSI_OPCODE_SGE; + case PIPE_FUNC_NOTEQUAL: return TGSI_OPCODE_SEQ; + case PIPE_FUNC_LEQUAL: return TGSI_OPCODE_SGT; + default: + assert(!"invalid comparison flags"); + return TGSI_OPCODE_SGT; + } +} + +#endif /* _NINE_SHADER_H_ */ diff --git a/src/gallium/frontends/nine/nine_state.c b/src/gallium/frontends/nine/nine_state.c new file mode 100644 index 0000000..5be60cf --- /dev/null +++ b/src/gallium/frontends/nine/nine_state.c @@ -0,0 +1,3910 @@ +/* + * Copyright 2011 Joakim Sindholt + * Copyright 2013 Christoph Bumiller + * SPDX-License-Identifier: MIT + */ + +#define NINE_STATE + +#include "device9.h" +#include "swapchain9.h" +#include "basetexture9.h" +#include "buffer9.h" +#include "indexbuffer9.h" +#include "surface9.h" +#include "vertexbuffer9.h" +#include "vertexdeclaration9.h" +#include "vertexshader9.h" +#include "pixelshader9.h" +#include "nine_pipe.h" +#include "nine_ff.h" +#include "nine_limits.h" +#include "pipe/p_context.h" +#include "pipe/p_state.h" +#include "cso_cache/cso_context.h" +#include "util/u_atomic.h" +#include "util/u_upload_mgr.h" +#include "util/u_math.h" +#include "util/box.h" +#include "util/u_simple_shaders.h" +#include "util/u_gen_mipmap.h" + +/* CSMT headers */ +#include "nine_queue.h" +#include "nine_csmt_helper.h" +#include "util/u_thread.h" + +#define DBG_CHANNEL DBG_DEVICE + +/* Nine CSMT */ + +struct csmt_instruction { + int (* func)(struct NineDevice9 *This, struct csmt_instruction *instr); +}; + +struct csmt_context { + thrd_t worker; + struct nine_queue_pool* pool; + BOOL terminate; + cnd_t event_processed; + mtx_t mutex_processed; + struct NineDevice9 *device; + BOOL processed; + BOOL toPause; + BOOL hasPaused; + mtx_t thread_running; + mtx_t thread_resume; +}; + +/* Wait for instruction to be processed. + * Caller has to ensure that only one thread waits at time. + */ +static void +nine_csmt_wait_processed(struct csmt_context *ctx) +{ + mtx_lock(&ctx->mutex_processed); + while (!p_atomic_read(&ctx->processed)) { + cnd_wait(&ctx->event_processed, &ctx->mutex_processed); + } + mtx_unlock(&ctx->mutex_processed); +} + +/* CSMT worker thread */ +static +int +nine_csmt_worker(void *arg) +{ + struct csmt_context *ctx = arg; + struct csmt_instruction *instr; + DBG("CSMT worker spawned\n"); + + u_thread_setname("CSMT-Worker"); + + while (1) { + nine_queue_wait_flush(ctx->pool); + mtx_lock(&ctx->thread_running); + + /* Get instruction. NULL on empty cmdbuf. */ + while (!p_atomic_read(&ctx->terminate) && + (instr = (struct csmt_instruction *)nine_queue_get(ctx->pool))) { + + /* decode */ + if (instr->func(ctx->device, instr)) { + mtx_lock(&ctx->mutex_processed); + p_atomic_set(&ctx->processed, true); + cnd_signal(&ctx->event_processed); + mtx_unlock(&ctx->mutex_processed); + } + if (p_atomic_read(&ctx->toPause)) { + mtx_unlock(&ctx->thread_running); + /* will wait here the thread can be resumed */ + mtx_lock(&ctx->thread_resume); + mtx_lock(&ctx->thread_running); + mtx_unlock(&ctx->thread_resume); + } + } + + mtx_unlock(&ctx->thread_running); + if (p_atomic_read(&ctx->terminate)) { + mtx_lock(&ctx->mutex_processed); + p_atomic_set(&ctx->processed, true); + cnd_signal(&ctx->event_processed); + mtx_unlock(&ctx->mutex_processed); + break; + } + } + + DBG("CSMT worker destroyed\n"); + return 0; +} + +/* Create a CSMT context. + * Spawns a worker thread. + */ +struct csmt_context * +nine_csmt_create( struct NineDevice9 *This ) +{ + struct csmt_context *ctx; + + ctx = CALLOC_STRUCT(csmt_context); + if (!ctx) + return NULL; + + ctx->pool = nine_queue_create(); + if (!ctx->pool) { + FREE(ctx); + return NULL; + } + cnd_init(&ctx->event_processed); + (void) mtx_init(&ctx->mutex_processed, mtx_plain); + (void) mtx_init(&ctx->thread_running, mtx_plain); + (void) mtx_init(&ctx->thread_resume, mtx_plain); + +#if MESA_DEBUG || !defined(NDEBUG) + u_thread_setname("Main thread"); +#endif + + ctx->device = This; + + if (thrd_success != u_thread_create(&ctx->worker, nine_csmt_worker, ctx)) { + nine_queue_delete(ctx->pool); + FREE(ctx); + return NULL; + } + + DBG("Returning context %p\n", ctx); + + return ctx; +} + +static int +nop_func( struct NineDevice9 *This, struct csmt_instruction *instr ) +{ + (void) This; + (void) instr; + + return 1; +} + +/* Push nop instruction and flush the queue. + * Waits for the worker to complete. */ +void +nine_csmt_process( struct NineDevice9 *device ) +{ + struct csmt_instruction* instr; + struct csmt_context *ctx = device->csmt_ctx; + + if (!device->csmt_active) + return; + + if (nine_queue_isempty(ctx->pool)) + return; + + DBG("device=%p\n", device); + + /* NOP */ + instr = nine_queue_alloc(ctx->pool, sizeof(struct csmt_instruction)); + assert(instr); + instr->func = nop_func; + + p_atomic_set(&ctx->processed, false); + nine_queue_flush(ctx->pool); + + nine_csmt_wait_processed(ctx); +} + +void +nine_csmt_flush( struct NineDevice9* device ) +{ + if (!device->csmt_active) + return; + + nine_queue_flush(device->csmt_ctx->pool); +} + + +/* Destroys a CSMT context. + * Waits for the worker thread to terminate. + */ +void +nine_csmt_destroy( struct NineDevice9 *device, struct csmt_context *ctx ) +{ + struct csmt_instruction* instr; + thrd_t render_thread = ctx->worker; + + DBG("device=%p ctx=%p\n", device, ctx); + + /* Push nop and flush the queue. */ + instr = nine_queue_alloc(ctx->pool, sizeof(struct csmt_instruction)); + assert(instr); + instr->func = nop_func; + + p_atomic_set(&ctx->processed, false); + /* Signal worker to terminate. */ + p_atomic_set(&ctx->terminate, true); + nine_queue_flush(ctx->pool); + + nine_csmt_wait_processed(ctx); + nine_queue_delete(ctx->pool); + + mtx_destroy(&ctx->thread_resume); + mtx_destroy(&ctx->thread_running); + + mtx_destroy(&ctx->mutex_processed); + cnd_destroy(&ctx->event_processed); + + FREE(ctx); + + thrd_join(render_thread, NULL); +} + +static void +nine_csmt_pause( struct NineDevice9 *device ) +{ + struct csmt_context *ctx = device->csmt_ctx; + + if (!device->csmt_active) + return; + + /* No need to pause the thread */ + if (nine_queue_no_flushed_work(ctx->pool)) + return; + + mtx_lock(&ctx->thread_resume); + p_atomic_set(&ctx->toPause, true); + + /* Wait the thread is paused */ + mtx_lock(&ctx->thread_running); + ctx->hasPaused = true; + p_atomic_set(&ctx->toPause, false); +} + +static void +nine_csmt_resume( struct NineDevice9 *device ) +{ + struct csmt_context *ctx = device->csmt_ctx; + + if (!device->csmt_active) + return; + + if (!ctx->hasPaused) + return; + + ctx->hasPaused = false; + mtx_unlock(&ctx->thread_running); + mtx_unlock(&ctx->thread_resume); +} + +struct pipe_context * +nine_context_get_pipe( struct NineDevice9 *device ) +{ + nine_csmt_process(device); + return device->context.pipe; +} + +struct pipe_context * +nine_context_get_pipe_multithread( struct NineDevice9 *device ) +{ + struct csmt_context *ctx = device->csmt_ctx; + + if (!device->csmt_active) + return device->context.pipe; + + if (!u_thread_is_self(ctx->worker)) + nine_csmt_process(device); + + return device->context.pipe; +} + +struct pipe_context * +nine_context_get_pipe_acquire( struct NineDevice9 *device ) +{ + nine_csmt_pause(device); + return device->context.pipe; +} + +void +nine_context_get_pipe_release( struct NineDevice9 *device ) +{ + nine_csmt_resume(device); +} + +bool +nine_context_is_worker( struct NineDevice9 *device ) +{ + struct csmt_context *ctx = device->csmt_ctx; + + if (!device->csmt_active) + return false; + + return u_thread_is_self(ctx->worker); +} + +/* Nine state functions */ + +/* Check if some states need to be set dirty */ + +static inline DWORD +check_multisample(struct NineDevice9 *device) +{ + struct nine_context *context = &device->context; + DWORD *rs = context->rs; + struct NineSurface9 *rt0 = context->rt[0]; + bool multisampled_target; + DWORD new_value; + + multisampled_target = rt0 && rt0->desc.MultiSampleType >= 1; + if (rt0 && rt0->desc.Format == D3DFMT_NULL && context->ds) + multisampled_target = context->ds->desc.MultiSampleType >= 1; + new_value = (multisampled_target && rs[D3DRS_MULTISAMPLEANTIALIAS]) ? 1 : 0; + if (rs[NINED3DRS_MULTISAMPLE] != new_value) { + rs[NINED3DRS_MULTISAMPLE] = new_value; + return NINE_STATE_RASTERIZER; + } + return 0; +} + +/* State preparation only */ + +static inline void +prepare_blend(struct NineDevice9 *device) +{ + nine_convert_blend_state(&device->context.pipe_data.blend, device->context.rs); + device->context.commit |= NINE_STATE_COMMIT_BLEND; +} + +static inline void +prepare_dsa(struct NineDevice9 *device) +{ + nine_convert_dsa_state(&device->context.pipe_data.dsa, device->context.rs); + device->context.commit |= NINE_STATE_COMMIT_DSA; +} + +static inline void +prepare_rasterizer(struct NineDevice9 *device) +{ + nine_convert_rasterizer_state(device, &device->context.pipe_data.rast, device->context.rs); + device->context.commit |= NINE_STATE_COMMIT_RASTERIZER; +} + +/* Mesa 26.x: threaded_context artik kullanici sabit tamponlarini kendisi + * yuklemiyor (117ac6ac0a0, MR 36715 -- "drivers should set + * prefer_real_buffer_in_constbuf0"), tc_set_constant_buffer() icinde + * assert(!cb->user_buffer) var. Yukleme artik frontend'in isi. + * + * prepare_{vs,ps}_constants_userbuf() zaten gercek bir tampona yukluyordu; + * SWVP ve fixed-function yollari ise user_buffer'i oldugu gibi birakiyordu. + * Bu yardimci onlara ayni islemi yaptirir. + * + * Yalnizca HW pipe icin gerekli: pipe_sw (softpipe) threaded_context + * kullanmiyor ve prefer_real_buffer_in_constbuf0 vermiyor, oradaki + * user_buffer yollari oldugu gibi calisiyor. */ +void +nine_upload_constant_buffer(struct nine_context *context, + struct pipe_constant_buffer *dst, + const void *data, unsigned size) +{ + uint8_t *upload_ptr = NULL; + struct pipe_resource *buf = NULL; + unsigned offset = 0; + + u_upload_alloc_ref(context->pipe->const_uploader, 0, size, + 256, /* prepare_vs_constants_userbuf ile ayni */ + &offset, &buf, (void **)&upload_ptr); + assert(buf && upload_ptr); + memcpy(upload_ptr, data, size); + u_upload_unmap(context->pipe->const_uploader); + + /* onceki kaynagi birak; nine_context CALLOC'lu, ilk cagrida NULL */ + pipe_resource_reference(&dst->buffer, NULL); + dst->buffer = buf; /* u_upload_alloc_ref zaten ref aldi */ + dst->buffer_offset = offset; + dst->buffer_size = size; + dst->user_buffer = NULL; +} + +static void +prepare_vs_constants_userbuf_swvp(struct NineDevice9 *device) +{ + struct nine_context *context = &device->context; + + if (device->driver_caps.emulate_ucp) { + /* TODO: Avoid memcpy all time by storing directly into the array */ + memcpy(&context->vs_const_f[4 * NINE_MAX_CONST_SWVP_SPE_OFFSET], &context->clip.ucp, sizeof(context->clip)); + context->changed.vs_const_f = 1; /* TODO optimize */ + } + + if (device->driver_caps.always_output_pointsize) { + context->vs_const_f[4 * (NINE_MAX_CONST_SWVP_SPE_OFFSET + 8)] = + CLAMP(asfloat(context->rs[D3DRS_POINTSIZE]), + asfloat(context->rs[D3DRS_POINTSIZE_MIN]), + asfloat(context->rs[D3DRS_POINTSIZE_MAX])); + context->changed.vs_const_f = 1; /* TODO optimize */ + } + + if (context->changed.vs_const_f || context->changed.group & NINE_STATE_SWVP) { + struct pipe_constant_buffer cb; + + cb.buffer_offset = 0; + cb.buffer_size = 4096 * sizeof(float[4]); + cb.user_buffer = context->vs_const_f_swvp; + + if (context->vs->lconstf.ranges) { + const struct nine_lconstf *lconstf = &(context->vs->lconstf); + const struct nine_range *r = lconstf->ranges; + unsigned n = 0; + float *dst = context->vs_lconstf_temp; + 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; + } + + nine_upload_constant_buffer(context, &context->pipe_data.cb0_swvp, + cb.user_buffer, cb.buffer_size); + + cb.user_buffer = (int8_t *)cb.user_buffer + 4096 * sizeof(float[4]); + nine_upload_constant_buffer(context, &context->pipe_data.cb1_swvp, + cb.user_buffer, cb.buffer_size); + + context->changed.vs_const_f = 0; + } + + if (context->changed.vs_const_i || context->changed.group & NINE_STATE_SWVP) { + struct pipe_constant_buffer cb; + + cb.buffer_offset = 0; + cb.buffer_size = 2048 * sizeof(float[4]); + cb.user_buffer = context->vs_const_i; + + nine_upload_constant_buffer(context, &context->pipe_data.cb2_swvp, + cb.user_buffer, cb.buffer_size); + context->changed.vs_const_i = 0; + } + + if (context->changed.vs_const_b || context->changed.group & NINE_STATE_SWVP) { + struct pipe_constant_buffer cb; + + cb.buffer_offset = 0; + cb.buffer_size = 512 * sizeof(float[4]); + cb.user_buffer = context->vs_const_b; + + nine_upload_constant_buffer(context, &context->pipe_data.cb3_swvp, + cb.user_buffer, cb.buffer_size); + context->changed.vs_const_b = 0; + } + + context->changed.group &= ~NINE_STATE_VS_CONST; + context->commit |= NINE_STATE_COMMIT_CONST_VS; +} + +static void +prepare_vs_constants_userbuf(struct NineDevice9 *device) +{ + struct nine_context *context = &device->context; + uint8_t *upload_ptr = NULL; + struct pipe_constant_buffer cb; + cb.buffer = NULL; + cb.buffer_offset = 0; + cb.buffer_size = context->cso_shader.vs_const_used_size; + cb.user_buffer = context->vs_const_f; + + if (context->swvp) { + prepare_vs_constants_userbuf_swvp(device); + return; + } + + if (device->driver_caps.emulate_ucp) { + /* TODO: Avoid memcpy all time by storing directly into the array */ + memcpy(&context->vs_const_f[4 * NINE_MAX_CONST_VS_SPE_OFFSET], &context->clip.ucp, sizeof(context->clip)); + } + if (device->driver_caps.always_output_pointsize) { + context->vs_const_f[4 * (NINE_MAX_CONST_VS_SPE_OFFSET + 8)] = + CLAMP(asfloat(context->rs[D3DRS_POINTSIZE]), + asfloat(context->rs[D3DRS_POINTSIZE_MIN]), + asfloat(context->rs[D3DRS_POINTSIZE_MAX])); + } + + if (context->changed.vs_const_i || context->changed.group & NINE_STATE_SWVP) { + int *idst = (int *)&context->vs_const_f[4 * device->max_vs_const_f]; + memcpy(idst, context->vs_const_i, NINE_MAX_CONST_I * sizeof(int[4])); + context->changed.vs_const_i = 0; + } + + if (context->changed.vs_const_b || context->changed.group & NINE_STATE_SWVP) { + int *idst = (int *)&context->vs_const_f[4 * device->max_vs_const_f]; + uint32_t *bdst = (uint32_t *)&idst[4 * NINE_MAX_CONST_I]; + memcpy(bdst, context->vs_const_b, NINE_MAX_CONST_B * sizeof(BOOL)); + context->changed.vs_const_b = 0; + } + + if (!cb.buffer_size) + return; + + if (context->vs->lconstf.ranges) { + /* TODO: Can we make it so that we don't have to copy everything ? */ + const struct nine_lconstf *lconstf = &(context->vs->lconstf); + const struct nine_range *r = lconstf->ranges; + unsigned n = 0; + float *dst = context->vs_lconstf_temp; + 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; + } + + /* Note: We probably don't want to do separate memcpy to + * upload_ptr directly, if we have to copy some constants + * at random locations (context->vs->lconstf.ranges), + * to have efficient WC. Thus for this case we really want + * that intermediate buffer. */ + + u_upload_alloc_ref(context->pipe->const_uploader, + 0, + cb.buffer_size, + 256, /* Be conservative about alignment */ + &(cb.buffer_offset), + &(cb.buffer), + (void**)&upload_ptr); + + assert(cb.buffer && upload_ptr); + + if (!context->cso_shader.vs_const_ranges) { + memcpy(upload_ptr, cb.user_buffer, cb.buffer_size); + } else { + unsigned i = 0; + unsigned offset = 0; + while (context->cso_shader.vs_const_ranges[i*2+1] != 0) { + memcpy(upload_ptr+offset, + &((float*)cb.user_buffer)[4*context->cso_shader.vs_const_ranges[i*2]], + context->cso_shader.vs_const_ranges[i*2+1] * sizeof(float[4])); + offset += context->cso_shader.vs_const_ranges[i*2+1] * sizeof(float[4]); + i++; + } + } + + u_upload_unmap(context->pipe->const_uploader); + cb.user_buffer = NULL; + + /* Free previous resource */ + pipe_resource_reference(&context->pipe_data.cb_vs.buffer, NULL); + + context->pipe_data.cb_vs = cb; + context->changed.vs_const_f = 0; + + context->changed.group &= ~NINE_STATE_VS_CONST; + context->commit |= NINE_STATE_COMMIT_CONST_VS; +} + +static void +prepare_ps_constants_userbuf(struct NineDevice9 *device) +{ + struct nine_context *context = &device->context; + uint8_t *upload_ptr = NULL; + struct pipe_constant_buffer cb; + cb.buffer = NULL; + cb.buffer_offset = 0; + cb.buffer_size = context->cso_shader.ps_const_used_size; + cb.user_buffer = context->ps_const_f; + + if (context->changed.ps_const_i) { + int *idst = (int *)&context->ps_const_f[4 * NINE_MAX_CONST_F_PS3]; + memcpy(idst, context->ps_const_i, sizeof(context->ps_const_i)); + context->changed.ps_const_i = 0; + } + if (context->changed.ps_const_b) { + int *idst = (int *)&context->ps_const_f[4 * NINE_MAX_CONST_F_PS3]; + uint32_t *bdst = (uint32_t *)&idst[4 * NINE_MAX_CONST_I]; + memcpy(bdst, context->ps_const_b, sizeof(context->ps_const_b)); + context->changed.ps_const_b = 0; + } + + /* Upload special constants needed to implement PS1.x instructions like TEXBEM,TEXBEML and BEM */ + if (context->ps->bumpenvmat_needed) + memcpy(&context->ps_const_f[4 * NINE_MAX_CONST_PS_SPE_OFFSET], &device->context.bumpmap_vars, sizeof(device->context.bumpmap_vars)); + + if (context->ps->byte_code.version < 0x30 && + context->rs[D3DRS_FOGENABLE]) { + float *dst = &context->ps_const_f[4 * (NINE_MAX_CONST_PS_SPE_OFFSET + 12)]; + + d3dcolor_to_rgba(dst, context->rs[D3DRS_FOGCOLOR]); + if (context->rs[D3DRS_FOGTABLEMODE] == D3DFOG_LINEAR) { + dst[4] = asfloat(context->rs[D3DRS_FOGEND]); + dst[5] = 1.0f / (asfloat(context->rs[D3DRS_FOGEND]) - asfloat(context->rs[D3DRS_FOGSTART])); + } else if (context->rs[D3DRS_FOGTABLEMODE] != D3DFOG_NONE) { + dst[4] = asfloat(context->rs[D3DRS_FOGDENSITY]); + } + } + + context->ps_const_f[4 * (NINE_MAX_CONST_PS_SPE_OFFSET + 14)] = context->rs[D3DRS_ALPHAREF] / 255.f; + + if (!cb.buffer_size) + return; + + u_upload_alloc_ref(context->pipe->const_uploader, + 0, + cb.buffer_size, + 256, /* Be conservative about alignment */ + &(cb.buffer_offset), + &(cb.buffer), + (void**)&upload_ptr); + + assert(cb.buffer && upload_ptr); + + if (!context->cso_shader.ps_const_ranges) { + memcpy(upload_ptr, cb.user_buffer, cb.buffer_size); + } else { + unsigned i = 0; + unsigned offset = 0; + while (context->cso_shader.ps_const_ranges[i*2+1] != 0) { + memcpy(upload_ptr+offset, + &((float*)cb.user_buffer)[4*context->cso_shader.ps_const_ranges[i*2]], + context->cso_shader.ps_const_ranges[i*2+1] * sizeof(float[4])); + offset += context->cso_shader.ps_const_ranges[i*2+1] * sizeof(float[4]); + i++; + } + } + + u_upload_unmap(context->pipe->const_uploader); + cb.user_buffer = NULL; + + /* Free previous resource */ + pipe_resource_reference(&context->pipe_data.cb_ps.buffer, NULL); + + context->pipe_data.cb_ps = cb; + context->changed.ps_const_f = 0; + + context->changed.group &= ~NINE_STATE_PS_CONST; + context->commit |= NINE_STATE_COMMIT_CONST_PS; +} + +static inline uint32_t +prepare_vs(struct NineDevice9 *device, uint8_t shader_changed) +{ + struct nine_context *context = &device->context; + struct NineVertexShader9 *vs = context->vs; + uint32_t changed_group = 0; + int has_key_changed = 0; + + if (likely(context->programmable_vs)) + has_key_changed = NineVertexShader9_UpdateKey(vs, device); + + if (!shader_changed && !has_key_changed) + return 0; + + /* likely because we dislike FF */ + if (likely(context->programmable_vs)) { + context->cso_shader.vs = NineVertexShader9_GetVariant(vs, + &context->cso_shader.vs_const_ranges, + &context->cso_shader.vs_const_used_size); + } else { + vs = device->ff.vs; + context->cso_shader.vs = vs->ff_cso; + } + + if (context->rs[NINED3DRS_VSPOINTSIZE] != vs->point_size) { + context->rs[NINED3DRS_VSPOINTSIZE] = vs->point_size; + changed_group |= NINE_STATE_RASTERIZER; + } + if (context->rs[NINED3DRS_POSITIONT] != vs->position_t) { + context->rs[NINED3DRS_POSITIONT] = vs->position_t; + if (!device->driver_caps.window_space_position_support && + device->driver_caps.disabling_depth_clipping_support) + changed_group |= NINE_STATE_RASTERIZER; + } + + if ((context->bound_samplers_mask_vs & vs->sampler_mask) != vs->sampler_mask) + /* Bound dummy sampler. */ + changed_group |= NINE_STATE_SAMPLER; + + context->commit |= NINE_STATE_COMMIT_VS; + return changed_group; +} + +static inline uint32_t +prepare_ps(struct NineDevice9 *device, uint8_t shader_changed) +{ + struct nine_context *context = &device->context; + struct NinePixelShader9 *ps = context->ps; + uint32_t changed_group = 0; + int has_key_changed = 0; + + if (likely(ps)) + has_key_changed = NinePixelShader9_UpdateKey(ps, context); + + if (!shader_changed && !has_key_changed) + return 0; + + if (likely(ps)) { + context->cso_shader.ps = NinePixelShader9_GetVariant(ps, + &context->cso_shader.ps_const_ranges, + &context->cso_shader.ps_const_used_size); + } else { + ps = device->ff.ps; + context->cso_shader.ps = ps->ff_cso; + } + + if ((context->bound_samplers_mask_ps & ps->sampler_mask) != ps->sampler_mask) + /* Bound dummy sampler. */ + changed_group |= NINE_STATE_SAMPLER; + + context->commit |= NINE_STATE_COMMIT_PS; + return changed_group; +} + +/* State preparation incremental */ + +/* State preparation + State commit */ + +static void +update_framebuffer(struct NineDevice9 *device, bool is_clear) +{ + struct nine_context *context = &device->context; + struct pipe_context *pipe = context->pipe; + struct pipe_framebuffer_state *fb = &context->pipe_data.fb; + unsigned i; + struct NineSurface9 *rt0 = context->rt[0]; + unsigned w = rt0->desc.Width; + unsigned h = rt0->desc.Height; + unsigned nr_samples = rt0->base.info.nr_samples; + unsigned ps_mask = context->ps ? context->ps->rt_mask : 1; + unsigned mask = is_clear ? 0xf : ps_mask; + const int sRGB = context->rs[D3DRS_SRGBWRITEENABLE] ? 1 : 0; + + DBG("\n"); + + context->rt_mask = 0x0; + fb->nr_cbufs = 0; + + /* all render targets must have the same size and the depth buffer must be + * bigger. Multisample has to match, according to spec. But some apps do + * things wrong there, and no error is returned. The behaviour they get + * apparently is that depth buffer is disabled if it doesn't match. + * Surely the same for render targets. */ + + /* Special case: D3DFMT_NULL is used to bound no real render target, + * but render to depth buffer. We have to not take into account the render + * target info. TODO: know what should happen when there are several render targets + * and the first one is D3DFMT_NULL */ + if (rt0->desc.Format == D3DFMT_NULL && context->ds) { + w = context->ds->desc.Width; + h = context->ds->desc.Height; + nr_samples = context->ds->base.info.nr_samples; + } + + for (i = 0; i < device->caps.NumSimultaneousRTs; ++i) { + struct NineSurface9 *rt = context->rt[i]; + + if (rt && rt->desc.Format != D3DFMT_NULL && (mask & (1 << i)) && + rt->desc.Width == w && rt->desc.Height == h && + rt->base.info.nr_samples == nr_samples) { + fb->cbufs[i] = *NineSurface9_GetSurface(rt, sRGB); + context->rt_mask |= 1 << i; + fb->nr_cbufs = i + 1; + } else { + /* Color outputs must match RT slot, + * drivers will have to handle NULL entries for GL, too. + */ + memset(&fb->cbufs[i], 0, sizeof(fb->cbufs[0])); + } + } + + if (context->ds && context->ds->desc.Width >= w && + context->ds->desc.Height >= h && + context->ds->base.info.nr_samples == nr_samples) { + fb->zsbuf = *NineSurface9_GetSurface(context->ds, 0); + } else { + memset(&fb->zsbuf, 0, sizeof(fb->zsbuf)); + } + + fb->width = w; + fb->height = h; + + pipe->set_framebuffer_state(pipe, fb); /* XXX: cso ? */ + + if (is_clear && context->rt_mask == ps_mask) + context->changed.group &= ~NINE_STATE_FB; +} + +static void +update_viewport(struct NineDevice9 *device) +{ + struct nine_context *context = &device->context; + const D3DVIEWPORT9 *vport = &context->viewport; + struct pipe_viewport_state pvport; + + /* D3D coordinates are: + * -1 .. +1 for X,Y and + * 0 .. +1 for Z (we 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.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.swizzle_x = PIPE_VIEWPORT_SWIZZLE_POSITIVE_X; + pvport.swizzle_y = PIPE_VIEWPORT_SWIZZLE_POSITIVE_Y; + pvport.swizzle_z = PIPE_VIEWPORT_SWIZZLE_POSITIVE_Z; + pvport.swizzle_w = PIPE_VIEWPORT_SWIZZLE_POSITIVE_W; + + /* We found R600 and SI cards have some imprecision + * on the barycentric coordinates used for interpolation. + * Some shaders rely on having something precise. + * We found that the proprietary driver has the imprecision issue, + * except when the render target width and height are powers of two. + * It is using some sort of workaround for these cases + * which covers likely all the cases the applications rely + * on something precise. + * We haven't found the workaround, but it seems like it's better + * for applications if the imprecision is biased towards infinity + * instead of -infinity (which is what measured). So shift slightly + * the viewport: not enough to change rasterization result (in particular + * for multisampling), but enough to make the imprecision biased + * towards infinity. We do this shift only if render target width and + * height are powers of two. + * Solves 'red shadows' bug on UE3 games. + */ + if (device->driver_bugs.buggy_barycentrics && + ((vport->Width & (vport->Width-1)) == 0) && + ((vport->Height & (vport->Height-1)) == 0)) { + pvport.translate[0] -= 1.0f / 128.0f; + pvport.translate[1] -= 1.0f / 128.0f; + } + + cso_set_viewport(context->cso, &pvport); +} + +/* 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_context *context = &device->context; + const struct NineVertexDeclaration9 *vdecl = device->context.vdecl; + const struct NineVertexShader9 *vs; + unsigned n, b, i; + int index; + int8_t vdecl_index_map[16]; /* vs->num_inputs <= 16 */ + uint16_t used_streams = 0; + int dummy_vbo_stream = -1; + BOOL need_dummy_vbo = false; + struct cso_velems_state ve; + unsigned vtxbuf_mask; + unsigned vtxbuf_holes_map[PIPE_MAX_ATTRIBS]; + + context->stream_usage_mask = 0; + memset(vdecl_index_map, -1, 16); + vs = context->programmable_vs ? context->vs : device->ff.vs; + + if (vdecl) { + 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); + + for (i = 0; i < vdecl->nelems; i++) { + if (vdecl->usage_map[i] == vs->input_map[n].ndecl) { + vdecl_index_map[n] = i; + used_streams |= BITFIELD_BIT(vdecl->elems[i].vertex_buffer_index); + break; + } + } + if (vdecl_index_map[n] < 0) + need_dummy_vbo = true; + } + } else { + /* No vertex declaration. Likely will never happen in practice, + * but we need not crash on this */ + need_dummy_vbo = true; + } + + if (need_dummy_vbo) { + u_foreach_bit(bit, BITFIELD_MASK(device->caps.MaxStreams) & ~used_streams) { + dummy_vbo_stream = bit; + break; + } + } + /* there are fewer vertex shader inputs than stream slots, + * so if we need a slot for the dummy vbo, we should have found one */ + assert (!need_dummy_vbo || dummy_vbo_stream != -1); + + /* calculate vtxbuf_holes_map to match for update_vertex_buffers() function */ + i = 0; + vtxbuf_mask = context->vtxbuf_mask | + (need_dummy_vbo ? BITFIELD_BIT(dummy_vbo_stream) : 0); + u_foreach_bit(bit, vtxbuf_mask) + vtxbuf_holes_map[bit] = i++; + + context->num_vertex_buffers = 0; + + for (n = 0; n < vs->num_inputs; ++n) { + index = vdecl_index_map[n]; + if (index >= 0) { + ve.velems[n] = vdecl->elems[index]; + b = ve.velems[n].vertex_buffer_index; + ve.velems[n].vertex_buffer_index = vtxbuf_holes_map[b]; + ve.velems[n].src_stride = context->vtxstride[b]; + context->stream_usage_mask |= 1 << b; + /* XXX wine just uses 1 here: */ + if (context->stream_freq[b] & D3DSTREAMSOURCE_INSTANCEDATA) + ve.velems[n].instance_divisor = context->stream_freq[b] & 0x7FFFFF; + } else { + /* if the vertex declaration is incomplete compared to what the + * vertex shader needs, we bind a dummy vbo with 0 0 0 0. + * This is not precised by the spec, but is the behaviour + * tested on win */ + ve.velems[n].vertex_buffer_index = vtxbuf_holes_map[dummy_vbo_stream]; + ve.velems[n].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT; + ve.velems[n].src_offset = 0; + ve.velems[n].src_stride = 0; + ve.velems[n].instance_divisor = 0; + ve.velems[n].dual_slot = false; + } + context->num_vertex_buffers = MAX2(context->num_vertex_buffers, + ve.velems[n].vertex_buffer_index + 1); + } + + if (context->dummy_vbo_bound_at != dummy_vbo_stream) { + if (context->dummy_vbo_bound_at >= 0) + context->changed.vtxbuf_dirty = true; + if (dummy_vbo_stream >= 0) + context->changed.vtxbuf_dirty = true; + context->dummy_vbo_bound_at = dummy_vbo_stream; + } + + ve.count = vs->num_inputs; + cso_set_vertex_elements(context->cso, &ve); +} + +static void +update_vertex_buffers(struct NineDevice9 *device) +{ + struct nine_context *context = &device->context; + struct pipe_context *pipe = context->pipe; + struct pipe_vertex_buffer vbuffer[PIPE_MAX_ATTRIBS]; + unsigned num_vertex_buffers = context->num_vertex_buffers; + unsigned mask, i, vtxbuf_i; + + mask = context->vtxbuf_mask | + ((context->dummy_vbo_bound_at >= 0) ? BITFIELD_BIT(context->dummy_vbo_bound_at) : 0); + + DBG("mask=%x\n", mask); + for (i = 0; mask; i++) { + vtxbuf_i = u_bit_scan(&mask); + if (vtxbuf_i == context->dummy_vbo_bound_at) { + vbuffer[i].buffer.resource = device->dummy_vbo; + vbuffer[i].is_user_buffer = false; + vbuffer[i].buffer_offset = 0; + } else { + memcpy(&vbuffer[i], &context->vtxbuf[vtxbuf_i], sizeof(struct pipe_vertex_buffer)); + } + } + + /* Gallium requires that we bind exactly the number of vertex buffers that's + * used by vertex elements. + */ + if (i < num_vertex_buffers) + memset(&vbuffer[i], 0, sizeof(vbuffer[i]) * (num_vertex_buffers - i)); + + if (num_vertex_buffers) + pipe->set_vertex_buffers(pipe, num_vertex_buffers, vbuffer); + else + pipe->set_vertex_buffers(pipe, 0, NULL); + + context->changed.vtxbuf_dirty = false; +} + +static inline bool +update_sampler_derived(struct nine_context *context, unsigned s) +{ + bool changed = false; + + if (context->samp[s][NINED3DSAMP_SHADOW] != context->texture[s].shadow) { + changed = true; + context->samp[s][NINED3DSAMP_SHADOW] = context->texture[s].shadow; + } + + if (context->samp[s][NINED3DSAMP_CUBETEX] != + (context->texture[s].type == D3DRTYPE_CUBETEXTURE)) { + changed = true; + context->samp[s][NINED3DSAMP_CUBETEX] = + context->texture[s].type == D3DRTYPE_CUBETEXTURE; + } + + if (context->samp[s][D3DSAMP_MIPFILTER] != D3DTEXF_NONE) { + int lod = context->samp[s][D3DSAMP_MAXMIPLEVEL] - context->texture[s].lod; + if (lod < 0) + lod = 0; + if (context->samp[s][NINED3DSAMP_MINLOD] != lod) { + changed = true; + context->samp[s][NINED3DSAMP_MINLOD] = lod; + } + } else { + context->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 nine_context *context = &device->context; + struct pipe_context *pipe = context->pipe; + struct pipe_sampler_view *view[NINE_MAX_SAMPLERS]; + unsigned num_textures = 0; + bool commit_samplers; + uint16_t sampler_mask = context->ps ? context->ps->sampler_mask : + device->ff.ps->sampler_mask; + + commit_samplers = false; + const uint16_t ps_mask = sampler_mask | context->enabled_samplers_mask_ps; + context->bound_samplers_mask_ps = ps_mask; + num_textures = util_last_bit(ps_mask); + /* iterate over the enabled samplers */ + u_foreach_bit(i, context->enabled_samplers_mask_ps) { + const unsigned s = NINE_SAMPLER_PS(i); + int sRGB = context->samp[s][D3DSAMP_SRGBTEXTURE] ? 1 : 0; + + view[i] = context->texture[s].view[sRGB]; + + if (update_sampler_derived(context, s) || (context->changed.sampler[s] & 0x05fe)) { + context->changed.sampler[s] = 0; + commit_samplers = true; + nine_convert_sampler_state(context->cso, s, context->samp[s]); + } + } + /* iterate over the dummy samplers */ + u_foreach_bit(i, sampler_mask & ~context->enabled_samplers_mask_ps) { + const unsigned s = NINE_SAMPLER_PS(i); + /* Bind dummy sampler. We do not bind dummy sampler when + * it is not needed because it could add overhead. The + * dummy sampler should have r=g=b=0 and a=1. We do not + * unbind dummy sampler directly when they are not needed + * anymore, but they're going to be removed as long as texture + * or sampler states are changed. */ + view[i] = device->dummy_sampler_view; + + cso_single_sampler(context->cso, MESA_SHADER_FRAGMENT, + s - NINE_SAMPLER_PS(0), &device->dummy_sampler_state); + + commit_samplers = true; + context->changed.sampler[s] = ~0; + } + /* fill in unused samplers */ + u_foreach_bit(i, BITFIELD_MASK(num_textures) & ~ps_mask) + view[i] = NULL; + + pipe->set_sampler_views(pipe, MESA_SHADER_FRAGMENT, 0, num_textures, + num_textures < context->enabled_sampler_count_ps ? context->enabled_sampler_count_ps - num_textures : 0, + view); + context->enabled_sampler_count_ps = num_textures; + + if (commit_samplers) + cso_single_sampler_done(context->cso, MESA_SHADER_FRAGMENT); + + commit_samplers = false; + sampler_mask = context->programmable_vs ? context->vs->sampler_mask : 0; + const uint16_t vs_mask = sampler_mask | context->enabled_samplers_mask_vs; + context->bound_samplers_mask_vs = vs_mask; + num_textures = util_last_bit(vs_mask); + u_foreach_bit(i, context->enabled_samplers_mask_vs) { + const unsigned s = NINE_SAMPLER_VS(i); + int sRGB = context->samp[s][D3DSAMP_SRGBTEXTURE] ? 1 : 0; + + view[i] = context->texture[s].view[sRGB]; + + if (update_sampler_derived(context, s) || (context->changed.sampler[s] & 0x05fe)) { + context->changed.sampler[s] = 0; + commit_samplers = true; + nine_convert_sampler_state(context->cso, s, context->samp[s]); + } + } + u_foreach_bit(i, sampler_mask & ~context->enabled_samplers_mask_vs) { + const unsigned s = NINE_SAMPLER_VS(i); + /* Bind dummy sampler. We do not bind dummy sampler when + * it is not needed because it could add overhead. The + * dummy sampler should have r=g=b=0 and a=1. We do not + * unbind dummy sampler directly when they are not needed + * anymore, but they're going to be removed as long as texture + * or sampler states are changed. */ + view[i] = device->dummy_sampler_view; + + cso_single_sampler(context->cso, MESA_SHADER_VERTEX, + s - NINE_SAMPLER_VS(0), &device->dummy_sampler_state); + + commit_samplers = true; + context->changed.sampler[s] = ~0; + } + /* fill in unused samplers */ + u_foreach_bit(i, BITFIELD_MASK(num_textures) & ~vs_mask) + view[i] = NULL; + + pipe->set_sampler_views(pipe, MESA_SHADER_VERTEX, 0, num_textures, + num_textures < context->enabled_sampler_count_vs ? context->enabled_sampler_count_vs - num_textures : 0, + view); + context->enabled_sampler_count_vs = num_textures; + + if (commit_samplers) + cso_single_sampler_done(context->cso, MESA_SHADER_VERTEX); +} + +/* State commit only */ + +static inline void +commit_blend(struct NineDevice9 *device) +{ + struct nine_context *context = &device->context; + + cso_set_blend(context->cso, &context->pipe_data.blend); +} + +static inline void +commit_dsa(struct NineDevice9 *device) +{ + struct nine_context *context = &device->context; + + cso_set_depth_stencil_alpha(context->cso, &context->pipe_data.dsa); +} + +static inline void +commit_scissor(struct NineDevice9 *device) +{ + struct nine_context *context = &device->context; + struct pipe_context *pipe = context->pipe; + + pipe->set_scissor_states(pipe, 0, 1, &context->scissor); +} + +static inline void +commit_rasterizer(struct NineDevice9 *device) +{ + struct nine_context *context = &device->context; + + cso_set_rasterizer(context->cso, &context->pipe_data.rast); +} + +static inline void +commit_vs_constants(struct NineDevice9 *device) +{ + struct nine_context *context = &device->context; + struct pipe_context *pipe = context->pipe; + + if (unlikely(!context->programmable_vs)) + pipe->set_constant_buffer(pipe, MESA_SHADER_VERTEX, 0, &context->pipe_data.cb_vs_ff); + else { + if (context->swvp) { + pipe->set_constant_buffer(pipe, MESA_SHADER_VERTEX, 0, &context->pipe_data.cb0_swvp); + pipe->set_constant_buffer(pipe, MESA_SHADER_VERTEX, 1, &context->pipe_data.cb1_swvp); + pipe->set_constant_buffer(pipe, MESA_SHADER_VERTEX, 2, &context->pipe_data.cb2_swvp); + pipe->set_constant_buffer(pipe, MESA_SHADER_VERTEX, 3, &context->pipe_data.cb3_swvp); + } else { + pipe->set_constant_buffer(pipe, MESA_SHADER_VERTEX, 0, &context->pipe_data.cb_vs); + } + } +} + +static inline void +commit_ps_constants(struct NineDevice9 *device) +{ + struct nine_context *context = &device->context; + struct pipe_context *pipe = context->pipe; + + if (unlikely(!context->ps)) + pipe->set_constant_buffer(pipe, MESA_SHADER_FRAGMENT, 0, &context->pipe_data.cb_ps_ff); + else + pipe->set_constant_buffer(pipe, MESA_SHADER_FRAGMENT, 0, &context->pipe_data.cb_ps); +} + +static inline void +commit_vs(struct NineDevice9 *device) +{ + struct nine_context *context = &device->context; + assert(context->cso_shader.vs); + + context->pipe->bind_vs_state(context->pipe, context->cso_shader.vs); +} + + +static inline void +commit_ps(struct NineDevice9 *device) +{ + struct nine_context *context = &device->context; + + context->pipe->bind_fs_state(context->pipe, context->cso_shader.ps); +} +/* State Update */ + +#define NINE_STATE_SHADER_CHANGE_VS \ + (NINE_STATE_VS | \ + NINE_STATE_TEXTURE | \ + NINE_STATE_VS_PARAMS_MISC | \ + NINE_STATE_SWVP) + +#define NINE_STATE_SHADER_CHANGE_PS \ + (NINE_STATE_PS | \ + NINE_STATE_TEXTURE | \ + NINE_STATE_PS_PARAMS_MISC) + +#define NINE_STATE_FREQUENT \ + (NINE_STATE_RASTERIZER | \ + NINE_STATE_TEXTURE | \ + NINE_STATE_SAMPLER | \ + NINE_STATE_VS_CONST | \ + NINE_STATE_PS_CONST | \ + NINE_STATE_MULTISAMPLE) + +#define NINE_STATE_COMMON \ + (NINE_STATE_FB | \ + NINE_STATE_BLEND | \ + NINE_STATE_DSA | \ + NINE_STATE_VIEWPORT | \ + NINE_STATE_VDECL | \ + NINE_STATE_IDXBUF | \ + NINE_STATE_STREAMFREQ) + +#define NINE_STATE_RARE \ + (NINE_STATE_SCISSOR | \ + NINE_STATE_BLEND_COLOR | \ + NINE_STATE_STENCIL_REF | \ + NINE_STATE_SAMPLE_MASK) + +static void +nine_update_state(struct NineDevice9 *device) +{ + struct nine_context *context = &device->context; + struct pipe_context *pipe = context->pipe; + uint32_t group; + + DBG("changed state groups: %x\n", context->changed.group); + + /* 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. + */ + + /* ff_update may change VS/PS dirty bits */ + if (unlikely(!context->programmable_vs || !context->ps)) + nine_ff_update(device); + group = context->changed.group; + + if (group & (NINE_STATE_SHADER_CHANGE_VS | NINE_STATE_SHADER_CHANGE_PS)) { + if (group & NINE_STATE_SHADER_CHANGE_VS) + group |= prepare_vs(device, (group & NINE_STATE_VS) != 0); /* may set NINE_STATE_RASTERIZER and NINE_STATE_SAMPLER*/ + if (group & NINE_STATE_SHADER_CHANGE_PS) + group |= prepare_ps(device, (group & NINE_STATE_PS) != 0); + } + + if (group & (NINE_STATE_COMMON | NINE_STATE_VS)) { + if (group & NINE_STATE_FB) + update_framebuffer(device, false); + if (group & NINE_STATE_BLEND) + prepare_blend(device); + if (group & NINE_STATE_DSA) + prepare_dsa(device); + if (group & NINE_STATE_VIEWPORT) + update_viewport(device); + if (group & (NINE_STATE_VDECL | NINE_STATE_VS | NINE_STATE_STREAMFREQ)) { + update_vertex_elements(device); + context->changed.vtxbuf_dirty = true; + } + } + + if (likely(group & (NINE_STATE_FREQUENT | NINE_STATE_VS | NINE_STATE_PS | NINE_STATE_SWVP))) { + if (group & NINE_STATE_MULTISAMPLE) + group |= check_multisample(device); + if (group & NINE_STATE_RASTERIZER) + prepare_rasterizer(device); + if (group & (NINE_STATE_TEXTURE | NINE_STATE_SAMPLER)) + update_textures_and_samplers(device); + if ((group & (NINE_STATE_VS_CONST | NINE_STATE_VS | NINE_STATE_SWVP)) && context->programmable_vs) + prepare_vs_constants_userbuf(device); + if ((group & (NINE_STATE_PS_CONST | NINE_STATE_PS)) && context->ps) + prepare_ps_constants_userbuf(device); + } + + if (context->changed.vtxbuf_dirty) + update_vertex_buffers(device); + + if (context->commit & NINE_STATE_COMMIT_BLEND) + commit_blend(device); + if (context->commit & NINE_STATE_COMMIT_DSA) + commit_dsa(device); + if (context->commit & NINE_STATE_COMMIT_RASTERIZER) + commit_rasterizer(device); + if (context->commit & NINE_STATE_COMMIT_CONST_VS) + commit_vs_constants(device); + if (context->commit & NINE_STATE_COMMIT_CONST_PS) + commit_ps_constants(device); + if (context->commit & NINE_STATE_COMMIT_VS) + commit_vs(device); + if (context->commit & NINE_STATE_COMMIT_PS) + commit_ps(device); + + context->commit = 0; + + if (unlikely(context->changed.ucp)) { + pipe->set_clip_state(pipe, &context->clip); + context->changed.ucp = false; + } + + if (unlikely(group & NINE_STATE_RARE)) { + if (group & NINE_STATE_SCISSOR) + commit_scissor(device); + if (group & NINE_STATE_BLEND_COLOR) { + struct pipe_blend_color color; + d3dcolor_to_rgba(&color.color[0], context->rs[D3DRS_BLENDFACTOR]); + pipe->set_blend_color(pipe, &color); + } + if (group & NINE_STATE_SAMPLE_MASK) { + if (context->rt[0]->desc.MultiSampleType <= D3DMULTISAMPLE_NONMASKABLE) { + pipe->set_sample_mask(pipe, ~0); + } else { + pipe->set_sample_mask(pipe, context->rs[D3DRS_MULTISAMPLEMASK]); + } + } + if (group & NINE_STATE_STENCIL_REF) { + struct pipe_stencil_ref ref; + ref.ref_value[0] = context->rs[D3DRS_STENCILREF]; + ref.ref_value[1] = ref.ref_value[0]; + pipe->set_stencil_ref(pipe, ref); + } + } + + context->changed.group &= + (NINE_STATE_FF | NINE_STATE_VS_CONST | NINE_STATE_PS_CONST); + + DBG("finished\n"); +} + +#define RESZ_CODE 0x7fa05000 + +static void +NineDevice9_ResolveZ( struct NineDevice9 *device ) +{ + struct nine_context *context = &device->context; + const struct util_format_description *desc; + struct NineSurface9 *source = context->ds; + struct pipe_resource *src, *dst; + struct pipe_blit_info blit; + + DBG("RESZ resolve\n"); + + if (!source || !context->texture[0].enabled || + context->texture[0].type != D3DRTYPE_TEXTURE) + return; + + src = source->base.resource; + dst = context->texture[0].resource; + + if (!src || !dst) + return; + + /* check dst is depth format. we know already for src */ + desc = util_format_description(dst->format); + if (desc->colorspace != UTIL_FORMAT_COLORSPACE_ZS) + return; + + memset(&blit, 0, sizeof(blit)); + blit.src.resource = src; + blit.src.level = 0; + blit.src.format = src->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 = src->width0; + blit.src.box.height = src->height0; + + blit.dst.resource = dst; + blit.dst.level = 0; + blit.dst.format = dst->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 = dst->width0; + blit.dst.box.height = dst->height0; + + blit.mask = PIPE_MASK_ZS; + blit.filter = PIPE_TEX_FILTER_NEAREST; + blit.scissor_enable = false; + + context->pipe->blit(context->pipe, &blit); +} + +#define ALPHA_TO_COVERAGE_ENABLE MAKEFOURCC('A', '2', 'M', '1') +#define ALPHA_TO_COVERAGE_DISABLE MAKEFOURCC('A', '2', 'M', '0') +#define FETCH4_ENABLE MAKEFOURCC('G', 'E', 'T', '4') +#define FETCH4_DISABLE MAKEFOURCC('G', 'E', 'T', '1') + +/* Nine_context functions. + * Serialized through CSMT macros. + */ + +static void +nine_context_set_texture_apply(struct NineDevice9 *device, + DWORD stage, + DWORD fetch4_shadow_enabled, + DWORD lod, + D3DRESOURCETYPE type, + uint8_t pstype, + struct pipe_resource *res, + struct pipe_sampler_view *view0, + struct pipe_sampler_view *view1); + +static void +nine_context_set_pixel_shader_constant_i_transformed(struct NineDevice9 *device, + UINT StartRegister, + const int *pConstantData, + unsigned pConstantData_size, + UINT Vector4iCount); + +CSMT_ITEM_NO_WAIT(nine_context_set_render_state, + ARG_VAL(D3DRENDERSTATETYPE, State), + ARG_VAL(DWORD, Value)) +{ + struct nine_context *context = &device->context; + + /* Amd hacks (equivalent to GL extensions) */ + if (unlikely(State == D3DRS_POINTSIZE)) { + if (Value == RESZ_CODE) { + NineDevice9_ResolveZ(device); + return; + } + + /* NINED3DRS_ALPHACOVERAGE: + * bit 0: NVIDIA alpha to coverage + * bit 1: NVIDIA ATOC state active + * bit 2: AMD alpha to coverage + * These need to be separate else the set of states to + * disable NVIDIA alpha to coverage can disable the AMD one */ + if (Value == ALPHA_TO_COVERAGE_ENABLE || + Value == ALPHA_TO_COVERAGE_DISABLE) { + context->rs[NINED3DRS_ALPHACOVERAGE] &= 3; + context->rs[NINED3DRS_ALPHACOVERAGE] |= (Value == ALPHA_TO_COVERAGE_ENABLE) ? 4 : 0; + context->changed.group |= NINE_STATE_BLEND; + return; + } + } + + /* NV hack */ + if (unlikely(State == D3DRS_ADAPTIVETESS_Y)) { + if (Value == D3DFMT_ATOC || (Value == D3DFMT_UNKNOWN && context->rs[NINED3DRS_ALPHACOVERAGE] & 3)) { + context->rs[NINED3DRS_ALPHACOVERAGE] &= 4; + context->rs[NINED3DRS_ALPHACOVERAGE] |= + ((Value == D3DFMT_ATOC) ? 3 : 0) & (context->rs[D3DRS_ALPHATESTENABLE] ? 3 : 2); + context->changed.group |= NINE_STATE_BLEND; + return; + } + } + if (unlikely(State == D3DRS_ALPHATESTENABLE && (context->rs[NINED3DRS_ALPHACOVERAGE] & 2))) { + context->rs[NINED3DRS_ALPHACOVERAGE] &= 6; + context->rs[NINED3DRS_ALPHACOVERAGE] |= (Value ? 1 : 0); + } + + context->rs[State] = nine_fix_render_state_value(State, Value); + context->changed.group |= nine_render_state_group[State]; + + if (device->driver_caps.alpha_test_emulation) { + if (State == D3DRS_ALPHATESTENABLE || State == D3DRS_ALPHAFUNC) { + context->rs[NINED3DRS_EMULATED_ALPHATEST] = context->rs[D3DRS_ALPHATESTENABLE] ? + d3dcmpfunc_to_pipe_func(context->rs[D3DRS_ALPHAFUNC]) : 7; + context->changed.group |= NINE_STATE_PS_PARAMS_MISC | NINE_STATE_PS_CONST | NINE_STATE_FF_SHADER; + } + if (State == D3DRS_ALPHAREF) + context->changed.group |= NINE_STATE_PS_CONST | NINE_STATE_FF_PS_CONSTS; + } + + if (device->driver_caps.always_output_pointsize) { + if (State == D3DRS_POINTSIZE || State == D3DRS_POINTSIZE_MIN || State == D3DRS_POINTSIZE_MAX) + context->changed.group |= NINE_STATE_VS_CONST; + } + + if (device->driver_caps.emulate_ucp && State == D3DRS_CLIPPLANEENABLE) + context->changed.group |= NINE_STATE_VS_PARAMS_MISC | NINE_STATE_VS_CONST; +} + +CSMT_ITEM_NO_WAIT(nine_context_set_texture_apply, + ARG_VAL(DWORD, stage), + ARG_VAL(DWORD, fetch4_shadow_enabled), + ARG_VAL(DWORD, lod), + ARG_VAL(D3DRESOURCETYPE, type), + ARG_VAL(uint8_t, pstype), + ARG_BIND_RES(struct pipe_resource, res), + ARG_BIND_VIEW(struct pipe_sampler_view, view0), + ARG_BIND_VIEW(struct pipe_sampler_view, view1)) +{ + struct nine_context *context = &device->context; + uint enabled = fetch4_shadow_enabled & 1; + uint shadow = (fetch4_shadow_enabled >> 1) & 1; + uint fetch4_compatible = (fetch4_shadow_enabled >> 2) & 1; + + context->texture[stage].enabled = enabled; + if (enabled) { + if (stage < NINE_MAX_SAMPLERS_PS) + context->enabled_samplers_mask_ps |= BITFIELD_BIT(stage - NINE_SAMPLER_PS(0)); + else if (stage >= NINE_SAMPLER_VS(0)) + context->enabled_samplers_mask_vs |= BITFIELD_BIT(stage - NINE_SAMPLER_VS(0)); + } else { + if (stage < NINE_MAX_SAMPLERS_PS) + context->enabled_samplers_mask_ps &= ~BITFIELD_BIT(stage - NINE_SAMPLER_PS(0)); + else if (stage >= NINE_SAMPLER_VS(0)) + context->enabled_samplers_mask_vs &= ~BITFIELD_BIT(stage - NINE_SAMPLER_VS(0)); + } + context->samplers_shadow &= ~(1 << stage); + context->samplers_shadow |= shadow << stage; + context->samplers_fetch4 &= ~(1 << stage); + context->samplers_fetch4 |= fetch4_compatible << stage; + context->texture[stage].shadow = shadow; + context->texture[stage].lod = lod; + context->texture[stage].type = type; + context->texture[stage].pstype = pstype; + pipe_resource_reference(&context->texture[stage].resource, res); + context->texture[stage].view[0] = view0; + context->texture[stage].view[1] = view1; + + context->changed.group |= NINE_STATE_TEXTURE; +} + +void +nine_context_set_texture(struct NineDevice9 *device, + DWORD Stage, + struct NineBaseTexture9 *tex) +{ + DWORD fetch4_shadow_enabled = 0; + DWORD lod = 0; + D3DRESOURCETYPE type = D3DRTYPE_TEXTURE; + uint8_t pstype = 0; + struct pipe_resource *res = NULL; + struct pipe_sampler_view *view0 = NULL, *view1 = NULL; + + /* For managed pool, the data can be initially incomplete. + * In that case, the texture is rebound later + * (in NineBaseTexture9_Validate/NineBaseTexture9_UploadSelf). */ + if (tex && tex->base.resource) { + fetch4_shadow_enabled = 1; + fetch4_shadow_enabled |= tex->shadow << 1; + fetch4_shadow_enabled |= tex->fetch4_compatible << 2; + lod = tex->managed.lod; + type = tex->base.type; + pstype = tex->pstype; + res = tex->base.resource; + view0 = NineBaseTexture9_GetSamplerView(tex, 0); + view1 = NineBaseTexture9_GetSamplerView(tex, 1); + } + + nine_context_set_texture_apply(device, Stage, + fetch4_shadow_enabled, + lod, type, pstype, + res, view0, view1); +} + +CSMT_ITEM_NO_WAIT(nine_context_set_sampler_state, + ARG_VAL(DWORD, Sampler), + ARG_VAL(D3DSAMPLERSTATETYPE, Type), + ARG_VAL(DWORD, Value)) +{ + struct nine_context *context = &device->context; + + if (unlikely(Type == D3DSAMP_MIPMAPLODBIAS)) { + if (Value == FETCH4_ENABLE || + Value == FETCH4_DISABLE) { + context->rs[NINED3DRS_FETCH4] &= ~(1 << Sampler); + context->rs[NINED3DRS_FETCH4] |= (Value == FETCH4_ENABLE) << Sampler; + context->changed.group |= NINE_STATE_PS_PARAMS_MISC; + if (Value == FETCH4_ENABLE) + WARN_ONCE("FETCH4 support is incomplete. Please report if buggy shadows."); + return; + } + } + + if (unlikely(!nine_check_sampler_state_value(Type, Value))) + return; + + context->samp[Sampler][Type] = Value; + context->changed.group |= NINE_STATE_SAMPLER; + context->changed.sampler[Sampler] |= 1 << Type; +} + +CSMT_ITEM_NO_WAIT(nine_context_set_stream_source_apply, + ARG_VAL(UINT, StreamNumber), + ARG_BIND_RES(struct pipe_resource, res), + ARG_VAL(UINT, OffsetInBytes), + ARG_VAL(UINT, Stride)) +{ + struct nine_context *context = &device->context; + const unsigned i = StreamNumber; + + /* For normal draws, these tests are useless, + * but not for *Up draws */ + if (context->vtxbuf[i].buffer.resource == res && + context->vtxbuf[i].buffer_offset == OffsetInBytes && + context->vtxstride[i] == Stride) + return; + + if (context->vtxstride[i] != Stride) { + context->vtxstride[i] = Stride; + context->changed.group |= NINE_STATE_VDECL; + } + context->vtxbuf[i].buffer_offset = OffsetInBytes; + pipe_resource_reference(&context->vtxbuf[i].buffer.resource, res); + + context->changed.vtxbuf_dirty = true; + if (res) + context->vtxbuf_mask |= 1 << StreamNumber; + else + context->vtxbuf_mask &= ~(1 << StreamNumber); +} + +void +nine_context_set_stream_source(struct NineDevice9 *device, + UINT StreamNumber, + struct NineVertexBuffer9 *pVBuf9, + UINT OffsetInBytes, + UINT Stride) +{ + struct pipe_resource *res = NULL; + unsigned offset = 0; + + if (pVBuf9) + res = NineVertexBuffer9_GetResource(pVBuf9, &offset); + /* in the future when there is internal offset, add it + * to OffsetInBytes */ + + nine_context_set_stream_source_apply(device, StreamNumber, + res, offset + OffsetInBytes, + Stride); +} + +CSMT_ITEM_NO_WAIT(nine_context_set_stream_source_freq, + ARG_VAL(UINT, StreamNumber), + ARG_VAL(UINT, Setting)) +{ + struct nine_context *context = &device->context; + + context->stream_freq[StreamNumber] = Setting; + + if (Setting & D3DSTREAMSOURCE_INSTANCEDATA) + context->stream_instancedata_mask |= 1 << StreamNumber; + else + context->stream_instancedata_mask &= ~(1 << StreamNumber); + + if (StreamNumber != 0) + context->changed.group |= NINE_STATE_STREAMFREQ; +} + +CSMT_ITEM_NO_WAIT(nine_context_set_indices_apply, + ARG_BIND_RES(struct pipe_resource, res), + ARG_VAL(UINT, IndexSize), + ARG_VAL(UINT, OffsetInBytes)) +{ + struct nine_context *context = &device->context; + + context->index_size = IndexSize; + context->index_offset = OffsetInBytes; + pipe_resource_reference(&context->idxbuf, res); + + context->changed.group |= NINE_STATE_IDXBUF; +} + +void +nine_context_set_indices(struct NineDevice9 *device, + struct NineIndexBuffer9 *idxbuf) +{ + struct pipe_resource *res = NULL; + UINT IndexSize = 0; + unsigned OffsetInBytes = 0; + + if (idxbuf) { + res = NineIndexBuffer9_GetBuffer(idxbuf, &OffsetInBytes); + IndexSize = idxbuf->index_size; + } + + nine_context_set_indices_apply(device, res, IndexSize, OffsetInBytes); +} + +CSMT_ITEM_NO_WAIT(nine_context_set_vertex_declaration, + ARG_BIND_REF(struct NineVertexDeclaration9, vdecl)) +{ + struct nine_context *context = &device->context; + BOOL was_programmable_vs = context->programmable_vs; + + nine_bind(&context->vdecl, vdecl); + + context->programmable_vs = context->vs && !(context->vdecl && context->vdecl->position_t); + if (was_programmable_vs != context->programmable_vs) { + context->commit |= NINE_STATE_COMMIT_CONST_VS; + context->changed.group |= NINE_STATE_VS; + } + + context->changed.group |= NINE_STATE_VDECL; +} + +CSMT_ITEM_NO_WAIT(nine_context_set_vertex_shader, + ARG_BIND_REF(struct NineVertexShader9, pShader)) +{ + struct nine_context *context = &device->context; + BOOL was_programmable_vs = context->programmable_vs; + + nine_bind(&context->vs, pShader); + + context->programmable_vs = context->vs && !(context->vdecl && context->vdecl->position_t); + + /* ff -> non-ff: commit back non-ff constants */ + if (!was_programmable_vs && context->programmable_vs) + context->commit |= NINE_STATE_COMMIT_CONST_VS; + + context->changed.group |= NINE_STATE_VS; +} + +CSMT_ITEM_NO_WAIT(nine_context_set_vertex_shader_constant_f, + ARG_VAL(UINT, StartRegister), + ARG_MEM(float, pConstantData), + ARG_MEM_SIZE(unsigned, pConstantData_size), + ARG_VAL(UINT, Vector4fCount)) +{ + struct nine_context *context = &device->context; + float *vs_const_f = device->may_swvp ? context->vs_const_f_swvp : context->vs_const_f; + + memcpy(&vs_const_f[StartRegister * 4], + pConstantData, + pConstantData_size); + + if (device->may_swvp) { + Vector4fCount = MIN2(StartRegister + Vector4fCount, NINE_MAX_CONST_F) - StartRegister; + if (StartRegister < NINE_MAX_CONST_F) + memcpy(&context->vs_const_f[StartRegister * 4], + pConstantData, + Vector4fCount * 4 * sizeof(context->vs_const_f[0])); + } + + context->changed.vs_const_f = true; + context->changed.group |= NINE_STATE_VS_CONST; +} + +CSMT_ITEM_NO_WAIT(nine_context_set_vertex_shader_constant_i, + ARG_VAL(UINT, StartRegister), + ARG_MEM(int, pConstantData), + ARG_MEM_SIZE(unsigned, pConstantData_size), + ARG_VAL(UINT, Vector4iCount)) +{ + struct nine_context *context = &device->context; + int i; + + if (device->driver_caps.vs_integer) { + memcpy(&context->vs_const_i[4 * StartRegister], + pConstantData, + pConstantData_size); + } else { + for (i = 0; i < Vector4iCount; i++) { + context->vs_const_i[4 * (StartRegister + i)] = fui((float)(pConstantData[4 * i])); + context->vs_const_i[4 * (StartRegister + i) + 1] = fui((float)(pConstantData[4 * i + 1])); + context->vs_const_i[4 * (StartRegister + i) + 2] = fui((float)(pConstantData[4 * i + 2])); + context->vs_const_i[4 * (StartRegister + i) + 3] = fui((float)(pConstantData[4 * i + 3])); + } + } + + context->changed.vs_const_i = true; + context->changed.group |= NINE_STATE_VS_CONST | NINE_STATE_VS_PARAMS_MISC; +} + +CSMT_ITEM_NO_WAIT(nine_context_set_vertex_shader_constant_b, + ARG_VAL(UINT, StartRegister), + ARG_MEM(BOOL, pConstantData), + ARG_MEM_SIZE(unsigned, pConstantData_size), + ARG_VAL(UINT, BoolCount)) +{ + struct nine_context *context = &device->context; + int i; + uint32_t bool_true = device->driver_caps.vs_integer ? 0xFFFFFFFF : fui(1.0f); + + (void) pConstantData_size; + + for (i = 0; i < BoolCount; i++) + context->vs_const_b[StartRegister + i] = pConstantData[i] ? bool_true : 0; + + context->changed.vs_const_b = true; + context->changed.group |= NINE_STATE_VS_CONST | NINE_STATE_VS_PARAMS_MISC; +} + +CSMT_ITEM_NO_WAIT(nine_context_set_pixel_shader, + ARG_BIND_REF(struct NinePixelShader9, ps)) +{ + struct nine_context *context = &device->context; + unsigned old_mask = context->ps ? context->ps->rt_mask : 1; + unsigned mask; + + /* ff -> non-ff: commit back non-ff constants */ + if (!context->ps && ps) + context->commit |= NINE_STATE_COMMIT_CONST_PS; + + nine_bind(&context->ps, ps); + + context->changed.group |= NINE_STATE_PS; + + mask = context->ps ? context->ps->rt_mask : 1; + /* We need to update cbufs if the pixel shader would + * write to different render targets */ + if (mask != old_mask) + context->changed.group |= NINE_STATE_FB; +} + +CSMT_ITEM_NO_WAIT(nine_context_set_pixel_shader_constant_f, + ARG_VAL(UINT, StartRegister), + ARG_MEM(float, pConstantData), + ARG_MEM_SIZE(unsigned, pConstantData_size), + ARG_VAL(UINT, Vector4fCount)) +{ + struct nine_context *context = &device->context; + + memcpy(&context->ps_const_f[StartRegister * 4], + pConstantData, + pConstantData_size); + + context->changed.ps_const_f = true; + context->changed.group |= NINE_STATE_PS_CONST; +} + +/* For stateblocks */ +CSMT_ITEM_NO_WAIT(nine_context_set_pixel_shader_constant_i_transformed, + ARG_VAL(UINT, StartRegister), + ARG_MEM(int, pConstantData), + ARG_MEM_SIZE(unsigned, pConstantData_size), + ARG_VAL(UINT, Vector4iCount)) +{ + struct nine_context *context = &device->context; + + memcpy(&context->ps_const_i[StartRegister][0], + pConstantData, + Vector4iCount * sizeof(context->ps_const_i[0])); + + context->changed.ps_const_i = true; + context->changed.group |= NINE_STATE_PS_CONST | NINE_STATE_PS_PARAMS_MISC; +} + +CSMT_ITEM_NO_WAIT(nine_context_set_pixel_shader_constant_i, + ARG_VAL(UINT, StartRegister), + ARG_MEM(int, pConstantData), + ARG_MEM_SIZE(unsigned, pConstantData_size), + ARG_VAL(UINT, Vector4iCount)) +{ + struct nine_context *context = &device->context; + int i; + + if (device->driver_caps.ps_integer) { + memcpy(&context->ps_const_i[StartRegister][0], + pConstantData, + pConstantData_size); + } else { + for (i = 0; i < Vector4iCount; i++) { + context->ps_const_i[StartRegister+i][0] = fui((float)(pConstantData[4*i])); + context->ps_const_i[StartRegister+i][1] = fui((float)(pConstantData[4*i+1])); + context->ps_const_i[StartRegister+i][2] = fui((float)(pConstantData[4*i+2])); + context->ps_const_i[StartRegister+i][3] = fui((float)(pConstantData[4*i+3])); + } + } + context->changed.ps_const_i = true; + context->changed.group |= NINE_STATE_PS_CONST | NINE_STATE_PS_PARAMS_MISC; +} + +CSMT_ITEM_NO_WAIT(nine_context_set_pixel_shader_constant_b, + ARG_VAL(UINT, StartRegister), + ARG_MEM(BOOL, pConstantData), + ARG_MEM_SIZE(unsigned, pConstantData_size), + ARG_VAL(UINT, BoolCount)) +{ + struct nine_context *context = &device->context; + int i; + uint32_t bool_true = device->driver_caps.ps_integer ? 0xFFFFFFFF : fui(1.0f); + + (void) pConstantData_size; + + for (i = 0; i < BoolCount; i++) + context->ps_const_b[StartRegister + i] = pConstantData[i] ? bool_true : 0; + + context->changed.ps_const_b = true; + context->changed.group |= NINE_STATE_PS_CONST | NINE_STATE_PS_PARAMS_MISC; +} + +/* XXX: use resource, as resource might change */ +CSMT_ITEM_NO_WAIT(nine_context_set_render_target, + ARG_VAL(DWORD, RenderTargetIndex), + ARG_BIND_REF(struct NineSurface9, rt)) +{ + struct nine_context *context = &device->context; + const unsigned i = RenderTargetIndex; + + if (i == 0) { + context->changed.group |= NINE_STATE_MULTISAMPLE; + + if (context->rt[0] && + (context->rt[0]->desc.MultiSampleType <= D3DMULTISAMPLE_NONMASKABLE) != + (rt->desc.MultiSampleType <= D3DMULTISAMPLE_NONMASKABLE)) + context->changed.group |= NINE_STATE_SAMPLE_MASK; + } + + if (context->rt[i] != rt) { + nine_bind(&context->rt[i], rt); + context->changed.group |= NINE_STATE_FB; + } +} + +/* XXX: use resource instead of ds, as resource might change */ +CSMT_ITEM_NO_WAIT(nine_context_set_depth_stencil, + ARG_BIND_REF(struct NineSurface9, ds)) +{ + struct nine_context *context = &device->context; + + nine_bind(&context->ds, ds); + context->changed.group |= NINE_STATE_FB; +} + +CSMT_ITEM_NO_WAIT(nine_context_set_viewport, + ARG_COPY_REF(D3DVIEWPORT9, viewport)) +{ + struct nine_context *context = &device->context; + + if (!memcmp(viewport, &context->viewport, sizeof(context->viewport))) + return; + + context->viewport = *viewport; + context->changed.group |= NINE_STATE_VIEWPORT; +} + +CSMT_ITEM_NO_WAIT(nine_context_set_scissor, + ARG_COPY_REF(struct pipe_scissor_state, scissor)) +{ + struct nine_context *context = &device->context; + + if (!memcmp(scissor, &context->scissor, sizeof(context->scissor))) + return; + + context->scissor = *scissor; + context->changed.group |= NINE_STATE_SCISSOR; +} + +CSMT_ITEM_NO_WAIT(nine_context_set_transform, + ARG_VAL(D3DTRANSFORMSTATETYPE, State), + ARG_COPY_REF(D3DMATRIX, pMatrix)) +{ + struct nine_context *context = &device->context; + D3DMATRIX *M = nine_state_access_transform(&context->ff, State, true); + + *M = *pMatrix; + if (State == D3DTS_PROJECTION) { + BOOL prev_zfog = context->zfog; + /* Pixel fog (with WFOG advertised): source is either Z or W. + * W is the source if the projection matrix is not orthogonal. + * Tests on Win 10 seem to indicate _34 + * and _33 are checked against 0, 1. */ + context->zfog = (M->_34 == 0.0f && + M->_44 == 1.0f); + if (context->zfog != prev_zfog) + context->changed.group |= NINE_STATE_PS_PARAMS_MISC; + } + context->ff.changed.transform[State / 32] |= 1 << (State % 32); + context->changed.group |= NINE_STATE_FF; +} + +CSMT_ITEM_NO_WAIT(nine_context_set_material, + ARG_COPY_REF(D3DMATERIAL9, pMaterial)) +{ + struct nine_context *context = &device->context; + + context->ff.material = *pMaterial; + context->changed.group |= NINE_STATE_FF_MATERIAL; +} + +CSMT_ITEM_NO_WAIT(nine_context_set_light, + ARG_VAL(DWORD, Index), + ARG_COPY_REF(D3DLIGHT9, pLight)) +{ + struct nine_context *context = &device->context; + + (void)nine_state_set_light(&context->ff, Index, pLight); + context->changed.group |= NINE_STATE_FF_LIGHTING; +} + + +/* For stateblocks */ +static void +nine_context_light_enable_stateblock(struct NineDevice9 *device, + const uint16_t active_light[NINE_MAX_LIGHTS_ACTIVE], /* TODO: use pointer that convey size for csmt */ + unsigned int num_lights_active) +{ + struct nine_context *context = &device->context; + + /* TODO: Use CSMT_* to avoid calling nine_csmt_process */ + nine_csmt_process(device); + memcpy(context->ff.active_light, active_light, NINE_MAX_LIGHTS_ACTIVE * sizeof(context->ff.active_light[0])); + context->ff.num_lights_active = num_lights_active; + context->changed.group |= NINE_STATE_FF_LIGHTING; +} + +CSMT_ITEM_NO_WAIT(nine_context_light_enable, + ARG_VAL(DWORD, Index), + ARG_VAL(BOOL, Enable)) +{ + struct nine_context *context = &device->context; + + nine_state_light_enable(&context->ff, Index, Enable); + context->changed.group |= NINE_STATE_FF_LIGHTING; +} + +CSMT_ITEM_NO_WAIT(nine_context_set_texture_stage_state, + ARG_VAL(DWORD, Stage), + ARG_VAL(D3DTEXTURESTAGESTATETYPE, Type), + ARG_VAL(DWORD, Value)) +{ + struct nine_context *context = &device->context; + int bumpmap_index = -1; + + context->ff.tex_stage[Stage][Type] = Value; + switch (Type) { + case D3DTSS_BUMPENVMAT00: + bumpmap_index = 4 * Stage; + break; + case D3DTSS_BUMPENVMAT01: + bumpmap_index = 4 * Stage + 1; + break; + case D3DTSS_BUMPENVMAT10: + bumpmap_index = 4 * Stage + 2; + break; + case D3DTSS_BUMPENVMAT11: + bumpmap_index = 4 * Stage + 3; + break; + case D3DTSS_BUMPENVLSCALE: + bumpmap_index = 4 * 8 + 2 * Stage; + break; + case D3DTSS_BUMPENVLOFFSET: + bumpmap_index = 4 * 8 + 2 * Stage + 1; + break; + case D3DTSS_TEXTURETRANSFORMFLAGS: + context->changed.group |= NINE_STATE_PS_PARAMS_MISC; + break; + default: + break; + } + + if (bumpmap_index >= 0) { + context->bumpmap_vars[bumpmap_index] = Value; + context->changed.group |= NINE_STATE_PS_CONST; + } + + context->changed.group |= NINE_STATE_FF_PS_CONSTS; + context->ff.changed.tex_stage[Stage][Type / 32] |= 1 << (Type % 32); +} + +CSMT_ITEM_NO_WAIT(nine_context_set_clip_plane, + ARG_VAL(DWORD, Index), + ARG_COPY_REF(struct nine_clipplane, pPlane)) +{ + struct nine_context *context = &device->context; + + memcpy(&context->clip.ucp[Index][0], pPlane, sizeof(context->clip.ucp[0])); + if (!device->driver_caps.emulate_ucp) + context->changed.ucp = true; + else + context->changed.group |= NINE_STATE_FF_VS_OTHER | NINE_STATE_VS_CONST; +} + +CSMT_ITEM_NO_WAIT(nine_context_set_swvp, + ARG_VAL(bool, swvp)) +{ + struct nine_context *context = &device->context; + + context->swvp = swvp; + context->changed.group |= NINE_STATE_SWVP; +} + +/* Do not write to nine_context directly. Slower, + * but works with csmt. TODO: write a special csmt version that + * would record the list of commands as much as possible, + * and use the version above else. + */ +void +nine_context_apply_stateblock(struct NineDevice9 *device, + const struct nine_state *src) +{ + int i; + + /* No need to apply src->changed.group, since all calls do + * set context->changed.group */ + + for (i = 0; i < ARRAY_SIZE(src->changed.rs); ++i) { + uint32_t m = src->changed.rs[i]; + while (m) { + const int r = ffs(m) - 1; + m &= ~(1 << r); + nine_context_set_render_state(device, i * 32 + r, src->rs_advertised[i * 32 + r]); + } + } + + /* Textures */ + if (src->changed.texture) { + uint32_t m = src->changed.texture; + unsigned s; + + for (s = 0; m; ++s, m >>= 1) { + struct NineBaseTexture9 *tex = src->texture[s]; + if (!(m & 1)) + continue; + nine_context_set_texture(device, s, tex); + } + } + + /* Sampler state */ + if (src->changed.group & NINE_STATE_SAMPLER) { + unsigned s; + + for (s = 0; s < NINE_MAX_SAMPLERS; ++s) { + uint32_t m = src->changed.sampler[s]; + while (m) { + const int i = ffs(m) - 1; + m &= ~(1 << i); + nine_context_set_sampler_state(device, s, i, src->samp_advertised[s][i]); + } + } + } + + /* Vertex buffers */ + if (src->changed.vtxbuf | src->changed.stream_freq) { + uint32_t m = src->changed.vtxbuf | src->changed.stream_freq; + for (i = 0; m; ++i, m >>= 1) { + if (src->changed.vtxbuf & (1 << i)) + nine_context_set_stream_source(device, i, src->stream[i], src->vtxbuf[i].buffer_offset, src->vtxstride[i]); + if (src->changed.stream_freq & (1 << i)) + nine_context_set_stream_source_freq(device, i, src->stream_freq[i]); + } + } + + /* Index buffer */ + if (src->changed.group & NINE_STATE_IDXBUF) + nine_context_set_indices(device, src->idxbuf); + + /* Vertex declaration */ + if ((src->changed.group & NINE_STATE_VDECL) && src->vdecl) + nine_context_set_vertex_declaration(device, src->vdecl); + + /* Vertex shader */ + if (src->changed.group & NINE_STATE_VS) + nine_context_set_vertex_shader(device, src->vs); + + /* Pixel shader */ + if (src->changed.group & NINE_STATE_PS) + nine_context_set_pixel_shader(device, src->ps); + + /* Vertex constants */ + if (src->changed.group & NINE_STATE_VS_CONST) { + struct nine_range *r; + for (r = src->changed.vs_const_f; r; r = r->next) + nine_context_set_vertex_shader_constant_f(device, r->bgn, + &src->vs_const_f[r->bgn * 4], + sizeof(float[4]) * (r->end - r->bgn), + r->end - r->bgn); + for (r = src->changed.vs_const_i; r; r = r->next) + nine_context_set_vertex_shader_constant_i(device, r->bgn, + &src->vs_const_i[r->bgn * 4], + sizeof(int[4]) * (r->end - r->bgn), + r->end - r->bgn); + for (r = src->changed.vs_const_b; r; r = r->next) + nine_context_set_vertex_shader_constant_b(device, r->bgn, + &src->vs_const_b[r->bgn * 4], + sizeof(BOOL) * (r->end - r->bgn), + r->end - r->bgn); + } + + /* Pixel constants */ + if (src->changed.group & NINE_STATE_PS_CONST) { + struct nine_range *r; + for (r = src->changed.ps_const_f; r; r = r->next) + nine_context_set_pixel_shader_constant_f(device, r->bgn, + &src->ps_const_f[r->bgn * 4], + sizeof(float[4]) * (r->end - r->bgn), + r->end - r->bgn); + if (src->changed.ps_const_i) { + uint16_t m = src->changed.ps_const_i; + for (i = ffs(m) - 1, m >>= i; m; ++i, m >>= 1) + if (m & 1) + nine_context_set_pixel_shader_constant_i_transformed(device, i, + src->ps_const_i[i], sizeof(int[4]), 1); + } + if (src->changed.ps_const_b) { + uint16_t m = src->changed.ps_const_b; + for (i = ffs(m) - 1, m >>= i; m; ++i, m >>= 1) + if (m & 1) + nine_context_set_pixel_shader_constant_b(device, i, + &src->ps_const_b[i], sizeof(BOOL), 1); + } + } + + /* Viewport */ + if (src->changed.group & NINE_STATE_VIEWPORT) + nine_context_set_viewport(device, &src->viewport); + + /* Scissor */ + if (src->changed.group & NINE_STATE_SCISSOR) + nine_context_set_scissor(device, &src->scissor); + + /* User Clip Planes */ + if (src->changed.ucp) + for (i = 0; i < PIPE_MAX_CLIP_PLANES; ++i) + if (src->changed.ucp & (1 << i)) + nine_context_set_clip_plane(device, i, (struct nine_clipplane*)&src->clip.ucp[i][0]); + + if (!(src->changed.group & NINE_STATE_FF)) + return; + + /* Fixed function state. */ + + if (src->changed.group & NINE_STATE_FF_MATERIAL) + nine_context_set_material(device, &src->ff.material); + + if (src->changed.group & NINE_STATE_FF_PS_CONSTS) { + unsigned s; + for (s = 0; s < NINE_MAX_TEXTURE_STAGES; ++s) { + for (i = 0; i < NINED3DTSS_COUNT; ++i) + if (src->ff.changed.tex_stage[s][i / 32] & (1 << (i % 32))) + nine_context_set_texture_stage_state(device, s, i, src->ff.tex_stage[s][i]); + } + } + if (src->changed.group & NINE_STATE_FF_LIGHTING) { + for (i = 0; i < src->ff.num_lights; ++i) + if (src->ff.light[i].Type != NINED3DLIGHT_INVALID) + nine_context_set_light(device, i, &src->ff.light[i]); + + nine_context_light_enable_stateblock(device, src->ff.active_light, src->ff.num_lights_active); + } + if (src->changed.group & NINE_STATE_FF_VSTRANSF) { + for (i = 0; i < ARRAY_SIZE(src->ff.changed.transform); ++i) { + unsigned s; + if (!src->ff.changed.transform[i]) + continue; + for (s = i * 32; s < (i * 32 + 32); ++s) { + if (!(src->ff.changed.transform[i] & (1 << (s % 32)))) + continue; + /* MaxVertexBlendMatrixIndex is 8, which means + * we don't read past index D3DTS_WORLDMATRIX(8). + * swvp is supposed to allow all 256, but we don't + * implement it for now. */ + if (s > D3DTS_WORLDMATRIX(8)) + break; + nine_context_set_transform(device, s, + nine_state_access_transform( + (struct nine_ff_state *)&src->ff, + s, false)); + } + } + } +} + +static void +nine_update_state_framebuffer_clear(struct NineDevice9 *device) +{ + struct nine_context *context = &device->context; + + if (context->changed.group & NINE_STATE_FB) + update_framebuffer(device, true); +} + +CSMT_ITEM_NO_WAIT(nine_context_clear_fb, + ARG_VAL(DWORD, Count), + ARG_COPY_REF(D3DRECT, pRects), + ARG_VAL(DWORD, Flags), + ARG_VAL(D3DCOLOR, Color), + ARG_VAL(float, Z), + ARG_VAL(DWORD, Stencil)) +{ + struct nine_context *context = &device->context; + const int sRGB = context->rs[D3DRS_SRGBWRITEENABLE] ? 1 : 0; + struct pipe_surface *cbuf, *zsbuf; + struct pipe_context *pipe = context->pipe; + struct NineSurface9 *zsbuf_surf = context->ds; + struct NineSurface9 *rt; + unsigned bufs = 0; + unsigned r, i; + union pipe_color_union rgba; + unsigned rt_mask = 0; + D3DRECT rect; + + nine_update_state_framebuffer_clear(device); + + if (Flags & D3DCLEAR_TARGET) bufs |= PIPE_CLEAR_COLOR; + /* Ignore Z buffer if not bound */ + if (context->pipe_data.fb.zsbuf.texture != NULL) { + if (Flags & D3DCLEAR_ZBUFFER) bufs |= PIPE_CLEAR_DEPTH; + if (Flags & D3DCLEAR_STENCIL) bufs |= PIPE_CLEAR_STENCIL; + } + if (!bufs) + return; + d3dcolor_to_pipe_color_union(&rgba, Color); + + rect.x1 = context->viewport.X; + rect.y1 = context->viewport.Y; + rect.x2 = context->viewport.Width + rect.x1; + rect.y2 = context->viewport.Height + rect.y1; + + /* Both rectangles apply, which is weird, but that's D3D9. */ + if (context->rs[D3DRS_SCISSORTESTENABLE]) { + rect.x1 = MAX2(rect.x1, context->scissor.minx); + rect.y1 = MAX2(rect.y1, context->scissor.miny); + rect.x2 = MIN2(rect.x2, context->scissor.maxx); + rect.y2 = MIN2(rect.y2, context->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 >= context->pipe_data.fb.width || rect.y1 >= context->pipe_data.fb.height) + return; + + for (i = 0; i < device->caps.NumSimultaneousRTs; ++i) { + if (context->rt[i] && context->rt[i]->desc.Format != D3DFMT_NULL) + rt_mask |= 1 << i; + } + + /* fast path, clears everything at once */ + if (!Count && + (!(bufs & PIPE_CLEAR_COLOR) || (rt_mask == context->rt_mask)) && + rect.x1 == 0 && rect.y1 == 0 && + /* Case we clear only render target. Check clear region vs rt. */ + ((!(bufs & (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL)) && + rect.x2 >= context->pipe_data.fb.width && + rect.y2 >= context->pipe_data.fb.height) || + /* Case we clear depth buffer (and eventually rt too). + * depth buffer size is always >= rt size. Compare to clear region */ + ((bufs & (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL)) && + rect.x2 >= zsbuf_surf->desc.Width && + rect.y2 >= zsbuf_surf->desc.Height))) { + DBG("Clear fast path\n"); + /* Mesa 26.x: pipe_context::clear() gained color/stencil write masks. + * Nine always does an unmasked clear, so pass all-ones. */ + pipe->clear(pipe, bufs, 0xffffffff, 0xff, NULL, &rgba, Z, Stencil); + return; + } + + if (!Count) { + Count = 1; + pRects = ▭ + } + + for (i = 0; i < device->caps.NumSimultaneousRTs; ++i) { + rt = context->rt[i]; + if (!rt || rt->desc.Format == D3DFMT_NULL || + !(bufs & PIPE_CLEAR_COLOR)) + continue; /* save space, compiler should hoist this */ + cbuf = NineSurface9_GetSurface(rt, sRGB); + 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 = MIN3(x2, rect.x2, rt->desc.Width); + y2 = MIN3(y2, rect.y2, rt->desc.Height); + + DBG("Clearing (%u..%u)x(%u..%u)\n", x1, x2, y1, y2); + pipe->clear_render_target(pipe, cbuf, &rgba, + x1, y1, x2 - x1, y2 - y1, false); + } + } + if (!(bufs & PIPE_CLEAR_DEPTHSTENCIL)) + return; + + 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 = MIN3(x2, rect.x2, zsbuf_surf->desc.Width); + y2 = MIN3(y2, rect.y2, zsbuf_surf->desc.Height); + + zsbuf = NineSurface9_GetSurface(zsbuf_surf, 0); + assert(zsbuf); + pipe->clear_depth_stencil(pipe, zsbuf, bufs, Z, Stencil, + x1, y1, x2 - x1, y2 - y1, false); + } + return; +} + + +static inline void +init_draw_info(struct pipe_draw_info *info, + struct pipe_draw_start_count_bias *draw, + struct NineDevice9 *dev, D3DPRIMITIVETYPE type, UINT count) +{ + info->mode = d3dprimitivetype_to_pipe_prim(type); + draw->count = prim_count_to_vertex_count(type, count); + info->start_instance = 0; + info->instance_count = 1; + if (dev->context.stream_instancedata_mask & dev->context.stream_usage_mask) + info->instance_count = MAX2(dev->context.stream_freq[0] & 0x7FFFFF, 1); + info->primitive_restart = false; + info->has_user_indices = false; + info->index_bias_varies = false; + info->increment_draw_id = false; + info->was_line_loop = false; + info->restart_index = 0; +} + +CSMT_ITEM_NO_WAIT(nine_context_draw_primitive, + ARG_VAL(D3DPRIMITIVETYPE, PrimitiveType), + ARG_VAL(UINT, StartVertex), + ARG_VAL(UINT, PrimitiveCount)) +{ + struct nine_context *context = &device->context; + struct pipe_draw_info info; + struct pipe_draw_start_count_bias draw; + + if (context->vs && context->vs->swvp_only && !context->swvp) + return; + + nine_update_state(device); + + init_draw_info(&info, &draw, device, PrimitiveType, PrimitiveCount); + info.index_size = 0; + draw.start = StartVertex; + draw.index_bias = 0; + info.min_index = draw.start; + info.max_index = draw.start + draw.count - 1; + info.index.resource = NULL; + + context->pipe->draw_vbo(context->pipe, &info, 0, NULL, &draw, 1); +} + +CSMT_ITEM_NO_WAIT(nine_context_draw_indexed_primitive, + ARG_VAL(D3DPRIMITIVETYPE, PrimitiveType), + ARG_VAL(INT, BaseVertexIndex), + ARG_VAL(UINT, MinVertexIndex), + ARG_VAL(UINT, NumVertices), + ARG_VAL(UINT, StartIndex), + ARG_VAL(UINT, PrimitiveCount)) +{ + struct nine_context *context = &device->context; + struct pipe_draw_info info; + struct pipe_draw_start_count_bias draw; + + if (context->vs && context->vs->swvp_only && !context->swvp) + return; + + nine_update_state(device); + + init_draw_info(&info, &draw, device, PrimitiveType, PrimitiveCount); + info.index_size = context->index_size; + draw.start = context->index_offset / context->index_size + StartIndex; + draw.index_bias = BaseVertexIndex; + info.index_bounds_valid = true; + /* These don't include index bias: */ + info.min_index = MinVertexIndex; + info.max_index = MinVertexIndex + NumVertices - 1; + info.index.resource = context->idxbuf; + + context->pipe->draw_vbo(context->pipe, &info, 0, NULL, &draw, 1); +} + +CSMT_ITEM_NO_WAIT(nine_context_draw_indexed_primitive_from_vtxbuf_idxbuf, + ARG_VAL(D3DPRIMITIVETYPE, PrimitiveType), + ARG_VAL(UINT, MinVertexIndex), + ARG_VAL(UINT, NumVertices), + ARG_VAL(UINT, PrimitiveCount), + ARG_VAL(UINT, vbuf_stride), + ARG_BIND_VBUF(struct pipe_vertex_buffer, vbuf), + ARG_BIND_RES(struct pipe_resource, ibuf), + ARG_VAL(void *, user_ibuf), + ARG_VAL(UINT, index_offset), + ARG_VAL(UINT, index_size)) +{ + struct nine_context *context = &device->context; + struct pipe_draw_info info; + struct pipe_draw_start_count_bias draw; + + if (context->vs && context->vs->swvp_only && !context->swvp) + return; + + if (context->vtxstride[0] != vbuf_stride) { + context->vtxstride[0] = vbuf_stride; + /* force elements update for stride. + * We don't need to restore the old value, + * as the caller set its to 0 after the call */ + context->changed.group |= NINE_STATE_VDECL; + } + + nine_update_state(device); + + init_draw_info(&info, &draw, device, PrimitiveType, PrimitiveCount); + info.index_size = index_size; + draw.start = index_offset / info.index_size; + draw.index_bias = 0; + info.index_bounds_valid = true; + info.min_index = MinVertexIndex; + info.max_index = MinVertexIndex + NumVertices - 1; + info.has_user_indices = ibuf == NULL; + if (ibuf) + info.index.resource = ibuf; + else + info.index.user = user_ibuf; + + context->pipe->set_vertex_buffers(context->pipe, 1, vbuf); + context->changed.vtxbuf_dirty = true; + + context->pipe->draw_vbo(context->pipe, &info, 0, NULL, &draw, 1); +} + +CSMT_ITEM_NO_WAIT(nine_context_resource_copy_region, + ARG_BIND_REF(struct NineUnknown, dst), + ARG_BIND_REF(struct NineUnknown, src), + ARG_BIND_RES(struct pipe_resource, dst_res), + ARG_VAL(unsigned, dst_level), + ARG_COPY_REF(struct pipe_box, dst_box), + ARG_BIND_RES(struct pipe_resource, src_res), + ARG_VAL(unsigned, src_level), + ARG_COPY_REF(struct pipe_box, src_box)) +{ + struct nine_context *context = &device->context; + + (void) dst; + (void) src; + + context->pipe->resource_copy_region(context->pipe, + dst_res, dst_level, + dst_box->x, dst_box->y, dst_box->z, + src_res, src_level, + src_box); +} + +CSMT_ITEM_NO_WAIT(nine_context_blit, + ARG_BIND_REF(struct NineUnknown, dst), + ARG_BIND_REF(struct NineUnknown, src), + ARG_BIND_BLIT(struct pipe_blit_info, blit)) +{ + struct nine_context *context = &device->context; + + (void) dst; + (void) src; + + context->pipe->blit(context->pipe, blit); +} + +CSMT_ITEM_NO_WAIT(nine_context_clear_render_target, + ARG_BIND_REF(struct NineSurface9, surface), + ARG_VAL(D3DCOLOR, color), + ARG_VAL(UINT, x), + ARG_VAL(UINT, y), + ARG_VAL(UINT, width), + ARG_VAL(UINT, height)) +{ + struct nine_context *context = &device->context; + struct pipe_surface *surf; + union pipe_color_union rgba; + + d3dcolor_to_pipe_color_union(&rgba, color); + surf = NineSurface9_GetSurface(surface, 0); + context->pipe->clear_render_target(context->pipe, surf, &rgba, x, y, width, height, false); +} + +CSMT_ITEM_NO_WAIT(nine_context_gen_mipmap, + ARG_BIND_REF(struct NineUnknown, dst), + ARG_BIND_RES(struct pipe_resource, res), + ARG_VAL(UINT, base_level), + ARG_VAL(UINT, last_level), + ARG_VAL(UINT, first_layer), + ARG_VAL(UINT, last_layer), + ARG_VAL(UINT, filter)) +{ + struct nine_context *context = &device->context; + + /* We just bind dst for the bind count */ + (void)dst; + + util_gen_mipmap(context->pipe, res, res->format, base_level, + last_level, first_layer, last_layer, filter); +} + +CSMT_ITEM_NO_WAIT_WITH_COUNTER(nine_context_range_upload, + ARG_BIND_REF(struct NineUnknown, src_ref), + ARG_BIND_RES(struct pipe_resource, res), + ARG_VAL(unsigned, offset), + ARG_VAL(unsigned, size), + ARG_VAL(unsigned, usage), + ARG_VAL(const void *, data)) +{ + struct nine_context *context = &device->context; + + /* Binding src_ref avoids release before upload */ + (void)src_ref; + + context->pipe->buffer_subdata(context->pipe, res, usage, offset, size, data); +} + +CSMT_ITEM_NO_WAIT_WITH_COUNTER(nine_context_box_upload, + ARG_BIND_REF(struct NineUnknown, src_ref), + ARG_BIND_RES(struct pipe_resource, res), + ARG_VAL(unsigned, level), + ARG_COPY_REF(struct pipe_box, dst_box), + ARG_VAL(enum pipe_format, src_format), + ARG_VAL(const void *, src), + ARG_VAL(unsigned, src_stride), + ARG_VAL(unsigned, src_layer_stride), + ARG_COPY_REF(struct pipe_box, src_box)) +{ + struct nine_context *context = &device->context; + struct pipe_context *pipe = context->pipe; + struct pipe_transfer *transfer = NULL; + uint8_t *map; + + /* Binding src_ref avoids release before upload */ + (void)src_ref; + + if (is_ATI1_ATI2(src_format)) { + const unsigned bw = util_format_get_blockwidth(src_format); + const unsigned bh = util_format_get_blockheight(src_format); + /* For these formats, the allocate surface can be too small to contain + * a block. Yet we can be asked to upload such surfaces. + * It is ok for these surfaces to have buggy content, + * but we should avoid crashing. + * Calling util_format_translate_3d would read out of bounds. */ + if (dst_box->width < bw || dst_box->height < bh) + return; + } + + map = pipe->texture_map(pipe, + res, + level, + PIPE_MAP_WRITE | PIPE_MAP_DISCARD_RANGE, + dst_box, &transfer); + if (!map) + return; + + /* Note: if formats are the sames, it will revert + * to normal memcpy */ + (void) util_format_translate_3d(res->format, + map, transfer->stride, + transfer->layer_stride, + 0, 0, 0, + src_format, + src, src_stride, + src_layer_stride, + src_box->x, src_box->y, src_box->z, + dst_box->width, dst_box->height, + dst_box->depth); + + pipe_texture_unmap(pipe, transfer); +} + +struct pipe_query * +nine_context_create_query(struct NineDevice9 *device, unsigned query_type) +{ + struct pipe_context *pipe; + struct pipe_query *res; + + pipe = nine_context_get_pipe_acquire(device); + res = pipe->create_query(pipe, query_type, 0); + nine_context_get_pipe_release(device); + return res; +} + +CSMT_ITEM_DO_WAIT(nine_context_destroy_query, + ARG_REF(struct pipe_query, query)) +{ + struct nine_context *context = &device->context; + + context->pipe->destroy_query(context->pipe, query); +} + +CSMT_ITEM_NO_WAIT_WITH_COUNTER(nine_context_begin_query, + ARG_REF(struct pipe_query, query)) +{ + struct nine_context *context = &device->context; + + (void) context->pipe->begin_query(context->pipe, query); +} + +CSMT_ITEM_NO_WAIT_WITH_COUNTER(nine_context_end_query, + ARG_REF(struct pipe_query, query)) +{ + struct nine_context *context = &device->context; + + (void) context->pipe->end_query(context->pipe, query); +} + +bool +nine_context_get_query_result(struct NineDevice9 *device, struct pipe_query *query, + unsigned *counter, bool flush, bool wait, + union pipe_query_result *result) +{ + struct pipe_context *pipe; + bool ret; + + if (wait) + nine_csmt_process(device); + else if (p_atomic_read(counter) > 0) { + if (flush && device->csmt_active) + nine_queue_flush(device->csmt_ctx->pool); + DBG("Pending begin/end. Returning\n"); + return false; + } + + pipe = nine_context_get_pipe_acquire(device); + ret = pipe->get_query_result(pipe, query, wait, result); + nine_context_get_pipe_release(device); + + DBG("Query result %s\n", ret ? "found" : "not yet available"); + return ret; +} + +CSMT_ITEM_NO_WAIT(nine_context_pipe_flush) +{ + struct nine_context *context = &device->context; + + context->pipe->flush(context->pipe, NULL, PIPE_FLUSH_ASYNC); +} + +/* State defaults */ + +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, + [NINED3DRS_ALPHACOVERAGE] = false, + [NINED3DRS_MULTISAMPLE] = false, + [NINED3DRS_FETCH4] = 0, + [NINED3DRS_EMULATED_ALPHATEST] = 7 /* ALWAYS pass */ +}; +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, + [NINED3DSAMP_CUBETEX] = 0 +}; + +/* Note: The following 4 functions assume there is no + * pending commands */ + +void nine_state_restore_non_cso(struct NineDevice9 *device) +{ + struct nine_context *context = &device->context; + + context->changed.group = NINE_STATE_ALL; /* TODO: we can remove states that have prepared commits */ + context->changed.vtxbuf_dirty = true; + context->changed.ucp = true; + context->commit |= 0xffffffff; /* re-commit everything */ + context->enabled_sampler_count_vs = 0; + context->enabled_sampler_count_ps = 0; +} + +void +nine_state_set_defaults(struct NineDevice9 *device, const D3DCAPS9 *caps, + bool is_reset) +{ + struct nine_state *state = &device->state; + struct nine_context *context = &device->context; + unsigned s; + + /* Initialize defaults. + */ + memcpy(context->rs, nine_render_state_defaults, sizeof(context->rs)); + + for (s = 0; s < ARRAY_SIZE(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 < ARRAY_SIZE(state->ff.tex_stage); ++s) + memcpy(&context->ff.tex_stage[s], state->ff.tex_stage[s], + sizeof(state->ff.tex_stage[s])); + + memset(&context->bumpmap_vars, 0, sizeof(context->bumpmap_vars)); + + for (s = 0; s < NINE_MAX_SAMPLERS; ++s) { + memcpy(&context->samp[s], nine_samp_state_defaults, + sizeof(context->samp[s])); + memcpy(&state->samp_advertised[s], nine_samp_state_defaults, + sizeof(state->samp_advertised[s])); + } + + memset(state->vs_const_f, 0, VS_CONST_F_SIZE(device)); + memset(context->vs_const_f, 0, device->vs_const_size); + if (context->vs_const_f_swvp) + memset(context->vs_const_f_swvp, 0, NINE_MAX_CONST_F_SWVP * sizeof(float[4])); + memset(state->vs_const_i, 0, VS_CONST_I_SIZE(device)); + memset(context->vs_const_i, 0, VS_CONST_I_SIZE(device)); + memset(state->vs_const_b, 0, VS_CONST_B_SIZE(device)); + memset(context->vs_const_b, 0, VS_CONST_B_SIZE(device)); + memset(state->ps_const_f, 0, device->ps_const_size); + memset(context->ps_const_f, 0, device->ps_const_size); + memset(state->ps_const_i, 0, sizeof(state->ps_const_i)); + memset(context->ps_const_i, 0, sizeof(context->ps_const_i)); + memset(state->ps_const_b, 0, sizeof(state->ps_const_b)); + memset(context->ps_const_b, 0, sizeof(context->ps_const_b)); + context->zfog = false; /* Guess from wine tests: both true or false are ok */ + + /* Cap dependent initial state: + */ + context->rs[D3DRS_POINTSIZE_MAX] = fui(caps->MaxPointSize); + + memcpy(state->rs_advertised, context->rs, sizeof(context->rs)); + + /* Set changed flags to initialize driver. + */ + context->changed.group = NINE_STATE_ALL; + context->changed.vtxbuf_dirty = true; + context->changed.ucp = true; + + context->ff.changed.transform[0] = ~0; + context->ff.changed.transform[D3DTS_WORLD / 32] |= 1 << (D3DTS_WORLD % 32); + + if (!is_reset) { + state->viewport.MinZ = context->viewport.MinZ = 0.0f; + state->viewport.MaxZ = context->viewport.MaxZ = 1.0f; + } + + for (s = 0; s < NINE_MAX_SAMPLERS; ++s) + context->changed.sampler[s] = ~0; + + if (!is_reset) + context->dummy_vbo_bound_at = -1; +} + +void +nine_device_state_clear(struct NineDevice9 *device) +{ + struct nine_state *state = &device->state; + unsigned i; + + for (i = 0; i < ARRAY_SIZE(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) + NineBindBufferToDevice(device, + (struct NineBuffer9 **)&state->stream[i], + NULL); + NineBindBufferToDevice(device, + (struct NineBuffer9 **)&state->idxbuf, + NULL); + + for (i = 0; i < NINE_MAX_SAMPLERS; ++i) + NineBindTextureToDevice(device, &state->texture[i], NULL); +} + +void +nine_context_clear(struct NineDevice9 *device) +{ + struct nine_context *context = &device->context; + struct pipe_context *pipe = context->pipe; + struct cso_context *cso = context->cso; + unsigned i; + + /* Early device ctor failure. Nothing to do */ + if (!pipe || !cso) + return; + + context->vtxbuf_mask = 0; + + 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, MESA_SHADER_VERTEX, 0, NULL); + cso_set_samplers(cso, MESA_SHADER_FRAGMENT, 0, NULL); + context->enabled_sampler_count_vs = 0; + context->enabled_sampler_count_ps = 0; + + pipe->set_sampler_views(pipe, MESA_SHADER_VERTEX, 0, 0, + NINE_MAX_SAMPLERS_VS, NULL); + pipe->set_sampler_views(pipe, MESA_SHADER_FRAGMENT, 0, 0, + NINE_MAX_SAMPLERS_PS, NULL); + + pipe->set_vertex_buffers(pipe, 0, NULL); + + for (i = 0; i < ARRAY_SIZE(context->rt); ++i) + nine_bind(&context->rt[i], NULL); + nine_bind(&context->ds, NULL); + nine_bind(&context->vs, NULL); + nine_bind(&context->ps, NULL); + nine_bind(&context->vdecl, NULL); + for (i = 0; i < PIPE_MAX_ATTRIBS; ++i) + pipe_vertex_buffer_unreference(&context->vtxbuf[i]); + pipe_resource_reference(&context->idxbuf, NULL); + pipe_resource_reference(&context->pipe_data.cb_vs.buffer, NULL); + pipe_resource_reference(&context->pipe_data.cb_ps.buffer, NULL); + + for (i = 0; i < NINE_MAX_SAMPLERS; ++i) { + context->texture[i].enabled = false; + pipe_resource_reference(&context->texture[i].resource, + NULL); + context->texture[i].view[0] = NULL; + context->texture[i].view[1] = NULL; + } +} + +void +nine_context_update_state(struct NineDevice9 *device) +{ + nine_update_state(device); +} + +void +nine_state_init_sw(struct NineDevice9 *device) +{ + struct pipe_context *pipe_sw = device->pipe_sw; + struct pipe_rasterizer_state rast; + struct pipe_blend_state blend; + struct pipe_depth_stencil_alpha_state dsa; + struct pipe_framebuffer_state fb; + + /* Only used with Streamout */ + memset(&rast, 0, sizeof(rast)); + rast.rasterizer_discard = true; + rast.point_quad_rasterization = 1; /* to make llvmpipe happy */ + cso_set_rasterizer(device->cso_sw, &rast); + + /* dummy settings */ + memset(&blend, 0, sizeof(blend)); + memset(&dsa, 0, sizeof(dsa)); + memset(&fb, 0, sizeof(fb)); + cso_set_blend(device->cso_sw, &blend); + cso_set_depth_stencil_alpha(device->cso_sw, &dsa); + cso_set_framebuffer(device->cso_sw, &fb); + cso_set_viewport_dims(device->cso_sw, 1.0, 1.0, false); + cso_set_fragment_shader_handle(device->cso_sw, util_make_empty_fragment_shader(pipe_sw)); +} + +/* There is duplication with update_vertex_elements. + * TODO: Share the code */ + +static int +update_vertex_elements_sw(struct NineDevice9 *device) +{ + struct nine_state *state = &device->state; + const struct NineVertexDeclaration9 *vdecl = device->state.vdecl; + const struct NineVertexShader9 *vs; + unsigned n, b, i, j; + int index; + int8_t vdecl_index_map[16]; /* vs->num_inputs <= 16 */ + int8_t used_streams[device->caps.MaxStreams]; + BOOL need_dummy_vbo = false; + int dummy_vbo_stream = -1; + struct cso_velems_state ve; + bool programmable_vs = state->vs && !(state->vdecl && state->vdecl->position_t); + unsigned vtxbuf_holes_map[PIPE_MAX_ATTRIBS]; + + memset(vdecl_index_map, -1, 16); + memset(used_streams, 0, device->caps.MaxStreams); + vs = programmable_vs ? device->state.vs : device->ff.vs; + + if (vdecl) { + 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); + + for (i = 0; i < vdecl->nelems; i++) { + if (vdecl->usage_map[i] == vs->input_map[n].ndecl) { + vdecl_index_map[n] = i; + used_streams[vdecl->elems[i].vertex_buffer_index] = 1; + break; + } + } + if (vdecl_index_map[n] < 0) + need_dummy_vbo = true; + } + } else { + /* No vertex declaration. Likely will never happen in practice, + * but we need not crash on this */ + need_dummy_vbo = true; + } + + if (need_dummy_vbo) { + for (i = 0; i < device->caps.MaxStreams; i++) { + if (!used_streams[i]) { + dummy_vbo_stream = i; + break; + } + } + } + /* there are less vertex shader inputs than stream slots, + * so if we need a slot for the dummy vbo, we should have found one */ + assert (!need_dummy_vbo || dummy_vbo_stream != -1); + + /* calculate vtxbuf_holes_map to match for update_vertex_buffers_sw() function */ + j = 0; + for (i = 0; i < device->caps.MaxStreams; i++) { + if (state->stream[i] || (need_dummy_vbo && dummy_vbo_stream == i)) { + vtxbuf_holes_map[i] = j; + j++; + } + } + + for (n = 0; n < vs->num_inputs; ++n) { + index = vdecl_index_map[n]; + if (index >= 0) { + ve.velems[n] = vdecl->elems[index]; + b = ve.velems[n].vertex_buffer_index; + ve.velems[n].vertex_buffer_index = vtxbuf_holes_map[b]; + /* XXX wine just uses 1 here: */ + if (state->stream_freq[b] & D3DSTREAMSOURCE_INSTANCEDATA) + ve.velems[n].instance_divisor = state->stream_freq[b] & 0x7FFFFF; + } else { + /* if the vertex declaration is incomplete compared to what the + * vertex shader needs, we bind a dummy vbo with 0 0 0 0. + * This is not precised by the spec, but is the behaviour + * tested on win */ + ve.velems[n].vertex_buffer_index = vtxbuf_holes_map[dummy_vbo_stream]; + ve.velems[n].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT; + ve.velems[n].src_offset = 0; + ve.velems[n].instance_divisor = 0; + ve.velems[n].dual_slot = false; + } + } + + ve.count = vs->num_inputs; + cso_set_vertex_elements(device->cso_sw, &ve); + return dummy_vbo_stream; +} + +static void +update_vertex_buffers_sw(struct NineDevice9 *device, int dummy_vbo_stream, + int start_vertice, int num_vertices) +{ + struct pipe_context *pipe = nine_context_get_pipe_acquire(device); + struct pipe_context *pipe_sw = device->pipe_sw; + struct nine_state *state = &device->state; + struct nine_state_sw_internal *sw_internal = &device->state_sw_internal; + struct pipe_vertex_buffer vbuffer[PIPE_MAX_ATTRIBS]; + unsigned vtxbuf_count = 0; + unsigned i, j = 0; + + for (i = 0; i < device->caps.MaxStreams; i++) { + if (dummy_vbo_stream == i) { + vbuffer[j].buffer.resource = NULL; + pipe_resource_reference(&vbuffer[j].buffer.resource, device->dummy_vbo_sw); + vbuffer[j].is_user_buffer = false; + vbuffer[j].buffer_offset = 0; + j++; + } else if (state->stream[i]) { + unsigned offset; + struct pipe_resource *buf; + struct pipe_box box; + void *userbuf; + + vbuffer[j] = state->vtxbuf[i]; + buf = NineVertexBuffer9_GetResource(state->stream[i], &offset); + + DBG("Locking %p (offset %d, length %d)\n", buf, + vbuffer[j].buffer_offset, num_vertices * state->vtxstride[i]); + + u_box_1d(vbuffer[j].buffer_offset + offset + start_vertice * + state->vtxstride[i], num_vertices * state->vtxstride[i], &box); + + userbuf = pipe->buffer_map(pipe, buf, 0, PIPE_MAP_READ, &box, + &(sw_internal->transfers_so[i])); + vbuffer[j].is_user_buffer = true; + vbuffer[j].buffer.user = userbuf; + + if (!device->driver_caps.user_sw_vbufs) { + vbuffer[j].buffer.resource = NULL; + vbuffer[j].is_user_buffer = false; + u_upload_data_ref(device->pipe_sw->stream_uploader, + 0, + box.width, + 16, + userbuf, + &(vbuffer[j].buffer_offset), + &(vbuffer[j].buffer.resource)); + u_upload_unmap(device->pipe_sw->stream_uploader); + } + j++; + } + } + + vtxbuf_count = j; + pipe_sw->set_vertex_buffers(pipe_sw, vtxbuf_count, vbuffer); + + nine_context_get_pipe_release(device); +} + +static void +update_vs_constants_sw(struct NineDevice9 *device) +{ + struct nine_state *state = &device->state; + struct pipe_context *pipe_sw = device->pipe_sw; + + DBG("updating\n"); + + { + struct pipe_constant_buffer cb; + const void *buf; + + cb.buffer = NULL; + cb.buffer_offset = 0; + cb.buffer_size = 4096 * sizeof(float[4]); + cb.user_buffer = state->vs_const_f; + + if (state->vs->lconstf.ranges) { + const struct nine_lconstf *lconstf = &device->state.vs->lconstf; + const struct nine_range *r = lconstf->ranges; + unsigned n = 0; + float *dst = device->state.vs_lconstf_temp; + float *src = (float *)cb.user_buffer; + memcpy(dst, src, 8192 * sizeof(float[4])); + 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; + } + + buf = cb.user_buffer; + + pipe_sw->set_constant_buffer(pipe_sw, MESA_SHADER_VERTEX, 0, &cb); + if (cb.buffer) + pipe_resource_reference(&cb.buffer, NULL); + + cb.user_buffer = (int8_t *)buf + 4096 * sizeof(float[4]); + + pipe_sw->set_constant_buffer(pipe_sw, MESA_SHADER_VERTEX, 1, &cb); + if (cb.buffer) + pipe_resource_reference(&cb.buffer, NULL); + } + + { + struct pipe_constant_buffer cb; + + cb.buffer = NULL; + cb.buffer_offset = 0; + cb.buffer_size = 2048 * sizeof(float[4]); + cb.user_buffer = state->vs_const_i; + + pipe_sw->set_constant_buffer(pipe_sw, MESA_SHADER_VERTEX, 2, &cb); + if (cb.buffer) + pipe_resource_reference(&cb.buffer, NULL); + } + + { + struct pipe_constant_buffer cb; + + cb.buffer = NULL; + cb.buffer_offset = 0; + cb.buffer_size = 512 * sizeof(float[4]); + cb.user_buffer = state->vs_const_b; + + pipe_sw->set_constant_buffer(pipe_sw, MESA_SHADER_VERTEX, 3, &cb); + if (cb.buffer) + pipe_resource_reference(&cb.buffer, NULL); + } + + { + struct pipe_constant_buffer cb; + const D3DVIEWPORT9 *vport = &device->state.viewport; + float viewport_data[8] = {(float)vport->Width * 0.5f, + (float)vport->Height * -0.5f, vport->MaxZ - vport->MinZ, 0.f, + (float)vport->Width * 0.5f + (float)vport->X, + (float)vport->Height * 0.5f + (float)vport->Y, + vport->MinZ, 0.f}; + + cb.buffer = NULL; + cb.buffer_offset = 0; + cb.buffer_size = 2 * sizeof(float[4]); + cb.user_buffer = viewport_data; + + { + u_upload_data_ref(device->pipe_sw->const_uploader, + 0, + cb.buffer_size, + 16, + cb.user_buffer, + &(cb.buffer_offset), + &(cb.buffer)); + u_upload_unmap(device->pipe_sw->const_uploader); + cb.user_buffer = NULL; + } + + pipe_sw->set_constant_buffer(pipe_sw, MESA_SHADER_VERTEX, 4, &cb); + if (cb.buffer) + pipe_resource_reference(&cb.buffer, NULL); + } + +} + +void +nine_state_prepare_draw_sw(struct NineDevice9 *device, struct NineVertexDeclaration9 *vdecl_out, + int start_vertice, int num_vertices, struct pipe_stream_output_info *so) +{ + struct nine_state *state = &device->state; + bool programmable_vs = state->vs && !(state->vdecl && state->vdecl->position_t); + struct NineVertexShader9 *vs = programmable_vs ? device->state.vs : device->ff.vs; + int dummy_vbo_stream; + + assert(programmable_vs); + + DBG("Preparing draw\n"); + cso_set_vertex_shader_handle(device->cso_sw, + NineVertexShader9_GetVariantProcessVertices(vs, vdecl_out, so)); + dummy_vbo_stream = update_vertex_elements_sw(device); + update_vertex_buffers_sw(device, dummy_vbo_stream, start_vertice, num_vertices); + update_vs_constants_sw(device); + DBG("Preparation succeeded\n"); +} + +void +nine_state_after_draw_sw(struct NineDevice9 *device) +{ + struct nine_state_sw_internal *sw_internal = &device->state_sw_internal; + struct pipe_context *pipe = nine_context_get_pipe_acquire(device); + struct pipe_context *pipe_sw = device->pipe_sw; + int i; + + pipe_sw->set_vertex_buffers(pipe_sw, 0, NULL); + for (i = 0; i < 4; i++) { + if (sw_internal->transfers_so[i]) + pipe->buffer_unmap(pipe, sw_internal->transfers_so[i]); + sw_internal->transfers_so[i] = NULL; + } + nine_context_get_pipe_release(device); +} + +void +nine_state_destroy_sw(struct NineDevice9 *device) +{ + (void) device; + /* Everything destroyed with cso */ +} + +/* +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 | NINE_STATE_MULTISAMPLE, + [D3DRS_FILLMODE] = NINE_STATE_RASTERIZER, + [D3DRS_SHADEMODE] = NINE_STATE_RASTERIZER | NINE_STATE_PS_PARAMS_MISC, + [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_BLEND, + [D3DRS_ALPHABLENDENABLE] = NINE_STATE_BLEND, + [D3DRS_FOGENABLE] = NINE_STATE_FF_SHADER | NINE_STATE_VS_PARAMS_MISC | NINE_STATE_PS_PARAMS_MISC | NINE_STATE_PS_CONST, + [D3DRS_SPECULARENABLE] = NINE_STATE_FF_LIGHTING, + [D3DRS_FOGCOLOR] = NINE_STATE_FF_PS_CONSTS | NINE_STATE_PS_CONST, + [D3DRS_FOGTABLEMODE] = NINE_STATE_FF_SHADER | NINE_STATE_PS_PARAMS_MISC | NINE_STATE_PS_CONST, + [D3DRS_FOGSTART] = NINE_STATE_FF_VS_OTHER | NINE_STATE_FF_PS_CONSTS | NINE_STATE_PS_CONST, + [D3DRS_FOGEND] = NINE_STATE_FF_VS_OTHER | NINE_STATE_FF_PS_CONSTS | NINE_STATE_PS_CONST, + [D3DRS_FOGDENSITY] = NINE_STATE_FF_VS_OTHER | NINE_STATE_FF_PS_CONSTS | NINE_STATE_PS_CONST, + [D3DRS_RANGEFOGENABLE] = NINE_STATE_FF_SHADER, + [D3DRS_STENCILENABLE] = NINE_STATE_DSA | NINE_STATE_MULTISAMPLE, + [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_PS_CONSTS, + [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_SHADER, + [D3DRS_COLORVERTEX] = NINE_STATE_FF_LIGHTING, + [D3DRS_LOCALVIEWER] = NINE_STATE_FF_LIGHTING, + [D3DRS_NORMALIZENORMALS] = NINE_STATE_FF_SHADER, + [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_SHADER, + [D3DRS_CLIPPLANEENABLE] = NINE_STATE_RASTERIZER, + [D3DRS_POINTSIZE] = NINE_STATE_RASTERIZER | NINE_STATE_FF_VS_OTHER, + [D3DRS_POINTSIZE_MIN] = NINE_STATE_RASTERIZER | NINE_STATE_FF_VS_OTHER | NINE_STATE_VS_PARAMS_MISC, + [D3DRS_POINTSPRITEENABLE] = NINE_STATE_RASTERIZER, + [D3DRS_POINTSCALEENABLE] = NINE_STATE_FF_SHADER, + [D3DRS_POINTSCALE_A] = NINE_STATE_FF_VS_OTHER, + [D3DRS_POINTSCALE_B] = NINE_STATE_FF_VS_OTHER, + [D3DRS_POINTSCALE_C] = NINE_STATE_FF_VS_OTHER, + [D3DRS_MULTISAMPLEANTIALIAS] = NINE_STATE_MULTISAMPLE, + [D3DRS_MULTISAMPLEMASK] = NINE_STATE_SAMPLE_MASK, + [D3DRS_PATCHEDGESTYLE] = NINE_STATE_UNHANDLED, + [D3DRS_DEBUGMONITORTOKEN] = NINE_STATE_UNHANDLED, + [D3DRS_POINTSIZE_MAX] = NINE_STATE_RASTERIZER | NINE_STATE_FF_VS_OTHER | NINE_STATE_VS_PARAMS_MISC, + [D3DRS_INDEXEDVERTEXBLENDENABLE] = NINE_STATE_FF_SHADER, + [D3DRS_COLORWRITEENABLE] = NINE_STATE_BLEND, + [D3DRS_TWEENFACTOR] = NINE_STATE_FF_VS_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 +}; + +/* Misc */ + +static D3DMATRIX nine_state_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 } }; + +void +nine_state_resize_transform(struct nine_ff_state *ff_state, unsigned N) +{ + unsigned n = ff_state->num_transforms; + + if (N <= n) + return; + + ff_state->transform = REALLOC(ff_state->transform, + n * sizeof(D3DMATRIX), + N * sizeof(D3DMATRIX)); + for (; n < N; ++n) + ff_state->transform[n] = nine_state_identity; + ff_state->num_transforms = N; +} + +D3DMATRIX * +nine_state_access_transform(struct nine_ff_state *ff_state, D3DTRANSFORMSTATETYPE t, + bool alloc) +{ + 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 >= ff_state->num_transforms) { + if (!alloc) + return &nine_state_identity; + nine_state_resize_transform(ff_state, index + 1); + } + return &ff_state->transform[index]; +} + +HRESULT +nine_state_set_light(struct nine_ff_state *ff_state, DWORD Index, + const D3DLIGHT9 *pLight) +{ + if (Index >= ff_state->num_lights) { + unsigned n = ff_state->num_lights; + unsigned N = Index + 1; + + ff_state->light = REALLOC(ff_state->light, n * sizeof(D3DLIGHT9), + N * sizeof(D3DLIGHT9)); + if (!ff_state->light) + return E_OUTOFMEMORY; + ff_state->num_lights = N; + + for (; n < Index; ++n) { + memset(&ff_state->light[n], 0, sizeof(D3DLIGHT9)); + ff_state->light[n].Type = (D3DLIGHTTYPE)NINED3DLIGHT_INVALID; + } + } + ff_state->light[Index] = *pLight; + + if (pLight->Type == D3DLIGHT_SPOT && pLight->Theta >= pLight->Phi) { + DBG("Warning: clamping D3DLIGHT9.Theta\n"); + ff_state->light[Index].Theta = ff_state->light[Index].Phi; + } + return D3D_OK; +} + +HRESULT +nine_state_light_enable(struct nine_ff_state *ff_state, + DWORD Index, BOOL Enable) +{ + unsigned i; + + user_assert(Index < ff_state->num_lights, D3DERR_INVALIDCALL); + + for (i = 0; i < ff_state->num_lights_active; ++i) { + if (ff_state->active_light[i] == Index) + break; + } + + if (Enable) { + if (i < ff_state->num_lights_active) + return D3D_OK; + /* XXX wine thinks this should still succeed: + */ + user_assert(i < NINE_MAX_LIGHTS_ACTIVE, D3DERR_INVALIDCALL); + + ff_state->active_light[i] = Index; + ff_state->num_lights_active++; + } else { + if (i == ff_state->num_lights_active) + return D3D_OK; + --ff_state->num_lights_active; + for (; i < ff_state->num_lights_active; ++i) + ff_state->active_light[i] = ff_state->active_light[i + 1]; + } + + return D3D_OK; +} + +#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/frontends/nine/nine_state.h b/src/gallium/frontends/nine/nine_state.h new file mode 100644 index 0000000..88ae703 --- /dev/null +++ b/src/gallium/frontends/nine/nine_state.h @@ -0,0 +1,702 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#ifndef _NINE_STATE_H_ +#define _NINE_STATE_H_ + +#include "d3d9.h" +#include "iunknown.h" +#include "nine_defines.h" +#include "pipe/p_state.h" +#include "util/list.h" + +#define NINED3DSAMP_MINLOD (D3DSAMP_DMAPOFFSET + 1) +#define NINED3DSAMP_SHADOW (D3DSAMP_DMAPOFFSET + 2) +#define NINED3DSAMP_CUBETEX (D3DSAMP_DMAPOFFSET + 3) + +#define NINED3DRS_VSPOINTSIZE (D3DRS_BLENDOPALPHA + 1) +#define NINED3DRS_RTMASK (D3DRS_BLENDOPALPHA + 2) +/* ALPHACOVERAGE: + * bit 0: enable alpha coverage + * bit 1: ATOC is on + */ +#define NINED3DRS_ALPHACOVERAGE (D3DRS_BLENDOPALPHA + 3) +#define NINED3DRS_MULTISAMPLE (D3DRS_BLENDOPALPHA + 4) +#define NINED3DRS_FETCH4 (D3DRS_BLENDOPALPHA + 5) +#define NINED3DRS_EMULATED_ALPHATEST (D3DRS_BLENDOPALPHA + 6) +#define NINED3DRS_POSITIONT (D3DRS_BLENDOPALPHA + 7) + +#define D3DRS_LAST D3DRS_BLENDOPALPHA +#define D3DSAMP_LAST D3DSAMP_DMAPOFFSET +#define NINED3DRS_LAST NINED3DRS_POSITIONT /* 217 */ +#define NINED3DSAMP_LAST NINED3DSAMP_CUBETEX /* 16 */ +#define NINED3DTSS_LAST D3DTSS_CONSTANT +#define NINED3DTS_LAST D3DTS_WORLDMATRIX(255) + +#define D3DRS_COUNT (D3DRS_LAST + 1) +#define D3DSAMP_COUNT (D3DSAMP_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_STREAMFREQ (1 << 14) +#define NINE_STATE_BLEND_COLOR (1 << 17) +#define NINE_STATE_STENCIL_REF (1 << 18) +#define NINE_STATE_SAMPLE_MASK (1 << 19) +#define NINE_STATE_FF (0x1f << 20) +#define NINE_STATE_FF_VS (0x17 << 20) +#define NINE_STATE_FF_PS (0x08 << 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_PS_CONSTS (1 << 23) +#define NINE_STATE_FF_VS_OTHER (1 << 24) +#define NINE_STATE_VS_PARAMS_MISC (1 << 25) +#define NINE_STATE_PS_PARAMS_MISC (1 << 26) +#define NINE_STATE_MULTISAMPLE (1 << 27) +#define NINE_STATE_SWVP (1 << 28) +#define NINE_STATE_ALL 0x1fffffff +#define NINE_STATE_UNHANDLED (1 << 29) + +/* These states affect the ff shader key, + * which we recompute every time. */ +#define NINE_STATE_FF_SHADER 0 + +#define NINE_STATE_COMMIT_DSA (1 << 0) +#define NINE_STATE_COMMIT_RASTERIZER (1 << 1) +#define NINE_STATE_COMMIT_BLEND (1 << 2) +#define NINE_STATE_COMMIT_CONST_VS (1 << 3) +#define NINE_STATE_COMMIT_CONST_PS (1 << 4) +#define NINE_STATE_COMMIT_VS (1 << 5) +#define NINE_STATE_COMMIT_PS (1 << 6) + + +#define NINE_MAX_SIMULTANEOUS_RENDERTARGETS 4 +#define NINE_MAX_CONST_F_PS3 224 +#define NINE_MAX_CONST_F 256 +#define NINE_MAX_CONST_I 16 +#define NINE_MAX_CONST_B 16 +#define NINE_MAX_CONST_F_SWVP 8192 +#define NINE_MAX_CONST_I_SWVP 2048 +#define NINE_MAX_CONST_B_SWVP 2048 +#define NINE_MAX_CONST_VS_SPE_OFFSET (NINE_MAX_CONST_F + (NINE_MAX_CONST_I + NINE_MAX_CONST_B / 4)) /* B consts count only 1/4 th */ +#define NINE_MAX_CONST_SWVP_SPE_OFFSET 3564 /* No app will read that far */ +#define NINE_MAX_CONST_VS_SPE 9 +#define NINE_MAX_CONST_ALL_VS (NINE_MAX_CONST_VS_SPE_OFFSET + NINE_MAX_CONST_VS_SPE) +#define NINE_MAX_CONST_PS_SPE_OFFSET (NINE_MAX_CONST_F_PS3 + (NINE_MAX_CONST_I + NINE_MAX_CONST_B / 4)) +/* bumpmap_vars (12), fog (2), D3DRS_ALPHAREF (1) */ +#define NINE_MAX_CONST_PS_SPE 15 +#define NINE_MAX_CONST_ALL_PS (NINE_MAX_CONST_PS_SPE_OFFSET + NINE_MAX_CONST_PS_SPE) + +#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 VS_CONST_F_SIZE(device) (device->may_swvp ? (NINE_MAX_CONST_F_SWVP * sizeof(float[4])) : (NINE_MAX_CONST_F * sizeof(float[4]))) +#define VS_CONST_I_SIZE(device) (device->may_swvp ? (NINE_MAX_CONST_I_SWVP * sizeof(int[4])) : (NINE_MAX_CONST_I * sizeof(int[4]))) +#define VS_CONST_B_SIZE(device) (device->may_swvp ? (NINE_MAX_CONST_B_SWVP * sizeof(BOOL)) : (NINE_MAX_CONST_B * sizeof(BOOL))) + + +#define NINE_MAX_TEXTURE_STAGES 8 + +#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_ff_state { + struct { + uint32_t tex_stage[NINE_MAX_TEXTURE_STAGES][(NINED3DTSS_COUNT + 31) / 32]; /* stateblocks only */ + uint32_t transform[(NINED3DTS_COUNT + 31) / 32]; + } changed; + + 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_TEXTURE_STAGES][NINED3DTSS_COUNT]; +}; + +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; + struct nine_range *vs_const_i; + uint16_t ps_const_i; /* NINE_MAX_CONST_I == 16 */ + struct nine_range *vs_const_b; + uint16_t ps_const_b; /* NINE_MAX_CONST_B == 16 */ + uint8_t ucp; + } changed; /* stateblocks only */ + + 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; + BOOL *vs_const_b; + float *vs_lconstf_temp; /* ProcessVertices */ + + struct NinePixelShader9 *ps; + float *ps_const_f; + int ps_const_i[NINE_MAX_CONST_I][4]; + BOOL ps_const_b[NINE_MAX_CONST_B]; + + struct NineVertexDeclaration9 *vdecl; + + struct NineIndexBuffer9 *idxbuf; + struct NineVertexBuffer9 *stream[PIPE_MAX_ATTRIBS]; + uint32_t stream_mask; /* i bit set for *stream[i] not NULL */ + struct pipe_vertex_buffer vtxbuf[PIPE_MAX_ATTRIBS]; /* vtxbuf.buffer unused */ + unsigned last_vtxbuf_count; + uint16_t vtxstride[PIPE_MAX_ATTRIBS]; + UINT stream_freq[PIPE_MAX_ATTRIBS]; + + struct pipe_clip_state clip; + + DWORD rs_advertised[NINED3DRS_COUNT]; /* the ones apps get with GetRenderState */ + + struct NineBaseTexture9 *texture[NINE_MAX_SAMPLERS]; /* PS, DMAP, VS */ + + DWORD samp_advertised[NINE_MAX_SAMPLERS][D3DSAMP_COUNT]; + + struct nine_ff_state ff; +}; + +struct nine_context { + struct { + uint32_t group; + uint16_t sampler[NINE_MAX_SAMPLERS]; + bool vtxbuf_dirty; + BOOL vs_const_f; + BOOL vs_const_i; + BOOL vs_const_b; + BOOL ps_const_f; + BOOL ps_const_i; + BOOL ps_const_b; + BOOL ucp; + } changed; + + uint32_t bumpmap_vars[6 * NINE_MAX_TEXTURE_STAGES]; + + struct NineSurface9 *rt[NINE_MAX_SIMULTANEOUS_RENDERTARGETS]; + struct NineSurface9 *ds; + + struct { + void *vs; + unsigned *vs_const_ranges; + unsigned vs_const_used_size; + void *ps; + unsigned *ps_const_ranges; + unsigned ps_const_used_size; + } cso_shader; + + struct pipe_context *pipe; + struct cso_context *cso; + + uint8_t rt_mask; + + D3DVIEWPORT9 viewport; + + struct pipe_scissor_state scissor; + + struct NineVertexShader9 *vs; + BOOL programmable_vs; + float *vs_const_f; + float *vs_const_f_swvp; + int *vs_const_i; + BOOL *vs_const_b; + float *vs_lconstf_temp; + + struct NinePixelShader9 *ps; + float *ps_const_f; + int ps_const_i[NINE_MAX_CONST_I][4]; + BOOL ps_const_b[NINE_MAX_CONST_B]; + BOOL zfog; + + struct NineVertexDeclaration9 *vdecl; + + unsigned num_vertex_buffers; + struct pipe_vertex_buffer vtxbuf[PIPE_MAX_ATTRIBS]; + uint32_t vtxbuf_mask; /* i bit set for context->vtxbuf[i].buffer.resource not NULL */ + uint16_t vtxstride[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_resource *idxbuf; + unsigned index_offset; + unsigned index_size; + + struct pipe_clip_state clip; + + DWORD rs[NINED3DRS_COUNT]; + + struct { + BOOL enabled; + BOOL shadow; + DWORD lod; + D3DRESOURCETYPE type; + struct pipe_resource *resource; + struct pipe_sampler_view *view[2]; + uint8_t pstype; + } texture[NINE_MAX_SAMPLERS]; + + DWORD samp[NINE_MAX_SAMPLERS][NINED3DSAMP_COUNT]; + + uint32_t samplers_shadow; + uint32_t samplers_fetch4; + + uint8_t bound_samplers_mask_vs; + uint8_t enabled_samplers_mask_vs; + uint8_t enabled_sampler_count_vs; + uint8_t enabled_sampler_count_ps; + uint16_t bound_samplers_mask_ps; + uint16_t enabled_samplers_mask_ps; + + int dummy_vbo_bound_at; /* -1 = not bound , >= 0 = bound index */ + + bool inline_constants; + + struct nine_ff_state ff; + + /* software vertex processing */ + bool swvp; + + uint32_t commit; + struct { + struct pipe_framebuffer_state fb; + struct pipe_depth_stencil_alpha_state dsa; + struct pipe_rasterizer_state rast; + struct pipe_blend_state blend; + struct pipe_constant_buffer cb_vs; + struct pipe_constant_buffer cb0_swvp; + struct pipe_constant_buffer cb1_swvp; + struct pipe_constant_buffer cb2_swvp; + struct pipe_constant_buffer cb3_swvp; + struct pipe_constant_buffer cb_ps; + struct pipe_constant_buffer cb_vs_ff; + struct pipe_constant_buffer cb_ps_ff; + } pipe_data; +}; + +struct nine_state_sw_internal { + struct pipe_transfer *transfers_so[4]; +}; + +struct nine_clipplane { + float plane[4]; +}; +/* 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; + +/* Internal multithreading: When enabled, the nine_context functions + * will append work to a worker thread when possible. Only the worker + * thread can access struct nine_context. */ + +void +nine_context_set_stream_source_apply(struct NineDevice9 *device, + UINT StreamNumber, + struct pipe_resource *res, + UINT OffsetInBytes, + UINT Stride); + +void +nine_context_set_indices_apply(struct NineDevice9 *device, + struct pipe_resource *res, + UINT IndexSize, + UINT OffsetInBytes); + +void +nine_context_set_render_state(struct NineDevice9 *device, + D3DRENDERSTATETYPE State, + DWORD Value); + +void +nine_context_set_texture(struct NineDevice9 *device, + DWORD Stage, + struct NineBaseTexture9 *tex); + +void +nine_context_set_sampler_state(struct NineDevice9 *device, + DWORD Sampler, + D3DSAMPLERSTATETYPE Type, + DWORD Value); + +void +nine_context_set_stream_source(struct NineDevice9 *device, + UINT StreamNumber, + struct NineVertexBuffer9 *pVBuf9, + UINT OffsetInBytes, + UINT Stride); + +void +nine_context_set_stream_source_freq(struct NineDevice9 *device, + UINT StreamNumber, + UINT Setting); + +void +nine_context_set_indices(struct NineDevice9 *device, + struct NineIndexBuffer9 *idxbuf); + +void +nine_context_set_vertex_declaration(struct NineDevice9 *device, + struct NineVertexDeclaration9 *vdecl); + +void +nine_context_set_vertex_shader(struct NineDevice9 *device, + struct NineVertexShader9 *pShader); + +void +nine_context_set_vertex_shader_constant_f(struct NineDevice9 *device, + UINT StartRegister, + const float *pConstantData, + const unsigned pConstantData_size, + UINT Vector4fCount); + +void +nine_context_set_vertex_shader_constant_i(struct NineDevice9 *device, + UINT StartRegister, + const int *pConstantData, + const unsigned pConstantData_size, + UINT Vector4iCount); + +void +nine_context_set_vertex_shader_constant_b(struct NineDevice9 *device, + UINT StartRegister, + const BOOL *pConstantData, + const unsigned pConstantData_size, + UINT BoolCount); + +void +nine_context_set_pixel_shader(struct NineDevice9 *device, + struct NinePixelShader9* ps); + +void +nine_context_set_pixel_shader_constant_f(struct NineDevice9 *device, + UINT StartRegister, + const float *pConstantData, + const unsigned pConstantData_size, + UINT Vector4fCount); + +void +nine_context_set_pixel_shader_constant_i(struct NineDevice9 *device, + UINT StartRegister, + const int *pConstantData, + const unsigned pConstantData_size, + UINT Vector4iCount); + +void +nine_context_set_pixel_shader_constant_b(struct NineDevice9 *device, + UINT StartRegister, + const BOOL *pConstantData, + const unsigned pConstantData_size, + UINT BoolCount); + +void +nine_context_set_viewport(struct NineDevice9 *device, + const D3DVIEWPORT9 *viewport); + +void +nine_context_set_scissor(struct NineDevice9 *device, + const struct pipe_scissor_state *scissor); + +void +nine_context_set_transform(struct NineDevice9 *device, + D3DTRANSFORMSTATETYPE State, + const D3DMATRIX *pMatrix); + +void +nine_context_set_material(struct NineDevice9 *device, + const D3DMATERIAL9 *pMaterial); + +void +nine_context_set_light(struct NineDevice9 *device, + DWORD Index, + const D3DLIGHT9 *pLight); + +void +nine_context_light_enable(struct NineDevice9 *device, + DWORD Index, + BOOL Enable); + +void +nine_context_set_texture_stage_state(struct NineDevice9 *device, + DWORD Stage, + D3DTEXTURESTAGESTATETYPE Type, + DWORD Value); + +void +nine_context_set_render_target(struct NineDevice9 *device, + DWORD RenderTargetIndex, + struct NineSurface9 *rt); + +void +nine_context_set_depth_stencil(struct NineDevice9 *device, + struct NineSurface9 *ds); + +void +nine_context_set_clip_plane(struct NineDevice9 *device, + DWORD Index, + const struct nine_clipplane *pPlane); + +void +nine_context_set_swvp(struct NineDevice9 *device, + bool swvp); + +void +nine_context_apply_stateblock(struct NineDevice9 *device, + const struct nine_state *src); + +void +nine_context_clear_fb(struct NineDevice9 *device, DWORD Count, + const D3DRECT *pRects, DWORD Flags, + D3DCOLOR Color, float Z, DWORD Stencil); + +void +nine_context_draw_primitive(struct NineDevice9 *device, + D3DPRIMITIVETYPE PrimitiveType, + UINT StartVertex, + UINT PrimitiveCount); + +void +nine_context_draw_indexed_primitive(struct NineDevice9 *device, + D3DPRIMITIVETYPE PrimitiveType, + INT BaseVertexIndex, + UINT MinVertexIndex, + UINT NumVertices, + UINT StartIndex, + UINT PrimitiveCount); + +void +nine_context_draw_indexed_primitive_from_vtxbuf_idxbuf(struct NineDevice9 *device, + D3DPRIMITIVETYPE PrimitiveType, + UINT MinVertexIndex, + UINT NumVertices, + UINT PrimitiveCount, + unsigned vbuf_stride, + struct pipe_vertex_buffer *vbuf, + struct pipe_resource *ibuf, + void *user_ibuf, + unsigned index_offset, + unsigned index_size); + +void +nine_context_resource_copy_region(struct NineDevice9 *device, + struct NineUnknown *dst, + struct NineUnknown *src, + struct pipe_resource* dst_res, + unsigned dst_level, + const struct pipe_box *dst_box, + struct pipe_resource* src_res, + unsigned src_level, + const struct pipe_box *src_box); + +void +nine_context_blit(struct NineDevice9 *device, + struct NineUnknown *dst, + struct NineUnknown *src, + struct pipe_blit_info *blit); + +void +nine_context_clear_render_target(struct NineDevice9 *device, + struct NineSurface9 *surface, + D3DCOLOR color, + UINT x, + UINT y, + UINT width, + UINT height); + +void +nine_context_gen_mipmap(struct NineDevice9 *device, + struct NineUnknown *dst, + struct pipe_resource *res, + UINT base_level, UINT last_level, + UINT first_layer, UINT last_layer, + UINT filter); + +void +nine_context_range_upload(struct NineDevice9 *device, + unsigned *counter, + struct NineUnknown *src_ref, + struct pipe_resource *res, + unsigned offset, + unsigned size, + unsigned usage, + const void *data); + +void +nine_context_box_upload(struct NineDevice9 *device, + unsigned *counter, + struct NineUnknown *src_ref, + struct pipe_resource *res, + unsigned level, + const struct pipe_box *dst_box, + enum pipe_format src_format, + const void *src, unsigned src_stride, + unsigned src_layer_stride, + const struct pipe_box *src_box); + +struct pipe_query * +nine_context_create_query(struct NineDevice9 *device, unsigned query_type); + +void +nine_context_destroy_query(struct NineDevice9 *device, struct pipe_query *query); + +void +nine_context_begin_query(struct NineDevice9 *device, unsigned *counter, struct pipe_query *query); + +void +nine_context_end_query(struct NineDevice9 *device, unsigned *counter, struct pipe_query *query); + +bool +nine_context_get_query_result(struct NineDevice9 *device, struct pipe_query *query, + unsigned *counter, bool flush, bool wait, + union pipe_query_result *result); + +void +nine_context_pipe_flush(struct NineDevice9 *device); + +void nine_state_restore_non_cso(struct NineDevice9 *device); +void nine_state_set_defaults(struct NineDevice9 *, const D3DCAPS9 *, + bool is_reset); +void nine_device_state_clear(struct NineDevice9 *); +void nine_context_clear(struct NineDevice9 *); +void nine_context_update_state(struct NineDevice9 *); + +/* HW pipe icin sabit tamponu gercek bir kaynaga yukler; Mesa 26.x'te + * threaded_context user_buffer kabul etmiyor. */ +void nine_upload_constant_buffer(struct nine_context *context, + struct pipe_constant_buffer *dst, + const void *data, unsigned size); + +void nine_state_init_sw(struct NineDevice9 *device); +void nine_state_prepare_draw_sw(struct NineDevice9 *device, + struct NineVertexDeclaration9 *vdecl_out, + int start_vertice, + int num_vertices, + struct pipe_stream_output_info *so); +void nine_state_after_draw_sw(struct NineDevice9 *device); +void nine_state_destroy_sw(struct NineDevice9 *device); + +void +nine_state_resize_transform(struct nine_ff_state *ff_state, unsigned N); + +/* 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_ff_state *, D3DTRANSFORMSTATETYPE, + bool alloc); + +HRESULT +nine_state_set_light(struct nine_ff_state *, DWORD, const D3DLIGHT9 *); + +HRESULT +nine_state_light_enable(struct nine_ff_state *, + DWORD, BOOL); + +const char *nine_d3drs_to_string(DWORD State); + +/* CSMT functions */ +struct csmt_context; + +struct csmt_context * +nine_csmt_create( struct NineDevice9 *This ); + +void +nine_csmt_destroy( struct NineDevice9 *This, struct csmt_context *ctx ); + +/* Flushes and waits everything is executed */ +void +nine_csmt_process( struct NineDevice9 *This ); + +/* Flushes and doesn't wait */ +void +nine_csmt_flush( struct NineDevice9 *This ); + +/* Get the pipe_context (should not be called from the worker thread). + * All the work in the worker thread is finished before returning. */ +struct pipe_context * +nine_context_get_pipe( struct NineDevice9 *device ); + +/* Can be called from all threads */ +struct pipe_context * +nine_context_get_pipe_multithread( struct NineDevice9 *device ); + + +/* Get the pipe_context (should not be called from the worker thread). + * All the work in the worker thread is paused before returning. + * It is necessary to release in order to restart the thread. + * This is intended for use of the nine_context pipe_context that don't + * need the worker thread to finish all queued job. */ +struct pipe_context * +nine_context_get_pipe_acquire( struct NineDevice9 *device ); + +void +nine_context_get_pipe_release( struct NineDevice9 *device ); + +bool +nine_context_is_worker( struct NineDevice9 *device ); + +#endif /* _NINE_STATE_H_ */ diff --git a/src/gallium/frontends/nine/nineexoverlayextension.c b/src/gallium/frontends/nine/nineexoverlayextension.c new file mode 100644 index 0000000..4ee21a7 --- /dev/null +++ b/src/gallium/frontends/nine/nineexoverlayextension.c @@ -0,0 +1,29 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#include "nineexoverlayextension.h" + +#define DBG_CHANNEL DBG_OVERLAYEXTENSION + +HRESULT NINE_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/frontends/nine/nineexoverlayextension.h b/src/gallium/frontends/nine/nineexoverlayextension.h new file mode 100644 index 0000000..8e90336 --- /dev/null +++ b/src/gallium/frontends/nine/nineexoverlayextension.h @@ -0,0 +1,32 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#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 NINE_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/frontends/nine/pixelshader9.c b/src/gallium/frontends/nine/pixelshader9.c new file mode 100644 index 0000000..1a7a2b6 --- /dev/null +++ b/src/gallium/frontends/nine/pixelshader9.c @@ -0,0 +1,255 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#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; + struct pipe_context *pipe; + HRESULT hr; + + DBG("This=%p pParams=%p pFunction=%p cso=%p\n", This, pParams, pFunction, cso); + + hr = NineUnknown_ctor(&This->base, pParams); + if (FAILED(hr)) + return hr; + + if (cso) { + This->ff_cso = cso; + return D3D_OK; + } + device = This->base.device; + + info.type = MESA_SHADER_FRAGMENT; + info.byte_code = pFunction; + info.const_i_base = NINE_CONST_I_BASE(NINE_MAX_CONST_F_PS3) / 16; + info.const_b_base = NINE_CONST_B_BASE(NINE_MAX_CONST_F_PS3) / 16; + info.sampler_mask_shadow = 0x0; + info.fetch4 = 0x0; + info.force_color_in_centroid = 0; + info.sampler_ps1xtypes = 0x0; + info.fog_enable = 0; + info.projected = 0; + info.alpha_test_emulation = 0; + info.color_flatshade = 0; + info.add_constants_defs.c_combination = NULL; + info.add_constants_defs.int_const_added = NULL; + info.add_constants_defs.bool_const_added = NULL; + info.process_vertices = false; + info.swvp_on = false; + + pipe = nine_context_get_pipe_acquire(device); + hr = nine_translate_shader(device, &info, pipe); + nine_context_get_pipe_release(device); + 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->variant.const_ranges = info.const_ranges; + This->variant.const_used_size = info.const_used_size; + This->last_cso = info.cso; + This->last_const_ranges = info.const_ranges; + This->last_const_used_size = info.const_used_size; + This->last_key = 0; + + This->sampler_mask = info.sampler_mask; + This->rt_mask = info.rt_mask; + This->bumpenvmat_needed = info.bumpenvmat_needed; + + memcpy(This->int_slots_used, info.int_slots_used, sizeof(This->int_slots_used)); + memcpy(This->bool_slots_used, info.bool_slots_used, sizeof(This->bool_slots_used)); + + This->const_int_slots = info.const_int_slots; + This->const_bool_slots = info.const_bool_slots; + + This->c_combinations = NULL; + + /* no constant relative addressing for ps */ + assert(info.lconstf.data == NULL); + assert(info.lconstf.ranges == NULL); + + return D3D_OK; +} + +void +NinePixelShader9_dtor( struct NinePixelShader9 *This ) +{ + DBG("This=%p\n", This); + + if (This->base.device) { + struct pipe_context *pipe = nine_context_get_pipe_multithread(This->base.device); + struct nine_shader_variant *var = &This->variant; + + do { + if (var->cso) { + if (This->base.device->context.cso_shader.ps == var->cso) { + /* unbind because it is illegal to delete something bound */ + pipe->bind_fs_state(pipe, NULL); + /* This will rebind cso_shader.ps in case somehow actually + * an identical shader with same cso is bound */ + This->base.device->context.commit |= NINE_STATE_COMMIT_PS; + } + pipe->delete_fs_state(pipe, var->cso); + FREE(var->const_ranges); + } + var = var->next; + } while (var); + + if (This->ff_cso) { + if (This->ff_cso == This->base.device->context.cso_shader.ps) { + pipe->bind_fs_state(pipe, NULL); + This->base.device->context.commit |= NINE_STATE_COMMIT_PS; + } + pipe->delete_fs_state(pipe, This->ff_cso); + } + } + nine_shader_variants_free(&This->variant); + + nine_shader_constant_combination_free(This->c_combinations); + + FREE((void *)This->byte_code.tokens); /* const_cast */ + + NineUnknown_dtor(&This->base); +} + +HRESULT NINE_WINAPI +NinePixelShader9_GetFunction( struct NinePixelShader9 *This, + void *pData, + UINT *pSizeOfData ) +{ + DBG("This=%p pData=%p pSizeOfData=%p\n", This, pData, 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, + unsigned **const_ranges, + unsigned *const_used_size ) +{ + /* GetVariant is called from nine_context, thus we can + * get pipe directly */ + struct pipe_context *pipe = This->base.device->context.pipe; + void *cso; + uint64_t key; + + key = This->next_key; + if (key == This->last_key) { + *const_ranges = This->last_const_ranges; + *const_used_size = This->last_const_used_size; + return This->last_cso; + } + + cso = nine_shader_variant_get(&This->variant, const_ranges, const_used_size, key); + if (!cso) { + struct NineDevice9 *device = This->base.device; + struct nine_shader_info info; + HRESULT hr; + + info.type = MESA_SHADER_FRAGMENT; + info.const_i_base = NINE_CONST_I_BASE(NINE_MAX_CONST_F_PS3) / 16; + info.const_b_base = NINE_CONST_B_BASE(NINE_MAX_CONST_F_PS3) / 16; + info.byte_code = This->byte_code.tokens; + info.sampler_mask_shadow = key & 0xffff; + /* intended overlap with sampler_mask_shadow */ + if (unlikely(This->byte_code.version < 0x20)) { + if (This->byte_code.version < 0x14) { + info.sampler_ps1xtypes = (key >> 4) & 0xff; + info.projected = (key >> 12) & 0xff; + } else { + info.sampler_ps1xtypes = (key >> 6) & 0xfff; + info.projected = 0; + } + } else { + info.sampler_ps1xtypes = 0; + info.projected = 0; + } + info.fog_enable = device->context.rs[D3DRS_FOGENABLE]; + info.fog_mode = device->context.rs[D3DRS_FOGTABLEMODE]; + info.zfog = device->context.zfog; + info.add_constants_defs.c_combination = + nine_shader_constant_combination_get(This->c_combinations, (key >> 24) & 0xff); + info.add_constants_defs.int_const_added = &This->int_slots_used; + info.add_constants_defs.bool_const_added = &This->bool_slots_used; + info.fetch4 = (key >> 32) & 0xffff; + info.force_color_in_centroid = (key >> 48) & 1; + info.alpha_test_emulation = (key >> 49) & 0x7; + info.color_flatshade = (key >> 52) & 1; + info.force_color_in_centroid &= !info.color_flatshade; /* centroid doesn't make sense with flatshade */ + info.process_vertices = false; + info.swvp_on = false; + + hr = nine_translate_shader(This->base.device, &info, pipe); + if (FAILED(hr)) + return NULL; + nine_shader_variant_add(&This->variant, key, info.cso, + info.const_ranges, info.const_used_size); + cso = info.cso; + *const_ranges = info.const_ranges; + *const_used_size = info.const_used_size; + } + + This->last_key = key; + This->last_cso = cso; + This->last_const_ranges = *const_ranges; + This->last_const_used_size = *const_used_size; + + 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 ) +{ + if (cso) { /* ff shader. Needs to start with bind count */ + NINE_DEVICE_CHILD_BIND_NEW(PixelShader9, ppOut, pDevice, pFunction, cso); + } else { + NINE_DEVICE_CHILD_NEW(PixelShader9, ppOut, pDevice, pFunction, cso); + } +} diff --git a/src/gallium/frontends/nine/pixelshader9.h b/src/gallium/frontends/nine/pixelshader9.h new file mode 100644 index 0000000..0bf79e3 --- /dev/null +++ b/src/gallium/frontends/nine/pixelshader9.h @@ -0,0 +1,150 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#ifndef _NINE_PIXELSHADER9_H_ +#define _NINE_PIXELSHADER9_H_ + +#include "iunknown.h" +#include "nine_shader.h" +#include "nine_state.h" +#include "basetexture9.h" +#include "nine_ff.h" +#include "surface9.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; + + uint8_t bumpenvmat_needed; + uint16_t sampler_mask; + uint8_t rt_mask; + + bool int_slots_used[NINE_MAX_CONST_I]; + bool bool_slots_used[NINE_MAX_CONST_B]; + + unsigned const_int_slots; + unsigned const_bool_slots; + + struct nine_shader_constant_combination *c_combinations; + + uint64_t ff_key[6]; + void *ff_cso; + + uint64_t last_key; + void *last_cso; + unsigned *last_const_ranges; + unsigned last_const_used_size; /* in bytes */ + + uint64_t next_key; +}; +static inline struct NinePixelShader9 * +NinePixelShader9( void *data ) +{ + return (struct NinePixelShader9 *)data; +} + +static inline BOOL +NinePixelShader9_UpdateKey( struct NinePixelShader9 *ps, + struct nine_context *context ) +{ + uint16_t samplers_shadow; + uint16_t samplers_fetch4; + uint16_t samplers_ps1_types; + uint8_t projected; + uint64_t key; + BOOL res; + + samplers_shadow = (uint16_t)((context->samplers_shadow & NINE_PS_SAMPLERS_MASK) >> NINE_SAMPLER_PS(0)); + samplers_fetch4 = (uint16_t)((context->samplers_fetch4 & NINE_PS_SAMPLERS_MASK) >> NINE_SAMPLER_PS(0)); + key = samplers_shadow & ps->sampler_mask; + samplers_fetch4 &= ps->sampler_mask; + + if (unlikely(ps->byte_code.version < 0x20)) { + /* variable targets */ + uint32_t m = ps->sampler_mask; + samplers_ps1_types = 0; + while (m) { + int s = ffs(m) - 1; + m &= ~(1 << s); + samplers_ps1_types |= (context->texture[s].enabled ? context->texture[s].pstype : 1) << (s * 2); + } + /* Note: For ps 1.X, only samplers 0 1 2 and 3 are available (except 1.4 where 4 and 5 are available). + * ps < 1.4: samplers_shadow 4b, samplers_ps1_types 8b, projected 8b + * ps 1.4: samplers_shadow 6b, samplers_ps1_types 12b + * Tot ps X.X samplers_shadow + extra: 20b */ + assert((ps->byte_code.version < 0x14 && !(ps->sampler_mask & 0xFFF0)) || !(ps->sampler_mask & 0xFFC0)); + + if (unlikely(ps->byte_code.version < 0x14)) { + key |= samplers_ps1_types << 4; + projected = nine_ff_get_projected_key_programmable(context); + key |= ((uint64_t) projected) << 12; + } else { + key |= samplers_ps1_types << 6; + } + } + + if (ps->byte_code.version < 0x30 && context->rs[D3DRS_FOGENABLE]) { + key |= 1 << 20; + key |= ((uint64_t)context->rs[D3DRS_FOGTABLEMODE]) << 21; /* 2 bits */ + key |= ((uint64_t)context->zfog) << 23; + } + + if ((ps->const_int_slots > 0 || ps->const_bool_slots > 0) && context->inline_constants) + key |= ((uint64_t)nine_shader_constant_combination_key(&ps->c_combinations, + ps->int_slots_used, + ps->bool_slots_used, + (void *)context->ps_const_i, + context->ps_const_b)) << 24; + + key |= ((uint64_t)(context->rs[NINED3DRS_FETCH4] & samplers_fetch4)) << 32; /* 16 bits */ + + /* centroid interpolation automatically used for color ps inputs */ + if (context->rt[0]->base.info.nr_samples) + key |= ((uint64_t)1) << 48; + key |= ((uint64_t)(context->rs[NINED3DRS_EMULATED_ALPHATEST] & 0x7)) << 49; /* 3 bits */ + if (context->rs[D3DRS_SHADEMODE] == D3DSHADE_FLAT) + key |= ((uint64_t)1) << 52; + + res = ps->last_key != key; + if (res) + ps->next_key = key; + return res; +} + +void * +NinePixelShader9_GetVariant( struct NinePixelShader9 *ps, + unsigned **const_ranges, + unsigned *const_used_size ); + +/*** 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 NINE_WINAPI +NinePixelShader9_GetFunction( struct NinePixelShader9 *This, + void *pData, + UINT *pSizeOfData ); + +#endif /* _NINE_PIXELSHADER9_H_ */ diff --git a/src/gallium/frontends/nine/query9.c b/src/gallium/frontends/nine/query9.c new file mode 100644 index 0000000..d1c3816 --- /dev/null +++ b/src/gallium/frontends/nine/query9.c @@ -0,0 +1,296 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#include "device9.h" +#include "nine_state.h" +#include "query9.h" +#include "nine_helpers.h" +#include "pipe/p_screen.h" +#include "pipe/p_context.h" +#include "util/u_math.h" +#include "nine_dump.h" + +#define DBG_CHANNEL DBG_QUERY + +static inline unsigned +d3dquerytype_to_pipe_query(struct pipe_screen *screen, D3DQUERYTYPE type) +{ + switch (type) { + case D3DQUERYTYPE_EVENT: + return PIPE_QUERY_GPU_FINISHED; + case D3DQUERYTYPE_OCCLUSION: + return screen->caps.occlusion_query ? + PIPE_QUERY_OCCLUSION_COUNTER : PIPE_QUERY_TYPES; + case D3DQUERYTYPE_TIMESTAMP: + return screen->caps.query_timestamp ? + PIPE_QUERY_TIMESTAMP : PIPE_QUERY_TYPES; + case D3DQUERYTYPE_TIMESTAMPDISJOINT: + case D3DQUERYTYPE_TIMESTAMPFREQ: + return screen->caps.query_timestamp ? + PIPE_QUERY_TIMESTAMP_DISJOINT : PIPE_QUERY_TYPES; + case D3DQUERYTYPE_VERTEXSTATS: + return screen->caps.query_pipeline_statistics ? + PIPE_QUERY_PIPELINE_STATISTICS : PIPE_QUERY_TYPES; + default: + return PIPE_QUERY_TYPES; /* Query not supported */ + } +} + +#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_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); + default: + assert(0); + return 0; + } +} + +HRESULT +nine_is_query_supported(struct pipe_screen *screen, D3DQUERYTYPE type) +{ + const unsigned ptype = d3dquerytype_to_pipe_query(screen, 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 NineDevice9 *device = pParams->device; + const unsigned ptype = d3dquerytype_to_pipe_query(device->screen, Type); + HRESULT hr; + + DBG("This=%p pParams=%p Type=%d\n", This, pParams, Type); + + 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 = nine_context_create_query(device, ptype); + if (!This->pq) + return E_OUTOFMEMORY; + } else { + assert(0); /* we have checked this case before */ + } + + 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 NineDevice9 *device = This->base.device; + + DBG("This=%p\n", This); + + if (This->pq) { + if (This->state == NINE_QUERY_STATE_RUNNING) + nine_context_end_query(device, &This->counter, This->pq); + nine_context_destroy_query(device, This->pq); + } + + NineUnknown_dtor(&This->base); +} + +D3DQUERYTYPE NINE_WINAPI +NineQuery9_GetType( struct NineQuery9 *This ) +{ + return This->type; +} + +DWORD NINE_WINAPI +NineQuery9_GetDataSize( struct NineQuery9 *This ) +{ + return This->result_size; +} + +HRESULT NINE_WINAPI +NineQuery9_Issue( struct NineQuery9 *This, + DWORD dwIssueFlags ) +{ + struct NineDevice9 *device = This->base.device; + + DBG("This=%p dwIssueFlags=%d\n", This, dwIssueFlags); + + user_assert((dwIssueFlags == D3DISSUE_BEGIN) || + (dwIssueFlags == 0) || + (dwIssueFlags == D3DISSUE_END), D3DERR_INVALIDCALL); + + /* Wine tests: always return D3D_OK on D3DISSUE_BEGIN + * even when the call is supposed to be forbidden */ + if (dwIssueFlags == D3DISSUE_BEGIN && This->instant) + return D3D_OK; + + if (dwIssueFlags == D3DISSUE_BEGIN) { + if (This->state == NINE_QUERY_STATE_RUNNING) + nine_context_end_query(device, &This->counter, This->pq); + nine_context_begin_query(device, &This->counter, This->pq); + This->state = NINE_QUERY_STATE_RUNNING; + } else { + if (This->state != NINE_QUERY_STATE_RUNNING && + This->type != D3DQUERYTYPE_EVENT && + This->type != D3DQUERYTYPE_TIMESTAMP) + nine_context_begin_query(device, &This->counter, This->pq); + nine_context_end_query(device, &This->counter, This->pq); + This->state = NINE_QUERY_STATE_ENDED; + } + return D3D_OK; +} + +union nine_query_result +{ + D3DDEVINFO_D3DVERTEXSTATS vertexstats; + DWORD dw; + BOOL b; + UINT64 u64; +}; + +HRESULT NINE_WINAPI +NineQuery9_GetData( struct NineQuery9 *This, + void *pData, + DWORD dwSize, + DWORD dwGetDataFlags ) +{ + struct NineDevice9 *device = This->base.device; + bool ok, wait_query_result = false; + union pipe_query_result presult; + union nine_query_result nresult; + + DBG("This=%p pData=%p dwSize=%d dwGetDataFlags=%d\n", + This, pData, dwSize, dwGetDataFlags); + + /* according to spec we should return D3DERR_INVALIDCALL here, but + * wine returns S_FALSE because it is apparently the behaviour + * on windows */ + user_assert(This->state != NINE_QUERY_STATE_RUNNING, S_FALSE); + user_assert(dwSize == 0 || pData, D3DERR_INVALIDCALL); + user_assert(dwGetDataFlags == 0 || + dwGetDataFlags == D3DGETDATA_FLUSH, D3DERR_INVALIDCALL); + + if (This->state == NINE_QUERY_STATE_FRESH) { + /* App forgot calling Issue. call it for it. + * However Wine states that return value should + * be S_OK, so wait for the result to return S_OK. */ + NineQuery9_Issue(This, D3DISSUE_END); + wait_query_result = true; + } + + /* The documentation mentions no special case for D3DQUERYTYPE_TIMESTAMP. + * However Windows tests show that the query always succeeds when + * D3DGETDATA_FLUSH is specified. */ + if (This->type == D3DQUERYTYPE_TIMESTAMP && + (dwGetDataFlags & D3DGETDATA_FLUSH)) + wait_query_result = true; + + + /* Note: We ignore dwGetDataFlags, because get_query_result will + * flush automatically if needed */ + + ok = nine_context_get_query_result(device, This->pq, &This->counter, + !!(dwGetDataFlags & D3DGETDATA_FLUSH), + wait_query_result, &presult); + + if (!ok) 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: + /* Applications use it to convert the TIMESTAMP value to time. + AMD drivers on win seem to return the actual hardware clock + resolution and corresponding values in TIMESTAMP. + However, this behaviour is not easy to replicate here. + So instead we do what wine and opengl do, and use + nanoseconds TIMESTAMPs. + (Which is also the unit used by PIPE_QUERY_TIMESTAMP.) + */ + nresult.u64 = 1000000000; + break; + case D3DQUERYTYPE_VERTEXSTATS: + nresult.vertexstats.NumRenderedTriangles = + presult.pipeline_statistics.c_invocations; + nresult.vertexstats.NumExtraClippingTriangles = + presult.pipeline_statistics.c_primitives; + 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/frontends/nine/query9.h b/src/gallium/frontends/nine/query9.h new file mode 100644 index 0000000..84b94b3 --- /dev/null +++ b/src/gallium/frontends/nine/query9.h @@ -0,0 +1,66 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#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, +}; + +struct NineQuery9 +{ + struct NineUnknown base; + struct pipe_query *pq; + DWORD result_size; + D3DQUERYTYPE type; + enum nine_query_state state; + bool instant; /* true if D3DISSUE_BEGIN is not needed / invalid */ + unsigned counter; /* Number of pending Begin/End (0 if internal multithreading off) */ +}; +static inline struct NineQuery9 * +NineQuery9( void *data ) +{ + return (struct NineQuery9 *)data; +} + +HRESULT +nine_is_query_supported(struct pipe_screen *screen, 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 NINE_WINAPI +NineQuery9_GetType( struct NineQuery9 *This ); + +DWORD NINE_WINAPI +NineQuery9_GetDataSize( struct NineQuery9 *This ); + +HRESULT NINE_WINAPI +NineQuery9_Issue( struct NineQuery9 *This, + DWORD dwIssueFlags ); + +HRESULT NINE_WINAPI +NineQuery9_GetData( struct NineQuery9 *This, + void *pData, + DWORD dwSize, + DWORD dwGetDataFlags ); + +#endif /* _NINE_QUERY9_H_ */ diff --git a/src/gallium/frontends/nine/resource9.c b/src/gallium/frontends/nine/resource9.c new file mode 100644 index 0000000..387007f --- /dev/null +++ b/src/gallium/frontends/nine/resource9.c @@ -0,0 +1,164 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#include "resource9.h" +#include "device9.h" +#include "nine_helpers.h" +#include "nine_defines.h" + +#include "util/u_inlines.h" +#include "util/u_resource.h" + +#include "pipe/p_screen.h" + +#define DBG_CHANNEL DBG_RESOURCE + +HRESULT +NineResource9_ctor( struct NineResource9 *This, + struct NineUnknownParams *pParams, + struct pipe_resource *initResource, + BOOL Allocate, + D3DRESOURCETYPE Type, + D3DPOOL Pool, + DWORD Usage) +{ + struct pipe_screen *screen; + HRESULT hr; + + DBG("This=%p pParams=%p initResource=%p Allocate=%d " + "Type=%d Pool=%d Usage=%d\n", + This, pParams, initResource, (int) Allocate, + Type, Pool, Usage); + + hr = NineUnknown_ctor(&This->base, pParams); + if (FAILED(hr)) + return hr; + + This->info.screen = screen = This->base.device->screen; + if (initResource) + pipe_resource_reference(&This->resource, initResource); + + if (Allocate) { + assert(!initResource); + + /* On Windows it is possible allocation fails when + * IDirect3DDevice9::GetAvailableTextureMem() still reports + * enough free space. + * + * Some games allocate surfaces + * in a loop until they receive D3DERR_OUTOFVIDEOMEMORY to measure + * the available texture memory size. + * + * We are not using the drivers VRAM statistics because: + * * This would add overhead to each resource allocation. + * * Freeing memory is lazy and takes some time, but applications + * expects the memory counter to change immediately after allocating + * or freeing memory. + * + * Vertexbuffers and indexbuffers are not accounted ! + */ + if (This->info.target != PIPE_BUFFER) { + This->size = util_resource_size(&This->info); + + p_atomic_add(&This->base.device->available_texture_mem, -This->size); + /* Before failing allocation, evict MANAGED memory */ + if (This->base.device && + p_atomic_read(&This->base.device->available_texture_mem) <= + This->base.device->available_texture_limit) + NineDevice9_EvictManagedResourcesInternal(This->base.device); + if (p_atomic_read(&This->base.device->available_texture_mem) <= + This->base.device->available_texture_limit) { + DBG("Memory allocation failure: software limit\n"); + return D3DERR_OUTOFVIDEOMEMORY; + } + } + + DBG("(%p) Creating pipe_resource.\n", This); + This->resource = nine_resource_create_with_retry(This->base.device, screen, &This->info); + if (!This->resource) + return D3DERR_OUTOFVIDEOMEMORY; + } + + DBG("Current texture memory count: (%d/%d)KB\n", + (int)(This->base.device->available_texture_mem >> 10), + (int)(This->base.device->available_texture_limit >> 10)); + + This->type = Type; + This->pool = Pool; + This->usage = Usage; + This->priority = 0; + + return D3D_OK; +} + +void +NineResource9_dtor( struct NineResource9 *This ) +{ + DBG("This=%p\n", This); + + /* NOTE: We do have to use refcounting, the driver might + * still hold a reference. */ + pipe_resource_reference(&This->resource, NULL); + + /* NOTE: size is 0, unless something has actually been allocated */ + if (This->base.device) + p_atomic_add(&This->base.device->available_texture_mem, This->size); + + NineUnknown_dtor(&This->base); +} + +struct pipe_resource * +NineResource9_GetResource( struct NineResource9 *This ) +{ + return This->resource; +} + +D3DPOOL +NineResource9_GetPool( struct NineResource9 *This ) +{ + return This->pool; +} + +DWORD NINE_WINAPI +NineResource9_SetPriority( struct NineResource9 *This, + DWORD PriorityNew ) +{ + DWORD prev; + DBG("This=%p, PriorityNew=%d\n", This, PriorityNew); + + if (This->pool != D3DPOOL_MANAGED || This->type == D3DRTYPE_SURFACE) + return 0; + + prev = This->priority; + This->priority = PriorityNew; + return prev; +} + +DWORD NINE_WINAPI +NineResource9_GetPriority( struct NineResource9 *This ) +{ + if (This->pool != D3DPOOL_MANAGED || This->type == D3DRTYPE_SURFACE) + return 0; + + return This->priority; +} + +/* NOTE: Don't forget to adjust locked vtable if you change this ! */ +void NINE_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 NINE_WINAPI +NineResource9_GetType( struct NineResource9 *This ) +{ + return This->type; +} diff --git a/src/gallium/frontends/nine/resource9.h b/src/gallium/frontends/nine/resource9.h new file mode 100644 index 0000000..8a089e3 --- /dev/null +++ b/src/gallium/frontends/nine/resource9.h @@ -0,0 +1,72 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#ifndef _NINE_RESOURCE9_H_ +#define _NINE_RESOURCE9_H_ + +#include "iunknown.h" +#include "pipe/p_state.h" + +struct pipe_screen; +struct hash_table; +struct NineDevice9; + +struct NineResource9 +{ + struct NineUnknown base; + + struct pipe_resource *resource; /* device resource */ + + D3DRESOURCETYPE type; + D3DPOOL pool; + DWORD priority; + DWORD usage; + + struct pipe_resource info; /* resource configuration */ + + long long size; +}; +static inline struct NineResource9 * +NineResource9( void *data ) +{ + return (struct NineResource9 *)data; +} + +HRESULT +NineResource9_ctor( struct NineResource9 *This, + struct NineUnknownParams *pParams, + struct pipe_resource *initResource, + BOOL Allocate, + D3DRESOURCETYPE Type, + D3DPOOL Pool, + DWORD Usage); + +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 ***/ + +DWORD NINE_WINAPI +NineResource9_SetPriority( struct NineResource9 *This, + DWORD PriorityNew ); + +DWORD NINE_WINAPI +NineResource9_GetPriority( struct NineResource9 *This ); + +void NINE_WINAPI +NineResource9_PreLoad( struct NineResource9 *This ); + +D3DRESOURCETYPE NINE_WINAPI +NineResource9_GetType( struct NineResource9 *This ); + +#endif /* _NINE_RESOURCE9_H_ */ diff --git a/src/gallium/frontends/nine/stateblock9.c b/src/gallium/frontends/nine/stateblock9.c new file mode 100644 index 0000000..41d94b3 --- /dev/null +++ b/src/gallium/frontends/nine/stateblock9.c @@ -0,0 +1,585 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#include "stateblock9.h" +#include "device9.h" +#include "basetexture9.h" +#include "nine_helpers.h" +#include "vertexdeclaration9.h" +#include "vertexbuffer9.h" +#include "indexbuffer9.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); + + DBG("This=%p pParams=%p type=%d\n", This, pParams, type); + + if (FAILED(hr)) + return hr; + + This->type = type; + + This->state.vs_const_f = MALLOC(VS_CONST_F_SIZE(This->base.device)); + This->state.ps_const_f = MALLOC(This->base.device->ps_const_size); + This->state.vs_const_i = MALLOC(VS_CONST_I_SIZE(This->base.device)); + This->state.vs_const_b = MALLOC(VS_CONST_B_SIZE(This->base.device)); + if (!This->state.vs_const_f || !This->state.ps_const_f || + !This->state.vs_const_i || !This->state.vs_const_b) + 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; + unsigned i; + + for (i = 0; i < ARRAY_SIZE(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) + nine_bind(&state->texture[i], NULL); + + FREE(state->vs_const_f); + FREE(state->ps_const_f); + FREE(state->vs_const_i); + FREE(state->vs_const_b); + + FREE(state->ff.light); + + 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); + } + if (This->state.changed.vs_const_i) { + for (r = This->state.changed.vs_const_i; r->next; r = r->next); + nine_range_pool_put_chain(pool, This->state.changed.vs_const_i, r); + } + if (This->state.changed.vs_const_b) { + for (r = This->state.changed.vs_const_b; r->next; r = r->next); + nine_range_pool_put_chain(pool, This->state.changed.vs_const_b, r); + } + + NineUnknown_dtor(&This->base); +} + +static void +NineStateBlock9_BindBuffer( struct NineDevice9 *device, + bool applyToDevice, + struct NineBuffer9 **slot, + struct NineBuffer9 *buf ) +{ + if (applyToDevice) + NineBindBufferToDevice(device, slot, buf); + else + nine_bind(slot, buf); +} + +static void +NineStateBlock9_BindTexture( struct NineDevice9 *device, + bool applyToDevice, + struct NineBaseTexture9 **slot, + struct NineBaseTexture9 *tex ) +{ + if (applyToDevice) + NineBindTextureToDevice(device, slot, tex); + else + nine_bind(slot, tex); +} + +/* 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 NineDevice9 *device, + struct nine_state *dst, + struct nine_state *src, + struct nine_state *mask, /* aliases either src or dst */ + const bool apply, + struct nine_range_pool *pool) +{ + unsigned i, s; + + DBG("apply:%d changed.group: %x\n", (int)apply, (int)mask->changed.group ); + + /* device changed.* are unused. + * Instead nine_context_apply_stateblock is used and will + * internally set the right context->changed fields. + * Uncomment these only if we want to apply a stateblock onto a stateblock. + * + * 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. + * + * Note: Currently when we apply stateblocks, it's always on the device state. + * Should it affect recording stateblocks ? Since it's on device state, there + * is no need to copy which ranges are dirty. If it turns out we should affect + * recording stateblocks, the info should be copied. + */ + 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)); + } + for (r = mask->changed.vs_const_i; r; r = r->next) { + memcpy(&dst->vs_const_i[r->bgn * 4], + &src->vs_const_i[r->bgn * 4], + (r->end - r->bgn) * 4 * sizeof(int)); + } + for (r = mask->changed.vs_const_b; r; r = r->next) { + memcpy(&dst->vs_const_b[r->bgn], + &src->vs_const_b[r->bgn], + (r->end - r->bgn) * sizeof(int)); + } + } + + /* 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 (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 (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]; + } + } + + /* Render states. + * TODO: Maybe build a list ? + */ + for (i = 0; i < ARRAY_SIZE(mask->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); + DBG("State %d %s = %d\n", i * 32 + r, nine_d3drs_to_string(i * 32 + r), (int)src->rs_advertised[i * 32 + r]); + dst->rs_advertised[i * 32 + r] = src->rs_advertised[i * 32 + r]; + } + } + + + /* Clip planes. */ + if (mask->changed.ucp) { + DBG("ucp: %x\n", 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_advertised[s], &src->samp_advertised[s], sizeof(dst->samp_advertised[s])); + } else { + uint32_t m = mask->changed.sampler[s]; + DBG("samp %d: changed = %x\n", i, (int)m); + while (m) { + const int i = ffs(m) - 1; + m &= ~(1 << i); + dst->samp_advertised[s][i] = src->samp_advertised[s][i]; + } + } + /* if (apply) + * dst->changed.sampler[s] |= mask->changed.sampler[s];*/ + } + } + + /* Index buffer. */ + if (mask->changed.group & NINE_STATE_IDXBUF) + NineStateBlock9_BindBuffer(device, + apply, + (struct NineBuffer9 **)&dst->idxbuf, + (struct NineBuffer9 *)src->idxbuf); + + /* Vertex streams. */ + if (mask->changed.vtxbuf | mask->changed.stream_freq) { + DBG("vtxbuf/stream_freq: %x/%x\n", 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)) { + NineStateBlock9_BindBuffer(device, + apply, + (struct NineBuffer9 **)&dst->stream[i], + (struct NineBuffer9 *)src->stream[i]); + if (src->stream[i]) { + dst->vtxbuf[i].buffer_offset = src->vtxbuf[i].buffer_offset; + dst->vtxstride[i] = src->vtxstride[i]; + } + } + if (mask->changed.stream_freq & (1 << i)) + dst->stream_freq[i] = src->stream_freq[i]; + } + /* + * if (apply) { + * dst->changed.vtxbuf |= mask->changed.vtxbuf; + * dst->changed.stream_freq |= mask->changed.stream_freq; + * }*/ + } + + /* Textures */ + if (mask->changed.texture) { + uint32_t m = mask->changed.texture; + for (s = 0; m; ++s, m >>= 1) + if (m & 1) + NineStateBlock9_BindTexture(device, apply, &dst->texture[s], src->texture[s]); + } + + if (!(mask->changed.group & NINE_STATE_FF)) + return; + WARN_ONCE("Fixed function state not handled properly by StateBlocks.\n"); + + /* Fixed function state. */ + + if (mask->changed.group & NINE_STATE_FF_MATERIAL) + dst->ff.material = src->ff.material; + + if (mask->changed.group & NINE_STATE_FF_PS_CONSTS) { + for (s = 0; s < NINE_MAX_TEXTURE_STAGES; ++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) { + unsigned num_lights = MAX2(dst->ff.num_lights, src->ff.num_lights); + /* Can happen in Capture() if device state has created new lights after + * the stateblock was created. + * Can happen in Apply() if the stateblock had recorded the creation of + * new lights. */ + if (dst->ff.num_lights < num_lights) { + dst->ff.light = REALLOC(dst->ff.light, + dst->ff.num_lights * sizeof(D3DLIGHT9), + num_lights * sizeof(D3DLIGHT9)); + memset(&dst->ff.light[dst->ff.num_lights], 0, (num_lights - dst->ff.num_lights) * sizeof(D3DLIGHT9)); + /* if mask == dst, a Type of 0 will trigger + * "dst->ff.light[i] = src->ff.light[i];" later, + * which is what we want in that case. */ + if (mask != dst) { + for (i = dst->ff.num_lights; i < num_lights; ++i) + dst->ff.light[i].Type = (D3DLIGHTTYPE)NINED3DLIGHT_INVALID; + } + dst->ff.num_lights = num_lights; + } + /* Can happen in Capture() if the stateblock had recorded the creation of + * new lights. + * Can happen in Apply() if device state has created new lights after + * the stateblock was created. */ + if (src->ff.num_lights < num_lights) { + src->ff.light = REALLOC(src->ff.light, + src->ff.num_lights * sizeof(D3DLIGHT9), + num_lights * sizeof(D3DLIGHT9)); + memset(&src->ff.light[src->ff.num_lights], 0, (num_lights - src->ff.num_lights) * sizeof(D3DLIGHT9)); + for (i = src->ff.num_lights; i < num_lights; ++i) + src->ff.light[i].Type = (D3DLIGHTTYPE)NINED3DLIGHT_INVALID; + src->ff.num_lights = num_lights; + } + /* Note: mask is either src or dst, so at this point src, dst and mask + * have num_lights lights. */ + for (i = 0; i < num_lights; ++i) + if (mask->ff.light[i].Type != NINED3DLIGHT_INVALID) + dst->ff.light[i] = src->ff.light[i]; + + memcpy(dst->ff.active_light, src->ff.active_light, sizeof(src->ff.active_light) ); + dst->ff.num_lights_active = src->ff.num_lights_active; + } + if (mask->changed.group & NINE_STATE_FF_VSTRANSF) { + for (i = 0; i < ARRAY_SIZE(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->ff, s, true) = + *nine_state_access_transform(&src->ff, s, false); + } + /* if (apply) + * dst->ff.changed.transform[i] |= mask->ff.changed.transform[i];*/ + } + } +} + +static void +nine_state_copy_common_all(struct NineDevice9 *device, + struct nine_state *dst, + struct nine_state *src, + struct nine_state *help, + const bool 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) { + memcpy(&dst->vs_const_f[0], + &src->vs_const_f[0], VS_CONST_F_SIZE(device)); + + memcpy(dst->vs_const_i, src->vs_const_i, VS_CONST_I_SIZE(device)); + memcpy(dst->vs_const_b, src->vs_const_b, VS_CONST_B_SIZE(device)); + } + + /* 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)); + + 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)); + } + + /* Render states. */ + memcpy(dst->rs_advertised, src->rs_advertised, sizeof(dst->rs_advertised)); + /* 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_advertised, src->samp_advertised, sizeof(dst->samp_advertised)); + /* if (apply) + * memcpy(dst->changed.sampler, + * src->changed.sampler, sizeof(dst->changed.sampler));*/ + + /* Index buffer. */ + NineStateBlock9_BindBuffer(device, + apply, + (struct NineBuffer9 **)&dst->idxbuf, + (struct NineBuffer9 *)src->idxbuf); + + /* Vertex streams. */ + if (1) { + for (i = 0; i < ARRAY_SIZE(dst->stream); ++i) { + NineStateBlock9_BindBuffer(device, + apply, + (struct NineBuffer9 **)&dst->stream[i], + (struct NineBuffer9 *)src->stream[i]); + if (src->stream[i]) { + dst->vtxbuf[i].buffer_offset = src->vtxbuf[i].buffer_offset; + dst->vtxstride[i] = src->vtxstride[i]; + } + dst->stream_freq[i] = src->stream_freq[i]; + } + /* if (apply) { + * dst->changed.vtxbuf = (1ULL << MaxStreams) - 1; + * dst->changed.stream_freq = (1ULL << MaxStreams) - 1; + * }*/ + } + + /* Textures */ + if (1) { + for (i = 0; i < NINE_MAX_SAMPLERS; i++) + NineStateBlock9_BindTexture(device, apply, &dst->texture[i], src->texture[i]); + } + + /* 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. */ + 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])); + + memcpy(dst->ff.active_light, src->ff.active_light, sizeof(src->ff.active_light) ); + dst->ff.num_lights_active = src->ff.num_lights_active; + } + + /* Transforms. */ + if (1) { + /* Increase dst size if required (to copy the new states). + * Increase src size if required (to initialize missing transforms). + */ + if (dst->ff.num_transforms != src->ff.num_transforms) { + int num_transforms = MAX2(src->ff.num_transforms, dst->ff.num_transforms); + nine_state_resize_transform(&src->ff, num_transforms); + nine_state_resize_transform(&dst->ff, num_transforms); + } + memcpy(dst->ff.transform, + src->ff.transform, dst->ff.num_transforms * sizeof(D3DMATRIX)); + /* Apply is always used on device state. + * src is then the D3DSBT_ALL stateblock which + * ff.changed.transform indicates all matrices are dirty. + * + * if (apply) + * 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 NINE_WINAPI +NineStateBlock9_Capture( struct NineStateBlock9 *This ) +{ + struct NineDevice9 *device = This->base.device; + struct nine_state *dst = &This->state; + struct nine_state *src = &device->state; + const int MaxStreams = device->caps.MaxStreams; + + DBG("This=%p\n", This); + + if (This->type == NINESBT_ALL) + nine_state_copy_common_all(device, dst, src, dst, false, NULL, MaxStreams); + else + nine_state_copy_common(device, dst, src, dst, false, NULL); + + if (dst->changed.group & NINE_STATE_VDECL) + nine_bind(&dst->vdecl, src->vdecl); + + return D3D_OK; +} + +/* Set state managed by this StateBlock as current device state. */ +HRESULT NINE_WINAPI +NineStateBlock9_Apply( struct NineStateBlock9 *This ) +{ + struct NineDevice9 *device = This->base.device; + struct nine_state *dst = &device->state; + struct nine_state *src = &This->state; + struct nine_range_pool *pool = &device->range_pool; + const int MaxStreams = device->caps.MaxStreams; + + DBG("This=%p\n", This); + + if (This->type == NINESBT_ALL) + nine_state_copy_common_all(device, dst, src, src, true, pool, MaxStreams); + else + nine_state_copy_common(device, dst, src, src, true, pool); + + nine_context_apply_stateblock(device, src); + + if ((src->changed.group & NINE_STATE_VDECL) && src->vdecl) + nine_bind(&dst->vdecl, src->vdecl); + + 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/frontends/nine/stateblock9.h b/src/gallium/frontends/nine/stateblock9.h new file mode 100644 index 0000000..16d032f --- /dev/null +++ b/src/gallium/frontends/nine/stateblock9.h @@ -0,0 +1,54 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#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 NINE_WINAPI +NineStateBlock9_Capture( struct NineStateBlock9 *This ); + +HRESULT NINE_WINAPI +NineStateBlock9_Apply( struct NineStateBlock9 *This ); + +#endif /* _NINE_STATEBLOCK9_H_ */ diff --git a/src/gallium/frontends/nine/surface9.c b/src/gallium/frontends/nine/surface9.c new file mode 100644 index 0000000..5b3f137 --- /dev/null +++ b/src/gallium/frontends/nine/surface9.c @@ -0,0 +1,854 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#include "iunknown.h" +#include "surface9.h" +#include "device9.h" + +/* for marking dirty */ +#include "basetexture9.h" +#include "texture9.h" +#include "cubetexture9.h" + +#include "nine_helpers.h" +#include "nine_pipe.h" +#include "nine_dump.h" +#include "nine_memory_helper.h" +#include "nine_state.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 + +static void +NineSurface9_CreatePipeSurfaces( struct NineSurface9 *This ); + +HRESULT +NineSurface9_ctor( struct NineSurface9 *This, + struct NineUnknownParams *pParams, + struct NineUnknown *pContainer, + struct pipe_resource *pResource, + struct nine_allocation *user_buffer, + uint8_t TextureType, + unsigned Level, + unsigned Layer, + D3DSURFACE_DESC *pDesc ) +{ + HRESULT hr; + bool allocate = !pContainer && pDesc->Format != D3DFMT_NULL; + D3DMULTISAMPLE_TYPE multisample_type; + + 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; + This->base.base.device = pParams->device; /* Early fill this field in case of failure */ + /* Make sure there's a Desc */ + assert(pDesc); + + assert(allocate || pResource || user_buffer || + pDesc->Format == D3DFMT_NULL); + assert(!allocate || (!pResource && !user_buffer)); + assert(!pResource || !user_buffer); + assert(!user_buffer || pDesc->Pool != D3DPOOL_DEFAULT); + assert(!pResource || pDesc->Pool == D3DPOOL_DEFAULT); + /* Allocation only from create_zs_or_rt_surface with params 0 0 0 */ + assert(!allocate || (Level == 0 && Layer == 0 && TextureType == 0)); + + This->data = user_buffer; + + multisample_type = pDesc->MultiSampleType; + + /* Map MultiSampleQuality to MultiSampleType */ + hr = d3dmultisample_type_check(pParams->device->screen, + pDesc->Format, + &multisample_type, + pDesc->MultiSampleQuality, + NULL); + if (FAILED(hr)) { + return hr; + } + + /* TODO: this is (except width and height) duplicate from + * container info (in the pContainer case). Some refactoring is + * needed to avoid duplication */ + This->base.info.screen = pParams->device->screen; + This->base.info.target = PIPE_TEXTURE_2D; + 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 = multisample_type; + This->base.info.nr_storage_samples = multisample_type; + This->base.info.usage = PIPE_USAGE_DEFAULT; + This->base.info.bind = PIPE_BIND_SAMPLER_VIEW; /* StretchRect */ + + if (pDesc->Usage & D3DUSAGE_RENDERTARGET) { + This->base.info.bind |= PIPE_BIND_RENDER_TARGET; + } else if (pDesc->Usage & D3DUSAGE_DEPTHSTENCIL) { + if (!depth_stencil_format(pDesc->Format)) + return D3DERR_INVALIDCALL; + This->base.info.bind = d3d9_get_pipe_depth_format_bindings(pDesc->Format); + if (TextureType) + This->base.info.bind |= PIPE_BIND_SAMPLER_VIEW; + } + + This->base.info.flags = 0; + This->base.info.format = d3d9_to_pipe_format_checked(This->base.info.screen, + pDesc->Format, + This->base.info.target, + This->base.info.nr_samples, + This->base.info.bind, + false, + pDesc->Pool == D3DPOOL_SCRATCH); + + if (This->base.info.format == PIPE_FORMAT_NONE && pDesc->Format != D3DFMT_NULL) + return D3DERR_INVALIDCALL; + + if (allocate && compressed_format(pDesc->Format)) { + const unsigned w = util_format_get_blockwidth(This->base.info.format); + const unsigned h = util_format_get_blockheight(This->base.info.format); + + /* Note: In the !allocate case, the test could fail (lower levels of a texture) */ + user_assert(!(pDesc->Width % w) && !(pDesc->Height % h), D3DERR_INVALIDCALL); + } + + /* Get true format */ + This->format_internal = d3d9_to_pipe_format_checked(This->base.info.screen, + pDesc->Format, + This->base.info.target, + This->base.info.nr_samples, + This->base.info.bind, + false, + true); + if (This->base.info.format != This->format_internal || + /* DYNAMIC Textures requires same stride as ram buffers. + * The workaround stores a copy in RAM for locks. It eats more virtual space, + * but that is compensated by the use of shmem */ + (pParams->device->workarounds.dynamic_texture_workaround && + pDesc->Pool == D3DPOOL_DEFAULT && pDesc->Usage & D3DUSAGE_DYNAMIC)) { + This->data_internal = nine_allocate(pParams->device->allocator, + nine_format_get_level_alloc_size(This->format_internal, + pDesc->Width, + pDesc->Height, + 0)); + if (!This->data_internal) + return E_OUTOFMEMORY; + This->stride_internal = nine_format_get_stride(This->format_internal, + pDesc->Width); + } + + if ((allocate && pDesc->Pool != D3DPOOL_DEFAULT) || pDesc->Format == D3DFMT_NULL) { + /* Ram buffer with no parent. Has to allocate the resource itself */ + assert(!user_buffer); + This->data = nine_allocate(pParams->device->allocator, + nine_format_get_level_alloc_size(This->base.info.format, + pDesc->Width, + pDesc->Height, + 0)); + if (!This->data) + return E_OUTOFMEMORY; + } + + hr = NineResource9_ctor(&This->base, pParams, pResource, + allocate && (pDesc->Pool == D3DPOOL_DEFAULT), + D3DRTYPE_SURFACE, pDesc->Pool, pDesc->Usage); + + if (FAILED(hr)) + return hr; + + This->transfer = NULL; + + This->texture = TextureType; + This->level = Level; + This->level_actual = Level; + This->layer = Layer; + This->desc = *pDesc; + + This->stride = nine_format_get_stride(This->base.info.format, pDesc->Width); + + if (This->base.resource && (pDesc->Usage & D3DUSAGE_DYNAMIC)) + This->base.resource->flags |= NINE_RESOURCE_FLAG_LOCKABLE; + + if (This->base.resource && (pDesc->Usage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL))) + NineSurface9_CreatePipeSurfaces(This); + + /* TODO: investigate what else exactly needs to be cleared */ + if (This->base.resource && (pDesc->Usage & D3DUSAGE_RENDERTARGET)) + nine_context_clear_render_target(pParams->device, This, 0, 0, 0, pDesc->Width, pDesc->Height); + + NineSurface9_Dump(This); + + return D3D_OK; +} + +void +NineSurface9_dtor( struct NineSurface9 *This ) +{ + bool is_worker = nine_context_is_worker(This->base.base.device); + DBG("This=%p\n", This); + + if (This->transfer) { + struct pipe_context *pipe = nine_context_get_pipe_multithread(This->base.base.device); + pipe->texture_unmap(pipe, This->transfer); + This->transfer = NULL; + } + + /* Note: Following condition cannot happen currently, since we + * refcount the surface in the functions increasing + * pending_uploads_counter. */ + if (p_atomic_read(&This->pending_uploads_counter)) + nine_csmt_process(This->base.base.device); + + if (!is_worker && This->lock_count && (This->data_internal || This->data)) { + /* For is_worker nine_free_worker will handle it */ + nine_pointer_strongrelease(This->base.base.device->allocator, + This->data_internal ? This->data_internal : This->data); + } + + /* Release system memory when we have to manage it (no parent) */ + if (This->data) { + if (is_worker) + nine_free_worker(This->base.base.device->allocator, This->data); + else + nine_free(This->base.base.device->allocator, This->data); + } + if (This->data_internal) { + if (is_worker) + nine_free_worker(This->base.base.device->allocator, This->data_internal); + else + nine_free(This->base.base.device->allocator, This->data_internal); + } + NineResource9_dtor(&This->base); +} + +static void +NineSurface9_CreatePipeSurfaces( struct NineSurface9 *This ) +{ + struct pipe_screen *screen = NineDevice9_GetScreen(This->base.base.device); + struct pipe_resource *resource = This->base.resource; + struct pipe_surface templ; + enum pipe_format srgb_format; + + assert(This->desc.Pool == D3DPOOL_DEFAULT); + assert(resource); + + srgb_format = util_format_srgb(resource->format); + if (srgb_format == PIPE_FORMAT_NONE || + !screen->is_format_supported(screen, srgb_format, + resource->target, 0, 0, resource->bind)) + srgb_format = resource->format; + + u_surface_default_template(&templ, resource); + /* Mesa 26.x: pipe_surface's u.tex union was flattened into the struct. */ + templ.level = This->level; + templ.first_layer = This->layer; + templ.last_layer = This->layer; + + This->surface[0] = templ; + + templ.format = srgb_format; + + This->surface[1] = templ; +} + +#if MESA_DEBUG || !defined(NDEBUG) +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->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 /* MESA_DEBUG || !NDEBUG */ + +HRESULT NINE_WINAPI +NineSurface9_GetContainer( struct NineSurface9 *This, + REFIID riid, + void **ppContainer ) +{ + HRESULT hr; + char guid_str[64]; + + DBG("This=%p riid=%p id=%s ppContainer=%p\n", + This, riid, riid ? GUID_sprintf(guid_str, riid) : "", ppContainer); + + (void)guid_str; + + if (!ppContainer) return E_POINTER; + + /* Use device for OffscreenPlainSurface, DepthStencilSurface and RenderTarget */ + hr = NineUnknown_QueryInterface(NineUnknown(This)->container ? + NineUnknown(This)->container : &NineUnknown(This)->device->base, + riid, ppContainer); + if (FAILED(hr)) + DBG("QueryInterface FAILED!\n"); + return hr; +} + +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->managed.dirty = true; + else + if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP) + tex->dirty_mip = true; + + BASETEX_REGISTER_UPDATE(tex); + } +} + +HRESULT NINE_WINAPI +NineSurface9_GetDesc( struct NineSurface9 *This, + D3DSURFACE_DESC *pDesc ) +{ + user_assert(pDesc != NULL, E_POINTER); + DBG("This=%p pDesc=%p\n", This, pDesc); + *pDesc = This->desc; + return D3D_OK; +} + +/* Add the dirty rects to the source texture */ +inline void +NineSurface9_AddDirtyRect( struct NineSurface9 *This, + const struct pipe_box *box ) +{ + RECT dirty_rect; + + DBG("This=%p box=%p\n", This, box); + + assert (This->base.pool != D3DPOOL_MANAGED || + This->texture == D3DRTYPE_CUBETEXTURE || + This->texture == D3DRTYPE_TEXTURE); + + if (This->base.pool == D3DPOOL_DEFAULT) + return; + + /* Add a dirty rect to level 0 of the parent texture */ + dirty_rect.left = box->x << This->level_actual; + dirty_rect.right = dirty_rect.left + (box->width << This->level_actual); + dirty_rect.top = box->y << This->level_actual; + dirty_rect.bottom = dirty_rect.top + (box->height << This->level_actual); + + if (This->texture == D3DRTYPE_TEXTURE) { + struct NineTexture9 *tex = + NineTexture9(This->base.base.container); + + NineTexture9_AddDirtyRect(tex, &dirty_rect); + } else if (This->texture == D3DRTYPE_CUBETEXTURE) { + struct NineCubeTexture9 *ctex = + NineCubeTexture9(This->base.base.container); + + NineCubeTexture9_AddDirtyRect(ctex, This->layer, &dirty_rect); + } +} + +static inline unsigned +NineSurface9_GetSystemMemOffset(enum pipe_format format, unsigned stride, + int x, int y) +{ + unsigned x_offset = util_format_get_stride(format, x); + + y = util_format_get_nblocksy(format, y); + + return y * stride + x_offset; +} + +HRESULT NINE_WINAPI +NineSurface9_LockRect( struct NineSurface9 *This, + D3DLOCKED_RECT *pLockedRect, + const RECT *pRect, + DWORD Flags ) +{ + struct pipe_resource *resource = This->base.resource; + struct pipe_context *pipe; + 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); + + /* check if it's already locked */ + user_assert(This->lock_count == 0, D3DERR_INVALIDCALL); + + /* set pBits to NULL after lock_count check */ + user_assert(pLockedRect, E_POINTER); + pLockedRect->pBits = NULL; + +#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) && (Flags & D3DLOCK_READONLY)), + D3DERR_INVALIDCALL); + + user_assert(This->desc.MultiSampleType == D3DMULTISAMPLE_NONE, + D3DERR_INVALIDCALL); + + if (pRect && This->desc.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 == 0 && pRect->right == This->desc.Width && + pRect->top == 0 && pRect->bottom == This->desc.Height) || + (!(pRect->left % w) && !(pRect->right % w) && + !(pRect->top % h) && !(pRect->bottom % h)), + D3DERR_INVALIDCALL); + } + + if (Flags & D3DLOCK_DISCARD) { + usage = PIPE_MAP_WRITE | PIPE_MAP_DISCARD_RANGE; + } else { + usage = (Flags & D3DLOCK_READONLY) ? + PIPE_MAP_READ : PIPE_MAP_READ_WRITE; + } + if (Flags & D3DLOCK_DONOTWAIT) + usage |= PIPE_MAP_DONTBLOCK; + + if (pRect) { + /* Windows XP accepts invalid locking rectangles, Windows 7 rejects + * them. Use Windows XP behaviour for now. */ + rect_to_pipe_box(&box, pRect); + } else { + u_box_origin_2d(This->desc.Width, This->desc.Height, &box); + } + box.z = This->layer; + + user_warn(This->desc.Format == D3DFMT_NULL); + + if (p_atomic_read(&This->pending_uploads_counter)) + nine_csmt_process(This->base.base.device); + + if (This->data_internal || This->data) { + enum pipe_format format = This->base.info.format; + unsigned stride = This->stride; + uint8_t *data = nine_get_pointer(This->base.base.device->allocator, This->data_internal ? This->data_internal : This->data); + if (This->data_internal) { + format = This->format_internal; + stride = This->stride_internal; + } + /* ATI1 and ATI2 need special handling, because of d3d9 bug. + * We must advertise to the application as if it is uncompressed + * and bpp 8, and the app has a workaround to work with the fact + * that it is actually compressed. */ + if (is_ATI1_ATI2(format)) { + pLockedRect->Pitch = This->desc.Width; + pLockedRect->pBits = data + box.y * This->desc.Width + box.x; + } else { + pLockedRect->Pitch = stride; + pLockedRect->pBits = data + + NineSurface9_GetSystemMemOffset(format, + stride, + box.x, + box.y); + } + DBG("returning system memory %p\n", pLockedRect->pBits); + } else { + bool no_refs = !p_atomic_read(&This->base.base.bind) && + !(This->base.base.container && p_atomic_read(&This->base.base.container->bind)); + DBG("mapping pipe_resource %p (level=%u usage=%x)\n", + resource, This->level, usage); + + /* if the object is not bound internally, there can't be any pending + * operation with the surface in the queue */ + if (no_refs) + pipe = nine_context_get_pipe_acquire(This->base.base.device); + else + pipe = NineDevice9_GetPipe(This->base.base.device); + pLockedRect->pBits = pipe->texture_map(pipe, resource, + This->level, usage, &box, + &This->transfer); + if (no_refs) + nine_context_get_pipe_release(This->base.base.device); + if (!This->transfer) { + DBG("texture_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); + NineSurface9_AddDirtyRect(This, &box); + } + + ++This->lock_count; + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineSurface9_UnlockRect( struct NineSurface9 *This ) +{ + struct pipe_box dst_box, src_box; + struct pipe_context *pipe; + DBG("This=%p lock_count=%u\n", This, This->lock_count); + user_assert(This->lock_count, D3DERR_INVALIDCALL); + if (This->transfer) { + pipe = nine_context_get_pipe_acquire(This->base.base.device); + pipe->texture_unmap(pipe, This->transfer); + nine_context_get_pipe_release(This->base.base.device); + This->transfer = NULL; + } + --This->lock_count; + + if (This->data_internal) { + nine_pointer_weakrelease(This->base.base.device->allocator, This->data_internal); + if (This->data) { + (void) util_format_translate(This->base.info.format, + nine_get_pointer(This->base.base.device->allocator, This->data), + This->stride, + 0, 0, + This->format_internal, + nine_get_pointer(This->base.base.device->allocator, This->data_internal), + This->stride_internal, + 0, 0, + This->desc.Width, This->desc.Height); + nine_pointer_weakrelease(This->base.base.device->allocator, This->data); + nine_pointer_strongrelease(This->base.base.device->allocator, This->data_internal); + } else { + u_box_2d_zslice(0, 0, This->layer, + This->desc.Width, This->desc.Height, &dst_box); + u_box_2d_zslice(0, 0, 0, + This->desc.Width, This->desc.Height, &src_box); + + nine_context_box_upload(This->base.base.device, + &This->pending_uploads_counter, + (struct NineUnknown *)This, + This->base.resource, + This->level, + &dst_box, + This->format_internal, + nine_get_pointer(This->base.base.device->allocator, This->data_internal), + This->stride_internal, + 0, /* depth = 1 */ + &src_box); + nine_pointer_delayedstrongrelease(This->base.base.device->allocator, This->data_internal, &This->pending_uploads_counter); + } + } else if (This->data) { + nine_pointer_weakrelease(This->base.base.device->allocator, This->data); + } + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineSurface9_GetDC( struct NineSurface9 *This, + HDC *phdc ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT NINE_WINAPI +NineSurface9_ReleaseDC( struct NineSurface9 *This, + HDC hdc ) +{ + STUB(D3DERR_INVALIDCALL); +} + +IDirect3DSurface9Vtbl NineSurface9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */ + (void *)NineUnknown_SetPrivateData, + (void *)NineUnknown_GetPrivateData, + (void *)NineUnknown_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 +}; + +/* When this function is called, we have already checked + * The copy regions fit the surfaces */ +void +NineSurface9_CopyMemToDefault( struct NineSurface9 *This, + struct NineSurface9 *From, + const POINT *pDestPoint, + const RECT *pSourceRect ) +{ + struct pipe_resource *r_dst = This->base.resource; + struct pipe_box dst_box, src_box; + int src_x, src_y, dst_x, dst_y, copy_width, copy_height; + + assert(This->base.pool == D3DPOOL_DEFAULT && + From->base.pool == D3DPOOL_SYSTEMMEM); + + if (pDestPoint) { + dst_x = pDestPoint->x; + dst_y = pDestPoint->y; + } else { + dst_x = 0; + dst_y = 0; + } + + if (pSourceRect) { + src_x = pSourceRect->left; + src_y = pSourceRect->top; + copy_width = pSourceRect->right - pSourceRect->left; + copy_height = pSourceRect->bottom - pSourceRect->top; + } else { + src_x = 0; + src_y = 0; + copy_width = From->desc.Width; + copy_height = From->desc.Height; + } + + u_box_2d_zslice(dst_x, dst_y, This->layer, + copy_width, copy_height, &dst_box); + u_box_2d_zslice(src_x, src_y, 0, + copy_width, copy_height, &src_box); + + if (This->data_internal) { + (void) util_format_translate(This->format_internal, + nine_get_pointer(This->base.base.device->allocator, This->data_internal), + This->stride_internal, + dst_x, dst_y, + From->base.info.format, + nine_get_pointer(This->base.base.device->allocator, From->data), + From->stride, + src_x, src_y, + copy_width, copy_height); + nine_pointer_weakrelease(This->base.base.device->allocator, From->data); + nine_pointer_strongrelease(This->base.base.device->allocator, This->data_internal); + } + + nine_context_box_upload(This->base.base.device, + &From->pending_uploads_counter, + (struct NineUnknown *)From, + r_dst, + This->level, + &dst_box, + From->base.info.format, + nine_get_pointer(This->base.base.device->allocator, From->data), + From->stride, + 0, /* depth = 1 */ + &src_box); + nine_pointer_delayedstrongrelease(This->base.base.device->allocator, From->data, &From->pending_uploads_counter); + + if (From->texture == D3DRTYPE_TEXTURE) { + struct NineTexture9 *tex = + NineTexture9(From->base.base.container); + /* D3DPOOL_SYSTEMMEM with buffer content passed + * from the user: execute the upload right now. + * It is possible it is enough to delay upload + * until the surface refcount is 0, but the + * bind refcount may not be 0, and thus the dtor + * is not executed (and doesn't trigger the + * pending_uploads_counter check). */ + if (!tex->managed_buffer) + nine_csmt_process(This->base.base.device); + } + + NineSurface9_MarkContainerDirty(This); +} + +void +NineSurface9_CopyDefaultToMem( struct NineSurface9 *This, + struct NineSurface9 *From ) +{ + struct pipe_context *pipe; + struct pipe_resource *r_src = From->base.resource; + struct pipe_transfer *transfer; + struct pipe_box src_box; + uint8_t *p_dst; + const uint8_t *p_src; + + assert(This->base.pool == D3DPOOL_SYSTEMMEM && + From->base.pool == D3DPOOL_DEFAULT); + + assert(This->desc.Width == From->desc.Width); + assert(This->desc.Height == From->desc.Height); + + u_box_origin_2d(This->desc.Width, This->desc.Height, &src_box); + src_box.z = From->layer; + + if (p_atomic_read(&This->pending_uploads_counter)) + nine_csmt_process(This->base.base.device); + + pipe = NineDevice9_GetPipe(This->base.base.device); + p_src = pipe->texture_map(pipe, r_src, From->level, + PIPE_MAP_READ, + &src_box, &transfer); + p_dst = nine_get_pointer(This->base.base.device->allocator, This->data); + + assert (p_src && p_dst); + + util_copy_rect(p_dst, This->base.info.format, + This->stride, 0, 0, + This->desc.Width, This->desc.Height, + p_src, + transfer->stride, 0, 0); + + pipe->texture_unmap(pipe, transfer); + + nine_pointer_weakrelease(This->base.base.device->allocator, This->data); +} + + +/* 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, + const struct pipe_box *damaged ) +{ + struct pipe_resource *res = This->base.resource; + struct pipe_box box; + + DBG("This=%p damaged=%p\n", This, damaged); + + assert(This->base.pool == D3DPOOL_MANAGED); + + if (damaged) { + box = *damaged; + box.z = This->layer; + box.depth = 1; + } else { + box.x = 0; + box.y = 0; + box.z = This->layer; + box.width = This->desc.Width; + box.height = This->desc.Height; + box.depth = 1; + } + + nine_context_box_upload(This->base.base.device, + &This->pending_uploads_counter, + (struct NineUnknown *)This, + res, + This->level, + &box, + res->format, + nine_get_pointer(This->base.base.device->allocator, This->data), + This->stride, + 0, /* depth = 1 */ + &box); + nine_pointer_delayedstrongrelease(This->base.base.device->allocator, This->data, &This->pending_uploads_counter); + + return D3D_OK; +} + +/* Currently nine_context uses the NineSurface9 + * fields when it is render target. Any modification requires + * pending commands with the surface to be executed. If the bind + * count is 0, there is no pending commands. */ +#define PROCESS_IF_BOUND(surf) \ + if (surf->base.base.bind) \ + nine_csmt_process(surf->base.base.device); + +void +NineSurface9_SetResource( struct NineSurface9 *This, + struct pipe_resource *resource, unsigned level ) +{ + /* No need to call PROCESS_IF_BOUND, because SetResource is used only + * for MANAGED textures, and they are not render targets. */ + assert(This->base.pool == D3DPOOL_MANAGED); + This->level = level; + pipe_resource_reference(&This->base.resource, resource); +} + +void +NineSurface9_SetMultiSampleType( struct NineSurface9 *This, + D3DMULTISAMPLE_TYPE mst ) +{ + PROCESS_IF_BOUND(This); + This->desc.MultiSampleType = mst; +} + +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); + + PROCESS_IF_BOUND(This); + 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->base.info.nr_samples = resource->nr_samples; + This->base.info.nr_storage_samples = resource->nr_storage_samples; + + This->stride = nine_format_get_stride(This->base.info.format, + This->desc.Width); + + NineSurface9_CreatePipeSurfaces(This); +} + + +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, + struct nine_allocation *user_buffer, + uint8_t TextureType, + unsigned Level, + unsigned Layer, + D3DSURFACE_DESC *pDesc, + struct NineSurface9 **ppOut ) +{ + NINE_DEVICE_CHILD_NEW(Surface9, ppOut, pDevice, /* args */ + pContainer, pResource, user_buffer, + TextureType, Level, Layer, pDesc); +} diff --git a/src/gallium/frontends/nine/surface9.h b/src/gallium/frontends/nine/surface9.h new file mode 100644 index 0000000..d40f635 --- /dev/null +++ b/src/gallium/frontends/nine/surface9.h @@ -0,0 +1,161 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#ifndef _NINE_SURFACE9_H_ +#define _NINE_SURFACE9_H_ + +#include "nine_memory_helper.h" +#include "resource9.h" + +#include "pipe/p_state.h" +#include "util/list.h" +#include "util/u_rect.h" +#include "util/u_inlines.h" + +struct NineSurface9 +{ + struct NineResource9 base; + + /* G3D state */ + 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; + + struct nine_allocation *data; /* system memory backing */ + struct nine_allocation *data_internal; /* for conversions */ + enum pipe_format format_internal; + unsigned stride; /* for system memory backing */ + unsigned stride_internal; + + unsigned pending_uploads_counter; /* pending uploads */ +}; +static inline struct NineSurface9 * +NineSurface9( void *data ) +{ + return (struct NineSurface9 *)data; +} + +HRESULT +NineSurface9_new( struct NineDevice9 *pDevice, + struct NineUnknown *pContainer, + struct pipe_resource *pResource, + struct nine_allocation *user_buffer, + 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, + struct nine_allocation *user_buffer, + uint8_t TextureType, + unsigned Level, + unsigned Layer, + D3DSURFACE_DESC *pDesc ); + +void +NineSurface9_dtor( struct NineSurface9 *This ); + +/*** Nine private ***/ + +void +NineSurface9_MarkContainerDirty( struct NineSurface9 *This ); + +static inline struct pipe_surface * +NineSurface9_GetSurface( struct NineSurface9 *This, int sRGB ) +{ + return &This->surface[sRGB]; +} + +static inline struct pipe_resource * +NineSurface9_GetResource( struct NineSurface9 *This ) +{ + return This->base.resource; +} + +void +NineSurface9_SetResource( struct NineSurface9 *This, + struct pipe_resource *resource, unsigned level ); + +void +NineSurface9_SetMultiSampleType( struct NineSurface9 *This, + D3DMULTISAMPLE_TYPE mst ); + +void +NineSurface9_SetResourceResize( struct NineSurface9 *This, + struct pipe_resource *resource ); + +void +NineSurface9_AddDirtyRect( struct NineSurface9 *This, + const struct pipe_box *box ); + +HRESULT +NineSurface9_UploadSelf( struct NineSurface9 *This, + const struct pipe_box *damaged ); + +void +NineSurface9_CopyMemToDefault( struct NineSurface9 *This, + struct NineSurface9 *From, + const POINT *pDestPoint, + const RECT *pSourceRect ); + +void +NineSurface9_CopyDefaultToMem( struct NineSurface9 *This, + struct NineSurface9 *From ); + +static inline bool +NineSurface9_IsOffscreenPlain (struct NineSurface9 *This ) +{ + return This->base.usage == 0 && !This->texture; +} + +#if MESA_DEBUG || !defined(NDEBUG) +void +NineSurface9_Dump( struct NineSurface9 *This ); +#else +static inline void +NineSurface9_Dump( struct NineSurface9 *This ) { } +#endif + +/*** Direct3D public ***/ + +HRESULT NINE_WINAPI +NineSurface9_GetContainer( struct NineSurface9 *This, + REFIID riid, + void **ppContainer ); + +HRESULT NINE_WINAPI +NineSurface9_GetDesc( struct NineSurface9 *This, + D3DSURFACE_DESC *pDesc ); + +HRESULT NINE_WINAPI +NineSurface9_LockRect( struct NineSurface9 *This, + D3DLOCKED_RECT *pLockedRect, + const RECT *pRect, + DWORD Flags ); + +HRESULT NINE_WINAPI +NineSurface9_UnlockRect( struct NineSurface9 *This ); + +HRESULT NINE_WINAPI +NineSurface9_GetDC( struct NineSurface9 *This, + HDC *phdc ); + +HRESULT NINE_WINAPI +NineSurface9_ReleaseDC( struct NineSurface9 *This, + HDC hdc ); + +#endif /* _NINE_SURFACE9_H_ */ diff --git a/src/gallium/frontends/nine/swapchain9.c b/src/gallium/frontends/nine/swapchain9.c new file mode 100644 index 0000000..de505c1 --- /dev/null +++ b/src/gallium/frontends/nine/swapchain9.c @@ -0,0 +1,1312 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#include "swapchain9.h" +#include "surface9.h" +#include "device9.h" + +#include "nine_helpers.h" +#include "nine_pipe.h" +#include "nine_dump.h" + +#include "util/u_atomic.h" +#include "util/u_inlines.h" +#include "util/u_surface.h" +#include "hud/hud_context.h" +#include "frontend/drm_driver.h" + +#include "threadpool.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; + int i; + + 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->implicit = implicit; + This->actx = pCTX; + This->present = pPresent; + This->mode = NULL; + + ID3DPresent_AddRef(pPresent); + if (This->base.device->minor_version_num > 2) { + D3DPRESENT_PARAMETERS2 params2; + + memset(¶ms2, 0, sizeof(D3DPRESENT_PARAMETERS2)); + params2.AllowDISCARDDelayedRelease = This->actx->discard_delayed_release; + params2.TearFreeDISCARD = This->actx->tearfree_discard; + ID3DPresent_SetPresentParameters2(pPresent, ¶ms2); + } + + if (!pPresentationParameters->hDeviceWindow) + pPresentationParameters->hDeviceWindow = hFocusWindow; + + This->rendering_done = false; + This->pool = NULL; + for (i = 0; i < D3DPRESENT_BACK_BUFFERS_MAX_EX + 1; i++) { + This->pending_presentation[i] = calloc(1, sizeof(BOOL)); + if (!This->pending_presentation[i]) + return E_OUTOFMEMORY; + } + return NineSwapChain9_Resize(This, pPresentationParameters, mode); +} + +static D3DWindowBuffer * +D3DWindowBuffer_create(struct NineSwapChain9 *This, + struct pipe_resource *resource, + int depth, + int for_frontbuffer_reading) +{ + D3DWindowBuffer *ret; + struct pipe_context *pipe = nine_context_get_pipe_acquire(This->base.device); + struct winsys_handle whandle; + int stride, dmaBufFd; + HRESULT hr; + + memset(&whandle, 0, sizeof(whandle)); + whandle.type = WINSYS_HANDLE_TYPE_FD; + if (!This->screen->resource_get_handle(This->screen, pipe, resource, + &whandle, + for_frontbuffer_reading ? + PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE : + PIPE_HANDLE_USAGE_EXPLICIT_FLUSH)) { + ERR("Failed to get handle for resource\n"); + return NULL; + } + nine_context_get_pipe_release(This->base.device); + stride = whandle.stride; + dmaBufFd = whandle.handle; + hr = ID3DPresent_NewD3DWindowBufferFromDmaBuf(This->present, + dmaBufFd, + resource->width0, + resource->height0, + stride, + depth, + 32, + &ret); + assert (SUCCEEDED(hr)); + + if (FAILED(hr)) { + ERR("Failed to create new D3DWindowBufferFromDmaBuf\n"); + return NULL; + } + return ret; +} + +static void +D3DWindowBuffer_release(struct NineSwapChain9 *This, + D3DWindowBuffer *present_handle) +{ + int i; + + /* IsBufferReleased API not available */ + if (This->base.device->minor_version_num <= 2) { + ID3DPresent_DestroyD3DWindowBuffer(This->present, present_handle); + return; + } + + /* Add it to the 'pending release' list */ + for (i = 0; i < D3DPRESENT_BACK_BUFFERS_MAX_EX + 1; i++) { + if (!This->present_handles_pending_release[i]) { + This->present_handles_pending_release[i] = present_handle; + break; + } + } + if (i == (D3DPRESENT_BACK_BUFFERS_MAX_EX + 1)) { + ERR("Server not releasing buffers...\n"); + assert(false); + } + + /* Destroy elements of the list released by the server */ + for (i = 0; i < D3DPRESENT_BACK_BUFFERS_MAX_EX + 1; i++) { + if (This->present_handles_pending_release[i] && + ID3DPresent_IsBufferReleased(This->present, This->present_handles_pending_release[i])) { + /* WaitBufferReleased also waits the presentation feedback + * (which should arrive at about the same time), + * while IsBufferReleased doesn't. DestroyD3DWindowBuffer unfortunately + * checks it to release immediately all data, else the release + * is postponed for This->present release. To avoid leaks (we may handle + * a lot of resize), call WaitBufferReleased. */ + ID3DPresent_WaitBufferReleased(This->present, This->present_handles_pending_release[i]); + ID3DPresent_DestroyD3DWindowBuffer(This->present, This->present_handles_pending_release[i]); + This->present_handles_pending_release[i] = NULL; + } + } +} + +static int +NineSwapChain9_GetBackBufferCountForParams( struct NineSwapChain9 *This, + D3DPRESENT_PARAMETERS *pParams ); + +HRESULT +NineSwapChain9_Resize( struct NineSwapChain9 *This, + D3DPRESENT_PARAMETERS *pParams, + D3DDISPLAYMODEEX *mode ) +{ + struct NineDevice9 *pDevice = This->base.device; + 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; + D3DMULTISAMPLE_TYPE multisample_type; + + DBG("This=%p pParams=%p\n", This, pParams); + user_assert(pParams != NULL, E_POINTER); + user_assert(pParams->SwapEffect, D3DERR_INVALIDCALL); + user_assert((pParams->SwapEffect != D3DSWAPEFFECT_COPY) || + (pParams->BackBufferCount <= 1), D3DERR_INVALIDCALL); + user_assert(pDevice->ex || pParams->BackBufferCount <= + D3DPRESENT_BACK_BUFFERS_MAX, D3DERR_INVALIDCALL); + user_assert(!pDevice->ex || pParams->BackBufferCount <= + D3DPRESENT_BACK_BUFFERS_MAX_EX, D3DERR_INVALIDCALL); + user_assert(pDevice->ex || + (pParams->SwapEffect == D3DSWAPEFFECT_FLIP) || + (pParams->SwapEffect == D3DSWAPEFFECT_COPY) || + (pParams->SwapEffect == D3DSWAPEFFECT_DISCARD), D3DERR_INVALIDCALL); + + 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->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 (This->actx->vblank_mode == 0) + pParams->PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + else if (This->actx->vblank_mode == 3) + pParams->PresentationInterval = D3DPRESENT_INTERVAL_ONE; + + if (mode && This->mode) { + *(This->mode) = *mode; + } else if (mode) { + This->mode = malloc(sizeof(D3DDISPLAYMODEEX)); + memcpy(This->mode, mode, sizeof(D3DDISPLAYMODEEX)); + } else { + free(This->mode); + This->mode = NULL; + } + + /* Note: It is the role of the backend to fill if necessary + * BackBufferWidth and BackBufferHeight */ + hr = ID3DPresent_SetPresentParameters(This->present, pParams, This->mode); + if (hr != D3D_OK) + return hr; + + oldBufferCount = This->num_back_buffers; + newBufferCount = NineSwapChain9_GetBackBufferCountForParams(This, pParams); + + multisample_type = pParams->MultiSampleType; + + /* Map MultiSampleQuality to MultiSampleType */ + hr = d3dmultisample_type_check(This->screen, pParams->BackBufferFormat, + &multisample_type, + pParams->MultiSampleQuality, + NULL); + if (FAILED(hr)) { + return hr; + } + + pf = d3d9_to_pipe_format_checked(This->screen, pParams->BackBufferFormat, + PIPE_TEXTURE_2D, multisample_type, + PIPE_BIND_RENDER_TARGET, false, false); + + if (This->actx->linear_framebuffer || + (pf != PIPE_FORMAT_B8G8R8X8_UNORM && + pf != PIPE_FORMAT_B8G8R8A8_UNORM) || + pParams->SwapEffect != D3DSWAPEFFECT_DISCARD || + multisample_type >= 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; + + memset(&tmplt, 0, sizeof(tmplt)); + 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 = pParams->MultiSampleQuality; + desc.Width = pParams->BackBufferWidth; + desc.Height = pParams->BackBufferHeight; + + for (i = 0; i < oldBufferCount; i++) { + if (This->tasks[i]) + _mesa_threadpool_wait_for_task(This->pool, &(This->tasks[i])); + } + memset(This->tasks, 0, sizeof(This->tasks)); + + if (This->pool) { + _mesa_threadpool_destroy(This, This->pool); + This->pool = NULL; + } + This->enable_threadpool = This->actx->thread_submit && (pParams->SwapEffect != D3DSWAPEFFECT_COPY); + if (This->enable_threadpool) + This->pool = _mesa_threadpool_create(This); + if (!This->pool) + This->enable_threadpool = false; + + for (i = 0; i < oldBufferCount; i++) { + D3DWindowBuffer_release(This, This->present_handles[i]); + This->present_handles[i] = NULL; + if (This->present_buffers[i]) + pipe_resource_reference(&(This->present_buffers[i]), NULL); + } + + if (newBufferCount != oldBufferCount) { + for (i = newBufferCount; i < oldBufferCount; + ++i) + NineUnknown_Detach(NineUnknown(This->buffers[i])); + + for (i = oldBufferCount; i < newBufferCount; ++i) { + This->buffers[i] = NULL; + This->present_handles[i] = NULL; + } + } + This->num_back_buffers = newBufferCount; + + for (i = 0; i < newBufferCount; ++i) { + tmplt.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET; + tmplt.nr_samples = multisample_type; + tmplt.nr_storage_samples = multisample_type; + if (!has_present_buffers) + tmplt.bind |= NINE_BIND_PRESENTBUFFER_FLAGS; + tmplt.format = d3d9_to_pipe_format_checked(This->screen, + pParams->BackBufferFormat, + PIPE_TEXTURE_2D, + tmplt.nr_samples, + tmplt.bind, false, false); + if (tmplt.format == PIPE_FORMAT_NONE) + return D3DERR_INVALIDCALL; + resource = nine_resource_create_with_retry(pDevice, 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_SetMultiSampleType(This->buffers[i], desc.MultiSampleType); + 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, NULL, 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 = NINE_BIND_PRESENTBUFFER_FLAGS; + tmplt.nr_samples = 0; + tmplt.nr_storage_samples = 0; + if (This->actx->linear_framebuffer) + tmplt.bind |= PIPE_BIND_LINEAR; + if (pParams->SwapEffect != D3DSWAPEFFECT_DISCARD) + tmplt.bind |= PIPE_BIND_RENDER_TARGET; + resource = nine_resource_create_with_retry(pDevice, This->screen, &tmplt); + pipe_resource_reference(&(This->present_buffers[i]), resource); + } + This->present_handles[i] = D3DWindowBuffer_create(This, resource, depth, false); + pipe_resource_reference(&resource, NULL); + if (!This->present_handles[i]) { + return D3DERR_DRIVERINTERNALERROR; + } + } + if (pParams->EnableAutoDepthStencil) { + tmplt.bind = d3d9_get_pipe_depth_format_bindings(pParams->AutoDepthStencilFormat); + tmplt.nr_samples = multisample_type; + tmplt.nr_storage_samples = multisample_type; + tmplt.format = d3d9_to_pipe_format_checked(This->screen, + pParams->AutoDepthStencilFormat, + PIPE_TEXTURE_2D, + tmplt.nr_samples, + tmplt.bind, + false, false); + + if (tmplt.format == PIPE_FORMAT_NONE) + return D3DERR_INVALIDCALL; + + if (This->zsbuf) { + resource = nine_resource_create_with_retry(pDevice, This->screen, &tmplt); + if (!resource) { + DBG("Failed to create pipe_resource for depth buffer.\n"); + return D3DERR_OUTOFVIDEOMEMORY; + } + + NineSurface9_SetMultiSampleType(This->zsbuf, desc.MultiSampleType); + NineSurface9_SetResourceResize(This->zsbuf, resource); + pipe_resource_reference(&resource, NULL); + } else { + hr = NineDevice9_CreateDepthStencilSurface(pDevice, + pParams->BackBufferWidth, + pParams->BackBufferHeight, + pParams->AutoDepthStencilFormat, + pParams->MultiSampleType, + pParams->MultiSampleQuality, + 0, + (IDirect3DSurface9 **)&This->zsbuf, + NULL); + if (FAILED(hr)) { + DBG("Failed to create ZS surface.\n"); + return hr; + } + NineUnknown_ConvertRefToBind(NineUnknown(This->zsbuf)); + } + } + + This->params = *pParams; + + return D3D_OK; +} + +/* Throttling: code adapted from the dri frontend */ + +/** + * 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->pool) + _mesa_threadpool_destroy(This, This->pool); + + for (i = 0; i < D3DPRESENT_BACK_BUFFERS_MAX_EX + 1; i++) { + if (This->pending_presentation[i]) + FREE(This->pending_presentation[i]); + } + + for (i = 0; i < D3DPRESENT_BACK_BUFFERS_MAX_EX + 1; i++) { + if (This->present_handles_pending_release[i]) + ID3DPresent_DestroyD3DWindowBuffer(This->present, This->present_handles_pending_release[i]); + } + + for (i = 0; i < This->num_back_buffers; i++) { + if (This->buffers[i]) + NineUnknown_Detach(NineUnknown(This->buffers[i])); + if (This->present_handles[i]) + ID3DPresent_DestroyD3DWindowBuffer(This->present, This->present_handles[i]); + if (This->present_buffers[i]) + pipe_resource_reference(&(This->present_buffers[i]), NULL); + } + if (This->zsbuf) + NineUnknown_Unbind(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; + + memset(&tmplt, 0, sizeof(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 = NINE_BIND_BACKBUFFER_FLAGS | + NINE_BIND_PRESENTBUFFER_FLAGS; + tmplt.nr_samples = 0; + if (This->actx->linear_framebuffer) + tmplt.bind |= PIPE_BIND_LINEAR; + *resource = nine_resource_create_with_retry(This->base.device, This->screen, &tmplt); + + *present_handle = D3DWindowBuffer_create(This, *resource, 24, true); + + if (!*present_handle) { + pipe_resource_reference(resource, NULL); + } +} + +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; + struct pipe_context *pipe; + + if (device->cursor.software && device->cursor.visible && device->cursor.w) { + memset(&blit, 0, sizeof(blit)); + 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; + + /* NOTE: blit messes up when box.x + box.width < 0, fix driver + * NOTE2: device->cursor.pos contains coordinates relative to the screen. + * This happens to be also the position of the cursor when we are fullscreen. + * We don't use sw cursor for Windowed mode */ + 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); + + blit.alpha_blend = true; + pipe = NineDevice9_GetPipe(This->base.device); + pipe->blit(pipe, &blit); + } + + if (device->hud && resource) { + /* Implicit use of context pipe */ + (void)NineDevice9_GetPipe(This->base.device); + hud_run(device->hud, NULL, resource); /* XXX: no offset */ + /* HUD doesn't clobber stipple */ + nine_state_restore_non_cso(device); + } +} + +struct end_present_struct { + struct pipe_screen *screen; + struct pipe_fence_handle *fence_to_wait; + ID3DPresent *present; + D3DWindowBuffer *present_handle; + BOOL *pending_presentation; + HWND hDestWindowOverride; +}; + +static void work_present(void *data) +{ + struct end_present_struct *work = data; + if (work->fence_to_wait) { + (void) work->screen->fence_finish(work->screen, NULL, work->fence_to_wait, OS_TIMEOUT_INFINITE); + work->screen->fence_reference(work->screen, &(work->fence_to_wait), NULL); + } + ID3DPresent_PresentBuffer(work->present, work->present_handle, work->hDestWindowOverride, NULL, NULL, NULL, 0); + p_atomic_set(work->pending_presentation, false); + free(work); +} + +static void pend_present(struct NineSwapChain9 *This, + struct pipe_fence_handle *fence, + HWND hDestWindowOverride) +{ + struct end_present_struct *work = calloc(1, sizeof(struct end_present_struct)); + + work->screen = This->screen; + This->screen->fence_reference(This->screen, &work->fence_to_wait, fence); + work->present = This->present; + work->present_handle = This->present_handles[0]; + work->hDestWindowOverride = hDestWindowOverride; + work->pending_presentation = This->pending_presentation[0]; + p_atomic_set(work->pending_presentation, true); + This->tasks[0] = _mesa_threadpool_queue_task(This->pool, work_present, work); + + return; +} + +static inline HRESULT +present( struct NineSwapChain9 *This, + const RECT *pSourceRect, + const RECT *pDestRect, + HWND hDestWindowOverride, + const RGNDATA *pDirtyRegion, + DWORD dwFlags ) +{ + struct pipe_context *pipe; + struct pipe_resource *resource; + struct pipe_fence_handle *fence; + HRESULT hr; + struct pipe_blit_info blit; + int target_width, target_height, target_depth, i; + RECT source_rect; + RECT dest_rect; + + 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); + + /* We can choose to only update pDirtyRegion, but the backend can choose + * to update everything. Let's ignore */ + (void) pDirtyRegion; + + resource = This->buffers[0]->base.resource; + + if (pSourceRect) { + DBG("pSourceRect = (%u..%u)x(%u..%u)\n", + pSourceRect->left, pSourceRect->right, + pSourceRect->top, pSourceRect->bottom); + source_rect = *pSourceRect; + if (source_rect.top == 0 && + source_rect.left == 0 && + source_rect.bottom == resource->height0 && + source_rect.right == resource->width0) + pSourceRect = NULL; + /* TODO: Handle more of pSourceRect. + * Currently we should support: + * . When there is no pSourceRect + * . When pSourceRect is the full buffer. + */ + } + if (pDestRect) { + DBG("pDestRect = (%u..%u)x(%u..%u)\n", + pDestRect->left, pDestRect->right, + pDestRect->top, pDestRect->bottom); + dest_rect = *pDestRect; + } + + if (This->rendering_done) + goto bypass_rendering; + + if (This->params.SwapEffect == D3DSWAPEFFECT_DISCARD) + handle_draw_cursor_and_hud(This, resource); + + hr = ID3DPresent_GetWindowInfo(This->present, hDestWindowOverride, &target_width, &target_height, &target_depth); + (void)target_depth; + + /* Can happen with old Wine (presentation can still succeed), + * or at window destruction. + * Also disable for very old wine as D3DWindowBuffer_release + * cannot do the DestroyD3DWindowBuffer workaround. */ + if (FAILED(hr) || target_width == 0 || target_height == 0 || + This->base.device->minor_version_num <= 2) { + target_width = resource->width0; + target_height = resource->height0; + } + + if (pDestRect) { + dest_rect.top = MAX2(0, dest_rect.top); + dest_rect.left = MAX2(0, dest_rect.left); + dest_rect.bottom = MIN2(target_height, dest_rect.bottom); + dest_rect.right = MIN2(target_width, dest_rect.right); + target_height = dest_rect.bottom - dest_rect.top; + target_width = dest_rect.right - dest_rect.left; + } + + /* Switch to using presentation buffers on window resize. + * Note: Most apps should resize the d3d back buffers when + * a window resize is detected, which will result in a call to + * NineSwapChain9_Resize. Thus everything will get released, + * and it will switch back to not using separate presentation + * buffers. */ + if (!This->present_buffers[0] && + (target_width != resource->width0 || target_height != resource->height0)) { + BOOL failure = false; + struct pipe_resource *new_resource[This->num_back_buffers]; + D3DWindowBuffer *new_handles[This->num_back_buffers]; + for (i = 0; i < This->num_back_buffers; i++) { + /* Note: if (!new_handles[i]), new_resource[i] + * gets released and contains NULL */ + create_present_buffer(This, target_width, target_height, &new_resource[i], &new_handles[i]); + if (!new_handles[i]) + failure = true; + } + if (failure) { + for (i = 0; i < This->num_back_buffers; i++) { + if (new_resource[i]) + pipe_resource_reference(&new_resource[i], NULL); + if (new_handles[i]) + D3DWindowBuffer_release(This, new_handles[i]); + } + } else { + for (i = 0; i < This->num_back_buffers; i++) { + D3DWindowBuffer_release(This, This->present_handles[i]); + This->present_handles[i] = new_handles[i]; + pipe_resource_reference(&This->present_buffers[i], new_resource[i]); + pipe_resource_reference(&new_resource[i], NULL); + } + } + } + + pipe = NineDevice9_GetPipe(This->base.device); + + if (This->present_buffers[0]) { + memset(&blit, 0, sizeof(blit)); + blit.src.resource = resource; + blit.src.level = 0; /* Note: This->buffers[0]->level should always be 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; + + /* Reallocate a new presentation buffer if the target window + * size has changed */ + if (target_width != This->present_buffers[0]->width0 || + target_height != This->present_buffers[0]->height0) { + struct pipe_resource *new_resource; + D3DWindowBuffer *new_handle; + + create_present_buffer(This, target_width, target_height, &new_resource, &new_handle); + /* Switch to the new buffer */ + if (new_handle) { + D3DWindowBuffer_release(This, This->present_handles[0]); + This->present_handles[0] = new_handle; + pipe_resource_reference(&This->present_buffers[0], new_resource); + pipe_resource_reference(&new_resource, NULL); + } + } + + 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 = (blit.dst.box.width == blit.src.box.width && + blit.dst.box.height == blit.src.box.height) ? + PIPE_TEX_FILTER_NEAREST : PIPE_TEX_FILTER_LINEAR; + blit.scissor_enable = false; + blit.alpha_blend = false; + + pipe->blit(pipe, &blit); + } + + /* The resource we present has to resolve fast clears + * if needed (and other things) */ + pipe->flush_resource(pipe, resource); + + if (This->params.SwapEffect != D3DSWAPEFFECT_DISCARD) + handle_draw_cursor_and_hud(This, resource); + + fence = NULL; + /* When threadpool is enabled, we don't submit before the fence + * tells us rendering was finished, thus we can flush async there */ + pipe->flush(pipe, &fence, PIPE_FLUSH_END_OF_FRAME | (This->enable_threadpool ? PIPE_FLUSH_ASYNC : 0)); + + /* Present now for thread_submit, because we have the fence. + * It's possible we return WASSTILLDRAWING and still Present, + * but it should be fine. */ + if (This->enable_threadpool) + pend_present(This, fence, hDestWindowOverride); + 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_finish(This->screen, NULL, fence, 0); + This->screen->fence_reference(This->screen, &fence, NULL); + } + if (still_draw) + return D3DERR_WASSTILLDRAWING; + } + + /* Throttle rendering if needed */ + fence = swap_fences_pop_front(This); + if (fence) { + (void) This->screen->fence_finish(This->screen, NULL, fence, OS_TIMEOUT_INFINITE); + This->screen->fence_reference(This->screen, &fence, NULL); + } + + This->rendering_done = false; + + if (!This->enable_threadpool) { + This->tasks[0]=NULL; + + hr = ID3DPresent_PresentBuffer(This->present, This->present_handles[0], hDestWindowOverride, pSourceRect, pDestRect ? &dest_rect : NULL, NULL, dwFlags); + + if (FAILED(hr)) { UNTESTED(3);return hr; } + } + + This->base.device->end_scene_since_present = 0; + This->base.device->frame_count++; + return D3D_OK; +} + +HRESULT NINE_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; + struct threadpool_task *task_temp; + BOOL *pending_presentation_temp; + int i; + HRESULT hr; + + DBG("This=%p pSourceRect=%p pDestRect=%p hDestWindowOverride=%p " + "pDirtyRegion=%p dwFlags=%d\n", + This, pSourceRect, pDestRect, hDestWindowOverride, + pDirtyRegion,dwFlags); + + if (This->base.device->ex) { + if (NineSwapChain9_GetOccluded(This)) { + DBG("Present is occluded. Returning S_PRESENT_OCCLUDED.\n"); + return S_PRESENT_OCCLUDED; + } + } else { + if (NineSwapChain9_GetOccluded(This) || + NineSwapChain9_ResolutionMismatch(This)) { + This->base.device->device_needs_reset = true; + } + if (This->base.device->device_needs_reset) { + DBG("Device is lost. Returning D3DERR_DEVICELOST.\n"); + return D3DERR_DEVICELOST; + } + } + + nine_csmt_process(This->base.device); + + hr = present(This, pSourceRect, pDestRect, + hDestWindowOverride, pDirtyRegion, dwFlags); + if (hr == D3DERR_WASSTILLDRAWING) + return hr; + + if (This->base.device->minor_version_num > 2 && + This->actx->discard_delayed_release && + This->params.SwapEffect == D3DSWAPEFFECT_DISCARD && + This->params.PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE) { + int next_buffer = -1; + + while (next_buffer == -1) { + /* Find a free backbuffer */ + for (i = 1; i < This->num_back_buffers; i++) { + if (!p_atomic_read(This->pending_presentation[i]) && + ID3DPresent_IsBufferReleased(This->present, This->present_handles[i])) { + DBG("Found buffer released: %d\n", i); + next_buffer = i; + break; + } + } + if (next_buffer == -1) { + DBG("Found no buffer released. Waiting for event\n"); + ID3DPresent_WaitBufferReleaseEvent(This->present); + } + } + + /* Free the task (we already checked it is finished) */ + if (This->tasks[next_buffer]) + _mesa_threadpool_wait_for_task(This->pool, &(This->tasks[next_buffer])); + assert(!*This->pending_presentation[next_buffer] && !This->tasks[next_buffer]); + This->tasks[next_buffer] = This->tasks[0]; + This->tasks[0] = NULL; + pending_presentation_temp = This->pending_presentation[next_buffer]; + This->pending_presentation[next_buffer] = This->pending_presentation[0]; + This->pending_presentation[0] = pending_presentation_temp; + + /* Switch with the released buffer */ + pipe_resource_reference(&res, This->buffers[0]->base.resource); + NineSurface9_SetResourceResize( + This->buffers[0], This->buffers[next_buffer]->base.resource); + NineSurface9_SetResourceResize( + This->buffers[next_buffer], res); + pipe_resource_reference(&res, NULL); + + if (This->present_buffers[0]) { + pipe_resource_reference(&res, This->present_buffers[0]); + pipe_resource_reference(&This->present_buffers[0], This->present_buffers[next_buffer]); + pipe_resource_reference(&This->present_buffers[next_buffer], res); + pipe_resource_reference(&res, NULL); + } + + handle_temp = This->present_handles[0]; + This->present_handles[0] = This->present_handles[next_buffer]; + This->present_handles[next_buffer] = handle_temp; + } else { + switch (This->params.SwapEffect) { + case D3DSWAPEFFECT_OVERLAY: /* Not implemented, fallback to FLIP */ + case D3DSWAPEFFECT_FLIPEX: /* Allows optimizations over FLIP for windowed mode. */ + case D3DSWAPEFFECT_DISCARD: /* Allows optimizations over FLIP */ + case D3DSWAPEFFECT_FLIP: + /* rotate the queue */ + pipe_resource_reference(&res, This->buffers[0]->base.resource); + for (i = 1; i < This->num_back_buffers; i++) { + NineSurface9_SetResourceResize(This->buffers[i - 1], + This->buffers[i]->base.resource); + } + NineSurface9_SetResourceResize( + This->buffers[This->num_back_buffers - 1], res); + pipe_resource_reference(&res, NULL); + + if (This->present_buffers[0]) { + pipe_resource_reference(&res, This->present_buffers[0]); + for (i = 1; i < This->num_back_buffers; i++) + pipe_resource_reference(&(This->present_buffers[i-1]), This->present_buffers[i]); + pipe_resource_reference(&(This->present_buffers[This->num_back_buffers - 1]), res); + pipe_resource_reference(&res, NULL); + } + + handle_temp = This->present_handles[0]; + for (i = 1; i < This->num_back_buffers; i++) { + This->present_handles[i-1] = This->present_handles[i]; + } + This->present_handles[This->num_back_buffers - 1] = handle_temp; + task_temp = This->tasks[0]; + for (i = 1; i < This->num_back_buffers; i++) { + This->tasks[i-1] = This->tasks[i]; + } + This->tasks[This->num_back_buffers - 1] = task_temp; + pending_presentation_temp = This->pending_presentation[0]; + for (i = 1; i < This->num_back_buffers; i++) { + This->pending_presentation[i-1] = This->pending_presentation[i]; + } + This->pending_presentation[This->num_back_buffers - 1] = pending_presentation_temp; + break; + + case D3DSWAPEFFECT_COPY: + /* do nothing */ + break; + } + + if (This->tasks[0]) + _mesa_threadpool_wait_for_task(This->pool, &(This->tasks[0])); + assert(!*This->pending_presentation[0]); + + ID3DPresent_WaitBufferReleased(This->present, This->present_handles[0]); + } + + This->base.device->context.changed.group |= NINE_STATE_FB; + + return hr; +} + +HRESULT NINE_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); + + user_assert(dest_surface->base.pool == D3DPOOL_SYSTEMMEM, D3DERR_INVALIDCALL); + + 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); + + if (!temp_resource || !temp_handle) { + return D3DERR_INVALIDCALL; + } + + desc.Type = D3DRTYPE_SURFACE; + desc.Pool = D3DPOOL_DEFAULT; + desc.MultiSampleType = D3DMULTISAMPLE_NONE; + desc.MultiSampleQuality = 0; + desc.Width = width; + desc.Height = height; + /* NineSurface9_CopyDefaultToMem needs same format. */ + desc.Format = dest_surface->desc.Format; + desc.Usage = D3DUSAGE_RENDERTARGET; + hr = NineSurface9_new(pDevice, NineUnknown(This), temp_resource, NULL, 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_CopyDefaultToMem(dest_surface, temp_surface); + + ID3DPresent_DestroyD3DWindowBuffer(This->present, temp_handle); + NineUnknown_Destroy(NineUnknown(temp_surface)); + + return D3D_OK; +} + +HRESULT NINE_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); + /* don't touch ppBackBuffer on error */ + user_assert(ppBackBuffer != NULL, D3DERR_INVALIDCALL); + user_assert(iBackBuffer < This->params.BackBufferCount, D3DERR_INVALIDCALL); + + NineUnknown_AddRef(NineUnknown(This->buffers[iBackBuffer])); + *ppBackBuffer = (IDirect3DSurface9 *)This->buffers[iBackBuffer]; + return D3D_OK; +} + +HRESULT NINE_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 NINE_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 NINE_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); +} + +BOOL +NineSwapChain9_GetOccluded( struct NineSwapChain9 *This ) +{ + if (This->base.device->minor_version_num > 0) { + return ID3DPresent_GetWindowOccluded(This->present); + } + + return false; +} + +BOOL +NineSwapChain9_ResolutionMismatch( struct NineSwapChain9 *This ) +{ + if (This->base.device->minor_version_num > 1) { + return ID3DPresent_ResolutionMismatch(This->present); + } + + return false; +} + +HANDLE +NineSwapChain9_CreateThread( struct NineSwapChain9 *This, + void *pFuncAddress, + void *pParam ) +{ + if (This->base.device->minor_version_num > 1) { + return ID3DPresent_CreateThread(This->present, pFuncAddress, pParam); + } + + return NULL; +} + +void +NineSwapChain9_WaitForThread( struct NineSwapChain9 *This, + HANDLE thread ) +{ + if (This->base.device->minor_version_num > 1) { + (void) ID3DPresent_WaitForThread(This->present, thread); + } +} + +static int +NineSwapChain9_GetBackBufferCountForParams( struct NineSwapChain9 *This, + D3DPRESENT_PARAMETERS *pParams ) +{ + int count = pParams->BackBufferCount; + + /* 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 */ + if (pParams->SwapEffect != D3DSWAPEFFECT_COPY) + count++; + /* With DISCARD, as there is no guarantee about the buffer contents, we can use + * an arbitrary number of buffers */ + if (pParams->SwapEffect == D3DSWAPEFFECT_DISCARD) { + /* thread_submit's can have maximum count or This->actx->throttling_value + 1 + * frames in flight being rendered and not shown. + * Do not let count decrease that number */ + if (This->actx->thread_submit && count < This->desired_fences) + count = This->desired_fences; + /* When we enable AllowDISCARDDelayedRelease, we must ensure + * to have at least 4 buffers to meet INTERVAL_IMMEDIATE, + * since the display server/compositor can hold 3 buffers + * without releasing them: + * . Buffer on screen. + * . Buffer scheduled kernel side to be next on screen. + * . Last buffer sent. */ + if (This->base.device->minor_version_num > 2 && + This->actx->discard_delayed_release && + pParams->PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE) { + if (This->actx->thread_submit && count < 4) + count = 4; + /* When thread_submit is not used, 5 buffers are actually needed, + * because in case a pageflip is missed because rendering wasn't finished, + * the Xserver will hold 4 buffers. */ + else if (!This->actx->thread_submit && count < 5) + count = 5; + /* Somehow this cases needs 5 with thread_submit, or else you get a small performance hit */ + if (This->actx->tearfree_discard && count < 5) + count = 5; + } + } + + return count; +} diff --git a/src/gallium/frontends/nine/swapchain9.h b/src/gallium/frontends/nine/swapchain9.h new file mode 100644 index 0000000..41c3c45 --- /dev/null +++ b/src/gallium/frontends/nine/swapchain9.h @@ -0,0 +1,141 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#ifndef _NINE_SWAPCHAIN9_H_ +#define _NINE_SWAPCHAIN9_H_ + +#include "iunknown.h" +#include "adapter9.h" + +#include "d3dadapter/d3dadapter9.h" + +#include "threadpool.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; + + /* presentation backend */ + ID3DPresent *present; + D3DPRESENT_PARAMETERS params; + D3DDISPLAYMODEEX *mode; + struct d3dadapter9_context *actx; + BOOL implicit; + unsigned num_back_buffers; + + /* buffer handles */ + struct NineSurface9 *buffers[D3DPRESENT_BACK_BUFFERS_MAX_EX + 1]; /* 0 to BackBufferCount-1 : the back buffers. BackBufferCount : additional buffer */ + struct pipe_resource *present_buffers[D3DPRESENT_BACK_BUFFERS_MAX_EX + 1]; + D3DWindowBuffer *present_handles[D3DPRESENT_BACK_BUFFERS_MAX_EX + 1]; + D3DWindowBuffer *present_handles_pending_release[D3DPRESENT_BACK_BUFFERS_MAX_EX + 1]; + + 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; + + struct threadpool *pool; + struct threadpool_task *tasks[D3DPRESENT_BACK_BUFFERS_MAX_EX + 1]; + BOOL *pending_presentation[D3DPRESENT_BACK_BUFFERS_MAX_EX + 1]; + BOOL enable_threadpool; +}; + +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 NINE_WINAPI +NineSwapChain9_Present( struct NineSwapChain9 *This, + const RECT *pSourceRect, + const RECT *pDestRect, + HWND hDestWindowOverride, + const RGNDATA *pDirtyRegion, + DWORD dwFlags ); + +HRESULT NINE_WINAPI +NineSwapChain9_GetFrontBufferData( struct NineSwapChain9 *This, + IDirect3DSurface9 *pDestSurface ); + +HRESULT NINE_WINAPI +NineSwapChain9_GetBackBuffer( struct NineSwapChain9 *This, + UINT iBackBuffer, + D3DBACKBUFFER_TYPE Type, + IDirect3DSurface9 **ppBackBuffer ); + +HRESULT NINE_WINAPI +NineSwapChain9_GetRasterStatus( struct NineSwapChain9 *This, + D3DRASTER_STATUS *pRasterStatus ); + +HRESULT NINE_WINAPI +NineSwapChain9_GetDisplayMode( struct NineSwapChain9 *This, + D3DDISPLAYMODE *pMode ); + +HRESULT NINE_WINAPI +NineSwapChain9_GetPresentParameters( struct NineSwapChain9 *This, + D3DPRESENT_PARAMETERS *pPresentationParameters ); + +BOOL +NineSwapChain9_GetOccluded( struct NineSwapChain9 *This ); + +BOOL +NineSwapChain9_ResolutionMismatch( struct NineSwapChain9 *This ); + +HANDLE +NineSwapChain9_CreateThread( struct NineSwapChain9 *This, + void *pFuncAddress, + void *pParam ); + +void +NineSwapChain9_WaitForThread( struct NineSwapChain9 *This, + HANDLE thread ); + +#endif /* _NINE_SWAPCHAIN9_H_ */ diff --git a/src/gallium/frontends/nine/swapchain9ex.c b/src/gallium/frontends/nine/swapchain9ex.c new file mode 100644 index 0000000..55a30b4 --- /dev/null +++ b/src/gallium/frontends/nine/swapchain9ex.c @@ -0,0 +1,100 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#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 ) +{ + DBG("This=%p pParams=%p implicit=%d pPresent=%p pPresentationParameters=%p " + "pCTX=%p hFocusWindow=%p mode=%p", + This, pParams, (int) implicit, pPresent, pPresentationParameters, pCTX, hFocusWindow, 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 NINE_WINAPI +NineSwapChain9Ex_GetLastPresentCount( struct NineSwapChain9Ex *This, + UINT *pLastPresentCount ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT NINE_WINAPI +NineSwapChain9Ex_GetPresentStats( struct NineSwapChain9Ex *This, + D3DPRESENTSTATS *pPresentationStatistics ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT NINE_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/frontends/nine/swapchain9ex.h b/src/gallium/frontends/nine/swapchain9ex.h new file mode 100644 index 0000000..db92131 --- /dev/null +++ b/src/gallium/frontends/nine/swapchain9ex.h @@ -0,0 +1,44 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#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 NINE_WINAPI +NineSwapChain9Ex_GetLastPresentCount( struct NineSwapChain9Ex *This, + UINT *pLastPresentCount ); + +HRESULT NINE_WINAPI +NineSwapChain9Ex_GetPresentStats( struct NineSwapChain9Ex *This, + D3DPRESENTSTATS *pPresentationStatistics ); + +HRESULT NINE_WINAPI +NineSwapChain9Ex_GetDisplayModeEx( struct NineSwapChain9Ex *This, + D3DDISPLAYMODEEX *pMode, + D3DDISPLAYROTATION *pRotation ); + +#endif /* _NINE_SWAPCHAIN9EX_H_ */ diff --git a/src/gallium/frontends/nine/texture9.c b/src/gallium/frontends/nine/texture9.c new file mode 100644 index 0000000..ee608ff --- /dev/null +++ b/src/gallium/frontends/nine/texture9.c @@ -0,0 +1,375 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#include "c99_alloca.h" + +#include "device9.h" +#include "surface9.h" +#include "texture9.h" +#include "nine_helpers.h" +#include "nine_memory_helper.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; + enum pipe_format pf; + unsigned *level_offsets = NULL; + unsigned l; + D3DSURFACE_DESC sfdesc; + HRESULT hr; + struct nine_allocation *user_buffer = NULL, *user_buffer_for_level; + + This->base.base.base.device = pParams->device; /* Early fill this field in case of failure */ + + 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(Width && Height, D3DERR_INVALIDCALL); + + /* pSharedHandle: can be non-null for ex only. + * D3DPOOL_SYSTEMMEM: Levels must be 1 + * D3DPOOL_DEFAULT: no restriction for Levels + * Other Pools are forbidden. */ + user_assert(!pSharedHandle || pParams->device->ex, D3DERR_INVALIDCALL); + user_assert(!pSharedHandle || + (Pool == D3DPOOL_SYSTEMMEM && Levels == 1) || + Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL); + + user_assert(!(Usage & D3DUSAGE_AUTOGENMIPMAP) || + (Pool != D3DPOOL_SYSTEMMEM && Pool != D3DPOOL_SCRATCH && Levels <= 1), + D3DERR_INVALIDCALL); + + /* TODO: implement pSharedHandle for D3DPOOL_DEFAULT (cross process + * buffer sharing). + * + * 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. + */ + + if (pSharedHandle && Pool == D3DPOOL_DEFAULT) { + if (!*pSharedHandle) { + 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; + + pf = d3d9_to_pipe_format_checked(screen, Format, PIPE_TEXTURE_2D, 0, + PIPE_BIND_SAMPLER_VIEW, false, + Pool == D3DPOOL_SCRATCH); + + if (Format != D3DFMT_NULL && pf == PIPE_FORMAT_NONE) + return D3DERR_INVALIDCALL; + + if (compressed_format(Format)) { + const unsigned w = util_format_get_blockwidth(pf); + const unsigned h = util_format_get_blockheight(pf); + + user_assert(!(Width % w) && !(Height % h), D3DERR_INVALIDCALL); + } + + info->screen = screen; + info->target = PIPE_TEXTURE_2D; + info->format = pf; + 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->nr_storage_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; + } + + if (Usage & D3DUSAGE_SOFTWAREPROCESSING) + DBG("Application asked for Software Vertex Processing, " + "but this is unimplemented\n"); + + hr = NineBaseTexture9_ctor(&This->base, pParams, NULL, D3DRTYPE_TEXTURE, Format, Pool, Usage); + if (FAILED(hr)) + return hr; + This->base.pstype = (Height == 1) ? 1 : 0; + + if (pSharedHandle && *pSharedHandle) { /* Pool == D3DPOOL_SYSTEMMEM */ + user_buffer = nine_wrap_external_pointer(pParams->device->allocator, (void *)*pSharedHandle); + level_offsets = alloca(sizeof(unsigned) * This->base.level_count); + (void) nine_format_get_size_and_offsets(pf, level_offsets, + Width, Height, + This->base.level_count-1); + } else if (Pool != D3DPOOL_DEFAULT) { + level_offsets = alloca(sizeof(unsigned) * This->base.level_count); + user_buffer = nine_allocate(pParams->device->allocator, + nine_format_get_size_and_offsets(pf, level_offsets, + Width, Height, + This->base.level_count-1)); + This->managed_buffer = user_buffer; + if (!This->managed_buffer) + return E_OUTOFMEMORY; + } + + This->surfaces = CALLOC(This->base.level_count, sizeof(*This->surfaces)); + if (!This->surfaces) + return E_OUTOFMEMORY; + + /* 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 < This->base.level_count; ++l) { + sfdesc.Width = u_minify(Width, l); + sfdesc.Height = u_minify(Height, l); + /* Some apps expect the memory to be allocated in + * continuous blocks */ + user_buffer_for_level = user_buffer ? + nine_suballocate(pParams->device->allocator, user_buffer, level_offsets[l]) : NULL; + + hr = NineSurface9_new(This->base.base.base.device, NineUnknown(This), + This->base.base.resource, user_buffer_for_level, + D3DRTYPE_TEXTURE, l, 0, + &sfdesc, &This->surfaces[l]); + if (FAILED(hr)) + return hr; + } + + /* Textures start initially dirty */ + This->dirty_rect.width = Width; + This->dirty_rect.height = Height; + This->dirty_rect.depth = 1; /* width == 0 means empty, depth stays 1 */ + + if (pSharedHandle && !*pSharedHandle) {/* Pool == D3DPOOL_SYSTEMMEM */ + *pSharedHandle = This->surfaces[0]->data; + } + + return D3D_OK; +} + +static void +NineTexture9_dtor( struct NineTexture9 *This ) +{ + bool is_worker = nine_context_is_worker(This->base.base.base.device); + unsigned l; + + DBG("This=%p\n", This); + + if (This->surfaces) { + /* The surfaces should have 0 references and be unbound now. */ + for (l = 0; l < This->base.level_count; ++l) + if (This->surfaces[l]) + NineUnknown_Destroy(&This->surfaces[l]->base.base); + FREE(This->surfaces); + } + + if (This->managed_buffer) { + if (is_worker) + nine_free_worker(This->base.base.base.device->allocator, This->managed_buffer); + else + nine_free(This->base.base.base.device->allocator, This->managed_buffer); + } + + NineBaseTexture9_dtor(&This->base); +} + +HRESULT NINE_WINAPI +NineTexture9_GetLevelDesc( struct NineTexture9 *This, + UINT Level, + D3DSURFACE_DESC *pDesc ) +{ + DBG("This=%p Level=%d pDesc=%p\n", This, Level, pDesc); + + user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL); + user_assert(pDesc, D3DERR_INVALIDCALL); + + *pDesc = This->surfaces[Level]->desc; + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineTexture9_GetSurfaceLevel( struct NineTexture9 *This, + UINT Level, + IDirect3DSurface9 **ppSurfaceLevel ) +{ + DBG("This=%p Level=%d ppSurfaceLevel=%p\n", This, Level, ppSurfaceLevel); + + user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL); + user_assert(ppSurfaceLevel, D3DERR_INVALIDCALL); + + NineUnknown_AddRef(NineUnknown(This->surfaces[Level])); + *ppSurfaceLevel = (IDirect3DSurface9 *)This->surfaces[Level]; + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineTexture9_LockRect( struct NineTexture9 *This, + UINT Level, + D3DLOCKED_RECT *pLockedRect, + const RECT *pRect, + DWORD Flags ) +{ + DBG("This=%p Level=%u pLockedRect=%p pRect=%p Flags=%d\n", + This, Level, pLockedRect, pRect, Flags); + + user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL); + + return NineSurface9_LockRect(This->surfaces[Level], pLockedRect, + pRect, Flags); +} + +HRESULT NINE_WINAPI +NineTexture9_UnlockRect( struct NineTexture9 *This, + UINT Level ) +{ + DBG("This=%p Level=%u\n", This, Level); + + user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL); + + return NineSurface9_UnlockRect(This->surfaces[Level]); +} + +HRESULT NINE_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 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_DEFAULT) { + if (This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP) { + This->base.dirty_mip = true; + BASETEX_REGISTER_UPDATE(&This->base); + } + return D3D_OK; + } + + if (This->base.base.pool == D3DPOOL_MANAGED) { + This->base.managed.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 { + if (This->dirty_rect.width == 0) { + rect_to_pipe_box_clamp(&This->dirty_rect, pDirtyRect); + } else { + struct pipe_box box; + rect_to_pipe_box_clamp(&box, pDirtyRect); + u_box_union_2d(&This->dirty_rect, &This->dirty_rect, &box); + } + (void) u_box_clip_2d(&This->dirty_rect, &This->dirty_rect, + This->base.base.info.width0, + This->base.base.info.height0); + } + return D3D_OK; +} + +IDirect3DTexture9Vtbl NineTexture9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */ + (void *)NineUnknown_SetPrivateData, + (void *)NineUnknown_GetPrivateData, + (void *)NineUnknown_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/frontends/nine/texture9.h b/src/gallium/frontends/nine/texture9.h new file mode 100644 index 0000000..2bf85d2 --- /dev/null +++ b/src/gallium/frontends/nine/texture9.h @@ -0,0 +1,60 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#ifndef _NINE_TEXTURE9_H_ +#define _NINE_TEXTURE9_H_ + +#include "basetexture9.h" +#include "nine_memory_helper.h" +#include "surface9.h" + +struct NineTexture9 +{ + struct NineBaseTexture9 base; + struct NineSurface9 **surfaces; + struct pipe_box dirty_rect; /* covers all mip levels */ + struct nine_allocation *managed_buffer; +}; +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 NINE_WINAPI +NineTexture9_GetLevelDesc( struct NineTexture9 *This, + UINT Level, + D3DSURFACE_DESC *pDesc ); + +HRESULT NINE_WINAPI +NineTexture9_GetSurfaceLevel( struct NineTexture9 *This, + UINT Level, + IDirect3DSurface9 **ppSurfaceLevel ); + +HRESULT NINE_WINAPI +NineTexture9_LockRect( struct NineTexture9 *This, + UINT Level, + D3DLOCKED_RECT *pLockedRect, + const RECT *pRect, + DWORD Flags ); + +HRESULT NINE_WINAPI +NineTexture9_UnlockRect( struct NineTexture9 *This, + UINT Level ); + +HRESULT NINE_WINAPI +NineTexture9_AddDirtyRect( struct NineTexture9 *This, + const RECT *pDirtyRect ); + +#endif /* _NINE_TEXTURE9_H_ */ diff --git a/src/gallium/frontends/nine/threadpool.c b/src/gallium/frontends/nine/threadpool.c new file mode 100644 index 0000000..37f6773 --- /dev/null +++ b/src/gallium/frontends/nine/threadpool.c @@ -0,0 +1,182 @@ +/* + * Copyright © 2012 Intel Corporation + * SPDX-License-Identifier: MIT + */ + +#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 "frontend/drm_driver.h" + +#include "util/u_thread.h" +#include "threadpool.h" + +/* POSIX thread function */ +static void * +threadpool_worker(void *data) +{ + struct threadpool *pool = data; + + pthread_mutex_lock(&pool->m); + + while (!pool->shutdown) { + struct threadpool_task *task; + + /* Block (dropping the lock) until new work arrives for us. */ + while (!pool->workqueue && !pool->shutdown) + pthread_cond_wait(&pool->new_work, &pool->m); + + if (pool->shutdown) + break; + + /* Pull the first task from the list. We don't free it -- it now lacks + * a reference other than the worker creator's, whose responsibility it + * is to call threadpool_wait_for_work() to free it. + */ + task = pool->workqueue; + pool->workqueue = task->next; + + /* Call the task's work func. */ + pthread_mutex_unlock(&pool->m); + task->work(task->data); + pthread_mutex_lock(&pool->m); + task->finished = true; + pthread_cond_broadcast(&task->finish); + } + + pthread_mutex_unlock(&pool->m); + + return NULL; +} + +/* Windows thread function */ +static DWORD NINE_WINAPI +wthreadpool_worker(void *data) +{ + threadpool_worker(data); + + return 0; +} + +struct threadpool * +_mesa_threadpool_create(struct NineSwapChain9 *swapchain) +{ + struct threadpool *pool = calloc(1, sizeof(*pool)); + + if (!pool) + return NULL; + + pthread_mutex_init(&pool->m, NULL); + pthread_cond_init(&pool->new_work, NULL); + + /* This uses WINE's CreateThread, so the thread function needs to use + * the Windows ABI */ + pool->wthread = NineSwapChain9_CreateThread(swapchain, wthreadpool_worker, pool); + if (!pool->wthread) { + /* using pthread as fallback */ + pthread_create(&pool->pthread, NULL, threadpool_worker, pool); + } + return pool; +} + +void +_mesa_threadpool_destroy(struct NineSwapChain9 *swapchain, struct threadpool *pool) +{ + if (!pool) + return; + + pthread_mutex_lock(&pool->m); + pool->shutdown = true; + pthread_cond_broadcast(&pool->new_work); + pthread_mutex_unlock(&pool->m); + + if (pool->wthread) { + NineSwapChain9_WaitForThread(swapchain, pool->wthread); + } else { + pthread_join(pool->pthread, NULL); + } + + pthread_cond_destroy(&pool->new_work); + pthread_mutex_destroy(&pool->m); + free(pool); +} + +/** + * Queues a request for the work function to be asynchronously executed by the + * thread pool. + * + * The work func will get the "data" argument as its parameter -- any + * communication between the caller and the work function will occur through + * that. + * + * If there is an error, the work function is called immediately and NULL is + * returned. + */ +struct threadpool_task * +_mesa_threadpool_queue_task(struct threadpool *pool, + threadpool_task_func work, void *data) +{ + struct threadpool_task *task, *previous; + + if (!pool) { + work(data); + return NULL; + } + + task = calloc(1, sizeof(*task)); + if (!task) { + work(data); + return NULL; + } + + task->work = work; + task->data = data; + task->next = NULL; + pthread_cond_init(&task->finish, NULL); + + pthread_mutex_lock(&pool->m); + + if (!pool->workqueue) { + pool->workqueue = task; + } else { + previous = pool->workqueue; + while (previous && previous->next) + previous = previous->next; + + previous->next = task; + } + pthread_cond_signal(&pool->new_work); + pthread_mutex_unlock(&pool->m); + + return task; +} + +/** + * Blocks on the completion of the given task and frees the task. + */ +void +_mesa_threadpool_wait_for_task(struct threadpool *pool, + struct threadpool_task **task_handle) +{ + struct threadpool_task *task = *task_handle; + + if (!pool || !task) + return; + + pthread_mutex_lock(&pool->m); + while (!task->finished) + pthread_cond_wait(&task->finish, &pool->m); + pthread_mutex_unlock(&pool->m); + + pthread_cond_destroy(&task->finish); + free(task); + *task_handle = NULL; +} diff --git a/src/gallium/frontends/nine/threadpool.h b/src/gallium/frontends/nine/threadpool.h new file mode 100644 index 0000000..57d3769 --- /dev/null +++ b/src/gallium/frontends/nine/threadpool.h @@ -0,0 +1,42 @@ +/* + * Copyright © 2012 Intel Corporation + * SPDX-License-Identifier: MIT + */ + +#ifndef _THREADPOOL_H_ +#define _THREADPOOL_H_ + +#include + +struct NineSwapChain9; + +#define MAXTHREADS 1 + +struct threadpool { + pthread_mutex_t m; + pthread_cond_t new_work; + + HANDLE wthread; + pthread_t pthread; + struct threadpool_task *workqueue; + BOOL shutdown; +}; + +typedef void (*threadpool_task_func)(void *data); + +struct threadpool_task { + threadpool_task_func work; + void *data; + struct threadpool_task *next; + pthread_cond_t finish; + BOOL finished; +}; + +struct threadpool *_mesa_threadpool_create(struct NineSwapChain9 *swapchain); +void _mesa_threadpool_destroy(struct NineSwapChain9 *swapchain, struct threadpool *pool); +struct threadpool_task *_mesa_threadpool_queue_task(struct threadpool *pool, + threadpool_task_func func, + void *data); +void _mesa_threadpool_wait_for_task(struct threadpool *pool, + struct threadpool_task **task); +#endif diff --git a/src/gallium/frontends/nine/vertexbuffer9.c b/src/gallium/frontends/nine/vertexbuffer9.c new file mode 100644 index 0000000..036fce0 --- /dev/null +++ b/src/gallium/frontends/nine/vertexbuffer9.c @@ -0,0 +1,109 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#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 "util/format/u_formats.h" +#include "util/box.h" + +#define DBG_CHANNEL DBG_VERTEXBUFFER + +HRESULT +NineVertexBuffer9_ctor( struct NineVertexBuffer9 *This, + struct NineUnknownParams *pParams, + D3DVERTEXBUFFER_DESC *pDesc ) +{ + HRESULT hr; + + DBG("This=%p Size=0x%x Usage=%x Pool=%u\n", This, + pDesc->Size, pDesc->Usage, pDesc->Pool); + + hr = NineBuffer9_ctor(&This->base, pParams, D3DRTYPE_VERTEXBUFFER, + pDesc->Usage, pDesc->Size, 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 ) +{ + NineBuffer9_dtor(&This->base); +} + +struct pipe_resource * +NineVertexBuffer9_GetResource( struct NineVertexBuffer9 *This, unsigned *offset ) +{ + return NineBuffer9_GetResource(&This->base, offset); +} + +HRESULT NINE_WINAPI +NineVertexBuffer9_Lock( struct NineVertexBuffer9 *This, + UINT OffsetToLock, + UINT SizeToLock, + void **ppbData, + DWORD Flags ) +{ + return NineBuffer9_Lock(&This->base, OffsetToLock, SizeToLock, ppbData, Flags); +} + +HRESULT NINE_WINAPI +NineVertexBuffer9_Unlock( struct NineVertexBuffer9 *This ) +{ + return NineBuffer9_Unlock(&This->base); +} + +HRESULT NINE_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 *)NineUnknown_SetPrivateData, + (void *)NineUnknown_GetPrivateData, + (void *)NineUnknown_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/frontends/nine/vertexbuffer9.h b/src/gallium/frontends/nine/vertexbuffer9.h new file mode 100644 index 0000000..8a820cb --- /dev/null +++ b/src/gallium/frontends/nine/vertexbuffer9.h @@ -0,0 +1,62 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#ifndef _NINE_VERTEXBUFFER9_H_ +#define _NINE_VERTEXBUFFER9_H_ +#include "resource9.h" +#include "buffer9.h" + +struct pipe_screen; +struct pipe_context; +struct pipe_transfer; + +struct NineVertexBuffer9 +{ + struct NineBuffer9 base; + + /* G3D */ + struct pipe_context *pipe; + 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 ); +/*** Nine private ***/ + +struct pipe_resource * +NineVertexBuffer9_GetResource( struct NineVertexBuffer9 *This, unsigned *offset ); + +/*** Direct3D public ***/ + +HRESULT NINE_WINAPI +NineVertexBuffer9_Lock( struct NineVertexBuffer9 *This, + UINT OffsetToLock, + UINT SizeToLock, + void **ppbData, + DWORD Flags ); + +HRESULT NINE_WINAPI +NineVertexBuffer9_Unlock( struct NineVertexBuffer9 *This ); + +HRESULT NINE_WINAPI +NineVertexBuffer9_GetDesc( struct NineVertexBuffer9 *This, + D3DVERTEXBUFFER_DESC *pDesc ); + +#endif /* _NINE_VERTEXBUFFER9_H_ */ diff --git a/src/gallium/frontends/nine/vertexdeclaration9.c b/src/gallium/frontends/nine/vertexdeclaration9.c new file mode 100644 index 0000000..9096f9f --- /dev/null +++ b/src/gallium/frontends/nine/vertexdeclaration9.c @@ -0,0 +1,515 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#include "vertexdeclaration9.h" +#include "vertexbuffer9.h" +#include "device9.h" +#include "nine_helpers.h" +#include "nine_shader.h" + +#include "util/format/u_formats.h" +#include "pipe/p_context.h" +#include "util/u_math.h" +#include "util/format/u_format.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 bool +nine_d3ddeclusage_check(unsigned usage, unsigned usage_idx) +{ + switch (usage) { + case D3DDECLUSAGE_POSITIONT: + case D3DDECLUSAGE_TESSFACTOR: + case D3DDECLUSAGE_DEPTH: + case D3DDECLUSAGE_NORMAL: + case D3DDECLUSAGE_TANGENT: + case D3DDECLUSAGE_BINORMAL: + case D3DDECLUSAGE_POSITION: + case D3DDECLUSAGE_BLENDWEIGHT: + case D3DDECLUSAGE_BLENDINDICES: + case D3DDECLUSAGE_COLOR: + return true; + case D3DDECLUSAGE_PSIZE: + case D3DDECLUSAGE_FOG: + case D3DDECLUSAGE_SAMPLE: + return usage_idx <= 0; + 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_i(n, usage_idx) +uint16_t +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_CASEi(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] = "POSITION", + [NINE_DECLUSAGE_BLENDWEIGHT] = "BLENDWEIGHT", + [NINE_DECLUSAGE_BLENDINDICES] = "BLENDINDICES", + [NINE_DECLUSAGE_NORMAL] = "NORMAL", + [NINE_DECLUSAGE_PSIZE] = "PSIZE", + [NINE_DECLUSAGE_TEXCOORD] = "TEXCOORD", + [NINE_DECLUSAGE_TANGENT] = "TANGENT", + [NINE_DECLUSAGE_BINORMAL] = "BINORMAL", + [NINE_DECLUSAGE_TESSFACTOR] = "TESSFACTOR", + [NINE_DECLUSAGE_POSITIONT] = "POSITIONT", + [NINE_DECLUSAGE_COLOR] = "DIFFUSE", + [NINE_DECLUSAGE_DEPTH] = "DEPTH", + [NINE_DECLUSAGE_FOG] = "FOG", + [NINE_DECLUSAGE_NONE] = "(NONE)", +}; +static inline const char * +nine_declusage_name(unsigned ndcl) +{ + return nine_declusage_names[ndcl % NINE_DECLUSAGE_COUNT]; +} + +HRESULT +NineVertexDeclaration9_ctor( struct NineVertexDeclaration9 *This, + struct NineUnknownParams *pParams, + const D3DVERTEXELEMENT9 *pElements ) +{ + const D3DCAPS9 *caps; + unsigned i, nelems; + DBG("This=%p pParams=%p pElements=%p\n", This, pParams, pElements); + + /* wine */ + for (nelems = 0; + pElements[nelems].Stream != 0xFF; + ++nelems) { + user_assert(pElements[nelems].Type != D3DDECLTYPE_UNUSED, E_FAIL); + user_assert(!(pElements[nelems].Offset & 3), E_FAIL); + } + + caps = NineDevice9_GetCaps(pParams->device); + user_assert(nelems <= caps->MaxStreams, D3DERR_INVALIDCALL); + + HRESULT hr = NineUnknown_ctor(&This->base, pParams); + if (FAILED(hr)) { return hr; } + + This->nelems = nelems; + This->decls = CALLOC(This->nelems+1, sizeof(D3DVERTEXELEMENT9)); + This->elems = CALLOC(This->nelems, sizeof(struct pipe_vertex_element)); + This->usage_map = CALLOC(This->nelems, sizeof(uint16_t)); + if (!This->decls || !This->elems || !This->usage_map) { return E_OUTOFMEMORY; } + memcpy(This->decls, pElements, sizeof(D3DVERTEXELEMENT9)*(This->nelems+1)); + + for (i = 0; i < This->nelems; ++i) { + uint16_t usage = nine_d3d9_to_nine_declusage(This->decls[i].Usage, + This->decls[i].UsageIndex); + This->usage_map[i] = usage; + + if (This->decls[i].Usage == D3DDECLUSAGE_POSITIONT) + This->position_t = true; + + 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); + This->elems[i].dual_slot = false; + /* XXX Remember Method (tessellation), Usage, UsageIndex */ + + DBG("VERTEXELEMENT[%u]: Stream=%u Offset=%u Type=%s DeclUsage=%s%d\n", i, + This->decls[i].Stream, + This->decls[i].Offset, + util_format_name(This->elems[i].src_format), + nine_declusage_name(usage), + usage / NINE_DECLUSAGE_COUNT); + } + + return D3D_OK; +} + +void +NineVertexDeclaration9_dtor( struct NineVertexDeclaration9 *This ) +{ + DBG("This=%p\n", This); + + FREE(This->decls); + FREE(This->elems); + FREE(This->usage_map); + + NineUnknown_dtor(&This->base); +} + +HRESULT NINE_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); +} + +void +NineVertexDeclaration9_FillStreamOutputInfo( + struct NineVertexDeclaration9 *This, + struct nine_vs_output_info *ShaderOutputsInfo, + unsigned numOutputs, + struct pipe_stream_output_info *so ) +{ + unsigned so_outputs = 0; + int i, j; + + memset(so, 0, sizeof(struct pipe_stream_output_info)); + + for (i = 0; i < numOutputs; i++) { + BYTE output_semantic = ShaderOutputsInfo[i].output_semantic; + unsigned output_semantic_index = ShaderOutputsInfo[i].output_semantic_index; + + for (j = 0; j < This->nelems; j++) { + if ((This->decls[j].Usage == output_semantic || + (output_semantic == D3DDECLUSAGE_POSITION && + This->decls[j].Usage == D3DDECLUSAGE_POSITIONT)) && + This->decls[j].UsageIndex == output_semantic_index) { + DBG("Matching %s %d: o%d -> %d\n", + nine_declusage_name(nine_d3d9_to_nine_declusage(This->decls[j].Usage, 0)), + This->decls[j].UsageIndex, i, j); + so->output[so_outputs].register_index = ShaderOutputsInfo[i].output_index; + so->output[so_outputs].start_component = 0; + if (ShaderOutputsInfo[i].mask & 8) + so->output[so_outputs].num_components = 4; + else if (ShaderOutputsInfo[i].mask & 4) + so->output[so_outputs].num_components = 3; + else if (ShaderOutputsInfo[i].mask & 2) + so->output[so_outputs].num_components = 2; + else + so->output[so_outputs].num_components = 1; + so->output[so_outputs].output_buffer = 0; + so->output[so_outputs].dst_offset = so_outputs * sizeof(float[4])/4; + so->output[so_outputs].stream = 0; + so_outputs++; + break; + } + } + } + + so->num_outputs = so_outputs; + so->stride[0] = so_outputs * sizeof(float[4])/4; +} + +/* 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, + void *pSrcBuf, + const struct pipe_stream_output_info *so ) +{ + struct translate *translate; + struct translate_key transkey; + HRESULT hr; + unsigned i; + void *dst_map; + + DBG("This=%p pDstBuf=%p DestIndex=%u VertexCount=%u pSrcBuf=%p so=%p\n", + This, pDstBuf, DestIndex, VertexCount, pSrcBuf, so); + + 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; + + translate->set_buffer(translate, 0, pSrcBuf, so->stride[0] * 4, ~0); + + translate->run(translate, 0, VertexCount, 0, 0, dst_map); + + NineVertexBuffer9_Unlock(pDstBuf); +out: + translate->release(translate); /* TODO: cache these */ + return hr; +} diff --git a/src/gallium/frontends/nine/vertexdeclaration9.h b/src/gallium/frontends/nine/vertexdeclaration9.h new file mode 100644 index 0000000..a06e005 --- /dev/null +++ b/src/gallium/frontends/nine/vertexdeclaration9.h @@ -0,0 +1,82 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#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 nine_vs_output_info; + +struct NineVertexDeclaration9 +{ + struct NineUnknown base; + + /* G3D state */ + struct pipe_vertex_element *elems; + unsigned nelems; + + /* index -> DECLUSAGE, for selecting the vertex element + * for each VS input */ + uint16_t *usage_map; + + D3DVERTEXELEMENT9 *decls; + DWORD fvf; + + BOOL position_t; +}; +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 NINE_WINAPI +NineVertexDeclaration9_GetDeclaration( struct NineVertexDeclaration9 *This, + D3DVERTEXELEMENT9 *pElement, + UINT *pNumElements ); + +void +NineVertexDeclaration9_FillStreamOutputInfo( + struct NineVertexDeclaration9 *This, + struct nine_vs_output_info *ShaderOutputsInfo, + unsigned numOutputs, + struct pipe_stream_output_info *so ); + +/* Convert stream output data to the vertex declaration's format. */ +HRESULT +NineVertexDeclaration9_ConvertStreamOutput( + struct NineVertexDeclaration9 *This, + struct NineVertexBuffer9 *pDstBuf, + UINT DestIndex, + UINT VertexCount, + void *pSrcBuf, + const struct pipe_stream_output_info *so ); + +#endif /* _NINE_VERTEXDECLARATION9_H_ */ diff --git a/src/gallium/frontends/nine/vertexshader9.c b/src/gallium/frontends/nine/vertexshader9.c new file mode 100644 index 0000000..3ff31ef --- /dev/null +++ b/src/gallium/frontends/nine/vertexshader9.c @@ -0,0 +1,299 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#include "nine_helpers.h" +#include "nine_shader.h" + +#include "vertexdeclaration9.h" +#include "vertexshader9.h" + +#include "device9.h" +#include "pipe/p_context.h" +#include "cso_cache/cso_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; + struct pipe_context *pipe; + HRESULT hr; + unsigned i; + + DBG("This=%p pParams=%p pFunction=%p cso=%p\n", + This, pParams, pFunction, cso); + + hr = NineUnknown_ctor(&This->base, pParams); + if (FAILED(hr)) + return hr; + + if (cso) { + This->ff_cso = cso; + return D3D_OK; + } + + device = This->base.device; + + info.type = MESA_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.fetch4 = 0x0; + info.sampler_ps1xtypes = 0x0; + info.fog_enable = 0; + info.point_size_min = 0; + info.point_size_max = 0; + info.clip_plane_emulation = 0; + info.add_constants_defs.c_combination = NULL; + info.add_constants_defs.int_const_added = NULL; + info.add_constants_defs.bool_const_added = NULL; + info.swvp_on = !!(device->params.BehaviorFlags & D3DCREATE_SOFTWARE_VERTEXPROCESSING); + info.process_vertices = false; + + pipe = nine_context_get_pipe_acquire(device); + hr = nine_translate_shader(device, &info, pipe); + if (hr == D3DERR_INVALIDCALL && + (device->params.BehaviorFlags & D3DCREATE_MIXED_VERTEXPROCESSING)) { + /* Retry with a swvp shader. It will require swvp to be on. */ + info.swvp_on = true; + hr = nine_translate_shader(device, &info, pipe); + } + nine_context_get_pipe_release(device); + if (hr == D3DERR_INVALIDCALL) + ERR("Encountered buggy shader\n"); + if (FAILED(hr)) + return hr; + This->byte_code.version = info.version; + This->swvp_only = info.swvp_on; + + 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->variant.const_ranges = info.const_ranges; + This->variant.const_used_size = info.const_used_size; + This->last_cso = info.cso; + This->last_const_ranges = info.const_ranges; + This->last_const_used_size = info.const_used_size; + This->last_key = (uint32_t) (info.swvp_on << 9); + + This->lconstf = info.lconstf; + This->sampler_mask = info.sampler_mask; + This->position_t = info.position_t; + This->point_size = info.point_size; + + memcpy(This->int_slots_used, info.int_slots_used, sizeof(This->int_slots_used)); + memcpy(This->bool_slots_used, info.bool_slots_used, sizeof(This->bool_slots_used)); + + This->const_int_slots = info.const_int_slots; + This->const_bool_slots = info.const_bool_slots; + + This->c_combinations = NULL; + + for (i = 0; i < info.num_inputs && i < ARRAY_SIZE(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\n", This); + + if (This->base.device) { + struct pipe_context *pipe = nine_context_get_pipe_multithread(This->base.device); + struct nine_shader_variant *var = &This->variant; + struct nine_shader_variant_so *var_so = &This->variant_so; + + do { + if (var->cso) { + if (This->base.device->context.cso_shader.vs == var->cso) { + /* unbind because it is illegal to delete something bound */ + pipe->bind_vs_state(pipe, NULL); + /* This will rebind cso_shader.vs in case somehow actually + * an identical shader with same cso is bound */ + This->base.device->context.commit |= NINE_STATE_COMMIT_VS; + } + pipe->delete_vs_state(pipe, var->cso); + FREE(var->const_ranges); + } + var = var->next; + } while (var); + + while (var_so && var_so->vdecl) { + if (var_so->cso) { + This->base.device->pipe_sw->delete_vs_state(This->base.device->pipe_sw, var_so->cso); + } + var_so = var_so->next; + } + + if (This->ff_cso) { + if (This->ff_cso == This->base.device->context.cso_shader.vs) { + pipe->bind_vs_state(pipe, NULL); + This->base.device->context.commit |= NINE_STATE_COMMIT_VS; + } + pipe->delete_vs_state(pipe, This->ff_cso); + } + } + nine_shader_variants_free(&This->variant); + nine_shader_variants_so_free(&This->variant_so); + + nine_shader_constant_combination_free(This->c_combinations); + + FREE((void *)This->byte_code.tokens); /* const_cast */ + + FREE(This->lconstf.data); + FREE(This->lconstf.ranges); + + NineUnknown_dtor(&This->base); +} + +HRESULT NINE_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, + unsigned **const_ranges, + unsigned *const_used_size ) +{ + /* GetVariant is called from nine_context, thus we can + * get pipe directly */ + struct pipe_context *pipe = This->base.device->context.pipe; + void *cso; + uint64_t key; + + key = This->next_key; + if (key == This->last_key) { + *const_ranges = This->last_const_ranges; + *const_used_size = This->last_const_used_size; + return This->last_cso; + } + + cso = nine_shader_variant_get(&This->variant, const_ranges, const_used_size, key); + if (!cso) { + struct NineDevice9 *device = This->base.device; + struct nine_shader_info info; + HRESULT hr; + + info.type = MESA_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; + info.fetch4 = 0x0; + info.fog_enable = device->context.rs[D3DRS_FOGENABLE]; + info.point_size_min = asfloat(device->context.rs[D3DRS_POINTSIZE_MIN]); + info.point_size_max = asfloat(device->context.rs[D3DRS_POINTSIZE_MAX]); + info.clip_plane_emulation = (key >> 24) & 0xff; + info.add_constants_defs.c_combination = + nine_shader_constant_combination_get(This->c_combinations, (key >> 16) & 0xff); + info.add_constants_defs.int_const_added = &This->int_slots_used; + info.add_constants_defs.bool_const_added = &This->bool_slots_used; + info.swvp_on = device->context.swvp; + info.process_vertices = false; + + hr = nine_translate_shader(This->base.device, &info, pipe); + if (FAILED(hr)) + return NULL; + nine_shader_variant_add(&This->variant, key, info.cso, + info.const_ranges, info.const_used_size); + cso = info.cso; + *const_ranges = info.const_ranges; + *const_used_size = info.const_used_size; + } + + This->last_key = key; + This->last_cso = cso; + This->last_const_ranges = *const_ranges; + This->last_const_used_size = *const_used_size; + + return cso; +} + +void * +NineVertexShader9_GetVariantProcessVertices( struct NineVertexShader9 *This, + struct NineVertexDeclaration9 *vdecl_out, + struct pipe_stream_output_info *so ) +{ + struct nine_shader_info info; + HRESULT hr; + void *cso; + + cso = nine_shader_variant_so_get(&This->variant_so, vdecl_out, so); + if (cso) + return cso; + + info.type = MESA_SHADER_VERTEX; + info.const_i_base = 0; + info.const_b_base = 0; + info.byte_code = This->byte_code.tokens; + info.sampler_mask_shadow = 0; + info.fetch4 = 0x0; + info.fog_enable = false; + info.point_size_min = 0; + info.point_size_max = 0; + info.add_constants_defs.c_combination = NULL; + info.add_constants_defs.int_const_added = NULL; + info.add_constants_defs.bool_const_added = NULL; + info.swvp_on = true; + info.vdecl_out = vdecl_out; + info.process_vertices = true; + hr = nine_translate_shader(This->base.device, &info, This->base.device->pipe_sw); + if (FAILED(hr)) + return NULL; + *so = info.so; + nine_shader_variant_so_add(&This->variant_so, vdecl_out, so, info.cso); + return info.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 ) +{ + if (cso) { + NINE_DEVICE_CHILD_BIND_NEW(VertexShader9, ppOut, pDevice, pFunction, cso); + } else { + NINE_DEVICE_CHILD_NEW(VertexShader9, ppOut, pDevice, pFunction, cso); + } +} diff --git a/src/gallium/frontends/nine/vertexshader9.h b/src/gallium/frontends/nine/vertexshader9.h new file mode 100644 index 0000000..aa4e1ac --- /dev/null +++ b/src/gallium/frontends/nine/vertexshader9.h @@ -0,0 +1,141 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#ifndef _NINE_VERTEXSHADER9_H_ +#define _NINE_VERTEXSHADER9_H_ + +#include "util/half_float.h" + +#include "iunknown.h" +#include "device9.h" +#include "nine_helpers.h" +#include "nine_shader.h" +#include "nine_state.h" + +struct NineVertexDeclaration9; + +struct NineVertexShader9 +{ + struct NineUnknown base; + struct nine_shader_variant variant; + + struct { + uint16_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; + + bool position_t; /* if true, disable vport transform */ + bool point_size; /* if true, set rasterizer.point_size_per_vertex to 1 */ + bool swvp_only; + + struct nine_lconstf lconstf; + + bool int_slots_used[NINE_MAX_CONST_I]; + bool bool_slots_used[NINE_MAX_CONST_B]; + + unsigned const_int_slots; + unsigned const_bool_slots; + + struct nine_shader_constant_combination *c_combinations; + + uint64_t ff_key[3]; + void *ff_cso; + + uint64_t last_key; + void *last_cso; + unsigned *last_const_ranges; + unsigned last_const_used_size; /* in bytes */ + + uint64_t next_key; + + /* so */ + struct nine_shader_variant_so variant_so; +}; +static inline struct NineVertexShader9 * +NineVertexShader9( void *data ) +{ + return (struct NineVertexShader9 *)data; +} + +static inline BOOL +NineVertexShader9_UpdateKey( struct NineVertexShader9 *vs, + struct NineDevice9 *device ) +{ + struct nine_context *context = &(device->context); + uint8_t samplers_shadow; + uint64_t key; + BOOL res; + + samplers_shadow = (uint8_t)((context->samplers_shadow & NINE_VS_SAMPLERS_MASK) >> NINE_SAMPLER_VS(0)); + samplers_shadow &= vs->sampler_mask; + key = samplers_shadow; + + if (vs->byte_code.version < 0x30) + key |= (uint32_t) ((!!context->rs[D3DRS_FOGENABLE]) << 8); + key |= (uint32_t) (context->swvp << 9); + + if ((vs->const_int_slots > 0 || vs->const_bool_slots > 0) && context->inline_constants && !context->swvp) + key |= ((uint64_t)nine_shader_constant_combination_key(&vs->c_combinations, + vs->int_slots_used, + vs->bool_slots_used, + context->vs_const_i, + context->vs_const_b)) << 16; + + if (device->driver_caps.emulate_ucp) + key |= (context->rs[D3DRS_CLIPPLANEENABLE] & 0xff) << 24; + + /* We want to use a 64 bits key for performance. + * Use compressed float16 values for the pointsize min/max in the key. + * Shaders do not usually output psize.*/ + if (vs->point_size) { + key |= ((uint64_t)_mesa_float_to_half(asfloat(context->rs[D3DRS_POINTSIZE_MIN]))) << 32; + key |= ((uint64_t)_mesa_float_to_half(asfloat(context->rs[D3DRS_POINTSIZE_MAX]))) << 48; + } + + res = vs->last_key != key; + if (res) + vs->next_key = key; + return res; +} + +void * +NineVertexShader9_GetVariant( struct NineVertexShader9 *vs, + unsigned **const_ranges, + unsigned *const_used_size ); + +void * +NineVertexShader9_GetVariantProcessVertices( struct NineVertexShader9 *vs, + struct NineVertexDeclaration9 *vdecl_out, + struct pipe_stream_output_info *so ); + +/*** 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 NINE_WINAPI +NineVertexShader9_GetFunction( struct NineVertexShader9 *This, + void *pData, + UINT *pSizeOfData ); + +#endif /* _NINE_VERTEXSHADER9_H_ */ diff --git a/src/gallium/frontends/nine/volume9.c b/src/gallium/frontends/nine/volume9.c new file mode 100644 index 0000000..c1e6d01 --- /dev/null +++ b/src/gallium/frontends/nine/volume9.c @@ -0,0 +1,540 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#include "device9.h" +#include "volume9.h" +#include "basetexture9.h" /* for marking dirty */ +#include "volumetexture9.h" +#include "nine_helpers.h" +#include "nine_pipe.h" +#include "nine_dump.h" + +#include "util/format/u_format.h" +#include "util/u_surface.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 *)align_calloc(size, 32); + 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; + + pipe_resource_reference(&This->resource, pResource); + + 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.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.nr_storage_samples = 0; + This->info.usage = PIPE_USAGE_DEFAULT; + This->info.bind = PIPE_BIND_SAMPLER_VIEW; + This->info.flags = 0; + This->info.format = d3d9_to_pipe_format_checked(This->info.screen, + pDesc->Format, + This->info.target, + This->info.nr_samples, + This->info.bind, false, + pDesc->Pool == D3DPOOL_SCRATCH); + + if (This->info.format == PIPE_FORMAT_NONE) + return D3DERR_DRIVERINTERNALERROR; + + 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); + + /* Get true format */ + This->format_internal = d3d9_to_pipe_format_checked(This->info.screen, + pDesc->Format, + This->info.target, + This->info.nr_samples, + This->info.bind, false, + true); + if (This->info.format != This->format_internal || + /* See surface9.c */ + (pParams->device->workarounds.dynamic_texture_workaround && + pDesc->Pool == D3DPOOL_DEFAULT && pDesc->Usage & D3DUSAGE_DYNAMIC)) { + This->stride_internal = nine_format_get_stride(This->format_internal, + pDesc->Width); + This->layer_stride_internal = util_format_get_2d_size(This->format_internal, + This->stride_internal, + pDesc->Height); + This->data_internal = align_calloc(This->layer_stride_internal * + This->desc.Depth, 32); + if (!This->data_internal) + return E_OUTOFMEMORY; + } + + 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) { + struct pipe_context *pipe = nine_context_get_pipe_multithread(This->base.device); + pipe->texture_unmap(pipe, This->transfer); + This->transfer = NULL; + } + + /* Note: Following condition cannot happen currently, since we + * refcount the volume in the functions increasing + * pending_uploads_counter. */ + if (p_atomic_read(&This->pending_uploads_counter)) + nine_csmt_process(This->base.device); + + if (This->data) + align_free(This->data); + if (This->data_internal) + align_free(This->data_internal); + + pipe_resource_reference(&This->resource, NULL); + + NineUnknown_dtor(&This->base); +} + +HRESULT NINE_WINAPI +NineVolume9_GetContainer( struct NineVolume9 *This, + REFIID riid, + void **ppContainer ) +{ + char guid_str[64]; + + DBG("This=%p riid=%p id=%s ppContainer=%p\n", + This, riid, riid ? GUID_sprintf(guid_str, riid) : "", ppContainer); + + (void)guid_str; + + 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; +#if MESA_DEBUG || !defined(NDEBUG) + /* 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->managed.dirty = true; + + BASETEX_REGISTER_UPDATE(tex); +} + +HRESULT NINE_WINAPI +NineVolume9_GetDesc( struct NineVolume9 *This, + D3DVOLUME_DESC *pDesc ) +{ + user_assert(pDesc != NULL, E_POINTER); + *pDesc = This->desc; + return D3D_OK; +} + +inline void +NineVolume9_AddDirtyRegion( struct NineVolume9 *This, + const struct pipe_box *box ) +{ + D3DBOX dirty_region; + struct NineVolumeTexture9 *tex = NineVolumeTexture9(This->base.container); + + if (!box) { + NineVolumeTexture9_AddDirtyBox(tex, NULL); + } else { + dirty_region.Left = box->x << This->level_actual; + dirty_region.Top = box->y << This->level_actual; + dirty_region.Front = box->z << This->level_actual; + dirty_region.Right = dirty_region.Left + (box->width << This->level_actual); + dirty_region.Bottom = dirty_region.Top + (box->height << This->level_actual); + dirty_region.Back = dirty_region.Front + (box->depth << This->level_actual); + NineVolumeTexture9_AddDirtyBox(tex, &dirty_region); + } +} + +static inline unsigned +NineVolume9_GetSystemMemOffset(enum pipe_format format, unsigned stride, + unsigned layer_stride, + int x, int y, int z) +{ + unsigned x_offset = util_format_get_stride(format, x); + + y = util_format_get_nblocksy(format, y); + + return z * layer_stride + y * stride + x_offset; +} + +HRESULT NINE_WINAPI +NineVolume9_LockBox( struct NineVolume9 *This, + D3DLOCKED_BOX *pLockedVolume, + const D3DBOX *pBox, + DWORD Flags ) +{ + struct pipe_context *pipe; + 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)); + + /* check if it's already locked */ + user_assert(This->lock_count == 0, D3DERR_INVALIDCALL); + + /* set pBits to NULL after lock_count check */ + user_assert(pLockedVolume, E_POINTER); + pLockedVolume->pBits = NULL; + + user_assert(This->desc.Pool != D3DPOOL_DEFAULT || + (This->desc.Usage & D3DUSAGE_DYNAMIC), D3DERR_INVALIDCALL); + + user_assert(!((Flags & D3DLOCK_DISCARD) && (Flags & D3DLOCK_READONLY)), + D3DERR_INVALIDCALL); + + if (pBox && compressed_format (This->desc.Format)) { /* For volume all pools are checked */ + const unsigned w = util_format_get_blockwidth(This->info.format); + const unsigned h = util_format_get_blockheight(This->info.format); + user_assert((pBox->Left == 0 && pBox->Right == This->desc.Width && + pBox->Top == 0 && pBox->Bottom == This->desc.Height) || + (!(pBox->Left % w) && !(pBox->Right % w) && + !(pBox->Top % h) && !(pBox->Bottom % h)), + D3DERR_INVALIDCALL); + } + + if (Flags & D3DLOCK_DISCARD) { + usage = PIPE_MAP_WRITE | PIPE_MAP_DISCARD_RANGE; + } else { + usage = (Flags & D3DLOCK_READONLY) ? + PIPE_MAP_READ : PIPE_MAP_READ_WRITE; + } + if (Flags & D3DLOCK_DONOTWAIT) + usage |= PIPE_MAP_DONTBLOCK; + + if (pBox) { + user_assert(pBox->Right > pBox->Left, D3DERR_INVALIDCALL); + user_assert(pBox->Bottom > pBox->Top, D3DERR_INVALIDCALL); + user_assert(pBox->Back > pBox->Front, D3DERR_INVALIDCALL); + user_assert(pBox->Right <= This->desc.Width, D3DERR_INVALIDCALL); + user_assert(pBox->Bottom <= This->desc.Height, D3DERR_INVALIDCALL); + user_assert(pBox->Back <= This->desc.Depth, D3DERR_INVALIDCALL); + + 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 (p_atomic_read(&This->pending_uploads_counter)) + nine_csmt_process(This->base.device); + + if (This->data_internal || This->data) { + enum pipe_format format = This->info.format; + unsigned stride = This->stride; + unsigned layer_stride = This->layer_stride; + uint8_t *data = This->data; + if (This->data_internal) { + format = This->format_internal; + stride = This->stride_internal; + layer_stride = This->layer_stride_internal; + data = This->data_internal; + } + pLockedVolume->RowPitch = stride; + pLockedVolume->SlicePitch = layer_stride; + pLockedVolume->pBits = data + + NineVolume9_GetSystemMemOffset(format, stride, + layer_stride, + box.x, box.y, box.z); + } else { + bool no_refs = !p_atomic_read(&This->base.bind) && + !p_atomic_read(&This->base.container->bind); + if (no_refs) + pipe = nine_context_get_pipe_acquire(This->base.device); + else + pipe = NineDevice9_GetPipe(This->base.device); + pLockedVolume->pBits = + pipe->texture_map(pipe, resource, This->level, usage, + &box, &This->transfer); + if (no_refs) + nine_context_get_pipe_release(This->base.device); + 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); + NineVolume9_AddDirtyRegion(This, &box); + } + + ++This->lock_count; + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineVolume9_UnlockBox( struct NineVolume9 *This ) +{ + struct pipe_context *pipe; + + DBG("This=%p lock_count=%u\n", This, This->lock_count); + user_assert(This->lock_count, D3DERR_INVALIDCALL); + if (This->transfer) { + pipe = nine_context_get_pipe_acquire(This->base.device); + pipe->texture_unmap(pipe, This->transfer); + This->transfer = NULL; + nine_context_get_pipe_release(This->base.device); + } + --This->lock_count; + + if (This->data_internal) { + struct pipe_box box; + + u_box_3d(0, 0, 0, This->desc.Width, This->desc.Height, This->desc.Depth, + &box); + + + if (This->data) { + (void) util_format_translate_3d(This->info.format, + This->data, This->stride, + This->layer_stride, + 0, 0, 0, + This->format_internal, + This->data_internal, + This->stride_internal, + This->layer_stride_internal, + 0, 0, 0, + This->desc.Width, This->desc.Height, + This->desc.Depth); + } else { + nine_context_box_upload(This->base.device, + &This->pending_uploads_counter, + (struct NineUnknown *)This, + This->resource, + This->level, + &box, + This->format_internal, + This->data_internal, + This->stride_internal, + This->layer_stride_internal, + &box); + } + } + + return D3D_OK; +} + +/* When this function is called, we have already checked + * The copy regions fit the volumes */ +void +NineVolume9_CopyMemToDefault( struct NineVolume9 *This, + struct NineVolume9 *From, + unsigned dstx, unsigned dsty, unsigned dstz, + struct pipe_box *pSrcBox ) +{ + struct pipe_resource *r_dst = This->resource; + struct pipe_box src_box; + struct pipe_box dst_box; + + DBG("This=%p From=%p dstx=%u dsty=%u dstz=%u pSrcBox=%p\n", + This, From, dstx, dsty, dstz, pSrcBox); + + assert(This->desc.Pool == D3DPOOL_DEFAULT && + From->desc.Pool == D3DPOOL_SYSTEMMEM); + + dst_box.x = dstx; + dst_box.y = dsty; + dst_box.z = dstz; + + if (pSrcBox) { + 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; + } + + dst_box.width = src_box.width; + dst_box.height = src_box.height; + dst_box.depth = src_box.depth; + + nine_context_box_upload(This->base.device, + &From->pending_uploads_counter, + (struct NineUnknown *)From, + r_dst, + This->level, + &dst_box, + From->info.format, + From->data, From->stride, + From->layer_stride, + &src_box); + + if (This->data_internal) + (void) util_format_translate_3d(This->format_internal, + This->data_internal, + This->stride_internal, + This->layer_stride_internal, + dstx, dsty, dstz, + From->info.format, + From->data, From->stride, + From->layer_stride, + src_box.x, src_box.y, + src_box.z, + src_box.width, + src_box.height, + src_box.depth); + + NineVolume9_MarkContainerDirty(This); + + return; +} + +HRESULT +NineVolume9_UploadSelf( struct NineVolume9 *This, + const struct pipe_box *damaged ) +{ + struct pipe_resource *res = This->resource; + struct pipe_box box; + + DBG("This=%p damaged=%p data=%p res=%p\n", This, damaged, + This->data, res); + + assert(This->desc.Pool == D3DPOOL_MANAGED); + assert(res); + + if (damaged) { + box = *damaged; + } else { + box.x = 0; + box.y = 0; + box.z = 0; + box.width = This->desc.Width; + box.height = This->desc.Height; + box.depth = This->desc.Depth; + } + + nine_context_box_upload(This->base.device, + &This->pending_uploads_counter, + (struct NineUnknown *)This, + res, + This->level, + &box, + res->format, + This->data, This->stride, + This->layer_stride, + &box); + + return D3D_OK; +} + + +IDirect3DVolume9Vtbl NineVolume9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineUnknown_GetDevice, /* actually part of Volume9 iface */ + (void *)NineUnknown_SetPrivateData, + (void *)NineUnknown_GetPrivateData, + (void *)NineUnknown_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); +} diff --git a/src/gallium/frontends/nine/volume9.h b/src/gallium/frontends/nine/volume9.h new file mode 100644 index 0000000..13deea3 --- /dev/null +++ b/src/gallium/frontends/nine/volume9.h @@ -0,0 +1,101 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#ifndef _NINE_VOLUME9_H_ +#define _NINE_VOLUME9_H_ + +#include "iunknown.h" + +#include "pipe/p_state.h" +#include "util/u_inlines.h" + +struct hash_table; + +struct NineDevice9; + +struct NineVolume9 +{ + struct NineUnknown base; + + struct pipe_resource *resource; + unsigned level; + unsigned level_actual; + + uint8_t *data; /* system memory backing */ + uint8_t *data_internal; /* for conversions */ + + D3DVOLUME_DESC desc; + struct pipe_resource info; + enum pipe_format format_internal; + unsigned stride; + unsigned stride_internal; + unsigned layer_stride; + unsigned layer_stride_internal; + + struct pipe_transfer *transfer; + unsigned lock_count; + + unsigned pending_uploads_counter; /* pending uploads */ +}; +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 ); + +void +NineVolume9_CopyMemToDefault( struct NineVolume9 *This, + struct NineVolume9 *From, + unsigned dstx, unsigned dsty, unsigned dstz, + struct pipe_box *pSrcBox ); + +HRESULT +NineVolume9_UploadSelf( struct NineVolume9 *This, + const struct pipe_box *damaged ); + + +/*** Direct3D public ***/ + +HRESULT NINE_WINAPI +NineVolume9_GetContainer( struct NineVolume9 *This, + REFIID riid, + void **ppContainer ); + +HRESULT NINE_WINAPI +NineVolume9_GetDesc( struct NineVolume9 *This, + D3DVOLUME_DESC *pDesc ); + +HRESULT NINE_WINAPI +NineVolume9_LockBox( struct NineVolume9 *This, + D3DLOCKED_BOX *pLockedVolume, + const D3DBOX *pBox, + DWORD Flags ); + +HRESULT NINE_WINAPI +NineVolume9_UnlockBox( struct NineVolume9 *This ); + +#endif /* _NINE_VOLUME9_H_ */ diff --git a/src/gallium/frontends/nine/volumetexture9.c b/src/gallium/frontends/nine/volumetexture9.c new file mode 100644 index 0000000..103bdac --- /dev/null +++ b/src/gallium/frontends/nine/volumetexture9.c @@ -0,0 +1,277 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#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; + struct pipe_screen *screen = pParams->device->screen; + enum pipe_format pf; + unsigned l; + D3DVOLUME_DESC voldesc; + HRESULT hr; + + DBG("This=%p pParams=%p Width=%u Height=%u Depth=%u Levels=%u " + "Usage=%d Format=%d Pool=%d pSharedHandle=%p\n", + This, pParams, Width, Height, Depth, Levels, + Usage, Format, Pool, pSharedHandle); + + user_assert(Width && Height && Depth, D3DERR_INVALIDCALL); + + /* user_assert(!pSharedHandle || Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL); */ + user_assert(!pSharedHandle, D3DERR_INVALIDCALL); /* TODO */ + + /* 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), D3DERR_INVALIDCALL); + + pf = d3d9_to_pipe_format_checked(screen, Format, PIPE_TEXTURE_3D, 0, + PIPE_BIND_SAMPLER_VIEW, false, + Pool == D3DPOOL_SCRATCH); + + if (pf == PIPE_FORMAT_NONE) + return D3DERR_INVALIDCALL; + + /* We support ATI1 and ATI2 hacks only for 2D and Cube textures */ + if (Format == D3DFMT_ATI1 || Format == D3DFMT_ATI2) + return D3DERR_INVALIDCALL; + + if (compressed_format(Format)) { + const unsigned w = util_format_get_blockwidth(pf); + const unsigned h = util_format_get_blockheight(pf); + /* Compressed formats are not compressed on depth component */ + user_assert(!(Width % w) && !(Height % h), D3DERR_INVALIDCALL); + } + + info->screen = pParams->device->screen; + info->target = PIPE_TEXTURE_3D; + info->format = pf; + 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->nr_storage_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; + } + if (Usage & D3DUSAGE_SOFTWAREPROCESSING) + DBG("Application asked for Software Vertex Processing, " + "but this is unimplemented\n"); + + This->base.pstype = 3; + + hr = NineBaseTexture9_ctor(&This->base, pParams, NULL, + D3DRTYPE_VOLUMETEXTURE, Format, Pool, Usage); + if (FAILED(hr)) + return hr; + + This->volumes = CALLOC(This->base.level_count, sizeof(*This->volumes)); + if (!This->volumes) + return E_OUTOFMEMORY; + + voldesc.Format = Format; + voldesc.Type = D3DRTYPE_VOLUME; + voldesc.Usage = Usage; + voldesc.Pool = Pool; + for (l = 0; l < This->base.level_count; ++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; + } + + /* Textures start initially dirty */ + NineVolumeTexture9_AddDirtyBox(This, NULL); + + 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.level_count; ++l) + if (This->volumes[l]) + NineUnknown_Destroy(&This->volumes[l]->base); + FREE(This->volumes); + } + + NineBaseTexture9_dtor(&This->base); +} + +HRESULT NINE_WINAPI +NineVolumeTexture9_GetLevelDesc( struct NineVolumeTexture9 *This, + UINT Level, + D3DVOLUME_DESC *pDesc ) +{ + user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL); + + *pDesc = This->volumes[Level]->desc; + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineVolumeTexture9_GetVolumeLevel( struct NineVolumeTexture9 *This, + UINT Level, + IDirect3DVolume9 **ppVolumeLevel ) +{ + user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL); + + NineUnknown_AddRef(NineUnknown(This->volumes[Level])); + *ppVolumeLevel = (IDirect3DVolume9 *)This->volumes[Level]; + + return D3D_OK; +} + +HRESULT NINE_WINAPI +NineVolumeTexture9_LockBox( struct NineVolumeTexture9 *This, + UINT Level, + D3DLOCKED_BOX *pLockedVolume, + const D3DBOX *pBox, + DWORD Flags ) +{ + DBG("This=%p Level=%u pLockedVolume=%p pBox=%p Flags=%d\n", + This, Level, pLockedVolume, pBox, Flags); + + user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL); + + return NineVolume9_LockBox(This->volumes[Level], pLockedVolume, pBox, + Flags); +} + +HRESULT NINE_WINAPI +NineVolumeTexture9_UnlockBox( struct NineVolumeTexture9 *This, + UINT Level ) +{ + DBG("This=%p Level=%u\n", This, Level); + + user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL); + + return NineVolume9_UnlockBox(This->volumes[Level]); +} + +HRESULT NINE_WINAPI +NineVolumeTexture9_AddDirtyBox( struct NineVolumeTexture9 *This, + const D3DBOX *pDirtyBox ) +{ + DBG("This=%p pDirtybox=%p\n", This, pDirtyBox); + + if (This->base.base.pool == D3DPOOL_DEFAULT) { + return D3D_OK; + } + + if (This->base.base.pool == D3DPOOL_MANAGED) { + This->base.managed.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 { + if (This->dirty_box.width == 0) { + d3dbox_to_pipe_box(&This->dirty_box, pDirtyBox); + } else { + struct pipe_box box; + d3dbox_to_pipe_box(&box, pDirtyBox); + u_box_union_3d(&This->dirty_box, &This->dirty_box, &box); + } + This->dirty_box.x = MAX2(This->dirty_box.x, 0); + This->dirty_box.y = MAX2(This->dirty_box.y, 0); + This->dirty_box.z = MAX2(This->dirty_box.z, 0); + This->dirty_box.width = MIN2(This->dirty_box.width, + This->base.base.info.width0 - This->dirty_box.x); + This->dirty_box.height = MIN2(This->dirty_box.height, + This->base.base.info.height0 - This->dirty_box.y); + This->dirty_box.depth = MIN2(This->dirty_box.depth, + This->base.base.info.depth0 - This->dirty_box.z); + } + return D3D_OK; +} + +IDirect3DVolumeTexture9Vtbl NineVolumeTexture9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */ + (void *)NineUnknown_SetPrivateData, + (void *)NineUnknown_GetPrivateData, + (void *)NineUnknown_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/frontends/nine/volumetexture9.h b/src/gallium/frontends/nine/volumetexture9.h new file mode 100644 index 0000000..73c1f69 --- /dev/null +++ b/src/gallium/frontends/nine/volumetexture9.h @@ -0,0 +1,58 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#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 NINE_WINAPI +NineVolumeTexture9_GetLevelDesc( struct NineVolumeTexture9 *This, + UINT Level, + D3DVOLUME_DESC *pDesc ); + +HRESULT NINE_WINAPI +NineVolumeTexture9_GetVolumeLevel( struct NineVolumeTexture9 *This, + UINT Level, + IDirect3DVolume9 **ppVolumeLevel ); + +HRESULT NINE_WINAPI +NineVolumeTexture9_LockBox( struct NineVolumeTexture9 *This, + UINT Level, + D3DLOCKED_BOX *pLockedVolume, + const D3DBOX *pBox, + DWORD Flags ); + +HRESULT NINE_WINAPI +NineVolumeTexture9_UnlockBox( struct NineVolumeTexture9 *This, + UINT Level ); + +HRESULT NINE_WINAPI +NineVolumeTexture9_AddDirtyBox( struct NineVolumeTexture9 *This, + const D3DBOX *pDirtyBox ); + +#endif /* _NINE_VOLUMETEXTURE9_H_ */ diff --git a/src/gallium/meson.build b/src/gallium/meson.build index 67011f5..8de1190 100644 --- a/src/gallium/meson.build +++ b/src/gallium/meson.build @@ -235,6 +235,10 @@ endif if with_platform_haiku subdir('frontends/hgl') endif +if with_gallium_st_nine + subdir('frontends/nine') + subdir('targets/d3dadapter9') +endif if with_gallium_st_d3d10umd subdir('frontends/d3d10umd') subdir('targets/d3d10umd') diff --git a/src/gallium/targets/d3dadapter9/.editorconfig b/src/gallium/targets/d3dadapter9/.editorconfig new file mode 100644 index 0000000..7b12a40 --- /dev/null +++ b/src/gallium/targets/d3dadapter9/.editorconfig @@ -0,0 +1,3 @@ +[*.{c,h}] +indent_style = space +indent_size = 4 diff --git a/src/gallium/targets/d3dadapter9/d3dadapter9.sym b/src/gallium/targets/d3dadapter9/d3dadapter9.sym new file mode 100644 index 0000000..2290dae --- /dev/null +++ b/src/gallium/targets/d3dadapter9/d3dadapter9.sym @@ -0,0 +1,6 @@ +{ + global: + D3DAdapter9GetProc; + local: + *; +}; diff --git a/src/gallium/targets/d3dadapter9/description.c b/src/gallium/targets/d3dadapter9/description.c new file mode 100644 index 0000000..4e46a3d --- /dev/null +++ b/src/gallium/targets/d3dadapter9/description.c @@ -0,0 +1,367 @@ +/* + * Copyright 2015 Patrick Rudolph + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include "adapter9.h" + +#define DBG_CHANNEL DBG_ADAPTER + +/* prototypes */ +void +d3d_match_vendor_id( D3DADAPTER_IDENTIFIER9* drvid, + unsigned fallback_ven, + unsigned fallback_dev, + const char* fallback_name ); +void d3d_fill_driver_version(D3DADAPTER_IDENTIFIER9* drvid); +void d3d_fill_cardname(D3DADAPTER_IDENTIFIER9* drvid); + +enum d3d_vendor_id +{ + HW_VENDOR_SOFTWARE = 0x0000, + HW_VENDOR_AMD = 0x1002, + HW_VENDOR_NVIDIA = 0x10de, + HW_VENDOR_VMWARE = 0x15ad, + HW_VENDOR_INTEL = 0x8086, +}; + +struct card_lookup_table { + const char *mesaname; + const char *d3d9name; +} +cards_amd[] = { + {"HAWAII", "AMD Radeon R9 290"}, + {"KAVERI", "AMD Radeon(TM) R7 Graphics"}, + {"KABINI", "AMD Radeon HD 8400 / R3 Series"}, + {"BONAIRE", "AMD Radeon HD 8770"}, + {"OLAND", "AMD Radeon HD 8670"}, + {"HAINAN", "AMD Radeon HD 8600M Series"}, + {"TAHITI", "AMD Radeon HD 7900 Series"}, + {"PITCAIRN", "AMD Radeon HD 7800 Series"}, + {"CAPE VERDE", "AMD Radeon HD 7700 Series"}, + {"ARUBA", "AMD Radeon HD 7660D"}, + {"CAYMAN", "AMD Radeon HD 6900 Series"}, + {"BARTS", "AMD Radeon HD 6800 Series"}, + {"TURKS", "AMD Radeon HD 6600 Series"}, + {"SUMO2", "AMD Radeon HD 6410D"}, + {"SUMO", "AMD Radeon HD 6550D"}, + {"CAICOS", "AMD Radeon HD 6400 Series"}, + {"PALM", "AMD Radeon HD 6300 series Graphics"}, + {"HEMLOCK", "ATI Radeon HD 5900 Series"}, + {"CYPRESS", "ATI Radeon HD 5800 Series"}, + {"JUNIPER", "ATI Radeon HD 5700 Series"}, + {"REDWOOD", "ATI Radeon HD 5600 Series"}, + {"CEDAR", "ATI Radeon HD 5500 Series"}, + {"R700", "ATI Radeon HD 4800 Series"}, + {"RV790", "ATI Radeon HD 4800 Series"}, + {"RV770", "ATI Radeon HD 4800 Series"}, + {"RV740", "ATI Radeon HD 4700 Series"}, + {"RV730", "ATI Radeon HD 4600 Series"}, + {"RV710", "ATI Radeon HD 4350"}, + {"RS880", "ATI Mobility Radeon HD 4200"}, + {"RS780", "ATI Radeon HD 3200 Graphics"}, + {"R680", "ATI Radeon HD 2900 XT"}, + {"R600", "ATI Radeon HD 2900 XT"}, + {"RV670", "ATI Radeon HD 2900 XT"}, + {"RV635", "ATI Mobility Radeon HD 2600"}, + {"RV630", "ATI Mobility Radeon HD 2600"}, + {"RV620", "ATI Mobility Radeon HD 2350"}, + {"RV610", "ATI Mobility Radeon HD 2350"}, + {"R580", "ATI Radeon X1600 Series"}, + {"R520", "ATI Radeon X1600 Series"}, + {"RV570", "ATI Radeon X1600 Series"}, + {"RV560", "ATI Radeon X1600 Series"}, + {"RV535", "ATI Radeon X1600 Series"}, + {"RV530", "ATI Radeon X1600 Series"}, + {"RV516", "ATI Radeon X700 SE"}, + {"RV515", "ATI Radeon X700 SE"}, + {"R481", "ATI Radeon X700 SE"}, + {"R480", "ATI Radeon X700 SE"}, + {"R430", "ATI Radeon X700 SE"}, + {"R423", "ATI Radeon X700 SE"}, + {"R420", "ATI Radeon X700 SE"}, + {"R410", "ATI Radeon X700 SE"}, + {"RV410", "ATI Radeon X700 SE"}, + {"RS740", "ATI RADEON XPRESS 200M Series"}, + {"RS690", "ATI RADEON XPRESS 200M Series"}, + {"RS600", "ATI RADEON XPRESS 200M Series"}, + {"RS485", "ATI RADEON XPRESS 200M Series"}, + {"RS482", "ATI RADEON XPRESS 200M Series"}, + {"RS480", "ATI RADEON XPRESS 200M Series"}, + {"RS400", "ATI RADEON XPRESS 200M Series"}, + {"R360", "ATI Radeon 9500"}, + {"R350", "ATI Radeon 9500"}, + {"R300", "ATI Radeon 9500"}, + {"RV370", "ATI Radeon 9500"}, + {"RV360", "ATI Radeon 9500"}, + {"RV351", "ATI Radeon 9500"}, + {"RV350", "ATI Radeon 9500"}, +}, +cards_nvidia[] = +{ + {"NV124", "NVIDIA GeForce GTX 970"}, + {"NV117", "NVIDIA GeForce GTX 750"}, + {"NVF1", "NVIDIA GeForce GTX 780 Ti"}, + {"NVF0", "NVIDIA GeForce GTX 780"}, + {"NVE6", "NVIDIA GeForce GTX 770M"}, + {"NVE4", "NVIDIA GeForce GTX 680"}, + {"NVD9", "NVIDIA GeForce GT 520"}, + {"NVCF", "NVIDIA GeForce GTX 550 Ti"}, + {"NVCE", "NVIDIA GeForce GTX 560"}, + {"NVC8", "NVIDIA GeForce GTX 570"}, + {"NVC4", "NVIDIA GeForce GTX 460"}, + {"NVC3", "NVIDIA GeForce GT 440"}, + {"NVC1", "NVIDIA GeForce GT 420"}, + {"NVC0", "NVIDIA GeForce GTX 480"}, + {"NVAF", "NVIDIA GeForce GT 320M"}, + {"NVAC", "NVIDIA GeForce 8200"}, + {"NVAA", "NVIDIA GeForce 8200"}, + {"NVA8", "NVIDIA GeForce 210"}, + {"NVA5", "NVIDIA GeForce GT 220"}, + {"NVA3", "NVIDIA GeForce GT 240"}, + {"NVA0", "NVIDIA GeForce GTX 280"}, + {"NV98", "NVIDIA GeForce 9200"}, + {"NV96", "NVIDIA GeForce 9400 GT"}, + {"NV94", "NVIDIA GeForce 9600 GT"}, + {"NV92", "NVIDIA GeForce 9800 GT"}, + {"NV86", "NVIDIA GeForce 8500 GT"}, + {"NV84", "NVIDIA GeForce 8600 GT"}, + {"NV50", "NVIDIA GeForce 8800 GTX"}, + {"NV68", "NVIDIA GeForce 6200"}, + {"NV67", "NVIDIA GeForce 6200"}, + {"NV63", "NVIDIA GeForce 6200"}, + {"NV4E", "NVIDIA GeForce 6200"}, + {"NV4C", "NVIDIA GeForce 6200"}, + {"NV4B", "NVIDIA GeForce 7600 GT"}, + {"NV4A", "NVIDIA GeForce 6200"}, + {"NV49", "NVIDIA GeForce 7800 GT"}, + {"NV47", "NVIDIA GeForce 7800 GT"}, + {"NV46", "NVIDIA GeForce Go 7400",}, + {"NV45", "NVIDIA GeForce 6800"}, + {"NV44", "NVIDIA GeForce 6200"}, + {"NV43", "NVIDIA GeForce 6600 GT"}, + {"NV42", "NVIDIA GeForce 6800"}, + {"NV41", "NVIDIA GeForce 6800"}, + {"NV40", "NVIDIA GeForce 6800"}, + {"NV38", "NVIDIA GeForce FX 5800"}, + {"NV36", "NVIDIA GeForce FX 5800"}, + {"NV35", "NVIDIA GeForce FX 5800"}, + {"NV34", "NVIDIA GeForce FX 5200"}, + {"NV31", "NVIDIA GeForce FX 5600"}, + {"NV30", "NVIDIA GeForce FX 5800"}, + {"nv28", "NVIDIA GeForce4 Ti 4200"}, + {"nv25", "NVIDIA GeForce4 Ti 4200"}, + {"nv20", "NVIDIA GeForce3"}, + {"nv1F", "NVIDIA GeForce4 MX 460"}, + {"nv1A", "NVIDIA GeForce2 GTS/GeForce2 Pro"}, + {"nv18", "NVIDIA GeForce4 MX 460"}, + {"nv17", "NVIDIA GeForce4 MX 460"}, + {"nv16", "NVIDIA GeForce2 GTS/GeForce2 Pro"}, + {"nv15", "NVIDIA GeForce2 GTS/GeForce2 Pro"}, + {"nv11", "NVIDIA GeForce2 MX/MX 400"}, + {"nv10", "NVIDIA GeForce 256"}, +}, +cards_vmware[] = +{ + {"SVGA3D", "VMware SVGA 3D (Microsoft Corporation - WDDM)"}, +}, +cards_intel[] = +{ + {"Haswell Mobile", "Intel(R) Haswell Mobile"}, + {"Ivybridge Server", "Intel(R) Ivybridge Server"}, + {"Ivybridge Mobile", "Intel(R) Ivybridge Mobile"}, + {"Ivybridge Desktop", "Intel(R) Ivybridge Desktop"}, + {"Sandybridge Server", "Intel(R) Sandybridge Server"}, + {"Sandybridge Mobile", "Intel(R) Sandybridge Mobile"}, + {"Sandybridge Desktop", "Intel(R) Sandybridge Desktop"}, + {"Ironlake Mobile", "Intel(R) Ironlake Mobile"}, + {"Ironlake Desktop", "Intel(R) Ironlake Desktop"}, + {"B43", "Intel(R) B43"}, + {"G41", "Intel(R) G41"}, + {"G45", "Intel(R) G45/G43"}, + {"Q45", "Intel(R) Q45/Q43"}, + {"Integrated Graphics Device", "Intel(R) Integrated Graphics Device"}, + {"GM45", "Mobile Intel(R) GM45 Express Chipset Family"}, + {"965GME", "Intel(R) 965GME"}, + {"965GM", "Mobile Intel(R) 965 Express Chipset Family"}, + {"946GZ", "Intel(R) 946GZ"}, + {"965G", "Intel(R) 965G"}, + {"965Q", "Intel(R) 965Q"}, + {"Pineview M", "Intel(R) IGD"}, + {"Pineview G", "Intel(R) IGD"}, + {"IGD", "Intel(R) IGD"}, + {"Q33", "Intel(R) Q33"}, + {"G33", "Intel(R) G33"}, + {"Q35", "Intel(R) Q35"}, + {"945GME", "Intel(R) 945GME"}, + {"945GM", "Mobile Intel(R) 945GM Express Chipset Family"}, + {"945G", "Intel(R) 945G"}, + {"915GM", "Mobile Intel(R) 915GM/GMS,910GML Express Chipset Family"}, + {"E7221G", "Intel(R) E7221G"}, + {"915G", "Intel(R) 82915G/GV/910GL Express Chipset Family"}, + {"865G", "Intel(R) 82865G Graphics Controller"}, + {"845G", "Intel(R) 845G"}, + {"855GM", "Intel(R) 82852/82855 GM/GME Graphics Controller"}, + {"830M", "Intel(R) 82830M Graphics Controller"}, +}; + +/* override VendorId, DeviceId and Description for unknown vendors */ +void +d3d_match_vendor_id( D3DADAPTER_IDENTIFIER9* drvid, + unsigned fallback_ven, + unsigned fallback_dev, + const char* fallback_name ) +{ + if (drvid->VendorId == HW_VENDOR_INTEL || + drvid->VendorId == HW_VENDOR_VMWARE || + drvid->VendorId == HW_VENDOR_AMD || + drvid->VendorId == HW_VENDOR_NVIDIA) + return; + + DBG("unknown vendor 0x4%x, emulating 0x4%x\n", drvid->VendorId, fallback_ven); + drvid->VendorId = fallback_ven; + drvid->DeviceId = fallback_dev; + snprintf(drvid->Description, sizeof(drvid->Description), "%s", fallback_name); +} + +/* fill in driver name and version */ +void d3d_fill_driver_version(D3DADAPTER_IDENTIFIER9* drvid) { + switch (drvid->VendorId) { + case HW_VENDOR_INTEL: + drvid->DriverVersionLowPart = 0x000A0682; + drvid->DriverVersionHighPart = 0x0006000F; + strncpy(drvid->Driver, "igdumd32.dll", sizeof(drvid->Driver)); + break; + case HW_VENDOR_VMWARE: + drvid->DriverVersionLowPart = 0x0001046E; + drvid->DriverVersionHighPart = 0x0006000E; + strncpy(drvid->Driver, "vm3dum.dll", sizeof(drvid->Driver)); + break; + case HW_VENDOR_AMD: + drvid->DriverVersionLowPart = 0x000A0500; + drvid->DriverVersionHighPart = 0x00060011; + strncpy(drvid->Driver, "atiumdag.dll", sizeof(drvid->Driver)); + break; + case HW_VENDOR_NVIDIA: + drvid->DriverVersionLowPart = 0x000D0FD4; + drvid->DriverVersionHighPart = 0x00060012; + strncpy(drvid->Driver, "nvd3dum.dll", sizeof(drvid->Driver)); + break; + default: + break; + } +} + +/* Gallium sürücüleri (crocus, iris, i915) ekran adı olarak Intel'in pazarlama + * ismini bildiriyor -- crocus IVB GT2 için "Mesa Intel(R) HD Graphics 4000". + * Yukarıdaki cards_intel[] tablosu ise kod adlarıyla ("Ivybridge Mobile") + * eşleştirme yapıyor, dolayısıyla strstr araması bu donanımda hiç tutmuyor ve + * her şey cards_intel[0] fallback'ine ("Intel(R) Haswell Mobile") düşüyor. + * crocus'un 97 PCI ID'sinden 84'ü bu durumda. + * + * PCI device id'si kesin bir ayraç, üstelik masaüstü/mobil/sunucu varyantını da + * ayırt ediyor -- pazarlama ismi ayırt edemiyor (0x0162 masaüstü ile 0x0166 + * mobil, ikisi de "HD Graphics 4000"). + * + * Kapsam: Ironlake, Sandybridge ve Ivybridge. Bu üç kuşakta Intel'in id şeması + * belirsizliğe yer bırakmıyor (..2 masaüstü, ..6 mobil, ..a sunucu) ve + * cards_intel[] üçü için de uygun d3d9 ismi içeriyor. Haswell ve sonrası + * (byt/chv dahil) tabloda karşılığı olmadığı için eski fallback'te kalıyor. + * Kaynak: include/pci_ids/crocus_pci_ids.h */ +static const struct { + unsigned deviceid; + const char *d3d9name; +} cards_intel_pciid[] = { + /* Ironlake */ + {0x0042, "Intel(R) Ironlake Desktop"}, + {0x0046, "Intel(R) Ironlake Mobile"}, + /* Sandybridge GT1 */ + {0x0102, "Intel(R) Sandybridge Desktop"}, + {0x0106, "Intel(R) Sandybridge Mobile"}, + {0x010a, "Intel(R) Sandybridge Server"}, + /* Sandybridge GT2 */ + {0x0112, "Intel(R) Sandybridge Desktop"}, + {0x0122, "Intel(R) Sandybridge Desktop"}, + {0x0116, "Intel(R) Sandybridge Mobile"}, + {0x0126, "Intel(R) Sandybridge Mobile"}, + /* Ivybridge GT1 */ + {0x0152, "Intel(R) Ivybridge Desktop"}, + {0x0156, "Intel(R) Ivybridge Mobile"}, + {0x015a, "Intel(R) Ivybridge Server"}, + /* Ivybridge GT2 */ + {0x0162, "Intel(R) Ivybridge Desktop"}, + {0x0166, "Intel(R) Ivybridge Mobile"}, + {0x016a, "Intel(R) Ivybridge Server"}, +}; + +/* try to match the device name and override it with Windows like device names */ +void d3d_fill_cardname(D3DADAPTER_IDENTIFIER9* drvid) { + unsigned i; + switch (drvid->VendorId) { + case HW_VENDOR_INTEL: + /* PCI id'siyle kesin eslesme once denenir; tutmazsa asagidaki + * kod adi aramasina dusulur (eski suruculer icin). */ + for (i = 0; i < sizeof(cards_intel_pciid) / sizeof(cards_intel_pciid[0]); i++) { + if (drvid->DeviceId == cards_intel_pciid[i].deviceid) { + snprintf(drvid->Description, sizeof(drvid->Description), + "%s", cards_intel_pciid[i].d3d9name); + return; + } + } + for (i = 0; i < sizeof(cards_intel) / sizeof(cards_intel[0]); i++) { + if (strstr(drvid->Description, cards_intel[i].mesaname)) { + snprintf(drvid->Description, sizeof(drvid->Description), + "%s", cards_intel[i].d3d9name); + return; + } + } + /* use a fall-back if nothing matches */ + DBG("Unknown card name %s!\n", drvid->DeviceName); + snprintf(drvid->Description, sizeof(drvid->Description), + "%s", cards_intel[0].d3d9name); + break; + case HW_VENDOR_VMWARE: + for (i = 0; i < sizeof(cards_vmware) / sizeof(cards_vmware[0]); i++) { + if (strstr(drvid->Description, cards_vmware[i].mesaname)) { + snprintf(drvid->Description, sizeof(drvid->Description), + "%s", cards_vmware[i].d3d9name); + return; + } + } + /* use a fall-back if nothing matches */ + DBG("Unknown card name %s!\n", drvid->DeviceName); + snprintf(drvid->Description, sizeof(drvid->Description), + "%s", cards_vmware[0].d3d9name); + break; + case HW_VENDOR_AMD: + for (i = 0; i < sizeof(cards_amd) / sizeof(cards_amd[0]); i++) { + if (strstr(drvid->Description, cards_amd[i].mesaname)) { + snprintf(drvid->Description, sizeof(drvid->Description), + "%s", cards_amd[i].d3d9name); + return; + } + } + /* use a fall-back if nothing matches */ + DBG("Unknown card name %s!\n", drvid->DeviceName); + snprintf(drvid->Description, sizeof(drvid->Description), + "%s", cards_amd[0].d3d9name); + break; + case HW_VENDOR_NVIDIA: + for (i = 0; i < sizeof(cards_nvidia) / sizeof(cards_nvidia[0]); i++) { + if (strstr(drvid->Description, cards_nvidia[i].mesaname)) { + snprintf(drvid->Description, sizeof(drvid->Description), + "%s", cards_nvidia[i].d3d9name); + return; + } + } + /* use a fall-back if nothing matches */ + DBG("Unknown card name %s!\n", drvid->DeviceName); + snprintf(drvid->Description, sizeof(drvid->Description), + "%s", cards_nvidia[0].d3d9name); + break; + default: + break; + } +} diff --git a/src/gallium/targets/d3dadapter9/drm.c b/src/gallium/targets/d3dadapter9/drm.c new file mode 100644 index 0000000..9b6f5a2 --- /dev/null +++ b/src/gallium/targets/d3dadapter9/drm.c @@ -0,0 +1,318 @@ +/* + * Copyright 2011 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +/* XXX: header order is slightly screwy here */ +#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/drm_helper.h" +#include "target-helpers/sw_helper.h" +#include "frontend/drm_driver.h" + +#include "d3dadapter/d3dadapter9.h" +#include "d3dadapter/drm.h" + +#include "util/xmlconfig.h" +#include "util/driconf.h" + +#include "drm-uapi/drm.h" +#include +#include +#include + +#define DBG_CHANNEL DBG_ADAPTER + +/* On non-x86 archs, Box86 has issues with thread_submit. */ +#if DETECT_ARCH_X86 || DETECT_ARCH_X86_64 +#define DEFAULT_THREADSUBMIT true +#else +#define DEFAULT_THREADSUBMIT false +#endif + +const driOptionDescription __driConfigOptionsNine[] = { + DRI_CONF_SECTION_PERFORMANCE + DRI_CONF_VBLANK_MODE(DRI_CONF_VBLANK_DEF_INTERVAL_1) + DRI_CONF_SECTION_END + DRI_CONF_SECTION_NINE + DRI_CONF_NINE_OVERRIDEVENDOR(-1) + DRI_CONF_NINE_THROTTLE(-2) + DRI_CONF_NINE_THREADSUBMIT(DEFAULT_THREADSUBMIT) + DRI_CONF_NINE_ALLOWDISCARDDELAYEDRELEASE(true) + DRI_CONF_NINE_TEARFREEDISCARD(true) + DRI_CONF_NINE_CSMT(-1) + DRI_CONF_NINE_DYNAMICTEXTUREWORKAROUND(true) + DRI_CONF_NINE_SHADERINLINECONSTANTS(false) + DRI_CONF_NINE_SHMEM_LIMIT() + DRI_CONF_NINE_FORCESWRENDERINGONCPU(false) + DRI_CONF_NINE_FORCEFEATURESEMULATION(false) + DRI_CONF_SECTION_END + DRI_CONF_SECTION_DEBUG + DRI_CONF_OVERRIDE_VRAM_SIZE() + DRI_CONF_SECTION_END +}; + +struct fallback_card_config { + const char *name; + unsigned vendor_id; + unsigned device_id; +} fallback_cards[] = { + {"NV124", 0x10de, 0x13C2}, /* NVIDIA GeForce GTX 970 */ + {"HAWAII", 0x1002, 0x67b1}, /* AMD Radeon R9 290 */ + {"Haswell Mobile", 0x8086, 0x13C2}, /* Intel Haswell Mobile */ + {"SVGA3D", 0x15ad, 0x0405}, /* VMware SVGA 3D */ +}; + +/* prototypes */ +void +d3d_match_vendor_id( D3DADAPTER_IDENTIFIER9* drvid, + unsigned fallback_ven, + unsigned fallback_dev, + const char* fallback_name ); + +void d3d_fill_driver_version(D3DADAPTER_IDENTIFIER9* drvid); + +void d3d_fill_cardname(D3DADAPTER_IDENTIFIER9* drvid); + +struct d3dadapter9drm_context +{ + struct d3dadapter9_context base; + struct pipe_loader_device *dev, *swdev; + int fd; +}; + +static void +drm_destroy( struct d3dadapter9_context *ctx ) +{ + struct d3dadapter9drm_context *drm = (struct d3dadapter9drm_context *)ctx; + + if (ctx->ref && ctx->hal != ctx->ref) + ctx->ref->destroy(ctx->ref); + /* because ref is a wrapper around hal, freeing ref frees hal too. */ + else if (ctx->hal) + ctx->hal->destroy(ctx->hal); + + if (drm->swdev && drm->swdev != drm->dev) + pipe_loader_release(&drm->swdev, 1); + if (drm->dev) + pipe_loader_release(&drm->dev, 1); + + close(drm->fd); + FREE(ctx); +} + +static inline void +get_bus_info( int fd, + DWORD *vendorid, + DWORD *deviceid, + DWORD *subsysid, + DWORD *revision ) +{ + int vid, did; + + if (loader_get_pci_id_for_fd(fd, &vid, &did)) { + DBG("PCI info: vendor=0x%04x, device=0x%04x\n", + vid, did); + *vendorid = vid; + *deviceid = did; + *subsysid = 0; + *revision = 0; + } else { + DBG("Unable to detect card. Faking %s\n", fallback_cards[0].name); + *vendorid = fallback_cards[0].vendor_id; + *deviceid = fallback_cards[0].device_id; + *subsysid = 0; + *revision = 0; + } +} + +static inline void +read_descriptor( struct d3dadapter9_context *ctx, + int fd, int override_vendorid ) +{ + unsigned i; + BOOL found; + D3DADAPTER_IDENTIFIER9 *drvid = &ctx->identifier; + + memset(drvid, 0, sizeof(*drvid)); + get_bus_info(fd, &drvid->VendorId, &drvid->DeviceId, + &drvid->SubSysId, &drvid->Revision); + snprintf(drvid->DeviceName, sizeof(drvid->DeviceName), + "Gallium 0.4 with %s", ctx->hal->get_vendor(ctx->hal)); + snprintf(drvid->Description, sizeof(drvid->Description), + "%s", ctx->hal->get_name(ctx->hal)); + + if (override_vendorid > 0) { + found = false; + /* fill in device_id and card name for fake vendor */ + for (i = 0; i < sizeof(fallback_cards)/sizeof(fallback_cards[0]); i++) { + if (fallback_cards[i].vendor_id == override_vendorid) { + DBG("Faking card '%s' vendor 0x%04x, device 0x%04x\n", + fallback_cards[i].name, + fallback_cards[i].vendor_id, + fallback_cards[i].device_id); + drvid->VendorId = fallback_cards[i].vendor_id; + drvid->DeviceId = fallback_cards[i].device_id; + snprintf(drvid->Description, sizeof(drvid->Description), + "%s", fallback_cards[i].name); + found = true; + break; + } + } + if (!found) { + DBG("Unknown fake vendor 0x%04x! Using detected vendor !\n", override_vendorid); + } + } + /* choose fall-back vendor if necessary to allow + * the following functions to return sane results */ + d3d_match_vendor_id(drvid, fallback_cards[0].vendor_id, fallback_cards[0].device_id, fallback_cards[0].name); + /* fill in driver name and version info */ + d3d_fill_driver_version(drvid); + /* override Description field with Windows like names */ + d3d_fill_cardname(drvid); + + /* this driver isn't WHQL certified */ + drvid->WHQLLevel = 0; + + /* this value is fixed */ + 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; +} + +static HRESULT WINAPI +drm_create_adapter( int fd, + ID3DAdapter9 **ppAdapter ) +{ + struct d3dadapter9drm_context *ctx = CALLOC_STRUCT(d3dadapter9drm_context); + HRESULT hr; + bool different_device; + driOptionCache defaultInitOptions; + driOptionCache userInitOptions; + int throttling_value_user = -2; + int override_vendorid = -1; + bool sw_rendering; + + if (!ctx) { return E_OUTOFMEMORY; } + + ctx->base.destroy = drm_destroy; + + /* Although the fd is provided from external source, mesa/nine + * takes ownership of it. */ + different_device = loader_get_user_preferred_fd(&fd, NULL); + ctx->fd = fd; + ctx->base.linear_framebuffer = different_device; + + 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; + } + + ctx->base.hal = pipe_loader_create_screen(ctx->dev, false); + if (!ctx->base.hal) { + ERR("Unable to load requested driver.\n"); + drm_destroy(&ctx->base); + return D3DERR_DRIVERINTERNALERROR; + } + + if (!ctx->base.hal->caps.dmabuf) { + ERR("The driver is not capable of dma-buf sharing." + "Abandon to load nine state tracker\n"); + drm_destroy(&ctx->base); + return D3DERR_DRIVERINTERNALERROR; + } + + /* Previously was set to pipe_caps.max_frames_in_flight, + * but the change of value of this cap to 1 seems to cause + * regressions. */ + ctx->base.throttling_value = 2; + ctx->base.throttling = ctx->base.throttling_value > 0; + + driParseOptionInfo(&defaultInitOptions, __driConfigOptionsNine, + ARRAY_SIZE(__driConfigOptionsNine)); + /* Mesa 26.x: driParseConfigFiles()'in 8 secici argumani + * driConfigFileParseParams struct'ina paketlendi. Verilmeyen alanlar + * designated initializer ile sifirlaniyor (eskiden NULL/0 geciliyordu). */ + const driConfigFileParseParams parse_params = { + .screenNum = 0, + .driverName = "nine", + }; + driParseConfigFiles(&userInitOptions, &defaultInitOptions, &parse_params); + if (driCheckOption(&userInitOptions, "throttle_value", DRI_INT)) { + throttling_value_user = driQueryOptioni(&userInitOptions, "throttle_value"); + if (throttling_value_user == -1) + ctx->base.throttling = false; + else if (throttling_value_user >= 0) { + ctx->base.throttling = true; + ctx->base.throttling_value = throttling_value_user; + } + } + + ctx->base.vblank_mode = driQueryOptioni(&userInitOptions, "vblank_mode"); + ctx->base.thread_submit = driQueryOptionb(&userInitOptions, "thread_submit"); /* TODO: default to TRUE if different_device */ + override_vendorid = driQueryOptioni(&userInitOptions, "override_vendorid"); + + ctx->base.discard_delayed_release = driQueryOptionb(&userInitOptions, "discard_delayed_release"); + ctx->base.tearfree_discard = driQueryOptionb(&userInitOptions, "tearfree_discard"); + + if (ctx->base.tearfree_discard && !ctx->base.discard_delayed_release) { + ERR("tearfree_discard requires discard_delayed_release\n"); + ctx->base.tearfree_discard = false; + } + + ctx->base.csmt_force = driQueryOptioni(&userInitOptions, "csmt_force"); + ctx->base.dynamic_texture_workaround = driQueryOptionb(&userInitOptions, "dynamic_texture_workaround"); + ctx->base.shader_inline_constants = driQueryOptionb(&userInitOptions, "shader_inline_constants"); + ctx->base.memfd_virtualsizelimit = driQueryOptioni(&userInitOptions, "texture_memory_limit"); + ctx->base.override_vram_size = driQueryOptioni(&userInitOptions, "override_vram_size"); + ctx->base.force_emulation = driQueryOptionb(&userInitOptions, "force_features_emulation"); + sw_rendering = driQueryOptionb(&userInitOptions, "force_sw_rendering_on_cpu"); + + driDestroyOptionCache(&userInitOptions); + driDestroyOptionInfo(&defaultInitOptions); + + sw_rendering |= debug_get_bool_option("D3D_ALWAYS_SOFTWARE", false); + /* wrap it to create a software screen that can share resources */ + if (sw_rendering && pipe_loader_sw_probe_wrapped(&ctx->swdev, ctx->base.hal)) + ctx->base.ref = pipe_loader_create_screen(ctx->swdev, false); + else { + /* Use the hardware for sw rendering */ + ctx->swdev = ctx->dev; + ctx->base.ref = ctx->base.hal; + } + + /* read out PCI info */ + read_descriptor(&ctx->base, fd, override_vendorid); + + /* 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 index 0000000..10e21a8 --- /dev/null +++ b/src/gallium/targets/d3dadapter9/getproc.c @@ -0,0 +1,30 @@ +/* + * Copyright 2013 Joakim Sindholt + * SPDX-License-Identifier: MIT + */ + +#include + +#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 < ARRAY_SIZE(drivers); ++i) { + if (strcmp(name, drivers[i].name) == 0) { + return drivers[i].desc; + } + } + return NULL; +} diff --git a/src/gallium/targets/d3dadapter9/meson.build b/src/gallium/targets/d3dadapter9/meson.build new file mode 100644 index 0000000..cdfbe3e --- /dev/null +++ b/src/gallium/targets/d3dadapter9/meson.build @@ -0,0 +1,72 @@ +# Copyright © 2017 Dylan Baker +# Copyright © 2018 Intel Corporation +# SPDX-License-Identifier: MIT + +# TODO: support non-static targets + +nine_version = ['1', '0', '0'] + +gallium_nine_c_args = [] +gallium_nine_ld_args = [] +gallium_nine_link_depends = [] +gallium_nine_link_with = [ + libgallium, libnine_st, + libpipe_loader_static, libws_null, libwsw, libswdri, + libswkmsdri, libgalliumvl_stub, +] + +if with_ld_version_script + gallium_nine_ld_args += ['-Wl,--version-script', join_paths(meson.current_source_dir(), 'd3dadapter9.sym')] + gallium_nine_link_depends += files('d3dadapter9.sym') +endif + +libgallium_nine = shared_library( + 'd3dadapter9', + files('description.c', 'getproc.c', 'drm.c'), + include_directories : [ + inc_include, inc_src, inc_loader, inc_mesa, inc_util, + inc_gallium, inc_gallium_aux, inc_gallium_winsys, + inc_gallium_drivers, inc_d3d9, + include_directories('../../frontends/nine'), + ], + c_args : [gallium_nine_c_args], + gnu_symbol_visibility : 'hidden', + link_args : [ld_args_build_id, ld_args_gc_sections, gallium_nine_ld_args], + link_depends : gallium_nine_link_depends, + link_with : gallium_nine_link_with, + dependencies : [ + dep_libdrm, dep_llvm, dep_thread, + idep_xmlconfig, idep_mesautil, idep_nir, + driver_asahi, + driver_v3d, + driver_crocus, + driver_etnaviv, + driver_freedreno, + driver_kmsro, + driver_lima, + driver_nouveau, + driver_panfrost, + driver_r300, + driver_r600, + driver_radeonsi, + driver_svga, + driver_swrast, + driver_i915, + driver_iris, + driver_v3d, + driver_vc4, + driver_zink + ], + name_prefix : '', + version : '.'.join(nine_version), + install : true, + install_dir : d3d_drivers_path, +) + +pkg.generate( + name : 'd3d', + description : 'Native D3D driver modules', + version : '.'.join(nine_version), + requires_private : 'libdrm >= ' + dep_libdrm.version(), + variables : ['moduledir=@0@'.format(d3d_drivers_path)], +) diff --git a/src/util/driconf.h b/src/util/driconf.h index b114915..d76f09d 100644 --- a/src/util/driconf.h +++ b/src/util/driconf.h @@ -524,6 +524,56 @@ #define DRI_CONF_DRI_DRIVER() \ DRI_CONF_OPT_S_NODEF(dri_driver, "Override the DRI driver to load") +/** + * \brief Gallium-Nine specific configuration options + */ + +#define DRI_CONF_SECTION_NINE DRI_CONF_SECTION("Gallium Nine") + +#define DRI_CONF_NINE_THROTTLE(def) \ + DRI_CONF_OPT_I(throttle_value, def, 0, 0, \ + "Define the throttling value. -1 for no throttling, -2 for default (usually 2), 0 for glfinish behaviour") + +#define DRI_CONF_NINE_THREADSUBMIT(def) \ + DRI_CONF_OPT_B(thread_submit, def, \ + "Use an additional thread to submit buffers.") + +#define DRI_CONF_NINE_OVERRIDEVENDOR(def) \ + DRI_CONF_OPT_I(override_vendorid, def, 0, 0, \ + "Define the vendor_id to report. This allows faking another hardware vendor.") + +#define DRI_CONF_NINE_ALLOWDISCARDDELAYEDRELEASE(def) \ + DRI_CONF_OPT_B(discard_delayed_release, def, \ + "Whether to allow the display server to release buffers with a delay when using d3d's presentation mode DISCARD. Default to true. Set to false if suffering from lag (thread_submit=true can also help in this situation).") + +#define DRI_CONF_NINE_TEARFREEDISCARD(def) \ + DRI_CONF_OPT_B(tearfree_discard, def, \ + "Whether to make d3d's presentation mode DISCARD (games usually use that mode) Tear Free. If rendering above screen refresh, some frames will get skipped. true by default.") + +#define DRI_CONF_NINE_CSMT(def) \ + DRI_CONF_OPT_I(csmt_force, def, 0, 0, \ + "If set to 1, force gallium nine CSMT. If set to 0, disable it. By default (-1) CSMT is enabled on known thread-safe drivers.") + +#define DRI_CONF_NINE_DYNAMICTEXTUREWORKAROUND(def) \ + DRI_CONF_OPT_B(dynamic_texture_workaround, def, \ + "If set to true, use a ram intermediate buffer for dynamic textures. Increases ram usage, which can cause out of memory issues, but can fix glitches for some games.") + +#define DRI_CONF_NINE_SHADERINLINECONSTANTS(def) \ + DRI_CONF_OPT_B(shader_inline_constants, def, \ + "If set to true, recompile shaders with integer or boolean constants when the values are known. Can cause stutter, but can increase slightly performance.") + +#define DRI_CONF_NINE_SHMEM_LIMIT() \ + DRI_CONF_OPT_I(texture_memory_limit, 128, 0, 0, \ + "In MB the limit of virtual memory used for textures until shmem files are unmapped (default 128MB, 32bits only). If negative disables shmem. Set to a low amount to reduce virtual memory usage, but can incur a small perf hit if too low.") + +#define DRI_CONF_NINE_FORCESWRENDERINGONCPU(def) \ + DRI_CONF_OPT_B(force_sw_rendering_on_cpu, def, \ + "If set to false, emulates software rendering on the requested device, else uses a software renderer.") + +#define DRI_CONF_NINE_FORCEFEATURESEMULATION(def) \ + DRI_CONF_OPT_B(force_features_emulation, def, \ + "If set to true, force emulation of d3d9 features when possible instead of using native hw support.") + #define DRI_CONF_V3D_NONMSAA_TEXTURE_SIZE_LIMIT(def) \ DRI_CONF_OPT_B(v3d_nonmsaa_texture_size_limit, def, \ "Report the non-MSAA-only texture size limit")