mirror of
https://github.com/djhackersdev/bemanitools.git
synced 2026-09-27 17:26:24 -05:00
Compare commits
176 Commits
pr322
...
sapling-pr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
18f84e4751 | ||
|
|
19f0776627 | ||
|
|
aad38449e3 | ||
|
|
1c0092c9be | ||
|
|
1db5260a59 | ||
|
|
c337bdb7c0 | ||
|
|
9cb37ccc11 | ||
|
|
549e50dfa7 | ||
|
|
d5e4cc3447 | ||
|
|
ae02d6556b | ||
|
|
071a3994ed | ||
|
|
5bee76e553 | ||
|
|
3c2dda505e | ||
|
|
d840f7bb8f | ||
|
|
df4f646b70 | ||
|
|
ca9cac9c19 | ||
|
|
7943ecffcd | ||
|
|
51ce7c739a | ||
|
|
c6180bdf47 | ||
|
|
c3a337ceb4 | ||
|
|
a3d890dcd7 | ||
|
|
ee3d1d2592 | ||
|
|
4159813873 | ||
|
|
c5083a6d4a | ||
|
|
8752c7dcc5 | ||
|
|
6276cb4e97 | ||
|
|
fcbb4160ee | ||
|
|
9bcbe9170f | ||
|
|
e74e3f1472 | ||
|
|
2062b803ff | ||
|
|
7391cfa555 | ||
|
|
06d4467d5a | ||
|
|
b0b380e70c | ||
|
|
f0b3556ac5 | ||
|
|
54284adf5f | ||
|
|
451f9d4021 | ||
|
|
1b0426941d | ||
|
|
f5a82fe049 | ||
|
|
2a5ddacb36 | ||
|
|
9246f72b80 | ||
|
|
f6d8e30671 | ||
|
|
8afab5c232 | ||
|
|
e7459659dd | ||
|
|
3aa128e525 | ||
|
|
74bdd65098 | ||
|
|
a66aba45b9 | ||
|
|
1373e9f1f4 | ||
|
|
9e2319bd13 | ||
|
|
5687392a92 | ||
|
|
addcdf8d16 | ||
|
|
1fbb5ac39f | ||
|
|
191e1e74f0 | ||
|
|
34807f0b9d | ||
|
|
d442177f21 | ||
|
|
af372df06b | ||
|
|
4ed3c97c2a | ||
|
|
0d876fc806 | ||
|
|
2b08a0cc1a | ||
|
|
d8e604cdd9 | ||
|
|
95f792f655 | ||
|
|
7b8eec72d3 | ||
|
|
83621fa5d5 | ||
|
|
563d6dd793 | ||
|
|
e69c75bf7f | ||
|
|
847cc3322e | ||
|
|
48cd2bc687 | ||
|
|
3db8bc4898 | ||
|
|
9b5f627dd1 | ||
|
|
29f57065fe | ||
|
|
05889947fe | ||
|
|
2a34bb19da | ||
|
|
8b22ef1e8c | ||
|
|
b2006ec9be | ||
|
|
db6e7a6ad9 | ||
|
|
f15eec50fe | ||
|
|
27bb8a0e2d | ||
|
|
e0c7141896 | ||
|
|
5f5824f9f8 | ||
|
|
9cf9cac4e3 | ||
|
|
a11c7a0704 | ||
|
|
83473a83be | ||
|
|
aa3e7d307d | ||
|
|
1800f75f3d | ||
|
|
c0289b14d3 | ||
|
|
d17dcea594 | ||
|
|
002a5727ef | ||
|
|
1e4fffb5f9 | ||
|
|
93fe44b46e | ||
|
|
e12eb2b969 | ||
|
|
0afadc6576 | ||
|
|
8b82b32894 | ||
|
|
8efeb68c75 | ||
|
|
d482acd533 | ||
|
|
8d49bd8f40 | ||
|
|
d977a0bf35 | ||
|
|
dab2230a1c | ||
|
|
d25d49b668 | ||
|
|
8282a9f3f4 | ||
|
|
2c00da6232 | ||
|
|
cf8df078f5 | ||
|
|
4d8c9359a1 | ||
|
|
c33e9bb06a | ||
|
|
77ff211c68 | ||
|
|
0257ad6b42 | ||
|
|
15a1762837 | ||
|
|
d92987b229 | ||
|
|
5f9aaeddf9 | ||
|
|
4cbef617a8 | ||
|
|
2ca95ab6d8 | ||
|
|
61691f06a7 | ||
|
|
218ffe72c1 | ||
|
|
8c5cf383b6 | ||
|
|
075381481d | ||
|
|
94aa0bdda3 | ||
|
|
70e8e2a965 | ||
|
|
d1db1d816f | ||
|
|
d3273bf1d8 | ||
|
|
f4f8e7d8e2 | ||
|
|
84ff799024 | ||
|
|
c369412f70 | ||
|
|
26d1da8660 | ||
|
|
04310f49fd | ||
|
|
d72996c5d9 | ||
|
|
5ac858e15d | ||
|
|
e4a221e15b | ||
|
|
ea835b32ee | ||
|
|
fb1442b734 | ||
|
|
87b7e53973 | ||
|
|
2e45f095ba | ||
|
|
e12cd63ba2 | ||
|
|
a4b3f92935 | ||
|
|
1126011d99 | ||
|
|
6a98ce1f59 | ||
|
|
dc6e745533 | ||
|
|
8804e667b3 | ||
|
|
f5b8af3f2a | ||
|
|
5833197b03 | ||
|
|
339bf0dfed | ||
|
|
6a320a38c0 | ||
|
|
d8a5619a51 | ||
|
|
ab6c3fc8bc | ||
|
|
215a4bdb15 | ||
|
|
4ac1399923 | ||
|
|
f688eead44 | ||
|
|
e8221631f9 | ||
|
|
0afca1da49 | ||
|
|
734c17a0a2 | ||
|
|
6940a9de4b | ||
|
|
1d489643d1 | ||
|
|
33fee83aff | ||
|
|
8b377f256a | ||
|
|
64cc7084dc | ||
|
|
7a086ea60b | ||
|
|
7ee9a2e219 | ||
|
|
fa5a50167f | ||
|
|
7a56fab96e | ||
|
|
0c08d19276 | ||
|
|
c78639f094 | ||
|
|
2ebfd39bea | ||
|
|
2fe21ae6b7 | ||
|
|
daba638bb0 | ||
|
|
359ab5a541 | ||
|
|
6dd3669559 | ||
|
|
fbadcc9b41 | ||
|
|
ca91e4c4ae | ||
|
|
08a72abb58 | ||
|
|
7e49fad175 | ||
|
|
0adec478cc | ||
|
|
bc9b8b508e | ||
|
|
33372f3ef2 | ||
|
|
dedbdaf729 | ||
|
|
3865e09f06 | ||
|
|
517f8e885f | ||
|
|
560aba3133 | ||
|
|
6b75b33253 | ||
|
|
312aa619c6 |
@@ -100,8 +100,6 @@ include src/main/bstio/Module.mk
|
|||||||
include src/main/camhook/Module.mk
|
include src/main/camhook/Module.mk
|
||||||
include src/main/cconfig/Module.mk
|
include src/main/cconfig/Module.mk
|
||||||
include src/main/config/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/d3d9-util/Module.mk
|
||||||
include src/main/d3d9exhook/Module.mk
|
include src/main/d3d9exhook/Module.mk
|
||||||
include src/main/ddrhook-util/Module.mk
|
include src/main/ddrhook-util/Module.mk
|
||||||
@@ -234,9 +232,6 @@ $(zipdir)/tools.zip: \
|
|||||||
build/bin/indep-32/ezusb2-dbg-hook.dll \
|
build/bin/indep-32/ezusb2-dbg-hook.dll \
|
||||||
build/bin/indep-32/ezusb2-tool.exe \
|
build/bin/indep-32/ezusb2-tool.exe \
|
||||||
build/bin/indep-32/ezusb-tool.exe \
|
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)/
|
| $(zipdir)/
|
||||||
$(V)echo ... $@
|
$(V)echo ... $@
|
||||||
$(V)zip -j $@ $^
|
$(V)zip -j $@ $^
|
||||||
@@ -251,9 +246,6 @@ $(zipdir)/tools-x64.zip: \
|
|||||||
build/bin/indep-64/iidx-ezusb2-exit-hook.dll \
|
build/bin/indep-64/iidx-ezusb2-exit-hook.dll \
|
||||||
build/bin/indep-64/jbiotest.exe \
|
build/bin/indep-64/jbiotest.exe \
|
||||||
build/bin/indep-64/mempatch-hook.dll \
|
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)/
|
| $(zipdir)/
|
||||||
$(V)echo ... $@
|
$(V)echo ... $@
|
||||||
$(V)zip -j $@ $^
|
$(V)zip -j $@ $^
|
||||||
|
|||||||
@@ -119,8 +119,6 @@ The following games are supported with their corresponding hook-libraries.
|
|||||||
- [extiotest](doc/tools/extiotest.md)
|
- [extiotest](doc/tools/extiotest.md)
|
||||||
- [aciotest](doc/tools/aciotest.md): Command line tool to quickly test ACIO devices
|
- [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)
|
- 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
|
- 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
|
- [mempatch-hook](doc/tools/mempatch-hook.md): Patch raw memory locations in the target process
|
||||||
based on the provided configuration
|
based on the provided configuration
|
||||||
|
|||||||
319
doc/dev/journal/2025-02-09-iidx-engine.md
Normal file
319
doc/dev/journal/2025-02-09-iidx-engine.md
Normal file
@@ -0,0 +1,319 @@
|
|||||||
|
# IIDX engine overview and how game-play is impacted by hardware and software
|
||||||
|
|
||||||
|
Date: 2025-02-09 Author: icex2
|
||||||
|
|
||||||
|
This document provides information and explains the following:
|
||||||
|
|
||||||
|
* A sort-of taxonomy of the different major IIDX game engine versions
|
||||||
|
* How the core game-play part of the engine works regarding
|
||||||
|
* Threading model
|
||||||
|
* Main render loop
|
||||||
|
* Timing and synchronization
|
||||||
|
|
||||||
|
The goal is to capture key knowledge about how the game's engine works to enable a better
|
||||||
|
understanding for developing bemanitools and how certain features can impact performance and
|
||||||
|
synchronization during game-play.
|
||||||
|
|
||||||
|
This document is not claiming to be complete or 100% accurate. It is based on my own personal
|
||||||
|
research and understanding of the IIDX game engine. It is very likely that some of the information
|
||||||
|
is wrong or misunderstood. Feel free to raise any questions or concerns in an issue as I want
|
||||||
|
this document to be as accurate as possible.
|
||||||
|
|
||||||
|
## Taxonomy of IIDX game engine versions
|
||||||
|
|
||||||
|
With every version, there have been numerous changes and improvements to the game engine. The
|
||||||
|
following is a rough taxonomy that is focused on cabinet and hardware changes. As these are likely
|
||||||
|
the main driver for key changes to the software and game engine, they create fairly distinct
|
||||||
|
stages throughout the different versions of the game. The key attributes to be considered here are:
|
||||||
|
|
||||||
|
* Main PCB
|
||||||
|
* IO board
|
||||||
|
* Monitor
|
||||||
|
|
||||||
|
All of these had significant impact on key software features appearing or changing.
|
||||||
|
|
||||||
|
### Twinkle hardware era: 1st Style to 8th Style
|
||||||
|
|
||||||
|
* [Twinkle PCB](https://github.com/shizmob/arcade-docs/blob/main/konami/boards.md#twinkle)
|
||||||
|
* [Original rear projection monitor](https://github.com/shizmob/arcade-docs/blob/main/konami/products.md#iidx-rear-projection-monitor)
|
||||||
|
* Homogenous hardware and software
|
||||||
|
|
||||||
|
### 1st gen PC-based upgrade only: 9th Style
|
||||||
|
|
||||||
|
* 9th Style came as an upgrade kit only to existing twinkle-based cabinet hardware
|
||||||
|
* [KNM-845G3-A02 PCB](https://github.com/shizmob/arcade-docs/blob/main/konami/boards.md#knm-845g3-a02)
|
||||||
|
* [C02 EZUSB FX USB IO board](https://github.com/shizmob/arcade-docs/blob/main/konami/io.md#gec02-pwbaa)
|
||||||
|
* Magnetic card readers connected to ezusb IO board
|
||||||
|
|
||||||
|
### 1st gen PC-based with dedicated cabinet: 10th Style to DistorteD (13)
|
||||||
|
|
||||||
|
* From here on, old cabinets that received the "Twinkle hardware" upgrade kit could always receive software only
|
||||||
|
upgrades
|
||||||
|
* [CRT monitor](https://github.com/shizmob/arcade-docs/blob/main/konami/products.md#iidx-crt-monitor) with new dedicated
|
||||||
|
cabinets
|
||||||
|
* [D01 EZUSB FX USB IO board](https://github.com/shizmob/arcade-docs/blob/main/konami/io.md#d01-io)
|
||||||
|
* Slotted card readers starting version 13
|
||||||
|
|
||||||
|
### 2nd gen PC: GOLD (14) to Lincle (19)
|
||||||
|
|
||||||
|
* [FAB-e945-KN205](https://github.com/shizmob/arcade-docs/blob/main/konami/boards.md#fab-e945-kn205)
|
||||||
|
* All prior cabinet configurations can be upgraded with a PCB and software upgrade
|
||||||
|
* New LCD monitor starting version 15
|
||||||
|
* Further variants of the LCD monitor appear starting version 18
|
||||||
|
* [IO2 EZUSB FX2 USB IO board](https://github.com/shizmob/arcade-docs/blob/main/konami/io.md#usbio2) introduced with
|
||||||
|
version 14
|
||||||
|
* Switch to wave pass readers on version 19
|
||||||
|
|
||||||
|
### 3rd gen PC: Tricoro (20) to Sinobuz (24)
|
||||||
|
|
||||||
|
* All prior cabinet configurations can be upgraded with a PCB and software upgrade
|
||||||
|
* [ADE-HM65](https://github.com/shizmob/arcade-docs/blob/main/konami/boards.md#hm65)
|
||||||
|
* Game engine supports HD mode (720p)
|
||||||
|
* Many new LCD monitor variants appear with every new version
|
||||||
|
|
||||||
|
### 4th gen PC: CANNON BALLERS (25) to RESIDENT (30)
|
||||||
|
|
||||||
|
* All prior cabinet configurations can be upgraded with a PCB and software upgrade
|
||||||
|
* [ADE-6291](https://github.com/shizmob/arcade-docs/blob/main/konami/boards.md#ade-6291)
|
||||||
|
* [BIO2 IO board](https://github.com/shizmob/arcade-docs/blob/main/konami/boards.md#hm65)
|
||||||
|
* Upgrade cabinets required the [BIO2 sub-IO board](https://github.com/shizmob/arcade-docs/blob/main/konami/io.md#bio2-ldj-sub-io)
|
||||||
|
* Drop of SD mode support starting version 27
|
||||||
|
* Supporting 120 hz monitors starting version 27
|
||||||
|
* Many new LCD monitor variants appear with every new version
|
||||||
|
* 42" 120 hz for lightning cabinets starting version 27
|
||||||
|
* 42" 60 hz for non-lightning cabinets starting version 25
|
||||||
|
|
||||||
|
### 5th gen PC: RESIDENT (30) to EPOLIS (31)
|
||||||
|
|
||||||
|
* All prior cabinet configurations can be upgraded with a PCB and software upgrade
|
||||||
|
* [C300-xonarae](https://github.com/shizmob/arcade-docs/blob/main/konami/boards.md#c300-xonarae)
|
||||||
|
* Game engine supports FHD mode (1080p)
|
||||||
|
|
||||||
|
## Threading model and core responsibilities in PC-based games
|
||||||
|
|
||||||
|
Since the early days of 9th Style to today (as of time of writing this: EPOLIS), the threading model
|
||||||
|
hasn't changed significantly:
|
||||||
|
|
||||||
|
* Main and rendering thread
|
||||||
|
* Runs your typical D3D9 render loop
|
||||||
|
* Using D3D9ex starting version 27
|
||||||
|
* Starting and managing other threads
|
||||||
|
* Any file and game asset loading
|
||||||
|
* Handles all the core game logic of the different screens starting from the initial boot screen
|
||||||
|
to the core game-play screen
|
||||||
|
* IO thread
|
||||||
|
* Polls the main IO hardware and synchronizes the in-memory input and output state with the
|
||||||
|
hardware
|
||||||
|
* Executes commands issued by the main thread to the IO board such as dongle or card reader
|
||||||
|
commands (ezusb generation of IO only)
|
||||||
|
* Card reader thread (not applicable to versions 9 to 12)
|
||||||
|
* Runs the protocol to read/write the hardware of the readers
|
||||||
|
* Async execution of higher level commands issued by the main thread to the card reader hardware,
|
||||||
|
e.g. card read, card eject etc.
|
||||||
|
* Audio thread
|
||||||
|
* Streaming of audio data to the sound API
|
||||||
|
* DirectSound for versions 9 to 26
|
||||||
|
* WASAPI for versions 27 to 30 for non-lighting cabinets with ADE-6291 hardware
|
||||||
|
* ASIO for versions 27 and newer for lighting cabinets
|
||||||
|
* ASIO for version 30/31 and newer for non-lighting cabinets with C300-xonarae hardware
|
||||||
|
* Async execution of higher level commands issued by the main thread to the audio backend, e.g.
|
||||||
|
play audio, stop audio, etc.
|
||||||
|
* Network thread
|
||||||
|
* Network plumbing with the xrpc protocol
|
||||||
|
* Async execution of request-response commands issued by the main thread
|
||||||
|
|
||||||
|
## Main and rendering thread
|
||||||
|
|
||||||
|
With the game having transitioning to different screens throughout it's lifecycle, the main render
|
||||||
|
loop might contain different logic such as asset loading. The following focuses on the main
|
||||||
|
game-play screen, only. Common rendering logic still applies to other screens.
|
||||||
|
|
||||||
|
This follows your typical D3D9 single threaded rendering loop which boils down to the following:
|
||||||
|
|
||||||
|
* Begin the scene (`BeginScene`)
|
||||||
|
* Set the render target (`SetRenderTarget`)
|
||||||
|
* Clear the back buffer (`Clear`)
|
||||||
|
* Run engine step. This includes and is mixed with
|
||||||
|
* IO input evaluation
|
||||||
|
* Game engine state and (re-) drawing the scene
|
||||||
|
* Commands to the audio playback, e.g. play key sounds
|
||||||
|
* Setting IO outputs
|
||||||
|
* End the scene (`EndScene`)
|
||||||
|
* Target a minimum frame time
|
||||||
|
* Introduced with version 11
|
||||||
|
* Sleep (`Sleep` or `SleepEx`) to fill up the frame up to either 13 ms or 14 ms (depending on the
|
||||||
|
version)
|
||||||
|
* This was likely introduced to not have the game run at hundreds of FPS if v-sync was disabled
|
||||||
|
(probably when running in window mode for development/testing purposes)
|
||||||
|
* Swapping the back buffers (`Present`)
|
||||||
|
* D3D9 is configured with v-sync enabled by default and targets 60 hz
|
||||||
|
* With this configuration, the call to `Present` fills up the remaining frame time to target the
|
||||||
|
configured 60 hz refresh rate
|
||||||
|
|
||||||
|
### Rendering resolutions
|
||||||
|
|
||||||
|
The game engine went through a couple of different rendering resolutions:
|
||||||
|
|
||||||
|
* 640x240: version 1 to 8 (all twinkle hardware)
|
||||||
|
* 640x480: version 9 to 19 (1st and 2nd gen PC-based)
|
||||||
|
* 1280x720 (HD mode) and 640x480 (SD mode): version 20 to 27 (3rd and 4th gen PC-based)
|
||||||
|
* 1280x720 (HD mode) only for version 28 to 29 (4th gen PC-based)
|
||||||
|
* 1280x720 (HD mode) and 1920x1080 (FHD mode) for version 30 (4th gen PC-based)
|
||||||
|
* 1920x1080 (FHD mode) only for version 30+ (5th gen PC-based)
|
||||||
|
|
||||||
|
## Core engine timing and synchronization
|
||||||
|
|
||||||
|
The following outlines and explains the core engine concepts related to timing and synchronization.
|
||||||
|
|
||||||
|
### The origins, twinkle hardware
|
||||||
|
|
||||||
|
* It appears that the game has been on the same codebase since it's inception.
|
||||||
|
* This can be reasoned by the following observations
|
||||||
|
* 9th style as the first PC-based game very buggy on initial release
|
||||||
|
* 9th style threading model very clunky with various thread settings showing they tried to
|
||||||
|
prioritize different processing on a single core CPU
|
||||||
|
* Coming from twinkle hardware that is a realtime system vs. a Windows XP system
|
||||||
|
* Fixed playstation 1 based hardware with a refresh rate of
|
||||||
|
[59.8260978565 hz](https://github.com/mamedev/mame/blob/bf9df04e005697788ae988ef5aea91a1878fd631/src/devices/video/psx.cpp#L435)
|
||||||
|
* No need to assume getting anything else if the resource budget per frame is not exceeded
|
||||||
|
* All sub-systems were driven synchronously to that fixed time step
|
||||||
|
* No need for the engine to synchronize audio during the song. When the song is started
|
||||||
|
correctly, it stayed sync throughout the song
|
||||||
|
* Observations and assumptions
|
||||||
|
* It appears the developers struggled a lot with the significant platform shift to PC as indicated
|
||||||
|
by various core engine improvements throughout the years still
|
||||||
|
* Switches of hardware generations further complicated the situation as these forced them to further
|
||||||
|
drift away from how the game engine was initially designed on the twinkle system
|
||||||
|
|
||||||
|
### Frame time/timing and engine step
|
||||||
|
|
||||||
|
* The game's engine step and timing is frame based
|
||||||
|
* The main render loop defines the minimum valid timing window for the game engine to be able to
|
||||||
|
evaluate
|
||||||
|
* 60 hz/fps = 16.667 ms (rounded to three decimal places)
|
||||||
|
* 120 hz/fps = 8.333 ms (rounded to three decimal places), only relevant for lightning cabinets with their 120 hz
|
||||||
|
screen/mode
|
||||||
|
* Depending on the GPU hardware and configuration, the GPU might drive the screen not exactly at
|
||||||
|
perfectly 60 hz/fps = 16.667 ms
|
||||||
|
* As outlined in the [main render loop](#main-and-rendering-thread), the `Present` call is the
|
||||||
|
key function call to determine the frame time for the game engine
|
||||||
|
* Just having v-sync enabled and telling D3D9 to **target** 60 hz, it still depends on how the GPU
|
||||||
|
driver is implemented and how the GPU driver's implementation of D3D9 executes on the `Present`
|
||||||
|
call
|
||||||
|
* This is primarily determined by how the GPU driver is operating and driving connected display
|
||||||
|
hardware
|
||||||
|
* The following factors can contribute to that either directly or indirectly
|
||||||
|
* Different monitor types analog vs. digital (CRT vs. LCD)
|
||||||
|
* Different monitor connections VGA vs. DVI/HDMI/DP
|
||||||
|
* Different GPU drivers
|
||||||
|
* Different GPU hardware and vendors
|
||||||
|
* Different GPU settings
|
||||||
|
|
||||||
|
### Monitor check screen
|
||||||
|
|
||||||
|
The monitor check screen was introduced with version 14. This was a solution to the problem of not
|
||||||
|
guaranteeing a single fixed refresh rate throughout different GPU and monitor combinations. See
|
||||||
|
a detailed explanation in the previous sub-subsection about
|
||||||
|
[what influences the frame time](#frame-timetiming-and-engine-step) of the game.
|
||||||
|
|
||||||
|
The goal of the monitor check is to measure the frame time of the main render loop and use the
|
||||||
|
results for [driving the core engine step](#engine-step-and-synchronization).
|
||||||
|
|
||||||
|
The monitor check evolved slightly as different GPU and monitor hardware, and GPU drivers yielded
|
||||||
|
varying refresh rates that determined the frame times of the main game loop.
|
||||||
|
|
||||||
|
Actual values are outlined further down in the [engine step time](#engine-step-time) section.
|
||||||
|
|
||||||
|
There are two main versions of the monitor check, all of them have always been part of the boot
|
||||||
|
process:
|
||||||
|
|
||||||
|
* 14
|
||||||
|
* Measures a total of 3000 frames
|
||||||
|
* If total time this took < 50004 ms -> so average of 16.668 ms per frame = 59.9952 hz
|
||||||
|
* S-Video mode -> 59.95 hz (also shows S-VIDEO when the monitor check completes)
|
||||||
|
* Otherwise VGA mode -> 60.05 hz
|
||||||
|
* If VGA is determined, the game patches the chart event data when loading
|
||||||
|
* `event_timestamp * 0.99817199 + 0.40000001`
|
||||||
|
* When S-Video no charts are patched and the timing data in the chart is used as is
|
||||||
|
* 15 to 18
|
||||||
|
* Identical to 14 except that chart patching now happens in milliseconds instead of frames
|
||||||
|
* VGA mode: `16.65279`
|
||||||
|
* S-Video mode: `16.680567`
|
||||||
|
* `event_timestamp * (1.0 / frame_time) + 0.40000001)`
|
||||||
|
* 19
|
||||||
|
* Identical to previous version
|
||||||
|
* Monitor check screen shows current FPS on the last revision of that version. However, it doesn't
|
||||||
|
use the value shown there by any means. Assuming this was added before the introduction of the
|
||||||
|
new monitor check on 20.
|
||||||
|
* 20 to 26
|
||||||
|
* Runs on boot or when switching monitor modes SD vs. HD
|
||||||
|
* Measures only 1200 frames
|
||||||
|
* Takes the average refresh rate of 1200 frames
|
||||||
|
* Applies the measured avg. frame time directly to the charts before song
|
||||||
|
* 27 to 30
|
||||||
|
* Frame rate measuring identical to prior versions
|
||||||
|
* Added additional logic after the frame time measurements for handling of 120 hz displays
|
||||||
|
* Includes checking the monitor and if the framerate matches as expected
|
||||||
|
* 30/31 LDJ-010 upgrade
|
||||||
|
* Added NvDisplayConfigLDJ tool which runs on system start and configures a custom timing in the
|
||||||
|
NVIDIA GPU driver to ensure a fixed monitor refresh rate
|
||||||
|
* 31
|
||||||
|
* Same code as before
|
||||||
|
* Consider the first 460 frames of the measurement as warm-up frames
|
||||||
|
* Discard these for the actual measurement to get more stable frame times
|
||||||
|
* Use a base avg. value of 119.982 for the 120 hz monitors and 59.9 for 60 hz monitors. Further
|
||||||
|
frames measured are counted towards the average with the given base value
|
||||||
|
|
||||||
|
### Engine core game-play with visual and audio synchronization
|
||||||
|
|
||||||
|
#### Chart data
|
||||||
|
|
||||||
|
* Chart data encodes note timing and timing window information
|
||||||
|
* Chart data consists of *note events* encoding a timestamp and note information such as type
|
||||||
|
and key-sound information
|
||||||
|
* Timing windows are defined per chart
|
||||||
|
* Most infamous example: GAMBOL (7Key/Another)
|
||||||
|
* Game engine timestamp evaluation and note event timestamp encoding
|
||||||
|
* 9 to 14: Refresh rate in hz
|
||||||
|
* 15 to 31: Milliseconds (equivalent to assuming 1000 fps)
|
||||||
|
* Fundamentally, that doesn't change game play experience as it's just a different way of
|
||||||
|
evaluating the timestamps since refresh rate in hz/frame rate in fps can be converted lossless to
|
||||||
|
frame time in ms
|
||||||
|
|
||||||
|
#### Engine step time
|
||||||
|
|
||||||
|
The engine uses the following source for frame rate/time to drive internal logic on the following
|
||||||
|
versions
|
||||||
|
|
||||||
|
* 9 to 13: Hardcoded 59.95 hz
|
||||||
|
* 14: Either 59.95 hz or 60.05 hz determined by which value is determined to be closer to the
|
||||||
|
measured one during the monitor check screen on startup
|
||||||
|
* 15 to 19: 59.95 hz or 60.05 hz
|
||||||
|
* Monitor check on startup measures the frame time and picks the value closest to what's been
|
||||||
|
measured
|
||||||
|
* Monitor check result can be overridden with the *Output Type* setting in the operator menu
|
||||||
|
* *S-Video* to force to 59.95 hz
|
||||||
|
* *VGA* to force to 60.05 hz
|
||||||
|
* 20 to 31: Monitor check on boot determines the frame time and uses the result throughout the
|
||||||
|
entire game session
|
||||||
|
|
||||||
|
#### Engine step and synchronization
|
||||||
|
|
||||||
|
Per frame engine step advancing and synchronization during game-play
|
||||||
|
|
||||||
|
* Game-play needs synchronization of the following aspects
|
||||||
|
* Drawn content on the screen
|
||||||
|
* Background audio playback track
|
||||||
|
* Key sound effects
|
||||||
|
* The game engine synchronizes these only at the start of a song
|
||||||
|
* It takes known/determined refresh rate/frame time as the fixed time for every frame cycle
|
||||||
|
throughout the entire song
|
||||||
|
* It starts playback of the background audio track together with playback of the chart data
|
||||||
|
* With every engine step/frame it advances internal calculations by that fixed amount of time.
|
||||||
|
Thus, the game engine expects this to be constant/stable throughout an entire song
|
||||||
|
* The chart data is advanced every frame by the engine
|
||||||
|
* Key sound events are turned into audio playback on command as the chart advances
|
||||||
|
* No re-synchronization or check-pointing between main rendering thread and audio is happening
|
||||||
|
throughout the song
|
||||||
|
* Remark: The above does not consider any kind of offsetting and timing adjustments for the sake
|
||||||
|
of keeping this simple and focus on the absolute core concepts
|
||||||
224
doc/iidxhook/iidx-syncbook.md
Normal file
224
doc/iidxhook/iidx-syncbook.md
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
# IIDX "Syncbook": A guide to ensuring sync and performant gameplay
|
||||||
|
|
||||||
|
This is a guide applicable to all IIDX versions that are native Windows PC-based. The goal is to
|
||||||
|
enable proper configuration of those games to ensure the game engine "runs in-sync" with any of its
|
||||||
|
IO (visual GPU/display output, audio output, user input) resulting in high and stable performance
|
||||||
|
for smooth game-play.
|
||||||
|
|
||||||
|
This document won't go into the implementation details of the game engine. Please refer to the
|
||||||
|
[IIDX engine details journal](../dev/journal/2025-02-09-iidx-engine.md) for a more in-depth
|
||||||
|
information.
|
||||||
|
|
||||||
|
## Understanding the problems and options to address them
|
||||||
|
|
||||||
|
First, let's understand what the key problems are and how they contribute to different issues
|
||||||
|
that impact game-play.
|
||||||
|
|
||||||
|
### Song de-syncing
|
||||||
|
|
||||||
|
Symptom: Throughout playing a song, the audio is de-syncing even it was fine when the song started.
|
||||||
|
|
||||||
|
Cause: The game engine is fundamentally designed to run on a fixed and consistent frame
|
||||||
|
rate/time per engine step. A mismatch of expected frame time by the game engine and actually delivered
|
||||||
|
frame time by the GPU driver. This can come either as a stable frame time that just mismatches in
|
||||||
|
general or (highly) fluctuating frame times.
|
||||||
|
|
||||||
|
* G-sync on modern displays causes known fluctuations because it adjusts dynamically the monitor
|
||||||
|
refresh rate
|
||||||
|
* V-sync not correctly configured/enforced or even vsync-off override in driver is causing
|
||||||
|
inconsistent frame times
|
||||||
|
* Incorrect display timings causing refresh rate fluctuations resulting in inconsistent frame times
|
||||||
|
|
||||||
|
Stable frame times but not having the correct ones that the game engine expects is a different
|
||||||
|
problem that can be addressed by:
|
||||||
|
|
||||||
|
* Knowing the refresh rates expected by the game engine of the different game versions
|
||||||
|
* Configuring your GPU driver's display timings to match the expected frame times
|
||||||
|
* Or, patch the game's chart data with your custom display timings so the game engine gets uses
|
||||||
|
*your* "correct" frame times
|
||||||
|
* Note: Offline patching the chart data doesn't work for several game versions as the monitor
|
||||||
|
check does override this data, but not as flexible as required
|
||||||
|
* Use the chart patch feature of bemanitools instead
|
||||||
|
|
||||||
|
### Micro-stuttering and non-smooth note scrolling
|
||||||
|
|
||||||
|
This is a trickier problem as it can be caused by a few different things.
|
||||||
|
|
||||||
|
* GPU related
|
||||||
|
* Fluctuating refresh rates result in fluctuating frame times in the main game loop
|
||||||
|
* GPU power configuration in non-performance mode (e.g. "power saving") causes processing latency
|
||||||
|
due to sleep states
|
||||||
|
* Display related
|
||||||
|
* Display firmware buggy and/or internal scalers that expect to run at very specific refresh rates
|
||||||
|
and cannot adapt to any custom display timings enforced by the GPU
|
||||||
|
* A known example is the official
|
||||||
|
[PENDUAL LCD monitor](https://github.com/shizmob/arcade-docs/blob/6ac99975cdb2bf668362f65fa9fa3ffb2127308b/konami/product/GULDJ-JI.md#notes-and-known-issues) that does not v-sync correctly to any other refresh-rate than 60.000 hz
|
||||||
|
* CPU related
|
||||||
|
* CPU power configuration on Windows in non-performance mode (e.g. "power saving") causes
|
||||||
|
processing latency due to sleep states
|
||||||
|
* Correct CPU C-states configuration in BIOS/UEFI
|
||||||
|
* These cannot be configured in Windows and are separate from Windows's power configuration
|
||||||
|
* Other stuff running in the background of the system causing fluctuations
|
||||||
|
* (Synchronous) Disk I/O heavy applications stealing CPU time
|
||||||
|
* Or any other process creating a considerable amount of CPU or GPU load
|
||||||
|
|
||||||
|
## Configuration guide for different game versions
|
||||||
|
|
||||||
|
### Measuring monitor refresh rate
|
||||||
|
|
||||||
|
Let's start with configuring the system to meet the game engine's expectation regarding the
|
||||||
|
target monitor refresh rate and requiring vsync.
|
||||||
|
|
||||||
|
First, use the [d3d9-monitor-check tool](../tools/d3d9-monitor-check.md) to measure the currently
|
||||||
|
configured refresh rate of your monitor. Note that your monitor might yield different timings on
|
||||||
|
different resolutions and different game versions run on
|
||||||
|
[different rendering resolutions](../dev/journal/2025-02-09-iidx-engine.md#rendering-resolutions).
|
||||||
|
|
||||||
|
For example, the game version is 31 with the rendering resolution of 1920x1080 in FHD mode that you
|
||||||
|
want to target:
|
||||||
|
|
||||||
|
```bat
|
||||||
|
d3d9-monitor-check.exe cmdline refresh-rate-test 1920 1080 60
|
||||||
|
```
|
||||||
|
|
||||||
|
The test shows the current monitor refresh rate and the average refresh rate over the course of
|
||||||
|
the test. Check that the avg. refresh rate is stable during the measuring phase (during warm-up,
|
||||||
|
it's ok if it fluctuates).
|
||||||
|
|
||||||
|
This test allows you to determine/check:
|
||||||
|
|
||||||
|
* Refresh rate/frame time fluctuations: if you see (high) fluctuations on the first or second
|
||||||
|
decimal place
|
||||||
|
* What's your current target refresh rate the GPU is driving your monitor at
|
||||||
|
* If vsync isn't overridden by some other driver setting as you want to see a refresh rate around
|
||||||
|
the 60 hz mark
|
||||||
|
|
||||||
|
### Measuring vsync issues
|
||||||
|
|
||||||
|
Some displays or the GPU configuration might lead to vsync issues which can be detected with the
|
||||||
|
`d3d9-monitor-check.exe` tool as well.
|
||||||
|
|
||||||
|
```bat
|
||||||
|
d3d9-monitor-check.exe cmdline vsync-test 1920 1080 60
|
||||||
|
```
|
||||||
|
|
||||||
|
This runs a test with a VSYNC text that alternates red and cyan colors. If the text appears grey
|
||||||
|
all the time, everything's fine. If you spot brief red or cyan text either occasionally or
|
||||||
|
periodically, your current configuration has vsync issues resulting in skipped frames or old
|
||||||
|
frames displaying longer.
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
The following are recommended configurations for the different game versions. If any of these
|
||||||
|
don't work as expected, you have to troubleshoot and tweak these potentially. Please refer to the
|
||||||
|
[guidelines above](#configuration-guide-for-different-game-versions) to understand how to use
|
||||||
|
the tooling and test your changes.
|
||||||
|
|
||||||
|
#### Recommended configuration with NVIDIA GPU and driver
|
||||||
|
|
||||||
|
We want to achieve the following configuration on the GPU driver:
|
||||||
|
|
||||||
|
* Turn-off g-sync if you have a monitor that supports it
|
||||||
|
* Disable power saving mode on GPU driver
|
||||||
|
* V-sync is not forced off
|
||||||
|
* Run the display on a target refresh rate of `59.950 hz` which has been determined to be
|
||||||
|
[the most compatible across all PC-based versions](../dev/journal/2025-02-09-iidx-engine.md#engine-step-time).
|
||||||
|
|
||||||
|
##### Turn-off g-sync
|
||||||
|
|
||||||
|
Create a new GPU profile for IIDX, if it doesn't exist yet:
|
||||||
|
|
||||||
|
```bat
|
||||||
|
nvgpu.exe profile create iidx
|
||||||
|
```
|
||||||
|
|
||||||
|
Add the application names when the profile needs to be applied:
|
||||||
|
|
||||||
|
```bat
|
||||||
|
:: For iidx versions 9 to 17
|
||||||
|
nvgpu.exe profile application-add iidx bm2dx.exe
|
||||||
|
:: For iidx versions 18+
|
||||||
|
nvgpu.exe profile application-add iidx launcher.exe
|
||||||
|
```
|
||||||
|
|
||||||
|
Disable G-SYNC for the profile:
|
||||||
|
|
||||||
|
```bat
|
||||||
|
nvgpu.exe profile gsync-disable iidx
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Disable power saving mode
|
||||||
|
|
||||||
|
Set GPU power state to maximum for the profile (assumes you have a
|
||||||
|
[GPU profile called `iidx` already created](#turn-off-g-sync)):
|
||||||
|
|
||||||
|
```bat
|
||||||
|
nvgpu.exe profile gpu-power-state-max iidx
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Configure and verify target refresh rate of 59.950 hz and vsync
|
||||||
|
|
||||||
|
Get display ID of your primary display:
|
||||||
|
|
||||||
|
```bat
|
||||||
|
nvgpu.exe display primary-display-id
|
||||||
|
```
|
||||||
|
|
||||||
|
Copy the hex-value of the display ID and use it in the following commands.
|
||||||
|
|
||||||
|
Test the custom display timing first, e.g. for versions that run in 1920x1080
|
||||||
|
(Replace `<DISPLAY_ID> ` with the primary display ID you got):
|
||||||
|
|
||||||
|
```bat
|
||||||
|
nvgpu.exe display custom-resolution-test <DISPLAY_ID> 1920 1080 59.95 10
|
||||||
|
```
|
||||||
|
|
||||||
|
This will test it for 10 seconds and then revert. If the result looked good, i.e. the screen didn't
|
||||||
|
go blank or the display output was garbage, apply it:
|
||||||
|
|
||||||
|
```bat
|
||||||
|
nvgpu.exe display custom-resolution-set <DISPLAY_ID> 1920 1080 59.95
|
||||||
|
```
|
||||||
|
|
||||||
|
Test and verify the configuration is applied and works correctly:
|
||||||
|
|
||||||
|
```bat
|
||||||
|
d3d9-monitor-check.exe cmdline refresh-rate-test 1920 1080 60
|
||||||
|
```
|
||||||
|
|
||||||
|
Test if the enforced refresh rate is compatible with your display and vsync is working correctly:
|
||||||
|
|
||||||
|
```bat
|
||||||
|
d3d9-monitor-check.exe cmdline vsync-test 1920 1080 60
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Alternative refresh rate configuration
|
||||||
|
|
||||||
|
If for some reason your display doesn't support 59.950 hz properly, i.e. display artifacts or vsync
|
||||||
|
issues, you can use any other 60 hz compatible refresh rate, e.g. anything between 59.900 hz and
|
||||||
|
60.100 hz that your display supports properly.
|
||||||
|
|
||||||
|
Follow the same steps [as above](#configure-and-verify-target-refresh-rate-of-59950-hz-and-vsync)
|
||||||
|
but use a different refresh rate, e.g. 60.000 hz.
|
||||||
|
|
||||||
|
Verify using the `d3d9-monitor-check.exe` with the outlined steps if you need to play around to find
|
||||||
|
a refresh rate that works for your setup.
|
||||||
|
|
||||||
|
For the game versions 9 to 19, you have to use the chart patch feature of bemanitools to patch
|
||||||
|
the charts to your custom refresh rate. Otherwise, the game engine will run on your configured
|
||||||
|
refresh rate, but it will take the non-matching refresh rate from the chart data which causes
|
||||||
|
song de-syncing.
|
||||||
|
|
||||||
|
For example, to configure a refresh rate of 60.000 hz in the iidxhook config file:
|
||||||
|
|
||||||
|
```text
|
||||||
|
gfx.monitor_check=60.000
|
||||||
|
```
|
||||||
|
|
||||||
|
##### ATI/AMD
|
||||||
|
|
||||||
|
Currently, there is no tooling provided by bemanitools to configure the AMD GPU driver. The basic
|
||||||
|
concepts of what needs to be configured still applies as outlined in the NVIDIA sections above
|
||||||
|
though, e.g. through AMD's GPU control panel.
|
||||||
|
|
||||||
|
Further steps and instructions TBD
|
||||||
@@ -146,16 +146,7 @@ This can be related to various issues:
|
|||||||
start "" /relatime "gamestart.bat"
|
start "" /relatime "gamestart.bat"
|
||||||
```
|
```
|
||||||
|
|
||||||
- Enforce v-sync enabled in your GPU settings.
|
Also refer to the [iidx-syncbook](iidx-syncbook.md).
|
||||||
- Ensure that you have a constant refresh rate around the 60 hz (59.9xx or 60.0xx) that is not
|
|
||||||
jumping around. Use the timebase feature of one of the newer games to check that or enable
|
|
||||||
iidxhook's timebase and check the log output for the determined value. Run this a few times and
|
|
||||||
check if the results differ.
|
|
||||||
- Use iidxhook's frame rate limiter feature (see further below) to software lock the refresh rate.
|
|
||||||
This might be necessary on Windows 7 and newer for D3D8 games, e.g. iidx 9 to 12, which seem to
|
|
||||||
ignore GPU side v-sync.
|
|
||||||
- Use iidxhook's auto timebase feature (see further below) or set a pre-determined value to cut down
|
|
||||||
start-up times.
|
|
||||||
|
|
||||||
### The game still stutters (randomly) and drifts off-sync
|
### The game still stutters (randomly) and drifts off-sync
|
||||||
|
|
||||||
@@ -173,9 +164,7 @@ This can be caused by:
|
|||||||
|
|
||||||
## My songs are offsync
|
## My songs are offsync
|
||||||
|
|
||||||
- Make sure your machine's refresh rate is stable
|
Refer to the [iidx-syncbook](iidx-syncbook.md).
|
||||||
- If you don't get a close to 59.94hz refresh rate, use the software monitor check/auto timebase
|
|
||||||
that's built into iidxhook (refer to help/config file)
|
|
||||||
|
|
||||||
## The game crashes instantly (10th, RED, HAPPY SKY)
|
## The game crashes instantly (10th, RED, HAPPY SKY)
|
||||||
|
|
||||||
@@ -233,6 +222,8 @@ file) or use a CLVSD.ax codec which has the debugger checks removed.
|
|||||||
|
|
||||||
## I used the auto timebase option and/or limited my refresh rate but the songs are still going offsync
|
## I used the auto timebase option and/or limited my refresh rate but the songs are still going offsync
|
||||||
|
|
||||||
|
Refer to the [iidx-syncbook](iidx-syncbook.md) if you haven't already.
|
||||||
|
|
||||||
There aren't many options left. The old games were developed for specific hardware and are not
|
There aren't many options left. The old games were developed for specific hardware and are not
|
||||||
guaranteed to work well on (especially) newer hardware. Multiple monitor setups can also have a bad
|
guaranteed to work well on (especially) newer hardware. Multiple monitor setups can also have a bad
|
||||||
impact on a stable refresh rate. Try a setup with just a single monitor you want to use for gameplay
|
impact on a stable refresh rate. Try a setup with just a single monitor you want to use for gameplay
|
||||||
|
|||||||
@@ -115,16 +115,7 @@ This can be related to various issues:
|
|||||||
start "" /relatime "gamestart.bat"
|
start "" /relatime "gamestart.bat"
|
||||||
```
|
```
|
||||||
|
|
||||||
- Enforce v-sync enabled in your GPU settings.
|
Also refer to the [iidx-syncbook](iidx-syncbook.md).
|
||||||
- Ensure that you have a constant refresh rate around the 60 hz (59.9xx or 60.0xx) that is not
|
|
||||||
jumping around. Use the timebase feature of one of the newer games to check that or enable
|
|
||||||
iidxhook's timebase and check the log output for the determined value. Run this a few times and
|
|
||||||
check if the results differ.
|
|
||||||
- Use iidxhook's frame rate limiter feature (see further below) to software lock the refresh rate.
|
|
||||||
This might be necessary on Windows 7 and newer for D3D8 games, e.g. iidx 9 to 12, which seem to
|
|
||||||
ignore GPU side v-sync.
|
|
||||||
- Use iidxhook's auto timebase feature (see further below) or set a pre-determined value to cut down
|
|
||||||
start-up times.
|
|
||||||
|
|
||||||
### The game still stutters (randomly) and drifts off-sync
|
### The game still stutters (randomly) and drifts off-sync
|
||||||
|
|
||||||
@@ -142,9 +133,7 @@ This can be caused by:
|
|||||||
|
|
||||||
## My songs are offsync
|
## My songs are offsync
|
||||||
|
|
||||||
- Make sure your machine's refresh rate is stable
|
Refer to the [iidx-syncbook](iidx-syncbook.md).
|
||||||
- If you don't get a close to 59.94hz refresh rate, use the software monitor check/auto timebase
|
|
||||||
that's built into iidxhook (refer to help/config file)
|
|
||||||
|
|
||||||
## The game crashes instantly
|
## The game crashes instantly
|
||||||
|
|
||||||
@@ -192,6 +181,8 @@ CLVSD.ax codec which has the debugger checks removed.
|
|||||||
|
|
||||||
## I used the auto timebase option and/or limited my refresh rate but the songs are still going offsync
|
## I used the auto timebase option and/or limited my refresh rate but the songs are still going offsync
|
||||||
|
|
||||||
|
Refer to the [iidx-syncbook](iidx-syncbook.md) if you haven't already.
|
||||||
|
|
||||||
There aren't many options left. The old games were developed for specific hardware and are not
|
There aren't many options left. The old games were developed for specific hardware and are not
|
||||||
guaranteed to work well on (especially) newer hardware. Multiple monitor setups can also have a bad
|
guaranteed to work well on (especially) newer hardware. Multiple monitor setups can also have a bad
|
||||||
impact on a stable refresh rate. Try a setup with just a single monitor you want to use for gameplay
|
impact on a stable refresh rate. Try a setup with just a single monitor you want to use for gameplay
|
||||||
|
|||||||
@@ -132,16 +132,7 @@ This can be related to various issues:
|
|||||||
start "" /relatime "gamestart.bat"
|
start "" /relatime "gamestart.bat"
|
||||||
```
|
```
|
||||||
|
|
||||||
- Enforce v-sync enabled in your GPU settings.
|
Also refer to the [iidx-syncbook](iidx-syncbook.md).
|
||||||
- Ensure that you have a constant refresh rate around the 60 hz (59.9xx or 60.0xx) that is not
|
|
||||||
jumping around. Use the timebase feature of one of the newer games to check that or enable
|
|
||||||
iidxhook's timebase and check the log output for the determined value. Run this a few times and
|
|
||||||
check if the results differ.
|
|
||||||
- Use iidxhook's frame rate limiter feature (see further below) to software lock the refresh rate.
|
|
||||||
This might be necessary on Windows 7 and newer for D3D8 games, e.g. iidx 9 to 12, which seem to
|
|
||||||
ignore GPU side v-sync.
|
|
||||||
- Use iidxhook's auto timebase feature (see further below) or set a pre-determined value to cut down
|
|
||||||
start-up times.
|
|
||||||
|
|
||||||
## "NETWORK WARNING" instead of "NETWORK OK"
|
## "NETWORK WARNING" instead of "NETWORK OK"
|
||||||
|
|
||||||
@@ -154,15 +145,7 @@ This can be caused by:
|
|||||||
|
|
||||||
## My songs are offsync
|
## My songs are offsync
|
||||||
|
|
||||||
The built-in monitor check just determines if the game should sync to either 59.94 hz (S-Video
|
Refer to the [iidx-syncbook](iidx-syncbook.md).
|
||||||
setting) or 60.04 hz (VGA setting). If you don't have a setup that runs on (as close as possible)
|
|
||||||
these values:
|
|
||||||
|
|
||||||
- Make sure your machine's refresh rate is stable, e.g. 60.00x hz.
|
|
||||||
- If you don't get a close to 59.94hz (S-Video setting) or 60.04 hz (VGA setting) refresh rate, go
|
|
||||||
an set the output mode in the operator menu to "VGA" to enforce the game to run chart syncing on
|
|
||||||
60.04 hz refresh rate (even if your setup does not have that value). Next, use the software
|
|
||||||
monitor check/auto timebase that's built into iidxhook (refer to cmd help/configfile).
|
|
||||||
|
|
||||||
## My game runs too fast
|
## My game runs too fast
|
||||||
|
|
||||||
@@ -205,6 +188,8 @@ CLVSD.ax codec which has the debugger checks removed.
|
|||||||
|
|
||||||
## I used the auto timebase option and/or limited my refresh rate but the songs are still going offsync
|
## I used the auto timebase option and/or limited my refresh rate but the songs are still going offsync
|
||||||
|
|
||||||
|
Refer to the [iidx-syncbook](iidx-syncbook.md) if you haven't already.
|
||||||
|
|
||||||
There aren't many options left. The old games were developed for specific hardware and are not
|
There aren't many options left. The old games were developed for specific hardware and are not
|
||||||
guaranteed to work well on (especially) newer hardware. Multiple monitor setups can also have a bad
|
guaranteed to work well on (especially) newer hardware. Multiple monitor setups can also have a bad
|
||||||
impact on a stable refresh rate. Try a setup with just a single monitor you want to use for gameplay
|
impact on a stable refresh rate. Try a setup with just a single monitor you want to use for gameplay
|
||||||
|
|||||||
@@ -143,16 +143,7 @@ This can be related to various issues:
|
|||||||
start "" /relatime "gamestart.bat"
|
start "" /relatime "gamestart.bat"
|
||||||
```
|
```
|
||||||
|
|
||||||
- Enforce v-sync enabled in your GPU settings.
|
Also refer to the [iidx-syncbook](iidx-syncbook.md).
|
||||||
- Ensure that you have a constant refresh rate around the 60 hz (59.9xx or 60.0xx) that is not
|
|
||||||
jumping around. Use the timebase feature of one of the newer games to check that or enable
|
|
||||||
iidxhook's timebase and check the log output for the determined value. Run this a few times and
|
|
||||||
check if the results differ.
|
|
||||||
- Use iidxhook's frame rate limiter feature (see further below) to software lock the refresh rate.
|
|
||||||
This might be necessary on Windows 7 and newer for D3D8 games, e.g. iidx 9 to 12, which seem to
|
|
||||||
ignore GPU side v-sync.
|
|
||||||
- Use iidxhook's auto timebase feature (see further below) or set a pre-determined value to cut down
|
|
||||||
start-up times.
|
|
||||||
|
|
||||||
## "NETWORK WARNING" instead of "NETWORK OK"
|
## "NETWORK WARNING" instead of "NETWORK OK"
|
||||||
|
|
||||||
@@ -165,15 +156,7 @@ This can be caused by:
|
|||||||
|
|
||||||
## My songs are offsync
|
## My songs are offsync
|
||||||
|
|
||||||
The built-in monitor check just determines if the game should sync to either 59.94 hz (S-Video
|
Refer to the [iidx-syncbook](iidx-syncbook.md).
|
||||||
setting) or 60.04 hz (VGA setting). If you don't have a setup that runs on (as close as possible)
|
|
||||||
these values:
|
|
||||||
|
|
||||||
- Make sure your machine's refresh rate is stable, e.g. 60.00x hz.
|
|
||||||
- If you don't get a close to 59.94hz (S-Video setting) or 60.04 hz (VGA setting) refresh rate, go
|
|
||||||
an set the output mode in the operator menu to "VGA" to enforce the game to run chart syncing on
|
|
||||||
60.04 hz refresh rate (even if your setup does not have that value). Next, use the software
|
|
||||||
monitor check/auto timebase that's built into iidxhook (refer to cmd help/configfile).
|
|
||||||
|
|
||||||
## My game runs too fast
|
## My game runs too fast
|
||||||
|
|
||||||
@@ -211,6 +194,8 @@ CLVSD.ax codec which has the debugger checks removed.
|
|||||||
|
|
||||||
## I used the auto timebase option and/or limited my refresh rate but the songs are still going offsync
|
## I used the auto timebase option and/or limited my refresh rate but the songs are still going offsync
|
||||||
|
|
||||||
|
Refer to the [iidx-syncbook](iidx-syncbook.md) if you haven't already.
|
||||||
|
|
||||||
There aren't many options left. The old games were developed for specific hardware and are not
|
There aren't many options left. The old games were developed for specific hardware and are not
|
||||||
guaranteed to work well on (especially) newer hardware. Multiple monitor setups can also have a bad
|
guaranteed to work well on (especially) newer hardware. Multiple monitor setups can also have a bad
|
||||||
impact on a stable refresh rate. Try a setup with just a single monitor you want to use for gameplay
|
impact on a stable refresh rate. Try a setup with just a single monitor you want to use for gameplay
|
||||||
|
|||||||
@@ -143,16 +143,7 @@ This can be related to various issues:
|
|||||||
start "" /relatime "gamestart.bat"
|
start "" /relatime "gamestart.bat"
|
||||||
```
|
```
|
||||||
|
|
||||||
- Enforce v-sync enabled in your GPU settings.
|
Also refer to the [iidx-syncbook](iidx-syncbook.md).
|
||||||
- Ensure that you have a constant refresh rate around the 60 hz (59.9xx or 60.0xx) that is not
|
|
||||||
jumping around. Use the timebase feature of one of the newer games to check that or enable
|
|
||||||
iidxhook's timebase and check the log output for the determined value. Run this a few times and
|
|
||||||
check if the results differ.
|
|
||||||
- Use iidxhook's frame rate limiter feature (see further below) to software lock the refresh rate.
|
|
||||||
This might be necessary on Windows 7 and newer for D3D8 games, e.g. iidx 9 to 12, which seem to
|
|
||||||
ignore GPU side v-sync.
|
|
||||||
- Use iidxhook's auto timebase feature (see further below) or set a pre-determined value to cut down
|
|
||||||
start-up times.
|
|
||||||
|
|
||||||
## "NETWORK WARNING" instead of "NETWORK OK"
|
## "NETWORK WARNING" instead of "NETWORK OK"
|
||||||
|
|
||||||
@@ -165,11 +156,7 @@ This can be caused by:
|
|||||||
|
|
||||||
## My songs are offsync
|
## My songs are offsync
|
||||||
|
|
||||||
From this version onwards (if you use the very final data of Lincle), the game comes with a built-in
|
Refer to the [iidx-syncbook](iidx-syncbook.md).
|
||||||
auto timebase option ("monitor check" on startup) which dynamically, detects the refresh rate of
|
|
||||||
your current setup. Thus, BT5's timebase option is not included from this hook version onwards,
|
|
||||||
anymore. Ensure that refresh rate displayed is very stable, e.g. 60.00x hz, and the game should be
|
|
||||||
able to provide you with a smooth and sync game experience.
|
|
||||||
|
|
||||||
## My game runs too fast
|
## My game runs too fast
|
||||||
|
|
||||||
|
|||||||
@@ -155,11 +155,7 @@ This can be related to various issues:
|
|||||||
start "" /relatime "gamestart.bat"
|
start "" /relatime "gamestart.bat"
|
||||||
```
|
```
|
||||||
|
|
||||||
- Enforce v-sync enabled in your GPU settings.
|
Also refer to the [iidx-syncbook](iidx-syncbook.md).
|
||||||
- Ensure that you have a constant refresh rate around the 60 hz (59.9xx or 60.0xx) that is not
|
|
||||||
jumping around. Use the timebase feature of one of the newer games to check that or enable
|
|
||||||
iidxhook's timebase and check the log output for the determined value. Run this a few times and
|
|
||||||
check if the results differ.
|
|
||||||
|
|
||||||
## "NETWORK WARNING" instead of "NETWORK OK"
|
## "NETWORK WARNING" instead of "NETWORK OK"
|
||||||
|
|
||||||
@@ -172,11 +168,7 @@ This can be caused by:
|
|||||||
|
|
||||||
## My songs are offsync
|
## My songs are offsync
|
||||||
|
|
||||||
From this version onwards (or Lincle very final revision), the game comes with a built-in auto
|
Refer to the [iidx-syncbook](iidx-syncbook.md).
|
||||||
timebase option ("monitor check" on startup) which dynamically, detects the refresh rate of your
|
|
||||||
current setup. Thus, BT5's timebase option is not included from this hook version onwards, anymore.
|
|
||||||
Ensure that refresh rate displayed is very stable, e.g. 60.00x hz, and the game should be able to
|
|
||||||
provide you with a smooth and sync game experience.
|
|
||||||
|
|
||||||
## My game runs too fast
|
## My game runs too fast
|
||||||
|
|
||||||
|
|||||||
@@ -159,11 +159,7 @@ This can be related to various issues:
|
|||||||
start "" /relatime "gamestart.bat"
|
start "" /relatime "gamestart.bat"
|
||||||
```
|
```
|
||||||
|
|
||||||
- Enforce v-sync enabled in your GPU settings.
|
Also refer to the [iidx-syncbook](iidx-syncbook.md).
|
||||||
- Ensure that you have a constant refresh rate around the 60 hz (59.9xx or 60.0xx) that is not
|
|
||||||
jumping around. Use the timebase feature of one of the newer games to check that or enable
|
|
||||||
iidxhook's timebase and check the log output for the determined value. Run this a few times and
|
|
||||||
check if the results differ.
|
|
||||||
|
|
||||||
## "NETWORK WARNING" instead of "NETWORK OK"
|
## "NETWORK WARNING" instead of "NETWORK OK"
|
||||||
|
|
||||||
@@ -176,11 +172,7 @@ This can be caused by:
|
|||||||
|
|
||||||
## My songs are offsync
|
## My songs are offsync
|
||||||
|
|
||||||
From IIDX 20 (or Lincle very final revision) onwards, the game comes with a built-in auto timebase
|
Refer to the [iidx-syncbook](iidx-syncbook.md).
|
||||||
option ("monitor check" on startup) which dynamically, detects the refresh rate of your current
|
|
||||||
setup. Thus, BT5's timebase option is not included from this hook version onwards, anymore. Ensure
|
|
||||||
that refresh rate displayed is very stable, e.g. 60.00x hz, and the game should be able to provide
|
|
||||||
you with a smooth and sync game experience.
|
|
||||||
|
|
||||||
## My game runs too fast
|
## My game runs too fast
|
||||||
|
|
||||||
|
|||||||
@@ -158,11 +158,7 @@ This can be related to various issues:
|
|||||||
start "" /relatime "gamestart.bat"
|
start "" /relatime "gamestart.bat"
|
||||||
```
|
```
|
||||||
|
|
||||||
- Enforce v-sync enabled in your GPU settings.
|
Also refer to the [iidx-syncbook](iidx-syncbook.md).
|
||||||
- Ensure that you have a constant refresh rate around the 60 hz (59.9xx or 60.0xx) that is not
|
|
||||||
jumping around. Use the timebase feature of one of the newer games to check that or enable
|
|
||||||
iidxhook's timebase and check the log output for the determined value. Run this a few times and
|
|
||||||
check if the results differ.
|
|
||||||
|
|
||||||
## "NETWORK WARNING" instead of "NETWORK OK"
|
## "NETWORK WARNING" instead of "NETWORK OK"
|
||||||
|
|
||||||
@@ -175,11 +171,7 @@ This can be caused by:
|
|||||||
|
|
||||||
## My songs are offsync
|
## My songs are offsync
|
||||||
|
|
||||||
From IIDX 20 (or Lincle very final revision) onwards, the game comes with a built-in auto timebase
|
Refer to the [iidx-syncbook](iidx-syncbook.md).
|
||||||
option ("monitor check" on startup) which dynamically, detects the refresh rate of your current
|
|
||||||
setup. Thus, BT5's timebase option is not included from this hook version onwards, anymore. Ensure
|
|
||||||
that refresh rate displayed is very stable, e.g. 60.00x hz, and the game should be able to provide
|
|
||||||
you with a smooth and sync game experience.
|
|
||||||
|
|
||||||
## My game runs too fast
|
## My game runs too fast
|
||||||
|
|
||||||
|
|||||||
@@ -205,11 +205,7 @@ This can be related to various issues:
|
|||||||
start "" /relatime "gamestart.bat"
|
start "" /relatime "gamestart.bat"
|
||||||
```
|
```
|
||||||
|
|
||||||
- Enforce v-sync enabled in your GPU settings.
|
Also refer to the [iidx-syncbook](iidx-syncbook.md).
|
||||||
- Ensure that you have a constant refresh rate around the 60 hz (59.9xx or 60.0xx) that is not
|
|
||||||
jumping around. Use the timebase feature of one of the newer games to check that or enable
|
|
||||||
iidxhook's timebase and check the log output for the determined value. Run this a few times and
|
|
||||||
check if the results differ.
|
|
||||||
|
|
||||||
## "NETWORK WARNING" instead of "NETWORK OK"
|
## "NETWORK WARNING" instead of "NETWORK OK"
|
||||||
|
|
||||||
@@ -222,11 +218,7 @@ This can be caused by:
|
|||||||
|
|
||||||
## My songs are offsync
|
## My songs are offsync
|
||||||
|
|
||||||
From IIDX 20 (or Lincle very final revision) onwards, the game comes with a built-in auto timebase
|
Refer to the [iidx-syncbook](iidx-syncbook.md).
|
||||||
option ("monitor check" on startup) which dynamically, detects the refresh rate of your current
|
|
||||||
setup. Thus, BT5's timebase option is not included from this hook version onwards, anymore. Ensure
|
|
||||||
that refresh rate displayed is very stable, e.g. 60.00x hz, and the game should be able to provide
|
|
||||||
you with a smooth and sync game experience.
|
|
||||||
|
|
||||||
## My game runs too fast
|
## My game runs too fast
|
||||||
|
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
exes += d3d9-monitor-check \
|
|
||||||
|
|
||||||
ldflags_d3d9-monitor-check := \
|
|
||||||
-ld3d9 \
|
|
||||||
-ldwmapi \
|
|
||||||
-lgdi32 \
|
|
||||||
-ld3dx9 \
|
|
||||||
|
|
||||||
libs_d3d9-monitor-check := \
|
|
||||||
util \
|
|
||||||
|
|
||||||
src_d3d9-monitor-check := \
|
|
||||||
main.c \
|
|
||||||
@@ -1,695 +0,0 @@
|
|||||||
#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;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user