mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-02-08 01:54:15 +01:00
[d3d8] Unify source file endline delimiters
This commit is contained in:
parent
475bf4e9c1
commit
8ead28e481
@ -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;
|
||||
|
||||
}
|
@ -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 <utility>
|
||||
|
||||
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 <utility>
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 <typename D3D9, typename D3D8>
|
||||
class D3D8DeviceChild : public D3D8WrappedObject<D3D9, D3D8> {
|
||||
|
||||
public:
|
||||
|
||||
D3D8DeviceChild(D3D8Device* pDevice, Com<D3D9>&& Object)
|
||||
: D3D8WrappedObject<D3D9, D3D8>(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<IDirect3DDevice8*>(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 <typename D3D9, typename D3D8>
|
||||
class D3D8DeviceChild : public D3D8WrappedObject<D3D9, D3D8> {
|
||||
|
||||
public:
|
||||
|
||||
D3D8DeviceChild(D3D8Device* pDevice, Com<D3D9>&& Object)
|
||||
: D3D8WrappedObject<D3D9, D3D8>(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<IDirect3DDevice8*>(m_parent);
|
||||
}
|
||||
|
||||
D3D8Device* GetParent() {
|
||||
return m_parent;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
D3D8Device* m_parent;
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -1,153 +1,153 @@
|
||||
#include "d3d8_interface.h"
|
||||
|
||||
#include "d3d8_device.h"
|
||||
#include "d3d8_texture.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
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<d3d9::IDirect3DDevice9> 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 <cstring>
|
||||
|
||||
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<d3d9::IDirect3DDevice9> 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;
|
||||
}
|
||||
|
||||
}
|
@ -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<IDirect3D8> {
|
||||
|
||||
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<UINT> m_adapterModeCounts;
|
||||
std::vector<std::vector<d3d9::D3DDISPLAYMODE>> m_adapterModes;
|
||||
|
||||
Com<d3d9::IDirect3D9> m_d3d9;
|
||||
Com<IDxvkD3D8InterfaceBridge> 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<IDirect3D8> {
|
||||
|
||||
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<UINT> m_adapterModeCounts;
|
||||
std::vector<std::vector<d3d9::D3DDISPLAYMODE>> m_adapterModes;
|
||||
|
||||
Com<d3d9::IDirect3D9> m_d3d9;
|
||||
Com<IDxvkD3D8InterfaceBridge> m_bridge;
|
||||
D3D8Options m_d3d8Options;
|
||||
};
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<std::pair<D3DVSDE_REGISTER, D3DVSDT_TYPE>> 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<std::string>("d3d8.forceVsDecl", "");
|
||||
batching = config.getOption<bool> ("d3d8.batching", batching);
|
||||
placeP8InScratch = config.getOption<bool> ("d3d8.placeP8InScratch", placeP8InScratch);
|
||||
forceLegacyDiscard = config.getOption<bool> ("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<std::pair<D3DVSDE_REGISTER, D3DVSDT_TYPE>> 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<std::string>("d3d8.forceVsDecl", "");
|
||||
batching = config.getOption<bool> ("d3d8.batching", batching);
|
||||
placeP8InScratch = config.getOption<bool> ("d3d8.placeP8InScratch", placeP8InScratch);
|
||||
forceLegacyDiscard = config.getOption<bool> ("d3d8.forceLegacyDiscard", forceLegacyDiscard);
|
||||
|
||||
parseVsDecl(forceVsDeclStr);
|
||||
}
|
||||
|
||||
void parseVsDecl(const std::string& decl);
|
||||
};
|
||||
}
|
||||
|
@ -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 <typename D3D9, typename D3D8>
|
||||
class D3D8Resource : public D3D8DeviceChild<D3D9, D3D8> {
|
||||
|
||||
public:
|
||||
|
||||
D3D8Resource(D3D8Device* pDevice, Com<D3D9>&& Object)
|
||||
: D3D8DeviceChild<D3D9, D3D8>(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<IUnknown*>(
|
||||
reinterpret_cast<const IUnknown*>(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<UINT*>(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<D3D9, D3D8>::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 <typename D3D9, typename D3D8>
|
||||
class D3D8Resource : public D3D8DeviceChild<D3D9, D3D8> {
|
||||
|
||||
public:
|
||||
|
||||
D3D8Resource(D3D8Device* pDevice, Com<D3D9>&& Object)
|
||||
: D3D8DeviceChild<D3D9, D3D8>(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<IUnknown*>(
|
||||
reinterpret_cast<const IUnknown*>(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<UINT*>(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<D3D9, D3D8>::GetInterface(riid);
|
||||
} catch (HRESULT err) {
|
||||
if (riid == __uuidof(IDirect3DResource8))
|
||||
return this;
|
||||
|
||||
throw err;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
DWORD m_priority;
|
||||
|
||||
private:
|
||||
|
||||
ComPrivateData m_privateData;
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
@ -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 <array>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
struct D3D8StateCapture {
|
||||
bool vs : 1;
|
||||
bool ps : 1;
|
||||
bool indices : 1;
|
||||
bool swvp : 1;
|
||||
|
||||
bit::bitset<d8caps::MAX_TEXTURE_STAGES> textures;
|
||||
bit::bitset<d8caps::MAX_STREAMS> 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<d3d9::IDirect3DStateBlock9>&& 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<d3d9::IDirect3DStateBlock9>&& 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<d3d9::IDirect3DStateBlock9> 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<IDirect3DBaseTexture8*, d8caps::MAX_TEXTURE_STAGES> m_textures; // textures
|
||||
std::array<D3D8VBOP, d8caps::MAX_STREAMS> 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 <array>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
struct D3D8StateCapture {
|
||||
bool vs : 1;
|
||||
bool ps : 1;
|
||||
bool indices : 1;
|
||||
bool swvp : 1;
|
||||
|
||||
bit::bitset<d8caps::MAX_TEXTURE_STAGES> textures;
|
||||
bit::bitset<d8caps::MAX_STREAMS> 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<d3d9::IDirect3DStateBlock9>&& 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<d3d9::IDirect3DStateBlock9>&& 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<d3d9::IDirect3DStateBlock9> 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<IDirect3DBaseTexture8*, d8caps::MAX_TEXTURE_STAGES> m_textures; // textures
|
||||
std::array<D3D8VBOP, d8caps::MAX_STREAMS> m_streams; // stream data
|
||||
|
||||
IDirect3DIndexBuffer8* m_indices = nullptr; // indices
|
||||
UINT m_baseVertexIndex; // indices
|
||||
|
||||
bool m_isSWVP; // D3DRS_SOFTWAREVERTEXPROCESSING
|
||||
};
|
||||
|
||||
|
||||
}
|
@ -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<d3d9::IDirect3DSurface9, IDirect3DSurface8>;
|
||||
class D3D8Surface final : public D3D8SurfaceBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D8Surface(
|
||||
D3D8Device* pDevice,
|
||||
IDirect3DBaseTexture8* pTexture,
|
||||
Com<d3d9::IDirect3DSurface9>&& pSurface)
|
||||
: D3D8SurfaceBase (pDevice, std::move(pSurface), pTexture) {
|
||||
}
|
||||
|
||||
// A surface does not need to be attached to a texture
|
||||
D3D8Surface(
|
||||
D3D8Device* pDevice,
|
||||
Com<d3d9::IDirect3DSurface9>&& 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<d3d9::IDirect3DSurface9> GetBlitImage() {
|
||||
if (unlikely(m_blitImage == nullptr)) {
|
||||
m_blitImage = CreateBlitImage();
|
||||
}
|
||||
|
||||
return m_blitImage;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
Com<d3d9::IDirect3DSurface9> CreateBlitImage();
|
||||
|
||||
Com<d3d9::IDirect3DSurface9> 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<d3d9::IDirect3DSurface9, IDirect3DSurface8>;
|
||||
class D3D8Surface final : public D3D8SurfaceBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D8Surface(
|
||||
D3D8Device* pDevice,
|
||||
IDirect3DBaseTexture8* pTexture,
|
||||
Com<d3d9::IDirect3DSurface9>&& pSurface)
|
||||
: D3D8SurfaceBase (pDevice, std::move(pSurface), pTexture) {
|
||||
}
|
||||
|
||||
// A surface does not need to be attached to a texture
|
||||
D3D8Surface(
|
||||
D3D8Device* pDevice,
|
||||
Com<d3d9::IDirect3DSurface9>&& 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<d3d9::IDirect3DSurface9> GetBlitImage() {
|
||||
if (unlikely(m_blitImage == nullptr)) {
|
||||
m_blitImage = CreateBlitImage();
|
||||
}
|
||||
|
||||
return m_blitImage;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
Com<d3d9::IDirect3DSurface9> CreateBlitImage();
|
||||
|
||||
Com<d3d9::IDirect3DSurface9> m_blitImage = nullptr;
|
||||
|
||||
};
|
||||
}
|
@ -1,254 +1,254 @@
|
||||
#pragma once
|
||||
|
||||
#include "d3d8_resource.h"
|
||||
#include "d3d8_surface.h"
|
||||
#include "d3d8_volume.h"
|
||||
|
||||
#include "d3d8_d3d9_util.h"
|
||||
|
||||
#include <vector>
|
||||
#include <new>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
template <typename SubresourceType, typename D3D9, typename D3D8>
|
||||
class D3D8BaseTexture : public D3D8Resource<D3D9, D3D8> {
|
||||
|
||||
public:
|
||||
|
||||
constexpr static UINT CUBE_FACES = 6;
|
||||
|
||||
using SubresourceType8 = typename SubresourceType::D3D8;
|
||||
using SubresourceType9 = typename SubresourceType::D3D9;
|
||||
|
||||
D3D8BaseTexture(
|
||||
D3D8Device* pDevice,
|
||||
Com<D3D9>&& pBaseTexture,
|
||||
UINT SubresourceCount)
|
||||
: D3D8Resource<D3D9, D3D8> ( 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<D3D9, D3D8>::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<SubresourceType9> 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<SubresourceType9> LookupSubresource(UINT Index) {
|
||||
Com<SubresourceType9> ptr = nullptr;
|
||||
HRESULT res = D3DERR_INVALIDCALL;
|
||||
if constexpr (std::is_same_v<D3D8, IDirect3DTexture8>) {
|
||||
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>) {
|
||||
res = this->GetD3D9()->GetCubeMapSurface(d3d9::D3DCUBEMAP_FACES(Index % CUBE_FACES), Index / CUBE_FACES, &ptr);
|
||||
}
|
||||
if (FAILED(res))
|
||||
throw res;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
std::vector<Com<SubresourceType, false>> m_subresources;
|
||||
|
||||
};
|
||||
|
||||
using D3D8Texture2DBase = D3D8BaseTexture<D3D8Surface, d3d9::IDirect3DTexture9, IDirect3DTexture8>;
|
||||
class D3D8Texture2D final : public D3D8Texture2DBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D8Texture2D(
|
||||
D3D8Device* pDevice,
|
||||
Com<d3d9::IDirect3DTexture9>&& 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<d3d9::D3DLOCKED_RECT*>(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<D3D8Volume, d3d9::IDirect3DVolumeTexture9, IDirect3DVolumeTexture8>;
|
||||
class D3D8Texture3D final : public D3D8Texture3DBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D8Texture3D(
|
||||
D3D8Device* pDevice,
|
||||
Com<d3d9::IDirect3DVolumeTexture9>&& 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<d3d9::D3DLOCKED_BOX*>(pLockedBox),
|
||||
reinterpret_cast<const d3d9::D3DBOX*>(pBox),
|
||||
Flags
|
||||
);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE UnlockBox(UINT Level) {
|
||||
return GetD3D9()->UnlockBox(Level);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE AddDirtyBox(CONST D3DBOX* pDirtyBox) {
|
||||
return GetD3D9()->AddDirtyBox(reinterpret_cast<const d3d9::D3DBOX*>(pDirtyBox));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
using D3D8TextureCubeBase = D3D8BaseTexture<D3D8Surface, d3d9::IDirect3DCubeTexture9, IDirect3DCubeTexture8>;
|
||||
class D3D8TextureCube final : public D3D8TextureCubeBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D8TextureCube(
|
||||
D3D8Device* pDevice,
|
||||
Com<d3d9::IDirect3DCubeTexture9>&& 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<d3d9::D3DLOCKED_RECT*>(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 <vector>
|
||||
#include <new>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
template <typename SubresourceType, typename D3D9, typename D3D8>
|
||||
class D3D8BaseTexture : public D3D8Resource<D3D9, D3D8> {
|
||||
|
||||
public:
|
||||
|
||||
constexpr static UINT CUBE_FACES = 6;
|
||||
|
||||
using SubresourceType8 = typename SubresourceType::D3D8;
|
||||
using SubresourceType9 = typename SubresourceType::D3D9;
|
||||
|
||||
D3D8BaseTexture(
|
||||
D3D8Device* pDevice,
|
||||
Com<D3D9>&& pBaseTexture,
|
||||
UINT SubresourceCount)
|
||||
: D3D8Resource<D3D9, D3D8> ( 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<D3D9, D3D8>::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<SubresourceType9> 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<SubresourceType9> LookupSubresource(UINT Index) {
|
||||
Com<SubresourceType9> ptr = nullptr;
|
||||
HRESULT res = D3DERR_INVALIDCALL;
|
||||
if constexpr (std::is_same_v<D3D8, IDirect3DTexture8>) {
|
||||
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>) {
|
||||
res = this->GetD3D9()->GetCubeMapSurface(d3d9::D3DCUBEMAP_FACES(Index % CUBE_FACES), Index / CUBE_FACES, &ptr);
|
||||
}
|
||||
if (FAILED(res))
|
||||
throw res;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
std::vector<Com<SubresourceType, false>> m_subresources;
|
||||
|
||||
};
|
||||
|
||||
using D3D8Texture2DBase = D3D8BaseTexture<D3D8Surface, d3d9::IDirect3DTexture9, IDirect3DTexture8>;
|
||||
class D3D8Texture2D final : public D3D8Texture2DBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D8Texture2D(
|
||||
D3D8Device* pDevice,
|
||||
Com<d3d9::IDirect3DTexture9>&& 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<d3d9::D3DLOCKED_RECT*>(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<D3D8Volume, d3d9::IDirect3DVolumeTexture9, IDirect3DVolumeTexture8>;
|
||||
class D3D8Texture3D final : public D3D8Texture3DBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D8Texture3D(
|
||||
D3D8Device* pDevice,
|
||||
Com<d3d9::IDirect3DVolumeTexture9>&& 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<d3d9::D3DLOCKED_BOX*>(pLockedBox),
|
||||
reinterpret_cast<const d3d9::D3DBOX*>(pBox),
|
||||
Flags
|
||||
);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE UnlockBox(UINT Level) {
|
||||
return GetD3D9()->UnlockBox(Level);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE AddDirtyBox(CONST D3DBOX* pDirtyBox) {
|
||||
return GetD3D9()->AddDirtyBox(reinterpret_cast<const d3d9::D3DBOX*>(pDirtyBox));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
using D3D8TextureCubeBase = D3D8BaseTexture<D3D8Surface, d3d9::IDirect3DCubeTexture9, IDirect3DCubeTexture8>;
|
||||
class D3D8TextureCube final : public D3D8TextureCubeBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D8TextureCube(
|
||||
D3D8Device* pDevice,
|
||||
Com<d3d9::IDirect3DCubeTexture9>&& 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<d3d9::D3DLOCKED_RECT*>(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);
|
||||
}
|
||||
};
|
||||
}
|
@ -1,46 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include "d3d8_subresource.h"
|
||||
#include "d3d8_d3d9_util.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
using D3D8VolumeBase = D3D8Subresource<d3d9::IDirect3DVolume9, IDirect3DVolume8>;
|
||||
class D3D8Volume final : public D3D8VolumeBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D8Volume(
|
||||
D3D8Device* pDevice,
|
||||
IDirect3DVolumeTexture8* pTexture,
|
||||
Com<d3d9::IDirect3DVolume9>&& 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<d3d9::D3DLOCKED_BOX*>(pLockedBox),
|
||||
reinterpret_cast<const d3d9::D3DBOX*>(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<d3d9::IDirect3DVolume9, IDirect3DVolume8>;
|
||||
class D3D8Volume final : public D3D8VolumeBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D8Volume(
|
||||
D3D8Device* pDevice,
|
||||
IDirect3DVolumeTexture8* pTexture,
|
||||
Com<d3d9::IDirect3DVolume9>&& 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<d3d9::D3DLOCKED_BOX*>(pLockedBox),
|
||||
reinterpret_cast<const d3d9::D3DBOX*>(pBox),
|
||||
Flags
|
||||
);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE UnlockBox() final {
|
||||
return GetD3D9()->UnlockBox();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -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<D3D9Surface*>(pDestSurface);
|
||||
D3D9Surface* src = static_cast<D3D9Surface*>(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<D3D9Surface*>(pDestSurface);
|
||||
D3D9Surface* src = static_cast<D3D9Surface*>(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();
|
||||
}
|
||||
}
|
||||
|
@ -1,117 +1,117 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#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 <windows.h>
|
||||
#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;
|
||||
};
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user