From f1db14b053a38923335ffd337ad868f999ea5c0f Mon Sep 17 00:00:00 2001 From: Voxel9 <16278868+Voxel9@users.noreply.github.com> Date: Sun, 22 Dec 2019 20:00:36 +0000 Subject: [PATCH 1/8] Implement BeginVisibilityTest, EndVisibilityTest and GetVisibilityTestResult --- src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 20 ++++++++++---------- src/core/hle/D3D8/Direct3D9/Direct3D9.h | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index 366cdd188..147635be2 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -3231,14 +3231,20 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_EndPush)(DWORD *pPush) } } +IDirect3DQuery9* VisibilityQuery; + // ****************************************************************** // * patch: D3DDevice_BeginVisibilityTest // ****************************************************************** -VOID WINAPI XTL::EMUPATCH(D3DDevice_BeginVisibilityTest)() +HRESULT WINAPI XTL::EMUPATCH(D3DDevice_BeginVisibilityTest)() { LOG_FUNC(); - LOG_UNIMPLEMENTED(); + g_pD3DDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, &VisibilityQuery); + + VisibilityQuery->Issue(D3DISSUE_BEGIN); + + return D3D_OK; } // LTCG specific D3DDevice_EndVisibilityTest function... @@ -3267,7 +3273,7 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_EndVisibilityTest) { LOG_FUNC_ONE_ARG(Index); - LOG_UNIMPLEMENTED(); + VisibilityQuery->Issue(D3DISSUE_END); return D3D_OK; } @@ -3301,13 +3307,7 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_GetVisibilityTestResult) LOG_FUNC_ARG(pTimeStamp) LOG_FUNC_END; - // TODO: actually emulate this!? - - if(pResult != 0) - *pResult = 640*480; - - if(pTimeStamp != 0) - *pTimeStamp = 0; + while(S_FALSE == VisibilityQuery->GetData(pResult, sizeof(DWORD), D3DGETDATA_FLUSH)); return D3D_OK; } diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.h b/src/core/hle/D3D8/Direct3D9/Direct3D9.h index 95a5317c2..a4c65d945 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.h +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.h @@ -161,7 +161,7 @@ VOID WINAPI EMUPATCH(D3DDevice_EndPush)(DWORD *pPush); // ****************************************************************** // * patch: D3DDevice_BeginVisibilityTest // ****************************************************************** -VOID WINAPI EMUPATCH(D3DDevice_BeginVisibilityTest)(); +HRESULT WINAPI EMUPATCH(D3DDevice_BeginVisibilityTest)(); // ****************************************************************** // * patch: D3DDevice_EndVisibilityTest From 81b1e87594bc2c0bbe9d4b1f989298daee144592 Mon Sep 17 00:00:00 2001 From: Voxel9 <16278868+Voxel9@users.noreply.github.com> Date: Sun, 22 Dec 2019 22:30:54 +0000 Subject: [PATCH 2/8] Move, assign and prefix global query variable appropriately --- src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index 147635be2..1616c1bc0 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -113,6 +113,7 @@ static IDirect3DVertexBuffer *g_pDummyBuffer = nullptr; // Dummy buffer, static IDirect3DIndexBuffer *g_pClosingLineLoopHostIndexBuffer = nullptr; static IDirect3DIndexBuffer *g_pQuadToTriangleHostIndexBuffer = nullptr; static IDirect3DSurface *g_pDefaultHostDepthBufferSurface = nullptr; +static IDirect3DQuery *g_pVisibilityQuery = nullptr; // cached Direct3D state variable(s) static size_t g_QuadToTriangleHostIndexBuffer_Size = 0; // = NrOfQuadIndices @@ -3231,8 +3232,6 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_EndPush)(DWORD *pPush) } } -IDirect3DQuery9* VisibilityQuery; - // ****************************************************************** // * patch: D3DDevice_BeginVisibilityTest // ****************************************************************** @@ -3240,9 +3239,9 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_BeginVisibilityTest)() { LOG_FUNC(); - g_pD3DDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, &VisibilityQuery); + g_pD3DDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, &g_pVisibilityQuery); - VisibilityQuery->Issue(D3DISSUE_BEGIN); + g_pVisibilityQuery->Issue(D3DISSUE_BEGIN); return D3D_OK; } @@ -3273,7 +3272,7 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_EndVisibilityTest) { LOG_FUNC_ONE_ARG(Index); - VisibilityQuery->Issue(D3DISSUE_END); + g_pVisibilityQuery->Issue(D3DISSUE_END); return D3D_OK; } @@ -3307,7 +3306,7 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_GetVisibilityTestResult) LOG_FUNC_ARG(pTimeStamp) LOG_FUNC_END; - while(S_FALSE == VisibilityQuery->GetData(pResult, sizeof(DWORD), D3DGETDATA_FLUSH)); + while(S_FALSE == g_pVisibilityQuery->GetData(pResult, sizeof(DWORD), D3DGETDATA_FLUSH)); return D3D_OK; } From d45101a7f5f30a336e25dd9435c7c5d0d0c7c6bb Mon Sep 17 00:00:00 2001 From: Voxel9 <16278868+Voxel9@users.noreply.github.com> Date: Sun, 22 Dec 2019 23:37:02 +0000 Subject: [PATCH 3/8] Check whether CreateQuery succeeds before accessing output --- src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index 1616c1bc0..25651f76c 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -3239,7 +3239,11 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_BeginVisibilityTest)() { LOG_FUNC(); - g_pD3DDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, &g_pVisibilityQuery); + HRESULT hRes = g_pD3DDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, &g_pVisibilityQuery); + if (hRes != D3D_OK) { + LOG_TEST_CASE("BeginVisibilityTest: CreateQuery failed"); + RETURN(hRes); + } g_pVisibilityQuery->Issue(D3DISSUE_BEGIN); From 566136c195840efc7a5f087284c4851260893ab2 Mon Sep 17 00:00:00 2001 From: Voxel9 <16278868+Voxel9@users.noreply.github.com> Date: Mon, 23 Dec 2019 18:44:19 +0000 Subject: [PATCH 4/8] Add checks for EndVisibilityTest --- src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index 25651f76c..8a8b71dcf 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -3276,7 +3276,19 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_EndVisibilityTest) { LOG_FUNC_ONE_ARG(Index); - g_pVisibilityQuery->Issue(D3DISSUE_END); + if (g_pVisibilityQuery != nullptr) + { + HRESULT hRes = g_pVisibilityQuery->Issue(D3DISSUE_END); + if (hRes != D3D_OK) + { + LOG_TEST_CASE("EndVisibilityTest: Failed to issue query"); + RETURN(hRes); + } + } + else + { + LOG_TEST_CASE("EndVisibilityTest: g_pVisibilityQuery = nullptr"); + } return D3D_OK; } From 1727b7e22bc78bd1fa93064ebc99fa9dac7473d9 Mon Sep 17 00:00:00 2001 From: Voxel9 <16278868+Voxel9@users.noreply.github.com> Date: Mon, 23 Dec 2019 18:52:48 +0000 Subject: [PATCH 5/8] Add D3D query nullptr check for GetVisibilityTestResult --- src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index 8a8b71dcf..5a53d7a05 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -3322,7 +3322,14 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_GetVisibilityTestResult) LOG_FUNC_ARG(pTimeStamp) LOG_FUNC_END; - while(S_FALSE == g_pVisibilityQuery->GetData(pResult, sizeof(DWORD), D3DGETDATA_FLUSH)); + if (g_pVisibilityQuery != nullptr) + { + while (S_FALSE == g_pVisibilityQuery->GetData(pResult, sizeof(DWORD), D3DGETDATA_FLUSH)); + } + else + { + LOG_TEST_CASE("GetVisibilityTestResult: g_pVisibilityQuery = nullptr"); + } return D3D_OK; } From fd2a0506af8c1f42398a583fa00ac444cfd3944c Mon Sep 17 00:00:00 2001 From: Voxel9 <16278868+Voxel9@users.noreply.github.com> Date: Mon, 23 Dec 2019 20:10:45 +0000 Subject: [PATCH 6/8] Add an explanation for the GetData while loop in GetVisibilityTestResult --- src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index 5a53d7a05..5df8bc0b2 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -3324,6 +3324,11 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_GetVisibilityTestResult) if (g_pVisibilityQuery != nullptr) { + // In order to prevent an endless loop if the D3D device becomes lost, we pass + // the D3DGETDATA_FLUSH flag. This tells GetData to return D3DERR_DEVICELOST if + // such a situation occurs, and break out of the loop as a result. + // Note: By Cxbx's design, we cannot do drawing within this while loop in order + // to further prevent any other endless loop situations. while (S_FALSE == g_pVisibilityQuery->GetData(pResult, sizeof(DWORD), D3DGETDATA_FLUSH)); } else From 0d43bc19aa872fe750269a4f2d4c1309dfdd2f34 Mon Sep 17 00:00:00 2001 From: PatrickvL Date: Tue, 24 Dec 2019 16:38:10 +0100 Subject: [PATCH 7/8] Continue with Voxel9's work, and extend it with support for multiple indexed occlusion queries --- src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 102 ++++++++++++++++------ 1 file changed, 77 insertions(+), 25 deletions(-) diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index 5df8bc0b2..ba84edfc6 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -28,6 +28,7 @@ #include "common\util\hasher.h" #include +#include // prevent name collisions namespace xboxkrnl @@ -113,7 +114,10 @@ static IDirect3DVertexBuffer *g_pDummyBuffer = nullptr; // Dummy buffer, static IDirect3DIndexBuffer *g_pClosingLineLoopHostIndexBuffer = nullptr; static IDirect3DIndexBuffer *g_pQuadToTriangleHostIndexBuffer = nullptr; static IDirect3DSurface *g_pDefaultHostDepthBufferSurface = nullptr; -static IDirect3DQuery *g_pVisibilityQuery = nullptr; + +static bool g_bEnableHostQueryVisibilityTest = true; +static std::stack g_HostQueryVisibilityTests; +static std::map g_HostVisibilityTestMap; // cached Direct3D state variable(s) static size_t g_QuadToTriangleHostIndexBuffer_Size = 0; // = NrOfQuadIndices @@ -2449,7 +2453,20 @@ static DWORD WINAPI EmuCreateDeviceProxy(LPVOID) DEBUG_D3DRESULT(hRet, "g_pD3DDevice->CreateQuery (callback event)"); } } else { - LOG_TEST_CASE("Can't CreateQuery on host!"); + LOG_TEST_CASE("Can't CreateQuery(D3DQUERYTYPE_EVENT) on host!"); + } + + // Can host driver create occlusion queries? + g_bEnableHostQueryVisibilityTest = false; + if (SUCCEEDED(g_pD3DDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, nullptr))) { + // Is host GPU query creation enabled? + if (!g_bHack_DisableHostGPUQueries) { + g_bEnableHostQueryVisibilityTest = true; + } else { + LOG_TEST_CASE("Disabled D3DQUERYTYPE_OCCLUSION on host!"); + } + } else { + LOG_TEST_CASE("Can't CreateQuery(D3DQUERYTYPE_OCCLUSION) on host!"); } hRet = g_pD3DDevice->CreateVertexBuffer @@ -3239,13 +3256,24 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_BeginVisibilityTest)() { LOG_FUNC(); - HRESULT hRes = g_pD3DDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, &g_pVisibilityQuery); - if (hRes != D3D_OK) { - LOG_TEST_CASE("BeginVisibilityTest: CreateQuery failed"); - RETURN(hRes); - } + if (g_bEnableHostQueryVisibilityTest) { + // Create a D3D occlusion query to handle "visibility test" with + IDirect3DQuery* pHostQueryVisibilityTest = nullptr; + HRESULT hRet = g_pD3DDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, &pHostQueryVisibilityTest); + DEBUG_D3DRESULT(hRet, "g_pD3DDevice->CreateQuery (visibility test)"); + if (pHostQueryVisibilityTest != nullptr) { + hRet = pHostQueryVisibilityTest->Issue(D3DISSUE_BEGIN); + DEBUG_D3DRESULT(hRet, "g_pHostQueryVisibilityTest->Issue(D3DISSUE_BEGIN)"); + if (SUCCEEDED(hRet)) { + g_HostQueryVisibilityTests.push(pHostQueryVisibilityTest); + } else { + LOG_TEST_CASE("Failed to issue query"); + pHostQueryVisibilityTest->Release(); + } - g_pVisibilityQuery->Issue(D3DISSUE_BEGIN); + pHostQueryVisibilityTest = nullptr; + } + } return D3D_OK; } @@ -3276,18 +3304,29 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_EndVisibilityTest) { LOG_FUNC_ONE_ARG(Index); - if (g_pVisibilityQuery != nullptr) - { - HRESULT hRes = g_pVisibilityQuery->Issue(D3DISSUE_END); - if (hRes != D3D_OK) - { - LOG_TEST_CASE("EndVisibilityTest: Failed to issue query"); - RETURN(hRes); + if (g_bEnableHostQueryVisibilityTest) { + // Check that the dedicated storage for the given Index isn't in use + if (g_HostVisibilityTestMap[Index] != nullptr) { + return E_OUTOFMEMORY; + } + + if (g_HostQueryVisibilityTests.empty()) { + return 2088; // visibility test incomplete (a prior BeginVisibilityTest call is needed) + } + + IDirect3DQuery* pHostQueryVisibilityTest = g_HostQueryVisibilityTests.top(); + g_HostQueryVisibilityTests.pop(); + assert(pHostQueryVisibilityTest != nullptr); + + HRESULT hRet = pHostQueryVisibilityTest->Issue(D3DISSUE_END); + DEBUG_D3DRESULT(hRet, "g_pHostQueryVisibilityTest->Issue(D3DISSUE_END)"); + if (hRet == D3D_OK) { + // Associate the result of this call with the given Index + g_HostVisibilityTestMap[Index] = pHostQueryVisibilityTest; + } else { + LOG_TEST_CASE("Failed to issue query"); + pHostQueryVisibilityTest->Release(); } - } - else - { - LOG_TEST_CASE("EndVisibilityTest: g_pVisibilityQuery = nullptr"); } return D3D_OK; @@ -3322,18 +3361,31 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_GetVisibilityTestResult) LOG_FUNC_ARG(pTimeStamp) LOG_FUNC_END; - if (g_pVisibilityQuery != nullptr) - { + if (g_bEnableHostQueryVisibilityTest) { + IDirect3DQuery* pHostQueryVisibilityTest = g_HostVisibilityTestMap[Index]; + if (pHostQueryVisibilityTest == nullptr) { + return E_OUTOFMEMORY; + } + // In order to prevent an endless loop if the D3D device becomes lost, we pass // the D3DGETDATA_FLUSH flag. This tells GetData to return D3DERR_DEVICELOST if // such a situation occurs, and break out of the loop as a result. // Note: By Cxbx's design, we cannot do drawing within this while loop in order // to further prevent any other endless loop situations. - while (S_FALSE == g_pVisibilityQuery->GetData(pResult, sizeof(DWORD), D3DGETDATA_FLUSH)); + while (S_FALSE == pHostQueryVisibilityTest->GetData(pResult, sizeof(DWORD), D3DGETDATA_FLUSH)); + + g_HostVisibilityTestMap[Index] = nullptr; + pHostQueryVisibilityTest->Release(); + } else { + // Fallback to old faked result when there's no host occlusion query : + if (pResult != xbnullptr) { + *pResult = 640 * 480; // TODO : Use actual backbuffer dimensions + } } - else - { - LOG_TEST_CASE("GetVisibilityTestResult: g_pVisibilityQuery = nullptr"); + + if (pTimeStamp != xbnullptr) { + LOG_TEST_CASE("pTimeStamp = nullptr"); + *pTimeStamp = sizeof(DWORD); // TODO : This should be an incrementing GPU-memory based DWORD-aligned memory address } return D3D_OK; From a21cb8f0fd00f96fa843971feee7050b1bfa3cf9 Mon Sep 17 00:00:00 2001 From: patrickvl Date: Wed, 25 Dec 2019 17:11:37 +0100 Subject: [PATCH 8/8] Clearer LOG_TEST_CASE message --- src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index ba84edfc6..ba1cedb79 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -3384,7 +3384,7 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_GetVisibilityTestResult) } if (pTimeStamp != xbnullptr) { - LOG_TEST_CASE("pTimeStamp = nullptr"); + LOG_TEST_CASE("requested value for pTimeStamp"); *pTimeStamp = sizeof(DWORD); // TODO : This should be an incrementing GPU-memory based DWORD-aligned memory address }