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.
529 lines
17 KiB
529 lines
17 KiB
//----------------------------------------------------------------------------
|
|
//
|
|
// testprov.cpp
|
|
//
|
|
// Test HAL provider class.
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1997.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
#include "pch.cpp"
|
|
#pragma hdrstop
|
|
|
|
//#ifdef DEBUG_PIPELINE
|
|
|
|
#include "testprov.h"
|
|
#include "testfile.h"
|
|
#include "stdio.h"
|
|
|
|
// Real rasterizer data
|
|
static D3DHALPROVIDER_INTERFACEDATA CurInterfaceData;
|
|
static IHalProvider *pCurHalProvider; // Real HAL provider
|
|
|
|
// Test provider data
|
|
static CTestHalProvider g_TestHalProvider;
|
|
static D3DHALPROVIDER_INTERFACEDATA TestInterfaceData;
|
|
static D3DHAL_CALLBACKS TestCallbacks;
|
|
static D3DHAL_CALLBACKS2 TestCallbacks2;
|
|
static D3DHAL_CALLBACKS3 TestCallbacks3;
|
|
static char szFileName[_MAX_PATH] = ""; // Output file name
|
|
static FILE *fout = NULL; // Output file
|
|
DWORD g_dwTestHalFlags = 0; // Could be set from debugger
|
|
|
|
// Bits for g_dwTestHalFlags
|
|
const DWORD __TESTHAL_OUTPUTFILE = 1; // If need output to test file
|
|
const DWORD __TESTHAL_NORENDER = 2; // If no rendering needed
|
|
|
|
//---------------------------------------------------------------------
|
|
// Provides access to DIRECTDRAWSURFACE memory;
|
|
// In the constructor the surface is locked.
|
|
// In the destructor it is unlocked.
|
|
// LPBYTE() or LPVOID() casts will get pointer to the surface bits.
|
|
//
|
|
class CLockedDDSurface
|
|
{
|
|
public:
|
|
CLockedDDSurface(LPDIRECTDRAWSURFACE surface);
|
|
~CLockedDDSurface();
|
|
operator LPVOID() {return descr.lpSurface;}
|
|
operator LPBYTE() {return (LPBYTE)descr.lpSurface;}
|
|
protected:
|
|
DDSURFACEDESC descr;
|
|
LPDIRECTDRAWSURFACE pSurface;
|
|
};
|
|
|
|
CLockedDDSurface::CLockedDDSurface(LPDIRECTDRAWSURFACE surface)
|
|
{
|
|
pSurface = surface;
|
|
memset (&descr, 0, sizeof(descr));
|
|
descr.dwSize = sizeof(descr);
|
|
surface->Lock(NULL, &descr, 0, NULL);
|
|
}
|
|
|
|
CLockedDDSurface::~CLockedDDSurface()
|
|
{
|
|
if (descr.lpSurface)
|
|
pSurface->Unlock(descr.lpSurface);
|
|
}
|
|
//---------------------------------------------------------------------
|
|
void PutHeader(DWORD id, DWORD size)
|
|
{
|
|
if (fout)
|
|
{
|
|
fwrite(&id, sizeof(DWORD), 1, fout);
|
|
fwrite(&size, sizeof(DWORD), 1, fout);
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------
|
|
DWORD GetCurrentPosition()
|
|
{
|
|
if (fout)
|
|
return ftell(fout);
|
|
else
|
|
return 0;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
void SetCurrentPosition(DWORD offset)
|
|
{
|
|
if (fout)
|
|
fseek(fout, offset, SEEK_SET);
|
|
}
|
|
//---------------------------------------------------------------------
|
|
void PutBuffer(LPVOID buffer, DWORD size)
|
|
{
|
|
if (fout)
|
|
{
|
|
fwrite(buffer, 1, size, fout);
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------
|
|
// Implementation of test callbacks
|
|
//
|
|
DWORD __stdcall
|
|
TestDrawOnePrimitive(LPD3DHAL_DRAWONEPRIMITIVEDATA data)
|
|
{
|
|
if (g_dwTestHalFlags & __TESTHAL_OUTPUTFILE)
|
|
{
|
|
TFREC_DRAWONEPRIMITIVE rec;
|
|
PutHeader(TFID_DRAWONEPRIMITIVE,
|
|
sizeof(rec) + data->dwNumVertices*sizeof(D3DTLVERTEX));
|
|
rec.primitiveType = data->PrimitiveType;
|
|
rec.vertexCount = data->dwNumVertices;
|
|
rec.vertexType = data->VertexType;
|
|
rec.dwFlags = data->dwFlags;
|
|
PutBuffer(&rec, sizeof(rec));
|
|
PutBuffer(data->lpvVertices, sizeof(D3DTLVERTEX)*data->dwNumVertices);
|
|
}
|
|
|
|
if (CurInterfaceData.pCallbacks2->DrawOnePrimitive &&
|
|
!(g_dwTestHalFlags & __TESTHAL_NORENDER))
|
|
return CurInterfaceData.pCallbacks2->DrawOnePrimitive(data);
|
|
else
|
|
return DDHAL_DRIVER_HANDLED;
|
|
}
|
|
|
|
DWORD __stdcall
|
|
TestDrawOneIndexedPrimitive(LPD3DHAL_DRAWONEINDEXEDPRIMITIVEDATA data)
|
|
{
|
|
if (g_dwTestHalFlags & __TESTHAL_OUTPUTFILE)
|
|
{
|
|
TFREC_DRAWONEINDEXEDPRIMITIVE rec;
|
|
PutHeader(TFID_DRAWONEINDEXEDPRIMITIVE,
|
|
sizeof(rec) +
|
|
data->dwNumVertices*sizeof(D3DTLVERTEX) +
|
|
data->dwNumIndices*sizeof(WORD));
|
|
rec.primitiveType = data->PrimitiveType;
|
|
rec.vertexCount = data->dwNumVertices;
|
|
rec.vertexType = data->VertexType;
|
|
rec.dwFlags = data->dwFlags;
|
|
rec.indexCount = data->dwNumIndices;
|
|
PutBuffer(&rec, sizeof(rec));
|
|
PutBuffer(data->lpvVertices, sizeof(D3DTLVERTEX)*data->dwNumVertices);
|
|
PutBuffer(data->lpwIndices, sizeof(WORD)*data->dwNumIndices);
|
|
}
|
|
|
|
if (CurInterfaceData.pCallbacks2->DrawOneIndexedPrimitive &&
|
|
!(g_dwTestHalFlags & __TESTHAL_NORENDER))
|
|
return CurInterfaceData.pCallbacks2->DrawOneIndexedPrimitive(data);
|
|
else
|
|
return DDHAL_DRIVER_HANDLED;
|
|
}
|
|
|
|
DWORD __stdcall
|
|
TestDrawPrimitives(LPD3DHAL_DRAWPRIMITIVESDATA data)
|
|
{
|
|
if (g_dwTestHalFlags & __TESTHAL_OUTPUTFILE)
|
|
{
|
|
DWORD endPos = 0;
|
|
LPVOID header = data->lpvData;
|
|
PutHeader(0,0); // Dummy header. Will be filled later
|
|
DWORD startPos = GetCurrentPosition();
|
|
for (;;)
|
|
{
|
|
DWORD nStates = ((D3DHAL_DRAWPRIMCOUNTS*)header)->wNumStateChanges;
|
|
DWORD nVertices = ((D3DHAL_DRAWPRIMCOUNTS*)header)->wNumVertices;
|
|
DWORD size;
|
|
// Primitive header
|
|
PutBuffer(header, sizeof(D3DHAL_DRAWPRIMCOUNTS));
|
|
header = (char*)header + sizeof(D3DHAL_DRAWPRIMCOUNTS);
|
|
// States
|
|
size = nStates * sizeof(WORD);
|
|
PutBuffer(header, size);
|
|
header = (char*)header + size;
|
|
header = (LPVOID)(((ULONG_PTR)header + 31) & ~31); //32 bytes aligned
|
|
// Vertices
|
|
if (!nVertices)
|
|
break;
|
|
size = nVertices * sizeof(D3DTLVERTEX);
|
|
PutBuffer(header, size);
|
|
|
|
}
|
|
// Write record header
|
|
endPos = GetCurrentPosition();
|
|
SetCurrentPosition(startPos - sizeof(TF_HEADER));
|
|
PutHeader(TFID_DRAWPRIMITIVES, endPos - startPos);
|
|
SetCurrentPosition(endPos);
|
|
}
|
|
|
|
if (CurInterfaceData.pCallbacks2->DrawPrimitives &&
|
|
!(g_dwTestHalFlags & __TESTHAL_NORENDER))
|
|
return CurInterfaceData.pCallbacks2->DrawPrimitives(data);
|
|
else
|
|
return DDHAL_DRIVER_HANDLED;
|
|
}
|
|
|
|
DWORD __stdcall
|
|
TestDrawPrimitives2(LPD3DHAL_DRAWPRIMITIVES2DATA data)
|
|
{
|
|
if (g_dwTestHalFlags & __TESTHAL_OUTPUTFILE)
|
|
{
|
|
TFREC_DRAWPRIMITIVES2 rec;
|
|
rec.dwFlags = 0;
|
|
PutBuffer(&rec, sizeof(rec));
|
|
PutHeader(TFID_DRAWPRIMITIVES, sizeof(rec));
|
|
}
|
|
|
|
if (CurInterfaceData.pCallbacks3->DrawPrimitives2 &&
|
|
!(g_dwTestHalFlags & __TESTHAL_NORENDER))
|
|
return CurInterfaceData.pCallbacks3->DrawPrimitives2(data);
|
|
else
|
|
return DDHAL_DRIVER_HANDLED;
|
|
}
|
|
|
|
DWORD __stdcall
|
|
TestRenderState(LPD3DHAL_RENDERSTATEDATA data)
|
|
{
|
|
if (g_dwTestHalFlags & __TESTHAL_OUTPUTFILE)
|
|
{
|
|
// mem should be destroyed before calling to real driver to unlock
|
|
// the surface
|
|
CLockedDDSurface mem(data->lpExeBuf);
|
|
LPD3DSTATE pState;
|
|
pState = (LPD3DSTATE)(LPBYTE(mem) + data->dwOffset);
|
|
PutHeader(TFID_RENDERSTATE, sizeof(DWORD) + data->dwCount*sizeof(D3DSTATE));
|
|
PutBuffer(&data->dwCount, sizeof(DWORD));
|
|
for (DWORD i = 0; i < data->dwCount; i++)
|
|
{
|
|
PutBuffer(&pState, sizeof(D3DSTATE));
|
|
pState++;
|
|
}
|
|
}
|
|
|
|
if (CurInterfaceData.pCallbacks->RenderState)
|
|
return CurInterfaceData.pCallbacks->RenderState(data);
|
|
else
|
|
return DDHAL_DRIVER_HANDLED;
|
|
}
|
|
|
|
DWORD __stdcall
|
|
TestRenderPrimitive(LPD3DHAL_RENDERPRIMITIVEDATA data)
|
|
{
|
|
if (g_dwTestHalFlags & __TESTHAL_OUTPUTFILE)
|
|
{
|
|
// mem and tlmem should be destroyed before calling the real driver
|
|
// to unlock the surface
|
|
CLockedDDSurface mem(data->lpExeBuf);
|
|
CLockedDDSurface tlmem(data->lpTLBuf);
|
|
LPBYTE lpPrimData;
|
|
LPD3DTLVERTEX lpTLData;
|
|
DWORD i;
|
|
DWORD primitiveDataSize;
|
|
DWORD count = data->diInstruction.wCount;
|
|
TFREC_RENDERPRIMITIVE rec;
|
|
|
|
// Find the pointer to the first primitive structure
|
|
lpPrimData = (LPBYTE)mem + data->dwOffset;
|
|
|
|
// Find the pointer to the vertex data
|
|
// Find the pointer to the first TL vertex
|
|
lpTLData = (LPD3DTLVERTEX)((LPBYTE)tlmem + data->dwTLOffset);
|
|
|
|
rec.status = data->dwStatus;
|
|
rec.vertexType = D3DVT_TLVERTEX;
|
|
// Find out number of vertices, primitive type and
|
|
// size of primitive data
|
|
switch (data->diInstruction.bOpcode)
|
|
{
|
|
case D3DOP_POINT:
|
|
rec.primitiveType = D3DPT_POINTLIST;
|
|
rec.vertexCount = count;
|
|
primitiveDataSize = count*sizeof(D3DPOINT);
|
|
break;
|
|
case D3DOP_LINE:
|
|
rec.primitiveType = D3DPT_LINELIST;
|
|
rec.vertexCount = count*2;
|
|
primitiveDataSize = count*sizeof(D3DLINE);
|
|
break;
|
|
case D3DOP_SPAN:
|
|
rec.primitiveType = D3DPT_POINTLIST;
|
|
rec.vertexCount = count;
|
|
primitiveDataSize = count*sizeof(D3DSPAN);
|
|
break;
|
|
case D3DOP_TRIANGLE:
|
|
rec.primitiveType = D3DPT_TRIANGLELIST;
|
|
rec.vertexCount = count*3;
|
|
primitiveDataSize = count*sizeof(D3DTRIANGLE);
|
|
break;
|
|
}
|
|
|
|
PutHeader(TFID_RENDERPRIMITIVE,
|
|
sizeof(D3DINSTRUCTION) +
|
|
sizeof(rec) + rec.vertexCount*sizeof(D3DTLVERTEX) +
|
|
primitiveDataSize);
|
|
PutBuffer(&rec, sizeof(rec));
|
|
PutBuffer(&data->diInstruction, sizeof(D3DINSTRUCTION));
|
|
|
|
// Parse the structures based on the instruction
|
|
switch (data->diInstruction.bOpcode)
|
|
{
|
|
case D3DOP_POINT:
|
|
{
|
|
LPD3DPOINT lpPoint = (LPD3DPOINT)lpPrimData;
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
PutBuffer(lpPoint, sizeof(D3DPOINT));
|
|
PutBuffer(&lpTLData[lpPoint->wFirst],
|
|
lpPoint->wCount*sizeof(D3DTLVERTEX));
|
|
lpPoint++;
|
|
}
|
|
break;
|
|
}
|
|
case D3DOP_LINE:
|
|
{
|
|
LPD3DLINE lpLine = (LPD3DLINE)lpPrimData;
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
PutBuffer(lpLine, sizeof(D3DLINE));
|
|
PutBuffer(&lpTLData[lpLine->v1], sizeof(D3DTLVERTEX));
|
|
PutBuffer(&lpTLData[lpLine->v2], sizeof(D3DTLVERTEX));
|
|
lpLine++;
|
|
}
|
|
break;
|
|
}
|
|
case D3DOP_SPAN:
|
|
{
|
|
LPD3DSPAN lpSpan = (LPD3DSPAN)lpPrimData;
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
PutBuffer(lpSpan, sizeof(D3DSPAN));
|
|
PutBuffer(&lpTLData[lpSpan->wFirst],
|
|
lpSpan->wCount*sizeof(D3DTLVERTEX));
|
|
lpSpan++;
|
|
}
|
|
break;
|
|
}
|
|
case D3DOP_TRIANGLE:
|
|
{
|
|
LPD3DTRIANGLE lpTri = (LPD3DTRIANGLE)lpPrimData;
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
PutBuffer(lpTri, sizeof(D3DTRIANGLE));
|
|
PutBuffer(&lpTLData[lpTri->v1], sizeof(D3DTLVERTEX));
|
|
PutBuffer(&lpTLData[lpTri->v2], sizeof(D3DTLVERTEX));
|
|
PutBuffer(&lpTLData[lpTri->v3], sizeof(D3DTLVERTEX));
|
|
lpTri++;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (CurInterfaceData.pCallbacks->RenderPrimitive &&
|
|
!(g_dwTestHalFlags & __TESTHAL_NORENDER))
|
|
return CurInterfaceData.pCallbacks->RenderPrimitive(data);
|
|
else
|
|
return DDHAL_DRIVER_HANDLED;
|
|
}
|
|
|
|
DWORD __stdcall
|
|
TestSceneCapture(LPD3DHAL_SCENECAPTUREDATA pData)
|
|
{
|
|
if (g_dwTestHalFlags & __TESTHAL_OUTPUTFILE)
|
|
{
|
|
PutHeader(TFID_SCENECAPTURE, sizeof(DWORD));
|
|
PutBuffer(&pData->dwFlag, sizeof(DWORD));
|
|
fflush(fout);
|
|
}
|
|
|
|
if (CurInterfaceData.pCallbacks->SceneCapture)
|
|
return CurInterfaceData.pCallbacks->SceneCapture(pData);
|
|
else
|
|
return DDHAL_DRIVER_HANDLED;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// TestHalProvider::QueryInterface
|
|
//
|
|
// Internal interface, no need to implement.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP CTestHalProvider::QueryInterface(THIS_ REFIID riid, LPVOID* ppvObj)
|
|
{
|
|
*ppvObj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// CTestHalProvider::AddRef
|
|
//
|
|
// Static implementation, no real refcount.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP_(ULONG) CTestHalProvider::AddRef(THIS)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// TestHalProvider::Release
|
|
//
|
|
// Static implementation, no real refcount.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP_(ULONG) CTestHalProvider::Release(THIS)
|
|
{
|
|
if (fout)
|
|
{
|
|
fclose(fout);
|
|
fout = NULL;
|
|
}
|
|
return pCurHalProvider->Release();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// GetTestProvider
|
|
//
|
|
// Input:
|
|
// riid and pCurrentHalProvider are equal to
|
|
// the currently selected provider.
|
|
// GlobalData - data provided by DDraw
|
|
// fileName - output file name
|
|
// dwFlagsInp - currently not used
|
|
//
|
|
// Returns:
|
|
// the test HAL provider in ppHalProvider.
|
|
//
|
|
// Notes:
|
|
// Only one instance of the test HAL is handled correctly.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDAPI GetTestHalProvider(REFIID riid,
|
|
DDRAWI_DIRECTDRAW_GBL *GlobalData,
|
|
IHalProvider **ppHalProvider,
|
|
IHalProvider * pCurrentHalProvider,
|
|
DWORD dwFlagsInp)
|
|
{
|
|
*ppHalProvider = &g_TestHalProvider;
|
|
pCurHalProvider = pCurrentHalProvider;
|
|
|
|
g_dwTestHalFlags |= __TESTHAL_NORENDER;
|
|
if (GetD3DRegValue(REG_SZ, "TestHalFile", &szFileName, _MAX_PATH) &&
|
|
szFileName[0] != 0)
|
|
{
|
|
g_dwTestHalFlags |= __TESTHAL_OUTPUTFILE;
|
|
}
|
|
DWORD dwValue;
|
|
if (GetD3DRegValue(REG_DWORD, "TestHalDoRender", &dwValue, sizeof(DWORD)) &&
|
|
dwValue != 0)
|
|
{
|
|
g_dwTestHalFlags &= ~__TESTHAL_NORENDER;
|
|
}
|
|
// Get interface from the current hal provider to call to it
|
|
pCurrentHalProvider->GetInterface(GlobalData, &CurInterfaceData, 3);
|
|
|
|
TestInterfaceData = CurInterfaceData;
|
|
TestInterfaceData.pCallbacks = &TestCallbacks;
|
|
TestInterfaceData.pCallbacks2 = &TestCallbacks2;
|
|
TestInterfaceData.pCallbacks3 = &TestCallbacks3;
|
|
|
|
// Initialize callbacks we do not care of
|
|
|
|
TestCallbacks = *CurInterfaceData.pCallbacks;
|
|
TestCallbacks2 = *CurInterfaceData.pCallbacks2;
|
|
TestCallbacks3 = *CurInterfaceData.pCallbacks3;
|
|
|
|
// Initialize callbacks that we want to intersept
|
|
|
|
TestCallbacks.RenderState = &TestRenderState;
|
|
TestCallbacks.RenderPrimitive = &TestRenderPrimitive;
|
|
TestCallbacks.SceneCapture = &TestSceneCapture;
|
|
|
|
TestCallbacks2.DrawOnePrimitive = &TestDrawOnePrimitive;
|
|
TestCallbacks2.DrawOneIndexedPrimitive = &TestDrawOneIndexedPrimitive;
|
|
TestCallbacks2.DrawPrimitives = &TestDrawPrimitives;
|
|
|
|
TestCallbacks3.DrawPrimitives2 = &TestDrawPrimitives2;
|
|
|
|
fout = NULL;
|
|
if (g_dwTestHalFlags & __TESTHAL_OUTPUTFILE)
|
|
{
|
|
fout = fopen(szFileName, "wb");
|
|
if (!fout)
|
|
return DDERR_GENERIC;
|
|
}
|
|
|
|
return D3D_OK;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// CTestHalProvider::GetInterface
|
|
//
|
|
// Returns test provider interface and real rasterizer global data.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTestHalProvider::GetInterface(THIS_
|
|
LPDDRAWI_DIRECTDRAW_GBL pDdGbl,
|
|
LPD3DHALPROVIDER_INTERFACEDATA pInterfaceData,
|
|
DWORD dwVersion)
|
|
{
|
|
*pInterfaceData = TestInterfaceData;
|
|
|
|
return D3D_OK;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// TestHalProvider::GetCaps
|
|
//
|
|
// Returns real rasterizer caps.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP
|
|
CTestHalProvider::GetCaps(THIS_
|
|
LPDDRAWI_DIRECTDRAW_GBL pDdGbl,
|
|
LPD3DDEVICEDESC pHwDesc,
|
|
LPD3DDEVICEDESC pHelDesc,
|
|
DWORD dwVersion)
|
|
{
|
|
return pCurHalProvider->GetCaps(pDdGbl, pHwDesc, pHelDesc, dwVersion);
|
|
}
|
|
|
|
//#endif //DEBUG_PIPELINE
|