diff --git a/src/d3d8/d3d8_caps.h b/src/d3d8/d3d8_caps.h index 0da600c78..5511ed3f0 100644 --- a/src/d3d8/d3d8_caps.h +++ b/src/d3d8/d3d8_caps.h @@ -1,8 +1,8 @@ -#pragma once - -namespace dxvk::d8caps { - - inline constexpr uint32_t MAX_TEXTURE_STAGES = 8; - inline constexpr uint32_t MAX_STREAMS = 16; - +#pragma once + +namespace dxvk::d8caps { + + inline constexpr uint32_t MAX_TEXTURE_STAGES = 8; + inline constexpr uint32_t MAX_STREAMS = 16; + } \ No newline at end of file diff --git a/src/d3d8/d3d8_d3d9_util.h b/src/d3d8/d3d8_d3d9_util.h index 96a83c10b..ad488d4c8 100644 --- a/src/d3d8/d3d8_d3d9_util.h +++ b/src/d3d8/d3d8_d3d9_util.h @@ -1,176 +1,176 @@ -#pragma once - -// Utility functions for converting -// between DirectX8 and DirectX9 types. - -#include "d3d8_include.h" -#include "d3d8_format.h" -#include "d3d8_options.h" - -#include - -namespace dxvk { - - // (8<-9) D3DCAPSX: Writes to D3DCAPS8 from D3DCAPS9 - inline void ConvertCaps8(const d3d9::D3DCAPS9& caps9, D3DCAPS8* pCaps8) { - - // should be aligned - std::memcpy(pCaps8, &caps9, sizeof(D3DCAPS8)); - - // Max supported shader model is PS 1.4 and VS 1.1 - pCaps8->VertexShaderVersion = D3DVS_VERSION(1, 1); - pCaps8->PixelShaderVersion = D3DPS_VERSION(1, 4); - - // This was removed by D3D9. We can probably render windowed. - pCaps8->Caps2 |= D3DCAPS2_CANRENDERWINDOWED; - - // Replaced by D3DPRASTERCAPS_DEPTHBIAS in D3D9 - pCaps8->RasterCaps |= D3DPRASTERCAPS_ZBIAS; - - - // Remove D3D9-specific caps: - pCaps8->Caps2 &= ~D3DCAPS2_CANAUTOGENMIPMAP; - - pCaps8->Caps3 &= ~D3DCAPS3_LINEAR_TO_SRGB_PRESENTATION - & ~D3DCAPS3_COPY_TO_VIDMEM - & ~D3DCAPS3_COPY_TO_SYSTEMMEM; - - pCaps8->PrimitiveMiscCaps &= ~D3DPMISCCAPS_INDEPENDENTWRITEMASKS - & ~D3DPMISCCAPS_PERSTAGECONSTANT - & ~D3DPMISCCAPS_FOGANDSPECULARALPHA - & ~D3DPMISCCAPS_SEPARATEALPHABLEND - & ~D3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS - & ~D3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING - & ~D3DPMISCCAPS_FOGVERTEXCLAMPED - & ~D3DPMISCCAPS_POSTBLENDSRGBCONVERT; - - pCaps8->RasterCaps &= ~D3DPRASTERCAPS_SCISSORTEST - & ~D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS - & ~D3DPRASTERCAPS_DEPTHBIAS - & ~D3DPRASTERCAPS_MULTISAMPLE_TOGGLE; - - pCaps8->SrcBlendCaps &= ~D3DPBLENDCAPS_BLENDFACTOR; - - pCaps8->DestBlendCaps &= ~D3DPBLENDCAPS_BLENDFACTOR; - - pCaps8->LineCaps &= ~D3DLINECAPS_ANTIALIAS; - - pCaps8->StencilCaps &= ~D3DSTENCILCAPS_TWOSIDED; - - pCaps8->VertexProcessingCaps &= ~D3DVTXPCAPS_TEXGEN_SPHEREMAP; - } - - // (9<-8) D3DD3DPRESENT_PARAMETERS: Returns D3D9's params given an input for D3D8 - inline d3d9::D3DPRESENT_PARAMETERS ConvertPresentParameters9(D3DPRESENT_PARAMETERS* pParams) { - // A 0 back buffer count needs to be corrected and made visible to the D3D8 application as well - pParams->BackBufferCount = std::max(pParams->BackBufferCount, 1u); - - if (pParams->BackBufferFormat == D3DFMT_UNKNOWN) - pParams->BackBufferFormat = D3DFMT_X8R8G8B8; - - d3d9::D3DPRESENT_PARAMETERS params; - params.BackBufferWidth = pParams->BackBufferWidth; - params.BackBufferHeight = pParams->BackBufferHeight; - params.BackBufferFormat = d3d9::D3DFORMAT(pParams->BackBufferFormat); - params.BackBufferCount = pParams->BackBufferCount; - - params.MultiSampleType = d3d9::D3DMULTISAMPLE_TYPE(pParams->MultiSampleType); - params.MultiSampleQuality = 0; // (D3D8: no MultiSampleQuality), TODO: get a value for this - - UINT PresentationInterval = pParams->FullScreen_PresentationInterval; - - if (pParams->Windowed) { - - if (unlikely(PresentationInterval != D3DPRESENT_INTERVAL_DEFAULT)) { - // TODO: what does dx8 do if windowed app sets FullScreen_PresentationInterval? - Logger::warn(str::format( - "D3D8: Application is windowed yet requested FullScreen_PresentationInterval ", PresentationInterval, - " (should be D3DPRESENT_INTERVAL_DEFAULT). This will be ignored.")); - } - - // D3D8: For windowed swap chain, the back buffer is copied to the window immediately. - PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; - } - - D3DSWAPEFFECT SwapEffect = pParams->SwapEffect; - - // D3DSWAPEFFECT_COPY_VSYNC has been removed - if (SwapEffect == D3DSWAPEFFECT_COPY_VSYNC) { - - SwapEffect = D3DSWAPEFFECT_COPY; - - // D3D8: In windowed mode, D3DSWAPEFFECT_COPY_VSYNC enables VSYNC. - // 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? - } - } - - params.SwapEffect = d3d9::D3DSWAPEFFECT(SwapEffect); - params.hDeviceWindow = pParams->hDeviceWindow; - params.Windowed = pParams->Windowed; - params.EnableAutoDepthStencil = pParams->EnableAutoDepthStencil; - params.AutoDepthStencilFormat = d3d9::D3DFORMAT(pParams->AutoDepthStencilFormat); - params.Flags = pParams->Flags; - - // D3DPRESENT_RATE_UNLIMITED is unsupported, use D3DPRESENT_RATE_DEFAULT (or 0) - if (unlikely(pParams->FullScreen_RefreshRateInHz == D3DPRESENT_RATE_UNLIMITED)) { - params.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; - } else { - params.FullScreen_RefreshRateInHz = pParams->FullScreen_RefreshRateInHz; - } - - // FullScreen_PresentationInterval -> PresentationInterval - params.PresentationInterval = PresentationInterval; - - return params; - } - - // (8<-9) Convert D3DSURFACE_DESC - inline void ConvertSurfaceDesc8(const d3d9::D3DSURFACE_DESC* pSurf9, D3DSURFACE_DESC* pSurf8) { - pSurf8->Format = D3DFORMAT(pSurf9->Format); - pSurf8->Type = D3DRESOURCETYPE(pSurf9->Type); - pSurf8->Usage = pSurf9->Usage; - pSurf8->Pool = D3DPOOL(pSurf9->Pool); - pSurf8->Size = getSurfaceSize(pSurf8->Format, pSurf9->Width, pSurf9->Height); - - pSurf8->MultiSampleType = D3DMULTISAMPLE_TYPE(pSurf9->MultiSampleType); - // DX8: No multisample quality - pSurf8->Width = pSurf9->Width; - pSurf8->Height = pSurf9->Height; - } - - // (8<-9) Convert D3DVOLUME_DESC - inline void ConvertVolumeDesc8(const d3d9::D3DVOLUME_DESC* pVol9, D3DVOLUME_DESC* pVol8) { - pVol8->Format = D3DFORMAT(pVol9->Format); - pVol8->Type = D3DRESOURCETYPE(pVol9->Type); - pVol8->Usage = pVol9->Usage; - pVol8->Pool = D3DPOOL(pVol9->Pool); - pVol8->Size = getSurfaceSize(pVol8->Format, pVol9->Width, pVol9->Height) * pVol9->Depth; - pVol8->Width = pVol9->Width; - pVol8->Height = pVol9->Height; - pVol8->Depth = pVol9->Depth; - } - - // If this D3DTEXTURESTAGESTATETYPE has been remapped to a d3d9::D3DSAMPLERSTATETYPE - // it will be returned, otherwise returns -1u - inline d3d9::D3DSAMPLERSTATETYPE GetSamplerStateType9(const D3DTEXTURESTAGESTATETYPE StageType) { - switch (StageType) { - // 13-21: - case D3DTSS_ADDRESSU: return d3d9::D3DSAMP_ADDRESSU; - case D3DTSS_ADDRESSV: return d3d9::D3DSAMP_ADDRESSV; - case D3DTSS_BORDERCOLOR: return d3d9::D3DSAMP_BORDERCOLOR; - case D3DTSS_MAGFILTER: return d3d9::D3DSAMP_MAGFILTER; - case D3DTSS_MINFILTER: return d3d9::D3DSAMP_MINFILTER; - case D3DTSS_MIPFILTER: return d3d9::D3DSAMP_MIPFILTER; - case D3DTSS_MIPMAPLODBIAS: return d3d9::D3DSAMP_MIPMAPLODBIAS; - case D3DTSS_MAXMIPLEVEL: return d3d9::D3DSAMP_MAXMIPLEVEL; - case D3DTSS_MAXANISOTROPY: return d3d9::D3DSAMP_MAXANISOTROPY; - // 25: - case D3DTSS_ADDRESSW: return d3d9::D3DSAMP_ADDRESSW; - default: return d3d9::D3DSAMPLERSTATETYPE(-1u); - } - } -} - +#pragma once + +// Utility functions for converting +// between DirectX8 and DirectX9 types. + +#include "d3d8_include.h" +#include "d3d8_format.h" +#include "d3d8_options.h" + +#include + +namespace dxvk { + + // (8<-9) D3DCAPSX: Writes to D3DCAPS8 from D3DCAPS9 + inline void ConvertCaps8(const d3d9::D3DCAPS9& caps9, D3DCAPS8* pCaps8) { + + // should be aligned + std::memcpy(pCaps8, &caps9, sizeof(D3DCAPS8)); + + // Max supported shader model is PS 1.4 and VS 1.1 + pCaps8->VertexShaderVersion = D3DVS_VERSION(1, 1); + pCaps8->PixelShaderVersion = D3DPS_VERSION(1, 4); + + // This was removed by D3D9. We can probably render windowed. + pCaps8->Caps2 |= D3DCAPS2_CANRENDERWINDOWED; + + // Replaced by D3DPRASTERCAPS_DEPTHBIAS in D3D9 + pCaps8->RasterCaps |= D3DPRASTERCAPS_ZBIAS; + + + // Remove D3D9-specific caps: + pCaps8->Caps2 &= ~D3DCAPS2_CANAUTOGENMIPMAP; + + pCaps8->Caps3 &= ~D3DCAPS3_LINEAR_TO_SRGB_PRESENTATION + & ~D3DCAPS3_COPY_TO_VIDMEM + & ~D3DCAPS3_COPY_TO_SYSTEMMEM; + + pCaps8->PrimitiveMiscCaps &= ~D3DPMISCCAPS_INDEPENDENTWRITEMASKS + & ~D3DPMISCCAPS_PERSTAGECONSTANT + & ~D3DPMISCCAPS_FOGANDSPECULARALPHA + & ~D3DPMISCCAPS_SEPARATEALPHABLEND + & ~D3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS + & ~D3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING + & ~D3DPMISCCAPS_FOGVERTEXCLAMPED + & ~D3DPMISCCAPS_POSTBLENDSRGBCONVERT; + + pCaps8->RasterCaps &= ~D3DPRASTERCAPS_SCISSORTEST + & ~D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS + & ~D3DPRASTERCAPS_DEPTHBIAS + & ~D3DPRASTERCAPS_MULTISAMPLE_TOGGLE; + + pCaps8->SrcBlendCaps &= ~D3DPBLENDCAPS_BLENDFACTOR; + + pCaps8->DestBlendCaps &= ~D3DPBLENDCAPS_BLENDFACTOR; + + pCaps8->LineCaps &= ~D3DLINECAPS_ANTIALIAS; + + pCaps8->StencilCaps &= ~D3DSTENCILCAPS_TWOSIDED; + + pCaps8->VertexProcessingCaps &= ~D3DVTXPCAPS_TEXGEN_SPHEREMAP; + } + + // (9<-8) D3DD3DPRESENT_PARAMETERS: Returns D3D9's params given an input for D3D8 + inline d3d9::D3DPRESENT_PARAMETERS ConvertPresentParameters9(D3DPRESENT_PARAMETERS* pParams) { + // A 0 back buffer count needs to be corrected and made visible to the D3D8 application as well + pParams->BackBufferCount = std::max(pParams->BackBufferCount, 1u); + + if (pParams->BackBufferFormat == D3DFMT_UNKNOWN) + pParams->BackBufferFormat = D3DFMT_X8R8G8B8; + + d3d9::D3DPRESENT_PARAMETERS params; + params.BackBufferWidth = pParams->BackBufferWidth; + params.BackBufferHeight = pParams->BackBufferHeight; + params.BackBufferFormat = d3d9::D3DFORMAT(pParams->BackBufferFormat); + params.BackBufferCount = pParams->BackBufferCount; + + params.MultiSampleType = d3d9::D3DMULTISAMPLE_TYPE(pParams->MultiSampleType); + params.MultiSampleQuality = 0; // (D3D8: no MultiSampleQuality), TODO: get a value for this + + UINT PresentationInterval = pParams->FullScreen_PresentationInterval; + + if (pParams->Windowed) { + + if (unlikely(PresentationInterval != D3DPRESENT_INTERVAL_DEFAULT)) { + // TODO: what does dx8 do if windowed app sets FullScreen_PresentationInterval? + Logger::warn(str::format( + "D3D8: Application is windowed yet requested FullScreen_PresentationInterval ", PresentationInterval, + " (should be D3DPRESENT_INTERVAL_DEFAULT). This will be ignored.")); + } + + // D3D8: For windowed swap chain, the back buffer is copied to the window immediately. + PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + } + + D3DSWAPEFFECT SwapEffect = pParams->SwapEffect; + + // D3DSWAPEFFECT_COPY_VSYNC has been removed + if (SwapEffect == D3DSWAPEFFECT_COPY_VSYNC) { + + SwapEffect = D3DSWAPEFFECT_COPY; + + // D3D8: In windowed mode, D3DSWAPEFFECT_COPY_VSYNC enables VSYNC. + // 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? + } + } + + params.SwapEffect = d3d9::D3DSWAPEFFECT(SwapEffect); + params.hDeviceWindow = pParams->hDeviceWindow; + params.Windowed = pParams->Windowed; + params.EnableAutoDepthStencil = pParams->EnableAutoDepthStencil; + params.AutoDepthStencilFormat = d3d9::D3DFORMAT(pParams->AutoDepthStencilFormat); + params.Flags = pParams->Flags; + + // D3DPRESENT_RATE_UNLIMITED is unsupported, use D3DPRESENT_RATE_DEFAULT (or 0) + if (unlikely(pParams->FullScreen_RefreshRateInHz == D3DPRESENT_RATE_UNLIMITED)) { + params.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; + } else { + params.FullScreen_RefreshRateInHz = pParams->FullScreen_RefreshRateInHz; + } + + // FullScreen_PresentationInterval -> PresentationInterval + params.PresentationInterval = PresentationInterval; + + return params; + } + + // (8<-9) Convert D3DSURFACE_DESC + inline void ConvertSurfaceDesc8(const d3d9::D3DSURFACE_DESC* pSurf9, D3DSURFACE_DESC* pSurf8) { + pSurf8->Format = D3DFORMAT(pSurf9->Format); + pSurf8->Type = D3DRESOURCETYPE(pSurf9->Type); + pSurf8->Usage = pSurf9->Usage; + pSurf8->Pool = D3DPOOL(pSurf9->Pool); + pSurf8->Size = getSurfaceSize(pSurf8->Format, pSurf9->Width, pSurf9->Height); + + pSurf8->MultiSampleType = D3DMULTISAMPLE_TYPE(pSurf9->MultiSampleType); + // DX8: No multisample quality + pSurf8->Width = pSurf9->Width; + pSurf8->Height = pSurf9->Height; + } + + // (8<-9) Convert D3DVOLUME_DESC + inline void ConvertVolumeDesc8(const d3d9::D3DVOLUME_DESC* pVol9, D3DVOLUME_DESC* pVol8) { + pVol8->Format = D3DFORMAT(pVol9->Format); + pVol8->Type = D3DRESOURCETYPE(pVol9->Type); + pVol8->Usage = pVol9->Usage; + pVol8->Pool = D3DPOOL(pVol9->Pool); + pVol8->Size = getSurfaceSize(pVol8->Format, pVol9->Width, pVol9->Height) * pVol9->Depth; + pVol8->Width = pVol9->Width; + pVol8->Height = pVol9->Height; + pVol8->Depth = pVol9->Depth; + } + + // If this D3DTEXTURESTAGESTATETYPE has been remapped to a d3d9::D3DSAMPLERSTATETYPE + // it will be returned, otherwise returns -1u + inline d3d9::D3DSAMPLERSTATETYPE GetSamplerStateType9(const D3DTEXTURESTAGESTATETYPE StageType) { + switch (StageType) { + // 13-21: + case D3DTSS_ADDRESSU: return d3d9::D3DSAMP_ADDRESSU; + case D3DTSS_ADDRESSV: return d3d9::D3DSAMP_ADDRESSV; + case D3DTSS_BORDERCOLOR: return d3d9::D3DSAMP_BORDERCOLOR; + case D3DTSS_MAGFILTER: return d3d9::D3DSAMP_MAGFILTER; + case D3DTSS_MINFILTER: return d3d9::D3DSAMP_MINFILTER; + case D3DTSS_MIPFILTER: return d3d9::D3DSAMP_MIPFILTER; + case D3DTSS_MIPMAPLODBIAS: return d3d9::D3DSAMP_MIPMAPLODBIAS; + case D3DTSS_MAXMIPLEVEL: return d3d9::D3DSAMP_MAXMIPLEVEL; + case D3DTSS_MAXANISOTROPY: return d3d9::D3DSAMP_MAXANISOTROPY; + // 25: + case D3DTSS_ADDRESSW: return d3d9::D3DSAMP_ADDRESSW; + default: return d3d9::D3DSAMPLERSTATETYPE(-1u); + } + } +} + diff --git a/src/d3d8/d3d8_device_child.h b/src/d3d8/d3d8_device_child.h index d4c2523eb..0cb8525b0 100644 --- a/src/d3d8/d3d8_device_child.h +++ b/src/d3d8/d3d8_device_child.h @@ -1,71 +1,71 @@ -#pragma once - -// Common methods for device-tied objects. -// - AddRef, Release from IUnknown -// - GetDevice from various classes including IDirect3DResource8 - -#include "d3d8_include.h" -#include "d3d8_wrapped_object.h" - -namespace dxvk { - - class D3D8Device; - - template - class D3D8DeviceChild : public D3D8WrappedObject { - - public: - - D3D8DeviceChild(D3D8Device* pDevice, Com&& Object) - : D3D8WrappedObject(std::move(Object)) - , m_parent( pDevice ) { } - - ULONG STDMETHODCALLTYPE AddRef() { - uint32_t refCount = this->m_refCount++; - if (unlikely(!refCount)) { - this->AddRefPrivate(); - GetDevice()->AddRef(); - } - - return refCount + 1; - } - - ULONG STDMETHODCALLTYPE Release() { - // ignore Release calls on objects with 0 refCount - if(unlikely(!this->m_refCount)) - return this->m_refCount; - - uint32_t refCount = --this->m_refCount; - if (unlikely(!refCount)) { - auto* pDevice = GetDevice(); - this->ReleasePrivate(); - pDevice->Release(); - } - return refCount; - } - - HRESULT STDMETHODCALLTYPE GetDevice(IDirect3DDevice8** ppDevice) { - InitReturnPtr(ppDevice); - - if (ppDevice == nullptr) - return D3DERR_INVALIDCALL; - - *ppDevice = ref(GetDevice()); - return D3D_OK; - } - - IDirect3DDevice8* GetDevice() { - return reinterpret_cast(m_parent); - } - - D3D8Device* GetParent() { - return m_parent; - } - - protected: - - D3D8Device* m_parent; - - }; - +#pragma once + +// Common methods for device-tied objects. +// - AddRef, Release from IUnknown +// - GetDevice from various classes including IDirect3DResource8 + +#include "d3d8_include.h" +#include "d3d8_wrapped_object.h" + +namespace dxvk { + + class D3D8Device; + + template + class D3D8DeviceChild : public D3D8WrappedObject { + + public: + + D3D8DeviceChild(D3D8Device* pDevice, Com&& Object) + : D3D8WrappedObject(std::move(Object)) + , m_parent( pDevice ) { } + + ULONG STDMETHODCALLTYPE AddRef() { + uint32_t refCount = this->m_refCount++; + if (unlikely(!refCount)) { + this->AddRefPrivate(); + GetDevice()->AddRef(); + } + + return refCount + 1; + } + + ULONG STDMETHODCALLTYPE Release() { + // ignore Release calls on objects with 0 refCount + if(unlikely(!this->m_refCount)) + return this->m_refCount; + + uint32_t refCount = --this->m_refCount; + if (unlikely(!refCount)) { + auto* pDevice = GetDevice(); + this->ReleasePrivate(); + pDevice->Release(); + } + return refCount; + } + + HRESULT STDMETHODCALLTYPE GetDevice(IDirect3DDevice8** ppDevice) { + InitReturnPtr(ppDevice); + + if (ppDevice == nullptr) + return D3DERR_INVALIDCALL; + + *ppDevice = ref(GetDevice()); + return D3D_OK; + } + + IDirect3DDevice8* GetDevice() { + return reinterpret_cast(m_parent); + } + + D3D8Device* GetParent() { + return m_parent; + } + + protected: + + D3D8Device* m_parent; + + }; + } \ No newline at end of file diff --git a/src/d3d8/d3d8_interface.cpp b/src/d3d8/d3d8_interface.cpp index a5550d532..1cd1462ce 100644 --- a/src/d3d8/d3d8_interface.cpp +++ b/src/d3d8/d3d8_interface.cpp @@ -1,153 +1,153 @@ -#include "d3d8_interface.h" - -#include "d3d8_device.h" -#include "d3d8_texture.h" - -#include - -namespace dxvk -{ - D3D8Interface::D3D8Interface() { - m_d3d9 = d3d9::Direct3DCreate9(D3D_SDK_VERSION); - - // Get the bridge interface to D3D9. - if (FAILED(m_d3d9->QueryInterface(__uuidof(IDxvkD3D8InterfaceBridge), (void**)&m_bridge))) { - throw DxvkError("D3D8Device: ERROR! Failed to get D3D9 Bridge. d3d9.dll might not be DXVK!"); - } - - m_bridge->SetD3D8CompatibilityMode(true); - - m_d3d8Options = D3D8Options(*m_bridge->GetConfig()); - - m_adapterCount = m_d3d9->GetAdapterCount(); - m_adapterModeCounts.resize(m_adapterCount); - m_adapterModes.reserve(m_adapterCount); - - for (UINT adapter = 0; adapter < m_adapterCount; adapter++) { - m_adapterModes.emplace_back(); - - // cache adapter modes and mode counts for each d3d9 format - for (d3d9::D3DFORMAT fmt : ADAPTER_FORMATS) { - - const UINT modeCount = m_d3d9->GetAdapterModeCount(adapter, fmt); - for (UINT mode = 0; mode < modeCount; mode++) { - - m_adapterModes[adapter].emplace_back(); - m_d3d9->EnumAdapterModes(adapter, fmt, mode, &(m_adapterModes[adapter].back())); - - // can't use modeCount as it's only for one fmt - m_adapterModeCounts[adapter]++; - } - } - } - } - - HRESULT STDMETHODCALLTYPE D3D8Interface::QueryInterface(REFIID riid, void** ppvObject) { - if (ppvObject == nullptr) - return E_POINTER; - - *ppvObject = nullptr; - - if (riid == __uuidof(IUnknown) - || riid == __uuidof(IDirect3D8)) { - *ppvObject = ref(this); - return S_OK; - } - - Logger::warn("D3D8Interface::QueryInterface: Unknown interface query"); - Logger::warn(str::format(riid)); - return E_NOINTERFACE; - } - - HRESULT STDMETHODCALLTYPE D3D8Interface::GetAdapterIdentifier( - UINT Adapter, - DWORD Flags, - D3DADAPTER_IDENTIFIER8* pIdentifier) { - if (unlikely(pIdentifier == nullptr)) - return D3DERR_INVALIDCALL; - - // This flag now has the opposite effect. - // Either way, WHQLevel will be 1 with Direct3D9Ex - if (Flags & D3DENUM_NO_WHQL_LEVEL) - Flags &= ~D3DENUM_WHQL_LEVEL; - else - Flags |= D3DENUM_WHQL_LEVEL; - - d3d9::D3DADAPTER_IDENTIFIER9 identifier9; - HRESULT res = m_d3d9->GetAdapterIdentifier(Adapter, Flags, &identifier9); - - if (likely(SUCCEEDED(res))) { - strncpy(pIdentifier->Driver, identifier9.Driver, MAX_DEVICE_IDENTIFIER_STRING); - strncpy(pIdentifier->Description, identifier9.Description, MAX_DEVICE_IDENTIFIER_STRING); - - pIdentifier->DriverVersion = identifier9.DriverVersion; - pIdentifier->VendorId = identifier9.VendorId; - pIdentifier->DeviceId = identifier9.DeviceId; - pIdentifier->SubSysId = identifier9.SubSysId; - pIdentifier->Revision = identifier9.Revision; - pIdentifier->DeviceIdentifier = identifier9.DeviceIdentifier; - - pIdentifier->WHQLLevel = identifier9.WHQLLevel; - } - - return res; - } - - HRESULT __stdcall D3D8Interface::EnumAdapterModes( - UINT Adapter, - UINT Mode, - D3DDISPLAYMODE* pMode) { - if (Adapter >= m_adapterCount || Mode >= m_adapterModeCounts[Adapter] || pMode == nullptr) { - return D3DERR_INVALIDCALL; - } - - pMode->Width = m_adapterModes[Adapter][Mode].Width; - pMode->Height = m_adapterModes[Adapter][Mode].Height; - pMode->RefreshRate = m_adapterModes[Adapter][Mode].RefreshRate; - pMode->Format = D3DFORMAT(m_adapterModes[Adapter][Mode].Format); - - return D3D_OK; - } - - HRESULT __stdcall D3D8Interface::CreateDevice( - UINT Adapter, - D3DDEVTYPE DeviceType, - HWND hFocusWindow, - DWORD BehaviorFlags, - D3DPRESENT_PARAMETERS* pPresentationParameters, - IDirect3DDevice8** ppReturnedDeviceInterface) { - InitReturnPtr(ppReturnedDeviceInterface); - - if (unlikely(pPresentationParameters == nullptr || - ppReturnedDeviceInterface == nullptr)) - return D3DERR_INVALIDCALL; - - // D3DSWAPEFFECT_COPY can not be used with more than one back buffer. - // This is also technically true for D3DSWAPEFFECT_COPY_VSYNC, however - // RC Cars depends on it not being rejected. - if (unlikely(pPresentationParameters->SwapEffect == D3DSWAPEFFECT_COPY - && pPresentationParameters->BackBufferCount > 1)) - return D3DERR_INVALIDCALL; - - Com pDevice9 = nullptr; - d3d9::D3DPRESENT_PARAMETERS params = ConvertPresentParameters9(pPresentationParameters); - HRESULT res = m_d3d9->CreateDevice( - Adapter, - (d3d9::D3DDEVTYPE)DeviceType, - hFocusWindow, - BehaviorFlags, - ¶ms, - &pDevice9 - ); - - if (likely(SUCCEEDED(res))) - *ppReturnedDeviceInterface = ref(new D3D8Device( - this, std::move(pDevice9), - DeviceType, hFocusWindow, BehaviorFlags, - pPresentationParameters - )); - - return res; - } - +#include "d3d8_interface.h" + +#include "d3d8_device.h" +#include "d3d8_texture.h" + +#include + +namespace dxvk +{ + D3D8Interface::D3D8Interface() { + m_d3d9 = d3d9::Direct3DCreate9(D3D_SDK_VERSION); + + // Get the bridge interface to D3D9. + if (FAILED(m_d3d9->QueryInterface(__uuidof(IDxvkD3D8InterfaceBridge), (void**)&m_bridge))) { + throw DxvkError("D3D8Device: ERROR! Failed to get D3D9 Bridge. d3d9.dll might not be DXVK!"); + } + + m_bridge->SetD3D8CompatibilityMode(true); + + m_d3d8Options = D3D8Options(*m_bridge->GetConfig()); + + m_adapterCount = m_d3d9->GetAdapterCount(); + m_adapterModeCounts.resize(m_adapterCount); + m_adapterModes.reserve(m_adapterCount); + + for (UINT adapter = 0; adapter < m_adapterCount; adapter++) { + m_adapterModes.emplace_back(); + + // cache adapter modes and mode counts for each d3d9 format + for (d3d9::D3DFORMAT fmt : ADAPTER_FORMATS) { + + const UINT modeCount = m_d3d9->GetAdapterModeCount(adapter, fmt); + for (UINT mode = 0; mode < modeCount; mode++) { + + m_adapterModes[adapter].emplace_back(); + m_d3d9->EnumAdapterModes(adapter, fmt, mode, &(m_adapterModes[adapter].back())); + + // can't use modeCount as it's only for one fmt + m_adapterModeCounts[adapter]++; + } + } + } + } + + HRESULT STDMETHODCALLTYPE D3D8Interface::QueryInterface(REFIID riid, void** ppvObject) { + if (ppvObject == nullptr) + return E_POINTER; + + *ppvObject = nullptr; + + if (riid == __uuidof(IUnknown) + || riid == __uuidof(IDirect3D8)) { + *ppvObject = ref(this); + return S_OK; + } + + Logger::warn("D3D8Interface::QueryInterface: Unknown interface query"); + Logger::warn(str::format(riid)); + return E_NOINTERFACE; + } + + HRESULT STDMETHODCALLTYPE D3D8Interface::GetAdapterIdentifier( + UINT Adapter, + DWORD Flags, + D3DADAPTER_IDENTIFIER8* pIdentifier) { + if (unlikely(pIdentifier == nullptr)) + return D3DERR_INVALIDCALL; + + // This flag now has the opposite effect. + // Either way, WHQLevel will be 1 with Direct3D9Ex + if (Flags & D3DENUM_NO_WHQL_LEVEL) + Flags &= ~D3DENUM_WHQL_LEVEL; + else + Flags |= D3DENUM_WHQL_LEVEL; + + d3d9::D3DADAPTER_IDENTIFIER9 identifier9; + HRESULT res = m_d3d9->GetAdapterIdentifier(Adapter, Flags, &identifier9); + + if (likely(SUCCEEDED(res))) { + strncpy(pIdentifier->Driver, identifier9.Driver, MAX_DEVICE_IDENTIFIER_STRING); + strncpy(pIdentifier->Description, identifier9.Description, MAX_DEVICE_IDENTIFIER_STRING); + + pIdentifier->DriverVersion = identifier9.DriverVersion; + pIdentifier->VendorId = identifier9.VendorId; + pIdentifier->DeviceId = identifier9.DeviceId; + pIdentifier->SubSysId = identifier9.SubSysId; + pIdentifier->Revision = identifier9.Revision; + pIdentifier->DeviceIdentifier = identifier9.DeviceIdentifier; + + pIdentifier->WHQLLevel = identifier9.WHQLLevel; + } + + return res; + } + + HRESULT __stdcall D3D8Interface::EnumAdapterModes( + UINT Adapter, + UINT Mode, + D3DDISPLAYMODE* pMode) { + if (Adapter >= m_adapterCount || Mode >= m_adapterModeCounts[Adapter] || pMode == nullptr) { + return D3DERR_INVALIDCALL; + } + + pMode->Width = m_adapterModes[Adapter][Mode].Width; + pMode->Height = m_adapterModes[Adapter][Mode].Height; + pMode->RefreshRate = m_adapterModes[Adapter][Mode].RefreshRate; + pMode->Format = D3DFORMAT(m_adapterModes[Adapter][Mode].Format); + + return D3D_OK; + } + + HRESULT __stdcall D3D8Interface::CreateDevice( + UINT Adapter, + D3DDEVTYPE DeviceType, + HWND hFocusWindow, + DWORD BehaviorFlags, + D3DPRESENT_PARAMETERS* pPresentationParameters, + IDirect3DDevice8** ppReturnedDeviceInterface) { + InitReturnPtr(ppReturnedDeviceInterface); + + if (unlikely(pPresentationParameters == nullptr || + ppReturnedDeviceInterface == nullptr)) + return D3DERR_INVALIDCALL; + + // D3DSWAPEFFECT_COPY can not be used with more than one back buffer. + // This is also technically true for D3DSWAPEFFECT_COPY_VSYNC, however + // RC Cars depends on it not being rejected. + if (unlikely(pPresentationParameters->SwapEffect == D3DSWAPEFFECT_COPY + && pPresentationParameters->BackBufferCount > 1)) + return D3DERR_INVALIDCALL; + + Com pDevice9 = nullptr; + d3d9::D3DPRESENT_PARAMETERS params = ConvertPresentParameters9(pPresentationParameters); + HRESULT res = m_d3d9->CreateDevice( + Adapter, + (d3d9::D3DDEVTYPE)DeviceType, + hFocusWindow, + BehaviorFlags, + ¶ms, + &pDevice9 + ); + + if (likely(SUCCEEDED(res))) + *ppReturnedDeviceInterface = ref(new D3D8Device( + this, std::move(pDevice9), + DeviceType, hFocusWindow, BehaviorFlags, + pPresentationParameters + )); + + return res; + } + } \ No newline at end of file diff --git a/src/d3d8/d3d8_interface.h b/src/d3d8/d3d8_interface.h index 3bd76f6fe..9baaaf0c8 100644 --- a/src/d3d8/d3d8_interface.h +++ b/src/d3d8/d3d8_interface.h @@ -1,172 +1,172 @@ -#pragma once - -#include "d3d8_include.h" -#include "d3d8_d3d9_util.h" -#include "d3d8_options.h" -#include "d3d8_format.h" -#include "../d3d9/d3d9_bridge.h" - -namespace dxvk { - - /** - * \brief D3D8 interface implementation - * - * Implements the IDirect3DDevice8 interfaces - * which provides the way to get adapters and create other objects such as \ref IDirect3DDevice8. - * similar to \ref DxgiFactory but for D3D8. - */ - class D3D8Interface final : public ComObjectClamp { - - static constexpr d3d9::D3DFORMAT ADAPTER_FORMATS[] = { - d3d9::D3DFMT_A1R5G5B5, - //d3d9::D3DFMT_A2R10G10B10, (not in D3D8) - d3d9::D3DFMT_A8R8G8B8, - d3d9::D3DFMT_R5G6B5, - d3d9::D3DFMT_X1R5G5B5, - d3d9::D3DFMT_X8R8G8B8 - }; - - public: - D3D8Interface(); - - HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject); - - HRESULT STDMETHODCALLTYPE RegisterSoftwareDevice(void* pInitializeFunction) { - return m_d3d9->RegisterSoftwareDevice(pInitializeFunction); - } - - UINT STDMETHODCALLTYPE GetAdapterCount() { - return m_d3d9->GetAdapterCount(); - } - - HRESULT STDMETHODCALLTYPE GetAdapterIdentifier( - UINT Adapter, - DWORD Flags, - D3DADAPTER_IDENTIFIER8* pIdentifier); - - UINT STDMETHODCALLTYPE GetAdapterModeCount(UINT Adapter) { - return m_adapterModeCounts[Adapter]; - } - - HRESULT STDMETHODCALLTYPE EnumAdapterModes( - UINT Adapter, - UINT Mode, - D3DDISPLAYMODE* pMode); - - HRESULT STDMETHODCALLTYPE GetAdapterDisplayMode(UINT Adapter, D3DDISPLAYMODE* pMode) { - return m_d3d9->GetAdapterDisplayMode(Adapter, (d3d9::D3DDISPLAYMODE*)pMode); - } - - HRESULT STDMETHODCALLTYPE CheckDeviceType( - UINT Adapter, - D3DDEVTYPE DevType, - D3DFORMAT AdapterFormat, - D3DFORMAT BackBufferFormat, - BOOL bWindowed) { - // Ignore the bWindowed parameter when querying D3D9. D3D8 does - // identical validations between windowed and fullscreen modes, adhering - // to the stricter fullscreen adapter and back buffer format validations. - return m_d3d9->CheckDeviceType( - Adapter, - (d3d9::D3DDEVTYPE)DevType, - (d3d9::D3DFORMAT)AdapterFormat, - (d3d9::D3DFORMAT)BackBufferFormat, - FALSE - ); - } - - HRESULT STDMETHODCALLTYPE CheckDeviceFormat( - UINT Adapter, - D3DDEVTYPE DeviceType, - D3DFORMAT AdapterFormat, - DWORD Usage, - D3DRESOURCETYPE RType, - D3DFORMAT CheckFormat) { - return m_d3d9->CheckDeviceFormat( - Adapter, - (d3d9::D3DDEVTYPE)DeviceType, - (d3d9::D3DFORMAT)AdapterFormat, - Usage, - (d3d9::D3DRESOURCETYPE)RType, - (d3d9::D3DFORMAT)CheckFormat - ); - } - - HRESULT STDMETHODCALLTYPE CheckDeviceMultiSampleType( - UINT Adapter, - D3DDEVTYPE DeviceType, - D3DFORMAT SurfaceFormat, - BOOL Windowed, - D3DMULTISAMPLE_TYPE MultiSampleType) { - DWORD* pQualityLevels = nullptr; - return m_d3d9->CheckDeviceMultiSampleType( - Adapter, - (d3d9::D3DDEVTYPE)DeviceType, - (d3d9::D3DFORMAT)SurfaceFormat, - Windowed, - (d3d9::D3DMULTISAMPLE_TYPE)MultiSampleType, - pQualityLevels - ); - } - - HRESULT STDMETHODCALLTYPE CheckDepthStencilMatch( - UINT Adapter, - D3DDEVTYPE DeviceType, - D3DFORMAT AdapterFormat, - D3DFORMAT RenderTargetFormat, - D3DFORMAT DepthStencilFormat) { - if (isSupportedDepthStencilFormat(DepthStencilFormat)) - return m_d3d9->CheckDepthStencilMatch( - Adapter, - (d3d9::D3DDEVTYPE)DeviceType, - (d3d9::D3DFORMAT)AdapterFormat, - (d3d9::D3DFORMAT)RenderTargetFormat, - (d3d9::D3DFORMAT)DepthStencilFormat - ); - - return D3DERR_NOTAVAILABLE; - } - - HRESULT STDMETHODCALLTYPE GetDeviceCaps( - UINT Adapter, - D3DDEVTYPE DeviceType, - D3DCAPS8* pCaps) { - if (unlikely(pCaps == nullptr)) - return D3DERR_INVALIDCALL; - - d3d9::D3DCAPS9 caps9; - HRESULT res = m_d3d9->GetDeviceCaps(Adapter, (d3d9::D3DDEVTYPE)DeviceType, &caps9); - - if (likely(SUCCEEDED(res))) - dxvk::ConvertCaps8(caps9, pCaps); - - return res; - } - - HMONITOR STDMETHODCALLTYPE GetAdapterMonitor(UINT Adapter) { - return m_d3d9->GetAdapterMonitor(Adapter); - } - - HRESULT STDMETHODCALLTYPE CreateDevice( - UINT Adapter, - D3DDEVTYPE DeviceType, - HWND hFocusWindow, - DWORD BehaviorFlags, - D3DPRESENT_PARAMETERS* pPresentationParameters, - IDirect3DDevice8** ppReturnedDeviceInterface); - - - const D3D8Options& GetOptions() { return m_d3d8Options; } - - private: - - UINT m_adapterCount; - std::vector m_adapterModeCounts; - std::vector> m_adapterModes; - - Com m_d3d9; - Com m_bridge; - D3D8Options m_d3d8Options; - }; - +#pragma once + +#include "d3d8_include.h" +#include "d3d8_d3d9_util.h" +#include "d3d8_options.h" +#include "d3d8_format.h" +#include "../d3d9/d3d9_bridge.h" + +namespace dxvk { + + /** + * \brief D3D8 interface implementation + * + * Implements the IDirect3DDevice8 interfaces + * which provides the way to get adapters and create other objects such as \ref IDirect3DDevice8. + * similar to \ref DxgiFactory but for D3D8. + */ + class D3D8Interface final : public ComObjectClamp { + + static constexpr d3d9::D3DFORMAT ADAPTER_FORMATS[] = { + d3d9::D3DFMT_A1R5G5B5, + //d3d9::D3DFMT_A2R10G10B10, (not in D3D8) + d3d9::D3DFMT_A8R8G8B8, + d3d9::D3DFMT_R5G6B5, + d3d9::D3DFMT_X1R5G5B5, + d3d9::D3DFMT_X8R8G8B8 + }; + + public: + D3D8Interface(); + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject); + + HRESULT STDMETHODCALLTYPE RegisterSoftwareDevice(void* pInitializeFunction) { + return m_d3d9->RegisterSoftwareDevice(pInitializeFunction); + } + + UINT STDMETHODCALLTYPE GetAdapterCount() { + return m_d3d9->GetAdapterCount(); + } + + HRESULT STDMETHODCALLTYPE GetAdapterIdentifier( + UINT Adapter, + DWORD Flags, + D3DADAPTER_IDENTIFIER8* pIdentifier); + + UINT STDMETHODCALLTYPE GetAdapterModeCount(UINT Adapter) { + return m_adapterModeCounts[Adapter]; + } + + HRESULT STDMETHODCALLTYPE EnumAdapterModes( + UINT Adapter, + UINT Mode, + D3DDISPLAYMODE* pMode); + + HRESULT STDMETHODCALLTYPE GetAdapterDisplayMode(UINT Adapter, D3DDISPLAYMODE* pMode) { + return m_d3d9->GetAdapterDisplayMode(Adapter, (d3d9::D3DDISPLAYMODE*)pMode); + } + + HRESULT STDMETHODCALLTYPE CheckDeviceType( + UINT Adapter, + D3DDEVTYPE DevType, + D3DFORMAT AdapterFormat, + D3DFORMAT BackBufferFormat, + BOOL bWindowed) { + // Ignore the bWindowed parameter when querying D3D9. D3D8 does + // identical validations between windowed and fullscreen modes, adhering + // to the stricter fullscreen adapter and back buffer format validations. + return m_d3d9->CheckDeviceType( + Adapter, + (d3d9::D3DDEVTYPE)DevType, + (d3d9::D3DFORMAT)AdapterFormat, + (d3d9::D3DFORMAT)BackBufferFormat, + FALSE + ); + } + + HRESULT STDMETHODCALLTYPE CheckDeviceFormat( + UINT Adapter, + D3DDEVTYPE DeviceType, + D3DFORMAT AdapterFormat, + DWORD Usage, + D3DRESOURCETYPE RType, + D3DFORMAT CheckFormat) { + return m_d3d9->CheckDeviceFormat( + Adapter, + (d3d9::D3DDEVTYPE)DeviceType, + (d3d9::D3DFORMAT)AdapterFormat, + Usage, + (d3d9::D3DRESOURCETYPE)RType, + (d3d9::D3DFORMAT)CheckFormat + ); + } + + HRESULT STDMETHODCALLTYPE CheckDeviceMultiSampleType( + UINT Adapter, + D3DDEVTYPE DeviceType, + D3DFORMAT SurfaceFormat, + BOOL Windowed, + D3DMULTISAMPLE_TYPE MultiSampleType) { + DWORD* pQualityLevels = nullptr; + return m_d3d9->CheckDeviceMultiSampleType( + Adapter, + (d3d9::D3DDEVTYPE)DeviceType, + (d3d9::D3DFORMAT)SurfaceFormat, + Windowed, + (d3d9::D3DMULTISAMPLE_TYPE)MultiSampleType, + pQualityLevels + ); + } + + HRESULT STDMETHODCALLTYPE CheckDepthStencilMatch( + UINT Adapter, + D3DDEVTYPE DeviceType, + D3DFORMAT AdapterFormat, + D3DFORMAT RenderTargetFormat, + D3DFORMAT DepthStencilFormat) { + if (isSupportedDepthStencilFormat(DepthStencilFormat)) + return m_d3d9->CheckDepthStencilMatch( + Adapter, + (d3d9::D3DDEVTYPE)DeviceType, + (d3d9::D3DFORMAT)AdapterFormat, + (d3d9::D3DFORMAT)RenderTargetFormat, + (d3d9::D3DFORMAT)DepthStencilFormat + ); + + return D3DERR_NOTAVAILABLE; + } + + HRESULT STDMETHODCALLTYPE GetDeviceCaps( + UINT Adapter, + D3DDEVTYPE DeviceType, + D3DCAPS8* pCaps) { + if (unlikely(pCaps == nullptr)) + return D3DERR_INVALIDCALL; + + d3d9::D3DCAPS9 caps9; + HRESULT res = m_d3d9->GetDeviceCaps(Adapter, (d3d9::D3DDEVTYPE)DeviceType, &caps9); + + if (likely(SUCCEEDED(res))) + dxvk::ConvertCaps8(caps9, pCaps); + + return res; + } + + HMONITOR STDMETHODCALLTYPE GetAdapterMonitor(UINT Adapter) { + return m_d3d9->GetAdapterMonitor(Adapter); + } + + HRESULT STDMETHODCALLTYPE CreateDevice( + UINT Adapter, + D3DDEVTYPE DeviceType, + HWND hFocusWindow, + DWORD BehaviorFlags, + D3DPRESENT_PARAMETERS* pPresentationParameters, + IDirect3DDevice8** ppReturnedDeviceInterface); + + + const D3D8Options& GetOptions() { return m_d3d8Options; } + + private: + + UINT m_adapterCount; + std::vector m_adapterModeCounts; + std::vector> m_adapterModes; + + Com m_d3d9; + Com m_bridge; + D3D8Options m_d3d8Options; + }; + } \ No newline at end of file diff --git a/src/d3d8/d3d8_main.cpp b/src/d3d8/d3d8_main.cpp index 169514829..f6775f88c 100644 --- a/src/d3d8/d3d8_main.cpp +++ b/src/d3d8/d3d8_main.cpp @@ -1,111 +1,111 @@ -#include "d3d8_interface.h" - -namespace dxvk { - Logger Logger::s_instance("d3d8.log"); - - HRESULT CreateD3D8(IDirect3D8** ppDirect3D8) { - if (!ppDirect3D8) - return D3DERR_INVALIDCALL; - - *ppDirect3D8 = ref(new D3D8Interface()); - return D3D_OK; - } -} - -extern "C" { - - DLLEXPORT HRESULT __stdcall ValidatePixelShader( - const DWORD* pPixelShader, - const D3DCAPS8* pCaps, - BOOL errorReturn, - char** pErrorString) { - std::string errorMessage = ""; - - if (unlikely(pPixelShader == nullptr)) { - errorMessage = "D3D8: ValidatePixelShader: Null pPixelShader"; - } else { - uint32_t majorVersion = (pPixelShader[0] >> 8) & 0xff; - uint32_t minorVersion = pPixelShader[0] & 0xff; - - if (unlikely(majorVersion != 1 || minorVersion > 4)) { - errorMessage = dxvk::str::format("D3D8: ValidatePixelShader: Unsupported PS version ", - majorVersion, ".", minorVersion); - } else if (unlikely(pCaps && pPixelShader[0] > pCaps->PixelShaderVersion)) { - errorMessage = dxvk::str::format("D3D8: ValidatePixelShader: Caps: Unsupported PS version ", - majorVersion, ".", minorVersion); - } - } - - const size_t errorMessageSize = errorMessage.size() + 1; - -#ifdef _WIN32 - if (pErrorString != nullptr && errorReturn) { - // Wine tests call HeapFree() on the returned error string, - // so the expectation is for it to be allocated on the heap. - *pErrorString = (char*) HeapAlloc(GetProcessHeap(), 0, errorMessageSize); - if (*pErrorString) - memcpy(*pErrorString, errorMessage.c_str(), errorMessageSize); - } -#endif - - if (errorMessageSize > 1) { - dxvk::Logger::warn(errorMessage); - return E_FAIL; - } - - return S_OK; - } - - DLLEXPORT HRESULT __stdcall ValidateVertexShader( - const DWORD* pVertexShader, - const DWORD* pVertexDecl, - const D3DCAPS8* pCaps, - BOOL errorReturn, - char** pErrorString) { - std::string errorMessage = ""; - - if (unlikely(pVertexShader == nullptr)) { - errorMessage = "D3D8: ValidateVertexShader: Null pVertexShader"; - } else { - uint32_t majorVersion = (pVertexShader[0] >> 8) & 0xff; - uint32_t minorVersion = pVertexShader[0] & 0xff; - - if (unlikely(majorVersion != 1 || minorVersion > 1)) { - errorMessage = dxvk::str::format("D3D8: ValidateVertexShader: Unsupported VS version ", - majorVersion, ".", minorVersion); - } else if (unlikely(pCaps && pVertexShader[0] > pCaps->VertexShaderVersion)) { - errorMessage = dxvk::str::format("D3D8: ValidateVertexShader: Caps: Unsupported VS version ", - majorVersion, ".", minorVersion); - } - } - - const size_t errorMessageSize = errorMessage.size() + 1; - -#ifdef _WIN32 - if (pErrorString != nullptr && errorReturn) { - // Wine tests call HeapFree() on the returned error string, - // so the expectation is for it to be allocated on the heap. - *pErrorString = (char*) HeapAlloc(GetProcessHeap(), 0, errorMessageSize); - if (*pErrorString) - memcpy(*pErrorString, errorMessage.c_str(), errorMessageSize); - } -#endif - - if (errorMessageSize > 1) { - dxvk::Logger::warn(errorMessage); - return E_FAIL; - } - - return S_OK; - } - - DLLEXPORT void __stdcall DebugSetMute() {} - - DLLEXPORT IDirect3D8* __stdcall Direct3DCreate8(UINT nSDKVersion) { - IDirect3D8* pDirect3D = nullptr; - dxvk::CreateD3D8(&pDirect3D); - - return pDirect3D; - } - -} +#include "d3d8_interface.h" + +namespace dxvk { + Logger Logger::s_instance("d3d8.log"); + + HRESULT CreateD3D8(IDirect3D8** ppDirect3D8) { + if (!ppDirect3D8) + return D3DERR_INVALIDCALL; + + *ppDirect3D8 = ref(new D3D8Interface()); + return D3D_OK; + } +} + +extern "C" { + + DLLEXPORT HRESULT __stdcall ValidatePixelShader( + const DWORD* pPixelShader, + const D3DCAPS8* pCaps, + BOOL errorReturn, + char** pErrorString) { + std::string errorMessage = ""; + + if (unlikely(pPixelShader == nullptr)) { + errorMessage = "D3D8: ValidatePixelShader: Null pPixelShader"; + } else { + uint32_t majorVersion = (pPixelShader[0] >> 8) & 0xff; + uint32_t minorVersion = pPixelShader[0] & 0xff; + + if (unlikely(majorVersion != 1 || minorVersion > 4)) { + errorMessage = dxvk::str::format("D3D8: ValidatePixelShader: Unsupported PS version ", + majorVersion, ".", minorVersion); + } else if (unlikely(pCaps && pPixelShader[0] > pCaps->PixelShaderVersion)) { + errorMessage = dxvk::str::format("D3D8: ValidatePixelShader: Caps: Unsupported PS version ", + majorVersion, ".", minorVersion); + } + } + + const size_t errorMessageSize = errorMessage.size() + 1; + +#ifdef _WIN32 + if (pErrorString != nullptr && errorReturn) { + // Wine tests call HeapFree() on the returned error string, + // so the expectation is for it to be allocated on the heap. + *pErrorString = (char*) HeapAlloc(GetProcessHeap(), 0, errorMessageSize); + if (*pErrorString) + memcpy(*pErrorString, errorMessage.c_str(), errorMessageSize); + } +#endif + + if (errorMessageSize > 1) { + dxvk::Logger::warn(errorMessage); + return E_FAIL; + } + + return S_OK; + } + + DLLEXPORT HRESULT __stdcall ValidateVertexShader( + const DWORD* pVertexShader, + const DWORD* pVertexDecl, + const D3DCAPS8* pCaps, + BOOL errorReturn, + char** pErrorString) { + std::string errorMessage = ""; + + if (unlikely(pVertexShader == nullptr)) { + errorMessage = "D3D8: ValidateVertexShader: Null pVertexShader"; + } else { + uint32_t majorVersion = (pVertexShader[0] >> 8) & 0xff; + uint32_t minorVersion = pVertexShader[0] & 0xff; + + if (unlikely(majorVersion != 1 || minorVersion > 1)) { + errorMessage = dxvk::str::format("D3D8: ValidateVertexShader: Unsupported VS version ", + majorVersion, ".", minorVersion); + } else if (unlikely(pCaps && pVertexShader[0] > pCaps->VertexShaderVersion)) { + errorMessage = dxvk::str::format("D3D8: ValidateVertexShader: Caps: Unsupported VS version ", + majorVersion, ".", minorVersion); + } + } + + const size_t errorMessageSize = errorMessage.size() + 1; + +#ifdef _WIN32 + if (pErrorString != nullptr && errorReturn) { + // Wine tests call HeapFree() on the returned error string, + // so the expectation is for it to be allocated on the heap. + *pErrorString = (char*) HeapAlloc(GetProcessHeap(), 0, errorMessageSize); + if (*pErrorString) + memcpy(*pErrorString, errorMessage.c_str(), errorMessageSize); + } +#endif + + if (errorMessageSize > 1) { + dxvk::Logger::warn(errorMessage); + return E_FAIL; + } + + return S_OK; + } + + DLLEXPORT void __stdcall DebugSetMute() {} + + DLLEXPORT IDirect3D8* __stdcall Direct3DCreate8(UINT nSDKVersion) { + IDirect3D8* pDirect3D = nullptr; + dxvk::CreateD3D8(&pDirect3D); + + return pDirect3D; + } + +} diff --git a/src/d3d8/d3d8_options.h b/src/d3d8/d3d8_options.h index 2b5047617..ff93e7bcd 100644 --- a/src/d3d8/d3d8_options.h +++ b/src/d3d8/d3d8_options.h @@ -1,56 +1,56 @@ -#pragma once - -#include "d3d8_include.h" -#include "../d3d9/d3d9_bridge.h" -#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 - std::vector> forceVsDecl; - - /// Specialized drawcall batcher, typically for games that draw a lot of similar - /// geometry in separate drawcalls (sometimes even one triangle at a time). - /// - /// May hurt performance outside of specifc games that benefit from it. - bool batching = false; - - /// The Lord of the Rings: The Fellowship of the Ring tries to create a P8 texture - /// in D3DPOOL_MANAGED on Nvidia and Intel, which fails, but has a separate code - /// path for ATI/AMD that creates it in D3DPOOL_SCRATCH instead, which works. - /// - /// The internal logic determining this path doesn't seem to be d3d-related, but - /// the game works universally if we mimic its own ATI/AMD workaround during P8 - /// texture creation. - /// - /// Early Nvidia GPUs, such as the GeForce 4 generation cards, included and exposed - /// P8 texture support. However, it was no longer advertised with cards in the FX series - /// and above. Most likely ATI/AMD drivers never supported P8 in the first place. - bool placeP8InScratch = false; - - /// Rayman 3 relies on D3DLOCK_DISCARD being ignored for everything except D3DUSAGE_DYNAMIC + - /// D3DUSAGE_WRITEONLY buffers, however this approach incurs a performance penalty. - /// - /// Some titles might abuse this early D3D8 quirk, however at some point in its history - /// it was brought in line with standard D3D9 behavior. - bool forceLegacyDiscard = false; - - D3D8Options() {} - D3D8Options(const Config& config) { - auto forceVsDeclStr = config.getOption("d3d8.forceVsDecl", ""); - batching = config.getOption ("d3d8.batching", batching); - placeP8InScratch = config.getOption ("d3d8.placeP8InScratch", placeP8InScratch); - forceLegacyDiscard = config.getOption ("d3d8.forceLegacyDiscard", forceLegacyDiscard); - - parseVsDecl(forceVsDeclStr); - } - - void parseVsDecl(const std::string& decl); - }; -} +#pragma once + +#include "d3d8_include.h" +#include "../d3d9/d3d9_bridge.h" +#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 + std::vector> forceVsDecl; + + /// Specialized drawcall batcher, typically for games that draw a lot of similar + /// geometry in separate drawcalls (sometimes even one triangle at a time). + /// + /// May hurt performance outside of specifc games that benefit from it. + bool batching = false; + + /// The Lord of the Rings: The Fellowship of the Ring tries to create a P8 texture + /// in D3DPOOL_MANAGED on Nvidia and Intel, which fails, but has a separate code + /// path for ATI/AMD that creates it in D3DPOOL_SCRATCH instead, which works. + /// + /// The internal logic determining this path doesn't seem to be d3d-related, but + /// the game works universally if we mimic its own ATI/AMD workaround during P8 + /// texture creation. + /// + /// Early Nvidia GPUs, such as the GeForce 4 generation cards, included and exposed + /// P8 texture support. However, it was no longer advertised with cards in the FX series + /// and above. Most likely ATI/AMD drivers never supported P8 in the first place. + bool placeP8InScratch = false; + + /// Rayman 3 relies on D3DLOCK_DISCARD being ignored for everything except D3DUSAGE_DYNAMIC + + /// D3DUSAGE_WRITEONLY buffers, however this approach incurs a performance penalty. + /// + /// Some titles might abuse this early D3D8 quirk, however at some point in its history + /// it was brought in line with standard D3D9 behavior. + bool forceLegacyDiscard = false; + + D3D8Options() {} + D3D8Options(const Config& config) { + auto forceVsDeclStr = config.getOption("d3d8.forceVsDecl", ""); + batching = config.getOption ("d3d8.batching", batching); + placeP8InScratch = config.getOption ("d3d8.placeP8InScratch", placeP8InScratch); + forceLegacyDiscard = config.getOption ("d3d8.forceLegacyDiscard", forceLegacyDiscard); + + parseVsDecl(forceVsDeclStr); + } + + void parseVsDecl(const std::string& decl); + }; +} diff --git a/src/d3d8/d3d8_resource.h b/src/d3d8/d3d8_resource.h index 4943decac..e890e19bb 100644 --- a/src/d3d8/d3d8_resource.h +++ b/src/d3d8/d3d8_resource.h @@ -1,111 +1,111 @@ -#pragma once - -/** Implements IDirect3DResource8 -* -* - SetPrivateData, GetPrivateData, FreePrivateData -* - SetPriority, GetPriority -* -* - Subclasses provide: PreLoad, GetType -*/ - -#include "d3d8_device_child.h" -#include "../util/com/com_private_data.h" - -namespace dxvk { - - template - class D3D8Resource : public D3D8DeviceChild { - - public: - - D3D8Resource(D3D8Device* pDevice, Com&& Object) - : D3D8DeviceChild(pDevice, std::move(Object)) - , m_priority ( 0 ) { } - - HRESULT STDMETHODCALLTYPE SetPrivateData( - REFGUID refguid, - const void* pData, - DWORD SizeOfData, - DWORD Flags) final { - HRESULT hr; - if (Flags & D3DSPD_IUNKNOWN) { - if(unlikely(SizeOfData != sizeof(IUnknown*))) - return D3DERR_INVALIDCALL; - IUnknown* unknown = - const_cast( - reinterpret_cast(pData)); - hr = m_privateData.setInterface( - refguid, unknown); - } - else - hr = m_privateData.setData( - refguid, SizeOfData, pData); - - if (unlikely(FAILED(hr))) - return D3DERR_INVALIDCALL; - - return D3D_OK; - } - - HRESULT STDMETHODCALLTYPE GetPrivateData( - REFGUID refguid, - void* pData, - DWORD* pSizeOfData) final { - if (unlikely(pData == nullptr && pSizeOfData == nullptr)) - return D3DERR_NOTFOUND; - - HRESULT hr = m_privateData.getData( - refguid, reinterpret_cast(pSizeOfData), pData); - - if (unlikely(FAILED(hr))) { - if(hr == DXGI_ERROR_MORE_DATA) - return D3DERR_MOREDATA; - else if (hr == DXGI_ERROR_NOT_FOUND) - return D3DERR_NOTFOUND; - else - return D3DERR_INVALIDCALL; - } - - return D3D_OK; - } - - HRESULT STDMETHODCALLTYPE FreePrivateData(REFGUID refguid) final { - HRESULT hr = m_privateData.setData(refguid, 0, nullptr); - - if (unlikely(FAILED(hr))) - return D3DERR_INVALIDCALL; - - return D3D_OK; - } - - DWORD STDMETHODCALLTYPE SetPriority(DWORD PriorityNew) { - DWORD oldPriority = m_priority; - m_priority = PriorityNew; - return oldPriority; - } - - DWORD STDMETHODCALLTYPE GetPriority() { - return m_priority; - } - - virtual IUnknown* GetInterface(REFIID riid) override try { - return D3D8DeviceChild::GetInterface(riid); - } catch (HRESULT err) { - if (riid == __uuidof(IDirect3DResource8)) - return this; - - throw err; - } - - protected: - - DWORD m_priority; - - private: - - ComPrivateData m_privateData; - - }; - - +#pragma once + +/** Implements IDirect3DResource8 +* +* - SetPrivateData, GetPrivateData, FreePrivateData +* - SetPriority, GetPriority +* +* - Subclasses provide: PreLoad, GetType +*/ + +#include "d3d8_device_child.h" +#include "../util/com/com_private_data.h" + +namespace dxvk { + + template + class D3D8Resource : public D3D8DeviceChild { + + public: + + D3D8Resource(D3D8Device* pDevice, Com&& Object) + : D3D8DeviceChild(pDevice, std::move(Object)) + , m_priority ( 0 ) { } + + HRESULT STDMETHODCALLTYPE SetPrivateData( + REFGUID refguid, + const void* pData, + DWORD SizeOfData, + DWORD Flags) final { + HRESULT hr; + if (Flags & D3DSPD_IUNKNOWN) { + if(unlikely(SizeOfData != sizeof(IUnknown*))) + return D3DERR_INVALIDCALL; + IUnknown* unknown = + const_cast( + reinterpret_cast(pData)); + hr = m_privateData.setInterface( + refguid, unknown); + } + else + hr = m_privateData.setData( + refguid, SizeOfData, pData); + + if (unlikely(FAILED(hr))) + return D3DERR_INVALIDCALL; + + return D3D_OK; + } + + HRESULT STDMETHODCALLTYPE GetPrivateData( + REFGUID refguid, + void* pData, + DWORD* pSizeOfData) final { + if (unlikely(pData == nullptr && pSizeOfData == nullptr)) + return D3DERR_NOTFOUND; + + HRESULT hr = m_privateData.getData( + refguid, reinterpret_cast(pSizeOfData), pData); + + if (unlikely(FAILED(hr))) { + if(hr == DXGI_ERROR_MORE_DATA) + return D3DERR_MOREDATA; + else if (hr == DXGI_ERROR_NOT_FOUND) + return D3DERR_NOTFOUND; + else + return D3DERR_INVALIDCALL; + } + + return D3D_OK; + } + + HRESULT STDMETHODCALLTYPE FreePrivateData(REFGUID refguid) final { + HRESULT hr = m_privateData.setData(refguid, 0, nullptr); + + if (unlikely(FAILED(hr))) + return D3DERR_INVALIDCALL; + + return D3D_OK; + } + + DWORD STDMETHODCALLTYPE SetPriority(DWORD PriorityNew) { + DWORD oldPriority = m_priority; + m_priority = PriorityNew; + return oldPriority; + } + + DWORD STDMETHODCALLTYPE GetPriority() { + return m_priority; + } + + virtual IUnknown* GetInterface(REFIID riid) override try { + return D3D8DeviceChild::GetInterface(riid); + } catch (HRESULT err) { + if (riid == __uuidof(IDirect3DResource8)) + return this; + + throw err; + } + + protected: + + DWORD m_priority; + + private: + + ComPrivateData m_privateData; + + }; + + } \ No newline at end of file diff --git a/src/d3d8/d3d8_state_block.h b/src/d3d8/d3d8_state_block.h index 730a421e0..fe4b31114 100644 --- a/src/d3d8/d3d8_state_block.h +++ b/src/d3d8/d3d8_state_block.h @@ -1,155 +1,155 @@ -#pragma once - -#include "d3d8_caps.h" -#include "d3d8_include.h" -#include "d3d8_device.h" -#include "d3d8_device_child.h" - -#include "../util/util_bit.h" - -#include - -namespace dxvk { - - struct D3D8StateCapture { - bool vs : 1; - bool ps : 1; - bool indices : 1; - bool swvp : 1; - - bit::bitset textures; - bit::bitset streams; - - D3D8StateCapture() - : vs(false) - , ps(false) - , indices(false) - , swvp(false) { - // Ensure all bits are initialized to false - textures.clearAll(); - streams.clearAll(); - } - }; - - // Wrapper class for D3D9 state blocks. Captures D3D8-specific state. - class D3D8StateBlock { - - public: - - D3D8StateBlock( - D3D8Device* pDevice, - D3DSTATEBLOCKTYPE Type, - Com&& pStateBlock) - : m_device(pDevice) - , m_stateBlock(std::move(pStateBlock)) - , m_type(Type) { - if (Type == D3DSBT_VERTEXSTATE || Type == D3DSBT_ALL) { - // Lights, D3DTSS_TEXCOORDINDEX and D3DTSS_TEXTURETRANSFORMFLAGS, - // vertex shader, VS constants, and various render states. - m_capture.vs = true; - } - - if (Type == D3DSBT_PIXELSTATE || Type == D3DSBT_ALL) { - // Pixel shader, PS constants, and various RS/TSS states. - m_capture.ps = true; - } - - if (Type == D3DSBT_ALL) { - m_capture.indices = true; - m_capture.swvp = true; - m_capture.textures.setAll(); - m_capture.streams.setAll(); - } - - m_textures.fill(nullptr); - m_streams.fill(D3D8VBOP()); - } - - ~D3D8StateBlock() {} - - // Construct a state block without a D3D9 object - D3D8StateBlock(D3D8Device* pDevice) - : D3D8StateBlock(pDevice, D3DSTATEBLOCKTYPE(0), nullptr) { - } - - // Attach a D3D9 object to a state block that doesn't have one yet - void SetD3D9(Com&& pStateBlock) { - if (likely(m_stateBlock == nullptr)) { - m_stateBlock = std::move(pStateBlock); - } else { - Logger::err("D3D8StateBlock::SetD3D9: m_stateBlock has already been initialized"); - } - } - - HRESULT Capture(); - - HRESULT Apply(); - - inline HRESULT SetVertexShader(DWORD Handle) { - m_vertexShader = Handle; - m_capture.vs = true; - return D3D_OK; - } - - inline HRESULT SetPixelShader(DWORD Handle) { - m_pixelShader = Handle; - m_capture.ps = true; - return D3D_OK; - } - - inline HRESULT SetTexture(DWORD Stage, IDirect3DBaseTexture8* pTexture) { - m_textures[Stage] = pTexture; - m_capture.textures.set(Stage, true); - return D3D_OK; - } - - inline HRESULT SetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer8* pStreamData, UINT Stride) { - m_streams[StreamNumber].buffer = pStreamData; - // The previous stride is preserved if pStreamData is NULL - if (likely(pStreamData != nullptr)) - m_streams[StreamNumber].stride = Stride; - m_capture.streams.set(StreamNumber, true); - return D3D_OK; - } - - inline HRESULT SetIndices(IDirect3DIndexBuffer8* pIndexData, UINT BaseVertexIndex) { - m_indices = pIndexData; - m_baseVertexIndex = BaseVertexIndex; - m_capture.indices = true; - return D3D_OK; - } - - inline HRESULT SetSoftwareVertexProcessing(bool value) { - m_isSWVP = value; - m_capture.swvp = true; - return D3D_OK; - } - - private: - D3D8Device* m_device; - Com m_stateBlock; - D3DSTATEBLOCKTYPE m_type; - - struct D3D8VBOP { - IDirect3DVertexBuffer8* buffer = nullptr; - UINT stride = 0; - }; - - private: // State Data // - - D3D8StateCapture m_capture; - - DWORD m_vertexShader; // vs - DWORD m_pixelShader; // ps - - std::array m_textures; // textures - std::array m_streams; // stream data - - IDirect3DIndexBuffer8* m_indices = nullptr; // indices - UINT m_baseVertexIndex; // indices - - bool m_isSWVP; // D3DRS_SOFTWAREVERTEXPROCESSING - }; - - +#pragma once + +#include "d3d8_caps.h" +#include "d3d8_include.h" +#include "d3d8_device.h" +#include "d3d8_device_child.h" + +#include "../util/util_bit.h" + +#include + +namespace dxvk { + + struct D3D8StateCapture { + bool vs : 1; + bool ps : 1; + bool indices : 1; + bool swvp : 1; + + bit::bitset textures; + bit::bitset streams; + + D3D8StateCapture() + : vs(false) + , ps(false) + , indices(false) + , swvp(false) { + // Ensure all bits are initialized to false + textures.clearAll(); + streams.clearAll(); + } + }; + + // Wrapper class for D3D9 state blocks. Captures D3D8-specific state. + class D3D8StateBlock { + + public: + + D3D8StateBlock( + D3D8Device* pDevice, + D3DSTATEBLOCKTYPE Type, + Com&& pStateBlock) + : m_device(pDevice) + , m_stateBlock(std::move(pStateBlock)) + , m_type(Type) { + if (Type == D3DSBT_VERTEXSTATE || Type == D3DSBT_ALL) { + // Lights, D3DTSS_TEXCOORDINDEX and D3DTSS_TEXTURETRANSFORMFLAGS, + // vertex shader, VS constants, and various render states. + m_capture.vs = true; + } + + if (Type == D3DSBT_PIXELSTATE || Type == D3DSBT_ALL) { + // Pixel shader, PS constants, and various RS/TSS states. + m_capture.ps = true; + } + + if (Type == D3DSBT_ALL) { + m_capture.indices = true; + m_capture.swvp = true; + m_capture.textures.setAll(); + m_capture.streams.setAll(); + } + + m_textures.fill(nullptr); + m_streams.fill(D3D8VBOP()); + } + + ~D3D8StateBlock() {} + + // Construct a state block without a D3D9 object + D3D8StateBlock(D3D8Device* pDevice) + : D3D8StateBlock(pDevice, D3DSTATEBLOCKTYPE(0), nullptr) { + } + + // Attach a D3D9 object to a state block that doesn't have one yet + void SetD3D9(Com&& pStateBlock) { + if (likely(m_stateBlock == nullptr)) { + m_stateBlock = std::move(pStateBlock); + } else { + Logger::err("D3D8StateBlock::SetD3D9: m_stateBlock has already been initialized"); + } + } + + HRESULT Capture(); + + HRESULT Apply(); + + inline HRESULT SetVertexShader(DWORD Handle) { + m_vertexShader = Handle; + m_capture.vs = true; + return D3D_OK; + } + + inline HRESULT SetPixelShader(DWORD Handle) { + m_pixelShader = Handle; + m_capture.ps = true; + return D3D_OK; + } + + inline HRESULT SetTexture(DWORD Stage, IDirect3DBaseTexture8* pTexture) { + m_textures[Stage] = pTexture; + m_capture.textures.set(Stage, true); + return D3D_OK; + } + + inline HRESULT SetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer8* pStreamData, UINT Stride) { + m_streams[StreamNumber].buffer = pStreamData; + // The previous stride is preserved if pStreamData is NULL + if (likely(pStreamData != nullptr)) + m_streams[StreamNumber].stride = Stride; + m_capture.streams.set(StreamNumber, true); + return D3D_OK; + } + + inline HRESULT SetIndices(IDirect3DIndexBuffer8* pIndexData, UINT BaseVertexIndex) { + m_indices = pIndexData; + m_baseVertexIndex = BaseVertexIndex; + m_capture.indices = true; + return D3D_OK; + } + + inline HRESULT SetSoftwareVertexProcessing(bool value) { + m_isSWVP = value; + m_capture.swvp = true; + return D3D_OK; + } + + private: + D3D8Device* m_device; + Com m_stateBlock; + D3DSTATEBLOCKTYPE m_type; + + struct D3D8VBOP { + IDirect3DVertexBuffer8* buffer = nullptr; + UINT stride = 0; + }; + + private: // State Data // + + D3D8StateCapture m_capture; + + DWORD m_vertexShader; // vs + DWORD m_pixelShader; // ps + + std::array m_textures; // textures + std::array m_streams; // stream data + + IDirect3DIndexBuffer8* m_indices = nullptr; // indices + UINT m_baseVertexIndex; // indices + + bool m_isSWVP; // D3DRS_SOFTWAREVERTEXPROCESSING + }; + + } \ No newline at end of file diff --git a/src/d3d8/d3d8_surface.h b/src/d3d8/d3d8_surface.h index 622f580d4..6493f7c94 100644 --- a/src/d3d8/d3d8_surface.h +++ b/src/d3d8/d3d8_surface.h @@ -1,87 +1,87 @@ -#pragma once - -#include "d3d8_include.h" -#include "d3d8_subresource.h" -#include "d3d8_d3d9_util.h" - -namespace dxvk { - - // TODO: all inherited methods in D3D8Surface should be final like in d9vk - - using D3D8SurfaceBase = D3D8Subresource; - class D3D8Surface final : public D3D8SurfaceBase { - - public: - - D3D8Surface( - D3D8Device* pDevice, - IDirect3DBaseTexture8* pTexture, - Com&& pSurface) - : D3D8SurfaceBase (pDevice, std::move(pSurface), pTexture) { - } - - // A surface does not need to be attached to a texture - D3D8Surface( - D3D8Device* pDevice, - Com&& pSurface) - : D3D8Surface (pDevice, nullptr, std::move(pSurface)) { - } - - D3DRESOURCETYPE STDMETHODCALLTYPE GetType() { - return D3DRESOURCETYPE(GetD3D9()->GetType()); - } - - HRESULT STDMETHODCALLTYPE GetDesc(D3DSURFACE_DESC* pDesc) { - if (unlikely(pDesc == nullptr)) - return D3DERR_INVALIDCALL; - - d3d9::D3DSURFACE_DESC desc; - HRESULT res = GetD3D9()->GetDesc(&desc); - - if (likely(SUCCEEDED(res))) - ConvertSurfaceDesc8(&desc, pDesc); - - return res; - } - - HRESULT STDMETHODCALLTYPE LockRect(D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) { - return GetD3D9()->LockRect((d3d9::D3DLOCKED_RECT*)pLockedRect, pRect, Flags); - } - - HRESULT STDMETHODCALLTYPE UnlockRect() { - return GetD3D9()->UnlockRect(); - } - - HRESULT STDMETHODCALLTYPE GetDC(HDC* phDC) { - return GetD3D9()->GetDC(phDC); - } - - HRESULT STDMETHODCALLTYPE ReleaseDC(HDC hDC) { - return GetD3D9()->ReleaseDC(hDC); - } - - public: - - /** - * \brief Allocate or reuse an image of the same size - * as this texture for performing blit into system mem. - * - * TODO: Consider creating only one texture to - * encompass all surface levels of a texture. - */ - Com GetBlitImage() { - if (unlikely(m_blitImage == nullptr)) { - m_blitImage = CreateBlitImage(); - } - - return m_blitImage; - } - - - private: - Com CreateBlitImage(); - - Com m_blitImage = nullptr; - - }; +#pragma once + +#include "d3d8_include.h" +#include "d3d8_subresource.h" +#include "d3d8_d3d9_util.h" + +namespace dxvk { + + // TODO: all inherited methods in D3D8Surface should be final like in d9vk + + using D3D8SurfaceBase = D3D8Subresource; + class D3D8Surface final : public D3D8SurfaceBase { + + public: + + D3D8Surface( + D3D8Device* pDevice, + IDirect3DBaseTexture8* pTexture, + Com&& pSurface) + : D3D8SurfaceBase (pDevice, std::move(pSurface), pTexture) { + } + + // A surface does not need to be attached to a texture + D3D8Surface( + D3D8Device* pDevice, + Com&& pSurface) + : D3D8Surface (pDevice, nullptr, std::move(pSurface)) { + } + + D3DRESOURCETYPE STDMETHODCALLTYPE GetType() { + return D3DRESOURCETYPE(GetD3D9()->GetType()); + } + + HRESULT STDMETHODCALLTYPE GetDesc(D3DSURFACE_DESC* pDesc) { + if (unlikely(pDesc == nullptr)) + return D3DERR_INVALIDCALL; + + d3d9::D3DSURFACE_DESC desc; + HRESULT res = GetD3D9()->GetDesc(&desc); + + if (likely(SUCCEEDED(res))) + ConvertSurfaceDesc8(&desc, pDesc); + + return res; + } + + HRESULT STDMETHODCALLTYPE LockRect(D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) { + return GetD3D9()->LockRect((d3d9::D3DLOCKED_RECT*)pLockedRect, pRect, Flags); + } + + HRESULT STDMETHODCALLTYPE UnlockRect() { + return GetD3D9()->UnlockRect(); + } + + HRESULT STDMETHODCALLTYPE GetDC(HDC* phDC) { + return GetD3D9()->GetDC(phDC); + } + + HRESULT STDMETHODCALLTYPE ReleaseDC(HDC hDC) { + return GetD3D9()->ReleaseDC(hDC); + } + + public: + + /** + * \brief Allocate or reuse an image of the same size + * as this texture for performing blit into system mem. + * + * TODO: Consider creating only one texture to + * encompass all surface levels of a texture. + */ + Com GetBlitImage() { + if (unlikely(m_blitImage == nullptr)) { + m_blitImage = CreateBlitImage(); + } + + return m_blitImage; + } + + + private: + Com CreateBlitImage(); + + Com m_blitImage = nullptr; + + }; } \ No newline at end of file diff --git a/src/d3d8/d3d8_texture.h b/src/d3d8/d3d8_texture.h index 7f57bb68a..75dc21b3a 100644 --- a/src/d3d8/d3d8_texture.h +++ b/src/d3d8/d3d8_texture.h @@ -1,254 +1,254 @@ -#pragma once - -#include "d3d8_resource.h" -#include "d3d8_surface.h" -#include "d3d8_volume.h" - -#include "d3d8_d3d9_util.h" - -#include -#include - -namespace dxvk { - - template - class D3D8BaseTexture : public D3D8Resource { - - public: - - constexpr static UINT CUBE_FACES = 6; - - using SubresourceType8 = typename SubresourceType::D3D8; - using SubresourceType9 = typename SubresourceType::D3D9; - - D3D8BaseTexture( - D3D8Device* pDevice, - Com&& pBaseTexture, - UINT SubresourceCount) - : D3D8Resource ( pDevice, std::move(pBaseTexture) ) { - m_subresources.resize(SubresourceCount, nullptr); - } - - ~D3D8BaseTexture() { - for (size_t i = 0; i < m_subresources.size(); i++) - if (m_subresources[i] != nullptr) - m_subresources[i] = nullptr; - } - - virtual IUnknown* GetInterface(REFIID riid) final override try { - return D3D8Resource::GetInterface(riid); - } catch (HRESULT err) { - if (riid == __uuidof(IDirect3DBaseTexture8)) - return this; - - throw err; - } - - void STDMETHODCALLTYPE PreLoad() final { - this->GetD3D9()->PreLoad(); - } - - DWORD STDMETHODCALLTYPE SetLOD(DWORD LODNew) final { - return this->GetD3D9()->SetLOD(LODNew); - } - - DWORD STDMETHODCALLTYPE GetLOD() final { - return this->GetD3D9()->GetLOD(); - } - - DWORD STDMETHODCALLTYPE GetLevelCount() final { - return this->GetD3D9()->GetLevelCount(); - } - - protected: - - HRESULT STDMETHODCALLTYPE GetSubresource(UINT Index, SubresourceType8** ppSubresource) { - InitReturnPtr(ppSubresource); - - if (unlikely(ppSubresource == nullptr)) - return D3DERR_INVALIDCALL; - - if (unlikely(Index >= m_subresources.size())) - return D3DERR_INVALIDCALL; - - if (m_subresources[Index] == nullptr) { - try { - Com subresource = LookupSubresource(Index); - - // Cache the subresource - m_subresources[Index] = new SubresourceType(this->m_parent, this, std::move(subresource)); - } catch (HRESULT res) { - return res; - } - } - - *ppSubresource = m_subresources[Index].ref(); - return D3D_OK; - } - - private: - - Com LookupSubresource(UINT Index) { - Com ptr = nullptr; - HRESULT res = D3DERR_INVALIDCALL; - if constexpr (std::is_same_v) { - res = this->GetD3D9()->GetSurfaceLevel(Index, &ptr); - } else if constexpr (std::is_same_v) { - res = this->GetD3D9()->GetVolumeLevel(Index, &ptr); - } else if constexpr (std::is_same_v) { - res = this->GetD3D9()->GetCubeMapSurface(d3d9::D3DCUBEMAP_FACES(Index % CUBE_FACES), Index / CUBE_FACES, &ptr); - } - if (FAILED(res)) - throw res; - return ptr; - } - - std::vector> m_subresources; - - }; - - using D3D8Texture2DBase = D3D8BaseTexture; - class D3D8Texture2D final : public D3D8Texture2DBase { - - public: - - D3D8Texture2D( - D3D8Device* pDevice, - Com&& pTexture) - : D3D8Texture2DBase(pDevice, std::move(pTexture), pTexture->GetLevelCount()) { - } - - D3DRESOURCETYPE STDMETHODCALLTYPE GetType() final { return D3DRTYPE_TEXTURE; } - - HRESULT STDMETHODCALLTYPE GetLevelDesc(UINT Level, D3DSURFACE_DESC* pDesc) { - if (unlikely(pDesc == nullptr)) - return D3DERR_INVALIDCALL; - - d3d9::D3DSURFACE_DESC surf; - HRESULT res = GetD3D9()->GetLevelDesc(Level, &surf); - - if (likely(SUCCEEDED(res))) - ConvertSurfaceDesc8(&surf, pDesc); - - return res; - } - - HRESULT STDMETHODCALLTYPE GetSurfaceLevel(UINT Level, IDirect3DSurface8** ppSurfaceLevel) { - return GetSubresource(Level, ppSurfaceLevel); - } - - HRESULT STDMETHODCALLTYPE LockRect(UINT Level, D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) { - return GetD3D9()->LockRect(Level, reinterpret_cast(pLockedRect), pRect, Flags); - } - - HRESULT STDMETHODCALLTYPE UnlockRect(UINT Level) { - return GetD3D9()->UnlockRect(Level); - } - - HRESULT STDMETHODCALLTYPE AddDirtyRect(CONST RECT* pDirtyRect) { - return GetD3D9()->AddDirtyRect(pDirtyRect); - } - - }; - - using D3D8Texture3DBase = D3D8BaseTexture; - class D3D8Texture3D final : public D3D8Texture3DBase { - - public: - - D3D8Texture3D( - D3D8Device* pDevice, - Com&& pVolumeTexture) - : D3D8Texture3DBase(pDevice, std::move(pVolumeTexture), pVolumeTexture->GetLevelCount()) {} - - D3DRESOURCETYPE STDMETHODCALLTYPE GetType() final { return D3DRTYPE_VOLUMETEXTURE; } - - HRESULT STDMETHODCALLTYPE GetLevelDesc(UINT Level, D3DVOLUME_DESC *pDesc) { - if (unlikely(pDesc == nullptr)) - return D3DERR_INVALIDCALL; - - d3d9::D3DVOLUME_DESC vol; - HRESULT res = GetD3D9()->GetLevelDesc(Level, &vol); - - if (likely(SUCCEEDED(res))) - ConvertVolumeDesc8(&vol, pDesc); - - return res; - } - - HRESULT STDMETHODCALLTYPE GetVolumeLevel(UINT Level, IDirect3DVolume8** ppVolumeLevel) { - return GetSubresource(Level, ppVolumeLevel); - } - - HRESULT STDMETHODCALLTYPE LockBox(UINT Level, D3DLOCKED_BOX* pLockedBox, CONST D3DBOX* pBox, DWORD Flags) { - return GetD3D9()->LockBox( - Level, - reinterpret_cast(pLockedBox), - reinterpret_cast(pBox), - Flags - ); - } - - HRESULT STDMETHODCALLTYPE UnlockBox(UINT Level) { - return GetD3D9()->UnlockBox(Level); - } - - HRESULT STDMETHODCALLTYPE AddDirtyBox(CONST D3DBOX* pDirtyBox) { - return GetD3D9()->AddDirtyBox(reinterpret_cast(pDirtyBox)); - } - - }; - - using D3D8TextureCubeBase = D3D8BaseTexture; - class D3D8TextureCube final : public D3D8TextureCubeBase { - - public: - - D3D8TextureCube( - D3D8Device* pDevice, - Com&& pTexture) - : D3D8TextureCubeBase(pDevice, std::move(pTexture), pTexture->GetLevelCount() * CUBE_FACES) { - } - - D3DRESOURCETYPE STDMETHODCALLTYPE GetType() final { return D3DRTYPE_CUBETEXTURE; } - - HRESULT STDMETHODCALLTYPE GetLevelDesc(UINT Level, D3DSURFACE_DESC* pDesc) { - if (unlikely(pDesc == nullptr)) - return D3DERR_INVALIDCALL; - - d3d9::D3DSURFACE_DESC surf; - HRESULT res = GetD3D9()->GetLevelDesc(Level, &surf); - - if (likely(SUCCEEDED(res))) - ConvertSurfaceDesc8(&surf, pDesc); - - return res; - } - - HRESULT STDMETHODCALLTYPE GetCubeMapSurface(D3DCUBEMAP_FACES Face, UINT Level, IDirect3DSurface8** ppSurfaceLevel) { - return GetSubresource((Level * CUBE_FACES) + Face, ppSurfaceLevel); - } - - HRESULT STDMETHODCALLTYPE LockRect( - D3DCUBEMAP_FACES Face, - UINT Level, - D3DLOCKED_RECT* pLockedRect, - const RECT* pRect, - DWORD Flags) { - return GetD3D9()->LockRect( - d3d9::D3DCUBEMAP_FACES(Face), - Level, - reinterpret_cast(pLockedRect), - pRect, - Flags); - } - - HRESULT STDMETHODCALLTYPE UnlockRect(D3DCUBEMAP_FACES Face, UINT Level) { - return GetD3D9()->UnlockRect(d3d9::D3DCUBEMAP_FACES(Face), Level); - } - - HRESULT STDMETHODCALLTYPE AddDirtyRect(D3DCUBEMAP_FACES Face, const RECT* pDirtyRect) { - return GetD3D9()->AddDirtyRect(d3d9::D3DCUBEMAP_FACES(Face), pDirtyRect); - } - }; +#pragma once + +#include "d3d8_resource.h" +#include "d3d8_surface.h" +#include "d3d8_volume.h" + +#include "d3d8_d3d9_util.h" + +#include +#include + +namespace dxvk { + + template + class D3D8BaseTexture : public D3D8Resource { + + public: + + constexpr static UINT CUBE_FACES = 6; + + using SubresourceType8 = typename SubresourceType::D3D8; + using SubresourceType9 = typename SubresourceType::D3D9; + + D3D8BaseTexture( + D3D8Device* pDevice, + Com&& pBaseTexture, + UINT SubresourceCount) + : D3D8Resource ( pDevice, std::move(pBaseTexture) ) { + m_subresources.resize(SubresourceCount, nullptr); + } + + ~D3D8BaseTexture() { + for (size_t i = 0; i < m_subresources.size(); i++) + if (m_subresources[i] != nullptr) + m_subresources[i] = nullptr; + } + + virtual IUnknown* GetInterface(REFIID riid) final override try { + return D3D8Resource::GetInterface(riid); + } catch (HRESULT err) { + if (riid == __uuidof(IDirect3DBaseTexture8)) + return this; + + throw err; + } + + void STDMETHODCALLTYPE PreLoad() final { + this->GetD3D9()->PreLoad(); + } + + DWORD STDMETHODCALLTYPE SetLOD(DWORD LODNew) final { + return this->GetD3D9()->SetLOD(LODNew); + } + + DWORD STDMETHODCALLTYPE GetLOD() final { + return this->GetD3D9()->GetLOD(); + } + + DWORD STDMETHODCALLTYPE GetLevelCount() final { + return this->GetD3D9()->GetLevelCount(); + } + + protected: + + HRESULT STDMETHODCALLTYPE GetSubresource(UINT Index, SubresourceType8** ppSubresource) { + InitReturnPtr(ppSubresource); + + if (unlikely(ppSubresource == nullptr)) + return D3DERR_INVALIDCALL; + + if (unlikely(Index >= m_subresources.size())) + return D3DERR_INVALIDCALL; + + if (m_subresources[Index] == nullptr) { + try { + Com subresource = LookupSubresource(Index); + + // Cache the subresource + m_subresources[Index] = new SubresourceType(this->m_parent, this, std::move(subresource)); + } catch (HRESULT res) { + return res; + } + } + + *ppSubresource = m_subresources[Index].ref(); + return D3D_OK; + } + + private: + + Com LookupSubresource(UINT Index) { + Com ptr = nullptr; + HRESULT res = D3DERR_INVALIDCALL; + if constexpr (std::is_same_v) { + res = this->GetD3D9()->GetSurfaceLevel(Index, &ptr); + } else if constexpr (std::is_same_v) { + res = this->GetD3D9()->GetVolumeLevel(Index, &ptr); + } else if constexpr (std::is_same_v) { + res = this->GetD3D9()->GetCubeMapSurface(d3d9::D3DCUBEMAP_FACES(Index % CUBE_FACES), Index / CUBE_FACES, &ptr); + } + if (FAILED(res)) + throw res; + return ptr; + } + + std::vector> m_subresources; + + }; + + using D3D8Texture2DBase = D3D8BaseTexture; + class D3D8Texture2D final : public D3D8Texture2DBase { + + public: + + D3D8Texture2D( + D3D8Device* pDevice, + Com&& pTexture) + : D3D8Texture2DBase(pDevice, std::move(pTexture), pTexture->GetLevelCount()) { + } + + D3DRESOURCETYPE STDMETHODCALLTYPE GetType() final { return D3DRTYPE_TEXTURE; } + + HRESULT STDMETHODCALLTYPE GetLevelDesc(UINT Level, D3DSURFACE_DESC* pDesc) { + if (unlikely(pDesc == nullptr)) + return D3DERR_INVALIDCALL; + + d3d9::D3DSURFACE_DESC surf; + HRESULT res = GetD3D9()->GetLevelDesc(Level, &surf); + + if (likely(SUCCEEDED(res))) + ConvertSurfaceDesc8(&surf, pDesc); + + return res; + } + + HRESULT STDMETHODCALLTYPE GetSurfaceLevel(UINT Level, IDirect3DSurface8** ppSurfaceLevel) { + return GetSubresource(Level, ppSurfaceLevel); + } + + HRESULT STDMETHODCALLTYPE LockRect(UINT Level, D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) { + return GetD3D9()->LockRect(Level, reinterpret_cast(pLockedRect), pRect, Flags); + } + + HRESULT STDMETHODCALLTYPE UnlockRect(UINT Level) { + return GetD3D9()->UnlockRect(Level); + } + + HRESULT STDMETHODCALLTYPE AddDirtyRect(CONST RECT* pDirtyRect) { + return GetD3D9()->AddDirtyRect(pDirtyRect); + } + + }; + + using D3D8Texture3DBase = D3D8BaseTexture; + class D3D8Texture3D final : public D3D8Texture3DBase { + + public: + + D3D8Texture3D( + D3D8Device* pDevice, + Com&& pVolumeTexture) + : D3D8Texture3DBase(pDevice, std::move(pVolumeTexture), pVolumeTexture->GetLevelCount()) {} + + D3DRESOURCETYPE STDMETHODCALLTYPE GetType() final { return D3DRTYPE_VOLUMETEXTURE; } + + HRESULT STDMETHODCALLTYPE GetLevelDesc(UINT Level, D3DVOLUME_DESC *pDesc) { + if (unlikely(pDesc == nullptr)) + return D3DERR_INVALIDCALL; + + d3d9::D3DVOLUME_DESC vol; + HRESULT res = GetD3D9()->GetLevelDesc(Level, &vol); + + if (likely(SUCCEEDED(res))) + ConvertVolumeDesc8(&vol, pDesc); + + return res; + } + + HRESULT STDMETHODCALLTYPE GetVolumeLevel(UINT Level, IDirect3DVolume8** ppVolumeLevel) { + return GetSubresource(Level, ppVolumeLevel); + } + + HRESULT STDMETHODCALLTYPE LockBox(UINT Level, D3DLOCKED_BOX* pLockedBox, CONST D3DBOX* pBox, DWORD Flags) { + return GetD3D9()->LockBox( + Level, + reinterpret_cast(pLockedBox), + reinterpret_cast(pBox), + Flags + ); + } + + HRESULT STDMETHODCALLTYPE UnlockBox(UINT Level) { + return GetD3D9()->UnlockBox(Level); + } + + HRESULT STDMETHODCALLTYPE AddDirtyBox(CONST D3DBOX* pDirtyBox) { + return GetD3D9()->AddDirtyBox(reinterpret_cast(pDirtyBox)); + } + + }; + + using D3D8TextureCubeBase = D3D8BaseTexture; + class D3D8TextureCube final : public D3D8TextureCubeBase { + + public: + + D3D8TextureCube( + D3D8Device* pDevice, + Com&& pTexture) + : D3D8TextureCubeBase(pDevice, std::move(pTexture), pTexture->GetLevelCount() * CUBE_FACES) { + } + + D3DRESOURCETYPE STDMETHODCALLTYPE GetType() final { return D3DRTYPE_CUBETEXTURE; } + + HRESULT STDMETHODCALLTYPE GetLevelDesc(UINT Level, D3DSURFACE_DESC* pDesc) { + if (unlikely(pDesc == nullptr)) + return D3DERR_INVALIDCALL; + + d3d9::D3DSURFACE_DESC surf; + HRESULT res = GetD3D9()->GetLevelDesc(Level, &surf); + + if (likely(SUCCEEDED(res))) + ConvertSurfaceDesc8(&surf, pDesc); + + return res; + } + + HRESULT STDMETHODCALLTYPE GetCubeMapSurface(D3DCUBEMAP_FACES Face, UINT Level, IDirect3DSurface8** ppSurfaceLevel) { + return GetSubresource((Level * CUBE_FACES) + Face, ppSurfaceLevel); + } + + HRESULT STDMETHODCALLTYPE LockRect( + D3DCUBEMAP_FACES Face, + UINT Level, + D3DLOCKED_RECT* pLockedRect, + const RECT* pRect, + DWORD Flags) { + return GetD3D9()->LockRect( + d3d9::D3DCUBEMAP_FACES(Face), + Level, + reinterpret_cast(pLockedRect), + pRect, + Flags); + } + + HRESULT STDMETHODCALLTYPE UnlockRect(D3DCUBEMAP_FACES Face, UINT Level) { + return GetD3D9()->UnlockRect(d3d9::D3DCUBEMAP_FACES(Face), Level); + } + + HRESULT STDMETHODCALLTYPE AddDirtyRect(D3DCUBEMAP_FACES Face, const RECT* pDirtyRect) { + return GetD3D9()->AddDirtyRect(d3d9::D3DCUBEMAP_FACES(Face), pDirtyRect); + } + }; } \ No newline at end of file diff --git a/src/d3d8/d3d8_volume.h b/src/d3d8/d3d8_volume.h index 2a47b99fd..3d871c38a 100644 --- a/src/d3d8/d3d8_volume.h +++ b/src/d3d8/d3d8_volume.h @@ -1,46 +1,46 @@ -#pragma once - -#include "d3d8_subresource.h" -#include "d3d8_d3d9_util.h" - -namespace dxvk { - - using D3D8VolumeBase = D3D8Subresource; - class D3D8Volume final : public D3D8VolumeBase { - - public: - - D3D8Volume( - D3D8Device* pDevice, - IDirect3DVolumeTexture8* pTexture, - Com&& pVolume) - : D3D8VolumeBase(pDevice, std::move(pVolume), pTexture) {} - - HRESULT STDMETHODCALLTYPE GetDesc(D3DVOLUME_DESC* pDesc) { - if (unlikely(pDesc == nullptr)) - return D3DERR_INVALIDCALL; - - d3d9::D3DVOLUME_DESC desc; - HRESULT res = GetD3D9()->GetDesc(&desc); - - if (likely(SUCCEEDED(res))) - ConvertVolumeDesc8(&desc, pDesc); - - return res; - } - - HRESULT STDMETHODCALLTYPE LockBox(D3DLOCKED_BOX* pLockedBox, CONST D3DBOX* pBox, DWORD Flags) final { - return GetD3D9()->LockBox( - reinterpret_cast(pLockedBox), - reinterpret_cast(pBox), - Flags - ); - } - - HRESULT STDMETHODCALLTYPE UnlockBox() final { - return GetD3D9()->UnlockBox(); - } - - }; - +#pragma once + +#include "d3d8_subresource.h" +#include "d3d8_d3d9_util.h" + +namespace dxvk { + + using D3D8VolumeBase = D3D8Subresource; + class D3D8Volume final : public D3D8VolumeBase { + + public: + + D3D8Volume( + D3D8Device* pDevice, + IDirect3DVolumeTexture8* pTexture, + Com&& pVolume) + : D3D8VolumeBase(pDevice, std::move(pVolume), pTexture) {} + + HRESULT STDMETHODCALLTYPE GetDesc(D3DVOLUME_DESC* pDesc) { + if (unlikely(pDesc == nullptr)) + return D3DERR_INVALIDCALL; + + d3d9::D3DVOLUME_DESC desc; + HRESULT res = GetD3D9()->GetDesc(&desc); + + if (likely(SUCCEEDED(res))) + ConvertVolumeDesc8(&desc, pDesc); + + return res; + } + + HRESULT STDMETHODCALLTYPE LockBox(D3DLOCKED_BOX* pLockedBox, CONST D3DBOX* pBox, DWORD Flags) final { + return GetD3D9()->LockBox( + reinterpret_cast(pLockedBox), + reinterpret_cast(pBox), + Flags + ); + } + + HRESULT STDMETHODCALLTYPE UnlockBox() final { + return GetD3D9()->UnlockBox(); + } + + }; + } \ No newline at end of file diff --git a/src/d3d9/d3d9_bridge.cpp b/src/d3d9/d3d9_bridge.cpp index 5e43117d5..40e3fa62d 100644 --- a/src/d3d9/d3d9_bridge.cpp +++ b/src/d3d9/d3d9_bridge.cpp @@ -1,111 +1,111 @@ - -#include "d3d9_device.h" -#include "d3d9_interface.h" -#include "d3d9_bridge.h" -#include "d3d9_swapchain.h" -#include "d3d9_surface.h" - -namespace dxvk { - - DxvkD3D8Bridge::DxvkD3D8Bridge(D3D9DeviceEx* pDevice) - : m_device(pDevice) { - } - - DxvkD3D8Bridge::~DxvkD3D8Bridge() { - } - - ULONG STDMETHODCALLTYPE DxvkD3D8Bridge::AddRef() { - return m_device->AddRef(); - } - - ULONG STDMETHODCALLTYPE DxvkD3D8Bridge::Release() { - return m_device->Release(); - } - - HRESULT STDMETHODCALLTYPE DxvkD3D8Bridge::QueryInterface( - REFIID riid, - void** ppvObject) { - return m_device->QueryInterface(riid, ppvObject); - } - - void DxvkD3D8Bridge::SetAPIName(const char* name) { - m_device->m_implicitSwapchain->SetApiName(name); - } - - HRESULT DxvkD3D8Bridge::UpdateTextureFromBuffer( - IDirect3DSurface9* pDestSurface, - IDirect3DSurface9* pSrcSurface, - const RECT* pSrcRect, - const POINT* pDestPoint) { - auto lock = m_device->LockDevice(); - - D3D9Surface* dst = static_cast(pDestSurface); - D3D9Surface* src = static_cast(pSrcSurface); - - if (unlikely(dst == nullptr || src == nullptr)) - return D3DERR_INVALIDCALL; - - D3D9CommonTexture* srcTextureInfo = src->GetCommonTexture(); - D3D9CommonTexture* dstTextureInfo = dst->GetCommonTexture(); - - VkOffset3D srcOffset = { 0u, 0u, 0u }; - VkOffset3D dstOffset = { 0u, 0u, 0u }; - VkExtent3D texLevelExtent = srcTextureInfo->GetExtentMip(src->GetSubresource()); - VkExtent3D extent = texLevelExtent; - - srcOffset = { pSrcRect->left, - pSrcRect->top, - 0u }; - - extent = { uint32_t(pSrcRect->right - pSrcRect->left), uint32_t(pSrcRect->bottom - pSrcRect->top), 1 }; - - // TODO: Validate extents like in D3D9DeviceEx::UpdateSurface - - dstOffset = { pDestPoint->x, - pDestPoint->y, - 0u }; - - - m_device->UpdateTextureFromBuffer( - srcTextureInfo, dstTextureInfo, - src->GetSubresource(), dst->GetSubresource(), - srcOffset, extent, dstOffset - ); - - dstTextureInfo->SetNeedsReadback(dst->GetSubresource(), true); - - if (dstTextureInfo->IsAutomaticMip()) - m_device->MarkTextureMipsDirty(dstTextureInfo); - - return D3D_OK; - } - - DxvkD3D8InterfaceBridge::DxvkD3D8InterfaceBridge(D3D9InterfaceEx* pObject) - : m_interface(pObject) { - } - - DxvkD3D8InterfaceBridge::~DxvkD3D8InterfaceBridge() { - } - - ULONG STDMETHODCALLTYPE DxvkD3D8InterfaceBridge::AddRef() { - return m_interface->AddRef(); - } - - ULONG STDMETHODCALLTYPE DxvkD3D8InterfaceBridge::Release() { - return m_interface->Release(); - } - - HRESULT STDMETHODCALLTYPE DxvkD3D8InterfaceBridge::QueryInterface( - REFIID riid, - void** ppvObject) { - return m_interface->QueryInterface(riid, ppvObject); - } - - void DxvkD3D8InterfaceBridge::SetD3D8CompatibilityMode(const bool compatMode) { - m_interface->SetD3D8CompatibilityMode(compatMode); - } - - const Config* DxvkD3D8InterfaceBridge::GetConfig() const { - return &m_interface->GetInstance()->config(); - } -} + +#include "d3d9_device.h" +#include "d3d9_interface.h" +#include "d3d9_bridge.h" +#include "d3d9_swapchain.h" +#include "d3d9_surface.h" + +namespace dxvk { + + DxvkD3D8Bridge::DxvkD3D8Bridge(D3D9DeviceEx* pDevice) + : m_device(pDevice) { + } + + DxvkD3D8Bridge::~DxvkD3D8Bridge() { + } + + ULONG STDMETHODCALLTYPE DxvkD3D8Bridge::AddRef() { + return m_device->AddRef(); + } + + ULONG STDMETHODCALLTYPE DxvkD3D8Bridge::Release() { + return m_device->Release(); + } + + HRESULT STDMETHODCALLTYPE DxvkD3D8Bridge::QueryInterface( + REFIID riid, + void** ppvObject) { + return m_device->QueryInterface(riid, ppvObject); + } + + void DxvkD3D8Bridge::SetAPIName(const char* name) { + m_device->m_implicitSwapchain->SetApiName(name); + } + + HRESULT DxvkD3D8Bridge::UpdateTextureFromBuffer( + IDirect3DSurface9* pDestSurface, + IDirect3DSurface9* pSrcSurface, + const RECT* pSrcRect, + const POINT* pDestPoint) { + auto lock = m_device->LockDevice(); + + D3D9Surface* dst = static_cast(pDestSurface); + D3D9Surface* src = static_cast(pSrcSurface); + + if (unlikely(dst == nullptr || src == nullptr)) + return D3DERR_INVALIDCALL; + + D3D9CommonTexture* srcTextureInfo = src->GetCommonTexture(); + D3D9CommonTexture* dstTextureInfo = dst->GetCommonTexture(); + + VkOffset3D srcOffset = { 0u, 0u, 0u }; + VkOffset3D dstOffset = { 0u, 0u, 0u }; + VkExtent3D texLevelExtent = srcTextureInfo->GetExtentMip(src->GetSubresource()); + VkExtent3D extent = texLevelExtent; + + srcOffset = { pSrcRect->left, + pSrcRect->top, + 0u }; + + extent = { uint32_t(pSrcRect->right - pSrcRect->left), uint32_t(pSrcRect->bottom - pSrcRect->top), 1 }; + + // TODO: Validate extents like in D3D9DeviceEx::UpdateSurface + + dstOffset = { pDestPoint->x, + pDestPoint->y, + 0u }; + + + m_device->UpdateTextureFromBuffer( + srcTextureInfo, dstTextureInfo, + src->GetSubresource(), dst->GetSubresource(), + srcOffset, extent, dstOffset + ); + + dstTextureInfo->SetNeedsReadback(dst->GetSubresource(), true); + + if (dstTextureInfo->IsAutomaticMip()) + m_device->MarkTextureMipsDirty(dstTextureInfo); + + return D3D_OK; + } + + DxvkD3D8InterfaceBridge::DxvkD3D8InterfaceBridge(D3D9InterfaceEx* pObject) + : m_interface(pObject) { + } + + DxvkD3D8InterfaceBridge::~DxvkD3D8InterfaceBridge() { + } + + ULONG STDMETHODCALLTYPE DxvkD3D8InterfaceBridge::AddRef() { + return m_interface->AddRef(); + } + + ULONG STDMETHODCALLTYPE DxvkD3D8InterfaceBridge::Release() { + return m_interface->Release(); + } + + HRESULT STDMETHODCALLTYPE DxvkD3D8InterfaceBridge::QueryInterface( + REFIID riid, + void** ppvObject) { + return m_interface->QueryInterface(riid, ppvObject); + } + + void DxvkD3D8InterfaceBridge::SetD3D8CompatibilityMode(const bool compatMode) { + m_interface->SetD3D8CompatibilityMode(compatMode); + } + + const Config* DxvkD3D8InterfaceBridge::GetConfig() const { + return &m_interface->GetInstance()->config(); + } +} diff --git a/src/d3d9/d3d9_bridge.h b/src/d3d9/d3d9_bridge.h index 4285aa0e2..6bde543c2 100644 --- a/src/d3d9/d3d9_bridge.h +++ b/src/d3d9/d3d9_bridge.h @@ -1,117 +1,117 @@ -#pragma once - -#include -#include "../util/config/config.h" - -/** - * 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. - */ - -/** - * \brief D3D9 device interface for D3D8 interop - */ -MIDL_INTERFACE("D3D9D3D8-42A9-4C1E-AA97-BEEFCAFE2000") -IDxvkD3D8Bridge : public IUnknown { - - // D3D8 keeps D3D9 objects contained in a namespace. - #ifdef DXVK_D3D9_NAMESPACE - using IDirect3DSurface9 = d3d9::IDirect3DSurface9; - #endif - - /** - * \brief Changes the API name displayed on the HUD - * - * \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 - * \param [in] pDestPoint Destination (top-left) point - */ - virtual HRESULT UpdateTextureFromBuffer( - IDirect3DSurface9* pDestSurface, - IDirect3DSurface9* pSrcSurface, - const RECT* pSrcRect, - const POINT* pDestPoint) = 0; -}; - -/** - * \brief D3D9 instance interface for D3D8 interop - */ -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; -}; - -#ifndef _MSC_VER -__CRT_UUID_DECL(IDxvkD3D8Bridge, 0xD3D9D3D8, 0x42A9, 0x4C1E, 0xAA, 0x97, 0xBE, 0xEF, 0xCA, 0xFE, 0x20, 0x00); -__CRT_UUID_DECL(IDxvkD3D8InterfaceBridge, 0xD3D9D3D8, 0xA407, 0x773E, 0x18, 0xE9, 0xCA, 0xFE, 0xBE, 0xEF, 0x30, 0x00); -#endif - -namespace dxvk { - - class D3D9DeviceEx; - class D3D9InterfaceEx; - - class DxvkD3D8Bridge : public IDxvkD3D8Bridge { - public: - DxvkD3D8Bridge(D3D9DeviceEx* pDevice); - ~DxvkD3D8Bridge(); - - ULONG STDMETHODCALLTYPE AddRef(); - ULONG STDMETHODCALLTYPE Release(); - HRESULT STDMETHODCALLTYPE QueryInterface( - REFIID riid, - void** ppvObject); - - void SetAPIName(const char* name); - - HRESULT UpdateTextureFromBuffer( - IDirect3DSurface9* pDestSurface, - IDirect3DSurface9* pSrcSurface, - const RECT* pSrcRect, - const POINT* pDestPoint); - - private: - D3D9DeviceEx* m_device; - }; - - class DxvkD3D8InterfaceBridge : public IDxvkD3D8InterfaceBridge { - public: - DxvkD3D8InterfaceBridge(D3D9InterfaceEx* pObject); - ~DxvkD3D8InterfaceBridge(); - - ULONG STDMETHODCALLTYPE AddRef(); - ULONG STDMETHODCALLTYPE Release(); - HRESULT STDMETHODCALLTYPE QueryInterface( - REFIID riid, - void** ppvObject); - - void SetD3D8CompatibilityMode(const bool compatMode); - - const Config* GetConfig() const; - - protected: - D3D9InterfaceEx* m_interface; - }; -} +#pragma once + +#include +#include "../util/config/config.h" + +/** + * 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. + */ + +/** + * \brief D3D9 device interface for D3D8 interop + */ +MIDL_INTERFACE("D3D9D3D8-42A9-4C1E-AA97-BEEFCAFE2000") +IDxvkD3D8Bridge : public IUnknown { + + // D3D8 keeps D3D9 objects contained in a namespace. + #ifdef DXVK_D3D9_NAMESPACE + using IDirect3DSurface9 = d3d9::IDirect3DSurface9; + #endif + + /** + * \brief Changes the API name displayed on the HUD + * + * \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 + * \param [in] pDestPoint Destination (top-left) point + */ + virtual HRESULT UpdateTextureFromBuffer( + IDirect3DSurface9* pDestSurface, + IDirect3DSurface9* pSrcSurface, + const RECT* pSrcRect, + const POINT* pDestPoint) = 0; +}; + +/** + * \brief D3D9 instance interface for D3D8 interop + */ +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; +}; + +#ifndef _MSC_VER +__CRT_UUID_DECL(IDxvkD3D8Bridge, 0xD3D9D3D8, 0x42A9, 0x4C1E, 0xAA, 0x97, 0xBE, 0xEF, 0xCA, 0xFE, 0x20, 0x00); +__CRT_UUID_DECL(IDxvkD3D8InterfaceBridge, 0xD3D9D3D8, 0xA407, 0x773E, 0x18, 0xE9, 0xCA, 0xFE, 0xBE, 0xEF, 0x30, 0x00); +#endif + +namespace dxvk { + + class D3D9DeviceEx; + class D3D9InterfaceEx; + + class DxvkD3D8Bridge : public IDxvkD3D8Bridge { + public: + DxvkD3D8Bridge(D3D9DeviceEx* pDevice); + ~DxvkD3D8Bridge(); + + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject); + + void SetAPIName(const char* name); + + HRESULT UpdateTextureFromBuffer( + IDirect3DSurface9* pDestSurface, + IDirect3DSurface9* pSrcSurface, + const RECT* pSrcRect, + const POINT* pDestPoint); + + private: + D3D9DeviceEx* m_device; + }; + + class DxvkD3D8InterfaceBridge : public IDxvkD3D8InterfaceBridge { + public: + DxvkD3D8InterfaceBridge(D3D9InterfaceEx* pObject); + ~DxvkD3D8InterfaceBridge(); + + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject); + + void SetD3D8CompatibilityMode(const bool compatMode); + + const Config* GetConfig() const; + + protected: + D3D9InterfaceEx* m_interface; + }; +}