修改 CHUNITHM 渲染分辨率
CHUNITHM 是一个固定渲染分辨率为 1920x1080 的游戏, 最近沉迷 Windows On ARM 尝试运行发现渲染压力过大只有 10fps. 遂尝试修改渲染分辨率。
起初尝试修改游戏代码但是发现由于 UI 设计为固定1080p, 修改了之后会导致 UI 超出渲染范围
最后经过尝试, HOOK 了 D3D9 以及创建窗口的代码来让游戏以为自己是 1080p 渲染的情况下实际以目标分辨率渲染,并且渲染分辨率和输出分辨率可分离。
HOOK 之后的 API 如下, 具体 HOOK 实现不做赘述:
BOOL __stdcall SetRectHook(LPRECT lprc, int xLeft, int yTop, int xRight, int yBottom)
{
lprc->left = 0;
lprc->top = 0;
lprc->right = g_config.out_width;
lprc->bottom = g_config.out_height;
return TRUE;
}
HRESULT __stdcall d3d9ex_proxy::CreateDevice(UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DDevice9** ppReturnedDeviceInterface)
{
IDirect3DDevice9* device = nullptr;
pPresentationParameters->BackBufferWidth = g_config.out_width;
pPresentationParameters->BackBufferHeight = g_config.out_height;
if (g_config.msaa_level)
{
pPresentationParameters->MultiSampleType = static_cast<D3DMULTISAMPLE_TYPE>(g_config.msaa_level);
pPresentationParameters->MultiSampleQuality = g_config.msaa_level;
}
auto hr = m_d3d->CreateDevice(Adapter, DeviceType, hFocusWindow, BehaviorFlags, pPresentationParameters, &device);
if (!SUCCEEDED(hr)) return hr;
*ppReturnedDeviceInterface = new d3d9ex_device_proxy(reinterpret_cast<IDirect3DDevice9Ex*>(device));
log("interface ex: created device\n");
return hr;
}
HRESULT __stdcall d3d9ex_device_proxy::CreateTexture(UINT Width, UINT Height, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DTexture9** ppTexture, HANDLE* pSharedHandle)
{
if (Usage == D3DUSAGE_RENDERTARGET || Usage == D3DUSAGE_DEPTHSTENCIL)
{
log("create render target: %u %u %x\n", Width, Height, Format);
if (Width == 1920 && Height == 1080)
{
if (Format == D3DFMT_A16B16G16R16F)
Format = D3DFMT_A8B8G8R8;
Width = g_config.render_width;
Height = g_config.render_height;
log("overridding render size: %u %u\n", Width, Height);
}
}
return m_device->CreateTexture(Width, Height, Levels, Usage, Format, Pool, ppTexture, pSharedHandle);
}
HRESULT __stdcall d3d9ex_device_proxy::SetViewport(const D3DVIEWPORT9* pViewport)
{
auto vp = const_cast<D3DVIEWPORT9*>(pViewport);
if (vp->Width == 1920 && vp->Height == 1080)
{
IDirect3DSurface9* backbuffer;
IDirect3DSurface9* rt;
m_device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);
m_device->GetRenderTarget(0, &rt);
if (rt == backbuffer)
{
vp->Width = g_config.out_width;
vp->Height = g_config.out_height;
}
else
{
vp->Width = g_config.render_width;
vp->Height = g_config.render_height;
}
}
return m_device->SetViewport(pViewport);
}
最终效果如下