2019-12-16 04:28:01 +01:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "d3d9_device.h"
|
|
|
|
#include "d3d9_surface.h"
|
|
|
|
#include "d3d9_volume.h"
|
|
|
|
#include "d3d9_util.h"
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
#include <list>
|
|
|
|
#include <mutex>
|
|
|
|
#include <new>
|
2020-03-02 17:11:07 +01:00
|
|
|
#include <type_traits>
|
2019-12-16 04:28:01 +01:00
|
|
|
|
|
|
|
namespace dxvk {
|
|
|
|
|
|
|
|
template <typename SubresourceType, typename... Base>
|
|
|
|
class D3D9BaseTexture : public D3D9Resource<Base...> {
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
2020-03-02 17:11:07 +01:00
|
|
|
using SubresourceData = std::aligned_storage_t<sizeof(SubresourceType), alignof(SubresourceType)>;
|
2019-12-16 04:28:01 +01:00
|
|
|
|
|
|
|
D3D9BaseTexture(
|
|
|
|
D3D9DeviceEx* pDevice,
|
|
|
|
const D3D9_COMMON_TEXTURE_DESC* pDesc,
|
2020-01-17 11:54:41 +01:00
|
|
|
D3DRESOURCETYPE ResourceType)
|
2019-12-16 04:28:01 +01:00
|
|
|
: D3D9Resource<Base...> ( pDevice )
|
2020-01-17 11:54:41 +01:00
|
|
|
, m_texture ( pDevice, pDesc, ResourceType )
|
2020-05-27 10:06:15 +02:00
|
|
|
, m_lod ( 0 ) {
|
2019-12-16 04:28:01 +01:00
|
|
|
const uint32_t arraySlices = m_texture.Desc()->ArraySize;
|
|
|
|
const uint32_t mipLevels = m_texture.Desc()->MipLevels;
|
|
|
|
|
|
|
|
m_subresources.resize(arraySlices * mipLevels);
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < arraySlices; i++) {
|
|
|
|
for (uint32_t j = 0; j < mipLevels; j++) {
|
|
|
|
const uint32_t subresource = m_texture.CalcSubresource(i, j);
|
|
|
|
|
|
|
|
SubresourceType* subObj = this->GetSubresource(subresource);
|
|
|
|
|
|
|
|
new (subObj) SubresourceType(
|
|
|
|
pDevice,
|
|
|
|
&m_texture,
|
|
|
|
i, j,
|
|
|
|
this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
~D3D9BaseTexture() {
|
|
|
|
for (uint32_t i = 0; i < m_subresources.size(); i++) {
|
|
|
|
SubresourceType* subObj = this->GetSubresource(i);
|
|
|
|
subObj->~SubresourceType();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD STDMETHODCALLTYPE SetLOD(DWORD LODNew) final {
|
|
|
|
DWORD oldLod = m_lod;
|
2021-11-12 00:52:35 +01:00
|
|
|
m_lod = std::min<DWORD>(LODNew, m_texture.Desc()->MipLevels - 1);
|
2019-12-16 04:28:01 +01:00
|
|
|
|
2021-11-12 00:52:35 +01:00
|
|
|
if (m_lod != oldLod) {
|
|
|
|
m_texture.CreateSampleView(LODNew);
|
|
|
|
if (this->GetPrivateRefCount() > 0)
|
|
|
|
this->m_parent->MarkTextureBindingDirty(this);
|
|
|
|
}
|
2019-12-16 04:28:01 +01:00
|
|
|
|
|
|
|
return oldLod;
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD STDMETHODCALLTYPE GetLOD() final {
|
|
|
|
return m_lod;
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD STDMETHODCALLTYPE GetLevelCount() final {
|
2020-05-26 14:11:24 +02:00
|
|
|
return m_texture.ExposedMipLevels();
|
2019-12-16 04:28:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE SetAutoGenFilterType(D3DTEXTUREFILTERTYPE FilterType) final {
|
2020-05-27 10:06:15 +02:00
|
|
|
if (unlikely(FilterType == D3DTEXF_NONE))
|
|
|
|
return D3DERR_INVALIDCALL;
|
|
|
|
|
2020-06-06 21:17:13 +02:00
|
|
|
auto lock = this->m_parent->LockDevice();
|
|
|
|
|
2020-05-27 10:06:15 +02:00
|
|
|
m_texture.SetMipFilter(FilterType);
|
2021-08-07 15:53:55 +02:00
|
|
|
if (m_texture.IsAutomaticMip())
|
|
|
|
this->m_parent->MarkTextureMipsDirty(&m_texture);
|
2019-12-16 04:28:01 +01:00
|
|
|
return D3D_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
D3DTEXTUREFILTERTYPE STDMETHODCALLTYPE GetAutoGenFilterType() final {
|
2020-05-27 10:06:15 +02:00
|
|
|
return m_texture.GetMipFilter();
|
2019-12-16 04:28:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void STDMETHODCALLTYPE GenerateMipSubLevels() final {
|
2020-05-26 19:42:46 +02:00
|
|
|
if (!m_texture.NeedsMipGen())
|
|
|
|
return;
|
|
|
|
|
2020-06-06 21:17:13 +02:00
|
|
|
auto lock = this->m_parent->LockDevice();
|
|
|
|
|
2020-05-26 19:48:42 +02:00
|
|
|
this->m_parent->MarkTextureMipsUnDirty(&m_texture);
|
2020-05-26 19:50:34 +02:00
|
|
|
this->m_parent->EmitGenerateMips(&m_texture);
|
2019-12-16 04:28:01 +01:00
|
|
|
}
|
|
|
|
|
2020-06-06 21:10:22 +02:00
|
|
|
void STDMETHODCALLTYPE PreLoad() final {
|
|
|
|
m_texture.PreLoadAll();
|
|
|
|
}
|
|
|
|
|
2019-12-16 04:28:01 +01:00
|
|
|
D3D9CommonTexture* GetCommonTexture() {
|
|
|
|
return &m_texture;
|
|
|
|
}
|
|
|
|
|
|
|
|
SubresourceType* GetSubresource(UINT Subresource) {
|
|
|
|
return reinterpret_cast<SubresourceType*>(&m_subresources[Subresource]);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
|
|
D3D9CommonTexture m_texture;
|
|
|
|
|
|
|
|
std::vector<SubresourceData> m_subresources;
|
|
|
|
|
2021-07-24 19:59:58 +02:00
|
|
|
DWORD m_lod;
|
|
|
|
|
2019-12-16 04:28:01 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
using D3D9Texture2DBase = D3D9BaseTexture<D3D9Surface, IDirect3DTexture9>;
|
|
|
|
class D3D9Texture2D final : public D3D9Texture2DBase {
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
D3D9Texture2D(
|
|
|
|
D3D9DeviceEx* pDevice,
|
2020-01-17 11:54:41 +01:00
|
|
|
const D3D9_COMMON_TEXTURE_DESC* pDesc);
|
2019-12-16 04:28:01 +01:00
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
|
|
|
|
|
|
|
|
D3DRESOURCETYPE STDMETHODCALLTYPE GetType();
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE GetLevelDesc(UINT Level, D3DSURFACE_DESC *pDesc);
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE GetSurfaceLevel(UINT Level, IDirect3DSurface9** ppSurfaceLevel);
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE LockRect(UINT Level, D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags);
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE UnlockRect(UINT Level);
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE AddDirtyRect(CONST RECT* pDirtyRect);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
using D3D9Texture3DBase = D3D9BaseTexture<D3D9Volume, IDirect3DVolumeTexture9>;
|
|
|
|
class D3D9Texture3D final : public D3D9Texture3DBase {
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
D3D9Texture3D(
|
|
|
|
D3D9DeviceEx* pDevice,
|
2020-01-17 11:54:41 +01:00
|
|
|
const D3D9_COMMON_TEXTURE_DESC* pDesc);
|
2019-12-16 04:28:01 +01:00
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
|
|
|
|
|
|
|
|
D3DRESOURCETYPE STDMETHODCALLTYPE GetType();
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE GetLevelDesc(UINT Level, D3DVOLUME_DESC *pDesc);
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE GetVolumeLevel(UINT Level, IDirect3DVolume9** ppSurfaceLevel);
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE LockBox(UINT Level, D3DLOCKED_BOX* pLockedBox, CONST D3DBOX* pBox, DWORD Flags);
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE UnlockBox(UINT Level);
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE AddDirtyBox(CONST D3DBOX* pDirtyBox);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
using D3D9TextureCubeBase = D3D9BaseTexture<D3D9Surface, IDirect3DCubeTexture9>;
|
|
|
|
class D3D9TextureCube final : public D3D9TextureCubeBase {
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
D3D9TextureCube(
|
|
|
|
D3D9DeviceEx* pDevice,
|
2020-01-17 11:54:41 +01:00
|
|
|
const D3D9_COMMON_TEXTURE_DESC* pDesc);
|
2019-12-16 04:28:01 +01:00
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
|
|
|
|
|
|
|
|
D3DRESOURCETYPE STDMETHODCALLTYPE GetType();
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE GetLevelDesc(UINT Level, D3DSURFACE_DESC *pDesc);
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE GetCubeMapSurface(D3DCUBEMAP_FACES Face, UINT Level, IDirect3DSurface9** ppSurfaceLevel);
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE LockRect(D3DCUBEMAP_FACES Face, UINT Level, D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags);
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE UnlockRect(D3DCUBEMAP_FACES Face, UINT Level);
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE AddDirtyRect(D3DCUBEMAP_FACES Face, CONST RECT* pDirtyRect);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2021-08-08 04:54:23 +02:00
|
|
|
static_assert(sizeof(D3D9Texture2D) == sizeof(D3D9Texture3D) &&
|
2021-08-11 05:25:29 +02:00
|
|
|
sizeof(D3D9Texture2D) == sizeof(D3D9TextureCube));
|
2021-08-08 04:54:23 +02:00
|
|
|
|
2019-12-16 04:28:01 +01:00
|
|
|
inline D3D9CommonTexture* GetCommonTexture(IDirect3DBaseTexture9* ptr) {
|
|
|
|
if (ptr == nullptr)
|
|
|
|
return nullptr;
|
|
|
|
|
2021-08-08 04:54:23 +02:00
|
|
|
// We can avoid needing to get the type as m_texture has the same offset
|
|
|
|
// no matter the texture type.
|
|
|
|
// The compiler is not smart enough to eliminate the call to GetType as it is
|
|
|
|
// not marked const.
|
2021-08-11 05:25:29 +02:00
|
|
|
return static_cast<D3D9Texture2D*>(ptr)->GetCommonTexture();
|
2019-12-16 04:28:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
inline D3D9CommonTexture* GetCommonTexture(D3D9Surface* ptr) {
|
|
|
|
if (ptr == nullptr)
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
return ptr->GetCommonTexture();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline D3D9CommonTexture* GetCommonTexture(IDirect3DSurface9* ptr) {
|
|
|
|
return GetCommonTexture(static_cast<D3D9Surface*>(ptr));
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void TextureRefPrivate(IDirect3DBaseTexture9* tex, bool AddRef) {
|
|
|
|
if (tex == nullptr)
|
|
|
|
return;
|
|
|
|
|
2021-08-08 04:54:23 +02:00
|
|
|
// We can avoid needing to get the type as m_refCount has the same offset
|
|
|
|
// no matter the texture type.
|
|
|
|
// The compiler is not smart enough to eliminate the call to GetType as it is
|
|
|
|
// not marked const.
|
2021-08-11 05:25:29 +02:00
|
|
|
return CastRefPrivate<D3D9Texture2D>(tex, AddRef);
|
2019-12-16 04:28:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void TextureChangePrivate(IDirect3DBaseTexture9*& dst, IDirect3DBaseTexture9* src) {
|
|
|
|
TextureRefPrivate(dst, false);
|
|
|
|
TextureRefPrivate(src, true);
|
|
|
|
dst = src;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|