Merge lle and hle vblank routines in a single thread

This commit is contained in:
ergo720 2023-03-02 22:34:05 +01:00 committed by RadWolfie
parent bc42cfaa6b
commit 1828ddfd6f
6 changed files with 73 additions and 72 deletions

View File

@ -72,7 +72,7 @@ Xbe::Xbe(const char *x_szFilename)
// This is necessary because CxbxInitWindow internally calls g_AffinityPolicy->SetAffinityOther. If we are launched directly from the command line and the dashboard
// cannot be opened, we will crash below because g_AffinityPolicy will be empty
g_AffinityPolicy = AffinityPolicy::InitPolicy();
CxbxInitWindow(false);
CxbxInitWindow();
ULONG FatalErrorCode = FATAL_ERROR_XBE_DASH_GENERIC;

View File

@ -229,7 +229,6 @@ static xbox::dword_xt *g_Xbox_D3DDevice; // TODO: This should b
// Static Function(s)
static DWORD WINAPI EmuRenderWindow(LPVOID);
static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
static xbox::void_xt NTAPI EmuUpdateTickCount(xbox::PVOID Arg);
static inline void EmuVerifyResourceIsRegistered(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTextureStage, DWORD dwSize);
static void UpdateCurrentMSpFAndFPS(); // Used for benchmarking/fps count
static void CxbxImpl_SetRenderTarget(xbox::X_D3DSurface *pRenderTarget, xbox::X_D3DSurface *pNewZStencil);
@ -629,25 +628,13 @@ const char *D3DErrorString(HRESULT hResult)
return buffer;
}
void CxbxInitWindow(bool bFullInit)
void CxbxInitWindow()
{
g_EmuShared->GetVideoSettings(&g_XBVideo);
if(g_XBVideo.bFullScreen)
CxbxKrnl_hEmuParent = NULL;
// create timing thread
if (bFullInit && !bLLE_GPU)
{
xbox::HANDLE hThread;
xbox::PsCreateSystemThread(&hThread, xbox::zeroptr, EmuUpdateTickCount, xbox::zeroptr, FALSE);
// We set the priority of this thread a bit higher, to assure reliable timing :
auto nativeHandle = GetNativeHandle(hThread);
assert(nativeHandle);
SetThreadPriority(*nativeHandle, THREAD_PRIORITY_ABOVE_NORMAL);
g_AffinityPolicy->SetAffinityOther(*nativeHandle);
}
/* TODO : Port this Dxbx code :
// create vblank handling thread
{
@ -1930,47 +1917,33 @@ std::chrono::steady_clock::time_point GetNextVBlankTime()
return steady_clock::now() + duration_cast<steady_clock::duration>(ms);
}
// timing thread procedure
static xbox::void_xt NTAPI EmuUpdateTickCount(xbox::PVOID Arg)
void hle_vblank()
{
CxbxSetThreadName("Cxbx Timing Thread");
// Note: This whole code block can be removed once NV2A interrupts are implemented
// And Both Swap and Present can be ran unpatched
// Once that is in place, MiniPort + Direct3D will handle this on it's own!
// Increment the VBlank Counter and Wake all threads there were waiting for the VBlank to occur
std::unique_lock<std::mutex> lk(g_VBConditionMutex);
g_Xbox_VBlankData.VBlank++;
g_VBConditionVariable.notify_all();
EmuLog(LOG_LEVEL::DEBUG, "Timing thread is running.");
// TODO: Fixme. This may not be right...
g_Xbox_SwapData.SwapVBlank = 1;
auto nextVBlankTime = GetNextVBlankTime();
while(true)
{
// Wait for VBlank
// Note: This whole code block can be removed once NV2A interrupts are implemented
// And Both Swap and Present can be ran unpatched
// Once that is in place, MiniPort + Direct3D will handle this on it's own!
SleepPrecise(nextVBlankTime);
nextVBlankTime = GetNextVBlankTime();
// Increment the VBlank Counter and Wake all threads there were waiting for the VBlank to occur
std::unique_lock<std::mutex> lk(g_VBConditionMutex);
g_Xbox_VBlankData.VBlank++;
g_VBConditionVariable.notify_all();
// TODO: Fixme. This may not be right...
g_Xbox_SwapData.SwapVBlank = 1;
if(g_pXbox_VerticalBlankCallback != xbox::zeroptr)
{
g_pXbox_VerticalBlankCallback(&g_Xbox_VBlankData);
}
g_Xbox_VBlankData.Swap = 0;
// TODO: This can't be accurate...
g_Xbox_SwapData.TimeUntilSwapVBlank = 0;
// TODO: Recalculate this for PAL version if necessary.
// Also, we should check the D3DPRESENT_INTERVAL value for accurracy.
// g_Xbox_SwapData.TimeBetweenSwapVBlanks = 1/60;
g_Xbox_SwapData.TimeBetweenSwapVBlanks = 0;
if (g_pXbox_VerticalBlankCallback != xbox::zeroptr)
{
g_pXbox_VerticalBlankCallback(&g_Xbox_VBlankData);
}
g_Xbox_VBlankData.Swap = 0;
// TODO: This can't be accurate...
g_Xbox_SwapData.TimeUntilSwapVBlank = 0;
// TODO: Recalculate this for PAL version if necessary.
// Also, we should check the D3DPRESENT_INTERVAL value for accurracy.
// g_Xbox_SwapData.TimeBetweenSwapVBlanks = 1/60;
g_Xbox_SwapData.TimeBetweenSwapVBlanks = 0;
}
void UpdateDepthStencilFlags(IDirect3DSurface *pDepthStencilSurface)

View File

@ -40,7 +40,7 @@
void LookupTrampolinesD3D();
// initialize render window
extern void CxbxInitWindow(bool bFullInit);
extern void CxbxInitWindow();
void CxbxUpdateNativeD3DResources();

View File

@ -1362,7 +1362,7 @@ static void CxbxrKrnlInitHacks()
// initialize graphics
EmuLogInit(LOG_LEVEL::DEBUG, "Initializing render window.");
CxbxInitWindow(true);
CxbxInitWindow();
// Now process the boot flags to see if there are any special conditions to handle
if (BootFlags & BOOT_EJECT_PENDING) {} // TODO

View File

@ -51,6 +51,7 @@
#include "core\kernel\init\CxbxKrnl.h" // For XBOX_MEMORY_SIZE, DWORD, etc
#include "core\kernel\support\Emu.h"
#include "core\kernel\support\NativeHandle.h"
#include "core\kernel\exports\EmuKrnl.h"
#include <backends/imgui_impl_win32.h>
#include <backends/imgui_impl_opengl3.h>
@ -58,6 +59,7 @@
#include "core\hle\Intercept.hpp"
#include "common/win32/Threads.h"
#include "Logging.h"
#include "Timer.h"
#include "vga.h"
#include "nv2a.h" // For NV2AState
@ -319,8 +321,8 @@ const NV2ABlockInfo* EmuNV2A_Block(xbox::addr_xt addr)
// HACK: Until we implement VGA/proper interrupt generation
// we simulate VBLANK by calling the interrupt at 60Hz
std::thread vblank_thread;
extern std::chrono::steady_clock::time_point GetNextVBlankTime();
extern void hle_vblank();
void _check_gl_reset()
{
@ -1097,25 +1099,37 @@ void NV2ADevice::UpdateHostDisplay(NV2AState *d)
}
// TODO: Fix this properly
static void nv2a_vblank_thread(NV2AState *d)
template<bool should_update_hle>
static xbox::void_xt NTAPI nv2a_vblank_thread(xbox::PVOID arg)
{
g_AffinityPolicy->SetAffinityOther();
CxbxSetThreadName("Cxbx NV2A VBLANK");
NV2AState *d = static_cast<NV2AState *>(arg);
if constexpr (should_update_hle) {
CxbxSetThreadName("Cxbxr NV2A and HLE VBLANK");
}
else {
g_AffinityPolicy->SetAffinityOther();
CxbxSetThreadName("Cxbxr NV2A VBLANK");
}
auto nextVBlankTime = GetNextVBlankTime();
while (!d->exiting) {
// Handle VBlank
if (std::chrono::steady_clock::now() > nextVBlankTime) {
d->pcrtc.pending_interrupts |= NV_PCRTC_INTR_0_VBLANK;
update_irq(d);
nextVBlankTime = GetNextVBlankTime();
while (!d->exiting) [[unlikely]] {
// TODO: We should swap here for the purposes of supporting overlays + direct framebuffer access
// But it causes crashes on AMD hardware for reasons currently unknown...
//NV2ADevice::UpdateHostDisplay(d);
// Wait for VBlank
SleepPrecise(nextVBlankTime);
nextVBlankTime = GetNextVBlankTime();
d->pcrtc.pending_interrupts |= NV_PCRTC_INTR_0_VBLANK;
update_irq(d);
// TODO: We should swap here for the purposes of supporting overlays + direct framebuffer access
// But it causes crashes on AMD hardware for reasons currently unknown...
//NV2ADevice::UpdateHostDisplay(d);
if constexpr (should_update_hle) {
hle_vblank();
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
@ -1202,7 +1216,20 @@ void NV2ADevice::Init()
pvideo_init(d);
}
vblank_thread = std::thread(nv2a_vblank_thread, d);
if (bLLE_GPU) {
xbox::HANDLE hThread;
xbox::PsCreateSystemThread(&hThread, xbox::zeroptr, nv2a_vblank_thread<false>, d, FALSE);
d->vblank_thread = *GetNativeHandle(hThread);
}
else {
xbox::HANDLE hThread;
xbox::PsCreateSystemThread(&hThread, xbox::zeroptr, nv2a_vblank_thread<true>, d, FALSE);
// We set the priority of this thread a bit higher, to assure reliable timing
d->vblank_thread = *GetNativeHandle(hThread);
SetThreadPriority(d->vblank_thread, THREAD_PRIORITY_ABOVE_NORMAL);
g_AffinityPolicy->SetAffinityOther(d->vblank_thread);
}
qemu_mutex_init(&d->pfifo.pfifo_lock);
qemu_cond_init(&d->pfifo.puller_cond);
@ -1227,9 +1254,9 @@ void NV2ADevice::Reset()
qemu_cond_broadcast(&d->pfifo.pusher_cond);
d->pfifo.puller_thread.join();
d->pfifo.pusher_thread.join();
qemu_mutex_destroy(&d->pfifo.pfifo_lock); // Cbxbx addition
qemu_mutex_destroy(&d->pfifo.pfifo_lock); // Cxbxr addition
if (d->pgraph.opengl_enabled) {
vblank_thread.join();
WaitForSingleObject(d->vblank_thread, INFINITE);
pvideo_destroy(d);
}

View File

@ -357,6 +357,7 @@ typedef struct OverlayState {
} OverlayState;
typedef struct NV2AState {
HANDLE vblank_thread;
// PCIDevice dev;
// qemu_irq irq;
bool exiting;