Leaked source code of windows server 2003
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

/******************************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;
}