|
|
#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__
|