Skip to content

Commit

Permalink
Add a GUI and basically rewrite half of the code (#33)
Browse files Browse the repository at this point in the history
* WIP migrate UI to ImGui

* OpenVR -> OVR

* cleanups, minimize, no resize and set resolution to Custom

* fix .ini categories and improve regions

* move some nvml stuff

* fix autostart and error handling

* Add saveSettings method and can write defaults + icon

* properly quit and cleanup with OpenVR

* add screenshot in readme, add lodepng license and clarify build steps

* Update icon.png

* display VRAM as GB and optimize getting it

* use openvr buffer

* settings wip

* Add tray icon

* reorder settings

* fix FPS going wild because of division by 0

* use int instead of float for configs

* code clarity + better nvml init

* prevent errors with config

* fix vram, fps and reprojection

* add missing configs in GUI

* Refactor settings finish them!

* Add Traypp license

* fix res change scales and defaults

* tray show instead of open

* Update screenshot.png

* fix resolution capitalization

* Apply most suggestions from Daniel

Co-Authored-By: Daniel Lemire <daniel@lemire.me>

* Simplify dependencies by only using CPM

Co-Authored-By: Daniel Lemire <daniel@lemire.me>

* Delete FindOpenVR.cmake

Co-Authored-By: Daniel Lemire <daniel@lemire.me>

* use another way to copy files so that it may not error

* Don't copy binary because CI doesn't like it

screw you CI

* Update .gitignore

* More portable!!! (#34)

* saving

* tweak

* various fixes

* various safety tricks

* trimming

* ok

* having fun

* cleanup regardless of tray

* check arguments

* formatting

---------

Co-authored-by: Daniel Lemire <dlemire@lemire.me>
Co-authored-by: Erimel <marioluigivideo@gmail.com>

* give printLine window a name

* silently restore settings

* Remove auto-start confirmation (non-error) message

* Update README.md

* improve default config

* update manifest

* add buttons to pause adjustment and disable current app

---------

Co-authored-by: Daniel Lemire <daniel@lemire.me>
  • Loading branch information
Erimelowo and lemire authored Oct 3, 2024
1 parent cd1424f commit b797e5a
Show file tree
Hide file tree
Showing 17 changed files with 1,187 additions and 565 deletions.
30 changes: 30 additions & 0 deletions .github/workflows/ubuntu.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Ubuntu 22.04

on: [push, pull_request]

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
ubuntu-build:
runs-on: ubuntu-22.04
strategy:
matrix:
shared: [OFF]
cxx: [g++-12]
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- name: Setup deps
run: sudo apt-get install ninja-build libwayland-dev libxrandr-dev libxkbcommon-x11-dev libxinerama-dev libxcursor-dev libxi-dev libglu1-mesa-dev freeglut3-dev mesa-common-dev libopenvr-dev
- name: Prepare
run: cmake -DBUILD_SHARED_LIBS=${{matrix.shared}} -G Ninja -B build
env:
CXX: ${{matrix.cxx}}
- name: Build
run: cmake --build build -j=4
- name: Test
run: ctest --output-on-failure --test-dir build
3 changes: 0 additions & 3 deletions .gitmodules

This file was deleted.

159 changes: 130 additions & 29 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,35 +1,123 @@
cmake_minimum_required(VERSION 3.17)
cmake_minimum_required(VERSION 3.16)

project(OpenVR-Dynamic-Resolution)
project(OVR-Dynamic-Resolution)
set(CMAKE_CXX_STANDARD 17)

include("${CMAKE_CURRENT_SOURCE_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake")
include(cmake/CPM.cmake)

set_property(GLOBAL PROPERTY USE_FOLDERS ON)

find_package(fmt CONFIG REQUIRED)
if(WIN32)
find_path(PDC_INCLUDES curses.h)
include_directories(${PDC_INCLUDES})
find_library(CURSES_LIBRARIES pdcurses REQUIRED)
## Find dependencies
find_package(Threads REQUIRED)

if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
message(STATUS "Under Linux, you may need to add some dependencies.")
message(STATUS "Ubuntu users should try:")
message(STATUS "apt-get install libwayland-dev libxrandr-dev libxkbcommon-x11-dev libxinerama-dev libxcursor-dev libxi-dev libglu1-mesa-dev freeglut3-dev mesa-common-dev")
endif()


IF(WIN32)
set(OPENVR_SHARED ON)
ELSE()
set(OPENVR_SHARED OFF)
ENDIF()
CPMAddPackage(
NAME openvr
URL https://github.com/ValveSoftware/openvr/archive/refs/tags/v2.5.1.zip
OPTIONS "BUILD_SHARED ${OPENVR_SHARED}"
)

get_directory_property(OPENVR_LIBNAME
DIRECTORY ${openvr_SOURCE_DIR}
DEFINITION LIBNAME)

get_directory_property(OPENVR_PLATFORM_NAME
DIRECTORY ${openvr_SOURCE_DIR}
DEFINITION PLATFORM_NAME)
get_directory_property(OPENVR_PROCESSOR_ARCH
DIRECTORY ${openvr_SOURCE_DIR}
DEFINITION PROCESSOR_ARCH)
get_directory_property(OPENVR_CMAKE_LIBRARY_OUTPUT_DIRECTORY
DIRECTORY ${openvr_SOURCE_DIR}
DEFINITION CMAKE_LIBRARY_OUTPUT_DIRECTORY)

message(STATUS "OpenVR detected your system as ${OPENVR_PLATFORM_NAME}${OPENVR_PROCESSOR_ARCH}")

if(EXISTS "${OPENVR_CMAKE_LIBRARY_OUTPUT_DIRECTORY}")
message(STATUS "Recovering OpenVR library from ${OPENVR_CMAKE_LIBRARY_OUTPUT_DIRECTORY}")
else()
find_package(Curses REQUIRED)
include_directories(${CURSES_INCLUDE_DIRS})
message(WARNING "Can't find OpenVR library at ${OPENVR_CMAKE_LIBRARY_OUTPUT_DIRECTORY} Is your system supported?")
endif()
find_library(OPENVR_LIB openvr_api)

set(protos_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/protos)
file(MAKE_DIRECTORY "${protos_OUTPUT_DIR}")
CPMAddPackage("gh:glfw/glfw#3.4")

include_directories(include)
CPMAddPackage("gh:fmtlib/fmt#11.0.2")

CPMAddPackage("gh:brofield/simpleini#v4.22")
add_library(simpleini INTERFACE)
target_include_directories(simpleini INTERFACE "${simpleini_SOURCE_DIR}")

CPMAddPackage("gh:ocornut/imgui@1.91.2")
add_library(imgui STATIC
${imgui_SOURCE_DIR}/imgui.cpp
${imgui_SOURCE_DIR}/imgui_demo.cpp
${imgui_SOURCE_DIR}/imgui_draw.cpp
${imgui_SOURCE_DIR}/imgui_widgets.cpp
${imgui_SOURCE_DIR}/imgui_tables.cpp
${imgui_SOURCE_DIR}/misc/cpp/imgui_stdlib.cpp
${imgui_SOURCE_DIR}/backends/imgui_impl_glfw.cpp
${imgui_SOURCE_DIR}/backends/imgui_impl_opengl3.cpp
)
target_link_libraries(imgui PUBLIC glfw)
target_include_directories(imgui PUBLIC "${imgui_SOURCE_DIR}")
target_include_directories(imgui PUBLIC "${imgui_SOURCE_DIR}/backends")

CPMAddPackage(
NAME lodepng
URL https://github.com/lvandeve/lodepng/archive/ed3c5f14b136c936d615ee3b38aaa7e7e642f12c.zip
)
add_library(lodepng STATIC "${lodepng_SOURCE_DIR}/lodepng.cpp")
target_include_directories(lodepng PUBLIC "${lodepng_SOURCE_DIR}")

IF(WIN32)
CPMAddPackage(
NAME tray
URL https://github.com/Soundux/traypp/archive/698db7d58dd450cc9e30dc12d3bd0c5ca4d6a5b1.zip
)
ENDIF()

set(CMAKE_SKIP_BUILD_RPATH FALSE)
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
set(CMAKE_INSTALL_RPATH $ORIGIN)

# Project
add_executable("${PROJECT_NAME}" "src/main.cpp" "src/pathtools_excerpt.cpp" "src/setup.cpp")
target_link_libraries("${PROJECT_NAME}" PRIVATE "${OPENVR_LIB}" fmt::fmt-header-only ${CURSES_LIBRARIES})
target_include_directories("${PROJECT_NAME}" PUBLIC ${protos_OUTPUT_DIR} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
# Set some Win32 Specific Settings
IF(WIN32)
SET(GUI_TYPE WIN32)
ENDIF(WIN32)
# Set some Apple MacOS Specific settings
IF (APPLE)
SET(GUI_TYPE MACOSX_BUNDLE)
ENDIF (APPLE)

link_directories("${openvr_SOURCE_DIR}/lib/${OPENVR_PLATFORM_NAME}${OPENVR_PROCESSOR_ARCH}")

if(WIN32)
link_directories("${OPENVR_CMAKE_LIBRARY_OUTPUT_DIRECTORY}")
endif()
if(WIN32)
add_executable("${PROJECT_NAME}" ${GUI_TYPE} "src/main.cpp" "src/pathtools_excerpt.cpp" "src/setup.cpp")
else()
add_executable("${PROJECT_NAME}" ${GUI_TYPE} "src/main.cpp" "src/setup.cpp")
endif()

target_link_libraries("${PROJECT_NAME}" openvr_api fmt::fmt-header-only simpleini imgui lodepng Threads::Threads)
if(TARGET tray)
target_link_libraries("${PROJECT_NAME}" tray)
endif()

target_include_directories("${PROJECT_NAME}" PRIVATE ${CMAKE_CURRENT_BINARY_DIR} PUBLIC "${openvr_SOURCE_DIR}/headers")
target_compile_features("${PROJECT_NAME}" PRIVATE cxx_std_17)

# IDE Config
Expand All @@ -45,21 +133,10 @@ add_custom_target(
)
add_dependencies("${PROJECT_NAME}" version)

install(FILES "${PROJECT_SOURCE_DIR}/manifest.vrmanifest"
DESTINATION "."
)

if (WIN32)
set(VCPKG_BINARIES "${CMAKE_BINARY_DIR}/vcpkg_installed/x64-windows/bin")
install(FILES "${VCPKG_BINARIES}/openvr_api.dll" DESTINATION ".")
elseif(UNIX)
set(VCPKG_BINARIES "${CMAKE_BINARY_DIR}/vcpkg_installed/x64-linux/bin")
install(FILES "${VCPKG_BINARIES}/libopenvr_api.so" DESTINATION ".")
endif()

install(TARGETS "${PROJECT_NAME}"
RUNTIME
DESTINATION .
BUNDLE DESTINATION ${CMAKE_SOURCE_DIR}
)

set(CPACK_SYSTEM_NAME ${CMAKE_SYSTEM_NAME})
Expand All @@ -78,3 +155,27 @@ set(CPACK_GENERATOR "ZIP")
set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY ON)
set(CPACK_VERBATIM_VARIABLES YES)
include(CPack)

if(${OPENVR_PLATFORM_NAME}$ MATCHES "win.*")
set(OPENVR_DLL_NAME "openvr_api.dll")
elseif(${OPENVR_PLATFORM_NAME}$ MATCHES "osx.*")
set(OPENVR_DLL_NAME "libopenvr_api.dylib")
else()
set(OPENVR_DLL_NAME "libopenvr_api.so")
endif()


if(WIN32)
# Visual Studio
set(ACTUAL_CURRENT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/Release)
else()
set(ACTUAL_CURRENT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
endif()
file(MAKE_DIRECTORY ${ACTUAL_CURRENT_BINARY_DIR}) # make sure it always exists
# Copy files
file(GLOB APP_RESOURCES "${CMAKE_SOURCE_DIR}/resources/*")
if(EXISTS ${OPENVR_CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${OPENVR_DLL_NAME})
file(COPY ${OPENVR_CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${OPENVR_DLL_NAME} ${APP_RESOURCES} DESTINATION ${ACTUAL_CURRENT_BINARY_DIR})
else()
file(COPY ${APP_RESOURCES} DESTINATION ${ACTUAL_CURRENT_BINARY_DIR})
endif()
65 changes: 34 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,48 +1,44 @@
# OpenVR Dynamic Resolution

[![Windows build testing](https://github.com/Louka3000/OpenVR-Dynamic-Resolution/actions/workflows/vs17.yml/badge.svg)](https://github.com/Louka3000/OpenVR-Dynamic-Resolution/actions/workflows/vs17.yml)
[![Windows build testing](https://github.com/Erimelowo/OpenVR-Dynamic-Resolution/actions/workflows/vs17.yml/badge.svg)](https://github.com/Erimelowo/OpenVR-Dynamic-Resolution/actions/workflows/vs17.yml)
[![Ubuntu 22.04](https://github.com/Erimelowo/OpenVR-Dynamic-Resolution/actions/workflows/ubuntu.yml/badge.svg)](https://github.com/Erimelowo/OpenVR-Dynamic-Resolution/actions/workflows/Ubuntu.yml)

OpenVR app that dynamically adjusts the HMD's resolution to the GPU frametime, CPU frametime and VRAM.
![screenshot of the app](screenshot.png)

This allows you to always have the maximum resolution your GPU can handle while hitting your target FPS (without reprojecting). Useful for games in which GPU requirement varies a lot (e.g. VRChat).
Lightweight OpenVR app to dynamically adjust your HMD's resolution depending on your GPU frametime, CPU frametime and VRAM.

This is **not** the same as SteamVR's Auto Resolution, which seems to be using some benchmarking approach that does not work for the same as OVRDR.
This allows you to always play at the maximum resolution your GPU can handle while hitting your target FPS (without reprojecting). This is especially useful for games in which performance varies a lot (e.g. VRChat).

Pro tip: if you want a higher resolution (for supersampling), you can lower your HMD's framerate to increase the target frametime.
This is **not** the same as SteamVR's Auto Resolution, which instead seems to be using a kind of benchmarking approach.

**Check out [WorkingGames.md](WorkingGames.md) for a list of working and non-working games.**

## Installation/Using It

**_Make sure SteamVR's Render Resolution is set to Custom_**

- Download the [latest release ](https://github.com/Louka3000/OpenVR-Dynamic-Resolution/releases/latest/download/OpenVR-Dynamic-Resolution.zip)
- Download the [latest release ](https://github.com/Erimelowo/OpenVR-Dynamic-Resolution/releases/latest/download/OVR-Dynamic-Resolution.zip)
- Extract the .zip
- Launch `OpenVR-Dynamic-Resolution.exe`
- Launch `OVR-Dynamic-Resolution.exe`

## Settings Descriptions

Settings are found in the `settings.ini` file. Do not rename that file. It should be located in the same folder as your executable file (`OpenVR-Dynamic-Resolution.exe`).
Settings are found in the `settings.ini` file. Do not rename that file. It should be located in the same folder as the executable file (`OpenVR-Dynamic-Resolution.exe`).
*Pro tip: if you want a higher resolution (for supersampling), you can lower your HMD's framerate or set `alwaysReproject` to 1 to increase the target frametime.*

- `autoStart`: (0 = disabled, 1 = enabled) Enabling it will launch the program with SteamVR automatically.

- `minimizeOnStart`: (0 = show, 1 = minimize, 2 = hide) Will automatically minimize or hide the window on launch. If set to 2 (hide), you won't be able to exit the program manually, but it will automatically exit with SteamVR.
- `minimizeOnStart`: (0 = show, 1 = minimize, 2 = hide) Will automatically minimize or hide the window on launch.

- `initialRes`: The resolution the program sets your HMD's resolution when starting. Also the resolution that is targeted in vramOnlyMode.

- `minRes`: The minimum value the program will be allowed to set your HMD's resolution to.

- `maxRes`: The maximum value the program will be allowed to set your HMD's resolution to.

- `dataPullDelayMs`: The time in milliseconds (1000ms = 1s) the program waits to pull and display new information. Adjust dataAverageSamples accordingly.

- `resChangeDelayMs`: The delay in milliseconds (1000ms = 1s) between each resolution change. Lowering it will make the resolution change more responsive, but will cause more stuttering from resolution changes.

- `minCpuTimeThreshold`: Don't increase resolution when CPU time in milliseconds is below this value. Useful to avoid the resolution increasing in the SteamVR void or during loading screens. Also see resetOnThreshold.
- `resIncreaseMin`: How many static % to increase resolution when we have GPU and VRAM headroom.

- `resIncreaseMin`: How many static % to increase resolution when we have GPU or/and VRAM headroom.

- `resDecreaseMin`: How many static % to decrease resolution when GPU frametime or/and VRAM usage is too high.
- `resDecreaseMin`: How many static % to decrease resolution when GPU frametime or VRAM usage is too high.

- `resIncreaseScale`: How much to increase resolution depending on GPU frametime headroom.

Expand All @@ -52,10 +48,16 @@ Settings are found in the `settings.ini` file. Do not rename that file. It shoul

- `resDecreaseThreshold`: Percentage of the target frametime at which the program will stop decreasing resolution

- `dataAverageSamples`: Number of samples to use for the average GPU time. Depends on dataPullDelayMs.
- `dataAverageSamples`: Number of samples to use for the average GPU time. One frame gives one sample.

- `minCpuTimeThreshold`: Don't increase resolution when CPU time in milliseconds is below this value. Useful to avoid the resolution increasing in the SteamVR void or during loading screens. Also see resetOnThreshold.

- `resetOnThreshold`: (0 = disabled, 1 = enabled) Enabling will reset the resolution to initialRes whenever minCpuTimeThreshold is met. Useful if you wanna go from playing a supported game to an unsuported games without having to reset your resolution/the program/SteamVR.

- `ignoreCpuTime`: (0 = disabled, 1 = enabled) Don't use the CPU frametime to adjust resolution.

- `preferReprojection`: (0 = disabled, 1 = enabled) If enabled, the GPU target frametime will double as soon as the CPU frametime is over the target frametime; else, the CPU frametime needs to be 2 times greater than the target frametime for the GPU target frametime to double.

- `alwaysReproject`: (0 = disabled, 1 = enabled) Enabling will double the target frametime, so if you're at a target FPS of 120, it'll target 60. Useful if you have a bad CPU but good GPU.

- `vramTarget`: The target VRAM usage in percents. Once your VRAM usage exceeds this amount, the resolution will stop increasing.
Expand All @@ -66,35 +68,36 @@ Settings are found in the `settings.ini` file. Do not rename that file. It shoul

- `vramOnlyMode`: (0 = disabled, 1 = enabled) Only adjust resolution based off VRAM; ignore GPU and CPU frametimes. Will always stay at initialRes or lower (if VRAM limit is reached).

- `preferReprojection`: (0 = disabled, 1 = enabled) If enabled, the GPU target frametime will double as soon as the CPU frametime is over the target frametime; else, the CPU frametime needs to be 2 times greater than the target frametime for the GPU target frametime to double.

- `ignoreCpuTime`: (0 = disabled, 1 = enabled) Don't use the CPU frametime to adjust resolution.

- `disabledApps`: Space-delimited list of OpenVR application keys that should be ignored for resolution adjustment. Steam games use the format steam.app.APPID, e.g. steam.app.438100 for VRChat and steam.app.620980 for Beat Saber.

## Building from source

We assume that you already have Git and CMake installed.
To build the project, run:
To set up the project, run:

```
git clone --recursive https://github.com/Erimelowo/OpenVR-Dynamic-Resolution.git
git clone https://github.com/Erimelowo/OpenVR-Dynamic-Resolution.git
cd OpenVR-Dynamic-Resolution
cmake -B build
cmake --build build --config Release
```

You can then execute the newly built binary by running:

Then you can build the project in release mode by running:
```
.\build\Release\OpenVR-Dynamic-Resolution.exe
cmake --build build --config Release
```

The newly built binary, its dependencies and resources will be in the `build/release` directory.
Note: you can delete `imgui.lib` and `lodepng.lib` as they're just leftovers.

## Licensing

[BSD 3-Clause License](/LICENSE)

This work is based on [SlimeVR-Feeder-App](https://github.com/SlimeVR/SlimeVR-Feeder-App) which is licensed under the BSD 3-Clause License.
We use the [OpenVR](https://github.com/ValveSoftware/openvr) library which is also available under the BSD 3-Clause License.
Additionally, we use [simpleini](https://github.com/brofield/simpleini) which is available the MIT License.
We also use the [fmt](https://github.com/fmtlib/fmt) library which is available under a Boost-like license.
We also use:
- The [OpenVR](https://github.com/ValveSoftware/openvr) library which is also available under the BSD 3-Clause License.
- [simpleini](https://github.com/brofield/simpleini) which is available the MIT License.
- The [fmt](https://github.com/fmtlib/fmt) library which is available under a Boost-like license.
- [DearImGui](https://github.com/ocornut/imgui) which is available under the MIT license.
- [lodepng](https://github.com/lvandeve/lodepng/blob/master/LICENSE) which is available under the zlib license.
- [Traypp](https://github.com/Soundux/traypp) which is available under the MIT license.
24 changes: 24 additions & 0 deletions cmake/CPM.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# SPDX-License-Identifier: MIT
#
# SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors

set(CPM_DOWNLOAD_VERSION 0.40.2)
set(CPM_HASH_SUM "c8cdc32c03816538ce22781ed72964dc864b2a34a310d3b7104812a5ca2d835d")

if(CPM_SOURCE_CACHE)
set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
elseif(DEFINED ENV{CPM_SOURCE_CACHE})
set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
else()
set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
endif()

# Expand relative path. This is important if the provided path contains a tilde (~)
get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE)

file(DOWNLOAD
https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM}
)

include(${CPM_DOWNLOAD_LOCATION})
Loading

0 comments on commit b797e5a

Please sign in to comment.