You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
411 lines
15 KiB
411 lines
15 KiB
/******************************Module*Header**********************************\
|
|
*
|
|
* *******************
|
|
* * D3D SAMPLE CODE *
|
|
* *******************
|
|
*
|
|
* Module Name: d3dtxman.c
|
|
*
|
|
* Content: D3D Texture manager
|
|
*
|
|
* Copyright (c) 1995-1999 Microsoft Corporation. All rights Reserved.
|
|
\*****************************************************************************/
|
|
#include "precomp.h"
|
|
#include "d3dtxman.h"
|
|
#include "dd.h"
|
|
#include "heap.h"
|
|
#define ALLOC_TAG ALLOC_TAG_TD2P
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// void TextureHeapHeapify
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void TextureHeapHeapify(PTextureHeap pTextureHeap, DWORD k)
|
|
{
|
|
while(true)
|
|
{
|
|
DWORD smallest;
|
|
DWORD l = lchild(k);
|
|
DWORD r = rchild(k);
|
|
if(l < pTextureHeap->m_next)
|
|
if(TextureCost(pTextureHeap->m_data_p[l]) <
|
|
TextureCost(pTextureHeap->m_data_p[k]))
|
|
smallest = l;
|
|
else
|
|
smallest = k;
|
|
else
|
|
smallest = k;
|
|
if(r < pTextureHeap->m_next)
|
|
if(TextureCost(pTextureHeap->m_data_p[r]) <
|
|
TextureCost(pTextureHeap->m_data_p[smallest]))
|
|
smallest = r;
|
|
if(smallest != k)
|
|
{
|
|
PPERMEDIA_D3DTEXTURE t = pTextureHeap->m_data_p[k];
|
|
pTextureHeap->m_data_p[k] = pTextureHeap->m_data_p[smallest];
|
|
pTextureHeap->m_data_p[k]->m_dwHeapIndex = k;
|
|
pTextureHeap->m_data_p[smallest] = t;
|
|
t->m_dwHeapIndex = smallest;
|
|
k = smallest;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// bool TextureHeapAdd
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
bool TextureHeapAdd(PTextureHeap pTextureHeap, PPERMEDIA_D3DTEXTURE lpD3DTexI)
|
|
{
|
|
if(pTextureHeap->m_next == pTextureHeap->m_size)
|
|
{
|
|
pTextureHeap->m_size = pTextureHeap->m_size * 2 - 1;
|
|
PPERMEDIA_D3DTEXTURE *p = (PPERMEDIA_D3DTEXTURE *)
|
|
ENGALLOCMEM( FL_ZERO_MEMORY,
|
|
sizeof(PPERMEDIA_D3DTEXTURE)*pTextureHeap->m_size,ALLOC_TAG);
|
|
|
|
if(p == 0)
|
|
{
|
|
DBG_D3D((0,"Failed to allocate memory to grow heap."));
|
|
pTextureHeap->m_size = (pTextureHeap->m_size + 1) / 2; // restore size
|
|
return false;
|
|
}
|
|
memcpy(p + 1, pTextureHeap->m_data_p + 1,
|
|
sizeof(PPERMEDIA_D3DTEXTURE) * (pTextureHeap->m_next - 1));
|
|
ENGFREEMEM( pTextureHeap->m_data_p);
|
|
pTextureHeap->m_data_p = p;
|
|
}
|
|
ULONGLONG Cost = TextureCost(lpD3DTexI);
|
|
for(DWORD k = pTextureHeap->m_next; k > 1; k = parent(k))
|
|
if(Cost < TextureCost(pTextureHeap->m_data_p[parent(k)]))
|
|
{
|
|
pTextureHeap->m_data_p[k] = pTextureHeap->m_data_p[parent(k)];
|
|
pTextureHeap->m_data_p[k]->m_dwHeapIndex = k;
|
|
}
|
|
else
|
|
break;
|
|
pTextureHeap->m_data_p[k] = lpD3DTexI;
|
|
lpD3DTexI->m_dwHeapIndex = k;
|
|
++pTextureHeap->m_next;
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// PPERMEDIA_D3DTEXTURE TextureHeapExtractMin
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
PPERMEDIA_D3DTEXTURE TextureHeapExtractMin(PTextureHeap pTextureHeap)
|
|
{
|
|
PPERMEDIA_D3DTEXTURE lpD3DTexI = pTextureHeap->m_data_p[1];
|
|
--pTextureHeap->m_next;
|
|
pTextureHeap->m_data_p[1] = pTextureHeap->m_data_p[pTextureHeap->m_next];
|
|
pTextureHeap->m_data_p[1]->m_dwHeapIndex = 1;
|
|
TextureHeapHeapify(pTextureHeap,1);
|
|
lpD3DTexI->m_dwHeapIndex = 0;
|
|
return lpD3DTexI;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// PPERMEDIA_D3DTEXTURE TextureHeapExtractMax
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
PPERMEDIA_D3DTEXTURE TextureHeapExtractMax(PTextureHeap pTextureHeap)
|
|
{
|
|
// 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.
|
|
unsigned max = pTextureHeap->m_next - 1;
|
|
ULONGLONG maxcost = 0;
|
|
for(unsigned i = max; lchild(i) >= pTextureHeap->m_next; --i)
|
|
{
|
|
ULONGLONG Cost = TextureCost(pTextureHeap->m_data_p[i]);
|
|
if(maxcost < Cost)
|
|
{
|
|
maxcost = Cost;
|
|
max = i;
|
|
}
|
|
}
|
|
PPERMEDIA_D3DTEXTURE lpD3DTexI = pTextureHeap->m_data_p[max];
|
|
TextureHeapDel(pTextureHeap,max);
|
|
return lpD3DTexI;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// void TextureHeapDel
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void TextureHeapDel(PTextureHeap pTextureHeap, DWORD k)
|
|
{
|
|
PPERMEDIA_D3DTEXTURE lpD3DTexI = pTextureHeap->m_data_p[k];
|
|
--pTextureHeap->m_next;
|
|
ULONGLONG Cost = TextureCost(pTextureHeap->m_data_p[pTextureHeap->m_next]);
|
|
if(Cost < TextureCost(lpD3DTexI))
|
|
{
|
|
while(k > 1)
|
|
{
|
|
if(Cost < TextureCost(pTextureHeap->m_data_p[parent(k)]))
|
|
{
|
|
pTextureHeap->m_data_p[k] = pTextureHeap->m_data_p[parent(k)];
|
|
pTextureHeap->m_data_p[k]->m_dwHeapIndex = k;
|
|
}
|
|
else
|
|
break;
|
|
k = parent(k);
|
|
}
|
|
pTextureHeap->m_data_p[k] = pTextureHeap->m_data_p[pTextureHeap->m_next];
|
|
pTextureHeap->m_data_p[k]->m_dwHeapIndex = k;
|
|
}
|
|
else
|
|
{
|
|
pTextureHeap->m_data_p[k] = pTextureHeap->m_data_p[pTextureHeap->m_next];
|
|
pTextureHeap->m_data_p[k]->m_dwHeapIndex = k;
|
|
TextureHeapHeapify(pTextureHeap,k);
|
|
}
|
|
lpD3DTexI->m_dwHeapIndex = 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// void TextureHeapUpdate
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void TextureHeapUpdate(PTextureHeap pTextureHeap, DWORD k,
|
|
DWORD priority, DWORD ticks)
|
|
{
|
|
PPERMEDIA_D3DTEXTURE lpD3DTexI = pTextureHeap->m_data_p[k];
|
|
ULONGLONG Cost = 0;
|
|
#ifdef _X86_
|
|
_asm
|
|
{
|
|
mov edx, 0;
|
|
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)priority << 31) + ((ULONGLONG)(ticks >> 1));
|
|
#endif
|
|
if(Cost < TextureCost(lpD3DTexI))
|
|
{
|
|
while(k > 1)
|
|
{
|
|
if(Cost < TextureCost(pTextureHeap->m_data_p[parent(k)]))
|
|
{
|
|
pTextureHeap->m_data_p[k] = pTextureHeap->m_data_p[parent(k)];
|
|
pTextureHeap->m_data_p[k]->m_dwHeapIndex = k;
|
|
}
|
|
else
|
|
break;
|
|
k = parent(k);
|
|
}
|
|
lpD3DTexI->m_dwPriority = priority;
|
|
lpD3DTexI->m_dwTicks = ticks;
|
|
lpD3DTexI->m_dwHeapIndex = k;
|
|
pTextureHeap->m_data_p[k] = lpD3DTexI;
|
|
}
|
|
else
|
|
{
|
|
lpD3DTexI->m_dwPriority = priority;
|
|
lpD3DTexI->m_dwTicks = ticks;
|
|
TextureHeapHeapify(pTextureHeap,k);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// HRESULT TextureCacheManagerInitialize
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT TextureCacheManagerInitialize(
|
|
PTextureCacheManager pTextureCacheManager)
|
|
{
|
|
pTextureCacheManager->tcm_ticks = 0;
|
|
pTextureCacheManager->m_heap.m_next = 1;
|
|
pTextureCacheManager->m_heap.m_size = 1024;
|
|
pTextureCacheManager->m_heap.m_data_p = (PPERMEDIA_D3DTEXTURE *)
|
|
ENGALLOCMEM( FL_ZERO_MEMORY,
|
|
sizeof(PPERMEDIA_D3DTEXTURE)*pTextureCacheManager->m_heap.m_size,
|
|
ALLOC_TAG);
|
|
if(pTextureCacheManager->m_heap.m_data_p == 0)
|
|
{
|
|
DBG_D3D((0,"Failed to allocate texture heap."));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
memset(pTextureCacheManager->m_heap.m_data_p, 0,
|
|
sizeof(PPERMEDIA_D3DTEXTURE) * pTextureCacheManager->m_heap.m_size);
|
|
return D3D_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// BOOL TextureCacheManagerFreeTextures
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL TextureCacheManagerFreeTextures(
|
|
PTextureCacheManager pTextureCacheManager,DWORD dwStage, DWORD dwBytes)
|
|
{
|
|
if(pTextureCacheManager->m_heap.m_next <= 1)
|
|
return false;
|
|
PPERMEDIA_D3DTEXTURE rc;
|
|
for(unsigned i = 0;
|
|
pTextureCacheManager->m_heap.m_next > 1 && i < dwBytes;
|
|
i += rc->m_dwBytes)
|
|
{
|
|
// Find the LRU texture and remove it.
|
|
rc = TextureHeapExtractMin(&pTextureCacheManager->m_heap);
|
|
TextureCacheManagerRemove(pTextureCacheManager,rc);
|
|
pTextureCacheManager->m_stats.dwLastPri = rc->m_dwPriority;
|
|
++pTextureCacheManager->m_stats.dwNumEvicts;
|
|
DBG_D3D((2, "Removed texture with timestamp %u,%u (current = %u).",
|
|
rc->m_dwPriority, rc->m_dwTicks, pTextureCacheManager->tcm_ticks));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// HRESULT TextureCacheManagerAllocNode
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT TextureCacheManagerAllocNode(
|
|
PERMEDIA_D3DCONTEXT* pContext,
|
|
PPERMEDIA_D3DTEXTURE pTexture)
|
|
{
|
|
DWORD trycount = 0, bytecount = pTexture->m_dwBytes;
|
|
PermediaSurfaceData* pPrivateData=pTexture->pTextureSurface;
|
|
PTextureCacheManager pTextureCacheManager=pContext->pTextureManager;
|
|
if (NULL == pPrivateData)
|
|
{
|
|
DBG_D3D((0,"pTextureSurface==NULL invalid texture"));
|
|
return D3D_OK; //we already have the video memory allocated
|
|
}
|
|
// Attempt to allocate a texture.
|
|
while(NULL == pPrivateData->fpVidMem)
|
|
{
|
|
LONG lScratchDelta;
|
|
DWORD PackedPP;
|
|
++trycount;
|
|
pPrivateData->fpVidMem=(FLATPTR)
|
|
ulVidMemAllocate( pContext->ppdev,
|
|
pTexture->wWidth,
|
|
pTexture->wHeight,
|
|
ShiftLookup[pTexture->dwRGBBitCount>>3],
|
|
&lScratchDelta,
|
|
&pPrivateData->pvmHeap,
|
|
&PackedPP,
|
|
FALSE);
|
|
DBG_D3D((8,"Got fpVidMem=%08lx",pPrivateData->fpVidMem));
|
|
if (NULL != pPrivateData->fpVidMem)
|
|
{ // No problem, there is enough memory.
|
|
pTexture->m_dwTicks = pTextureCacheManager->tcm_ticks;
|
|
if(!TextureHeapAdd(&pTextureCacheManager->m_heap,pTexture))
|
|
{
|
|
VidMemFree(pPrivateData->pvmHeap->lpHeap,
|
|
pPrivateData->fpVidMem);
|
|
pPrivateData->fpVidMem=NULL;
|
|
DBG_D3D((0,"Out of memory"));
|
|
return DDERR_OUTOFMEMORY;
|
|
}
|
|
pPrivateData->dwFlags |= P2_SURFACE_NEEDUPDATE;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (!TextureCacheManagerFreeTextures(
|
|
pTextureCacheManager,0, bytecount))
|
|
{
|
|
DBG_D3D((0,"all Freed no further video memory available"));
|
|
return DDERR_OUTOFVIDEOMEMORY; //nothing left
|
|
}
|
|
bytecount <<= 1;
|
|
}
|
|
}
|
|
if(trycount > 1)
|
|
{
|
|
DBG_D3D((8, "Allocated texture after %u tries.", trycount));
|
|
}
|
|
TextureCacheManagerIncTotSz(pTextureCacheManager,
|
|
pTexture->m_dwBytes);
|
|
++pTextureCacheManager->m_stats.dwWorkingSet;
|
|
pTextureCacheManager->m_stats.dwWorkingSetBytes
|
|
+= (pTexture->m_dwBytes);
|
|
++pTextureCacheManager->m_stats.dwNumVidCreates;
|
|
return D3D_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// void TextureCacheManagerRemove
|
|
//
|
|
// remove all HW handles and release surface
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void TextureCacheManagerRemove(
|
|
PTextureCacheManager pTextureCacheManager,
|
|
PPERMEDIA_D3DTEXTURE pTexture)
|
|
{
|
|
PermediaSurfaceData* pPrivateData=pTexture->pTextureSurface;
|
|
if (CHECK_P2_SURFACEDATA_VALIDITY(pPrivateData) && pPrivateData->fpVidMem)
|
|
{
|
|
VidMemFree(pPrivateData->pvmHeap->lpHeap,pPrivateData->fpVidMem);
|
|
pPrivateData->fpVidMem=NULL;
|
|
TextureCacheManagerDecTotSz(pTextureCacheManager,
|
|
pTexture->m_dwBytes);
|
|
--pTextureCacheManager->m_stats.dwWorkingSet;
|
|
pTextureCacheManager->m_stats.dwWorkingSetBytes -=
|
|
(pTexture->m_dwBytes);
|
|
}
|
|
if (pTexture->m_dwHeapIndex && pTextureCacheManager->m_heap.m_data_p)
|
|
TextureHeapDel(&pTextureCacheManager->m_heap,
|
|
pTexture->m_dwHeapIndex);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// void TextureCacheManagerEvictTextures
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void TextureCacheManagerEvictTextures(
|
|
PTextureCacheManager pTextureCacheManager)
|
|
{
|
|
while(pTextureCacheManager->m_heap.m_next > 1)
|
|
{
|
|
PPERMEDIA_D3DTEXTURE lpD3DTexI =
|
|
TextureHeapExtractMin(&pTextureCacheManager->m_heap);
|
|
TextureCacheManagerRemove(pTextureCacheManager,lpD3DTexI);
|
|
}
|
|
pTextureCacheManager->tcm_ticks = 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// void TextureCacheManagerTimeStamp
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void TextureCacheManagerTimeStamp(
|
|
PTextureCacheManager pTextureCacheManager,PPERMEDIA_D3DTEXTURE lpD3DTexI)
|
|
{
|
|
TextureHeapUpdate(&pTextureCacheManager->m_heap,
|
|
lpD3DTexI->m_dwHeapIndex, lpD3DTexI->m_dwPriority,
|
|
pTextureCacheManager->tcm_ticks);
|
|
pTextureCacheManager->tcm_ticks += 2;
|
|
}
|