mirror of
https://github.com/djhackersdev/bemanitools.git
synced 2025-02-26 22:49:28 +01:00
feat: d3d9-monitor-check tool
A separate application to run the infamous IIDX “monitor check”. The on-screen output has been enhanced to provide more detailed information about the on-going process. The tool furthermore allows basic querying of adapter and adapter modes information from the command line. These additional options can be useful to gather more debug information or select correct parameters for the monitor test from actually supported mode parameters by the adapter. The tool has been tested on an actual cabinet with nvgpu setting different custom timings. The accuracy seems to be even higher than what IIDX’s monitor check is actually showing. For example, with a custom timing of 59.900, the tool yields 59.902. Meanwhile, the monitor check of iidx 29 59.8981 hz to 59.8997 hz on screen. This doesn’t mean the game’s getting inaccurate values. The game actually syncs and plays just fine. However, the game’s monitor check cannot be used as a reference for “getting the avg. refresh rate” value as an input parameter for other tools, e.g. chart patching with btools.
This commit is contained in:
parent
a11c7a0704
commit
db6e7a6ad9
@ -101,6 +101,7 @@ include src/main/camhook/Module.mk
|
||||
include src/main/cconfig/Module.mk
|
||||
include src/main/config/Module.mk
|
||||
include src/main/d3d9-frame-graph-hook/Module.mk
|
||||
include src/main/d3d9-monitor-check/Module.mk
|
||||
include src/main/d3d9-util/Module.mk
|
||||
include src/main/d3d9exhook/Module.mk
|
||||
include src/main/ddrhook-util/Module.mk
|
||||
@ -240,6 +241,7 @@ $(zipdir)/tools.zip: \
|
||||
build/bin/indep-32/ezusb-tool.exe \
|
||||
build/bin/indep-32/nvgpu.exe \
|
||||
build/bin/indep-32/d3d9-frame-graph-hook.dll \
|
||||
build/bin/indep-32/d3d9-monitor-check.exe \
|
||||
| $(zipdir)/
|
||||
$(V)echo ... $@
|
||||
$(V)zip -j $@ $^
|
||||
@ -256,6 +258,7 @@ $(zipdir)/tools-x64.zip: \
|
||||
build/bin/indep-64/mempatch-hook.dll \
|
||||
build/bin/indep-64/nvgpu.exe \
|
||||
build/bin/indep-64/d3d9-frame-graph-hook.dll \
|
||||
build/bin/indep-64/d3d9-monitor-check.exe \
|
||||
| $(zipdir)/
|
||||
$(V)echo ... $@
|
||||
$(V)zip -j $@ $^
|
||||
|
@ -119,6 +119,8 @@ The following games are supported with their corresponding hook-libraries.
|
||||
- [extiotest](doc/tools/extiotest.md)
|
||||
- [aciotest](doc/tools/aciotest.md): Command line tool to quickly test ACIO devices
|
||||
- config: UI input/output configuration tool when using the default bemanitools API (geninput)
|
||||
- [d3d9-monitor-check](doc/tools/d3d9-monitor-check.md): Command line tool to check the monitor refresh rate of the
|
||||
current GPU + monitor configuration
|
||||
- ir-beat-patch-9/10: Patch the IR beat phase on IIDX 9 and 10
|
||||
- [mempatch-hook](doc/tools/mempatch-hook.md): Patch raw memory locations in the target process
|
||||
based on the provided configuration
|
||||
|
27
doc/tools/d3d9-monitor-check.md
Normal file
27
doc/tools/d3d9-monitor-check.md
Normal file
@ -0,0 +1,27 @@
|
||||
# D3D9 Monitor Check
|
||||
|
||||
A separate application to run the infamous IIDX “monitor check” without having to run the actual
|
||||
game. The tool can be used to test measure the current avg. monitor refresh rate or debug/check if
|
||||
that value is fluctuating for some reason.
|
||||
|
||||
The final avg. value that is provided at the end of the test can be used as input for other tooling
|
||||
or settings (e.g. patching charts to a different refresh rate on older games with bemanitools).
|
||||
|
||||
Simply run the tool without any arguments to get a full synopsis with usage instructions.
|
||||
|
||||
## "Accuracy" remarks
|
||||
|
||||
The tool has been tested on an actual cabinet with `nvgpu` setting different custom timings. The
|
||||
accuracy seems to be even higher than what IIDX’s monitor check is actually showing. For example,
|
||||
with a custom timing of 59.900 hz, this tool yields fairly accurate and stable avg. 59.902 hz.
|
||||
|
||||
The monitor check of IIDX 29 shows results of 59.8981 hz to 59.8997 hz on screen. As these are the
|
||||
only visible values to the user, determining a specific (avg.) value that can be used as input for
|
||||
other tooling or settings (e.g. patching charts to a different refresh rate on older games with
|
||||
bemanitools) is difficult. This doesn't mean that the game's monitor checks are actually
|
||||
inaccurate or wrong. Modern games with a built-in monitor check (starting IIDX 20) are syncing up
|
||||
fine and don't need any further patching or modifications.
|
||||
|
||||
For older games, picking a value that is not as close as possible to an accurate avg. value can
|
||||
easily lead to issues with sync. So it's recommended to use the d3d9-monitor-check tool to get the
|
||||
most accurate value.
|
13
src/main/d3d9-monitor-check/Module.mk
Normal file
13
src/main/d3d9-monitor-check/Module.mk
Normal file
@ -0,0 +1,13 @@
|
||||
exes += d3d9-monitor-check \
|
||||
|
||||
ldflags_d3d9-monitor-check := \
|
||||
-ld3d9 \
|
||||
-ldwmapi \
|
||||
-lgdi32 \
|
||||
-ld3dx9 \
|
||||
|
||||
libs_d3d9-monitor-check := \
|
||||
util \
|
||||
|
||||
src_d3d9-monitor-check := \
|
||||
main.c \
|
695
src/main/d3d9-monitor-check/main.c
Normal file
695
src/main/d3d9-monitor-check/main.c
Normal file
@ -0,0 +1,695 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <d3d9.h>
|
||||
#include <d3dx9core.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "util/time.h"
|
||||
#include "util/winerr.h"
|
||||
|
||||
#define printf_out(fmt, ...) \
|
||||
fprintf(stdout, fmt, ##__VA_ARGS__)
|
||||
#define printf_err(fmt, ...) \
|
||||
fprintf(stderr, fmt, ##__VA_ARGS__)
|
||||
#define printfln_out(fmt, ...) \
|
||||
fprintf(stdout, fmt "\n", ##__VA_ARGS__)
|
||||
#define printfln_err(fmt, ...) \
|
||||
fprintf(stderr, fmt "\n", ##__VA_ARGS__)
|
||||
|
||||
#define printfln_winerr(fmt, ...) \
|
||||
char *winerr = util_winerr_format_last_error_code(); \
|
||||
fprintf(stderr, fmt ": %s\n", ##__VA_ARGS__, winerr); \
|
||||
free(winerr);
|
||||
|
||||
static const D3DFORMAT _d3dformat = D3DFMT_X8R8G8B8;
|
||||
|
||||
static void _print_synopsis()
|
||||
{
|
||||
printfln_err("D3D9 monitor check");
|
||||
printfln_err("");
|
||||
printfln_err("Improved open source re-implementation of IIDX's infamous \"monitor check\" screen");
|
||||
printfln_err("Run a bare D3D9 render loop to measure the refresh rate of the current GPU + monitor configuration");
|
||||
printfln_err("");
|
||||
printfln_err("Usage:");
|
||||
printfln_err(" d3d9-monitor-check <command> <args>");
|
||||
printfln_err("");
|
||||
printfln_err("Available commands:");
|
||||
printfln_err(" adapter: Query adapter information");
|
||||
printfln_err(" modes: Query adapter modes");
|
||||
printfln_err(" run <width> <height> <refresh_rate> [--total-warm-up-frame-count n] [--total-frame-count n] [--windowed] [--vsync-off]: Run the monitor check. Ensure that the mandatory parameters for width, height and refresh rate are values that are supported by the adapter's mode. Use the \"modes\" subcommand to get a list of supported modes.");
|
||||
printfln_err(" width: Width of the rendering resolution to run the test at");
|
||||
printfln_err(" height: Height of the rendering resolution to run the test at");
|
||||
printfln_err(" refresh_rate: Target refresh rate to run the test at");
|
||||
printfln_err(" total-warm-up-frame-count: Optional. Number of frames to warm-up before executing the main run that counts towards the measurement results");
|
||||
printfln_err(" total-frame-count: Optional. Total number of frames to run the test for that count towards the measurement results");
|
||||
printfln_err(" windowed: Optional. Run the test in windowed mode (not recommended)");
|
||||
printfln_err(" vsync-off: Optional. Run the test with vsync off (not recommended)");
|
||||
}
|
||||
|
||||
static bool _create_d3d_context(IDirect3D9 **d3d)
|
||||
{
|
||||
// Initialize D3D
|
||||
*d3d = Direct3DCreate9(D3D_SDK_VERSION);
|
||||
|
||||
if (!*d3d) {
|
||||
printfln_winerr("Creating d3d context failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _query_adapter_identifier(IDirect3D9 *d3d, D3DADAPTER_IDENTIFIER9 *identifier)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
hr = IDirect3D9_GetAdapterIdentifier(d3d, D3DADAPTER_DEFAULT, 0, identifier);
|
||||
|
||||
if (hr != D3D_OK) {
|
||||
printfln_winerr("GetAdapterIdentifier failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _create_window(uint32_t width, uint32_t height, HWND *hwnd)
|
||||
{
|
||||
WNDCLASSEX wc;
|
||||
|
||||
memset(&wc, 0, sizeof(wc));
|
||||
|
||||
wc.cbSize = sizeof(wc);
|
||||
wc.lpfnWndProc = DefWindowProc;
|
||||
wc.hInstance = GetModuleHandle(NULL);
|
||||
wc.lpszClassName = "D3D9MonitorCheck";
|
||||
|
||||
RegisterClassExA(&wc);
|
||||
|
||||
// Create window
|
||||
*hwnd = CreateWindowA(
|
||||
wc.lpszClassName,
|
||||
"D3D9 Monitor Check",
|
||||
WS_OVERLAPPEDWINDOW,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
width,
|
||||
height,
|
||||
NULL,
|
||||
NULL,
|
||||
wc.hInstance,
|
||||
NULL);
|
||||
|
||||
if (!*hwnd) {
|
||||
printfln_winerr("Failed to create window");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _create_d3d_device(
|
||||
HWND hwnd,
|
||||
IDirect3D9 *d3d,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
uint32_t refresh_rate,
|
||||
bool windowed,
|
||||
bool vsync_off,
|
||||
IDirect3DDevice9 **device)
|
||||
{
|
||||
D3DPRESENT_PARAMETERS pp;
|
||||
HRESULT hr;
|
||||
|
||||
memset(&pp, 0, sizeof(pp));
|
||||
|
||||
if (windowed) {
|
||||
ShowWindow(hwnd, SW_SHOW);
|
||||
|
||||
pp.Windowed = TRUE;
|
||||
pp.FullScreen_RefreshRateInHz = 0;
|
||||
} else {
|
||||
ShowCursor(FALSE);
|
||||
|
||||
pp.Windowed = FALSE;
|
||||
pp.FullScreen_RefreshRateInHz = refresh_rate;
|
||||
}
|
||||
|
||||
if (vsync_off) {
|
||||
pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
|
||||
} else {
|
||||
pp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
|
||||
}
|
||||
|
||||
pp.BackBufferWidth = width;
|
||||
pp.BackBufferHeight = height;
|
||||
pp.BackBufferFormat = _d3dformat;
|
||||
pp.BackBufferCount = 2;
|
||||
pp.MultiSampleType = D3DMULTISAMPLE_NONE;
|
||||
pp.MultiSampleQuality = 0;
|
||||
pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
||||
pp.hDeviceWindow = hwnd;
|
||||
pp.EnableAutoDepthStencil = TRUE;
|
||||
pp.AutoDepthStencilFormat = D3DFMT_D16;
|
||||
pp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
|
||||
|
||||
// Create D3D device
|
||||
hr = IDirect3D9_CreateDevice(
|
||||
d3d,
|
||||
D3DADAPTER_DEFAULT,
|
||||
D3DDEVTYPE_HAL,
|
||||
hwnd,
|
||||
D3DCREATE_HARDWARE_VERTEXPROCESSING,
|
||||
&pp,
|
||||
device);
|
||||
|
||||
if (hr != D3D_OK) {
|
||||
printfln_winerr("Creating d3d device failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint32_t _get_font_height(uint32_t resolution_height)
|
||||
{
|
||||
// Default size for 480p
|
||||
return (uint32_t) (20.0f * resolution_height / 480.0f);
|
||||
}
|
||||
|
||||
static uint32_t _get_text_offset_x(uint32_t resolution_width)
|
||||
{
|
||||
// Default offset for 480p
|
||||
return (uint32_t) (20.0f * resolution_width / 480.0f);
|
||||
}
|
||||
|
||||
static uint32_t _get_text_offset_y(uint32_t resolution_height, uint32_t font_height)
|
||||
{
|
||||
// Default offset for 480p
|
||||
return (uint32_t) (font_height + 10 * (resolution_height / 640.0f));
|
||||
}
|
||||
|
||||
static bool _create_font(IDirect3DDevice9 *device, uint32_t font_height, ID3DXFont **font)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
hr = D3DXCreateFont(device, font_height, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET,
|
||||
OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
|
||||
"Arial", font);
|
||||
|
||||
if (hr != D3D_OK) {
|
||||
printfln_winerr("Creating font failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void _draw_text(IDirect3DDevice9 *device, ID3DXFont *font, uint32_t font_height, int x, int y, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
char text[1024];
|
||||
RECT rect;
|
||||
|
||||
va_start(args, fmt);
|
||||
vsprintf(text, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
rect.left = x;
|
||||
rect.top = y;
|
||||
// Base width of 300 is based on 480p
|
||||
rect.right = x + (480 * (font_height / 20.0f));
|
||||
rect.bottom = y + font_height;
|
||||
|
||||
ID3DXFont_DrawText(font, NULL, text, -1, &rect, DT_LEFT | DT_TOP, D3DCOLOR_XRGB(255, 255, 255));
|
||||
}
|
||||
|
||||
static bool _adapter()
|
||||
{
|
||||
IDirect3D9 *d3d;
|
||||
D3DADAPTER_IDENTIFIER9 identifier;
|
||||
|
||||
if (!_create_d3d_context(&d3d)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_query_adapter_identifier(d3d, &identifier)) {
|
||||
IDirect3D9_Release(d3d);
|
||||
return false;
|
||||
}
|
||||
|
||||
printfln_out("Driver: %s", identifier.Driver);
|
||||
printfln_out("Description: %s", identifier.Description);
|
||||
printfln_out("DeviceName: %s", identifier.DeviceName);
|
||||
#ifdef _WIN32
|
||||
printfln_out("DriverVersion: %lld", identifier.DriverVersion.QuadPart);
|
||||
#else
|
||||
printfln_out("DriverVersion: %lu.%lu", identifier.DriverVersionHighPart, identifier.DriverVersionLowPart);
|
||||
#endif
|
||||
printfln_out("VendorId: %lu", identifier.VendorId);
|
||||
printfln_out("DeviceId: %lu", identifier.DeviceId);
|
||||
printfln_out("SubSysId: %lu", identifier.SubSysId);
|
||||
printfln_out("Revision: %lu", identifier.Revision);
|
||||
printfln_out("DeviceIdentifier: {%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
|
||||
identifier.DeviceIdentifier.Data1,
|
||||
identifier.DeviceIdentifier.Data2,
|
||||
identifier.DeviceIdentifier.Data3,
|
||||
identifier.DeviceIdentifier.Data4[0],
|
||||
identifier.DeviceIdentifier.Data4[1],
|
||||
identifier.DeviceIdentifier.Data4[2],
|
||||
identifier.DeviceIdentifier.Data4[3],
|
||||
identifier.DeviceIdentifier.Data4[4],
|
||||
identifier.DeviceIdentifier.Data4[5],
|
||||
identifier.DeviceIdentifier.Data4[6],
|
||||
identifier.DeviceIdentifier.Data4[7]);
|
||||
printfln_out("WHQLLevel: %lu", identifier.WHQLLevel);
|
||||
|
||||
IDirect3D9_Release(d3d);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _modes()
|
||||
{
|
||||
IDirect3D9 *d3d;
|
||||
HRESULT hr;
|
||||
UINT mode_count;
|
||||
D3DDISPLAYMODE mode;
|
||||
|
||||
memset(&mode, 0, sizeof(D3DDISPLAYMODE));
|
||||
|
||||
if (!_create_d3d_context(&d3d)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mode_count = IDirect3D9_GetAdapterModeCount(d3d, D3DADAPTER_DEFAULT, _d3dformat);
|
||||
|
||||
printfln_err("Available adapter modes (total %d)", mode_count);
|
||||
printfln_err("Mode index: width x height @ refresh rate");
|
||||
|
||||
for (UINT i = 0; i < mode_count; i++) {
|
||||
hr = IDirect3D9_EnumAdapterModes(d3d, D3DADAPTER_DEFAULT, _d3dformat, i, &mode);
|
||||
|
||||
if (hr != D3D_OK) {
|
||||
printfln_winerr("EnumAdapterMode index %d failed", i);
|
||||
IDirect3D9_Release(d3d);
|
||||
return false;
|
||||
}
|
||||
|
||||
printfln_out("%d: %d x %d @ %d hz", i, mode.Width, mode.Height, mode.RefreshRate);
|
||||
}
|
||||
|
||||
IDirect3D9_Release(d3d);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _run(uint32_t width, uint32_t height, uint32_t refresh_rate, uint32_t total_warm_up_frame_count, uint32_t total_frame_count, bool windowed, bool vsync_off)
|
||||
{
|
||||
HWND hwnd;
|
||||
IDirect3D9 *d3d;
|
||||
D3DADAPTER_IDENTIFIER9 identifier;
|
||||
IDirect3DDevice9 *device;
|
||||
uint32_t font_height;
|
||||
ID3DXFont *font;
|
||||
uint32_t text_offset_x;
|
||||
uint32_t text_offset_y;
|
||||
|
||||
MSG msg;
|
||||
bool exit_loop;
|
||||
bool warm_up_done;
|
||||
uint32_t warm_up_frame_count;
|
||||
uint32_t frame_count;
|
||||
uint64_t start_time;
|
||||
uint64_t end_time;
|
||||
uint64_t elapsed_us;
|
||||
uint64_t total_elapsed_us;
|
||||
|
||||
printfln_err("Creating d3d context ...");
|
||||
|
||||
if (!_create_d3d_context(&d3d)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
printfln_err("Querying adapter identifier ...");
|
||||
|
||||
if (!_query_adapter_identifier(d3d, &identifier)) {
|
||||
IDirect3D9_Release(d3d);
|
||||
return false;
|
||||
}
|
||||
|
||||
printfln_err("Adapter:");
|
||||
printfln_err("Driver: %s", identifier.Driver);
|
||||
printfln_err("Description: %s", identifier.Description);
|
||||
printfln_err("DeviceName: %s", identifier.DeviceName);
|
||||
#ifdef _WIN32
|
||||
printfln_err("DriverVersion: %lld", identifier.DriverVersion.QuadPart);
|
||||
#else
|
||||
printfln_err("DriverVersion: %lu.%lu", identifier.DriverVersionHighPart, identifier.DriverVersionLowPart);
|
||||
#endif
|
||||
|
||||
printfln_err("Creating window with %dx%d ...", width, height);
|
||||
|
||||
if (!_create_window(width, height, &hwnd)) {
|
||||
IDirect3D9_Release(d3d);
|
||||
return false;
|
||||
}
|
||||
|
||||
printfln_err("Creating d3d device %d x %d @ %d hz %s vsync %s ...",
|
||||
width,
|
||||
height,
|
||||
refresh_rate,
|
||||
windowed ? "windowed" : "fullscreen",
|
||||
vsync_off ? "off" : "on");
|
||||
|
||||
if (!_create_d3d_device(
|
||||
hwnd,
|
||||
d3d,
|
||||
width,
|
||||
height,
|
||||
refresh_rate,
|
||||
windowed,
|
||||
vsync_off,
|
||||
&device)) {
|
||||
IDirect3D9_Release(d3d);
|
||||
DestroyWindow(hwnd);
|
||||
return false;
|
||||
}
|
||||
|
||||
printfln_err("Creating font ...");
|
||||
|
||||
font_height = _get_font_height(height);
|
||||
|
||||
if (!_create_font(device, font_height, &font)) {
|
||||
IDirect3DDevice9_Release(device);
|
||||
IDirect3D9_Release(d3d);
|
||||
DestroyWindow(hwnd);
|
||||
return false;
|
||||
}
|
||||
|
||||
text_offset_x = _get_text_offset_x(width);
|
||||
text_offset_y = _get_text_offset_y(height, font_height);
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
|
||||
exit_loop = false;
|
||||
warm_up_done = false;
|
||||
|
||||
warm_up_frame_count = 0;
|
||||
frame_count = 0;
|
||||
|
||||
elapsed_us = 0;
|
||||
total_elapsed_us = 0;
|
||||
|
||||
printfln_err("Warm-up for %d frames ...", total_warm_up_frame_count);
|
||||
|
||||
start_time = time_get_counter();
|
||||
|
||||
while (warm_up_frame_count + frame_count < total_warm_up_frame_count + total_frame_count) {
|
||||
// reset when warm-up is done
|
||||
if (warm_up_frame_count >= total_warm_up_frame_count && !warm_up_done) {
|
||||
warm_up_done = true;
|
||||
total_elapsed_us = 0;
|
||||
printfln_err("Warm-up finished");
|
||||
printfln_err("Running test for %d frames ...", total_frame_count);
|
||||
}
|
||||
|
||||
// Required to not make windows think we are stuck and not responding
|
||||
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||
if (msg.message == WM_QUIT) {
|
||||
exit_loop = true;
|
||||
break;
|
||||
}
|
||||
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
if (exit_loop) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(VK_ESCAPE) & 0x8000) {
|
||||
exit_loop = true;
|
||||
break;
|
||||
}
|
||||
|
||||
IDirect3DDevice9_Clear(
|
||||
device,
|
||||
0,
|
||||
NULL,
|
||||
D3DCLEAR_TARGET,
|
||||
D3DCOLOR_XRGB(0, 0, 0),
|
||||
1.0f,
|
||||
0);
|
||||
IDirect3DDevice9_BeginScene(device);
|
||||
|
||||
_draw_text(device, font, font_height, text_offset_x, text_offset_y, "D3D9 Monitor Check");
|
||||
_draw_text(device, font, font_height, text_offset_x, text_offset_y * 3,
|
||||
"GPU: %s", identifier.Description);
|
||||
_draw_text(device, font, font_height, text_offset_x, text_offset_y * 4,
|
||||
"Spec: %d x %d @ %d hz, %s, vsync %s", width, height, refresh_rate,
|
||||
windowed ? "windowed" : "fullscreen", vsync_off ? "off" : "on");
|
||||
|
||||
if (warm_up_frame_count < total_warm_up_frame_count) {
|
||||
// First frame won't have any data available causing division by zero in the stats
|
||||
if (warm_up_frame_count != 0) {
|
||||
_draw_text(device, font, font_height, text_offset_x, text_offset_y * 6, "Status: Warm-up in progress ...");
|
||||
|
||||
_draw_text(device, font, font_height, text_offset_x, text_offset_y * 7,
|
||||
"Frame: %d / %d", warm_up_frame_count, total_warm_up_frame_count);
|
||||
_draw_text(device, font, font_height, text_offset_x, text_offset_y * 8,
|
||||
"Last frame time: %.3f ms", elapsed_us / 1000.0f);
|
||||
_draw_text(device, font, font_height, text_offset_x, text_offset_y * 9,
|
||||
"Avg frame time: %.3f ms", total_elapsed_us / warm_up_frame_count / 1000.0f);
|
||||
_draw_text(device, font, font_height, text_offset_x, text_offset_y * 10,
|
||||
"Last refresh rate: %.3f Hz", 1000.0f / (elapsed_us / 1000.0f));
|
||||
_draw_text(device, font, font_height, text_offset_x, text_offset_y * 11,
|
||||
"Avg refresh rate: %.3f Hz", 1000.0f / (total_elapsed_us / warm_up_frame_count / 1000.0f));
|
||||
}
|
||||
} else {
|
||||
// First frame won't have any data available causing division by zero in the stats
|
||||
if (frame_count != 0) {
|
||||
_draw_text(device, font, font_height, text_offset_x, text_offset_y * 6, "Status: Measuring in progress ...");
|
||||
|
||||
_draw_text(device, font, font_height, text_offset_x, text_offset_y * 7,
|
||||
"Frame: %d / %d", frame_count, total_frame_count);
|
||||
_draw_text(device, font, font_height, text_offset_x, text_offset_y * 8,
|
||||
"Last frame time: %.3f ms", elapsed_us / 1000.0f);
|
||||
_draw_text(device, font, font_height, text_offset_x, text_offset_y * 9,
|
||||
"Avg frame time: %.3f ms", total_elapsed_us / frame_count / 1000.0f);
|
||||
_draw_text(device, font, font_height, text_offset_x, text_offset_y * 10,
|
||||
"Last refresh rate: %.3f Hz", 1000.0f / (elapsed_us / 1000.0f));
|
||||
_draw_text(device, font, font_height, text_offset_x, text_offset_y * 11,
|
||||
"Avg refresh rate: %.3f Hz", 1000.0f / (total_elapsed_us / frame_count / 1000.0f));
|
||||
}
|
||||
}
|
||||
|
||||
_draw_text(device, font, font_height, text_offset_x, text_offset_y * 13, "Press ESC to exit early");
|
||||
|
||||
IDirect3DDevice9_EndScene(device);
|
||||
IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
|
||||
|
||||
end_time = time_get_counter();
|
||||
elapsed_us = time_get_elapsed_us(end_time - start_time);
|
||||
start_time = end_time;
|
||||
total_elapsed_us += elapsed_us;
|
||||
|
||||
if (warm_up_frame_count < total_warm_up_frame_count) {
|
||||
warm_up_frame_count++;
|
||||
} else {
|
||||
frame_count++;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
|
||||
printfln_err("Running test finished");
|
||||
|
||||
IDirect3DDevice9_Clear(
|
||||
device,
|
||||
0,
|
||||
NULL,
|
||||
D3DCLEAR_TARGET,
|
||||
D3DCOLOR_XRGB(0, 0, 0),
|
||||
1.0f,
|
||||
0);
|
||||
IDirect3DDevice9_BeginScene(device);
|
||||
|
||||
_draw_text(device, font, font_height, text_offset_x, text_offset_y, "D3D9 Monitor Check");
|
||||
_draw_text(device, font, font_height, text_offset_x, text_offset_y * 3,
|
||||
"GPU: %s", identifier.Description);
|
||||
_draw_text(device, font, font_height, text_offset_x, text_offset_y * 4,
|
||||
"Spec: %d x %d @ %d hz, %s, vsync %s", width, height, refresh_rate,
|
||||
windowed ? "windowed" : "fullscreen", vsync_off ? "off" : "on");
|
||||
|
||||
if (exit_loop) {
|
||||
_draw_text(device, font, font_height, text_offset_x, text_offset_y * 6, "Status: Exited early");
|
||||
} else {
|
||||
_draw_text(device, font, font_height, text_offset_x, text_offset_y * 6, "Status: Finished");
|
||||
}
|
||||
|
||||
_draw_text(device, font, font_height, text_offset_x, text_offset_y * 7,
|
||||
"Total warm-up frame count: %d", warm_up_frame_count);
|
||||
_draw_text(device, font, font_height, text_offset_x, text_offset_y * 8,
|
||||
"Total sample frame count: %d", frame_count);
|
||||
_draw_text(device, font, font_height, text_offset_x, text_offset_y * 9,
|
||||
"Avg frame time: %.3f ms", total_elapsed_us / frame_count / 1000.0f);
|
||||
_draw_text(device, font, font_height, text_offset_x, text_offset_y * 10,
|
||||
"Avg refresh rate: %.3f Hz", 1000.0f / (total_elapsed_us / frame_count / 1000.0f));
|
||||
|
||||
_draw_text(device, font, font_height, text_offset_x, text_offset_y * 12, "Exiting in 5 seconds ...");
|
||||
|
||||
IDirect3DDevice9_EndScene(device);
|
||||
IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
|
||||
|
||||
Sleep(5000);
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
|
||||
printfln_err("Final results");
|
||||
printfln_out("GPU: %s", identifier.Description);
|
||||
printfln_out("Spec: %d x %d @ %d hz, %s, vsync %s", width, height, refresh_rate,
|
||||
windowed ? "windowed" : "fullscreen", vsync_off ? "off" : "on");
|
||||
printfln_out("Avg frame time (ms): %.3f", total_elapsed_us / frame_count / 1000.0f);
|
||||
printfln_out("Avg refresh rate (hz): %.3f", 1000.0f / (total_elapsed_us / frame_count / 1000.0f));
|
||||
|
||||
ID3DXFont_Release(font);
|
||||
IDirect3DDevice9_Release(device);
|
||||
IDirect3D9_Release(d3d);
|
||||
DestroyWindow(hwnd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _cmd_adapter()
|
||||
{
|
||||
return _adapter();
|
||||
}
|
||||
|
||||
static bool _cmd_modes()
|
||||
{
|
||||
return _modes();
|
||||
}
|
||||
|
||||
static bool _cmd_run(int argc, char **argv)
|
||||
{
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t refresh_rate;
|
||||
uint32_t total_warm_up_frame_count;
|
||||
uint32_t total_frame_count;
|
||||
bool windowed;
|
||||
bool vsync_off;
|
||||
|
||||
if (argc < 3) {
|
||||
_print_synopsis();
|
||||
printfln_err("ERROR: Insufficient arguments");
|
||||
return false;
|
||||
}
|
||||
|
||||
width = atoi(argv[0]);
|
||||
|
||||
if (width == 0 || width > 16384) {
|
||||
_print_synopsis();
|
||||
printfln_err("ERROR: Invalid width: %d", width);
|
||||
return false;
|
||||
}
|
||||
|
||||
height = atoi(argv[1]);
|
||||
|
||||
if (height == 0 || height > 16384) {
|
||||
_print_synopsis();
|
||||
printfln_err("ERROR: Invalid height: %d", height);
|
||||
return false;
|
||||
}
|
||||
|
||||
refresh_rate = atoi(argv[2]);
|
||||
|
||||
if (refresh_rate == 0 || refresh_rate > 1000) {
|
||||
_print_synopsis();
|
||||
printfln_err("ERROR: Invalid refresh rate: %d", refresh_rate);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Sane defaults
|
||||
total_warm_up_frame_count = 500;
|
||||
total_frame_count = 1000;
|
||||
windowed = false;
|
||||
vsync_off = false;
|
||||
|
||||
for (int i = 3; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "--total-warm-up-frame-count")) {
|
||||
if (i + 1 < argc) {
|
||||
total_warm_up_frame_count = atoi(argv[++i]);
|
||||
|
||||
if (total_warm_up_frame_count == 0) {
|
||||
_print_synopsis();
|
||||
printfln_err("ERROR: Invalid total warm-up frame count: %d", total_warm_up_frame_count);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
_print_synopsis();
|
||||
printfln_err("ERROR: Missing argument for --total-warm-up-frame-count");
|
||||
return false;
|
||||
}
|
||||
} else if (!strcmp(argv[i], "--total-frame-count")) {
|
||||
if (i + 1 < argc) {
|
||||
total_frame_count = atoi(argv[++i]);
|
||||
|
||||
if (total_frame_count == 0) {
|
||||
_print_synopsis();
|
||||
printfln_err("ERROR: Invalid total frame count: %d", total_frame_count);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
_print_synopsis();
|
||||
printfln_err("ERROR: Missing argument for --total-frame-count");
|
||||
return false;
|
||||
}
|
||||
} else if (!strcmp(argv[i], "--windowed")) {
|
||||
windowed = true;
|
||||
} else if (!strcmp(argv[i], "--vsync-off")) {
|
||||
vsync_off = true;
|
||||
}
|
||||
}
|
||||
|
||||
return _run(width, height, refresh_rate, total_warm_up_frame_count, total_frame_count, windowed, vsync_off);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *command;
|
||||
|
||||
if (argc < 2) {
|
||||
_print_synopsis();
|
||||
printfln_err("ERROR: Insufficient arguments");
|
||||
return 1;
|
||||
}
|
||||
|
||||
command = argv[1];
|
||||
|
||||
if (!strcmp(command, "adapter")) {
|
||||
if (!_cmd_adapter(argc - 2, argv + 2)) {
|
||||
return 1;
|
||||
}
|
||||
} else if (!strcmp(command, "modes")) {
|
||||
if (!_cmd_modes(argc - 2, argv + 2)) {
|
||||
return 1;
|
||||
}
|
||||
} else if (!strcmp(command, "run")) {
|
||||
if (!_cmd_run(argc - 2, argv + 2)) {
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
_print_synopsis(argv[0]);
|
||||
printfln_err("ERROR: Unknown command: %s", command);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user