1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-02-21 04:54:15 +01:00

[d3d8] Alignment and formatting improvements

This commit is contained in:
WinterSnowfall 2025-01-09 11:59:59 +02:00 committed by Philip Rebohle
parent 639f815432
commit 4151d35e8e
24 changed files with 120 additions and 94 deletions

View File

@ -16,7 +16,9 @@ namespace dxvk {
// Vertex buffer that can handle many tiny locks while
// still maintaing the lock ordering of direct-mapped buffers.
class D3D8BatchBuffer final : public D3D8VertexBuffer {
public:
D3D8BatchBuffer(
D3D8Device* pDevice,
D3DPOOL Pool,
@ -67,11 +69,13 @@ namespace dxvk {
}
private:
std::vector<BYTE> m_data;
DWORD m_fvf;
};
// Main handler for batching D3D8 draw calls.
class D3D8Batcher {
@ -86,6 +90,7 @@ namespace dxvk {
};
public:
D3D8Batcher(D3D8Device* pDevice8, Com<d3d9::IDirect3DDevice9>&& pDevice9)
: m_device8(pDevice8)
, m_device(std::move(pDevice9)) {
@ -115,10 +120,10 @@ namespace dxvk {
d3d9::D3DFMT_INDEX16,
m_stream->GetPtr(draw.MinVertex * m_stride),
m_stride);
m_device->SetStreamSource(0, D3D8VertexBuffer::GetD3D9Nullable(m_stream), 0, m_stride);
m_device->SetIndices(D3D8IndexBuffer::GetD3D9Nullable(m_indices));
draw.PrimitiveType = D3DPRIMITIVETYPE(0);
draw.Offset = 0;
draw.MinVertex = UINT_MAX;
@ -231,6 +236,7 @@ namespace dxvk {
}
private:
D3D8Device* m_device8;
Com<d3d9::IDirect3DDevice9> m_device;
@ -239,5 +245,7 @@ namespace dxvk {
D3D8IndexBuffer* m_indices = nullptr;
INT m_baseVertexIndex = 0;
std::array<Batch, D3DPT_COUNT> m_batches;
};
}

View File

@ -103,7 +103,7 @@ namespace dxvk {
// In fullscreen, D3DPRESENT_INTERVAL_IMMEDIATE is meaningless.
if (pParams->Windowed || (PresentationInterval & D3DPRESENT_INTERVAL_IMMEDIATE) != 0) {
PresentationInterval = D3DPRESENT_INTERVAL_ONE;
// TODO: what does dx8 do if multiple D3DPRESENT_INTERVAL flags are set?
// TODO: what does dx8 do if multiple D3DPRESENT_INTERVAL flags are set?
}
}
@ -172,5 +172,5 @@ namespace dxvk {
default: return d3d9::D3DSAMPLERSTATETYPE(-1u);
}
}
}
}

View File

