修改 CHUNITHM 渲染分辨率

SEGA Jul 4, 2024

CHUNITHM 是一个固定渲染分辨率为 1920x1080 的游戏, 最近沉迷 Windows On ARM 尝试运行发现渲染压力过大只有 10fps. 遂尝试修改渲染分辨率。

起初尝试修改游戏代码但是发现由于 UI 设计为固定1080p, 修改了之后会导致 UI 超出渲染范围

场景是正常的但是 UI 超出了 (720p)

最后经过尝试, 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);
}

最终效果如下

640x480 渲染, 1920x1080 输出
3840x2160 渲染, 2560x1440 输出

标签