windows-nt/Source/XPSP1/NT/multimedia/directx/dxg/ref8/drv/surfman.cpp
2020-09-26 16:20:57 +08:00

357 lines
11 KiB
C++

//----------------------------------------------------------------------------
//
// surfman.cpp
//
// Reference rasterizer callback functions for D3DIM.
//
// Copyright (C) Microsoft Corporation, 1997.
//
//----------------------------------------------------------------------------
#include "pch.cpp"
#pragma hdrstop
// Global Surface Manager, one per process
RDSurfaceManager g_SurfMgr;
///////////////////////////////////////////////////////////////////////////////
//
// Helper functions
//
///////////////////////////////////////////////////////////////////////////////
HRESULT
CreateAppropriateSurface( LPDDRAWI_DDRAWSURFACE_LCL pDDSLcl,
DWORD* pHandle,
RDSurface** ppSurf )
{
HRESULT hr = S_OK;
*ppSurf = NULL;
*pHandle = 0;
// Obtain the Handle
DWORD dwHandle = pDDSLcl->lpSurfMore->dwSurfaceHandle;
*pHandle = dwHandle;
// Figure out if we care for this surface. Currently,
// we care only for:
// 1) Textures (MipMaps and Cubemaps)
// 2) RenderTargets & DepthBuffers
if( pDDSLcl->ddsCaps.dwCaps &
(DDSCAPS_TEXTURE | DDSCAPS_ZBUFFER | DDSCAPS_3DDEVICE) )
{
RDSurface2D* pSurf2D = new RDSurface2D();
if( pSurf2D == NULL )
{
DPFERR("New RDSurface2D failed, out of memory" );
return DDERR_OUTOFMEMORY;
}
*ppSurf = pSurf2D;
}
else if( pDDSLcl->ddsCaps.dwCaps & DDSCAPS_EXECUTEBUFFER )
{
// Strictly speaking, RDVertexBuffer should be
// called RDLinearBuffer (it could be vertex, index or command)
// For the time being, there is no need to distinguish between
// the three. There is not harm in recognizing it for the Index
// and Command buffer case. In case in the future, we do need to
// make a distinction between Vertex and Index buffers, we need
// to make the following tests:
// For VB:
// (pDDSLcl->pDDSLcl->lpSurfMore->ddsCapsEx.dwCaps2 &
// DDSCAPS2_VERTEXBUFFER))
// For IB:
// (pDDSLcl->pDDSLcl->lpSurfMore->ddsCapsEx.dwCaps2 &
// DDSCAPS2_INDEXBUFFER))
RDVertexBuffer* pVB = new RDVertexBuffer();
if( pVB == NULL )
{
DPFERR("New RDVertexBuffer failed, out of memory" );
return DDERR_OUTOFMEMORY;
}
*ppSurf = pVB;
}
else
{
DPFM(2, DRV, ("RefCreateSurfaceEx w/o "
"DDSCAPS_TEXTURE/3DDEVICE/ZBUFFER Ignored"
"dwCaps=%08lx dwSurfaceHandle=%08lx",
pDDSLcl->ddsCaps.dwCaps,
pDDSLcl->lpSurfMore->dwSurfaceHandle));
return hr;
}
if( FAILED( hr = (*ppSurf)->Initialize( pDDSLcl ) ) )
{
DPFERR( "Initialize failed" );
delete (*ppSurf);
return hr;
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// RDVertexBuffer implementation
//
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
// RDVertexBuffer::Initialize
// Initializer.
//-----------------------------------------------------------------------------
HRESULT
RDVertexBuffer::Initialize( LPDDRAWI_DDRAWSURFACE_LCL pSLcl )
{
HRESULT hr = S_OK;
SetInitialized();
m_SurfType = RR_ST_VERTEXBUFFER;
if( pSLcl->lpGbl->dwReserved1 )
{
RDCREATESURFPRIVATE* pPriv =
(RDCREATESURFPRIVATE *)pSLcl->lpGbl->dwReserved1;
m_pBits = pPriv->pBits;
m_cbSize = (int)pPriv->dwVBSize;
SetRefCreated();
}
else
{
m_pBits = (LPBYTE)SURFACE_MEMORY(pSLcl);
m_cbSize = pSLcl->lpGbl->dwLinearSize;
}
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
//
// RDSurfaceArrayNode implementation
//
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
// RDSurfaceArrayNode::RDSurfaceArrayNode
// Constructor.
//-----------------------------------------------------------------------------
RDSurfaceArrayNode::RDSurfaceArrayNode(LPDDRAWI_DIRECTDRAW_LCL pDDLcl)
: RDListEntry(), m_SurfHandleArray()
{
m_pDDLcl = pDDLcl;
}
//-----------------------------------------------------------------------------
// RDSurfaceArrayNode::~RDSurfaceArrayNode
// Destructor.
//-----------------------------------------------------------------------------
RDSurfaceArrayNode::~RDSurfaceArrayNode()
{
// Release all the allocated surfaces
for( DWORD i=0; i<m_SurfHandleArray.GetSize(); i++ )
{
delete m_SurfHandleArray[i].m_pSurf;
}
}
//-----------------------------------------------------------------------------
// RDSurfaceArrayNode::AddSurface
// Adds a surface to its internal growable array if not already
// present. ppSurf can be NULL.
//-----------------------------------------------------------------------------
HRESULT
RDSurfaceArrayNode::AddSurface( LPDDRAWI_DDRAWSURFACE_LCL pDDSLcl,
RDSurface** ppSurf )
{
DWORD dwHandle = 0;
HRESULT hr = S_OK;
RDSurface* pSurf = NULL;
if( FAILED(hr = CreateAppropriateSurface( pDDSLcl, &dwHandle, &pSurf ) ) )
{
return hr;
}
// If it is zero, there was something wrong
if( pSurf == NULL || dwHandle == 0 ) return E_FAIL;
hr = m_SurfHandleArray.Grow( dwHandle );
if (FAILED(hr))
{
return hr;
}
if( m_SurfHandleArray[dwHandle].m_pSurf )
{
#if DBG
_ASSERT( m_SurfHandleArray[dwHandle].m_tag,
"A surface is associated with this handle even though it was never initialized!" );
#endif
delete m_SurfHandleArray[dwHandle].m_pSurf;
}
m_SurfHandleArray[dwHandle].m_pSurf = pSurf;
#if DBG
m_SurfHandleArray[dwHandle].m_tag = 1;
#endif
if( ppSurf ) *ppSurf = pSurf;
return S_OK;
}
//-----------------------------------------------------------------------------
// RDSurfaceArrayNode::GetSurface
// Gets a surface from its internal array if present.
//-----------------------------------------------------------------------------
RDSurface*
RDSurfaceArrayNode::GetSurface( DWORD dwHandle )
{
if( m_SurfHandleArray.IsValidIndex( dwHandle ) )
return m_SurfHandleArray[dwHandle].m_pSurf;
return NULL;
}
//-----------------------------------------------------------------------------
// RDSurfaceArrayNode::RemoveSurface
// Removed the surface with the given handle from the list.
//-----------------------------------------------------------------------------
HRESULT
RDSurfaceArrayNode::RemoveSurface( DWORD dwHandle )
{
if( m_SurfHandleArray.IsValidIndex( dwHandle ) &&
m_SurfHandleArray[dwHandle].m_pSurf )
{
delete m_SurfHandleArray[dwHandle].m_pSurf;
m_SurfHandleArray[dwHandle].m_pSurf = NULL;
return S_OK;
}
DPFERR( "Bad handle passed for delete" );
return DDERR_INVALIDPARAMS;
}
///////////////////////////////////////////////////////////////////////////////
//
// RDSurfaceManager implementation
//
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
// RDSurfaceManager::AddLclNode
// Adds a node with the given DDLcl to the list if not already
// present.
//-----------------------------------------------------------------------------
RDSurfaceArrayNode*
RDSurfaceManager::AddLclNode( LPDDRAWI_DIRECTDRAW_LCL pDDLcl )
{
RDSurfaceArrayNode* pCurrNode = m_pFirstNode;
while( pCurrNode )
{
if( pDDLcl == pCurrNode->m_pDDLcl ) return pCurrNode;
pCurrNode = pCurrNode->m_pNext;
}
// This means that we didnt find an existing node, create a
// new one.
RDSurfaceArrayNode* pTmpNode = m_pFirstNode;
m_pFirstNode = new RDSurfaceArrayNode( pDDLcl );
if( m_pFirstNode == NULL )
{
DPFERR("New Failed allocating a new RDSurfaceArrayNode\n");
m_pFirstNode = pTmpNode;
return NULL;
}
m_pFirstNode->m_pNext = pTmpNode;
return m_pFirstNode;
}
//-----------------------------------------------------------------------------
// RDSurfaceManager::GetLclNode
// Gets a node with the given DDLcl from the list if present.
//-----------------------------------------------------------------------------
RDSurfaceArrayNode*
RDSurfaceManager::GetLclNode( LPDDRAWI_DIRECTDRAW_LCL pDDLcl )
{
RDSurfaceArrayNode* pCurrNode = m_pFirstNode;
while( pCurrNode )
{
if( pDDLcl == pCurrNode->m_pDDLcl ) break;
pCurrNode = pCurrNode->m_pNext;
}
return pCurrNode;
}
//-----------------------------------------------------------------------------
// RDSurfaceManager::AddSurfToList
// Adds a surface to the node with a matching DDLcl. If the node
// is not present it is created. The ppSurf param can be NULL.
//-----------------------------------------------------------------------------
HRESULT
RDSurfaceManager::AddSurfToList( LPDDRAWI_DIRECTDRAW_LCL pDDLcl,
LPDDRAWI_DDRAWSURFACE_LCL pDDSLcl,
RDSurface** ppSurf )
{
HRESULT hr = S_OK;
RDSurface* pSurf = NULL;
RDSurfaceArrayNode* pCurrNode = AddLclNode( pDDLcl );
if( pCurrNode )
{
hr = pCurrNode->AddSurface( pDDSLcl, &pSurf );
if( ppSurf ) *ppSurf = pSurf;
return hr;
}
return DDERR_OUTOFMEMORY;
}
//-----------------------------------------------------------------------------
// RDSurfaceManager::GetSurfFromList
// Gets a surface with the matching handle from the node with a
// matching DDLcl, if the node and the surface is present.
//-----------------------------------------------------------------------------
RDSurface*
RDSurfaceManager::GetSurfFromList( LPDDRAWI_DIRECTDRAW_LCL pDDLcl,
DWORD dwHandle )
{
RDSurfaceArrayNode* pCurrNode = GetLclNode( pDDLcl );
if( pCurrNode ) return pCurrNode->GetSurface( dwHandle );
return NULL;
}
//-----------------------------------------------------------------------------
// RDSurfaceManager::RemoveSurfFromList
// Deletes the surface handle.
//-----------------------------------------------------------------------------
HRESULT
RDSurfaceManager::RemoveSurfFromList( LPDDRAWI_DIRECTDRAW_LCL pDDLcl,
DWORD dwHandle )
{
RDSurfaceArrayNode* pCurrNode = GetLclNode( pDDLcl );
if( pCurrNode ) return pCurrNode->RemoveSurface( dwHandle );
DPFERR("The DrawLcl is unrecognized\n");
return DDERR_INVALIDPARAMS;
}
HRESULT
RDSurfaceManager::RemoveSurfFromList( LPDDRAWI_DIRECTDRAW_LCL pDDLcl,
LPDDRAWI_DDRAWSURFACE_LCL pDDSLcl )
{
RDSurfaceArrayNode* pCurrNode = GetLclNode( pDDLcl );
if( pCurrNode ) return pCurrNode->RemoveSurface(
pDDSLcl->lpSurfMore->dwSurfaceHandle );
DPFERR("The DrawLcl is unrecognized\n");
return DDERR_INVALIDPARAMS;
}