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
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));
|
|
}
|