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.
3213 lines
122 KiB
3213 lines
122 KiB
/******************************Module*Header**********************************\
|
|
*
|
|
* *******************
|
|
* * D3D SAMPLE CODE *
|
|
* *******************
|
|
*
|
|
* Module Name: d3ddp2op.c
|
|
*
|
|
* Content: D3D DrawPrimitives2 command buffer operations support
|
|
*
|
|
* 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"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// __OP_IntersectRectl
|
|
//
|
|
// This function intersects two RECTLs. If no intersection exists returns FALSE
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL
|
|
__OP_IntersectRectl(
|
|
RECTL* prcresult,
|
|
RECTL* prcin1,
|
|
RECT* prcin2)
|
|
{
|
|
prcresult->left = max(prcin1->left, prcin2->left);
|
|
prcresult->right = min(prcin1->right, prcin2->right);
|
|
|
|
if (prcresult->left < prcresult->right)
|
|
{
|
|
prcresult->top = max(prcin1->top, prcin2->top);
|
|
prcresult->bottom = min(prcin1->bottom, prcin2->bottom);
|
|
|
|
if (prcresult->top < prcresult->bottom)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
} // __OP_IntersectRectl
|
|
|
|
#if DX7_TEXMANAGEMENT
|
|
VOID __OP_MarkManagedSurfDirty(P3_D3DCONTEXT* pContext,
|
|
DWORD dwSurfHandle,
|
|
P3_SURF_INTERNAL* pTexture);
|
|
#endif
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_Clear2
|
|
//
|
|
// This function processes the D3DDP2OP_CLEAR DP2 command token.
|
|
//
|
|
// It builds a mask and a value for the stencil/depth clears. The mask is used
|
|
// to stop unwanted bits being updated during the clear. The value is scaled in
|
|
// the case of the Z depth, and is shifted in the case of the stencil. This
|
|
// results in the correct value being written, at the correct location in the
|
|
// ZBuffer, while doing fast-block fills through SGRAM
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#define P3RX_UPDATE_WRITE_MASK(a) \
|
|
if (dwCurrentMask != a) \
|
|
{ \
|
|
P3_DMA_GET_BUFFER_ENTRIES(2); \
|
|
SEND_P3_DATA(FBHardwareWriteMask, a); \
|
|
P3_DMA_COMMIT_BUFFER(); \
|
|
dwCurrentMask = a; \
|
|
}
|
|
|
|
VOID
|
|
_D3D_OP_Clear2(
|
|
P3_D3DCONTEXT* pContext,
|
|
D3DHAL_DP2CLEAR* lpcd2,
|
|
DWORD dwNumRects)
|
|
{
|
|
DWORD i;
|
|
RECTL rect, rect_vwport;
|
|
DWORD dwDepthValue;
|
|
DWORD dwStencilValue;
|
|
DWORD dwStencilMask;
|
|
DWORD dwDepthMask;
|
|
DWORD color;
|
|
DWORD dwCurrentMask = 0xFFFFFFFF;
|
|
BOOL bNoBlockFillZ = FALSE;
|
|
BOOL bNoBlockFillStencil = FALSE;
|
|
BOOL bComputeIntersections = FALSE;
|
|
BYTE Bytes[4];
|
|
P3_THUNKEDDATA* pThisDisplay = pContext->pThisDisplay;
|
|
HRESULT ddrval;
|
|
D3DHAL_DP2CLEAR WholeViewport;
|
|
|
|
P3_DMA_DEFS();
|
|
|
|
DBG_CB_ENTRY(_D3D_OP_Clear2);
|
|
|
|
// Check if we were asked to clear a valid buffer
|
|
if ( (lpcd2->dwFlags & (D3DCLEAR_TARGET |
|
|
D3DCLEAR_ZBUFFER |
|
|
D3DCLEAR_STENCIL) ) == 0)
|
|
{
|
|
// We have been asked to do nothing - and that's what we've done.
|
|
DBG_CB_EXIT(_D3D_OP_Clear2, DD_OK);
|
|
return;
|
|
}
|
|
|
|
|
|
#if DX8_DDI
|
|
// When zero clear rects is passed to a DX8 driver with D3DDP2OP_CLEAR
|
|
// token, the driver should clear the whole viewport. The zero number
|
|
// of rects could be passed only if D3D is using a pure device.
|
|
|
|
// D3DCLEAR_COMPUTERECTS has been added to the dwFlags of D3DHAL_CLEARDATA.
|
|
// When set, the flag means that user provided clear rects should be
|
|
// culled against the current viewport.
|
|
|
|
if (!(lpcd2->dwFlags & D3DCLEAR_COMPUTERECTS))
|
|
{
|
|
// Do nothing for non-pure device
|
|
}
|
|
else
|
|
if (dwNumRects == 0)
|
|
{
|
|
// When wStateCount is zero we need to clear whole viewport
|
|
WholeViewport.dwFlags = lpcd2->dwFlags;
|
|
WholeViewport.dwFillColor = lpcd2->dwFillColor;
|
|
WholeViewport.dvFillDepth = lpcd2->dvFillDepth;
|
|
WholeViewport.dwFillStencil = lpcd2->dwFillStencil;
|
|
WholeViewport.Rects[0].left = pContext->ViewportInfo.dwX;
|
|
WholeViewport.Rects[0].top = pContext->ViewportInfo.dwY;
|
|
WholeViewport.Rects[0].right = pContext->ViewportInfo.dwX +
|
|
pContext->ViewportInfo.dwWidth;
|
|
WholeViewport.Rects[0].bottom = pContext->ViewportInfo.dwY +
|
|
pContext->ViewportInfo.dwHeight;
|
|
// Replace pointers and continue as usual
|
|
lpcd2 = &WholeViewport;
|
|
dwNumRects = 1;
|
|
}
|
|
else
|
|
{
|
|
// We need to cull all rects against the current viewport
|
|
// but in order not to allocate a temporary RECT array in
|
|
// kernel heap we'll compute this inside the clearing loop
|
|
|
|
rect_vwport.left = pContext->ViewportInfo.dwX;
|
|
rect_vwport.top = pContext->ViewportInfo.dwY;
|
|
rect_vwport.right = pContext->ViewportInfo.dwX +
|
|
pContext->ViewportInfo.dwWidth;
|
|
rect_vwport.bottom = pContext->ViewportInfo.dwY +
|
|
pContext->ViewportInfo.dwHeight;
|
|
|
|
bComputeIntersections = TRUE;
|
|
|
|
}
|
|
#endif // DX8_DDI
|
|
|
|
// Check if there is any rect to clear at all
|
|
if ( dwNumRects == 0)
|
|
{
|
|
// We have been asked to do nothing - and that's what we've done.
|
|
DBG_CB_EXIT(_D3D_OP_Clear2, DD_OK);
|
|
return;
|
|
}
|
|
|
|
// Wait until we have we finished flipping before clearing anything
|
|
do
|
|
{
|
|
ddrval =
|
|
_DX_QueryFlipStatus(pContext->pThisDisplay,
|
|
pContext->pSurfRenderInt->fpVidMem,
|
|
TRUE);
|
|
} while ( FAILED (ddrval) );
|
|
|
|
// Switch to hw Ddraw context in order to do the clears
|
|
DDRAW_OPERATION(pContext, pThisDisplay);
|
|
|
|
// Prepare any data necessary to clear the render target
|
|
if ((lpcd2->dwFlags & D3DCLEAR_TARGET) &&
|
|
(pContext->pSurfRenderInt != NULL))
|
|
{
|
|
color = lpcd2->dwFillColor;
|
|
|
|
// Clear depending on depth
|
|
switch (pContext->pSurfRenderInt->dwPixelSize)
|
|
{
|
|
// 16 Bit colors come in as 32 Bit RGB Values
|
|
// Color will be packed in the clear function
|
|
case __GLINT_16BITPIXEL:
|
|
if (pThisDisplay->ddpfDisplay.dwRBitMask == 0x7C00)
|
|
{
|
|
color = ((color & 0xf8) >> 3) |
|
|
((color & 0xf800) >> (16 - 10)) |
|
|
((color & 0xf80000) >> (24 - 15));
|
|
}
|
|
else
|
|
{
|
|
color = ((color & 0xff) >> 3) |
|
|
((color & 0xfc00) >> (16 - 11)) |
|
|
((color & 0xf80000) >> (24 - 16));
|
|
}
|
|
break;
|
|
|
|
case __GLINT_24BITPIXEL:
|
|
DISPDBG((ERRLVL,"P3 doesn't support 24 bpp render target"));
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
} // if (lpcd2->dwFlags & D3DCLEAR_TARGET)
|
|
|
|
// Prepare any data necessary to clear the depth buffer
|
|
if ((lpcd2->dwFlags & D3DCLEAR_ZBUFFER) &&
|
|
(pContext->pSurfZBufferInt != NULL))
|
|
{
|
|
float fDepth;
|
|
|
|
DDPIXELFORMAT* pPixFormat = &pContext->pSurfZBufferInt->pixFmt;
|
|
|
|
DWORD dwZBitDepth = pPixFormat->dwZBufferBitDepth;
|
|
|
|
// Find the depth bits, remembering to remove any stencil bits.
|
|
if (pPixFormat->dwFlags & DDPF_STENCILBUFFER)
|
|
{
|
|
dwZBitDepth -= pPixFormat->dwStencilBitDepth;
|
|
}
|
|
|
|
dwDepthMask = (0xFFFFFFFF >> (32 - dwZBitDepth));
|
|
|
|
// 32 bit depth buffers on Perm3 are really
|
|
// limited to 31 bits of precision
|
|
if (dwZBitDepth == 32)
|
|
{
|
|
dwDepthMask = dwDepthMask >> 1;
|
|
}
|
|
|
|
if (lpcd2->dvFillDepth == 1.0f)
|
|
{
|
|
dwDepthValue = dwDepthMask;
|
|
}
|
|
else
|
|
{
|
|
fDepth = lpcd2->dvFillDepth * (float)dwDepthMask;
|
|
|
|
// This is a hardware dependency on how the Perm3 handles the
|
|
// limited precision of 32bit floats(24 bits of mantissa) and
|
|
// converts the value into a 32bit z buffer value. This doesn't
|
|
// happen with any other z bit depth but 32.
|
|
if (dwZBitDepth == 32)
|
|
{
|
|
fDepth += 0.5f;
|
|
}
|
|
|
|
myFtoi((int*)&dwDepthValue, fDepth);
|
|
}
|
|
|
|
// As we are fast-block filling, make sure we copy the
|
|
// Mask to the top bits.
|
|
switch (pContext->pSurfZBufferInt->dwPixelSize)
|
|
{
|
|
case __GLINT_16BITPIXEL:
|
|
dwDepthMask &= 0xFFFF;
|
|
dwDepthMask |= (dwDepthMask << 16);
|
|
break;
|
|
case __GLINT_8BITPIXEL:
|
|
dwDepthMask &= 0xFF;
|
|
dwDepthMask |= dwDepthMask << 8;
|
|
dwDepthMask |= dwDepthMask << 16;
|
|
break;
|
|
}
|
|
|
|
if (pThisDisplay->pGLInfo->bDRAMBoard)
|
|
{
|
|
// Check for a DRAM fill that the chip isn't emulating.
|
|
Bytes[0] = (BYTE)(dwDepthMask & 0xFF);
|
|
Bytes[1] = (BYTE)((dwDepthMask & 0xFF00) >> 8);
|
|
Bytes[2] = (BYTE)((dwDepthMask & 0xFF0000) >> 16);
|
|
Bytes[3] = (BYTE)((dwDepthMask & 0xFF000000) >> 24);
|
|
if (((Bytes[0] != 0) && (Bytes[0] != 0xFF)) ||
|
|
((Bytes[1] != 0) && (Bytes[1] != 0xFF)) ||
|
|
((Bytes[2] != 0) && (Bytes[2] != 0xFF)) ||
|
|
((Bytes[3] != 0) && (Bytes[3] != 0xFF)))
|
|
{
|
|
bNoBlockFillZ = TRUE;
|
|
}
|
|
}
|
|
|
|
DISPDBG((DBGLVL,"ZClear Value = 0x%x, ZClear Mask = 0x%x",
|
|
dwDepthValue, dwDepthMask));
|
|
} // if (lpcd2->dwFlags & D3DCLEAR_ZBUFFER)
|
|
|
|
// Prepare any data necessary to clear the stencil buffer
|
|
if ((lpcd2->dwFlags & D3DCLEAR_STENCIL) &&
|
|
(pContext->pSurfZBufferInt != NULL))
|
|
{
|
|
int dwShiftCount = 0;
|
|
DDPIXELFORMAT* pPixFormat = &pContext->pSurfZBufferInt->pixFmt;
|
|
|
|
// Find out where to shift the
|
|
dwStencilMask = pPixFormat->dwStencilBitMask;
|
|
|
|
if (dwStencilMask != 0)
|
|
{
|
|
while ((dwStencilMask & 0x1) == 0)
|
|
{
|
|
dwStencilMask >>= 1;
|
|
dwShiftCount++;
|
|
}
|
|
|
|
dwStencilValue = (lpcd2->dwFillStencil << dwShiftCount);
|
|
dwStencilMask = pPixFormat->dwStencilBitMask;
|
|
|
|
// As we are fast-block filling, make sure we copy the
|
|
// Mask to the top bits.
|
|
switch (pContext->pSurfZBufferInt->dwPixelSize)
|
|
{
|
|
case __GLINT_16BITPIXEL:
|
|
dwStencilMask &= 0xFFFF;
|
|
dwStencilMask |= (dwStencilMask << 16);
|
|
break;
|
|
|
|
case __GLINT_8BITPIXEL:
|
|
dwStencilMask &= 0xFF;
|
|
dwStencilMask |= dwStencilMask << 8;
|
|
dwStencilMask |= dwStencilMask << 16;
|
|
break;
|
|
}
|
|
|
|
DISPDBG((DBGLVL,"Stencil Clear Value = 0x%x, Stencil Mask = 0x%x",
|
|
dwStencilValue, dwStencilMask));
|
|
}
|
|
else
|
|
{
|
|
DISPDBG((ERRLVL,"ERROR: Stencil mask is not valid!"));
|
|
dwStencilValue = 0;
|
|
dwStencilMask = 0;
|
|
}
|
|
|
|
if (pThisDisplay->pGLInfo->bDRAMBoard)
|
|
{
|
|
// Check for a DRAM fill that the chip isn't emulating.
|
|
Bytes[0] = (BYTE)(dwStencilMask & 0xFF);
|
|
Bytes[1] = (BYTE)((dwStencilMask & 0xFF00) >> 8);
|
|
Bytes[2] = (BYTE)((dwStencilMask & 0xFF0000) >> 16);
|
|
Bytes[3] = (BYTE)((dwStencilMask & 0xFF000000) >> 24);
|
|
if (((Bytes[0] != 0) && (Bytes[0] != 0xFF)) ||
|
|
((Bytes[1] != 0) && (Bytes[1] != 0xFF)) ||
|
|
((Bytes[2] != 0) && (Bytes[2] != 0xFF)) ||
|
|
((Bytes[3] != 0) && (Bytes[3] != 0xFF)))
|
|
{
|
|
bNoBlockFillStencil = TRUE;
|
|
}
|
|
}
|
|
} // if (lpcd2->dwFlags & D3DCLEAR_STENCIL)
|
|
|
|
|
|
// Loop through each clearing rect and perform the clearing hw operations
|
|
i = dwNumRects;
|
|
while (i-- > 0)
|
|
{
|
|
if (bComputeIntersections)
|
|
{
|
|
// Compute intersection between the viewport and the incoming
|
|
// RECTLs. If no intersection exists skip into next one.
|
|
|
|
if (!__OP_IntersectRectl(&rect, &rect_vwport, &lpcd2->Rects[i]))
|
|
{
|
|
// No intersection, so skip it
|
|
goto Next_Rectl_To_Clear;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// We already have the rects we need to clear, so
|
|
// just use them in reverse order
|
|
rect.left = lpcd2->Rects[i].left;
|
|
rect.right = lpcd2->Rects[i].right;
|
|
rect.top = lpcd2->Rects[i].top;
|
|
rect.bottom = lpcd2->Rects[i].bottom;
|
|
}
|
|
|
|
// Clear the frame buffer
|
|
if ((lpcd2->dwFlags & D3DCLEAR_TARGET) &&
|
|
(pContext->pSurfRenderInt != NULL))
|
|
{
|
|
P3RX_UPDATE_WRITE_MASK(__GLINT_ALL_WRITEMASKS_SET);
|
|
|
|
#if DX8_MULTISAMPLING || DX7_ANTIALIAS
|
|
if (pContext->Flags & SURFACE_ANTIALIAS)
|
|
{
|
|
RECTL Temp = rect;
|
|
Temp.left *= 2;
|
|
Temp.right *= 2;
|
|
Temp.top *= 2;
|
|
Temp.bottom *= 2;
|
|
|
|
_DD_BLT_P3Clear_AA(pThisDisplay,
|
|
&Temp,
|
|
pContext->dwAliasBackBuffer -
|
|
pThisDisplay->dwScreenFlatAddr,
|
|
color,
|
|
FALSE,
|
|
pContext->pSurfRenderInt->dwPatchMode,
|
|
pContext->pSurfRenderInt->dwPixelPitch,
|
|
pContext->pSurfRenderInt->pixFmt.dwRGBBitCount,
|
|
pContext->pSurfRenderInt->ddsCapsInt);
|
|
}
|
|
else
|
|
#endif // DX8_MULTISAMPLING || DX7_ANTIALIAS
|
|
{
|
|
|
|
_DD_BLT_P3Clear(pThisDisplay,
|
|
&rect,
|
|
color,
|
|
FALSE,
|
|
FALSE,
|
|
pContext->pSurfRenderInt->fpVidMem,
|
|
pContext->pSurfRenderInt->dwPatchMode,
|
|
pContext->pSurfRenderInt->dwPixelPitch,
|
|
pContext->pSurfRenderInt->pixFmt.dwRGBBitCount);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// Clear the z buffer
|
|
if ((lpcd2->dwFlags & D3DCLEAR_ZBUFFER) &&
|
|
(pContext->pSurfZBufferInt != NULL) )
|
|
{
|
|
P3RX_UPDATE_WRITE_MASK(dwDepthMask);
|
|
|
|
if (bNoBlockFillZ)
|
|
{
|
|
P3_DMA_GET_BUFFER_ENTRIES(4);
|
|
SEND_P3_DATA(FBSoftwareWriteMask, dwDepthMask);
|
|
SEND_P3_DATA(FBDestReadMode,
|
|
P3RX_FBDESTREAD_READENABLE(__PERMEDIA_ENABLE) |
|
|
P3RX_FBDESTREAD_ENABLE0(__PERMEDIA_ENABLE));
|
|
P3_DMA_COMMIT_BUFFER();
|
|
}
|
|
|
|
#if DX8_MULTISAMPLING || DX7_ANTIALIAS
|
|
if (pContext->Flags & SURFACE_ANTIALIAS)
|
|
{
|
|
RECTL Temp = rect;
|
|
Temp.left *= 2;
|
|
Temp.right *= 2;
|
|
Temp.top *= 2;
|
|
Temp.bottom *= 2;
|
|
_DD_BLT_P3Clear_AA(pThisDisplay,
|
|
&Temp,
|
|
pContext->dwAliasZBuffer -
|
|
pThisDisplay->dwScreenFlatAddr,
|
|
dwDepthValue,
|
|
bNoBlockFillZ,
|
|
pContext->pSurfZBufferInt->dwPatchMode,
|
|
pContext->pSurfZBufferInt->dwPixelPitch,
|
|
pContext->pSurfZBufferInt->pixFmt.dwRGBBitCount,
|
|
pContext->pSurfZBufferInt->ddsCapsInt);
|
|
|
|
}
|
|
else
|
|
#endif // DX8_MULTISAMPLING || DX7_ANTIALIAS
|
|
{
|
|
_DD_BLT_P3Clear(pThisDisplay,
|
|
&rect,
|
|
dwDepthValue,
|
|
bNoBlockFillZ,
|
|
TRUE,
|
|
pContext->pSurfZBufferInt->fpVidMem,
|
|
pContext->pSurfZBufferInt->dwPatchMode,
|
|
pContext->pSurfZBufferInt->dwPixelPitch,
|
|
pContext->pSurfZBufferInt->pixFmt.dwRGBBitCount
|
|
);
|
|
}
|
|
|
|
if (bNoBlockFillZ)
|
|
{
|
|
P3_DMA_GET_BUFFER_ENTRIES(4);
|
|
SEND_P3_DATA(FBSoftwareWriteMask, __GLINT_ALL_WRITEMASKS_SET);
|
|
SEND_P3_DATA(FBDestReadMode, __PERMEDIA_DISABLE);
|
|
P3_DMA_COMMIT_BUFFER();
|
|
}
|
|
}
|
|
|
|
// Clear the stencil buffer
|
|
if ((lpcd2->dwFlags & D3DCLEAR_STENCIL) &&
|
|
(pContext->pSurfZBufferInt != NULL) )
|
|
{
|
|
P3RX_UPDATE_WRITE_MASK(dwStencilMask);
|
|
|
|
if (bNoBlockFillStencil)
|
|
{
|
|
P3_DMA_GET_BUFFER_ENTRIES(4);
|
|
SEND_P3_DATA(FBSoftwareWriteMask, dwStencilMask);
|
|
SEND_P3_DATA(FBDestReadMode,
|
|
P3RX_FBDESTREAD_READENABLE(__PERMEDIA_ENABLE) |
|
|
P3RX_FBDESTREAD_ENABLE0(__PERMEDIA_ENABLE));
|
|
P3_DMA_COMMIT_BUFFER();
|
|
}
|
|
|
|
#if DX8_MULTISAMPLING || DX7_ANTIALIAS
|
|
if (pContext->Flags & SURFACE_ANTIALIAS)
|
|
{
|
|
RECTL Temp = rect;
|
|
Temp.left *= 2;
|
|
Temp.right *= 2;
|
|
Temp.top *= 2;
|
|
Temp.bottom *= 2;
|
|
_DD_BLT_P3Clear_AA(pThisDisplay,
|
|
&Temp,
|
|
pContext->dwAliasZBuffer -
|
|
pThisDisplay->dwScreenFlatAddr,
|
|
dwStencilValue,
|
|
bNoBlockFillStencil,
|
|
pContext->pSurfZBufferInt->dwPatchMode,
|
|
pContext->pSurfZBufferInt->dwPixelPitch,
|
|
pContext->pSurfZBufferInt->pixFmt.dwRGBBitCount,
|
|
pContext->pSurfZBufferInt->ddsCapsInt
|
|
);
|
|
|
|
}
|
|
else
|
|
#endif // DX8_MULTISAMPLING || DX7_ANTIALIAS
|
|
{
|
|
|
|
_DD_BLT_P3Clear(pThisDisplay,
|
|
&rect,
|
|
dwStencilValue,
|
|
bNoBlockFillStencil,
|
|
TRUE,
|
|
pContext->pSurfZBufferInt->fpVidMem,
|
|
pContext->pSurfZBufferInt->dwPatchMode,
|
|
pContext->pSurfZBufferInt->dwPixelPitch,
|
|
pContext->pSurfZBufferInt->pixFmt.dwRGBBitCount
|
|
);
|
|
}
|
|
|
|
if (bNoBlockFillStencil)
|
|
{
|
|
P3_DMA_GET_BUFFER_ENTRIES(4);
|
|
SEND_P3_DATA(FBSoftwareWriteMask, __GLINT_ALL_WRITEMASKS_SET);
|
|
SEND_P3_DATA(FBDestReadMode, __PERMEDIA_DISABLE);
|
|
P3_DMA_COMMIT_BUFFER();
|
|
}
|
|
|
|
}
|
|
|
|
Next_Rectl_To_Clear:
|
|
;
|
|
|
|
} // while
|
|
|
|
// Make sure the WriteMask is reset to it's default value
|
|
{
|
|
P3_DMA_GET_BUFFER_ENTRIES(4);
|
|
|
|
SEND_P3_DATA(FBHardwareWriteMask, __GLINT_ALL_WRITEMASKS_SET);
|
|
SEND_P3_DATA(FBDestReadMode, __PERMEDIA_DISABLE);
|
|
|
|
P3_DMA_COMMIT_BUFFER();
|
|
}
|
|
|
|
DBG_CB_EXIT(_D3D_OP_Clear2, DD_OK);
|
|
return;
|
|
|
|
} // _D3D_OP_Clear2
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_TextureBlt
|
|
//
|
|
// This function processes the D3DDP2OP_TEXBLT DP2 command token.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID _D3D_OP_TextureBlt(P3_D3DCONTEXT* pContext,
|
|
P3_THUNKEDDATA*pThisDisplay,
|
|
D3DHAL_DP2TEXBLT* pBlt)
|
|
{
|
|
LPDDRAWI_DDRAWSURFACE_LCL pSrcLcl;
|
|
LPDDRAWI_DDRAWSURFACE_LCL pDestLcl;
|
|
P3_SURF_INTERNAL* pSrcTexture;
|
|
P3_SURF_INTERNAL* pDestTexture;
|
|
P3_SURF_FORMAT* pFormatSource;
|
|
P3_SURF_FORMAT* pFormatDest;
|
|
MIPTEXTURE *pSrcMipLevel, *pDstMipLevel;
|
|
RECTL rSrc, rDest;
|
|
int iMaxLogWidth, iCurrLogWidth;
|
|
int iSrcLOD, iDestLOD, iCurrSrcLOD, iCurrDstLOD;
|
|
BOOL bMipMap, bMipMapLevelsMatch;
|
|
|
|
DISPDBG((DBGLVL, "TextureBlt Source %d Dest %d",
|
|
pBlt->dwDDSrcSurface,
|
|
pBlt->dwDDDestSurface));
|
|
|
|
if (0 == pBlt->dwDDSrcSurface)
|
|
{
|
|
DISPDBG((ERRLVL,"Invalid handle TexBlt from %08lx to %08lx",
|
|
pBlt->dwDDSrcSurface,pBlt->dwDDDestSurface));
|
|
return;
|
|
}
|
|
|
|
// Get the source texture structure pointer
|
|
pSrcTexture = GetSurfaceFromHandle(pContext, pBlt->dwDDSrcSurface);
|
|
|
|
// Check that the source texture is valid
|
|
if (pSrcTexture == NULL)
|
|
{
|
|
DISPDBG((ERRLVL, "ERROR: Source texture %d is invalid!",
|
|
pBlt->dwDDSrcSurface));
|
|
return;
|
|
}
|
|
|
|
// Validate the destination texture handle
|
|
if (0 == pBlt->dwDDDestSurface)
|
|
{
|
|
#if DX7_TEXMANAGEMENT
|
|
|
|
// If we do texture management then a destination handle of 0
|
|
// has the special meaning of preloading the source texture.
|
|
|
|
if (!_D3D_TM_Preload_Tex_IntoVidMem(pContext, pSrcTexture))
|
|
{
|
|
DISPDBG((ERRLVL,"_D3D_OP_TextureBlt unable to "
|
|
"preload texture"));
|
|
}
|
|
|
|
return;
|
|
|
|
#else
|
|
// If there's no driver texture managament support we can't go
|
|
// on if the destination handle is 0
|
|
DISPDBG((ERRLVL,"Invalid handle TexBlt from %08lx to %08lx",
|
|
pBlt->dwDDSrcSurface,pBlt->dwDDDestSurface));
|
|
return;
|
|
#endif
|
|
}
|
|
|
|
// Get the destination texture structure pointer for regular TexBlts
|
|
pDestTexture = GetSurfaceFromHandle(pContext, pBlt->dwDDDestSurface);
|
|
|
|
// Check that the destination texture is valid
|
|
if (pDestTexture == NULL)
|
|
{
|
|
DISPDBG((ERRLVL, "ERROR: Dest texture %d is invalid!",
|
|
pBlt->dwDDDestSurface));
|
|
return;
|
|
}
|
|
|
|
// Make sure the textures are of the same proportion
|
|
if ((pSrcTexture->wWidth * pDestTexture->wHeight) !=
|
|
(pSrcTexture->wHeight * pDestTexture->wWidth))
|
|
{
|
|
DISPDBG((ERRLVL, "ERROR: TEXBLT the src and dest textures are not of the same proportion"));
|
|
return;
|
|
}
|
|
|
|
// It is possible that the source and destination textures may contain
|
|
// different number of mipmap levels. In this case, the driver is
|
|
// expected to BitBlt the common levels. For example, if a 256x256 source
|
|
// texture has 8 mipmap levels, and if the destination is a 64x64 texture
|
|
// with 6 levels, then the driver should BitBlt the 6 corresponding levels
|
|
// from the source. The driver can expect the dimensions of the top mip
|
|
// level of destination texture to be always equal to or lesser than the
|
|
// dimensions of the top mip level of the source texture.
|
|
|
|
// It might also be the case that only one of the textures is mipmapped
|
|
// Since we keep all relevant info also in the MipLevels substructre for
|
|
// the surface, we can treat both surfaces as mipmapped even if only
|
|
// one of them was created as such and proceed with the TexBlt.
|
|
|
|
if (pSrcTexture->bMipMap || pDestTexture->bMipMap)
|
|
{
|
|
bMipMap = TRUE;
|
|
iMaxLogWidth = max(pSrcTexture->logWidth, pDestTexture->logWidth);
|
|
iCurrLogWidth = iMaxLogWidth;
|
|
iSrcLOD = 0; // start LOD for src
|
|
iDestLOD = 0; // start LOD for dest
|
|
}
|
|
else
|
|
{
|
|
// just one level
|
|
bMipMap = FALSE; // No mipmapping cases to be handled
|
|
iMaxLogWidth = iCurrLogWidth = iSrcLOD = iDestLOD = 0;
|
|
}
|
|
|
|
// Init the rects from and into which we will blt . This is top level
|
|
// mipmap or non-mipmap texture, just use rect from Blt.
|
|
rSrc = pBlt->rSrc;
|
|
|
|
// Create a destination rectangle for compatibility
|
|
// with the DD blitting function we are calling.
|
|
rDest.left = pBlt->pDest.x;
|
|
rDest.top = pBlt->pDest.y;
|
|
rDest.right = (pBlt->rSrc.right - pBlt->rSrc.left) + rDest.left;
|
|
rDest.bottom = (pBlt->rSrc.bottom - pBlt->rSrc.top) + rDest.top;
|
|
|
|
// Traverse all the mip map levels and try to match them for a blt to be
|
|
// done. If no mipmaps are present just do for the "first" and only
|
|
// levels present.
|
|
do
|
|
{
|
|
DISPDBG((DBGLVL,"TEXBLT iteration %d %d %d %d",
|
|
iMaxLogWidth,iCurrLogWidth,iSrcLOD,iDestLOD));
|
|
|
|
// Get the local surface pointers and make sure the level sizes
|
|
// match in the case of mip map Texblts.
|
|
if (bMipMap)
|
|
{
|
|
bMipMapLevelsMatch = FALSE;
|
|
|
|
// Verify you only look at valid mipmap levels - they might
|
|
// be incomplete (and we want not to AV or access garbage!)
|
|
// for example, a source 256x256 texture may contain 5 levels,
|
|
// but the destination 256x256 texture may contain 8. The
|
|
// driver is expected to safely handle this case, but it is
|
|
// not expected to produce correct results
|
|
if ((iSrcLOD < pSrcTexture->iMipLevels) &&
|
|
(iDestLOD < pDestTexture->iMipLevels))
|
|
{
|
|
DISPDBG((DBGLVL,"Checking match! %d vs. %d",
|
|
pSrcTexture->MipLevels[iSrcLOD].logWidth,
|
|
pDestTexture->MipLevels[iDestLOD].logWidth));
|
|
|
|
// Do we currently have two levels that match in size ?
|
|
bMipMapLevelsMatch =
|
|
( pSrcTexture->MipLevels[iSrcLOD].logWidth ==
|
|
pDestTexture->MipLevels[iDestLOD].logWidth);
|
|
}
|
|
|
|
// Record which levels are we currently blitting
|
|
iCurrSrcLOD = iSrcLOD;
|
|
iCurrDstLOD = iDestLOD;
|
|
|
|
// Get ready for next loop by updating the LODs to use
|
|
// increment LOD# if we are currently looking at a level
|
|
// equal or smaller to mip maps level 0 size
|
|
if (iCurrLogWidth <= pSrcTexture->logWidth)
|
|
{
|
|
iSrcLOD++;
|
|
}
|
|
|
|
if (iCurrLogWidth <= pDestTexture->logWidth)
|
|
{
|
|
iDestLOD++;
|
|
}
|
|
|
|
// Decrease the width into next smaller level
|
|
iCurrLogWidth--;
|
|
}
|
|
else
|
|
{
|
|
// Single level blt - we set bMipMapLevelsMatch in order to blt it!
|
|
bMipMapLevelsMatch = TRUE;
|
|
iCurrSrcLOD = 0;
|
|
iCurrDstLOD = 0;
|
|
}
|
|
|
|
if (bMipMapLevelsMatch)
|
|
{
|
|
// Switch to the DirectDraw context
|
|
DDRAW_OPERATION(pContext, pThisDisplay);
|
|
|
|
DISPDBG((DBGLVL,"Blitting level %d into level %d",
|
|
iCurrSrcLOD,
|
|
iCurrDstLOD));
|
|
|
|
pSrcMipLevel = &pSrcTexture->MipLevels[iCurrSrcLOD];
|
|
pDstMipLevel = &pDestTexture->MipLevels[iCurrDstLOD];
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
// Here we handle all possible blt cases between different types
|
|
// of memory and different scenarios of managed/unmanaged surfaces
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
#if DX7_TEXMANAGEMENT
|
|
if ((0 == (pDestTexture->dwCaps2 & DDSCAPS2_TEXTUREMANAGE)) &&
|
|
(0 == (pSrcTexture->dwCaps2 & DDSCAPS2_TEXTUREMANAGE)) )
|
|
#endif // DX7_TEXMANAGEMENT
|
|
{
|
|
//----------------------------------
|
|
//----------------------------------
|
|
// TEXBLT among non-managed textures
|
|
//----------------------------------
|
|
//----------------------------------
|
|
|
|
if ((pSrcTexture->Location == SystemMemory) &&
|
|
(pDestTexture->Location == VideoMemory))
|
|
{
|
|
//----------------------------
|
|
// Do the system->videomem blt
|
|
//----------------------------
|
|
_DD_P3Download(pThisDisplay,
|
|
pSrcMipLevel->fpVidMem,
|
|
pDstMipLevel->fpVidMem,
|
|
pSrcTexture->dwPatchMode,
|
|
pDestTexture->dwPatchMode,
|
|
pSrcMipLevel->lPitch,
|
|
pDstMipLevel->lPitch,
|
|
pDstMipLevel->P3RXTextureMapWidth.Width,
|
|
pDestTexture->dwPixelSize,
|
|
&rSrc,
|
|
&rDest);
|
|
}
|
|
else if ((pSrcTexture->Location == VideoMemory) &&
|
|
(pDestTexture->Location == VideoMemory))
|
|
{
|
|
//------------------------------
|
|
// Do the videomem->videomem blt
|
|
//------------------------------
|
|
_DD_BLT_P3CopyBlt(pThisDisplay,
|
|
pSrcMipLevel->fpVidMem,
|
|
pDstMipLevel->fpVidMem,
|
|
pSrcTexture->dwPatchMode,
|
|
pDestTexture->dwPatchMode,
|
|
pSrcMipLevel->P3RXTextureMapWidth.Width,
|
|
pDstMipLevel->P3RXTextureMapWidth.Width,
|
|
pSrcMipLevel->dwOffsetFromMemoryBase,
|
|
pDstMipLevel->dwOffsetFromMemoryBase,
|
|
pDestTexture->dwPixelSize,
|
|
&rSrc,
|
|
&rDest);
|
|
}
|
|
else if ((pSrcTexture->Location == AGPMemory) &&
|
|
(pDestTexture->Location == VideoMemory))
|
|
{
|
|
//-------------------------------
|
|
// Do the AGP mem -> videomem blt
|
|
//-------------------------------
|
|
DDCOLORKEY ddck_dummy = { 0 , 0 };
|
|
|
|
// We use the strecth blt because it handles AGP source
|
|
// surfaces, not becuase we should stretch the surface in any way
|
|
_DD_P3BltStretchSrcChDstCh(
|
|
pThisDisplay,
|
|
// src data
|
|
pSrcMipLevel->fpVidMem,
|
|
pSrcTexture->pFormatSurface,
|
|
pSrcTexture->dwPixelSize,
|
|
pSrcMipLevel->wWidth,
|
|
pSrcMipLevel->wHeight,
|
|
pSrcMipLevel->P3RXTextureMapWidth.Width,
|
|
pSrcMipLevel->P3RXTextureMapWidth.Layout,
|
|
pSrcMipLevel->dwOffsetFromMemoryBase,
|
|
pSrcTexture->dwFlagsInt,
|
|
&pSrcTexture->pixFmt,
|
|
1, // src IS AGP, otherwise we
|
|
//would'nt call this
|
|
// dest data
|
|
pDstMipLevel->fpVidMem,
|
|
pDestTexture->pFormatSurface,
|
|
pDestTexture->dwPixelSize,
|
|
pDstMipLevel->wWidth,
|
|
pDstMipLevel->wHeight,
|
|
pDstMipLevel->P3RXTextureMapWidth.Width,
|
|
pDstMipLevel->P3RXTextureMapWidth.Layout,
|
|
pDstMipLevel->dwOffsetFromMemoryBase,
|
|
|
|
0, // dwBltFlags no special blt effects
|
|
0, // dwBltDDFX no special effects info
|
|
ddck_dummy, // BltSrcColorKey dummy arg
|
|
ddck_dummy, // BltDestColorKey dummy arg
|
|
&rSrc,
|
|
&rDest
|
|
);
|
|
}
|
|
else
|
|
{
|
|
DISPDBG((ERRLVL,"Non-managed Tex Blt variation unimplemented! "
|
|
"(from %d into %d)",
|
|
pSrcTexture->Location,
|
|
pDestTexture->Location));
|
|
}
|
|
}
|
|
#if DX7_TEXMANAGEMENT
|
|
else if (pSrcTexture->dwCaps2 & DDSCAPS2_TEXTUREMANAGE)
|
|
{
|
|
//----------------------------------
|
|
//----------------------------------
|
|
// TEXBLT from a managed texture
|
|
//----------------------------------
|
|
//----------------------------------
|
|
|
|
if ((pDestTexture->Location == SystemMemory) ||
|
|
(pDestTexture->dwCaps2 & DDSCAPS2_TEXTUREMANAGE))
|
|
{
|
|
//-------------------------------------------------
|
|
// Do the Managed surf -> sysmem | managed surf blt
|
|
//-------------------------------------------------
|
|
|
|
// make sure we'll reload the vidmem copy of the dest surf
|
|
if (pDestTexture->dwCaps2 & DDSCAPS2_TEXTUREMANAGE)
|
|
{
|
|
__OP_MarkManagedSurfDirty(pContext,
|
|
pBlt->dwDDDestSurface,
|
|
pDestTexture);
|
|
}
|
|
|
|
_DD_BLT_SysMemToSysMemCopy(
|
|
pSrcMipLevel->fpVidMem,
|
|
pSrcMipLevel->lPitch,
|
|
pSrcTexture->dwBitDepth,
|
|
pDstMipLevel->fpVidMem,
|
|
pDstMipLevel->lPitch,
|
|
pDestTexture->dwBitDepth,
|
|
&rSrc,
|
|
&rDest);
|
|
}
|
|
else if (pDestTexture->Location == VideoMemory)
|
|
{
|
|
//-------------------------------------------------
|
|
// Do the Managed surf -> vidmem surf blt
|
|
//-------------------------------------------------
|
|
|
|
// This might be optimized by doing a vidmem->vidmem
|
|
// when the source managed texture has a vidmem copy
|
|
|
|
_DD_P3Download(pThisDisplay,
|
|
pSrcMipLevel->fpVidMem,
|
|
pDstMipLevel->fpVidMem,
|
|
pSrcTexture->dwPatchMode,
|
|
pDestTexture->dwPatchMode,
|
|
pSrcMipLevel->lPitch,
|
|
pDstMipLevel->lPitch,
|
|
pDstMipLevel->P3RXTextureMapWidth.Width,
|
|
pDestTexture->dwPixelSize,
|
|
&rSrc,
|
|
&rDest);
|
|
}
|
|
else
|
|
{
|
|
DISPDBG((ERRLVL,"Src-managed Tex Blt variation unimplemented! "
|
|
"(from %d into %d)",
|
|
pSrcTexture->Location,
|
|
pDestTexture->Location));
|
|
}
|
|
|
|
|
|
}
|
|
else if (pDestTexture->dwCaps2 & DDSCAPS2_TEXTUREMANAGE)
|
|
{
|
|
//--------------------------------------------------------------
|
|
//--------------------------------------------------------------
|
|
// TEXBLT into a managed texture (except from a managed texture)
|
|
//--------------------------------------------------------------
|
|
//--------------------------------------------------------------
|
|
|
|
// managed->managed is handled in the previous case
|
|
|
|
if (pSrcTexture->Location == SystemMemory)
|
|
{
|
|
//-------------------------------------------------
|
|
// Do the sysmem surf -> managed surf blt
|
|
//-------------------------------------------------
|
|
|
|
// make sure we'll reload the vidmem copy of the dest surf
|
|
__OP_MarkManagedSurfDirty(pContext,
|
|
pBlt->dwDDDestSurface,
|
|
pDestTexture);
|
|
|
|
_DD_BLT_SysMemToSysMemCopy(
|
|
pSrcMipLevel->fpVidMem,
|
|
pSrcMipLevel->lPitch,
|
|
pSrcTexture->dwBitDepth,
|
|
pDstMipLevel->fpVidMem,
|
|
pDstMipLevel->lPitch,
|
|
pDestTexture->dwBitDepth,
|
|
&rSrc,
|
|
&rDest);
|
|
}
|
|
else if (pSrcTexture->Location == VideoMemory)
|
|
{
|
|
//-------------------------------------------------
|
|
// Do the vidmem surf -> Managed surf blt
|
|
//-------------------------------------------------
|
|
|
|
if (0 != pSrcMipLevel->fpVidMemTM)
|
|
{
|
|
// Destination is already in vidmem so instead of
|
|
// "dirtying" the managed texture lets do the
|
|
// vidmem->vidmem blt which is faster than doing the
|
|
// update later (in the hope we'll really use it)
|
|
|
|
_DD_BLT_P3CopyBlt(pThisDisplay,
|
|
pSrcMipLevel->fpVidMem,
|
|
pDstMipLevel->fpVidMemTM,
|
|
pSrcTexture->dwPatchMode,
|
|
pDestTexture->dwPatchMode,
|
|
pSrcMipLevel->P3RXTextureMapWidth.Width,
|
|
pDstMipLevel->P3RXTextureMapWidth.Width,
|
|
pSrcMipLevel->dwOffsetFromMemoryBase,
|
|
pDstMipLevel->dwOffsetFromMemoryBase,
|
|
pDestTexture->dwPixelSize,
|
|
&rSrc,
|
|
&rDest);
|
|
}
|
|
else
|
|
{
|
|
// make sure we'll reload the
|
|
// vidmem copy of the dest surf
|
|
__OP_MarkManagedSurfDirty(pContext,
|
|
pBlt->dwDDDestSurface,
|
|
pDestTexture);
|
|
}
|
|
|
|
// Do slow mem mapped framebuffer blt into sysmem
|
|
// The source surface lives in video mem so we need to get a
|
|
// "real" sysmem address for it:
|
|
_DD_BLT_SysMemToSysMemCopy(
|
|
D3DMIPLVL_GETPOINTER(pSrcMipLevel, pThisDisplay),
|
|
pSrcMipLevel->lPitch,
|
|
pSrcTexture->dwBitDepth,
|
|
pDstMipLevel->fpVidMem,
|
|
pDstMipLevel->lPitch,
|
|
pDestTexture->dwBitDepth,
|
|
&rSrc,
|
|
&rDest);
|
|
}
|
|
else if (pSrcTexture->Location == AGPMemory)
|
|
{
|
|
// make sure we'll reload the vidmem copy of the dest surf
|
|
__OP_MarkManagedSurfDirty(pContext,
|
|
pBlt->dwDDDestSurface,
|
|
pDestTexture);
|
|
|
|
_DD_BLT_SysMemToSysMemCopy(
|
|
pSrcMipLevel->fpVidMem,
|
|
pSrcMipLevel->lPitch,
|
|
pSrcTexture->dwBitDepth,
|
|
pDstMipLevel->fpVidMem,
|
|
pDstMipLevel->lPitch,
|
|
pDestTexture->dwBitDepth,
|
|
&rSrc,
|
|
&rDest);
|
|
}
|
|
else
|
|
{
|
|
DISPDBG((ERRLVL,"Dest-managed Tex Blt variation unimplemented! "
|
|
"(from %d into %d)",
|
|
pSrcTexture->Location,
|
|
pDestTexture->Location));
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
DISPDBG((ERRLVL,"Tex Blt variation unimplemented! "
|
|
"(from %d into %d)",
|
|
pSrcTexture->Location,
|
|
pDestTexture->Location));
|
|
}
|
|
#endif // DX7_TEXMANAGEMENT
|
|
|
|
|
|
// Switch back to the Direct3D context
|
|
D3D_OPERATION(pContext, pThisDisplay);
|
|
|
|
} // if (bMipMapLevelsMatch)
|
|
|
|
|
|
// Update transfer rectangles if mip mapping
|
|
if (bMipMap)
|
|
{
|
|
DWORD right, bottom;
|
|
|
|
// Update source rectangle , the regions to be copied in mipmap
|
|
// sub-levels can be obtained by dividing rSrc and pDest by
|
|
// 2 at each level.
|
|
rSrc.left >>= 1;
|
|
rSrc.top >>= 1;
|
|
right = (rSrc.right + 1) >> 1;
|
|
bottom = (rSrc.bottom + 1) >> 1;
|
|
rSrc.right = ((right - rSrc.left) < 1) ? (rSrc.left + 1) : (right);
|
|
rSrc.bottom = ((bottom - rSrc.top ) < 1) ? (rSrc.top + 1) : (bottom);
|
|
|
|
// Update destination rectangle
|
|
rDest.left >>= 1;
|
|
rDest.top >>= 1;
|
|
right = (rDest.right + 1) >> 1;
|
|
bottom = (rDest.bottom + 1) >> 1;
|
|
rDest.right = ((right - rDest.left) < 1) ? (rDest.left + 1) : (right);
|
|
rDest.bottom = ((bottom - rDest.top ) < 1) ? (rDest.top + 1) : (bottom);
|
|
}
|
|
|
|
} while (bMipMap && ((iSrcLOD < pSrcTexture->iMipLevels) &&
|
|
(iDestLOD < pDestTexture->iMipLevels))); // do until we're done looking at 1x1
|
|
|
|
} // _D3D_OP_TextureBlt
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_SetRenderTarget
|
|
//
|
|
// Sets up the hw for the chosen render target and depth buffer
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
_D3D_OP_SetRenderTarget(
|
|
P3_D3DCONTEXT* pContext,
|
|
P3_SURF_INTERNAL* pRenderInt,
|
|
P3_SURF_INTERNAL* pZBufferInt,
|
|
BOOL bNewAliasBuffers)
|
|
{
|
|
|
|
P3_SOFTWARECOPY* pSoftP3RX = &pContext->SoftCopyGlint;
|
|
P3_THUNKEDDATA *pThisDisplay = pContext->pThisDisplay;
|
|
DWORD AAMultiplier = 1;
|
|
P3_DMA_DEFS();
|
|
|
|
DBG_ENTRY(_D3D_OP_SetRenderTarget);
|
|
|
|
// Verify the render target is in video memory
|
|
if (pRenderInt)
|
|
{
|
|
if (pRenderInt->ddsCapsInt.dwCaps & DDSCAPS_SYSTEMMEMORY)
|
|
{
|
|
DISPDBG((ERRLVL, "ERROR: Render Surface in SYSTEM MEMORY"));
|
|
return DDERR_GENERIC;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Must have a render target
|
|
DISPDBG((ERRLVL, "ERROR: Render Surface is NULL"));
|
|
return DDERR_GENERIC;
|
|
}
|
|
|
|
// If a Z Buffer verify it
|
|
if (pZBufferInt)
|
|
{
|
|
if (pZBufferInt->ddsCapsInt.dwCaps & DDSCAPS_SYSTEMMEMORY)
|
|
{
|
|
DISPDBG((ERRLVL, "ERROR: Z Surface in SYSTEM MEMORY, failing"));
|
|
return DDERR_GENERIC;
|
|
}
|
|
}
|
|
|
|
// Validate the RenderTarget to be 32 bit or 16 bit 565
|
|
if ((pRenderInt->pixFmt.dwRGBBitCount == 32 ) &&
|
|
(pRenderInt->pixFmt.dwRBitMask == 0x00FF0000) &&
|
|
(pRenderInt->pixFmt.dwGBitMask == 0x0000FF00) &&
|
|
(pRenderInt->pixFmt.dwBBitMask == 0x000000FF))
|
|
{
|
|
// were OK at 32bpp
|
|
}
|
|
else
|
|
if ((pRenderInt->pixFmt.dwRGBBitCount == 16 ) &&
|
|
(pRenderInt->pixFmt.dwRBitMask == 0xF800) &&
|
|
(pRenderInt->pixFmt.dwGBitMask == 0x07E0) &&
|
|
(pRenderInt->pixFmt.dwBBitMask == 0x001F))
|
|
{
|
|
// were OK at 16bpp
|
|
}
|
|
else
|
|
{
|
|
// we cant set our render target to this format !!!
|
|
DISPDBG((WRNLVL, " SRT Error !!!"));
|
|
DISPDBG((WRNLVL, " dwRGBBitCount: 0x%x",
|
|
pRenderInt->pixFmt.dwRGBBitCount));
|
|
DISPDBG((WRNLVL, " dwR/Y BitMask: 0x%x",
|
|
pRenderInt->pixFmt.dwRBitMask));
|
|
DISPDBG((WRNLVL, " dwG/U BitMask: 0x%x",
|
|
pRenderInt->pixFmt.dwGBitMask));
|
|
DISPDBG((WRNLVL, " dwB/V BitMask: 0x%x",
|
|
pRenderInt->pixFmt.dwBBitMask));
|
|
DISPDBG((WRNLVL, " dwRGBAlphaBitMask: 0x%x",
|
|
pRenderInt->pixFmt.dwRGBAlphaBitMask));
|
|
return DDERR_GENERIC;
|
|
}
|
|
|
|
#if DX8_MULTISAMPLING
|
|
// Decide whether antialising is requested and can be handled
|
|
if ((pContext->pSurfRenderInt->dwSampling) &&
|
|
(! _D3D_ST_CanRenderAntialiased(pContext, bNewAliasBuffers)))
|
|
{
|
|
return DDERR_OUTOFMEMORY;
|
|
}
|
|
#endif // DX8_MULTISAMPLING
|
|
|
|
// If we page flipped, clear the flag
|
|
pThisDisplay->bFlippedSurface = FALSE;
|
|
|
|
P3_DMA_GET_BUFFER();
|
|
|
|
P3_ENSURE_DX_SPACE(46);
|
|
WAIT_FIFO(26);
|
|
|
|
pContext->pSurfRenderInt = pRenderInt;
|
|
pContext->pSurfZBufferInt = pZBufferInt;
|
|
|
|
// Check for Z Buffer
|
|
if (pZBufferInt)
|
|
{
|
|
DDPIXELFORMAT* pZFormat = &pZBufferInt->pixFmt;
|
|
|
|
if( pThisDisplay->dwDXVersion >= DX6_RUNTIME)
|
|
{
|
|
// On DX6 we look in the pixel format for the depth and stencil info.
|
|
switch(pZFormat->dwZBufferBitDepth)
|
|
{
|
|
default:
|
|
DISPDBG((ERRLVL,"ERROR: Unknown Z Pixel format!"));
|
|
// Regard the buffer as 16 bit one and fall through
|
|
|
|
case 16:
|
|
if (pZFormat->dwStencilBitDepth == 1)
|
|
{
|
|
// 15 bit Z, 1 bit stencil
|
|
pSoftP3RX->P3RXLBReadFormat.StencilPosition = 0; // Ignored in this mode
|
|
pSoftP3RX->P3RXLBReadFormat.StencilWidth = P3RX_STENCIL_WIDTH_1;
|
|
pSoftP3RX->P3RXLBReadFormat.DepthWidth = P3RX_DEPTH_WIDTH_15;
|
|
|
|
pSoftP3RX->P3RXStencilMode.StencilWidth = P3RX_STENCIL_WIDTH_1;
|
|
|
|
pSoftP3RX->P3RXLBWriteFormat.StencilPosition = 0; // Ignored in this mode
|
|
pSoftP3RX->P3RXLBWriteFormat.StencilWidth = P3RX_STENCIL_WIDTH_1;
|
|
pSoftP3RX->P3RXLBWriteFormat.DepthWidth = P3RX_DEPTH_WIDTH_15;
|
|
|
|
pSoftP3RX->P3RXDepthMode.Width = P3RX_DEPTH_WIDTH_15;
|
|
|
|
pSoftP3RX->P3RXLBSourceReadMode.Packed16 = 1;
|
|
pSoftP3RX->P3RXLBDestReadMode.Packed16 = 1;
|
|
pSoftP3RX->P3RXLBWriteMode.Packed16 = 1;
|
|
pSoftP3RX->P3RXLBWriteMode.ByteEnables = 0x3;
|
|
}
|
|
else
|
|
{
|
|
// 16 bit Z, no stencil
|
|
pSoftP3RX->P3RXLBReadFormat.StencilPosition = 0; // Ignored in this mode
|
|
pSoftP3RX->P3RXLBReadFormat.StencilWidth = P3RX_STENCIL_WIDTH_0;
|
|
pSoftP3RX->P3RXStencilMode.StencilWidth = P3RX_STENCIL_WIDTH_0;
|
|
pSoftP3RX->P3RXLBReadFormat.DepthWidth = P3RX_DEPTH_WIDTH_16;
|
|
pSoftP3RX->P3RXLBWriteFormat.StencilPosition = 0; // Ignored in this mode
|
|
pSoftP3RX->P3RXLBWriteFormat.StencilWidth = P3RX_STENCIL_WIDTH_0;
|
|
pSoftP3RX->P3RXLBWriteFormat.DepthWidth = P3RX_DEPTH_WIDTH_16;
|
|
pSoftP3RX->P3RXDepthMode.Width = P3RX_DEPTH_WIDTH_16;
|
|
pSoftP3RX->P3RXLBWriteMode.ByteEnables = 0x3;
|
|
pSoftP3RX->P3RXLBSourceReadMode.Packed16 = 1;
|
|
pSoftP3RX->P3RXLBDestReadMode.Packed16 = 1;
|
|
pSoftP3RX->P3RXLBWriteMode.Packed16 = 1;
|
|
}
|
|
break;
|
|
|
|
case 32:
|
|
if (pZFormat->dwStencilBitDepth == 8)
|
|
{
|
|
// 24 bit Z, 8 bit stencil
|
|
pSoftP3RX->P3RXLBReadFormat.StencilPosition = P3RX_STENCIL_POSITION_24;
|
|
pSoftP3RX->P3RXLBReadFormat.StencilWidth = P3RX_STENCIL_WIDTH_8;
|
|
pSoftP3RX->P3RXStencilMode.StencilWidth = P3RX_STENCIL_WIDTH_8;
|
|
pSoftP3RX->P3RXLBReadFormat.DepthWidth = P3RX_DEPTH_WIDTH_24;
|
|
pSoftP3RX->P3RXLBWriteFormat.StencilPosition = P3RX_STENCIL_POSITION_24;
|
|
pSoftP3RX->P3RXLBWriteFormat.StencilWidth = P3RX_STENCIL_WIDTH_8;
|
|
pSoftP3RX->P3RXLBWriteFormat.DepthWidth = P3RX_DEPTH_WIDTH_24;
|
|
pSoftP3RX->P3RXDepthMode.Width = P3RX_DEPTH_WIDTH_24;
|
|
pSoftP3RX->P3RXLBWriteMode.ByteEnables = 0xF;
|
|
pSoftP3RX->P3RXLBSourceReadMode.Packed16 = 0;
|
|
pSoftP3RX->P3RXLBDestReadMode.Packed16 = 0;
|
|
pSoftP3RX->P3RXLBWriteMode.Packed16 = 0;
|
|
}
|
|
else
|
|
{
|
|
// 32 bit Z, no stencil
|
|
pSoftP3RX->P3RXLBReadFormat.StencilPosition = 0;
|
|
pSoftP3RX->P3RXLBReadFormat.StencilWidth = P3RX_STENCIL_WIDTH_0;
|
|
pSoftP3RX->P3RXStencilMode.StencilWidth = P3RX_STENCIL_WIDTH_0;
|
|
pSoftP3RX->P3RXLBReadFormat.DepthWidth = P3RX_DEPTH_WIDTH_32;
|
|
pSoftP3RX->P3RXLBWriteFormat.StencilPosition = 0;
|
|
pSoftP3RX->P3RXLBWriteFormat.StencilWidth = P3RX_STENCIL_WIDTH_0;
|
|
pSoftP3RX->P3RXLBWriteFormat.DepthWidth = P3RX_DEPTH_WIDTH_32;
|
|
pSoftP3RX->P3RXDepthMode.Width = P3RX_DEPTH_WIDTH_32;
|
|
pSoftP3RX->P3RXLBWriteMode.ByteEnables = 0xF;
|
|
pSoftP3RX->P3RXLBSourceReadMode.Packed16 = 0;
|
|
pSoftP3RX->P3RXLBDestReadMode.Packed16 = 0;
|
|
pSoftP3RX->P3RXLBWriteMode.Packed16 = 0;
|
|
|
|
}
|
|
break;
|
|
}
|
|
|
|
}
|
|
else
|
|
// On DX5 we don't look at the pixel format, just the depth of the Z Buffer.
|
|
{
|
|
// Choose the correct Z Buffer depth
|
|
switch(pZBufferInt->pixFmt.dwRGBBitCount)
|
|
{
|
|
default:
|
|
DISPDBG((ERRLVL,"ERROR: Unknown depth format in _D3D_OP_SetRenderTarget!"));
|
|
// Regard the buffer as 16 bit one and fall through
|
|
|
|
case 16:
|
|
pSoftP3RX->P3RXLBReadFormat.DepthWidth = __GLINT_DEPTH_WIDTH_16;
|
|
pSoftP3RX->P3RXLBWriteFormat.DepthWidth = __GLINT_DEPTH_WIDTH_16;
|
|
pSoftP3RX->P3RXDepthMode.Width = __GLINT_DEPTH_WIDTH_16;
|
|
pSoftP3RX->P3RXLBWriteMode.ByteEnables = 0x3;
|
|
pSoftP3RX->P3RXLBSourceReadMode.Packed16 = 1;
|
|
pSoftP3RX->P3RXLBDestReadMode.Packed16 = 1;
|
|
pSoftP3RX->P3RXLBWriteMode.Packed16 = 1;
|
|
break;
|
|
|
|
case 24:
|
|
pSoftP3RX->P3RXLBReadFormat.DepthWidth = __GLINT_DEPTH_WIDTH_24;
|
|
pSoftP3RX->P3RXLBWriteFormat.DepthWidth = __GLINT_DEPTH_WIDTH_24;
|
|
pSoftP3RX->P3RXDepthMode.Width = __GLINT_DEPTH_WIDTH_24;
|
|
pSoftP3RX->P3RXLBWriteMode.ByteEnables = 0x7;
|
|
pSoftP3RX->P3RXLBSourceReadMode.Packed16 = 0;
|
|
pSoftP3RX->P3RXLBDestReadMode.Packed16 = 0;
|
|
pSoftP3RX->P3RXLBWriteMode.Packed16 = 0;
|
|
break;
|
|
|
|
case 32:
|
|
pSoftP3RX->P3RXLBReadFormat.DepthWidth = __GLINT_DEPTH_WIDTH_32;
|
|
pSoftP3RX->P3RXLBWriteFormat.DepthWidth = __GLINT_DEPTH_WIDTH_32;
|
|
pSoftP3RX->P3RXDepthMode.Width = __GLINT_DEPTH_WIDTH_32;
|
|
pSoftP3RX->P3RXLBWriteMode.ByteEnables = 0xF;
|
|
pSoftP3RX->P3RXLBSourceReadMode.Packed16 = 0;
|
|
pSoftP3RX->P3RXLBDestReadMode.Packed16 = 0;
|
|
pSoftP3RX->P3RXLBWriteMode.Packed16 = 0;
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
pSoftP3RX->P3RXLBSourceReadMode.Layout = pZBufferInt->dwPatchMode;
|
|
pSoftP3RX->P3RXLBDestReadMode.Layout = pZBufferInt->dwPatchMode;
|
|
pSoftP3RX->P3RXLBWriteMode.Layout = pZBufferInt->dwPatchMode;
|
|
} // if (pZBufferInt)
|
|
|
|
switch (pRenderInt->dwPixelSize)
|
|
{
|
|
case __GLINT_8BITPIXEL:
|
|
// 8 Bit color index mode
|
|
pSoftP3RX->DitherMode.ColorFormat =
|
|
pSoftP3RX->P3RXAlphaBlendColorMode.ColorFormat = P3RX_ALPHABLENDMODE_COLORFORMAT_CI;
|
|
SEND_P3_DATA(PixelSize, 2 - __GLINT_8BITPIXEL);
|
|
break;
|
|
|
|
case __GLINT_16BITPIXEL:
|
|
if (pThisDisplay->ddpfDisplay.dwRBitMask == 0x7C00)
|
|
{
|
|
// 5551 format
|
|
pSoftP3RX->DitherMode.ColorFormat = P3RX_DITHERMODE_COLORFORMAT_5551;
|
|
pSoftP3RX->P3RXAlphaBlendColorMode.ColorFormat = P3RX_ALPHABLENDMODE_COLORFORMAT_5551;
|
|
}
|
|
else
|
|
{
|
|
// 565 format
|
|
pSoftP3RX->DitherMode.ColorFormat = P3RX_DITHERMODE_COLORFORMAT_565;
|
|
pSoftP3RX->P3RXAlphaBlendColorMode.ColorFormat = P3RX_ALPHABLENDMODE_COLORFORMAT_565;
|
|
}
|
|
SEND_P3_DATA(PixelSize, 2 - __GLINT_16BITPIXEL);
|
|
break;
|
|
|
|
case __GLINT_24BITPIXEL:
|
|
case __GLINT_32BITPIXEL:
|
|
// 32 Bit Color Index mode
|
|
pSoftP3RX->DitherMode.ColorFormat =
|
|
pSoftP3RX->P3RXAlphaBlendColorMode.ColorFormat = P3RX_ALPHABLENDMODE_COLORFORMAT_8888;
|
|
SEND_P3_DATA(PixelSize, 2 - __GLINT_32BITPIXEL);
|
|
break;
|
|
}
|
|
|
|
pSoftP3RX->P3RXFBDestReadMode.Layout0 = pRenderInt->dwPatchMode;
|
|
pSoftP3RX->P3RXFBWriteMode.Layout0 = pRenderInt->dwPatchMode;
|
|
pSoftP3RX->P3RXFBSourceReadMode.Layout = pRenderInt->dwPatchMode;
|
|
|
|
COPY_P3_DATA(FBWriteMode, pSoftP3RX->P3RXFBWriteMode);
|
|
COPY_P3_DATA(FBDestReadMode, pSoftP3RX->P3RXFBDestReadMode);
|
|
COPY_P3_DATA(FBSourceReadMode, pSoftP3RX->P3RXFBSourceReadMode);
|
|
|
|
#if DX8_MULTISAMPLING || DX7_ANTIALIAS
|
|
if (!(pContext->Flags & SURFACE_ANTIALIAS) ||
|
|
(pContext->dwAliasBackBuffer == 0))
|
|
{
|
|
#endif // DX8_MULTISAMPLING || DX7_ANTIALIAS
|
|
pContext->PixelOffset = (DWORD)(pRenderInt->fpVidMem -
|
|
pThisDisplay->dwScreenFlatAddr );
|
|
|
|
if (pContext->pSurfZBufferInt)
|
|
{
|
|
pContext->ZPixelOffset = (DWORD)(pZBufferInt->fpVidMem -
|
|
pThisDisplay->dwScreenFlatAddr);
|
|
}
|
|
AAMultiplier = 1;
|
|
|
|
SEND_P3_DATA(PixelSize, (2 - pRenderInt->dwPixelSize));
|
|
#if DX8_MULTISAMPLING || DX7_ANTIALIAS
|
|
}
|
|
else
|
|
{
|
|
pContext->PixelOffset = pContext->dwAliasPixelOffset;
|
|
pContext->ZPixelOffset = pContext->dwAliasZPixelOffset;
|
|
AAMultiplier = 2;
|
|
}
|
|
#endif // DX8_MULTISAMPLING || DX7_ANTIALIAS
|
|
|
|
COPY_P3_DATA(AlphaBlendColorMode, pSoftP3RX->P3RXAlphaBlendColorMode);
|
|
COPY_P3_DATA(DitherMode, pSoftP3RX->DitherMode);
|
|
|
|
SEND_P3_DATA(FBWriteBufferAddr0, pContext->PixelOffset);
|
|
SEND_P3_DATA(FBDestReadBufferAddr0, pContext->PixelOffset);
|
|
SEND_P3_DATA(FBSourceReadBufferAddr, pContext->PixelOffset);
|
|
|
|
SEND_P3_DATA(FBWriteBufferWidth0,
|
|
pContext->pSurfRenderInt->dwPixelPitch * AAMultiplier);
|
|
SEND_P3_DATA(FBDestReadBufferWidth0,
|
|
pContext->pSurfRenderInt->dwPixelPitch * AAMultiplier);
|
|
SEND_P3_DATA(FBSourceReadBufferWidth,
|
|
pContext->pSurfRenderInt->dwPixelPitch * AAMultiplier);
|
|
|
|
WAIT_FIFO(20);
|
|
|
|
// Is there a Z Buffer?
|
|
if (pContext->pSurfZBufferInt != NULL)
|
|
{
|
|
// Offset is in BYTES
|
|
SEND_P3_DATA(LBSourceReadBufferAddr, pContext->ZPixelOffset);
|
|
SEND_P3_DATA(LBDestReadBufferAddr, pContext->ZPixelOffset);
|
|
SEND_P3_DATA(LBWriteBufferAddr, pContext->ZPixelOffset);
|
|
|
|
pSoftP3RX->P3RXLBWriteMode.Width =
|
|
pContext->pSurfZBufferInt->dwPixelPitch * AAMultiplier;
|
|
pSoftP3RX->P3RXLBSourceReadMode.Width =
|
|
pContext->pSurfZBufferInt->dwPixelPitch * AAMultiplier;
|
|
pSoftP3RX->P3RXLBDestReadMode.Width =
|
|
pContext->pSurfZBufferInt->dwPixelPitch * AAMultiplier;
|
|
|
|
COPY_P3_DATA(LBDestReadMode, pSoftP3RX->P3RXLBDestReadMode);
|
|
COPY_P3_DATA(LBSourceReadMode, pSoftP3RX->P3RXLBSourceReadMode);
|
|
COPY_P3_DATA(LBWriteMode, pSoftP3RX->P3RXLBWriteMode);
|
|
|
|
COPY_P3_DATA(StencilMode, pSoftP3RX->P3RXStencilMode);
|
|
COPY_P3_DATA(LBReadFormat, pSoftP3RX->P3RXLBReadFormat);
|
|
COPY_P3_DATA(LBWriteFormat, pSoftP3RX->P3RXLBWriteFormat);
|
|
|
|
COPY_P3_DATA(DepthMode, pSoftP3RX->P3RXDepthMode);
|
|
}
|
|
|
|
DIRTY_VIEWPORT(pContext);
|
|
|
|
P3_DMA_COMMIT_BUFFER();
|
|
|
|
DBG_EXIT(_D3D_OP_SetRenderTarget,0);
|
|
|
|
return DD_OK;
|
|
|
|
} // _D3D_OP_SetRenderTarget
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_SceneCapture
|
|
//
|
|
// This function is called twice, once at the start of the rendering,
|
|
// and once at the end of the rendering. The start is ignored, but
|
|
// the end might be used to ensure that the DMA buffer has been flushed.
|
|
// This is needed for the case where a scene has little in it, and
|
|
// doesn't fill the buffer up.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID
|
|
_D3D_OP_SceneCapture(
|
|
P3_D3DCONTEXT *pContext,
|
|
DWORD dwFlag)
|
|
{
|
|
P3_THUNKEDDATA *pThisDisplay;
|
|
|
|
pThisDisplay = pContext->pThisDisplay;
|
|
|
|
if (dwFlag == D3DHAL_SCENE_CAPTURE_START)
|
|
{
|
|
DISPDBG((DBGLVL,"Scene Start"));
|
|
}
|
|
else if (dwFlag == D3DHAL_SCENE_CAPTURE_END)
|
|
{
|
|
#if DX8_MULTISAMPLING || DX7_ANTIALIAS
|
|
if (pContext->Flags & SURFACE_ANTIALIAS)
|
|
{
|
|
// Since we were antialiasing we need to put the data where
|
|
// the user asked which requires a copy from our AA buffer
|
|
// into the true target buffer
|
|
|
|
// P3 Shrinking is done in the DDRAW context. This means you
|
|
// don't have to save and restore the state around the call
|
|
// - the next D3D_OPERATION will recover for you
|
|
DDRAW_OPERATION(pContext, pThisDisplay);
|
|
|
|
P3RX_AA_Shrink(pContext);
|
|
}
|
|
#endif // DX8_MULTISAMPLING || DX7_ANTIALIAS
|
|
|
|
DISPDBG((DBGLVL,"Scene End"));
|
|
}
|
|
|
|
return;
|
|
} // _D3D_OP_SceneCapture
|
|
|
|
#if DX7_TEXMANAGEMENT
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// __OP_MarkManagedSurfDirty
|
|
//
|
|
// Make sure textures are setup again if the texture is being used in any of
|
|
// the texture stages (for reloading purpouses) and make sure we mark it as
|
|
// dirty (since we're modifying the sysmem copy of the texture)
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID __OP_MarkManagedSurfDirty(P3_D3DCONTEXT* pContext,
|
|
DWORD dwSurfHandle,
|
|
P3_SURF_INTERNAL* pTexture)
|
|
{
|
|
// If the destination texture is in use in any of the texture
|
|
// stages, make sure hw gets re-setup again before using it.
|
|
if ((pContext->TextureStageState[0].m_dwVal[D3DTSS_TEXTUREMAP]
|
|
== dwSurfHandle) ||
|
|
(pContext->TextureStageState[1].m_dwVal[D3DTSS_TEXTUREMAP]
|
|
== dwSurfHandle))
|
|
{
|
|
DIRTY_TEXTURE(pContext);
|
|
}
|
|
|
|
// Mark the destination texture as needing to be updated
|
|
// into vidmem before using it.
|
|
pTexture->m_bTMNeedUpdate = TRUE;
|
|
|
|
} // __OP_MarkManagedSurfDirty
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_SetTexLod
|
|
//
|
|
// This function processes the D3DDP2OP_SETTEXLOD DP2 command token.
|
|
// This communicates to the texture manager the most detailed mip map level
|
|
// required to load for a given managed surface.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID
|
|
_D3D_OP_SetTexLod(
|
|
P3_D3DCONTEXT *pContext,
|
|
D3DHAL_DP2SETTEXLOD* pSetTexLod)
|
|
{
|
|
P3_SURF_INTERNAL* pTexture;
|
|
|
|
// Get the source texture structure pointer
|
|
pTexture = GetSurfaceFromHandle(pContext, pSetTexLod->dwDDSurface);
|
|
|
|
if (pTexture == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Set up the HW texture states again if this texture is in use
|
|
// and the new LOD value is smaller than the current setting.
|
|
if (((pContext->TextureStageState[0].m_dwVal[D3DTSS_TEXTUREMAP]
|
|
== pSetTexLod->dwDDSurface) ||
|
|
(pContext->TextureStageState[1].m_dwVal[D3DTSS_TEXTUREMAP]
|
|
== pSetTexLod->dwDDSurface)) &&
|
|
(pSetTexLod->dwLOD < pTexture->m_dwTexLOD))
|
|
{
|
|
DIRTY_TEXTURE(pContext);
|
|
}
|
|
|
|
// Change the texture's largest level to be actually used
|
|
pTexture->m_dwTexLOD = pSetTexLod->dwLOD;
|
|
|
|
} // _D3D_OP_SetTexLod
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_SetPriority
|
|
//
|
|
// This function processes the D3DDP2OP_SETPRIORITY DP2 command token.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID
|
|
_D3D_OP_SetPriority(
|
|
P3_D3DCONTEXT *pContext,
|
|
D3DHAL_DP2SETPRIORITY* pSetPriority)
|
|
{
|
|
P3_SURF_INTERNAL* pTexture;
|
|
|
|
// Get the source texture structure pointer
|
|
#if WNT_DDRAW
|
|
pTexture = GetSurfaceFromHandle(pContext, pSetPriority->dwDDDestSurface);
|
|
#else
|
|
pTexture = GetSurfaceFromHandle(pContext, pSetPriority->dwDDSurface);
|
|
#endif
|
|
|
|
if (NULL != pTexture)
|
|
{
|
|
// Managed resources should be evicted depending on their priorities.
|
|
// If of same priority then LRU is used to break the tie.
|
|
pTexture->m_dwPriority = pSetPriority->dwPriority;
|
|
}
|
|
|
|
} // _D3D_OP_SetPriority
|
|
|
|
#if DX8_DDI
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_AddDirtyRect
|
|
//
|
|
// This function processes the D3DDP2OP_ADDDIRTYRECT DP2 command token.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID
|
|
_D3D_OP_AddDirtyRect(
|
|
P3_D3DCONTEXT *pContext,
|
|
D3DHAL_DP2ADDDIRTYRECT* pAddDirtyRect)
|
|
{
|
|
P3_SURF_INTERNAL* pTexture;
|
|
|
|
// Get the source texture structure pointer
|
|
pTexture = GetSurfaceFromHandle(pContext, pAddDirtyRect->dwSurface);
|
|
|
|
if (NULL != pTexture)
|
|
{
|
|
//azn TODO
|
|
// As a first implementation in this driver we mark the whole surface
|
|
// as dirty instead of marking just the indicated rect - which could be
|
|
// transferred more efficiently
|
|
__OP_MarkManagedSurfDirty(pContext,
|
|
pAddDirtyRect->dwSurface,
|
|
pTexture);
|
|
}
|
|
|
|
} // _D3D_OP_AddDirtyRect
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_AddDirtyBox
|
|
//
|
|
// This function processes the D3DDP2OP_ADDDIRTYBOX DP2 command token.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID
|
|
_D3D_OP_AddDirtyBox(
|
|
P3_D3DCONTEXT *pContext,
|
|
D3DHAL_DP2ADDDIRTYBOX* pAddDirtyBox)
|
|
{
|
|
P3_SURF_INTERNAL* pTexture;
|
|
|
|
// Get the source texture structure pointer
|
|
pTexture = GetSurfaceFromHandle(pContext, pAddDirtyBox->dwSurface);
|
|
|
|
if (NULL != pTexture)
|
|
{
|
|
//azn TODO
|
|
// As a first implementation in this driver we mark the whole surface
|
|
// as dirty instead of marking just the indicated rect - which could be
|
|
// transferred more efficiently
|
|
__OP_MarkManagedSurfDirty(pContext,
|
|
pAddDirtyBox->dwSurface,
|
|
pTexture);
|
|
}
|
|
|
|
} // _D3D_OP_AddDirtyBox
|
|
#endif
|
|
#endif // DX7_TEXMANAGEMENT
|
|
|
|
|
|
|
|
#if DX8_3DTEXTURES
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// __OP_BasicVolumeBlt
|
|
//
|
|
// This function blts one single level/slice at a time for volume textures
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID __OP_BasicVolumeBlt(P3_D3DCONTEXT* pContext,
|
|
P3_THUNKEDDATA*pThisDisplay,
|
|
P3_SURF_INTERNAL* pSrcTexture,
|
|
P3_SURF_INTERNAL* pDestTexture,
|
|
DWORD dwDestSurfHandle,
|
|
RECTL *prSrc,
|
|
RECTL *prDest)
|
|
{
|
|
#if DX7_TEXMANAGEMENT
|
|
if ((0 == (pDestTexture->dwCaps2 & DDSCAPS2_TEXTUREMANAGE)) &&
|
|
(0 == (pSrcTexture->dwCaps2 & DDSCAPS2_TEXTUREMANAGE)) )
|
|
#endif // DX7_TEXMANAGEMENT
|
|
{
|
|
if ((pSrcTexture->Location == SystemMemory) &&
|
|
(pDestTexture->Location == VideoMemory))
|
|
{
|
|
//----------------------------
|
|
// Do the system->videomem blt
|
|
//----------------------------
|
|
_DD_P3Download(pThisDisplay,
|
|
pSrcTexture->fpVidMem,
|
|
pDestTexture->fpVidMem,
|
|
pSrcTexture->dwPatchMode,
|
|
pDestTexture->dwPatchMode,
|
|
pSrcTexture->lPitch,
|
|
pDestTexture->lPitch,
|
|
pDestTexture->dwPixelPitch,
|
|
pDestTexture->dwPixelSize,
|
|
prSrc,
|
|
prDest);
|
|
}
|
|
else
|
|
{
|
|
DISPDBG((ERRLVL, "ERROR: __OP_BasicVolumeBlt b3DTexture (%d -> %d)"
|
|
"not suported yet!",
|
|
pSrcTexture->Location,
|
|
pDestTexture->Location));
|
|
}
|
|
}
|
|
#if DX7_TEXMANAGEMENT
|
|
else if (pSrcTexture->dwCaps2 & DDSCAPS2_TEXTUREMANAGE)
|
|
{
|
|
//----------------------------------
|
|
//----------------------------------
|
|
// TEXBLT from a managed texture
|
|
//----------------------------------
|
|
//----------------------------------
|
|
|
|
if ((pDestTexture->Location == SystemMemory) ||
|
|
(pDestTexture->dwCaps2 & DDSCAPS2_TEXTUREMANAGE))
|
|
{
|
|
//-------------------------------------------------
|
|
// Do the Managed surf -> sysmem | managed surf blt
|
|
//-------------------------------------------------
|
|
|
|
// make sure we'll reload the vidmem copy of the dest surf
|
|
if (pDestTexture->dwCaps2 & DDSCAPS2_TEXTUREMANAGE)
|
|
{
|
|
__OP_MarkManagedSurfDirty(pContext,
|
|
dwDestSurfHandle,
|
|
pDestTexture);
|
|
}
|
|
|
|
_DD_BLT_SysMemToSysMemCopy(
|
|
pSrcTexture->fpVidMem,
|
|
pSrcTexture->lPitch,
|
|
pSrcTexture->dwBitDepth,
|
|
pDestTexture->fpVidMem,
|
|
pDestTexture->lPitch,
|
|
pDestTexture->dwBitDepth,
|
|
prSrc,
|
|
prDest);
|
|
}
|
|
else if (pDestTexture->Location == VideoMemory)
|
|
{
|
|
//-------------------------------------------------
|
|
// Do the Managed surf -> vidmem surf blt
|
|
//-------------------------------------------------
|
|
|
|
// This might be optimized by doing a vidmem->vidmem
|
|
// when the source managed texture has a vidmem copy
|
|
|
|
_DD_P3Download(pThisDisplay,
|
|
pSrcTexture->fpVidMem,
|
|
pDestTexture->fpVidMem,
|
|
pSrcTexture->dwPatchMode,
|
|
pDestTexture->dwPatchMode,
|
|
pSrcTexture->lPitch,
|
|
pDestTexture->lPitch,
|
|
pDestTexture->dwPixelPitch,
|
|
pDestTexture->dwPixelSize,
|
|
prSrc,
|
|
prDest);
|
|
}
|
|
else
|
|
{
|
|
DISPDBG((ERRLVL,"Src-managed __OP_BasicVolumeBlt variation "
|
|
"unimplemented! (from %d into %d)",
|
|
pSrcTexture->Location,
|
|
pDestTexture->Location));
|
|
}
|
|
|
|
|
|
}
|
|
else if (pDestTexture->dwCaps2 & DDSCAPS2_TEXTUREMANAGE)
|
|
{
|
|
//--------------------------------------------------------------
|
|
//--------------------------------------------------------------
|
|
// TEXBLT into a managed texture (except from a managed texture)
|
|
//--------------------------------------------------------------
|
|
//--------------------------------------------------------------
|
|
|
|
// managed->managed is handled in the previous case
|
|
|
|
if (pSrcTexture->Location == SystemMemory)
|
|
{
|
|
//-------------------------------------------------
|
|
// Do the sysmem surf -> managed surf blt
|
|
//-------------------------------------------------
|
|
|
|
// make sure we'll reload the vidmem copy of the dest surf
|
|
__OP_MarkManagedSurfDirty(pContext,
|
|
dwDestSurfHandle,
|
|
pDestTexture);
|
|
|
|
_DD_BLT_SysMemToSysMemCopy(
|
|
pSrcTexture->fpVidMem,
|
|
pSrcTexture->lPitch,
|
|
pSrcTexture->dwBitDepth,
|
|
pDestTexture->fpVidMem,
|
|
pDestTexture->lPitch,
|
|
pDestTexture->dwBitDepth,
|
|
prSrc,
|
|
prDest);
|
|
}
|
|
else if (pSrcTexture->Location == VideoMemory)
|
|
{
|
|
//-------------------------------------------------
|
|
// Do the vidmem surf -> Managed surf blt
|
|
//-------------------------------------------------
|
|
|
|
if (0 != pSrcTexture->MipLevels[0].fpVidMemTM)
|
|
{
|
|
// Destination is already in vidmem so instead of
|
|
// "dirtying" the managed texture lets do the
|
|
// vidmem->vidmem blt which is faster than doing the
|
|
// update later (in the hope we'll really use it)
|
|
|
|
_DD_BLT_P3CopyBlt(pThisDisplay,
|
|
pSrcTexture->fpVidMem,
|
|
pDestTexture->MipLevels[0].fpVidMemTM,
|
|
pSrcTexture->dwPatchMode,
|
|
pDestTexture->dwPatchMode,
|
|
pSrcTexture->dwPixelPitch,
|
|
pDestTexture->dwPixelPitch,
|
|
pSrcTexture->MipLevels[0].dwOffsetFromMemoryBase,
|
|
pDestTexture->MipLevels[0].dwOffsetFromMemoryBase,
|
|
pDestTexture->dwPixelSize,
|
|
prSrc,
|
|
prDest);
|
|
}
|
|
else
|
|
{
|
|
// make sure we'll reload the
|
|
// vidmem copy of the dest surf
|
|
__OP_MarkManagedSurfDirty(pContext,
|
|
dwDestSurfHandle,
|
|
pDestTexture);
|
|
}
|
|
|
|
// Do slow mem mapped framebuffer blt into sysmem
|
|
// The source surface lives in video mem so we need to get a
|
|
// "real" sysmem address for it:
|
|
_DD_BLT_SysMemToSysMemCopy(
|
|
D3DSURF_GETPOINTER(pSrcTexture, pThisDisplay),
|
|
pSrcTexture->lPitch,
|
|
pSrcTexture->dwBitDepth,
|
|
pDestTexture->fpVidMem,
|
|
pDestTexture->lPitch,
|
|
pDestTexture->dwBitDepth,
|
|
prSrc,
|
|
prDest);
|
|
}
|
|
else if (pSrcTexture->Location == AGPMemory)
|
|
{
|
|
// make sure we'll reload the vidmem copy of the dest surf
|
|
__OP_MarkManagedSurfDirty(pContext,
|
|
dwDestSurfHandle,
|
|
pDestTexture);
|
|
|
|
_DD_BLT_SysMemToSysMemCopy(
|
|
pSrcTexture->fpVidMem,
|
|
pSrcTexture->lPitch,
|
|
pSrcTexture->dwBitDepth,
|
|
pDestTexture->fpVidMem,
|
|
pDestTexture->lPitch,
|
|
pDestTexture->dwBitDepth,
|
|
prSrc,
|
|
prDest);
|
|
}
|
|
else
|
|
{
|
|
DISPDBG((ERRLVL,"Dest-managed __OP_BasicVolumeBlt variation "
|
|
"unimplemented! (from %d into %d)",
|
|
pSrcTexture->Location,
|
|
pDestTexture->Location));
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
DISPDBG((ERRLVL,"__OP_BasicVolumeBlt variation unimplemented! "
|
|
"(from %d into %d)",
|
|
pSrcTexture->Location,
|
|
pDestTexture->Location));
|
|
}
|
|
#endif // DX7_TEXMANAGEMENT
|
|
|
|
|
|
} // __OP_BasicVolumeBlt
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_VolumeBlt
|
|
//
|
|
// This function processes the D3DDP2OP_VOLUMEBLT DP2 command token.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID _D3D_OP_VolumeBlt(P3_D3DCONTEXT* pContext,
|
|
P3_THUNKEDDATA*pThisDisplay,
|
|
D3DHAL_DP2VOLUMEBLT* pBlt)
|
|
{
|
|
LPDDRAWI_DDRAWSURFACE_LCL pSrcLcl;
|
|
LPDDRAWI_DDRAWSURFACE_LCL pDestLcl;
|
|
P3_SURF_INTERNAL* pSrcTexture;
|
|
P3_SURF_INTERNAL* pDestTexture;
|
|
P3_SURF_FORMAT* pFormatSource;
|
|
P3_SURF_FORMAT* pFormatDest;
|
|
RECTL rSrc, rDest;
|
|
DWORD dwSrcCurrDepth, dwDestCurrDepth, dwEndDepth;
|
|
|
|
// Get the texture structure pointers
|
|
pSrcTexture = GetSurfaceFromHandle(pContext, pBlt->dwDDSrcSurface);
|
|
pDestTexture = GetSurfaceFromHandle(pContext, pBlt->dwDDDestSurface);
|
|
|
|
// Check that the textures are valid
|
|
if (pSrcTexture == NULL)
|
|
{
|
|
DISPDBG((ERRLVL, "ERROR: Source texture %d is invalid!",
|
|
pBlt->dwDDSrcSurface));
|
|
return;
|
|
}
|
|
|
|
if (pDestTexture == NULL)
|
|
{
|
|
DISPDBG((ERRLVL, "ERROR: Dest texture %d is invalid!",
|
|
pBlt->dwDDDestSurface));
|
|
return;
|
|
}
|
|
|
|
// If we are going to blt 3D texture, both have to be 3D texture
|
|
if ((pSrcTexture->b3DTexture == FALSE) != (pDestTexture->b3DTexture == FALSE))
|
|
{
|
|
DISPDBG((ERRLVL, "ERROR: TEXBLT b3DTexture (%d %d)does not match!",
|
|
pSrcTexture->b3DTexture,
|
|
pDestTexture->b3DTexture));
|
|
return;
|
|
}
|
|
|
|
// Do we blt whole 3D texture ?
|
|
if ((pBlt->srcBox.Left == 0) &&
|
|
(pBlt->srcBox.Top == 0) &&
|
|
(pBlt->srcBox.Right == pSrcTexture->wWidth) &&
|
|
(pBlt->srcBox.Bottom == pSrcTexture->wHeight) &&
|
|
(pBlt->srcBox.Front == 0) &&
|
|
(pBlt->srcBox.Back == pSrcTexture->wDepth) &&
|
|
(pBlt->dwDestX == 0) &&
|
|
(pBlt->dwDestY == 0) &&
|
|
(pBlt->dwDestZ == 0) &&
|
|
(pSrcTexture->wWidth == pDestTexture->wWidth) &&
|
|
(pSrcTexture->wHeight == pDestTexture->wHeight) &&
|
|
(pSrcTexture->wDepth == pDestTexture->wDepth))
|
|
{
|
|
// Build source rectangle
|
|
|
|
rSrc.left = 0;
|
|
rSrc.top = 0;
|
|
rSrc.right = pBlt->srcBox.Right;
|
|
rSrc.bottom = pBlt->srcBox.Bottom * pBlt->srcBox.Back;
|
|
|
|
// Destination rectangle is same as source.
|
|
|
|
rDest = rSrc;
|
|
|
|
// Switch to the DirectDraw context
|
|
DDRAW_OPERATION(pContext, pThisDisplay);
|
|
|
|
// Do the Blt!
|
|
__OP_BasicVolumeBlt(pContext,
|
|
pThisDisplay,
|
|
pSrcTexture,
|
|
pDestTexture,
|
|
pBlt->dwDDDestSurface,
|
|
&rSrc,
|
|
&rDest);
|
|
|
|
// Switch back to the Direct3D context
|
|
D3D_OPERATION(pContext, pThisDisplay);
|
|
|
|
return;
|
|
}
|
|
|
|
// Build source rectangle.
|
|
rSrc.left = pBlt->srcBox.Left;
|
|
rSrc.top = pBlt->srcBox.Top;
|
|
rSrc.right = pBlt->srcBox.Right;
|
|
rSrc.bottom = pBlt->srcBox.Bottom;
|
|
|
|
// Build destination rectangle.
|
|
rDest.left = pBlt->dwDestX;
|
|
rDest.top = pBlt->dwDestY;
|
|
rDest.right = pBlt->dwDestX + (rSrc.right - rSrc.left);
|
|
rDest.bottom = pBlt->dwDestY + (rSrc.bottom - rSrc.top);
|
|
|
|
// Adjust rectangle if blt from non-1st slice.
|
|
if (pBlt->srcBox.Front)
|
|
{
|
|
ULONG ulOffset = pSrcTexture->wDepth * pBlt->srcBox.Front;
|
|
rSrc.top += ulOffset;
|
|
rSrc.bottom += ulOffset;
|
|
}
|
|
|
|
// Adjust rectangle if blt to non-1st slice.
|
|
if (pBlt->dwDestZ)
|
|
{
|
|
ULONG ulOffset = pDestTexture->wDepth * pBlt->dwDestZ;
|
|
rDest.top += ulOffset;
|
|
rDest.bottom += ulOffset;
|
|
}
|
|
|
|
dwSrcCurrDepth = pBlt->srcBox.Front;
|
|
dwDestCurrDepth = pBlt->dwDestZ;
|
|
|
|
dwEndDepth = min(pBlt->dwDestZ + (pBlt->srcBox.Back - pBlt->srcBox.Front),
|
|
pDestTexture->wDepth);
|
|
dwEndDepth = min(dwEndDepth, pSrcTexture->wDepth);
|
|
|
|
while(dwDestCurrDepth < dwEndDepth)
|
|
{
|
|
// Switch to the DirectDraw context
|
|
DDRAW_OPERATION(pContext, pThisDisplay);
|
|
|
|
// Do the Blt!
|
|
__OP_BasicVolumeBlt(pContext,
|
|
pThisDisplay,
|
|
pSrcTexture,
|
|
pDestTexture,
|
|
pBlt->dwDDDestSurface,
|
|
&rSrc,
|
|
&rDest);
|
|
|
|
// Switch back to the Direct3D context
|
|
D3D_OPERATION(pContext, pThisDisplay);
|
|
|
|
// Move the source and destination rect to next slice.
|
|
rSrc.top += pSrcTexture->wDepth;
|
|
rSrc.bottom += pSrcTexture->wDepth;
|
|
rDest.top += pDestTexture->wDepth;
|
|
rDest.bottom += pDestTexture->wDepth;
|
|
|
|
// Move on to next slice.
|
|
dwSrcCurrDepth++;
|
|
dwDestCurrDepth++;
|
|
}
|
|
} // _D3D_OP_VolumeBlt
|
|
|
|
#endif // DX8_3DTEXTURES
|
|
|
|
#if DX8_DDI
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_BufferBlt
|
|
//
|
|
// This function processes the D3DDP2OP_BUFFERBLT DP2 command token.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID _D3D_OP_BufferBlt(P3_D3DCONTEXT* pContext,
|
|
P3_THUNKEDDATA*pThisDisplay,
|
|
D3DHAL_DP2BUFFERBLT* pBlt)
|
|
{
|
|
|
|
#if DX7_VERTEXBUFFERS
|
|
// This command token is only sent to drivers
|
|
// supporting videomemory vertexbuffers. That is
|
|
// why we won't see it come down to this driver.
|
|
#endif DX7_VERTEXBUFFERS
|
|
|
|
} // _D3D_OP_BufferBlt
|
|
|
|
#endif // DX8_DDI
|
|
|
|
#if DX8_VERTEXSHADERS
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_VertexShader_Create
|
|
//
|
|
// This function processes the D3DDP2OP_CREATEVERTEXSHADER DP2 command token.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
_D3D_OP_VertexShader_Create(
|
|
P3_D3DCONTEXT* pContext,
|
|
DWORD dwVtxShaderHandle,
|
|
DWORD dwDeclSize,
|
|
DWORD dwCodeSize,
|
|
BYTE *pShader)
|
|
{
|
|
// Here we would use the data passed by the vertex shader
|
|
// creation block in order to instantiate or compile the
|
|
// given vertex shader. Since this hardware can't support
|
|
// vertex shaders at this time, we just skip the data.
|
|
|
|
return DD_OK;
|
|
|
|
} // _D3D_OP_VertexShader_Create
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_VertexShader_Delete
|
|
//
|
|
// This function processes the D3DDP2OP_DELETEVERTEXSHADER DP2 command token.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID
|
|
_D3D_OP_VertexShader_Delete(
|
|
P3_D3DCONTEXT* pContext,
|
|
DWORD dwVtxShaderHandle)
|
|
{
|
|
// Here we would use the data passed by the vertex shader
|
|
// delete block in order to destroy the given vertex shader.
|
|
// Since this hardware can't support vertex shaders at
|
|
// this time, we just skip the data.
|
|
|
|
} // _D3D_OP_VertexShader_Delete
|
|
|
|
#define RDVSD_ISLEGACY(ShaderHandle) !(ShaderHandle & D3DFVF_RESERVED0)
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_VertexShader_Set
|
|
//
|
|
// This function processes the D3DDP2OP_SETVERTEXSHADER DP2 command token.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID
|
|
_D3D_OP_VertexShader_Set(
|
|
P3_D3DCONTEXT* pContext,
|
|
DWORD dwVtxShaderHandle)
|
|
{
|
|
// Here we would use the data passed by the vertex shader
|
|
// set block in order to setup the given vertex shader.
|
|
// Since this hardware can't support vertex shaders at
|
|
// this time, we usually just skip the data. However under
|
|
// the circumstances described below, we might be passed a
|
|
// FVF vertex format
|
|
|
|
DISPDBG((DBGLVL,"Setting up shader # 0x%x",dwVtxShaderHandle));
|
|
|
|
#if DX7_D3DSTATEBLOCKS
|
|
if ( pContext->bStateRecMode )
|
|
{
|
|
_D3D_SB_Record_VertexShader_Set(pContext, dwVtxShaderHandle);
|
|
return;
|
|
}
|
|
#endif // DX7_D3DSTATEBLOCKS
|
|
|
|
// Zero is a special handle that tells the driver to
|
|
// invalidate the currently set shader.
|
|
if( dwVtxShaderHandle == 0 )
|
|
{
|
|
DISPDBG((WRNLVL,"Invalidating the currently set shader"));
|
|
return ;
|
|
}
|
|
|
|
if( RDVSD_ISLEGACY(dwVtxShaderHandle) )
|
|
{
|
|
// Make it parse the FVF
|
|
pContext->dwVertexType = dwVtxShaderHandle;
|
|
}
|
|
else
|
|
{
|
|
DISPDBG((ERRLVL,"_D3D_OP_VertexShader_Set: Illegal shader handle "
|
|
"(This driver cant do vertex processing)"));
|
|
}
|
|
|
|
} // _D3D_OP_VertexShader_Set
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_VertexShader_SetConst
|
|
//
|
|
// This function processes the D3DDP2OP_SETVERTEXSHADERCONST DP2 command token.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID
|
|
_D3D_OP_VertexShader_SetConst(
|
|
P3_D3DCONTEXT* pContext,
|
|
DWORD dwRegister,
|
|
DWORD dwConst,
|
|
DWORD *pdwValues)
|
|
{
|
|
// Here we would use the data passed by the vertex shader
|
|
// constant block in order to set up the constant entry.
|
|
// Since this hardware can't support vertex shaders at
|
|
// this time, we just skip the data.
|
|
|
|
} // _D3D_OP_VertexShader_SetConst
|
|
|
|
#endif // DX8_VERTEXSHADERS
|
|
|
|
#if DX8_PIXELSHADERS
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_PixelShader_Create
|
|
//
|
|
// This function processes the D3DDP2OP_CREATEPIXELSHADER DP2 command token.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
_D3D_OP_PixelShader_Create(
|
|
P3_D3DCONTEXT* pContext,
|
|
DWORD dwPxlShaderHandle,
|
|
DWORD dwCodeSize,
|
|
BYTE *pShader)
|
|
{
|
|
// Here we would use the data passed by the pixel shader
|
|
// creation block in order to instantiate or compile the
|
|
// given pixel shader.
|
|
|
|
// Since this hardware can't support pixel shaders at this
|
|
// time, we fail the call in case we're called to create a
|
|
// 255.255 version shader!
|
|
|
|
return D3DERR_DRIVERINVALIDCALL;
|
|
|
|
} // _D3D_OP_PixelShader_Create
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_PixelShader_Delete
|
|
//
|
|
// This function processes the D3DDP2OP_DELETEPIXELSHADER DP2 command token.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID
|
|
_D3D_OP_PixelShader_Delete(
|
|
P3_D3DCONTEXT* pContext,
|
|
DWORD dwPxlShaderHandle)
|
|
{
|
|
// Here we would use the data passed by the pixel shader
|
|
// delete block in order to destroy the given pixel shader.
|
|
// Since this hardware can't support pixel shaders at
|
|
// this time, we just skip the data.
|
|
|
|
} // _D3D_OP_PixelShader_Delete
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_PixelShader_Set
|
|
//
|
|
// This function processes the D3DDP2OP_SETPIXELSHADER DP2 command token.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID
|
|
_D3D_OP_PixelShader_Set(
|
|
P3_D3DCONTEXT* pContext,
|
|
DWORD dwPxlShaderHandle)
|
|
{
|
|
// Here we would use the data passed by the pixel shader
|
|
// set block in order to setup the given pixel shader.
|
|
// Since this hardware can't support pixel shaders at
|
|
// this time, we just skip the data.
|
|
|
|
} // _D3D_OP_PixelShader_Set
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_PixelShader_SetConst
|
|
//
|
|
// This function processes the D3DDP2OP_SETPIXELSHADERCONST DP2 command token.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID
|
|
_D3D_OP_PixelShader_SetConst(
|
|
P3_D3DCONTEXT* pContext,
|
|
DWORD dwRegister,
|
|
DWORD dwCount,
|
|
DWORD *pdwValues)
|
|
{
|
|
// Here we would use the data passed by the pixel shader
|
|
// set block in order to setup the given pixel shader constants.
|
|
// Since this hardware can't support pixel shaders at
|
|
// this time, we just skip the data.
|
|
|
|
} // _D3D_OP_PixelShader_SetConst
|
|
#endif // DX8_PIXELSHADERS
|
|
|
|
#if DX8_MULTSTREAMS
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_MStream_SetSrc
|
|
//
|
|
// This function processes the D3DDP2OP_SETSTREAMSOURCE DP2 command token.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID
|
|
_D3D_OP_MStream_SetSrc(
|
|
P3_D3DCONTEXT* pContext,
|
|
DWORD dwStream,
|
|
DWORD dwVBHandle,
|
|
DWORD dwStride)
|
|
{
|
|
P3_SURF_INTERNAL *pSrcStream;
|
|
|
|
DBG_ENTRY(_D3D_OP_MStream_SetSrc);
|
|
|
|
#if DX7_D3DSTATEBLOCKS
|
|
if ( pContext->bStateRecMode )
|
|
{
|
|
_D3D_SB_Record_MStream_SetSrc(pContext, dwStream, dwVBHandle, dwStride);
|
|
return;
|
|
}
|
|
#endif // DX7_D3DSTATEBLOCKS
|
|
|
|
if (dwVBHandle != 0)
|
|
{
|
|
if (dwStream == 0)
|
|
{
|
|
// Get the surface structure pointers for stream #0
|
|
pSrcStream = GetSurfaceFromHandle(pContext, dwVBHandle);
|
|
|
|
if (pSrcStream)
|
|
{
|
|
DISPDBG((DBGLVL,"Address of VB = 0x%x "
|
|
"dwVBHandle = %d , dwStride = %d",
|
|
pSrcStream->fpVidMem,dwVBHandle, dwStride));
|
|
pContext->lpVertices = (LPDWORD)pSrcStream->fpVidMem;
|
|
pContext->dwVerticesStride = dwStride;
|
|
|
|
if (dwStride > 0)
|
|
{
|
|
// DX8 has mixed types of vertices in one VB, size in bytes
|
|
// of the vertex buffer must be preserved
|
|
pContext->dwVBSizeInBytes = pSrcStream->lPitch;
|
|
|
|
// for VBs the wHeight should always be == 1.
|
|
// dwNumVertices stores the # of vertices in the VB
|
|
// On Win2K, both wWidth and lPitch are the buffer size
|
|
// On Win9x, only lPitch is the buffer size, wWidth is 0
|
|
// The same fact is also true for the index buffer
|
|
pContext->dwNumVertices = pSrcStream->lPitch / dwStride;
|
|
|
|
DISPDBG((DBGLVL,"dwVBHandle pContext->dwNumVertices = "
|
|
"pSrcStream->lPitch / dwStride = %d %d %d %d",
|
|
dwVBHandle,
|
|
pContext->dwNumVertices,
|
|
pSrcStream->lPitch,dwStride));
|
|
|
|
#if DX7_D3DSTATEBLOCKS
|
|
pContext->dwVBHandle = dwVBHandle;
|
|
#endif // DX7_D3DSTATEBLOCKS
|
|
}
|
|
else
|
|
{
|
|
pContext->dwVBSizeInBytes = 0;
|
|
pContext->dwNumVertices = 0;
|
|
DISPDBG((ERRLVL,"INVALID Stride is 0. VB Size undefined"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DISPDBG((ERRLVL,"ERROR Address of VB is NULL, "
|
|
"dwStream = %d dwVBHandle = %d , dwStride = %d",
|
|
dwStream, dwVBHandle, dwStride));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DISPDBG((WRNLVL,"We don't handle other streams than #0"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// We are unsetting the stream
|
|
pContext->lpVertices = NULL;
|
|
|
|
DISPDBG((WRNLVL,"Unsetting a stream: "
|
|
"dwStream = %d dwVBHandle = %d , dwStride = %d",
|
|
dwStream, dwVBHandle, dwStride));
|
|
}
|
|
|
|
DBG_EXIT(_D3D_OP_MStream_SetSrc, 0);
|
|
} // _D3D_OP_MStream_SetSrc
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_MStream_SetSrcUM
|
|
//
|
|
// This function processes the D3DDP2OP_SETSTREAMSOURCEUM DP2 command token.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID
|
|
_D3D_OP_MStream_SetSrcUM(
|
|
P3_D3DCONTEXT* pContext,
|
|
DWORD dwStream,
|
|
DWORD dwStride,
|
|
LPBYTE pUMVtx,
|
|
DWORD dwVBSize)
|
|
{
|
|
DBG_ENTRY(_D3D_OP_MStream_SetSrcUM);
|
|
|
|
if (dwStream == 0)
|
|
{
|
|
// Set the stream # 0 information
|
|
DISPDBG((DBGLVL,"_D3D_OP_MStream_SetSrcUM: "
|
|
"Setting VB@ 0x%x dwstride=%d", pUMVtx, dwStride));
|
|
pContext->lpVertices = (LPDWORD)pUMVtx;
|
|
pContext->dwVerticesStride = dwStride;
|
|
pContext->dwVBSizeInBytes = dwVBSize * dwStride;
|
|
pContext->dwNumVertices = dwVBSize ; // comes from the DP2 data
|
|
// structure
|
|
|
|
}
|
|
else
|
|
{
|
|
DISPDBG((WRNLVL,"_D3D_OP_MStream_SetSrcUM: "
|
|
"We don't handle other streams than #0"));
|
|
}
|
|
|
|
DBG_EXIT(_D3D_OP_MStream_SetSrcUM, 0);
|
|
} // _D3D_OP_MStream_SetSrcUM
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_MStream_SetIndices
|
|
//
|
|
// This function processes the D3DDP2OP_SETINDICES DP2 command token.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID
|
|
_D3D_OP_MStream_SetIndices(
|
|
P3_D3DCONTEXT* pContext,
|
|
DWORD dwVBHandle,
|
|
DWORD dwStride)
|
|
{
|
|
P3_SURF_INTERNAL *pIndxStream;
|
|
|
|
DBG_ENTRY(_D3D_OP_MStream_SetIndices);
|
|
|
|
#if DX7_D3DSTATEBLOCKS
|
|
if ( pContext->bStateRecMode )
|
|
{
|
|
_D3D_SB_Record_MStream_SetIndices(pContext, dwVBHandle, dwStride);
|
|
return;
|
|
}
|
|
#endif // DX7_D3DSTATEBLOCKS
|
|
|
|
// NULL dwVBHandle just means that the Index should be unset
|
|
if (dwVBHandle != 0)
|
|
{
|
|
// Get the indices surface structure pointer
|
|
pIndxStream = GetSurfaceFromHandle(pContext, dwVBHandle);
|
|
|
|
if (pIndxStream)
|
|
{
|
|
DISPDBG((DBGLVL,"Address of VB = 0x%x", pIndxStream->fpVidMem));
|
|
|
|
pContext->lpIndices = (LPDWORD)pIndxStream->fpVidMem;
|
|
pContext->dwIndicesStride = dwStride; // 2 or 4 for 16/32bit indices
|
|
#if DX7_D3DSTATEBLOCKS
|
|
pContext->dwIndexHandle = dwVBHandle; // Index buffer handle
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
DISPDBG((ERRLVL,"ERROR Address of Index Surface is NULL, "
|
|
"dwVBHandle = %d , dwStride = %d",
|
|
dwVBHandle, dwStride));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// We are unsetting the stream
|
|
pContext->lpIndices = NULL;
|
|
|
|
DISPDBG((WRNLVL,"Unsetting an index stream: "
|
|
"dwVBHandle = %d , dwStride = %d",
|
|
dwVBHandle, dwStride));
|
|
}
|
|
|
|
DBG_EXIT(_D3D_OP_MStream_SetIndices, 0);
|
|
} // _D3D_OP_MStream_SetIndices
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_MStream_DrawPrim
|
|
//
|
|
// This function processes the D3DDP2OP_DRAWPRIMITIVE DP2 command token.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID
|
|
_D3D_OP_MStream_DrawPrim(
|
|
P3_D3DCONTEXT* pContext,
|
|
D3DPRIMITIVETYPE primType,
|
|
DWORD VStart,
|
|
DWORD PrimitiveCount)
|
|
{
|
|
DBG_ENTRY(_D3D_OP_MStream_DrawPrim);
|
|
|
|
DISPDBG((DBGLVL,"_D3D_OP_MStream_DrawPrim "
|
|
"primType=0x%x VStart=%d PrimitiveCount=%d",
|
|
primType, VStart, PrimitiveCount));
|
|
|
|
_D3D_OP_MStream_DrawPrim2(pContext,
|
|
primType,
|
|
VStart * pContext->FVFData.dwStride,
|
|
PrimitiveCount);
|
|
|
|
DBG_EXIT(_D3D_OP_MStream_DrawPrim, 0);
|
|
} // _D3D_OP_MStream_DrawPrim
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_MStream_DrawIndxP
|
|
//
|
|
// This function processes the D3DDP2OP_DRAWINDEXEDPRIMITIVE DP2 command token.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID
|
|
_D3D_OP_MStream_DrawIndxP(
|
|
P3_D3DCONTEXT* pContext,
|
|
D3DPRIMITIVETYPE primType,
|
|
DWORD BaseVertexIndex,
|
|
DWORD MinIndex,
|
|
DWORD NumVertices,
|
|
DWORD StartIndex,
|
|
DWORD PrimitiveCount)
|
|
{
|
|
DBG_ENTRY(_D3D_OP_MStream_DrawIndxP);
|
|
|
|
DISPDBG((DBGLVL,"_D3D_OP_MStream_DrawIndxP "
|
|
"primType=0x%x BaseVertexIndex=%d MinIndex=%d"
|
|
"NumVertices =%d StartIndex=%d PrimitiveCount=%d",
|
|
primType, BaseVertexIndex, MinIndex,
|
|
NumVertices, StartIndex, PrimitiveCount));
|
|
|
|
_D3D_OP_MStream_DrawIndxP2(pContext,
|
|
primType,
|
|
BaseVertexIndex * pContext->FVFData.dwStride,
|
|
MinIndex,
|
|
NumVertices,
|
|
StartIndex * pContext->dwIndicesStride,
|
|
PrimitiveCount);
|
|
|
|
DBG_EXIT(_D3D_OP_MStream_DrawIndxP, 0);
|
|
} // _D3D_OP_MStream_DrawIndxP
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Validate the context settings to use the current streams
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL
|
|
__OP_ValidateStreams(
|
|
P3_D3DCONTEXT* pContext,
|
|
BOOL bCheckIndexStream)
|
|
{
|
|
if ((pContext->dwVerticesStride == 0) ||
|
|
(pContext->FVFData.dwStride == 0))
|
|
{
|
|
DISPDBG((ERRLVL,"The zero'th stream is doesn't have a valid VB set"));
|
|
return FALSE;
|
|
}
|
|
|
|
if (pContext->dwVerticesStride < pContext->FVFData.dwStride)
|
|
{
|
|
DISPDBG((ERRLVL,"The stride set for the vertex stream is "
|
|
"less than the FVF vertex size"));
|
|
return FALSE;
|
|
}
|
|
|
|
//@@BEGIN_DDKSPLIT
|
|
// This shouldn't happen, but lets watch for it since it would show
|
|
// up as weird mangled & distorted triangles
|
|
if (pContext->dwVerticesStride != pContext->FVFData.dwStride)
|
|
{
|
|
DISPDBG((ERRLVL,"Strides(indx-prim) <> %d %d ",
|
|
pContext->dwVerticesStride,pContext->FVFData.dwStride));
|
|
}
|
|
//@@END_DDKSPLIT
|
|
|
|
if ((bCheckIndexStream) && (NULL == pContext->lpIndices))
|
|
{
|
|
DISPDBG((ERRLVL,"Pointer to index buffer is null"));
|
|
return FALSE;
|
|
}
|
|
|
|
if (NULL == pContext->lpVertices)
|
|
{
|
|
DISPDBG((ERRLVL,"Pointer to vertex buffer is null"));
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
} // __OP_ValidateStreams
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_MStream_DrawPrim2
|
|
//
|
|
// This function processes the D3DDP2OP_DRAWPRIMITIVE2 DP2 command token.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
VOID
|
|
_D3D_OP_MStream_DrawPrim2(
|
|
P3_D3DCONTEXT* pContext,
|
|
D3DPRIMITIVETYPE primType,
|
|
DWORD FirstVertexOffset,
|
|
DWORD PrimitiveCount)
|
|
{
|
|
BOOL bError;
|
|
WORD wVStart;
|
|
DWORD dwFillMode = pContext->RenderStates[D3DRENDERSTATE_FILLMODE];
|
|
LPBYTE lpVertices;
|
|
DWORD dwNumVertices;
|
|
|
|
DBG_ENTRY(_D3D_OP_MStream_DrawPrim2);
|
|
|
|
DISPDBG((DBGLVL ,"_D3D_OP_MStream_DrawPrim2 "
|
|
"primType=0x%x FirstVertexOffset=%d PrimitiveCount=%d",
|
|
primType, FirstVertexOffset, PrimitiveCount));
|
|
|
|
if (!__OP_ValidateStreams(pContext, FALSE))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Watchout: Sometimes (particularly when CLIPPEDTRIFAN are drawn),
|
|
// FirstVertexOffset might not be divided evenly by the dwStride
|
|
lpVertices = ((LPBYTE)pContext->lpVertices) + FirstVertexOffset;
|
|
dwNumVertices = pContext->dwVBSizeInBytes - FirstVertexOffset;
|
|
dwNumVertices /= pContext->dwVerticesStride;
|
|
wVStart = 0;
|
|
|
|
switch(primType)
|
|
{
|
|
case D3DPT_POINTLIST:
|
|
{
|
|
D3DHAL_DP2POINTS dp2Points;
|
|
dp2Points.wVStart = wVStart;
|
|
|
|
#if DX8_POINTSPRITES
|
|
if(IS_POINTSPRITE_ACTIVE(pContext))
|
|
{
|
|
_D3D_R3_DP2_PointsSprite_DWCount(pContext,
|
|
PrimitiveCount,
|
|
(LPBYTE)&dp2Points,
|
|
(LPD3DTLVERTEX)lpVertices,
|
|
dwNumVertices,
|
|
&bError);
|
|
}
|
|
else
|
|
#endif // DX8_POINTSPRITES
|
|
{
|
|
|
|
_D3D_R3_DP2_Points_DWCount(pContext,
|
|
PrimitiveCount,
|
|
(LPBYTE)&dp2Points,
|
|
(LPD3DTLVERTEX)lpVertices,
|
|
dwNumVertices,
|
|
&bError);
|
|
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case D3DPT_LINELIST:
|
|
|
|
_D3D_R3_DP2_LineList(pContext,
|
|
PrimitiveCount,
|
|
(LPBYTE)&wVStart,
|
|
(LPD3DTLVERTEX)lpVertices,
|
|
dwNumVertices,
|
|
&bError);
|
|
break;
|
|
|
|
case D3DPT_LINESTRIP:
|
|
|
|
_D3D_R3_DP2_LineStrip(pContext,
|
|
PrimitiveCount,
|
|
(LPBYTE)&wVStart,
|
|
(LPD3DTLVERTEX)lpVertices,
|
|
dwNumVertices,
|
|
&bError);
|
|
break;
|
|
|
|
case D3DPT_TRIANGLELIST:
|
|
|
|
_D3D_R3_DP2_TriangleList(pContext,
|
|
PrimitiveCount,
|
|
(LPBYTE)&wVStart,
|
|
(LPD3DTLVERTEX)lpVertices,
|
|
dwNumVertices,
|
|
&bError);
|
|
break;
|
|
|
|
case D3DPT_TRIANGLESTRIP:
|
|
|
|
_D3D_R3_DP2_TriangleStrip(pContext,
|
|
PrimitiveCount,
|
|
(LPBYTE)&wVStart,
|
|
(LPD3DTLVERTEX)lpVertices,
|
|
dwNumVertices,
|
|
&bError);
|
|
break;
|
|
|
|
case D3DPT_TRIANGLEFAN:
|
|
|
|
_D3D_R3_DP2_TriangleFan(pContext,
|
|
PrimitiveCount,
|
|
(LPBYTE)&wVStart,
|
|
(LPD3DTLVERTEX)lpVertices,
|
|
dwNumVertices,
|
|
&bError);
|
|
break;
|
|
}
|
|
|
|
DBG_EXIT(_D3D_OP_MStream_DrawPrim2, 0);
|
|
} // _D3D_OP_MStream_DrawPrim2
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_MStream_DrawIndxP2
|
|
//
|
|
// This function processes the D3DDP2OP_DRAWINDEXEDPRIMITIVE2 DP2 command token.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID
|
|
_D3D_OP_MStream_DrawIndxP2(
|
|
P3_D3DCONTEXT* pContext,
|
|
D3DPRIMITIVETYPE primType,
|
|
INT BaseVertexOffset,
|
|
DWORD MinIndex,
|
|
DWORD NumVertices,
|
|
DWORD StartIndexOffset,
|
|
DWORD PrimitiveCount)
|
|
{
|
|
INT BaseIndexOffset;
|
|
LPDWORD lpVertices;
|
|
LPBYTE lpIndices;
|
|
BOOL bError;
|
|
|
|
R3_DP2_PRIM_TYPE_MS *pRenderFunc;
|
|
|
|
DBG_ENTRY(_D3D_OP_MStream_DrawIndxP2);
|
|
|
|
DISPDBG((DBGLVL,"_D3D_OP_MStream_DrawIndxP2 "
|
|
"primType=0x%x BaseVertexOffset=%d MinIndex=%d "
|
|
"NumVertices=%d StartIndexOffset=%d PrimitiveCount=%d",
|
|
primType, BaseVertexOffset, MinIndex,
|
|
NumVertices, StartIndexOffset, PrimitiveCount));
|
|
|
|
if (!__OP_ValidateStreams(pContext, TRUE))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// The MinIndex and NumVertices parameters specify the range of vertex i
|
|
// ndices used for each DrawIndexedPrimitive call. These are used to
|
|
// optimize vertex processing of indexed primitives by processing a
|
|
// sequential range of vertices prior to indexing into these vertices
|
|
|
|
// ********** IMPORTANT NOTE **********
|
|
//
|
|
// BaseVertexOffset is a signed quantity (INT) unlike the other parameters
|
|
// to this call which are DWORDS. This may appear strange. Why would
|
|
// the offset into the vertex buffer be negative? Clearly you cannot access
|
|
// vertex data before the start of the vertex buffer, and indeed, you never
|
|
// do. When you have a negative BaseVertexOffset you will also receive
|
|
// indices which are large enough that when applied to the start pointer
|
|
// (obtained from adding a negative BaseVertexOffset to the vertex data
|
|
// pointer) which fall within the correct range of the vertices in the
|
|
// actual vertex buffer, i.e., the indices "undo" any negative vertex offset
|
|
// and vertex accesses will end up being in the legal range for that vertex
|
|
// buffer.
|
|
//
|
|
// Hence, you must write your driver code with this in mind. For example,
|
|
// you can't assume that given an index i and with a current vertex buffer
|
|
// of size v:
|
|
//
|
|
// ((StartIndexOffset + i) >= 0) && ((StartIndexOffset + i) < v)
|
|
//
|
|
// Your code needs to take into account that your indices are not offsets
|
|
// from the start of the vertex buffer but rather from the start of the
|
|
// vertex buffer plus BaseVertexOffset and that furthermore BaseVertexOffset
|
|
// may be negative.
|
|
//
|
|
// The reason BaseVertexOffset can be negative is that it provides a
|
|
// significant advantage to the runtime in certain vertex processing scenarios.
|
|
|
|
lpVertices = (LPDWORD)((LPBYTE)pContext->lpVertices + BaseVertexOffset);
|
|
|
|
lpIndices = (LPBYTE)pContext->lpIndices + StartIndexOffset;
|
|
|
|
|
|
// Select the appropriate rendering function
|
|
pRenderFunc = NULL;
|
|
|
|
if (pContext->dwIndicesStride == 2)
|
|
{
|
|
// Handle 16 bit indices
|
|
|
|
switch(primType)
|
|
{
|
|
case D3DPT_LINELIST:
|
|
pRenderFunc = _D3D_R3_DP2_IndexedLineList_MS_16IND;
|
|
break;
|
|
|
|
case D3DPT_LINESTRIP:
|
|
pRenderFunc = _D3D_R3_DP2_IndexedLineStrip_MS_16IND;
|
|
break;
|
|
|
|
case D3DPT_TRIANGLELIST:
|
|
pRenderFunc = _D3D_R3_DP2_IndexedTriangleList_MS_16IND;
|
|
break;
|
|
|
|
case D3DPT_TRIANGLESTRIP:
|
|
pRenderFunc = _D3D_R3_DP2_IndexedTriangleStrip_MS_16IND;
|
|
break;
|
|
|
|
case D3DPT_TRIANGLEFAN:
|
|
pRenderFunc = _D3D_R3_DP2_IndexedTriangleFan_MS_16IND;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Handle 32 bit indices
|
|
|
|
switch(primType)
|
|
{
|
|
case D3DPT_LINELIST:
|
|
pRenderFunc = _D3D_R3_DP2_IndexedLineList_MS_32IND;
|
|
break;
|
|
|
|
case D3DPT_LINESTRIP:
|
|
pRenderFunc = _D3D_R3_DP2_IndexedLineStrip_MS_32IND;
|
|
break;
|
|
|
|
case D3DPT_TRIANGLELIST:
|
|
pRenderFunc = _D3D_R3_DP2_IndexedTriangleList_MS_32IND;
|
|
break;
|
|
|
|
case D3DPT_TRIANGLESTRIP:
|
|
pRenderFunc = _D3D_R3_DP2_IndexedTriangleStrip_MS_32IND;
|
|
break;
|
|
|
|
case D3DPT_TRIANGLEFAN:
|
|
pRenderFunc = _D3D_R3_DP2_IndexedTriangleFan_MS_32IND;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Call our rendering function
|
|
if (pRenderFunc)
|
|
{
|
|
// As mentioned above, the actual range of indices seen by the driver
|
|
// doesn't necessarily lie within the range zero to one less than
|
|
// the number of vertices in the vertex buffer due to BaseVertexOffset.
|
|
// If BaseVertexOffset is positive the range of valid indices is
|
|
// smaller than the size of the vertex buffer (the vertices that
|
|
// lie in the vertex buffer before the BaseVertexOffset are not
|
|
// considered). Furthermore, if BaseVertexOffset a valid index can
|
|
// actually by greater than the number of vertices in the vertex
|
|
// buffer.
|
|
//
|
|
// To assist with the validation performed by the rendering functions
|
|
// we here compute a minimum and maximum index which take into
|
|
// account the value of BaseVertexOffset. Thus a test for a valid
|
|
// index becomes:
|
|
//
|
|
// ((BaseIndexOffset + StartIndexOffset + Index) >= 0) &&
|
|
// ((BaseIndexOffset + StartIndexOffset + Index) < VertexCount)
|
|
|
|
BaseIndexOffset = (BaseVertexOffset / (int)pContext->dwVerticesStride);
|
|
|
|
DISPDBG((DBGLVL,"_D3D_OP_MStream_DrawIndxP2 BaseIndexOffset = %d",
|
|
BaseIndexOffset));
|
|
|
|
(*pRenderFunc)(pContext,
|
|
PrimitiveCount,
|
|
(LPBYTE)lpIndices,
|
|
(LPD3DTLVERTEX)lpVertices,
|
|
BaseIndexOffset,
|
|
pContext->dwNumVertices,
|
|
&bError);
|
|
}
|
|
|
|
DBG_EXIT(_D3D_OP_MStream_DrawIndxP2, 0);
|
|
} // _D3D_OP_MStream_DrawIndxP2
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_MStream_ClipTriFan
|
|
//
|
|
// This function processes the D3DDP2OP_CLIPPEDTRIANGLEFAN DP2 command token.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID
|
|
_D3D_OP_MStream_ClipTriFan(
|
|
P3_D3DCONTEXT* pContext,
|
|
DWORD FirstVertexOffset,
|
|
DWORD dwEdgeFlags,
|
|
DWORD PrimitiveCount)
|
|
{
|
|
BOOL bError;
|
|
|
|
DBG_ENTRY(_D3D_OP_MStream_ClipTriFan);
|
|
|
|
DISPDBG((DBGLVL,"_D3D_OP_MStream_ClipTriFan "
|
|
"FirstVertexOffset=%d dwEdgeFlags=0x%x PrimitiveCount=%d",
|
|
FirstVertexOffset, dwEdgeFlags, PrimitiveCount));
|
|
|
|
if (pContext->RenderStates[D3DRENDERSTATE_FILLMODE] == D3DFILL_WIREFRAME)
|
|
{
|
|
D3DHAL_DP2TRIANGLEFAN_IMM dp2TriFanWire;
|
|
|
|
if (!__OP_ValidateStreams(pContext, FALSE))
|
|
{
|
|
DBG_EXIT(_D3D_OP_MStream_ClipTriFan, 0);
|
|
return;
|
|
}
|
|
|
|
dp2TriFanWire.dwEdgeFlags = dwEdgeFlags;
|
|
|
|
_D3D_R3_DP2_TriangleFanImm(pContext,
|
|
(WORD)PrimitiveCount,
|
|
(LPBYTE)&dp2TriFanWire,
|
|
(LPD3DTLVERTEX)pContext->lpVertices,
|
|
pContext->dwNumVertices,
|
|
&bError);
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
_D3D_OP_MStream_DrawPrim2(pContext,
|
|
D3DPT_TRIANGLEFAN,
|
|
FirstVertexOffset,
|
|
PrimitiveCount);
|
|
}
|
|
|
|
DBG_EXIT(_D3D_OP_MStream_ClipTriFan, 0);
|
|
} // _D3D_OP_MStream_ClipTriFan
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_MStream_DrawRectSurface
|
|
//
|
|
// This function processes the D3DDP2OP_DRAWRECTSURFACE DP2 command token.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID _D3D_OP_MStream_DrawRectSurface(P3_D3DCONTEXT* pContext,
|
|
DWORD Handle,
|
|
DWORD Flags,
|
|
PVOID lpPrim)
|
|
{
|
|
// High order surfaces are only supported for hw/drivers with
|
|
// TnL support and 1.0 vertex shader support
|
|
|
|
} // _D3D_OP_MStream_DrawRectSurface
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_MStream_DrawTriSurface
|
|
//
|
|
// This function processes the D3DDP2OP_DRAWTRISURFACE DP2 command token.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID _D3D_OP_MStream_DrawTriSurface(P3_D3DCONTEXT* pContext,
|
|
DWORD Handle,
|
|
DWORD Flags,
|
|
PVOID lpPrim)
|
|
{
|
|
// High order surfaces are only supported for hw/drivers with
|
|
// TnL support and 1.0 vertex shader support
|
|
|
|
} // _D3D_OP_MStream_DrawTriSurface
|
|
|
|
#endif // DX8_MULTSTREAMS
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_Viewport
|
|
//
|
|
// This function processes the D3DDP2OP_VIEWPORTINFO DP2 command token.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
VOID _D3D_OP_Viewport(P3_D3DCONTEXT* pContext,
|
|
D3DHAL_DP2VIEWPORTINFO* lpvp)
|
|
{
|
|
#if DX7_D3DSTATEBLOCKS
|
|
if ( pContext->bStateRecMode )
|
|
{
|
|
_D3D_SB_Record_Viewport(pContext, lpvp);
|
|
}
|
|
else
|
|
#endif // DX7_D3DSTATEBLOCKS
|
|
{
|
|
pContext->ViewportInfo = *lpvp;
|
|
DIRTY_VIEWPORT(pContext);
|
|
}
|
|
} // _D3D_OP_Viewport
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_ZRange
|
|
//
|
|
// This function processes the D3DDP2OP_ZRANGE DP2 command token.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
VOID _D3D_OP_ZRange(P3_D3DCONTEXT* pContext,
|
|
D3DHAL_DP2ZRANGE* lpzr)
|
|
{
|
|
#if DX7_D3DSTATEBLOCKS
|
|
if ( pContext->bStateRecMode )
|
|
{
|
|
_D3D_SB_Record_ZRange(pContext, lpzr);
|
|
}
|
|
else
|
|
#endif // DX7_D3DSTATEBLOCKS
|
|
{
|
|
pContext->ZRange = *lpzr;
|
|
DIRTY_VIEWPORT(pContext);
|
|
}
|
|
} // _D3D_OP_ZRange
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_UpdatePalette
|
|
//
|
|
// This function processes the D3DDP2OP_UPDATEPALETTE DP2 command token.
|
|
//
|
|
// Note : This function is need to skip D3DDP2OP_UPDATEPALETTE sent down
|
|
// by some DX6 apps, even if when PALETTE TEXTURE is not supported
|
|
// Also notice that for legacy DX apps, the palette doesn't get
|
|
// properly restored in another app transitions into full screen
|
|
// mode and back. This is because the (legacy) runtimes don't
|
|
// sent proper notification (through UpdatePalette/SetPalette) of
|
|
// this event
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT _D3D_OP_UpdatePalette(P3_D3DCONTEXT* pContext,
|
|
D3DHAL_DP2UPDATEPALETTE* pUpdatePalette,
|
|
DWORD* pdwPalEntries)
|
|
{
|
|
#if DX7_PALETTETEXTURE
|
|
D3DHAL_DP2UPDATEPALETTE* pPalette;
|
|
P3_SURF_INTERNAL* pTexture;
|
|
|
|
// Find internal palette pointer from handle
|
|
pPalette = GetPaletteFromHandle(pContext,
|
|
pUpdatePalette->dwPaletteHandle);
|
|
|
|
// Palette doesn't exist
|
|
if (! pPalette)
|
|
{
|
|
DISPDBG((WRNLVL, "_D3D_OP_UpdatePalette : Can't find palette"));
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
// Check the range of palette entries
|
|
if (pUpdatePalette->wStartIndex > LUT_ENTRIES)
|
|
{
|
|
DISPDBG((WRNLVL,
|
|
"_D3D_OP_UpdatePalette : wStartIndex (%d) is bigger than 256",
|
|
pUpdatePalette->wStartIndex));
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if ((pUpdatePalette->wStartIndex + pUpdatePalette->wNumEntries)
|
|
> LUT_ENTRIES)
|
|
{
|
|
DISPDBG((WRNLVL, "_D3D_OP_UpdatePalette : too many entries"));
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
// Each palette is ARGB 8:8:8:8
|
|
memcpy(((LPBYTE)(pPalette + 1)) + pUpdatePalette->wStartIndex*sizeof(DWORD),
|
|
pdwPalEntries,
|
|
pUpdatePalette->wNumEntries*sizeof(DWORD));
|
|
|
|
// Check if the palette is in use
|
|
// Palette Texture can not be used alone in the 2nd stage, so only the
|
|
// 1st stage must be checked.
|
|
if (pContext->TextureStageState[0].m_dwVal[D3DTSS_TEXTUREMAP])
|
|
{
|
|
pTexture = GetSurfaceFromHandle(pContext,
|
|
pContext->TextureStageState[0].m_dwVal[D3DTSS_TEXTUREMAP]);
|
|
if (pTexture)
|
|
{
|
|
if ((pTexture->pFormatSurface->DeviceFormat == SURF_CI8) &&
|
|
(pTexture->dwPaletteHandle == pUpdatePalette->dwPaletteHandle))
|
|
{
|
|
DIRTY_TEXTURE(pContext);
|
|
}
|
|
}
|
|
}
|
|
|
|
return DD_OK;
|
|
#else
|
|
return DD_OK;
|
|
#endif // DX7_PALETTETEXTURE
|
|
} // D3D_OP_UpdatePalette
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _D3D_OP_SetPalette
|
|
//
|
|
// This function processes the D3DDP2OP_SETPALETTE DP2 command token.
|
|
//
|
|
// Note : This function is need to skip D3DDP2OP_SETPALETTE sent down
|
|
// by some DX6 apps, even if when PALETTE TEXTURE is not supported
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT _D3D_OP_SetPalettes(P3_D3DCONTEXT* pContext,
|
|
D3DHAL_DP2SETPALETTE* pSetPalettes,
|
|
int iNumSetPalettes)
|
|
{
|
|
#if DX7_PALETTETEXTURE
|
|
int i;
|
|
P3_SURF_INTERNAL* pTexture;
|
|
D3DHAL_DP2UPDATEPALETTE* pPalette;
|
|
|
|
// Loop to process N surface palette association
|
|
for (i = 0; i < iNumSetPalettes; i++, pSetPalettes++)
|
|
{
|
|
|
|
DISPDBG((DBGLVL,"SETPALETTE: Binding surf # %d to palette # %d",
|
|
pSetPalettes->dwSurfaceHandle,
|
|
pSetPalettes->dwPaletteHandle));
|
|
|
|
// Find internal surface pointer from handle
|
|
pTexture = GetSurfaceFromHandle(pContext,
|
|
pSetPalettes->dwSurfaceHandle);
|
|
if (! pTexture)
|
|
{
|
|
// Associated texture can't be found
|
|
DISPDBG((WRNLVL,
|
|
"SetPalettes : invalid texture handle %08lx",
|
|
pSetPalettes->dwSurfaceHandle));
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
// Create the internal palette structure if necessary
|
|
if (pSetPalettes->dwPaletteHandle)
|
|
{
|
|
// Find internal palette pointer from handle
|
|
pPalette = GetPaletteFromHandle(pContext,
|
|
pSetPalettes->dwPaletteHandle);
|
|
|
|
if (! pPalette)
|
|
{
|
|
pPalette = (D3DHAL_DP2UPDATEPALETTE *)
|
|
HEAP_ALLOC(FL_ZERO_MEMORY,
|
|
sizeof(D3DHAL_DP2UPDATEPALETTE)
|
|
+ LUT_ENTRIES*sizeof(DWORD),
|
|
ALLOC_TAG_DX(P));
|
|
// Out of memory case
|
|
if (! pPalette)
|
|
{
|
|
DISPDBG((WRNLVL, "_D3D_OP_SetPalettes : Out of memory."));
|
|
return DDERR_OUTOFMEMORY;
|
|
}
|
|
|
|
// Add this texture to the surface list
|
|
if (! PA_SetEntry(pContext->pPalettePointerArray,
|
|
pSetPalettes->dwPaletteHandle,
|
|
pPalette))
|
|
{
|
|
HEAP_FREE(pPalette);
|
|
DISPDBG((WRNLVL, "_D3D_OP_SetPalettes : "
|
|
"PA_SetEntry() failed."));
|
|
return DDERR_OUTOFMEMORY;
|
|
}
|
|
|
|
// Set up the internal data structure
|
|
pPalette->dwPaletteHandle = pSetPalettes->dwPaletteHandle;
|
|
pPalette->wStartIndex = 0;
|
|
pPalette->wNumEntries = LUT_ENTRIES;
|
|
}
|
|
}
|
|
|
|
// Record palette handle and flags in internal surface data
|
|
pTexture->dwPaletteHandle = pSetPalettes->dwPaletteHandle;
|
|
pTexture->dwPaletteFlags = pSetPalettes->dwPaletteFlags;
|
|
|
|
// Mark texture as dirty if current texture is affected
|
|
if ((pContext->TextureStageState[0].m_dwVal[D3DTSS_TEXTUREMAP] ==
|
|
pSetPalettes->dwSurfaceHandle) ||
|
|
(pContext->TextureStageState[1].m_dwVal[D3DTSS_TEXTUREMAP] ==
|
|
pSetPalettes->dwSurfaceHandle))
|
|
{
|
|
DIRTY_TEXTURE(pContext);
|
|
}
|
|
|
|
}
|
|
|
|
return DD_OK;
|
|
#else
|
|
return DD_OK;
|
|
#endif // DX7_PALETTETEXTURE
|
|
} // _D3D_OP_SetPalettes
|
|
|