@ -32,12 +32,12 @@ namespace dxvk {
};
D3D8Device::D3D8Device(
D3D8Interface* pParent,
Com<d3d9::IDirect3DDevice9>&& pDevice,
D3DDEVTYPE DeviceType,
HWND hFocusWindow,
DWORD BehaviorFlags,
D3DPRESENT_PARAMETERS* pParams)
D3D8Interface* pParent,
Com<d3d9::IDirect3DDevice9>&& pDevice,
D3DDEVTYPE DeviceType,
HWND hFocusWindow,
DWORD BehaviorFlags,
D3DPRESENT_PARAMETERS* pParams)
: D3D8DeviceBase(std::move(pDevice))
, m_d3d8Options(pParent->GetOptions())
, m_parent(pParent)
@ -55,7 +55,7 @@ namespace dxvk {
ResetState();
RecreateBackBuffersAndAutoDepthStencil();
if (m_d3d8Options.batching)
m_batcher = new D3D8Batcher(this, GetD3D9());
}
@ -73,7 +73,7 @@ namespace dxvk {
HRESULT res;
Com<d3d9::IDirect3DQuery9> pQuery;
switch (DevInfoID) {
// pre-D3D8 queries
case 0:
@ -81,7 +81,7 @@ namespace dxvk {
case D3DDEVINFOID_D3DTEXTUREMANAGER:
case D3DDEVINFOID_TEXTURING:
return E_FAIL;
case D3DDEVINFOID_VCACHE:
// The query will return D3D_OK on Nvidia and D3DERR_NOTAVAILABLE on AMD/Intel
// in D3D9, however in the case of the latter we'll need to return a
@ -148,7 +148,7 @@ namespace dxvk {
return GetD3D9()->GetAvailableTextureMem();
}
HRESULT STDMETHODCALLTYPE D3D8Device::ResourceManagerDiscardBytes(DWORD bytes) {
HRESULT STDMETHODCALLTYPE D3D8Device::ResourceManagerDiscardBytes(DWORD bytes) {
return GetD3D9()->EvictManagedResources();
}
@ -165,7 +165,7 @@ namespace dxvk {
HRESULT res = GetD3D9()->GetDeviceCaps(&caps9);
if (likely(SUCCEEDED(res)))
dxvk::ConvertCaps8(caps9, pCaps);
ConvertCaps8(caps9, pCaps);
return res;
}
@ -207,7 +207,7 @@ namespace dxvk {
if (unlikely(pPresentationParameters == nullptr || ppSwapChain == nullptr))
return D3DERR_INVALIDCALL;
Com<d3d9::IDirect3DSwapChain9> pSwapChain9;
d3d9::D3DPRESENT_PARAMETERS params = ConvertPresentParameters9(pPresentationParameters);
HRESULT res = GetD3D9()->CreateAdditionalSwapChain(
@ -429,7 +429,7 @@ namespace dxvk {
if (likely(SUCCEEDED(res)))
*ppVertexBuffer = ref(new D3D8VertexBuffer(this, std::move(pVertexBuffer9), Pool, Usage));
return res;
}
@ -446,10 +446,10 @@ namespace dxvk {
Com<d3d9::IDirect3DIndexBuffer9> pIndexBuffer9 = nullptr;
HRESULT res = GetD3D9()->CreateIndexBuffer(Length, Usage, d3d9::D3DFORMAT(Format), d3d9::D3DPOOL(Pool), &pIndexBuffer9, NULL);
if (likely(SUCCEEDED(res)))
*ppIndexBuffer = ref(new D3D8IndexBuffer(this, std::move(pIndexBuffer9), Pool, Usage));
return res;
}
@ -570,7 +570,7 @@ namespace dxvk {
res = src->LockRect(&srcLocked, &srcRect, D3DLOCK_READONLY);
if (FAILED(res))
return res;
res = dst->LockRect(&dstLocked, &dstRect, 0);
if (FAILED(res)) {
src->UnlockRect();
@ -1012,7 +1012,7 @@ namespace dxvk {
}
HRESULT STDMETHODCALLTYPE D3D8Device::BeginScene() { return GetD3D9()->BeginScene(); }
HRESULT STDMETHODCALLTYPE D3D8Device::EndScene() { StateChange(); return GetD3D9()->EndScene(); }
HRESULT STDMETHODCALLTYPE D3D8Device::Clear(
@ -1115,7 +1115,7 @@ namespace dxvk {
HRESULT STDMETHODCALLTYPE D3D8Device::GetClipPlane(DWORD Index, float* pPlane) {
return GetD3D9()->GetClipPlane(Index, pPlane);
}
HRESULT STDMETHODCALLTYPE D3D8Device::CreateStateBlock(
D3DSTATEBLOCKTYPE Type,
DWORD* pToken) {
@ -1404,7 +1404,7 @@ namespace dxvk {
m_streams[0] = D3D8VBO {nullptr, 0};
m_indices = nullptr;
m_baseVertexIndex = 0;
return GetD3D9()->DrawIndexedPrimitiveUP(
d3d9::D3DPRIMITIVETYPE(PrimitiveType),
MinVertexIndex,
@ -1490,12 +1490,12 @@ namespace dxvk {
if (unlikely(StreamNumber >= d8caps::MAX_STREAMS))
return D3DERR_INVALIDCALL;
const D3D8VBO& vbo = m_streams[StreamNumber];
*ppStreamData = vbo.buffer.ref();
*pStride = vbo.stride;
return D3D_OK;
}
@ -1719,7 +1719,7 @@ namespace dxvk {
info.function.push_back(pFunction[i]);
info.function.push_back(D3DVS_END());
}
D3D9VertexShaderCode result = TranslateVertexShader8(pDeclaration, pFunction, m_d3d8Options);
// Create vertex declaration
@ -1821,7 +1821,7 @@ namespace dxvk {
/*
// Slow path. Use to debug cached shader validation. //
d3d9::IDirect3DVertexShader9* pVertexShader;
HRESULT res = GetD3D9()->GetVertexShader(&pVertexShader);
@ -1873,12 +1873,12 @@ namespace dxvk {
if (unlikely(!pInfo))
return D3DERR_INVALIDCALL;
UINT SizeOfData = *pSizeOfData;
// Get actual size
UINT ActualSize = pInfo->declaration.size() * sizeof(DWORD);
if (pData == nullptr) {
*pSizeOfData = ActualSize;
return D3D_OK;
@ -1903,12 +1903,12 @@ namespace dxvk {
if (unlikely(!pInfo))
return D3DERR_INVALIDCALL;
UINT SizeOfData = *pSizeOfData;
// Get actual size
UINT ActualSize = pInfo->function.size() * sizeof(DWORD);
if (pData == nullptr) {
*pSizeOfData = ActualSize;
return D3D_OK;
@ -1946,7 +1946,7 @@ namespace dxvk {
}
d3d9::IDirect3DPixelShader9* pPixelShader;
HRESULT res = GetD3D9()->CreatePixelShader(pFunction, &pPixelShader);
if (likely(SUCCEEDED(res))) {
@ -1959,7 +1959,7 @@ namespace dxvk {
}
inline d3d9::IDirect3DPixelShader9* getPixelShaderPtr(D3D8Device* device, DWORD Handle) {
Handle = getShaderIndex(Handle);
if (unlikely(Handle >= device->m_pixelShaders.size())) {
@ -2045,11 +2045,11 @@ namespace dxvk {
return D3DERR_INVALIDCALL;
UINT SizeOfData = *pSizeOfData;
// Get actual size
UINT ActualSize = 0;
pPixelShader->GetFunction(nullptr, &ActualSize);
if (pData == nullptr) {
*pSizeOfData = ActualSize;
return D3D_OK;

View File

@ -27,18 +27,19 @@ namespace dxvk {
class D3D8Device final : public D3D8DeviceBase {
friend class D3D8StateBlock;
public:
D3D8Device(
D3D8Interface* pParent,
Com<d3d9::IDirect3DDevice9>&& pDevice,
D3DDEVTYPE DeviceType,
HWND hFocusWindow,
DWORD BehaviorFlags,
D3DPRESENT_PARAMETERS* pParams);
D3D8Interface* pParent,
Com<d3d9::IDirect3DDevice9>&& pDevice,
D3DDEVTYPE DeviceType,
HWND hFocusWindow,
DWORD BehaviorFlags,
D3DPRESENT_PARAMETERS* pParams);
~D3D8Device();
HRESULT STDMETHODCALLTYPE TestCooperativeLevel();
UINT STDMETHODCALLTYPE GetAvailableTextureMem();
@ -206,7 +207,7 @@ namespace dxvk {
HRESULT STDMETHODCALLTYPE SetRenderState(D3DRENDERSTATETYPE State, DWORD Value);
HRESULT STDMETHODCALLTYPE GetRenderState(D3DRENDERSTATETYPE State, DWORD* pValue);
HRESULT STDMETHODCALLTYPE CreateStateBlock(
D3DSTATEBLOCKTYPE Type,
DWORD* pToken);
@ -306,7 +307,7 @@ namespace dxvk {
HRESULT STDMETHODCALLTYPE GetVertexShaderConstant(DWORD Register, void* pConstantData, DWORD ConstantCount);
HRESULT STDMETHODCALLTYPE GetVertexShaderDeclaration(DWORD Handle, void* pData, DWORD* pSizeOfData);
HRESULT STDMETHODCALLTYPE GetVertexShaderFunction(DWORD Handle, void* pData, DWORD* pSizeOfData);
HRESULT STDMETHODCALLTYPE SetStreamSource(
@ -326,7 +327,7 @@ namespace dxvk {
UINT* pBaseVertexIndex);
HRESULT STDMETHODCALLTYPE CreatePixelShader(
const DWORD* pFunction,
const DWORD* pFunction,
DWORD* pHandle);
HRESULT STDMETHODCALLTYPE SetPixelShader(DWORD Handle);
@ -356,8 +357,6 @@ namespace dxvk {
HRESULT STDMETHODCALLTYPE DeletePatch(UINT Handle);
public: // Internal Methods //
const D3D8Options* GetOptions() const {
return &m_d3d8Options;
}
@ -394,7 +393,7 @@ namespace dxvk {
m_backBuffers.clear();
m_backBuffers.resize(m_presentParams.BackBufferCount);
m_autoDepthStencil = nullptr;
}
@ -437,7 +436,7 @@ namespace dxvk {
Com<D3D8VertexBuffer, false> buffer = nullptr;
UINT stride = 0;
};
// Remember to fill() these in the constructor!
std::array<Com<D3D8Texture2D, false>, d8caps::MAX_TEXTURE_STAGES> m_textures;
std::array<D3D8VBO, d8caps::MAX_STREAMS> m_streams;

View File

@ -29,7 +29,7 @@ namespace dxvk {
return refCount + 1;
}
ULONG STDMETHODCALLTYPE Release() {
// ignore Release calls on objects with 0 refCount
if(unlikely(!this->m_refCount))

View File

@ -3,6 +3,7 @@
#include "d3d8_include.h"
namespace dxvk {
constexpr bool isDXT(D3DFORMAT fmt) {
return fmt == D3DFMT_DXT1
|| fmt == D3DFMT_DXT2
@ -208,7 +209,6 @@ namespace dxvk {
return size;
}
constexpr UINT getSurfaceSize(D3DFORMAT Format, UINT Width, UINT Height) {
if (isDXT(Format)) {
Width = ((Width + 3) >> 2);

View File

@ -86,7 +86,7 @@ namespace d3d9 {
/**
* \brief Direct3D 9
*
*
* All D3D9 interfaces are included within
* a namespace, so as not to collide with
* D3D8 interfaces.

View File

@ -5,8 +5,8 @@
#include <cstring>
namespace dxvk
{
namespace dxvk {
D3D8Interface::D3D8Interface() {
m_d3d9 = d3d9::Direct3DCreate9(D3D_SDK_VERSION);
@ -89,7 +89,7 @@ namespace dxvk
pIdentifier->WHQLLevel = identifier9.WHQLLevel;
}
return res;
}

View File

@ -138,7 +138,7 @@ namespace dxvk {
HRESULT res = m_d3d9->GetDeviceCaps(Adapter, (d3d9::D3DDEVTYPE)DeviceType, &caps9);
if (likely(SUCCEEDED(res)))
dxvk::ConvertCaps8(caps9, pCaps);
ConvertCaps8(caps9, pCaps);
return res;
}

View File

@ -1,6 +1,7 @@
#include "d3d8_interface.h"
namespace dxvk {
Logger Logger::s_instance("d3d8.log");
HRESULT CreateD3D8(IDirect3D8** ppDirect3D8) {
@ -10,6 +11,7 @@ namespace dxvk {
*ppDirect3D8 = ref(new D3D8Interface());
return D3D_OK;
}
}
extern "C" {

View File

@ -1,4 +1,5 @@
#include "d3d8_options.h"
#include "../d3d9/d3d9_bridge.h"
#include "../util/config/config.h"
#include "../util/util_string.h"
@ -6,6 +7,7 @@
#include <charconv>
namespace dxvk {
static inline uint32_t parseDword(std::string_view str) {
uint32_t value = UINT32_MAX;
std::from_chars(str.data(), str.data() + str.size(), value);
@ -50,6 +52,6 @@ namespace dxvk {
forceVsDecl.emplace_back(D3DVSDE_REGISTER(reg), D3DVSDT_TYPE(type));
}
}
}

View File

@ -5,11 +5,12 @@
#include "../util/config/config.h"
namespace dxvk {
struct D3D8Options {
/// Some games rely on undefined behavior by using undeclared vertex shader inputs.
/// The simplest way to fix them is to simply modify their vertex shader decl.
///
///
/// This option takes a comma-separated list of colon-separated number pairs, where
/// the first number is a D3DVSDE_REGISTER value, the second is a D3DVSDT_TYPE value.
/// e.g. "0:2,3:2,7:1" for float3 position : v0, float3 normal : v3, float2 uv : v7
@ -42,6 +43,7 @@ namespace dxvk {
bool forceLegacyDiscard = false;
D3D8Options() {}
D3D8Options(const Config& config) {
auto forceVsDeclStr = config.getOption<std::string>("d3d8.forceVsDecl", "");
batching = config.getOption<bool> ("d3d8.batching", batching);
@ -53,4 +55,5 @@ namespace dxvk {
void parseVsDecl(const std::string& decl);
};
}

View File

@ -1,10 +1,10 @@
#pragma once
#pragma once
/** Implements IDirect3DResource8
*
*
* - SetPrivateData, GetPrivateData, FreePrivateData
* - SetPriority, GetPriority
*
*
* - Subclasses provide: PreLoad, GetType
*/
@ -12,7 +12,7 @@
#include "../util/com/com_private_data.h"
namespace dxvk {
template <typename D3D9, typename D3D8>
class D3D8Resource : public D3D8DeviceChild<D3D9, D3D8> {
@ -93,7 +93,7 @@ namespace dxvk {
} catch (HRESULT err) {
if (riid == __uuidof(IDirect3DResource8))
return this;
throw err;
}
@ -107,5 +107,4 @@ namespace dxvk {
};
}

View File

@ -333,4 +333,5 @@ namespace dxvk {
return result;
}
}

View File

@ -3,14 +3,14 @@
namespace dxvk {
D3D8StateBlock::D3D8StateBlock(
D3D8Device* pDevice,
D3DSTATEBLOCKTYPE Type,
Com<d3d9::IDirect3DStateBlock9>&& pStateBlock)
: m_device(pDevice)
, m_stateBlock(std::move(pStateBlock))
, m_type(Type)
, m_isSWVP(pDevice->GetD3D9()->GetSoftwareVertexProcessing()) {
D3D8StateBlock::D3D8StateBlock(
D3D8Device* pDevice,
D3DSTATEBLOCKTYPE Type,
Com<d3d9::IDirect3DStateBlock9>&& pStateBlock)
: m_device(pDevice)
, m_stateBlock(std::move(pStateBlock))
, m_type(Type)
, m_isSWVP(pDevice->GetD3D9()->GetSoftwareVertexProcessing()) {
if (Type == D3DSBT_VERTEXSTATE || Type == D3DSBT_ALL) {
// Lights, D3DTSS_TEXCOORDINDEX and D3DTSS_TEXTURETRANSFORMFLAGS,
// vertex shader, VS constants, and various render states.

View File

@ -56,6 +56,7 @@ namespace dxvk {
protected:
IDirect3DBaseTexture8* m_container;
};
}

View File

@ -55,7 +55,7 @@ namespace dxvk {
HRESULT STDMETHODCALLTYPE D3D8Surface::ReleaseDC(HDC hDC) {
return GetD3D9()->ReleaseDC(hDC);
}
// TODO: Consider creating only one texture to
// encompass all surface levels of a texture.
Com<d3d9::IDirect3DSurface9> D3D8Surface::GetBlitImage() {
@ -78,11 +78,11 @@ namespace dxvk {
d3d9::D3DMULTISAMPLE_NONE, 0,
FALSE,
&image,
NULL);
NULL);
if (FAILED(res))
throw new DxvkError("D3D8: Failed to create blit image");
return image;
}

View File

@ -4,7 +4,7 @@
#include "d3d8_surface.h"
namespace dxvk {
using D3D8SwapChainBase = D3D8DeviceChild<d3d9::IDirect3DSwapChain9, IDirect3DSwapChain8>;
class D3D8SwapChain final : public D3D8SwapChainBase {

View File

@ -38,7 +38,7 @@ namespace dxvk {
} catch (HRESULT err) {
if (riid == __uuidof(IDirect3DBaseTexture8))
return this;
throw err;
}
@ -68,7 +68,7 @@ namespace dxvk {
if (unlikely(Index >= m_subresources.size()))
return D3DERR_INVALIDCALL;
if (m_subresources[Index] == nullptr) {
try {
Com<SubresourceType9> subresource = LookupSubresource(Index);
@ -90,7 +90,7 @@ namespace dxvk {
Com<SubresourceType9> ptr = nullptr;
HRESULT res = D3DERR_INVALIDCALL;
if constexpr (std::is_same_v<D3D8, IDirect3DTexture8>) {
res = this->GetD3D9()->GetSurfaceLevel(Index, &ptr);
res = this->GetD3D9()->GetSurfaceLevel(Index, &ptr);
} else if constexpr (std::is_same_v<D3D8, IDirect3DVolumeTexture8>) {
res = this->GetD3D9()->GetVolumeLevel(Index, &ptr);
} else if constexpr (std::is_same_v<D3D8, IDirect3DCubeTexture8>) {

View File

@ -8,7 +8,7 @@ namespace dxvk {
D3D8Device* pDevice,
IDirect3DVolumeTexture8* pTexture,
Com<d3d9::IDirect3DVolume9>&& pVolume)
: D3D8VolumeBase(pDevice, std::move(pVolume), pTexture) {
: D3D8VolumeBase(pDevice, std::move(pVolume), pTexture) {
}
HRESULT STDMETHODCALLTYPE D3D8Volume::GetDesc(D3DVOLUME_DESC* pDesc) {

View File

@ -3,7 +3,7 @@
#include "d3d8_subresource.h"
namespace dxvk {
using D3D8VolumeBase = D3D8Subresource<d3d9::IDirect3DVolume9, IDirect3DVolume8>;
class D3D8Volume final : public D3D8VolumeBase {

View File

@ -38,7 +38,7 @@ namespace dxvk {
return this;
if (riid == __uuidof(D3D8))
return this;
throw E_NOINTERFACE;
}
@ -58,7 +58,6 @@ namespace dxvk {
}
}
private:
Com<D3D9> m_d3d9;

View File

@ -76,7 +76,7 @@ namespace dxvk {
if (dstTextureInfo->IsAutomaticMip())
m_device->MarkTextureMipsDirty(dstTextureInfo);
return D3D_OK;
}
@ -108,4 +108,5 @@ namespace dxvk {
const Config* DxvkD3D8InterfaceBridge::GetConfig() const {
return &m_interface->GetInstance()->config();
}
}

View File

@ -6,7 +6,7 @@
/**
* The D3D9 bridge allows D3D8 to access DXVK internals.
* For Vulkan interop without needing DXVK internals, see d3d9_interop.h.
*
*
* NOTE: You must include "d3d9_include.h" or "d3d8_include.h" before this header.
*/
@ -23,14 +23,14 @@ IDxvkD3D8Bridge : public IUnknown {
/**
* \brief Changes the API name displayed on the HUD
*
* \param [in] name The new API name
*
* \param [in] name The new API name
*/
virtual void SetAPIName(const char* name) = 0;
/**
* \brief Updates a D3D9 surface from a D3D9 buffer
*
*
* \param [in] pDestSurface Destination surface (typically in VRAM)
* \param [in] pSrcSurface Source surface (typically in system memory)
* \param [in] pSrcRect Source rectangle
@ -50,14 +50,14 @@ MIDL_INTERFACE("D3D9D3D8-A407-773E-18E9-CAFEBEEF3000")
IDxvkD3D8InterfaceBridge : public IUnknown {
/**
* \brief Enables or disables D3D9-specific features and validations
*
*
* \param [in] compatMode Compatibility state
*/
virtual void SetD3D8CompatibilityMode(const bool compatMode) = 0;
/**
* \brief Retrieves the DXVK configuration
*
*
* \returns The DXVK Config object
*/
virtual const dxvk::Config* GetConfig() const = 0;
@ -74,8 +74,11 @@ namespace dxvk {
class D3D9InterfaceEx;
class DxvkD3D8Bridge : public IDxvkD3D8Bridge {
public:
DxvkD3D8Bridge(D3D9DeviceEx* pDevice);
~DxvkD3D8Bridge();
ULONG STDMETHODCALLTYPE AddRef();
@ -93,12 +96,17 @@ namespace dxvk {
const POINT* pDestPoint);
private:
D3D9DeviceEx* m_device;
};
class DxvkD3D8InterfaceBridge : public IDxvkD3D8InterfaceBridge {
public:
DxvkD3D8InterfaceBridge(D3D9InterfaceEx* pObject);
~DxvkD3D8InterfaceBridge();
ULONG STDMETHODCALLTYPE AddRef();
@ -112,6 +120,9 @@ namespace dxvk {
const Config* GetConfig() const;
protected:
D3D9InterfaceEx* m_interface;
};
}