Merge pull request #1109 from PatrickvL/viewport_scaling

Viewport scaling
This commit is contained in:
Luke Usher 2018-05-03 14:06:23 +01:00 committed by GitHub
commit fe464da7fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 355 additions and 191 deletions

Binary file not shown.

View File

@ -135,6 +135,7 @@
#define ID_HACKS_UNCAPFRAMERATE 40097
#define ID_HACKS_RUNXBOXTHREADSONALLCORES 40098
#define ID_HACKS_PATCHCPUFREQUENCY 40099
#define ID_HACKS_SCALEVIEWPORT 40100
#define IDC_STATIC -1
// Next default values for new objects

View File

@ -45,8 +45,8 @@ Wnd::Wnd(HINSTANCE x_hInstance) : m_hInstance(x_hInstance)
m_wndname = "Cxbx-Reloaded Generic Window";
m_x = 150;
m_y = 150;
m_w = 320;
m_h = 240;
m_w = 640;
m_h = 480;
m_parent = NULL;
m_clsstyle = CS_HREDRAW | CS_VREDRAW;
m_wndstyle = WS_CLIPCHILDREN | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE;

View File

@ -113,6 +113,52 @@ void WndMain::InitializeSettings() {
#define TIMERID_FPS 0
#define TIMERID_LED 1
void WndMain::ResizeWindow(HWND hwnd, bool bForGUI)
{
RECT desktopRect;
RECT windowRect;
// Set the window size back to it's GUI dimensions
m_w = 640;
m_h = 480;
if (!bForGUI) {
// For emulation, get the configured window dimensions
XBVideo XBVideoConf;
g_EmuShared->GetXBVideo(&XBVideoConf);
const char* resolution = XBVideoConf.GetVideoResolution();
if (2 != sscanf(resolution, "%d x %d", &m_w, &m_h)) {
DbgPrintf("Couldn't parse resolution : %s.\n", resolution);
}
}
// TODO : Acknowledge DPI scaling here
GetWindowRect(GetDesktopWindow(), &desktopRect);
// Limit width/height to desktop resolution
int dWidth = desktopRect.right - desktopRect.left;
int dHeight = desktopRect.bottom - desktopRect.top;
if (m_w > dWidth)
m_w = dWidth;
if (m_h > dHeight)
m_h = dHeight;
// Center to desktop
m_x = desktopRect.left + ((desktopRect.right - desktopRect.left - m_w) / 2);
m_y = desktopRect.top + ((desktopRect.bottom - desktopRect.top - m_h) / 2);
// Resize the window so it's client area can contain the requested resolution
windowRect = { m_x, m_y, m_x + m_w, m_y + m_h };
AdjustWindowRectEx(&windowRect, GetWindowLong(hwnd, GWL_STYLE), GetMenu(hwnd) != NULL, GetWindowLong(hwnd, GWL_EXSTYLE));
// TODO : For DPI screens, replace AdjustWindowRectEx by DwmGetWindowAttribute using DWMWA_EXTENDED_FRAME_BOUNDS
SetWindowPos(hwnd, 0,
windowRect.left,
windowRect.top,
windowRect.right - windowRect.left,
windowRect.bottom - windowRect.top,
SWP_NOOWNERZORDER | SWP_NOZORDER);
}
WndMain::WndMain(HINSTANCE x_hInstance) :
Wnd(x_hInstance),
m_bCreated(false),
@ -130,9 +176,6 @@ WndMain::WndMain(HINSTANCE x_hInstance) :
m_classname = "WndMain";
m_wndname = "Cxbx-Reloaded " _CXBX_VERSION;
m_w = 640;
m_h = 480;
m_XbeFilename = (char*)calloc(1, MAX_PATH);
m_CxbxDebugFilename = (char*)calloc(1, MAX_PATH);
@ -142,16 +185,6 @@ WndMain::WndMain(HINSTANCE x_hInstance) :
m_szRecentXbe[v] = 0;
}
// center to desktop
{
RECT rect;
GetWindowRect(GetDesktopWindow(), &rect);
m_x = rect.left + (rect.right - rect.left)/2 - m_w/2;
m_y = rect.top + (rect.bottom - rect.top)/2 - m_h/2;
}
// load configuration from registry
{
DWORD dwDisposition, dwType, dwSize;
@ -197,6 +230,12 @@ WndMain::WndMain(HINSTANCE x_hInstance) :
m_PatchCpuFrequency = 0;
}
dwType = REG_DWORD; dwSize = sizeof(DWORD);
result = RegQueryValueEx(hKey, "HackScaleViewport", NULL, &dwType, (PBYTE)&m_ScaleViewport, &dwSize);
if (result != ERROR_SUCCESS) {
m_ScaleViewport = 0;
}
dwType = REG_DWORD; dwSize = sizeof(DWORD);
result = RegQueryValueEx(hKey, "CxbxDebug", NULL, &dwType, (PBYTE)&m_CxbxDebug, &dwSize);
if (result != ERROR_SUCCESS) {
@ -359,6 +398,9 @@ WndMain::~WndMain()
dwType = REG_DWORD; dwSize = sizeof(DWORD);
RegSetValueEx(hKey, "HackPatchCpuFrequency", 0, dwType, (PBYTE)&m_PatchCpuFrequency, dwSize);
dwType = REG_DWORD; dwSize = sizeof(DWORD);
RegSetValueEx(hKey, "HackScaleViewport", 0, dwType, (PBYTE)&m_ScaleViewport, dwSize);
dwType = REG_DWORD; dwSize = sizeof(DWORD);
RegSetValueEx(hKey, "CxbxDebug", 0, dwType, (PBYTE)&m_CxbxDebug, dwSize);
@ -401,21 +443,10 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP
SetMenu(hwnd, hMenu);
}
// resize window so that client area := 640x480
{
RECT cRect;
RECT wRect;
// Set window size to GUI dimensions
ResizeWindow(hwnd, /*bForGUI=*/true);
GetClientRect(hwnd, &cRect);
GetWindowRect(hwnd, &wRect);
uint32 difW = (wRect.right - wRect.left) - (cRect.right);
uint32 difH = (wRect.bottom - wRect.top) - (cRect.bottom);
MoveWindow(hwnd, wRect.left, wRect.top, difW + m_w, difH + m_h, TRUE);
}
// initialize back buffer
// initialize back buffer
{
HDC hDC = GetDC(hwnd);
@ -477,8 +508,8 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP
{
CreateThread(NULL, NULL, CrashMonitorWrapper, (void*)this, NULL, NULL); // create the crash monitoring thread
if (m_hwndChild == NULL) {
float fps = 0;
float mspf = 0;
float fps = 0.0f;
float mspf = 0.0f;
int LedSequence[4] = { XBOX_LED_COLOUR_GREEN, XBOX_LED_COLOUR_GREEN, XBOX_LED_COLOUR_GREEN, XBOX_LED_COLOUR_GREEN };
g_EmuShared->SetCurrentMSpF(&mspf);
g_EmuShared->SetCurrentFPS(&fps);
@ -654,13 +685,15 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP
case VK_F9:
{
// Try to open the most recent Xbe if none is opened yet :
if (m_Xbe == nullptr)
OpenMRU(0);
if (!m_bIsStarted) {
if (m_Xbe == nullptr)
OpenMRU(0);
if (m_Xbe != nullptr)
if (!m_bIsStarted)
if (m_Xbe != nullptr)
StartEmulation(hwnd, debuggerOn);
}
}
break;
default:
{
@ -1338,6 +1371,11 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP
RefreshMenus();
break;
case ID_HACKS_SCALEVIEWPORT:
m_ScaleViewport = !m_ScaleViewport;
RefreshMenus();
break;
case ID_HELP_ABOUT:
{
ShowAboutDialog(hwnd);
@ -1768,6 +1806,9 @@ void WndMain::RefreshMenus()
chk_flag = (m_PatchCpuFrequency) ? MF_CHECKED : MF_UNCHECKED;
CheckMenuItem(settings_menu, ID_HACKS_PATCHCPUFREQUENCY, chk_flag);
chk_flag = (m_ScaleViewport) ? MF_CHECKED : MF_UNCHECKED;
CheckMenuItem(settings_menu, ID_HACKS_SCALEVIEWPORT, chk_flag);
}
// emulation menu
@ -2142,6 +2183,18 @@ void WndMain::StartEmulation(HWND hwndParent, DebuggerState LocalDebuggerState /
g_EmuShared->SetUncapFramerate(&m_UncapFramerate);
g_EmuShared->SetUseAllCores(&m_UseAllCores);
g_EmuShared->SetPatchCpuFrequency(&m_PatchCpuFrequency);
g_EmuShared->SetScaleViewport(&m_ScaleViewport);
if (m_ScaleViewport) {
// Set the window size to emulation dimensions
// Note : Doing this here assures the emulation process will use
// the configured dimensions (because if done inside the emulation
// process, that doesn't resize correctly sometimes)
// TODO : Instead of doing the resize before launch, move it
// towards CreateDevice emulation, using Xbox-requested dimensions
// (and fix the issue of incorrect resizing)
ResizeWindow(m_hwnd, /*bForGUI*/false);
}
// shell exe
{
@ -2211,6 +2264,8 @@ void WndMain::StopEmulation()
UpdateCaption();
RefreshMenus();
// Set the window size back to it's GUI dimensions
ResizeWindow(m_hwnd, /*bForGUI=*/true);
}

View File

@ -87,6 +87,11 @@ class WndMain : public Wnd
static void SuggestFilename(const char *x_orig_filename, char *x_filename, char x_extension[4]);
private:
// ******************************************************************
// * resize the main window for either GUI or emulation
// ******************************************************************
void ResizeWindow(HWND hwnd, bool bForGUI);
// ******************************************************************
// * after an xbe is loaded, some things must be updated
// ******************************************************************
@ -217,6 +222,7 @@ class WndMain : public Wnd
int m_UncapFramerate;
int m_UseAllCores;
int m_PatchCpuFrequency;
int m_ScaleViewport;
// ******************************************************************
// * debug output filenames

View File

@ -583,6 +583,7 @@ void PrintCurrentConfigurationLog()
printf("Uncap Framerate: %s\n", g_UncapFramerate == 1 ? "On" : "Off");
printf("Run Xbox threads on all cores: %s\n", g_UseAllCores == 1 ? "On" : "Off");
printf("Patch CPU Frequency (rdtsc): %s\n", g_PatchCpuFrequency == 1 ? "On" : "Off");
printf("Scale Xbox to host viewport (and back): %s\n", g_ScaleViewport == 1 ? "On" : "Off");
}
printf("------------------------- END OF CONFIG LOG ------------------------\n");
@ -1102,6 +1103,8 @@ __declspec(noreturn) void CxbxKrnlInit
g_UseAllCores = !!HackEnabled;
g_EmuShared->GetPatchCpuFrequency(&HackEnabled);
g_PatchCpuFrequency = !!HackEnabled;
g_EmuShared->GetScaleViewport(&HackEnabled);
g_ScaleViewport = !!HackEnabled;
}
#ifdef _DEBUG_PRINT_CURRENT_CONF

View File

@ -68,6 +68,7 @@ bool g_DisablePixelShaders = false;
bool g_UncapFramerate = false;
bool g_UseAllCores = false;
bool g_PatchCpuFrequency = false;
bool g_ScaleViewport = false;
// Delta added to host SystemTime, used in xboxkrnl::KeQuerySystemTime and xboxkrnl::NtSetSystemTime
LARGE_INTEGER HostSystemTimeDelta = {};

View File

@ -111,4 +111,5 @@ extern bool g_DisablePixelShaders;
extern bool g_UncapFramerate;
extern bool g_UseAllCores;
extern bool g_PatchCpuFrequency;
extern bool g_ScaleViewport;
#endif

View File

@ -99,9 +99,6 @@ static bool g_bSupportsFormatVolumeTexture[XTL::X_D3DFMT
static bool g_bSupportsFormatCubeTexture[XTL::X_D3DFMT_LIN_R8G8B8A8 + 1] = { false }; // Does device support surface format?
static XTL::LPDIRECTDRAW7 g_pDD7 = NULL; // DirectDraw7
static XTL::DDCAPS g_DriverCaps = { 0 };
static DWORD g_dwOverlayW = 640; // Cached Overlay Width
static DWORD g_dwOverlayH = 480; // Cached Overlay Height
static DWORD g_dwOverlayP = 640; // Cached Overlay Pitch
static HBRUSH g_hBgBrush = NULL; // Background Brush
static volatile bool g_bRenderWindowActive = false;
static XBVideo g_XBVideo;
@ -923,7 +920,6 @@ void SetHostResource(XTL::X_D3DResource* pXboxResource, XTL::IDirect3DResource*
hostResourceInfo.forceRehash = false;
g_HostResources[key] = hostResourceInfo;
}
XTL::IDirect3DSurface *GetHostSurface(XTL::X_D3DResource *pXboxResource)
@ -1119,6 +1115,40 @@ uint CxbxGetPixelContainerMipMapLevels
return 1;
}
uint32_t GetPixelContainerWidth(XTL::X_D3DPixelContainer *pPixelContainer)
{
DWORD Size = pPixelContainer->Size;
uint32_t Result;
if (Size != 0) {
Result = ((Size & X_D3DSIZE_WIDTH_MASK) /* >> X_D3DSIZE_WIDTH_SHIFT*/) + 1;
}
else {
DWORD l2w = (pPixelContainer->Format & X_D3DFORMAT_USIZE_MASK) >> X_D3DFORMAT_USIZE_SHIFT;
Result = 1 << l2w;
}
return Result;
}
uint32_t GetPixelContainerHeigth(XTL::X_D3DPixelContainer *pPixelContainer)
{
DWORD Size = pPixelContainer->Size;
uint32_t Result;
if (Size != 0) {
Result = ((Size & X_D3DSIZE_HEIGHT_MASK) >> X_D3DSIZE_HEIGHT_SHIFT) + 1;
}
else {
DWORD l2h = (pPixelContainer->Format & X_D3DFORMAT_VSIZE_MASK) >> X_D3DFORMAT_VSIZE_SHIFT;
Result = 1 << l2h;
}
return Result;
}
VOID CxbxGetPixelContainerMeasures
(
XTL::X_D3DPixelContainer *pPixelContainer,
@ -1387,36 +1417,24 @@ static DWORD WINAPI EmuRenderWindow(LPVOID lpVoid)
// create the window
{
DWORD dwStyle = (g_XBVideo.GetFullscreen() || (CxbxKrnl_hEmuParent == 0))? WS_OVERLAPPEDWINDOW : WS_CHILD;
int nTitleHeight = GetSystemMetrics(SM_CYCAPTION);
int nBorderWidth = GetSystemMetrics(SM_CXSIZEFRAME);
int nBorderHeight = GetSystemMetrics(SM_CYSIZEFRAME);
int x = 100, y = 100, nWidth = 640, nHeight = 480;
nWidth += nBorderWidth*2;
nHeight += nBorderHeight*2 + nTitleHeight;
sscanf(g_XBVideo.GetVideoResolution(), "%d x %d", &nWidth, &nHeight);
if(g_XBVideo.GetFullscreen())
{
x = y = nWidth = nHeight = 0;
dwStyle = WS_POPUP;
}
HWND hwndParent = GetDesktopWindow();
DWORD dwStyle = WS_POPUP;
RECT windowRect = { 0 };
if(!g_XBVideo.GetFullscreen())
{
hwndParent = CxbxKrnl_hEmuParent;
if (!g_XBVideo.GetFullscreen()) {
hwndParent = CxbxKrnl_hEmuParent;
GetWindowRect(hwndParent, &windowRect);
dwStyle = (CxbxKrnl_hEmuParent == 0) ? WS_OVERLAPPEDWINDOW : WS_CHILD;
}
g_hEmuWindow = CreateWindow
(
"CxbxRender", "Cxbx-Reloaded",
dwStyle, x, y, nWidth, nHeight,
dwStyle,
windowRect.left,
windowRect.top,
windowRect.right - windowRect.left,
windowRect.bottom - windowRect.top,
hwndParent, NULL, GetModuleHandle(NULL), NULL
);
}
@ -1805,25 +1823,51 @@ static DWORD WINAPI EmuCreateDeviceProxy(LPVOID)
{
DbgPrintf("EmuD3D8: CreateDevice proxy thread received request.\n");
if(g_EmuCDPD.bCreate)
{
// only one device should be created at once
// TODO: ensure all surfaces are somehow cleaned up?
if(g_pD3DDevice != nullptr)
{
DbgPrintf("EmuD3D8: CreateDevice proxy thread releasing old Device.\n");
// only one device should be created at once
if (g_pD3DDevice != nullptr) {
DbgPrintf("EmuD3D8: CreateDevice proxy thread releasing old Device.\n");
g_pD3DDevice->EndScene();
g_pD3DDevice->EndScene();
// Address DirectX Debug Runtime reported error in _DEBUG builds
// Direct3D8: (ERROR) :Not all objects were freed: the following indicate the types of unfreed objects.
#ifndef _DEBUG
while(g_pD3DDevice->Release() != 0);
#endif
for (auto &hostResourceIterator : g_HostResources) {
if (hostResourceIterator.second.pHostResource) {
(hostResourceIterator.second.pHostResource)->Release();
}
}
g_HostResources.clear();
g_pD3DDevice = nullptr;
}
// TODO: ensure all other resources are cleaned up too
g_EmuCDPD.hRet = g_pD3DDevice->Release();
// Address DirectX Debug Runtime reported error in _DEBUG builds
// Direct3D8: (ERROR) :Not all objects were freed: the following indicate the types of unfreed objects.
#ifndef _DEBUG
while(g_pD3DDevice->Release() != 0);
#endif
g_pD3DDevice = nullptr;
// cleanup overlay clipper
if (g_pDDClipper != nullptr) {
g_pDDClipper->Release();
g_pDDClipper = nullptr;
}
// cleanup directdraw surface
if (g_pDDSPrimary != nullptr) {
g_pDDSPrimary->Release();
g_pDDSPrimary = nullptr;
}
// cleanup directdraw
if (g_pDD7 != nullptr) {
g_pDD7->Release();
g_pDD7 = nullptr;
}
}
if (g_EmuCDPD.bCreate) {
if(g_EmuCDPD.XboxPresentationParameters.BufferSurfaces[0] != NULL)
EmuWarning("BufferSurfaces[0] : 0x%.08X", g_EmuCDPD.XboxPresentationParameters.BufferSurfaces[0]);
@ -1884,7 +1928,16 @@ static DWORD WINAPI EmuCreateDeviceProxy(LPVOID)
// retrieve resolution from configuration
if(g_EmuCDPD.HostPresentationParameters.Windowed)
{
sscanf(g_XBVideo.GetVideoResolution(), "%d x %d", &g_EmuCDPD.HostPresentationParameters.BackBufferWidth, &g_EmuCDPD.HostPresentationParameters.BackBufferHeight);
const char* resolution = g_XBVideo.GetVideoResolution();
if (2 != sscanf(resolution, "%d x %d", &g_EmuCDPD.HostPresentationParameters.BackBufferWidth, &g_EmuCDPD.HostPresentationParameters.BackBufferHeight)) {
DbgPrintf("EmuCreateDeviceProxy: Couldn't parse resolution : %s.\n", resolution);
}
else {
if (g_EmuCDPD.HostPresentationParameters.BackBufferWidth == 640)
DbgPrintf("EmuCreateDeviceProxy: Default width wasn't updated.\n");
if (g_EmuCDPD.HostPresentationParameters.BackBufferWidth == 480)
DbgPrintf("EmuCreateDeviceProxy: Default height wasn't updated.\n");
}
XTL::D3DDISPLAYMODE D3DDisplayMode;
@ -1897,11 +1950,20 @@ static DWORD WINAPI EmuCreateDeviceProxy(LPVOID)
{
char szBackBufferFormat[16];
sscanf(g_XBVideo.GetVideoResolution(), "%d x %d %*dbit %s (%d hz)",
&g_EmuCDPD.HostPresentationParameters.BackBufferWidth,
&g_EmuCDPD.HostPresentationParameters.BackBufferHeight,
szBackBufferFormat,
&g_EmuCDPD.HostPresentationParameters.FullScreen_RefreshRateInHz);
const char* resolution = g_XBVideo.GetVideoResolution();
if (4 != sscanf(resolution, "%d x %d %*dbit %s (%d hz)",
&g_EmuCDPD.HostPresentationParameters.BackBufferWidth,
&g_EmuCDPD.HostPresentationParameters.BackBufferHeight,
szBackBufferFormat,
&g_EmuCDPD.HostPresentationParameters.FullScreen_RefreshRateInHz)) {
DbgPrintf("EmuCreateDeviceProxy: Couldn't parse resolution : %s.\n", resolution);
}
else {
if (g_EmuCDPD.HostPresentationParameters.BackBufferWidth == 640)
DbgPrintf("EmuCreateDeviceProxy: Default width wasn't updated.\n");
if (g_EmuCDPD.HostPresentationParameters.BackBufferWidth == 480)
DbgPrintf("EmuCreateDeviceProxy: Default height wasn't updated.\n");
}
if(strcmp(szBackBufferFormat, "x1r5g5b5") == 0)
g_EmuCDPD.HostPresentationParameters.BackBufferFormat = XTL::D3DFMT_X1R5G5B5;
@ -2151,48 +2213,10 @@ static DWORD WINAPI EmuCreateDeviceProxy(LPVOID)
// begin scene
hRet = g_pD3DDevice->BeginScene();
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->BeginScene(2nd)");
// signal completion
g_EmuCDPD.bReady = false;
}
else
{
// release direct3d
if(g_pD3DDevice != nullptr)
{
DbgPrintf("EmuD3D8: CreateDevice proxy thread releasing old Device.\n");
g_pD3DDevice->EndScene();
g_EmuCDPD.hRet = g_pD3DDevice->Release();
if(g_EmuCDPD.hRet == 0)
g_pD3DDevice = nullptr;
}
// cleanup overlay clipper
if (g_pDDClipper != nullptr)
{
g_pDDClipper->Release();
g_pDDClipper = nullptr;
}
// cleanup directdraw surface
if(g_pDDSPrimary != nullptr)
{
g_pDDSPrimary->Release();
g_pDDSPrimary = nullptr;
}
// cleanup directdraw
if(g_pDD7 != nullptr)
{
g_pDD7->Release();
g_pDD7 = nullptr;
}
// signal completion
g_EmuCDPD.bReady = false;
}
// signal completion
g_EmuCDPD.bReady = false;
}
Sleep(1);
@ -3134,6 +3158,45 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_GetBackBuffer)
*ppBackBuffer = EMUPATCH(D3DDevice_GetBackBuffer2)(BackBuffer);
}
bool GetHostRenderTargetDimensions(DWORD *pHostWidth, DWORD *pHostHeight)
{
XTL::IDirect3DSurface* pHostRenderTarget = nullptr;
g_pD3DDevice->GetRenderTarget(
#ifdef CXBX_USE_D3D9
0, // RenderTargetIndex
#endif
&pHostRenderTarget);
// The following can only work if we could retrieve a host render target
if (!pHostRenderTarget)
return false;
// Get current host render target dimensions
XTL::D3DSURFACE_DESC HostRenderTarget_Desc;
pHostRenderTarget->GetDesc(&HostRenderTarget_Desc);
pHostRenderTarget->Release();
// Emulate field-rendering not by halving the host backbuffer, but by faking
// the host backbuffer to half-height, which results in a correct viewport scale :
if (g_EmuCDPD.XboxPresentationParameters.Flags & X_D3DPRESENTFLAG_FIELD) {
HostRenderTarget_Desc.Height /= 2;
}
*pHostWidth = HostRenderTarget_Desc.Width;
*pHostHeight = HostRenderTarget_Desc.Height;
return true;
}
DWORD ScaleDWORD(DWORD Value, DWORD FromMax, DWORD ToMax)
{
uint64_t tmp = Value;
tmp *= ToMax;
tmp /= FromMax;
return (DWORD)tmp;
}
// ******************************************************************
// * patch: D3DDevice_SetViewport
// ******************************************************************
@ -3146,42 +3209,41 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SetViewport)
LOG_FUNC_ONE_ARG(pViewport);
DWORD dwWidth = pViewport->Width;
DWORD dwHeight = pViewport->Height;
D3DVIEWPORT HostViewPort = *pViewport;
// resize to fit screen (otherwise crashes occur)
/*{
if(dwWidth > 640)
{
EmuWarning("Resizing Viewport->Width to 640");
((D3DVIEWPORT*)pViewport)->Width = 640;
}
if (g_ScaleViewport) {
#if 0 // Disabled for now, as the Xbox code triggers an error-code 6 in uc_emu_start()
// Use a trampoline here, so GetViewport can be unpatched
XB_trampoline(VOID, WINAPI, D3DDevice_SetViewport, (CONST X_D3DVIEWPORT8 *));
XB_D3DDevice_SetViewport(pViewport);
#endif
if(dwHeight > 480)
{
EmuWarning("Resizing Viewport->Height to 480");
((D3DVIEWPORT*)pViewport)->Height = 480;
}
}*/
// Get current Xbox render target dimensions
DWORD XboxRenderTarget_Width = GetPixelContainerWidth(g_pXboxRenderTarget);
DWORD XboxRenderTarget_Height = GetPixelContainerHeigth(g_pXboxRenderTarget);
HRESULT hRet = g_pD3DDevice->SetViewport(pViewport);
// Get current host render target dimensions
DWORD HostRenderTarget_Width;
DWORD HostRenderTarget_Height;
// restore originals
/*{
if(dwWidth > 640)
((D3DVIEWPORT*)pViewport)->Width = dwWidth;
if (GetHostRenderTargetDimensions(&HostRenderTarget_Width, &HostRenderTarget_Height)) {
if(dwHeight > 480)
((D3DVIEWPORT*)pViewport)->Height = dwHeight;
}
// Scale Xbox to host dimensions (avoiding hard-coding 640 x 480)
HostViewPort.X = ScaleDWORD(pViewport->X, XboxRenderTarget_Width, HostRenderTarget_Width);
HostViewPort.Y = ScaleDWORD(pViewport->Y, XboxRenderTarget_Height, HostRenderTarget_Height);
HostViewPort.Width = ScaleDWORD(pViewport->Width, XboxRenderTarget_Width, HostRenderTarget_Width);
HostViewPort.Height = ScaleDWORD(pViewport->Height, XboxRenderTarget_Height, HostRenderTarget_Height);
// TODO : Fix test-case Shenmue 2 (which halves height, leaving the bottom half unused)
HostViewPort.MinZ = pViewport->MinZ; // No need scale Z for now
HostViewPort.MaxZ = pViewport->MaxZ;
}
else {
EmuWarning("GetHostRenderTargetDimensions failed - SetViewport sets Xbox viewport instead!");
}
}
HRESULT hRet = g_pD3DDevice->SetViewport(&HostViewPort);
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetViewport");
if(FAILED(hRet))
{
EmuWarning("Unable to set viewport! We're lying");
hRet = D3D_OK;
}*/
}
// ******************************************************************
@ -3196,15 +3258,44 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_GetViewport)
LOG_FUNC_ONE_ARG(pViewport);
HRESULT hRet = g_pD3DDevice->GetViewport(pViewport);
D3DVIEWPORT HostViewPort;
HRESULT hRet = g_pD3DDevice->GetViewport(&HostViewPort);
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->GetViewport");
if(FAILED(hRet))
{
EmuWarning("Unable to get viewport! - We're lying");
if (!g_ScaleViewport) {
*pViewport = HostViewPort;
}
else {
// Note : We cannot return the Xbox viewport as set in EMUPATCH(D3DDevice_SetViewport)
// because various Xbox D3D functions reset the Xbox viewport. Since we call comparable
// functions on host D3D, the host viewport is better suited as a return value;
// We just need to scale the host viewport back to Xbox dimensions - the exact opposite
// operation from the up-scaling that happens in EMUPATCH(D3DDevice_SetViewport).
hRet = D3D_OK;
}
// Get current host render target dimensions
DWORD HostRenderTarget_Width;
DWORD HostRenderTarget_Height;
if (GetHostRenderTargetDimensions(&HostRenderTarget_Width, &HostRenderTarget_Height)) {
// Get current Xbox render target dimensions
DWORD XboxRenderTarget_Width = GetPixelContainerWidth(g_pXboxRenderTarget);
DWORD XboxRenderTarget_Height = GetPixelContainerHeigth(g_pXboxRenderTarget);
// Scale host back to Xbox dimensions (avoiding hard-coding 640 x 480)
pViewport->X = ScaleDWORD(HostViewPort.X, HostRenderTarget_Width, XboxRenderTarget_Width);
pViewport->Y = ScaleDWORD(HostViewPort.Y, HostRenderTarget_Height, XboxRenderTarget_Height);
pViewport->Width = ScaleDWORD(HostViewPort.Width, HostRenderTarget_Width, XboxRenderTarget_Width);
pViewport->Height = ScaleDWORD(HostViewPort.Height, HostRenderTarget_Height, XboxRenderTarget_Height);
pViewport->MinZ = HostViewPort.MinZ; // No need scale Z for now
pViewport->MaxZ = HostViewPort.MaxZ;
}
else {
*pViewport = HostViewPort;
EmuWarning("GetHostRenderTargetDimensions failed - GetViewport returns host viewport instead!");
}
}
}
// LTCG specific D3DDevice_GetViewportOffsetAndScale function...
@ -3244,6 +3335,10 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_GetViewportOffsetAndScale)
LOG_FUNC_ARG(pScale)
LOG_FUNC_END;
LOG_TEST_CASE("D3DDevice_GetViewportOffsetAndScale"); // Get us some test-cases
// Test case : Spongebob - Battle for Bikini Bottom
#if 0
float fScaleX = 1.0f;
float fScaleY = 1.0f;
float fScaleZ = 1.0f;
@ -3251,22 +3346,8 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_GetViewportOffsetAndScale)
float fOffsetY = 0.5 + 1.0/32;
X_D3DVIEWPORT8 Viewport;
EMUPATCH(D3DDevice_GetViewport)(&Viewport);
pScale->x = 1.0f;
pScale->y = 1.0f;
pScale->z = 1.0f;
pScale->w = 1.0f;
pOffset->x = 0.0f;
pOffset->y = 0.0f;
pOffset->z = 0.0f;
pOffset->w = 0.0f;
/*
pScale->x = (float)Viewport.Width * 0.5f * fScaleX;
pScale->y = (float)Viewport.Height * -0.5f * fScaleY;
pScale->z = (Viewport.MaxZ - Viewport.MinZ) * fScaleZ;
@ -3276,9 +3357,17 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_GetViewportOffsetAndScale)
pOffset->y = (float)Viewport.Height * fScaleY * 0.5f + (float)Viewport.Y * fScaleY + fOffsetY;
pOffset->z = Viewport.MinZ * fScaleZ;
pOffset->w = 0;
*/
#else
pScale->x = 1.0f;
pScale->y = 1.0f;
pScale->z = 1.0f;
pScale->w = 1.0f;
pOffset->x = 0.0f;
pOffset->y = 0.0f;
pOffset->z = 0.0f;
pOffset->w = 0.0f;
#endif
}
// LTCG specific D3DDevice_SetShaderConstantMode function...
// This uses a custom calling convention where parameter is passed in EAX
@ -4521,12 +4610,11 @@ void CreateHostResource(XTL::X_D3DResource *pResource, int iTextureStage, DWORD
XTL::X_D3DPixelContainer *pPixelContainer = (XTL::X_D3DPixelContainer*)pResource;
XTL::X_D3DFORMAT X_Format = GetXboxPixelContainerFormat(pPixelContainer);
DWORD D3DUsage = 0;
XTL::D3DPOOL D3DPool = XTL::D3DPOOL_MANAGED; // TODO : Nuance D3DPOOL where/when needed
if (pPixelContainer == g_pXboxDepthStencil) {
if (EmuXBFormatIsDepthBuffer(X_Format))
D3DUsage = D3DUSAGE_DEPTHSTENCIL;
else
EmuWarning("Updating DepthStencil %s with an incompatible format!", ResourceTypeName);
if (EmuXBFormatIsDepthBuffer(X_Format)) {
D3DUsage = D3DUSAGE_DEPTHSTENCIL;
D3DPool = XTL::D3DPOOL_DEFAULT;
}
else if (pPixelContainer == g_pXboxRenderTarget) {
if (EmuXBFormatIsRenderTarget(X_Format))
@ -4670,8 +4758,6 @@ void CreateHostResource(XTL::X_D3DResource *pResource, int iTextureStage, DWORD
XTL::IDirect3DTexture *pNewHostTexture = nullptr; // for X_D3DRTYPE_TEXTURE
XTL::IDirect3DVolumeTexture *pNewHostVolumeTexture = nullptr; // for X_D3DRTYPE_VOLUMETEXTURE
XTL::IDirect3DCubeTexture *pNewHostCubeTexture = nullptr; // for X_D3DRTYPE_CUBETEXTURE
XTL::D3DPOOL D3DPool = XTL::D3DPOOL_MANAGED; // TODO : Nuance D3DPOOL where/when needed
HRESULT hRet;
// Create the surface/volume/(volume/cube/)texture
@ -5220,11 +5306,12 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_UpdateOverlay)
if (pSurface == NULL) {
EmuWarning("pSurface == NULL!");
} else {
uint08 *pYUY2SourceBuffer = (uint08*)GetDataFromXboxResource(pSurface);
g_dwOverlayW = (pSurface->Size & X_D3DSIZE_WIDTH_MASK) + 1;
g_dwOverlayH = ((pSurface->Size & X_D3DSIZE_HEIGHT_MASK) >> X_D3DSIZE_HEIGHT_SHIFT) + 1;
g_dwOverlayP = (((pSurface->Size & X_D3DSIZE_PITCH_MASK) >> X_D3DSIZE_PITCH_SHIFT) + 1) * 64;
uint08 *pOverlayData = (uint08*)GetDataFromXboxResource(pSurface);
UINT OverlayWidth, OverlayHeight, OverlayDepth, OverlayRowPitch, OverlaySlicePitch;
CxbxGetPixelContainerMeasures(
(XTL::X_D3DPixelContainer *)pSurface,
0, // dwMipMapLevel
&OverlayWidth, &OverlayHeight, &OverlayDepth, &OverlayRowPitch, &OverlaySlicePitch);
RECT EmuSourRect;
RECT EmuDestRect;
@ -5232,7 +5319,7 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_UpdateOverlay)
if (SrcRect != NULL) {
EmuSourRect = *SrcRect;
} else {
SetRect(&EmuSourRect, 0, 0, g_dwOverlayW, g_dwOverlayH);
SetRect(&EmuSourRect, 0, 0, OverlayWidth, OverlayHeight);
}
if (DstRect != NULL) {
@ -5279,9 +5366,9 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_UpdateOverlay)
/* pDestSurface = */ pCurrentHostBackBuffer,
/* pDestPalette = */ nullptr, // Palette not needed for YUY2
/* pDestRect = */DstRect, // Either the unmodified original (can be NULL) or a pointer to our local variable
/* pSrcMemory = */ pYUY2SourceBuffer, // Source buffer
/* pSrcMemory = */ pOverlayData, // Source buffer
/* SrcFormat = */ D3DFMT_YUY2,
/* SrcPitch = */ g_dwOverlayP,
/* SrcPitch = */ OverlayRowPitch,
/* pSrcPalette = */ nullptr, // Palette not needed for YUY2
/* SrcRect = */ &EmuSourRect,
/* Filter = */ D3DX_FILTER_POINT, // Dxbx note : D3DX_FILTER_LINEAR gives a smoother image, but 'bleeds' across borders
@ -6570,8 +6657,10 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SetVertexShader)
// 59 (c-37) used for screen space transformation.
if(g_VertexShaderConstantMode != X_D3DSCM_NORESERVEDCONSTANTS)
{
// TODO: Proper solution.
static float vScale[] = { (2.0f / 640), (-2.0f / 480), 0.0f, 0.0f };
D3DVIEWPORT ViewPort;
g_pD3DDevice->GetViewport(&ViewPort);
float vScale[] = { (2.0f / ViewPort.Width), (-2.0f / ViewPort.Height), 0.0f, 0.0f };
static float vOffset[] = { -1.0f, 1.0f, 0.0f, 1.0f };
#ifdef CXBX_USE_D3D9

View File

@ -358,7 +358,12 @@ typedef enum _X_D3DSET_DEPTH_CLIP_PLANES_FLAGS
}
X_D3DSET_DEPTH_CLIP_PLANES_FLAGS;
#define X_D3DPRESENTFLAG_LOCKABLE_BACKBUFFER 0x00000001
#define X_D3DPRESENTFLAG_WIDESCREEN 0x00000010
#define X_D3DPRESENTFLAG_INTERLACED 0x00000020
#define X_D3DPRESENTFLAG_PROGRESSIVE 0x00000040
#define X_D3DPRESENTFLAG_FIELD 0x00000080
#define X_D3DPRESENTFLAG_10X11PIXELASPECTRATIO 0x00000100
typedef struct _X_D3DDISPLAYMODE
{

View File

@ -128,6 +128,8 @@ class EmuShared : public Mutex
void SetUseAllCores(int* value) { Lock(); m_UseAllCores = *value; Unlock(); }
void GetPatchCpuFrequency(int* value) { Lock(); *value = m_PatchCpuFrequeny; Unlock(); }
void SetPatchCpuFrequency(int* value) { Lock(); m_PatchCpuFrequeny = *value; Unlock(); }
void GetScaleViewport(int* value) { Lock(); *value = m_ScaleViewport; Unlock(); }
void SetScaleViewport(int* value) { Lock(); m_ScaleViewport = *value; Unlock(); }
// ******************************************************************
// * MSpF/Benchmark values Accessors
@ -202,6 +204,7 @@ class EmuShared : public Mutex
bool m_bMultiXbeFlag;
bool m_bDebugging;
int m_LedSequence[4];
int m_ScaleViewport;
};
// ******************************************************************