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.
 
 
 
 
 
 

646 lines
20 KiB

/******************************Module*Header**********************************\
*
* *******************
* * SAMPLE CODE *
* *******************
*
* Module Name: p2ctxt.c
*
* Content: Context switching for Permedia 2. Used to create and swap
* contexts in and out.
* The GDI, DDraw and D3D part each have another context.
*
* Copyright (c) 1994-1998 3Dlabs Inc. Ltd. All rights reserved.
* Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved.
\*****************************************************************************/
#include "precomp.h"
#include "p2ctxt.h"
#include "gdi.h"
#define ALLOC_TAG ALLOC_TAG_XC2P
static DWORD readableRegistersP2[] = {
__Permedia2TagStartXDom,
__Permedia2TagdXDom,
__Permedia2TagStartXSub,
__Permedia2TagdXSub,
__Permedia2TagStartY,
__Permedia2TagdY,
__Permedia2TagCount,
__Permedia2TagRasterizerMode,
__Permedia2TagYLimits,
__Permedia2TagXLimits,
__Permedia2TagScissorMode,
__Permedia2TagScissorMinXY,
__Permedia2TagScissorMaxXY,
__Permedia2TagScreenSize,
__Permedia2TagAreaStippleMode,
__Permedia2TagWindowOrigin,
__Permedia2TagAreaStipplePattern0,
__Permedia2TagAreaStipplePattern1,
__Permedia2TagAreaStipplePattern2,
__Permedia2TagAreaStipplePattern3,
__Permedia2TagAreaStipplePattern4,
__Permedia2TagAreaStipplePattern5,
__Permedia2TagAreaStipplePattern6,
__Permedia2TagAreaStipplePattern7,
__Permedia2TagTextureAddressMode,
__Permedia2TagSStart,
__Permedia2TagdSdx,
__Permedia2TagdSdyDom,
__Permedia2TagTStart,
__Permedia2TagdTdx,
__Permedia2TagdTdyDom,
__Permedia2TagQStart,
__Permedia2TagdQdx,
__Permedia2TagdQdyDom,
// texellutindex..transfer are treated seperately
__Permedia2TagTextureBaseAddress,
__Permedia2TagTextureMapFormat,
__Permedia2TagTextureDataFormat,
__Permedia2TagTexel0,
__Permedia2TagTextureReadMode,
__Permedia2TagTexelLUTMode,
__Permedia2TagTextureColorMode,
__Permedia2TagFogMode,
__Permedia2TagFogColor,
__Permedia2TagFStart,
__Permedia2TagdFdx,
__Permedia2TagdFdyDom,
__Permedia2TagKsStart,
__Permedia2TagdKsdx,
__Permedia2TagdKsdyDom,
__Permedia2TagKdStart,
__Permedia2TagdKddx,
__Permedia2TagdKddyDom,
__Permedia2TagRStart,
__Permedia2TagdRdx,
__Permedia2TagdRdyDom,
__Permedia2TagGStart,
__Permedia2TagdGdx,
__Permedia2TagdGdyDom,
__Permedia2TagBStart,
__Permedia2TagdBdx,
__Permedia2TagdBdyDom,
__Permedia2TagAStart,
__Permedia2TagColorDDAMode,
__Permedia2TagConstantColor,
__Permedia2TagAlphaBlendMode,
__Permedia2TagDitherMode,
__Permedia2TagFBSoftwareWriteMask,
__Permedia2TagLogicalOpMode,
__Permedia2TagLBReadMode,
__Permedia2TagLBReadFormat,
__Permedia2TagLBSourceOffset,
__Permedia2TagLBWindowBase,
__Permedia2TagLBWriteMode,
__Permedia2TagLBWriteFormat,
__Permedia2TagTextureDownloadOffset,
__Permedia2TagWindow,
__Permedia2TagStencilMode,
__Permedia2TagStencilData,
__Permedia2TagStencil,
__Permedia2TagDepthMode,
__Permedia2TagDepth,
__Permedia2TagZStartU,
__Permedia2TagZStartL,
__Permedia2TagdZdxU,
__Permedia2TagdZdxL,
__Permedia2TagdZdyDomU,
__Permedia2TagdZdyDomL,
__Permedia2TagFBReadMode,
__Permedia2TagFBSourceOffset,
__Permedia2TagFBPixelOffset,
__Permedia2TagFBWindowBase,
__Permedia2TagFBWriteMode,
__Permedia2TagFBHardwareWriteMask,
__Permedia2TagFBBlockColor,
__Permedia2TagFBReadPixel,
__Permedia2TagFilterMode,
__Permedia2TagStatisticMode,
__Permedia2TagMinRegion,
__Permedia2TagMaxRegion,
__Permedia2TagFBBlockColorU,
__Permedia2TagFBBlockColorL,
__Permedia2TagFBSourceBase,
__Permedia2TagTexelLUT0,
__Permedia2TagTexelLUT1,
__Permedia2TagTexelLUT2,
__Permedia2TagTexelLUT3,
__Permedia2TagTexelLUT4,
__Permedia2TagTexelLUT5,
__Permedia2TagTexelLUT6,
__Permedia2TagTexelLUT7,
__Permedia2TagTexelLUT8,
__Permedia2TagTexelLUT9,
__Permedia2TagTexelLUT10,
__Permedia2TagTexelLUT11,
__Permedia2TagTexelLUT12,
__Permedia2TagTexelLUT13,
__Permedia2TagTexelLUT14,
__Permedia2TagTexelLUT15,
__Permedia2TagYUVMode,
__Permedia2TagChromaUpperBound,
__Permedia2TagChromaLowerBound,
__Permedia2TagAlphaMapUpperBound,
__Permedia2TagAlphaMapLowerBound,
// delta tag values. must be at the end of this array
// v0/1/2 fixed are not used and for that reason not in the context
__Permedia2TagV0FloatS,
__Permedia2TagV0FloatT,
__Permedia2TagV0FloatQ,
__Permedia2TagV0FloatKs,
__Permedia2TagV0FloatKd,
__Permedia2TagV0FloatR,
__Permedia2TagV0FloatG,
__Permedia2TagV0FloatB,
__Permedia2TagV0FloatA,
__Permedia2TagV0FloatF,
__Permedia2TagV0FloatX,
__Permedia2TagV0FloatY,
__Permedia2TagV0FloatZ,
__Permedia2TagV1FloatS,
__Permedia2TagV1FloatT,
__Permedia2TagV1FloatQ,
__Permedia2TagV1FloatKs,
__Permedia2TagV1FloatKd,
__Permedia2TagV1FloatR,
__Permedia2TagV1FloatG,
__Permedia2TagV1FloatB,
__Permedia2TagV1FloatA,
__Permedia2TagV1FloatF,
__Permedia2TagV1FloatX,
__Permedia2TagV1FloatY,
__Permedia2TagV1FloatZ,
__Permedia2TagV2FloatS,
__Permedia2TagV2FloatT,
__Permedia2TagV2FloatQ,
__Permedia2TagV2FloatKs,
__Permedia2TagV2FloatKd,
__Permedia2TagV2FloatR,
__Permedia2TagV2FloatG,
__Permedia2TagV2FloatB,
__Permedia2TagV2FloatA,
__Permedia2TagV2FloatF,
__Permedia2TagV2FloatX,
__Permedia2TagV2FloatY,
__Permedia2TagV2FloatZ,
__Permedia2TagDeltaMode
};
#define N_READABLE_TAGSP2 (sizeof(readableRegistersP2) / sizeof(readableRegistersP2[0]))
//-----------------------------------------------------------------------------
//
// P2AllocateNewContext:
//
// allocate a new context. If all registers are to be saved in the context then
// pTag is passed as null.
// ppdev--------ppdev
// pTag---------user can supply list of registers to save and restore on
// context switch. NULL defaults to all registers.
// Holds pointer to user function if dwCtxtType==P2CtxtUserFunc
// lTags--------number of tags in user supplied register list
// dwCtxtType---P2CtxtReadWrite (default)
// on a context switch, all Permedia 2 registers are
// saved and restored.
// P2CtxtWriteOnly
// registers of context will be saved once at the first
// context switch. After that they will always be restored
// to the state ate the very beginning. This method avoids
// readback of registers when switching away from context.
// P2CtxtUserFunc
// User can supply a user function to set context to a known
// state, to avoid readback when switching away from context.
//
//-----------------------------------------------------------------------------
P2CtxtPtr
P2AllocateNewContext(PPDev ppdev,
DWORD *pTag,
LONG lTags,
P2CtxtType dwCtxtType
)
{
P2CtxtTablePtr pCtxtTable, pNewCtxtTable;
P2CtxtPtr pEntry;
P2CtxtData *pData;
LONG lEntries;
LONG lExtraSize;
LONG lSize;
LONG lCtxtId;
PERMEDIA_DECL;
PERMEDIA_DEFS(ppdev);
// first time round allocate the context table of pointers. We will
// grow this table as required.
//
if (permediaInfo->ContextTable == NULL)
{
DISPDBG((7, "creating context table"));
lSize = sizeof(P2CtxtTableRec);
pCtxtTable = (P2CtxtTableRec *)
ENGALLOCMEM( FL_ZERO_MEMORY, sizeof(P2CtxtTableRec), ALLOC_TAG);
if (pCtxtTable == NULL)
{
DISPDBG((0, "failed to allocate Permedia2 context table. out of memory"));
return(NULL);
}
pCtxtTable->lEntries = CTXT_CHUNK;
pCtxtTable->lSize = lSize;
permediaInfo->ContextTable = pCtxtTable;
permediaInfo->pCurrentCtxt = NULL;
}
// find an empty entry in the table
// I suppose if we have hundreds of contexts this could be a bit slow but then
// allocating the context isn't time critical, swapping in and out is.
//
pCtxtTable = (P2CtxtTablePtr) permediaInfo->ContextTable;
lEntries = pCtxtTable->lEntries;
for (lCtxtId = 0; lCtxtId < lEntries; ++lCtxtId)
if(pCtxtTable->pEntry[lCtxtId] == NULL)
break;
// if we found no free entries try to grow the table
if (lCtxtId == lEntries) {
DISPDBG((1, "context table full so enlarging"));
lSize = pCtxtTable->lSize + (CTXT_CHUNK * sizeof(P2CtxtPtr));
pNewCtxtTable =
(P2CtxtTablePtr) ENGALLOCMEM( FL_ZERO_MEMORY, sizeof(BYTE)*lSize, ALLOC_TAG);
if (pNewCtxtTable == NULL) {
DISPDBG((0, "failed to increase Permedia 2 context table. out of memory"));
return(NULL);
}
// copy the old table to the new one
RtlCopyMemory(pNewCtxtTable, pCtxtTable, pCtxtTable->lSize);
pNewCtxtTable->lSize = lSize;
pNewCtxtTable->lEntries = lEntries + CTXT_CHUNK;
permediaInfo->ContextTable = (PVOID)pNewCtxtTable;
// first of the newly allocated entries is next free one
lCtxtId = lEntries;
// free the old context table and reassign some variables
ENGFREEMEM(pCtxtTable);
pCtxtTable = pNewCtxtTable;
lEntries = pCtxtTable->lEntries;
}
// if pTag is passed as null then we are to add all readable registers to the
// context.
lExtraSize = 0;
if (dwCtxtType != P2CtxtUserFunc)
{
if (pTag == 0)
{
DISPDBG((7, "adding all readable registers to the context"));
DISPDBG((7, "Using PERMEDIA 2 register set for other context switch"));
pTag = readableRegistersP2;
lTags = N_READABLE_TAGSP2;
}
} else
{
lTags = 1;
}
// now allocate space for the new entry. We are given the number of tags to save
// when context switching. Allocate twice this much memory as we have to hold the
// data values as well.
DISPDBG((7, "Allocating space for context. lTags = %d", lTags));
lSize = sizeof(P2CtxtRec) + (lTags-1) * sizeof(P2CtxtData);
pEntry = (P2CtxtPtr)
ENGALLOCMEM( FL_ZERO_MEMORY, sizeof(BYTE)*(lSize+lExtraSize), ALLOC_TAG);
if (pEntry == NULL) {
DISPDBG((0, "out of memory trying to allocate space for new context"));
return(NULL);
}
DISPDBG((7, "Got pEntry 0x%x", pEntry));
pCtxtTable->pEntry[lCtxtId] = pEntry;
// allocate enough space for the Texel LUT: 256 entries
pEntry->dwCtxtType=dwCtxtType;
pEntry->bInitialized=FALSE;
pEntry->pTexelLUTCtxt = (PULONG)
ENGALLOCMEM( FL_ZERO_MEMORY, sizeof(ULONG)*256, ALLOC_TAG);
if (pEntry->pTexelLUTCtxt!=0)
{
pEntry->ulTexelLUTEntries = 256;
} else
{
pEntry->ulTexelLUTEntries = 0;
}
pEntry->lNumOfTags = lTags;
pEntry->P2UserFunc = NULL;
pData = pEntry->pData;
if (dwCtxtType != P2CtxtUserFunc)
{
// we must initialize the new context to something reasonable. We choose to
// initialize to the current state of the chip. We can't leave it uninitialized
// since the first thing the caller will do when he wants to draw is validate
// the new context which will load junk into the chip. At some point we
// should define a reasonable starting context which would mean we wouldn't
// have to do this readback.
// copy the tags and read the data back from the chip. We don't sync since we are
// only initialising the context to something reasonable. i.e. we don't care if
// the FIFO is still draining while we do this.
DISPDBG((7, "Reading current chip context back"));
while (--lTags >= 0) {
pData->dwTag = *pTag++;
READ_PERMEDIA_FIFO_REG(pData->dwTag, pData->dwData);
++pData;
}
// save the texel LUT
if(pEntry->ulTexelLUTEntries &&
pEntry->pTexelLUTCtxt!=NULL)
{
ULONG *pul;
INT i=0;
lEntries = pEntry->ulTexelLUTEntries;
pul = pEntry->pTexelLUTCtxt;
//special mechanism: reset readback index to 0
READ_PERMEDIA_FIFO_REG(__Permedia2TagTexelLUTIndex, i);
for(i = 0; i < lEntries; ++i, ++pul)
{
READ_PERMEDIA_FIFO_REG(__Permedia2TagTexelLUTData, *pul);
}
}
} else
{
pEntry->P2UserFunc = (PCtxtUserFunc) pTag;
}
DISPDBG((1, "Allocated context %lx", pEntry));
return(pEntry);
} // P2AllocateNewContext
//-----------------------------------------------------------------------------
//
// P2FreeContext:
//
// free a previously allocated context.
//
//-----------------------------------------------------------------------------
VOID
P2FreeContext( PPDev ppdev,
P2CtxtPtr pEntry)
{
PERMEDIA_DECL;
P2CtxtTablePtr pCtxtTable;
ULONG lCtxtId;
pCtxtTable = (P2CtxtTablePtr) permediaInfo->ContextTable;
for (lCtxtId = 0; lCtxtId < pCtxtTable->lEntries; ++lCtxtId)
if(pCtxtTable->pEntry[lCtxtId] == pEntry)
break;
ASSERTDD(lCtxtId != pCtxtTable->lEntries, "P2FreeContext: context not found");
// free LUT Table
if(pEntry->pTexelLUTCtxt)
{
ENGFREEMEM( pEntry->pTexelLUTCtxt);
}
ENGFREEMEM( pEntry);
pCtxtTable->pEntry[lCtxtId] = NULL;
// if this was the current context, mark the current context as invalid so we
// force a reload next time.
if (permediaInfo->pCurrentCtxt == pEntry)
{
permediaInfo->pCurrentCtxt = NULL;
}
DISPDBG((1, "Released context %lx", pEntry));
}
//-----------------------------------------------------------------------------
//
// VOID P2SwitchContext:
//
// load a new context into the hardware. We assume that this call is
// protected by a test that the given context is not the current one -
// hence the assertion.
// The code would work but the driver should never try to load an already
// loaded context so we trap it as an error.
//
//-----------------------------------------------------------------------------
VOID
P2SwitchContext(
PPDev ppdev,
P2CtxtPtr pEntry)
{
P2CtxtTablePtr pCtxtTable;
P2CtxtData *pData;
P2CtxtPtr pOldCtxt;
LONG lTags;
LONG i;
ULONG *pul;
LONG lEntries;
PERMEDIA_DECL;
PERMEDIA_DEFS(ppdev);
//@@BEGIN_DDKSPLIT
#if MULTITHREADED
EngAcquireSemaphore(ppdev->hsemLock);
ASSERTDD(ppdev->ulLockCount, "P2SwitchContext: ulLockCount = 0\n Context could change as caller is NOT protected!");
ppdev->ulLockCount++;
#endif
//@@END_DDKSPLIT
pCtxtTable = (P2CtxtTablePtr)permediaInfo->ContextTable;
ASSERTDD(pCtxtTable, "Can't perform context switch: no contexts have been created!");
pOldCtxt = permediaInfo->pCurrentCtxt;
DISPDBG((3, "swapping from context %d to context %d", pOldCtxt, pEntry));
if(pOldCtxt == permediaInfo->pGDICtxt)
{
DISPDBG((6, "Switching from GDI context"));
ASSERTDD(ppdev->bNeedSync ||
(ppdev->pulInFifoPtr == ppdev->pulInFifoStart),
"P2SwitchContext: bNeedSync flag is wrong");
InputBufferSync(ppdev);
ppdev->bGdiContext = FALSE;
ppdev->pP2dma->bEnabled = TRUE;
}
// for each register in the old context, read it back
if (pOldCtxt != NULL) {
//
// P2CtxtWriteOnly will only be readback once after context initialization
//
if ((pOldCtxt->dwCtxtType==P2CtxtReadWrite) ||
(pOldCtxt->dwCtxtType==P2CtxtWriteOnly && !pOldCtxt->bInitialized)
)
{
// sync with the chip before reading back the current state. The flag
// is used to control context manipulation on lockup recovery.
SYNC_WITH_PERMEDIA;
pData = pOldCtxt->pData;
lTags = pOldCtxt->lNumOfTags;
while (--lTags >= 0) {
READ_PERMEDIA_FIFO_REG(pData->dwTag, pData->dwData);
++pData;
}
// save the texel LUT
if(pOldCtxt->ulTexelLUTEntries &&
pOldCtxt->pTexelLUTCtxt!=NULL)
{
lEntries = pOldCtxt->ulTexelLUTEntries;
pul = pOldCtxt->pTexelLUTCtxt;
//special mechanism: reset readback index to 0
READ_PERMEDIA_FIFO_REG(__Permedia2TagTexelLUTIndex, i);
for(i = 0; i < lEntries; ++i, ++pul)
{
READ_PERMEDIA_FIFO_REG(__Permedia2TagTexelLUTData, *pul);
}
}
pOldCtxt->bInitialized=TRUE;
}
}
// load the new context. We allow -1 to be passed so that we can force a
// save of the current context and force the current context to be
// undefined.
//
if (pEntry != NULL)
{
if (pEntry->dwCtxtType==P2CtxtUserFunc)
{
ASSERTDD(pEntry->P2UserFunc!=NULL,"supplied user function not initialized");
(*pEntry->P2UserFunc)(ppdev);
} else
if (pEntry->dwCtxtType==P2CtxtWriteOnly ||
pEntry->dwCtxtType==P2CtxtReadWrite)
{
lTags = pEntry->lNumOfTags;
pData = pEntry->pData;
while (lTags > 0) {
lEntries = MAX_P2_FIFO_ENTRIES;
lTags -= lEntries;
if (lTags < 0)
lEntries += lTags;
RESERVEDMAPTR(lEntries);
while (--lEntries >= 0) {
LD_INPUT_FIFO(pData->dwTag, pData->dwData);
DISPDBG((20, "loading tag 0x%x, data 0x%x", pData->dwTag, pData->dwData));
++pData;
}
COMMITDMAPTR();
}
// restore the texel LUT
if(pEntry->ulTexelLUTEntries &&
pEntry->pTexelLUTCtxt!=NULL )
{
lEntries = pEntry->ulTexelLUTEntries;
pul = pEntry->pTexelLUTCtxt;
RESERVEDMAPTR(lEntries+1);
LD_INPUT_FIFO(__Permedia2TagTexelLUTIndex, 0);
for(i = 0; i < lEntries; ++i, ++pul)
{
LD_INPUT_FIFO(__Permedia2TagTexelLUTData, *pul);
}
COMMITDMAPTR();
FLUSHDMA();
}
} else
{
ASSERTDD( FALSE, "undefined state for entry in context table");
}
}
if(pEntry == permediaInfo->pGDICtxt)
{
DISPDBG((6, "Switching to GDI context"));
//
// we have to do a full sync here, because GDI and DDraw
// share the same DMA buffer. To make sure nothing will be
// overridden, we do a complete sync
//
SYNC_WITH_PERMEDIA;
//
// Turn off permedia interrupt handler
//
WRITE_CTRL_REG( PREG_INTENABLE, 0);
ppdev->bGdiContext = TRUE;
ppdev->pP2dma->bEnabled = FALSE;
// invalidate the mono brush cache entry
// stipple unit was restored to default values
ppdev->abeMono.prbVerify = NULL;
}
DISPDBG((6, "context %lx now current", pEntry));
permediaInfo->pCurrentCtxt = pEntry;
//@@BEGIN_DDKSPLIT
#if MULTITHREADED
ppdev->ulLockCount--;
EngReleaseSemaphore(ppdev->hsemLock);
#endif
//@@END_DDKSPLIT
}