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.
1312 lines
44 KiB
1312 lines
44 KiB
/******************************Module*Header**********************************\
|
|
*
|
|
* *******************
|
|
* * D3D SAMPLE CODE *
|
|
* *******************
|
|
*
|
|
* Module Name: d3dbuff.c
|
|
*
|
|
//@@BEGIN_DDKSPLIT
|
|
* Content: Main context callbacks for D3D videomemory buffers
|
|
//@@END_DDKSPLIT
|
|
*
|
|
* Copyright (c) 1994-1999 3Dlabs Inc. Ltd. All rights reserved.
|
|
* Copyright (c) 1995-2003 Microsoft Corporation. All rights reserved.
|
|
\*****************************************************************************/
|
|
|
|
#include "glint.h"
|
|
#include "dma.h"
|
|
#include "tag.h"
|
|
|
|
//@@BEGIN_DDKSPLIT
|
|
#if DX7_VERTEXBUFFERS
|
|
|
|
#define _32_KBYTES ( 32 * 1024 )
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// in-the-file nonexported forward declarations
|
|
//-----------------------------------------------------------------------------
|
|
|
|
BOOL __EB_RemoveFromBufferQueue(P3_THUNKEDDATA* pThisDisplay,
|
|
P3_VERTEXBUFFERINFO* pVictim);
|
|
void __EB_Wait(P3_THUNKEDDATA* pThisDisplay, P3_VERTEXBUFFERINFO* pBuffer);
|
|
|
|
#if DBG
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// __EB_DisplayHeapInfo
|
|
//
|
|
// A debug function. Displays the current buffer queue
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
__EB_DisplayHeapInfo(
|
|
int DebugLevel,
|
|
P3_THUNKEDDATA* pThisDisplay)
|
|
{
|
|
DWORD dwSequenceID = 0xFFFFFFFF;
|
|
|
|
if (DebugLevel <= P3R3DX_DebugLevel)
|
|
{
|
|
P3_VERTEXBUFFERINFO* pCurrentCommandBuffer =
|
|
pThisDisplay->pRootCommandBuffer;
|
|
P3_VERTEXBUFFERINFO* pCurrentVertexBuffer =
|
|
pThisDisplay->pRootVertexBuffer;
|
|
int count = 0;
|
|
|
|
DISPDBG((DebugLevel,"Command buffer heap"));
|
|
|
|
dwSequenceID = 0xFFFFFFFF;
|
|
if (pCurrentCommandBuffer)
|
|
{
|
|
do
|
|
{
|
|
// A debug check to ensure that the sequence ID's go backwards
|
|
ASSERTDD((dwSequenceID >= pCurrentCommandBuffer->dwSequenceID),
|
|
"ERROR: Sequence ID's broken!");
|
|
|
|
DISPDBG((DebugLevel,"Buffer %d,SequenceID:0x%x Pointer: 0x%x",
|
|
count++,
|
|
pCurrentCommandBuffer->dwSequenceID,
|
|
pCurrentCommandBuffer));
|
|
DISPDBG((DebugLevel," pPrev: 0x%x, pNext: 0x%x",
|
|
pCurrentCommandBuffer->pPrev,
|
|
pCurrentCommandBuffer->pNext));
|
|
DISPDBG((DebugLevel," bInUse: %d",
|
|
pCurrentCommandBuffer->bInUse));
|
|
|
|
dwSequenceID = pCurrentCommandBuffer->dwSequenceID;
|
|
pCurrentCommandBuffer = pCurrentCommandBuffer->pNext;
|
|
|
|
} while (pCurrentCommandBuffer != pThisDisplay->pRootCommandBuffer);
|
|
}
|
|
|
|
DISPDBG((DebugLevel,"Vertex buffer heap"));
|
|
|
|
dwSequenceID = 0xFFFFFFFF;
|
|
if (pCurrentVertexBuffer)
|
|
{
|
|
do
|
|
{
|
|
// A debug check to ensure that the sequence ID's go backwards
|
|
ASSERTDD((dwSequenceID >= pCurrentVertexBuffer->dwSequenceID),
|
|
"ERROR: Sequence ID's broken!");
|
|
|
|
DISPDBG((DebugLevel,"Buffer %d,SequenceID:0x%x Pointer: 0x%x",
|
|
count++,
|
|
pCurrentVertexBuffer->dwSequenceID,
|
|
pCurrentVertexBuffer));
|
|
DISPDBG((DebugLevel," pPrev: 0x%x, pNext: 0x%x",
|
|
pCurrentVertexBuffer->pPrev,
|
|
pCurrentVertexBuffer->pNext));
|
|
DISPDBG((DebugLevel," bInUse: %d",
|
|
pCurrentVertexBuffer->bInUse));
|
|
|
|
dwSequenceID = pCurrentVertexBuffer->dwSequenceID;
|
|
pCurrentVertexBuffer = pCurrentVertexBuffer->pNext;
|
|
} while (pCurrentVertexBuffer != pThisDisplay->pRootVertexBuffer);
|
|
}
|
|
|
|
}
|
|
|
|
} // __EB_DisplayHeapInfo
|
|
|
|
#endif // DBG
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// __EB_FreeCachedBuffer
|
|
//
|
|
// Frees a buffer associated with this directdraw surface. This is called
|
|
// in response to a destroyexecutebuffer call
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
__EB_FreeCachedBuffer(
|
|
P3_THUNKEDDATA* pThisDisplay,
|
|
LPDDRAWI_DDRAWSURFACE_LCL pSurf)
|
|
{
|
|
P3_VERTEXBUFFERINFO* pVictim =
|
|
(P3_VERTEXBUFFERINFO*)pSurf->lpGbl->dwReserved1;
|
|
|
|
if (pVictim != NULL)
|
|
{
|
|
DISPDBG((DBGLVL,"Buffer is one of ours - destroying it"));
|
|
|
|
// Wait for the buffer to be consumed
|
|
__EB_Wait(pThisDisplay, pVictim);
|
|
|
|
// Set the inuse flag off so the buffer will be freed.
|
|
pVictim->bInUse = FALSE;
|
|
|
|
// Remove the buffer from the pending list
|
|
// The memory won't be freed if the buffer isn't in the list
|
|
if (!__EB_RemoveFromBufferQueue(pThisDisplay, pVictim))
|
|
{
|
|
// Free the memory
|
|
switch (pVictim->BufferType)
|
|
{
|
|
case COMMAND_BUFFER:
|
|
_DX_LIN_FreeLinearMemory(&pThisDisplay->CachedCommandHeapInfo,
|
|
PtrToUlong(pVictim));
|
|
break;
|
|
|
|
case VERTEX_BUFFER:
|
|
_DX_LIN_FreeLinearMemory(&pThisDisplay->CachedVertexHeapInfo,
|
|
PtrToUlong(pVictim));
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Reset the buffer pointers
|
|
pSurf->lpGbl->dwReserved1 = 0;
|
|
pSurf->lpGbl->fpVidMem = 0;
|
|
}
|
|
|
|
} // __EB_FreeCachedBuffer
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// __EB_GetSequenceID
|
|
//
|
|
// Each vertex buffer and command buffer is "stamped" with a sequence ID which
|
|
// can be queried in order to find out if a given buffer was already consumed
|
|
// by the hardware. __EB_GetSequenceID returns us the sequence ID of the last
|
|
// processed buffer.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
const DWORD
|
|
__EB_GetSequenceID(
|
|
P3_THUNKEDDATA* pThisDisplay)
|
|
{
|
|
DWORD dwSequenceID;
|
|
|
|
dwSequenceID = READ_GLINT_CTRL_REG(HostInID);
|
|
|
|
DISPDBG((DBGLVL,"HostIn ID: 0x%x", dwSequenceID));
|
|
|
|
return dwSequenceID;
|
|
|
|
} // __EB_GetSequenceID
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// __EB_GetNewSequenceID
|
|
//
|
|
// A driver routine to increment the sequence ID and return it. This
|
|
// routine handles the case where the buffer is wrapped beyond the maximum
|
|
// number that it can hold. In such case all buffers are flushed
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
const DWORD
|
|
__EB_GetNewSequenceID(
|
|
P3_THUNKEDDATA* pThisDisplay)
|
|
{
|
|
DWORD dwWrapMask;
|
|
|
|
DBG_ENTRY(__EB_GetNewSequenceID);
|
|
|
|
#if DBG
|
|
dwWrapMask = 0x1F;
|
|
#else
|
|
dwWrapMask = 0xFFFFFFFF;
|
|
#endif
|
|
|
|
if( pThisDisplay->dwCurrentSequenceID >= dwWrapMask )
|
|
{
|
|
// We have wrapped, so flush all the buffers
|
|
// but wait for them to be consumed (bWait == TRUE)
|
|
_D3D_EB_FlushAllBuffers(pThisDisplay , TRUE);
|
|
|
|
// This SYNC is needed for unknown reasons - further investigation
|
|
// required. //azn???
|
|
|
|
SYNC_WITH_GLINT;
|
|
|
|
// Reset the sequence ID numbering
|
|
pThisDisplay->dwCurrentSequenceID = 0;
|
|
}
|
|
else
|
|
{
|
|
pThisDisplay->dwCurrentSequenceID++;
|
|
}
|
|
|
|
DISPDBG((DBGLVL, "Returning Sequence ID: 0x%x",
|
|
pThisDisplay->dwCurrentSequenceID));
|
|
|
|
DBG_EXIT(__EB_GetNewSequenceID,pThisDisplay->dwCurrentSequenceID);
|
|
return pThisDisplay->dwCurrentSequenceID;
|
|
|
|
} // __EB_GetNewSequenceID
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// __EB_Wait
|
|
//
|
|
// If the current buffer is in the queue, wait for it to pass through
|
|
// the chip.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
__EB_Wait(
|
|
P3_THUNKEDDATA* pThisDisplay,
|
|
P3_VERTEXBUFFERINFO* pBuffer)
|
|
{
|
|
DBG_ENTRY(__EB_Wait);
|
|
|
|
ASSERTDD(pBuffer, "ERROR: Buffer passed to __EB_Wait is null!");
|
|
|
|
// Don't wait for the buffer, if it has not been added to the queue
|
|
if (pBuffer->pNext != NULL)
|
|
{
|
|
// Flush to ensure that the hostin ID has been sent to the chip
|
|
P3_DMA_DEFS();
|
|
P3_DMA_GET_BUFFER();
|
|
P3_DMA_FLUSH_BUFFER();
|
|
|
|
DISPDBG((DBGLVL, "*** In __EB_Wait: Buffer Sequence ID: 0x%x",
|
|
pBuffer->dwSequenceID));
|
|
|
|
while (__EB_GetSequenceID(pThisDisplay) < pBuffer->dwSequenceID)
|
|
{
|
|
static int blockCount;
|
|
|
|
// This buffer is in the chain of buffers that are being used
|
|
// by the host-in unit. We must wait for it to be consumed
|
|
// before freeing it.
|
|
|
|
blockCount = 100;
|
|
while( blockCount-- )
|
|
NULL;
|
|
}
|
|
}
|
|
|
|
DBG_EXIT(__EB_Wait,0);
|
|
} // __EB_Wait
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// __EB_RemoveFromBufferQueue
|
|
//
|
|
// Removes a buffer from the queue. Will also free the associated memory
|
|
// if it is no longer in use
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL
|
|
__EB_RemoveFromBufferQueue(
|
|
P3_THUNKEDDATA* pThisDisplay,
|
|
P3_VERTEXBUFFERINFO* pVictim)
|
|
{
|
|
ASSERTDD(pVictim != NULL,
|
|
"ERROR: NULL buffer passed to EB_RemoveFromList");
|
|
|
|
DBG_ENTRY(__EB_RemoveFromBufferQueue);
|
|
|
|
// Don't remove a buffer that isn't already in the queue
|
|
if (pVictim->pNext == NULL)
|
|
{
|
|
DBG_EXIT(__EB_RemoveFromBufferQueue,FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
DISPDBG((DBGLVL,"Removing buffer for queue, ID: 0x%x",
|
|
pVictim->dwSequenceID));
|
|
|
|
// Remove this entry from the list
|
|
pVictim->pPrev->pNext = pVictim->pNext;
|
|
pVictim->pNext->pPrev = pVictim->pPrev;
|
|
|
|
switch (pVictim->BufferType)
|
|
{
|
|
case COMMAND_BUFFER:
|
|
// Replace the root node if necessary
|
|
if (pVictim == pThisDisplay->pRootCommandBuffer)
|
|
{
|
|
if (pVictim->pNext != pThisDisplay->pRootCommandBuffer)
|
|
{
|
|
pThisDisplay->pRootCommandBuffer = pVictim->pNext;
|
|
}
|
|
else
|
|
{
|
|
pThisDisplay->pRootCommandBuffer = NULL;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case VERTEX_BUFFER:
|
|
// Replace the root node if necessary
|
|
if (pVictim == pThisDisplay->pRootVertexBuffer)
|
|
{
|
|
if (pVictim->pNext != pThisDisplay->pRootVertexBuffer)
|
|
{
|
|
pThisDisplay->pRootVertexBuffer = pVictim->pNext;
|
|
}
|
|
else
|
|
{
|
|
pThisDisplay->pRootVertexBuffer = NULL;
|
|
}
|
|
}
|
|
break;
|
|
|
|
} // switch (pVictim->BufferType)
|
|
|
|
// Buffer is no longer in the list
|
|
pVictim->pPrev = NULL;
|
|
pVictim->pNext = NULL;
|
|
|
|
// Free the memory we found if it isn't reserved as a real buffer.
|
|
if (!pVictim->bInUse)
|
|
{
|
|
DISPDBG((DBGLVL," Buffer is old - freeing the memory"));
|
|
|
|
switch (pVictim->BufferType)
|
|
{
|
|
case COMMAND_BUFFER:
|
|
_DX_LIN_FreeLinearMemory(&pThisDisplay->CachedCommandHeapInfo,
|
|
PtrToUlong(pVictim));
|
|
break;
|
|
|
|
case VERTEX_BUFFER:
|
|
_DX_LIN_FreeLinearMemory(&pThisDisplay->CachedVertexHeapInfo,
|
|
PtrToUlong(pVictim));
|
|
break;
|
|
}
|
|
|
|
DBG_EXIT(__EB_RemoveFromBufferQueue,TRUE);
|
|
return TRUE;
|
|
}
|
|
|
|
DBG_EXIT(__EB_RemoveFromBufferQueue,FALSE);
|
|
return FALSE;
|
|
|
|
} // __EB_RemoveFromBufferQueue
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// __EB_AddToBufferQueue
|
|
//
|
|
// Adds a buffer to the queue. Note that buffers are always added
|
|
// at the start to maintain a temporal ordering of the buffers.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
__EB_AddToBufferQueue(
|
|
P3_THUNKEDDATA* pThisDisplay,
|
|
P3_VERTEXBUFFERINFO* pNewBuffer)
|
|
{
|
|
DBG_ENTRY(__EB_AddToBufferQueue);
|
|
|
|
ASSERTDD(pNewBuffer != NULL,
|
|
"ERROR: NULL buffer passed to EB_AddToList");
|
|
ASSERTDD(pNewBuffer->pNext == NULL,
|
|
"ERROR: Buffer already in queue (pNext!NULL)");
|
|
ASSERTDD(pNewBuffer->pPrev == NULL,
|
|
"ERROR: Buffer already in queue (pPrev!NULL)");
|
|
|
|
switch(pNewBuffer->BufferType)
|
|
{
|
|
case COMMAND_BUFFER:
|
|
// Add the buffer to the queue
|
|
// Check that the queue isn't empty.
|
|
// If it is start a new list
|
|
if (pThisDisplay->pRootCommandBuffer == NULL)
|
|
{
|
|
DISPDBG((DBGLVL,"Command Buffer queue is empty."
|
|
" Starting a new one"));
|
|
|
|
// Sew in the buffer
|
|
pThisDisplay->pRootCommandBuffer = pNewBuffer;
|
|
pNewBuffer->pNext = pNewBuffer;
|
|
pNewBuffer->pPrev = pNewBuffer;
|
|
}
|
|
else
|
|
{
|
|
DISPDBG((DBGLVL,"Adding command buffer to the list"));
|
|
|
|
// Always put new buffers at the root.
|
|
pNewBuffer->pNext = pThisDisplay->pRootCommandBuffer;
|
|
pNewBuffer->pPrev = pThisDisplay->pRootCommandBuffer->pPrev;
|
|
pThisDisplay->pRootCommandBuffer->pPrev->pNext = pNewBuffer;
|
|
pThisDisplay->pRootCommandBuffer->pPrev = pNewBuffer;
|
|
pThisDisplay->pRootCommandBuffer = pNewBuffer;
|
|
}
|
|
break;
|
|
|
|
case VERTEX_BUFFER:
|
|
// Add the buffer to the queue
|
|
// Check that the queue isn't empty. If it is start a new list
|
|
if (pThisDisplay->pRootVertexBuffer == NULL)
|
|
{
|
|
DISPDBG((DBGLVL,"Vertex Buffer queue is empty. Starting a new one"));
|
|
|
|
// Sew in the buffer
|
|
pThisDisplay->pRootVertexBuffer = pNewBuffer;
|
|
pNewBuffer->pNext = pNewBuffer;
|
|
pNewBuffer->pPrev = pNewBuffer;
|
|
}
|
|
else
|
|
{
|
|
DISPDBG((DBGLVL,"Adding vertex buffer to the list"));
|
|
|
|
// Always put new buffers at the root.
|
|
pNewBuffer->pNext = pThisDisplay->pRootVertexBuffer;
|
|
pNewBuffer->pPrev = pThisDisplay->pRootVertexBuffer->pPrev;
|
|
pThisDisplay->pRootVertexBuffer->pPrev->pNext = pNewBuffer;
|
|
pThisDisplay->pRootVertexBuffer->pPrev = pNewBuffer;
|
|
pThisDisplay->pRootVertexBuffer = pNewBuffer;
|
|
}
|
|
break;
|
|
} // switch(pNewBuffer->BufferType)
|
|
|
|
|
|
DISPDBG((DBGLVL, "Added buffer to queue, ID: 0x%x", pNewBuffer->dwSequenceID));
|
|
DBG_EXIT(__EB_AddToBufferQueue,pNewBuffer->dwSequenceID);
|
|
|
|
} // __EB_AddToBufferQueue
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// __EB_AllocateCachedBuffer
|
|
//
|
|
// Allocates a cached buffer and stores it in the surface structure.
|
|
// First this function will try to allocate out of the linear heap.
|
|
// If this fails, it will keep walking the buffer queue until there
|
|
// are no more buffers left that are pending and aren't in use.
|
|
// If all else fails this driver will return FALSE indicating that
|
|
// it couldn't allocate the memory due to lack of space
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL
|
|
__EB_AllocateCachedBuffer(
|
|
P3_THUNKEDDATA* pThisDisplay,
|
|
DWORD dwBytes,
|
|
LPDDRAWI_DDRAWSURFACE_LCL pSurf)
|
|
{
|
|
P3_MEMREQUEST mmrq;
|
|
DWORD dwResult;
|
|
P3_VERTEXBUFFERINFO* pCurrentBuffer;
|
|
P3_VERTEXBUFFERINFO** ppRootBuffer;
|
|
BOOL bFound;
|
|
eBufferType BufferType;
|
|
pLinearAllocatorInfo pAllocHeap;
|
|
static int blockCount;
|
|
|
|
DBG_ENTRY(__EB_AllocateCachedBuffer);
|
|
|
|
#if WNT_DDRAW
|
|
pAllocHeap = &pThisDisplay->CachedVertexHeapInfo;
|
|
BufferType = VERTEX_BUFFER;
|
|
ppRootBuffer = &pThisDisplay->pRootVertexBuffer;
|
|
#else
|
|
// Decide on which heap this surface should come out of.
|
|
if (pSurf->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_COMMANDBUFFER)
|
|
{
|
|
pAllocHeap = &pThisDisplay->CachedCommandHeapInfo;
|
|
BufferType = COMMAND_BUFFER;
|
|
ppRootBuffer = &pThisDisplay->pRootCommandBuffer;
|
|
|
|
DISPDBG((DBGLVL,"Buffer is COMMAND_BUFFER"));
|
|
}
|
|
else
|
|
{
|
|
pAllocHeap = &pThisDisplay->CachedVertexHeapInfo;
|
|
BufferType = VERTEX_BUFFER;
|
|
ppRootBuffer = &pThisDisplay->pRootVertexBuffer;
|
|
|
|
DISPDBG((DBGLVL,"Buffer is VERTEX_BUFFER"));
|
|
}
|
|
#endif // WNT_DDRAW
|
|
|
|
#if DBG
|
|
// Dump the memory and the pending buffer heaps.
|
|
__EB_DisplayHeapInfo(DBGLVL, pThisDisplay);
|
|
#endif //DBG
|
|
|
|
// Do a quick check to see if the buffer at the back is free.
|
|
if ((*ppRootBuffer) != NULL)
|
|
{
|
|
pCurrentBuffer = (*ppRootBuffer)->pPrev;
|
|
// If the buffer is big enough, and it's completed, and
|
|
// it isn't in use, then free it.
|
|
if ( ((dwBytes + sizeof(P3_VERTEXBUFFERINFO)) <= pCurrentBuffer->dwSize) &&
|
|
(!pCurrentBuffer->bInUse) &&
|
|
(__EB_GetSequenceID(pThisDisplay) >= pCurrentBuffer->dwSequenceID) )
|
|
{
|
|
// Mark this buffer as in use, so that it doesn't get freed
|
|
pCurrentBuffer->bInUse = TRUE;
|
|
|
|
// It isn't pending any more, so remove it from the queue
|
|
// Note that the memory won't be deallocated because we have explicity
|
|
// marked it as in use.
|
|
__EB_RemoveFromBufferQueue(pThisDisplay, pCurrentBuffer);
|
|
|
|
// Pass back a pointer to the memory
|
|
pSurf->lpGbl->fpVidMem = (FLATPTR)((BYTE *)pCurrentBuffer) +
|
|
sizeof(P3_VERTEXBUFFERINFO);
|
|
|
|
// Store a pointer to the info block at the start of the memory
|
|
pSurf->lpGbl->dwReserved1 = (ULONG_PTR)pCurrentBuffer;
|
|
#if W95_DDRAW
|
|
// Setup the caps
|
|
pSurf->lpGbl->dwGlobalFlags |= DDRAWISURFGBL_SYSMEMEXECUTEBUFFER;
|
|
#endif
|
|
// If you set these you don't see any locks....
|
|
pSurf->ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
|
|
|
|
// Remember the new size
|
|
pSurf->lpGbl->dwLinearSize = dwBytes;
|
|
|
|
// Mark the buffer as in use and return it
|
|
pCurrentBuffer->dwSequenceID = 0;
|
|
pCurrentBuffer->bInUse = TRUE;
|
|
pCurrentBuffer->pNext = NULL;
|
|
pCurrentBuffer->pPrev = NULL;
|
|
pCurrentBuffer->BufferType = BufferType;
|
|
pCurrentBuffer->dwSize = dwBytes + sizeof(P3_VERTEXBUFFERINFO);
|
|
|
|
DISPDBG((DBGLVL,"Found a re-useable buffer "
|
|
"- didn't need to reallocate memory"));
|
|
|
|
DBG_EXIT(__EB_AllocateCachedBuffer,TRUE);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// do things the longer way...
|
|
// Try to allocate the requested memory
|
|
do
|
|
{
|
|
ZeroMemory(&mmrq, sizeof(P3_MEMREQUEST));
|
|
mmrq.dwSize = sizeof(P3_MEMREQUEST);
|
|
mmrq.dwAlign = 4;
|
|
mmrq.dwBytes = dwBytes + sizeof(P3_VERTEXBUFFERINFO);
|
|
mmrq.dwFlags = MEM3DL_FIRST_FIT | MEM3DL_FRONT;
|
|
dwResult = _DX_LIN_AllocateLinearMemory(pAllocHeap, &mmrq);
|
|
if (dwResult == GLDD_SUCCESS)
|
|
{
|
|
DISPDBG((DBGLVL,"Allocated a cached buffer"));
|
|
|
|
// Pass back a pointer to the memory
|
|
pSurf->lpGbl->fpVidMem = mmrq.pMem + sizeof(P3_VERTEXBUFFERINFO);
|
|
|
|
// Store a pointer to the info block at the start of the memory
|
|
pSurf->lpGbl->dwReserved1 = mmrq.pMem;
|
|
#if W95_DDRAW
|
|
// Setup the caps
|
|
pSurf->lpGbl->dwGlobalFlags |= DDRAWISURFGBL_SYSMEMEXECUTEBUFFER;
|
|
#endif
|
|
// If you set these you don't see any locks....
|
|
pSurf->ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
|
|
|
|
// Remember the new size
|
|
pSurf->lpGbl->dwLinearSize = dwBytes;
|
|
|
|
// Mark the buffer as in use and return it
|
|
pCurrentBuffer = (P3_VERTEXBUFFERINFO*)(ULONG_PTR)mmrq.pMem;
|
|
pCurrentBuffer->dwSequenceID = 0;
|
|
pCurrentBuffer->bInUse = TRUE;
|
|
pCurrentBuffer->pNext = NULL;
|
|
pCurrentBuffer->pPrev = NULL;
|
|
pCurrentBuffer->BufferType = BufferType;
|
|
pCurrentBuffer->dwSize = dwBytes + sizeof(P3_VERTEXBUFFERINFO);
|
|
|
|
DBG_EXIT(__EB_AllocateCachedBuffer,TRUE);
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
DISPDBG((DBGLVL,"Failed to allocate cached buffer"));
|
|
|
|
// Remember that we haven't found any memory yet.
|
|
// and that there isn't any memory to use.
|
|
bFound = FALSE;
|
|
|
|
// There are no buffers currently available.
|
|
// Wait for a new one to be free from the
|
|
// ones that are available and in the queue
|
|
|
|
// None at all? No chance of any memory being free
|
|
// Return FALSE to indicate this.
|
|
if ((*ppRootBuffer) == NULL)
|
|
{
|
|
DISPDBG((DBGLVL,"No buffers in the list!"));
|
|
|
|
DBG_EXIT(__EB_AllocateCachedBuffer,FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
// Start at the back of the queue, as these are
|
|
// the least recently used buffers
|
|
pCurrentBuffer = (*ppRootBuffer)->pPrev;
|
|
do
|
|
{
|
|
P3_DMA_DEFS();
|
|
|
|
// Ensure that all DMA is completed so that the HostIn
|
|
// ID is up to date
|
|
P3_DMA_GET_BUFFER();
|
|
P3_DMA_FLUSH_BUFFER();
|
|
|
|
DISPDBG((DBGLVL,"Searching for old buffers..."));
|
|
|
|
// Check to see if this buffer is available to be freed
|
|
// It may not be if it is a buffer that hasn't been swapped out,
|
|
// such as a vertex buffer.
|
|
|
|
DISPDBG((DBGLVL,"This buffer ID: 0x%x",
|
|
pCurrentBuffer->dwSequenceID));
|
|
|
|
if( __EB_GetSequenceID(pThisDisplay) >=
|
|
pCurrentBuffer->dwSequenceID )
|
|
{
|
|
DISPDBG((DBGLVL,"Found a buffer that can be "
|
|
"removed from the list"));
|
|
|
|
// It isn't pending any more, so remove it from the queue
|
|
if (__EB_RemoveFromBufferQueue(pThisDisplay, pCurrentBuffer))
|
|
{
|
|
bFound = TRUE;
|
|
break;
|
|
}
|
|
|
|
// If the queue is gone, exit (bFound hasn't been
|
|
// setup because we didn't find any memory in the queue)
|
|
if ((*ppRootBuffer) == NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Reset to the last buffer in the chain. This ensures that
|
|
// we always look at the least recent buffer
|
|
pCurrentBuffer = (*ppRootBuffer)->pPrev;
|
|
}
|
|
else
|
|
{
|
|
// BLOCK!
|
|
// The buffer we are looking at hasn't become available yet.
|
|
// We should back off here until it does.
|
|
|
|
blockCount = 100;
|
|
while( blockCount-- )
|
|
NULL;
|
|
|
|
DISPDBG((DBGLVL,"Blocked waiting for buffer to be free"));
|
|
}
|
|
} while (pCurrentBuffer != NULL);
|
|
}
|
|
// Loop until we haven't found any more space to allocate buffers into
|
|
} while (bFound);
|
|
|
|
DISPDBG((WRNLVL,"!! No available new buffers pending to be freed!!"));
|
|
|
|
DBG_EXIT(__EB_AllocateCachedBuffer,FALSE);
|
|
return FALSE;
|
|
|
|
} // __EB_AllocateCachedBuffer
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_EB_FlushAllBuffers
|
|
//
|
|
// Empties the queue. Note that this will cause any allocated buffer
|
|
// memory to be freed along the way. This version doesn't wait for the
|
|
// buffer to be consumed. It is used when a context switch has
|
|
// occured and we know it is safe to do
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
_D3D_EB_FlushAllBuffers(
|
|
P3_THUNKEDDATA* pThisDisplay,
|
|
BOOL bWait)
|
|
{
|
|
P3_VERTEXBUFFERINFO* pCurrentBuffer;
|
|
|
|
DBG_ENTRY(_D3D_EB_FlushAllBuffers);
|
|
|
|
// Walk the list of buffers, flushing them from the queue
|
|
while (pThisDisplay->pRootVertexBuffer != NULL)
|
|
{
|
|
pCurrentBuffer = pThisDisplay->pRootVertexBuffer;
|
|
|
|
if(bWait)
|
|
{
|
|
// Wait for the buffer to be consumed
|
|
__EB_Wait(pThisDisplay, pCurrentBuffer);
|
|
}
|
|
|
|
// Remove the buffer from the queue
|
|
__EB_RemoveFromBufferQueue(pThisDisplay, pCurrentBuffer);
|
|
}
|
|
|
|
while (pThisDisplay->pRootCommandBuffer != NULL)
|
|
{
|
|
pCurrentBuffer = pThisDisplay->pRootCommandBuffer;
|
|
|
|
if(bWait)
|
|
{
|
|
// Wait for the buffer to be consumed
|
|
__EB_Wait(pThisDisplay, pCurrentBuffer);
|
|
}
|
|
|
|
// Remove the buffer from the queue
|
|
__EB_RemoveFromBufferQueue(pThisDisplay, pCurrentBuffer);
|
|
}
|
|
|
|
DBG_EXIT(_D3D_EB_FlushAllBuffers,0);
|
|
|
|
} // _D3D_EB_FlushAllBuffers
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_EB_GetAndWaitForBuffers
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
_D3D_EB_GetAndWaitForBuffers(
|
|
P3_THUNKEDDATA* pThisDisplay,
|
|
LPD3DHAL_DRAWPRIMITIVES2DATA pdp2d ,
|
|
P3_VERTEXBUFFERINFO** ppVertexBufferInfo,
|
|
P3_VERTEXBUFFERINFO** ppCommandBufferInfo)
|
|
{
|
|
P3_VERTEXBUFFERINFO* pVertexBufferInfo;
|
|
P3_VERTEXBUFFERINFO* pCommandBufferInfo;
|
|
|
|
pCommandBufferInfo =
|
|
(P3_VERTEXBUFFERINFO*)pdp2d->lpDDCommands->lpGbl->dwReserved1;
|
|
|
|
// Check if vertex buffer resides in user memory or in a DDraw surface
|
|
if (pdp2d->dwFlags & D3DHALDP2_USERMEMVERTICES)
|
|
{
|
|
pVertexBufferInfo = NULL;
|
|
}
|
|
else
|
|
{
|
|
// This pointer may be NULL, indicating a buffer passed that isn't
|
|
// one of ours. That doesn't mean to say that we can't swap in one
|
|
// of our buffers if there is one available.
|
|
pVertexBufferInfo =
|
|
(P3_VERTEXBUFFERINFO*)pdp2d->lpDDVertex->lpGbl->dwReserved1;
|
|
}
|
|
|
|
// If the vertex buffer is in the queue, wait for it.
|
|
if (pVertexBufferInfo && pVertexBufferInfo->pPrev)
|
|
{
|
|
// Wait for this buffer if we need to
|
|
__EB_Wait(pThisDisplay, pVertexBufferInfo);
|
|
|
|
// Remove this buffer from the queue
|
|
if (__EB_RemoveFromBufferQueue(pThisDisplay, pVertexBufferInfo))
|
|
{
|
|
DISPDBG((ERRLVL,"ERROR: This buffer should not have been freed "
|
|
"(is in use!)"));
|
|
}
|
|
}
|
|
|
|
// If the command buffer is in the queue, wait for it.
|
|
if (pCommandBufferInfo && pCommandBufferInfo->pPrev)
|
|
{
|
|
// Wait for this buffer if we need to
|
|
__EB_Wait(pThisDisplay, pCommandBufferInfo);
|
|
|
|
// Remove this buffer from the queue
|
|
if (__EB_RemoveFromBufferQueue(pThisDisplay, pCommandBufferInfo))
|
|
{
|
|
DISPDBG((ERRLVL,"ERROR: This buffer should not have been freed"
|
|
" (is in use!)"));
|
|
}
|
|
}
|
|
|
|
// Return current values of pointers to EB buffers
|
|
*ppCommandBufferInfo = pCommandBufferInfo;
|
|
*ppVertexBufferInfo = pVertexBufferInfo;
|
|
} // _D3D_EB_GetAndWaitForBuffers
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_EB_UpdateSwapBuffers
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
_D3D_EB_UpdateSwapBuffers(
|
|
P3_THUNKEDDATA* pThisDisplay,
|
|
LPD3DHAL_DRAWPRIMITIVES2DATA pdp2d ,
|
|
P3_VERTEXBUFFERINFO* pVertexBufferInfo,
|
|
P3_VERTEXBUFFERINFO* pCommandBufferInfo)
|
|
{
|
|
// Add the buffers to the pending queue.
|
|
// Only do this if the buffers actually belong to us.
|
|
|
|
// If either of the buffers was sent, update the HOSTIN ID.
|
|
// We need to make the new sequence ID and the update of the hostin
|
|
// 'atomic', or the wraparound will cause a lockup
|
|
|
|
if (pVertexBufferInfo)
|
|
{
|
|
P3_DMA_DEFS();
|
|
|
|
pVertexBufferInfo->dwSequenceID =
|
|
__EB_GetNewSequenceID(pThisDisplay);
|
|
|
|
__EB_AddToBufferQueue(pThisDisplay, pVertexBufferInfo);
|
|
|
|
P3_DMA_GET_BUFFER_ENTRIES( 2 );
|
|
|
|
SEND_P3_DATA(HostInID, pVertexBufferInfo->dwSequenceID);
|
|
|
|
P3_DMA_COMMIT_BUFFER();
|
|
}
|
|
|
|
if (pCommandBufferInfo)
|
|
{
|
|
P3_DMA_DEFS();
|
|
|
|
pCommandBufferInfo->dwSequenceID =
|
|
__EB_GetNewSequenceID(pThisDisplay);
|
|
|
|
__EB_AddToBufferQueue(pThisDisplay, pCommandBufferInfo);
|
|
|
|
P3_DMA_GET_BUFFER_ENTRIES( 2 );
|
|
|
|
SEND_P3_DATA(HostInID, pCommandBufferInfo->dwSequenceID);
|
|
|
|
P3_DMA_COMMIT_BUFFER();
|
|
}
|
|
|
|
if (D3DHALDP2_SWAPVERTEXBUFFER & pdp2d->dwFlags)
|
|
{
|
|
DWORD dwNewSize = pdp2d->lpDDVertex->lpGbl->dwLinearSize;
|
|
|
|
DISPDBG((DBGLVL,"D3DHALDP2_SWAPVERTEXBUFFER..."));
|
|
if (D3DHALDP2_REQVERTEXBUFSIZE & pdp2d->dwFlags)
|
|
{
|
|
DISPDBG((DBGLVL,"D3DHALDP2_REQVERTEXBUFSIZE - %d",
|
|
pdp2d->dwReqVertexBufSize));
|
|
if (dwNewSize < pdp2d->dwReqVertexBufSize)
|
|
{
|
|
dwNewSize = pdp2d->dwReqVertexBufSize;
|
|
}
|
|
}
|
|
|
|
DISPDBG((DBGLVL,"Current vertex buffer size: %d, "
|
|
"New size will be: %d",
|
|
pdp2d->lpDDVertex->lpGbl->dwLinearSize,
|
|
dwNewSize));
|
|
|
|
// The vertex buffer we just sent off is fixed in place until we
|
|
// mark it as not in use, which we will after allocating a new
|
|
// buffer. The following call will try to get a new buffer and
|
|
// update the surface structure appropriately. Note that it won't
|
|
// trash the current surface unless the allocation succeeds.
|
|
if (__EB_AllocateCachedBuffer(pThisDisplay,
|
|
dwNewSize,
|
|
pdp2d->lpDDVertex))
|
|
{
|
|
DISPDBG((DBGLVL,"Got a new swap vertex buffer"));
|
|
|
|
#define STAMP_BUFFER 0
|
|
#if STAMP_BUFFER
|
|
{
|
|
DWORD i, *pv;
|
|
|
|
pv = (DWORD * ) pdp2d->lpDDVertex->lpGbl->fpVidMem;
|
|
|
|
for( i = 0; i < ( dwNewSize / 4 ); i++ )
|
|
{
|
|
*pv++ = 0x44000000;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Fix up the discarded buffer if required
|
|
if (pVertexBufferInfo)
|
|
{
|
|
// Mark the current buffer as not in use, meaning it can
|
|
// be freed once it has cleared P3. This might occur the
|
|
// next time we are here.
|
|
pVertexBufferInfo->bInUse = FALSE;
|
|
|
|
// A gotcha! The buffer we just launched was consumed so
|
|
// fast that it was freed from the pending list to make
|
|
// room for it's replacement. This is normally OK, but in
|
|
// this case the buffer we freed isn't being put back
|
|
// anywhere - i.e. no surface now owns it, and the memory
|
|
// associated with it wasn't freed because as far as the
|
|
// driver is concerned it is still in use until it is
|
|
// replaced due to the above succesfull call. The
|
|
// 'solution' is to add it back into the queue if it is
|
|
// not in it, and make sure that it is marked as not in
|
|
// use and at a 0 hostin ID.
|
|
if (!pVertexBufferInfo->pPrev)
|
|
{
|
|
pVertexBufferInfo->dwSequenceID = 0;
|
|
__EB_AddToBufferQueue(pThisDisplay,
|
|
pVertexBufferInfo);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Couldn't swap this buffer, so we have to wait
|
|
|
|
DISPDBG((DBGLVL,"Not swapping vertex buffer "
|
|
"due to lack of space!"));
|
|
|
|
__EB_Wait(pThisDisplay, pVertexBufferInfo);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DISPDBG((DBGLVL,"No vertex buffer swapping..."));
|
|
}
|
|
|
|
if (D3DHALDP2_SWAPCOMMANDBUFFER & pdp2d->dwFlags)
|
|
{
|
|
DWORD dwNewSize = pdp2d->lpDDCommands->lpGbl->dwLinearSize;
|
|
|
|
DISPDBG((DBGLVL,"D3DHALDP2_SWAPCOMMANDBUFFER..."));
|
|
|
|
if (D3DHALDP2_REQCOMMANDBUFSIZE & pdp2d->dwFlags)
|
|
{
|
|
DISPDBG((DBGLVL,"D3DHALDP2_REQCOMMANDBUFSIZE - %d",
|
|
pdp2d->dwReqCommandBufSize));
|
|
|
|
if (dwNewSize < pdp2d->dwReqCommandBufSize)
|
|
{
|
|
dwNewSize = pdp2d->dwReqCommandBufSize;
|
|
}
|
|
}
|
|
|
|
DISPDBG((DBGLVL,"Current command buffer size: "
|
|
"%d, New size will be: %d",
|
|
pdp2d->lpDDCommands->lpGbl->dwLinearSize,
|
|
dwNewSize));
|
|
|
|
// The command buffer we just sent off is fixed in place until we
|
|
// mark it as not in use, which we will after allocating a new
|
|
// buffer. The following call will try to get a new buffer and
|
|
// update the surface structure appropriately. Note that it won't
|
|
// trash the current surface unless the allocation succeeds
|
|
if (__EB_AllocateCachedBuffer(pThisDisplay,
|
|
dwNewSize,
|
|
pdp2d->lpDDCommands))
|
|
{
|
|
DISPDBG((DBGLVL,"Got a new swap command buffer"));
|
|
|
|
// Fix up the previous command buffer if required.
|
|
if (pCommandBufferInfo)
|
|
{
|
|
// Mark the current buffer as not in use, meaning it can
|
|
// be freed once it has cleared P3. This might occur the
|
|
// next time we are here.
|
|
pCommandBufferInfo->bInUse = FALSE;
|
|
|
|
// A gotcha! The buffer we just launched was consumed so
|
|
// fast that it was freed from the pending list to make
|
|
// room for it's replacement. This is normally OK, but in
|
|
// this case the buffer we freed isn't being put back
|
|
// anywhere - i.e. no surface now owns it, and the memory
|
|
// associated with it wasn't freed because as far as the
|
|
// driver is concerned it is still in use until it is
|
|
// replaced due to the above succesfull call. The
|
|
// 'solution' is to add it back into the queue if it is
|
|
// not in it, and make sure that it is marked as not in
|
|
// use and at a 0 hostin ID.
|
|
if (!pCommandBufferInfo->pPrev)
|
|
{
|
|
pCommandBufferInfo->dwSequenceID = 0;
|
|
__EB_AddToBufferQueue(pThisDisplay,
|
|
pCommandBufferInfo);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Couldn't swap this buffer, so we have to wait
|
|
|
|
DISPDBG((DBGLVL,"Not swapping command buffer "
|
|
"due to lack of space!"));
|
|
|
|
__EB_Wait(pThisDisplay, pCommandBufferInfo);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DISPDBG((DBGLVL,"No Command buffer swapping..."));
|
|
}
|
|
} // _D3D_EB_UpdateSwapBuffers
|
|
|
|
//-----------------------------Public Routine----------------------------------
|
|
//
|
|
// D3DCanCreateD3DBuffer
|
|
//
|
|
// Called by the runtime to ask if a type of vertex/command buffer can
|
|
// be created by the driver. We don't do anything here at present
|
|
//
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
DWORD CALLBACK
|
|
D3DCanCreateD3DBuffer(
|
|
LPDDHAL_CANCREATESURFACEDATA pccsd)
|
|
{
|
|
P3_THUNKEDDATA* pThisDisplay;
|
|
|
|
DBG_CB_ENTRY(D3DCanCreateD3DBuffer);
|
|
|
|
GET_THUNKEDDATA(pThisDisplay, pccsd->lpDD);
|
|
|
|
VALIDATE_MODE_AND_STATE(pThisDisplay);
|
|
|
|
DBGDUMP_DDSURFACEDESC(DBGLVL, pccsd->lpDDSurfaceDesc);
|
|
|
|
pccsd->ddRVal = DD_OK;
|
|
|
|
DBG_CB_EXIT(D3DCanCreateD3DBuffer,pccsd->ddRVal);
|
|
return DDHAL_DRIVER_HANDLED;
|
|
|
|
} // D3DCanCreateD3DBuffer
|
|
|
|
//-----------------------------Public Routine----------------------------------
|
|
//
|
|
// D3DCreateD3DBuffer
|
|
//
|
|
// Called by the runtime to create a vertex buffer. We try to allocate
|
|
// from our cached heap here.
|
|
//
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
DWORD CALLBACK
|
|
D3DCreateD3DBuffer(
|
|
LPDDHAL_CREATESURFACEDATA pcsd)
|
|
{
|
|
P3_THUNKEDDATA* pThisDisplay;
|
|
LPDDRAWI_DDRAWSURFACE_LCL pSurf;
|
|
LPDDRAWI_DDRAWSURFACE_LCL FAR* ppSList;
|
|
BOOL bHandled = FALSE;
|
|
DWORD i;
|
|
|
|
DBG_CB_ENTRY(D3DCreateD3DBuffer);
|
|
|
|
GET_THUNKEDDATA(pThisDisplay, pcsd->lpDD);
|
|
|
|
VALIDATE_MODE_AND_STATE(pThisDisplay);
|
|
|
|
STOP_SOFTWARE_CURSOR(pThisDisplay);
|
|
DDRAW_OPERATION(pContext, pThisDisplay);
|
|
|
|
ppSList = pcsd->lplpSList;
|
|
|
|
for (i = 0; i < pcsd->dwSCnt; i++)
|
|
{
|
|
pSurf = ppSList[i];
|
|
|
|
// Allocate the size we want
|
|
DISPDBG((DBGLVL,"Surface %d requested is 0x%x big",
|
|
i, pSurf->lpGbl->dwLinearSize));
|
|
|
|
DBGDUMP_DDRAWSURFACE_LCL(DBGLVL, pSurf);
|
|
|
|
pSurf->lpGbl->dwReserved1 = 0;
|
|
|
|
// A 32 kB command buffer gives a high probability of being allowed
|
|
// to swap the associated vertex buffer
|
|
|
|
if( pSurf->lpGbl->dwLinearSize < _32_KBYTES )
|
|
{
|
|
pSurf->lpGbl->dwLinearSize = _32_KBYTES;
|
|
}
|
|
|
|
if (__EB_AllocateCachedBuffer(pThisDisplay,
|
|
pSurf->lpGbl->dwLinearSize,
|
|
pSurf))
|
|
{
|
|
DISPDBG((DBGLVL,"Allocated a new cached buffer for use by D3D"));
|
|
bHandled = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// If we can't find a buffer, the best thing to do is to
|
|
// punt to D3D and always copy the data into a DMA buffer
|
|
// (because it won't be contiguous). The DP2 call should
|
|
// check the reserved field before using the HostIn unit
|
|
DISPDBG((ERRLVL,"WARNING: Couldn't find any vertex memory"
|
|
" in the heap or in the sent list!"));
|
|
|
|
pSurf->lpGbl->dwReserved1 = 0;
|
|
|
|
bHandled = FALSE;
|
|
}
|
|
}
|
|
|
|
START_SOFTWARE_CURSOR(pThisDisplay);
|
|
|
|
pcsd->ddRVal = DD_OK;
|
|
|
|
if (bHandled)
|
|
{
|
|
DBG_EXIT(D3DCreateD3DBuffer,DDHAL_DRIVER_HANDLED);
|
|
return DDHAL_DRIVER_HANDLED;
|
|
}
|
|
else
|
|
{
|
|
DBG_CB_EXIT(D3DCreateD3DBuffer,DDHAL_DRIVER_NOTHANDLED);
|
|
return DDHAL_DRIVER_NOTHANDLED;
|
|
}
|
|
|
|
} // D3DCreateD3DBuffer
|
|
|
|
//-----------------------------Public Routine----------------------------------
|
|
//
|
|
// D3DDestroyD3DBuffer
|
|
//
|
|
// Called by the runtime to destroy a vertex buffer. We free the buffer
|
|
// from our memory heap and the current queue.
|
|
//
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
DWORD CALLBACK
|
|
D3DDestroyD3DBuffer(
|
|
LPDDHAL_DESTROYSURFACEDATA pdd)
|
|
{
|
|
P3_THUNKEDDATA* pThisDisplay;
|
|
|
|
DBG_CB_ENTRY(D3DDestroyD3DBuffer);
|
|
|
|
GET_THUNKEDDATA(pThisDisplay, pdd->lpDD);
|
|
|
|
VALIDATE_MODE_AND_STATE(pThisDisplay);
|
|
|
|
STOP_SOFTWARE_CURSOR(pThisDisplay);
|
|
DDRAW_OPERATION(pContext, pThisDisplay);
|
|
|
|
// Debug data
|
|
DBGDUMP_DDRAWSURFACE_LCL(DBGLVL, pdd->lpDDSurface);
|
|
|
|
// Free the D3D buffer. If its in use, we will wait for it to be ready.
|
|
__EB_FreeCachedBuffer(pThisDisplay, pdd->lpDDSurface);
|
|
|
|
#ifdef CHECK_BUFFERS_ARENT_LEFT_AFTER_APPLICATION_SHUTDOWN
|
|
// Flush all the buffers
|
|
// This checks that the queue is OK. If you don't do this
|
|
// you may see the linear allocator on the 16 bit side complain
|
|
// that there is freeable memory there. This is quite alright.
|
|
_D3D_EB_FlushAllBuffers(pThisDisplay , TRUE);
|
|
#endif
|
|
|
|
START_SOFTWARE_CURSOR(pThisDisplay);
|
|
|
|
// We don't handle the call because DDRAW has allocated out of AGP memory
|
|
pdd->ddRVal = DD_OK;
|
|
|
|
DBG_CB_EXIT(D3DDestroyD3DBuffer,DDHAL_DRIVER_HANDLED);
|
|
return DDHAL_DRIVER_HANDLED;
|
|
|
|
} // D3DDestroyD3DBuffer
|
|
|
|
//-----------------------------Public Routine----------------------------------
|
|
//
|
|
// D3DLockD3DBuffer
|
|
//
|
|
// Called by the runtime to lock a vertex buffer. We make sure
|
|
// it has been consumed by the queue, then we continue.
|
|
//
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
DWORD CALLBACK
|
|
D3DLockD3DBuffer(
|
|
LPDDHAL_LOCKDATA pld)
|
|
{
|
|
P3_THUNKEDDATA* pThisDisplay;
|
|
P3_VERTEXBUFFERINFO* pCurrentBuffer;
|
|
|
|
DBG_CB_ENTRY(D3DLockD3DBuffer);
|
|
|
|
GET_THUNKEDDATA(pThisDisplay, pld->lpDD);
|
|
|
|
VALIDATE_MODE_AND_STATE(pThisDisplay);
|
|
|
|
DBGDUMP_DDRAWSURFACE_LCL(DBGLVL, pld->lpDDSurface);
|
|
|
|
STOP_SOFTWARE_CURSOR(pThisDisplay);
|
|
DDRAW_OPERATION(pContext, pThisDisplay);
|
|
|
|
if (pld->bHasRect)
|
|
{
|
|
DISPDBG((ERRLVL,"Trying to lock a rect in a D3D buffer (error):"));
|
|
DISPDBG((ERRLVL,"left:%d, top:%d, right:%d, bottom:%d",
|
|
pld->rArea.left, pld->rArea.top,
|
|
pld->rArea.right, pld->rArea.bottom));
|
|
// This is just a debugging aid
|
|
// We will ignore any rects requested and lock the whole buffer
|
|
}
|
|
|
|
// If the buffer has a next pointer then it is in the circular list
|
|
// and we need to wait for the chip to finish consuming it.
|
|
pCurrentBuffer = (P3_VERTEXBUFFERINFO*)pld->lpDDSurface->lpGbl->dwReserved1;
|
|
if (pCurrentBuffer)
|
|
{
|
|
// Wait for the buffer to be consumed
|
|
__EB_Wait(pThisDisplay, pCurrentBuffer);
|
|
|
|
// Remove it from the queue
|
|
if (__EB_RemoveFromBufferQueue(pThisDisplay, pCurrentBuffer))
|
|
{
|
|
// There was an error removing it from the queue
|
|
DISPDBG((ERRLVL,"ERROR: This buffer should not have been freed"
|
|
"(its in use!)"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DISPDBG((WRNLVL,"Buffer was not allocated by the driver"));
|
|
}
|
|
|
|
START_SOFTWARE_CURSOR(pThisDisplay);
|
|
|
|
// Return the pointer
|
|
pld->lpSurfData = (LPVOID)pld->lpDDSurface->lpGbl->fpVidMem;
|
|
|
|
DISPDBG((DBGLVL,"Returning 0x%x for locked buffer address",
|
|
pld->lpDDSurface->lpGbl->fpVidMem));
|
|
|
|
pld->ddRVal = DD_OK;
|
|
|
|
DBG_CB_EXIT(D3DLockD3DBuffer,DDHAL_DRIVER_HANDLED);
|
|
return DDHAL_DRIVER_HANDLED;
|
|
|
|
} // D3DLockD3DBuffer
|
|
|
|
//-----------------------------Public Routine----------------------------------
|
|
//
|
|
// D3DUnlockD3DBuffer
|
|
//
|
|
// Called by the runtime to unlock a vertex buffer.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
DWORD CALLBACK
|
|
D3DUnlockD3DBuffer(
|
|
LPDDHAL_UNLOCKDATA puld)
|
|
{
|
|
DBG_CB_ENTRY(D3DUnlockD3DBuffer);
|
|
|
|
// We don't need to do anything special here.
|
|
|
|
puld->ddRVal = DD_OK;
|
|
|
|
DBG_CB_EXIT(D3DUnlockD3DBuffer,DDHAL_DRIVER_HANDLED);
|
|
return DDHAL_DRIVER_HANDLED;
|
|
|
|
} // D3DUnlockD3DBuffer
|
|
|
|
#endif // DX7_VERTEXBUFFERS
|
|
//@@END_DDKSPLIT
|
|
|
|
|
|
|
|
|