Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1271 lines
49 KiB

/*==========================================================================;
*
* Copyright (C) 1997 Microsoft Corporation. All Rights Reserved.
*
* File: cbhal.cpp
* Content: DrawPrimitive implementation for command buffer HALs
*
***************************************************************************/
#include "pch.cpp"
#pragma hdrstop
#include "drawprim.hpp"
#include "clipfunc.h"
#include "d3dfei.h"
extern const DWORD LOWVERTICESNUMBER;
extern "C" HRESULT WINAPI
DDInternalLock( LPDDRAWI_DDRAWSURFACE_LCL this_lcl, LPVOID* lpBits );
extern "C" FLATPTR GetAliasedVidMem( LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl,
LPDDRAWI_DDRAWSURFACE_LCL surf_lcl,
FLATPTR fpVidMem );
// Each vertex buffer is big enough to hold 256 TL vertices
const DWORD CDirect3DDeviceIDP2::dwD3DDefaultVertexBatchSize = 256; // * 32 = 8K bytes
// Command buffer size tuned to 16K to minimize flushes in Unreal
const DWORD CDirect3DDeviceIDP2::dwD3DDefaultCommandBatchSize = 16384; // * 1 = 16K bytes
inline void CDirect3DDeviceIDP2::ClearBatch()
{
// Reset command buffer
lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)lpvDP2Commands;
dwDP2CommandLength = 0;
dp2data.dwCommandOffset = 0;
dp2data.dwCommandLength = 0;
bDP2CurrCmdOP = 0;
// Reset vertex buffer
if (this->dwFlags & D3DPV_WITHINPRIMITIVE)
{
// Do not reset vertex buffer
// or reset to the start of current primitives'
// vertex data to prevent unecessary processing
// of unused vertices by the driver.
/*
dp2data.dwVertexOffset = dwDP2CurrPrimVertexOffset;
dp2data.dwVertexLength -= dwDP2CurrPrimVertexOffset;
*/
}
else
{
dp2data.dwVertexOffset = 0;
dp2data.dwVertexLength = 0;
dwVertexBase = 0;
TLVbuf.Base() = 0;
if (dp2data.dwFlags & D3DHALDP2_USERMEMVERTICES)
{
// We are flushing a user mem primitive.
// We need to clear dp2data.lpUMVertices
// since we are done with it. We replace
// it with TLVbuf.
DDASSERT(lpDP2CurrBatchVBI == NULL);
dp2data.lpDDVertex = ((LPDDRAWI_DDRAWSURFACE_INT)TLVbuf.GetDDS())->lpLcl;
lpDP2CurrBatchVBI = TLVbuf.GetVBI();
lpDP2CurrBatchVBI->AddRef();
dp2data.dwFlags &= ~D3DHALDP2_USERMEMVERTICES;
}
}
}
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDeviceIDP2::CheckSurfaces()"
HRESULT CDirect3DDeviceIDP2::CheckSurfaces()
{
HRESULT hr;
if(this->lpDirect3DI->lpTextureManager->CheckIfLost())
{
D3D_ERR("Managed Textures lost");
return DDERR_SURFACELOST;
}
if ( ((LPDDRAWI_DDRAWSURFACE_INT) this->lpDDSTarget)->lpLcl->lpGbl->dwUsageCount ||
(this->lpDDSZBuffer && ((LPDDRAWI_DDRAWSURFACE_INT) this->lpDDSZBuffer)->lpLcl->lpGbl->dwUsageCount) )
{
D3D_ERR("Render target or Z buffer locked");
return DDERR_SURFACEBUSY;
}
if ( ((LPDDRAWI_DDRAWSURFACE_INT) this->lpDDSTarget)->lpLcl->dwFlags & DDRAWISURF_INVALID )\
{
D3D_ERR("Render target buffer lost");
return DDERR_SURFACELOST;
}
if ( this->lpDDSZBuffer && ( ((LPDDRAWI_DDRAWSURFACE_INT) this->lpDDSZBuffer)->lpLcl->dwFlags & DDRAWISURF_INVALID ) )
{
D3D_ERR("Z buffer lost");
return DDERR_SURFACELOST;
}
if (!(this->dp2data.dwFlags & D3DHALDP2_USERMEMVERTICES) && (this->dp2data.lpDDVertex->dwFlags & DDRAWISURF_INVALID))
{
D3D_ERR("Vertex buffer lost");
return DDERR_SURFACELOST;
}
if (this->dp2data.lpDDCommands->dwFlags & DDRAWISURF_INVALID)
{
D3D_ERR("Command buffer lost");
return DDERR_SURFACELOST;
}
return D3D_OK;
}
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDeviceIDP2::FlushStates(void)"
HRESULT CDirect3DDeviceIDP2::FlushStates()
{
HRESULT dwRet=D3D_OK;
FlushTextureFromDevice( this ); // delink all texture surfaces
if (dwDP2CommandLength) // Do we have some instructions to flush ?
{
CLockD3DST lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock (ST only).
// Check if render target and / or z buffer is lost
if ((dwRet = CheckSurfaces()) != D3D_OK)
{ // If lost, we'll just chuck all this work into the bit bucket
ClearBatch();
if (dwRet == DDERR_SURFACELOST)
{
this->dwFEFlags |= D3DFE_LOSTSURFACES;
dwRet = D3D_OK;
}
}
else
{
// Save since it will get overwritten by ddrval after DDI call
DWORD dwVertexSize = dp2data.dwVertexSize;
dp2data.dwCommandLength = dwDP2CommandLength;
//we clear this to break re-entering as SW rasterizer needs to lock DDRAWSURFACE
dwDP2CommandLength = 0;
// Try and set these 2 values only once during initialization
dp2data.dwhContext = this->dwhContext;
dp2data.lpdwRStates = this->rstates;
DDASSERT(dp2data.dwVertexSize != 0);
// If we need the same TLVbuf next time do not swap buffers.
if (this->dwFlags & D3DPV_WITHINPRIMITIVE)
{
dp2data.dwFlags &= ~D3DHALDP2_SWAPVERTEXBUFFER;
}
D3D_INFO(6, "dwVertexType passed to the driver = 0x%08x", dp2data.dwVertexType);
#ifndef WIN95
if (!IS_DX7HAL_DEVICE(this))
{
if((dwRet = CheckContextSurface(this)) != D3D_OK)
{
ClearBatch();
return dwRet;
}
}
#else
// Take Win 16 Lock here
LOCK_HAL( dwRet, this );
#endif //WIN95
// Spin waiting on the driver if wait requested
do {
// Need to set this since the driver may have overwrote it by
// setting ddrval = DDERR_WASSTILLDRAWING
dp2data.dwVertexSize = dwVertexSize;
CALL_HAL3ONLY_NOLOCK(dwRet, this, DrawPrimitives2, &dp2data);
if (dwRet != DDHAL_DRIVER_HANDLED)
{
D3D_ERR ( "Driver not handled in DrawPrimitives2" );
// Need sensible return value in this case,
// currently we return whatever the driver stuck in here.
}
} while (dp2data.ddrval == DDERR_WASSTILLDRAWING);
if (dp2data.ddrval == D3DERR_COMMAND_UNPARSED)
{ // This should never occur since the driver must understand
// all the instruction we batch.
D3D_ERR("Driver could not parse this batch!");
dwRet = DDERR_GENERIC; // Some thing better here ?
}
else
{
dwRet= dp2data.ddrval;
#ifdef WIN95
// update command buffer pointer
if ((dwRet == D3D_OK) && (dp2data.dwFlags & D3DHALDP2_SWAPCOMMANDBUFFER))
{
// Get Aliased vid mem pointer if it is a vid mem surf.
if (dp2data.dwFlags & D3DHALDP2_VIDMEMCOMMANDBUF)
{
D3D_INFO(7, "Got back new vid mem command buffer");
FLATPTR paliasbits = GetAliasedVidMem( dp2data.lpDDCommands->lpSurfMore->lpDD_lcl,
dp2data.lpDDCommands, (FLATPTR) dp2data.lpDDCommands->lpGbl->fpVidMem );
if (paliasbits == NULL)
{
DPF_ERR("Could not get Aliased pointer for vid mem command buffer");
// Since we can't use this pointer, set it's size to 0
// That way next time around we will try and allocate a new one
dp2data.lpDDCommands->lpGbl->dwLinearSize = 0;
}
lpvDP2Commands = (LPVOID)paliasbits;
}
else
{
D3D_INFO(7, "Got back new sys mem command buffer");
lpvDP2Commands = (LPVOID)dp2data.lpDDCommands->lpGbl->fpVidMem;
}
dwDP2CommandBufSize = dp2data.lpDDCommands->lpGbl->dwLinearSize;
}
// update vertex buffer pointer
if ((dwRet == D3D_OK) && (dp2data.dwFlags & D3DHALDP2_SWAPVERTEXBUFFER))
{
if (dp2data.dwFlags & D3DHALDP2_VIDMEMVERTEXBUF)
{
D3D_INFO(7, "Got back new vid mem vertex buffer");
FLATPTR paliasbits = GetAliasedVidMem( dp2data.lpDDVertex->lpSurfMore->lpDD_lcl,
dp2data.lpDDVertex, (FLATPTR) dp2data.lpDDVertex->lpGbl->fpVidMem );
if (paliasbits == NULL)
{
DPF_ERR("Could not get Aliased pointer for vid mem vertex buffer");
// Since we can't use this pointer, set it's size to 0
// That way next time around we will try and allocate a new one
dp2data.lpDDVertex->lpGbl->dwLinearSize = 0;
}
TLVbuf.alignedBuf = (LPVOID)paliasbits;
}
else
{
D3D_INFO(7, "Got back new sys mem vertex buffer");
TLVbuf.alignedBuf = (LPVOID)dp2data.lpDDVertex->lpGbl->fpVidMem;
}
TLVbuf.size = dp2data.lpDDVertex->lpGbl->dwLinearSize;
}
#endif
}
#ifdef WIN95
// Release Win16 Lock here
UNLOCK_HAL( this );
#endif
// Restore to value before the DDI call
dp2data.dwVertexSize = dwVertexSize;
ClearBatch();
}
}
// There are situations when the command stream has no data, but there is data in
// the vertex pool. This could happen, for instance if every triangle got rejected
// while clipping. In this case we still need to "Flush out" the vertex data.
else if (dp2data.dwCommandLength == 0)
{
ClearBatch();
}
return dwRet;
}
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDeviceIDP2::FlushStates(DWORD)"
HRESULT CDirect3DDeviceIDP2::FlushStates(DWORD dwReqSize)
{
// Request the driver to grow the command buffer upon flush
dp2data.dwReqVertexBufSize = dwReqSize;
dp2data.dwFlags |= D3DHALDP2_SWAPVERTEXBUFFER | D3DHALDP2_REQVERTEXBUFSIZE;
HRESULT ret = FlushStates();
dp2data.dwFlags &= ~D3DHALDP2_REQVERTEXBUFSIZE;
return ret;
}
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDeviceIDP2::GrowCommandBuffer"
// Check and grow command buffer
HRESULT CDirect3DDeviceIDP2::GrowCommandBuffer(LPDIRECT3DI lpD3DI, DWORD dwSize)
{
HRESULT ret;
if (dwSize > dwDP2CommandBufSize)
{
if (lpDDSCB1)
lpDDSCB1->Release();
// Create command buffer through DirectDraw
DDSURFACEDESC2 ddsd;
memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
ddsd.dwSize = sizeof(DDSURFACEDESC2);
ddsd.dwFlags = DDSD_WIDTH | DDSD_CAPS;
ddsd.dwWidth = dwSize;
ddsd.ddsCaps.dwCaps = DDSCAPS_EXECUTEBUFFER;
if (IS_HW_DEVICE(this))
ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
else
ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
ddsd.ddsCaps.dwCaps2 = DDSCAPS2_COMMANDBUFFER;
// Try explicit video memory first
D3D_INFO(7, "Trying to create a vid mem command buffer");
ret = lpD3DI->lpDD4->CreateSurface(&ddsd, &lpDDSCB1, NULL);
if (ret != DD_OK)
{
// If that failed, try explicit system memory
ddsd.ddsCaps.dwCaps &= ~DDSCAPS_VIDEOMEMORY;
ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
D3D_INFO(7, "Trying to create a sys mem command buffer");
ret = lpD3DI->lpDD4->CreateSurface(&ddsd, &lpDDSCB1, NULL);
if (ret != DD_OK)
{
D3D_ERR("failed to allocate Command Buffer 1");
return ret;
}
}
// Lock command buffer
ret = lpDDSCB1->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL);
if (ret != DD_OK)
{
D3D_ERR("Could not lock command buffer.");
return ret;
}
// update command buffer pointer
lpvDP2Commands = ddsd.lpSurface;
dp2data.lpDDCommands = ((LPDDRAWI_DDRAWSURFACE_INT)lpDDSCB1)->lpLcl;
dwDP2CommandBufSize = dwSize;
}
return D3D_OK;
}
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDeviceIDP2::Init"
HRESULT CDirect3DDeviceIDP2::Init(REFCLSID riid, LPDIRECT3DI lpD3DI, LPDIRECTDRAWSURFACE lpDDS,
IUnknown* pUnkOuter, LPUNKNOWN* lplpD3DDevice, DWORD dwVersion)
{
dwDP2CommandBufSize = 0;
dwDP2Flags =0;
lpDDSCB1 = NULL;
lpvDP2Commands = NULL;
// We do this early in case of DP2 since GrowCommandBuffer depends on this check
if (IsEqualIID(riid, IID_IDirect3DHALDevice))
{
this->dwFEFlags |= D3DFE_REALHAL;
}
HRESULT ret = GrowCommandBuffer(lpD3DI, dwD3DDefaultCommandBatchSize);
if (ret != D3D_OK)
return ret;
// Fill the dp2data structure with initial values
dp2data.dwFlags = D3DHALDP2_SWAPCOMMANDBUFFER;
dp2data.dwVertexType = D3DFVF_TLVERTEX; // Initial assumption
dp2data.dwVertexSize = sizeof(D3DTLVERTEX); // Initial assumption
ClearBatch();
// Initialize the DDI independent part of the device
ret = DIRECT3DDEVICEI::Init(riid, lpD3DI, lpDDS, pUnkOuter, lplpD3DDevice, dwVersion);
if (ret != D3D_OK)
{
return ret;
}
lpDP2CurrBatchVBI = TLVbuf.GetVBI();
lpDP2CurrBatchVBI->AddRef();
dp2data.lpDDVertex = ((LPDDRAWI_DDRAWSURFACE_INT)(lpDP2CurrBatchVBI->GetDDS()))->lpLcl;
return ret;
}
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDeviceIDP2::~CDirect3DDeviceIDP2"
CDirect3DDeviceIDP2::~CDirect3DDeviceIDP2()
{
DestroyDevice();
if (lpDDSCB1)
lpDDSCB1->Release();
if (lpDP2CurrBatchVBI)
lpDP2CurrBatchVBI->Release();
}
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDeviceIDP2::SetRenderStateI"
HRESULT D3DAPI CDirect3DDeviceIDP2::SetRenderStateI(D3DRENDERSTATETYPE dwStateType,
DWORD value)
{
HRESULT ret = D3D_OK;
if (bDP2CurrCmdOP == D3DDP2OP_RENDERSTATE)
{ // Last instruction is a renderstate, append this one to it
if (dwDP2CommandLength + sizeof(D3DHAL_DP2RENDERSTATE) <= dwDP2CommandBufSize)
{
LPD3DHAL_DP2RENDERSTATE lpRState = (LPD3DHAL_DP2RENDERSTATE)((LPBYTE)lpvDP2Commands +
dwDP2CommandLength + dp2data.dwCommandOffset);
lpDP2CurrCommand->wStateCount = ++wDP2CurrCmdCnt;
lpRState->RenderState = dwStateType;
lpRState->dwState = value;
dwDP2CommandLength += sizeof(D3DHAL_DP2RENDERSTATE);
D3D_INFO(6, "Modify Ins:%08lx", *(LPDWORD)lpDP2CurrCommand);
return ret;
}
}
// Check for space
if (dwDP2CommandLength + sizeof(D3DHAL_DP2COMMAND) +
sizeof(D3DHAL_DP2RENDERSTATE) > dwDP2CommandBufSize)
{
ret = FlushStates();
// Since we ran out of space, we were not able to put (dwStateType, value)
// into the batch so rstates will reflect only the last batched
// renderstate (since the driver updates rstates from the batch).
// To fix this, we simply put the current (dwStateType, value) into rstates.
this->rstates[dwStateType]=value;
if (ret != D3D_OK)
{
D3D_ERR("Error trying to render batched commands in SetRenderStateI");
return ret;
}
}
// Add new renderstate instruction
lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands +
dwDP2CommandLength + dp2data.dwCommandOffset);
lpDP2CurrCommand->bCommand = D3DDP2OP_RENDERSTATE;
bDP2CurrCmdOP = D3DDP2OP_RENDERSTATE;
lpDP2CurrCommand->bReserved = 0;
lpDP2CurrCommand->wStateCount = 1;
wDP2CurrCmdCnt = 1;
D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand);
// Add renderstate data
LPD3DHAL_DP2RENDERSTATE lpRState = (LPD3DHAL_DP2RENDERSTATE)(lpDP2CurrCommand + 1);
lpRState->RenderState = dwStateType;
lpRState->dwState = value;
dwDP2CommandLength += sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2RENDERSTATE);
return ret;
}
// Map D3DPRIMITIVETYPE to D3DHAL_DP2OPERATION
const iprim2cmdop[] = {
0, // Invalid
0, // Points are invalid too
D3DDP2OP_INDEXEDLINELIST2,
D3DDP2OP_INDEXEDLINESTRIP,
D3DDP2OP_INDEXEDTRIANGLELIST2,
D3DDP2OP_INDEXEDTRIANGLESTRIP,
D3DDP2OP_INDEXEDTRIANGLEFAN
};
// Map D3DPRIMITIVETYPE to D3DHAL_DP2OPERATION (Execute buffer case)
// Only triangle lists and line lists are valid
const iprim2cmdopEx[] = {
0,
0,
D3DDP2OP_INDEXEDLINELIST,
0,
D3DDP2OP_INDEXEDTRIANGLELIST,
0,
0
};
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDeviceIDP2::DrawIndexPrim"
//---------------------------------------------------------------------
//
// The vertices are already in the vertex buffer.
//
HRESULT CDirect3DDeviceIDP2::DrawIndexPrim()
{
HRESULT ret = D3D_OK;
DWORD dwByteCount; // Command length plus indices
DWORD dwIndicesByteCount; // Indices only
if(this->dwFEFlags & D3DFE_NEED_TEXTURE_UPDATE)
{
UpdateTextures();
this->dwFEFlags &= ~D3DFE_NEED_TEXTURE_UPDATE;
}
if (this->dwFlags & D3DPV_INSIDEEXECUTE)
{
if (this->primType == D3DPT_TRIANGLELIST)
// Edge flags WORD presents in every triangle
dwIndicesByteCount = sizeof(WORD) * this->dwNumPrimitives * 4;
else
// This is Line List
dwIndicesByteCount = sizeof(WORD) * this->dwNumIndices;
dwByteCount = dwIndicesByteCount + sizeof(D3DHAL_DP2COMMAND);
}
else
{
dwIndicesByteCount = sizeof(WORD) * this->dwNumIndices;
dwByteCount = dwIndicesByteCount + sizeof(D3DHAL_DP2COMMAND) +
sizeof(D3DHAL_DP2STARTVERTEX);
}
if (dwDP2CommandLength + dwByteCount > dwDP2CommandBufSize)
{
// Request the driver to grow the command buffer upon flush
dp2data.dwReqCommandBufSize = dwByteCount;
dp2data.dwFlags |= D3DHALDP2_REQCOMMANDBUFSIZE;
ret = FlushStates();
dp2data.dwFlags &= ~D3DHALDP2_REQCOMMANDBUFSIZE;
if (ret != D3D_OK)
return ret;
// Check if the driver did give us what we need or do it ourselves
ret = GrowCommandBuffer(this->lpDirect3DI, dwByteCount);
if (ret != D3D_OK)
{
D3D_ERR("Could not grow Command Buffer");
return ret;
}
}
// Insert indexed primitive instruction
LPD3DHAL_DP2COMMAND lpDP2CurrCommand;
lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands +
dwDP2CommandLength + dp2data.dwCommandOffset);
lpDP2CurrCommand->bReserved = 0;
lpDP2CurrCommand->wPrimitiveCount = (WORD)this->dwNumPrimitives;
LPBYTE pIndices = (BYTE*)(lpDP2CurrCommand + 1); // Place for indices
if (!(this->dwFlags & D3DPV_INSIDEEXECUTE))
{
lpDP2CurrCommand->bCommand = (BYTE)iprim2cmdop[this->primType];
((LPD3DHAL_DP2STARTVERTEX)(lpDP2CurrCommand+1))->wVStart =
(WORD)this->dwVertexBase;
pIndices += sizeof(D3DHAL_DP2STARTVERTEX);
}
else
{
// If we are inside Execute, the indexed triangle and line lists
// do not have wVStart inside the command
lpDP2CurrCommand->bCommand = (BYTE)iprim2cmdopEx[this->primType];
}
D3D_INFO(6, "Write Ins :%08lx @ %08lx", *(LPDWORD)lpDP2CurrCommand,lpDP2CurrCommand);
D3D_INFO(6, "Vertex Base: %08lx", this->dwVertexBase);
#if DBG
if (lpDP2CurrCommand->bCommand == 0)
{
D3D_ERR("Illegal primitive type");
return DDERR_GENERIC;
}
#endif
bDP2CurrCmdOP = lpDP2CurrCommand->bCommand;
memcpy(pIndices, this->lpwIndices, dwIndicesByteCount);
wDP2CurrCmdCnt = lpDP2CurrCommand->wPrimitiveCount;
dwDP2CommandLength += dwByteCount;
// We have batched some stuff, so we could be within a primitive
// Unless the higher functions clear this flag we need to assume
// we are mid-primitive during our flushes.
this->dwFlags |= D3DPV_WITHINPRIMITIVE;
return ret;
}
// Map D3DPRIMITIVETYPE to D3DHAL_DP2OPERATION
const prim2cmdop[] = {
0, // Invalid
D3DDP2OP_POINTS,
D3DDP2OP_LINELIST,
D3DDP2OP_LINESTRIP,
D3DDP2OP_TRIANGLELIST,
D3DDP2OP_TRIANGLESTRIP,
D3DDP2OP_TRIANGLEFAN
};
// Map D3DPRIMITIVETYPE to bytes needed in command stream
const prim2cmdsz[] = {
0, // Invalid
sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2POINTS),
sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2LINELIST),
sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2LINESTRIP),
sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2TRIANGLELIST),
sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2TRIANGLESTRIP),
sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2TRIANGLEFAN)
};
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDeviceIDP2::DrawPrim"
HRESULT CDirect3DDeviceIDP2::DrawPrim()
{
HRESULT ret = D3D_OK;
DWORD dwVertexPoolSize = this->dwNumVertices * this->dwOutputSize;
if(this->dwFEFlags & D3DFE_NEED_TEXTURE_UPDATE)
{
UpdateTextures();
this->dwFEFlags &= ~D3DFE_NEED_TEXTURE_UPDATE;
}
// This primitive is generated by the clipper.
// The vertices of this primitive are pointed to by the
// lpvOut member, which need to be copied into the
// command stream immediately after the command itself.
if (this->dwFlags & D3DPV_CLIPPERPRIM)
{
DWORD dwExtra = 0;
LPVOID lpvVerticesImm; // Place for vertices
if (this->primType == D3DPT_TRIANGLEFAN)
{
if (rstates[D3DRENDERSTATE_FILLMODE] == D3DFILL_WIREFRAME &&
this->dwFlags & D3DPV_NONCLIPPED)
{
// For unclipped (but pretended to be clipped) tri fans in
// wireframe mode we generate 3-vertex tri fans to enable drawing of
// interior edges
BYTE vertices[__MAX_VERTEX_SIZE*3];
BYTE *pV1 = vertices + this->dwOutputSize;
BYTE *pV2 = pV1 + this->dwOutputSize;
BYTE *pInput = (BYTE*)this->lpvOut;
memcpy(vertices, pInput, this->dwOutputSize);
pInput += this->dwOutputSize;
const DWORD nTriangles = this->dwNumVertices - 2;
this->dwNumVertices = 3;
this->dwNumPrimitives = 1;
this->lpvOut = vertices;
this->dwFlags &= ~D3DPV_NONCLIPPED; // Remove this flag for recursive call
for (DWORD i = nTriangles; i; i--)
{
memcpy(pV1, pInput, this->dwOutputSize);
memcpy(pV2, pInput+this->dwOutputSize, this->dwOutputSize);
pInput += this->dwOutputSize;
// To enable all edge flag we set the fill mode to SOLID.
// This will prevent checking the clip flags in the clipper state.
rstates[D3DRENDERSTATE_FILLMODE] = D3DFILL_SOLID;
ret = DrawPrim();
rstates[D3DRENDERSTATE_FILLMODE] = D3DFILL_WIREFRAME;
if (ret != D3D_OK)
return ret;
}
return D3D_OK;
}
dwExtra = sizeof(D3DHAL_DP2TRIANGLEFAN_IMM);
}
DWORD dwPad = (sizeof(D3DHAL_DP2COMMAND) + dwDP2CommandLength + dwExtra) & 3;
DWORD dwByteCount = sizeof(D3DHAL_DP2COMMAND) + dwPad + dwExtra + dwVertexPoolSize;
// Check for space in the command buffer for commands & vertices
if (dwDP2CommandLength + dwByteCount > dwDP2CommandBufSize)
{
// Flush the current batch but hold on to the vertices
ret = FlushStates();
if (ret != D3D_OK)
return ret;
if (dwByteCount > dwDP2CommandBufSize)
{
ret = GrowCommandBuffer(this->lpDirect3DI, dwByteCount);
if (ret != D3D_OK)
{
D3D_ERR("Could not grow Command Buffer");
return ret;
}
}
dwPad = (sizeof(D3DHAL_DP2COMMAND) + dwExtra) & 3;
dwByteCount = sizeof(D3DHAL_DP2COMMAND) + dwExtra + dwPad + dwVertexPoolSize;
}
lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands +
dwDP2CommandLength + dp2data.dwCommandOffset);
lpDP2CurrCommand->wPrimitiveCount = (WORD)this->dwNumPrimitives;
lpDP2CurrCommand->bReserved = 0;
if (this->primType == D3DPT_TRIANGLEFAN)
{
// Insert inline instruction and vertices
bDP2CurrCmdOP = D3DDP2OP_TRIANGLEFAN_IMM;
lpDP2CurrCommand->bCommand = bDP2CurrCmdOP;
D3D_INFO(6, "Write Ins :%08lx @ %08lx", *(LPDWORD)lpDP2CurrCommand,lpDP2CurrCommand);
LPD3DHAL_DP2TRIANGLEFAN_IMM lpTriFanImm = (LPD3DHAL_DP2TRIANGLEFAN_IMM)(lpDP2CurrCommand + 1);
if (rstates[D3DRENDERSTATE_FILLMODE] == D3DFILL_WIREFRAME)
{
lpTriFanImm->dwEdgeFlags = 0;
ClipVertex **clip = this->ClipperState.current_vbuf;
// Look at the exterior edges and mark the visible ones
for(DWORD i = 0; i < this->dwNumVertices; ++i)
{
if (clip[i]->clip & CLIPPED_ENABLE)
lpTriFanImm->dwEdgeFlags |= (1 << i);
}
}
else
{
// Mark all exterior edges visible
lpTriFanImm->dwEdgeFlags = 0xFFFFFFFF;
}
lpvVerticesImm = (LPBYTE)(lpTriFanImm + 1) + dwPad;
}
else
{
// Insert inline instruction and vertices
bDP2CurrCmdOP = D3DDP2OP_LINELIST_IMM;
lpDP2CurrCommand->bCommand = bDP2CurrCmdOP;
D3D_INFO(6, "Write Ins :%08lx @ %08lx", *(LPDWORD)lpDP2CurrCommand,lpDP2CurrCommand);
lpvVerticesImm = (LPBYTE)(lpDP2CurrCommand + 1) + dwPad;
}
memcpy(lpvVerticesImm, this->lpvOut, dwVertexPoolSize);
dwDP2CommandLength += dwByteCount;
}
else
{
// Check for space in the command buffer for new command.
// The vertices are already in the vertex buffer.
if (dwDP2CommandLength + prim2cmdsz[this->primType] > dwDP2CommandBufSize)
{
ret = FlushStates();
if (ret != D3D_OK)
return ret;
}
// Insert non indexed primitive instruction
lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands +
dwDP2CommandLength + dp2data.dwCommandOffset);
bDP2CurrCmdOP = (BYTE)prim2cmdop[this->primType];
lpDP2CurrCommand->bCommand = bDP2CurrCmdOP;
lpDP2CurrCommand->bReserved = 0;
switch(bDP2CurrCmdOP)
{
case D3DDP2OP_POINTS:
{
lpDP2CurrCommand->wPrimitiveCount = 1;
LPD3DHAL_DP2POINTS lpPoints = (LPD3DHAL_DP2POINTS)(lpDP2CurrCommand + 1);
lpPoints->wCount = (WORD)this->dwNumVertices;
lpPoints->wVStart = (WORD)this->dwVertexBase;
D3D_INFO(6, "Write Ins :%08lx @ %08lx", *(LPDWORD)lpDP2CurrCommand,lpDP2CurrCommand);
D3D_INFO(6, "Write Data:%08lx", *(LPDWORD)lpPoints);
}
break;
case D3DDP2OP_LINELIST:
case D3DDP2OP_TRIANGLELIST:
{
lpDP2CurrCommand->wPrimitiveCount = (WORD)this->dwNumPrimitives;
// Linelist and trianglelist are identical
LPD3DHAL_DP2LINELIST lpLines = (LPD3DHAL_DP2LINELIST)(lpDP2CurrCommand + 1);
lpLines->wVStart = (WORD)this->dwVertexBase;
D3D_INFO(6, "Write Ins :%08lx @ %08lx", *(LPDWORD)lpDP2CurrCommand,lpDP2CurrCommand);
D3D_INFO(6, "Write Data:%08lx", (DWORD)lpLines->wVStart);
}
break;
default: // strips or fans
{
lpDP2CurrCommand->wPrimitiveCount = (WORD)this->dwNumPrimitives;
// Linestrip, trianglestrip and trianglefan are identical
LPD3DHAL_DP2LINESTRIP lpStrip = (LPD3DHAL_DP2LINESTRIP)(lpDP2CurrCommand + 1);
lpStrip->wVStart = (WORD)this->dwVertexBase;
D3D_INFO(6, "Write Ins :%08lx @ %08lx", *(LPDWORD)lpDP2CurrCommand,lpDP2CurrCommand);
D3D_INFO(6, "Write Data:%08lx", (DWORD)lpStrip->wVStart);
}
}
wDP2CurrCmdCnt = lpDP2CurrCommand->wPrimitiveCount;
dwDP2CommandLength += prim2cmdsz[this->primType];
}
// We have batched some stuff, so we could be within a primitive
// Unless the higher functions clear this flag we need to assume
// we are mid-primitive during our flushes.
this->dwFlags |= D3DPV_WITHINPRIMITIVE;
return ret;
}
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDeviceIDP2::SetTextureStageState"
HRESULT D3DAPI
CDirect3DDeviceIDP2::SetTextureStageState(DWORD dwStage,
D3DTEXTURESTAGESTATETYPE dwState,
DWORD dwValue)
{
// Holds D3D lock until exit.
CLockD3DMT ldmLock(this, DPF_MODNAME, REMIND(""));
#if DBG
if (dwStage >= D3DHAL_TSS_MAXSTAGES ||
dwState == 0 || dwState >= D3DTSS_MAX)
{
D3D_ERR( "Invalid texture stage or state index" );
return DDERR_INVALIDPARAMS;
}
#endif //DBG
HRESULT hr;
if (this->tsstates[dwStage][dwState] == dwValue)
{
D3D_WARN(4,"Ignoring redundant SetTextureStageState");
return D3D_OK;
}
// Update runtime copy of state.
DWORD dwOldValue = tsstates[dwStage][dwState];
tsstates[dwStage][dwState] = dwValue;
if (dwState == D3DTSS_TEXCOORDINDEX && TextureStageEnabled(this, dwStage) ||
dwState == D3DTSS_COLOROP &&
((dwValue == D3DTOP_DISABLE) == !(dwOldValue == D3DTOP_DISABLE)))
{
this->dwFVFLastIn = 0; // Force to recompute output VID
this->dwFEFlags |= D3DFE_TSSINDEX_DIRTY;
}
if (dwStage >= dwMaxTextureBlendStages) return D3D_OK; // Ignore higher stage states
hr = SetTSSI(dwStage, dwState, dwValue);
return hr;
}
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDeviceIDP2::SetTSSI"
HRESULT CDirect3DDeviceIDP2::SetTSSI(DWORD dwStage, D3DTEXTURESTAGESTATETYPE dwState, DWORD dwValue)
{
HRESULT ret = D3D_OK;
if (bDP2CurrCmdOP == D3DDP2OP_TEXTURESTAGESTATE)
{ // Last instruction is a texture stage state, append this one to it
if (dwDP2CommandLength + sizeof(D3DHAL_DP2TEXTURESTAGESTATE) <= dwDP2CommandBufSize)
{
LPD3DHAL_DP2TEXTURESTAGESTATE lpRState = (LPD3DHAL_DP2TEXTURESTAGESTATE)((LPBYTE)lpvDP2Commands +
dwDP2CommandLength + dp2data.dwCommandOffset);
lpDP2CurrCommand->wStateCount = ++wDP2CurrCmdCnt;
lpRState->wStage = (WORD)dwStage;
lpRState->TSState = (WORD)dwState;
lpRState->dwValue = dwValue;
dwDP2CommandLength += sizeof(D3DHAL_DP2TEXTURESTAGESTATE);
D3D_INFO(6, "Modify Ins:%08lx", *(LPDWORD)lpDP2CurrCommand);
return ret;
}
}
// Check for space
if (dwDP2CommandLength + sizeof(D3DHAL_DP2COMMAND) +
sizeof(D3DHAL_DP2TEXTURESTAGESTATE) > dwDP2CommandBufSize)
{
ret = FlushStates();
if (ret != D3D_OK)
{
D3D_ERR("Error trying to render batched commands in SetTSSI");
return ret;
}
}
// Add new renderstate instruction
lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands +
dwDP2CommandLength + dp2data.dwCommandOffset);
lpDP2CurrCommand->bCommand = D3DDP2OP_TEXTURESTAGESTATE;
bDP2CurrCmdOP = D3DDP2OP_TEXTURESTAGESTATE;
lpDP2CurrCommand->bReserved = 0;
lpDP2CurrCommand->wStateCount = 1;
wDP2CurrCmdCnt = 1;
D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand);
// Add renderstate data
LPD3DHAL_DP2TEXTURESTAGESTATE lpRState = (LPD3DHAL_DP2TEXTURESTAGESTATE)(lpDP2CurrCommand + 1);
lpRState->wStage = (WORD)dwStage;
lpRState->TSState = (WORD)dwState;
lpRState->dwValue = dwValue;
dwDP2CommandLength += sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2TEXTURESTAGESTATE);
return ret;
}
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDeviceIDP2::ValidateDevice"
HRESULT D3DAPI
CDirect3DDeviceIDP2::ValidateDevice(LPDWORD lpdwNumPasses)
{
// Holds D3D lock until exit.
CLockD3DMT ldmLock(this, DPF_MODNAME, REMIND(""));
HRESULT ret;
D3DHAL_VALIDATETEXTURESTAGESTATEDATA vbod;
TRY
{
if (!VALID_DIRECT3DDEVICE3_PTR(this))
{
D3D_ERR( "Invalid Direct3DDevice3 pointer" );
return DDERR_INVALIDOBJECT;
}
if (!VALID_PTR(lpdwNumPasses, sizeof(DWORD)))
{
D3D_ERR( "Invalid lpdwNumPasses pointer" );
return DDERR_INVALIDPARAMS;
}
}
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
{
D3D_ERR( "Exception encountered validating parameters" );
return DDERR_INVALIDPARAMS;
}
// First, Update textures since drivers pass /fail this call based
// on the current texture handles
ret = UpdateTextures();
if (ret != D3D_OK)
{
D3D_ERR("Error trying to update managed textures in ValidateDevice");
return ret;
}
// Second, flush states, so we can validate the current state
ret = FlushStates();
if (ret != D3D_OK)
{
D3D_ERR("Error trying to FlushStates in ValidateDevice");
return ret;
}
// Now ask the driver!
*lpdwNumPasses = 0;
memset(&vbod, 0, sizeof(D3DHAL_VALIDATETEXTURESTAGESTATEDATA));
vbod.dwhContext = this->dwhContext;
if (this->lpD3DHALCallbacks3->ValidateTextureStageState)
{
CALL_HAL3ONLY(ret, this, ValidateTextureStageState, &vbod);
if (ret != DDHAL_DRIVER_HANDLED)
return DDERR_UNSUPPORTED;
*lpdwNumPasses = vbod.dwNumPasses;
return vbod.ddrval;
}
else
{
D3D_ERR("Error: ValidateTextureStageState not supported by the driver.");
}
return DDERR_UNSUPPORTED;
}
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDeviceIDP2::StartPrimVB"
//---------------------------------------------------------------------
// This function prepares the batch for new primitive.
// Called only if vertices from user memory are NOT used for rendering
//
HRESULT CDirect3DDeviceIDP2::StartPrimVB(LPDIRECT3DVERTEXBUFFERI lpVBI,
DWORD dwStartVertex)
{
HRESULT ret = D3D_OK;
// If VID has been changed or new vertex buffer is used we flush the batch
if (this->dwVIDOut != dp2data.dwVertexType ||
lpDP2CurrBatchVBI != lpVBI ||
dp2data.lpDDVertex != ((LPDDRAWI_DDRAWSURFACE_INT)(lpVBI->GetDDS()))->lpLcl)
{
ret = FlushStates();
if (ret != D3D_OK)
return ret;
dp2data.dwVertexType = this->dwVIDOut;
dp2data.dwVertexSize = this->dwOutputSize;
dp2data.lpDDVertex = ((LPDDRAWI_DDRAWSURFACE_INT)(lpVBI->GetDDS()))->lpLcl;
// Release previously used vertex buffer (if any), because we do not
// need it any more. We did AddRef() to TL buffer, so it is safe.
if (lpDP2CurrBatchVBI)
lpDP2CurrBatchVBI->Release();
// If a vertex buffer is used for rendering, make sure that it is not
// released by user. So do AddRef().
lpDP2CurrBatchVBI = lpVBI;
lpDP2CurrBatchVBI->AddRef();
}
if (this->TLVbuf.GetVBI() == lpVBI)
{
this->dwVertexBase = this->dp2data.dwVertexLength;
DDASSERT(this->dwVertexBase < MAX_DX6_VERTICES);
dp2data.dwFlags |= D3DHALDP2_SWAPVERTEXBUFFER;
}
else
{
this->dwVertexBase = dwStartVertex;
dp2data.dwFlags &= ~D3DHALDP2_SWAPVERTEXBUFFER;
}
this->dp2data.dwVertexLength = this->dwVertexBase + this->dwNumVertices;
this->dwFlags |= D3DPV_WITHINPRIMITIVE;
return ret;
}
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDeviceIDP2::StartPrimUserMem"
//---------------------------------------------------------------------
// This function prepares the batch for new primitive.
// Called if vertices from user memory is used for rendering
//
HRESULT CDirect3DDeviceIDP2::StartPrimUserMem(LPVOID lpMem)
{
const DWORD vertexPoolSize = this->dwNumVertices * this->dwOutputSize;
HRESULT ret = D3D_OK;
// If the primitive is small, we copy vertices into the TL buffer
if (this->dwNumVertices < LOWVERTICESNUMBER)
{
if (vertexPoolSize > this->TLVbuf.GetSize())
{
if (this->TLVbuf.Grow(this, vertexPoolSize) != D3D_OK)
{
D3D_ERR( "Could not grow TL vertex buffer" );
ret = DDERR_OUTOFMEMORY;
goto l_exit;
}
}
// So now user memory is not used any more.
ret = StartPrimVB(this->TLVbuf.GetVBI(), 0);
if (ret != D3D_OK)
goto l_exit;
LPVOID tmp = this->TLVbuf.GetAddress();
memcpy(tmp, this->lpvOut, vertexPoolSize);
// We have to update lpvOut, because it was set to user memory
this->lpvOut = tmp;
}
else
{
// We can not mix user memory primitive with other primitives, so
// flush the batch.
// Do not forget to flush the batch after rendering this primitive
ret = this->FlushStates();
if (ret != D3D_OK)
goto l_exit;
// Release previously used vertex buffer (if any), because we do not
// it any more
if (lpDP2CurrBatchVBI)
{
lpDP2CurrBatchVBI->Release();
lpDP2CurrBatchVBI = NULL;
}
dp2data.dwVertexType = this->dwVIDOut;
dp2data.dwVertexSize = this->dwOutputSize;
dp2data.lpVertices = lpMem;
dp2data.dwFlags |= D3DHALDP2_USERMEMVERTICES;
dp2data.dwFlags &= ~D3DHALDP2_SWAPVERTEXBUFFER;
dp2data.dwVertexLength = this->dwNumVertices;
this->dwFlags |= D3DPV_USERMEMVERTICES;
}
l_exit:
this->dwFlags |= D3DPV_WITHINPRIMITIVE;
return ret;
}
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDeviceIDP2::EndPrim"
//---------------------------------------------------------------------
// This function should not be called from DrawVertexBufferVB
//
HRESULT CDirect3DDeviceIDP2::EndPrim(DWORD dwVertexPoolSize)
{
HRESULT ret = D3D_OK;
if (this->dwFlags & D3DPV_USERMEMVERTICES)
// We can not mix user memory primitive, so flush it.
ret = this->FlushStates();
else
{
// If TL buffer was used, we have to move its internal base pointer
this->TLVbuf.Base() += dwVertexPoolSize;
}
this->dwFlags &= ~(D3DPV_USERMEMVERTICES | D3DPV_WITHINPRIMITIVE);
return ret;
}
//---------------------------------------------------------------------
//
//
HRESULT CDirect3DDeviceIDP2::UpdateDrvViewInfo(LPD3DVIEWPORT2 lpVwpData)
{
HRESULT ret = D3D_OK;
// Check to see if there is space to add a new command for space
if (dwDP2CommandLength + sizeof(D3DHAL_DP2COMMAND) +
sizeof(D3DHAL_DP2VIEWPORTINFO) > dwDP2CommandBufSize)
{
ret = FlushStates();
if (ret != D3D_OK)
{
D3D_ERR("Error trying to render batched commands in UpdateDrvViewInfo");
return ret;
}
}
// Add new ViewInfo instruction
lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands +
dwDP2CommandLength + dp2data.dwCommandOffset);
lpDP2CurrCommand->bCommand = D3DDP2OP_VIEWPORTINFO;
bDP2CurrCmdOP = D3DDP2OP_VIEWPORTINFO;
lpDP2CurrCommand->bReserved = 0;
lpDP2CurrCommand->wStateCount = 1;
wDP2CurrCmdCnt = 1;
D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand);
// Add ViewInfo data
LPD3DHAL_DP2VIEWPORTINFO lpVpInfo = (LPD3DHAL_DP2VIEWPORTINFO)(lpDP2CurrCommand + 1);
lpVpInfo->dwX = lpVwpData->dwX;
lpVpInfo->dwY = lpVwpData->dwY;
lpVpInfo->dwWidth = lpVwpData->dwWidth;
lpVpInfo->dwHeight = lpVwpData->dwHeight;
dwDP2CommandLength += sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2VIEWPORTINFO);
return ret;
}
//---------------------------------------------------------------------
//
//
HRESULT CDirect3DDeviceIDP2::UpdateDrvWInfo()
{
HRESULT ret = D3D_OK;
// Check to see if there is space to add a new command for space
if (dwDP2CommandLength + sizeof(D3DHAL_DP2COMMAND) +
sizeof(D3DHAL_DP2WINFO) > dwDP2CommandBufSize)
{
ret = FlushStates();
if (ret != D3D_OK)
{
D3D_ERR("Error trying to render batched commands in UpdateDrvViewInfo");
return ret;
}
}
// Add new WInfo instruction
lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands +
dwDP2CommandLength + dp2data.dwCommandOffset);
lpDP2CurrCommand->bCommand = D3DDP2OP_WINFO;
bDP2CurrCmdOP = D3DDP2OP_WINFO;
lpDP2CurrCommand->bReserved = 0;
lpDP2CurrCommand->wStateCount = 1;
wDP2CurrCmdCnt = 1;
D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand);
// Add WInfo data
D3DMATRIXI &m = transform.proj;
LPD3DHAL_DP2WINFO lpWInfo = (LPD3DHAL_DP2WINFO)(lpDP2CurrCommand + 1);
if( (m._33 == m._34) || (m._33 == 0.0f) )
{
D3D_ERR( "Cannot compute WNear and WFar from the supplied projection matrix.\n Setting wNear to 0.0 and wFar to 1.0" );
lpWInfo->dvWNear = 0.0f;
lpWInfo->dvWFar = 1.0f;
dwDP2CommandLength += sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2WINFO);
return ret;
}
lpWInfo->dvWNear = m._44 - m._43/m._33*m._34;
lpWInfo->dvWFar = (m._44 - m._43)/(m._33 - m._34)*m._34 + m._44;
dwDP2CommandLength += sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2WINFO);
return ret;
}
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDeviceIDP2::UpdatePalette"
//---------------------------------------------------------------------
// This function should be called from PaletteUpdateNotify
//
HRESULT CDirect3DDeviceIDP2::UpdatePalette(
DWORD dwPaletteHandle,
DWORD dwStartIndex,
DWORD dwNumberOfIndices,
LPPALETTEENTRY pFirstIndex)
{
HRESULT ret = D3D_OK;
DWORD dwSizeChange=sizeof(D3DHAL_DP2COMMAND) +
sizeof(D3DHAL_DP2UPDATEPALETTE) + dwNumberOfIndices*sizeof(PALETTEENTRY);
if (bDP2CurrCmdOP == D3DDP2OP_UPDATEPALETTE)
{ // Last instruction is a tex blt, append this one to it
}
// Check for space
if (dwDP2CommandLength + dwSizeChange > dwDP2CommandBufSize)
{
ret = FlushStates();
if (ret != D3D_OK)
{
D3D_ERR("Error trying to render batched commands in TexBltI");
return ret;
}
}
// Add new renderstate instruction
lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands +
dwDP2CommandLength + dp2data.dwCommandOffset);
lpDP2CurrCommand->bCommand = D3DDP2OP_UPDATEPALETTE;
bDP2CurrCmdOP = D3DDP2OP_UPDATEPALETTE;
lpDP2CurrCommand->bReserved = 0;
lpDP2CurrCommand->wStateCount = 1;
wDP2CurrCmdCnt = 1;
D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand);
// Add texture blt data
LPD3DHAL_DP2UPDATEPALETTE lpUpdatePal = (LPD3DHAL_DP2UPDATEPALETTE)(lpDP2CurrCommand + 1);
lpUpdatePal->dwPaletteHandle=dwPaletteHandle;
lpUpdatePal->wStartIndex=(WORD)dwStartIndex;
lpUpdatePal->wNumEntries=(WORD)dwNumberOfIndices;
memcpy((LPVOID)(lpUpdatePal+1),(LPVOID)pFirstIndex,
dwNumberOfIndices*sizeof(PALETTEENTRY));
dwDP2CommandLength += dwSizeChange;
return ret;
}
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDeviceIDP2::SetPalette"
//---------------------------------------------------------------------
// This function should be called from PaletteAssociateNotify
//
HRESULT CDirect3DDeviceIDP2::SetPalette(DWORD dwPaletteHandle, DWORD dwPaletteFlags, DWORD dwSurfaceHandle )
{
HRESULT ret = D3D_OK;
DWORD dwSizeChange;
if (bDP2CurrCmdOP == D3DDP2OP_SETPALETTE)
{ // Last instruction is a tex blt, append this one to it
}
dwSizeChange=sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2SETPALETTE);
// Check for space
if (dwDP2CommandLength + dwSizeChange > dwDP2CommandBufSize)
{
ret = FlushStates();
if (ret != D3D_OK)
{
D3D_ERR("Error trying to render batched commands in TexBltI");
return ret;
}
}
// Add new renderstate instruction
lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands +
dwDP2CommandLength + dp2data.dwCommandOffset);
bDP2CurrCmdOP = lpDP2CurrCommand->bCommand = D3DDP2OP_SETPALETTE;
lpDP2CurrCommand->bReserved = 0;
lpDP2CurrCommand->wStateCount = 1;
wDP2CurrCmdCnt = 1;
D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand);
LPD3DHAL_DP2SETPALETTE lpSetPal = (LPD3DHAL_DP2SETPALETTE)(lpDP2CurrCommand + 1);
lpSetPal->dwPaletteHandle=dwPaletteHandle;
lpSetPal->dwPaletteFlags=dwPaletteFlags;
lpSetPal->dwSurfaceHandle=dwSurfaceHandle;
dwDP2CommandLength += dwSizeChange;
return ret;
}
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDeviceIDP2::SetRenderTargetI"
void CDirect3DDeviceIDP2::SetRenderTargetI(LPDIRECTDRAWSURFACE pRenderTarget, LPDIRECTDRAWSURFACE pZBuffer)
{
DWORD dwSizeChange;
dwSizeChange=sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2SETRENDERTARGET);
// Check for space
if (dwDP2CommandLength + dwSizeChange > dwDP2CommandBufSize)
{
if (FlushStates() != D3D_OK)
{
D3D_ERR("Error trying to render batched commands in SetRenderTargetI");
return;
}
}
// Add new renderstate instruction
lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands +
dwDP2CommandLength + dp2data.dwCommandOffset);
bDP2CurrCmdOP = lpDP2CurrCommand->bCommand = D3DDP2OP_SETRENDERTARGET;
lpDP2CurrCommand->bReserved = 0;
lpDP2CurrCommand->wStateCount = 1;
wDP2CurrCmdCnt = 1;
D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand);
LPD3DHAL_DP2SETRENDERTARGET pData = (LPD3DHAL_DP2SETRENDERTARGET)(lpDP2CurrCommand + 1);
pData->hRenderTarget = ((LPDDRAWI_DDRAWSURFACE_INT)pRenderTarget)->lpLcl->lpSurfMore->dwSurfaceHandle;
if (pZBuffer)
pData->hZBuffer = ((LPDDRAWI_DDRAWSURFACE_INT)pZBuffer)->lpLcl->lpSurfMore->dwSurfaceHandle;
else
pData->hZBuffer = 0;
dwDP2CommandLength += dwSizeChange;
}
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDeviceIDP2::ClearI"
void CDirect3DDeviceIDP2::ClearI(DWORD dwFlags, DWORD clrCount, LPD3DRECT clrRects, D3DCOLOR dwColor, D3DVALUE dvZ, DWORD dwStencil)
{
DWORD dwCommandSize = sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2CLEAR) + sizeof(RECT) * (clrCount - 1);
// Check to see if there is space to add a new command for space
if (dwCommandSize + dwDP2CommandLength > dwDP2CommandBufSize)
{
HRESULT ret = FlushStates();
if (ret != D3D_OK)
{
D3D_ERR("Error trying to render batched commands");
throw ret;
}
}
lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands +
dwDP2CommandLength + dp2data.dwCommandOffset);
lpDP2CurrCommand->bCommand = D3DDP2OP_CLEAR;
bDP2CurrCmdOP = D3DDP2OP_CLEAR;
lpDP2CurrCommand->bReserved = 0;
wDP2CurrCmdCnt = (WORD)clrCount;
lpDP2CurrCommand->wStateCount = wDP2CurrCmdCnt;
D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand);
dwDP2CommandLength += dwCommandSize;
// Write data
LPD3DHAL_DP2CLEAR pData = (LPD3DHAL_DP2CLEAR)(lpDP2CurrCommand + 1);
pData->dwFlags = dwFlags;
pData->dwFillColor = dwColor;
pData->dvFillDepth = dvZ;
pData->dwFillStencil = dwStencil;
memcpy(pData->Rects, clrRects, clrCount * sizeof(D3DRECT));
}