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

722 lines
19 KiB
C++

#ifndef __RESOURCE_HPP__
#define __RESOURCE_HPP__
/*==========================================================================;
*
* Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
*
* File: resource.hpp
* Content: Base class header for resources. A resource is an non-trivial
* object that is directly used by the graphics pipeline. It
* be composed of a set of buffers; for example a mip-map is
* a resource that is composed of Surfaces (which are buffers).
*
* Since resources are non-trivial (i.e. more than few bytes),
* they may need management. The resource cooperates with the
* Resource Manager component to get management functionality.
*
***************************************************************************/
#include "d3dobj.hpp"
// Forward Decl
struct CMgmtInfo;
class CResourceManager;
// Handle for Resource Manager; internally implemented as a pointer
typedef CMgmtInfo *RMHANDLE;
// A Resource is a Base Object that additionally
// has a Priority field
class CResource : public CBaseObject
{
public:
static HRESULT RestoreDriverManagementState(CBaseDevice *pDevice);
// These methods are for the
// use of the Resource Manager
RMHANDLE RMHandle() const
{
return m_RMHandle;
}; // RMHandle
// Determine if a resource is managed or driver-managed
BOOL IsD3DManaged() const
{
// Zero is not a valid RM handle
return (m_RMHandle != 0);
}; // IsD3DManaged
// Set the device batch number that
// this resource was last used in. In this
// context; the batch refers to whether
// this resource was used in the current
// command buffer (i.e. containing unflushed commands).
void Batch();
// Same as Batch() except it batches the
// backing (or sysmem) texture rather than the
// promoted (or vidmem) one.
void BatchBase();
// Notifies the device that this resource
// is about to be modified in a way that
// may require a flush. (i.e. Whenever the bits
// could change or a surface is going away.)
void Sync();
// Sets batch number
void SetBatchNumber(ULONGLONG batch)
{
// Batch numbers should only be increasing since we
// start at zero.
DXGASSERT(batch >= m_qwBatchCount);
m_qwBatchCount = batch;
} // SetBatchNumber
// returns the batch number that this resource
// was last referred in
ULONGLONG GetBatchNumber() const
{
return m_qwBatchCount;
}
// returns the DrawPrim handle associated with
// the Driver-Accessible clone if it is Managed;
// otherwise returns the handle of itself.
DWORD DriverAccessibleDrawPrimHandle() const;
// returns the Kernel handle associated with
// the Driver-Accessible clone if it is Managed;
// otherwise returns the handle of itself.
HANDLE DriverAccessibleKernelHandle() const;
// Specifies a creation of a resource that
// looks just like the current one. The LOD parameter
// may not be relevant for all Resource types.
virtual HRESULT Clone(D3DPOOL Pool,
CResource **ppResource) const PURE;
// Provides a method to access basic structure of the
// pieces of the resource.
virtual const D3DBUFFER_DESC* GetBufferDesc() const PURE;
// Tells the resource that it should copy itself
// to the target. It is the caller's responsibility
// to make sure that Target is compatible with the
// Source. (The Target may have different number of mip-levels
// and be in a different pool; however, it must have the same size,
// faces, format, etc.)
//
// This function will clear the dirty state.
virtual HRESULT UpdateDirtyPortion(CResource *pResourceTarget) PURE;
// Allows the Resource Manager to mark the texture
// as needing to be completely updated on next
// call to UpdateDirtyPortion
virtual void MarkAllDirty() PURE;
// Indicates whether the Resource has been modified since
// the last time that UpdateDirtyPortion has been called.
// All managed resources start out in the Dirty state.
BOOL IsDirty() const
{
return m_bIsDirty;
} // IsDirty
void PreLoadImpl();
// Returns the pool which the user passed in
D3DPOOL GetUserPool() const
{
return m_poolUser;
} // GetUserPool
protected:
// The following are methods that only make sense
// to be called by derived classes
// Helper to check if a type is managed
static BOOL IsTypeD3DManaged(CBaseDevice *pDevice,
D3DRESOURCETYPE Type,
D3DPOOL Pool);
static BOOL IsTypeDriverManaged(CBaseDevice *pDevice,
D3DRESOURCETYPE Type,
D3DPOOL Pool);
// Helper to determine what the 'real' pool is
// for a managed resource.
static D3DPOOL DetermineCreationPool(CBaseDevice *pDevice,
D3DRESOURCETYPE Type,
DWORD dwUsage,
D3DPOOL Pool);
// Constructor for Resources; all resources start out dirty
CResource(CBaseDevice *pDevice, D3DPOOL Pool, REF_TYPE refType = REF_EXTERNAL) :
CBaseObject(pDevice, refType),
m_RMHandle(0),
m_qwBatchCount(0),
m_Priority(0),
m_bIsDirty(TRUE),
m_poolUser(Pool),
m_pPrev(0)
{
m_pNext = pDevice->GetResourceList();
pDevice->SetResourceList(this);
if (m_pNext != 0)
{
m_pNext->m_pPrev = this;
}
}; // CResource
virtual ~CResource();
// Priority Inlines
DWORD SetPriorityImpl(DWORD newPri);
DWORD GetPriorityImpl();
// Allows initialization of the RMHandle after
// construction is basically complete
HRESULT InitializeRMHandle();
// Allows RMHandle to be set to zero
void DeleteRMHandle();
// Helper to notify the RM that
// we are now dirty.
void OnResourceDirty();
// Helper to notify resource when it
// is all clean
void OnResourceClean();
// Resources need to implement OnDestroy by
// calling Sync; (Textures overload this
// to call OnTextureDestroy on the device before
// calling their base class.)
virtual void OnDestroy(void)
{
Sync();
return;
} // OnDestroy
// Returns the current priority
DWORD GetPriorityI() const
{
return m_Priority;
}
// Sets the current priority (but does not do any work)
DWORD SetPriorityI(DWORD Priority)
{
DWORD oldPriority = m_Priority;
m_Priority = Priority;
return oldPriority;
}
private:
RMHANDLE m_RMHandle;
ULONGLONG m_qwBatchCount;
DWORD m_Priority;
BOOL m_bIsDirty;
// Remember the pool that the user passed in
D3DPOOL m_poolUser;
// Linked list of resources
CResource *m_pPrev;
CResource *m_pNext;
friend CResourceManager;
}; // CResource
struct CMgmtInfo
{
// This is static because we assume all resources
// to be in heap zero. WHEN the resource manager
// supports multiple heaps, m_rmHeap should be
// made per object again.
static DWORD m_rmHeap;
DWORD m_priority;
DWORD m_LOD;
BOOL m_bInUse;
DWORD m_rmHeapIndex;
DWORD m_scene;
DWORD m_ticks;
CResource *m_pRes;
CResource *m_pBackup;
CMgmtInfo(CResource*);
~CMgmtInfo();
ULONGLONG Cost() const
{
#ifdef _X86_
ULONGLONG retval;
_asm
{
mov ebx, this;
mov edx, [ebx]CMgmtInfo.m_bInUse;
shl edx, 31;
mov eax, [ebx]CMgmtInfo.m_priority;
mov ecx, eax;
shr eax, 1;
or edx, eax;
mov DWORD PTR retval + 4, edx;
shl ecx, 31;
mov eax, [ebx]CMgmtInfo.m_ticks;
shr eax, 1;
or eax, ecx;
mov DWORD PTR retval, eax;
}
return retval;
#else
return ((ULONGLONG)m_bInUse << 63) + ((ULONGLONG)m_priority << 31) + ((ULONGLONG)(m_ticks >> 1));
#endif
}
}; // CMgmtInfo
inline CMgmtInfo::CMgmtInfo(CResource *pBackup)
{
m_priority = 0;
m_LOD = 0;
m_bInUse = FALSE;
m_rmHeap = 0;
m_rmHeapIndex = 0;
m_scene = 0;
m_ticks = 0;
m_pRes = 0;
m_pBackup = pBackup;
} // CMgmtInfo::CMgmtInfo
inline CMgmtInfo::~CMgmtInfo()
{
if (m_pRes != 0)
{
m_pRes->DecrementUseCount();
}
} // CMgmtInfo::~CMgmtInfo
class CRMHeap
{
private:
enum { InitialSize = 1023 };
DWORD m_next, m_size;
CMgmtInfo **m_data_p;
DWORD parent(DWORD k) const { return k / 2; }
DWORD lchild(DWORD k) const { return k * 2; }
DWORD rchild(DWORD k) const { return k * 2 + 1; }
void heapify(DWORD k);
public:
CRMHeap(DWORD size = InitialSize);
~CRMHeap();
BOOL Initialize();
DWORD length() const { return m_next - 1; }
CMgmtInfo* minCost() const { return m_data_p[1]; }
BOOL add(CMgmtInfo*);
CMgmtInfo* extractMin();
CMgmtInfo* extractMax();
CMgmtInfo* extractNotInScene(DWORD dwScene);
void del(CMgmtInfo*);
void update(CMgmtInfo*, BOOL inuse, DWORD priority, DWORD ticks);
void resetAllTimeStamps(DWORD ticks);
}; // class CRMHeap
inline CRMHeap::CRMHeap(DWORD size)
{
m_next = 1;
m_size = size + 1;
} // CRMHeap::CRMHeap
inline CRMHeap::~CRMHeap()
{
delete[] m_data_p;
} // CRMHeap::~CRMHeap
class CResourceManager
{
public:
CResourceManager();
~CResourceManager();
// Need to call before using the manager
HRESULT Init(CBaseDevice *pD3D8);
// Check to see if a type is going to driver managed
// or going to be D3D managed
BOOL IsDriverManaged(D3DRESOURCETYPE Type) const;
// Specify that a resource needs to be managed
//
// Error indicates that we don't support management for this
// resource type.
HRESULT Manage(CResource *pResource, RMHANDLE *pHandle);
// Stop managing a resouce; called when a managed resource
// is going away
void UnManage(RMHANDLE hRMHandle);
// The RM manages Priority and LOD for the resource
DWORD SetPriority(RMHANDLE hRMHandle, DWORD newPriority);
DWORD SetLOD(RMHANDLE hRMHandle, DWORD dwLodNew);
// Preloads resource into video memory
void PreLoad(RMHANDLE hRMHandle);
// Checks if the resource is in video memory
BOOL InVidmem(RMHANDLE hRMHandle) const;
// This is called when DrawPrimitive needs to
// make sure that all resources used in the
// current call are in video memory and are
// uptodate.
HRESULT UpdateVideo(RMHANDLE hRMHandle, BOOL *bDirty);
HRESULT UpdateVideoInternal(CMgmtInfo *pMgmtInfo);
// This returns the appropriate handle for a
// managed resource
DWORD DrawPrimHandle(RMHANDLE hRMHandle) const;
// This returns the appropriate kernel handle for a
// managed resource
HANDLE KernelHandle(RMHANDLE hRMHandle) const;
// This call will batch the appropriate resource
// for the purpose of syncing
void Batch(RMHANDLE hRMHandle, ULONGLONG batch) const;
// Called from outside when a managed resource becomes dirty
void OnResourceDirty(RMHANDLE hRMHandle) const;
void DiscardBytes(DWORD cbBytes);
void SceneStamp() { ++m_dwScene; }
private:
CBaseDevice *m_pD3D8;
unsigned tcm_ticks, m_dwScene, m_dwNumHeaps;
BOOL m_PreLoading;
CRMHeap *m_heap_p;
BOOL FreeResources(DWORD dwHeap, DWORD dwBytes);
void Lock(RMHANDLE hRMHandle);
void Unlock(RMHANDLE hRMHandle);
void TimeStamp(CMgmtInfo *pMgmtInfo);
}; // class CResourceManager
#undef DPF_MODNAME
#define DPF_MODNAME "CResource::IsTypeD3DManaged"
inline BOOL CResource::IsTypeD3DManaged(CBaseDevice *pDevice,
D3DRESOURCETYPE Type,
D3DPOOL Pool)
{
if (Pool == D3DPOOL_MANAGED)
{
return !IsTypeDriverManaged(pDevice, Type, Pool);
}
else
{
return FALSE;
}
}; // IsTypeD3DManaged
#undef DPF_MODNAME
#define DPF_MODNAME "CResource::IsTypeDriverManaged"
inline BOOL CResource::IsTypeDriverManaged(CBaseDevice *pDevice,
D3DRESOURCETYPE Type,
D3DPOOL Pool)
{
if (Pool == D3DPOOL_MANAGED)
{
if (pDevice->ResourceManager()->IsDriverManaged(Type))
{
return TRUE;
}
}
return FALSE;
}; // IsTypeDriverManaged
#undef DPF_MODNAME
#define DPF_MODNAME "CResource::DetermineCreationPool"
inline D3DPOOL CResource::DetermineCreationPool(CBaseDevice *pDevice,
D3DRESOURCETYPE Type,
DWORD dwUsage,
D3DPOOL Pool)
{
if (Pool == D3DPOOL_MANAGED)
{
if (IsTypeDriverManaged(pDevice, Type, Pool))
{
// This pool is used by the thunk layer
// to use the driver management flag during
// create
return D3DPOOL_MANAGED;
}
else
{
// If it is not driver managed; then it
// becomes D3DMANAGED
return D3DPOOL_SYSTEMMEM;
}
}
else
{
// Not managed at all; so we just
// use the same pool we started with
return Pool;
}
} // DetermineCreationPool
#undef DPF_MODNAME
#define DPF_MODNAME "CResource::~CResource"
inline CResource::~CResource()
{
// If managed, we need to notify
// the ResourceManager that we are going away
if (IsD3DManaged())
{
Device()->ResourceManager()->UnManage(m_RMHandle);
}
// Unlink from the resource list
if (m_pNext != 0)
{
m_pNext->m_pPrev = m_pPrev;
}
if (m_pPrev != 0)
{
m_pPrev->m_pNext = m_pNext;
DXGASSERT(Device()->GetResourceList() != this);
}
else
{
DXGASSERT(Device()->GetResourceList() == this);
Device()->SetResourceList(m_pNext);
}
}; // ~CResource
#undef DPF_MODNAME
#define DPF_MODNAME "CResource::InitializeRMHandle"
// Allows initialization of the RMHandle after
// construction is basically complete
inline HRESULT CResource::InitializeRMHandle()
{
// We should not already have a handle
DXGASSERT(m_RMHandle == 0);
// Get a handle from the resource manager
return Device()->ResourceManager()->Manage(this, &m_RMHandle);
}; // InitializeRMHandle
#undef DPF_MODNAME
#define DPF_MODNAME "CResource::DeleteRMHandle"
inline void CResource::DeleteRMHandle()
{
// We should already have a handle
DXGASSERT(m_RMHandle != 0);
Device()->ResourceManager()->UnManage(m_RMHandle);
m_RMHandle = 0;
}
#undef DPF_MODNAME
#define DPF_MODNAME "CResource::OnResourceDirty"
// Add a helper to notify the RM that
// we are now dirty.
inline void CResource::OnResourceDirty()
{
// Update our state
m_bIsDirty = TRUE;
// Only need to notify RM for managed textures
// that have been been set through SetTexture
if (IsD3DManaged() && IsInUse())
{
Device()->ResourceManager()->OnResourceDirty(m_RMHandle);
}
return;
}; // OnResourceDirty
#undef DPF_MODNAME
#define DPF_MODNAME "CResource::OnResourceClean"
// Add a helper to help maintain m_bIsDirty bit
inline void CResource::OnResourceClean()
{
DXGASSERT(m_bIsDirty == TRUE);
m_bIsDirty = FALSE;
return;
}; // OnResourceDirty
#undef DPF_MODNAME
#define DPF_MODNAME "CResource::DriverAccessibleDrawPrimHandle"
inline DWORD CResource::DriverAccessibleDrawPrimHandle() const
{
if (IsD3DManaged())
{
// Return the DrawPrim handle of my clone
return Device()->ResourceManager()->DrawPrimHandle(RMHandle());
}
else
{
return BaseDrawPrimHandle();
}
} // CResource::DriverAccessibleDrawPrimHandle
#undef DPF_MODNAME
#define DPF_MODNAME "CResource::DriverAccessibleKernelHandle"
inline HANDLE CResource::DriverAccessibleKernelHandle() const
{
if (IsD3DManaged())
{
// Return the DrawPrim handle of my clone
HANDLE h = Device()->ResourceManager()->KernelHandle(RMHandle());
// If this handle is NULL, then it means it was called
// without calling UpdateVideo which isn't allowed/sane
DXGASSERT(h != NULL);
return h;
}
else
{
return BaseKernelHandle();
}
} // CResource::DriverAccessibleKernelHandle
#undef DPF_MODNAME
#define DPF_MODNAME "CResourceManager::CResourceManager"
inline CResourceManager::CResourceManager()
{
m_pD3D8 = 0;
tcm_ticks = m_dwScene = m_dwNumHeaps = 0;
m_heap_p = 0;
m_PreLoading = FALSE;
} // CResourceManager::CResourceManager
#undef DPF_MODNAME
#define DPF_MODNAME "CResourceManager::~CResourceManager"
inline CResourceManager::~CResourceManager()
{
// We should not call DiscardBytes here
// because this destructor can be called via
// the device destructor chain. In this situation
// DiscardBytes will access bad or already freed
// data.
delete[] m_heap_p;
} // CResourceManager::~CResourceManager
#undef DPF_MODNAME
#define DPF_MODNAME "CResourceManager::DrawPrimHandle"
inline DWORD CResourceManager::DrawPrimHandle(RMHANDLE hRMHandle) const
{
if (InVidmem(hRMHandle))
{
CMgmtInfo* &pMgmtInfo = hRMHandle;
return pMgmtInfo->m_pRes->BaseDrawPrimHandle();
}
else
{
return 0;
}
} // CResourceManager::DrawPrimHandle
#undef DPF_MODNAME
#define DPF_MODNAME "CResourceManager::KernelHandle"
inline HANDLE CResourceManager::KernelHandle(RMHANDLE hRMHandle) const
{
if (InVidmem(hRMHandle))
{
CMgmtInfo* &pMgmtInfo = hRMHandle;
return pMgmtInfo->m_pRes->BaseKernelHandle();
}
else
{
return 0;
}
} // CResourceManager::Kernelhandle
#undef DPF_MODNAME
#define DPF_MODNAME "CResourceManager::InVidmem"
inline BOOL CResourceManager::InVidmem(RMHANDLE hRMHandle) const
{
CMgmtInfo* &pMgmtInfo = hRMHandle;
DXGASSERT(pMgmtInfo != 0);
return pMgmtInfo->m_pRes != 0;
} // CResourceManager::InVidmem
#undef DPF_MODNAME
#define DPF_MODNAME "CResourceManager::Batch"
inline void CResourceManager::Batch(RMHANDLE hRMHandle, ULONGLONG batch) const
{
if (InVidmem(hRMHandle))
{
CMgmtInfo* &pMgmtInfo = hRMHandle;
pMgmtInfo->m_pRes->SetBatchNumber(batch);
}
} // CResourceManager::Batch
#undef DPF_MODNAME
#define DPF_MODNAME "CResourceManager::UpdateVideo"
inline HRESULT CResourceManager::UpdateVideo(RMHANDLE hRMHandle, BOOL *bDirty)
{
HRESULT ddrval = S_OK;
CMgmtInfo* &pMgmtInfo = hRMHandle;
if (!InVidmem(hRMHandle))
{
ddrval = UpdateVideoInternal(pMgmtInfo);
*bDirty = TRUE;
}
else
{
if (pMgmtInfo->m_pBackup->IsDirty())
{
ddrval = pMgmtInfo->m_pBackup->UpdateDirtyPortion(pMgmtInfo->m_pRes);
}
TimeStamp(pMgmtInfo);
}
return ddrval;
}
#endif // __RESOURCE_HPP__