windows-nt/Source/XPSP1/NT/multimedia/directx/dxg/d3d8/fw/texture.cpp
2020-09-26 16:20:57 +08:00

387 lines
11 KiB
C++

/*==========================================================================;
*
* Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
*
* File: texture.cpp
* Content: Implementation of the CBaseTexture class.
*
*
***************************************************************************/
#include "ddrawpr.h"
#include "texture.hpp"
#include "d3di.hpp"
#include "ddi.h"
#undef DPF_MODNAME
#define DPF_MODNAME "CBaseTexture::CanTexBlt"
BOOL CBaseTexture::CanTexBlt(CBaseTexture *pDstTexture) const
{
const D3D8_DRIVERCAPS* pDriverCaps = Device()->GetCoreCaps();
D3DPOOL SrcPool = GetBufferDesc()->Pool;
D3DPOOL DstPool = pDstTexture->GetBufferDesc()->Pool;
// Real pools should not be default
DXGASSERT(SrcPool != D3DPOOL_DEFAULT);
DXGASSERT(DstPool != D3DPOOL_DEFAULT);
DXGASSERT(VALID_INTERNAL_POOL(SrcPool));
DXGASSERT(VALID_INTERNAL_POOL(DstPool));
// Check if the device can do TexBlt
if (Device()->CanTexBlt() == FALSE)
return FALSE;
// Check that source and dest formats match
DXGASSERT(GetBufferDesc()->Format == pDstTexture->GetBufferDesc()->Format);
// FourCC may not be copy-able
if (CPixel::IsFourCC(GetBufferDesc()->Format))
{
if (!(pDriverCaps->D3DCaps.Caps2 & DDCAPS2_COPYFOURCC))
{
return FALSE;
}
}
// Note that we do not support TexBlt to anything
// that is persistent across Reset; because TexBlt is
// asynchronous and may not succeed if we get lost.
//
// This can break apps that expect the blt to have
// succeeded.
if (pDriverCaps->D3DCaps.Caps2 & DDCAPS2_NONLOCALVIDMEMCAPS)
{
if (SrcPool == D3DPOOL_SYSTEMMEM)
{
if ((DstPool == D3DPOOL_NONLOCALVIDMEM) &&
(pDriverCaps->D3DCaps.DevCaps & D3DDEVCAPS_CANBLTSYSTONONLOCAL))
{
return TRUE;
}
else if ((DstPool == D3DPOOL_LOCALVIDMEM) &&
(pDriverCaps->SVBCaps & DDCAPS_BLT))
{
return TRUE;
}
}
else if (SrcPool == D3DPOOL_NONLOCALVIDMEM)
{
if ((DstPool == D3DPOOL_LOCALVIDMEM) &&
(pDriverCaps->NLVCaps & DDCAPS_BLT))
{
return TRUE;
}
}
else if ((SrcPool == D3DPOOL_LOCALVIDMEM) ||
(SrcPool == D3DPOOL_MANAGED))
{
if ((DstPool == D3DPOOL_LOCALVIDMEM) &&
(pDriverCaps->D3DCaps.Caps & DDCAPS_BLT))
{
return TRUE;
}
}
}
else
{
if (SrcPool == D3DPOOL_SYSTEMMEM)
{
if ((DstPool == D3DPOOL_LOCALVIDMEM) &&
(pDriverCaps->SVBCaps & DDCAPS_BLT))
{
return TRUE;
}
}
else if ((SrcPool == D3DPOOL_LOCALVIDMEM) ||
(SrcPool == D3DPOOL_MANAGED))
{
if ((DstPool == D3DPOOL_LOCALVIDMEM) &&
(pDriverCaps->D3DCaps.Caps & DDCAPS_BLT))
{
return TRUE;
}
}
}
return FALSE;
} // CBaseTexture::CanTexBlt
#undef DPF_MODNAME
#define DPF_MODNAME "CBaseTexture::VerifyFormat"
HRESULT CBaseTexture::Validate(CBaseDevice *pDevice,
D3DRESOURCETYPE Type,
D3DPOOL Pool,
DWORD Usage,
D3DFORMAT Format)
{
DXGASSERT(pDevice);
DXGASSERT(Type == D3DRTYPE_TEXTURE ||
Type == D3DRTYPE_CUBETEXTURE ||
Type == D3DRTYPE_VOLUMETEXTURE);
// Check pool
if (!VALID_POOL(Pool))
{
DPF_ERR("Invalid Pool specified for texture");
return D3DERR_INVALIDCALL;
}
//pool scratch doesn't allow any usages
if (Pool == D3DPOOL_SCRATCH)
{
if (Usage)
{
DPF_ERR("D3DPOOL_SCRATCH resources aren't allowed to have any usage flags");
return D3DERR_INVALIDCALL;
}
}
// Check usage flags
if (Usage & ~D3DUSAGE_TEXTURE_VALID)
{
DPF_ERR("Invalid usage flag specified for texture.");
return D3DERR_INVALIDCALL;
}
// Check if USAGE_DYNAMIC is allowed
if (Usage & D3DUSAGE_DYNAMIC)
{
if (Pool == D3DPOOL_MANAGED)
{
DPF_ERR("Managed textures cannot be dynamic.");
return D3DERR_INVALIDCALL;
}
}
// Check is load-once is supported
if (Usage & D3DUSAGE_LOADONCE)
{
// Only SysMem and Managed are load-once-able
if (Pool != D3DPOOL_SYSTEMMEM &&
Pool != D3DPOOL_MANAGED)
{
DPF_ERR("Only SysMem and Managed textures support D3DUSAGE_LOADONCE");
return D3DERR_INVALIDCALL;
}
// Only D16_LOCKABLE is a lockable depth; doesn't
// make sense to have a non-lockable LOAD_ONCE texture
if (CPixel::IsNonLockableZ(Format))
{
DPF_ERR("Depth formats other than D3DFMT_D16_LOCKABLE are not lockable.");
return D3DERR_INVALIDCALL;
}
}
// Check that only POOL_DEFAULT is supported for
// RT or DS textures
if (Usage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL))
{
if (Pool != D3DPOOL_DEFAULT)
{
DPF_ERR("Pool must be D3DPOOL_DEFAULT for RenderTarget and"
" DepthStencil Usages");
return D3DERR_INVALIDCALL;
}
}
// Sys scratch or Managed must have a format that we can use directly
if (Pool == D3DPOOL_SYSTEMMEM ||
Pool == D3DPOOL_MANAGED ||
Pool == D3DPOOL_SCRATCH)
{
// Can't create format unless it is supported
if (!CPixel::IsSupported(Type, Format))
{
DPF_ERR("SystemMem, Scratch and Managed textures do not support this"
" format.");
return D3DERR_INVALIDCALL;
}
if (CPixel::IsNonLockableZ(Format))
{
DPF_ERR("This format is not supported for SystemMem, Scratch or Managed textures");
return D3DERR_INVALIDCALL;
}
}
if (Pool != D3DPOOL_SCRATCH)
{
HRESULT hr = pDevice->CheckDeviceFormat(Usage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_DYNAMIC),
Type,
Format);
if (FAILED(hr))
{
DPF_ERR("Invalid format specified for texture");
return D3DERR_INVALIDCALL;
}
}
return S_OK;
}; // CBaseTexture::Validate
#undef DPF_MODNAME
#define DPF_MODNAME "CBaseTexture::InferUsageFlags"
// Infer usage flags based on external parameters
DWORD CBaseTexture::InferUsageFlags(D3DPOOL Pool,
DWORD Usage,
D3DFORMAT Format)
{
//scratch textures have only usage lock
if (Pool == D3DPOOL_SCRATCH)
return D3DUSAGE_LOCK;
// All textures have this usage set
DWORD UsageInferred = D3DUSAGE_TEXTURE;
DXGASSERT(!(Usage & D3DUSAGE_LOCK));
DXGASSERT(!(Usage & D3DUSAGE_TEXTURE));
// Infer Lock
if ((Pool != D3DPOOL_DEFAULT) &&
!(CPixel::IsNonLockableZ(Format)) &&
!(Usage & D3DUSAGE_LOADONCE))
{
// Pool Default is not lockable
// Usage Load Once implies absence of USAGE_LOCK
// Z formats (other than D16_LOCKABLE) are not lockable
// Otherwise, locking is support by default
UsageInferred |= D3DUSAGE_LOCK;
}
else if (CPixel::IsIHVFormat(Format))
{
// IHV formats are lockable
UsageInferred |= D3DUSAGE_LOCK;
}
else if (Usage & D3DUSAGE_DYNAMIC)
{
DXGASSERT(Pool != D3DPOOL_MANAGED);
// Dynamic textures are lockable
UsageInferred |= D3DUSAGE_LOCK;
}
return (UsageInferred | Usage);
} // CBaseTexture::InferUsageFlags
#ifdef DEBUG
#undef DPF_MODNAME
#define DPF_MODNAME "CBaseTexture::ReportWhyLockFailed"
// DPF why Lock failed as clearly as possible
void CBaseTexture::ReportWhyLockFailed(void) const
{
// If there are multiple reasons that lock failed; we report
// them all to minimize user confusion
if (GetUserPool() == D3DPOOL_DEFAULT)
{
DPF_ERR("Lock is not supported for textures allocated with"
" POOL_DEFAULT unless they are marked D3DUSAGE_DYNAMIC.");
}
if (CPixel::IsNonLockableZ(GetUserFormat()))
{
DPF_ERR("Lock is not supported for depth formats other than D3DFMT_D16_LOCKABLE");
}
if (GetBufferDesc()->Usage & D3DUSAGE_LOADONCE)
{
DPF_ERR("For textures created with D3DUSAGE_LOADONCE,"
" each level can only be locked once.");
}
// If we got here; then USAGE_LOCK should not have been set
DXGASSERT(!(GetBufferDesc()->Usage & D3DUSAGE_LOCK));
return;
} // CBaseTexture::ReportWhyLockFailed
#endif // DEBUG
#undef DPF_MODNAME
#define DPF_MODNAME "CBaseTexture::OnDestroy"
// Textures overload this to call OnTextureDestroy on the
// Device before calling Sync.
void CBaseTexture::OnDestroy(void)
{
if (GetUserPool() != D3DPOOL_SCRATCH)
{
// we need to call this before freeing the texture so
// that currently set textures get unset.
if (BaseKernelHandle())
{
// m_hKernelHandle might not be available if Create fails early
CD3DBase *pDev = static_cast<CD3DBase *>(Device());
pDev->OnTextureDestroy(this);
}
// After FE has been notified, then we need
// to sync; so call our base class
CResource::OnDestroy();
}
return;
} // CBaseTexture::OnDestroy
#undef DPF_MODNAME
#define DPF_MODNAME "CBaseTexture::SetLODImpl"
DWORD CBaseTexture::SetLODImpl(DWORD LOD)
{
// Clamp to max lod since we can't return errors
if (LOD >= GetLevelCountImpl())
{
DPF_ERR("Invalid dwLOD passed to SetLOD; clamping to number-of-levels-minus-one.");
LOD = GetLevelCountImpl() - 1;
}
DWORD oldLOD = 0;
if (IsD3DManaged())
{
oldLOD = Device()->ResourceManager()->SetLOD(RMHandle(), LOD);
}
// If IsD3DManaged() is FALSE and if the actual pool
// is found to be D3DPOOL_MANAGED then the resource
// MUST be driver managed.
else if (GetBufferDesc()->Pool == D3DPOOL_MANAGED)
{
CD3DBase *pDev = static_cast<CD3DBase*>(Device());
DXGASSERT(IS_DX8HAL_DEVICE(pDev));
oldLOD = SetLODI(LOD);
pDev->SetTexLOD(this, LOD);
}
// If above two conditions are false, then we must
// check if we have fallen back to sysmem for some
// reason even if the app requested managed. THIS
// IS IMPOSSIBLE, so ASSERT.
else if (GetUserPool() == D3DPOOL_MANAGED)
{
// We assert because sysmem fallback is not possible
// for textures (and hence SetLOD)
DXGASSERT(FALSE);
}
else
{
DPF_ERR("LOD set on non-managed object");
}
return oldLOD;
}; // SetLODImpl
#undef DPF_MODNAME
#define DPF_MODNAME "CBaseTexture::GetLODImpl"
DWORD CBaseTexture::GetLODImpl()
{
if (!IsD3DManaged() && GetBufferDesc()->Pool != D3DPOOL_MANAGED)
{
DPF_ERR("LOD accessed on non-managed object");
return 0;
}
return GetLODI();
}; // GetLODImpl
// End of file : texture.cpp