/*==========================================================================; * * Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved. * * File: rman.cpp * Content: Resource management * ***************************************************************************/ #include "ddrawpr.h" #include "dxgint.h" #include "resource.hpp" #include "texture.hpp" #include "d3di.hpp" #include "ddi.h" // Always use heap 0 DWORD CMgmtInfo::m_rmHeap = 0; #undef DPF_MODNAME #define DPF_MODNAME "CResource::UpdateDirtyPortion" // These stub functions are only supported for managed resources; // they should never get called; the asserts are there to help // determine where the bug is if they do get called. HRESULT CResource::UpdateDirtyPortion(CResource *pResourceTarget) { // This should not be called except for D3D_MANAGED // objects because we don't keep dirty portion records // for other kinds of objects. // If we were D3D_MANAGED: the real class should have // overriden this method DXGASSERT(!IsTypeD3DManaged(Device(), GetBufferDesc()->Type, GetBufferDesc()->Pool)); // If this isn't D3DManaged, we shouldn't have // been called. DXGASSERT(FALSE); // return something benign for retail build return S_OK; } #undef DPF_MODNAME #define DPF_MODNAME "CResource::MarkAllDirty" void CResource::MarkAllDirty() { // This should not be called except for D3D_MANAGED // objects because we don't keep dirty portion records // for other kinds of objects. // If we were D3D_MANAGED: the real class should have // overriden this method DXGASSERT(!IsTypeD3DManaged(Device(), GetBufferDesc()->Type, GetBufferDesc()->Pool)); // If this isn't D3DManaged, we shouldn't have // been called. DXGASSERT(FALSE); } // CResource::MarkAllDirty #undef DPF_MODNAME #define DPF_MODNAME "CResource::SetPriorityImpl" DWORD CResource::SetPriorityImpl(DWORD newPri) { DWORD oldPriority = 0; if (IsD3DManaged()) { oldPriority = Device()->ResourceManager()->SetPriority(m_RMHandle, newPri); } // 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(Device()); DXGASSERT(IS_DX8HAL_DEVICE(pDev)); oldPriority = SetPriorityI(newPri); pDev->SetPriority(this, newPri); } // 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. We // can know whether the app requested D3DPOOL_MANAGED // by calling GetUserPool(). else if (GetUserPool() == D3DPOOL_MANAGED) { // We assert because sysmem fallback is currently // possible for only vertex or index buffers. DXGASSERT(GetBufferDesc()->Type == D3DRTYPE_VERTEXBUFFER || GetBufferDesc()->Type == D3DRTYPE_INDEXBUFFER); // No need to do any real work since the // resource is in sysmem in any case. oldPriority = SetPriorityI(newPri); } else { DPF_ERR("Priority set on non-managed object. SetPriority returns zero."); } return oldPriority; } // SetPriorityImpl #undef DPF_MODNAME #define DPF_MODNAME "CResource::GetPriorityImpl" DWORD CResource::GetPriorityImpl() { if (!IsD3DManaged() && GetBufferDesc()->Pool != D3DPOOL_MANAGED && GetUserPool() != D3DPOOL_MANAGED) { DPF_ERR("Priority accessed on non-managed object. GetPriority returns zero."); return 0; } return GetPriorityI(); } // GetPriorityImpl #undef DPF_MODNAME #define DPF_MODNAME "CResource::PreLoadImpl" void CResource::PreLoadImpl() { if (IsD3DManaged()) { Device()->ResourceManager()->PreLoad(m_RMHandle); } // 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(Device()); DXGASSERT(IS_DX8HAL_DEVICE(pDev)); if(GetBufferDesc()->Type == D3DRTYPE_TEXTURE || GetBufferDesc()->Type == D3DRTYPE_VOLUMETEXTURE || GetBufferDesc()->Type == D3DRTYPE_CUBETEXTURE) { POINT p = {0, 0}; RECTL r = {0, 0, 0, 0}; pDev->TexBlt(0, static_cast(this), &p, &r); } else { DXGASSERT(GetBufferDesc()->Type == D3DRTYPE_VERTEXBUFFER || GetBufferDesc()->Type == D3DRTYPE_INDEXBUFFER); D3DRANGE range = {0, 0}; pDev->BufBlt(0, static_cast(this), 0, &range); } } // 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. We // can know whether the app requested D3DPOOL_MANAGED // by calling GetUserPool(). else if (GetUserPool() == D3DPOOL_MANAGED) { // We assert because sysmem fallback is currently // possible for only vertex or index buffers. DXGASSERT(GetBufferDesc()->Type == D3DRTYPE_VERTEXBUFFER || GetBufferDesc()->Type == D3DRTYPE_INDEXBUFFER); // Do nothing since vertex/index buffer are in sysmem // and preload has no meaning } else { DPF_ERR("PreLoad called on non-managed object"); } } // PreLoadImpl #undef DPF_MODNAME #define DPF_MODNAME "CResource::RestoreDriverManagementState" HRESULT CResource::RestoreDriverManagementState(CBaseDevice *pDevice) { for(CResource *pRes = pDevice->GetResourceList(); pRes != 0; pRes = pRes->m_pNext) { if (pRes->GetBufferDesc()->Pool == D3DPOOL_MANAGED && !pRes->IsD3DManaged()) // Must be driver managed { static_cast(pDevice)->SetPriority(pRes, pRes->GetPriorityI()); if (pRes->GetBufferDesc()->Type == D3DRTYPE_TEXTURE || pRes->GetBufferDesc()->Type == D3DRTYPE_VOLUMETEXTURE || pRes->GetBufferDesc()->Type == D3DRTYPE_CUBETEXTURE) { static_cast(pDevice)->SetTexLOD(static_cast(pRes), static_cast(pRes)->GetLODI()); } // We need to update cached pointers for read/write vertex and index buffers else if (pRes->GetBufferDesc()->Type == D3DRTYPE_VERTEXBUFFER && (pRes->GetBufferDesc()->Usage & D3DUSAGE_WRITEONLY) == 0) { HRESULT hr = static_cast(pRes)->UpdateCachedPointer(pDevice); if (FAILED(hr)) { return hr; } } else if (pRes->GetBufferDesc()->Type == D3DRTYPE_INDEXBUFFER && (pRes->GetBufferDesc()->Usage & D3DUSAGE_WRITEONLY) == 0) { HRESULT hr = static_cast(pRes)->UpdateCachedPointer(pDevice); if (FAILED(hr)) { return hr; } } } } return S_OK; } // RestoreDriverManagementState #undef DPF_MODNAME #define DPF_MODNAME "CRMHeap::Initialize" BOOL CRMHeap::Initialize() { m_data_p = new CMgmtInfo*[m_size]; if (m_data_p == 0) { DPF_ERR("Failed to allocate texture heap."); return FALSE; } memset(m_data_p, 0, sizeof(CMgmtInfo*) * m_size); return TRUE; } // CRMHeap::Initialize #undef DPF_MODNAME #define DPF_MODNAME "CRMHeap::heapify" void CRMHeap::heapify(DWORD k) { while(TRUE) { DWORD smallest; DWORD l = lchild(k); DWORD r = rchild(k); if (l < m_next) if (m_data_p[l]->Cost() < m_data_p[k]->Cost()) smallest = l; else smallest = k; else smallest = k; if (r < m_next) if (m_data_p[r]->Cost() < m_data_p[smallest]->Cost()) smallest = r; if (smallest != k) { CMgmtInfo *t = m_data_p[k]; m_data_p[k] = m_data_p[smallest]; m_data_p[k]->m_rmHeapIndex = k; m_data_p[smallest] = t; m_data_p[smallest]->m_rmHeapIndex = smallest; k = smallest; } else break; } } // CRMHeap::heapify #undef DPF_MODNAME #define DPF_MODNAME "CRMHeap::add" BOOL CRMHeap::add(CMgmtInfo *pMgmtInfo) { DXGASSERT(pMgmtInfo->m_rmHeapIndex == 0); if (m_next == m_size) { m_size = m_size * 2 - 1; CMgmtInfo **p = new CMgmtInfo*[m_size]; if (p == 0) { DPF_ERR("Failed to allocate memory to grow heap."); m_size = (m_size + 1) / 2; // restore size return FALSE; } memcpy(p + 1, m_data_p + 1, sizeof(CMgmtInfo*) * (m_next - 1)); delete[] m_data_p; m_data_p = p; } ULONGLONG Cost = pMgmtInfo->Cost(); for (DWORD k = m_next; k > 1; k = parent(k)) if (Cost < m_data_p[parent(k)]->Cost()) { m_data_p[k] = m_data_p[parent(k)]; m_data_p[k]->m_rmHeapIndex = k; } else break; m_data_p[k] = pMgmtInfo; m_data_p[k]->m_rmHeapIndex = k; ++m_next; return TRUE; } // CRMHeap::add #undef DPF_MODNAME #define DPF_MODNAME "CRMHeap::extractMin" CMgmtInfo* CRMHeap::extractMin() { CMgmtInfo *pMgmtInfo = m_data_p[1]; --m_next; m_data_p[1] = m_data_p[m_next]; m_data_p[1]->m_rmHeapIndex = 1; heapify(1); pMgmtInfo->m_rmHeapIndex = 0; return pMgmtInfo; } // CRMHeap::extractMin #undef DPF_MODNAME #define DPF_MODNAME "CRMHeap::extractMax" CMgmtInfo* CRMHeap::extractMax() { // When extracting the max element from the heap, we don't need to // search the entire heap, but just the leafnodes. This is because // it is guaranteed that parent nodes are cheaper than the leaf nodes // so once you have looked through the leaves, you won't find anything // cheaper. // NOTE: (lchild(i) >= m_next) is TRUE only for leaf nodes. // ALSO NOTE: You cannot have a rchild without a lchild, so simply // checking for lchild is sufficient. // // CONSIDER(40358): Should have asserts to verify above assumptions; but // it would require writing a heap-consistency // checker. Maybe someday. // unsigned max = m_next - 1; ULONGLONG maxcost = 0; for (unsigned i = max; lchild(i) >= m_next; --i) { ULONGLONG Cost = m_data_p[i]->Cost(); if (maxcost < Cost) { maxcost = Cost; max = i; } } CMgmtInfo* pMgmtInfo = m_data_p[max]; if (pMgmtInfo->m_bInUse) { max = 0; maxcost = 0; for (i = m_next - 1; i > 0; --i) { ULONGLONG Cost = m_data_p[i]->Cost(); if (maxcost < Cost && !m_data_p[i]->m_bInUse) { maxcost = Cost; max = i; } } if (max == 0) // All textures in use return 0; pMgmtInfo = m_data_p[max]; } del(m_data_p[max]); return pMgmtInfo; } // CRMHeap::extractMax #undef DPF_MODNAME #define DPF_MODNAME "CRMHeap::extractNotInScene" CMgmtInfo* CRMHeap::extractNotInScene(DWORD dwScene) { for (unsigned i = 1; i < m_next; ++i) { if (m_data_p[i]->m_scene != dwScene) { CMgmtInfo* pMgmtInfo = m_data_p[i]; del(m_data_p[i]); return pMgmtInfo; } } return 0; } // CRMHeap::extractNotInScene #undef DPF_MODNAME #define DPF_MODNAME "CRMHeap::del" void CRMHeap::del(CMgmtInfo* pMgmtInfo) { DWORD k = pMgmtInfo->m_rmHeapIndex; --m_next; ULONGLONG Cost = m_data_p[m_next]->Cost(); if (Cost < pMgmtInfo->Cost()) { while(k > 1) { if (Cost < m_data_p[parent(k)]->Cost()) { m_data_p[k] = m_data_p[parent(k)]; m_data_p[k]->m_rmHeapIndex = k; } else break; k = parent(k); } m_data_p[k] = m_data_p[m_next]; m_data_p[k]->m_rmHeapIndex = k; } else { m_data_p[k] = m_data_p[m_next]; m_data_p[k]->m_rmHeapIndex = k; heapify(k); } pMgmtInfo->m_rmHeapIndex = 0; } // CRMHeap::del #undef DPF_MODNAME #define DPF_MODNAME "CRMHeap::update" void CRMHeap::update(CMgmtInfo* pMgmtInfo, BOOL inuse, DWORD priority, DWORD ticks) { DWORD k = pMgmtInfo->m_rmHeapIndex; ULONGLONG Cost; #ifdef _X86_ _asm { mov edx, inuse; shl edx, 31; mov eax, priority; mov ecx, eax; shr eax, 1; or edx, eax; mov DWORD PTR Cost + 4, edx; shl ecx, 31; mov eax, ticks; shr eax, 1; or eax, ecx; mov DWORD PTR Cost, eax; } #else Cost = ((ULONGLONG)inuse << 63) + ((ULONGLONG)priority << 31) + ((ULONGLONG)(ticks >> 1)); #endif if (Cost < pMgmtInfo->Cost()) { while(k > 1) { if (Cost < m_data_p[parent(k)]->Cost()) { m_data_p[k] = m_data_p[parent(k)]; m_data_p[k]->m_rmHeapIndex = k; } else break; k = parent(k); } pMgmtInfo->m_bInUse = inuse; pMgmtInfo->m_priority = priority; pMgmtInfo->m_ticks = ticks; pMgmtInfo->m_rmHeapIndex = k; m_data_p[k] = pMgmtInfo; } else { pMgmtInfo->m_bInUse = inuse; pMgmtInfo->m_priority = priority; pMgmtInfo->m_ticks = ticks; heapify(k); } } // CRMHeap::update #undef DPF_MODNAME #define DPF_MODNAME "CRMHeap::resetAllTimeStamps" void CRMHeap::resetAllTimeStamps(DWORD ticks) { for (unsigned i = 1; i < m_next; ++i) { update(m_data_p[i], m_data_p[i]->m_bInUse, m_data_p[i]->m_priority, ticks); } } // CRMHeap::resetAllTimeStamps #undef DPF_MODNAME #define DPF_MODNAME "CResourceManager::Init" HRESULT CResourceManager::Init(CBaseDevice *pD3D8) { const D3DCAPS8* pCaps = pD3D8->GetD3DCaps(); if (pCaps != 0) if (pCaps->DevCaps & D3DDEVCAPS_SEPARATETEXTUREMEMORIES) { m_dwNumHeaps = pD3D8->GetD3DCaps()->MaxSimultaneousTextures; if (m_dwNumHeaps < 1) { DPF_ERR("Max simultaneous textures not set. Forced to 1."); m_dwNumHeaps = 1; } DPF(2, "Number of heaps set to %u.", m_dwNumHeaps); } else m_dwNumHeaps = 1; else m_dwNumHeaps = 1; m_heap_p = new CRMHeap[m_dwNumHeaps]; if (m_heap_p == 0) { DPF_ERR("Out of memory allocating texture heap."); return E_OUTOFMEMORY; } for (DWORD i = 0; i < m_dwNumHeaps; ++i) { if (m_heap_p[i].Initialize() == FALSE) { delete[] m_heap_p; m_heap_p = 0; return E_OUTOFMEMORY; } } m_pD3D8 = pD3D8; return S_OK; } // CResourceManager::Init #undef DPF_MODNAME #define DPF_MODNAME "CResourceManager::IsDriverManaged" BOOL CResourceManager::IsDriverManaged(D3DRESOURCETYPE Type) const { #if DBG switch (Type) { case D3DRTYPE_TEXTURE: case D3DRTYPE_VOLUMETEXTURE: case D3DRTYPE_CUBETEXTURE: case D3DRTYPE_VERTEXBUFFER: case D3DRTYPE_INDEXBUFFER: break; default: DXGASSERT(FALSE && "Management not supported for this type"); return FALSE; }; #endif // DBG return m_pD3D8->CanDriverManageResource(); }; // IsDriverManaged(D3DRESOURCETYPE) #undef DPF_MODNAME #define DPF_MODNAME "CResourceManager::Manage" HRESULT CResourceManager::Manage(CResource *pResource, RMHANDLE *pHandle) { *pHandle = 0; DXGASSERT(!pResource->IsD3DManaged()); CMgmtInfo *pRMInfo = new CMgmtInfo(pResource); if (pRMInfo == 0) { return E_OUTOFMEMORY; } *pHandle = pRMInfo; return S_OK; } // CResourceManager::Manage #undef DPF_MODNAME #define DPF_MODNAME "CResourceManager::UnManage" void CResourceManager::UnManage(RMHANDLE hRMHandle) { CMgmtInfo* &pMgmtInfo = hRMHandle; if (pMgmtInfo == 0) return; if (InVidmem(hRMHandle)) { m_heap_p[pMgmtInfo->m_rmHeap].del(pMgmtInfo); } delete pMgmtInfo; } // CResourceManager::UnManage #undef DPF_MODNAME #define DPF_MODNAME "CResourceManager::SetPriority" DWORD CResourceManager::SetPriority(RMHANDLE hRMHandle, DWORD newPriority) { CMgmtInfo* &pMgmtInfo = hRMHandle; DXGASSERT(pMgmtInfo != 0); DWORD oldPriority = pMgmtInfo->m_pBackup->SetPriorityI(newPriority); if (InVidmem(hRMHandle)) { m_heap_p[pMgmtInfo->m_rmHeap].update(pMgmtInfo, pMgmtInfo->m_bInUse, newPriority, pMgmtInfo->m_ticks); } return oldPriority; } // CResourceManager::SetPriority #undef DPF_MODNAME #define DPF_MODNAME "CResourceManager::SetLOD" DWORD CResourceManager::SetLOD(RMHANDLE hRMHandle, DWORD dwLodNew) { DWORD oldLOD; CMgmtInfo* &pMgmtInfo = hRMHandle; DXGASSERT(pMgmtInfo != 0); DXGASSERT(pMgmtInfo->m_pBackup->GetBufferDesc()->Type == D3DRTYPE_TEXTURE || pMgmtInfo->m_pBackup->GetBufferDesc()->Type == D3DRTYPE_VOLUMETEXTURE || pMgmtInfo->m_pBackup->GetBufferDesc()->Type == D3DRTYPE_CUBETEXTURE); CBaseTexture *pTex = static_cast(pMgmtInfo->m_pBackup); if (dwLodNew < pTex->GetLevelCount()) { oldLOD = pTex->SetLODI(dwLodNew); } else { DPF_ERR("Texture does not have sufficient miplevels for current LOD. LOD set to GetLevelCount()-1."); oldLOD = pTex->SetLODI(pTex->GetLevelCount() - 1); } if (InVidmem(hRMHandle)) { m_heap_p[pMgmtInfo->m_rmHeap].del(pMgmtInfo); pMgmtInfo->m_pRes->DecrementUseCount(); pMgmtInfo->m_pRes = 0; static_cast(this->m_pD3D8)->NeedResourceStateUpdate(); // Need to call this so that DrawPrimitive will do the necessary work } return oldLOD; } // CResourceManager::SetLOD #undef DPF_MODNAME #define DPF_MODNAME "CResourceManager::PreLoad" void CResourceManager::PreLoad(RMHANDLE hRMHandle) { CMgmtInfo* &pMgmtInfo = hRMHandle; DXGASSERT(pMgmtInfo != 0); BOOL bDirty = FALSE; m_PreLoading = TRUE; UpdateVideo(hRMHandle, &bDirty); m_PreLoading = FALSE; } // CResourceManaged::PreLoad #undef DPF_MODNAME #define DPF_MODNAME "CResourceManager::Lock" void CResourceManager::Lock(RMHANDLE hRMHandle) { if (hRMHandle != 0) { CMgmtInfo* &pMgmtInfo = hRMHandle; if (InVidmem(hRMHandle)) { m_heap_p[pMgmtInfo->m_rmHeap].update(pMgmtInfo, TRUE, pMgmtInfo->m_pBackup->GetPriorityI(), pMgmtInfo->m_ticks); } } } // CResourceManager::Lock #undef DPF_MODNAME #define DPF_MODNAME "CResourceManager::Unlock" void CResourceManager::Unlock(RMHANDLE hRMHandle) { if (hRMHandle != 0) { CMgmtInfo* &pMgmtInfo = hRMHandle; if (InVidmem(hRMHandle)) { m_heap_p[pMgmtInfo->m_rmHeap].update(pMgmtInfo, FALSE, pMgmtInfo->m_pBackup->GetPriorityI(), pMgmtInfo->m_ticks); } } } // CResourceManager::Unlock #undef DPF_MODNAME #define DPF_MODNAME "CResourceManager::FreeResources" BOOL CResourceManager::FreeResources(DWORD dwHeap, DWORD dwBytes) { if (m_heap_p[dwHeap].length() == 0) return FALSE; unsigned sz; CMgmtInfo *rc; for (unsigned i = 0; m_heap_p[dwHeap].length() != 0 && i < dwBytes; i += sz) { // Find the LRU texture and remove it. rc = m_heap_p[dwHeap].minCost(); if (rc->m_bInUse) return FALSE; sz = rc->m_pRes->GetBufferDesc()->Size; // save size if (rc->m_scene == m_dwScene) { if(m_PreLoading) { return TRUE; } if (m_pD3D8->GetD3DCaps()->RasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR) { DPF(0, "Trying to locate texture not used in current scene..."); rc = m_heap_p[dwHeap].extractNotInScene(m_dwScene); if (rc == 0) { DPF_ERR("No such texture found. Cannot evict textures used in current scene."); return FALSE; } DPF(0, "Texture found!"); rc->m_pRes->DecrementUseCount(); rc->m_pRes = 0; } else { DPF(1, "Texture cache thrashing. Removing MRU texture."); rc = m_heap_p[dwHeap].extractMax(); if (rc == 0) { DPF_ERR("All textures in use, cannot evict texture."); return FALSE; } rc->m_pRes->DecrementUseCount(); rc->m_pRes = 0; } } else { rc = m_heap_p[dwHeap].extractMin(); rc->m_pRes->DecrementUseCount(); rc->m_pRes = 0; } DPF(2, "Removed texture with timestamp %u,%u (current = %u).", rc->m_priority, rc->m_ticks, tcm_ticks); } return TRUE; } // CResourceManager::FreeResources #undef DPF_MODNAME #define DPF_MODNAME "CResourceManager::DiscardBytes" void CResourceManager::DiscardBytes(DWORD cbBytes) { for (DWORD i = 0; i < m_dwNumHeaps; ++i) { if (cbBytes == 0) { while(m_heap_p[i].length()) { CMgmtInfo *pMgmtInfo = m_heap_p[i].extractMin(); pMgmtInfo->m_pRes->DecrementUseCount(); pMgmtInfo->m_pRes = 0; } } else { FreeResources(i, cbBytes / m_dwNumHeaps); } } static_cast(m_pD3D8)->NeedResourceStateUpdate(); tcm_ticks = 0; m_dwScene = 0; } // CResourceManager::DiscardBytes #undef DPF_MODNAME #define DPF_MODNAME "CResourceManager::TimeStamp" void CResourceManager::TimeStamp(CMgmtInfo *pMgmtInfo) { pMgmtInfo->m_scene = m_dwScene; m_heap_p[pMgmtInfo->m_rmHeap].update(pMgmtInfo, pMgmtInfo->m_bInUse, pMgmtInfo->m_pBackup->GetPriorityI(), tcm_ticks); unsigned tickp2 = tcm_ticks + 2; if (tickp2 > tcm_ticks) { tcm_ticks = tickp2; } else // counter has overflowed. Let's reset all timestamps to zero { DPF(2, "Timestamp counter overflowed. Reseting timestamps for all textures."); tcm_ticks = 0; for (DWORD i = 0; i < m_dwNumHeaps; ++i) m_heap_p[i].resetAllTimeStamps(0); } } // CResourceManager::TimeStamp #undef DPF_MODNAME #define DPF_MODNAME "CResourceManager::UpdateVideoInternal" HRESULT CResourceManager::UpdateVideoInternal(CMgmtInfo *pMgmtInfo) { HRESULT ddrval; DWORD trycount = 0, bytecount = pMgmtInfo->m_pBackup->GetBufferDesc()->Size; LPD3DBASE lpDevI = static_cast(m_pD3D8); // We need to make sure that we don't evict any mapped textures for (DWORD dwStage = 0; dwStage < lpDevI->m_dwMaxTextureBlendStages; ++dwStage) { if (lpDevI->m_lpD3DMappedTexI[dwStage] != 0) { Lock(lpDevI->m_lpD3DMappedTexI[dwStage]->RMHandle()); } } for (DWORD dwStream = 0; dwStream < lpDevI->m_dwNumStreams; ++dwStream) { if (lpDevI->m_pStream[dwStream].m_pVB != 0) { Lock(lpDevI->m_pStream[dwStream].m_pVB->RMHandle()); } } if (lpDevI->m_pIndexStream->m_pVBI != 0) { Lock(lpDevI->m_pIndexStream->m_pVBI->RMHandle()); } // Attempt to allocate a texture. do { ++trycount; ddrval = pMgmtInfo->m_pBackup->Clone(D3DPOOL_DEFAULT, &pMgmtInfo->m_pRes); if (SUCCEEDED(ddrval)) // No problem, there is enough memory. { pMgmtInfo->m_scene = m_dwScene; pMgmtInfo->m_ticks = tcm_ticks; DXGASSERT(pMgmtInfo->m_rmHeapIndex == 0); if (!m_heap_p[pMgmtInfo->m_rmHeap].add(pMgmtInfo)) { ddrval = E_OUTOFMEMORY; goto exit2; } } else if (ddrval == D3DERR_OUTOFVIDEOMEMORY) // If out of video memory { if (!FreeResources(pMgmtInfo->m_rmHeap, bytecount)) { DPF_ERR("all Freed no further video memory available"); ddrval = D3DERR_OUTOFVIDEOMEMORY; //nothing left goto exit1; } bytecount <<= 1; } else { D3DRESOURCETYPE Type = pMgmtInfo->m_pBackup->GetBufferDesc()->Type; if (Type == D3DRTYPE_VERTEXBUFFER || Type == D3DRTYPE_INDEXBUFFER) { if (lpDevI->VBFailOversDisabled()) { DPF_ERR("Cannot create Vidmem or Driver managed VB/IB. Will ***NOT*** failover to Sysmem."); goto exit1; } // Fallback to sysmem DPF(5, "Driver does not support vidmem VB, falling back to sysmem"); CResource *pRes = pMgmtInfo->m_pBackup; pRes->DeleteRMHandle(); // HACK HACK HACK ((D3DBUFFER_DESC*)pRes->GetBufferDesc())->Pool = D3DPOOL_SYSTEMMEM; ddrval = S_OK; } else { DPF(0, "Unexpected error in Clone %08x", ddrval); } goto exit1; } } while (ddrval == D3DERR_OUTOFVIDEOMEMORY); if (trycount > 1) { lpDevI->NeedResourceStateUpdate(); DPF(1, "Allocated texture after %u tries.", trycount); } pMgmtInfo->m_pBackup->MarkAllDirty(); ddrval = pMgmtInfo->m_pBackup->UpdateDirtyPortion(pMgmtInfo->m_pRes); if (FAILED(ddrval)) { DPF(0, "Unexpected error in UpdateDirtyPortion %08x", ddrval); goto exit3; } ddrval = S_OK; goto exit1; exit3: m_heap_p[pMgmtInfo->m_rmHeap].del(pMgmtInfo); exit2: pMgmtInfo->m_pRes->DecrementUseCount(); pMgmtInfo->m_pRes = 0; exit1: for (dwStage = 0; dwStage < lpDevI->m_dwMaxTextureBlendStages; ++dwStage) { if (lpDevI->m_lpD3DMappedTexI[dwStage]) { Unlock(lpDevI->m_lpD3DMappedTexI[dwStage]->RMHandle()); } } for (dwStream = 0; dwStream < lpDevI->m_dwNumStreams; ++dwStream) { if (lpDevI->m_pStream[dwStream].m_pVB != 0) { Unlock(lpDevI->m_pStream[dwStream].m_pVB->RMHandle()); } } if (lpDevI->m_pIndexStream->m_pVBI != 0) { Unlock(lpDevI->m_pIndexStream->m_pVBI->RMHandle()); } return ddrval; } // CResourceManager::UpdateVideo #undef DPF_MODNAME #define DPF_MODNAME "CResourceManager::OnResourceDirty" void CResourceManager::OnResourceDirty(RMHANDLE hRMHandle) const { static_cast(m_pD3D8)->NeedResourceStateUpdate(); } // CResourceManager::OnResourceDirty // End of file : resource.cpp