More Index Buffer work

This commit is contained in:
Luke Usher 2017-04-28 12:49:59 +01:00
parent 7939ca665d
commit 7b60aa1020
3 changed files with 65 additions and 111 deletions

View File

@ -754,6 +754,9 @@ void CxbxKrnlInit
// initialize grapchics
DbgPrintf("EmuMain: Initializing render window.\n");
XTL::CxbxInitWindow(pXbeHeader, dwXbeHeaderSize);
EmuHLEIntercept(pXbeHeader);
if (bLLE_GPU)
{
DbgPrintf("EmuMain: Initializing OpenGL.\n");
@ -765,7 +768,6 @@ void CxbxKrnlInit
XTL::EmuD3DInit();
}
EmuHLEIntercept(pXbeHeader);
// Apply Media Patches to bypass Anti-Piracy checks
// Required until we perfect emulation of X2 DVD Authentication
// See: https://multimedia.cx/eggs/xbox-sphinx-protocol/

View File

@ -35,6 +35,7 @@
// ******************************************************************
#define _CXBXKRNL_INTERNAL
#define _XBOXKRNL_DEFEXTRN_
#include "xxhash32.h"
// prevent name collisions
namespace xboxkrnl
@ -53,6 +54,7 @@ namespace xboxkrnl
#include "EmuAlloc.h"
#include "MemoryManager.h"
#include "EmuXTL.h"
#include "HLEDatabase.h"
#include <assert.h>
#include <process.h>
@ -172,6 +174,9 @@ struct EmuD3D8CreateDeviceProxyData
}
g_EmuCDPD = {0};
// TODO: This should be a D3DDevice structure
BYTE g_XboxD3DDevice[ONE_MB] = { 0 };
VOID XTL::CxbxInitWindow(Xbe::Header *XbeHeader, uint32 XbeHeaderSize)
{
g_EmuShared->GetXBVideo(&g_XBVideo);
@ -1499,32 +1504,17 @@ static void EmuUnswizzleTextureStages()
}
typedef struct {
DWORD IndexData;
DWORD IndexEnd;
XTL::IDirect3DIndexBuffer8* pHostIndexBuffer;
DWORD Hash = 0;
DWORD IndexCount = 0;;
XTL::IDirect3DIndexBuffer8* pHostIndexBuffer = nullptr;
} ConvertedIndexBuffer;
std::vector<ConvertedIndexBuffer> g_ConvertedIndexBuffers;
std::map<PWORD, ConvertedIndexBuffer> g_ConvertedIndexBuffers;
void CxbxRemoveIndexBuffer(PWORD pData)
{
// Now, see if we already have a (partial) index buffer for this range :
ConvertedIndexBuffer* pConvertedIndexBuffer = nullptr;
auto it = g_ConvertedIndexBuffers.begin();
for (; it != g_ConvertedIndexBuffers.end(); ++it) {
// Check if we found an index buffer containing this pointer
if ((DWORD)it->IndexData <= (DWORD)pData && (DWORD)pData < (DWORD)it->IndexEnd) {
pConvertedIndexBuffer = &(*it);
break;
}
}
if (pConvertedIndexBuffer != nullptr) {
DbgPrintf("DxbxRemoveIndexBuffer: Removing buffer for 0x%08x-0x%08x", pConvertedIndexBuffer->IndexData, pConvertedIndexBuffer->IndexEnd);
pConvertedIndexBuffer->pHostIndexBuffer->Release();
g_ConvertedIndexBuffers.erase(it);
}
// HACK: Never Free
return;
}
void CxbxUpdateActiveIndexBuffer
@ -1534,116 +1524,66 @@ void CxbxUpdateActiveIndexBuffer
UINT &uiStartIndex
)
{
PWORD pwInitialStart = pIndexData; // Remember this to calculate StartIndex later!
PWORD pwIndexEnd = pIndexData + IndexCount;
bool MustCopy = false;
// Note : We assume that all outdated index buffer(s) are already removed,
// so that we'll never merge with buffers already destroyed on the Xbox side!
// Now, see if we already have a (partial) index buffer for this range :
ConvertedIndexBuffer* pConvertedIndexBuffer = nullptr;
for (auto it = g_ConvertedIndexBuffers.begin(); it != g_ConvertedIndexBuffers.end(); ++it) {
// Check if the given index range overlaps with this buffer :
if ((DWORD)pIndexData > (DWORD)it->IndexEnd) {
// new buffer starts beyond current (so no overlap)
}
else if ((DWORD)pwIndexEnd < (DWORD)it->IndexData) {
// new buffer end before current (so no overlap)
}
else {
// The new and current buffer overlap - we found a merge candidate!
break;
}
pConvertedIndexBuffer = &(*it);
}
// Did we find a merge candidate?
if (pConvertedIndexBuffer == nullptr) {
DbgPrintf("DxbxUpdateActiveIndexBuffer: Creating new buffer for 0x%08x-0x%08x (%d indices)\n", pIndexData, pwIndexEnd, pwIndexEnd - pIndexData);
// No merge, so add a new converted index buffer to the chain :
// If the index buffer is not already in our data structure, add it
if(g_ConvertedIndexBuffers.find(pIndexData) == g_ConvertedIndexBuffers.end()) {
ConvertedIndexBuffer buffer;
g_ConvertedIndexBuffers.push_back(buffer);
g_ConvertedIndexBuffers[pIndexData] = buffer;
};
pConvertedIndexBuffer = &g_ConvertedIndexBuffers.back();
MustCopy = true;
}
else {
// We found an existing index buffer, see if we must extend it's bounds :
if ((DWORD)pIndexData < pConvertedIndexBuffer->IndexData) {
MustCopy = true; // The merge has a new start pointer
}
else {
pIndexData = (PWORD)pConvertedIndexBuffer->IndexData; // The merge keeps the old start pointer
}
if ((DWORD)pwIndexEnd > pConvertedIndexBuffer->IndexEnd) {
MustCopy = true; // The merge has a new end pointer
}
else {
pwIndexEnd = (PWORD)pConvertedIndexBuffer->IndexEnd; // The merge keeps the old end pointer
}
// TODO : What if this grow causes two (or more) existing ranges to overlap - we should merge them all...
// TOOD : What if the index buffer exceeds D3DCaps.MaxVertexIndex ?
// TODO : If not MustCopy, Add a CRC check on the contents (forcing MustCopy) ?
if (MustCopy) {
DbgPrintf("DxbxUpdateActiveIndexBuffer: Enlarging buffer to 0x%08x-0x%08x (%d indices)\n", pIndexData, pwIndexEnd, pwIndexEnd - pIndexData);
// Remove previous native buffer (this might leave one stale reference,
// but this one will be released automatically in the next SetIndices call) :
pConvertedIndexBuffer->pHostIndexBuffer->Release();
pConvertedIndexBuffer->pHostIndexBuffer = nullptr;
}
// If the size has changed, free the buffer so it will be re-created
if (g_ConvertedIndexBuffers[pIndexData].pHostIndexBuffer != nullptr &&
g_ConvertedIndexBuffers[pIndexData].IndexCount != IndexCount) {
g_ConvertedIndexBuffers[pIndexData].Hash = 0;
g_ConvertedIndexBuffers[pIndexData].IndexCount = 0;
g_ConvertedIndexBuffers[pIndexData].pHostIndexBuffer->Release();
g_ConvertedIndexBuffers[pIndexData].pHostIndexBuffer = nullptr;
}
HRESULT hRet;
if (MustCopy) {
// Remember the (new) buffer bounds :
pConvertedIndexBuffer->IndexData = (DWORD)pIndexData;
pConvertedIndexBuffer->IndexEnd = (DWORD)pwIndexEnd;
IndexCount = pwIndexEnd - pIndexData; // Calculate the number of WORD's between start & end
// Create a new native index buffer of the above determined size :
hRet = g_pD3DDevice8->CreateIndexBuffer(
// If we need to create an index buffer, do so.
if (g_ConvertedIndexBuffers[pIndexData].pHostIndexBuffer == nullptr) {
// Create a new native index buffer of the above determined size :
HRESULT hRet = g_pD3DDevice8->CreateIndexBuffer(
IndexCount * 2,
D3DUSAGE_WRITEONLY,
XTL::D3DFMT_INDEX16,
XTL::D3DPOOL_MANAGED,
&pConvertedIndexBuffer->pHostIndexBuffer);
&g_ConvertedIndexBuffers[pIndexData].pHostIndexBuffer);
if (FAILED(hRet)) {
CxbxKrnlCleanup("DxbxUpdateActiveIndexBuffer: IndexBuffer Create Failed!");
}
}
// If the data needs updating, do so
uint32_t uiHash = XXHash32::hash(pIndexData, IndexCount * 2, 0);
if (uiHash != g_ConvertedIndexBuffers[pIndexData].Hash) {
g_ConvertedIndexBuffers[pIndexData].IndexCount = IndexCount;
// Copy the xbox indexes into this native buffer :
BYTE* pData = nullptr;
pConvertedIndexBuffer->pHostIndexBuffer->Lock(0, 0, &pData, 0);
g_ConvertedIndexBuffers[pIndexData].pHostIndexBuffer->Lock(0, 0, &pData, 0);
if (pData == nullptr) {
CxbxKrnlCleanup("DxbxUpdateActiveIndexBuffer: Could not lock index buffer!");
}
DbgPrintf("DxbxUpdateActiveIndexBuffer: Copying %d indices (D3DFMT_INDEX16)\n", IndexCount);
memcpy(pData, pIndexData, IndexCount * 2); // TODO : Why does this crash at the 4th copy in Cartoon sample?
memcpy(pData, pIndexData, IndexCount * 2);
pConvertedIndexBuffer->pHostIndexBuffer->Unlock();
g_ConvertedIndexBuffers[pIndexData].pHostIndexBuffer->Unlock();
}
DWORD index = 0;
// Determine the vertex index from D3D
index = *(DWORD*)(g_XboxD3DDevice + 0x1C);
// Activate the new native index buffer :
hRet = g_pD3DDevice8->SetIndices(pConvertedIndexBuffer->pHostIndexBuffer, 0);
HRESULT hRet = g_pD3DDevice8->SetIndices(g_ConvertedIndexBuffers[pIndexData].pHostIndexBuffer, index);
if (FAILED(hRet)) {
CxbxKrnlCleanup("DxbxUpdateActiveIndexBuffer: SetIndices Failed!");
}
// Make sure the caller knows what StartIndex it has to use to point to the indicated index start pointer :
uiStartIndex = (UINT)pwInitialStart - (UINT)pConvertedIndexBuffer->IndexData;
uiStartIndex = 0;
}
// ******************************************************************
@ -1705,8 +1645,9 @@ HRESULT WINAPI XTL::EMUPATCH(Direct3D_CreateDevice)
// Wait until proxy is completed
while(g_EmuCDPD.bReady)
Sleep(10);
// Set the Xbox g_pD3DDevice pointer to our D3D Device object
*((DWORD*)XRefDataBase[XREF_D3DDEVICE]) = (DWORD)g_XboxD3DDevice;
return g_EmuCDPD.hRet;
}
@ -5335,7 +5276,7 @@ ULONG WINAPI XTL::EMUPATCH(D3DResource_AddRef)
ULONG uRet = (++(pThis->Common)) & X_D3DCOMMON_REFCOUNT_MASK;
// Index buffers don't have a native resource assigned
if (!(pThis->Common & X_D3DCOMMON_TYPE_INDEXBUFFER)) {
if (pThis->Common & X_D3DCOMMON_TYPE_MASK != X_D3DCOMMON_TYPE_INDEXBUFFER) {
EmuVerifyResourceIsRegistered(pThis);
// If this is the first reference on a surface
@ -5395,7 +5336,7 @@ ULONG WINAPI XTL::EMUPATCH(D3DResource_Release)
}
EMUPATCH(D3DDevice_EnableOverlay)(FALSE);
} else if (pThis->Common & X_D3DCOMMON_TYPE_INDEXBUFFER) {
} else if ((pThis->Common & X_D3DCOMMON_TYPE_MASK) == X_D3DCOMMON_TYPE_INDEXBUFFER) {
if ((pThis->Common & X_D3DCOMMON_REFCOUNT_MASK) == 1) {
CxbxRemoveIndexBuffer((PWORD)GetDataFromXboxResource(pThis));
}
@ -5420,8 +5361,10 @@ ULONG WINAPI XTL::EMUPATCH(D3DResource_Release)
D3DRESOURCETYPE Type = pResource8->GetType();
#endif
uRet = pResource8->Release();
if(uRet == 0)
/*
* Temporarily disable this until we figure out correct reference counting!
uRet = pResource8->Release();
if(uRet == 0 && pThis->Common)
{
DbgPrintf("EmuIDirect3DResource8_Release : Cleaned up a Resource!\n");
@ -5434,7 +5377,7 @@ ULONG WINAPI XTL::EMUPATCH(D3DResource_Release)
#endif
//delete pThis;
}
} */
}
pThis->Common--; // Release
@ -7705,7 +7648,6 @@ XTL::X_D3DVertexBuffer* WINAPI XTL::EMUPATCH(D3DDevice_GetStreamSource2)
X_D3DVertexBuffer* pVertexBuffer = EmuNewD3DVertexBuffer();
g_pD3DDevice8->GetStreamSource(StreamNumber, &pVertexBuffer->EmuVertexBuffer8, pStride);
return pVertexBuffer;
}
@ -8113,6 +8055,8 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_DrawIndexedVertices)
VertPatch.Restore();
g_pD3DDevice8->SetIndices(NULL, 0);
// Execute callback procedure
if( g_CallbackType == X_D3DCALLBACK_WRITE )
{

View File

@ -138,8 +138,13 @@ void EmuHLEIntercept(Xbe::Header *pXbeHeader)
CxbxKrnlCleanup("EmuD3DDeferredTextureState was not found!");
}
if (g_HLECache.find("D3DDEVICE") == g_HLECache.end()) {
CxbxKrnlCleanup("D3DDEVICE was not found!");
}
XTL::EmuD3DDeferredRenderState = (DWORD*)g_HLECache["D3DDeferredRenderState"];
XTL::EmuD3DDeferredTextureState = (DWORD*)g_HLECache["D3DDeferredTextureState"];
XRefDataBase[XREF_D3DDEVICE] = g_HLECache["D3DDEVICE"];
// TODO: Move this into a function rather than duplicating from HLE scanning code
for (int v = 0; v<44; v++) {
@ -150,6 +155,7 @@ void EmuHLEIntercept(Xbe::Header *pXbeHeader)
for (int v = 0; v<32; v++)
XTL::EmuD3DDeferredTextureState[v + s * 32] = X_D3DTSS_UNK;
}
g_HLECacheUsed = true;
}
@ -385,6 +391,8 @@ void EmuHLEIntercept(Xbe::Header *pXbeHeader)
XRefDataBase[XREF_D3DDEVICE] = DerivedAddr_D3DDevice;
}
g_HLECache["D3DDEVICE"] = DerivedAddr_D3DDevice;
// Temporary verification - is XREF_D3DRS_CULLMODE derived correctly?
if (XRefDataBase[XREF_D3DRS_CULLMODE] != DerivedAddr_D3DRS_CULLMODE)
{