diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index 478529b0c..abf49c93d 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -1,4 +1,202 @@
-24.11.21
+24.11.30.3
+==========
+ + Properly remove Adaptive Trigger force feedback when impulse vibration stops
+
+24.11.30.2
+==========
+ + Implement PlayStation Adaptive Trigger support for DualSense controllers
+ connected using Bluetooth.
+
+24.11.30.1
+==========
+ + Bring back original slUpgradeInterface / slGetNativeInterface implementation
+ that could handle situations where sl.interposer.dll is loaded late.
+ + Increase default impulse trigger strength modifier to 0.75x, and properly
+ handle the case where setVibration (...) has zero trigger data.
+
+24.11.30
+========
+ + For all Unreal Engine games that use GameInput, enable Xbox Emulation by
+ default on first launch.
+ + Implement Adaptive Trigger response for GameInput Impulse Trigger emulation,
+ shooting guns and stabbing stuff in STALKER 2 now has Force Feedback that
+ would otherwise be Xbox exclusive!
+
+24.11.29.5
+==========
+ + Enable XInput emulation by default in STALKER 2
+
+24.11.29.4
+==========
+ + Ensure that "LowSpecMode" is enabled even for Metaphor: ReFantazio users with
+ texture mods installer, and change the auto-disable feature to only apply
+ when staging texture cache is enabled.
+ + Disable deferred context isolation in Metaphor by default for performance,
+ re-enable it if you need live texture modding or hudless screenshots.
+ + Improved thread interlocking for XInput rumble
+
+24.11.29.3
+==========
+ + Make Impulse Trigger Str. (Left/Right) configruable from SK's control panel.
+ + Correctly clear rumble when games pass a nullptr to SetRumbleState (...).
+
+24.11.29.2
+==========
+ + Added preliminary Xbox Impulse Triggers -> DualSense Haptics, in STALKER 2;
+ think of it more as supplementary rumble for the time being.
+
+ It does give a sensation you wouldn't get from just the 2 normal high/low
+ frequency rumble motors (or emulated motors in DualSense's case), but it
+ is not as advanced as actual haptic effects or Force Feedback Triggers.
+
+ I think a combination of the two could possibly create a convincing feeling,
+ but haven't had time to implement the various force feedback effect types
+ yet.
+
+24.11.29.1
+==========
+ + Avoid memory move in SK_Exception_HandleThreadName (...) when assigning
+ wide character name, explicitly copy the string.
+
+24.11.29
+========
+ + Stop forcing latency waitable swapchains on in games that do not normally
+ use them unless SwapChainWait is set to a non-zero value in INI.
+ + Optimize NVIDIA Reflex timing marker code in D3D12 games to avoid a constant
+ check for sl.interposer.dll.
+
+24.11.28.7
+==========
+ + Adjust Unreal Engine thread priorities for reduced stutter.
+ + Disable OpenGL and D3D9 hooks in ReShade is loaded as dxgi.dll or d3d12.dll,
+ in order to speed initialization up and reduce the chances of hook races.
+
+24.11.28.6
+==========
+ + Fix potential crash on non-Latency Waitable D3D12 SwapChains when SK
+ attempts to query the device latency from the D3D12 Device's DXGI Device.
+ + Remove Latency Waitable status from S.T.A.L.K.E.R. 2's SwapChain to help
+ reduce stutter slightly.
+
+24.11.28.5
+==========
+ + Implemented PlayStation->GameInput translation for DualShock 3/4 and
+ DualSense controllers over USB and Bluetooth (DS4/DualSense only).
+ + Removed warning about needing DS4Windows in GameInput games.
+
+24.11.28.4
+==========
+ + Implement haptic/rumble blocking support for GameInput; S.T.A.L.K.E.R. 2
+ uses impulse triggers, so next step is to translate those to DualSense.
+
+24.11.28.3
+==========
+ + Remove warning for ReShade loaded as dxgi.dll/d3d12.dll in D3D12 games;
+ it's still not a fully compatible combination, but the UI will at least
+ work (no SK Add-On releated features will).
+
+24.11.28.2
+==========
+ + Add 1 frame delay before returning GAMEINPUT_E_READING_NOT_FOUND when
+ initiating GameInput device blocking, so that the game will first read
+ safe neutralized input values.
+
+ (i.e. you don't keep running forward when the control panel opens).
+
+24.11.28.1
+==========
+ + Improved gamepad input blocking when using GameInput
+ + Wrapped IGameInputReading in order to implement PlayStation->GameInput
+ translation (not complete).
+
+24.11.28
+========
+ + Added initial support for GameInput; that means activity indicators in the
+ active Input API section of the control panel and blocking device classes
+ when SK's control panel is open or devices are enabled/disabled.
+ + Currently Special K cannot emulate GameInput for PlayStation controllers,
+
+ >> You must use DS4Windows to play games such as STALKER2 using a DualShock
+ or DualSense controller.
+
+ * Emulation support is planned, but the API is new to me and there is only
+ one known game that uses the API at the moment :)
+
+24.11.27
+========
+ + Adjusted Tomb Raider Remastered (OpenGL)'s default settings to use 8-bpc
+ instead of 10-bpc, because the game is sRGB.
+
+24.11.25
+========
+ + Disable the option to clear Flip Model backbuffers on present by default,
+ because it prevents OBS Game Capture in some (D3D11) scenarios.
+
+24.11.24.2
+==========
+ + Allow moving windows to different monitors by dragging without triggering
+ SK's monitor-change message (causes games to maximize the game window).
+
+24.11.24.1
+==========
+ + Fixed accidentally using ImGuiKey_MouseLeft to index the ImGuiIO::MouseDown
+ array (which only has 5 buttons; the value of ImGuiKey_MouseLeft is 653!)
+ * It should have been ImGuiIO::AddMouseButtonEvent (ImGuiKey_MouseLeft,...).
+ >> This relatively new bug only affected games w/ (Low-Level) Mouse Hooks...
+
+ + Ignore mouse button capture when the mouse cursor is over a non-client part
+ of a game window (i.e. title bar or resize grips).
+ + Disengage the "confine cursor" option temporarily while a game window has
+ been grabbed and is inside of the "size/move" modal loop, so that the
+ window can actually be resized or repositioned without interference.
+
+24.11.24
+========
+ + Unload plug-in DLLs at game exit _before_ uninstalling all hooked functions.
+ + Add plug-in DLL names to the unload log entires during game shutdown.
+ + Run each plug-in unload attempt within its own exception handler and
+ continue unloading remaining plug-ins if there is an exception.
+
+24.11.23.2
+==========
+ + Fixed the issue in 24.11.23.1 the correct way :) The staging copy of the
+ backbuffer needs to be enqueued, the reference to the backbuffer released,
+ and the command queue flushed immediately and then there are no chances
+ for the swapchain backbuffers to have outstanding references.
+
+24.11.23.1
+==========
+ + Fixed D3D11 screenshots occasionally causing display mode changes to fail if
+ a (Blt Model) game requested a mode change within 500-ms of the last screen
+ capture.
+
+24.11.23
+========
+ + Cleaned-up Mouse Cursor section of Input Control Panel and removed the old
+ "Low-Level Mouse Settings" section.
+
+ + Auto-Bluetooth Compatibility now only powers off PlayStation controllers
+ that have advanced Bluetooth mode active if SK has seen the game attempt
+ to poll input using WinMM or DirectInput 7/8 at least one time first.
+
+ # Controllers start in "simple" Bluetooth mode when initially powered on,
+ which is a mode compatible with DirectInput and WinMM.
+
+ >> Prior to this change, it could cause an endless loop of the controller
+ powering off, Steam Input re-initializing the controller in advanced
+ Bluetooth mode when powered back on, and then SK turning it back off!
+
+ * It is a niche feature that is more likely to be accidentally enabled by
+ users not completely familiar with its purpose than the chances of
+ playing a game that requires it.
+
+24.11.22
+========
+ + Update ReShade Add-on API headers to include new events in the next release.
+ + Reduce unnecessary WM_NCHITTEST messages sent to games when the cursor is not
+ even moving.
+
+24.11.21
========
+ Enable Fake Fullscreen mode by default in STALKER 2, because it uses that
crap (in D3D12) for HDR... yay!
diff --git a/SpecialK.vcxproj b/SpecialK.vcxproj
index 5122e639c..aa454817f 100644
--- a/SpecialK.vcxproj
+++ b/SpecialK.vcxproj
@@ -1587,6 +1587,15 @@ if exist "$(TargetDir)$(TargetName).exp" ( del "$(TargetDir)$(TargetName).exp" )
+
+
+
+
+
+
+
+
+
@@ -1688,6 +1697,7 @@ if exist "$(TargetDir)$(TargetName).exp" ( del "$(TargetDir)$(TargetName).exp" )
+
@@ -1906,6 +1916,7 @@ if exist "$(TargetDir)$(TargetName).exp" ( del "$(TargetDir)$(TargetName).exp" )
+
diff --git a/SpecialK.vcxproj.filters b/SpecialK.vcxproj.filters
index e027e1122..cdf79c1c9 100644
--- a/SpecialK.vcxproj.filters
+++ b/SpecialK.vcxproj.filters
@@ -394,6 +394,15 @@
{66e76b0e-72c4-46e4-af00-6bc57613bee9}
+
+ {dba4d6c2-fe48-4698-a44d-91be9d537dfa}
+
+
+ {0ce28763-ac3a-4457-991b-9919900c43f1}
+
+
+ {bd56277a-178a-4f88-bd68-60f7aa34fe67}
+
@@ -3198,6 +3207,36 @@
Header Files\External Libraries
+
+ Header Files\External Libraries\ReShade
+
+
+ Header Files\External Libraries\ReShade
+
+
+ Header Files\External Libraries\ReShade
+
+
+ Header Files\External Libraries\ReShade
+
+
+ Header Files\External Libraries\ReShade
+
+
+ Header Files\External Libraries\ReShade
+
+
+ Header Files\External Libraries\ReShade
+
+
+ Header Files\External Libraries\ReShade
+
+
+ Header Files\External Libraries\ReShade
+
+
+ Header Files\Backends\Input\GameInput
+
@@ -3818,6 +3857,9 @@
Source Files\Backends\Input
+
+ Source Files\Backends\Input\GameInput
+
diff --git a/depends/include/ReShade/reshade.hpp b/depends/include/ReShade/reshade.hpp
index 251a2a03d..bf0704320 100644
--- a/depends/include/ReShade/reshade.hpp
+++ b/depends/include/ReShade/reshade.hpp
@@ -5,6 +5,8 @@
#pragma once
+#define RESHADE_NO_IMGUI
+
#include "reshade_events.hpp"
#include "reshade_overlay.hpp"
#include
@@ -29,15 +31,20 @@ RESHADE_API_LIBRARY_DECL void ReShadeGetBasePath(char *path, size_t *path_size);
RESHADE_API_LIBRARY_DECL bool ReShadeGetConfigValue(HMODULE module, reshade::api::effect_runtime *runtime, const char *section, const char *key, char *value, size_t *value_size);
RESHADE_API_LIBRARY_DECL void ReShadeSetConfigValue(HMODULE module, reshade::api::effect_runtime *runtime, const char *section, const char *key, const char *value);
+RESHADE_API_LIBRARY_DECL void ReShadeSetConfigArray(HMODULE module, reshade::api::effect_runtime *runtime, const char *section, const char *key, const char *value, size_t value_size);
RESHADE_API_LIBRARY_DECL bool ReShadeRegisterAddon(HMODULE module, uint32_t api_version);
RESHADE_API_LIBRARY_DECL void ReShadeUnregisterAddon(HMODULE module);
RESHADE_API_LIBRARY_DECL void ReShadeRegisterEvent(reshade::addon_event ev, void *callback);
+RESHADE_API_LIBRARY_DECL void ReShadeRegisterEventForAddon(HMODULE module, reshade::addon_event ev, void *callback);
RESHADE_API_LIBRARY_DECL void ReShadeUnregisterEvent(reshade::addon_event ev, void *callback);
+RESHADE_API_LIBRARY_DECL void ReShadeUnregisterEventForAddon(HMODULE module, reshade::addon_event ev, void *callback);
RESHADE_API_LIBRARY_DECL void ReShadeRegisterOverlay(const char *title, void(*callback)(reshade::api::effect_runtime *runtime));
+RESHADE_API_LIBRARY_DECL void ReShadeRegisterOverlayForAddon(HMODULE module, const char *title, void(*callback)(reshade::api::effect_runtime *runtime));
RESHADE_API_LIBRARY_DECL void ReShadeUnregisterOverlay(const char *title, void(*callback)(reshade::api::effect_runtime *runtime));
+RESHADE_API_LIBRARY_DECL void ReShadeUnregisterOverlayForAddon(HMODULE module, const char *title, void(*callback)(reshade::api::effect_runtime *runtime));
RESHADE_API_LIBRARY_DECL bool ReShadeCreateEffectRuntime(reshade::api::device_api api, void *opaque_device, void *opaque_command_queue, void *opaque_swapchain, const char *config_path, reshade::api::effect_runtime **out_runtime);
RESHADE_API_LIBRARY_DECL void ReShadeDestroyEffectRuntime(reshade::api::effect_runtime *runtime);
@@ -53,9 +60,9 @@ namespace reshade { namespace internal
///
/// Gets the handle to the ReShade module.
///
- inline HMODULE get_reshade_module_handle(HMODULE reshade_module = nullptr)
+ inline HMODULE get_reshade_module_handle(HMODULE initial_handle = nullptr)
{
- static HMODULE handle = reshade_module;
+ static HMODULE handle = initial_handle;
if (handle == nullptr)
{
HMODULE modules[1024]; DWORD num = 0;
@@ -81,13 +88,12 @@ namespace reshade { namespace internal
///
/// Gets the handle to the current add-on module.
///
- inline HMODULE get_current_module_handle(HMODULE addon_module = nullptr)
+ inline HMODULE get_current_module_handle(HMODULE initial_handle = nullptr)
{
- static HMODULE handle = addon_module;
+ static HMODULE handle = initial_handle;
return handle;
}
-
- inline BOOL has_addon(const wchar_t* name)
+ inline BOOL has_addon(const wchar_t* name)
{
if (name == nullptr)
return FALSE;
@@ -118,44 +124,49 @@ namespace reshade { namespace internal
namespace reshade
{
- ///
- /// Available log severity levels.
- ///
- enum class log_level
+#if !defined(RESHADE_API_LIBRARY_EXPORT) || defined(BUILTIN_ADDON)
+ namespace log
{
///
- /// | [ERROR] | ...
- ///
- error = 1,
- ///
- /// | [WARN] | ...
+ /// Severity levels for logging.
///
- warning = 2,
- ///
- /// | [INFO] | ...
- ///
- info = 3,
+ enum class level
+ {
+ ///
+ /// | ERROR | ...
+ ///
+ error = 1,
+ ///
+ /// | WARN | ...
+ ///
+ warning = 2,
+ ///
+ /// | INFO | ...
+ ///
+ info = 3,
+ ///
+ /// | DEBUG | ...
+ ///
+ debug = 4,
+ };
+
///
- /// | [DEBUG] | ...
+ /// Writes a message to ReShade's log.
///
- debug = 4
- };
-
- ///
- /// Writes a message to ReShade's log.
- ///
- /// Severity level.
- /// A null-terminated message string.
- inline void log_message(log_level level, const char *message)
- {
+ /// Severity level.
+ /// A null-terminated message string.
+ inline void message(level level, const char *message)
+ {
#if defined(RESHADE_API_LIBRARY)
- ReShadeLogMessage(nullptr, static_cast(level), message);
+ ReShadeLogMessage(nullptr, static_cast(level), message);
#else
- static const auto func = reinterpret_cast(
- GetProcAddress(internal::get_reshade_module_handle(), "ReShadeLogMessage"));
- func(internal::get_current_module_handle(), static_cast(level), message);
+ static const auto func = reinterpret_cast(
+ GetProcAddress(internal::get_reshade_module_handle(), "ReShadeLogMessage"));
+ func(internal::get_current_module_handle(), static_cast(level), message);
#endif
+ }
}
+#endif
///
/// Gets the base path ReShade uses to resolve relative paths.
@@ -245,6 +256,16 @@ namespace reshade
set_config_value(runtime, section, key, value ? 1 : 0);
}
#endif
+ inline void set_config_value(api::effect_runtime *runtime, const char *section, const char *key, const char *value, size_t value_size)
+ {
+#if defined(RESHADE_API_LIBRARY)
+ ReShadeSetConfigArray(nullptr, runtime, section, key, value, value_size);
+#else
+ static const auto func = reinterpret_cast(
+ GetProcAddress(internal::get_reshade_module_handle(), "ReShadeSetConfigArray"));
+ func(internal::get_current_module_handle(), runtime, section, key, value, value_size);
+#endif
+ }
///
/// Registers this module as an add-on with ReShade.
@@ -268,14 +289,13 @@ namespace reshade
// Check that the ReShade module supports the used API
if (func == nullptr || !func(addon_module, RESHADE_API_VERSION))
return false;
-#if 0
-#if defined(IMGUI_VERSION_NUM)
+
+#if defined(IMGUI_VERSION_NUM) && !defined(RESHADE_NO_IMGUI)
const auto imgui_func = reinterpret_cast(
GetProcAddress(reshade_module, "ReShadeGetImGuiFunctionTable"));
// Check that the ReShade module was built with Dear ImGui support and supports the used version
if (imgui_func == nullptr || !(imgui_function_table_instance() = imgui_func(IMGUI_VERSION_NUM)))
return false;
-#endif
#endif
return true;
diff --git a/depends/include/ReShade/reshade_api.hpp b/depends/include/ReShade/reshade_api.hpp
index 7d3c7ece1..e1616005f 100644
--- a/depends/include/ReShade/reshade_api.hpp
+++ b/depends/include/ReShade/reshade_api.hpp
@@ -31,6 +31,8 @@ namespace reshade { namespace api
///
RESHADE_DEFINE_HANDLE(effect_uniform_variable);
+ struct display;
+
///
/// Input source for events triggered by user input.
///
@@ -65,6 +67,10 @@ namespace reshade { namespace api
///
virtual uint32_t get_back_buffer_count() const = 0;
+ ///
+ /// Gets the current back buffer resource.
+ ///
+ resource get_current_back_buffer() { return get_back_buffer(get_current_back_buffer_index()); }
///
/// Gets the index of the back buffer resource that can currently be rendered into.
///
@@ -91,10 +97,10 @@ namespace reshade { namespace api
virtual void render_effects(command_list *cmd_list, resource_view rtv, resource_view rtv_srgb) = 0;
///
- /// Captures a screenshot of the current back buffer resource and returns its image data in 32 bits-per-pixel RGBA format.
+ /// Captures a screenshot of the current back buffer resource and returns its image data.
///
- /// Pointer to an array of width * height * 4 bytes the image data is written to.
- virtual bool capture_screenshot(uint8_t *pixels) = 0;
+ /// Pointer to an array of width * height * bpp bytes the image data is written to (where bpp is the number of bytes per pixel of the back buffer format).
+ virtual bool capture_screenshot(void *pixels) = 0;
///
/// Gets the current buffer dimensions of the swap chain.
@@ -159,7 +165,7 @@ namespace reshade { namespace api
/// File name of the effect file to enumerate uniform variables from, or to enumerate those of all loaded effects.
/// Function to call for every uniform variable.
template
- inline void enumerate_uniform_variables(const char *effect_name, F lambda)
+ void enumerate_uniform_variables(const char *effect_name, F lambda)
{
enumerate_uniform_variables(effect_name, [](effect_runtime *runtime, effect_uniform_variable variable, void *user_data) { static_cast(user_data)->operator()(runtime, variable); }, &lambda);
}
@@ -193,7 +199,7 @@ namespace reshade { namespace api
/// Pointer to an integer that contains the size of the string buffer and is set to the actual length of the string, including the null-terminator.
virtual void get_uniform_variable_name(effect_uniform_variable variable, char *name, size_t *name_size) const = 0;
template
- inline void get_uniform_variable_name(effect_uniform_variable variable, char(&name)[SIZE]) const
+ void get_uniform_variable_name(effect_uniform_variable variable, char(&name)[SIZE]) const
{
size_t name_size = SIZE;
get_uniform_variable_name(variable, name, &name_size);
@@ -249,7 +255,7 @@ namespace reshade { namespace api
/// if the annotation exists on the uniform variable, otherwise.
virtual bool get_annotation_string_from_uniform_variable(effect_uniform_variable variable, const char *name, char *value, size_t *value_size) const = 0;
template
- inline bool get_annotation_string_from_uniform_variable(effect_uniform_variable variable, const char *name, char(&value)[SIZE]) const
+ bool get_annotation_string_from_uniform_variable(effect_uniform_variable variable, const char *name, char(&value)[SIZE]) const
{
size_t value_size = SIZE;
return get_annotation_string_from_uniform_variable(variable, name, value, &value_size);
@@ -308,7 +314,7 @@ namespace reshade { namespace api
/// Optional value of the second component in the vector that is used to update this uniform variable.
/// Optional value of the third component in the vector that is used to update this uniform variable.
/// Optional value of the fourth component in the vector that is used to update this uniform variable.
- inline void set_uniform_value_bool(effect_uniform_variable variable, bool x, bool y = bool(0), bool z = bool(0), bool w = bool(0))
+ void set_uniform_value_bool(effect_uniform_variable variable, bool x, bool y = bool(0), bool z = bool(0), bool w = bool(0))
{
const bool values[4] = { x, y, z, w };
set_uniform_value_bool(variable, values, 4);
@@ -333,7 +339,7 @@ namespace reshade { namespace api
/// Optional value of the second component in the vector that is used to update this uniform variable.
/// Optional value of the third component in the vector that is used to update this uniform variable.
/// Optional value of the fourth component in the vector that is used to update this uniform variable.
- inline void set_uniform_value_float(effect_uniform_variable variable, float x, float y = float(0), float z = float(0), float w = float(0))
+ void set_uniform_value_float(effect_uniform_variable variable, float x, float y = float(0), float z = float(0), float w = float(0))
{
const float values[4] = { x, y, z, w };
set_uniform_value_float(variable, values, 4);
@@ -358,7 +364,7 @@ namespace reshade { namespace api
/// Optional value of the second component in the vector that is used to update this uniform variable.
/// Optional value of the third component in the vector that is used to update this uniform variable.
/// Optional value of the fourth component in the vector that is used to update this uniform variable.
- inline void set_uniform_value_int(effect_uniform_variable variable, int32_t x, int32_t y = int32_t(0), int32_t z = int32_t(0), int32_t w = int32_t(0))
+ void set_uniform_value_int(effect_uniform_variable variable, int32_t x, int32_t y = int32_t(0), int32_t z = int32_t(0), int32_t w = int32_t(0))
{
const int32_t values[4] = { x, y, z, w };
set_uniform_value_int(variable, values, 4);
@@ -383,7 +389,7 @@ namespace reshade { namespace api
/// Optional value of the second component in the vector that is used to update this uniform variable.
/// Optional value of the third component in the vector that is used to update this uniform variable.
/// Optional value of the fourth component in the vector that is used to update this uniform variable.
- inline void set_uniform_value_uint(effect_uniform_variable variable, uint32_t x, uint32_t y = uint32_t(0), uint32_t z = uint32_t(0), uint32_t w = uint32_t(0))
+ void set_uniform_value_uint(effect_uniform_variable variable, uint32_t x, uint32_t y = uint32_t(0), uint32_t z = uint32_t(0), uint32_t w = uint32_t(0))
{
const uint32_t values[4] = { x, y, z, w };
set_uniform_value_uint(variable, values, 4);
@@ -402,7 +408,7 @@ namespace reshade { namespace api
/// File name of the effect file to enumerate texture variables from, or to enumerate those of all loaded effects.
/// Function to call for every texture variable.
template
- inline void enumerate_texture_variables(const char *effect_name, F lambda)
+ void enumerate_texture_variables(const char *effect_name, F lambda)
{
enumerate_texture_variables(effect_name, [](effect_runtime *runtime, effect_texture_variable variable, void *user_data) { static_cast(user_data)->operator()(runtime, variable); }, &lambda);
}
@@ -423,7 +429,7 @@ namespace reshade { namespace api
/// Pointer to an integer that contains the size of the string buffer and is set to the actual length of the string, including the null-terminator.
virtual void get_texture_variable_name(effect_texture_variable variable, char *name, size_t *name_size) const = 0;
template
- inline void get_texture_variable_name(effect_texture_variable variable, char(&name)[SIZE]) const
+ void get_texture_variable_name(effect_texture_variable variable, char(&name)[SIZE]) const
{
size_t name_size = SIZE;
get_texture_variable_name(variable, name, &name_size);
@@ -479,20 +485,20 @@ namespace reshade { namespace api
/// if the annotation exists on the texture variable, otherwise.
virtual bool get_annotation_string_from_texture_variable(effect_texture_variable variable, const char *name, char *value, size_t *value_size) const = 0;
template
- inline bool get_annotation_string_from_texture_variable(effect_texture_variable variable, const char *name, char(&value)[SIZE]) const
+ bool get_annotation_string_from_texture_variable(effect_texture_variable variable, const char *name, char(&value)[SIZE]) const
{
size_t value_size = SIZE;
return get_annotation_string_from_texture_variable(variable, name, value, &value_size);
}
///
- /// Uploads 32 bits-per-pixel RGBA image data to the specified texture .
+ /// Uploads image data to the specified texture .
///
/// Opaque handle to the texture variable.
/// Width of the image data.
/// Height of the image data.
- /// Pointer to an array of width * height * 4 bytes the image data is read from.
- virtual void update_texture(effect_texture_variable variable, const uint32_t width, const uint32_t height, const uint8_t *pixels) = 0;
+ /// Pointer to an array of width * height * bpp bytes the image data is read from (where bpp is the number of bytes per pixel of the texture format).
+ virtual void update_texture(effect_texture_variable variable, const uint32_t width, const uint32_t height, const void *pixels) = 0;
///
/// Gets the shader resource view that is bound to the specified texture .
@@ -526,7 +532,7 @@ namespace reshade { namespace api
/// File name of the effect file to enumerate techniques from, or to enumerate those of all loaded effects.
/// Function to call for every technique.
template
- inline void enumerate_techniques(const char *effect_name, F lambda)
+ void enumerate_techniques(const char *effect_name, F lambda)
{
enumerate_techniques(effect_name, [](effect_runtime *runtime, effect_technique technique, void *user_data) { static_cast(user_data)->operator()(runtime, technique); }, &lambda);
}
@@ -547,7 +553,7 @@ namespace reshade { namespace api
/// Pointer to an integer that contains the size of the string buffer and is set to the actual length of the string, including the null-terminator.
virtual void get_technique_name(effect_technique technique, char *name, size_t *name_size) const = 0;
template
- inline void get_technique_name(effect_technique technique, char(&name)[SIZE]) const
+ void get_technique_name(effect_technique technique, char(&name)[SIZE]) const
{
size_t name_size = SIZE;
get_technique_name(technique, name, &name_size);
@@ -603,7 +609,7 @@ namespace reshade { namespace api
/// if the annotation exists on the technique, otherwise.
virtual bool get_annotation_string_from_technique(effect_technique technique, const char *name, char *value, size_t *value_size) const = 0;
template
- inline bool get_annotation_string_from_technique(effect_technique technique, const char *name, char(&value)[SIZE]) const
+ bool get_annotation_string_from_technique(effect_technique technique, const char *name, char(&value)[SIZE]) const
{
size_t value_size = SIZE;
return get_annotation_string_from_technique(technique, name, value, &value_size);
@@ -631,7 +637,7 @@ namespace reshade { namespace api
/// if the preprocessor definition is defined, otherwise.
virtual bool get_preprocessor_definition(const char *name, char *value, size_t *value_size) const = 0;
template
- inline bool get_preprocessor_definition(const char *name, char(&value)[SIZE]) const
+ bool get_preprocessor_definition(const char *name, char(&value)[SIZE]) const
{
size_t value_size = SIZE;
return get_preprocessor_definition(name, value, &value_size);
@@ -674,7 +680,7 @@ namespace reshade { namespace api
/// Pointer to an integer that contains the size of the string buffer and is set to the actual length of the string, including the null-terminator.
virtual void get_current_preset_path(char *path, size_t *path_size) const = 0;
template
- inline void get_current_preset_path(char(&path)[SIZE]) const
+ void get_current_preset_path(char(&path)[SIZE]) const
{
size_t path_size = SIZE;
get_current_preset_path(path, &path_size);
@@ -715,7 +721,7 @@ namespace reshade { namespace api
/// Pointer to an integer that contains the size of the string buffer and is set to the actual length of the string, including the null-terminator.
virtual void get_uniform_variable_effect_name(effect_uniform_variable variable, char *effect_name, size_t *effect_name_size) const = 0;
template
- inline void get_uniform_variable_effect_name(effect_uniform_variable variable, char(&effect_name)[SIZE]) const
+ void get_uniform_variable_effect_name(effect_uniform_variable variable, char(&effect_name)[SIZE]) const
{
size_t effect_name_size = SIZE;
get_uniform_variable_effect_name(variable, effect_name, &effect_name_size);
@@ -729,7 +735,7 @@ namespace reshade { namespace api
/// Pointer to an integer that contains the size of the string buffer and is set to the actual length of the string, including the null-terminator.
virtual void get_texture_variable_effect_name(effect_texture_variable variable, char *effect_name, size_t *effect_name_size) const = 0;
template
- inline void get_texture_variable_effect_name(effect_texture_variable variable, char(&effect_name)[SIZE]) const
+ void get_texture_variable_effect_name(effect_texture_variable variable, char(&effect_name)[SIZE]) const
{
size_t effect_name_size = SIZE;
get_texture_variable_effect_name(variable, effect_name, &effect_name_size);
@@ -743,7 +749,7 @@ namespace reshade { namespace api
/// Pointer to an integer that contains the size of the string buffer and is set to the actual length of the string, including the null-terminator.
virtual void get_technique_effect_name(effect_technique technique, char *effect_name, size_t *effect_name_size) const = 0;
template
- inline void get_technique_effect_name(effect_technique technique, char(&effect_name)[SIZE]) const
+ void get_technique_effect_name(effect_technique technique, char(&effect_name)[SIZE]) const
{
size_t effect_name_size = SIZE;
get_technique_effect_name(technique, effect_name, &effect_name_size);
@@ -764,7 +770,7 @@ namespace reshade { namespace api
/// if the preprocessor definition is defined, otherwise.
virtual bool get_preprocessor_definition_for_effect(const char *effect_name, const char *name, char *value, size_t *value_size) const = 0;
template
- inline bool get_preprocessor_definition_for_effect(const char *effect_name, const char *name, char(&value)[SIZE]) const
+ bool get_preprocessor_definition_for_effect(const char *effect_name, const char *name, char(&value)[SIZE]) const
{
size_t value_size = SIZE;
return get_preprocessor_definition_for_effect(effect_name, name, value, &value_size);
@@ -789,5 +795,23 @@ namespace reshade { namespace api
/// Overrides the color space used for presentation.
///
virtual void set_color_space(color_space color_space) = 0;
+
+ ///
+ /// Resets the value of the specified uniform .
+ ///
+ /// Opaque handle to the uniform variable.
+ virtual void reset_uniform_value(effect_uniform_variable variable) = 0;
+
+ ///
+ /// Queues up the specified effect for reloading in the next frame.
+ /// This can be called multiple times with different effects to append to the queue.
+ ///
+ /// File name of the effect file that should be reloaded.
+ virtual void reload_effect_next_frame(const char *effect_name) = 0;
+
+ ///
+ /// Gets the active display, which may change between frames or return nullptr if the swapchain does not have a unique output device.
+ ///
+ virtual display* get_active_display() const = 0;
};
} }
diff --git a/depends/include/ReShade/reshade_api_device.hpp b/depends/include/ReShade/reshade_api_device.hpp
index 87e39b9d0..3deed5332 100644
--- a/depends/include/ReShade/reshade_api_device.hpp
+++ b/depends/include/ReShade/reshade_api_device.hpp
@@ -10,8 +10,9 @@
namespace reshade { namespace api
{
///
- /// The underlying render API a device is using, as returned by .
+ /// Underlying graphics API a device is using.
///
+ ///
enum class device_api
{
/// Direct3D 9
@@ -35,8 +36,9 @@ namespace reshade { namespace api
};
///
- /// The available features a device may support.
+ /// Optional capabilities a device may support, depending on the underlying graphics API and hardware.
///
+ ///
enum class device_caps
{
///
@@ -56,7 +58,7 @@ namespace reshade { namespace api
hull_and_domain_shader,
///
/// Specifies whether logic operations are available in the blend state.
- /// If this feature is not present, the and fields are ignored.
+ /// If this feature is not present, and are ignored.
///
logic_op,
///
@@ -76,7 +78,7 @@ namespace reshade { namespace api
fill_mode_non_solid,
///
/// Specifies whether conservative rasterization is supported.
- /// If this feature is not present, the field must be 0.
+ /// If this feature is not present, must be 0.
///
conservative_rasterization,
///
@@ -136,7 +138,7 @@ namespace reshade { namespace api
copy_query_heap_results,
///
/// Specifies whether comparison sampling is supported.
- /// If this feature is not present, the field is ignored and the compare filter types have no effect.
+ /// If this feature is not present, is ignored and the compare filter types have no effect.
///
sampler_compare,
///
@@ -174,17 +176,64 @@ namespace reshade { namespace api
/// If this feature is not present, must not be used.
///
shared_fence_nt_handle,
+ ///
+ /// Specifies whether amplification and mesh shaders are supported.
+ /// If this feature is not present, the and stages and must not be used.
+ ///
+ amplification_and_mesh_shader,
+ ///
+ /// Specifies whether ray tracing is supported.
+ /// If this feature is not present, , , and must not be used.
+ ///
+ ray_tracing,
};
///
- /// Describes an adapter/physical device.
+ /// Properties that may be queried from a device.
///
- struct device_properties
+ ///
+ enum class device_properties
{
- unsigned int api_version = 0;
- unsigned int driver_version = 0;
- unsigned int vendor_id = 0, device_id = 0;
- char description[256] = "";
+ ///
+ /// Version of the underlying graphics API the device is using.
+ /// Data is a 32-bit unsigned integer value.
+ ///
+ api_version = 1,
+ ///
+ /// Version of the graphics driver that is being used.
+ /// Data is a 32-bit unsigned integer value.
+ ///
+ driver_version,
+ ///
+ /// PCI vendor ID of the hardware associated with the logical render device.
+ /// Data is a 32-bit unsigned integer value.
+ ///
+ vendor_id,
+ ///
+ /// PCI device ID of the hardware associated with the logical render device.
+ /// Data is a 32-bit unsigned integer value.
+ ///
+ device_id,
+ ///
+ /// Description text of the hardware associated with the logical render device.
+ /// Data is an array of 256 byte-sized characters representing a null-terminated string.
+ ///
+ description,
+ ///
+ /// Size of a handle as written by .
+ /// Data is a 32-bit unsigned integer value.
+ ///
+ shader_group_handle_size,
+ ///
+ /// Required alignment of the base handle in the buffers passed to .
+ /// Data is a 32-bit unsigned integer value.
+ ///
+ shader_group_alignment,
+ ///
+ /// Required alignment of each handle in the buffers passed to .
+ /// Data is a 32-bit unsigned integer value.
+ ///
+ shader_group_handle_alignment,
};
///
@@ -219,7 +268,8 @@ namespace reshade { namespace api
///
/// Gets a reference to user-defined data from the object that was previously allocated via .
///
- template inline T &get_private_data() const
+ template
+ T &get_private_data() const
{
uint64_t res;
get_private_data(reinterpret_cast(&__uuidof(T)), &res);
@@ -228,16 +278,18 @@ namespace reshade { namespace api
///
/// Allocates user-defined data and stores it in the object.
///
- template inline T &create_private_data(Args... args)
+ template
+ T &create_private_data(Args &&... args)
{
- uint64_t res = reinterpret_cast(new T(std::forward(args)...));
+ uint64_t res = reinterpret_cast(new T(static_cast(args)...));
set_private_data(reinterpret_cast(&__uuidof(T)), res);
return *reinterpret_cast(static_cast(res));
}
///
/// Frees user-defined data that was previously allocated via .
///
- template inline void destroy_private_data()
+ template
+ void destroy_private_data()
{
uint64_t res;
get_private_data(reinterpret_cast(&__uuidof(T)), &res);
@@ -273,29 +325,29 @@ namespace reshade { namespace api
/// Creates a new sampler state object.
///
/// Description of the sampler to create.
- /// Pointer to a variable that is set to the handle of the created sampler.
- /// if the sampler was successfully created, otherwise (in this case is set to zero).
- virtual bool create_sampler(const sampler_desc &desc, sampler *out_handle) = 0;
+ /// Pointer to a variable that is set to the handle of the created sampler.
+ /// if the sampler was successfully created, otherwise (in this case is set to zero).
+ virtual bool create_sampler(const sampler_desc &desc, sampler *out_sampler) = 0;
///
/// Instantly destroys a sampler that was previously created via .
///
- virtual void destroy_sampler(sampler handle) = 0;
+ virtual void destroy_sampler(sampler sampler) = 0;
///
/// Allocates and creates a new resource.
///
/// Description of the resource to create.
/// Optional data to upload to the resource after creation. This should point to an array of , one for each subresource (mipmap levels and array layers). Can be to indicate no initial data to upload.
- /// Initial state of the resource after creation. This can later be changed via .
- /// Pointer to a variable that is set to the handle of the created resource.
+ /// Initial state of the resource after creation. This can later be changed via . It should also be part of the flags of the description.
+ /// Pointer to a variable that is set to the handle of the created resource.
/// Optional pointer to a variable of type HANDLE used when contains . When that variable is a , it is set to the exported shared handle of the created resource. When that variable is a valid handle, the resource is imported from that shared handle.
- /// if the resource was successfully created, otherwise (in this case is set to zero).
- virtual bool create_resource(const resource_desc &desc, const subresource_data *initial_data, resource_usage initial_state, resource *out_handle, void **shared_handle = nullptr) = 0;
+ /// if the resource was successfully created, otherwise (in this case is set to zero).
+ virtual bool create_resource(const resource_desc &desc, const subresource_data *initial_data, resource_usage initial_state, resource *out_resource, void **shared_handle = nullptr) = 0;
///
/// Instantly destroys a resource that was previously created via and frees its memory.
- /// Make sure the resource is no longer in use on the GPU (via any command list that may reference it and is still being executed) before doing this and never try to destroy resources created by the application!
+ /// Make sure the resource is no longer in use on the GPU (via any command list that may reference it and is still being executed) before doing this (e.g. with ) and never try to destroy resources created by the application!
///
- virtual void destroy_resource(resource handle) = 0;
+ virtual void destroy_resource(resource resource) = 0;
///
/// Gets the description of the specified resource.
@@ -308,13 +360,13 @@ namespace reshade { namespace api
/// Resource to create the view to.
/// Usage type of the resource view to create. Set to to create a shader resource view, for a depth-stencil view, for a render target etc.
/// Description of the resource view to create.
- /// Pointer to a variable that is set to the handle of the created resource view.
- /// if the resource view was successfully created, otherwise (in this case is set to zero).
- virtual bool create_resource_view(resource resource, resource_usage usage_type, const resource_view_desc &desc, resource_view *out_handle) = 0;
+ /// Pointer to a variable that is set to the handle of the created resource view.
+ /// if the resource view was successfully created, otherwise (in this case is set to zero).
+ virtual bool create_resource_view(resource resource, resource_usage usage_type, const resource_view_desc &desc, resource_view *out_view) = 0;
///
/// Instantly destroys a resource view that was previously created via .
///
- virtual void destroy_resource_view(resource_view handle) = 0;
+ virtual void destroy_resource_view(resource_view view) = 0;
///
/// Gets the handle to the underlying resource the specified resource was created for.
@@ -382,53 +434,53 @@ namespace reshade { namespace api
///
/// Pipeline layout to use.
/// Number of sub-objects.
- /// Pointer to an array of sub-objects that describe this pipeline.
- /// Pointer to a variable that is set to the handle of the created pipeline state object.
- /// if the pipeline state object was successfully created, otherwise (in this case is set to zero).
- virtual bool create_pipeline(pipeline_layout layout, uint32_t subobject_count, const pipeline_subobject *subobjects, pipeline *out_handle) = 0;
+ /// Pointer to the first element of an array of sub-objects that describe this pipeline.
+ /// Pointer to a variable that is set to the handle of the created pipeline state object.
+ /// if the pipeline state object was successfully created, otherwise (in this case is set to zero).
+ virtual bool create_pipeline(pipeline_layout layout, uint32_t subobject_count, const pipeline_subobject *subobjects, pipeline *out_pipeline) = 0;
///
/// Instantly destroys a pipeline state object that was previously created via .
///
- virtual void destroy_pipeline(pipeline handle) = 0;
+ virtual void destroy_pipeline(pipeline pipeline) = 0;
///
/// Creates a new pipeline layout.
///
/// Number of layout parameters.
- /// Pointer to an array of layout parameters that describe this pipeline layout.
- /// Pointer to a variable that is set to the handle of the created pipeline layout.
- /// if the pipeline layout was successfully created, otherwise (in this case is set to zero).
- virtual bool create_pipeline_layout(uint32_t param_count, const pipeline_layout_param *params, pipeline_layout *out_handle) = 0;
+ /// Pointer to the first element of an array of layout parameters that describe this pipeline layout.
+ /// Pointer to a variable that is set to the handle of the created pipeline layout.
+ /// if the pipeline layout was successfully created, otherwise (in this case is set to zero).
+ virtual bool create_pipeline_layout(uint32_t param_count, const pipeline_layout_param *params, pipeline_layout *out_layout) = 0;
///
/// Instantly destroys a pipeline layout that was previously created via .
///
- virtual void destroy_pipeline_layout(pipeline_layout handle) = 0;
+ virtual void destroy_pipeline_layout(pipeline_layout layout) = 0;
///
- /// Allocates a descriptor table from an internal heap.
+ /// Allocates a descriptor table from an internal descriptor heap.
///
/// Pipeline layout that contains a parameter that describes the descriptor table.
/// Index of the pipeline layout parameter that describes the descriptor table.
- /// Pointer to a a variable that is set to the handles of the created descriptor table.
- /// if the descriptor table was successfully allocated, otherwise (in this case is set to zeroe).
- inline bool allocate_descriptor_table(pipeline_layout layout, uint32_t param, descriptor_table *out_handle) { return allocate_descriptor_tables(1, layout, param, out_handle); }
+ /// Pointer to a a variable that is set to the handles of the created descriptor table.
+ /// if the descriptor table was successfully allocated, otherwise (in this case is set to zeroe).
+ bool allocate_descriptor_table(pipeline_layout layout, uint32_t param, descriptor_table *out_table) { return allocate_descriptor_tables(1, layout, param, out_table); }
///
- /// Allocates one or more descriptor tables from an internal heap.
+ /// Allocates one or more descriptor tables from an internal descriptor heap.
///
/// Number of descriptor tables to allocate.
- /// Pipeline layout that contains a parameter that describes the descriptor table.
- /// Index of the pipeline layout parameter that describes the descriptor table.
- /// Pointer to an array of handles with at least elements that is filled with the handles of the created descriptor tables.
- /// if the descriptor tables were successfully allocated, otherwise (in this case is filled with zeroes).
- virtual bool allocate_descriptor_tables(uint32_t count, pipeline_layout layout, uint32_t param, descriptor_table *out_handles) = 0;
+ /// Pipeline layout that contains a parameter that describes the descriptor tables.
+ /// Index of the pipeline layout parameter that describes the descriptor tables.
+ /// Pointer to the first element of an array of handles with at least elements that is filled with the handles of the created descriptor tables.
+ /// if the descriptor tables were successfully allocated, otherwise (in this case is filled with zeroes).
+ virtual bool allocate_descriptor_tables(uint32_t count, pipeline_layout layout, uint32_t param, descriptor_table *out_tables) = 0;
///
- /// Frees a descriptor table that was previously allocated via .
+ /// Frees a descriptor table that was previously allocated via .
///
- inline void free_descriptor_table(descriptor_table handle) { free_descriptor_tables(1, &handle); }
+ void free_descriptor_table(descriptor_table table) { free_descriptor_tables(1, &table); }
///
- /// Frees one or more descriptor tables that were previously allocated via .
+ /// Frees one or more descriptor tables that were previously allocated via .
///
- virtual void free_descriptor_tables(uint32_t count, const descriptor_table *handles) = 0;
+ virtual void free_descriptor_tables(uint32_t count, const descriptor_table *tables) = 0;
///
/// Gets the offset (in descriptors) of the specified binding in the underlying descriptor heap of a descriptor table.
@@ -444,23 +496,23 @@ namespace reshade { namespace api
/// Copies the contents of a descriptor table to another descriptor table.
///
/// Descriptor table copy to process.
- inline void copy_descriptors(const descriptor_table_copy ©) { copy_descriptor_tables(1, ©); }
+ void copy_descriptors(const descriptor_table_copy ©) { copy_descriptor_tables(1, ©); }
///
/// Copies the contents between multiple descriptor tables.
///
/// Number of to process.
- /// Pointer to an array of descriptor table copies to process.
+ /// Pointer to the first element of an array of descriptor table copies to process.
virtual void copy_descriptor_tables(uint32_t count, const descriptor_table_copy *copies) = 0;
///
/// Updates the contents of a descriptor table with the specified descriptors.
///
/// Descriptor table update to process.
- inline void update_descriptors(const descriptor_table_update &update) { update_descriptor_tables(1, &update); }
+ void update_descriptors(const descriptor_table_update &update) { update_descriptor_tables(1, &update); }
///
/// Updates the contents of multiple descriptor tables with the specified descriptors.
///
/// Number of to process.
- /// Pointer to an array of descriptor table updates to process.
+ /// Pointer to the first element of an array of descriptor table updates to process.
virtual void update_descriptor_tables(uint32_t count, const descriptor_table_update *updates) = 0;
///
@@ -468,13 +520,13 @@ namespace reshade { namespace api
///
/// Type of queries that will be used with this query heap.
/// Number of queries to allocate in the query heap.
- /// Pointer to a variable that is set to the handle of the created query heap.
- /// if the query heap was successfully created, otherwise (in this case is set to zero).
- virtual bool create_query_heap(query_type type, uint32_t size, query_heap *out_handle) = 0;
+ /// Pointer to a variable that is set to the handle of the created query heap.
+ /// if the query heap was successfully created, otherwise (in this case is set to zero).
+ virtual bool create_query_heap(query_type type, uint32_t size, query_heap *out_heap) = 0;
///
/// Instantly destroys a query heap that was previously created via .
///
- virtual void destroy_query_heap(query_heap handle) = 0;
+ virtual void destroy_query_heap(query_heap heap) = 0;
///
/// Gets the results of queries in a query heap.
@@ -482,7 +534,7 @@ namespace reshade { namespace api
/// Query heap that contains the queries.
/// Index of the first query in the query heap to copy the results from.
/// Number of query results to copy.
- /// Pointer to an array that is filled with the results.
+ /// Pointer to the first element of an array that is filled with the results. The necessary data type is documented at the enumeration.
/// Size (in bytes) of each element in the array.
/// if the query results were successfully downloaded from the GPU, otherwise.
virtual bool get_query_heap_results(query_heap heap, uint32_t first, uint32_t count, void *results, uint32_t stride) = 0;
@@ -490,29 +542,29 @@ namespace reshade { namespace api
///
/// Associates a name with a resource, for easier debugging in external tools.
///
- /// Resource to associate a name with.
+ /// Resource to associate a name with.
/// Null-terminated name string.
- virtual void set_resource_name(resource handle, const char *name) = 0;
+ virtual void set_resource_name(resource resource, const char *name) = 0;
///
/// Associates a name with a resource view, for easier debugging in external tools.
///
- /// Resource view to associate a name with.
+ /// Resource view to associate a name with.
/// Null-terminated name string.
- virtual void set_resource_view_name(resource_view handle, const char *name) = 0;
+ virtual void set_resource_view_name(resource_view view, const char *name) = 0;
///
/// Creates a new fence synchronization object.
///
/// The initial value for the fence.
/// Fence creation options.
- /// Pointer to a variable that is set to the handle of the created fence.
+ /// Pointer to a variable that is set to the handle of the created fence.
/// Optional pointer to a variable of type HANDLE used when contains . When that variable is a , it is set to the exported shared handle of the created fence. When that variable is a valid handle, the fence is imported from that shared handle.
- /// if the fence was successfully created, otherwise (in this case is set to zero).
- virtual bool create_fence(uint64_t initial_value, fence_flags flags, fence *out_handle, void **shared_handle = nullptr) = 0;
+ /// if the fence was successfully created, otherwise (in this case is set to zero).
+ virtual bool create_fence(uint64_t initial_value, fence_flags flags, fence *out_fence, void **shared_handle = nullptr) = 0;
///
/// Instantly destroys a fence that was previously created via .
///
- virtual void destroy_fence(fence handle) = 0;
+ virtual void destroy_fence(fence fence) = 0;
///
/// Gets the current value of the specified fence.
@@ -536,9 +588,43 @@ namespace reshade { namespace api
virtual bool signal(fence fence, uint64_t value) = 0;
///
- /// Gets information about the primary adapter associated with this logical render device.
+ /// Gets data for a of this device.
///
- virtual device_properties get_properties() const = 0;
+ /// Property to query.
+ /// Pointer to a variable that is set to the value of the property. The necessary data type is documented at the enumeration.
+ /// if the property exists and was retrieved, otherwise.
+ virtual bool get_property(device_properties property, void *data) const = 0;
+
+ ///
+ /// Gets the GPU address for a resource view.
+ ///
+ /// Resource view to query.
+ /// GPU address of the resource view, or zero in case of failure or when no fixed GPU address exists.
+ virtual uint64_t get_resource_view_gpu_address(resource_view view) const = 0;
+
+ ///
+ /// Gets the required acceleration structure size needed to build the specified data.
+ ///
+ ///
+ /// Type of the acceleration structure.
+ /// Acceleration structure build options.
+ /// Number of build inputs.
+ /// Pointer to the first element of an array of build inputs describing the geometry of the acceleration structure.
+ /// Pointer to a variable that is set to the required buffer size for the acceleration structure.
+ /// Pointer to a variable that is set to the required scratch buffer size for building the acceleration structure.
+ /// Pointer to a variable that is set to the required scratch buffer size for updating the acceleration structure.
+ virtual void get_acceleration_structure_size(acceleration_structure_type type, acceleration_structure_build_flags flags, uint32_t input_count, const acceleration_structure_build_input *inputs, uint64_t *out_size, uint64_t *out_build_scratch_size, uint64_t *out_update_scratch_size) const = 0;
+
+ ///
+ /// Gets the shader group handles for a ray tracing pipeline, to be put into a shader binding table.
+ ///
+ ///
+ /// Ray tracing pipeline to query.
+ /// Index of the first shader group in the array that was used to create the pipeline.
+ /// Number of shader groups to get handles for.
+ /// Pointer to the first element of an array (with elements of the size reported by ) that is filled with the handles.
+ /// if the shader group handles were successfully retrieved, otherwise.
+ virtual bool get_pipeline_shader_group_handles(pipeline pipeline, uint32_t first, uint32_t count, void *out_handles) = 0;
};
///
@@ -553,14 +639,17 @@ namespace reshade { namespace api
};
///
- /// The available indirect command types.
+ /// Type of an indirect draw/dispatch command.
///
+ ///
enum class indirect_command
{
unknown,
draw,
draw_indexed,
- dispatch
+ dispatch,
+ dispatch_mesh,
+ dispatch_rays
};
///
@@ -574,26 +663,27 @@ namespace reshade { namespace api
{
///
/// Adds a barrier for the specified to the command stream.
- /// When both and are a UAV barrier is added, otherwise a state transition is performed.
+ /// Multiple barriers are more efficiently issued using the overload that takes arrays.
+ /// When both and are , a UAV barrier is added, otherwise a state transition is performed.
///
/// Resource to transition.
/// Usage flags describing how the was used before this barrier.
/// Usage flags describing how the will be used after this barrier.
- inline void barrier(resource resource, resource_usage old_state, resource_usage new_state) { barrier(1, &resource, &old_state, &new_state); }
+ void barrier(resource resource, resource_usage old_state, resource_usage new_state) { barrier(1, &resource, &old_state, &new_state); }
///
/// Adds a barrier for the specified to the command stream.
///
/// Number of resources to transition.
- /// Pointer to an array of resources to transition.
- /// Pointer to an array of usage flags describing how the were used before this barrier.
- /// Pointer to an array of usage flags describing how the will be used after this barrier.
+ /// Pointer to the first element of an array of resources to transition.
+ /// Pointer to the first element of an array of usage flags describing how the were used before this barrier.
+ /// Pointer to the first element of an array of usage flags describing how the will be used after this barrier.
virtual void barrier(uint32_t count, const resource *resources, const resource_usage *old_states, const resource_usage *new_states) = 0;
///
/// Begins a render pass and binds render target and depth-stencil resource views.
///
/// Number of render target views to bind.
- /// Pointer to an array of render target descriptions.
+ /// Pointer to the first element of an array of render target descriptions.
/// Optional pointer to a depth-stencil description, or to bind none.
virtual void begin_render_pass(uint32_t count, const render_pass_render_target_desc *rts, const render_pass_depth_stencil_desc *ds = nullptr) = 0;
///
@@ -608,7 +698,7 @@ namespace reshade { namespace api
///
///
/// Number of render target views to bind.
- /// Pointer to an array of render target views to bind.
+ /// Pointer to the first element of an array of render target views to bind.
/// Depth-stencil view to bind, or zero to bind none.
virtual void bind_render_targets_and_depth_stencil(uint32_t count, const resource_view *rtvs, resource_view dsv = { 0 }) = 0;
@@ -624,14 +714,14 @@ namespace reshade { namespace api
///
/// Pipeline state to update.
/// Value to update the pipeline state to.
- inline void bind_pipeline_state(dynamic_state state, uint32_t value) { bind_pipeline_states(1, &state, &value); }
+ void bind_pipeline_state(dynamic_state state, uint32_t value) { bind_pipeline_states(1, &state, &value); }
///
/// Updates the specfified pipeline to the specified .
/// This is only valid for states that have been listed in the dynamic states provided at creation of the currently bound pipeline state object ().
///
/// Number of pipeline states to update.
- /// Pointer to an array of pipeline states to update.
- /// Pointer to an array of values to update the pipeline states to, with one for each state in .
+ /// Pointer to the first element of an array of pipeline states to update.
+ /// Pointer to the first element of an array of values to update the pipeline states to, with one for each state in .
virtual void bind_pipeline_states(uint32_t count, const dynamic_state *states, const uint32_t *values) = 0;
///
/// Binds an array of viewports to the rasterizer stage.
@@ -639,7 +729,7 @@ namespace reshade { namespace api
///
/// Index of the first viewport to bind. In D3D9, D3D10, D3D11 and D3D12 this has to be 0.
/// Number of viewports to bind.
- /// Pointer to an array of viewports.
+ /// Pointer to the first element of an array of viewports.
virtual void bind_viewports(uint32_t first, uint32_t count, const viewport *viewports) = 0;
///
/// Binds an array of scissor rectangles to the rasterizer stage.
@@ -647,7 +737,7 @@ namespace reshade { namespace api
///
/// Index of the first scissor rectangle to bind. In D3D9, D3D10, D3D11 and D3D12 this has to be 0.
/// Number of scissor rectangles to bind.
- /// Pointer to an array of scissor rectangles.
+ /// Pointer to the first element of an array of scissor rectangles.
virtual void bind_scissor_rects(uint32_t first, uint32_t count, const rect *rects) = 0;
///
@@ -660,7 +750,7 @@ namespace reshade { namespace api
/// Layout parameter index of the constant range in the pipeline (root parameter index in D3D12).
/// Start offset (in 32-bit values) to the first constant in the constant range to begin updating.
/// Number of 32-bit values to update.
- /// Pointer to an array of 32-bit values to set the constants to. These can be floating-point, integer or boolean depending on what the shader is expecting.
+ /// Pointer to the first element of an array of 32-bit values to set the constants to. These can be floating-point, integer or boolean depending on what the shader is expecting.
virtual void push_constants(shader_stage stages, pipeline_layout layout, uint32_t param, uint32_t first, uint32_t count, const void *values) = 0;
///
/// Directly binds a temporary descriptor table for the specfified shader pipeline stage and updates with an array of descriptors.
@@ -678,7 +768,7 @@ namespace reshade { namespace api
/// Pipeline layout that describes the descriptors.
/// Index of the pipeline parameter that describes the descriptor table (root parameter index in D3D12, descriptor set index in Vulkan).
/// Descriptor table to bind.
- inline void bind_descriptor_table(shader_stage stages, pipeline_layout layout, uint32_t param, descriptor_table table) { bind_descriptor_tables(stages, layout, param, 1, &table); }
+ void bind_descriptor_table(shader_stage stages, pipeline_layout layout, uint32_t param, descriptor_table table) { bind_descriptor_tables(stages, layout, param, 1, &table); }
///
/// Binds an array of descriptor tables.
///
@@ -686,7 +776,7 @@ namespace reshade { namespace api
/// Pipeline layout that describes the descriptors.
/// Index of the first pipeline parameter that describes the first descriptor table to bind (root parameter index in D3D12, descriptor set index in Vulkan).
/// Number of descriptor tables to bind.
- /// Pointer to an array of descriptor tables to bind.
+ /// Pointer to the first element of an array of descriptor tables to bind.
virtual void bind_descriptor_tables(shader_stage stages, pipeline_layout layout, uint32_t first, uint32_t count, const descriptor_table *tables) = 0;
///
@@ -703,15 +793,15 @@ namespace reshade { namespace api
/// Vertex buffer resource. This resources must have been created with the usage.
/// Offset (in bytes) from the start of the vertex buffer to the first vertex element to use.
/// Size (in bytes) of the vertex element that will be used from the vertex buffer (is added to an element offset to advance to the next).
- inline void bind_vertex_buffer(uint32_t index, resource buffer, uint64_t offset, uint32_t stride) { bind_vertex_buffers(index, 1, &buffer, &offset, &stride); }
+ void bind_vertex_buffer(uint32_t index, resource buffer, uint64_t offset, uint32_t stride) { bind_vertex_buffers(index, 1, &buffer, &offset, &stride); }
///
/// Binds an array of vertex buffers to the input-assembler stage.
///
/// First input slot for binding.
/// Number of vertex buffers to bind.
- /// Pointer to an array of vertex buffer resources. These resources must have been created with the usage.
- /// Pointer to an array of offset values, one for each buffer. Each offset is the number of bytes from the start of the vertex buffer to the first vertex element to use.
- /// Pointer to an array of stride values, one for each buffer. Each stride is the size (in bytes) of the vertex element that will be used from that vertex buffer (is added to an element offset to advance to the next).
+ /// Pointer to the first element of an array of vertex buffer resources. These resources must have been created with the usage.
+ /// Pointer to the first element of an array of offset values, one for each buffer. Each offset is the number of bytes from the start of the vertex buffer to the first vertex element to use.
+ /// Pointer to the first element of an array of stride values, one for each buffer. Each stride is the size (in bytes) of the vertex element that will be used from that vertex buffer (is added to an element offset to advance to the next).
virtual void bind_vertex_buffers(uint32_t first, uint32_t count, const resource *buffers, const uint64_t *offsets, const uint32_t *strides) = 0;
///
@@ -719,11 +809,11 @@ namespace reshade { namespace api
///
/// First stream-output slot for binding.
/// Number of stream-output targets to bind.
- /// Pointer to an array of buffer resources. These resources must have been created with the usage.
- /// Pointer to an array of offset values, one for each buffer. Each offset is the number of bytes from the start of the buffer to the first element to write to.
+ /// Pointer to the first element of an array of buffer resources. These resources must have been created with the usage.
+ /// Pointer to the first element of an array of offset values, one for each buffer. Each offset is the number of bytes from the start of the buffer to the first element to write to.
/// Optional pointer to an array of size values, one for each buffer. Can be or have elements set to UINT64_MAX to use the entire buffer.
- /// Pointer to an array of counter buffer resources. These resources must have been created with the usage.
- /// Pointer to an array of counter offset values, one for each counter buffer. Each offset is the number of bytes from the start of the counter buffer to the first element to write to.
+ /// Pointer to the first element of an array of counter buffer resources. These resources must have been created with the usage.
+ /// Pointer to the first element of an array of counter offset values, one for each counter buffer. Each offset is the number of bytes from the start of the counter buffer to the first element to write to.
virtual void bind_stream_output_buffers(uint32_t first, uint32_t count, const api::resource *buffers, const uint64_t *offsets, const uint64_t *max_sizes, const api::resource *counter_buffers, const uint64_t *counter_offsets) = 0;
///
@@ -866,7 +956,7 @@ namespace reshade { namespace api
/// Optional value to clear the depth buffer with.
/// Optional value to clear the stencil buffer with.
/// Number of rectangles to clear in the depth-stencil resource, or zero to clear the whole resource.
- /// Pointer to an array of rectangles.
+ /// Pointer to the first element of an array of rectangles.
virtual void clear_depth_stencil_view(resource_view dsv, const float *depth, const uint8_t *stencil, uint32_t rect_count = 0, const rect *rects = nullptr) = 0;
///
/// Clears the resource referenced by the render target view.
@@ -877,7 +967,7 @@ namespace reshade { namespace api
/// Resource view handle of the render target.
/// Value to clear the resource with.
/// Number of rectangles to clear in the render target resource, or zero to clear the whole resource.
- /// Pointer to an array of rectangles.
+ /// Pointer to the first element of an array of rectangles.
virtual void clear_render_target_view(resource_view rtv, const float color[4], uint32_t rect_count = 0, const rect *rects = nullptr) = 0;
///
/// Clears the resource referenced by the unordered access view.
@@ -888,7 +978,7 @@ namespace reshade { namespace api
/// Resource view handle of the unordered access view.
/// Value to clear the resource with.
/// Number of rectangles to clear in the unordered access resource, or zero to clear the whole resource.
- /// Pointer to an array of rectangles.
+ /// Pointer to the first element of an array of rectangles.
virtual void clear_unordered_access_view_uint(resource_view uav, const uint32_t values[4], uint32_t rect_count = 0, const rect *rects = nullptr) = 0;
///
/// Clears the resource referenced by the unordered access view.
@@ -899,7 +989,7 @@ namespace reshade { namespace api
/// Resource view handle of the unordered access view.
/// Value to clear the resource with.
/// Number of rectangles to clear in the unordered access resource, or zero to clear the whole resource.
- /// Pointer to an array of rectangles.
+ /// Pointer to the first element of an array of rectangles.
virtual void clear_unordered_access_view_float(resource_view uav, const float values[4], uint32_t rect_count = 0, const rect *rects = nullptr) = 0;
///
@@ -959,11 +1049,69 @@ namespace reshade { namespace api
/// Null-terminated string containing the label of the debug marker.
/// Optional RGBA color value associated with the debug marker.
virtual void insert_debug_marker(const char *label, const float color[4] = nullptr) = 0;
+
+ ///
+ /// Performs a mesh shader dispatch.
+ ///
+ ///
+ /// Number of thread groups dispatched in the x direction.
+ /// Number of thread groups dispatched in the y direction.
+ /// Number of thread groups dispatched in the z direction.
+ virtual void dispatch_mesh(uint32_t group_count_x, uint32_t group_count_y, uint32_t group_count_z) = 0;
+
+ ///
+ /// Performs a ray tracing dispatch.
+ ///
+ ///
+ /// The buffer resources have to be in the state.
+ ///
+ ///
+ /// Buffer resource containing the ray generation shader handle to use.
+ /// Buffer resource containing the miss shader handles to use.
+ /// Buffer resource containing the hit group handles to use.
+ /// Buffer resource containing the callable shader handles to use.
+ /// Width of the ray generation shader thread grid.
+ /// Height of the ray generation shader thread grid.
+ /// Depth of the ray generation shader thread grid.
+ virtual void dispatch_rays(resource raygen, uint64_t raygen_offset, uint64_t raygen_size, resource miss, uint64_t miss_offset, uint64_t miss_size, uint64_t miss_stride, resource hit_group, uint64_t hit_group_offset, uint64_t hit_group_size, uint64_t hit_group_stride, resource callable, uint64_t callable_offset, uint64_t callable_size, uint64_t callable_stride, uint32_t width, uint32_t height, uint32_t depth) = 0;
+
+ ///
+ /// Copies or transforms data from the acceleration structure to the ination acceleration structure.
+ ///
+ ///
+ /// The and ination acceleration structure resources have to be in the state.
+ ///
+ ///
+ /// Acceleration structure to copy from.
+ /// Acceleration structure to copy to.
+ /// Choose between copying or transforming the data in the acceleration structure.
+ virtual void copy_acceleration_structure(resource_view source, resource_view dest, acceleration_structure_copy_mode mode) = 0;
+
+ ///
+ /// Builds or updates an acceleration structure for ray tracing.
+ ///
+ ///
+ /// The build input vertex, index and instance buffers have to be in the state.
+ /// The resource has to be in the state.
+ /// The and ination acceleration structure resources have to be in the state.
+ ///
+ ///
+ /// Type of the acceleration structure to build.
+ /// Acceleration structure build options.
+ /// Number of build inputs.
+ /// Pointer to the first element of an array of build inputs describing the geometry of the acceleration structure to build.
+ /// Buffer resource to use as scratch space during building.
+ /// Offset (in bytes) into the buffer.
+ /// Acceleration structure to read data from when is , otherwise zero.
+ /// Acceleration structure to write data to.
+ /// Choose between building a new or updating an existing acceleration structure.
+ virtual void build_acceleration_structure(acceleration_structure_type type, acceleration_structure_build_flags flags, uint32_t input_count, const acceleration_structure_build_input *inputs, api::resource scratch, uint64_t scratch_offset, resource_view source, resource_view dest, acceleration_structure_build_mode mode) = 0;
};
///
- /// A list of flags that represent the available command queue types, as returned by .
+ /// Command queue type flags, which can be combined to describe the capabilities of a command queue.
///
+ ///
enum class command_queue_type
{
graphics = 0x1,
@@ -1039,6 +1187,7 @@ namespace reshade { namespace api
///
/// Queries the GPU timestamp frequency in ticks per second.
///
+ /// Timestamp frequency in number of ticks per second, or zero if GPU timestamps are not supported on this queue.
virtual uint64_t get_timestamp_frequency() const = 0;
};
@@ -1059,15 +1208,26 @@ namespace reshade { namespace api
///
/// Defines how the back buffers should be swapped when a present occurs.
- /// Depending on the render API this can be a 'D3DSWAPEFFECT', 'DXGI_SWAP_EFFECT', 'WGL_SWAP_METHOD_ARB' or 'VkPresentModeKHR' value.
+ /// Depending on the graphics API this can be a 'D3DSWAPEFFECT', 'DXGI_SWAP_EFFECT', 'WGL_SWAP_METHOD_ARB' or 'VkPresentModeKHR' value.
///
uint32_t present_mode = 0;
///
/// Swap chain creation flags.
- /// Depending on the render API this can be a 'D3DPRESENT', 'DXGI_PRESENT', 'PFD_*' or 'VkSwapchainCreateFlagsKHR' value.
+ /// Depending on the graphics API this can be a 'D3DPRESENT', 'DXGI_PRESENT', 'PFD_*' or 'VkSwapchainCreateFlagsKHR' value.
///
uint32_t present_flags = 0;
+
+ ///
+ /// Initial fullscreen state.
+ ///
+ bool fullscreen_state = false;
+
+ ///
+ /// Refresh rate of the display in fullscreen mode, in Hertz.
+ /// Set to zero to use the default.
+ ///
+ float fullscreen_refresh_rate = 0;
};
///
@@ -1095,7 +1255,7 @@ namespace reshade { namespace api
///
/// Gets the current back buffer resource.
///
- inline resource get_current_back_buffer() { return get_back_buffer(get_current_back_buffer_index()); }
+ resource get_current_back_buffer() { return get_back_buffer(get_current_back_buffer_index()); }
///
/// Gets the index of the back buffer resource that can currently be rendered into.
///
diff --git a/depends/include/ReShade/reshade_api_display.hpp b/depends/include/ReShade/reshade_api_display.hpp
new file mode 100644
index 000000000..934099d39
--- /dev/null
+++ b/depends/include/ReShade/reshade_api_display.hpp
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2024 Patrick Mours
+ * SPDX-License-Identifier: BSD-3-Clause OR MIT
+ */
+
+#pragma once
+
+#include "reshade_api_device.hpp"
+#include
+#include
+
+namespace reshade { namespace api
+{
+ ///
+ /// Describes quantities defined precisely as the ratio of two integers, such as refresh rates.
+ ///
+ struct rational
+ {
+ uint32_t numerator = 0;
+ uint32_t denomenator = 0;
+
+ constexpr float as_float() const { return denomenator != 0 ? static_cast (numerator)/static_cast(denomenator) : 0.0f; }
+ };
+
+ ///
+ /// Describes the colorimetry of a colorspace.
+ ///
+ struct colorimetry
+ {
+ float red [2] = { 0.0f, 0.0f };
+ float green [2] = { 0.0f, 0.0f };
+ float blue [2] = { 0.0f, 0.0f };
+ float white [2] = { 0.0f, 0.0f };
+ };
+
+ ///
+ /// Describes the dynamic range of a display or image.
+ ///
+ struct luminance_levels
+ {
+ float min_nits = 0.0f;
+ float max_nits = 0.0f;
+ float max_avg_nits = 0.0f;
+ };
+
+ ///
+ /// An output display.
+ /// Functionally equivalent to a 'IDXGIOutput'.
+ ///
+ struct __declspec(novtable) display : public api_object
+ {
+ ///
+ /// Indicates if cached properties are valid or potentially stale (i.e. refresh rate or resolution have changed).
+ ///
+ ///
+ /// If this returns false, wait one frame and call runtime::get_active_display() to get updated data.
+ ///
+ virtual bool is_current() const = 0;
+
+ using monitor = void*;
+
+ ///
+ /// Gets the handle of the monitor this display encapsulates.
+ ///
+ virtual monitor get_monitor() const = 0;
+
+ ///
+ /// Gets the (GDI) device name (i.e. \\DISPLAY1) of the the monitor; do not use this as a persistent display identifier!
+ ///
+ ///
+ /// This device name is not valid as a persistent display identifier for storage in configuration files, it may not refer to the same display device after a reboot.
+ ///
+ virtual const wchar_t* get_device_name() const = 0;
+
+ ///
+ /// Gets the device path (i.e. \\?\DISPLAY#DELA1E4#5&d93f871&0&UID33025#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}) of the the monitor.
+ ///
+ ///
+ /// The device path uniquely identifies a specific monitor (down to its serial number and the port it is attached to) and remains valid across system reboots.
+ /// This identifier is suitable for persistent user-defined display configuration, partial name matches can be used to identify instances of the same monitor when the port it attaches to is unimportant.
+ ///
+ virtual const wchar_t* get_device_path() const = 0;
+
+ ///
+ /// Gets the human readable name (i.e. Dell AW3423DW) of the the monitor.
+ ///
+ virtual const wchar_t* get_display_name() const = 0;
+
+ ///
+ /// Gets the size and location of the display on the desktop.
+ ///
+ virtual rect get_desktop_coords() const = 0;
+
+ ///
+ /// Gets the current color depth of the display.
+ ///
+ virtual uint32_t get_color_depth() const = 0;
+
+ ///
+ /// Gets the current refresh rate of the display.
+ ///
+ virtual rational get_refresh_rate() const = 0;
+
+ ///
+ /// Gets the current color space used for desktop composition.
+ ///
+ ///
+ /// This is independent from swap chain colorspace, it identifies a display as HDR capable even when not rendering in HDR.
+ ///
+ virtual color_space get_color_space() const = 0;
+
+ ///
+ /// Gets the display's reported native colorimetry (the data provided are often invalid or placeholders).
+ ///
+ ///
+ /// Users running Windows 11 or newer are encouraged to run "Windows HDR Calibration" to ensure the values reported to ReShade and games are accurate.
+ ///
+ virtual colorimetry get_colorimetry() const = 0;
+
+ ///
+ /// Gets the display's light output capabilities (the data provided are often invalid or placeholders).
+ ///
+ ///
+ /// Users running Windows 11 or newer are encouraged to run "Windows HDR Calibration" to ensure the values reported to ReShade and games are accurate.
+ ///
+ virtual luminance_levels get_luminance_caps() const = 0;
+
+ ///
+ /// Gets the desktop compositor's whitelevel for mapping SDR content to HDR.
+ ///
+ virtual float get_sdr_white_nits() const = 0;
+
+ ///
+ /// Checks if HDR is supported on the display, even if it is not currently enabled.
+ ///
+ virtual bool is_hdr_supported() const = 0;
+
+ ///
+ /// Checks if HDR is enabled on the display.
+ ///
+ virtual bool is_hdr_enabled() const = 0;
+
+ ///
+ /// Enables HDR on the display.
+ ///
+ ///
+ /// Be aware that this is a global display setting, and will not automatically revert to its original state when the application exits.
+ ///
+ virtual bool enable_hdr(bool enable) = 0;
+ };
+
+ using display_cache = std::unordered_map>;
+} }
\ No newline at end of file
diff --git a/depends/include/ReShade/reshade_api_format.hpp b/depends/include/ReShade/reshade_api_format.hpp
index 023b87e05..363e00076 100644
--- a/depends/include/ReShade/reshade_api_format.hpp
+++ b/depends/include/ReShade/reshade_api_format.hpp
@@ -11,7 +11,7 @@
namespace reshade { namespace api
{
///
- /// The available data and texture formats.
+ /// Available data and texture formats.
/// This is mostly compatible with 'DXGI_FORMAT'.
///
enum class format : uint32_t
@@ -336,6 +336,7 @@ namespace reshade { namespace api
case format::b10g10r10a2_typeless:
return format::b10g10r10a2_unorm;
case format::d16_unorm:
+ return format::r16_unorm;
case format::r16_typeless:
return format::r16_float;
case format::r16g16_typeless:
@@ -415,6 +416,50 @@ namespace reshade { namespace api
}
}
+ ///
+ /// Gets the average component bit depth of the specified format .
+ ///
+ inline const uint32_t format_bit_depth(format value)
+ {
+ switch (value)
+ {
+ case format::b5g6r5_unorm:
+ case format::b5g5r5a1_unorm:
+ case format::b5g5r5x1_unorm:
+ return 5;
+ case format::r8g8b8a8_typeless:
+ case format::r8g8b8a8_unorm:
+ case format::r8g8b8a8_unorm_srgb:
+ case format::r8g8b8x8_unorm:
+ case format::r8g8b8x8_unorm_srgb:
+ case format::b8g8r8a8_typeless:
+ case format::b8g8r8a8_unorm:
+ case format::b8g8r8a8_unorm_srgb:
+ case format::b8g8r8x8_typeless:
+ case format::b8g8r8x8_unorm:
+ case format::b8g8r8x8_unorm_srgb:
+ return 8;
+ case format::r10g10b10a2_typeless:
+ case format::r10g10b10a2_unorm:
+ case format::r10g10b10a2_xr_bias:
+ case format::b10g10r10a2_typeless:
+ case format::b10g10r10a2_unorm:
+ return 10;
+ case format::r11g11b10_float:
+ return 11;
+ case format::r16g16b16a16_typeless:
+ case format::r16g16b16a16_float:
+ return 16;
+ case format::r32g32b32_typeless:
+ case format::r32g32b32_float:
+ case format::r32g32b32a32_typeless:
+ case format::r32g32b32a32_float:
+ return 32;
+ default:
+ return 0;
+ }
+ }
+
///
/// Gets the number of bytes a texture row of the specified format occupies.
///
diff --git a/depends/include/ReShade/reshade_api_pipeline.hpp b/depends/include/ReShade/reshade_api_pipeline.hpp
index 71fc10e51..b9758a8f3 100644
--- a/depends/include/ReShade/reshade_api_pipeline.hpp
+++ b/depends/include/ReShade/reshade_api_pipeline.hpp
@@ -10,7 +10,7 @@
namespace reshade { namespace api
{
///
- /// A list of flags that represent the available shader stages in the render pipeline.
+ /// Flags that specify the shader stages in the render pipeline.
///
enum class shader_stage : uint32_t
{
@@ -21,14 +21,25 @@ namespace reshade { namespace api
pixel = 0x10,
compute = 0x20,
+ amplification = 0x40,
+ mesh = 0x80,
+
+ raygen = 0x0100,
+ any_hit = 0x0200,
+ closest_hit = 0x0400,
+ miss = 0x0800,
+ intersection = 0x1000,
+ callable = 0x2000,
+
all = 0x7FFFFFFF,
all_compute = compute,
- all_graphics = vertex | hull | domain | geometry | pixel
+ all_graphics = vertex | hull | domain | geometry | pixel | amplification | mesh,
+ all_ray_tracing = raygen | any_hit | closest_hit | miss | intersection | callable
};
RESHADE_DEFINE_ENUM_FLAG_OPERATORS(shader_stage);
///
- /// A list of flags that represent the available pipeline stages in the render pipeline.
+ /// Flags that specify the pipeline stages in the render pipeline.
///
enum class pipeline_stage : uint32_t
{
@@ -39,6 +50,11 @@ namespace reshade { namespace api
pixel_shader = 0x80,
compute_shader = 0x800,
+ amplification_shader = 0x80000,
+ mesh_shader = 0x100000,
+
+ ray_tracing_shader = 0x00200000,
+
input_assembler = 0x2,
stream_output = 0x4,
rasterizer = 0x100,
@@ -48,32 +64,67 @@ namespace reshade { namespace api
all = 0x7FFFFFFF,
all_compute = compute_shader,
all_graphics = vertex_shader | hull_shader | domain_shader | geometry_shader | pixel_shader | input_assembler | stream_output | rasterizer | depth_stencil | output_merger,
+ all_ray_tracing = ray_tracing_shader,
all_shader_stages = vertex_shader | hull_shader | domain_shader | geometry_shader | pixel_shader | compute_shader
};
RESHADE_DEFINE_ENUM_FLAG_OPERATORS(pipeline_stage);
///
- /// The available descriptor types.
+ /// Type of a descriptor.
///
enum class descriptor_type : uint32_t
{
+ ///
+ /// Descriptors are an array of .
+ ///
sampler = 0,
+ ///
+ /// Descriptors are an array of .
+ ///
sampler_with_resource_view = 1,
- shader_resource_view = 2,
- unordered_access_view = 3,
+ ///
+ /// Descriptors are an array of .
+ ///
+ buffer_shader_resource_view = 4,
+ ///
+ /// Descriptors are an array of .
+ ///
+ buffer_unordered_access_view = 5,
+ ///
+ /// Descriptors are an array of .
+ ///
+ texture_shader_resource_view = 2,
+ shader_resource_view = texture_shader_resource_view,
+ ///
+ /// Descriptors are an array of .
+ ///
+ texture_unordered_access_view = 3,
+ unordered_access_view = texture_unordered_access_view,
+ ///
+ /// Descriptors are an array of .
+ ///
constant_buffer = 6,
- shader_storage_buffer = 7
+ ///
+ /// Descriptors are an array of .
+ ///
+ shader_storage_buffer = 7,
+ ///
+ /// Descriptors are an array of .
+ ///
+ acceleration_structure = 8
};
///
- /// The available pipeline layout parameter types.
+ /// Type of a pipeline layout parameter.
///
enum class pipeline_layout_param_type : uint32_t
{
push_constants = 1,
descriptor_table = 0,
+ descriptor_table_with_static_samplers = 4,
push_descriptors = 2,
- push_descriptors_with_ranges = 3
+ push_descriptors_with_ranges = 3,
+ push_descriptors_with_static_samplers = 5
};
///
@@ -141,6 +192,13 @@ namespace reshade { namespace api
///
descriptor_type type = descriptor_type::sampler;
};
+ struct descriptor_range_with_static_samplers : public descriptor_range
+ {
+ ///
+ /// Optional array of sampler descriptions to statically embed into the descriptor table when the descriptor type is or .
+ ///
+ const sampler_desc *static_samplers = nullptr;
+ };
///
/// Describes a single parameter in a pipeline layout.
@@ -150,7 +208,9 @@ namespace reshade { namespace api
constexpr pipeline_layout_param() : push_descriptors() {}
constexpr pipeline_layout_param(const constant_range &push_constants) : type(pipeline_layout_param_type::push_constants), push_constants(push_constants) {}
constexpr pipeline_layout_param(const descriptor_range &push_descriptors) : type(pipeline_layout_param_type::push_descriptors), push_descriptors(push_descriptors) {}
+ constexpr pipeline_layout_param(const descriptor_range_with_static_samplers &push_descriptors) : type(pipeline_layout_param_type::push_descriptors_with_static_samplers), descriptor_table_with_static_samplers({ 1, &push_descriptors }) {}
constexpr pipeline_layout_param(uint32_t count, const descriptor_range *ranges) : type(pipeline_layout_param_type::descriptor_table), descriptor_table({ count, ranges }) {}
+ constexpr pipeline_layout_param(uint32_t count, const descriptor_range_with_static_samplers *ranges) : type(pipeline_layout_param_type::descriptor_table_with_static_samplers), descriptor_table_with_static_samplers({ count, ranges }) {}
///
/// Type of the parameter.
@@ -177,6 +237,15 @@ namespace reshade { namespace api
uint32_t count;
const descriptor_range *ranges;
} descriptor_table;
+
+ ///
+ /// Used when parameter type is or .
+ ///
+ struct
+ {
+ uint32_t count;
+ const descriptor_range_with_static_samplers *ranges;
+ } descriptor_table_with_static_samplers;
};
};
@@ -187,7 +256,7 @@ namespace reshade { namespace api
RESHADE_DEFINE_HANDLE(pipeline_layout);
///
- /// The fill mode to use when rendering triangles.
+ /// Fill mode to use when rendering triangles.
///
enum class fill_mode : uint32_t
{
@@ -209,7 +278,7 @@ namespace reshade { namespace api
RESHADE_DEFINE_ENUM_FLAG_OPERATORS(cull_mode);
///
- /// The available logic operations.
+ /// Logic operations.
///
enum class logic_op : uint32_t
{
@@ -232,7 +301,7 @@ namespace reshade { namespace api
};
///
- /// The available color or alpha blending operations.
+ /// Color or alpha blending operations.
///
enum class blend_op : uint32_t
{
@@ -244,7 +313,7 @@ namespace reshade { namespace api
};
///
- /// The available blend factors in color or alpha blending operations.
+ /// Blend factors in color or alpha blending operations, which modulate values between the pixel shader output and render target.
///
enum class blend_factor : uint32_t
{
@@ -270,7 +339,7 @@ namespace reshade { namespace api
};
///
- /// The available stencil operations that can be performed during depth-stencil testing.
+ /// Stencil operations that can be performed during depth-stencil testing.
///
enum class stencil_op : uint32_t
{
@@ -372,6 +441,96 @@ namespace reshade { namespace api
const uint32_t *spec_constant_values = nullptr;
};
+ ///
+ /// Type of a ray tracing shader group.
+ ///
+ enum class shader_group_type
+ {
+ raygen = 0,
+ miss = 3,
+ hit_group_triangles = 1,
+ hit_group_aabbs = 2,
+ callable = 4,
+ };
+
+ ///
+ /// Describes a ray tracing shader group.
+ ///
+ struct shader_group
+ {
+ shader_group() : hit_group() {}
+ shader_group(shader_group_type type, uint32_t closest_hit_shader_index, uint32_t any_hit_shader_index = UINT32_MAX, uint32_t intersection_shader_index = UINT32_MAX) : type(type), hit_group({ closest_hit_shader_index, any_hit_shader_index, intersection_shader_index }) {}
+
+ ///
+ /// Type of the shader group.
+ ///
+ shader_group_type type = shader_group_type::raygen;
+
+ union
+ {
+ ///
+ /// Used when type is .
+ ///
+ struct
+ {
+ ///
+ /// Index of the shader in the ray generation shader pipeline subobject.
+ ///
+ ///
+ uint32_t shader_index = UINT32_MAX;
+ } raygen;
+
+ ///
+ /// Used when type is .
+ ///
+ struct
+ {
+ ///
+ /// Index of the shader in the miss shader pipeline subobject.
+ ///
+ ///
+ uint32_t shader_index = UINT32_MAX;
+ } miss;
+
+ ///
+ /// Used when type is or .
+ ///
+ struct
+ {
+ ///
+ /// Index of the shader in the closest-hit shader pipeline subobject.
+ /// Set to -1 (UINT32_MAX) to indicate that this shader type is not used in the hit group.
+ ///
+ ///
+ uint32_t closest_hit_shader_index = UINT32_MAX;
+ ///
+ /// Index of the shader in the any-hit shader pipeline subobject.
+ /// Set to -1 (UINT32_MAX) to indicate that this shader type is not used in the hit group.
+ ///
+ ///
+ uint32_t any_hit_shader_index = UINT32_MAX;
+ ///
+ /// Index of the shader in the intersection shader pipeline subobject.
+ /// Set to -1 (UINT32_MAX) to indicate that this shader type is not used in the hit group.
+ ///
+ ///
+ uint32_t intersection_shader_index = UINT32_MAX;
+ } hit_group;
+
+ ///
+ /// Used when type is .
+ ///
+ struct
+ {
+ ///
+ /// Index of the shader in the callable shader pipeline subobject.
+ ///
+ ///
+ uint32_t shader_index = UINT32_MAX;
+ } callable;
+ };
+ };
+
///
/// Describes a single element in the vertex layout for the input-assembler stage.
///
@@ -622,7 +781,19 @@ namespace reshade { namespace api
};
///
- /// The available pipeline sub-object types.
+ /// Flags that specify additional parameters of a pipeline.
+ ///
+ enum class pipeline_flags : uint32_t
+ {
+ none = 0,
+ library = (1 << 0),
+ skip_triangles = (1 << 1),
+ skip_aabbs = (1 << 2),
+ };
+ RESHADE_DEFINE_ENUM_FLAG_OPERATORS(pipeline_flags);
+
+ ///
+ /// Type of a pipeline sub-object.
///
enum class pipeline_subobject_type : uint32_t
{
@@ -739,7 +910,93 @@ namespace reshade { namespace api
/// Maximum number of vertices a draw call with this pipeline will draw.
/// Sub-object data is a pointer to a 32-bit unsigned integer value.
///
- max_vertex_count
+ max_vertex_count,
+ ///
+ /// Amplification shader to use.
+ /// Sub-object data is a pointer to a .
+ ///
+ ///
+ ///
+ amplification_shader,
+ ///
+ /// Mesh shader to use.
+ /// Sub-object data is a pointer to a .
+ ///
+ ///
+ ///
+ mesh_shader,
+ ///
+ /// Ray generation shader(s) to use.
+ /// Sub-object data is a pointer to a .
+ ///
+ ///
+ ///
+ raygen_shader,
+ ///
+ /// Any-hit shader(s) to use.
+ /// Sub-object data is a pointer to a .
+ ///
+ ///
+ ///
+ any_hit_shader,
+ ///
+ /// Closest-hit shader(s) to use.
+ /// Sub-object data is a pointer to a .
+ ///
+ ///
+ ///
+ closest_hit_shader,
+ ///
+ /// Miss shader(s) to use.
+ /// Sub-object data is a pointer to a .
+ ///
+ ///
+ ///
+ miss_shader,
+ ///
+ /// Intersection shader(s) to use.
+ /// Sub-object data is a pointer to a .
+ ///
+ ///
+ ///
+ intersection_shader,
+ ///
+ /// Callable shader(s) to use.
+ /// Sub-object data is a pointer to a .
+ ///
+ ///
+ ///
+ callable_shader,
+ ///
+ /// Existing shader libraries added to this pipeline.
+ /// Sub-object data is a pointer to an array of handles.
+ ///
+ libraries,
+ ///
+ /// Ray tracing shader groups to use.
+ /// Sub-object data is a pointer to an array of values.
+ ///
+ shader_groups,
+ ///
+ /// Maximum payload size of shaders executed by this pipeline.
+ /// Sub-object data is a pointer to a 32-bit unsigned integer value.
+ ///
+ max_payload_size,
+ ///
+ /// Maximum hit attribute size of shaders executed by this pipeline.
+ /// Sub-object data is a pointer to a 32-bit unsigned integer value.
+ ///
+ max_attribute_size,
+ ///
+ /// Maximum recursion depth of shaders executed by this pipeline.
+ /// Sub-object data is a pointer to a 32-bit unsigned integer value.
+ ///
+ max_recursion_depth,
+ ///
+ /// Additional pipeline creation flags.
+ /// Sub-object data is a pointer to a value.
+ ///
+ flags
};
///
@@ -875,7 +1132,7 @@ namespace reshade { namespace api
descriptor_type type = descriptor_type::sampler;
///
/// Pointer to an array of descriptors to update in the descriptor table (which should be as large as the specified ).
- /// Depending on the descriptor this should be pointer to an array of , , or .
+ /// Depending on the descriptor this should be pointer to an array of , , , or .
///
const void *descriptors = nullptr;
};
@@ -887,14 +1144,34 @@ namespace reshade { namespace api
RESHADE_DEFINE_HANDLE(descriptor_heap);
///
- /// The available query types.
+ /// Type of a query.
///
enum class query_type
{
+ ///
+ /// Number of samples that passed the depth and stencil tests between beginning and end of the query.
+ /// Data is a 64-bit unsigned integer value.
+ ///
occlusion = 0,
+ ///
+ /// Zero if no samples passed, one if at least one sample passed the depth and stencil tests between beginning and end of the query.
+ /// Data is a 64-bit unsigned integer value.
+ ///
binary_occlusion = 1,
+ ///
+ /// GPU timestamp at the frequency returned by .
+ /// Data is a 64-bit unsigned integer value.
+ ///
timestamp = 2,
+ ///
+ /// Pipeline statistics (such as the number of shader invocations) between beginning and end of the query.
+ /// Data is a structure of type { uint64_t ia_vertices; uint64_t ia_primitives; uint64_t vs_invocations; uint64_t gs_invocations; uint64_t gs_primitives; uint64_t invocations; uint64_t primitives; uint64_t ps_invocations; uint64_t hs_invocations; uint64_t ds_invocations; uint64_t cs_invocations; }.
+ ///
pipeline_statistics = 3,
+ ///
+ /// Streaming output statistics for stream 0 between beginning and end of the query.
+ /// Data is a structure of type { uint64_t primitives_written; uint64_t primitives_storage_needed; }.
+ ///
stream_output_statistics_0 = 4,
stream_output_statistics_1,
stream_output_statistics_2,
@@ -909,7 +1186,7 @@ namespace reshade { namespace api
///
/// A list of all possible render pipeline states that can be set independent of pipeline state objects.
- /// Support for these varies between render APIs (e.g. modern APIs like D3D12 and Vulkan support much less dynamic states than D3D9).
+ /// Support for these varies between graphics APIs (e.g. modern APIs like D3D12 and Vulkan support much less dynamic states than D3D9).
///
enum class dynamic_state
{
@@ -970,6 +1247,10 @@ namespace reshade { namespace api
back_stencil_pass_op = 188,
back_stencil_fail_op = 186,
back_stencil_depth_fail_op = 187,
+
+ // Ray tracing state
+
+ ray_tracing_pipeline_stack_size = 2000
};
///
@@ -1000,7 +1281,7 @@ namespace reshade { namespace api
};
///
- /// A list of flags that describe fence creation options.
+ /// Flags that specify additional parameters of a fence.
///
enum class fence_flags : uint32_t
{
diff --git a/depends/include/ReShade/reshade_api_resource.hpp b/depends/include/ReShade/reshade_api_resource.hpp
index 9da2df04f..b70229be0 100644
--- a/depends/include/ReShade/reshade_api_resource.hpp
+++ b/depends/include/ReShade/reshade_api_resource.hpp
@@ -29,7 +29,7 @@
namespace reshade { namespace api
{
///
- /// The available comparison types.
+ /// Comparison operations.
///
enum class compare_op : uint32_t
{
@@ -44,7 +44,7 @@ namespace reshade { namespace api
};
///
- /// The available filtering modes used for texture sampling operations.
+ /// Texture filtering modes available for texture sampling operations.
///
enum class filter_mode : uint32_t
{
@@ -71,7 +71,7 @@ namespace reshade { namespace api
};
///
- /// Specifies behavior of sampling with texture coordinates outside a texture resource.
+ /// Sampling behavior at texture coordinates outside the bounds of a texture resource.
///
enum class texture_address_mode : uint32_t
{
@@ -131,12 +131,12 @@ namespace reshade { namespace api
///
/// An opaque handle to a sampler state object.
- /// Depending on the render API this can be a pointer to a 'ID3D10SamplerState', 'ID3D11SamplerState' or a 'D3D12_CPU_DESCRIPTOR_HANDLE' (to a sampler descriptor) or 'VkSampler' handle.
+ /// Depending on the graphics API this can be a pointer to a 'ID3D10SamplerState', 'ID3D11SamplerState' or a 'D3D12_CPU_DESCRIPTOR_HANDLE' (to a sampler descriptor) or 'VkSampler' handle.
///
RESHADE_DEFINE_HANDLE(sampler);
///
- /// The available memory mapping access types.
+ /// Memory mapping access types.
///
enum class map_access
{
@@ -147,7 +147,7 @@ namespace reshade { namespace api
};
///
- /// The available memory heap types, which give a hint as to where to place the memory allocation for a resource.
+ /// Memory heap types, which give a hint as to where to place the allocation for a resource.
///
enum class memory_heap : uint32_t
{
@@ -162,7 +162,7 @@ namespace reshade { namespace api
};
///
- /// The available resource types. The type of a resource is specified during creation and is immutable.
+ /// Type of a resource. This is specified during creation and is immutable.
/// Various operations may have special requirements on the type of resources they operate on (e.g. copies can only happen between resources of the same type, ...).
///
enum class resource_type : uint32_t
@@ -176,23 +176,39 @@ namespace reshade { namespace api
};
///
- /// A list of flags that describe additional parameters of a resource.
+ /// Flags that specify additional parameters of a resource.
///
enum class resource_flags : uint32_t
{
none = 0,
+ ///
+ /// Dynamic resources can be frequently updated during a frame, with previous contents automatically being shadowed so to no affect already executing operations on the GPU.
+ /// Required for . The flag is not supported in D3D12 or Vulkan.
+ ///
dynamic = (1 << 3),
+ ///
+ /// Required to create or views of the resource.
+ ///
cube_compatible = (1 << 2),
+ ///
+ /// Required to use the resource with .
+ ///
generate_mipmaps = (1 << 0),
+ ///
+ /// Shared resources can be imported/exported from/to different graphics APIs and/or processes.
+ /// Required to use the "shared_handle" parameter of .
+ ///
shared = (1 << 1),
shared_nt_handle = (1 << 11),
- structured = (1 << 6),
- sparse_binding = (1 << 18)
+ ///
+ /// Resource is backed using sparse memory binding.
+ ///
+ sparse_binding = (1 << 18),
};
RESHADE_DEFINE_ENUM_FLAG_OPERATORS(resource_flags);
///
- /// A list of flags that specify how a resource is to be used.
+ /// Flags that specify how a resource is used.
/// This needs to be specified during creation and is also used to transition between different resource states within a command list.
///
enum class resource_usage : uint32_t
@@ -219,6 +235,8 @@ namespace reshade { namespace api
resolve_dest = 0x1000,
resolve_source = 0x2000,
+ acceleration_structure = 0x400000,
+
// The following are special resource states and may only be used in barriers:
general = 0x80000000,
@@ -233,8 +251,8 @@ namespace reshade { namespace api
struct [[nodiscard]] resource_desc
{
constexpr resource_desc() : texture() {}
- constexpr resource_desc(uint64_t size, memory_heap heap, resource_usage usage) :
- type(resource_type::buffer), buffer({ size }), heap(heap), usage(usage) {}
+ constexpr resource_desc(uint64_t size, memory_heap heap, resource_usage usage, resource_flags flags = resource_flags::none) :
+ type(resource_type::buffer), buffer({ size }), heap(heap), usage(usage), flags(flags) {}
constexpr resource_desc(uint32_t width, uint32_t height, uint16_t layers, uint16_t levels, format format, uint16_t samples, memory_heap heap, resource_usage usage, resource_flags flags = resource_flags::none) :
type(resource_type::texture_2d), texture({ width, height, layers, levels, format, samples }), heap(heap), usage(usage), flags(flags) {}
constexpr resource_desc(resource_type type, uint32_t width, uint32_t height, uint16_t depth_or_layers, uint16_t levels, format format, uint16_t samples, memory_heap heap, resource_usage usage, resource_flags flags = resource_flags::none) :
@@ -300,24 +318,25 @@ namespace reshade { namespace api
///
memory_heap heap = memory_heap::unknown;
///
- /// Flags that specify how this resource may be used.
+ /// Flags that specify how this resource is used.
+ /// This should contain all resource states the resource will ever be transitioned to (including the initial state specified for resource creation).
///
resource_usage usage = resource_usage::undefined;
///
- /// Flags that describe additional parameters.
+ /// Flags that specify additional parameters.
///
resource_flags flags = resource_flags::none;
};
///
/// An opaque handle to a resource object (buffer, texture, ...).
- /// Resources created by the application are only guaranteed to be valid during event callbacks.
- /// Depending on the render API this can be a pointer to a 'IDirect3DResource9', 'ID3D10Resource', 'ID3D11Resource' or 'ID3D12Resource' object or a 'VkImage' handle.
+ /// Resources created by the application are only guaranteed to be valid during event callbacks.
+ /// Depending on the graphics API this can be a pointer to a 'IDirect3DResource9', 'ID3D10Resource', 'ID3D11Resource' or 'ID3D12Resource' object or a 'VkImage' handle.
///
RESHADE_DEFINE_HANDLE(resource);
///
- /// The available resource view types. These identify how a resource view interprets the data of its resource.
+ /// Type of a resource view. This identifies how a resource view interprets the data of its resource.
///
enum class resource_view_type : uint32_t
{
@@ -331,7 +350,8 @@ namespace reshade { namespace api
texture_2d_multisample_array,
texture_3d,
texture_cube,
- texture_cube_array
+ texture_cube_array,
+ acceleration_structure
};
///
@@ -344,6 +364,8 @@ namespace reshade { namespace api
type(resource_view_type::buffer), format(format), buffer({ offset, size }) {}
constexpr resource_view_desc(format format, uint32_t first_level, uint32_t levels, uint32_t first_layer, uint32_t layers) :
type(resource_view_type::texture_2d), format(format), texture({ first_level, levels, first_layer, layers }) {}
+ constexpr resource_view_desc(resource_view_type type, format format, uint64_t offset, uint64_t size) :
+ type(type), format(format), buffer({ offset, size }) {}
constexpr resource_view_desc(resource_view_type type, format format, uint32_t first_level, uint32_t levels, uint32_t first_layer, uint32_t layers) :
type(type), format(format), texture({ first_level, levels, first_layer, layers }) {}
constexpr explicit resource_view_desc(format format) : type(resource_view_type::texture_2d), format(format), texture({ 0, 1, 0, 1 }) {}
@@ -360,7 +382,7 @@ namespace reshade { namespace api
union
{
///
- /// Used when view type is a buffer.
+ /// Used when view type is a buffer or acceleration structure.
///
struct
{
@@ -404,8 +426,8 @@ namespace reshade { namespace api
///
/// An opaque handle to a resource view object (depth-stencil, render target, shader resource view, ...).
- /// Resource views created by the application are only guaranteed to be valid during event callbacks.
- /// Depending on the render API this can be a pointer to a 'IDirect3DResource9', 'ID3D10View' or 'ID3D11View' object, or a 'D3D12_CPU_DESCRIPTOR_HANDLE' (to a view descriptor) or 'VkImageView' handle.
+ /// Resource views created by the application are only guaranteed to be valid during event callbacks.
+ /// Depending on the graphics API this can be a pointer to a 'IDirect3DResource9', 'ID3D10View' or 'ID3D11View' object, or a 'D3D12_CPU_DESCRIPTOR_HANDLE' (to a view descriptor), 'D3D12_GPU_VIRTUAL_ADDRESS' (to an acceleration structrue), 'VkImageView' or 'VkAccelerationStructureKHR' handle.
///
RESHADE_DEFINE_HANDLE(resource_view);
@@ -525,4 +547,147 @@ namespace reshade { namespace api
///
float clear_color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
};
+
+ ///
+ /// Type of an acceleration structure.
+ ///
+ enum class acceleration_structure_type
+ {
+ top_level = 0,
+ bottom_level = 1,
+ generic = 2
+ };
+
+ ///
+ /// Type of an acceleration structure copy operation.
+ ///
+ enum class acceleration_structure_copy_mode
+ {
+ clone = 0,
+ compact = 1,
+ serialize = 2,
+ deserialize = 3
+ };
+
+ ///
+ /// Type of an acceleration structure build operation.
+ ///
+ enum class acceleration_structure_build_mode
+ {
+ build = 0,
+ update = 1
+ };
+
+ ///
+ /// Flags that specify additional parameters to an acceleration structure build operation.
+ ///
+ enum class acceleration_structure_build_flags : uint32_t
+ {
+ none = 0,
+ allow_update = (1 << 0),
+ allow_compaction = (1 << 1),
+ prefer_fast_trace = (1 << 2),
+ prefer_fast_build = (1 << 3),
+ minimize_memory_usage = (1 << 4)
+ };
+ RESHADE_DEFINE_ENUM_FLAG_OPERATORS(acceleration_structure_build_flags);
+
+ ///
+ /// Type of an acceleration structure structure build input.
+ ///
+ enum class acceleration_structure_build_input_type : uint32_t
+ {
+ triangles = 0,
+ aabbs = 1,
+ instances = 2
+ };
+
+ ///
+ /// Flags that specify additional parameters of an acceleration structure build input.
+ ///
+ enum class acceleration_structure_build_input_flags : uint32_t
+ {
+ none = 0,
+ opaque = (1 << 0),
+ no_duplicate_any_hit_invocation = (1 << 1)
+ };
+ RESHADE_DEFINE_ENUM_FLAG_OPERATORS(acceleration_structure_build_input_flags);
+
+ ///
+ /// Describes a single instance in a top-level acceleration structure.
+ /// The data in should be an array of this structure.
+ ///
+ struct acceleration_structure_instance
+ {
+ float transform[3][4];
+ uint32_t custom_index : 24;
+ uint32_t mask : 8;
+ uint32_t shader_binding_table_offset : 24;
+ uint32_t flags : 8;
+ uint64_t acceleration_structure_gpu_address;
+ };
+
+ ///
+ /// Describes a build input for an acceleration structure build operation.
+ ///
+ struct acceleration_structure_build_input
+ {
+ constexpr acceleration_structure_build_input() : triangles() {}
+ constexpr acceleration_structure_build_input(api::resource vertex_buffer, uint64_t vertex_offset, uint32_t vertex_count, uint64_t vertex_stride, api::format vertex_format, api::resource index_buffer, uint64_t index_offset, uint32_t index_count, api::format index_format, uint64_t transform_address = 0) : type(acceleration_structure_build_input_type::triangles), triangles({ vertex_buffer, vertex_offset, vertex_count, vertex_stride, vertex_format, index_buffer, index_offset, index_count, index_format, transform_address }) {}
+ constexpr acceleration_structure_build_input(api::resource aabb_buffer, uint64_t aabb_offset, uint32_t aabb_count, uint64_t aabb_stride) : type(acceleration_structure_build_input_type::aabbs), aabbs({ aabb_buffer, aabb_offset, aabb_count, aabb_stride }) {}
+ constexpr acceleration_structure_build_input(api::resource instance_buffer, uint64_t instance_offset, uint32_t instance_count, bool array_of_pointers = false) : type(acceleration_structure_build_input_type::instances), instances({ instance_buffer, instance_offset, instance_count, array_of_pointers }) {}
+
+ ///
+ /// Type of the acceleration structure build input.
+ ///
+ acceleration_structure_build_input_type type = acceleration_structure_build_input_type::triangles;
+
+ union
+ {
+ ///
+ /// Used when build input type is .
+ ///
+ struct
+ {
+ api::resource vertex_buffer = {};
+ uint64_t vertex_offset = 0;
+ uint32_t vertex_count = 0;
+ uint64_t vertex_stride = 0;
+ api::format vertex_format = api::format::unknown;
+ api::resource index_buffer = {};
+ uint64_t index_offset = 0;
+ uint32_t index_count = 0;
+ api::format index_format = api::format::unknown;
+ api::resource transform_buffer = {};
+ uint64_t transform_offset = 0;
+ } triangles;
+
+ ///
+ /// Used when build input type is .
+ ///
+ struct
+ {
+ api::resource buffer = {};
+ uint64_t offset = 0;
+ uint32_t count = 0;
+ uint64_t stride = 0;
+ } aabbs;
+
+ ///
+ /// Used when build input type is .
+ ///
+ struct
+ {
+ api::resource buffer = {};
+ uint64_t offset = 0;
+ uint32_t count = 0;
+ bool array_of_pointers = false;
+ } instances;
+ };
+
+ ///
+ /// Flags that specify additional parameters.
+ ///
+ acceleration_structure_build_input_flags flags = acceleration_structure_build_input_flags::none;
+ };
} }
diff --git a/depends/include/ReShade/reshade_events.hpp b/depends/include/ReShade/reshade_events.hpp
index 4b30a3a88..89ac91252 100644
--- a/depends/include/ReShade/reshade_events.hpp
+++ b/depends/include/ReShade/reshade_events.hpp
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (C) 2021 Patrick Mours
* SPDX-License-Identifier: BSD-3-Clause OR MIT
*/
@@ -106,15 +106,19 @@ namespace reshade
/// - IDirect3D9::CreateDevice (for the implicit swap chain)
/// - IDirect3D9Ex::CreateDeviceEx (for the implicit swap chain)
/// - IDirect3D9Device::CreateAdditionalSwapChain
- /// - IDirect3DDevice9::Reset (for the implicit swap chain)
- /// - IDirect3DDevice9Ex::ResetEx (for the implicit swap chain)
/// - IDXGIFactory::CreateSwapChain
/// - IDXGIFactory2::CreateSwapChain(...)
- /// - IDXGISwapChain::ResizeBuffers
- /// - IDXGISwapChain3::ResizeBuffers1
/// - wglMakeCurrent
/// - wglSwapBuffers (after window was resized)
/// - vkCreateSwapchainKHR
+ /// - xrCreateSession
+ ///
+ /// In addition, called when swap chain is resized, after:
+ ///
+ /// - IDirect3DDevice9::Reset (for the implicit swap chain)
+ /// - IDirect3DDevice9Ex::ResetEx (for the implicit swap chain)
+ /// - IDXGISwapChain::ResizeBuffers
+ /// - IDXGISwapChain3::ResizeBuffers1
///
/// Callback function signature: void (api::swapchain *swapchain)
///
@@ -151,8 +155,9 @@ namespace reshade
/// - wglDeleteContext
/// - wglSwapBuffers (after window was resized)
/// - vkDestroySwapchainKHR
+ /// - xrDestroySession
///
- /// In addition, called when swap chain is reset, before:
+ /// In addition, called when swap chain is resized, before:
///
/// - IDirect3DDevice9::Reset (for the implicit swap chain)
/// - IDirect3DDevice9Ex::ResetEx (for the implicit swap chain)
@@ -284,6 +289,9 @@ namespace reshade
///
/// Callback function signature: void (api::device *device, const api::resource_desc &desc, const api::subresource_data *initial_data, api::resource_usage initial_state, api::resource resource)
///
+ ///
+ /// May be called multiple times with the same resource handle (whenever the resource is updated or its reference count is incremented).
+ ///
init_resource,
///
@@ -394,9 +402,13 @@ namespace reshade
/// - glTextureView
/// - vkCreateBufferView
/// - vkCreateImageView
+ /// - vkCreateAccelerationStructureKHR
///
/// Callback function signature: void (api::device *device, api::resource resource, api::resource_usage usage_type, const api::resource_view_desc &desc, api::resource_view view)
///
+ ///
+ /// May be called multiple times with the same resource view handle (whenever the resource view is updated).
+ ///
init_resource_view,
///
@@ -422,6 +434,7 @@ namespace reshade
/// - glTextureView
/// - vkCreateBufferView
/// - vkCreateImageView
+ /// - vkCreateAccelerationStructureKHR
///
/// Callback function signature: bool (api::device *device, api::resource resource, api::resource_usage usage_type, api::resource_view_desc &desc)
///
@@ -440,6 +453,7 @@ namespace reshade
/// - glDeleteTextures
/// - vkDestroyBufferView
/// - vkDestroyImageView
+ /// - vkDestroyAccelerationStructureKHR
///
/// Callback function signature: void (api::device *device, api::resource_view view)
///
@@ -586,6 +600,8 @@ namespace reshade
/// - ID3D12Device::CreateComputePipelineState
/// - ID3D12Device::CreateGraphicsPipelineState
/// - ID3D12Device2::CreatePipelineState
+ /// - ID3D12Device5::CreateStateObject
+ /// - ID3D12Device7::AddToStateObject
/// - ID3D12PipelineLibrary::LoadComputePipeline
/// - ID3D12PipelineLibrary::LoadGraphicsPipeline
/// - ID3D12PipelineLibrary1::LoadPipeline
@@ -632,6 +648,7 @@ namespace reshade
/// - ID3D12Device::CreateComputePipelineState
/// - ID3D12Device::CreateGraphicsPipelineState
/// - ID3D12Device2::CreatePipelineState
+ /// - ID3D12Device5::CreateStateObject
/// - glShaderSource
/// - vkCreateComputePipelines
/// - vkCreateGraphicsPipelines
@@ -664,6 +681,7 @@ namespace reshade
/// - ID3D11DepthStencilState::Release
/// - ID3D11RasterizerState::Release
/// - ID3D12PipelineState::Release
+ /// - ID3D12StateObject::Release
/// - glDeleteProgram
/// - vkDestroyPipeline
///
@@ -682,12 +700,22 @@ namespace reshade
///
/// Callback function signature: void (api::device *device, uint32_t param_count, const api::pipeline_layout_param *params, api::pipeline_layout layout)
///
+ ///
+ /// In case of D3D9, D3D10, D3D11 and OpenGL this is called during device initialization as well and behaves as if an implicit global pipeline layout was created.
+ ///
init_pipeline_layout,
///
- /// Called on pipeline layout creation.
- /// Callback function signature: bool (api::device *device, uint32_t param_count, const api::pipeline_layout_param *params)
+ /// Called on pipeline layout creation, before:
+ ///
+ /// - ID3D12Device::CreateRootSignature
+ /// - vkCreatePipelineLayout
+ ///
+ /// Callback function signature: bool (api::device *device, uint32_t ¶m_count, api::pipeline_layout_param *¶ms)
///
+ ///
+ /// Is not called in D3D9, D3D10, D3D11 or OpenGL.
+ ///
create_pipeline_layout,
///
@@ -853,7 +881,9 @@ namespace reshade
/// - ID3D11DeviceContext::RSSetState
/// - ID3D12GraphicsCommandList::Reset
/// - ID3D12GraphicsCommandList::SetPipelineState
+ /// - ID3D12GraphicsCommandList4::SetPipelineState1
/// - glUseProgram
+ /// - glBindVertexArray
/// - vkCmdBindPipeline
///
/// Callback function signature: void (api::command_list *cmd_list, api::pipeline_stage stages, api::pipeline pipeline)
@@ -1120,7 +1150,34 @@ namespace reshade
///
/// To prevent this command from being executed, return , otherwise return .
///
- dispatch,
+ dispatch = 54,
+
+ ///
+ /// Called before:
+ ///
+ /// - ID3D12GraphicsCommandList::DispatchMesh
+ /// - vkCmdDrawMeshTasksEXT
+ ///
+ /// Callback function signature: bool (api::command_list *cmd_list, uint32_t group_count_x, uint32_t group_count_y, uint32_t group_count_z)
+ ///
+ ///
+ /// To prevent this command from being executed, return , otherwise return .
+ ///
+ dispatch_mesh = 89,
+
+ ///
+ /// Called before:
+ ///
+ /// - ID3D12GraphicsCommandList::DispatchRays
+ /// - vkCmdTraceRaysKHR
+ ///
+ /// Callback function signature: bool (api::command_list *cmd_list, api::resource raygen, uint64_t raygen_offset, uint64_t raygen_size, api::resource miss, uint64_t miss_offset, uint64_t miss_size, uint64_t miss_stride, api::resource hit_group, uint64_t hit_group_offset, uint64_t hit_group_size, uint64_t hit_group_stride, api::resource callable, uint64_t callable_offset, uint64_t callable_size, uint64_t callable_stride, uint32_t width, uint32_t height, uint32_t depth)
+ ///
+ ///
+ /// To prevent this command from being executed, return , otherwise return .
+ /// In case of D3D12 and Vulkan, the shader handle buffer handles may be zero with the buffers instead referred to via a device address passed in the related offset argument.
+ ///
+ dispatch_rays = 90,
///
/// Called before:
@@ -1137,13 +1194,16 @@ namespace reshade
/// - vkCmdDrawIndirect
/// - vkCmdDrawIndexedIndirect
/// - vkCmdDispatchIndirect
+ /// - vkCmdTraceRaysIndirect2KHR
+ /// - vkCmdDrawMeshTasksIndirectEXT
+ /// - vkCmdDrawMeshTasksIndirectCountEXT
///
/// Callback function signature: bool (api::command_list *cmd_list, api::indirect_command type, api::resource buffer, uint64_t offset, uint32_t draw_count, uint32_t stride)
///
///
/// To prevent this command from being executed, return , otherwise return .
///
- draw_or_dispatch_indirect,
+ draw_or_dispatch_indirect = 55,
///
/// Called before:
@@ -1403,7 +1463,35 @@ namespace reshade
///
/// To prevent this command from being executed, return , otherwise return .
///
- copy_query_heap_results,
+ copy_query_heap_results = 69,
+
+ ///
+ /// Called before:
+ ///
+ /// - ID3D12GraphicsCommandList4::CopyRaytracingAccelerationStructure
+ /// - vkCmdCopyAccelerationStructureKHR
+ ///
+ /// Callback function signature: bool (api::command_list *cmd_list, api::resource_view source, api::resource_view dest, api::acceleration_structure_copy_mode mode)
+ ///
+ ///
+ /// To prevent this command from being executed, return , otherwise return .
+ ///
+ copy_acceleration_structure = 91,
+
+ ///
+ /// Called before:
+ ///
+ /// - ID3D12GraphicsCommandList4::BuildRaytracingAccelerationStructure
+ /// - vkCmdBuildAccelerationStructuresKHR
+ ///
+ /// Callback function signature: bool (api::command_list *cmd_list, api::acceleration_structure_type type, api::acceleration_structure_build_flags flags, uint32_t input_count, const api::acceleration_structure_build_input *inputs, api::resource scratch, uint64_t scratch_offset, api::resource_view source, api::resource_view dest, api::acceleration_structure_build_mode mode)
+ ///
+ ///
+ /// To prevent this command from being executed, return , otherwise return .
+ /// In case of D3D12 and Vulkan, the scratch buffer handle may be zero with the buffer instead referred to via a device address passed in the related offset argument.
+ /// Scratch buffer will be in the resource state.
+ ///
+ build_acceleration_structure = 92,
///
/// Called before:
@@ -1416,7 +1504,7 @@ namespace reshade
///
/// Is not called for immediate command lists (since they cannot be reset).
///
- reset_command_list,
+ reset_command_list = 70,
///
/// Called before:
@@ -1474,6 +1562,7 @@ namespace reshade
/// - wglSwapBuffers
/// - vkQueuePresentKHR
/// - IVRCompositor::Submit
+ /// - xrEndFrame
///
/// Callback function signature: void (api::command_queue *queue, api::swapchain *swapchain, const api::rect *source_rect, const api::rect *dest_rect, uint32_t dirty_rect_count, const api::rect *dirty_rects)
///
@@ -1482,11 +1571,25 @@ namespace reshade
///
present,
+ ///
+ /// Called before:
+ ///
+ /// - IDXGISwapChain::SetFullscreenState
+ /// - vkAcquireFullScreenExclusiveModeEXT
+ /// - vkReleaseFullScreenExclusiveModeEXT
+ ///
+ /// Callback function signature: bool (api::swapchain *swapchain, bool fullscreen, void *hmonitor)
+ ///
+ ///
+ /// To prevent the fullscreen state from being changed, return , otherwise return .
+ ///
+ set_fullscreen_state = 93,
+
///
/// Called after ReShade has rendered its overlay.
/// Callback function signature: void (api::effect_runtime *runtime)
///
- reshade_present,
+ reshade_present = 75,
///
/// Called right before ReShade effects are rendered.
@@ -1514,7 +1617,7 @@ namespace reshade
///
///
/// To prevent the variable value from being changed, return , otherwise return .
- /// The new value has the data type reported by and the new value size is in bytes.
+ /// The new value has the data type reported by . The new value size is in bytes.
///
reshade_set_uniform_value,
///
@@ -1548,12 +1651,21 @@ namespace reshade
///
reshade_render_technique,
+ ///
+ /// Called when all effects are about to be enabled or disabled.
+ /// Callback function signature: bool (api::effect_runtime *runtime, bool enabled)
+ ///
+ ///
+ /// To prevent the effects state from being changed, return , otherwise return .
+ ///
+ reshade_set_effects_state = 94,
+
///
/// Called after a preset was loaded and applied.
/// This occurs after effect reloading or when the user chooses a new preset in the overlay.
/// Callback function signature: void (api::effect_runtime *runtime, const char *path)
///
- reshade_set_current_preset_path,
+ reshade_set_current_preset_path = 84,
///
/// Called when the rendering order of loaded techniques is changed, with a handle array specifying the new order.
@@ -1573,8 +1685,34 @@ namespace reshade
///
reshade_open_overlay,
+ ///
+ /// Called when a uniform variable widget is added to the variable list in the overlay.
+ /// Can be used to replace with custom one or add widgets for specific uniform variables.
+ /// Callback function signature: bool (api::effect_runtime *runtime, api::effect_uniform_variable variable)
+ ///
+ ///
+ /// To prevent the normal widget from being added to the overlay, return , otherwise return .
+ ///
+ reshade_overlay_uniform_variable,
+
+ ///
+ /// Called when a technique is added to the technique list in the overlay.
+ /// Can be used to replace with custom one or add widgets for specific techniques.
+ /// Callback function signature: bool (api::effect_runtime *runtime, api::effect_technique technique)
+ ///
+ ///
+ /// To prevent the normal widget from being added to the overlay, return , otherwise return .
+ ///
+ reshade_overlay_technique,
+
+ ///
+ /// Called when the active display changes for the current runtime.
+ /// Callback function signature: void (api::effect_runtime *runtime, api::display display)
+ ///
+ display_change = 95,
+
#if RESHADE_ADDON
- max // Last value used internally by ReShade to determine number of events in this enum
+ max = 96 // Last value used internally by ReShade to determine number of events in this enum
#endif
};
@@ -1629,7 +1767,7 @@ namespace reshade
RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::destroy_pipeline, void, api::device *device, api::pipeline pipeline);
RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::init_pipeline_layout, void, api::device *device, uint32_t param_count, const api::pipeline_layout_param *params, api::pipeline_layout layout);
- RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::create_pipeline_layout, bool, api::device *device, uint32_t param_count, const api::pipeline_layout_param *params);
+ RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::create_pipeline_layout, bool, api::device *device, uint32_t ¶m_count, api::pipeline_layout_param *¶ms);
RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::destroy_pipeline_layout, void, api::device *device, api::pipeline_layout layout);
RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::copy_descriptor_tables, bool, api::device *device, uint32_t count, const api::descriptor_table_copy *copies);
@@ -1661,6 +1799,8 @@ namespace reshade
RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::draw, bool, api::command_list *cmd_list, uint32_t vertex_count, uint32_t instance_count, uint32_t first_vertex, uint32_t first_instance);
RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::draw_indexed, bool, api::command_list *cmd_list, uint32_t index_count, uint32_t instance_count, uint32_t first_index, int32_t vertex_offset, uint32_t first_instance);
RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::dispatch, bool, api::command_list *cmd_list, uint32_t group_count_x, uint32_t group_count_y, uint32_t group_count_z);
+ RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::dispatch_mesh, bool, api::command_list *cmd_list, uint32_t group_count_x, uint32_t group_count_y, uint32_t group_count_z);
+ RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::dispatch_rays, bool, api::command_list *cmd_list, api::resource raygen, uint64_t raygen_offset, uint64_t raygen_size, api::resource miss, uint64_t miss_offset, uint64_t miss_size, uint64_t miss_stride, api::resource hit_group, uint64_t hit_group_offset, uint64_t hit_group_size, uint64_t hit_group_stride, api::resource callable, uint64_t callable_offset, uint64_t callable_size, uint64_t callable_stride, uint32_t width, uint32_t height, uint32_t depth);
RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::draw_or_dispatch_indirect, bool, api::command_list *cmd_list, api::indirect_command type, api::resource buffer, uint64_t offset, uint32_t draw_count, uint32_t stride);
RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::copy_resource, bool, api::command_list *cmd_list, api::resource source, api::resource dest);
@@ -1681,6 +1821,9 @@ namespace reshade
RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::end_query, bool, api::command_list *cmd_list, api::query_heap heap, api::query_type type, uint32_t index);
RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::copy_query_heap_results, bool, api::command_list *cmd_list, api::query_heap heap, api::query_type type, uint32_t first, uint32_t count, api::resource dest, uint64_t dest_offset, uint32_t stride);
+ RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::copy_acceleration_structure, bool, api::command_list *cmd_list, api::resource_view source, api::resource_view dest, api::acceleration_structure_copy_mode mode);
+ RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::build_acceleration_structure, bool, api::command_list *cmd_list, api::acceleration_structure_type type, api::acceleration_structure_build_flags flags, uint32_t input_count, const api::acceleration_structure_build_input *inputs, api::resource scratch, uint64_t scratch_offset, api::resource_view source, api::resource_view dest, api::acceleration_structure_build_mode mode);
+
RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::reset_command_list, void, api::command_list *cmd_list);
RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::close_command_list, void, api::command_list *cmd_list);
@@ -1688,6 +1831,7 @@ namespace reshade
RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::execute_secondary_command_list, void, api::command_list *cmd_list, api::command_list *secondary_cmd_list);
RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::present, void, api::command_queue *queue, api::swapchain *swapchain, const api::rect *source_rect, const api::rect *dest_rect, uint32_t dirty_rect_count, const api::rect *dirty_rects);
+ RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::set_fullscreen_state, bool, api::swapchain *swapchain, bool fullscreen, void *hmonitor);
RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::reshade_present, void, api::effect_runtime *runtime);
RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::reshade_begin_effects, void, api::effect_runtime *runtime, api::command_list *cmd_list, api::resource_view rtv, api::resource_view rtv_srgb);
@@ -1702,8 +1846,14 @@ namespace reshade
RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::reshade_render_technique, void, api::effect_runtime *runtime, api::effect_technique technique, api::command_list *cmd_list, api::resource_view rtv, api::resource_view rtv_srgb);
+ RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::reshade_set_effects_state, bool, api::effect_runtime *runtime, bool enabled);
RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::reshade_set_current_preset_path, void, api::effect_runtime *runtime, const char *path);
RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::reshade_reorder_techniques, bool, api::effect_runtime *runtime, size_t count, api::effect_technique *techniques);
RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::reshade_open_overlay, bool, api::effect_runtime *runtime, bool open, api::input_source source);
+
+ RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::reshade_overlay_uniform_variable, bool, api::effect_runtime *runtime, api::effect_uniform_variable variable);
+ RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::reshade_overlay_technique, bool, api::effect_runtime *runtime, api::effect_technique technique);
+
+ RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::display_change, void, api::effect_runtime *runtime, api::display* display);
}
diff --git a/depends/include/ReShade/reshade_overlay.hpp b/depends/include/ReShade/reshade_overlay.hpp
index ce34ec7a7..23bbe37c1 100644
--- a/depends/include/ReShade/reshade_overlay.hpp
+++ b/depends/include/ReShade/reshade_overlay.hpp
@@ -1,28 +1,27 @@
/*
* Copyright (C) 2021 Patrick Mours
- * Copyright (C) 2014-2023 Omar Cornut
+ * Copyright (C) 2014-2024 Omar Cornut
* SPDX-License-Identifier: BSD-3-Clause OR MIT
*/
-#if 0
-#if defined(IMGUI_VERSION_NUM)
+#if defined(IMGUI_VERSION_NUM) && !defined(RESHADE_NO_IMGUI)
-#if IMGUI_VERSION_NUM != 18971
-#error Unexpected ImGui version, please update the "imgui.h" header to version 18971!
+#if IMGUI_VERSION_NUM != 19040
+#error Unexpected ImGui version, please update the "imgui.h" header to version 19040!
#endif
// Check that the 'ImTextureID' type has the same size as 'reshade::api::resource_view'
static_assert(sizeof(ImTextureID) == 8, "missing \"#define ImTextureID ImU64\" before \"#include \"");
-struct imgui_function_table_18971
+struct imgui_function_table_19040
{
ImGuiIO&(*GetIO)();
ImGuiStyle&(*GetStyle)();
const char*(*GetVersion)();
bool(*Begin)(const char* name, bool* p_open, ImGuiWindowFlags flags);
void(*End)();
- bool(*BeginChild)(const char* str_id, const ImVec2& size, bool border, ImGuiWindowFlags flags);
- bool(*BeginChild2)(ImGuiID id, const ImVec2& size, bool border, ImGuiWindowFlags flags);
+ bool(*BeginChild)(const char* str_id, const ImVec2& size, ImGuiChildFlags child_flags, ImGuiWindowFlags window_flags);
+ bool(*BeginChild2)(ImGuiID id, const ImVec2& size, ImGuiChildFlags child_flags, ImGuiWindowFlags window_flags);
void(*EndChild)();
bool(*IsWindowAppearing)();
bool(*IsWindowCollapsed)();
@@ -88,8 +87,17 @@ struct imgui_function_table_18971
ImVec2(*GetFontTexUvWhitePixel)();
ImU32(*GetColorU32)(ImGuiCol idx, float alpha_mul);
ImU32(*GetColorU322)(const ImVec4& col);
- ImU32(*GetColorU323)(ImU32 col);
+ ImU32(*GetColorU323)(ImU32 col, float alpha_mul);
const ImVec4&(*GetStyleColorVec4)(ImGuiCol idx);
+ ImVec2(*GetCursorScreenPos)();
+ void(*SetCursorScreenPos)(const ImVec2& pos);
+ ImVec2(*GetCursorPos)();
+ float(*GetCursorPosX)();
+ float(*GetCursorPosY)();
+ void(*SetCursorPos)(const ImVec2& local_pos);
+ void(*SetCursorPosX)(float local_x);
+ void(*SetCursorPosY)(float local_y);
+ ImVec2(*GetCursorStartPos)();
void(*Separator)();
void(*SameLine)(float offset_from_start_x, float spacing);
void(*NewLine)();
@@ -99,15 +107,6 @@ struct imgui_function_table_18971
void(*Unindent)(float indent_w);
void(*BeginGroup)();
void(*EndGroup)();
- ImVec2(*GetCursorPos)();
- float(*GetCursorPosX)();
- float(*GetCursorPosY)();
- void(*SetCursorPos)(const ImVec2& local_pos);
- void(*SetCursorPosX)(float local_x);
- void(*SetCursorPosY)(float local_y);
- ImVec2(*GetCursorStartPos)();
- ImVec2(*GetCursorScreenPos)();
- void(*SetCursorScreenPos)(const ImVec2& pos);
void(*AlignTextToFramePadding)();
float(*GetTextLineHeight)();
float(*GetTextLineHeightWithSpacing)();
@@ -140,13 +139,13 @@ struct imgui_function_table_18971
bool(*RadioButton2)(const char* label, int* v, int v_button);
void(*ProgressBar)(float fraction, const ImVec2& size_arg, const char* overlay);
void(*Bullet)();
- void(*Image)(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col);
- bool(*ImageButton)(const char* str_id, ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col);
+ void(*Image)(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col);
+ bool(*ImageButton)(const char* str_id, ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col);
bool(*BeginCombo)(const char* label, const char* preview_value, ImGuiComboFlags flags);
void(*EndCombo)();
bool(*Combo)(const char* label, int* current_item, const char* const items[], int items_count, int popup_max_height_in_items);
bool(*Combo2)(const char* label, int* current_item, const char* items_separated_by_zeros, int popup_max_height_in_items);
- bool(*Combo3)(const char* label, int* current_item, bool(*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int popup_max_height_in_items);
+ bool(*Combo3)(const char* label, int* current_item, const char*(*getter)(void* user_data, int idx), void* user_data, int items_count, int popup_max_height_in_items);
bool(*DragFloat)(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, ImGuiSliderFlags flags);
bool(*DragFloat2)(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* format, ImGuiSliderFlags flags);
bool(*DragFloat3)(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* format, ImGuiSliderFlags flags);
@@ -211,7 +210,7 @@ struct imgui_function_table_18971
bool(*BeginListBox)(const char* label, const ImVec2& size);
void(*EndListBox)();
bool(*ListBox)(const char* label, int* current_item, const char* const items[], int items_count, int height_in_items);
- bool(*ListBox2)(const char* label, int* current_item, bool(*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int height_in_items);
+ bool(*ListBox2)(const char* label, int* current_item, const char*(*getter)(void* user_data, int idx), void* user_data, int items_count, int height_in_items);
void(*PlotLines)(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride);
void(*PlotLines2)(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size);
void(*PlotHistogram)(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride);
@@ -251,8 +250,9 @@ struct imgui_function_table_18971
bool(*TableSetColumnIndex)(int column_n);
void(*TableSetupColumn)(const char* label, ImGuiTableColumnFlags flags, float init_width_or_weight, ImGuiID user_id);
void(*TableSetupScrollFreeze)(int cols, int rows);
- void(*TableHeadersRow)();
void(*TableHeader)(const char* label);
+ void(*TableHeadersRow)();
+ void(*TableAngledHeadersRow)();
ImGuiTableSortSpecs*(*TableGetSortSpecs)();
int(*TableGetColumnCount)();
int(*TableGetColumnIndex)();
@@ -323,8 +323,6 @@ struct imgui_function_table_18971
const char*(*GetStyleColorName)(ImGuiCol idx);
void(*SetStateStorage)(ImGuiStorage* storage);
ImGuiStorage*(*GetStateStorage)();
- bool(*BeginChildFrame)(ImGuiID id, const ImVec2& size, ImGuiWindowFlags flags);
- void(*EndChildFrame)();
ImVec2(*CalcTextSize)(const char* text, const char* text_end, bool hide_text_after_double_hash, float wrap_width);
ImVec4(*ColorConvertU32ToFloat4)(ImU32 in);
ImU32(*ColorConvertFloat4ToU32)(const ImVec4& in);
@@ -333,6 +331,7 @@ struct imgui_function_table_18971
bool(*IsKeyDown)(ImGuiKey key);
bool(*IsKeyPressed)(ImGuiKey key, bool repeat);
bool(*IsKeyReleased)(ImGuiKey key);
+ bool(*IsKeyChordPressed)(ImGuiKeyChord key_chord);
int(*GetKeyPressedAmount)(ImGuiKey key, float repeat_delay, float rate);
const char*(*GetKeyName)(ImGuiKey key);
void(*SetNextFrameWantCaptureKeyboard)(bool want_capture_keyboard);
@@ -370,14 +369,14 @@ struct imgui_function_table_18971
bool*(*ImGuiStorage_GetBoolRef)(ImGuiStorage *_this, ImGuiID key, bool default_val);
float*(*ImGuiStorage_GetFloatRef)(ImGuiStorage *_this, ImGuiID key, float default_val);
void**(*ImGuiStorage_GetVoidPtrRef)(ImGuiStorage *_this, ImGuiID key, void* default_val);
- void(*ImGuiStorage_SetAllInt)(ImGuiStorage *_this, int val);
void(*ImGuiStorage_BuildSortByKey)(ImGuiStorage *_this);
+ void(*ImGuiStorage_SetAllInt)(ImGuiStorage *_this, int val);
void(*ConstructImGuiListClipper)(ImGuiListClipper *_this);
void(*DestructImGuiListClipper)(ImGuiListClipper *_this);
void(*ImGuiListClipper_Begin)(ImGuiListClipper *_this, int items_count, float items_height);
void(*ImGuiListClipper_End)(ImGuiListClipper *_this);
bool(*ImGuiListClipper_Step)(ImGuiListClipper *_this);
- void(*ImGuiListClipper_IncludeRangeByIndices)(ImGuiListClipper *_this, int item_begin, int item_end);
+ void(*ImGuiListClipper_IncludeItemsByIndex)(ImGuiListClipper *_this, int item_begin, int item_end);
void(*ImDrawList_PushClipRect)(ImDrawList *_this, const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect);
void(*ImDrawList_PushClipRectFullScreen)(ImDrawList *_this);
void(*ImDrawList_PopClipRect)(ImDrawList *_this);
@@ -395,6 +394,8 @@ struct imgui_function_table_18971
void(*ImDrawList_AddCircleFilled)(ImDrawList *_this, const ImVec2& center, float radius, ImU32 col, int num_segments);
void(*ImDrawList_AddNgon)(ImDrawList *_this, const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness);
void(*ImDrawList_AddNgonFilled)(ImDrawList *_this, const ImVec2& center, float radius, ImU32 col, int num_segments);
+ void(*ImDrawList_AddEllipse)(ImDrawList *_this, const ImVec2& center, float radius_x, float radius_y, ImU32 col, float rot, int num_segments, float thickness);
+ void(*ImDrawList_AddEllipseFilled)(ImDrawList *_this, const ImVec2& center, float radius_x, float radius_y, ImU32 col, float rot, int num_segments);
void(*ImDrawList_AddText)(ImDrawList *_this, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end);
void(*ImDrawList_AddText2)(ImDrawList *_this, const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end, float wrap_width, const ImVec4* cpu_fine_clip_rect);
void(*ImDrawList_AddPolyline)(ImDrawList *_this, const ImVec2* points, int num_points, ImU32 col, ImDrawFlags flags, float thickness);
@@ -406,6 +407,7 @@ struct imgui_function_table_18971
void(*ImDrawList_AddImageRounded)(ImDrawList *_this, ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawFlags flags);
void(*ImDrawList_PathArcTo)(ImDrawList *_this, const ImVec2& center, float radius, float a_min, float a_max, int num_segments);
void(*ImDrawList_PathArcToFast)(ImDrawList *_this, const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12);
+ void(*ImDrawList_PathEllipticalArcTo)(ImDrawList *_this, const ImVec2& center, float radius_x, float radius_y, float rot, float a_min, float a_max, int num_segments);
void(*ImDrawList_PathBezierCubicCurveTo)(ImDrawList *_this, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments);
void(*ImDrawList_PathBezierQuadraticCurveTo)(ImDrawList *_this, const ImVec2& p2, const ImVec2& p3, int num_segments);
void(*ImDrawList_PathRect)(ImDrawList *_this, const ImVec2& rect_min, const ImVec2& rect_max, float rounding, ImDrawFlags flags);
@@ -428,7 +430,7 @@ struct imgui_function_table_18971
};
-using imgui_function_table = imgui_function_table_18971;
+using imgui_function_table = imgui_function_table_19040;
inline const imgui_function_table *&imgui_function_table_instance()
{
@@ -445,8 +447,8 @@ namespace ImGui
inline const char* GetVersion() { return imgui_function_table_instance()->GetVersion(); }
inline bool Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) { return imgui_function_table_instance()->Begin(name, p_open, flags); }
inline void End() { imgui_function_table_instance()->End(); }
- inline bool BeginChild(const char* str_id, const ImVec2& size, bool border, ImGuiWindowFlags flags) { return imgui_function_table_instance()->BeginChild(str_id, size, border, flags); }
- inline bool BeginChild(ImGuiID id, const ImVec2& size, bool border, ImGuiWindowFlags flags) { return imgui_function_table_instance()->BeginChild2(id, size, border, flags); }
+ inline bool BeginChild(const char* str_id, const ImVec2& size, ImGuiChildFlags child_flags, ImGuiWindowFlags window_flags) { return imgui_function_table_instance()->BeginChild(str_id, size, child_flags, window_flags); }
+ inline bool BeginChild(ImGuiID id, const ImVec2& size, ImGuiChildFlags child_flags, ImGuiWindowFlags window_flags) { return imgui_function_table_instance()->BeginChild2(id, size, child_flags, window_flags); }
inline void EndChild() { imgui_function_table_instance()->EndChild(); }
inline bool IsWindowAppearing() { return imgui_function_table_instance()->IsWindowAppearing(); }
inline bool IsWindowCollapsed() { return imgui_function_table_instance()->IsWindowCollapsed(); }
@@ -512,8 +514,17 @@ namespace ImGui
inline ImVec2 GetFontTexUvWhitePixel() { return imgui_function_table_instance()->GetFontTexUvWhitePixel(); }
inline ImU32 GetColorU32(ImGuiCol idx, float alpha_mul) { return imgui_function_table_instance()->GetColorU32(idx, alpha_mul); }
inline ImU32 GetColorU32(const ImVec4& col) { return imgui_function_table_instance()->GetColorU322(col); }
- inline ImU32 GetColorU32(ImU32 col) { return imgui_function_table_instance()->GetColorU323(col); }
+ inline ImU32 GetColorU32(ImU32 col, float alpha_mul) { return imgui_function_table_instance()->GetColorU323(col, alpha_mul); }
inline const ImVec4& GetStyleColorVec4(ImGuiCol idx) { return imgui_function_table_instance()->GetStyleColorVec4(idx); }
+ inline ImVec2 GetCursorScreenPos() { return imgui_function_table_instance()->GetCursorScreenPos(); }
+ inline void SetCursorScreenPos(const ImVec2& pos) { imgui_function_table_instance()->SetCursorScreenPos(pos); }
+ inline ImVec2 GetCursorPos() { return imgui_function_table_instance()->GetCursorPos(); }
+ inline float GetCursorPosX() { return imgui_function_table_instance()->GetCursorPosX(); }
+ inline float GetCursorPosY() { return imgui_function_table_instance()->GetCursorPosY(); }
+ inline void SetCursorPos(const ImVec2& local_pos) { imgui_function_table_instance()->SetCursorPos(local_pos); }
+ inline void SetCursorPosX(float local_x) { imgui_function_table_instance()->SetCursorPosX(local_x); }
+ inline void SetCursorPosY(float local_y) { imgui_function_table_instance()->SetCursorPosY(local_y); }
+ inline ImVec2 GetCursorStartPos() { return imgui_function_table_instance()->GetCursorStartPos(); }
inline void Separator() { imgui_function_table_instance()->Separator(); }
inline void SameLine(float offset_from_start_x, float spacing) { imgui_function_table_instance()->SameLine(offset_from_start_x, spacing); }
inline void NewLine() { imgui_function_table_instance()->NewLine(); }
@@ -523,15 +534,6 @@ namespace ImGui
inline void Unindent(float indent_w) { imgui_function_table_instance()->Unindent(indent_w); }
inline void BeginGroup() { imgui_function_table_instance()->BeginGroup(); }
inline void EndGroup() { imgui_function_table_instance()->EndGroup(); }
- inline ImVec2 GetCursorPos() { return imgui_function_table_instance()->GetCursorPos(); }
- inline float GetCursorPosX() { return imgui_function_table_instance()->GetCursorPosX(); }
- inline float GetCursorPosY() { return imgui_function_table_instance()->GetCursorPosY(); }
- inline void SetCursorPos(const ImVec2& local_pos) { imgui_function_table_instance()->SetCursorPos(local_pos); }
- inline void SetCursorPosX(float local_x) { imgui_function_table_instance()->SetCursorPosX(local_x); }
- inline void SetCursorPosY(float local_y) { imgui_function_table_instance()->SetCursorPosY(local_y); }
- inline ImVec2 GetCursorStartPos() { return imgui_function_table_instance()->GetCursorStartPos(); }
- inline ImVec2 GetCursorScreenPos() { return imgui_function_table_instance()->GetCursorScreenPos(); }
- inline void SetCursorScreenPos(const ImVec2& pos) { imgui_function_table_instance()->SetCursorScreenPos(pos); }
inline void AlignTextToFramePadding() { imgui_function_table_instance()->AlignTextToFramePadding(); }
inline float GetTextLineHeight() { return imgui_function_table_instance()->GetTextLineHeight(); }
inline float GetTextLineHeightWithSpacing() { return imgui_function_table_instance()->GetTextLineHeightWithSpacing(); }
@@ -570,13 +572,13 @@ namespace ImGui
inline bool RadioButton(const char* label, int* v, int v_button) { return imgui_function_table_instance()->RadioButton2(label, v, v_button); }
inline void ProgressBar(float fraction, const ImVec2& size_arg, const char* overlay) { imgui_function_table_instance()->ProgressBar(fraction, size_arg, overlay); }
inline void Bullet() { imgui_function_table_instance()->Bullet(); }
- inline void Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col) { imgui_function_table_instance()->Image(user_texture_id, size, uv0, uv1, tint_col, border_col); }
- inline bool ImageButton(const char* str_id, ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col) { return imgui_function_table_instance()->ImageButton(str_id, user_texture_id, size, uv0, uv1, bg_col, tint_col); }
+ inline void Image(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col) { imgui_function_table_instance()->Image(user_texture_id, image_size, uv0, uv1, tint_col, border_col); }
+ inline bool ImageButton(const char* str_id, ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col) { return imgui_function_table_instance()->ImageButton(str_id, user_texture_id, image_size, uv0, uv1, bg_col, tint_col); }
inline bool BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags) { return imgui_function_table_instance()->BeginCombo(label, preview_value, flags); }
inline void EndCombo() { imgui_function_table_instance()->EndCombo(); }
inline bool Combo(const char* label, int* current_item, const char* const items[], int items_count, int popup_max_height_in_items) { return imgui_function_table_instance()->Combo(label, current_item, items, items_count, popup_max_height_in_items); }
inline bool Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int popup_max_height_in_items) { return imgui_function_table_instance()->Combo2(label, current_item, items_separated_by_zeros, popup_max_height_in_items); }
- inline bool Combo(const char* label, int* current_item, bool(*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int popup_max_height_in_items) { return imgui_function_table_instance()->Combo3(label, current_item, items_getter, data, items_count, popup_max_height_in_items); }
+ inline bool Combo(const char* label, int* current_item, const char*(*getter)(void* user_data, int idx), void* user_data, int items_count, int popup_max_height_in_items) { return imgui_function_table_instance()->Combo3(label, current_item, getter, user_data, items_count, popup_max_height_in_items); }
inline bool DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, ImGuiSliderFlags flags) { return imgui_function_table_instance()->DragFloat(label, v, v_speed, v_min, v_max, format, flags); }
inline bool DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* format, ImGuiSliderFlags flags) { return imgui_function_table_instance()->DragFloat2(label, v, v_speed, v_min, v_max, format, flags); }
inline bool DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* format, ImGuiSliderFlags flags) { return imgui_function_table_instance()->DragFloat3(label, v, v_speed, v_min, v_max, format, flags); }
@@ -645,7 +647,7 @@ namespace ImGui
inline bool BeginListBox(const char* label, const ImVec2& size) { return imgui_function_table_instance()->BeginListBox(label, size); }
inline void EndListBox() { imgui_function_table_instance()->EndListBox(); }
inline bool ListBox(const char* label, int* current_item, const char* const items[], int items_count, int height_in_items) { return imgui_function_table_instance()->ListBox(label, current_item, items, items_count, height_in_items); }
- inline bool ListBox(const char* label, int* current_item, bool(*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int height_in_items) { return imgui_function_table_instance()->ListBox2(label, current_item, items_getter, data, items_count, height_in_items); }
+ inline bool ListBox(const char* label, int* current_item, const char*(*getter)(void* user_data, int idx), void* user_data, int items_count, int height_in_items) { return imgui_function_table_instance()->ListBox2(label, current_item, getter, user_data, items_count, height_in_items); }
inline void PlotLines(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride) { imgui_function_table_instance()->PlotLines(label, values, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size, stride); }
inline void PlotLines(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size) { imgui_function_table_instance()->PlotLines2(label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size); }
inline void PlotHistogram(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride) { imgui_function_table_instance()->PlotHistogram(label, values, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size, stride); }
@@ -687,8 +689,9 @@ namespace ImGui
inline bool TableSetColumnIndex(int column_n) { return imgui_function_table_instance()->TableSetColumnIndex(column_n); }
inline void TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, float init_width_or_weight, ImGuiID user_id) { imgui_function_table_instance()->TableSetupColumn(label, flags, init_width_or_weight, user_id); }
inline void TableSetupScrollFreeze(int cols, int rows) { imgui_function_table_instance()->TableSetupScrollFreeze(cols, rows); }
- inline void TableHeadersRow() { imgui_function_table_instance()->TableHeadersRow(); }
inline void TableHeader(const char* label) { imgui_function_table_instance()->TableHeader(label); }
+ inline void TableHeadersRow() { imgui_function_table_instance()->TableHeadersRow(); }
+ inline void TableAngledHeadersRow() { imgui_function_table_instance()->TableAngledHeadersRow(); }
inline ImGuiTableSortSpecs* TableGetSortSpecs() { return imgui_function_table_instance()->TableGetSortSpecs(); }
inline int TableGetColumnCount() { return imgui_function_table_instance()->TableGetColumnCount(); }
inline int TableGetColumnIndex() { return imgui_function_table_instance()->TableGetColumnIndex(); }
@@ -759,8 +762,6 @@ namespace ImGui
inline const char* GetStyleColorName(ImGuiCol idx) { return imgui_function_table_instance()->GetStyleColorName(idx); }
inline void SetStateStorage(ImGuiStorage* storage) { imgui_function_table_instance()->SetStateStorage(storage); }
inline ImGuiStorage* GetStateStorage() { return imgui_function_table_instance()->GetStateStorage(); }
- inline bool BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags flags) { return imgui_function_table_instance()->BeginChildFrame(id, size, flags); }
- inline void EndChildFrame() { imgui_function_table_instance()->EndChildFrame(); }
inline ImVec2 CalcTextSize(const char* text, const char* text_end, bool hide_text_after_double_hash, float wrap_width) { return imgui_function_table_instance()->CalcTextSize(text, text_end, hide_text_after_double_hash, wrap_width); }
inline ImVec4 ColorConvertU32ToFloat4(ImU32 in) { return imgui_function_table_instance()->ColorConvertU32ToFloat4(in); }
inline ImU32 ColorConvertFloat4ToU32(const ImVec4& in) { return imgui_function_table_instance()->ColorConvertFloat4ToU32(in); }
@@ -769,6 +770,7 @@ namespace ImGui
inline bool IsKeyDown(ImGuiKey key) { return imgui_function_table_instance()->IsKeyDown(key); }
inline bool IsKeyPressed(ImGuiKey key, bool repeat) { return imgui_function_table_instance()->IsKeyPressed(key, repeat); }
inline bool IsKeyReleased(ImGuiKey key) { return imgui_function_table_instance()->IsKeyReleased(key); }
+ inline bool IsKeyChordPressed(ImGuiKeyChord key_chord) { return imgui_function_table_instance()->IsKeyChordPressed(key_chord); }
inline int GetKeyPressedAmount(ImGuiKey key, float repeat_delay, float rate) { return imgui_function_table_instance()->GetKeyPressedAmount(key, repeat_delay, rate); }
inline const char* GetKeyName(ImGuiKey key) { return imgui_function_table_instance()->GetKeyName(key); }
inline void SetNextFrameWantCaptureKeyboard(bool want_capture_keyboard) { imgui_function_table_instance()->SetNextFrameWantCaptureKeyboard(want_capture_keyboard); }
@@ -809,14 +811,14 @@ inline int* ImGuiStorage::GetIntRef(ImGuiID key, int default_val) { return imgui
inline bool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val) { return imgui_function_table_instance()->ImGuiStorage_GetBoolRef(this, key, default_val); }
inline float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val) { return imgui_function_table_instance()->ImGuiStorage_GetFloatRef(this, key, default_val); }
inline void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val) { return imgui_function_table_instance()->ImGuiStorage_GetVoidPtrRef(this, key, default_val); }
-inline void ImGuiStorage::SetAllInt(int val) { imgui_function_table_instance()->ImGuiStorage_SetAllInt(this, val); }
inline void ImGuiStorage::BuildSortByKey() { imgui_function_table_instance()->ImGuiStorage_BuildSortByKey(this); }
+inline void ImGuiStorage::SetAllInt(int val) { imgui_function_table_instance()->ImGuiStorage_SetAllInt(this, val); }
inline ImGuiListClipper::ImGuiListClipper() { imgui_function_table_instance()->ConstructImGuiListClipper(this); }
inline ImGuiListClipper::~ImGuiListClipper() { imgui_function_table_instance()->DestructImGuiListClipper(this); }
inline void ImGuiListClipper::Begin(int items_count, float items_height) { imgui_function_table_instance()->ImGuiListClipper_Begin(this, items_count, items_height); }
inline void ImGuiListClipper::End() { imgui_function_table_instance()->ImGuiListClipper_End(this); }
inline bool ImGuiListClipper::Step() { return imgui_function_table_instance()->ImGuiListClipper_Step(this); }
-inline void ImGuiListClipper::IncludeRangeByIndices(int item_begin, int item_end) { imgui_function_table_instance()->ImGuiListClipper_IncludeRangeByIndices(this, item_begin, item_end); }
+inline void ImGuiListClipper::IncludeItemsByIndex(int item_begin, int item_end) { imgui_function_table_instance()->ImGuiListClipper_IncludeItemsByIndex(this, item_begin, item_end); }
inline void ImDrawList::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect) { imgui_function_table_instance()->ImDrawList_PushClipRect(this, clip_rect_min, clip_rect_max, intersect_with_current_clip_rect); }
inline void ImDrawList::PushClipRectFullScreen() { imgui_function_table_instance()->ImDrawList_PushClipRectFullScreen(this); }
inline void ImDrawList::PopClipRect() { imgui_function_table_instance()->ImDrawList_PopClipRect(this); }
@@ -834,6 +836,8 @@ inline void ImDrawList::AddCircle(const ImVec2& center, float radius, ImU32 col,
inline void ImDrawList::AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments) { imgui_function_table_instance()->ImDrawList_AddCircleFilled(this, center, radius, col, num_segments); }
inline void ImDrawList::AddNgon(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness) { imgui_function_table_instance()->ImDrawList_AddNgon(this, center, radius, col, num_segments, thickness); }
inline void ImDrawList::AddNgonFilled(const ImVec2& center, float radius, ImU32 col, int num_segments) { imgui_function_table_instance()->ImDrawList_AddNgonFilled(this, center, radius, col, num_segments); }
+inline void ImDrawList::AddEllipse(const ImVec2& center, float radius_x, float radius_y, ImU32 col, float rot, int num_segments, float thickness) { imgui_function_table_instance()->ImDrawList_AddEllipse(this, center, radius_x, radius_y, col, rot, num_segments, thickness); }
+inline void ImDrawList::AddEllipseFilled(const ImVec2& center, float radius_x, float radius_y, ImU32 col, float rot, int num_segments) { imgui_function_table_instance()->ImDrawList_AddEllipseFilled(this, center, radius_x, radius_y, col, rot, num_segments); }
inline void ImDrawList::AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end) { imgui_function_table_instance()->ImDrawList_AddText(this, pos, col, text_begin, text_end); }
inline void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end, float wrap_width, const ImVec4* cpu_fine_clip_rect) { imgui_function_table_instance()->ImDrawList_AddText2(this, font, font_size, pos, col, text_begin, text_end, wrap_width, cpu_fine_clip_rect); }
inline void ImDrawList::AddPolyline(const ImVec2* points, int num_points, ImU32 col, ImDrawFlags flags, float thickness) { imgui_function_table_instance()->ImDrawList_AddPolyline(this, points, num_points, col, flags, thickness); }
@@ -845,6 +849,7 @@ inline void ImDrawList::AddImageQuad(ImTextureID user_texture_id, const ImVec2&
inline void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawFlags flags) { imgui_function_table_instance()->ImDrawList_AddImageRounded(this, user_texture_id, p_min, p_max, uv_min, uv_max, col, rounding, flags); }
inline void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments) { imgui_function_table_instance()->ImDrawList_PathArcTo(this, center, radius, a_min, a_max, num_segments); }
inline void ImDrawList::PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12) { imgui_function_table_instance()->ImDrawList_PathArcToFast(this, center, radius, a_min_of_12, a_max_of_12); }
+inline void ImDrawList::PathEllipticalArcTo(const ImVec2& center, float radius_x, float radius_y, float rot, float a_min, float a_max, int num_segments) { imgui_function_table_instance()->ImDrawList_PathEllipticalArcTo(this, center, radius_x, radius_y, rot, a_min, a_max, num_segments); }
inline void ImDrawList::PathBezierCubicCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments) { imgui_function_table_instance()->ImDrawList_PathBezierCubicCurveTo(this, p2, p3, p4, num_segments); }
inline void ImDrawList::PathBezierQuadraticCurveTo(const ImVec2& p2, const ImVec2& p3, int num_segments) { imgui_function_table_instance()->ImDrawList_PathBezierQuadraticCurveTo(this, p2, p3, num_segments); }
inline void ImDrawList::PathRect(const ImVec2& rect_min, const ImVec2& rect_max, float rounding, ImDrawFlags flags) { imgui_function_table_instance()->ImDrawList_PathRect(this, rect_min, rect_max, rounding, flags); }
@@ -869,4 +874,3 @@ inline void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2&
#endif
#endif
-#endif
\ No newline at end of file
diff --git a/depends/src/DirectXTex/DirectXTex_Desktop_2015.suppress b/depends/src/DirectXTex/DirectXTex_Desktop_2015.suppress
new file mode 100644
index 000000000..b2415f554
--- /dev/null
+++ b/depends/src/DirectXTex/DirectXTex_Desktop_2015.suppress
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 3
+ false
+
+
+ debug_utils.h
+ V802
+ On _-bit platform, structure size can be reduced from _ to _ bytes by rearranging the fields according to their sizes in decreasing order.
+ 1907953360
+ 123
+ 14801337
+
+
\ No newline at end of file
diff --git a/include/SpecialK/DLL_VERSION.H b/include/SpecialK/DLL_VERSION.H
index d5f66fc14..0b70d3750 100644
--- a/include/SpecialK/DLL_VERSION.H
+++ b/include/SpecialK/DLL_VERSION.H
@@ -2,9 +2,9 @@
#define SK_YEAR 24
#define SK_MONTH 11
-#define SK_DATE 20
-#define SK_REV_N 0
-#define SK_REV 0
+#define SK_DATE 30
+#define SK_REV_N 3
+#define SK_REV 3
#ifndef _A2
#define _A2(a) #a
diff --git a/include/SpecialK/config.h b/include/SpecialK/config.h
index e34a52a56..b67a75776 100644
--- a/include/SpecialK/config.h
+++ b/include/SpecialK/config.h
@@ -809,7 +809,7 @@ struct sk_config_t
bool temporary_dwm_hdr = false; // Always turns HDR on and off for this game
bool disable_virtual_vbi = true; // Disable Windows 11 Dynamic Refresh Rate
bool ignore_thread_flags = false; // Remove threading flags from D3D11 devices
- bool clear_flipped_chain = true; // Clear buffers on present? (non-compliant)
+ bool clear_flipped_chain = false; // Clear buffers on present? (non-compliant)
float chain_clear_color[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
bool suppress_resize_fail = true; // Workaround DLSS FrameGen compat. issues in D3D12
bool suppress_rtv_mismatch= false; // Hide SwapChain RTV format warnings for buggy games
@@ -1078,10 +1078,13 @@ struct sk_config_t
bool hook_raw_input = true;
bool hook_windows_gaming = true;
bool hook_winmm = true;
+ bool hook_game_input = true;
bool allow_steam_winmm = true;
bool native_ps4 = false;
bool bt_input_only = false;
float low_battery_percent = 25.0f;
+ float impulse_strength_l = 0.75f;
+ float impulse_strength_r = 0.75f;
struct xinput_s {
unsigned
@@ -1268,6 +1271,11 @@ struct sk_config_t
int use_joystick_thread = -1;
int poll_sentinel = -1;
} sdl;
+ // Messages that SK may post to a game's
+ // window in order to trigger various
+ // window management responsibilities.
+ bool allow_fake_displaychange = true;
+ bool allow_fake_size = true;
} compatibility;
struct apis_s {
@@ -1720,6 +1728,7 @@ enum class SK_GAME_ID
DragonAgeTheVeilguard, // Dragon Age The Veilguard.exe
TombRaider123Remastered, // tomb123.exe
Stalker2, // Stalker2-WinGDK-Shipping.exe (Microsoft Store) Stalker2-Win64-Shipping.exe (Steam)
+ vlc, // vlc.exe
UNKNOWN_GAME = 0xffff
};
diff --git a/include/SpecialK/diagnostics/debug_utils.h b/include/SpecialK/diagnostics/debug_utils.h
index eaefcb6f5..94abf7432 100644
--- a/include/SpecialK/diagnostics/debug_utils.h
+++ b/include/SpecialK/diagnostics/debug_utils.h
@@ -23,6 +23,7 @@
#define __SK__DEBUG_UTILS_H__
#include
+#include
#include
#include
@@ -663,9 +664,9 @@ using SymLoadModule64_pfn = DWORD64 (IMAGEAPI *)( _In_ HANDLE hProcess,
_In_ DWORD SizeOfDll );
-std::wstring& SK_Thread_GetName (DWORD dwTid);
-std::wstring& SK_Thread_GetName (HANDLE hThread);
-DWORD SK_Thread_FindByName (std::wstring name);
+const wchar_t* SK_Thread_GetName (DWORD dwTid);
+const wchar_t* SK_Thread_GetName (HANDLE hThread);
+DWORD SK_Thread_FindByName (std::wstring name);
#include
@@ -865,7 +866,7 @@ SK_SetThreadPriority ( HANDLE hThread,
extern SK_LazyGlobal <
- concurrency::concurrent_unordered_map
+ concurrency::concurrent_unordered_map >
> _SK_ThreadNames;
extern SK_LazyGlobal <
concurrency::concurrent_unordered_set
@@ -879,4 +880,38 @@ bool SK_Process_Resume (DWORD dwPid);
void WINAPI SK_OutputDebugStringW (LPCWSTR lpOutputString);
void WINAPI SK_OutputDebugStringA (LPCSTR lpOutputString);
+using SetLastError_pfn = void (WINAPI *)(_In_ DWORD dwErrCode);
+using GetProcAddress_pfn = FARPROC (WINAPI *)(HMODULE,LPCSTR);
+using CloseHandle_pfn = BOOL (WINAPI *)(HANDLE);
+
+using GetCommandLineW_pfn = LPWSTR (WINAPI *)(void);
+using GetCommandLineA_pfn = LPSTR (WINAPI *)(void);
+using TerminateThread_pfn = BOOL (WINAPI *)( _In_ HANDLE hThread,
+ _In_ DWORD dwExitCode );
+ using ExitThread_pfn = VOID (WINAPI *)(_In_ DWORD dwExitCode);
+using _endthreadex_pfn = void (__cdecl *)( _In_ unsigned _ReturnCode );
+using NtTerminateProcess_pfn = NTSTATUS (*)(HANDLE, NTSTATUS);
+using RtlExitUserThread_pfn = VOID (NTAPI *)(_In_ NTSTATUS Status);
+using SHGetKnownFolderPath_pfn = HRESULT (WINAPI *)(REFKNOWNFOLDERID,DWORD,HANDLE,PWSTR*);
+
+extern SHGetKnownFolderPath_pfn SHGetKnownFolderPath_Original;
+
+extern GetCommandLineW_pfn GetCommandLineW_Original;
+extern GetCommandLineA_pfn GetCommandLineA_Original;
+
+extern NtTerminateProcess_pfn NtTerminateProcess_Original;
+extern RtlExitUserThread_pfn RtlExitUserThread_Original;
+extern ExitThread_pfn ExitThread_Original;
+extern _endthreadex_pfn _endthreadex_Original;
+extern TerminateThread_pfn TerminateThread_Original;
+
+extern RaiseException_pfn RaiseException_Original;
+extern SetLastError_pfn SetLastError_Original;
+extern GetProcAddress_pfn GetProcAddress_Original;
+extern TerminateProcess_pfn TerminateProcess_Original;
+extern ExitProcess_pfn ExitProcess_Original;
+extern OutputDebugStringA_pfn OutputDebugStringA_Original;
+extern OutputDebugStringW_pfn OutputDebugStringW_Original;
+extern CloseHandle_pfn CloseHandle_Original;
+
#endif /* __SK__DEBUG_UTILS_H__ */
diff --git a/include/SpecialK/diagnostics/memory.h b/include/SpecialK/diagnostics/memory.h
index 8accc8221..47991749c 100644
--- a/include/SpecialK/diagnostics/memory.h
+++ b/include/SpecialK/diagnostics/memory.h
@@ -1,4 +1,4 @@
-/**
+/**
* This file is part of Special K.
*
* Special K is free software : you can redistribute it
@@ -82,7 +82,7 @@ typedef BOOL (WINAPI *HeapFree_pfn)(
extern VirtualAlloc_pfn VirtualAlloc_Original;
extern VirtualFree_pfn VirtualFree_Original;
- extern RtlAllocateHeap_pfn RtlAllocaeHeap_Original;
+ extern RtlAllocateHeap_pfn RtlAllocateHeap_Original;
extern HeapFree_pfn HeapFree_Original;
diff --git a/include/SpecialK/input/game_input.h b/include/SpecialK/input/game_input.h
new file mode 100644
index 000000000..fd8b4d5f4
--- /dev/null
+++ b/include/SpecialK/input/game_input.h
@@ -0,0 +1,277 @@
+/**
+ * This file is part of Special K.
+ *
+ * Special K is free software : you can redistribute it
+ * and/or modify it under the terms of the GNU General Public License
+ * as published by The Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * Special K is distributed in the hope that it will be useful,
+ *
+ * But WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Special K.
+ *
+ * If not, see .
+ *
+**/
+
+#ifndef __SK__GAME_INPUT_H__
+#define __SK__GAME_INPUT_H__
+
+#include
+
+class SK_IWrapGameInput : IGameInput
+{
+public:
+ SK_IWrapGameInput (IGameInput *pGameInput) : pReal (pGameInput),
+ ver_ (0)
+ {
+ if (pGameInput == nullptr)
+ return;
+ }
+
+#pragma region IUnknown
+ virtual HRESULT __stdcall QueryInterface (REFIID riid, void **ppvObject) noexcept override;
+ virtual ULONG __stdcall AddRef (void) noexcept override;
+ virtual ULONG __stdcall Release (void) noexcept override;
+#pragma endregion
+
+#pragma region IGameInput
+ virtual uint64_t __stdcall GetCurrentTimestamp (void) noexcept override;
+ virtual HRESULT __stdcall GetCurrentReading (_In_ GameInputKind inputKind,
+ _In_opt_ IGameInputDevice *device,
+ _COM_Outptr_ IGameInputReading **reading) noexcept override;
+ virtual HRESULT __stdcall GetNextReading (_In_ IGameInputReading *referenceReading,
+ _In_ GameInputKind inputKind,
+ _In_opt_ IGameInputDevice *device,
+ _COM_Outptr_ IGameInputReading **reading) noexcept override;
+ virtual HRESULT __stdcall GetPreviousReading (_In_ IGameInputReading *referenceReading,
+ _In_ GameInputKind inputKind,
+ _In_opt_ IGameInputDevice *device,
+ _COM_Outptr_ IGameInputReading **reading) noexcept override;
+ virtual HRESULT __stdcall GetTemporalReading (_In_ uint64_t timestamp,
+ _In_ IGameInputDevice *device,
+ _COM_Outptr_ IGameInputReading **reading) noexcept override;
+
+ virtual HRESULT __stdcall RegisterReadingCallback (_In_opt_ IGameInputDevice *device,
+ _In_ GameInputKind inputKind,
+ _In_ float analogThreshold,
+ _In_opt_ void *context,
+ _In_ GameInputReadingCallback callbackFunc,
+ _Out_opt_ _Result_zeroonfailure_ GameInputCallbackToken *callbackToken) noexcept override;
+ virtual HRESULT __stdcall RegisterDeviceCallback (_In_opt_ IGameInputDevice *device,
+ _In_ GameInputKind inputKind,
+ _In_ GameInputDeviceStatus statusFilter,
+ _In_ GameInputEnumerationKind enumerationKind,
+ _In_opt_ void *context,
+ _In_ GameInputDeviceCallback callbackFunc,
+ _Out_opt_ _Result_zeroonfailure_ GameInputCallbackToken *callbackToken) noexcept override;
+
+ virtual HRESULT __stdcall RegisterSystemButtonCallback (_In_opt_ IGameInputDevice *device,
+ _In_ GameInputSystemButtons buttonFilter,
+ _In_opt_ void *context,
+ _In_ GameInputSystemButtonCallback callbackFunc,
+ _Out_opt_ _Result_zeroonfailure_ GameInputCallbackToken *callbackToken) noexcept override;
+ virtual HRESULT __stdcall RegisterKeyboardLayoutCallback (_In_opt_ IGameInputDevice *device,
+ _In_opt_ void *context,
+ _In_ GameInputKeyboardLayoutCallback callbackFunc,
+ _Out_opt_ _Result_zeroonfailure_ GameInputCallbackToken *callbackToken) noexcept override;
+
+ virtual void __stdcall StopCallback (_In_ GameInputCallbackToken callbackToken) noexcept override;
+ virtual bool __stdcall UnregisterCallback (_In_ GameInputCallbackToken callbackToken,
+ _In_ uint64_t timeoutInMicroseconds) noexcept override;
+
+ virtual HRESULT __stdcall CreateDispatcher (_COM_Outptr_ IGameInputDispatcher **dispatcher) noexcept override;
+ virtual HRESULT __stdcall CreateAggregateDevice (_In_ GameInputKind inputKind,
+ _COM_Outptr_ IGameInputDevice **device) noexcept override;
+
+ virtual HRESULT __stdcall FindDeviceFromId (_In_ APP_LOCAL_DEVICE_ID const *value,
+ _COM_Outptr_ IGameInputDevice **device) noexcept override;
+ virtual HRESULT __stdcall FindDeviceFromObject (_In_ IUnknown *value,
+ _COM_Outptr_ IGameInputDevice **device) noexcept override;
+ virtual HRESULT __stdcall FindDeviceFromPlatformHandle (_In_ HANDLE value,
+ _COM_Outptr_ IGameInputDevice **device) noexcept override;
+ virtual HRESULT __stdcall FindDeviceFromPlatformString (_In_ LPCWSTR value,
+ _COM_Outptr_ IGameInputDevice **device) noexcept override;
+
+ virtual HRESULT __stdcall EnableOemDeviceSupport (_In_ uint16_t vendorId,
+ _In_ uint16_t productId,
+ _In_ uint8_t interfaceNumber,
+ _In_ uint8_t collectionNumber) noexcept override;
+ virtual void __stdcall SetFocusPolicy (_In_ GameInputFocusPolicy policy) noexcept override;
+#pragma endregion
+
+private:
+ volatile LONG refs_ = 1;
+ IGameInput *pReal;
+ unsigned int ver_ = 0;
+};
+
+
+class SK_IGameInputDevice : IGameInputDevice
+{
+public:
+ SK_IGameInputDevice (IGameInputDevice *pGameInputDevice) : pReal (pGameInputDevice),
+ ver_ (0)
+ {
+ if (pGameInputDevice == nullptr)
+ return;
+ };
+
+#pragma region IUnknown
+ virtual HRESULT __stdcall QueryInterface (REFIID riid, void **ppvObject) noexcept override; // 0
+ virtual ULONG __stdcall AddRef (void) noexcept override; // 1
+ virtual ULONG __stdcall Release (void) noexcept override; // 2
+#pragma endregion
+
+#pragma region IGameInputDevice
+ virtual GameInputDeviceInfo const* __stdcall GetDeviceInfo (void) noexcept override; // 3
+ virtual GameInputDeviceStatus __stdcall GetDeviceStatus (void) noexcept override; // 4
+ virtual void __stdcall GetBatteryState (GameInputBatteryState *state) noexcept override; // 5
+
+ virtual HRESULT __stdcall CreateForceFeedbackEffect (uint32_t motorIndex,
+ GameInputForceFeedbackParams const *params,
+ IGameInputForceFeedbackEffect **effect) noexcept override; // 6
+ virtual bool __stdcall IsForceFeedbackMotorPoweredOn (uint32_t motorIndex) noexcept override; // 7
+ virtual void __stdcall SetForceFeedbackMotorGain (uint32_t motorIndex, float masterGain) noexcept override; // 8
+ virtual HRESULT __stdcall SetHapticMotorState (uint32_t motorIndex,
+ GameInputHapticFeedbackParams const *params) noexcept override; // 9
+ virtual void __stdcall SetRumbleState (GameInputRumbleParams const *params) noexcept override; // 10
+ virtual void __stdcall SetInputSynchronizationState ( bool enabled) noexcept override; // 11
+ virtual void __stdcall SendInputSynchronizationHint (void) noexcept override; // 12
+ virtual void __stdcall PowerOff (void) noexcept override; // 13
+
+ virtual HRESULT __stdcall CreateRawDeviceReport (uint32_t reportId,
+ GameInputRawDeviceReportKind reportKind,
+ IGameInputRawDeviceReport **report) noexcept override; // 14
+ virtual HRESULT __stdcall GetRawDeviceFeature (uint32_t reportId,
+ IGameInputRawDeviceReport **report) noexcept override; // 15
+ virtual HRESULT __stdcall SetRawDeviceFeature (IGameInputRawDeviceReport *report) noexcept override; // 16
+ virtual HRESULT __stdcall SendRawDeviceOutput (IGameInputRawDeviceReport *report) noexcept override; // 17
+ virtual HRESULT __stdcall SendRawDeviceOutputWithResponse (IGameInputRawDeviceReport *requestReport,
+ IGameInputRawDeviceReport **responseReport) noexcept override; // 18
+ virtual HRESULT __stdcall ExecuteRawDeviceIoControl (uint32_t controlCode,
+ size_t inputBufferSize,
+ void const *inputBuffer,
+ size_t outputBufferSize,
+ void *outputBuffer,
+ size_t *outputSize) noexcept override; // 19
+ virtual bool __stdcall AcquireExclusiveRawDeviceAccess (uint64_t timeoutInMicroseconds) noexcept override; // 20
+ virtual void __stdcall ReleaseExclusiveRawDeviceAccess (void) noexcept override; // 21
+#pragma endregion
+
+private:
+ volatile LONG refs_ = 1;
+ IGameInputDevice *pReal;
+ unsigned int ver_ = 0;
+};
+
+class SK_IWrapGameInputReading : IGameInputReading
+{
+public:
+ SK_IWrapGameInputReading (IGameInputReading *pGameInputReading) : pReal (pGameInputReading),
+ ver_ (0)
+ {
+ if (pGameInputReading == nullptr)
+ return;
+ };
+
+#pragma region IUnknown
+ virtual HRESULT __stdcall QueryInterface (REFIID riid, void **ppvObject) noexcept override;
+ virtual ULONG __stdcall AddRef (void) noexcept override;
+ virtual ULONG __stdcall Release (void) noexcept override;
+#pragma endregion
+
+#pragma region IGameInputReading
+ virtual GameInputKind __stdcall GetInputKind (void) noexcept override;
+ virtual uint64_t __stdcall GetSequenceNumber (GameInputKind inputKind) noexcept override;
+ virtual uint64_t __stdcall GetTimestamp (void) noexcept override;
+ virtual void __stdcall GetDevice (IGameInputDevice **device) noexcept override;
+ virtual bool __stdcall GetRawReport (IGameInputRawDeviceReport **report) noexcept override;
+ virtual uint32_t __stdcall GetControllerAxisCount (void) noexcept override;
+ virtual uint32_t __stdcall GetControllerAxisState (uint32_t stateArrayCount,
+ float *stateArray) noexcept override;
+ virtual uint32_t __stdcall GetControllerButtonCount (void) noexcept override;
+ virtual uint32_t __stdcall GetControllerButtonState (uint32_t stateArrayCount,
+ bool *stateArray) noexcept override;
+ virtual uint32_t __stdcall GetControllerSwitchCount (void) noexcept override;
+ virtual uint32_t __stdcall GetControllerSwitchState (uint32_t stateArrayCount,
+ GameInputSwitchPosition *stateArray) noexcept override;
+ virtual uint32_t __stdcall GetKeyCount (void) noexcept override;
+ virtual uint32_t __stdcall GetKeyState (uint32_t stateArrayCount,
+ GameInputKeyState *stateArray) noexcept override;
+ virtual bool __stdcall GetMouseState (GameInputMouseState *state) noexcept override;
+ virtual uint32_t __stdcall GetTouchCount (void) noexcept override;
+ virtual uint32_t __stdcall GetTouchState (uint32_t stateArrayCount,
+ GameInputTouchState *stateArray) noexcept override;
+ virtual bool __stdcall GetMotionState (GameInputMotionState *state) noexcept override;
+ virtual bool __stdcall GetArcadeStickState (GameInputArcadeStickState *state) noexcept override;
+ virtual bool __stdcall GetFlightStickState (GameInputFlightStickState *state) noexcept override;
+ virtual bool __stdcall GetGamepadState (GameInputGamepadState *state) noexcept override;
+ virtual bool __stdcall GetRacingWheelState (GameInputRacingWheelState *state) noexcept override;
+ virtual bool __stdcall GetUiNavigationState (GameInputUiNavigationState *state) noexcept override;
+#pragma endregion
+
+private:
+ volatile LONG refs_ = 1;
+ IGameInputReading *pReal;
+ unsigned int ver_ = 0;
+};
+
+class SK_IPlayStationGameInputReading : IGameInputReading
+{
+public:
+ SK_IPlayStationGameInputReading (HANDLE hDeviceFile) : hDevice (hDeviceFile),
+ ver_ (0)
+ {
+ };
+
+#pragma region IUnknown
+ virtual HRESULT __stdcall QueryInterface (REFIID riid, void **ppvObject) noexcept override;
+ virtual ULONG __stdcall AddRef (void) noexcept override;
+ virtual ULONG __stdcall Release (void) noexcept override;
+#pragma endregion
+
+#pragma region IGameInputReading
+ virtual GameInputKind __stdcall GetInputKind (void) noexcept override;
+ virtual uint64_t __stdcall GetSequenceNumber (GameInputKind inputKind) noexcept override;
+ virtual uint64_t __stdcall GetTimestamp (void) noexcept override;
+ virtual void __stdcall GetDevice (IGameInputDevice **device) noexcept override;
+ virtual bool __stdcall GetRawReport (IGameInputRawDeviceReport **report) noexcept override;
+ virtual uint32_t __stdcall GetControllerAxisCount (void) noexcept override;
+ virtual uint32_t __stdcall GetControllerAxisState (uint32_t stateArrayCount,
+ float *stateArray) noexcept override;
+ virtual uint32_t __stdcall GetControllerButtonCount (void) noexcept override;
+ virtual uint32_t __stdcall GetControllerButtonState (uint32_t stateArrayCount,
+ bool *stateArray) noexcept override;
+ virtual uint32_t __stdcall GetControllerSwitchCount (void) noexcept override;
+ virtual uint32_t __stdcall GetControllerSwitchState (uint32_t stateArrayCount,
+ GameInputSwitchPosition *stateArray) noexcept override;
+ virtual uint32_t __stdcall GetKeyCount (void) noexcept override;
+ virtual uint32_t __stdcall GetKeyState (uint32_t stateArrayCount,
+ GameInputKeyState *stateArray) noexcept override;
+ virtual bool __stdcall GetMouseState (GameInputMouseState *state) noexcept override;
+ virtual uint32_t __stdcall GetTouchCount (void) noexcept override;
+ virtual uint32_t __stdcall GetTouchState (uint32_t stateArrayCount,
+ GameInputTouchState *stateArray) noexcept override;
+ virtual bool __stdcall GetMotionState (GameInputMotionState *state) noexcept override;
+ virtual bool __stdcall GetArcadeStickState (GameInputArcadeStickState *state) noexcept override;
+ virtual bool __stdcall GetFlightStickState (GameInputFlightStickState *state) noexcept override;
+ virtual bool __stdcall GetGamepadState (GameInputGamepadState *state) noexcept override;
+ virtual bool __stdcall GetRacingWheelState (GameInputRacingWheelState *state) noexcept override;
+ virtual bool __stdcall GetUiNavigationState (GameInputUiNavigationState *state) noexcept override;
+#pragma endregion
+
+private:
+ volatile LONG refs_ = 1;
+ HANDLE hDevice;
+ unsigned int ver_ = 0;
+};
+
+void SK_Input_HookGameInput (void);
+
+#endif /* __SK__GAME_INPUT_H__ */
\ No newline at end of file
diff --git a/include/SpecialK/input/input.h b/include/SpecialK/input/input.h
index ea1190f57..8edc80da2 100644
--- a/include/SpecialK/input/input.h
+++ b/include/SpecialK/input/input.h
@@ -46,6 +46,8 @@ extern int64_t SK_PerfFreq;
bool SK_ImGui_WantGamepadCapture (bool update = false);
bool SK_ImGui_WantHWCursor (void);
bool SK_ImGui_WantMouseCapture (bool update = false);
+bool SK_ImGui_WantMouseButtonCapture
+ (void);
bool SK_ImGui_WantMouseCaptureEx (DWORD dwReasonMask = 0xFFFF);
bool SK_ImGui_WantKeyboardCapture (bool update = false);
bool SK_ImGui_WantTextCapture (void);
@@ -105,25 +107,26 @@ enum class sk_cursor_state {
struct sk_imgui_cursor_s
{
- HWND child_input = HWND_DESKTOP;
- RECT child_client = { 0, 0, 0, 0 };
- RECT child_rect = { 0, 0, 0, 0 };
+ HWND child_input = HWND_DESKTOP;
+ RECT child_client = { 0, 0, 0, 0 };
+ RECT child_rect = { 0, 0, 0, 0 };
- HCURSOR real_img = nullptr;
- POINT orig_pos = { 0, 0 };
- bool orig_vis = false;
+ HCURSOR real_img = nullptr;
+ POINT orig_pos = { 0, 0 };
+ bool orig_vis = false;
- HCURSOR img = nullptr;
- POINT pos = { 0, 0 };
+ HCURSOR img = nullptr;
+ POINT pos = { 0, 0 };
- bool visible = false;
- bool idle = true; // Hasn't moved
- DWORD last_move = MAXDWORD;
- DWORD last_toggle = 0;
- DWORD refs_added = 0;
- DWORD64 times_set = 0; // Times the game has set a non-zero cursor
+ bool visible = false;
+ bool idle = true; // Hasn't moved
+ DWORD last_move = MAXDWORD;
+ DWORD last_toggle = 0;
+ DWORD refs_added = 0;
+ POINT last_screen_pos = { 0, 0 };
+ DWORD64 times_set = 0; // Times the game has set a non-zero cursor
- sk_cursor_state force = sk_cursor_state::None;
+ sk_cursor_state force = sk_cursor_state::None;
void showSystemCursor (bool system = true);
void showImGuiCursor (void);
@@ -449,6 +452,7 @@ extern SK_LazyGlobal SK_Win32_Backend;
extern SK_LazyGlobal SK_WinMM_Backend;
extern SK_LazyGlobal SK_WinHook_Backend; // (Low-Level) KB/M Hook
extern SK_LazyGlobal SK_RawInput_Backend;
+extern SK_LazyGlobal SK_GameInput_Backend;
extern SK_LazyGlobal SK_MessageBus_Backend; // NVIDIA stuff
@@ -1035,18 +1039,22 @@ struct SK_HID_PlayStationDevice
struct vibration_s {
volatile ULONG left, right;
- BYTE last_left,
- last_right;
- DWORD last_set;
- DWORD last_output;
+ volatile ULONG last_set;
- USHORT max_val = 0;
+ struct {
+ volatile ULONG left;
+ volatile ULONG right;
+ ULONG last_left;
+ ULONG last_right;
+ } trigger;
+
+ volatile ULONG max_val = 0;
// At most, allow the controller to vibrate for 1000 ms without
// some kind of attempt to set a new value... otherwise, it
// will tend to vibrate infinitely.
static constexpr auto MAX_TTL_IN_MSECS = 1000UL;
- } _vibration = { 0, 0, 0, 0, 0, 0 };
+ } _vibration = { 0, 0, 0, 0, 0, 0, 0, 0 };
void setRGB (BYTE red, BYTE green, BYTE blue) {
_color.r = red;
@@ -1058,6 +1066,12 @@ struct SK_HID_PlayStationDevice
USHORT right,
USHORT max_val = std::numeric_limits ::max () );
+ void setVibration ( USHORT low_freq,
+ USHORT high_freq,
+ USHORT left_trigger,
+ USHORT right_trigger,
+ USHORT max_val = std::numeric_limits ::max () );
+
bool request_input_report (void);
bool write_output_report (bool force = false);
@@ -1076,9 +1090,9 @@ struct SK_HID_OverlappedRequest {
struct SK_HID_DeviceFile {
HIDP_CAPS hidpCaps = { };
- wchar_t wszProductName [128] = { };
- wchar_t wszManufacturerName [128] = { };
- wchar_t wszSerialNumber [128] = { };
+ wchar_t wszProductName [2048] = { };
+ wchar_t wszManufacturerName [2048] = { };
+ wchar_t wszSerialNumber [2048] = { };
wchar_t wszDevicePath [MAX_PATH + 2] = { };
sk_input_dev_type device_type = sk_input_dev_type::Other;
USHORT device_vid = 0x0;
diff --git a/include/SpecialK/plugin/reshade.h b/include/SpecialK/plugin/reshade.h
index 71659021e..b1318dd0e 100644
--- a/include/SpecialK/plugin/reshade.h
+++ b/include/SpecialK/plugin/reshade.h
@@ -27,6 +27,7 @@
#include
#include <../depends/include/ReShade/reshade_api.hpp>
+#include <../depends/include/ReShade/reshade_api_display.hpp>
#include <../depends/include/DirectXTex/DirectXTex.h>
HMODULE
diff --git a/include/SpecialK/render/d3d11/d3d11_core.h b/include/SpecialK/render/d3d11/d3d11_core.h
index 4ef168053..ba0cb9f74 100644
--- a/include/SpecialK/render/d3d11/d3d11_core.h
+++ b/include/SpecialK/render/d3d11/d3d11_core.h
@@ -136,7 +136,8 @@ class SK_D3D11_HookTallyWhacker
const bool bIsDevCtxDeferred = \
SK_D3D11_IsDevCtxDeferred (pDevCtx); \
\
- if (! bIsDevCtxDeferred) \
+ std::ignore = bIsDevCtxDeferred; \
+ if (true)/*! bIsDevCtxDeferred)*/ \
{ \
call_tally.hooked ( bWrapped ? 0 : 1 ); \
call_tally.wrapped ( bWrapped ? 1 : 0 ); \
@@ -235,7 +236,7 @@ SK_D3D11_ResetContextState ( ID3D11DeviceContext *pDevCtx,
extern std::pair
SK_ImGui_FlagDrawing_OnD3D11Ctx (UINT dev_idx);
extern bool
-SK_ImGui_IsDrawing_OnD3D11Ctx (UINT dev_idx, ID3D11DeviceContext* pDevCtx);
+SK_ImGui_IsDrawing_OnD3D11Ctx (UINT& dev_idx, ID3D11DeviceContext* pDevCtx);
struct shader_stage_s
@@ -2890,7 +2891,7 @@ struct SK_IMGUI_D3D11StateBlock {
};
extern std::pair SK_ImGui_FlagDrawing_OnD3D11Ctx (UINT dev_idx);
-extern bool SK_ImGui_IsDrawing_OnD3D11Ctx (UINT dev_idx, ID3D11DeviceContext* pDevCtx);
+extern bool SK_ImGui_IsDrawing_OnD3D11Ctx (UINT& dev_idx, ID3D11DeviceContext* pDevCtx);
void SK_D3D11_InitMutexes (void);
BOOL SK_D3D11_SetWrappedImmediateContext ( ID3D11Device *pDev,
diff --git a/include/SpecialK/render/dxgi/dxgi_swapchain.h b/include/SpecialK/render/dxgi/dxgi_swapchain.h
index f91c554a9..4cf31b77c 100644
--- a/include/SpecialK/render/dxgi/dxgi_swapchain.h
+++ b/include/SpecialK/render/dxgi/dxgi_swapchain.h
@@ -138,6 +138,7 @@ IWrapDXGISwapChain : IDXGISwapChain4
{
SK_ComQIPtr
pDXGIDev12 (pDev12.p);
+ if ( pDXGIDev12 != nullptr )
pDXGIDev12->GetMaximumFrameLatency (&gameFrameLatency_);
}
@@ -147,6 +148,7 @@ IWrapDXGISwapChain : IDXGISwapChain4
{
SK_ComQIPtr
pDXGIDev11 (pDevice);
+ if ( pDXGIDev11 != nullptr )
pDXGIDev11->GetMaximumFrameLatency (&gameFrameLatency_);
SK_ComPtr pDevCtx;
@@ -255,6 +257,7 @@ IWrapDXGISwapChain : IDXGISwapChain4
{
SK_ComQIPtr
pDXGIDev12 (pDev12.p);
+ if ( pDXGIDev12 != nullptr )
pDXGIDev12->GetMaximumFrameLatency (&gameFrameLatency_);
}
@@ -264,6 +267,7 @@ IWrapDXGISwapChain : IDXGISwapChain4
{
SK_ComQIPtr
pDXGIDev11 (pDevice);
+ if ( pDXGIDev11 != nullptr )
pDXGIDev11->GetMaximumFrameLatency (&gameFrameLatency_);
SK_ComPtr pDevCtx;
diff --git a/include/SpecialK/stdafx.h b/include/SpecialK/stdafx.h
index 694d47427..c49172f41 100644
--- a/include/SpecialK/stdafx.h
+++ b/include/SpecialK/stdafx.h
@@ -281,6 +281,7 @@
#include
#include
#include
+#include
#include
@@ -16648,4 +16649,6 @@ extern const char* SK_VersionStrA;
#include
-#pragma warning ( disable : 4652 )
\ No newline at end of file
+#pragma warning ( disable : 4652 )
+
+#define RESHADE_NO_IMGUI
\ No newline at end of file
diff --git a/include/SpecialK/tls.h b/include/SpecialK/tls.h
index d37acc8d2..e323494b1 100644
--- a/include/SpecialK/tls.h
+++ b/include/SpecialK/tls.h
@@ -1,4 +1,4 @@
-/**
+/**
* This file is part of Special K.
*
* Special K is free software : you can redistribute it
@@ -20,6 +20,8 @@
**/
#pragma once
+#define SK_MAX_THREAD_NAME_LEN MAX_PATH*2
+
// Useless warning: 'typedef ': ignored on left of '' when no variable is declared
#pragma warning (disable: 4091)
@@ -61,8 +63,6 @@ struct SK_MMCS_TaskEntry;
#endif
-#define MAX_THREAD_NAME_LEN MAX_PATH
-
class SK_ModuleAddrMap
{
public:
@@ -791,7 +791,7 @@ class SK_TLS
LONG exception_repeats = 0;
callsite_list_t suppressed_addrs = { };
wchar_t name
- [MAX_THREAD_NAME_LEN] = { };
+ [SK_MAX_THREAD_NAME_LEN+1] = { };
SK_AutoHandle handle =
SK_AutoHandle (INVALID_HANDLE_VALUE);
DWORD tls_idx = 0;
diff --git a/include/SpecialK/window.h b/include/SpecialK/window.h
index de8557f91..65692550d 100644
--- a/include/SpecialK/window.h
+++ b/include/SpecialK/window.h
@@ -398,7 +398,7 @@ struct sk_window_s {
bool active = true;
- struct {
+ struct cursor_s {
bool inside = true;
bool tracking = false;
bool can_track = false; // Able to use TrackMouseEvent?
@@ -455,6 +455,7 @@ struct sk_window_s {
LONG game_x = 640; // Resolution game thinks it's running at
LONG game_y = 480; // Resolution game thinks it's running at
+ BOOL size_move = FALSE;
RECT cursor_clip { LONG_MIN, LONG_MIN,
LONG_MAX, LONG_MAX };
@@ -475,6 +476,7 @@ struct sk_window_s {
bool needsCoordTransform (void);
void updateDims (void);
+ bool isCursorHovering (void);
SetWindowLongPtr_pfn SetWindowLongPtr = SK_SetWindowLongPtrW;
GetWindowLongPtr_pfn GetWindowLongPtr = SK_GetWindowLongPtrW;
diff --git a/include/imgui/imgui_user.inl b/include/imgui/imgui_user.inl
index e390459ff..9c2d1fc5c 100644
--- a/include/imgui/imgui_user.inl
+++ b/include/imgui/imgui_user.inl
@@ -383,14 +383,16 @@ SK_ImGui_ProcessRawInput ( _In_ HRAWINPUT hRawInput,
{
case RIM_TYPEMOUSE:
{
- if (SK_ImGui_WantMouseCapture ())
+ //// Block mouse input to the game while it's in the background
+ if ((! foreground) && config.input.mouse.disabled_to_game == 2)
{
filter = true;
}
- // Block mouse input to the game while it's in the background
- if (SK_WantBackgroundRender () && (! focus))
+ else if (SK_ImGui_WantMouseCapture ())
+ {
filter = true;
+ }
mouse = true;
@@ -415,62 +417,59 @@ SK_ImGui_ProcessRawInput ( _In_ HRAWINPUT hRawInput,
(((RAWINPUT *)pData)->data.keyboard.VKey & 0xFF);
- // Only filter keydown message, not key releases
- if (SK_ImGui_WantKeyboardCapture ())
+ if (VKey & 0xF8) // Valid Keys: 8 - 255
{
- if (VKey & 0xF8) // Valid Keys: 8 - 255
- filter = true;
+ keyboard = true;
}
-
- if (SK_ImGui_WantMouseCapture ())
+ // That's actually a mouse button...
+ else if (VKey < 7)
{
- // That's actually a mouse button...
- if (foreground && VKey < 7)
- {
- if (((RAWINPUT *)pData)->data.keyboard.Message == WM_KEYDOWN)
- filter = true;
-
- if (((RAWINPUT *)pData)->data.keyboard.Message == WM_SYSKEYDOWN)
- filter = true;
+ mouse = true;
- if (((RAWINPUT *)pData)->data.keyboard.Message == WM_KEYUP)
- filter = true;
-
- if (((RAWINPUT *)pData)->data.keyboard.Message == WM_SYSKEYUP)
- filter = true;
+ if (((! foreground) && config.input.mouse.disabled_to_game == 2) || SK_ImGui_WantMouseCapture ())
+ {
+ switch (((RAWINPUT *)pData)->data.keyboard.Message)
+ {
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+ filter = true;
+ break;
+ }
}
}
+ if (keyboard)
+ {
+ // Block keyboard input to the game while the console is active
+ if (pConsole->isVisible ())
+ filter = true;
- // Block keyboard input to the game while the console is active
- if (pConsole->isVisible () && (VKey & 0xFF) > 7)
- filter = true;
-
-
- // Block keyboard input to the game while it's in the background
- if (SK_WantBackgroundRender () && (! focus))
- filter = true;
-
-
- if (VKey & 0xF8) // Valid Keys: 8 - 255
- keyboard = true;
+ // Block keyboard input to the game while it does not have keyboard focus
+ else if ((! focus))
+ filter = true;
- if (keyboard && ( SK_ImGui_WantKeyboardCapture () ||
- (((RAWINPUT *)pData)->data.keyboard.Message == WM_CHAR ||
- ((RAWINPUT *)pData)->data.keyboard.Message == WM_SYSCHAR) ))
- filter = true;
+ else if ( SK_ImGui_WantKeyboardCapture () ||
+ (((RAWINPUT *)pData)->data.keyboard.Message == WM_CHAR ||
+ ((RAWINPUT *)pData)->data.keyboard.Message == WM_SYSCHAR) )
+ filter = true;
+ }
if ( (! already_processed)
&& uiCommand == RID_INPUT )
{
+ const auto type =
+ (keyboard ? sk_input_dev_type::Keyboard : sk_input_dev_type::Mouse);
+
if (! filter)
{
- SK_RAWINPUT_READ (sk_input_dev_type::Keyboard)
- SK_RAWINPUT_VIEW (sk_input_dev_type::Keyboard)
+ SK_RAWINPUT_READ (type)
+ SK_RAWINPUT_VIEW (type)
}
- else SK_RAWINPUT_HIDE (sk_input_dev_type::Keyboard)
+ else SK_RAWINPUT_HIDE (type)
}
} break;
@@ -514,23 +513,39 @@ SK_ImGui_ProcessRawInput ( _In_ HRAWINPUT hRawInput,
if (self)
{
if ( ((RAWINPUT *)pData)->data.mouse.ulButtons & RI_MOUSE_LEFT_BUTTON_DOWN )
- io.MouseDown [0] = true;
+ io.AddMouseButtonEvent (ImGuiKey_MouseLeft, true);
+ //if ( ((RAWINPUT *)pData)->data.mouse.ulButtons & RI_MOUSE_LEFT_BUTTON_UP )
+ // io.AddMouseButtonEvent (ImGuiKey_MouseLeft, false);
if ( ((RAWINPUT *)pData)->data.mouse.ulButtons & RI_MOUSE_RIGHT_BUTTON_DOWN )
- io.MouseDown [1] = true;
+ io.AddMouseButtonEvent (ImGuiKey_MouseRight, true);
+ //if ( ((RAWINPUT *)pData)->data.mouse.ulButtons & RI_MOUSE_RIGHT_BUTTON_UP )
+ // io.AddMouseButtonEvent (ImGuiKey_MouseRight, false);
if ( ((RAWINPUT *)pData)->data.mouse.ulButtons & RI_MOUSE_MIDDLE_BUTTON_DOWN )
- io.MouseDown [2] = true;
+ io.AddMouseButtonEvent (ImGuiKey_MouseMiddle, true);
+ //if ( ((RAWINPUT *)pData)->data.mouse.ulButtons & RI_MOUSE_MIDDLE_BUTTON_UP )
+ // io.AddMouseButtonEvent (ImGuiKey_MouseMiddle, false);
if ( ((RAWINPUT *)pData)->data.mouse.ulButtons & RI_MOUSE_BUTTON_4_DOWN )
- io.MouseDown [3] = true;
+ io.AddMouseButtonEvent (ImGuiKey_MouseX1, true);
+ //if ( ((RAWINPUT *)pData)->data.mouse.ulButtons & RI_MOUSE_BUTTON_4_UP )
+ // io.AddMouseButtonEvent (ImGuiKey_MouseX1, false);
if ( ((RAWINPUT *)pData)->data.mouse.ulButtons & RI_MOUSE_BUTTON_5_DOWN )
- io.MouseDown [4] = true;
- }
+ io.AddMouseButtonEvent (ImGuiKey_MouseX2, true);
+ //if ( ((RAWINPUT *)pData)->data.mouse.ulButtons & RI_MOUSE_BUTTON_5_UP )
+ // io.AddMouseButtonEvent (ImGuiKey_MouseX2, false);
- if ( ((RAWINPUT *)pData)->data.mouse.usButtonFlags == RI_MOUSE_WHEEL && self )
- {
- io.MouseWheel +=
- ((float)(short)((RAWINPUT *)pData)->data.mouse.usButtonData) /
- (float)WHEEL_DELTA;
+ if ( ((RAWINPUT *)pData)->data.mouse.usButtonFlags & RI_MOUSE_WHEEL )
+ {
+ io.AddMouseWheelEvent (0.0f,
+ ((float)(short)((RAWINPUT *)pData)->data.mouse.usButtonData) /
+ (float)WHEEL_DELTA);
+ }
+ if ( ((RAWINPUT *)pData)->data.mouse.usButtonFlags & RI_MOUSE_HWHEEL )
+ {
+ io.AddMouseWheelEvent (
+ ((float)(short)((RAWINPUT *)pData)->data.mouse.usButtonData) /
+ (float)WHEEL_DELTA, 0.0f);
+ }
}
}
} break;
@@ -1047,6 +1062,15 @@ ImGui_WndProcHandler ( HWND hWnd, UINT msg,
}
}
+ if (msg == WM_ENTERSIZEMOVE || msg == WM_EXITSIZEMOVE)
+ {
+ if (hWnd == game_window.hWnd)
+ {
+ game_window.size_move = (msg == WM_ENTERSIZEMOVE);
+ SK_Window_RepositionIfNeeded ();
+ }
+ }
+
if (msg == WM_SETCURSOR)
{
//SK_LOG0 ( (L"ImGui Witnessed WM_SETCURSOR"), L"Window Mgr" );
@@ -2276,57 +2300,63 @@ SK_ImGui_PollGamepad_EndFrame (XINPUT_STATE* pState)
}
}
+ static auto last_frame = SK_GetFramesDrawn ();
static bool last_haptic = false;
- if (bUseGamepad && SK_ImGui_Active () && config.input.gamepad.haptic_ui && nav_usable)
+ auto this_frame = SK_GetFramesDrawn ();
+
+ if (std::exchange (last_frame, this_frame) != this_frame)
{
- ImGuiContext& g =
- *GImGui;
+ if (bUseGamepad && SK_ImGui_Active () && config.input.gamepad.haptic_ui && nav_usable)
+ {
+ ImGuiContext& g =
+ *GImGui;
- static ImGuiID nav_id = 0;
+ static ImGuiID nav_id = 0;
- if (g.NavId != nav_id)
- {
- if (haptic_events.PulseNav.end > static_cast (SK::ControlPanel::current_time))
+ if (g.NavId != nav_id)
{
- haptic_events.PulseNav.end += haptic_events.PulseNav.duration;
- haptic_events.PulseNav.start += haptic_events.PulseNav.duration;
+ if (haptic_events.PulseNav.end > static_cast (SK::ControlPanel::current_time))
+ {
+ haptic_events.PulseNav.end += haptic_events.PulseNav.duration;
+ haptic_events.PulseNav.start += haptic_events.PulseNav.duration;
+ }
+
+ else
+ {
+ haptic_events.PulseNav.start = static_cast (SK::ControlPanel::current_time);
+ haptic_events.PulseNav.end = haptic_events.PulseNav.start +
+ haptic_events.PulseNav.duration;
+ }
}
- else
+ if (g.ActiveIdIsJustActivated)
{
- haptic_events.PulseNav.start = static_cast (SK::ControlPanel::current_time);
- haptic_events.PulseNav.end = haptic_events.PulseNav.start +
- haptic_events.PulseNav.duration;
+ haptic_events.PulseButton.start = static_cast (SK::ControlPanel::current_time);
+ haptic_events.PulseButton.end = haptic_events.PulseButton.start +
+ haptic_events.PulseButton.duration;
}
- }
- if (g.ActiveIdIsJustActivated)
- {
- haptic_events.PulseButton.start = static_cast (SK::ControlPanel::current_time);
- haptic_events.PulseButton.end = haptic_events.PulseButton.start +
- haptic_events.PulseButton.duration;
- }
-
- SK_XInput_PulseController ( config.input.gamepad.xinput.ui_slot,
- haptic_events.PulseTitle.run () +
- haptic_events.PulseButton.run () +
- std::min (0.4f, haptic_events.PulseNav.run ()),
+ SK_XInput_PulseController ( config.input.gamepad.xinput.ui_slot,
haptic_events.PulseTitle.run () +
haptic_events.PulseButton.run () +
- std::min (0.4f, haptic_events.PulseNav.run ()) );
+ std::min (0.4f, haptic_events.PulseNav.run ()),
+ haptic_events.PulseTitle.run () +
+ haptic_events.PulseButton.run () +
+ std::min (0.4f, haptic_events.PulseNav.run ()) );
- nav_id = g.NavId;
+ nav_id = g.NavId;
- last_haptic = true;
- }
+ last_haptic = true;
+ }
- else if (std::exchange (last_haptic, false))
- {
- // Clear haptics on the first frame after they're no longer relevant
- SK_XInput_PulseController (
- config.input.gamepad.xinput.ui_slot, 0.0f, 0.0f
- );
+ else if (std::exchange (last_haptic, false))
+ {
+ // Clear haptics on the first frame after they're no longer relevant
+ SK_XInput_PulseController (
+ config.input.gamepad.xinput.ui_slot, 0.0f, 0.0f
+ );
+ }
}
if (bUseGamepad)
@@ -2895,11 +2925,13 @@ SK_ImGui_FallbackTrackMouseEvent (POINT& cursor_pos)
else
{
- last.hWndTop = game_window.hWnd;
- last.cursor_pos = cursor_pos;
+ last.hWndTop = game_window.hWnd;
}
+
+ if (last.hWndTop == game_window.hWnd)
+ last.cursor_pos = cursor_pos;
}
-
+
hWndTop =
last.hWndTop;
@@ -3358,8 +3390,18 @@ SK_ImGui_User_NewFrame (void)
hWndFocus : hWndGame != hWndFocus ?
hWndGame : nullptr;
+ static POINT last_cursor_pos;
+ static bool last_fg_or_top;
+
bool bMouseIsForegroundOrTop = ( hWndForeground == hWndMouse0 ||
hWndForeground == hWndMouse1 );
+
+ if (std::exchange(last_cursor_pos.x,cursor_pos.x) == cursor_pos.x&&
+ std::exchange(last_cursor_pos.y,cursor_pos.y) == cursor_pos.y)
+ {
+ bMouseIsForegroundOrTop = last_fg_or_top;
+ }
+
if (! bMouseIsForegroundOrTop)
{
const HWND hWndAtCursor =
@@ -3370,6 +3412,8 @@ SK_ImGui_User_NewFrame (void)
hWndAtCursor == hWndMouse1 );
}
+ last_fg_or_top = bMouseIsForegroundOrTop;
+
if (bMouseIsForegroundOrTop)
{
SK_ImGui_Cursor.ScreenToLocal (&cursor_pos);
@@ -3377,8 +3421,8 @@ SK_ImGui_User_NewFrame (void)
if ( cursor_pos.x != last_x ||
cursor_pos.y != last_y )
{
- if ( abs (SK_ImGui_Cursor.pos.x - cursor_pos.x) > 3 ||
- abs (SK_ImGui_Cursor.pos.y - cursor_pos.y) > 3 )
+ if ( abs (SK_ImGui_Cursor.pos.x - cursor_pos.x) > 0 ||
+ abs (SK_ImGui_Cursor.pos.y - cursor_pos.y) > 0 )
{
SK_ImGui_Cursor.pos = cursor_pos;
}
@@ -3391,6 +3435,11 @@ SK_ImGui_User_NewFrame (void)
io.MousePos.y = static_cast (SK_ImGui_Cursor.pos.y);
}
}
+
+ else
+ {
+ game_window.mouse.inside = false;
+ }
}
// Cursor stops being treated as idle when it's not in the game window :)
@@ -3445,8 +3494,8 @@ SK_ImGui_User_NewFrame (void)
// regular mouse capture includes swallowing input for "Disabled to Game".
bool bWantMouseCaptureForUI = SK_ImGui_WantMouseCaptureEx (0x0) && (anything_hovered || ImGui::IsPopupOpen (nullptr, ImGuiPopupFlags_AnyPopupId | ImGuiPopupFlags_AnyPopupLevel));
- if ( abs (last_x - SK_ImGui_Cursor.pos.x) > 3 ||
- abs (last_y - SK_ImGui_Cursor.pos.y) > 3 ||
+ if ( abs (last_x - SK_ImGui_Cursor.pos.x) > 0 ||
+ abs (last_y - SK_ImGui_Cursor.pos.y) > 0 ||
bWantMouseCaptureForUI )
{
SK_ImGui_Cursor.last_move = SK::ControlPanel::current_time;
@@ -3526,7 +3575,7 @@ SK_ImGui_User_NewFrame (void)
if (! SK_ImGui_Cursor.idle)
{
- if (capture_mouse && anything_hovered)
+ if (capture_mouse && anything_hovered && (last_x != SK_ImGui_Cursor.pos.x || last_y != SK_ImGui_Cursor.pos.y))
{
SK_SendMsgSetCursor (ImGui_DesiredCursor ());
}
@@ -3678,6 +3727,9 @@ SK_ImGui_User_NewFrame (void)
SK_ImGui_WantMouseCapture (true);
SK_ImGui_WantGamepadCapture (true);
SK_IsGameWindowActive (true);
+
+ SK_GetCursorPos (&cursor_pos);
+ SK_ImGui_Cursor.last_screen_pos = cursor_pos;
}
bool
diff --git a/src/SpecialK.cpp b/src/SpecialK.cpp
index d7f1e9271..8b8f0d041 100644
--- a/src/SpecialK.cpp
+++ b/src/SpecialK.cpp
@@ -592,6 +592,7 @@ DllMain ( HMODULE hModule,
if (DLL_ROLE::INVALID == SK_GetDLLRole ()) return EarlyOut (TRUE);
if (! SK_Attach (SK_GetDLLRole ())) return EarlyOut (TRUE);
+ SK_MinHook_Init ();
CreateTeardownEvent ();
InterlockedIncrementRelease (
diff --git a/src/config.cpp b/src/config.cpp
index e2ab79049..acbc09593 100644
--- a/src/config.cpp
+++ b/src/config.cpp
@@ -269,7 +269,8 @@ SK_GetCurrentGameID (void)
{ L"Dragon Age The Veilguard.exe", SK_GAME_ID::DragonAgeTheVeilguard },
{ L"tomb123.exe", SK_GAME_ID::TombRaider123Remastered },
{ L"Stalker2-WinGDK-Shipping.exe", SK_GAME_ID::Stalker2 },
- { L"Stalker2-Win64-Shipping.exe", SK_GAME_ID::Stalker2 }
+ { L"Stalker2-Win64-Shipping.exe", SK_GAME_ID::Stalker2 },
+ { L"vlc.exe", SK_GAME_ID::vlc }
};
first_check = false;
@@ -1054,6 +1055,7 @@ struct {
sk::ParameterBool* hook_xinput = nullptr;
sk::ParameterBool* hook_scepad = nullptr;
sk::ParameterBool* hook_raw_input = nullptr;
+ sk::ParameterBool* hook_game_input = nullptr;
sk::ParameterBool* hook_windows_gaming = nullptr;
sk::ParameterBool* hook_winmm = nullptr;
sk::ParameterBool* allow_steam_winmm = nullptr;
@@ -1112,6 +1114,8 @@ struct {
sk::ParameterBool* bt_input_only = nullptr;
sk::ParameterFloat* low_battery_warning = nullptr;
sk::ParameterBool* blocks_screensaver = nullptr;
+ sk::ParameterFloat* left_impulse_strength = nullptr;
+ sk::ParameterFloat* right_impulse_strength = nullptr;
} gamepad;
} input;
@@ -1692,10 +1696,13 @@ auto DeclKeybind =
ConfigEntry (input.gamepad.hook_dinput8, L"Install hooks for DirectInput 8", dll_ini, L"Input.Gamepad", L"EnableDirectInput8"),
ConfigEntry (input.gamepad.hook_dinput7, L"Install hooks for DirectInput 7", dll_ini, L"Input.Gamepad", L"EnableDirectInput7"),
ConfigEntry (input.gamepad.hook_hid, L"Install hooks for HID", dll_ini, L"Input.Gamepad", L"EnableHID"),
+ ConfigEntry (input.gamepad.hook_game_input, L"Install hooks for GameInput", dll_ini, L"Input.Gamepad", L"HookGameInput"),
ConfigEntry (input.gamepad.hook_winmm, L"Install hooks for joyGet* APIs", dll_ini, L"Input.Gamepad", L"HookWinMM"),
ConfigEntry (input.gamepad.allow_steam_winmm, L"Use Steam-manipulated version of WinMM input", dll_ini, L"Input.Gamepad", L"AllowSteamWinMM"),
ConfigEntry (input.gamepad.disable_rumble, L"Disable Rumble from ALL SOURCES (across all APIs)", dll_ini, L"Input.Gamepad", L"DisableRumble"),
ConfigEntry (input.gamepad.blocks_screensaver, L"Gamepad activity will block screensaver activation", dll_ini, L"Input.Gamepad", L"BlocksScreenSaver"),
+ ConfigEntry (input.gamepad.right_impulse_strength, L"Scale the Right Impulse Triggers in GameInput games", dll_ini, L"Input.Gamepad", L"RightImpulseStrength"),
+ ConfigEntry (input.gamepad.left_impulse_strength, L"Scale the Right Impulse Triggers in GameInput games", dll_ini, L"Input.Gamepad", L"LeftImpulseStrength"),
ConfigEntry (input.gamepad.bt_input_only, L"Prevent Bluetooth Output (PlayStation DirectInput compat.)",dll_ini, L"Input.Gamepad", L"BluetoothInputOnly"),
ConfigEntry (input.gamepad.hid.max_allowed_buffers, L"Maximum allowed HID buffers; 32=NS default, 8=SK default,"
L" this will lower latency at the expense of possibly missed"
@@ -3693,15 +3700,17 @@ auto DeclKeybind =
// Game requires special sRGB treatment.
case SK_GAME_ID::TombRaider123Remastered:
config.render.dxgi.srgb_behavior = 0;
+ config.render.gl.prefer_10bpc = false;
break;
case SK_GAME_ID::Stalker2:
// Stupid game requires Fullscreen Exclusive (in D3D12) for HDR
config.render.dxgi.fake_fullscreen_mode = true;
+ config.input.gamepad.xinput.emulate = true;
+ // GameInput has poor support for non-Xbox controllers...
break;
case SK_GAME_ID::Metaphor:
- config.threads.enable_dynamic_spinlocks = true;
config.compatibility.init_on_separate_thread = false;
config.priority.perf_cores_only = true;
config.window.background_render = true;
@@ -3712,9 +3721,8 @@ auto DeclKeybind =
config.input.gamepad.xinput.emulate = true; // XInput-only
config.render.hdr.remaster_8bpc_as_unorm = true;
config.render.hdr.remaster_subnative_as_unorm = true;
- config.input.gamepad.dinput.block_enum_devices = true; // Avoid perf issues
config.textures.cache.allow_staging = false;
- config.render.dxgi.deferred_isolation = true; // Needed for correct texture caching on staging uploads
+ config.render.dxgi.deferred_isolation = false; // Needed for correct texture caching on staging uploads
config.render.d3d12.force_anisotropic = true;
config.render.d3d12.force_lod_bias = 0.0f;
@@ -4633,6 +4641,7 @@ auto DeclKeybind =
// Hidden INI values; they're loaded, but never written
input.gamepad.hook_winmm->load (config.input.gamepad.hook_winmm);
+ input.gamepad.hook_game_input->load (config.input.gamepad.hook_game_input);
input.gamepad.allow_steam_winmm->load (config.input.gamepad.allow_steam_winmm);
input.gamepad.hook_windows_gaming->load(config.input.gamepad.hook_windows_gaming);
input.gamepad.hook_raw_input->load (config.input.gamepad.hook_raw_input);
@@ -4665,6 +4674,8 @@ auto DeclKeybind =
input.gamepad.bt_input_only->load (config.input.gamepad.bt_input_only);
input.gamepad.disable_rumble->load (config.input.gamepad.disable_rumble);
input.gamepad.blocks_screensaver->load (config.input.gamepad.blocks_screensaver);
+ input.gamepad.left_impulse_strength->load (config.input.gamepad.impulse_strength_l);
+ input.gamepad.right_impulse_strength->load (config.input.gamepad.impulse_strength_r);
input.gamepad.xinput.hook_setstate->load (config.input.gamepad.xinput.hook_setstate);
input.gamepad.xinput.auto_slot_assign->load (config.input.gamepad.xinput.auto_slot_assign);
input.gamepad.xinput.blackout_api->load (config.input.gamepad.xinput.blackout_api);
@@ -5492,8 +5503,10 @@ auto DeclKeybind =
return_to_skif->load (config.system.return_to_skif);
auto_load_asi_files->load (config.system.auto_load_asi_files);
- if (version->load (config.system.version))
+ SK_RunOnce (
+ if (version->load (config.system.version))
config.system.first_run = false;
+ );
skif_autostop_behavior->load (config.skif.auto_stop_behavior);
@@ -6161,6 +6174,8 @@ SK_SaveConfig ( std::wstring name,
input.gamepad.bt_input_only->store (config.input.gamepad.bt_input_only);
input.gamepad.disable_rumble->store (config.input.gamepad.disable_rumble);
input.gamepad.blocks_screensaver->store (config.input.gamepad.blocks_screensaver);
+ input.gamepad.left_impulse_strength->store (config.input.gamepad.impulse_strength_l);
+ input.gamepad.right_impulse_strength->store (config.input.gamepad.impulse_strength_r);
input.gamepad.xinput.hook_setstate->store (config.input.gamepad.xinput.hook_setstate);
input.gamepad.xinput.auto_slot_assign->store (config.input.gamepad.xinput.auto_slot_assign);
input.gamepad.xinput.blackout_api->store (config.input.gamepad.xinput.blackout_api);
diff --git a/src/control_panel.cpp b/src/control_panel.cpp
index de94f7027..ed003161d 100644
--- a/src/control_panel.cpp
+++ b/src/control_panel.cpp
@@ -867,61 +867,12 @@ SK_ImGui_ControlPanelTitle (void)
void
SK_ImGui_AdjustCursor (void)
{
-#if 0
- static SK_AutoHandle hAdjustEvent (
- SK_CreateEvent (nullptr, TRUE, FALSE, nullptr)
- );
-
- SetEvent (hAdjustEvent.m_h);
-
- static HANDLE
- hThread = SK_Thread_CreateEx (
- [](LPVOID pUser)-> DWORD
- {
- HANDLE hSignals [] = {
- __SK_DLL_TeardownEvent,
- (HANDLE)pUser
- };
-
- DWORD dwWaitStatus =
- WAIT_ABANDONED;
-
- while (dwWaitStatus != WAIT_OBJECT_0)
- {
- dwWaitStatus =
- WaitForMultipleObjects ( 2, hSignals, FALSE, INFINITE );
-
- if (dwWaitStatus == (WAIT_OBJECT_0 + 1))
- {
- ResetEvent (hSignals [1]);
-
- //SK_ClipCursor (nullptr);
- // SK_AdjustWindow (); // Restore game's clip cursor behavior
-
- SK_Window_RepositionIfNeeded ();
-
- //extern void SK_AdjustClipRect (void);
- // SK_AdjustClipRect ();
- }
- };
-
- hAdjustEvent.Close ();
-
- SK_Thread_CloseSelf ();
-
- return 0;
- },
- L"[SK] Cursor Adjustment Thread",
- (LPVOID)hAdjustEvent.m_h
- );
-#else
// This really doesn't need to be done in a second thread, it's already
// got a thread that waits for signaled work.
SK_Window_RepositionIfNeeded ();
// The logic used to be different, but now RepositionIfNeeded also handles
// any necessary changes to the cursor clipping rectangle.
-#endif
}
bool reset_frame_history = true;
@@ -2221,9 +2172,11 @@ SK_Display_ResolutionSelectUI (bool bMarkDirty)
{
// Trigger the game to resize the SwapChain so we can change its aspect ratio
//
+ if (config.compatibility.allow_fake_size)
PostMessage ( game_window.hWnd, WM_SIZE, SIZE_RESTORED,
MAKELPARAM (config.window.res.override.x, config.window.res.override.y)
);
+ if (config.compatibility.allow_fake_displaychange)
PostMessage ( game_window.hWnd, WM_DISPLAYCHANGE, 32,
MAKELPARAM (config.window.res.override.x, config.window.res.override.y)
);
@@ -2347,11 +2300,13 @@ DisplayModeMenu (bool windowed)
// Trigger the game to resize the SwapChain so we can change its format and colorspace
//
+ if (config.compatibility.allow_fake_size)
PostMessage ( game_window.hWnd, WM_SIZE, SIZE_RESTORED,
MAKELPARAM (game_window.actual.client.right -
game_window.actual.client.left, game_window.actual.client.bottom -
game_window.actual.client.top )
);
+ if (config.compatibility.allow_fake_displaychange)
PostMessage ( game_window.hWnd, WM_DISPLAYCHANGE, 32,
MAKELPARAM (game_window.actual.client.right -
game_window.actual.client.left, game_window.actual.client.bottom -
@@ -7292,7 +7247,7 @@ LRESULT
CALLBACK
SK_ImGui_MouseProc (int code, WPARAM wParam, LPARAM lParam)
{
- if (code < 0 || (! SK_IsGameWindowActive ())) // We saw nothing (!!)
+ if (code < 0 || GImGui == nullptr || GImGui->CurrentWindow == nullptr) // We saw nothing (!!)
return CallNextHookEx (0, code, wParam, lParam);
auto& io =
@@ -7330,12 +7285,12 @@ SK_ImGui_MouseProc (int code, WPARAM wParam, LPARAM lParam)
case WM_LBUTTONDBLCLK:
if (! bPassthrough)
{
- io.MouseDown [0] = true;
+ io.AddMouseButtonEvent (ImGuiKey_MouseLeft, true);
// Only capture mouse clicks when the window is in the foreground, failure to let
// left-clicks passthrough would prevent activating the game window.
- if ( SK_ImGui_WantMouseCapture () && game_window.active &&
- SK_GetForegroundWindow () == game_window.hWnd )
+ if ( game_window.active && SK_ImGui_WantMouseButtonCapture () &&
+ game_window.hWnd == SK_GetForegroundWindow () )
return 1;
}
break;
@@ -7343,7 +7298,9 @@ SK_ImGui_MouseProc (int code, WPARAM wParam, LPARAM lParam)
case WM_LBUTTONUP:
if (! bPassthrough)
{
- if (SK_ImGui_WantMouseCapture ())
+ //io.AddMouseButtonEvent (ImGuiKey_MouseLeft, false);
+
+ if (SK_ImGui_WantMouseButtonCapture ())
return 1;
}
break;
@@ -7352,9 +7309,9 @@ SK_ImGui_MouseProc (int code, WPARAM wParam, LPARAM lParam)
case WM_RBUTTONDBLCLK:
if (! bPassthrough)
{
- io.MouseDown [1] = true;
+ io.AddMouseButtonEvent (ImGuiKey_MouseRight, true);
- if (SK_ImGui_WantMouseCapture ())
+ if (SK_ImGui_WantMouseButtonCapture ())
return 1;
}
break;
@@ -7362,7 +7319,9 @@ SK_ImGui_MouseProc (int code, WPARAM wParam, LPARAM lParam)
case WM_RBUTTONUP:
if (! bPassthrough)
{
- if (SK_ImGui_WantMouseCapture ())
+ //io.AddMouseButtonEvent (ImGuiKey_MouseRight, false);
+
+ if (SK_ImGui_WantMouseButtonCapture ())
return 1;
}
break;
@@ -7371,9 +7330,9 @@ SK_ImGui_MouseProc (int code, WPARAM wParam, LPARAM lParam)
case WM_MBUTTONDBLCLK:
if (! bPassthrough)
{
- io.MouseDown [2] = true;
+ io.AddMouseButtonEvent (ImGuiKey_MouseMiddle, true);
- if (SK_ImGui_WantMouseCapture ())
+ if (SK_ImGui_WantMouseButtonCapture ())
return 1;
}
break;
@@ -7381,7 +7340,9 @@ SK_ImGui_MouseProc (int code, WPARAM wParam, LPARAM lParam)
case WM_MBUTTONUP:
if (! bPassthrough)
{
- if (SK_ImGui_WantMouseCapture ())
+ //io.AddMouseButtonEvent (ImGuiKey_MouseMiddle, false);
+
+ if (SK_ImGui_WantMouseButtonCapture ())
return 1;
}
break;
@@ -7393,17 +7354,27 @@ SK_ImGui_MouseProc (int code, WPARAM wParam, LPARAM lParam)
MOUSEHOOKSTRUCTEX* mhsx =
(MOUSEHOOKSTRUCTEX*)lParam;
- io.MouseDown [3] |= ((HIWORD (mhsx->mouseData)) == XBUTTON1);
- io.MouseDown [4] |= ((HIWORD (mhsx->mouseData)) == XBUTTON2);
+ if (((HIWORD (mhsx->mouseData)) == XBUTTON1))
+ io.AddMouseButtonEvent (ImGuiKey_MouseX1, true);
+ if (((HIWORD (mhsx->mouseData)) == XBUTTON2))
+ io.AddMouseButtonEvent (ImGuiKey_MouseX2, true);
- if (SK_ImGui_WantMouseCapture ())
+ if (SK_ImGui_WantMouseButtonCapture ())
return 1;
} break;
case WM_XBUTTONUP:
if (! bPassthrough)
{
- if (SK_ImGui_WantMouseCapture ())
+ // MOUSEHOOKSTRUCTEX* mhsx =
+ //(MOUSEHOOKSTRUCTEX*)lParam;
+
+ //if (((HIWORD (mhsx->mouseData)) == XBUTTON1))
+ // io.AddMouseButtonEvent (ImGuiKey_MouseX1, false);
+ //if (((HIWORD (mhsx->mouseData)) == XBUTTON2))
+ // io.AddMouseButtonEvent (ImGuiKey_MouseX2, false);
+
+ if (SK_ImGui_WantMouseButtonCapture ())
return 1;
} break;
@@ -7416,18 +7387,18 @@ SK_ImGui_MouseProc (int code, WPARAM wParam, LPARAM lParam)
if (wParam == WM_MOUSEWHEEL)
{
- io.MouseWheel +=
+ io.AddMouseWheelEvent (0.0f,
(float)GET_WHEEL_DELTA_WPARAM (mhsx->mouseData) /
- (float)WHEEL_DELTA;
+ (float)WHEEL_DELTA);
}
else {
- io.MouseWheelH +=
+ io.AddMouseWheelEvent (
(float)GET_WHEEL_DELTA_WPARAM (mhsx->mouseData) /
- (float)WHEEL_DELTA;
+ (float)WHEEL_DELTA, 0.0f);
}
- if (SK_ImGui_WantMouseCapture ())
+ if (SK_ImGui_WantMouseButtonCapture ())
return 1;
} break;
@@ -7439,14 +7410,20 @@ SK_ImGui_MouseProc (int code, WPARAM wParam, LPARAM lParam)
{
// Install a mouse tracker to get WM_MOUSELEAVE
if (! (game_window.mouse.tracking && game_window.mouse.inside))
- SK_ImGui_UpdateMouseTracker ();
+ {
+ if (wParam != WM_NCMOUSEMOVE)
+ {
+ SK_ImGui_UpdateMouseTracker ();
+ }
+ }
// Returning 1 here breaks WM_SETCURSOR behavior;
//
// Hopefully we have a subclassed window / window proc hook and
// can remove mouse motion that way, because returning 1 is
// not an option.
- return 0;
+ if (wParam != WM_NCMOUSEMOVE)
+ return 0;
}
}
@@ -8855,8 +8832,6 @@ SK_ImGui_Toggle (void)
{
SK_ImGui_Cursor.last_move = current_time;
- //SK_ImGui_Cursor.showImGuiCursor ();
-
if (SK::ControlPanel::Platform::WarnIfUnsupported ())
config.imgui.show_eula = true;
else
@@ -8884,76 +8859,79 @@ SK_ImGui_Toggle (void)
if (SK::SteamAPI::AppID () != 0 && SK_ImGui_Visible)
SK::SteamAPI::UpdateNumPlayers ();
- static SK_AutoHandle hMoveCursor (
- SK_CreateEvent (nullptr, FALSE, FALSE, nullptr)
- );
-
- SK_RunOnce (
- SK_Thread_CreateEx ([](LPVOID) -> DWORD
- {
- SK_Thread_SetCurrentPriority (THREAD_PRIORITY_IDLE);
-
- HANDLE hEvents [] = {
- __SK_DLL_TeardownEvent,
- hMoveCursor.m_h
- };
+ if (config.input.ui.center_cursor)
+ {
+ static SK_AutoHandle hMoveCursor (
+ SK_CreateEvent (nullptr, FALSE, FALSE, nullptr)
+ );
- while (true)
+ SK_RunOnce (
+ SK_Thread_CreateEx ([](LPVOID) -> DWORD
{
- DWORD dwWait =
- WaitForMultipleObjectsEx (2, hEvents, FALSE, INFINITE, FALSE);
+ SK_Thread_SetCurrentPriority (THREAD_PRIORITY_IDLE);
- if (dwWait == WAIT_OBJECT_0)
- break;
+ HANDLE hEvents [] = {
+ __SK_DLL_TeardownEvent,
+ hMoveCursor.m_h
+ };
- // Stupid hack to make sure the mouse cursor swaps between SK's and
- // the game's in response to opening/closing the control panel
- if (dwWait == WAIT_OBJECT_0 + 1)
+ while (true)
{
- auto frames_drawn =
- SK_GetFramesDrawn ();
+ DWORD dwWait =
+ WaitForMultipleObjectsEx (2, hEvents, FALSE, INFINITE, FALSE);
- while (frames_drawn > SK_GetFramesDrawn () - 2)
- SwitchToThread ();
+ if (dwWait == WAIT_OBJECT_0)
+ break;
- POINT ptCursor;
- if (SK_GetCursorPos (&ptCursor) && SK_GetForegroundWindow () == game_window.hWnd)
+ // Stupid hack to make sure the mouse cursor swaps between SK's and
+ // the game's in response to opening/closing the control panel
+ if (dwWait == WAIT_OBJECT_0 + 1)
{
- GetWindowRect (game_window.hWnd,
- &game_window.actual.window);
- if (PtInRect (&game_window.actual.window, ptCursor))
+ auto frames_drawn =
+ SK_GetFramesDrawn ();
+
+ while (frames_drawn > SK_GetFramesDrawn () - 2)
+ SwitchToThread ();
+
+ POINT ptCursor;
+ if (SK_GetCursorPos (&ptCursor) && SK_GetForegroundWindow () == game_window.hWnd)
{
- SK_SetCursorPos (ptCursor.x + 1, ptCursor.y - 1);
- Send_WM_SETCURSOR ();
+ GetWindowRect (game_window.hWnd,
+ &game_window.actual.window);
+ if (PtInRect (&game_window.actual.window, ptCursor))
+ {
+ SK_SetCursorPos (ptCursor.x + 1, ptCursor.y - 1);
+ Send_WM_SETCURSOR ();
- frames_drawn =
- SK_GetFramesDrawn ();
+ frames_drawn =
+ SK_GetFramesDrawn ();
- while (frames_drawn > SK_GetFramesDrawn () - 2)
- SwitchToThread ();
+ while (frames_drawn > SK_GetFramesDrawn () - 2)
+ SwitchToThread ();
- SK_GetCursorPos (&ptCursor);
- SK_SetCursorPos ( ptCursor.x - 1, ptCursor.y + 1);
- Send_WM_SETCURSOR ( );
+ SK_GetCursorPos (&ptCursor);
+ SK_SetCursorPos ( ptCursor.x - 1, ptCursor.y + 1);
+ Send_WM_SETCURSOR ( );
+ }
}
}
}
- }
- SK_Thread_CloseSelf ();
+ SK_Thread_CloseSelf ();
- return 0;
- }, L"[SK] Rodeo Mouse Wrangler");
- );
+ return 0;
+ }, L"[SK] Rodeo Mouse Wrangler");
+ );
+
+ // Move the cursor a couple of times to change the loaded image
+ if (SK_ImGui_WantHWCursor ())
+ SetEvent (hMoveCursor);
+ }
// Save config on control panel close, not open
if (! SK_ImGui_Visible)
config.utility.save_async ();
- // Move the cursor a couple of times to change the loaded image
- if (SK_ImGui_WantHWCursor ())
- SetEvent (hMoveCursor);
-
// Immediately stop capturing keyboard/mouse events,
// this is the only way to preserve cursor visibility
diff --git a/src/control_panel/cfg_d3d11.cpp b/src/control_panel/cfg_d3d11.cpp
index a64ccf518..45f1ca52e 100644
--- a/src/control_panel/cfg_d3d11.cpp
+++ b/src/control_panel/cfg_d3d11.cpp
@@ -637,10 +637,11 @@ SK::ControlPanel::D3D11::Draw (void)
ImGui::PopStyleColor (3);
}
+#ifdef D3D12_STATE_TRACK
+#pragma region "Advanced"
auto currentFrame =
SK_GetFramesDrawn ();
-#pragma region "Advanced"
if ( (config.render.dxgi.allow_d3d12_footguns || config.reshade.is_addon) &&
ImGui::TreeNode ("Recently Used Shaders")
)
@@ -841,6 +842,7 @@ SK::ControlPanel::D3D11::Draw (void)
ImGui::EndGroup ();
ImGui::TreePop ();
}
+#endif
#pragma endregion
ImGui::PushStyleColor (ImGuiCol_Header, ImVec4 (0.90f, 0.68f, 0.02f, 0.45f));
ImGui::PushStyleColor (ImGuiCol_HeaderHovered, ImVec4 (0.90f, 0.72f, 0.07f, 0.80f));
diff --git a/src/control_panel/cfg_input.cpp b/src/control_panel/cfg_input.cpp
index 41beb9ec8..8263df860 100644
--- a/src/control_panel/cfg_input.cpp
+++ b/src/control_panel/cfg_input.cpp
@@ -108,6 +108,7 @@ static DWORD last_di8 = 0;
static DWORD last_steam = 0;
static DWORD last_messagebus = 0;
static DWORD last_rawinput = 0;
+static DWORD last_gameinput = 0;
static DWORD last_winhook = 0;
static DWORD last_winmm = 0;
static DWORD last_win32 = 0;
@@ -121,6 +122,7 @@ static DWORD hide_di8 = 0;
static DWORD hide_steam = 0;
static DWORD hide_messagebus = 0;
static DWORD hide_rawinput = 0;
+static DWORD hide_gameinput = 0;
static DWORD hide_winhook = 0;
static DWORD hide_winmm = 0;
static DWORD hide_win32 = 0;
@@ -198,13 +200,14 @@ SK::ControlPanel::Input::Draw (void)
struct { ULONG kbd_reads, mouse_reads; } winhook { };
- struct { ULONG kbd_reads, mouse_reads, gamepad_reads; } di7 { };
- struct { ULONG kbd_reads, mouse_reads, gamepad_reads; } di8 { };
- struct { ULONG kbd_reads, mouse_reads, gamepad_reads; } hid { };
- struct { ULONG kbd_reads, mouse_reads, gamepad_reads; } raw_input { };
+ struct { ULONG kbd_reads, mouse_reads, gamepad_reads; } di7 { };
+ struct { ULONG kbd_reads, mouse_reads, gamepad_reads; } di8 { };
+ struct { ULONG kbd_reads, mouse_reads, gamepad_reads; } hid { };
+ struct { ULONG kbd_reads, mouse_reads, gamepad_reads; } raw_input { };
+ struct { ULONG kbd_reads, mouse_reads, gamepad_reads; } game_input { };
struct { ULONG cursorpos, keystate,
- keyboardstate, asynckeystate; } win32 { };
+ keyboardstate, asynckeystate; } win32 { };
xinput.reads [0] = SK_XInput_Backend->reads [0];
xinput.reads [1] = SK_XInput_Backend->reads [1];
@@ -248,6 +251,10 @@ SK::ControlPanel::Input::Draw (void)
raw_input.mouse_reads = SK_RawInput_Backend->reads [0];
raw_input.gamepad_reads = SK_RawInput_Backend->reads [2];
+ game_input.kbd_reads = SK_GameInput_Backend->reads [1];
+ game_input.mouse_reads = SK_GameInput_Backend->reads [0];
+ game_input.gamepad_reads= SK_GameInput_Backend->reads [2];
+
win32.asynckeystate = SK_Win32_Backend->reads [3];
win32.keyboardstate = SK_Win32_Backend->reads [2];
win32.keystate = SK_Win32_Backend->reads [1];
@@ -278,6 +285,7 @@ SK::ControlPanel::Input::Draw (void)
UPDATE_BACKEND_TIMES (DI7, di7, nextFrame);
UPDATE_BACKEND_TIMES (DI8, di8, nextFrame);
UPDATE_BACKEND_TIMES (RawInput, rawinput, nextFrame);
+ UPDATE_BACKEND_TIMES (GameInput, gameinput, nextFrame);
UPDATE_BACKEND_TIMES (WinHook, winhook, nextFrame);
UPDATE_BACKEND_TIMES (Win32, win32, nextFrameWin32);
UPDATE_BACKEND_TIMES (WinMM, winmm, nextFrame);
@@ -303,31 +311,22 @@ SK::ControlPanel::Input::Draw (void)
//bool is_emulating_xinput =
// steam_ctx.Input ()->GetControllerForGamepadIndex (0) != 0;
- if (ImGui::IsItemHovered ( ))
+ if (ImGui::BeginItemTooltip ())
{
- ImGui::BeginTooltip ( );
- {
- ImGui::BeginGroup ( );
- if (steam.active [0]) ImGui::TextUnformatted ("Xbox");
- if (steam.active [1]) ImGui::TextUnformatted ("PlayStation");
- if (steam.active [2]) ImGui::TextUnformatted ("Generic");
- if (steam.active [3]) ImGui::TextUnformatted ("Nintendo");
- ImGui::EndGroup ( );
- ImGui::SameLine ( );
- ImGui::BeginGroup ( );
- if (steam.active [0]) ImGui::Text ("%lu", steam.reads [0]);
- if (steam.active [1]) ImGui::Text ("%lu", steam.reads [1]);
- if (steam.active [2]) ImGui::Text ("%lu", steam.reads [2]);
- if (steam.active [3]) ImGui::Text ("%lu", steam.reads [3]);
- ImGui::EndGroup ( );
-
- //if (is_emulating_xinput)
- //{
- // ImGui::Separator ();
- // ImGui::BulletText ("Click to configure (XInput Emulation)");
- //}
- }
- ImGui::EndTooltip ( );
+ ImGui::BeginGroup ( );
+ if (steam.active [0]) ImGui::TextUnformatted ("Xbox");
+ if (steam.active [1]) ImGui::TextUnformatted ("PlayStation");
+ if (steam.active [2]) ImGui::TextUnformatted ("Generic");
+ if (steam.active [3]) ImGui::TextUnformatted ("Nintendo");
+ ImGui::EndGroup ( );
+ ImGui::SameLine ( );
+ ImGui::BeginGroup ( );
+ if (steam.active [0]) ImGui::Text ("%lu", steam.reads [0]);
+ if (steam.active [1]) ImGui::Text ("%lu", steam.reads [1]);
+ if (steam.active [2]) ImGui::Text ("%lu", steam.reads [2]);
+ if (steam.active [3]) ImGui::Text ("%lu", steam.reads [3]);
+ ImGui::EndGroup ( );
+ ImGui::EndTooltip ( );
}
//if (is_emulating_xinput && ImGui::IsItemClicked ())
@@ -348,18 +347,17 @@ SK::ControlPanel::Input::Draw (void)
ImGui::Text (" %s", SK_XInput_GetPrimaryHookName ());
ImGui::PopStyleColor ();
- if (ImGui::IsItemHovered ())
+ if (ImGui::BeginItemTooltip ())
{
- ImGui::BeginTooltip ();
- ImGui::BeginGroup ();
+ ImGui::BeginGroup ();
for ( int i = 0 ; i < XUSER_MAX_COUNT ; ++i )
{
if (xinput.reads [i] > 0)
ImGui::Text ("Gamepad %d %lu", i, xinput.reads [i]);
}
- ImGui::EndGroup ();
- ImGui::SameLine ();
- ImGui::BeginGroup ();
+ ImGui::EndGroup ();
+ ImGui::SameLine ();
+ ImGui::BeginGroup ();
for ( int i = 0 ; i < XUSER_MAX_COUNT ; ++i )
{
if (xinput.reads [i] > 0)
@@ -369,8 +367,8 @@ SK::ControlPanel::Input::Draw (void)
" Disabled" : "" );
}
}
- ImGui::EndGroup ();
- ImGui::EndTooltip ();
+ ImGui::EndGroup ();
+ ImGui::EndTooltip ();
}
}
@@ -399,16 +397,15 @@ SK::ControlPanel::Input::Draw (void)
SETUP_LABEL_COLOR (wgi, 500.0f);
- ImGui::SameLine ();
- ImGui::Text (SK_WGI_EmulatedPlayStation ? " Windows.Gaming.Input " ICON_FA_PLAYSTATION
- : " Windows.Gaming.Input");
- ImGui::PopStyleColor ();
+ ImGui::SameLine ();
+ ImGui::Text (SK_WGI_EmulatedPlayStation ? " Windows.Gaming.Input " ICON_FA_PLAYSTATION
+ : " Windows.Gaming.Input");
+ ImGui::PopStyleColor ();
- if (ImGui::IsItemHovered ( ))
+ if (ImGui::BeginItemTooltip ())
{
- ImGui::BeginTooltip ( );
- ImGui::Text ("Gamepad %lu", wgi.reads);
- ImGui::EndTooltip ( );
+ ImGui::Text ("Gamepad %lu", wgi.reads);
+ ImGui::EndTooltip ();
}
}
@@ -431,10 +428,8 @@ SK::ControlPanel::Input::Draw (void)
ImGui::Text (" HID");
ImGui::PopStyleColor ();
- if (ImGui::IsItemHovered ())
+ if (ImGui::BeginItemTooltip ())
{
- ImGui::BeginTooltip ();
-
if (hid.kbd_reads > 0)
ImGui::Text ("Keyboard %lu", hid.kbd_reads);
if (hid.mouse_reads > 0)
@@ -451,16 +446,15 @@ SK::ControlPanel::Input::Draw (void)
{
SETUP_LABEL_COLOR (winmm, 500.0f);
- ImGui::SameLine ();
- ImGui::Text (" WinMM Joystick");
- ImGui::PopStyleColor ();
+ ImGui::SameLine ();
+ ImGui::Text (" WinMM Joystick");
+ ImGui::PopStyleColor ();
- if (ImGui::IsItemHovered ())
+ if (ImGui::BeginItemTooltip ())
{
- ImGui::BeginTooltip ();
if (winmm.reads > 0)
- ImGui::Text ("Gamepad %lu", winmm.reads);
- ImGui::EndTooltip ();
+ ImGui::Text ("Gamepad %lu", winmm.reads);
+ ImGui::EndTooltip ();
}
}
@@ -475,12 +469,11 @@ SK::ControlPanel::Input::Draw (void)
ImGui::Text (" NVIDIA MessageBus");
ImGui::PopStyleColor ();
- if (ImGui::IsItemHovered ())
+ if (ImGui::BeginItemTooltip ())
{
- ImGui::BeginTooltip ();
if (messagebus.reads > 0)
- ImGui::Text ("Gamepad %lu", messagebus.reads);
- ImGui::EndTooltip ();
+ ImGui::Text ("Gamepad %lu", messagebus.reads);
+ ImGui::EndTooltip ();
}
}
#endif
@@ -490,25 +483,23 @@ SK::ControlPanel::Input::Draw (void)
{
SETUP_LABEL_COLOR (di7, 500.0f);
- ImGui::SameLine ();
- ImGui::Text (" DirectInput 7");
- ImGui::PopStyleColor ();
+ ImGui::SameLine ();
+ ImGui::Text (" DirectInput 7");
+ ImGui::PopStyleColor ();
- if (ImGui::IsItemHovered ())
+ if (ImGui::BeginItemTooltip ())
{
- ImGui::BeginTooltip ();
-
if (di7.kbd_reads > 0) {
- ImGui::Text ("Keyboard %lu", di7.kbd_reads);
+ ImGui::Text ("Keyboard %lu", di7.kbd_reads);
}
if (di7.mouse_reads > 0) {
- ImGui::Text ("Mouse %lu", di7.mouse_reads);
+ ImGui::Text ("Mouse %lu", di7.mouse_reads);
}
if (di7.gamepad_reads > 0) {
- ImGui::Text ("Gamepad %lu", di7.gamepad_reads);
+ ImGui::Text ("Gamepad %lu", di7.gamepad_reads);
};
- ImGui::EndTooltip ();
+ ImGui::EndTooltip ();
}
}
@@ -517,25 +508,72 @@ SK::ControlPanel::Input::Draw (void)
{
SETUP_LABEL_COLOR (di8, 500.0f);
- ImGui::SameLine ();
- ImGui::Text (" DirectInput 8");
- ImGui::PopStyleColor ();
+ ImGui::SameLine ();
+ ImGui::Text (" DirectInput 8");
+ ImGui::PopStyleColor ();
- if (ImGui::IsItemHovered ())
+ if (ImGui::BeginItemTooltip ())
{
- ImGui::BeginTooltip ();
-
if (di8.kbd_reads > 0) {
- ImGui::Text ("Keyboard %lu", di8.kbd_reads);
+ ImGui::Text ("Keyboard %lu", di8.kbd_reads);
}
if (di8.mouse_reads > 0) {
- ImGui::Text ("Mouse %lu", di8.mouse_reads);
+ ImGui::Text ("Mouse %lu", di8.mouse_reads);
}
if (di8.gamepad_reads > 0) {
- ImGui::Text ("Gamepad %lu", di8.gamepad_reads);
+ ImGui::Text ("Gamepad %lu", di8.gamepad_reads);
};
- ImGui::EndTooltip ();
+ ImGui::EndTooltip ();
+ }
+ }
+
+ if ( last_gameinput > current_time - 500UL ||
+ hide_gameinput > current_time - 500UL )
+ {
+ bool SK_GameInput_EmulatedPlayStation = true;
+
+ if (SK_HID_PlayStationControllers.empty ())
+ SK_GameInput_EmulatedPlayStation = false;
+
+ else
+ {
+ bool bConnected = false;
+
+ for (auto& controller : SK_HID_PlayStationControllers)
+ {
+ if (controller.bConnected)
+ {
+ bConnected = true;
+ break;
+ }
+ }
+
+ if (! bConnected)
+ SK_GameInput_EmulatedPlayStation = false;
+ }
+
+ SETUP_LABEL_COLOR (gameinput, 500.0f);
+
+ ImGui::SameLine ();
+ ImGui::Text (SK_GameInput_EmulatedPlayStation ?
+ " GameInput " ICON_FA_PLAYSTATION :
+ " GameInput");
+ ImGui::PopStyleColor ();
+
+ if (ImGui::BeginItemTooltip ())
+ {
+ if (game_input.kbd_reads > 0) {
+ ImGui::Text ("Keyboard %lu", game_input.kbd_reads);
+ }
+ if (game_input.mouse_reads > 0) {
+ ImGui::Text ("Mouse %lu", game_input.mouse_reads);
+ }
+ if (game_input.gamepad_reads > 0) {
+ ImGui::Text ("Gamepad %lu", game_input.gamepad_reads);
+ }
+
+ ImGui::EndTooltip ();
}
}
@@ -548,14 +586,13 @@ SK::ControlPanel::Input::Draw (void)
ImGui::Text (" Windows Hook");
ImGui::PopStyleColor ();
- if (ImGui::IsItemHovered ())
+ if (ImGui::BeginItemTooltip ())
{
- ImGui::BeginTooltip ();
if (winhook.mouse_reads > 0)
- ImGui::Text ("Mouse %lu", winhook.mouse_reads);
+ ImGui::Text ("Mouse %lu", winhook.mouse_reads);
if (winhook.kbd_reads > 0)
- ImGui::Text ("Keyboard %lu", winhook.kbd_reads);
- ImGui::EndTooltip ();
+ ImGui::Text ("Keyboard %lu", winhook.kbd_reads);
+ ImGui::EndTooltip ();
}
}
@@ -568,33 +605,36 @@ SK::ControlPanel::Input::Draw (void)
ImGui::Text (" Win32");
ImGui::PopStyleColor ();
- if (ImGui::IsItemHovered ())
+ if (ImGui::BeginItemTooltip ())
{
- ImGui::BeginTooltip ();
- ImGui::BeginGroup ();
+ ImGui::BeginGroup ();
if (win32.asynckeystate > 0)
- ImGui::TextUnformatted ("GetAsyncKeyState\t");
+ ImGui::TextUnformatted
+ ("GetAsyncKeyState\t");
if (win32.keystate > 0)
- ImGui::TextUnformatted ("GetKeyState\t");
+ ImGui::TextUnformatted
+ ("GetKeyState\t");
if (win32.keyboardstate > 0)
- ImGui::TextUnformatted ("GetKeyboardState\t");
+ ImGui::TextUnformatted
+ ("GetKeyboardState\t");
if (win32.cursorpos > 0)
- ImGui::TextUnformatted ("GetCursorPos\t");
+ ImGui::TextUnformatted
+ ("GetCursorPos\t");
- ImGui::EndGroup ();
- ImGui::SameLine ();
- ImGui::BeginGroup ();
+ ImGui::EndGroup ();
+ ImGui::SameLine ();
+ ImGui::BeginGroup ();
if (win32.asynckeystate > 0)
- ImGui::Text ("%lu", win32.asynckeystate);
+ ImGui::Text ("%lu", win32.asynckeystate);
if (win32.keystate > 0)
- ImGui::Text ("%lu", win32.keystate);
+ ImGui::Text ("%lu", win32.keystate);
if (win32.keyboardstate > 0)
- ImGui::Text ("%lu", win32.keyboardstate);
+ ImGui::Text ("%lu", win32.keyboardstate);
if (win32.cursorpos > 0)
ImGui::Text ("%lu", win32.cursorpos);
- ImGui::EndGroup ();
- ImGui::EndTooltip ();
+ ImGui::EndGroup ();
+ ImGui::EndTooltip ();
}
}
@@ -604,25 +644,23 @@ SK::ControlPanel::Input::Draw (void)
{
SETUP_LABEL_COLOR (rawinput, 500.0f);
- ImGui::SameLine ();
- ImGui::Text (" Raw Input");
- ImGui::PopStyleColor ();
+ ImGui::SameLine ();
+ ImGui::Text (" Raw Input");
+ ImGui::PopStyleColor ();
- if (ImGui::IsItemHovered ())
+ if (ImGui::BeginItemTooltip ())
{
- ImGui::BeginTooltip ();
-
if (raw_input.kbd_reads > 0) {
- ImGui::Text ("Keyboard %lu", raw_input.kbd_reads);
+ ImGui::Text ("Keyboard %lu", raw_input.kbd_reads);
}
if (raw_input.mouse_reads > 0) {
- ImGui::Text ("Mouse %lu", raw_input.mouse_reads);
+ ImGui::Text ("Mouse %lu", raw_input.mouse_reads);
}
if (raw_input.gamepad_reads > 0) {
- ImGui::Text ("Gamepad %lu", raw_input.gamepad_reads);
+ ImGui::Text ("Gamepad %lu", raw_input.gamepad_reads);
}
- ImGui::EndTooltip ();
+ ImGui::EndTooltip ();
}
}
}
@@ -634,7 +672,7 @@ SK::ControlPanel::Input::Draw (void)
ImGui::PushStyleColor (ImGuiCol_HeaderActive, ImVec4 (0.87f, 0.78f, 0.14f, 0.80f));
ImGui::TreePush ("");
- if (ImGui::CollapsingHeader ("Mouse Cursor"))
+ if (ImGui::CollapsingHeader ("Mouse"))
{
auto _CursorBoundaryWidget = [&]()
{
@@ -657,26 +695,22 @@ SK::ControlPanel::Input::Draw (void)
ImVec2 vCursorWidgetPos (0.0f, 0.0f);
- if (config.input.cursor.manage) {
+ if (config.input.cursor.manage)
+ {
ImGui::TreePush ("");
ImGui::BeginGroup ( );
- ImGui::Checkbox ( "Keyboard Activates",
- &config.input.cursor.keys_activate );
-#if 1
- ImGui::Checkbox ( "Gamepad Deactivates",
- &config.input.cursor.gamepad_deactivates );
- if (ImGui::IsItemHovered ())
- {
- ImGui::SetTooltip (
- "Uses XInput or HID (PlayStation) to auto-hide the cursor "
- "on gamepad input."
- );
- }
-#endif
+ ImGui::Checkbox ( "Keyboard Activates",
+ &config.input.cursor.keys_activate );
+ ImGui::Checkbox ( "Gamepad Deactivates",
+ &config.input.cursor.gamepad_deactivates );
+ ImGui::SetItemTooltip
+ (
+ "Auto-hide the cursor in response to XInput or HID (PlayStation) activity."
+ );
ImGui::EndGroup ( );
ImGui::SameLine ( );
vCursorWidgetPos =
- ImGui::GetCursorPos ();
+ ImGui::GetCursorPos();
ImGui::TreePop ( );
}
@@ -760,7 +794,63 @@ SK::ControlPanel::Input::Draw (void)
_CursorBoundaryWidget ();
}
- ImGui::TreePop ();
+#if 0
+ ImGui::BeginGroup ( );
+ ImGui::Text ("Mouse Problems?");
+ ImGui::TreePush ("");
+
+ ImGui::Checkbox ("Fix Synaptics Scroll", &config.input.mouse.fix_synaptics);
+
+ if (ImGui::BeginItemTooltip ())
+ {
+ ImGui::Text ("Generate Missing DirectInput / RawInput / HID Events for Touchpad Scroll");
+ ImGui::Separator ();
+ ImGui::BulletText ("Synaptics touchpads only generate Win32 API messages and scroll events go unnoticed by most games.");
+ ImGui::BulletText ("Enabling this will attempt to fix missing input APIs for the Synaptics driver.");
+ ImGui::EndTooltip ();
+ }
+
+ ImGui::TreePop ();
+ ImGui::EndGroup ();
+
+ ImGui::SameLine ();
+ ImGui::SeparatorEx (ImGuiSeparatorFlags_Vertical);
+ ImGui::SameLine ();
+#endif
+
+ ImGui::Separator ( );
+ ImGui::BeginGroup ( );
+ ImGui::Text ("Mouse Input Capture");
+ ImGui::TreePush ("");
+ if (ImGui::Checkbox ("Block Mouse Input when Overlay is Visible", &config.input.ui.capture_mouse))
+ {
+ SK_ImGui_UpdateCursor ();
+ //SK_ImGui_AdjustCursor ();
+ }
+
+ if (ImGui::BeginItemTooltip ())
+ {
+ ImGui::TextColored (ImVec4 (1.f, 1.f, 1.f, 1.f),
+ "Prevent Game from Detecting All Forms of Mouse Input while this UI is Visible.");
+ ImGui::EndTooltip ();
+ }
+
+ if (! config.input.ui.capture_mouse)
+ {
+ ImGui::SameLine (0.0f, 15);
+ ImGui::Checkbox ("Block Mouse Input if No Cursor is Visible", &config.input.ui.capture_hidden);
+
+ if (ImGui::BeginItemTooltip ())
+ {
+ ImGui::BulletText ("Normally, SK allows games to see mouse clicks and movement as long as the cursor is not hovering SK's UI.");
+ ImGui::BulletText ("If the System Cursor is not visible, games are usually in mouselook mode... which could cause UI problems.");
+ ImGui::EndTooltip ();
+ }
+ }
+
+ ImGui::TreePop ();
+ ImGui::EndGroup ();
+ ImGui::TreePop ();
}
if (bHasPlayStation)
@@ -868,25 +958,23 @@ SK::ControlPanel::Input::Draw (void)
ImGui::Columns (2);
if (config.input.gamepad.hook_xinput)
{
- ImGui::Checkbox ("Haptic UI Feedback", &config.input.gamepad.haptic_ui);
+ ImGui::Checkbox ("Haptic UI Feedback", &config.input.gamepad.haptic_ui);
- if (ImGui::IsItemHovered ())
+ if (ImGui::BeginItemTooltip ())
{
- ImGui::BeginTooltip ();
ImGui::TextUnformatted ("Rumble when interacting with SK's control panel using a gamepad");
ImGui::Separator ();
ImGui::BulletText ("Quickly identifies when games are not receiving gamepad input because of the control panel.");
ImGui::EndTooltip ();
}
- ImGui::SameLine ();
+ ImGui::SameLine ();
if (config.input.gamepad.hook_xinput && config.input.gamepad.xinput.hook_setstate)
- ImGui::Checkbox ("Disable ALL Rumble", &config.input.gamepad.disable_rumble);
+ ImGui::Checkbox ("Disable ALL Rumble", &config.input.gamepad.disable_rumble);
- if (ImGui::IsItemHovered ())
+ if (ImGui::BeginItemTooltip ())
{
- ImGui::BeginTooltip ();
ImGui::TextUnformatted ("Prevent the GAME from making use of controller vibration");
ImGui::Separator ();
ImGui::BulletText ("In some games, there is a performance penalty for rumble and it cannot be turned off in-game...");
@@ -894,20 +982,19 @@ SK::ControlPanel::Input::Draw (void)
}
}
- ImGui::NextColumn ();
+ ImGui::NextColumn ();
if (config.input.gamepad.hook_xinput)
{
ImGui::Checkbox ("Rehook XInput", &config.input.gamepad.rehook_xinput); ImGui::SameLine ();
- if (ImGui::IsItemHovered ())
+ if (ImGui::BeginItemTooltip ())
{
- ImGui::BeginTooltip ();
ImGui::TextColored (ImVec4 (1.f, 1.f, 1.f, 1.f),
"Re-installs input hooks if third-party hooks are detected.");
- ImGui::Separator ();
- ImGui::BulletText ("This may improve compatibility with x360ce, but will require a game restart.");
- ImGui::EndTooltip ();
+ ImGui::Separator ();
+ ImGui::BulletText ("This may improve compatibility with x360ce, but will require a game restart.");
+ ImGui::EndTooltip ();
}
}
@@ -929,9 +1016,8 @@ SK::ControlPanel::Input::Draw (void)
_need_restart = true;
}
- if (ImGui::IsItemHovered ())
+ if (ImGui::BeginItemTooltip ())
{
- ImGui::BeginTooltip ();
ImGui::TextUnformatted ("Consider blocking XInput in games that natively support non-Xbox controllers.");
ImGui::Separator ();
ImGui::BulletText ("Blocking XInput may prevent double-inputs if using something like DS4Windows.");
@@ -947,9 +1033,8 @@ SK::ControlPanel::Input::Draw (void)
_need_restart = true;
}
- if (ImGui::IsItemHovered ())
+ if (ImGui::BeginItemTooltip ())
{
- ImGui::BeginTooltip ();
ImGui::TextUnformatted ("Sometimes a game supports both HID and XInput, but XInput has more features...");
ImGui::Separator ();
ImGui::BulletText ("Blocking HID may prevent double-inputs.");
@@ -990,14 +1075,10 @@ SK::ControlPanel::Input::Draw (void)
{
_need_restart = true;
}
- if (ImGui::IsItemHovered ())
- {
- ImGui::SetTooltip (
- "Work In Progress: "
- "You probably will not get gamepad input at all if Steam Input is active and blocked."
- );
- }
- ImGui::EndGroup ();
+ ImGui::SetItemTooltip ("Work In Progress: "
+ "You probably will not get gamepad input at all if Steam Input is active and blocked.");
+
+ ImGui::EndGroup ( );
if (_need_restart)
{
@@ -1005,13 +1086,13 @@ SK::ControlPanel::Input::Draw (void)
ImGui::BulletText ("Game Restart May Be Required");
ImGui::PopStyleColor ();
}
- ImGui::EndMenu ();
+ ImGui::EndMenu ( );
}
ImGui::NextColumn ( );
ImGui::Columns (1);
- ImGui::Separator ();
+ ImGui::Separator ( );
bool connected [XUSER_MAX_COUNT] = {
SK_XInput_WasLastPollSuccessful (0), SK_XInput_WasLastPollSuccessful (1),
@@ -1056,8 +1137,7 @@ SK::ControlPanel::Input::Draw (void)
ImGui::RadioButton ("Nothing##XInputSlot",
(int *)&config.input.gamepad.xinput.ui_slot, 4);
- if (ImGui::IsItemHovered ())
- ImGui::SetTooltip ("Config menu will only respond to keyboard/mouse input");
+ ImGui::SetItemTooltip ("Config menu will only respond to keyboard/mouse input");
ImGui::NextColumn ( );
@@ -1066,8 +1146,7 @@ SK::ControlPanel::Input::Draw (void)
{
ImGui::Checkbox ("Dynamic XInput " ICON_FA_GAMEPAD " 0", &config.input.gamepad.xinput.auto_slot_assign);
- if (ImGui::IsItemHovered ())
- ImGui::SetTooltip ("Automatically reassign slot 0 in response to gamepad input");
+ ImGui::SetItemTooltip ("Automatically reassign slot 0 in response to gamepad input");
}
else
@@ -1089,13 +1168,14 @@ SK::ControlPanel::Input::Draw (void)
ImGui::Checkbox (szChordLabel, &config.input.gamepad.scepad.enhanced_ps_button);
- if (ImGui::IsItemHovered ())
+ if (ImGui::BeginItemTooltip ())
{
if (config.input.gamepad.xinput.ui_slot > 3)
- ImGui::SetTooltip ("Will not work while \"UI Controller\" is set to 'Nothing'");
+ {
+ ImGui::TextUnformatted ("Will not work while \"UI Controller\" is set to 'Nothing'");
+ }
else
{
- ImGui::BeginTooltip ();
if (bHasPlayStation)
ImGui::TextUnformatted ("Exit \"Control Panel Exclusive Input Mode\" by Holding Share/Select or Pressing Caps Lock");
else
@@ -1164,8 +1244,8 @@ SK::ControlPanel::Input::Draw (void)
ImGui::TextUnformatted ("Media Next Track");
ImGui::EndGroup ();
}
- ImGui::EndTooltip ();
}
+ ImGui::EndTooltip ();
}
ImGui::NextColumn ( );
@@ -1176,17 +1256,16 @@ SK::ControlPanel::Input::Draw (void)
ImGui::Text ("XInput Slots:\t");
ImGui::SameLine ();
- if (ImGui::IsItemHovered ())
+ if (ImGui::BeginItemTooltip ())
{
- ImGui::BeginTooltip ();
- ImGui::TextColored (ImVec4 (1.f, 1.f, 1.f, 1.f),
- "Substitute (or Disable) XInput Controllers With Virtual Ones Until A Real One Is Connected");
- ImGui::Separator ();
- ImGui::BulletText ("Placeholding (checked) a slot is useful for games that do not normally support hot-plugging");
- ImGui::BulletText ("Disabling (red button) a slot is useful if Steam Input and DS4Windows are both emulating XInput");
- ImGui::Separator ();
- ImGui::BulletText ("Both may improve performance in games that poll disconnected controllers");
- ImGui::EndTooltip ();
+ ImGui::TextColored (ImVec4 (1.f, 1.f, 1.f, 1.f),
+ "Substitute (or Disable) XInput Controllers With Virtual Ones Until A Real One Is Connected");
+ ImGui::Separator ();
+ ImGui::BulletText ("Placeholding (checked) a slot is useful for games that do not normally support hot-plugging");
+ ImGui::BulletText ("Disabling (red button) a slot is useful if Steam Input and DS4Windows are both emulating XInput");
+ ImGui::Separator ();
+ ImGui::BulletText ("Both may improve performance in games that poll disconnected controllers");
+ ImGui::EndTooltip ();
}
auto XInputPlaceholderCheckbox = [](const char* szName, DWORD dwIndex)
@@ -1253,62 +1332,56 @@ SK::ControlPanel::Input::Draw (void)
ImGui::PopStyleColor (4);
}
- if (ImGui::IsItemHovered ())
+ if (ImGui::BeginItemTooltip ())
{
const SK_XInput_PacketJournal journal =
SK_XInput_GetPacketJournal (dwIndex);
- ImGui::BeginTooltip ( );
-
- ImGui::BeginGroup ( );
+ ImGui::BeginGroup ( );
ImGui::TextUnformatted ("Device State: ");
ImGui::TextUnformatted ("Placeholding: ");
- ImGui::EndGroup ( );
-
- ImGui::SameLine ( );
-
- ImGui::BeginGroup ( );
+ ImGui::EndGroup ( );
+ ImGui::SameLine ( );
+ ImGui::BeginGroup ( );
if (config.input.gamepad.xinput.disable [dwIndex] || config.input.gamepad.xinput.blackout_api)
- ImGui::TextColored (ImVec4 (1.0f, 0.1f, 0.1f, 1.0f), "Disabled");
+ ImGui::TextColored (ImVec4 (1.0f, 0.1f, 0.1f, 1.0f), "Disabled");
else if (SK_ImGui_WantGamepadCapture ())
- ImGui::TextColored (ImVec4 (1.0f, 1.0f, 0.1f, 1.0f), "Blocked");
+ ImGui::TextColored (ImVec4 (1.0f, 1.0f, 0.1f, 1.0f), "Blocked");
else
- ImGui::TextColored (ImVec4 (0.1f, 1.0f, 0.1f, 1.0f), "Enabled");
+ ImGui::TextColored (ImVec4 (0.1f, 1.0f, 0.1f, 1.0f), "Enabled");
if (config.input.gamepad.xinput.placehold [dwIndex])
{
if (SK_XInput_Holding (dwIndex))
- ImGui::TextColored (ImVec4 ( 0.1f, 1.0f, 0.1f, 1.0f), "Enabled and Active");
+ ImGui::TextColored (ImVec4 ( 0.1f, 1.0f, 0.1f, 1.0f), "Enabled and Active");
else
- ImGui::TextColored (ImVec4 (0.75f, 0.75f, 0.75f, 1.0f), "Enabled");
+ ImGui::TextColored (ImVec4 (0.75f, 0.75f, 0.75f, 1.0f), "Enabled");
}
else
- ImGui::TextColored (ImVec4 ( 0.5f, 0.5f, 0.5f, 1.0f), "N/A");
- ImGui::EndGroup ( );
-
- ImGui::Separator ( );
-
+ ImGui::TextColored (ImVec4 ( 0.5f, 0.5f, 0.5f, 1.0f), "N/A");
+ ImGui::EndGroup ( );
+ ImGui::Separator ( );
if (config.input.gamepad.xinput.placehold [dwIndex] && journal.packet_count.virt > 0)
{
- ImGui::TextColored (ImColor (255, 255, 255), "Hardware Packet Sequencing");
- ImGui::TextColored (ImColor (160, 160, 160), "(Last: %lu | Now: %lu)",
- journal.sequence.last, journal.sequence.current);
- ImGui::Separator ( );
- ImGui::Columns (2, nullptr, false);
- ImGui::TextColored (ImColor (255, 165, 0), "Virtual Packets..."); ImGui::NextColumn ();
- ImGui::Text ("%+07li", journal.packet_count.virt); ImGui::NextColumn ();
- ImGui::TextColored (ImColor (127, 255, 0), "Real Packets..."); ImGui::NextColumn ();
- ImGui::Text ("%+07li", journal.packet_count.real);
- ImGui::Columns (1);
+ ImGui::TextColored (ImColor (255, 255, 255), "Hardware Packet Sequencing");
+ ImGui::TextColored (ImColor (160, 160, 160), "(Last: %lu | Now: %lu)",
+ journal.sequence.last, journal.sequence.current);
+ ImGui::Separator ( );
+ ImGui::Columns (2, nullptr, false);
+ ImGui::TextColored (ImColor (255, 165, 0), "Virtual Packets..."); ImGui::NextColumn ();
+ ImGui::Text ("%+07li", journal.packet_count.virt); ImGui::NextColumn ();
+ ImGui::TextColored (ImColor (127, 255, 0), "Real Packets..."); ImGui::NextColumn ();
+ ImGui::Text ("%+07li", journal.packet_count.real);
+ ImGui::Columns (1);
}
else
{
- ImGui::BulletText ("Inputs Processed:\t%lu", journal.packet_count.real);
+ ImGui::BulletText ("Inputs Processed:\t%lu", journal.packet_count.real);
}
- ImGui::EndTooltip ( );
+ ImGui::EndTooltip ( );
}
};
@@ -1430,17 +1503,14 @@ SK::ControlPanel::Input::Draw (void)
if (*ps_controller.wszSerialNumber != L'\0')
{
- if (ImGui::IsItemHovered ())
- {
- ImGui::SetTooltip (
- "Serial # %wc%wc:%wc%wc:%wc%wc:%wc%wc:%wc%wc:%wc%wc",
- (unsigned short)ps_controller.wszSerialNumber [ 0], (unsigned short)ps_controller.wszSerialNumber [ 1],
- (unsigned short)ps_controller.wszSerialNumber [ 2], (unsigned short)ps_controller.wszSerialNumber [ 3],
- (unsigned short)ps_controller.wszSerialNumber [ 4], (unsigned short)ps_controller.wszSerialNumber [ 5],
- (unsigned short)ps_controller.wszSerialNumber [ 6], (unsigned short)ps_controller.wszSerialNumber [ 7],
- (unsigned short)ps_controller.wszSerialNumber [ 8], (unsigned short)ps_controller.wszSerialNumber [ 9],
- (unsigned short)ps_controller.wszSerialNumber [10], (unsigned short)ps_controller.wszSerialNumber [11] );
- }
+ ImGui::SetItemTooltip ( "Serial # %wc%wc:%wc%wc:%wc%wc:%wc%wc:%wc%wc:%wc%wc",
+ (unsigned short)ps_controller.wszSerialNumber [ 0], (unsigned short)ps_controller.wszSerialNumber [ 1],
+ (unsigned short)ps_controller.wszSerialNumber [ 2], (unsigned short)ps_controller.wszSerialNumber [ 3],
+ (unsigned short)ps_controller.wszSerialNumber [ 4], (unsigned short)ps_controller.wszSerialNumber [ 5],
+ (unsigned short)ps_controller.wszSerialNumber [ 6], (unsigned short)ps_controller.wszSerialNumber [ 7],
+ (unsigned short)ps_controller.wszSerialNumber [ 8], (unsigned short)ps_controller.wszSerialNumber [ 9],
+ (unsigned short)ps_controller.wszSerialNumber [10], (unsigned short)ps_controller.wszSerialNumber [11]
+ );
}
}
ImGui::EndGroup ();
@@ -1586,9 +1656,8 @@ SK::ControlPanel::Input::Draw (void)
ImGui::OpenPopup ("PowerManagementMenu");
}
- else if (ImGui::IsItemHovered ())
+ else if (ImGui::BeginItemTooltip ())
{
- ImGui::BeginTooltip ( );
ImGui::BeginGroup ( );
ImGui::TextColored ( ImColor::HSV (0.18f, 0.88f, 0.94f),
" Left-Click" );
@@ -1617,8 +1686,7 @@ SK::ControlPanel::Input::Draw (void)
config.utility.save_async ();
}
- if (ImGui::IsItemHovered ())
- ImGui::SetTooltip ("Polls gyro and touchpad less frequently to save power.");
+ ImGui::SetItemTooltip ("Polls gyro and touchpad less frequently to save power.");
}
if (ImGui::SliderFloat ("Critical Battery Level", &config.input.gamepad.low_battery_percent, 0.0f, 45.0f, "%3.0f%% Remaining"))
@@ -1626,16 +1694,15 @@ SK::ControlPanel::Input::Draw (void)
config.utility.save_async ();
}
- if (ImGui::IsItemHovered ())
+ if (ImGui::BeginItemTooltip ())
{
- ImGui::BeginTooltip ();
ImGui::TextUnformatted ("Display warning notifications when PlayStation controller battery levels are critical.");
ImGui::Separator ();
ImGui::BulletText ("The warning is only displayed while the controller is running on battery.");
ImGui::BulletText ("The warning can be disabled by setting 0%%");
ImGui::EndTooltip ();
}
- ImGui::EndPopup ();
+ ImGui::EndPopup ();
}
}
} break;
@@ -1690,9 +1757,8 @@ SK::ControlPanel::Input::Draw (void)
config.utility.save_async ();
}
- if (ImGui::IsItemHovered ())
+ if (ImGui::BeginItemTooltip ())
{
- ImGui::BeginTooltip ();
ImGui::TextUnformatted ("Adds PlayStation controller support to Xbox-only games");
ImGui::Separator ();
ImGui::BulletText ("Fully supports DualSense and DualShock 4 (USB and Bluetooth)");
@@ -1733,8 +1799,10 @@ SK::ControlPanel::Input::Draw (void)
if (SK_ImGui_IsItemRightClicked ())
show_debug_option = true;
- else if (ImGui::IsItemHovered ())
- ImGui::SetTooltip ("Apply a Deadzone to Analog Stick Input (" ICON_FA_XBOX " Mode)");
+ else
+ {
+ ImGui::SetItemTooltip ("Apply a Deadzone to Analog Stick Input (" ICON_FA_XBOX " Mode)");
+ }
if (show_debug_option)
{
@@ -1813,9 +1881,9 @@ SK::ControlPanel::Input::Draw (void)
config.utility.save_async ();
}
- if (ImGui::IsItemHovered () && bHasBluetooth)
+ if (bHasBluetooth)
{
- ImGui::SetTooltip ("RGB lighting can be turned off to save battery...");
+ ImGui::SetItemTooltip ("RGB lighting can be turned off to save battery...");
}
ImGui::BeginGroup ();
@@ -1862,8 +1930,7 @@ SK::ControlPanel::Input::Draw (void)
config.utility.save_async ();
}
- if (ImGui::IsItemHovered ())
- ImGui::SetTooltip ("Controls the brightness of status lights as well as RGB");
+ ImGui::SetItemTooltip ("Controls the brightness of status lights as well as RGB");
}
else {
ImGui::SameLine ();
@@ -1872,9 +1939,8 @@ SK::ControlPanel::Input::Draw (void)
///if (bHasBluetooth && bHasSimpleBluetooth && (! bHasNonBluetooth))
///{
- /// if (ImGui::IsItemHovered ())
+ /// if (ImGui::BeginItemTooltip ())
/// {
- /// ImGui::BeginTooltip ();
/// ImGui::TextUnformatted ("Bluetooth Compatibility Mode is Active");
/// ImGui::Separator ();
/// ImGui::BulletText ("RGB Overrides may only apply after a game triggers rumble, or if you use USB.");
@@ -1888,9 +1954,8 @@ SK::ControlPanel::Input::Draw (void)
ImGui::SliderInt ( "HID Input Buffers",
&config.input.gamepad.hid.max_allowed_buffers, 2, 128, "%d-Buffer Circular Queue" );
- if (ImGui::IsItemHovered ())
+ if (ImGui::BeginItemTooltip ())
{
- ImGui::BeginTooltip ();
ImGui::TextUnformatted ("Reduce Input Buffer Queue (Latency) on Gamepads");
ImGui::Separator ();
ImGui::BulletText (
@@ -1940,9 +2005,8 @@ SK::ControlPanel::Input::Draw (void)
" Compatibility Mode: Features newer than DualShock 3 unsupported."
);
- if (ImGui::IsItemHovered ( ))
+ if (ImGui::BeginItemTooltip ())
{
- ImGui::BeginTooltip ( );
ImGui::TextUnformatted (
"Plug your controller in, or trigger rumble in-game to put the "
"Bluetooth controller into DualShock 4 / DualSense mode; "
@@ -1952,13 +2016,13 @@ SK::ControlPanel::Input::Draw (void)
#ifdef SK_HID_BROKEN_DUALSHOCK4_REV2
if (bHasDualShock4v2_Bt)
{
- ImGui::Separator ();
- ImGui::BulletText (
+ ImGui::Separator ();
+ ImGui::BulletText (
"DualShock 4 v2 controllers will not work over Bluetooth with SK in Compatibility Mode."
);
}
#endif
- ImGui::EndTooltip ( );
+ ImGui::EndTooltip ();
}
}
@@ -1994,8 +2058,7 @@ SK::ControlPanel::Input::Draw (void)
{
ImGui::Checkbox ("Hook libScePad", &config.input.gamepad.hook_scepad);
- if (ImGui::IsItemHovered ())
- ImGui::SetTooltip ("SONY's native input API; unlocks additional settings in games that use it");
+ ImGui::SetItemTooltip ("SONY's native input API; unlocks additional settings in games that use it");
if (config.input.gamepad.hook_scepad && last_scepad != 0)
{
@@ -2014,8 +2077,26 @@ SK::ControlPanel::Input::Draw (void)
}
#endif
+ static bool has_gameinput =
+ GetModuleHandleW (L"GameInput.dll") != nullptr;
+
+ if (has_gameinput && SK_GameInput_Backend->reads [2] > 0)
+ {
+ ImGui::TreePush (""); bool changed =
+ ImGui::SliderFloat ("Left Trigger", &config.input.gamepad.impulse_strength_l, 0.0f, 1.5f, "%3.1fx Impulse Strength");
+ ImGui::SameLine ( ); changed |=
+ ImGui::SliderFloat ("Right Trigger", &config.input.gamepad.impulse_strength_r, 0.0f, 1.5f, "%3.1fx Impulse Strength");
+ ImGui::TreePop ( );
+
+ if (changed)
+ config.utility.save_async ();
+ }
+
ImGui::BeginGroup ();
- if (ImGui::TreeNode ("Compatibility Options"))
+ bool compat_expanded =
+ ImGui::TreeNode ("Compatibility Options");
+
+ if (compat_expanded)
{
bool hovered = false;
bool changed = false;
@@ -2091,23 +2172,38 @@ SK::ControlPanel::Input::Draw (void)
{
if (alt_models) ImGui::SameLine ();
- ImGui::BeginGroup ();
+ ImGui::BeginGroup ();
if (ImGui::Checkbox ("Current Game Requires " ICON_FA_BLUETOOTH " Compatibility Mode",
&config.input.gamepad.bt_input_only))
{ if (config.input.gamepad.bt_input_only)
{
- SK_DeferCommand ("Input.Gamepad.PowerOff 1");
+ if ( SK_WinMM_Backend->reads [2] +
+ SK_DI7_Backend->reads [2] +
+ SK_DI8_Backend->reads [2] > 0 )
+ {
+ SK_DeferCommand ("Input.Gamepad.PowerOff 1");
+ }
}
changed = true;
}
- if (ImGui::IsItemHovered ())
+ if (ImGui::BeginItemTooltip ())
{
- ImGui::SetTooltip (
- "Enable this if your current game only supports DirectInput, "
- "SK will power-off your controller(s) if necessary."
- );
+ ImGui::TextUnformatted
+ ( "Enable this if the current game only has "
+ "support for DirectInput"
+ );
+ ImGui::Separator ();
+ ImGui::BulletText (
+ "SK will power-off your controller(s) if it detects the game"
+ " trying to use WinMM or DirectInput.");
+ ImGui::Separator ();
+ ImGui::TextUnformatted
+ ( "When powered-on, the controller will be "
+ "compatible with DirectInput (until something uses rumble "
+ "or sets LEDs)." );
+ ImGui::EndTooltip ();
}
if (! config.input.gamepad.bt_input_only)
@@ -2118,9 +2214,8 @@ SK::ControlPanel::Input::Draw (void)
changed = true;
}
- if (ImGui::IsItemHovered ())
+ if (ImGui::BeginItemTooltip ())
{
- ImGui::BeginTooltip ();
ImGui::TextUnformatted ("Allow SK to use your controller's full functionality, "
"even if that requires enabling Advanced Bluetooth mode.");
ImGui::Separator ();
@@ -2133,14 +2228,14 @@ SK::ControlPanel::Input::Draw (void)
#ifdef SK_HID_BROKEN_DUALSHOCK4_REV2
if (bHasDualShock4v2_Bt)
{
- ImGui::Separator ();
- ImGui::BulletText (
+ ImGui::Separator ();
+ ImGui::BulletText (
"DualShock 4 v2 controllers will not work over Bluetooth with SK unless this is enabled"
);
}
else
{
- ImGui::Separator ();
+ ImGui::Separator ();
}
ImGui::TextUnformatted ("This is a global setting.");
@@ -2157,6 +2252,7 @@ SK::ControlPanel::Input::Draw (void)
ImGui::TreePop ( );
}
ImGui::EndGroup ();
+ if (!compat_expanded)
ImGui::SameLine ();
ImGui::BeginGroup ();
if (ImGui::TreeNode ("Button Mapping"))
@@ -2373,16 +2469,10 @@ extern float SK_ImGui_PulseNav_Strength;
bool expanded = ImGui::CollapsingHeader (SK_FormatString ("%ws##JOYSTICK_DEBUG", joy_caps.szPname).c_str ());
- ImGui::Combo ("Gamepad Type", &config.input.gamepad.predefined_layout, "PlayStation 4\0Steam\0\0", 2);
-
- if (ImGui::IsItemHovered ())
- {
- ImGui::SetTooltip ("This setting is only used if XInput or DirectInput are not working.");
- }
-
- ImGui::SameLine ();
-
- ImGui::Checkbox ("Use DirectInput instead of XInput", &config.input.gamepad.native_ps4);
+ ImGui::Combo ("Gamepad Type", &config.input.gamepad.predefined_layout, "PlayStation 4\0Steam\0\0", 2);
+ ImGui::SetItemTooltip ("This setting is only used if XInput or DirectInput are not working.");
+ ImGui::SameLine ();
+ ImGui::Checkbox ("Use DirectInput instead of XInput", &config.input.gamepad.native_ps4);
if (expanded)
{
@@ -2546,9 +2636,8 @@ extern float SK_ImGui_PulseNav_Strength;
}
}
- if (ImGui::IsItemHovered ())
+ if (ImGui::BeginItemTooltip ())
{
- ImGui::BeginTooltip ();
ImGui::TextUnformatted ("Tests the latency of DS4Windows, Steam Input or a native Xbox controller");
ImGui::Separator ();
ImGui::BulletText ("If you have no Xbox controllers or third-party utilities emulating XInput, this does nothing");
@@ -2598,99 +2687,6 @@ extern float SK_ImGui_PulseNav_Strength;
ImGui::TreePop ( );
}
- if (ImGui::CollapsingHeader ("Low-Level Mouse Settings"))
- {
- ImGui::TreePush ("");
-
- ImGui::BeginGroup ( );
- ImGui::Text ("Mouse Problems?");
- ImGui::TreePush ("");
-
- ImGui::Checkbox ("Fix Synaptics Scroll", &config.input.mouse.fix_synaptics);
-
- if (ImGui::IsItemHovered ())
- {
- ImGui::BeginTooltip ();
- ImGui::Text ("Generate Missing DirectInput / RawInput / HID Events for Touchpad Scroll");
- ImGui::Separator ();
- ImGui::BulletText ("Synaptics touchpads only generate Win32 API messages and scroll events go unnoticed by most games.");
- ImGui::BulletText ("Enabling this will attempt to fix missing input APIs for the Synaptics driver.");
- ImGui::EndTooltip ();
- }
-
- ImGui::TreePop ();
- ImGui::EndGroup ();
-
- ImGui::SameLine ();
- ImGui::SeparatorEx (ImGuiSeparatorFlags_Vertical);
- ImGui::SameLine ();
-
- ImGui::BeginGroup ();
- ImGui::Text ("Mouse Input Capture");
- ImGui::TreePush ("");
-
- ImGui::BeginGroup ( );
-
- if (ImGui::Checkbox ("Block Mouse", &config.input.ui.capture_mouse))
- {
- SK_ImGui_UpdateCursor ();
- //SK_ImGui_AdjustCursor ();
- }
-
- if (ImGui::IsItemHovered ())
- {
- ImGui::BeginTooltip ();
- ImGui::TextColored (ImVec4 (1.f, 1.f, 1.f, 1.f), "Prevent Game from Detecting Mouse Input while this UI is Visible");
- ImGui::Separator ();
- ImGui::BulletText ("May help with mouselook in some games");
- ImGui::EndTooltip ();
- }
-
- ImGui::SameLine ();
-
- if (ImGui::Checkbox ("Use Hardware Cursor", &config.input.ui.use_hw_cursor))
- {
- SK_ImGui_UpdateCursor ();
- }
-
- if (ImGui::IsItemHovered ())
- {
- ImGui::BeginTooltip ();
- ImGui::TextColored (ImVec4 (1.f, 1.f, 1.f, 1.f), "Reduce Input Latency -- (Trade Cursor Lag for UI Lag)");
- ImGui::Separator ();
- ImGui::BulletText ("You will experience several frames of lag while dragging UI windows around.");
- ImGui::BulletText ("Most Games use Hardware Cursors; turning this on will reduce visible cursor trails.");
- ImGui::BulletText ("Automatically switches to Software when the game is not using Hardware.");
- ImGui::EndTooltip ();
- }
-
- ImGui::SameLine ();
-
- ImGui::Checkbox ("Block Mouse if No Cursor is Visible", &config.input.ui.capture_hidden);
-
- if (ImGui::IsItemHovered ())
- ImGui::SetTooltip ("Generally prevents mouselook if you move your cursor away from the config UI");
-
- ImGui::EndGroup ( );
- ImGui::TreePop ( );
- ImGui::EndGroup ( );
-
-#if 0
- extern bool SK_DInput8_BlockWindowsKey (bool block);
- extern bool SK_DInput8_HasKeyboard (void);
-
- if (SK_DInput8_HasKeyboard ())
- {
- if (ImGui::Checkbox ("Block Windows Key", &config.input.keyboard.block_windows_key))
- {
- config.input.keyboard.block_windows_key = SK_DInput8_BlockWindowsKey (config.input.keyboard.block_windows_key);
- }
- }
-#endif
-
- ImGui::TreePop ();
- }
-
const bool devices =
ImGui::CollapsingHeader ("Enable / Disable Devices", ImGuiTreeNodeFlags_DefaultOpen);
@@ -2714,8 +2710,8 @@ extern float SK_ImGui_PulseNav_Strength;
if (mouse_changed || keyboard_changed)
config.utility.save_async ();
- if (ImGui::IsItemHovered () && config.input.keyboard.disabled_to_game == SK_InputEnablement::DisabledInBackground)
- ImGui::SetTooltip ("Most games block keyboard input in the background to begin with...");
+ if (config.input.keyboard.disabled_to_game == SK_InputEnablement::DisabledInBackground)
+ ImGui::SetItemTooltip ("Most games block keyboard input in the background to begin with...");
if (/*config.input.gamepad.hook_dinput7 ||*/ config.input.gamepad.hook_dinput8 ||
config.input.gamepad.hook_hid || config.input.gamepad.hook_xinput ||
@@ -3170,17 +3166,32 @@ SK_ImGui_GamepadComboDialog0 (SK_GamepadCombo_V0* combo)
void
SK_ImGui_CursorBoundaryConfig (bool window_mgmt = false)
{
- ImGui::BeginGroup ( );
- ImGui::Text ("Cursor Boundaries");
+ ImGui::BeginGroup ( );
+ ImGui::Text ("Cursor Boundaries");
if (! window_mgmt)
{
- ImGui::SameLine ( );
- ImGui::SeparatorEx (ImGuiSeparatorFlags_Vertical);
- ImGui::SameLine ( );
- ImGui::Checkbox ("Center Cursor on UI When Opening Overlay", &config.input.ui.center_cursor);
+ ImGui::SameLine (0.0f, 15);
+ ImGui::SeparatorEx (ImGuiSeparatorFlags_Vertical);
+ ImGui::SameLine (0.0f, 15);
+ ImGui::Checkbox ("Center Cursor on UI", &config.input.ui.center_cursor);
+ ImGui::SetItemTooltip
+ ("Move the System Cursor to the center of SK's Control Panel when opening it.");
+ ImGui::SameLine (0.0f, 15);
+ if (ImGui::Checkbox ("Use Hardware Cursor", &config.input.ui.use_hw_cursor))
+ {
+ SK_ImGui_UpdateCursor ();
+ }
+ if (ImGui::BeginItemTooltip ())
+ {
+ ImGui::TextColored (ImVec4 (1.f, 1.f, 1.f, 1.f), "Reduce Mouse Latency in SK's Overlay");
+ ImGui::Separator ( );
+ ImGui::BulletText ("Enabling this may cause some games to use SK's cursor image instead of their own.");
+ ImGui::BulletText ("Normally the cursor will revert back to whatever the game was using when not hovering SK's UI.");
+ ImGui::EndTooltip ( );
+ }
}
- ImGui::EndGroup ( );
- ImGui::TreePush ("");
+ ImGui::EndGroup ( );
+ ImGui::TreePush ("");
int ovr = 0;
bool changed = false;
@@ -3193,19 +3204,17 @@ SK_ImGui_CursorBoundaryConfig (bool window_mgmt = false)
changed |= ImGui::RadioButton ("Normal Game Behavior", &ovr, 0); ImGui::SameLine ();
changed |= ImGui::RadioButton ("Keep Inside Window", &ovr, 1); ImGui::SameLine ();
- if (ImGui::IsItemHovered ())
+ if (ImGui::BeginItemTooltip ())
{
- ImGui::BeginTooltip ();
- ImGui::Text ("Prevents Mouse Cursor from Leaving the Game Window");
- ImGui::Separator ();
- ImGui::BulletText ("This window-lock will be disengaged when you press Alt + Tab");
- ImGui::EndTooltip ();
+ ImGui::Text ("Prevents Mouse Cursor from Leaving the Game Window");
+ ImGui::Separator ();
+ ImGui::BulletText ("This window-lock will be disengaged when you press Alt + Tab");
+ ImGui::EndTooltip ();
}
changed |= ImGui::RadioButton ("Unrestrict Cursor", &ovr, 2);
- if (ImGui::IsItemHovered ())
- ImGui::SetTooltip ("Prevent Game from Restricting Cursor to Window");
+ ImGui::SetItemTooltip ("Prevent Game from Restricting Cursor to Window");
if (changed)
{
diff --git a/src/core.cpp b/src/core.cpp
index cbfb6856d..a32cb3d5a 100644
--- a/src/core.cpp
+++ b/src/core.cpp
@@ -701,7 +701,11 @@ void SK_SEH_InitFinishCallback (void)
{
if (! (SK_GetDLLRole () & DLL_ROLE::DXGI))
SK::DXGI::StartBudgetThread_NoAdapter ();
-
+ }__except(GetExceptionCode()==EXCEPTION_WINE_STUB ?
+ EXCEPTION_EXECUTE_HANDLER:
+ EXCEPTION_CONTINUE_SEARCH){ }
+ __try
+ {
static const GUID nil_guid = { };
GUID* pGUID = nullptr;
@@ -721,14 +725,15 @@ void SK_SEH_InitFinishCallback (void)
{
PowerSetActiveScheme (nullptr, &config.cpu.power_scheme_guid);
}
-
+ }__except(GetExceptionCode()==EXCEPTION_WINE_STUB ?
+ EXCEPTION_EXECUTE_HANDLER:
+ EXCEPTION_CONTINUE_SEARCH){ }
+ __try
+ {
SK_LoadGPUVendorAPIs ();
- }
-
- __except ( GetExceptionCode () == EXCEPTION_WINE_STUB ?
- EXCEPTION_EXECUTE_HANDLER :
- EXCEPTION_CONTINUE_SEARCH )
- { }
+ }__except(GetExceptionCode()==EXCEPTION_WINE_STUB ?
+ EXCEPTION_EXECUTE_HANDLER:
+ EXCEPTION_CONTINUE_SEARCH){ }
}
void
@@ -2879,8 +2884,7 @@ __stdcall
SK_ShutdownCore (const wchar_t* backend)
{
SK_Inject_BroadcastExitNotify ();
-
- SK_DisableApplyQueuedHooks ();
+ SK_DisableApplyQueuedHooks ();
if ( __SK_DLL_TeardownEvent != nullptr)
SetEvent (__SK_DLL_TeardownEvent);
@@ -3139,29 +3143,22 @@ SK_ShutdownCore (const wchar_t* backend)
dll_log->LogEx (false, L"done! (%4u ms)\n", SK_timeGetTime () - dwTime);
}
+ // Unload imports before shutting down MinHook
+ SK_UnloadImports ();
+
dll_log->LogEx (true, L"[ SpecialK ] Shutting down MinHook... ");
dwTime = SK_timeGetTime ();
SK_MinHook_UnInit ();
dll_log->LogEx (false, L"done! (%4u ms)\n", SK_timeGetTime () - dwTime);
- LoadLibraryW_Original = nullptr;
- LoadLibraryA_Original = nullptr;
- LoadLibraryExA_Original = nullptr;
- LoadLibraryExW_Original = nullptr;
- FreeLibrary_Original = nullptr;
- SleepEx_Original = nullptr;
-
- // ... Many, many more...
-
dll_log->LogEx (true, L"[ SpecialK ] Closing secondary logs... ");
dwTime = SK_timeGetTime ();
SK_Log_CleanupLogs ();
+ SK_ReShadeAddOn_CleanupConfigAndLogs
+ ();
dll_log->LogEx (false, L"done! (%4u ms)\n", SK_timeGetTime () - dwTime);
- SK_UnloadImports ();
-
- SK_ReShadeAddOn_CleanupConfigAndLogs ();
}
@@ -3857,6 +3854,7 @@ SK_BackgroundRender_EndFrame (void)
static bool last_foreground = false;
+ static const
DWORD dwProcessId = GetCurrentProcessId ();
DWORD dwForegroundPid = 0x0;
DWORD dwForegroundTid = 0x0;
@@ -3913,19 +3911,19 @@ SK_BackgroundRender_EndFrame (void)
if ((! std::exchange (last_foreground, true)) && (config.window.always_on_top >= AlwaysOnTop || implicit_smart_always_on_top))
SK_DeferCommand ("Window.TopMost true");
}
- }
- if (SK_GetForegroundWindow () != game_window.hWnd)
- {
- //
- // If SKIF is in the foreground, and SK is set to background render mode,
- // then post a message to SKIF to keep it drawing constantly so that VRR
- // in the game does not disengage.
- //
- // The minor overhead from SKIF drawing constantly is much less than the
- // performance oddities caused by the game periodically losing DirectFlip.
- //
- SK_Inject_PostHeartbeatToSKIF ();
+ if (hForegroundWnd != game_window.hWnd)
+ {
+ //
+ // If SKIF is in the foreground, and SK is set to background render mode,
+ // then post a message to SKIF to keep it drawing constantly so that VRR
+ // in the game does not disengage.
+ //
+ // The minor overhead from SKIF drawing constantly is much less than the
+ // performance oddities caused by the game periodically losing DirectFlip.
+ //
+ SK_Inject_PostHeartbeatToSKIF ();
+ }
}
}
@@ -4412,6 +4410,13 @@ SK_EndBufferSwap (HRESULT hr, IUnknown* device, SK_TLS* pTLS)
void SK_ImGui_DrawGraph_Latency (bool predraw);
SK_ImGui_DrawGraph_Latency (true);
+ // While in the size/move modal loop, continually evaluate
+ // window size/position and unrestrict the mouse.
+ if (game_window.size_move)
+ {
+ SK_Window_RepositionIfNeeded ();
+ }
+
return hr;
}
diff --git a/src/diagnostics/compatibility.cpp b/src/diagnostics/compatibility.cpp
index 69d03cae6..2976a2926 100644
--- a/src/diagnostics/compatibility.cpp
+++ b/src/diagnostics/compatibility.cpp
@@ -1196,16 +1196,21 @@ SK_slGetNativeInterface (void *proxyInterface, void **baseInterface)
if (FAILED (pUnk->QueryInterface (__uuidof (IStreamlineBaseInterface), baseInterface)))
return sl::Result::eErrorUnsupportedInterface;
#else
- slGetNativeInterface_pfn
- slGetNativeInterface =
- (slGetNativeInterface_pfn)SK_GetProcAddress (L"sl.interposer.dll",
- "slGetNativeInterface");
-
- if (slGetNativeInterface != nullptr)
- return slGetNativeInterface (proxyInterface, baseInterface);
+ sl::Result result;
+
+ static
+ slGetNativeInterface_pfn
+ slGetNativeInterface = nullptr;
+ if (slGetNativeInterface == nullptr && SK_GetFramesDrawn () < 240)
+ slGetNativeInterface =
+ (slGetNativeInterface_pfn)SK_GetProcAddress (L"sl.interposer.dll",
+ "slGetNativeInterface"); result =
+ slGetNativeInterface != nullptr ?
+ slGetNativeInterface (proxyInterface, baseInterface) :
+ sl::Result::eErrorNotInitialized ;
+
+ return result;
#endif
-
- return sl::Result::eErrorNotInitialized;
}
sl::Result
@@ -1259,14 +1264,19 @@ SK_slUpgradeInterface (void **baseInterface)
return result;
}
#else
- slUpgradeInterface_pfn
- slUpgradeInterface =
- (slUpgradeInterface_pfn)SK_GetProcAddress (L"sl.interposer.dll",
- "slUpgradeInterface");
-
- if (slUpgradeInterface != nullptr)
- return slUpgradeInterface (baseInterface);
+ sl::Result result;
+
+ static
+ slUpgradeInterface_pfn
+ slUpgradeInterface = nullptr;
+ if (slUpgradeInterface == nullptr && SK_GetFramesDrawn () < 240)
+ slUpgradeInterface =
+ (slUpgradeInterface_pfn)SK_GetProcAddress (L"sl.interposer.dll",
+ "slUpgradeInterface"); result =
+ slUpgradeInterface != nullptr ?
+ slUpgradeInterface (baseInterface) :
+ sl::Result::eErrorNotInitialized ;
+
+ return result;
#endif
-
- return sl::Result::eErrorNotInitialized;
}
\ No newline at end of file
diff --git a/src/diagnostics/debug_utils.cpp b/src/diagnostics/debug_utils.cpp
index 9060e8255..f22d98353 100644
--- a/src/diagnostics/debug_utils.cpp
+++ b/src/diagnostics/debug_utils.cpp
@@ -44,47 +44,22 @@ SHGetKnownFolderPath_Detour ( _In_ REFKNOWNFOLDERID rfid,
_In_opt_ HANDLE hToken,
_Outptr_ PWSTR * ppszPath );
-using GetCommandLineW_pfn = LPWSTR (WINAPI *)(void);
- GetCommandLineW_pfn
- GetCommandLineW_Original = nullptr;
-
-using GetCommandLineA_pfn = LPSTR (WINAPI *)(void);
- GetCommandLineA_pfn
- GetCommandLineA_Original = nullptr;
-
-using TerminateThread_pfn = BOOL (WINAPI *)( _In_ HANDLE hThread,
- _In_ DWORD dwExitCode );
- TerminateThread_pfn
- TerminateThread_Original = nullptr;
-
-using ExitThread_pfn = VOID (WINAPI *)(_In_ DWORD dwExitCode);
- ExitThread_pfn
- ExitThread_Original = nullptr;
-
-using _endthreadex_pfn = void (__cdecl *)( _In_ unsigned _ReturnCode );
- _endthreadex_pfn
- _endthreadex_Original = nullptr;
-
-using NtTerminateProcess_pfn = NTSTATUS (*)(HANDLE, NTSTATUS);
- NtTerminateProcess_pfn
- NtTerminateProcess_Original = nullptr;
-
-using RtlExitUserThread_pfn = VOID (NTAPI *)(_In_ NTSTATUS Status);
- RtlExitUserThread_pfn
- RtlExitUserThread_Original = nullptr;
-
-using SHGetKnownFolderPath_pfn = HRESULT (WINAPI *)(REFKNOWNFOLDERID,DWORD,HANDLE,PWSTR*);
- SHGetKnownFolderPath_pfn
- SHGetKnownFolderPath_Original = nullptr;
-
-using CloseHandle_pfn = BOOL (WINAPI *)(HANDLE);
-
-TerminateProcess_pfn TerminateProcess_Original = nullptr;
-ExitProcess_pfn ExitProcess_Original = nullptr;
-ExitProcess_pfn ExitProcess_Hook = nullptr;
-OutputDebugStringA_pfn OutputDebugStringA_Original = nullptr;
-OutputDebugStringW_pfn OutputDebugStringW_Original = nullptr;
-CloseHandle_pfn CloseHandle_Original = nullptr;
+SHGetKnownFolderPath_pfn SHGetKnownFolderPath_Original = nullptr;
+
+GetCommandLineW_pfn GetCommandLineW_Original = nullptr;
+GetCommandLineA_pfn GetCommandLineA_Original = nullptr;
+
+NtTerminateProcess_pfn NtTerminateProcess_Original = nullptr;
+RtlExitUserThread_pfn RtlExitUserThread_Original = nullptr;
+ExitThread_pfn ExitThread_Original = nullptr;
+_endthreadex_pfn _endthreadex_Original = nullptr;
+TerminateThread_pfn TerminateThread_Original = nullptr;
+TerminateProcess_pfn TerminateProcess_Original = nullptr;
+ExitProcess_pfn ExitProcess_Original = nullptr;
+ExitProcess_pfn ExitProcess_Hook = nullptr;
+OutputDebugStringA_pfn OutputDebugStringA_Original = nullptr;
+OutputDebugStringW_pfn OutputDebugStringW_Original = nullptr;
+CloseHandle_pfn CloseHandle_Original = nullptr;
bool SK_SEH_CompatibleCallerName (LPCVOID lpAddr, wchar_t* wszDllFullName);\
@@ -188,13 +163,8 @@ static SymGetTypeInfo_pfn SymGetTypeInfo_Imp = nullptr;
void
SK_SymSetOpts (void);
-using SetLastError_pfn = void (WINAPI *)(_In_ DWORD dwErrCode);
- SetLastError_pfn
- SetLastError_Original = nullptr;
-
-using GetProcAddress_pfn = FARPROC (WINAPI *)(HMODULE,LPCSTR);
- GetProcAddress_pfn
- GetProcAddress_Original = nullptr;
+SetLastError_pfn SetLastError_Original = nullptr;
+GetProcAddress_pfn GetProcAddress_Original = nullptr;
using LdrLockLoaderLock_pfn = NTSTATUS (WINAPI *)(ULONG Flags, ULONG *State, ULONG_PTR *Cookie);
using LdrUnlockLoaderLock_pfn = NTSTATUS (WINAPI *)(ULONG Flags, ULONG_PTR Cookie);
@@ -2075,10 +2045,10 @@ ZwSetInformationThread_Detour (
{
if (pTLS != nullptr) pTLS->debug.hidden = true;
- SK_LOG0 ( ( L"tid=%x (%s) tried to hide itself from debuggers; please "
+ SK_LOG0 ( ( L"tid=%x (%ws) tried to hide itself from debuggers; please "
L"attach one and investigate!",
GetThreadId (ThreadHandle),
- SK_Thread_GetName (ThreadHandle).c_str () ),
+ SK_Thread_GetName (ThreadHandle) ),
L"DieAntiDbg" );
}
@@ -2243,8 +2213,7 @@ ZwCreateThreadEx_Detour (
auto& ThreadNames =
*_SK_ThreadNames;
- if ( ThreadNames.find (tid) ==
- ThreadNames.cend ( ) )
+ if (ThreadNames.count (tid) == 0)
{
ulLen =
SK_GetSymbolNameFromModuleAddr (
@@ -2274,9 +2243,8 @@ ZwCreateThreadEx_Detour (
thread_name )
);
- ThreadNames.insert (
- std::make_pair ( tid, thr_name )
- );
+ wcsncpy_s (ThreadNames [tid].data (), SK_MAX_THREAD_NAME_LEN,
+ thr_name.c_str (), _TRUNCATE);
SK_TLS* pTLS =
SK_TLS_BottomEx (tid);
@@ -2284,7 +2252,7 @@ ZwCreateThreadEx_Detour (
if (pTLS != nullptr)
{
wcsncpy_s (
- pTLS->debug.name, MAX_THREAD_NAME_LEN,
+ pTLS->debug.name, SK_MAX_THREAD_NAME_LEN,
thr_name.c_str (), _TRUNCATE
);
}
@@ -2453,9 +2421,8 @@ NtCreateThreadEx_Detour (
thread_name )
);
- ThreadNames.insert (
- std::make_pair ( tid, thr_name )
- );
+ wcsncpy_s (ThreadNames [tid].data (), SK_MAX_THREAD_NAME_LEN,
+ thr_name.c_str (), _TRUNCATE);
SK_TLS* pTLS =
SK_TLS_BottomEx (tid);
@@ -2463,7 +2430,7 @@ NtCreateThreadEx_Detour (
if (pTLS != nullptr)
{
wcsncpy_s (
- pTLS->debug.name, MAX_THREAD_NAME_LEN,
+ pTLS->debug.name, SK_MAX_THREAD_NAME_LEN,
thr_name.c_str (), _TRUNCATE
);
}
@@ -2917,8 +2884,8 @@ SK_Exception_HandleThreadName (
if (non_empty)
{
- static auto& ThreadNames = _SK_ThreadNames.get ();
- static auto& SelfTitled = _SK_SelfTitledThreads.get ();
+ auto& ThreadNames = _SK_ThreadNames.get ();
+ auto& SelfTitled = _SK_SelfTitledThreads.get ();
DWORD dwTid = ( info->dwThreadID != -1 ?
info->dwThreadID :
@@ -2933,20 +2900,23 @@ SK_Exception_HandleThreadName (
SK_TLS_BottomEx (dwTid);
std::wstring wide_name (
- SK_UTF8ToWideChar (info->szName)
+ SK_UTF8ToWideChar (info->szName).c_str ()
);
if (pTLS != nullptr)
{
wcsncpy_s (
pTLS->debug.name,
- std::min (len+1, (size_t)MAX_THREAD_NAME_LEN-1),
+ std::min (len+1, (size_t)SK_MAX_THREAD_NAME_LEN-1),
wide_name.c_str (),
_TRUNCATE );
}
- ThreadNames [dwTid] =
- wide_name;
+ // Do not move the string; truncate the string,
+ // and replace any existing name with a copy!
+ *ThreadNames [dwTid].data () = L'\0';
+ wcsncpy_s (ThreadNames [dwTid].data (),SK_MAX_THREAD_NAME_LEN,
+ wide_name.c_str (), _TRUNCATE);
#ifdef _M_AMD64
if (SK_GetCurrentGameID () == SK_GAME_ID::EldenRing)
diff --git a/src/diagnostics/load_library.cpp b/src/diagnostics/load_library.cpp
index ee3c2f282..cd7474149 100644
--- a/src/diagnostics/load_library.cpp
+++ b/src/diagnostics/load_library.cpp
@@ -504,6 +504,9 @@ SK_TraceLoadLibrary ( HMODULE hCallingMod,
{ if (!SK_IsModuleLoaded (L"EOSOVH-Win64-Shipping.dll"))
SK_RunOnce (SK_BootOpenGL ());
}
+ else if ( StrStrI (lpFileName, SK_TEXT("GameInput.dll")) ||
+ StrStrIW (wszModName, L"GameInput.dll") )
+ SK_RunOnce (SK_Input_HookGameInput ());
else if ( //SK_XInput_LinkedVersion.empty () &&
StrStrI (lpFileName, SK_TEXT("xinput1_3.dll")) )
SK_RunOnce (SK_Input_HookXInput1_3 ());
diff --git a/src/hooks.cpp b/src/hooks.cpp
index 51a2e4ba8..5d5a85ec2 100644
--- a/src/hooks.cpp
+++ b/src/hooks.cpp
@@ -1761,6 +1761,44 @@ SK_MinHook_UnInit (void)
SK_LOG_MINHOOK_ ( status, L"Failed to Uninitialize MinHook Library!" );
}
+ LoadLibraryW_Original = nullptr;
+ LoadLibraryA_Original = nullptr;
+ LoadLibraryExA_Original = nullptr;
+ LoadLibraryExW_Original = nullptr;
+ FreeLibrary_Original = nullptr;
+ SleepEx_Original = nullptr;
+ Sleep_Original = nullptr;
+ GetProcAddress_Original = nullptr;
+ SetLastError_Original = nullptr;
+ RaiseException_Original = nullptr;
+ NtTerminateProcess_Original = nullptr;
+ RtlExitUserThread_Original = nullptr;
+ ExitThread_Original = nullptr;
+ _endthreadex_Original = nullptr;
+ TerminateThread_Original = nullptr;
+ TerminateProcess_Original = nullptr;
+ ExitProcess_Original = nullptr;
+ OutputDebugStringA_Original = nullptr;
+ OutputDebugStringW_Original = nullptr;
+
+ CloseHandle_Original = nullptr;
+
+ GlobalAlloc_Original = nullptr;
+ GlobalFree_Original = nullptr;
+ LocalAlloc_Original = nullptr;
+ LocalFree_Original = nullptr;
+ VirtualAlloc_Original = nullptr;
+ VirtualFree_Original = nullptr;
+ RtlAllocateHeap_Original = nullptr;
+ HeapFree_Original = nullptr;
+
+ GetCommandLineW_Original = nullptr;
+ GetCommandLineA_Original = nullptr;
+
+ SHGetKnownFolderPath_Original = nullptr;
+
+ // ... Many, many more...
+
return status;
}
diff --git a/src/imgui/backends/imgui_d3d11.cpp b/src/imgui/backends/imgui_d3d11.cpp
index 968e17350..89fb29925 100644
--- a/src/imgui/backends/imgui_d3d11.cpp
+++ b/src/imgui/backends/imgui_d3d11.cpp
@@ -1963,7 +1963,6 @@ SK_D3D11_RenderCtx::release (IDXGISwapChain* pSwapChain)
// )
//{
//}
-
if ( (_pSwapChain.p != nullptr && pSwapChain == nullptr) ||
_pSwapChain.IsEqualObject (pSwapChain) )//||
//_pSwapChain.IsEqualObject (pUnwrapped) )
diff --git a/src/imgui/backends/imgui_d3d12.cpp b/src/imgui/backends/imgui_d3d12.cpp
index 27a18d5b2..9c0cc4b5a 100644
--- a/src/imgui/backends/imgui_d3d12.cpp
+++ b/src/imgui/backends/imgui_d3d12.cpp
@@ -33,6 +33,7 @@
#define __SK_SUBSYSTEM__ L"D3D12BkEnd"
#define SK_D3D12_PERSISTENT_IMGUI_DEV_OBJECTS
+//#define SK_D3D12_STATE_TRACK
D3D12GraphicsCommandList_ResourceBarrier_pfn
D3D12GraphicsCommandList_ResourceBarrier_Original = nullptr;
@@ -354,11 +355,12 @@ ImGui_ImplDX12_RenderDrawData ( ImDrawData* draw_data,
ctx->SetDescriptorHeaps (1, &descriptorHeaps.pImGui.p);
-
+#ifdef D3D12_STATE_TRACK
// Don't let the user disable ImGui's pipeline state (!!)
bool _enable = false;
_imgui_d3d12.pPipelineState->SetPrivateData (SKID_D3D12DisablePipelineState, sizeof (bool), &_enable);
SK_RunOnce (_criticalVertexShaders.insert (_imgui_d3d12.pPipelineState));
+#endif
//
@@ -1197,6 +1199,9 @@ ImGui_ImplDX12_Init ( ID3D12Device* device,
void
ImGui_ImplDX12_Shutdown (void)
{
+ extern void SK_D3D12_ProcessScreenshotQueueEx (SK_ScreenshotStage, bool, bool);
+ SK_D3D12_ProcessScreenshotQueueEx (SK_ScreenshotStage::_FlushQueue, true,false);
+
///ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
///IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
@@ -1292,6 +1297,7 @@ D3D12GraphicsCommandList_SetPipelineState_Detour (
{
SK_LOG_FIRST_CALL
+#ifdef D3D12_STATE_TRACK
if (pPipelineState != nullptr)
{
// We do not actually care what this is, only that it exists.
@@ -1323,6 +1329,7 @@ D3D12GraphicsCommandList_SetPipelineState_Detour (
SKID_D3D12DisablePipelineState, sizeof (bool),
&disable );
}
+#endif
D3D12GraphicsCommandList_SetPipelineState_Original ( This,
pPipelineState );
@@ -1373,6 +1380,7 @@ D3D12GraphicsCommandList_DrawInstanced_Detour (
{
SK_LOG_FIRST_CALL
+#ifdef D3D12_STATE_TRACK
UINT size = sizeof (bool);
bool disable = false;
@@ -1405,6 +1413,7 @@ D3D12GraphicsCommandList_DrawInstanced_Detour (
//if (trigger_reshade)
//{
//}
+#endif
return
D3D12GraphicsCommandList_DrawInstanced_Original (
@@ -1424,6 +1433,7 @@ D3D12GraphicsCommandList_DrawIndexedInstanced_Detour (
{
SK_LOG_FIRST_CALL
+#ifdef D3D12_STATE_TRACK
UINT size = sizeof (bool);
bool disable = false;
@@ -1443,6 +1453,7 @@ D3D12GraphicsCommandList_DrawIndexedInstanced_Detour (
//return;
}
}
+#endif
return
D3D12GraphicsCommandList_DrawIndexedInstanced_Original (
@@ -1486,6 +1497,7 @@ D3D12GraphicsCommandList_ExecuteIndirect_Detour (
{
SK_LOG_FIRST_CALL
+#ifdef D3D12_STATE_TRACK
UINT size = sizeof (bool);
bool disable = false;
@@ -1505,6 +1517,7 @@ D3D12GraphicsCommandList_ExecuteIndirect_Detour (
//return;
}
}
+#endif
return
D3D12GraphicsCommandList_ExecuteIndirect_Original (
@@ -2453,10 +2466,12 @@ SK_D3D12_RenderCtx::present (IDXGISwapChain3 *pSwapChain)
_InitCopyTextureRegionHook (pCommandList)
);
+#ifdef D3D12_STATE_TRACK
// Don't let user disable HDR re-processing
bool _enable = false;
pHDRPipeline->SetPrivateData (SKID_D3D12DisablePipelineState, sizeof (bool), &_enable);
SK_RunOnce (_criticalVertexShaders.insert (pHDRPipeline));
+#endif
HDR_LUMINANCE
diff --git a/src/import.cpp b/src/import.cpp
index 95ea3ebb6..03465cf01 100644
--- a/src/import.cpp
+++ b/src/import.cpp
@@ -450,7 +450,7 @@ SK_LoadEarlyImports64 (void)
SK_StripUserNameFromPathW (file);
- dll_log->LogEx (true, L"[ SpecialK ] * Loading Early Custom Import %s... ",
+ dll_log->Log (L"[ SpecialK ] * Loading Early Custom Import %s... ",
file.m_pData);
if (! blacklisted)
@@ -467,7 +467,7 @@ SK_LoadEarlyImports64 (void)
SK_GetModuleFullName ( import.hLibrary ).c_str ()
);
- dll_log->LogEx (false, L"success!\n");
+ //dll_log->LogEx (false, L"success!\n");
++success;
if (import.role->is_equal (SK_IMPORT_ROLE_PLUGIN)) {
@@ -483,7 +483,7 @@ SK_LoadEarlyImports64 (void)
_com_error err (HRESULT_FROM_WIN32 (GetLastError ()));
import.hLibrary = (HMODULE)-2;
- dll_log->LogEx (false, L"failed: 0x%04X (%s)!\n",
+ dll_log->Log (L"LoadLibrary failed: 0x%04X (%s)!\n",
err.WCode (), err.ErrorMessage () );
}
}
@@ -534,7 +534,7 @@ SK_LoadPlugIns64 (void)
SK_StripUserNameFromPathW (file);
- dll_log->LogEx (true, L"[ SpecialK ] * Loading Special K Plug-In %s... ",
+ dll_log->Log (L"[ SpecialK ] * Loading Special K Plug-In %s... ",
file.m_pData);
if (! blacklisted)
@@ -546,7 +546,7 @@ SK_LoadPlugIns64 (void)
if (SK_Import_GetShimmedLibrary (import.hLibrary, import.hShim))
std::swap (import.hLibrary, import.hShim);
- dll_log->LogEx (false, L"success!\n");
+ //dll_log->LogEx (false, L"success!\n");
++success;
import.product_desc =
@@ -619,7 +619,7 @@ SK_LoadLateImports64 (void)
SK_StripUserNameFromPathW (file);
- dll_log->LogEx (true, L"[ SpecialK ] * Loading Late Custom Import %s... ",
+ dll_log->Log (L"[ SpecialK ] * Loading Late Custom Import %s... ",
file.m_pData);
if (! blacklisted)
@@ -631,7 +631,7 @@ SK_LoadLateImports64 (void)
if (SK_Import_GetShimmedLibrary (import.hLibrary, import.hShim))
std::swap (import.hLibrary, import.hShim);
- dll_log->LogEx (false, L"success!\n");
+ //dll_log->LogEx (false, L"success!\n");
++success;
import.product_desc =
@@ -645,14 +645,14 @@ SK_LoadLateImports64 (void)
_com_error err (HRESULT_FROM_WIN32 (GetLastError ()));
import.hLibrary = (HMODULE)-2;
- dll_log->LogEx (false, L"failed: 0x%04X (%s)!\n",
+ dll_log->Log (L"LoadLibrary failed: 0x%04X (%s)!\n",
err.WCode (), err.ErrorMessage () );
}
}
else
{
- dll_log->LogEx (false, L"failed: Host App is Blacklisted!\n");
+ dll_log->Log (L"LoadLibrary failed: Host App is Blacklisted!\n");
}
}
}
@@ -696,7 +696,7 @@ SK_LoadLazyImports64 (void)
SK_StripUserNameFromPathW (file);
- dll_log->LogEx (true, L"[ SpecialK ] * Loading Lazy Custom Import %s... ",
+ dll_log->Log (L"[ SpecialK ] * Loading Lazy Custom Import %s... ",
file.m_pData);
if (! blacklisted)
@@ -708,7 +708,7 @@ SK_LoadLazyImports64 (void)
if (SK_Import_GetShimmedLibrary (import.hLibrary, import.hShim))
std::swap (import.hLibrary, import.hShim);
- dll_log->LogEx (false, L"success!\n");
+ //dll_log->LogEx (false, L"success!\n");
++success;
import.product_desc =
@@ -722,14 +722,14 @@ SK_LoadLazyImports64 (void)
_com_error err (HRESULT_FROM_WIN32 (GetLastError ()));
import.hLibrary = (HMODULE)-3;
- dll_log->LogEx (false, L"failed: 0x%04X (%s)!\n",
+ dll_log->Log (L"LoadLibrary failed: 0x%04X (%s)!\n",
err.WCode (), err.ErrorMessage () );
}
}
else
{
- dll_log->LogEx (false, L"failed: Host App is Blacklisted!\n");
+ dll_log->Log (L"LoadLibrary failed: Host App is Blacklisted!\n");
}
}
}
@@ -816,7 +816,7 @@ SK_LoadEarlyImports32 (void)
SK_StripUserNameFromPathW (file);
- dll_log->LogEx (true, L"[ SpecialK ] * Loading Early Custom Import %s... ",
+ dll_log->Log (L"[ SpecialK ] * Loading Early Custom Import %s... ",
file.m_pData);
if (! blacklisted)
@@ -828,7 +828,7 @@ SK_LoadEarlyImports32 (void)
if (SK_Import_GetShimmedLibrary (import.hLibrary, import.hShim))
std::swap (import.hLibrary, import.hShim);
- dll_log->LogEx (false, L"success!\n");
+ //dll_log->LogEx (false, L"success!\n");
++success;
import.product_desc =
@@ -850,14 +850,14 @@ SK_LoadEarlyImports32 (void)
_com_error err (HRESULT_FROM_WIN32 (GetLastError ()));
import.hLibrary = (HMODULE)-2;
- dll_log->LogEx (false, L"failed: 0x%04X (%s)!\n",
+ dll_log->Log (L"LoadLibrary failed: 0x%04X (%s)!\n",
err.WCode (), err.ErrorMessage () );
}
}
else
{
- dll_log->LogEx (false, L"failed: Host App is Blacklisted!\n");
+ dll_log->Log (L"LoadLibrary failed: Host App is Blacklisted!\n");
}
}
}
@@ -901,7 +901,7 @@ SK_LoadPlugIns32 (void)
SK_StripUserNameFromPathW (file);
- dll_log->LogEx (true, L"[ SpecialK ] * Loading Special K Plug-In %s... ",
+ dll_log->Log (L"[ SpecialK ] * Loading Special K Plug-In %s... ",
file.m_pData);
if (! blacklisted)
@@ -913,7 +913,7 @@ SK_LoadPlugIns32 (void)
if (SK_Import_GetShimmedLibrary (import.hLibrary, import.hShim))
std::swap (import.hLibrary, import.hShim);
- dll_log->LogEx (false, L"success!\n");
+ //dll_log->LogEx (false, L"success!\n");
++success;
import.product_desc =
@@ -986,7 +986,7 @@ SK_LoadLateImports32 (void)
SK_StripUserNameFromPathW (file);
- dll_log->LogEx (true, L"[ SpecialK ] * Loading Late Custom Import %s... ",
+ dll_log->Log (L"[ SpecialK ] * Loading Late Custom Import %s... ",
file.m_pData);
if (! blacklisted)
@@ -998,7 +998,7 @@ SK_LoadLateImports32 (void)
if (SK_Import_GetShimmedLibrary (import.hLibrary, import.hShim))
std::swap (import.hLibrary, import.hShim);
- dll_log->LogEx (false, L"success!\n");
+ //dll_log->LogEx (false, L"success!\n");
++success;
import.product_desc =
@@ -1012,14 +1012,14 @@ SK_LoadLateImports32 (void)
_com_error err (HRESULT_FROM_WIN32 (GetLastError ()));
import.hLibrary = (HMODULE)-2;
- dll_log->LogEx (false, L"failed: 0x%04X (%s)!\n",
+ dll_log->Log (L"LoadLibrary failed: 0x%04X (%s)!\n",
err.WCode (), err.ErrorMessage () );
}
}
else
{
- dll_log->LogEx (false, L"failed: Host App is Blacklisted!\n");
+ dll_log->Log (L"LoadLibrary failed: Host App is Blacklisted!\n");
}
}
}
@@ -1063,7 +1063,7 @@ SK_LoadLazyImports32 (void)
SK_StripUserNameFromPathW (file);
- dll_log->LogEx (true, L"[ SpecialK ] * Loading Lazy Custom Import %s... ",
+ dll_log->Log (L"[ SpecialK ] * Loading Lazy Custom Import %s... ",
file.m_pData);
if (! blacklisted)
@@ -1075,7 +1075,7 @@ SK_LoadLazyImports32 (void)
if (SK_Import_GetShimmedLibrary (import.hLibrary, import.hShim))
std::swap (import.hLibrary, import.hShim);
- dll_log->LogEx (false, L"success!\n");
+ //dll_log->LogEx (false, L"success!\n");
++success;
import.product_desc =
@@ -1089,14 +1089,14 @@ SK_LoadLazyImports32 (void)
_com_error err (HRESULT_FROM_WIN32 (GetLastError ()));
import.hLibrary = (HMODULE)-3;
- dll_log->LogEx (false, L"failed: 0x%04X (%s)!\n",
+ dll_log->Log (L"LoadLibrary failed: 0x%04X (%s)!\n",
err.WCode (), err.ErrorMessage () );
}
}
else
{
- dll_log->LogEx (false, L"failed: Host App is Blacklisted!\n");
+ dll_log->Log (L"LoadLibrary failed: Host App is Blacklisted!\n");
import.hLibrary = (HMODULE)-3;
}
}
@@ -1121,16 +1121,16 @@ SK_LogLastErr (void)
void
SK_UnloadImports (void)
{
- auto orig_se =
- SK_SEH_ApplyTranslator (
- SK_FilteringStructuredExceptionTranslator (
- EXCEPTION_ACCESS_VIOLATION
- )
- );
- try {
- // Unload in reverse order, because that's safer :)
- for (int i = SK_MAX_IMPORTS - 1; i >= 0; i--)
- {
+ // Unload in reverse order, because that's safer :)
+ for (int i = SK_MAX_IMPORTS - 1; i >= 0; i--)
+ {
+ auto orig_se =
+ SK_SEH_ApplyTranslator (
+ SK_FilteringStructuredExceptionTranslator (
+ EXCEPTION_ACCESS_VIOLATION
+ )
+ );
+ try {
auto& import =
imports->imports [i];
@@ -1156,7 +1156,7 @@ SK_UnloadImports (void)
if (SKPlugIn_Shutdown != nullptr)
SKPlugIn_Shutdown (nullptr);
}
-
+
///dll_log.Log ( L"[ SpecialK ] Unloading Custom Import %s...",
/// import.filename->get_value_str ().c_str () );
@@ -1165,8 +1165,8 @@ SK_UnloadImports (void)
SK_FreeLibrary (import.hLibrary) )
{
dll_log->LogEx ( false,
- L"-------------------------[ Free Lib ] "
- L" success! (%4u ms)\n",
+ L"-------------------------[ Free Lib ] %41ws"
+ L" success! (%4u ms)\n", import.name.c_str (),
SK_timeGetTime ( ) - dwTime );
}
@@ -1176,11 +1176,16 @@ SK_UnloadImports (void)
}
}
}
- }
- catch (const SK_SEH_IgnoredException&)
- { }
- SK_SEH_RemoveTranslator (orig_se);
+ catch (const SK_SEH_IgnoredException&)
+ {
+ dll_log->Log (
+ L"Structured Exception encountered while unloading library: %ws!",
+ imports->imports [i].name.c_str ()
+ );
+ }
+ SK_SEH_RemoveTranslator (orig_se);
+ }
}
diff --git a/src/injection/injection.cpp b/src/injection/injection.cpp
index f2d61ab96..aa1e3b4b8 100644
--- a/src/injection/injection.cpp
+++ b/src/injection/injection.cpp
@@ -1260,24 +1260,27 @@ SK_Inject_SpawnUnloadListener (void)
CreateThread (nullptr, 0, [](LPVOID) ->
DWORD
{
- HMODULE hModKernel32 =
- SK_LoadLibraryW (L"Kernel32");
+ if (SK_IsInjected ())
+ { // Avoid changing thread names in processes we do not care about
+ HMODULE hModKernel32 =
+ SK_LoadLibraryW (L"Kernel32");
- if (hModKernel32 != nullptr)
- {
- // Try the Windows 10 API for Thread Names first, it's ideal unless ... not Win10 :)
- SetThreadDescription_pfn
- _SetThreadDescriptionWin10 =
- (SetThreadDescription_pfn)SK_GetProcAddress (hModKernel32, "SetThreadDescription");
-
- if (_SetThreadDescriptionWin10 != nullptr) {
- _SetThreadDescriptionWin10 (
- g_hPacifierThread,
- L"[SK] Global Hook Pacifier"
- );
- }
+ if (hModKernel32 != nullptr)
+ {
+ // Try the Windows 10 API for Thread Names first, it's ideal unless ... not Win10 :)
+ SetThreadDescription_pfn
+ _SetThreadDescriptionWin10 =
+ (SetThreadDescription_pfn)SK_GetProcAddress (hModKernel32, "SetThreadDescription");
+
+ if (_SetThreadDescriptionWin10 != nullptr) {
+ _SetThreadDescriptionWin10 (
+ g_hPacifierThread,
+ L"[SK] Global Hook Pacifier"
+ );
+ }
- SK_FreeLibrary (hModKernel32);
+ SK_FreeLibrary (hModKernel32);
+ }
}
SetThreadPriority (g_hPacifierThread, THREAD_PRIORITY_TIME_CRITICAL);
diff --git a/src/input/cursor.cpp b/src/input/cursor.cpp
index 7e95622cd..534873e9d 100644
--- a/src/input/cursor.cpp
+++ b/src/input/cursor.cpp
@@ -528,6 +528,19 @@ sk_imgui_cursor_s::activateWindow (bool active)
static constexpr const DWORD REASON_DISABLED = 0x4;
+bool
+sk_window_s::isCursorHovering (void)
+{
+ if (! SK_GImDefaultContext ())
+ return mouse.inside;
+
+ const auto& io =
+ ImGui::GetIO ();
+
+ return
+ mouse.inside && io.MousePos.x != -FLT_MAX && io.MousePos.y != -FLT_MAX;
+}
+
bool
SK_ImGui_WantMouseCaptureEx (DWORD dwReasonMask)
{
@@ -554,6 +567,10 @@ SK_ImGui_WantMouseCaptureEx (DWORD dwReasonMask)
bool imgui_capture = false;
+ LRESULT hit_test = 0;
+ POINT ptCursor;
+ SK_GetCursorPos (&ptCursor);
+
if (SK_ImGui_IsMouseRelevantEx (false))
{
static const auto& io =
@@ -573,6 +590,28 @@ SK_ImGui_WantMouseCaptureEx (DWORD dwReasonMask)
if (game_window.active && ReadULong64Acquire (&config.input.mouse.temporarily_allow) > SK_GetFramesDrawn () - 20)
imgui_capture = false;
+
+ if ((! imgui_capture) && (! game_window.isCursorHovering ()) && (! SK_IsGameWindowActive ()))
+ {
+ hit_test =
+ DefWindowProcW (game_window.hWnd,WM_NCHITTEST,0,MAKELPARAM(ptCursor.x,ptCursor.y));
+
+ // Do not block the mouse while it is on the window's titlebar, resize grips, etc.
+ if (hit_test == HTCLIENT)
+ {
+ if (SK_WantBackgroundRender ())
+ imgui_capture = true;
+
+ else
+ {
+ DWORD dwProcId;
+ GetWindowThreadProcessId (WindowFromPoint (SK_ImGui_Cursor.last_screen_pos), &dwProcId);
+
+ if (dwProcId != GetCurrentProcessId ())
+ imgui_capture = true;
+ }
+ }
+ }
}
if ((! SK_IsGameWindowActive ()) && config.input.mouse.disabled_to_game == SK_InputEnablement::DisabledInBackground)
@@ -589,6 +628,27 @@ SK_ImGui_WantHWCursor (void)
( config.input.ui.use_hw_cursor );
}
+bool
+SK_ImGui_WantMouseButtonCapture (void)
+{
+ bool capture = SK_ImGui_WantMouseCapture ();
+ if ( capture )
+ {
+ POINT ptCursor = {};
+ if (SK_GetCursorPos (&ptCursor))
+ {
+ LRESULT hit_test =
+ DefWindowProcW (game_window.hWnd,WM_NCHITTEST,0,MAKELPARAM(ptCursor.x,ptCursor.y));
+
+ // Do not block the mouse while it is on the window's titlebar, resize grips, etc.
+ if (hit_test > HTCLIENT)
+ capture = false;
+ }
+ }
+
+ return capture;
+}
+
bool
SK_ImGui_WantMouseCapture (bool update)
{
@@ -1057,8 +1117,7 @@ GetCursorPos_Detour (LPPOINT lpPoint)
#endif
}
-
- if (SK_ImGui_IsMouseRelevant ())
+ if (!game_window.isCursorHovering () || SK_ImGui_IsMouseRelevant())
{
//
// Compute delta mouse coordinates for games that use cursor warping (i.e. mouselook)
diff --git a/src/input/game_input.cpp b/src/input/game_input.cpp
new file mode 100644
index 000000000..66ffc7f67
--- /dev/null
+++ b/src/input/game_input.cpp
@@ -0,0 +1,1918 @@
+/**
+ * This file is part of Special K.
+ *
+ * Special K is free software : you can redistribute it
+ * and/or modify it under the terms of the GNU General Public License
+ * as published by The Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * Special K is distributed in the hope that it will be useful,
+ *
+ * But WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Special K.
+ *
+ * If not, see .
+ *
+**/
+
+#include
+#include
+
+#include
+
+#ifdef __SK_SUBSYSTEM__
+#undef __SK_SUBSYSTEM__
+#endif
+#define __SK_SUBSYSTEM__ L"Input Mgr."
+
+#define SK_LOG_INPUT_CALL { static int calls = 0; \
+ { SK_LOG0 ( (L"[!] > Call #%lu: %hs", calls++, __FUNCTION__), \
+ L"Input Mgr." ); } }
+
+///////////////////////////////////////////////////////
+//
+// GameInput.dll (SK_GI)
+//
+///////////////////////////////////////////////////////
+
+extern SK_LazyGlobal SK_GameInput_Backend;
+
+#define SK_GAMEINPUT_READ(type) SK_GameInput_Backend->markRead (type);
+#define SK_GAMEINPUT_WRITE(type) SK_GameInput_Backend->markWrite (type);
+#define SK_GAMEINPUT_VIEW(type) SK_GameInput_Backend->markViewed (type);
+#define SK_GAMEINPUT_HIDE(type) SK_GameInput_Backend->markHidden (type);
+
+#define GI_VIRTUAL_HOOK(_Base,_Index,_Name,_Override,_Original,_Type) { \
+ void** _vftable = *(void***)*(_Base); \
+ \
+ if ((_Original) == nullptr) { \
+ SK_CreateVFTableHook2 ( L##_Name, \
+ _vftable, \
+ (_Index), \
+ (_Override), \
+ (LPVOID *)&(_Original)); \
+ } \
+}
+
+using GameInputCreate_pfn = HRESULT (WINAPI *)(IGameInput**);
+ GameInputCreate_pfn
+ GameInputCreate_Original = nullptr;
+
+static IGameInputDevice *s_virtual_gameinput_device = nullptr;
+
+HRESULT
+STDMETHODCALLTYPE
+SK_IWrapGameInput::QueryInterface (REFIID riid, void **ppvObject) noexcept
+{
+ if (ppvObject == nullptr)
+ {
+ return E_POINTER;
+ }
+
+ if ( riid == __uuidof (IUnknown) ||
+ riid == __uuidof (IGameInput) )
+ {
+ auto _GetVersion = [](REFIID riid) ->
+ UINT
+ {
+ if (riid == __uuidof (IGameInput)) return 0;
+
+ return 0;
+ };
+
+ UINT required_ver =
+ _GetVersion (riid);
+
+ if (ver_ < required_ver)
+ {
+ IUnknown* pPromoted = nullptr;
+
+ if ( FAILED (
+ pReal->QueryInterface ( riid,
+ (void **)&pPromoted )
+ ) || pPromoted == nullptr
+ )
+ {
+ return E_NOINTERFACE;
+ }
+
+ ver_ =
+ SK_COM_PromoteInterface (&pReal, pPromoted) ?
+ required_ver : ver_;
+ }
+
+ else
+ {
+ AddRef ();
+ }
+
+ *ppvObject = this;
+
+ return S_OK;
+ }
+
+ HRESULT hr =
+ pReal->QueryInterface (riid, ppvObject);
+
+ static
+ concurrency::concurrent_unordered_set reported_guids;
+
+ wchar_t wszGUID [41] = { };
+ StringFromGUID2 (riid, wszGUID, 40);
+
+ bool once =
+ reported_guids.count (wszGUID) > 0;
+
+ if (! once)
+ {
+ reported_guids.insert (wszGUID);
+
+ SK_LOG0 ( ( L"QueryInterface on wrapped IGameInput for Mystery UUID: %s",
+ wszGUID ), L"Game Input" );
+ }
+
+ return hr;
+};
+
+ULONG
+STDMETHODCALLTYPE
+SK_IWrapGameInput::AddRef (void) noexcept
+{
+ InterlockedIncrement (&refs_);
+
+ return
+ pReal->AddRef ();
+};
+
+ULONG
+STDMETHODCALLTYPE
+SK_IWrapGameInput::Release (void) noexcept
+{
+ ULONG xrefs =
+ InterlockedDecrement (&refs_),
+ refs = pReal->Release ();
+
+ if (xrefs == 0)
+ {
+ if (refs != 0)
+ {
+ SK_LOG0 ( ( L"Inconsistent reference count for IGameInput; expected=%d, actual=%d",
+ xrefs, refs ),
+ L"Game Input" );
+ }
+
+ else
+ delete this;
+ }
+
+ return
+ refs;
+};
+
+uint64_t
+STDMETHODCALLTYPE
+SK_IWrapGameInput::GetCurrentTimestamp (void) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return pReal->GetCurrentTimestamp ();
+}
+
+static concurrency::concurrent_unordered_map >> _current_readings;
+
+HRESULT
+STDMETHODCALLTYPE
+SK_IWrapGameInput::GetCurrentReading (_In_ GameInputKind inputKind,
+ _In_opt_ IGameInputDevice *device,
+ _COM_Outptr_ IGameInputReading **reading) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ bool capture_input = false;
+
+ if (device == s_virtual_gameinput_device)
+ {
+ static SK_IPlayStationGameInputReading virtual_current_reading (0);
+ *reading = (IGameInputReading *)&virtual_current_reading;
+ return S_OK;
+ }
+
+ switch (inputKind)
+ {
+ case GameInputKindKeyboard:
+ if (SK_ImGui_WantKeyboardCapture ())
+ {
+ capture_input = true;
+ }
+ break;
+
+ case GameInputKindMouse:
+ case GameInputKindTouch:
+ if (SK_ImGui_WantMouseCapture ())
+ {
+ capture_input = true;
+ }
+ break;
+
+ case GameInputKindGamepad:
+ case GameInputKindController:
+ case GameInputKindControllerSwitch:
+ case GameInputKindControllerButton:
+ case GameInputKindControllerAxis:
+ case GameInputKindRawDeviceReport:
+ case GameInputKindUiNavigation:
+ if (SK_ImGui_WantGamepadCapture ())
+ {
+ capture_input = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (! capture_input)
+ {
+ HRESULT hr =
+ pReal->GetCurrentReading (inputKind, device, reading);
+
+ if (reading != nullptr)
+ _current_readings [device][inputKind] = *reading;
+
+ return hr;
+ }
+
+ else
+ {
+ if (reading != nullptr && _current_readings.count (device) &&
+ _current_readings [device].count (inputKind) &&
+ _current_readings [device][inputKind].p != nullptr) {
+ _current_readings [device][inputKind].p->AddRef ();
+ *reading = _current_readings [device][inputKind];
+ return S_OK;
+ }
+
+ else if (reading != nullptr)
+ {
+ HRESULT hr =
+ pReal->GetCurrentReading (inputKind, device, reading);
+ _current_readings [device][inputKind] = *reading;
+
+ return hr;
+ }
+ }
+
+ return
+ pReal->GetCurrentReading (inputKind, device, reading);
+}
+
+using IGameInputDevice_SetHapticMotorState_pfn = HRESULT (STDMETHODCALLTYPE *)(IGameInputDevice*,uint32_t,GameInputHapticFeedbackParams const*) noexcept;
+using IGameInputDevice_SetRumbleState_pfn = void (STDMETHODCALLTYPE *)(IGameInputDevice*,GameInputRumbleParams const*) noexcept;
+
+IGameInputDevice_SetHapticMotorState_pfn IGameInputDevice_SetHapticMotorState_Original = nullptr;
+IGameInputDevice_SetRumbleState_pfn IGameInputDevice_SetRumbleState_Original = nullptr;
+
+HRESULT
+STDMETHODCALLTYPE
+IGameInputDevice_SetHapticMotorState_Override (IGameInputDevice *This, uint32_t motorIndex, GameInputHapticFeedbackParams const* params) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ if (params != nullptr)
+ {
+ auto params_ = params != nullptr ? *params : GameInputHapticFeedbackParams {};
+
+ if (config.input.gamepad.disable_rumble || SK_ImGui_WantGamepadCapture ())
+ {
+ params_ = {};
+ }
+
+ return
+ IGameInputDevice_SetHapticMotorState_Original (This, motorIndex, ¶ms_);
+ }
+
+ return
+ IGameInputDevice_SetHapticMotorState_Original (This, motorIndex, nullptr);
+}
+
+void
+STDMETHODCALLTYPE
+IGameInputDevice_SetRumbleState_Override (IGameInputDevice *This, GameInputRumbleParams const *params) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ auto params_ = params != nullptr ? *params : GameInputRumbleParams {};
+
+ //if (params_.leftTrigger > 0.0f || params_.rightTrigger > 0.0f)
+ //{
+ // SK_RunOnce (SK_ImGui_Warning (L"Game uses Impulse Triggers!"));
+ //}
+
+ if (config.input.gamepad.disable_rumble || SK_ImGui_WantGamepadCapture ())
+ {
+ params_.highFrequency = params_.lowFrequency = 0.0f;
+ params_.leftTrigger = params_.rightTrigger = 0.0f;
+ }
+
+ return
+ IGameInputDevice_SetRumbleState_Original (This, ¶ms_);
+}
+
+HRESULT
+STDMETHODCALLTYPE
+SK_IWrapGameInput::GetNextReading (_In_ IGameInputReading *referenceReading,
+ _In_ GameInputKind inputKind,
+ _In_opt_ IGameInputDevice *device,
+ _COM_Outptr_ IGameInputReading **reading) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ bool capture_input = false;
+
+ if (device != nullptr && device != s_virtual_gameinput_device)
+ {
+ SK_RunOnce (
+ GI_VIRTUAL_HOOK ( &device, 9,
+ "IGameInputDevice::SetHapticMotorState",
+ IGameInputDevice_SetHapticMotorState_Override,
+ IGameInputDevice_SetHapticMotorState_Original,
+ IGameInputDevice_SetHapticMotorState_pfn );
+ GI_VIRTUAL_HOOK ( &device, 10,
+ "IGameInputDevice::SetRunbleState",
+ IGameInputDevice_SetRumbleState_Override,
+ IGameInputDevice_SetRumbleState_Original,
+ IGameInputDevice_SetRumbleState_pfn );
+
+ SK_ApplyQueuedHooks ();
+ );
+ }
+
+ switch (inputKind)
+ {
+ case GameInputKindKeyboard:
+ SK_GAMEINPUT_READ (sk_input_dev_type::Keyboard);
+ if (SK_ImGui_WantKeyboardCapture ())
+ { SK_GAMEINPUT_HIDE (sk_input_dev_type::Keyboard);
+ capture_input = true;
+ } else
+ { SK_GAMEINPUT_VIEW (sk_input_dev_type::Keyboard); }
+ break;
+
+ case GameInputKindMouse:
+ case GameInputKindTouch:
+ SK_GAMEINPUT_READ (sk_input_dev_type::Mouse);
+ if (SK_ImGui_WantMouseCapture ())
+ { SK_GAMEINPUT_HIDE (sk_input_dev_type::Mouse);
+ capture_input = true;
+ } else
+ { SK_GAMEINPUT_VIEW (sk_input_dev_type::Mouse); }
+ break;
+
+ case GameInputKindGamepad:
+ case GameInputKindController:
+ case GameInputKindControllerSwitch:
+ case GameInputKindControllerButton:
+ case GameInputKindControllerAxis:
+ case GameInputKindRawDeviceReport:
+ case GameInputKindUiNavigation:
+ {
+ // 1 frame delay before blocking, so we have time to neutralize input readings
+ static concurrency::concurrent_unordered_map >
+ capture_last_frame;
+ const bool capture_this_frame = SK_ImGui_WantGamepadCapture ();
+ SK_GAMEINPUT_READ (sk_input_dev_type::Gamepad);
+ if (capture_this_frame && capture_last_frame [device][inputKind])
+ { SK_GAMEINPUT_HIDE (sk_input_dev_type::Gamepad);
+ capture_input = true;
+ } else
+ { SK_GAMEINPUT_VIEW (sk_input_dev_type::Gamepad); }
+ capture_last_frame [device][inputKind] = capture_this_frame;
+ } break;
+
+ default:
+ break;
+ }
+
+ if (capture_input)
+ {
+ if (reading != nullptr)
+ *reading = nullptr;
+ return GAMEINPUT_E_READING_NOT_FOUND;
+ }
+
+ if (device == s_virtual_gameinput_device && inputKind == GameInputKindGamepad)
+ {
+ static SK_IPlayStationGameInputReading virtual_next_reading (0);
+ static UINT64 last_virtual_active = 0;
+ UINT64 virtual_active = 0;
+
+ if (! SK_HID_PlayStationControllers.empty ())
+ {
+ if (config.input.gamepad.xinput.emulate && (! config.input.gamepad.xinput.blackout_api))
+ {
+ SK_HID_PlayStationDevice *pNewestInputDevice = nullptr;
+
+ for ( auto& controller : SK_HID_PlayStationControllers )
+ {
+ if (controller.bConnected)
+ {
+ if (pNewestInputDevice == nullptr ||
+ pNewestInputDevice->xinput.last_active < controller.xinput.last_active)
+ {
+ pNewestInputDevice = &controller;
+ }
+ }
+ }
+
+ if (pNewestInputDevice != nullptr)
+ {
+ virtual_active = pNewestInputDevice->xinput.last_active;
+ }
+ }
+ }
+
+ if (std::exchange (last_virtual_active, virtual_active) != last_virtual_active)
+ {
+ if (reading != nullptr)
+ *reading = (IGameInputReading *)&virtual_next_reading;
+
+ return S_OK;
+ }
+
+ if (reading != nullptr)
+ *reading = nullptr;
+
+ return GAMEINPUT_E_READING_NOT_FOUND;
+ }
+
+ const GameInputDeviceInfo* info =
+ device->GetDeviceInfo ();
+
+ SK_RunOnce (
+ {
+ SK_LOGi0 (L"GameInputDevice: VID=%x", info->vendorId);
+ SK_LOGi0 (L"GameInputDevice: PID=%x", info->productId);
+ SK_LOGi0 (L"GameInputDevice: Revision=%d", info->revisionNumber);
+ SK_LOGi0 (L"GameInputDevice: Id=%x", info->deviceId);
+ SK_LOGi0 (L"GameInputDevice: RootId=%x", info->deviceRootId);
+ SK_LOGi0 (L"GameInputDevice: DeviceFamily=%x", info->deviceFamily);
+ SK_LOGi0 (L"GameInputDevice: Usage={%x,%x}", info->usage.id, info->usage.page);
+ SK_LOGi0 (L"GameInputDevice: Interface=%d", info->interfaceNumber);
+ SK_LOGi0 (L"GameInputDevice: Collection=%d", info->collectionNumber);
+ SK_LOGi0 (L"GameInputDevice: HW Version="
+ "%01d.%01d.%01d.%01d", info->hardwareVersion.major, info->hardwareVersion.minor,
+ info->hardwareVersion.build, info->hardwareVersion.revision);
+ SK_LOGi0 (L"GameInputDevice: FW Version="
+ "%01d.%01d.%01d.%01d", info->firmwareVersion.major, info->firmwareVersion.minor,
+ info->firmwareVersion.build, info->firmwareVersion.revision);
+ SK_LOGi0 (L"GameInputDevice: Capabilities=%x", info->capabilities);
+ SK_LOGi0 (L"GameInputDevice: SupportedInput=%x", info->supportedInput);
+ SK_LOGi0 (L"GameInputDevice: SupportedRumbleMotors=%x", info->supportedRumbleMotors);
+ SK_LOGi0 (L"GameInputDevice: SupportedSystemButtons=%x",info->supportedSystemButtons);
+ });
+
+ if (inputKind == GameInputKindGamepad)
+ {
+ IGameInputReading *reading_;
+
+ HRESULT hr =
+ pReal->GetNextReading (referenceReading, inputKind, device, &reading_);
+
+ if (SUCCEEDED (hr))
+ {
+ if (reading != nullptr)
+ {
+ *reading = (IGameInputReading *)new SK_IWrapGameInputReading (reading_);
+ _current_readings [device][inputKind] = *reading;
+ }
+
+ else
+ {
+ reading_->Release ();
+ }
+
+ return hr;
+ }
+ }
+
+ return
+ pReal->GetNextReading (referenceReading, inputKind, device, reading);
+}
+
+HRESULT
+STDMETHODCALLTYPE
+SK_IWrapGameInput::GetPreviousReading (_In_ IGameInputReading *referenceReading,
+ _In_ GameInputKind inputKind,
+ _In_opt_ IGameInputDevice *device,
+ _COM_Outptr_ IGameInputReading **reading) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ bool capture_input = false;
+ static concurrency::concurrent_unordered_map >> readings;
+
+ switch (inputKind)
+ {
+ case GameInputKindKeyboard:
+ if (SK_ImGui_WantKeyboardCapture ())
+ {
+ capture_input = true;
+ }
+ break;
+
+ case GameInputKindMouse:
+ case GameInputKindTouch:
+ if (SK_ImGui_WantMouseCapture ())
+ {
+ capture_input = true;
+ }
+ break;
+
+ case GameInputKindGamepad:
+ case GameInputKindController:
+ case GameInputKindControllerSwitch:
+ case GameInputKindControllerButton:
+ case GameInputKindControllerAxis:
+ case GameInputKindRawDeviceReport:
+ case GameInputKindUiNavigation:
+ if (SK_ImGui_WantGamepadCapture ())
+ {
+ capture_input = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (! capture_input)
+ {
+ HRESULT hr =
+ pReal->GetPreviousReading (referenceReading, inputKind, device, reading);
+
+ if (reading != nullptr)
+ readings [device][inputKind] = *reading;
+
+ return hr;
+ }
+
+ else
+ {
+ if (reading != nullptr && readings.count (device) &&
+ readings [device].count (inputKind) &&
+ readings [device] [inputKind].p != nullptr) {
+ readings [device][inputKind].p->AddRef ();
+ *reading = readings [device][inputKind];
+ }
+
+ else if (SUCCEEDED (pReal->GetPreviousReading (referenceReading, inputKind, device, reading)))
+ {
+ if (reading != nullptr)
+ {
+ readings [device][inputKind] = *reading;
+ }
+ }
+
+ return S_OK;
+ }
+}
+
+HRESULT
+STDMETHODCALLTYPE
+SK_IWrapGameInput::GetTemporalReading (_In_ uint64_t timestamp,
+ _In_ IGameInputDevice *device,
+ _COM_Outptr_ IGameInputReading **reading) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->GetTemporalReading (timestamp, device, reading);
+}
+
+HRESULT
+STDMETHODCALLTYPE
+SK_IWrapGameInput::RegisterReadingCallback (_In_opt_ IGameInputDevice *device,
+ _In_ GameInputKind inputKind,
+ _In_ float analogThreshold,
+ _In_opt_ void *context,
+ _In_ GameInputReadingCallback callbackFunc,
+ _Out_opt_ _Result_zeroonfailure_ GameInputCallbackToken *callbackToken) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->RegisterReadingCallback (device, inputKind, analogThreshold, context, callbackFunc, callbackToken);
+}
+
+HRESULT
+STDMETHODCALLTYPE
+SK_IWrapGameInput::RegisterDeviceCallback (_In_opt_ IGameInputDevice *device,
+ _In_ GameInputKind inputKind,
+ _In_ GameInputDeviceStatus statusFilter,
+ _In_ GameInputEnumerationKind enumerationKind,
+ _In_opt_ void *context,
+ _In_ GameInputDeviceCallback callbackFunc,
+ _Out_opt_ _Result_zeroonfailure_ GameInputCallbackToken *callbackToken) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ HRESULT hr =
+ pReal->RegisterDeviceCallback (device, inputKind, statusFilter, enumerationKind, context, callbackFunc, callbackToken);
+
+ if (SUCCEEDED (hr) && inputKind == GameInputKindGamepad && (statusFilter & GameInputDeviceConnected) != 0 && (config.input.gamepad.xinput.emulate || ! SK_XInput_PollController (0)))
+ {
+ // TODO: Implement hotplug
+ if (s_virtual_gameinput_device == nullptr)
+ s_virtual_gameinput_device = (IGameInputDevice *)new SK_IGameInputDevice (nullptr);
+
+ callbackFunc (callbackToken != nullptr ? *callbackToken : 0, context, s_virtual_gameinput_device, SK_QueryPerf ().QuadPart, GameInputDeviceConnected, GameInputDeviceConnected);
+ }
+
+ return hr;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+SK_IWrapGameInput::RegisterSystemButtonCallback (_In_opt_ IGameInputDevice *device,
+ _In_ GameInputSystemButtons buttonFilter,
+ _In_opt_ void *context,
+ _In_ GameInputSystemButtonCallback callbackFunc,
+ _Out_opt_ _Result_zeroonfailure_ GameInputCallbackToken *callbackToken) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->RegisterSystemButtonCallback (device, buttonFilter, context, callbackFunc, callbackToken);
+}
+
+HRESULT
+STDMETHODCALLTYPE
+SK_IWrapGameInput::RegisterKeyboardLayoutCallback (_In_opt_ IGameInputDevice *device,
+ _In_opt_ void *context,
+ _In_ GameInputKeyboardLayoutCallback callbackFunc,
+ _Out_opt_ _Result_zeroonfailure_ GameInputCallbackToken *callbackToken) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->RegisterKeyboardLayoutCallback (device, context, callbackFunc, callbackToken);
+}
+
+void
+STDMETHODCALLTYPE
+SK_IWrapGameInput::StopCallback (_In_ GameInputCallbackToken callbackToken) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->StopCallback (callbackToken);
+}
+
+bool
+STDMETHODCALLTYPE
+SK_IWrapGameInput::UnregisterCallback (_In_ GameInputCallbackToken callbackToken,
+ _In_ uint64_t timeoutInMicroseconds) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->UnregisterCallback (callbackToken, timeoutInMicroseconds);
+}
+
+HRESULT
+STDMETHODCALLTYPE
+SK_IWrapGameInput::CreateDispatcher (_COM_Outptr_ IGameInputDispatcher **dispatcher) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->CreateDispatcher (dispatcher);
+}
+
+HRESULT
+STDMETHODCALLTYPE
+SK_IWrapGameInput::CreateAggregateDevice (_In_ GameInputKind inputKind,
+ _COM_Outptr_ IGameInputDevice **device) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->CreateAggregateDevice (inputKind, device);
+}
+
+HRESULT
+STDMETHODCALLTYPE
+SK_IWrapGameInput::FindDeviceFromId (_In_ APP_LOCAL_DEVICE_ID const *value,
+ _COM_Outptr_ IGameInputDevice **device) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->FindDeviceFromId (value, device);
+}
+
+HRESULT
+STDMETHODCALLTYPE
+SK_IWrapGameInput::FindDeviceFromObject (_In_ IUnknown *value,
+ _COM_Outptr_ IGameInputDevice **device) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->FindDeviceFromObject (value, device);
+}
+
+HRESULT
+STDMETHODCALLTYPE
+SK_IWrapGameInput::FindDeviceFromPlatformHandle (_In_ HANDLE value,
+ _COM_Outptr_ IGameInputDevice **device) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->FindDeviceFromPlatformHandle (value, device);
+}
+
+HRESULT
+STDMETHODCALLTYPE
+SK_IWrapGameInput::FindDeviceFromPlatformString (_In_ LPCWSTR value,
+ _COM_Outptr_ IGameInputDevice **device) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->FindDeviceFromPlatformString (value, device);
+}
+
+HRESULT
+STDMETHODCALLTYPE
+SK_IWrapGameInput::EnableOemDeviceSupport (_In_ uint16_t vendorId,
+ _In_ uint16_t productId,
+ _In_ uint8_t interfaceNumber,
+ _In_ uint8_t collectionNumber) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->EnableOemDeviceSupport (vendorId, productId, interfaceNumber, collectionNumber);
+}
+
+void
+STDMETHODCALLTYPE
+SK_IWrapGameInput::SetFocusPolicy (_In_ GameInputFocusPolicy policy) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->SetFocusPolicy (policy);
+}
+
+
+HRESULT
+WINAPI
+GameInputCreate_Detour (IGameInput** gameInput)
+{
+ SK_LOG_FIRST_CALL
+
+ IGameInput* pReal;
+
+ HRESULT hr =
+ GameInputCreate_Original (&pReal);
+
+ if (SUCCEEDED (hr))
+ {
+ if (gameInput != nullptr)
+ {
+ // Turn on XInput emulation by default on first-run for Unreal Engine.
+ //
+ // -> Their GameInput integration is extremely simple and SK is fully compatible.
+ //
+ if (config.system.first_run && (! SK_XInput_PollController (0)))
+ {
+ SK_RunOnce (if (! SK_ImGui_HasPlayStationController ())
+ SK_HID_SetupPlayStationControllers ());
+
+ if (SK_ImGui_HasPlayStationController () && StrStrIW (SK_GetFullyQualifiedApp (), L"WinGDK"))
+ {
+ SK_LOGi0 (L"Enabling Xbox Mode because Unreal Engine is using GameInput...");
+
+ config.input.gamepad.xinput.emulate = true;
+ }
+ }
+
+ *gameInput = (IGameInput *)new SK_IWrapGameInput (pReal);
+ }
+
+ else
+ {
+ pReal->Release ();
+ }
+ }
+
+ return hr;
+}
+
+
+#pragma warning (disable: 4100)
+
+HRESULT
+__stdcall
+SK_IGameInputDevice::QueryInterface (REFIID riid, void **ppvObject) noexcept
+{
+ if (ppvObject == nullptr)
+ {
+ return E_POINTER;
+ }
+
+ if ( riid == __uuidof (IUnknown) ||
+ riid == __uuidof (IGameInputDevice) )
+ {
+ AddRef ();
+
+ *ppvObject = this;
+
+ return S_OK;
+ }
+
+ static
+ concurrency::concurrent_unordered_set reported_guids;
+
+ wchar_t wszGUID [41] = { };
+ StringFromGUID2 (riid, wszGUID, 40);
+
+ bool once =
+ reported_guids.count (wszGUID) > 0;
+
+ if (! once)
+ {
+ reported_guids.insert (wszGUID);
+
+ SK_LOG0 ( ( L"QueryInterface on wrapped IGameInputDevice for Mystery UUID: %s",
+ wszGUID ), L"Game Input" );
+ }
+
+ return E_NOINTERFACE;
+}
+
+ULONG
+__stdcall
+SK_IGameInputDevice::AddRef (void) noexcept
+{
+ return InterlockedIncrement (&refs_);
+}
+
+ULONG
+__stdcall
+SK_IGameInputDevice::Release (void) noexcept
+{
+ return InterlockedDecrement (&refs_);
+}
+
+GameInputDeviceInfo const*
+__stdcall
+SK_IGameInputDevice::GetDeviceInfo (void) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ static GameInputDeviceInfo dev_info = {};
+
+ dev_info.infoSize = sizeof (GameInputDeviceInfo);
+
+ dev_info.controllerAxisCount = 6;
+ dev_info.controllerButtonCount = 13;
+
+ dev_info.deviceId = {1};
+ dev_info.deviceRootId = {1};
+
+ dev_info.capabilities = GameInputDeviceCapabilityPowerOff | GameInputDeviceCapabilityWireless;
+
+ dev_info.vendorId = 0x45e;
+ dev_info.productId = 0x28e;
+
+ dev_info.deviceFamily = GameInputFamilyXbox360;
+ dev_info.usage.id = 5;
+ dev_info.usage.page = 1;
+
+ dev_info.interfaceNumber = 0;
+
+ dev_info.supportedInput = GameInputKindControllerAxis | GameInputKindControllerButton | GameInputKindGamepad | GameInputKindUiNavigation;
+ dev_info.supportedRumbleMotors = GameInputRumbleLowFrequency | GameInputRumbleHighFrequency;
+ dev_info.supportedSystemButtons = GameInputSystemButtonGuide;
+
+ return &dev_info;
+}
+
+GameInputDeviceStatus
+__stdcall
+SK_IGameInputDevice::GetDeviceStatus (void) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ GameInputDeviceStatus ret = GameInputDeviceNoStatus;
+
+ if (SK_ImGui_HasPlayStationController ())
+ {
+ ret |= GameInputDeviceConnected | GameInputDeviceInputEnabled | GameInputDeviceOutputEnabled;
+ }
+
+ return ret;
+}
+
+void
+__stdcall
+SK_IGameInputDevice::GetBatteryState (GameInputBatteryState *state) noexcept
+{
+ SK_LOG_FIRST_CALL
+}
+
+HRESULT
+__stdcall
+SK_IGameInputDevice::CreateForceFeedbackEffect (uint32_t motorIndex,
+ GameInputForceFeedbackParams const *params,
+ IGameInputForceFeedbackEffect **effect) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return E_NOTIMPL;
+}
+
+bool
+__stdcall
+SK_IGameInputDevice::IsForceFeedbackMotorPoweredOn (uint32_t motorIndex) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return false;
+}
+
+void
+__stdcall
+SK_IGameInputDevice::SetForceFeedbackMotorGain (uint32_t motorIndex, float masterGain) noexcept
+{
+ SK_LOG_FIRST_CALL
+}
+
+HRESULT
+__stdcall
+SK_IGameInputDevice::SetHapticMotorState (uint32_t motorIndex,
+ GameInputHapticFeedbackParams const *params) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ // ...
+
+ return S_OK;
+}
+
+void
+__stdcall
+SK_IGameInputDevice::SetRumbleState (GameInputRumbleParams const *params) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ if (config.input.gamepad.disable_rumble)
+ {
+ SK_XInput_ZeroHaptics (0);
+ return;
+ }
+
+ if (! params)
+ {
+ if (! SK_ImGui_WantGamepadCapture ())
+ {
+ if (config.input.gamepad.xinput.emulate && (! config.input.gamepad.xinput.blackout_api))
+ {
+ SK_XInput_ZeroHaptics (0);
+ }
+ }
+
+ return;
+ }
+
+ GameInputRumbleParams params_ = *params;
+
+ if (config.input.gamepad.xinput.emulate && (! config.input.gamepad.xinput.blackout_api) && (! SK_ImGui_WantGamepadCapture ()))
+ {
+ if (params_.leftTrigger == 0 && params_.rightTrigger == 0)
+ {
+ const float left = params_.lowFrequency;
+ const float right = params_.highFrequency;
+
+ SK_XInput_PulseController ( 0, std::clamp (left, 0.0f, 1.0f),
+ std::clamp (right, 0.0f, 1.0f) );
+ }
+
+ else
+ {
+ if (config.input.gamepad.xinput.emulate && (! config.input.gamepad.xinput.blackout_api))
+ {
+ SK_HID_PlayStationDevice *pNewestInputDevice = nullptr;
+
+ for ( auto& controller : SK_HID_PlayStationControllers )
+ {
+ if (controller.bConnected)
+ {
+ if (pNewestInputDevice == nullptr ||
+ pNewestInputDevice->xinput.last_active < controller.xinput.last_active)
+ {
+ pNewestInputDevice = &controller;
+ }
+ }
+ }
+
+ if (pNewestInputDevice != nullptr)
+ {
+ pNewestInputDevice->setVibration (std::min (65535ui16, static_cast (params_.lowFrequency * 65536.0f)),
+ std::min (65535ui16, static_cast (params_.highFrequency * 65536.0f)),
+ std::min (65535ui16, static_cast (params_.leftTrigger * 65536.0f)),
+ std::min (65535ui16, static_cast (params_.rightTrigger * 65536.0f)), 65535ui16);
+ }
+ }
+ }
+ }
+}
+
+void
+__stdcall
+SK_IGameInputDevice::SetInputSynchronizationState (bool enabled) noexcept
+{
+ SK_LOG_FIRST_CALL
+}
+
+void
+__stdcall
+SK_IGameInputDevice::SendInputSynchronizationHint (void) noexcept
+{
+ SK_LOG_FIRST_CALL
+}
+
+void
+__stdcall
+SK_IGameInputDevice::PowerOff (void) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ // ...
+}
+
+HRESULT
+__stdcall
+SK_IGameInputDevice::CreateRawDeviceReport (uint32_t reportId,
+ GameInputRawDeviceReportKind reportKind,
+ IGameInputRawDeviceReport **report) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return E_NOTIMPL;
+}
+
+HRESULT
+__stdcall
+SK_IGameInputDevice::GetRawDeviceFeature (uint32_t reportId,
+ IGameInputRawDeviceReport **report) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return E_NOTIMPL;
+}
+
+HRESULT
+__stdcall
+SK_IGameInputDevice::SetRawDeviceFeature (IGameInputRawDeviceReport *report) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return E_NOTIMPL;
+}
+
+HRESULT
+__stdcall
+SK_IGameInputDevice::SendRawDeviceOutput (IGameInputRawDeviceReport *report) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return E_NOTIMPL;
+}
+
+HRESULT
+__stdcall
+SK_IGameInputDevice::SendRawDeviceOutputWithResponse (IGameInputRawDeviceReport *requestReport,
+ IGameInputRawDeviceReport **responseReport) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return E_NOTIMPL;
+}
+
+HRESULT
+__stdcall
+SK_IGameInputDevice::ExecuteRawDeviceIoControl (uint32_t controlCode,
+ size_t inputBufferSize,
+ void const *inputBuffer,
+ size_t outputBufferSize,
+ void *outputBuffer,
+ size_t *outputSize) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return E_NOTIMPL;
+}
+
+bool
+__stdcall
+SK_IGameInputDevice::AcquireExclusiveRawDeviceAccess (uint64_t timeoutInMicroseconds) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return true;
+}
+
+void
+__stdcall
+SK_IGameInputDevice::ReleaseExclusiveRawDeviceAccess(void) noexcept
+{
+ SK_LOG_FIRST_CALL
+}
+
+
+HRESULT
+STDMETHODCALLTYPE
+SK_IWrapGameInputReading::QueryInterface (REFIID riid, void **ppvObject) noexcept
+{
+ if (ppvObject == nullptr)
+ {
+ return E_POINTER;
+ }
+
+ if ( riid == __uuidof (IUnknown) ||
+ riid == __uuidof (IGameInputReading) )
+ {
+ auto _GetVersion = [](REFIID riid) ->
+ UINT
+ {
+ if (riid == __uuidof (IGameInputReading)) return 0;
+
+ return 0;
+ };
+
+ UINT required_ver =
+ _GetVersion (riid);
+
+ if (ver_ < required_ver)
+ {
+ IUnknown* pPromoted = nullptr;
+
+ if ( FAILED (
+ pReal->QueryInterface ( riid,
+ (void **)&pPromoted )
+ ) || pPromoted == nullptr
+ )
+ {
+ return E_NOINTERFACE;
+ }
+
+ ver_ =
+ SK_COM_PromoteInterface (&pReal, pPromoted) ?
+ required_ver : ver_;
+ }
+
+ else
+ {
+ AddRef ();
+ }
+
+ *ppvObject = this;
+
+ return S_OK;
+ }
+
+ HRESULT hr =
+ pReal->QueryInterface (riid, ppvObject);
+
+ static
+ concurrency::concurrent_unordered_set reported_guids;
+
+ wchar_t wszGUID [41] = { };
+ StringFromGUID2 (riid, wszGUID, 40);
+
+ bool once =
+ reported_guids.count (wszGUID) > 0;
+
+ if (! once)
+ {
+ reported_guids.insert (wszGUID);
+
+ SK_LOG0 ( ( L"QueryInterface on wrapped IGameInputReading for Mystery UUID: %s",
+ wszGUID ), L"Game Input" );
+ }
+
+ return hr;
+}
+
+ULONG
+STDMETHODCALLTYPE
+SK_IWrapGameInputReading::AddRef (void) noexcept
+{
+ InterlockedIncrement (&refs_);
+
+ return
+ pReal->AddRef ();
+}
+
+ULONG
+STDMETHODCALLTYPE
+SK_IWrapGameInputReading::Release (void) noexcept
+{
+ ULONG xrefs =
+ InterlockedDecrement (&refs_),
+ refs = pReal->Release ();
+
+ if (xrefs == 0)
+ {
+ if (refs != 0)
+ {
+ SK_LOG0 ( ( L"Inconsistent reference count for IGameInputReading; expected=%d, actual=%d",
+ xrefs, refs ),
+ L"Game Input" );
+ }
+
+ else
+ delete this;
+ }
+
+ return
+ refs;
+}
+
+GameInputKind
+STDMETHODCALLTYPE
+SK_IWrapGameInputReading::GetInputKind (void) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->GetInputKind ();
+}
+
+uint64_t
+STDMETHODCALLTYPE
+SK_IWrapGameInputReading::GetSequenceNumber (GameInputKind inputKind) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->GetSequenceNumber (inputKind);
+}
+
+uint64_t
+STDMETHODCALLTYPE
+SK_IWrapGameInputReading::GetTimestamp (void) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->GetTimestamp ();
+}
+
+void
+STDMETHODCALLTYPE
+SK_IWrapGameInputReading::GetDevice (IGameInputDevice **device) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->GetDevice (device);
+}
+
+bool
+STDMETHODCALLTYPE
+SK_IWrapGameInputReading::GetRawReport (IGameInputRawDeviceReport **report) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->GetRawReport (report);
+}
+
+uint32_t
+STDMETHODCALLTYPE
+SK_IWrapGameInputReading::GetControllerAxisCount (void) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->GetControllerAxisCount ();
+}
+
+uint32_t
+STDMETHODCALLTYPE
+SK_IWrapGameInputReading::GetControllerAxisState (uint32_t stateArrayCount,
+ float *stateArray) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->GetControllerAxisState (stateArrayCount, stateArray);
+}
+
+uint32_t
+STDMETHODCALLTYPE
+SK_IWrapGameInputReading::GetControllerButtonCount (void) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->GetControllerButtonCount ();
+}
+
+uint32_t
+STDMETHODCALLTYPE
+SK_IWrapGameInputReading::GetControllerButtonState (uint32_t stateArrayCount,
+ bool *stateArray) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->GetControllerButtonState (stateArrayCount, stateArray);
+}
+
+uint32_t
+STDMETHODCALLTYPE
+SK_IWrapGameInputReading::GetControllerSwitchCount (void) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->GetControllerSwitchCount ();
+}
+
+uint32_t
+STDMETHODCALLTYPE
+SK_IWrapGameInputReading::GetControllerSwitchState (uint32_t stateArrayCount,
+ GameInputSwitchPosition *stateArray) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->GetControllerSwitchState (stateArrayCount, stateArray);
+}
+
+uint32_t
+STDMETHODCALLTYPE
+SK_IWrapGameInputReading::GetKeyCount (void) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->GetKeyCount ();
+}
+
+uint32_t
+STDMETHODCALLTYPE
+SK_IWrapGameInputReading::GetKeyState (uint32_t stateArrayCount,
+ GameInputKeyState *stateArray) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->GetKeyState (stateArrayCount, stateArray);
+}
+
+bool
+STDMETHODCALLTYPE
+SK_IWrapGameInputReading::GetMouseState (GameInputMouseState *state) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->GetMouseState (state);
+}
+
+uint32_t
+STDMETHODCALLTYPE
+SK_IWrapGameInputReading::GetTouchCount (void) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->GetTouchCount ();
+}
+
+uint32_t
+STDMETHODCALLTYPE
+SK_IWrapGameInputReading::GetTouchState (uint32_t stateArrayCount,
+ GameInputTouchState *stateArray) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->GetTouchState (stateArrayCount, stateArray);
+}
+
+bool
+STDMETHODCALLTYPE
+SK_IWrapGameInputReading::GetMotionState (GameInputMotionState *state) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->GetMotionState (state);
+}
+
+bool
+STDMETHODCALLTYPE
+SK_IWrapGameInputReading::GetArcadeStickState (GameInputArcadeStickState* state) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->GetArcadeStickState (state);
+}
+
+bool
+STDMETHODCALLTYPE
+SK_IWrapGameInputReading::GetFlightStickState (GameInputFlightStickState *state) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->GetFlightStickState (state);
+}
+
+bool
+STDMETHODCALLTYPE
+SK_IWrapGameInputReading::GetGamepadState (GameInputGamepadState *state) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+
+ if (pReal->GetGamepadState (state))
+ {
+ if (SK_ImGui_WantGamepadCapture ())
+ {
+ ZeroMemory (state, sizeof (GameInputGamepadState));
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool
+STDMETHODCALLTYPE
+SK_IWrapGameInputReading::GetRacingWheelState (GameInputRacingWheelState *state) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->GetRacingWheelState (state);
+}
+
+bool
+STDMETHODCALLTYPE
+SK_IWrapGameInputReading::GetUiNavigationState (GameInputUiNavigationState *state) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return
+ pReal->GetUiNavigationState (state);
+}
+
+void
+SK_Input_HookGameInput (void)
+{
+ if (! config.input.gamepad.hook_game_input)
+ return;
+
+ if (GetModuleHandleW (L"GameInput.dll") != nullptr)
+ {
+ static volatile LONG hooked = FALSE;
+ if (! InterlockedCompareExchange (&hooked, TRUE, FALSE))
+ {
+ SK_CreateDLLHook2 ( L"GameInput.dll",
+ "GameInputCreate",
+ GameInputCreate_Detour,
+ static_cast_p2p (&GameInputCreate_Original) );
+ SK_ApplyQueuedHooks ();
+ }
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+HRESULT
+STDMETHODCALLTYPE
+SK_IPlayStationGameInputReading::QueryInterface (REFIID riid, void **ppvObject) noexcept
+{
+ if (ppvObject == nullptr)
+ {
+ return E_POINTER;
+ }
+
+ if ( riid == __uuidof (IUnknown) ||
+ riid == __uuidof (IGameInputReading) )
+ {
+ AddRef ();
+
+ *ppvObject = this;
+
+ return S_OK;
+ }
+
+ static
+ concurrency::concurrent_unordered_set reported_guids;
+
+ wchar_t wszGUID [41] = { };
+ StringFromGUID2 (riid, wszGUID, 40);
+
+ bool once =
+ reported_guids.count (wszGUID) > 0;
+
+ if (! once)
+ {
+ reported_guids.insert (wszGUID);
+
+ SK_LOG0 ( ( L"QueryInterface on PlayStation IGameInputReading for Mystery UUID: %s",
+ wszGUID ), L"Game Input" );
+ }
+
+ return E_NOINTERFACE;
+}
+
+ULONG
+STDMETHODCALLTYPE
+SK_IPlayStationGameInputReading::AddRef (void) noexcept
+{
+ InterlockedIncrement (&refs_);
+
+ return refs_;
+}
+
+ULONG
+STDMETHODCALLTYPE
+SK_IPlayStationGameInputReading::Release (void) noexcept
+{
+ InterlockedDecrement (&refs_);
+
+ return refs_;
+}
+
+GameInputKind
+STDMETHODCALLTYPE
+SK_IPlayStationGameInputReading::GetInputKind (void) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return GameInputKindGamepad;
+}
+
+uint64_t
+STDMETHODCALLTYPE
+SK_IPlayStationGameInputReading::GetSequenceNumber (GameInputKind inputKind) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ SK_RunOnce (SK_LOGi0 (L"Stub"));
+
+ return 0;
+ //pReal->GetSequenceNumber (inputKind);
+}
+
+uint64_t
+STDMETHODCALLTYPE
+SK_IPlayStationGameInputReading::GetTimestamp (void) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ //
+ // Obviously this is implemented wrong, it should be accessing a history buffer
+ // of previous readings, not iterating through all PlayStation controllers and
+ // finding the one with the newest input.
+ //
+ // * This entire class should be encapsulating a single reading, not merely
+ // providing the data from the newest sampled input available (!!)
+ //
+ static volatile UINT64 last_timestamp = 0;
+
+ if (config.input.gamepad.xinput.emulate && (! config.input.gamepad.xinput.blackout_api))
+ {
+ UINT64 timestamp = ReadULong64Acquire (&last_timestamp);
+ const UINT64 orig_timestamp { timestamp };
+
+ if (! SK_HID_PlayStationControllers.empty ())
+ {
+ for (const auto& controller : SK_HID_PlayStationControllers)
+ {
+ if (controller.bConnected)
+ {
+ timestamp =
+ std::max (timestamp, controller.xinput.last_active);
+ }
+ }
+ }
+
+ if (timestamp > orig_timestamp)
+ {
+ InterlockedCompareExchange (
+ &last_timestamp, timestamp,
+ orig_timestamp
+ );
+ }
+ }
+
+ return
+ ReadULong64Acquire (&last_timestamp);
+}
+
+void
+STDMETHODCALLTYPE
+SK_IPlayStationGameInputReading::GetDevice (IGameInputDevice **device) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ SK_ReleaseAssert (s_virtual_gameinput_device != nullptr);
+
+ if (device != nullptr) {
+ s_virtual_gameinput_device->AddRef ();
+ *device = s_virtual_gameinput_device;
+ }
+}
+
+bool
+STDMETHODCALLTYPE
+SK_IPlayStationGameInputReading::GetRawReport (IGameInputRawDeviceReport **report) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ SK_RunOnce (SK_LOGi0 (L"Stub"));
+
+ return false;
+}
+
+uint32_t
+STDMETHODCALLTYPE
+SK_IPlayStationGameInputReading::GetControllerAxisCount (void) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return 6;
+}
+
+uint32_t
+STDMETHODCALLTYPE
+SK_IPlayStationGameInputReading::GetControllerAxisState (uint32_t stateArrayCount,
+ float *stateArray) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ SK_RunOnce (SK_LOGi0 (L"Stub"));
+
+ return 0;
+ //pReal->GetControllerAxisState (stateArrayCount, stateArray);
+}
+
+uint32_t
+STDMETHODCALLTYPE
+SK_IPlayStationGameInputReading::GetControllerButtonCount (void) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return 13;
+}
+
+uint32_t
+STDMETHODCALLTYPE
+SK_IPlayStationGameInputReading::GetControllerButtonState (uint32_t stateArrayCount,
+ bool *stateArray) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ SK_RunOnce (SK_LOGi0 (L"Stub"));
+
+ return 0;
+}
+
+uint32_t
+STDMETHODCALLTYPE
+SK_IPlayStationGameInputReading::GetControllerSwitchCount (void) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ SK_RunOnce (SK_LOGi0 (L"Stub"));
+
+ return 0;
+}
+
+uint32_t
+STDMETHODCALLTYPE
+SK_IPlayStationGameInputReading::GetControllerSwitchState (uint32_t stateArrayCount,
+ GameInputSwitchPosition *stateArray) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ SK_RunOnce (SK_LOGi0 (L"Stub"));
+
+ return 0;
+}
+
+uint32_t
+STDMETHODCALLTYPE
+SK_IPlayStationGameInputReading::GetKeyCount (void) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return 0;
+}
+
+uint32_t
+STDMETHODCALLTYPE
+SK_IPlayStationGameInputReading::GetKeyState (uint32_t stateArrayCount,
+ GameInputKeyState *stateArray) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return 0;
+}
+
+bool
+STDMETHODCALLTYPE
+SK_IPlayStationGameInputReading::GetMouseState (GameInputMouseState *state) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return false;
+}
+
+uint32_t
+STDMETHODCALLTYPE
+SK_IPlayStationGameInputReading::GetTouchCount (void) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ SK_RunOnce (SK_LOGi0 (L"Stub"));
+
+ return 0;
+}
+
+uint32_t
+STDMETHODCALLTYPE
+SK_IPlayStationGameInputReading::GetTouchState (uint32_t stateArrayCount,
+ GameInputTouchState *stateArray) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ SK_RunOnce (SK_LOGi0 (L"Stub"));
+
+ return 0;
+}
+
+bool
+STDMETHODCALLTYPE
+SK_IPlayStationGameInputReading::GetMotionState (GameInputMotionState *state) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return false;
+}
+
+bool
+STDMETHODCALLTYPE
+SK_IPlayStationGameInputReading::GetArcadeStickState (GameInputArcadeStickState* state) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return false;
+}
+
+bool
+STDMETHODCALLTYPE
+SK_IPlayStationGameInputReading::GetFlightStickState (GameInputFlightStickState *state) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return false;
+}
+
+bool
+STDMETHODCALLTYPE
+SK_IPlayStationGameInputReading::GetGamepadState (GameInputGamepadState *state) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ ZeroMemory (state, sizeof (GameInputGamepadState));
+
+ if (! SK_HID_PlayStationControllers.empty ())
+ {
+ if (config.input.gamepad.xinput.emulate && (! config.input.gamepad.xinput.blackout_api))
+ {
+ SK_HID_PlayStationDevice *pNewestInputDevice = nullptr;
+
+ for ( auto& controller : SK_HID_PlayStationControllers )
+ {
+ if (controller.bConnected)
+ {
+ if (pNewestInputDevice == nullptr ||
+ pNewestInputDevice->xinput.last_active < controller.xinput.last_active)
+ {
+ pNewestInputDevice = &controller;
+ }
+ }
+ }
+
+ if (pNewestInputDevice != nullptr)
+ {
+ if (! SK_ImGui_WantGamepadCapture ())
+ {
+ state->leftThumbstickX =
+ static_cast (static_cast (pNewestInputDevice->xinput.report.Gamepad.sThumbLX) / 32767.0);
+ state->leftThumbstickY =
+ static_cast (static_cast (pNewestInputDevice->xinput.report.Gamepad.sThumbLY) / 32767.0);
+
+ state->rightThumbstickX =
+ static_cast (static_cast (pNewestInputDevice->xinput.report.Gamepad.sThumbRX) / 32767.0);
+ state->rightThumbstickY =
+ static_cast (static_cast (pNewestInputDevice->xinput.report.Gamepad.sThumbRY) / 32767.0);
+
+ state->leftTrigger =
+ static_cast (static_cast (pNewestInputDevice->xinput.report.Gamepad.bLeftTrigger) / 255.0);
+ state->rightTrigger =
+ static_cast (static_cast (pNewestInputDevice->xinput.report.Gamepad.bRightTrigger) / 255.0);
+
+ state->buttons |= (pNewestInputDevice->xinput.report.Gamepad.wButtons & XINPUT_GAMEPAD_A) != 0 ? GameInputGamepadA : GameInputGamepadNone;
+ state->buttons |= (pNewestInputDevice->xinput.report.Gamepad.wButtons & XINPUT_GAMEPAD_B) != 0 ? GameInputGamepadB : GameInputGamepadNone;
+ state->buttons |= (pNewestInputDevice->xinput.report.Gamepad.wButtons & XINPUT_GAMEPAD_X) != 0 ? GameInputGamepadX : GameInputGamepadNone;
+ state->buttons |= (pNewestInputDevice->xinput.report.Gamepad.wButtons & XINPUT_GAMEPAD_Y) != 0 ? GameInputGamepadY : GameInputGamepadNone;
+
+ state->buttons |= (pNewestInputDevice->xinput.report.Gamepad.wButtons & XINPUT_GAMEPAD_START) != 0 ? GameInputGamepadMenu : GameInputGamepadNone;
+ state->buttons |= (pNewestInputDevice->xinput.report.Gamepad.wButtons & XINPUT_GAMEPAD_BACK) != 0 ? GameInputGamepadView : GameInputGamepadNone;
+
+ state->buttons |= (pNewestInputDevice->xinput.report.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) != 0 ? GameInputGamepadDPadUp : GameInputGamepadNone;
+ state->buttons |= (pNewestInputDevice->xinput.report.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) != 0 ? GameInputGamepadDPadDown : GameInputGamepadNone;
+ state->buttons |= (pNewestInputDevice->xinput.report.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) != 0 ? GameInputGamepadDPadLeft : GameInputGamepadNone;
+ state->buttons |= (pNewestInputDevice->xinput.report.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) != 0 ? GameInputGamepadDPadRight : GameInputGamepadNone;
+
+ state->buttons |= (pNewestInputDevice->xinput.report.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) != 0 ? GameInputGamepadLeftShoulder : GameInputGamepadNone;
+ state->buttons |= (pNewestInputDevice->xinput.report.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) != 0 ? GameInputGamepadRightShoulder : GameInputGamepadNone;
+
+ state->buttons |= (pNewestInputDevice->xinput.report.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) != 0 ? GameInputGamepadLeftThumbstick : GameInputGamepadNone;
+ state->buttons |= (pNewestInputDevice->xinput.report.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) != 0 ? GameInputGamepadRightThumbstick : GameInputGamepadNone;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+bool
+STDMETHODCALLTYPE
+SK_IPlayStationGameInputReading::GetRacingWheelState (GameInputRacingWheelState *state) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ return false;
+}
+
+bool
+STDMETHODCALLTYPE
+SK_IPlayStationGameInputReading::GetUiNavigationState (GameInputUiNavigationState *state) noexcept
+{
+ SK_LOG_FIRST_CALL
+
+ SK_RunOnce (SK_LOGi0 (L"Stub"));
+
+ return false;
+}
\ No newline at end of file
diff --git a/src/input/hid.cpp b/src/input/hid.cpp
index d34a2b62f..5e7172657 100644
--- a/src/input/hid.cpp
+++ b/src/input/hid.cpp
@@ -124,11 +124,11 @@ SK_HID_DeviceFile::SK_HID_DeviceFile (HANDLE file, const wchar_t *wszPath)
wcsncpy_s ( wszDevicePath, MAX_PATH,
wszPath, _TRUNCATE );
- wcsncpy_s ( wszProductName, 128,
+ wcsncpy_s ( wszProductName, 2047,
known_path.wszProductName, _TRUNCATE );
- wcsncpy_s ( wszManufacturerName, 128,
+ wcsncpy_s ( wszManufacturerName, 2047,
known_path.wszManufacturerName, _TRUNCATE );
- wcsncpy_s ( wszSerialNumber, 128,
+ wcsncpy_s ( wszSerialNumber, 2047,
known_path.wszSerialNumber, _TRUNCATE );
device_type = known_path.device_type;
@@ -177,17 +177,17 @@ SK_HID_DeviceFile::SK_HID_DeviceFile (HANDLE file, const wchar_t *wszPath)
{
SK_DeviceIoControl (
hFile, IOCTL_HID_GET_PRODUCT_STRING, 0, 0,
- wszProductName, 128, &dwBytesRead, nullptr
+ wszProductName, 4093, &dwBytesRead, nullptr
);
SK_DeviceIoControl (
hFile, IOCTL_HID_GET_MANUFACTURER_STRING, 0, 0,
- wszManufacturerName, 128, &dwBytesRead, nullptr
+ wszManufacturerName, 4093, &dwBytesRead, nullptr
);
SK_DeviceIoControl (
hFile, IOCTL_HID_GET_SERIALNUMBER_STRING, 0, 0,
- wszSerialNumber, 128, &dwBytesRead, nullptr
+ wszSerialNumber, 4093, &dwBytesRead, nullptr
);
setPollingFrequency (0);
@@ -284,17 +284,17 @@ SK_HID_DeviceFile::SK_HID_DeviceFile (HANDLE file, const wchar_t *wszPath)
{
SK_DeviceIoControl (
hFile, IOCTL_HID_GET_PRODUCT_STRING, 0, 0,
- wszProductName, 128, &dwBytesRead, nullptr
+ wszProductName, 4093, &dwBytesRead, nullptr
);
SK_DeviceIoControl (
hFile, IOCTL_HID_GET_MANUFACTURER_STRING, 0, 0,
- wszManufacturerName, 128, &dwBytesRead, nullptr
+ wszManufacturerName, 4093, &dwBytesRead, nullptr
);
SK_DeviceIoControl (
hFile, IOCTL_HID_GET_SERIALNUMBER_STRING, 0, 0,
- wszSerialNumber, 128, &dwBytesRead, nullptr
+ wszSerialNumber, 4093, &dwBytesRead, nullptr
);
SK_ImGui_Warning (wszSerialNumber);
@@ -1268,6 +1268,9 @@ SK_StrSupW (const wchar_t *wszString, const wchar_t *wszPattern, int len = -1)
if (len == -1)
len = sk::narrow_cast (wcslen (wszPattern));
+ len =
+ std::min (len, sk::narrow_cast (wcslen (wszPattern)));
+
return
0 == StrCmpNIW (wszString, wszPattern, len);
}
@@ -1281,6 +1284,9 @@ SK_StrSupA (const char *szString, const char *szPattern, int len = -1)
if (len == -1)
len = sk::narrow_cast (strlen (szPattern));
+ len =
+ std::min (len, sk::narrow_cast (strlen (szString)));
+
return
0 == StrCmpNIA (szString, szPattern, len);
}
@@ -1349,7 +1355,7 @@ CreateFileA_Detour (LPCSTR lpFileName,
SK_Input_DeviceFiles.insert (hRet);
}
- auto&& dev_file =
+ auto& dev_file =
SK_HID_DeviceFiles [hRet];
for (auto& overlapped_request : dev_file._overlappedRequests)
@@ -1359,7 +1365,7 @@ CreateFileA_Detour (LPCSTR lpFileName,
overlapped_request.second.lpBuffer = nullptr;
}
- dev_file = std::move (hid_file);
+ dev_file = hid_file;
}
}
@@ -1448,7 +1454,7 @@ CreateFile2_Detour (
SK_Input_DeviceFiles.insert (hRet);
}
- auto&& dev_file =
+ auto& dev_file =
SK_HID_DeviceFiles [hRet];
for (auto& overlapped_request : dev_file._overlappedRequests)
@@ -1458,7 +1464,7 @@ CreateFile2_Detour (
overlapped_request.second.lpBuffer = nullptr;
}
- dev_file = std::move (hid_file);
+ dev_file = hid_file;
}
}
@@ -1549,7 +1555,7 @@ CreateFileW_Detour ( LPCWSTR lpFileName,
SK_Input_DeviceFiles.insert (hRet);
}
- auto&& dev_file =
+ auto& dev_file =
SK_HID_DeviceFiles [hRet];
for (auto& overlapped_request : dev_file._overlappedRequests)
@@ -1559,7 +1565,7 @@ CreateFileW_Detour ( LPCWSTR lpFileName,
overlapped_request.second.lpBuffer = nullptr;
}
- dev_file = std::move (hid_file);
+ dev_file = hid_file;
}
}
@@ -2199,7 +2205,7 @@ SK_Input_HookHID (void)
SK_GetOverlappedResult = GetOverlappedResult_Original;
SK_GetOverlappedResultEx = GetOverlappedResultEx_Original;
- if (ReadAcquire (&__SK_Init) > 0) SK_ApplyQueuedHooks ();
+ SK_ApplyQueuedHooks ();
InterlockedIncrementRelease (&hooked);
}
diff --git a/src/input/hid_reports/playstation.cpp b/src/input/hid_reports/playstation.cpp
index 5607dcffb..35ea94fba 100644
--- a/src/input/hid_reports/playstation.cpp
+++ b/src/input/hid_reports/playstation.cpp
@@ -820,6 +820,61 @@ struct SK_HID_DualShock4_GetStateDataBt : SK_HID_DualShock4_GetStateData {
};
#pragma pack(pop)
+void
+SK_HID_PlayStationDevice::setVibration (
+ USHORT low_freq,
+ USHORT high_freq,
+ USHORT left_trigger,
+ USHORT right_trigger,
+ USHORT max_val )
+{
+ if (max_val == 0)
+ {
+ const auto last_max = ReadULongAcquire (&_vibration.max_val);
+
+ InterlockedCompareExchange (
+ &_vibration.max_val,
+ std::max ( { last_max,
+ static_cast (low_freq),
+ static_cast (high_freq),
+ static_cast (left_trigger),
+ static_cast (right_trigger),} ),
+ last_max
+ );
+
+ if (last_max > 255)
+ max_val = 65535;
+ else
+ max_val = 255;
+ }
+
+ WriteULongRelease (&_vibration.left,
+ std::min (255UL,
+ static_cast (
+ std::clamp (static_cast (low_freq)/
+ static_cast (max_val), 0.0, 1.0) * 256.0)));
+
+ WriteULongRelease (&_vibration.right,
+ std::min (255UL,
+ static_cast (
+ std::clamp (static_cast (high_freq)/
+ static_cast (max_val), 0.0, 1.0) * 256.0)));
+
+ WriteULongRelease (&_vibration.trigger.left,
+ std::min (255UL,
+ static_cast (
+ std::clamp (static_cast (left_trigger)/
+ static_cast (max_val), 0.0, 1.0) * 256.0)));
+
+ WriteULongRelease (&_vibration.trigger.right,
+ std::min (255UL,
+ static_cast (
+ std::clamp (static_cast (right_trigger)/
+ static_cast (max_val), 0.0, 1.0) * 256.0)));
+
+ WriteULongRelease (&_vibration.last_set, SK::ControlPanel::current_time);
+}
+
void
SK_HID_PlayStationDevice::setVibration (
USHORT left,
@@ -828,28 +883,38 @@ SK_HID_PlayStationDevice::setVibration (
{
if (max_val == 0)
{
- _vibration.max_val =
- std::max ( { _vibration.max_val, left, right } );
+ const auto last_max = ReadULongAcquire (&_vibration.max_val);
+
+ InterlockedCompareExchange (
+ &_vibration.max_val,
+ std::max ( { last_max,
+ static_cast (left),
+ static_cast (right) } ),
+ last_max
+ );
- if (_vibration.max_val > 255)
+ if (last_max > 255)
max_val = 65535;
else
max_val = 255;
}
WriteULongRelease (&_vibration.left,
- sk::narrow_cast (255.0 *
- std::clamp (
- (static_cast (left)/
- static_cast (max_val)), 0.0, 1.0)));
+ std::min (255UL,
+ static_cast (
+ std::clamp (static_cast (left)/
+ static_cast (max_val), 0.0, 1.0) * 256.0)));
WriteULongRelease (&_vibration.right,
- sk::narrow_cast (255.0 *
- std::clamp (
- (static_cast (right)/
- static_cast (max_val)), 0.0, 1.0)));
+ std::min (255UL,
+ static_cast (
+ std::clamp (static_cast (right)/
+ static_cast (max_val), 0.0, 1.0) * 256.0)));
+
+ WriteULongRelease (&_vibration.trigger.left, 0);
+ WriteULongRelease (&_vibration.trigger.right, 0);
- _vibration.last_set = SK::ControlPanel::current_time;
+ WriteULongRelease (&_vibration.last_set, SK::ControlPanel::current_time);
}
bool
@@ -1503,14 +1568,22 @@ SK_HID_PlayStationDevice::request_input_report (void)
{
if (config.input.gamepad.bt_input_only)
{
- SK_ImGui_CreateNotification ( "HID.Bluetooth.ModeChange", SK_ImGui_Toast::Warning,
- "Reconnect them to Activate DualShock 3 Compatibility Mode",
- "Special K has Disconnected all Bluetooth Controllers!",
- //"Bluetooth PlayStation Controller(s) Running in DualShock 4 / DualSense Mode!",
- 15000UL, SK_ImGui_Toast::UseDuration | SK_ImGui_Toast::ShowTitle |
- SK_ImGui_Toast::ShowCaption | SK_ImGui_Toast::ShowNewest );
-
- SK_DeferCommand ("Input.Gamepad.PowerOff 1");
+ const bool legacy_input_detected =
+ ( SK_WinMM_Backend->reads [2] +
+ SK_DI7_Backend->reads [2] +
+ SK_DI8_Backend->reads [2] > 0 );
+
+ if (legacy_input_detected)
+ {
+ SK_ImGui_CreateNotification ( "HID.Bluetooth.ModeChange", SK_ImGui_Toast::Warning,
+ "Reconnect them to Activate DualShock 3 Compatibility Mode",
+ "Special K has Disconnected all Bluetooth Controllers!",
+ //"Bluetooth PlayStation Controller(s) Running in DualShock 4 / DualSense Mode!",
+ 15000UL, SK_ImGui_Toast::UseDuration | SK_ImGui_Toast::ShowTitle |
+ SK_ImGui_Toast::ShowCaption | SK_ImGui_Toast::ShowNewest );
+
+ SK_DeferCommand ("Input.Gamepad.PowerOff 1");
+ }
}
else
@@ -2551,21 +2624,32 @@ SK_HID_PlayStationDevice::write_output_report (bool force)
(BYTE *)pDevice->output_report.data ();
SK_HID_DualSense_SetStateData* output =
- (SK_HID_DualSense_SetStateData *)&pOutputRaw [1];
+ (SK_HID_DualSense_SetStateData *)&pOutputRaw [1];
- const ULONG dwRightMotor = ReadULongAcquire (&pDevice->_vibration.right);
- const ULONG dwLeftMotor = ReadULongAcquire (&pDevice->_vibration.left);
+ const ULONG dwRightMotor = ReadULongAcquire (&pDevice->_vibration.right);
+ const ULONG dwLeftMotor = ReadULongAcquire (&pDevice->_vibration.left);
+ const ULONG dwRightTrigger = ReadULongAcquire (&pDevice->_vibration.trigger.right);
+ const ULONG dwLeftTrigger = ReadULongAcquire (&pDevice->_vibration.trigger.left);
+
+ const ULONG last_trigger_r = pDevice->_vibration.trigger.last_right;
+ const ULONG last_trigger_l = pDevice->_vibration.trigger.last_left;
const bool bRumble =
- (dwRightMotor != 0 || dwLeftMotor != 0);
+ (dwRightMotor != 0 ||
+ dwLeftMotor != 0) || (dwLeftTrigger != 0
+ || dwRightTrigger != 0);
// 500 msec grace period before allowing controller to use native haptics
output->UseRumbleNotHaptics = bRumble ||
- (pDevice->_vibration.last_set > SK::ControlPanel::current_time - 500UL);
+ (ReadULongAcquire (&pDevice->_vibration.last_set) > SK::ControlPanel::current_time - 500UL)
+ || last_trigger_r != 0
+ || last_trigger_l != 0;
- if (bRumble)
+ if (bRumble || (last_trigger_r != 0 || last_trigger_l != 0))
{
- pDevice->_vibration.last_set = SK::ControlPanel::current_time;
+ WriteULongRelease (&pDevice->_vibration.last_set, SK::ControlPanel::current_time);
+ output->AllowMotorPowerLevel = true;
+ output->EnableRumbleEmulation = true;
}
output->AllowMuteLight = true;
@@ -2578,9 +2662,6 @@ SK_HID_PlayStationDevice::write_output_report (bool force)
output->AllowLedColor = true;
}
- output->AllowHapticLowPassFilter = true;
- output->AllowMotorPowerLevel = false;
-
// Firmware reqs
output->
EnableImprovedRumbleEmulation = true;
@@ -2594,6 +2675,45 @@ SK_HID_PlayStationDevice::write_output_report (bool force)
ReadULongAcquire (&pDevice->_vibration.left)
);
+ uint8_t effects[3][11] = {
+ { 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x01, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x06, 15, 63, 0, 0, 0, 0, 0, 0, 0, 0 },
+ };
+
+ if (bRumble || (last_trigger_r != 0 || last_trigger_l != 0))
+ {
+ if (dwLeftTrigger != 0)
+ { output->AllowLeftTriggerFFB = true;
+ const auto trigger_effect = 2;
+ memcpy (output->LeftTriggerFFB, effects [trigger_effect], sizeof (effects [trigger_effect]));
+ output->LeftTriggerFFB [2] =
+ static_cast (std::clamp (
+ static_cast (dwLeftTrigger) *
+ config.input.gamepad.impulse_strength_l, 0.0f, 1.0f) );
+ pDevice->_vibration.trigger.last_left = dwLeftTrigger;
+ } else { output->AllowLeftTriggerFFB = true;
+ const auto trigger_effect = 0;
+ memcpy (output->LeftTriggerFFB, effects [trigger_effect], sizeof (effects [trigger_effect]));
+ pDevice->_vibration.trigger.last_left = dwLeftTrigger;
+ }
+ if (dwRightTrigger != 0)
+ { output->AllowRightTriggerFFB = true;
+ const auto trigger_effect = 2;
+ memcpy (output->RightTriggerFFB, effects [trigger_effect], sizeof (effects [trigger_effect]));
+ output->RightTriggerFFB [2] =
+ static_cast (std::clamp (
+ static_cast (dwRightTrigger) *
+ config.input.gamepad.impulse_strength_r, 0.0f, 1.0f) );
+ pDevice->_vibration.trigger.last_right = dwRightTrigger;
+ } else { output->AllowRightTriggerFFB = true;
+ const auto trigger_effect = 0;
+ memcpy (output->RightTriggerFFB, effects [trigger_effect], sizeof (effects [trigger_effect]));
+ pDevice->_vibration.trigger.last_right = dwRightTrigger;
+ }
+ }
+
+
static bool bMuted = SK_IsGameMuted ();
static DWORD dwLastMuteCheck = SK_timeGetTime ();
@@ -2612,9 +2732,8 @@ SK_HID_PlayStationDevice::write_output_report (bool force)
output->TouchPowerSave = config.input.gamepad.scepad.power_save_mode;
output->MotionPowerSave = config.input.gamepad.scepad.power_save_mode;
output->AudioPowerSave = config.input.gamepad.scepad.power_save_mode;
- output->HapticLowPassFilter = true;
+ output->HapticPowerSave = false;
- output->RumbleMotorPowerReduction = 0x0;
//config.input.gamepad.scepad.rumble_power_level == 100.0f ? 0
// :
//static_cast ((100.0f - config.input.gamepad.scepad.rumble_power_level) / 12.5f);
@@ -2709,23 +2828,70 @@ SK_HID_PlayStationDevice::write_output_report (bool force)
SK_HID_DualSense_SetStateData* output =
(SK_HID_DualSense_SetStateData *)&bt_data [3];
- const ULONG dwRightMotor = ReadULongAcquire (&pDevice->_vibration.right);
- const ULONG dwLeftMotor = ReadULongAcquire (&pDevice->_vibration.left);
+ const ULONG dwRightMotor = ReadULongAcquire (&pDevice->_vibration.right);
+ const ULONG dwLeftMotor = ReadULongAcquire (&pDevice->_vibration.left);
+ const ULONG dwRightTrigger = ReadULongAcquire (&pDevice->_vibration.trigger.right);
+ const ULONG dwLeftTrigger = ReadULongAcquire (&pDevice->_vibration.trigger.left);
+
+ const ULONG last_trigger_r = pDevice->_vibration.trigger.last_right;
+ const ULONG last_trigger_l = pDevice->_vibration.trigger.last_left;
const bool bRumble =
- (dwRightMotor != 0 || dwLeftMotor != 0);
+ (dwRightMotor != 0 ||
+ dwLeftMotor != 0) || (dwRightTrigger != 0
+ || dwLeftTrigger != 0);
// 500 msec grace period before allowing controller to use native haptics
output->UseRumbleNotHaptics = bRumble ||
- (pDevice->_vibration.last_set > SK::ControlPanel::current_time - 500UL);
+ (ReadULongAcquire (&pDevice->_vibration.last_set) > SK::ControlPanel::current_time - 500UL)
+ || last_trigger_r != 0
+ || last_trigger_l != 0;
if (bRumble)
{
- pDevice->_vibration.last_set = SK::ControlPanel::current_time;
+ WriteULongRelease (&pDevice->_vibration.last_set, SK::ControlPanel::current_time);
+ output->AllowMotorPowerLevel = true;
+ output->EnableRumbleEmulation = true;
}
- output->EnableRumbleEmulation = true;
- output->AllowMuteLight = true;
+ uint8_t effects[3][11] = {
+ { 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x01, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x06, 15, 63, 0, 0, 0, 0, 0, 0, 0, 0 },
+ };
+
+ if (bRumble || (last_trigger_r != 0 || last_trigger_l != 0))
+ {
+ if (dwLeftTrigger != 0)
+ { output->AllowLeftTriggerFFB = true;
+ const auto trigger_effect = 2;
+ memcpy (output->LeftTriggerFFB, effects [trigger_effect], sizeof (effects [trigger_effect]));
+ output->LeftTriggerFFB [2] =
+ static_cast (std::clamp (
+ static_cast (dwLeftTrigger) *
+ config.input.gamepad.impulse_strength_l, 0.0f, 1.0f) );
+ pDevice->_vibration.trigger.last_left = dwLeftTrigger;
+ } else { output->AllowLeftTriggerFFB = true;
+ const auto trigger_effect = 0;
+ memcpy (output->LeftTriggerFFB, effects [trigger_effect], sizeof (effects [trigger_effect]));
+ pDevice->_vibration.trigger.last_left = dwLeftTrigger;
+ }
+ if (dwRightTrigger != 0)
+ { output->AllowRightTriggerFFB = true;
+ const auto trigger_effect = 2;
+ memcpy (output->RightTriggerFFB, effects [trigger_effect], sizeof (effects [trigger_effect]));
+ output->RightTriggerFFB [2] =
+ static_cast (std::clamp (
+ static_cast (dwRightTrigger) *
+ config.input.gamepad.impulse_strength_r, 0.0f, 1.0f) );
+ pDevice->_vibration.trigger.last_right = dwRightTrigger;
+ } else { output->AllowRightTriggerFFB = true;
+ const auto trigger_effect = 0;
+ memcpy (output->RightTriggerFFB, effects [trigger_effect], sizeof (effects [trigger_effect]));
+ pDevice->_vibration.trigger.last_right = dwRightTrigger;
+ }
+ }
+ output->AllowMuteLight = true;
if (config.input.gamepad.scepad.led_color_r >= 0 ||
config.input.gamepad.scepad.led_color_g >= 0 ||
@@ -2735,10 +2901,8 @@ SK_HID_PlayStationDevice::write_output_report (bool force)
output->AllowLedColor = true;
}
- output->AllowPlayerIndicators = config.input.gamepad.xinput.debug;
- output->AllowHapticLowPassFilter = true;
- output->AllowMotorPowerLevel = false;
-
+ output->AllowPlayerIndicators = config.input.gamepad.xinput.debug;
+
// Firmware reqs
output->
EnableImprovedRumbleEmulation = true;
@@ -2767,7 +2931,10 @@ SK_HID_PlayStationDevice::write_output_report (bool force)
: On
: Off;
- output->HapticLowPassFilter = true;
+ output->TouchPowerSave = config.input.gamepad.scepad.power_save_mode;
+ output->MotionPowerSave = config.input.gamepad.scepad.power_save_mode;
+ output->AudioPowerSave = config.input.gamepad.scepad.power_save_mode;
+ output->HapticPowerSave = false;
if (config.input.gamepad.xinput.debug)
{
@@ -3688,13 +3855,10 @@ SK_HID_PlayStationDevice::reset_device (void)
latency.ping = 0;
latency.last_poll = 0;
- _vibration.left = 0;
- _vibration.right = 0;
- _vibration.last_left = 0;
- _vibration.last_right = 0;
- _vibration.last_set = 0;
- _vibration.last_output = 0;
- _vibration.max_val = 0;
+ WriteULongRelease (&_vibration.left, 0);
+ WriteULongRelease (&_vibration.right, 0);
+ WriteULongRelease (&_vibration.last_set, 0);
+ WriteULongRelease (&_vibration.max_val, 0);
xinput.last_active = 0;
diff --git a/src/input/input.cpp b/src/input/input.cpp
index a76d0bf73..5c8d3788f 100644
--- a/src/input/input.cpp
+++ b/src/input/input.cpp
@@ -144,9 +144,9 @@ SK_ImGui_WantGamepadCapture (bool update)
DWORD dwForegroundPid = 0x0;
GetWindowThreadProcessId (hWndForeground, &dwForegroundPid);
- for ( auto pid : g_sHookedPIDs )
+ for ( const auto pid : g_sHookedPIDs )
{
- if (pid == (LONG)dwForegroundPid)
+ if (pid == static_cast (dwForegroundPid))
{
bCapture = true;
}
@@ -293,6 +293,17 @@ SK_ImGui_HandlesMessage (MSG *lpMsg, bool /*remove*/, bool /*peek*/)
}
break;
+ case WM_ENTERSIZEMOVE:
+ case WM_EXITSIZEMOVE:
+ if (lpMsg->hwnd == game_window.hWnd)
+ {
+ game_window.size_move =
+ (lpMsg->message == WM_ENTERSIZEMOVE);
+
+ SK_Window_RepositionIfNeeded ();
+ }
+ break;
+
case WM_CHAR:
case WM_MENUCHAR:
{
@@ -642,6 +653,9 @@ void SK_Input_PreInit (void)
if (config.input.gamepad.hook_windows_gaming)
SK_Input_HookWGI ();
+ if (config.input.gamepad.hook_game_input)
+ SK_Input_HookGameInput ();
+
if (config.input.gamepad.hook_xinput)
SK_XInput_InitHotPlugHooks ( );
@@ -964,6 +978,7 @@ SK_LazyGlobal SK_WGI_Backend;
SK_LazyGlobal SK_HID_Backend;
SK_LazyGlobal SK_RawInput_Backend;
SK_LazyGlobal SK_MessageBus_Backend; // NVIDIA stuff
+SK_LazyGlobal SK_GameInput_Backend;
SK_LazyGlobal SK_Win32_Backend;
SK_LazyGlobal SK_WinHook_Backend;
diff --git a/src/input/windows.gaming.input.cpp b/src/input/windows.gaming.input.cpp
index d5788e4e9..c6e7447d5 100644
--- a/src/input/windows.gaming.input.cpp
+++ b/src/input/windows.gaming.input.cpp
@@ -725,7 +725,7 @@ WGI_Gamepad_GetCurrentReading_Override (ABI::Windows::Gaming::Input::IGamepad
if (controller.bConnected)
{
if (pNewestInputDevice == nullptr ||
- pNewestInputDevice->xinput.last_active <= controller.xinput.last_active)
+ pNewestInputDevice->xinput.last_active < controller.xinput.last_active)
{
pNewestInputDevice = &controller;
}
@@ -733,7 +733,7 @@ WGI_Gamepad_GetCurrentReading_Override (ABI::Windows::Gaming::Input::IGamepad
}
}
- if (pNewestInputDevice != nullptr && (bUseEmulation || pNewestInputDevice->xinput.last_active > ReadULong64Acquire (&last_time [0])))
+ if (pNewestInputDevice != nullptr && (bUseEmulation || pNewestInputDevice->xinput.last_active >= ReadULong64Acquire (&last_time [0])))
{
SK_WGI_VIEW (SK_WGI_Backend, 0);
diff --git a/src/input/winhook_input.cpp b/src/input/winhook_input.cpp
index 61ad39043..7d63a52e2 100644
--- a/src/input/winhook_input.cpp
+++ b/src/input/winhook_input.cpp
@@ -61,93 +61,117 @@ SK_Proxy_MouseProc (
{
if (nCode == HC_ACTION || nCode == HC_NOREMOVE)
{
- if (nCode == HC_ACTION)
+ if (SK_GImDefaultContext ())
{
- switch (wParam)
+ if (nCode == HC_ACTION)
{
- case WM_MOUSEMOVE:
- case WM_LBUTTONDOWN:
- case WM_LBUTTONDBLCLK:
- case WM_RBUTTONDOWN:
- case WM_RBUTTONDBLCLK:
- case WM_MBUTTONDOWN:
- case WM_MBUTTONDBLCLK:
- case WM_XBUTTONDOWN:
- case WM_XBUTTONDBLCLK:
+ switch (wParam)
{
- MOUSEHOOKSTRUCT *mhs =
- (MOUSEHOOKSTRUCT *)lParam;
+ case WM_MOUSEMOVE:
+ case WM_LBUTTONDOWN:
+ case WM_LBUTTONDBLCLK:
+ case WM_RBUTTONDOWN:
+ case WM_RBUTTONDBLCLK:
+ case WM_MBUTTONDOWN:
+ case WM_MBUTTONDBLCLK:
+ case WM_XBUTTONDOWN:
+ case WM_XBUTTONDBLCLK:
+ {
+ MOUSEHOOKSTRUCT *mhs =
+ (MOUSEHOOKSTRUCT *)lParam;
- static auto& io =
- ImGui::GetIO ();
+ auto& io =
+ ImGui::GetIO ();
- io.KeyCtrl |= ((mhs->dwExtraInfo & MK_CONTROL) != 0);
- io.KeyShift |= ((mhs->dwExtraInfo & MK_SHIFT ) != 0);
+ io.KeyCtrl |= ((mhs->dwExtraInfo & MK_CONTROL) != 0);
+ io.KeyShift |= ((mhs->dwExtraInfo & MK_SHIFT ) != 0);
- switch (wParam)
- {
- case WM_MOUSEMOVE:
+ // No TrackMouseEvent available, have to do this manually
+ if (! game_window.mouse.can_track)
{
- // No TrackMouseEvent available, have to do this manually
- if (! game_window.mouse.can_track)
+ POINT pt (mhs->pt);
+ ScreenToClient (game_window.child != nullptr ?
+ game_window.child :
+ game_window.hWnd, &pt);
+ if (ChildWindowFromPointEx (game_window.child != nullptr ?
+ game_window.child :
+ game_window.hWnd, pt, CWP_SKIPDISABLED) == (game_window.child != nullptr ?
+ game_window.child :
+ game_window.hWnd))
{
- POINT pt (mhs->pt);
- ScreenToClient (game_window.child != nullptr ?
- game_window.child :
- game_window.hWnd, &pt);
- if (ChildWindowFromPointEx (game_window.child != nullptr ?
- game_window.child :
- game_window.hWnd, pt, CWP_SKIPDISABLED) == (game_window.child != nullptr ?
- game_window.child :
- game_window.hWnd))
- {
- SK_ImGui_Cursor.ClientToLocal (&pt);
- SK_ImGui_Cursor.pos = pt;
+ SK_ImGui_Cursor.ClientToLocal (&pt);
+ SK_ImGui_Cursor.pos = pt;
- io.MousePos.x = (float)SK_ImGui_Cursor.pos.x;
- io.MousePos.y = (float)SK_ImGui_Cursor.pos.y;
- }
-
- else
- io.MousePos = ImVec2 (-FLT_MAX, -FLT_MAX);
+ io.MousePos.x = (float)SK_ImGui_Cursor.pos.x;
+ io.MousePos.y = (float)SK_ImGui_Cursor.pos.y;
}
- // Install a mouse tracker to get WM_MOUSELEAVE
- if (! (game_window.mouse.tracking && game_window.mouse.inside))
+ else
+ io.MousePos = ImVec2 (-FLT_MAX, -FLT_MAX);
+ }
+
+ // Install a mouse tracker to get WM_MOUSELEAVE
+ if (! (game_window.mouse.tracking && game_window.mouse.inside))
+ {
+ if (wParam != WM_NCMOUSEMOVE)
{
if (SK_ImGui_WantMouseCapture ())
{
SK_ImGui_UpdateMouseTracker ();
}
}
- } break;
+ }
- case WM_LBUTTONDOWN:
- case WM_LBUTTONDBLCLK:
- io.MouseDown [0] = true;
- break;
+ switch (wParam)
+ {
+ case WM_LBUTTONDOWN:
+ case WM_LBUTTONDBLCLK:
+ io.AddMouseButtonEvent (ImGuiKey_MouseLeft, true);
+ break;
+
+ case WM_RBUTTONDOWN:
+ case WM_RBUTTONDBLCLK:
+ io.AddMouseButtonEvent (ImGuiKey_MouseRight, true);
+ break;
+
+ case WM_MBUTTONDOWN:
+ case WM_MBUTTONDBLCLK:
+ io.AddMouseButtonEvent (ImGuiKey_MouseMiddle, true);
+ break;
+
+ case WM_XBUTTONDOWN:
+ case WM_XBUTTONDBLCLK:
+ {
+ MOUSEHOOKSTRUCTEX* mhsx =
+ (MOUSEHOOKSTRUCTEX*)lParam;
- case WM_RBUTTONDOWN:
- case WM_RBUTTONDBLCLK:
- io.MouseDown [1] = true;
- break;
+ if ((HIWORD (mhsx->mouseData)) == XBUTTON1) io.AddMouseButtonEvent (ImGuiKey_MouseX1, true);
+ if ((HIWORD (mhsx->mouseData)) == XBUTTON2) io.AddMouseButtonEvent (ImGuiKey_MouseX2, true);
+ } break;
- case WM_MBUTTONDOWN:
- case WM_MBUTTONDBLCLK:
- io.MouseDown [2] = true;
- break;
+ case WM_LBUTTONUP:
+ //io.AddMouseButtonEvent (ImGuiKey_MouseLeft, false);
+ break;
- case WM_XBUTTONDOWN:
- case WM_XBUTTONDBLCLK:
- {
- MOUSEHOOKSTRUCTEX* mhsx =
- (MOUSEHOOKSTRUCTEX*)lParam;
+ case WM_RBUTTONUP:
+ //io.AddMouseButtonEvent (ImGuiKey_MouseRight, false);
+ break;
- if ((HIWORD (mhsx->mouseData)) == XBUTTON1) io.MouseDown [3] = true;
- if ((HIWORD (mhsx->mouseData)) == XBUTTON2) io.MouseDown [4] = true;
- } break;
- }
- } break;
+ case WM_MBUTTONUP:
+ //io.AddMouseButtonEvent (ImGuiKey_MouseMiddle, false);
+ break;
+
+ case WM_XBUTTONUP:
+ {
+ //MOUSEHOOKSTRUCTEX* mhsx =
+ // (MOUSEHOOKSTRUCTEX*)lParam;
+
+ //if ((HIWORD (mhsx->mouseData)) == XBUTTON1) io.AddMouseButtonEvent (ImGuiKey_MouseX1, false);
+ //if ((HIWORD (mhsx->mouseData)) == XBUTTON2) io.AddMouseButtonEvent (ImGuiKey_MouseX2, false);
+ } break;
+ }
+ } break;
+ }
}
}
@@ -203,51 +227,87 @@ SK_Proxy_LLMouseProc (
{
if (nCode == HC_ACTION)
{
- switch (wParam)
- {
- case WM_MOUSEMOVE:
- case WM_LBUTTONDOWN:
- case WM_LBUTTONDBLCLK:
- case WM_RBUTTONDOWN:
- case WM_RBUTTONDBLCLK:
- case WM_MBUTTONDOWN:
- case WM_MBUTTONDBLCLK:
- case WM_XBUTTONDOWN:
- case WM_XBUTTONDBLCLK:
- {
- MSLLHOOKSTRUCT *mhs =
- (MSLLHOOKSTRUCT *)lParam;
+ MSLLHOOKSTRUCT *mhs =
+ (MSLLHOOKSTRUCT *)lParam;
- static auto& io =
- ImGui::GetIO ();
+ if (SK_GImDefaultContext ())
+ {
+ auto& io =
+ ImGui::GetIO ();
- io.KeyCtrl |= ((mhs->dwExtraInfo & MK_CONTROL) != 0);
- io.KeyShift |= ((mhs->dwExtraInfo & MK_SHIFT ) != 0);
+ // No TrackMouseEvent available, have to do this manually
+ if (! game_window.mouse.can_track)
+ {
+ POINT pt (mhs->pt);
+ ScreenToClient (game_window.child != nullptr ?
+ game_window.child :
+ game_window.hWnd, &pt);
+ if (ChildWindowFromPointEx (game_window.child != nullptr ?
+ game_window.child :
+ game_window.hWnd, pt, CWP_SKIPDISABLED) == (game_window.child != nullptr ?
+ game_window.child :
+ game_window.hWnd))
+ {
+ SK_ImGui_Cursor.ClientToLocal (&pt);
+ SK_ImGui_Cursor.pos = pt;
+
+ io.MousePos.x = (float)SK_ImGui_Cursor.pos.x;
+ io.MousePos.y = (float)SK_ImGui_Cursor.pos.y;
+ }
+
+ else
+ io.MousePos = ImVec2 (-FLT_MAX, -FLT_MAX);
+ }
+
+ // Install a mouse tracker to get WM_MOUSELEAVE
+ if (! (game_window.mouse.tracking && game_window.mouse.inside))
+ {
+ if (SK_ImGui_WantMouseCapture ())
+ {
+ SK_ImGui_UpdateMouseTracker ();
+ }
+ }
- switch (wParam)
+ switch (wParam)
+ {
+ case WM_MOUSEMOVE:
+ case WM_LBUTTONDOWN:
+ case WM_LBUTTONDBLCLK:
+ case WM_RBUTTONDOWN:
+ case WM_RBUTTONDBLCLK:
+ case WM_MBUTTONDOWN:
+ case WM_MBUTTONDBLCLK:
+ case WM_XBUTTONDOWN:
+ case WM_XBUTTONDBLCLK:
{
- case WM_LBUTTONDOWN:
- case WM_LBUTTONDBLCLK:
- io.MouseDown [0] = true;
- break;
+ io.KeyCtrl |= ((mhs->dwExtraInfo & MK_CONTROL) != 0);
+ io.KeyShift |= ((mhs->dwExtraInfo & MK_SHIFT ) != 0);
- case WM_RBUTTONDOWN:
- case WM_RBUTTONDBLCLK:
- io.MouseDown [1] = true;
- break;
+ switch (wParam)
+ {
+ case WM_LBUTTONDOWN:
+ case WM_LBUTTONDBLCLK:
+ io.AddMouseButtonEvent (ImGuiKey_MouseLeft, true);
+ break;
- case WM_MBUTTONDOWN:
- case WM_MBUTTONDBLCLK:
- io.MouseDown [2] = true;
- break;
+ case WM_RBUTTONDOWN:
+ case WM_RBUTTONDBLCLK:
+ io.AddMouseButtonEvent (ImGuiKey_MouseRight, true);
+ break;
- case WM_XBUTTONDOWN:
- case WM_XBUTTONDBLCLK:
- if ((HIWORD (mhs->mouseData)) == XBUTTON1) io.MouseDown [3] = true;
- if ((HIWORD (mhs->mouseData)) == XBUTTON2) io.MouseDown [4] = true;
- break;
- }
- } break;
+ case WM_MBUTTONDOWN:
+ case WM_MBUTTONDBLCLK:
+ io.AddMouseButtonEvent (ImGuiKey_MouseMiddle, true);
+ break;
+
+ case WM_XBUTTONDOWN:
+ case WM_XBUTTONDBLCLK:
+ if ((HIWORD (mhs->mouseData)) == XBUTTON1) io.AddMouseButtonEvent (ImGuiKey_MouseX1, true);
+ if ((HIWORD (mhs->mouseData)) == XBUTTON2) io.AddMouseButtonEvent (ImGuiKey_MouseX2, true);
+ break;
+ }
+ } break;
+ }
}
if (SK_ImGui_WantMouseCapture ())
@@ -260,31 +320,28 @@ SK_Proxy_LLMouseProc (
wParam, lParam );
}
- else
+ // Game uses a mouse hook for input that the Steam overlay cannot block
+ if (SK_GetStoreOverlayState (true))
{
- // Game uses a mouse hook for input that the Steam overlay cannot block
- if (SK_GetStoreOverlayState (true))
- {
- SK_WinHook_Backend->markHidden (sk_input_dev_type::Mouse);
+ SK_WinHook_Backend->markHidden (sk_input_dev_type::Mouse);
- return
- CallNextHookEx (0, nCode, wParam, lParam);
- }
+ return
+ CallNextHookEx (0, nCode, wParam, lParam);
+ }
- SK_WinHook_Backend->markRead (sk_input_dev_type::Mouse);
+ SK_WinHook_Backend->markRead (sk_input_dev_type::Mouse);
- DWORD dwTid =
- GetCurrentThreadId ();
+ DWORD dwTid =
+ GetCurrentThreadId ();
- auto hook_fn = __hooks._RealMouseProcs [dwTid];
- hook_fn =
- hook_fn != nullptr ?
- hook_fn :
- __hooks._RealMouseProc;
-
- if (hook_fn != nullptr)
- return hook_fn (nCode, wParam, lParam);
- }
+ auto hook_fn = __hooks._RealMouseProcs [dwTid];
+ hook_fn =
+ hook_fn != nullptr ?
+ hook_fn :
+ __hooks._RealMouseProc;
+
+ if (hook_fn != nullptr)
+ return hook_fn (nCode, wParam, lParam);
}
return
@@ -324,7 +381,10 @@ SK_Proxy_KeyboardProc (
}
if ((! isPressed) || SK_IsGameWindowActive ())
- ImGui::GetIO ().KeysDown [vKey] = isPressed;
+ {
+ if (SK_GImDefaultContext ())
+ ImGui::GetIO ().KeysDown [vKey] = isPressed;
+ }
bool hide =
SK_ImGui_WantKeyboardCapture ();
@@ -447,7 +507,10 @@ SK_Proxy_LLKeyboardProc (
}
if (bWindowActive || (! isPressed))
- ImGui::GetIO ().KeysDown [vKey] = isPressed;
+ {
+ if (SK_GImDefaultContext ())
+ ImGui::GetIO ().KeysDown [vKey] = isPressed;
+ }
bool hide =
SK_ImGui_WantKeyboardCapture ();
diff --git a/src/input/xinput_core.cpp b/src/input/xinput_core.cpp
index 5011d733e..9883c84d2 100644
--- a/src/input/xinput_core.cpp
+++ b/src/input/xinput_core.cpp
@@ -549,7 +549,7 @@ XInputGetState1_4_Detour (
if (controller.bConnected)
{
if (pNewestInputDevice == nullptr ||
- pNewestInputDevice->xinput.last_active <= controller.xinput.last_active)
+ pNewestInputDevice->xinput.last_active < controller.xinput.last_active)
{
pNewestInputDevice = &controller;
}
@@ -820,7 +820,7 @@ XInputGetStateEx1_4_Detour (
if (controller.bConnected)
{
if (pNewestInputDevice == nullptr ||
- pNewestInputDevice->xinput.last_active <= controller.xinput.last_active)
+ pNewestInputDevice->xinput.last_active < controller.xinput.last_active)
{
pNewestInputDevice = &controller;
}
@@ -1175,7 +1175,7 @@ XInputSetState1_4_Detour (
{
if (controller.bConnected)
{
- if (controller.xinput.last_active > ReadULong64Acquire (&last_time [dwUserIndex]))
+ if (controller.xinput.last_active >= ReadULong64Acquire (&last_time [dwUserIndex]))
{
if ( pNewestInputDevice == nullptr ||
pNewestInputDevice->xinput.last_active < controller.xinput.last_active )
@@ -2992,9 +2992,9 @@ SK_XInput_PulseController ( INT iJoyID,
XINPUT_VIBRATION
vibes {
.wLeftMotorSpeed =
- sk::narrow_cast (std::min (0.99999f, fStrengthLeft) * 65535.0f),
+ static_cast (std::min (65535U, static_cast (std::clamp (fStrengthLeft, 0.0f, 1.0f) * 65536.0f))),
.wRightMotorSpeed =
- sk::narrow_cast (std::min (0.99999f, fStrengthRight) * 65535.0f)
+ static_cast (std::min (65535U, static_cast (std::clamp (fStrengthRight, 0.0f, 1.0f) * 65536.0f)))
};
#if 0
@@ -3035,7 +3035,7 @@ SK_XInput_PulseController ( INT iJoyID,
{
if (controller.bConnected)
{
- if (controller.xinput.last_active > ReadULong64Acquire (&last_time [iJoyID]))
+ if (controller.xinput.last_active >= ReadULong64Acquire (&last_time [iJoyID]))
{
if ( pNewestInputDevice == nullptr ||
pNewestInputDevice->xinput.last_active < controller.xinput.last_active )
diff --git a/src/nvapi.cpp b/src/nvapi.cpp
index f96904a79..bdba02848 100644
--- a/src/nvapi.cpp
+++ b/src/nvapi.cpp
@@ -464,69 +464,94 @@ NvAPI_Disp_GetHdrCapabilities_Override ( NvU32 displayId,
std::lock_guard
lock (SK_NvAPI_Threading->locks.Disp_GetHdrCapabilities);
- SK_LOG0 ( ( L"NV_HDR_CAPABILITIES Version: %lu", pHdrCapabilities->version ),
- __SK_SUBSYSTEM__ );
- SK_LOG0 ( ( L" >> Wants Driver to Expand Default HDR Params: %s",
- pHdrCapabilities->driverExpandDefaultHdrParameters ? L"Yes" :
- L"No" ),
- __SK_SUBSYSTEM__ );
+ static NvU32 version = pHdrCapabilities->version;
+ static DWORD calls = 0;
- // We don't care what the game wants, we're filling-in default values dammit!
- pHdrCapabilities->driverExpandDefaultHdrParameters = true;
+ if (version == pHdrCapabilities->version)
+ calls++;
+ else
+ {
+ version = pHdrCapabilities->version;
+ calls = 0;
+ }
+
+ if (calls == 5)
+ {
+ SK_LOGi0 (
+ L"Repeated calls to NvAPI_Disp_GetHdrCapabilities (version=%x), silencing future calls...",
+ version
+ );
+ }
+
+ if (calls < 5)
+ {
+ // We don't care what the game wants, we're filling-in default values dammit!
+ pHdrCapabilities->driverExpandDefaultHdrParameters = true;
+ }
NvAPI_Status ret =
NvAPI_Disp_GetHdrCapabilities_Original ( displayId, pHdrCapabilities );
- const SK_RenderBackend_V2::output_s* const pBackendDisplay =
- SK_GetCurrentRenderBackend ().displays->nvapi.getDisplayFromId (displayId);
-
- dll_log->LogEx ( true,
- L"[ HDR Caps ]\n"
- L" +-----------------+---------------------\n"
- L" | Red Primary.... | %f, %f\n"
- L" | Green Primary.. | %f, %f\n"
- L" | Blue Primary... | %f, %f\n"
- L" | White Point.... | %f, %f\n"
- L" | =============== |\n"
- L" | Min Luminance.. | %10.5f cd/m²\n"
- L" | Max Luminance.. | %10.5f cd/m²\n"
- L" | |- FullFrame.. | %10.5f cd/m²\n"
- L" | SDR Luminance.. | %10.5f cd/m²\n"
- L" | =============== |\n"
- L" | ST2084 EOTF.... | %s\n"
- L" | CTA-861.3 HDR.. | %s\n"
- L" | CTA-861.3 SDR.. | %s\n"
- L" | =============== |\n"
- L" | HDR10+......... | %s\n"
- L" | HDR10+ Gaming.. | %s\n"
- L" | =============== |\n"
- L" | Dolby Vision... | %s\n"
- L" | YUV 4:2:2 12bpc | %s\n"
- L" | Low Latency.... | %s\n"
- L" | |- 4:4:4 10bpc | %s\n"
- L" | |- 4:4:4 12bpc | %s\n"
- L" +-----------------+---------------------\n",
- (float)pHdrCapabilities->display_data.displayPrimary_x0 / (float)0xC350, (float)pHdrCapabilities->display_data.displayPrimary_y0 / (float)0xC350,
- (float)pHdrCapabilities->display_data.displayPrimary_x1 / (float)0xC350, (float)pHdrCapabilities->display_data.displayPrimary_y1 / (float)0xC350,
- (float)pHdrCapabilities->display_data.displayPrimary_x2 / (float)0xC350, (float)pHdrCapabilities->display_data.displayPrimary_y2 / (float)0xC350,
- (float)pHdrCapabilities->display_data.displayWhitePoint_x / (float)0xC350, (float)pHdrCapabilities->display_data.displayWhitePoint_y / (float)0xC350,
- (float)pHdrCapabilities->display_data.desired_content_min_luminance * 0.0001f,
- (float)pHdrCapabilities->display_data.desired_content_max_luminance,
- (float)pHdrCapabilities->display_data.desired_content_max_frame_average_luminance,
- pBackendDisplay != nullptr ?
- pBackendDisplay->hdr.white_level :
- (float)pHdrCapabilities->display_data.desired_content_max_frame_average_luminance,
- pHdrCapabilities->isST2084EotfSupported ? L"Yes" : L"No",
- pHdrCapabilities->isTraditionalHdrGammaSupported ? L"Yes" : L"No",
- pHdrCapabilities->isTraditionalSdrGammaSupported ? L"Yes" : L"No",
- pHdrCapabilities->isHdr10PlusSupported ? L"Yes" : L"No",
- pHdrCapabilities->isHdr10PlusGamingSupported ? L"Yes" : L"No",
- pHdrCapabilities->isDolbyVisionSupported ? L"Yes" : L"No",
- pHdrCapabilities->dv_static_metadata.supports_YUV422_12bit ? L"Yes" : L"No",
- (pHdrCapabilities->dv_static_metadata.interface_supported_by_sink
- & 0x2) ? L"Yes" : L"No",
- (pHdrCapabilities->dv_static_metadata.supports_10b_12b_444 & 0x1) ? L"Yes" : L"No",
- (pHdrCapabilities->dv_static_metadata.supports_10b_12b_444 & 0x2) ? L"Yes" : L"No");
+ if (calls < 5)
+ {
+ SK_LOG0 ( ( L"NV_HDR_CAPABILITIES Version: %lu", pHdrCapabilities->version ),
+ __SK_SUBSYSTEM__ );
+ SK_LOG0 ( ( L" >> Wants Driver to Expand Default HDR Params: %s",
+ pHdrCapabilities->driverExpandDefaultHdrParameters ? L"Yes" :
+ L"No" ),
+ __SK_SUBSYSTEM__ );
+
+ const SK_RenderBackend_V2::output_s* const pBackendDisplay =
+ SK_GetCurrentRenderBackend ().displays->nvapi.getDisplayFromId (displayId);
+
+ dll_log->LogEx ( true,
+ L"[ HDR Caps ]\n"
+ L" +-----------------+---------------------\n"
+ L" | Red Primary.... | %f, %f\n"
+ L" | Green Primary.. | %f, %f\n"
+ L" | Blue Primary... | %f, %f\n"
+ L" | White Point.... | %f, %f\n"
+ L" | =============== |\n"
+ L" | Min Luminance.. | %10.5f cd/m²\n"
+ L" | Max Luminance.. | %10.5f cd/m²\n"
+ L" | |- FullFrame.. | %10.5f cd/m²\n"
+ L" | SDR Luminance.. | %10.5f cd/m²\n"
+ L" | =============== |\n"
+ L" | ST2084 EOTF.... | %s\n"
+ L" | CTA-861.3 HDR.. | %s\n"
+ L" | CTA-861.3 SDR.. | %s\n"
+ L" | =============== |\n"
+ L" | HDR10+......... | %s\n"
+ L" | HDR10+ Gaming.. | %s\n"
+ L" | =============== |\n"
+ L" | Dolby Vision... | %s\n"
+ L" | YUV 4:2:2 12bpc | %s\n"
+ L" | Low Latency.... | %s\n"
+ L" | |- 4:4:4 10bpc | %s\n"
+ L" | |- 4:4:4 12bpc | %s\n"
+ L" +-----------------+---------------------\n",
+ (float)pHdrCapabilities->display_data.displayPrimary_x0 / (float)0xC350, (float)pHdrCapabilities->display_data.displayPrimary_y0 / (float)0xC350,
+ (float)pHdrCapabilities->display_data.displayPrimary_x1 / (float)0xC350, (float)pHdrCapabilities->display_data.displayPrimary_y1 / (float)0xC350,
+ (float)pHdrCapabilities->display_data.displayPrimary_x2 / (float)0xC350, (float)pHdrCapabilities->display_data.displayPrimary_y2 / (float)0xC350,
+ (float)pHdrCapabilities->display_data.displayWhitePoint_x / (float)0xC350, (float)pHdrCapabilities->display_data.displayWhitePoint_y / (float)0xC350,
+ (float)pHdrCapabilities->display_data.desired_content_min_luminance * 0.0001f,
+ (float)pHdrCapabilities->display_data.desired_content_max_luminance,
+ (float)pHdrCapabilities->display_data.desired_content_max_frame_average_luminance,
+ pBackendDisplay != nullptr ?
+ pBackendDisplay->hdr.white_level :
+ (float)pHdrCapabilities->display_data.desired_content_max_frame_average_luminance,
+ pHdrCapabilities->isST2084EotfSupported ? L"Yes" : L"No",
+ pHdrCapabilities->isTraditionalHdrGammaSupported ? L"Yes" : L"No",
+ pHdrCapabilities->isTraditionalSdrGammaSupported ? L"Yes" : L"No",
+ pHdrCapabilities->isHdr10PlusSupported ? L"Yes" : L"No",
+ pHdrCapabilities->isHdr10PlusGamingSupported ? L"Yes" : L"No",
+ pHdrCapabilities->isDolbyVisionSupported ? L"Yes" : L"No",
+ pHdrCapabilities->dv_static_metadata.supports_YUV422_12bit ? L"Yes" : L"No",
+ (pHdrCapabilities->dv_static_metadata.interface_supported_by_sink
+ & 0x2) ? L"Yes" : L"No",
+ (pHdrCapabilities->dv_static_metadata.supports_10b_12b_444 & 0x1) ? L"Yes" : L"No",
+ (pHdrCapabilities->dv_static_metadata.supports_10b_12b_444 & 0x2) ? L"Yes" : L"No");
+ }
return ret;
}
diff --git a/src/plugins/reshade.cpp b/src/plugins/reshade.cpp
index a56961b0e..5ad7db96a 100644
--- a/src/plugins/reshade.cpp
+++ b/src/plugins/reshade.cpp
@@ -566,6 +566,24 @@ SK_ReShadeAddOn_ToggleOverlay (void)
SK_ReShadeAddOn_ActivateOverlay (!ReShadeOverlayActive);
}
+void
+__cdecl
+SK_ReShadeAddOn_DisplayChange (reshade::api::effect_runtime *runtime, reshade::api::display* display)
+{
+ std::ignore = runtime;
+ std::ignore = display;
+
+#if 0
+ auto width = display != nullptr ? (display->get_desktop_coords ().right-display->get_desktop_coords ().left) : 0;
+ auto height = display != nullptr ? (display->get_desktop_coords ().bottom-display->get_desktop_coords ().top) : 0;
+ float refresh = display != nullptr ? (display->get_refresh_rate ().as_float ()) : 0.0f;
+
+ SK_ImGui_Warning (
+ SK_FormatStringW (L"ReShade Display Change: %ws (%dx%d@%3.1fHz)", display != nullptr ? display->get_display_name () : L"Unknown Monitor", width, height, refresh).c_str ()
+ );
+#endif
+}
+
bool
__cdecl
SK_ReShadeAddOn_OverlayActivation (reshade::api::effect_runtime *runtime, bool open, reshade::api::input_source source)
@@ -1099,24 +1117,48 @@ SK_ReShadeAddOn_Init (HMODULE reshade_module)
CreateDirectoryW (addon_path.c_str (), nullptr);
}
+ bool fully_compatible = true;
+
if ( StrStrIW (mod_name.c_str (), L"dxgi.dll") ||
StrStrIW (mod_name.c_str (), L"d3d12.dll") )
{
+ config.apis.OpenGL.hook = false;
+ config.apis.OpenGL.hook_next = false;
+ config.apis.d3d9.hook = false;
+ config.apis.d3d9.hook_next = false;
+ config.apis.d3d9ex.hook = false;
+ config.apis.d3d9ex.hook_next = false;
+
+ if (config.apis.last_known == SK_RenderAPI::OpenGL)
+ config.apis.last_known = SK_RenderAPI::Reserved;
+ if (config.apis.last_last_known == SK_RenderAPI::OpenGL)
+ config.apis.last_last_known = SK_RenderAPI::Reserved;
+
+ if (config.apis.last_known == SK_RenderAPI::D3D9)
+ config.apis.last_known = SK_RenderAPI::Reserved;
+ if (config.apis.last_last_known == SK_RenderAPI::D3D9)
+ config.apis.last_last_known = SK_RenderAPI::Reserved;
+
+ if (config.apis.last_known == SK_RenderAPI::D3D9Ex)
+ config.apis.last_known = SK_RenderAPI::Reserved;
+ if (config.apis.last_last_known == SK_RenderAPI::D3D9Ex)
+ config.apis.last_last_known = SK_RenderAPI::Reserved;
+
if ((config.apis.last_last_known == SK_RenderAPI::Reserved &&
config.apis. last_known == SK_RenderAPI::Reserved) ||
config.apis. last_known == SK_RenderAPI::D3D12 ||
config.apis.last_last_known == SK_RenderAPI::D3D12)
{
- SK_RunOnce (
- SK_ImGui_WarningWithTitle (
- L"ReShade may cause serious problems if loaded as dxgi.dll/d3d12.dll in D3D12 games rather than a plug-in.\r\n\r\n"
- L"\tThis may be a false positive\r\n\r\n"
- L"If you are not using D3D12, the message will go away and all of ReShade's features should work after restarting the game.",
- L"Incompatible ReShade Install Detected"
- )
- );
-
- return false;
+ //SK_RunOnce (
+ // SK_ImGui_WarningWithTitle (
+ // L"ReShade is not fully compatible with Special K when loaded as dxgi.dll/d3d12.dll in D3D12 games.\r\n\r\n"
+ // L"\tThis may be a false positive\r\n\r\n"
+ // L"If you are not using D3D12, the message will go away and all of ReShade's features should work after restarting the game.",
+ // L"Incompatible ReShade is Detected"
+ // )
+ //);
+
+ fully_compatible = false;
}
}
@@ -1125,8 +1167,8 @@ SK_ReShadeAddOn_Init (HMODULE reshade_module)
if (registered)
return true;
- registered =
- reshade::register_addon (SK_GetDLL (), reshade_module);
+ registered = fully_compatible ?
+ reshade::register_addon (SK_GetDLL (), reshade_module) : true;
if (registered)
{
@@ -1141,15 +1183,19 @@ SK_ReShadeAddOn_Init (HMODULE reshade_module)
if (! PathIsDirectoryW (shared_addon_path.c_str ()))
CreateDirectoryW (shared_addon_path.c_str (), nullptr);
- config.reshade.is_addon = true;
-
- reshade::register_event (SK_ReShadeAddOn_Present);
- reshade::register_event (SK_ReShadeAddOn_InitRuntime);
- reshade::register_event (SK_ReShadeAddOn_DestroyRuntime);
- reshade::register_event (SK_ReShadeAddOn_DestroyDevice);
- reshade::register_event (SK_ReShadeAddOn_DestroySwapChain);
- reshade::register_event (SK_ReShadeAddOn_DestroyCmdQueue);
- reshade::register_event (SK_ReShadeAddOn_OverlayActivation);
+ if (fully_compatible)
+ {
+ config.reshade.is_addon = true;
+
+ reshade::register_event (SK_ReShadeAddOn_Present);
+ reshade::register_event (SK_ReShadeAddOn_InitRuntime);
+ reshade::register_event (SK_ReShadeAddOn_DestroyRuntime);
+ reshade::register_event (SK_ReShadeAddOn_DestroyDevice);
+ reshade::register_event (SK_ReShadeAddOn_DestroySwapChain);
+ reshade::register_event (SK_ReShadeAddOn_DestroyCmdQueue);
+ reshade::register_event (SK_ReShadeAddOn_OverlayActivation);
+ reshade::register_event (SK_ReShadeAddOn_DisplayChange);
+ }
auto _AutoLoadAddOns = [&](void)
{
@@ -1178,8 +1224,8 @@ SK_ReShadeAddOn_Init (HMODULE reshade_module)
const auto filename = path.filename ().wstring ();
const auto filename_utf8 = path.filename ().u8string ();
- dll_log->LogEx (
- true, L"[ SpecialK ] * Loading ReShade AddOn: '%ws' from '%ws' ... ",
+ dll_log->Log (
+ L"[ SpecialK ] * Loading ReShade AddOn: '%ws' from '%ws' ... ",
filename.c_str (),
SK_StripUserNameFromPathW (path.parent_path ().wstring ().data ())
);
@@ -1190,7 +1236,7 @@ SK_ReShadeAddOn_Init (HMODULE reshade_module)
if (hModAddOn != skModuleRegistry::INVALID_MODULE)
{
- dll_log->LogEx (false, L"success!\n");
+ //dll_log->LogEx (false, L"success!\n");
// Don't announce global AddOns
if (! StrStrIW (path.c_str (), L"Global\\ReShade\\"))
@@ -1209,7 +1255,7 @@ SK_ReShadeAddOn_Init (HMODULE reshade_module)
{
_com_error err (HRESULT_FROM_WIN32 (GetLastError ()));
- dll_log->LogEx (false, L"failed: 0x%04X (%s)!\n",
+ dll_log->Log (L"LoadLibrary failed: 0x%04X (%s)!\n",
err.WCode (), err.ErrorMessage () );
}
}
diff --git a/src/plugins/sekiro.cpp b/src/plugins/sekiro.cpp
index 87f7758e1..d9adc7c07 100644
--- a/src/plugins/sekiro.cpp
+++ b/src/plugins/sekiro.cpp
@@ -188,8 +188,8 @@ WSAAPI WSAWaitForMultipleEvents_Detour (
if (! disable_network_code)
{
- dll_log->Log ( L" >> Calling Thread for Network Activity: %s",
- SK_Thread_GetName (SK_Thread_GetCurrentId ()).c_str () );
+ dll_log->Log ( L" >> Calling Thread for Network Activity: %ws",
+ SK_Thread_GetName (SK_Thread_GetCurrentId ()) );
}
UNREFERENCED_PARAMETER (cEvents);
@@ -226,8 +226,8 @@ WSAAPI WSASocketW_Detour (
if (! disable_network_code)
{
- dll_log->Log ( L" >> Calling Thread for Network Activity: %s",
- SK_Thread_GetName (SK_Thread_GetCurrentId () ).c_str () );
+ dll_log->Log ( L" >> Calling Thread for Network Activity: %ws",
+ SK_Thread_GetName (SK_Thread_GetCurrentId ()) );
}
UNREFERENCED_PARAMETER (af);
diff --git a/src/plugins/unclassified.cpp b/src/plugins/unclassified.cpp
index 47c707cf6..0b4df3cbc 100644
--- a/src/plugins/unclassified.cpp
+++ b/src/plugins/unclassified.cpp
@@ -1617,6 +1617,10 @@ SK_Metaphor_InitPlugin (void)
SK_CPU_IsZen ();
}
+ // This was auto-disabled for many users with texture mods, it should be enabled for performance reasons
+ config.textures.cache.allow_staging = false;
+ config.render.dxgi.low_spec_mode = true;
+
SK_SaveConfig ();
SK_CreateFuncHook ( L"SK_DetourWindowProc",
diff --git a/src/render/d3d11/d3d11.cpp b/src/render/d3d11/d3d11.cpp
index 6e751497b..0da1f6dc1 100644
--- a/src/render/d3d11/d3d11.cpp
+++ b/src/render/d3d11/d3d11.cpp
@@ -2993,8 +2993,10 @@ SK_D3D11_DrawHandler ( ID3D11DeviceContext *pDevCtx,
SK_D3D11DrawType draw_type,
UINT num_verts,
SK_TLS **ppTLS = nullptr,
- UINT& dev_idx = NegativeOne )
+ UINT& _dev_idx = NegativeOne )
{
+ UINT dev_idx = _dev_idx;
+
std::ignore = draw_type;
std::ignore = num_verts;
@@ -3036,18 +3038,20 @@ SK_D3D11_DrawHandler ( ID3D11DeviceContext *pDevCtx,
///if (SK_D3D11_IsDevCtxDeferred (pDevCtx))
/// return false;
+ ///
dev_idx = ( dev_idx == NegativeOne ? SK_D3D11_GetDeviceContextHandle (pDevCtx)
: dev_idx );
+ if (&_dev_idx != &NegativeOne)
+ _dev_idx = dev_idx;
+
// ImGui gets to pass-through without invoking the hook
if (SK_ImGui_IsDrawing_OnD3D11Ctx (dev_idx, pDevCtx))
{
return Normal;
}
- std::scoped_lock auto_lock (*cs_render_view);
-
using _Registry =
SK_D3D11_KnownShaders::ShaderRegistry *;
@@ -3161,6 +3165,8 @@ const
if (SK_D3D11_EnableTracking)
{
+ std::scoped_lock shader_lock (*cs_render_view);
+
SK_D3D11_DrawThreads->mark ();
bool rtv_active = false;
@@ -3274,6 +3280,8 @@ const
if (SK_D3D11_ShouldSkipHUD ())
{
+ std::scoped_lock hud_lock (*cs_render_view);
+
if ( vertex.hud.find (current_vs) != vertex.hud.cend () ||
pixel.hud.find (current_ps) != pixel.hud.cend () ||
geometry.hud.find (current_gs) != geometry.hud.cend () ||
@@ -3306,6 +3314,8 @@ const
if ( blacklist_cache.count > 0 )
{
+ std::scoped_lock blacklist_lock (*cs_render_view);
+
if ( vertex.blacklist.find (current_vs) != vertex.blacklist.cend () ||
pixel.blacklist.find (current_ps) != pixel.blacklist.cend () ||
geometry.blacklist.find (current_gs) != geometry.blacklist.cend () ||
@@ -3338,6 +3348,8 @@ const
auto& views =
blacklist.first->current.views [dev_idx];
+ std::scoped_lock blacklist_view_lock (*cs_render_view);
+
for (auto& it2 : views)
{
if (it2 == nullptr)
@@ -3426,6 +3438,8 @@ const
if (pDev != nullptr)
{
+ std::scoped_lock auto_lock (*cs_render_view);
+
auto& pTLS_d3d11 =
_SetupOverrideContext ();
@@ -3495,6 +3509,8 @@ const
if (pDev != nullptr)
{
+ std::scoped_lock auto_lock (*cs_render_view);
+
auto& pTLS_d3d11 =
_SetupOverrideContext ();
@@ -3555,6 +3571,8 @@ const
overrides = { nullptr };
+ std::scoped_lock cbuffer_lock (*cs_render_view);
+
for (int i = 0; i < 5; i++)
{
if (current_shaders [i] == 0x00)
@@ -9239,8 +9257,6 @@ D3D11Dev_GetImmediateContext3_Override (
void
SK_D3D11_EndFrame (SK_TLS* pTLS)
{
- std::scoped_lock auto_lock2 (*cs_render_view);
-
for ( auto end_frame_fn : plugin_mgr->end_frame_fns )
{
end_frame_fn ();
@@ -9263,6 +9279,8 @@ SK_D3D11_EndFrame (SK_TLS* pTLS)
return;
}
+ std::scoped_lock auto_lock2 (*cs_render_view);
+
const SK_RenderBackend& rb =
SK_GetCurrentRenderBackend ();
diff --git a/src/render/d3d11/d3d11_screenshot.cpp b/src/render/d3d11/d3d11_screenshot.cpp
index 54d4e4b98..4c9435db5 100644
--- a/src/render/d3d11/d3d11_screenshot.cpp
+++ b/src/render/d3d11/d3d11_screenshot.cpp
@@ -333,12 +333,6 @@ SK_D3D11_Screenshot::SK_D3D11_Screenshot (const SK_ComPtr & pDevic
else
pImmediateCtx = rb.d3d11.immediate_ctx;
- SK_ComQIPtr pImmediateCtx3 (pImmediateCtx);
-
- if ( pImmediateCtx3 != nullptr &&
- pImmediateCtx3 != pImmediateCtx )
- { pImmediateCtx = pImmediateCtx3; }
-
D3D11_QUERY_DESC fence_query_desc =
{
D3D11_QUERY_EVENT,
@@ -682,6 +676,8 @@ SK_D3D11_Screenshot::SK_D3D11_Screenshot (const SK_ComPtr & pDevic
pImmediateCtx->CopyResource ( pStagingBackbufferCopy,
pBackbufferSurface );
}
+
+ pBackbufferSurface.Release ();
}
else
@@ -709,14 +705,12 @@ SK_D3D11_Screenshot::SK_D3D11_Screenshot (const SK_ComPtr & pDevic
pImmediateCtx->CopyResource ( pStagingBackbufferCopy,
pResolvedTex );
}
- }
- if (pImmediateCtx3 != nullptr)
- {
- pImmediateCtx3->Flush1 (D3D11_CONTEXT_TYPE_COPY, nullptr);
+ pBackbufferSurface.Release ();
}
- pImmediateCtx->End (pPixelBufferFence);
+ pImmediateCtx->End (pPixelBufferFence);
+ pImmediateCtx->Flush ();
if (bPlaySound)
SK_Screenshot_PlaySound ();
@@ -909,10 +903,6 @@ volatile LONG __SK_ScreenShot_CapturingHUDless = 0;
volatile LONG __SK_D3D11_QueuedShots = 0;
volatile LONG __SK_D3D11_InitiateHudFreeShot = 0;
-SK_LazyGlobal > screenshot_queue;
-SK_LazyGlobal > screenshot_write_queue;
-
-
static volatile LONG
__SK_HUD_YesOrNo = 1L;
@@ -1155,6 +1145,16 @@ SK_D3D11_ProcessScreenshotQueueEx ( SK_ScreenshotStage stage_,
return;
+ static concurrency::concurrent_queue screenshot_queue;
+ static concurrency::concurrent_queue screenshot_write_queue;
+ // Any incomplete captures are pushed onto this queue, and then the pending
+ // queue (once drained) is re-built.
+ //
+ // This is faster than iterating a synchronized list in highly multi-threaded engines.
+ static concurrency::concurrent_queue rejected_screenshots;
+ static concurrency::concurrent_queue raw_images_;
+
+
if ( stage == ( __MaxStage + 1 ) && purge )
{
// Empty all stage queues first, then we
@@ -1171,7 +1171,6 @@ SK_D3D11_ProcessScreenshotQueueEx ( SK_ScreenshotStage stage_,
}
}
-
else if (stage <= __MaxStage)
{
if (ReadAcquire (&enqueued_screenshots.stages [stage]) > 0)
@@ -1206,7 +1205,7 @@ SK_D3D11_ProcessScreenshotQueueEx ( SK_ScreenshotStage stage_,
std::string title = "";
std::swap (enqueued_titles.stages [stage], title);
- screenshot_queue->push (
+ screenshot_queue.push (
new SK_D3D11_Screenshot (
pDev, allow_sound, clipboard_only, title
)
@@ -1277,11 +1276,11 @@ SK_D3D11_ProcessScreenshotQueueEx ( SK_ScreenshotStage stage_,
static std::vector to_write;
- while (! screenshot_write_queue->empty ())
+ while (! screenshot_write_queue.empty ())
{
- SK_D3D11_Screenshot* pop_off = nullptr;
- if ( screenshot_write_queue->try_pop (pop_off) &&
- pop_off != nullptr )
+ SK_D3D11_Screenshot* pop_off = nullptr;
+ if ( screenshot_write_queue.try_pop (pop_off) &&
+ pop_off != nullptr )
{
if (purge_and_run)
{
@@ -1824,9 +1823,6 @@ SK_D3D11_ProcessScreenshotQueueEx ( SK_ScreenshotStage stage_,
continue;
}
- static concurrency::concurrent_queue
- raw_images_;
-
SK_Screenshot::framebuffer_s* fb_orig =
it->getFinishedData ();
@@ -2115,22 +2111,15 @@ SK_D3D11_ProcessScreenshotQueueEx ( SK_ScreenshotStage stage_,
if (stage_ != SK_ScreenshotStage::_FlushQueue && wait == false && purge == false)
return;
-
- // Any incomplete captures are pushed onto this queue, and then the pending
- // queue (once drained) is re-built.
- //
- // This is faster than iterating a synchronized list in highly multi-threaded engines.
- static concurrency::concurrent_queue rejected_screenshots;
-
bool new_jobs = false;
do
{
do
{
- SK_D3D11_Screenshot* pop_off = nullptr;
- if ( screenshot_queue->try_pop (pop_off) &&
- pop_off != nullptr )
+ SK_D3D11_Screenshot* pop_off = nullptr;
+ if ( screenshot_queue.try_pop (pop_off) &&
+ pop_off != nullptr )
{
if (purge)
delete pop_off;
@@ -2147,7 +2136,7 @@ SK_D3D11_ProcessScreenshotQueueEx ( SK_ScreenshotStage stage_,
//
if (pop_off->getData (&Width, &Height, &pData, wait))
{
- screenshot_write_queue->push (pop_off);
+ screenshot_write_queue.push (pop_off);
new_jobs = true;
}
@@ -2155,7 +2144,7 @@ SK_D3D11_ProcessScreenshotQueueEx ( SK_ScreenshotStage stage_,
rejected_screenshots.push (pop_off);
}
}
- } while ((! screenshot_queue->empty ()) && (purge || wait));
+ } while ((! screenshot_queue.empty ()) && (purge || wait));
do
{
@@ -2167,17 +2156,17 @@ SK_D3D11_ProcessScreenshotQueueEx ( SK_ScreenshotStage stage_,
delete push_back;
else
- screenshot_queue->push (push_back);
+ screenshot_queue.push (push_back);
}
} while ((! rejected_screenshots.empty ()) && (purge || wait));
if ( wait ||
purge )
{
- if ( screenshot_queue->empty () &&
+ if ( screenshot_queue.empty () &&
rejected_screenshots.empty () )
{
- if ( purge && (! screenshot_write_queue->empty ()) )
+ if ( purge && (! screenshot_write_queue.empty ()) )
{
SetThreadPriority ( hWriteThread, THREAD_PRIORITY_TIME_CRITICAL );
SignalObjectAndWait ( signal.abort.initiate,
diff --git a/src/render/d3d11/d3d11_shader.cpp b/src/render/d3d11/d3d11_shader.cpp
index 1b892cb24..9e3684177 100644
--- a/src/render/d3d11/d3d11_shader.cpp
+++ b/src/render/d3d11/d3d11_shader.cpp
@@ -869,7 +869,7 @@ SK_D3D11_SetShaderResources_Impl (
bool early_out = (! bMustNotIgnore) || shader_base == nullptr ||
SK_D3D11_IgnoreWrappedOrDeferred (bWrapped,
SK_D3D11_IsDevCtxDeferred (pDevContext),
- pDevContext) || cs_lock == nullptr;
+ pDevContext);
if (early_out)
{
@@ -880,6 +880,7 @@ SK_D3D11_SetShaderResources_Impl (
if (dev_idx == UINT_MAX)
dev_idx = SK_D3D11_GetDeviceContextHandle (pDevContext);
+
auto& views =
shader_base->current.views [dev_idx];
@@ -954,6 +955,7 @@ SK_D3D11_SetShaderResources_Impl (
std::lock (*cs_lock, *cs_render_view);
std::lock_guard auto_lock1 (*cs_lock, std::adopt_lock);
std::lock_guard auto_lock2 (*cs_render_view, std::adopt_lock);
+
for (UINT i = 0; i < NumViews; i++)
{
if (StartSlot + i >= D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT)
diff --git a/src/render/d3d11/d3d11_state_tracker.cpp b/src/render/d3d11/d3d11_state_tracker.cpp
index de1433472..8a07c5eb2 100644
--- a/src/render/d3d11/d3d11_state_tracker.cpp
+++ b/src/render/d3d11/d3d11_state_tracker.cpp
@@ -64,7 +64,7 @@ volatile LONG
SK_D3D11_CBufferTrackingReqs = 0L;
bool
-SK_ImGui_IsDrawing_OnD3D11Ctx (UINT dev_idx, ID3D11DeviceContext* pDevCtx)
+SK_ImGui_IsDrawing_OnD3D11Ctx (UINT& dev_idx, ID3D11DeviceContext* pDevCtx)
{
if (pDevCtx == nullptr || dev_idx == UINT_MAX)
{
diff --git a/src/render/d3d11/mod_tools/d3d11_shader_mods.cpp b/src/render/d3d11/mod_tools/d3d11_shader_mods.cpp
index 80a03ab0e..1282afb55 100644
--- a/src/render/d3d11/mod_tools/d3d11_shader_mods.cpp
+++ b/src/render/d3d11/mod_tools/d3d11_shader_mods.cpp
@@ -265,15 +265,6 @@ SK_D3D11_ShaderModDlg (SK_TLS* pTLS = SK_TLS_Bottom ())
const SK_RenderBackend_V2& rb =
SK_GetCurrentRenderBackend ();
- std::scoped_lock < SK_Thread_HybridSpinlock, SK_Thread_HybridSpinlock,
- SK_Thread_HybridSpinlock, SK_Thread_HybridSpinlock,
- SK_Thread_HybridSpinlock, SK_Thread_HybridSpinlock,
- SK_Thread_HybridSpinlock >
- fort_knox ( *cs_shader, *cs_shader_vs, *cs_shader_ps,
- *cs_shader_gs, *cs_shader_hs, *cs_shader_ds,
- *cs_shader_cs );
-
-
const float font_size = (ImGui::GetFont ()->FontSize * io.FontGlobalScale);
const float font_size_multiline = font_size + ImGui::GetStyle ().ItemSpacing.y +
ImGui::GetStyle ().ItemInnerSpacing.y;
@@ -293,6 +284,14 @@ SK_D3D11_ShaderModDlg (SK_TLS* pTLS = SK_TLS_Bottom ())
// SK_D3D11_DispatchThreads.count_active (), SK_D3D11_DispatchThreads.count_all () ).c_str (),
&show_dlg ) )
{
+ std::scoped_lock < SK_Thread_HybridSpinlock, SK_Thread_HybridSpinlock,
+ SK_Thread_HybridSpinlock, SK_Thread_HybridSpinlock,
+ SK_Thread_HybridSpinlock, SK_Thread_HybridSpinlock,
+ SK_Thread_HybridSpinlock, SK_Thread_HybridSpinlock >
+ fort_knox ( *cs_shader, *cs_shader_vs, *cs_shader_ps,
+ *cs_shader_gs, *cs_shader_hs, *cs_shader_ds,
+ *cs_shader_cs, *cs_render_view );
+
static bool draw_srv_overlay = false;
static SK_ComPtr pOverlaySRV;
diff --git a/src/render/d3d11/tex_mgr/d3d11_tex_mgr.cpp b/src/render/d3d11/tex_mgr/d3d11_tex_mgr.cpp
index 7f74b2583..33f12287f 100644
--- a/src/render/d3d11/tex_mgr/d3d11_tex_mgr.cpp
+++ b/src/render/d3d11/tex_mgr/d3d11_tex_mgr.cpp
@@ -2611,6 +2611,78 @@ SK_D3D11_UseTexture (ID3D11Texture2D* pTex)
SK_D3D11_TextureIsCachedEx (pTex, true);
}
+void
+SK_D3D11_SafeCopyDebugName (ID3D11DeviceChild* pObject, std::string& debug_name)
+{
+ if (pObject == nullptr || (! debug_name.empty ()))
+ return;
+
+ UINT uiDescLen = 127;
+
+ __try
+ {
+ wchar_t wszDesc [128] = { };
+ uiDescLen = sizeof (wszDesc) - sizeof (wchar_t);
+
+ if ( SUCCEEDED (
+ pObject->GetPrivateData (
+ WKPDID_D3DDebugObjectNameW,
+ &uiDescLen, wszDesc )
+ ) && uiDescLen > sizeof (wchar_t)
+ )
+ {
+ wszDesc [127] = L'\0';
+
+ debug_name.resize (uiDescLen
+ / sizeof (wchar_t) + 1);
+ std::string_view d (debug_name.data (), 128);
+ SK_FormatStringView (d,"%ws",wszDesc);
+ }
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER) {};
+
+ if (! debug_name.empty ())
+ return;
+
+ __try
+ {
+ char szDesc [128] = { };
+ uiDescLen = sizeof (szDesc) - sizeof (char);
+
+ if ( SUCCEEDED (
+ pObject->GetPrivateData (
+ WKPDID_D3DDebugObjectName,
+ &uiDescLen, szDesc )
+ ) && uiDescLen > sizeof (char)
+ )
+ {
+ szDesc [127] = '\0';
+
+ debug_name.assign (szDesc);
+ }
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER) {};
+}
+
+void
+SK_D3D11_SafeAssignTexDebugName (ID3D11Texture2D* tex_ref)
+{
+ __try
+ {
+ auto& tex_desc =
+ SK_D3D11_Textures->Textures_2D [tex_ref];
+
+ if (tex_desc.debug_name.empty ())
+ {
+ SK_D3D11_SafeCopyDebugName (tex_ref, tex_desc.debug_name);
+ }
+ }
+
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ };
+}
+
bool
__stdcall
SK_D3D11_RemoveTexFromCache (ID3D11Texture2D* pTex, bool blacklist)
@@ -2696,57 +2768,10 @@ SK_D3D11_TexMgr::updateDebugNames (void)
if ( TexRefs_2D.count (it2.second) &&
Textures_2D.count (it2.second) )
{
- const auto& tex_ref =
- TexRefs_2D.find (it2.second);
-
- auto& tex_desc =
- Textures_2D [*tex_ref];
-
- if (tex_desc.debug_name.empty ())
+ if (const auto& tex_ref = TexRefs_2D.find (it2.second);
+ tex_ref != TexRefs_2D.end ())
{
- char szDesc [128] = { };
- wchar_t wszDesc [128] = { };
- UINT uiDescLen = 127;
-
- auto se_orig =
- SK_SEH_ApplyTranslator (
- SK_FilteringStructuredExceptionTranslator (
- EXCEPTION_ACCESS_VIOLATION
- )
- );
- try
- {
- uiDescLen = sizeof (wszDesc) - sizeof (wchar_t);
-
- if ( SUCCEEDED (
- (*tex_ref)->GetPrivateData (
- WKPDID_D3DDebugObjectNameW,
- &uiDescLen, wszDesc )
- ) && uiDescLen > sizeof (wchar_t)
- )
- {
- tex_desc.debug_name =
- SK_WideCharToUTF8 (wszDesc);
- }
-
- else
- {
- uiDescLen = sizeof (szDesc) - sizeof (char);
-
- if ( SUCCEEDED (
- (*tex_ref)->GetPrivateData (
- WKPDID_D3DDebugObjectName,
- &uiDescLen, szDesc )
- ) && uiDescLen > sizeof (char)
- )
- {
- tex_desc.debug_name =
- szDesc;
- }
- }
- }
- catch (const SK_SEH_IgnoredException&) { }
- SK_SEH_RemoveTranslator (se_orig);
+ SK_D3D11_SafeAssignTexDebugName (*tex_ref);
}
}
}
@@ -3186,7 +3211,7 @@ SK_D3D11_PopulateResourceList (bool refresh)
if (files > 0)
{
- if (config.render.dxgi.low_spec_mode)
+ if (config.render.dxgi.low_spec_mode && config.textures.cache.allow_staging)
{ config.render.dxgi.low_spec_mode = false;
dll_log->Log (
diff --git a/src/render/d3d12/d3d12_device.cpp b/src/render/d3d12/d3d12_device.cpp
index f72fff73c..94aea3bed 100644
--- a/src/render/d3d12/d3d12_device.cpp
+++ b/src/render/d3d12/d3d12_device.cpp
@@ -160,6 +160,7 @@ SK_D3D12_ShouldSkipHUD (void)
ReadAcquire (&__SK_HUD_YesOrNo) <= 0 );
if ( ReadAcquire (&__SK_HUD_YesOrNo) <= 0 )
{
+#ifdef D3D12_STATE_TRACK
UINT size = 1;
bool disable = true;
@@ -168,6 +169,7 @@ SK_D3D12_ShouldSkipHUD (void)
if (live && (! _criticalVertexShaders.count (ps)))
ps->SetPrivateData ( SKID_D3D12DisablePipelineState, size, &disable );
}
+#endif
}
return ret;
@@ -177,7 +179,7 @@ LONG
SK_D3D12_ShowGameHUD (void)
{
//InterlockedDecrement (&SK_D3D11_DrawTrackingReqs);
-
+#ifdef D3D12_STATE_TRACK
UINT size = 1;
bool disable = false;
@@ -186,6 +188,7 @@ SK_D3D12_ShowGameHUD (void)
if (live)
ps->SetPrivateData ( SKID_D3D12DisablePipelineState, size, &disable );
}
+#endif
return
InterlockedIncrement (&__SK_HUD_YesOrNo);
@@ -196,6 +199,7 @@ SK_D3D12_HideGameHUD (void)
{
//InterlockedIncrement (&SK_D3D11_DrawTrackingReqs);
+#ifdef D3D12_STATE_TRACK
UINT size = 1;
bool disable = true;
@@ -204,6 +208,7 @@ SK_D3D12_HideGameHUD (void)
if (live && (! _criticalVertexShaders.count (ps)))
ps->SetPrivateData ( SKID_D3D12DisablePipelineState, size, &disable );
}
+#endif
return
InterlockedDecrement (&__SK_HUD_YesOrNo);
@@ -370,6 +375,7 @@ _COM_Outptr_ void **ppPipelineState )
if (pDesc == nullptr)
return hrPipelineCreate;
+#ifdef D3D12_STATE_TRACK
static const
std::unordered_map
repo_map =
@@ -493,6 +499,7 @@ _COM_Outptr_ void **ppPipelineState )
SK_ReleaseAssert (! "ID3DDestructionNotifier Implemented");
}
}
+#endif
return
hrPipelineCreate;
@@ -824,6 +831,7 @@ _COM_Outptr_ void **ppPipelineState )
D3D12Device2_CreatePipelineState_Original (
This, pDesc, riid, ppPipelineState );
+#ifdef D3D12_STATE_TRACK
// Do not enable in other games for now, needs more testing
//
static const bool bEldenRing =
@@ -859,6 +867,7 @@ _COM_Outptr_ void **ppPipelineState )
}
}
}
+#endif
return hr;
}
diff --git a/src/render/d3d12/d3d12_screenshot.cpp b/src/render/d3d12/d3d12_screenshot.cpp
index 1dde5c754..eb66609ed 100644
--- a/src/render/d3d12/d3d12_screenshot.cpp
+++ b/src/render/d3d12/d3d12_screenshot.cpp
@@ -811,10 +811,6 @@ SK_D3D12_Screenshot::getData ( UINT* const pWidth,
volatile LONG __SK_D3D12_QueuedShots = 0;
volatile LONG __SK_D3D12_InitiateHudFreeShot = 0;
-SK_LazyGlobal > screenshot_queue;
-SK_LazyGlobal > screenshot_write_queue;
-
-
//static volatile LONG
// __SK_HUD_YesOrNo = 1L;
//
@@ -1054,6 +1050,15 @@ SK_D3D12_ProcessScreenshotQueueEx ( SK_ScreenshotStage stage_ = SK_ScreenshotSta
bool wait = false,
bool purge = false )
{
+ static std::atomic_int run_count = 0;
+
+ if (stage_ != SK_ScreenshotStage::_FlushQueue)
+ ++run_count;
+
+ else if (run_count == 0)
+ return;
+
+
const SK_RenderBackend& rb =
SK_GetCurrentRenderBackend ();
@@ -1069,6 +1074,16 @@ SK_D3D12_ProcessScreenshotQueueEx ( SK_ScreenshotStage stage_ = SK_ScreenshotSta
return;
+ static concurrency::concurrent_queue screenshot_queue;
+ static concurrency::concurrent_queue screenshot_write_queue;
+ // Any incomplete captures are pushed onto this queue, and then the pending
+ // queue (once drained) is re-built.
+ //
+ // This is faster than iterating a synchronized list in highly multi-threaded engines.
+ static concurrency::concurrent_queue rejected_screenshots;
+ static concurrency::concurrent_queue raw_images_;
+
+
if ( stage == ( __MaxStage + 1 ) && purge )
{
// Empty all stage queues first, then we
@@ -1085,7 +1100,6 @@ SK_D3D12_ProcessScreenshotQueueEx ( SK_ScreenshotStage stage_ = SK_ScreenshotSta
}
}
-
else if (stage <= __MaxStage)
{
if (ReadAcquire (&enqueued_screenshots.stages [stage]) > 0)
@@ -1124,7 +1138,7 @@ SK_D3D12_ProcessScreenshotQueueEx ( SK_ScreenshotStage stage_ = SK_ScreenshotSta
std::string title = "";
std::swap (enqueued_titles.stages [stage], title);
- screenshot_queue->push (
+ screenshot_queue.push (
new SK_D3D12_Screenshot (
pDev, rb.d3d12.command_queue, (IDXGISwapChain3 *)
rb.swapchain.p,
@@ -1196,11 +1210,11 @@ SK_D3D12_ProcessScreenshotQueueEx ( SK_ScreenshotStage stage_ = SK_ScreenshotSta
static std::vector to_write;
- while (! screenshot_write_queue->empty ())
+ while (! screenshot_write_queue.empty ())
{
- SK_D3D12_Screenshot* pop_off = nullptr;
- if ( screenshot_write_queue->try_pop (pop_off) &&
- pop_off != nullptr )
+ SK_D3D12_Screenshot* pop_off = nullptr;
+ if ( screenshot_write_queue.try_pop (pop_off) &&
+ pop_off != nullptr )
{
if (purge_and_run)
{
@@ -1790,9 +1804,6 @@ SK_D3D12_ProcessScreenshotQueueEx ( SK_ScreenshotStage stage_ = SK_ScreenshotSta
continue;
}
- static concurrency::concurrent_queue
- raw_images_;
-
SK_Screenshot::framebuffer_s* fb_orig =
it->getFinishedData ();
@@ -2137,22 +2148,15 @@ SK_D3D12_ProcessScreenshotQueueEx ( SK_ScreenshotStage stage_ = SK_ScreenshotSta
if (stage_ != SK_ScreenshotStage::_FlushQueue && wait == false && purge == false)
return;
-
- // Any incomplete captures are pushed onto this queue, and then the pending
- // queue (once drained) is re-built.
- //
- // This is faster than iterating a synchronized list in highly multi-threaded engines.
- static concurrency::concurrent_queue rejected_screenshots;
-
bool new_jobs = false;
do
{
do
{
- SK_D3D12_Screenshot* pop_off = nullptr;
- if ( screenshot_queue->try_pop (pop_off) &&
- pop_off != nullptr )
+ SK_D3D12_Screenshot* pop_off = nullptr;
+ if ( screenshot_queue.try_pop (pop_off) &&
+ pop_off != nullptr )
{
if (purge)
delete pop_off;
@@ -2169,7 +2173,7 @@ SK_D3D12_ProcessScreenshotQueueEx ( SK_ScreenshotStage stage_ = SK_ScreenshotSta
//
if (pop_off->getData (&Width, &Height, &pData, wait))
{
- screenshot_write_queue->push (pop_off);
+ screenshot_write_queue.push (pop_off);
new_jobs = true;
}
@@ -2177,7 +2181,7 @@ SK_D3D12_ProcessScreenshotQueueEx ( SK_ScreenshotStage stage_ = SK_ScreenshotSta
rejected_screenshots.push (pop_off);
}
}
- } while ((! screenshot_queue->empty ()) && (purge || wait));
+ } while ((! screenshot_queue.empty ()) && (purge || wait));
do
{
@@ -2189,17 +2193,17 @@ SK_D3D12_ProcessScreenshotQueueEx ( SK_ScreenshotStage stage_ = SK_ScreenshotSta
delete push_back;
else
- screenshot_queue->push (push_back);
+ screenshot_queue.push (push_back);
}
} while ((!rejected_screenshots.empty ()) && (purge || wait));
if ( wait ||
purge )
{
- if ( screenshot_queue->empty () &&
+ if ( screenshot_queue.empty () &&
rejected_screenshots.empty () )
{
- if ( purge && (! screenshot_write_queue->empty ()) )
+ if ( purge && (! screenshot_write_queue.empty ()) )
{
SetThreadPriority ( hWriteThread, THREAD_PRIORITY_TIME_CRITICAL );
SignalObjectAndWait ( signal.abort.initiate,
diff --git a/src/render/dxgi/dxgi.cpp b/src/render/dxgi/dxgi.cpp
index 525f014f0..7164036c9 100644
--- a/src/render/dxgi/dxgi.cpp
+++ b/src/render/dxgi/dxgi.cpp
@@ -3203,16 +3203,19 @@ SK_DXGI_PresentBase ( IDXGISwapChain *This,
if (config.render.framerate.swapchain_wait > 0 || rb.active_traits.bImplicitlyWaitable)
{
- SK_AutoHandle hWaitHandle (rb.getSwapWaitHandle ());
- if (SK_WaitForSingleObject (hWaitHandle.m_h, 0) == WAIT_TIMEOUT)
+ if ((intptr_t)rb.getSwapWaitHandle () > 0)
{
- if (rb.active_traits.bImplicitlyWaitable || pLimiter->get_limit () > 0.0)
+ SK_AutoHandle hWaitHandle (rb.getSwapWaitHandle ());
+ if (SK_WaitForSingleObject (hWaitHandle.m_h, 0) == WAIT_TIMEOUT)
{
- // Wait on the SwapChain for up to a frame to try and
- // shrink the queue without a full-on stutter.
- SK_WaitForSingleObject (
- hWaitHandle.m_h, rb.active_traits.bImplicitlyWaitable ? INFINITE : (DWORD)pLimiter->get_ms_to_next_tick ()
- );
+ if (rb.active_traits.bImplicitlyWaitable || pLimiter->get_limit () > 0.0)
+ {
+ // Wait on the SwapChain for up to a frame to try and
+ // shrink the queue without a full-on stutter.
+ SK_WaitForSingleObject (
+ hWaitHandle.m_h, rb.active_traits.bImplicitlyWaitable ? INFINITE : (DWORD)pLimiter->get_ms_to_next_tick ()
+ );
+ }
}
}
}
@@ -5053,6 +5056,11 @@ SK_DXGI_CreateSwapChain_PreInit (
if (_NO_ALLOW_MODE_SWITCH)
pDesc->Flags &= ~DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
+ if (SK_IsCurrentGame (SK_GAME_ID::Stalker2))
+ {
+ pDesc->Flags &= ~DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
+ }
+
if (config.render.framerate.disable_flip)
{
@@ -6269,12 +6277,12 @@ DXGIFactory_CreateSwapChain_Override (
if (pCmdQueue != nullptr)
{ pCmdQueue->GetDevice (IID_PPV_ARGS (&pDev12.p));
- if ((new_desc.Flags & DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT) == 0)
- { new_desc.Flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
- rb.active_traits.bImplicitlyWaitable = true;
- }
-
- else
+ //if ((new_desc.Flags & DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT) == 0)
+ //{ new_desc.Flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
+ // rb.active_traits.bImplicitlyWaitable = true;
+ //}
+ //
+ //else
{
rb.active_traits.bImplicitlyWaitable = false;
}
@@ -6974,12 +6982,12 @@ _In_opt_ IDXGIOutput *pRestrictToOutput,
if (pCmdQueue != nullptr)
{ pCmdQueue->GetDevice (IID_PPV_ARGS (&pDev12.p));
- if ((new_desc1.Flags & DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT) == 0)
- { new_desc1.Flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
- rb.active_traits.bImplicitlyWaitable = true;
- }
-
- else
+ //if ((new_desc1.Flags & DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT) == 0)
+ //{ new_desc1.Flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
+ // rb.active_traits.bImplicitlyWaitable = true;
+ //}
+ //
+ //else
{
rb.active_traits.bImplicitlyWaitable = false;
}
diff --git a/src/render/dxgi/dxgi_swapchain.cpp b/src/render/dxgi/dxgi_swapchain.cpp
index 64c65fba5..7d4305236 100644
--- a/src/render/dxgi/dxgi_swapchain.cpp
+++ b/src/render/dxgi/dxgi_swapchain.cpp
@@ -1380,8 +1380,12 @@ IWrapDXGISwapChain::GetFrameLatencyWaitableObject (void)
std::clamp (config.render.framerate.pre_render_limit, 1, 14) );
}
- // Disable waitable SwapChains when HW Flip Queue is active, they don't work right...
- if (false)//rb.windows.unity || rb.windows.unreal)// || rb.displays [rb.active_display].wddm_caps._3_0.HwFlipQueueEnabled)
+ //auto& rb =
+ // SK_GetCurrentRenderBackend ();
+ //
+ //// Disable waitable SwapChains when HW Flip Queue is active, they don't work right...
+ //if (rb.windows.unity || rb.windows.unreal)// || rb.displays [rb.active_display].wddm_caps._3_0.HwFlipQueueEnabled)
+ if (false)
{
static HANDLE fake_waitable =
SK_CreateEvent (nullptr, TRUE, TRUE, nullptr);
@@ -2054,7 +2058,37 @@ SK_DXGI_SwapChain_ResizeBuffers_Impl (
if (SUCCEEDED (ret))
{
if (rb.api == SK_RenderAPI::D3D12) _d3d12_rbk->init ((IDXGISwapChain3 *)pSwapChain, _d3d12_rbk->_pCommandQueue);
- else if (rb.api == SK_RenderAPI::D3D11) _d3d11_rbk->init ((IDXGISwapChain3 *)pSwapChain, _d3d11_rbk->_pDevice, _d3d11_rbk->_pDeviceCtx);
+ else if (rb.api == SK_RenderAPI::D3D11)
+ { // The D3D11 backend releases device and device context, unlike D3D12 that has a
+ // persistent command queue object across destruction and creation of new swapchains.
+ SK_ComPtr pDevice (_d3d11_rbk->_pDevice);
+ SK_ComPtr pDeviceCtx (_d3d11_rbk->_pDeviceCtx);
+
+ if ( pDevice && !pDeviceCtx.p)
+ pDevice->GetImmediateContext (&pDeviceCtx.p);
+ else if (pDeviceCtx && !pDevice.p)
+ pDeviceCtx->GetDevice (&pDevice.p);
+ if (SUCCEEDED(pSwapChain->GetDevice (IID_ID3D11Device,
+ reinterpret_cast(&pDevice.p))))
+ pDevice->
+ GetImmediateContext(&pDeviceCtx.p);
+
+ if (rb.device == nullptr)
+ {
+ rb.setDevice (pDevice);
+ rb.d3d11.immediate_ctx = pDeviceCtx;
+ }
+
+ _d3d11_rbk->init ((IDXGISwapChain3 *)pSwapChain, pDevice, pDeviceCtx);
+ }
+ }
+
+ else
+ {
+ rb.releaseOwnedResources ();
+
+ if (rb.api == SK_RenderAPI::D3D12) ResetImGui_D3D12 (pSwapChain);
+ else if (rb.api == SK_RenderAPI::D3D11) ResetImGui_D3D11 (pSwapChain);
}
};
@@ -2386,10 +2420,16 @@ SK_DXGI_SwapChain_ResizeBuffers_Impl (
{
if (ret != DXGI_ERROR_DEVICE_REMOVED && ret != E_ACCESSDENIED)
{
- SK_LOGi0 ( L"SwapChain Resize Failed (%x) - Error Suppressed!",
- ret );
+ SK_LOGi0 ( L"SwapChain Resize Failed [%x](%ws)!",
+ ret, _com_error (ret).ErrorMessage () );
_ReleaseResourcesAndRetryResize (ret);
+
+ if (SUCCEEDED (ret))
+ {
+ SK_LOGi0 (L" # Successfully recovered after a full teardown of all "
+ L"owned and shared SwapChain resources.");
+ }
}
}
@@ -2463,10 +2503,16 @@ SK_DXGI_SwapChain_ResizeBuffers_Impl (
{
if (ret != DXGI_ERROR_DEVICE_REMOVED && ret != E_ACCESSDENIED)
{
- SK_LOGi0 ( L"SwapChain Resize Failed (%x) - Error Suppressed!",
- ret );
+ SK_LOGi0 ( L"SwapChain Resize Failed [%x](%ws)!",
+ ret, _com_error (ret).ErrorMessage () );
_ReleaseResourcesAndRetryResize (ret);
+
+ if (SUCCEEDED (ret))
+ {
+ SK_LOGi0 (L" # Successfully recovered after a full teardown of all "
+ L"owned and shared SwapChain resources.");
+ }
}
}
@@ -2476,6 +2522,12 @@ SK_DXGI_SwapChain_ResizeBuffers_Impl (
rb.swapchain_consistent = SUCCEEDED (ret);
+ if (rb.swapchain_consistent)
+ {
+ SK_LOGi0 (L" # Successfully recovered after a full teardown of all "
+ L"owned and shared SwapChain resources.");
+ }
+
if (SK_IsDebuggerPresent ())
{
SK_DXGI_OutputDebugString ( "IDXGISwapChain::ResizeBuffers (...) failed, look alive...",
diff --git a/src/render/render_backend.cpp b/src/render/render_backend.cpp
index 37373d137..7e17df550 100644
--- a/src/render/render_backend.cpp
+++ b/src/render/render_backend.cpp
@@ -1150,6 +1150,7 @@ SK_RenderBackend_V2::requestFullscreenMode (bool override)
SUCCEEDED (SK_DXGI_ResizeTarget (pSwapChain,
&swap_desc.BufferDesc, TRUE)) )
{
+ if (config.compatibility.allow_fake_size)
PostMessage ( swap_desc.OutputWindow, WM_SIZE, SIZE_RESTORED,
MAKELPARAM ( swap_desc.BufferDesc.Width,
swap_desc.BufferDesc.Height ) );
diff --git a/src/scheduler.cpp b/src/scheduler.cpp
index 9b8e38d87..654e88192 100644
--- a/src/scheduler.cpp
+++ b/src/scheduler.cpp
@@ -740,10 +740,16 @@ NtWaitForSingleObject_Detour (
// Timeout = nullptr;
#pragma endregion
- auto ret =
- NtWaitForSingleObject_Original (
- Handle, Alertable, Timeout
- );
+ auto ret = STATUS_TIMEOUT;
+
+ // Waiting while debugging occasionally causes crashes
+ __try {
+ ret =
+ NtWaitForSingleObject_Original (
+ Handle, Alertable, Timeout
+ );
+ } __except (GetExceptionCode () == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER
+ : EXCEPTION_CONTINUE_SEARCH) {};
if (ret != STATUS_TIMEOUT)
SK_MMCS_ApplyPendingTaskPriority ();
@@ -1821,15 +1827,15 @@ void SK_Scheduler_Init (void)
SwitchToThread_Detour,
static_cast_p2p (&SwitchToThread_Original) );
- SK_CreateDLLHook2 ( L"NtDll",
- "NtWaitForSingleObject",
- NtWaitForSingleObject_Detour,
- static_cast_p2p (&NtWaitForSingleObject_Original) );
+ ////SK_CreateDLLHook2 ( L"NtDll",
+ //// "NtWaitForSingleObject",
+ //// NtWaitForSingleObject_Detour,
+ //// static_cast_p2p (&NtWaitForSingleObject_Original) );
- SK_CreateDLLHook2 ( L"NtDll",
- "NtWaitForMultipleObjects",
- NtWaitForMultipleObjects_Detour,
- static_cast_p2p (&NtWaitForMultipleObjects_Original) );
+ ////SK_CreateDLLHook2 ( L"NtDll",
+ //// "NtWaitForMultipleObjects",
+ //// NtWaitForMultipleObjects_Detour,
+ //// static_cast_p2p (&NtWaitForMultipleObjects_Original) );
SK_CreateDLLHook2 ( L"Kernel32",
"SetProcessAffinityMask",
diff --git a/src/thread.cpp b/src/thread.cpp
index 97ebcc257..2377ebaca 100644
--- a/src/thread.cpp
+++ b/src/thread.cpp
@@ -44,9 +44,9 @@ SetThreadDescription_pfn SetThreadDescription_Original = nullptr;
static constexpr DWORD MAGIC_THREAD_EXCEPTION = 0x406D1388;
-SK_LazyGlobal > _SK_ThreadNames;
-SK_LazyGlobal > _SK_SelfTitledThreads;
-SK_LazyGlobal > _SK_UntitledThreads;
+SK_LazyGlobal >> _SK_ThreadNames;
+SK_LazyGlobal > _SK_SelfTitledThreads;
+SK_LazyGlobal > _SK_UntitledThreads;
void __make_self_titled (DWORD dwTid);
@@ -97,7 +97,7 @@ SK_GetThreadDescription ( _In_ HANDLE hThread,
static std::wstring _noname = L"";
-std::wstring&
+const wchar_t*
SK_Thread_QueryNameFromOS (DWORD dwTid)
{
if (_SK_UntitledThreads->find (dwTid) == _SK_UntitledThreads->cend ())
@@ -115,16 +115,15 @@ SK_Thread_QueryNameFromOS (DWORD dwTid)
if ( wszThreadName != nullptr &&
*wszThreadName != L'\0' ) // Empty strings are not useful :)
{
- auto& names =
- _SK_ThreadNames.get ();
+ auto name =
+ _SK_ThreadNames.get()[dwTid].data();
__make_self_titled (dwTid);
- names [dwTid] = wszThreadName;
+ wcsncpy_s (name, SK_MAX_THREAD_NAME_LEN, wszThreadName, _TRUNCATE);
LocalFree (wszThreadName);
- return
- names [dwTid];
+ return name;
}
LocalFree (wszThreadName);
@@ -135,7 +134,7 @@ SK_Thread_QueryNameFromOS (DWORD dwTid)
}
return
- _noname;
+ L"";
}
DWORD
@@ -144,16 +143,16 @@ SK_Thread_FindByName (std::wstring name)
auto& threads =
_SK_ThreadNames.get ();
- for (auto &thread : threads)
+ for (const auto &thread : threads)
{
- if (thread.second._Equal (name.c_str ()))
+ if (!_wcsicmp (thread.second.data (), name.c_str ()))
return thread.first;
}
return 0;
}
-std::wstring&
+const wchar_t*
SK_Thread_GetName (DWORD dwTid)
{
auto& names =
@@ -163,13 +162,13 @@ SK_Thread_GetName (DWORD dwTid)
names.find (dwTid);
if (it != names.cend ())
- return (*it).second;
+ return (*it).second.data ();
return
SK_Thread_QueryNameFromOS (dwTid);
}
-std::wstring&
+const wchar_t*
SK_Thread_GetName (HANDLE hThread)
{
return
@@ -218,6 +217,16 @@ SK_Thread_SetWin10NameFromException (THREADNAME_INFO *pTni)
SK_SetThreadDescription ( hThread.m_h,
wideDesc.c_str () )
);
+
+ if (bRet)
+ {
+ if (StrStrIW (wideDesc.c_str (), L"D3D Background Thread"))
+ {
+ // Running these threads at idle priority leads to optimal shaders
+ // never being compiled in CPU-heavy games.
+ SetThreadPriority (hThread.m_h, THREAD_PRIORITY_LOWEST);
+ }
+ }
}
}
@@ -270,9 +279,9 @@ SetCurrentThreadDescription (_In_ PCWSTR lpThreadDescription)
bool non_empty =
SUCCEEDED ( StringCbLengthW (
- lpThreadDescription, MAX_THREAD_NAME_LEN-1, &len
+ lpThreadDescription, SK_MAX_THREAD_NAME_LEN-1, &len
)
- ) && len > 0;
+ ) && len > 0;
if (non_empty)
{
@@ -283,9 +292,10 @@ SetCurrentThreadDescription (_In_ PCWSTR lpThreadDescription)
SK_TLS *pTLS =
SK_TLS_Bottom ();
- DWORD dwTid = SK_Thread_GetCurrentId ();
- __make_self_titled (dwTid);
- ThreadNames [dwTid] = lpThreadDescription;
+ DWORD dwTid = SK_Thread_GetCurrentId ();
+ __make_self_titled (dwTid);
+ wcsncpy_s (ThreadNames [dwTid].data (), SK_MAX_THREAD_NAME_LEN,
+ lpThreadDescription, _TRUNCATE);
if (pTLS != nullptr)
{
@@ -293,14 +303,14 @@ SetCurrentThreadDescription (_In_ PCWSTR lpThreadDescription)
// when no debugger is attached.
wcsncpy_s (
pTLS->debug.name,
- std::min (MAX_THREAD_NAME_LEN, (int)len+1),
+ std::min (SK_MAX_THREAD_NAME_LEN, (int)len+1),
lpThreadDescription,
_TRUNCATE
);
}
- char szDesc [MAX_THREAD_NAME_LEN] = { };
- wcstombs (szDesc, lpThreadDescription, MAX_THREAD_NAME_LEN-1);
+ char szDesc [SK_MAX_THREAD_NAME_LEN] = { };
+ wcstombs (szDesc, lpThreadDescription, SK_MAX_THREAD_NAME_LEN-1);
THREADNAME_INFO info = { };
info.dwType = 4096;
@@ -332,10 +342,10 @@ GetCurrentThreadDescription (_Out_ PWSTR *threadDescription)
{
// This is not freed here; the caller is expected to free it!
*threadDescription =
- (wchar_t *)SK_LocalAlloc (LPTR, sizeof (wchar_t) * MAX_THREAD_NAME_LEN);
+ (wchar_t *)SK_LocalAlloc (LPTR, sizeof (wchar_t) * SK_MAX_THREAD_NAME_LEN);
wcsncpy_s (
- *threadDescription, MAX_THREAD_NAME_LEN-1,
+ *threadDescription, SK_MAX_THREAD_NAME_LEN-1,
pTLS->debug.name, _TRUNCATE
);
@@ -424,8 +434,8 @@ SetThreadDescription_Detour (HANDLE hThread, PCWSTR lpThreadDescription)
SK_ValidatePointer ((void *)lpThreadDescription, true)
)
{
- char szDesc [MAX_THREAD_NAME_LEN] = { };
- wcstombs (szDesc, lpThreadDescription, MAX_THREAD_NAME_LEN-1);
+ char szDesc [SK_MAX_THREAD_NAME_LEN] = { };
+ wcstombs (szDesc, lpThreadDescription, SK_MAX_THREAD_NAME_LEN-1);
THREADNAME_INFO info = { };
info.dwType = 4096;
diff --git a/src/widgets/hdr.cpp b/src/widgets/hdr.cpp
index dbca136f7..c375bb9f9 100644
--- a/src/widgets/hdr.cpp
+++ b/src/widgets/hdr.cpp
@@ -1233,11 +1233,13 @@ class SKWG_HDR_Control : public SK_Widget, SK_IVariableListener
// Trigger the game to resize the SwapChain so we can change its format and colorspace
//
+ if (config.compatibility.allow_fake_size)
PostMessage ( game_window.hWnd, WM_SIZE, SIZE_RESTORED,
MAKELPARAM (game_window.actual.client.right -
game_window.actual.client.left, game_window.actual.client.bottom -
game_window.actual.client.top )
);
+ if (config.compatibility.allow_fake_displaychange)
PostMessage ( game_window.hWnd, WM_DISPLAYCHANGE, 32,
MAKELPARAM (game_window.actual.client.right -
game_window.actual.client.left, game_window.actual.client.bottom -
diff --git a/src/widgets/threads.cpp b/src/widgets/threads.cpp
index 2d030db1a..402fb3516 100644
--- a/src/widgets/threads.cpp
+++ b/src/widgets/threads.cpp
@@ -709,6 +709,36 @@ SKX_DEBUG_FastSymName (LPCVOID ret_addr)
symbol_name.data ();
}
+void
+SK_Thread_ReprioritizeUnreal (HANDLE hThread, const std::wstring& name)
+{
+ if (SK_GetFramesDrawn () > 5000)
+ return;
+
+ static int game_thread_iters = 0;
+ static int fg_thread_iters = 0;
+ static int io_service_iters = 0;
+
+ // Re-prioritize Unreal Engine threads
+ if (game_thread_iters < 2 && !_wcsicmp (name.c_str (), L"GameThread"))
+ {
+ if (GetThreadPriority (hThread) < THREAD_PRIORITY_HIGHEST)
+ if (SetThreadPriority (hThread, THREAD_PRIORITY_HIGHEST)) ++game_thread_iters;
+ }
+
+ if (fg_thread_iters < 4 && StrStrIW (name.c_str (), L"Foreground Worker #"))
+ {
+ if (GetThreadPriority (hThread) < THREAD_PRIORITY_ABOVE_NORMAL)
+ if (SetThreadPriority (hThread, THREAD_PRIORITY_ABOVE_NORMAL)) ++fg_thread_iters;
+ }
+
+ if (io_service_iters < 10 && !_wcsicmp (name.c_str (), L"IoService"))
+ {
+ if (GetThreadPriority (hThread) < THREAD_PRIORITY_HIGHEST)
+ if (SetThreadPriority (hThread, THREAD_PRIORITY_HIGHEST)) ++io_service_iters;
+ }
+}
+
void
SK_ImGui_ThreadCallstack ( HANDLE hThread, LARGE_INTEGER userTime,
LARGE_INTEGER kernelTime )
@@ -1142,6 +1172,9 @@ class SKWG_Thread_Profiler : public SK_Widget
if (config.compatibility.using_wine)
return;
+ if (ReadAcquire (&__SK_DLL_Ending))
+ return;
+
std::scoped_lock
lock (run_lock);
@@ -1204,22 +1237,23 @@ class SKWG_Thread_Profiler : public SK_Widget
blacklist.find (it.second->dwTid) !=
blacklist.cend ( ) )
{
+ // Give it another shot the next time around
+ if (blacklist.find (it.second->dwTid) !=
+ blacklist.cend ( ))
+ { blacklist.erase (it.second->dwTid); }
+
continue;
}
SK_TLS* pTLS =
SK_TLS_BottomEx (it.second->dwTid);
- if (pTLS != nullptr)
+ if (pTLS == nullptr)
{
blacklist.emplace (it.second->dwTid);
continue;
}
- if (blacklist.find (it.second->dwTid) !=
- blacklist.cend ( ))
- { blacklist.erase (it.second->dwTid); }
-
rebalance_list.push_back (it.second);
}
@@ -1258,7 +1292,7 @@ class SKWG_Thread_Profiler : public SK_Widget
HANDLE hThreadOrig =
it->hThread;
- if (it->hThread == INVALID_HANDLE_VALUE)
+ if ((intptr_t)it->hThread <= 0 || GetThreadPriority (it->hThread) == THREAD_PRIORITY_ERROR_RETURN)
{
it->hThread =
OpenThread (THREAD_ALL_ACCESS, FALSE, it->dwTid);
@@ -1273,6 +1307,8 @@ class SKWG_Thread_Profiler : public SK_Widget
if ( pnum != sk::narrow_cast (-1) && dwExitCode == STILL_ACTIVE )
{
+ SK_Thread_ReprioritizeUnreal (it->hThread, it->name);
+
static SYSTEM_INFO
sysinfo = { };
if (sysinfo.dwNumberOfProcessors == 0)
@@ -1309,10 +1345,10 @@ class SKWG_Thread_Profiler : public SK_Widget
else
++rebalance_idx;
- if (it->hThread != hThreadOrig)
+ if (it->hThread != hThreadOrig && (intptr_t)hThreadOrig > 0)
{
SK_CloseHandle (it->hThread);
- it->hThread = INVALID_HANDLE_VALUE;
+ it->hThread = hThreadOrig;
}
}
@@ -2404,10 +2440,11 @@ class SKWG_Thread_Profiler : public SK_Widget
if (! it.second->self_titled)
{
- auto& thread_name = SK_Thread_GetName (it.second->dwTid);
- auto self_titled = SK_Thread_HasCustomName (it.second->dwTid);
+ auto thread_name = SK_Thread_GetName (it.second->dwTid);
+ auto self_titled = SK_Thread_HasCustomName (it.second->dwTid);
- if (! thread_name.empty ())
+ // Not empty?
+ if (thread_name [0] != L'\0')
{
it.second->name = thread_name;
it.second->self_titled = self_titled;
@@ -2442,9 +2479,9 @@ class SKWG_Thread_Profiler : public SK_Widget
if (STATUS_SUCCESS == ntStatus)
{
- char thread_name [MAX_THREAD_NAME_LEN] = { };
- char szSymbol [256] = { };
- ULONG ulLen = 191;
+ char thread_name [SK_MAX_THREAD_NAME_LEN] = { };
+ char szSymbol [256] = { };
+ ULONG ulLen = 191;
SK::Diagnostics::CrashHandler::InitSyms ();
@@ -2456,13 +2493,13 @@ class SKWG_Thread_Profiler : public SK_Widget
if (ulLen > 0)
{
- snprintf ( thread_name, MAX_THREAD_NAME_LEN-1, "%s+%s",
+ snprintf ( thread_name, SK_MAX_THREAD_NAME_LEN-1, "%s+%s",
SK_WideCharToUTF8 (SK_GetCallerName ((LPCVOID)pdwStartAddress)).c_str ( ),
szSymbol );
}
else {
- snprintf ( thread_name, MAX_THREAD_NAME_LEN-1, "%s",
+ snprintf ( thread_name, SK_MAX_THREAD_NAME_LEN-1, "%s",
SK_WideCharToUTF8 (SK_GetCallerName ((LPCVOID)pdwStartAddress)).c_str ( ) );
}
@@ -2470,15 +2507,19 @@ class SKWG_Thread_Profiler : public SK_Widget
SK_TLS_BottomEx (it.second->dwTid);
if (pTLS != nullptr)
- wcsncpy_s ( pTLS->debug.name, MAX_THREAD_NAME_LEN-1,
+ wcsncpy_s ( pTLS->debug.name, SK_MAX_THREAD_NAME_LEN-1,
SK_UTF8ToWideChar (thread_name).c_str (), _TRUNCATE );
- if (_SK_ThreadNames->find (it.second->dwTid) == _SK_ThreadNames->cend ())
+ auto global_name =
+ _SK_ThreadNames [it.second->dwTid].data ();
+
+ if (*global_name == L'\0')
{
- _SK_ThreadNames [it.second->dwTid] =
- SK_UTF8ToWideChar (thread_name);
+ wcsncpy_s ( global_name, SK_MAX_THREAD_NAME_LEN,
+ SK_UTF8ToWideChar (thread_name).c_str (), _TRUNCATE);
- it.second->name = _SK_ThreadNames [it.second->dwTid];
+ it.second->name.resize (SK_MAX_THREAD_NAME_LEN);
+ it.second->name.assign (global_name);
}
}
diff --git a/src/window.cpp b/src/window.cpp
index 8d2f60190..9336774e2 100644
--- a/src/window.cpp
+++ b/src/window.cpp
@@ -53,6 +53,32 @@ static constexpr int SK_MAX_WINDOW_DIM = 16384;
# define SK_WINDOW_LOG_CALL_UNTESTED() { }
#endif
+using SetWindowDisplayAffinity_pfn = BOOL (WINAPI *)(HWND,DWORD);
+static SetWindowDisplayAffinity_pfn
+ SetWindowDisplayAffinity_Original = nullptr;
+
+BOOL
+WINAPI
+SetWindowDisplayAffinity_Detour (
+ _In_ HWND hWnd,
+ _In_ DWORD dwAffinity )
+{
+ SK_LOG_FIRST_CALL
+
+ if (dwAffinity != WDA_NONE)
+ {
+ SK_LOGi0 (
+ L"SetWindowDisplayAffinity (...) called with dwAffinity = %x on HWND %x",
+ dwAffinity, hWnd
+ );
+ }
+
+ dwAffinity = WDA_NONE;
+
+ return
+ SetWindowDisplayAffinity_Original (hWnd, dwAffinity);
+}
+
BOOL
WINAPI
SetWindowPlacement_Detour (
@@ -3518,8 +3544,10 @@ SK_Window_RepositionIfNeeded (void)
SK_RunOnce (rb.updateOutputTopology ());
- HMONITOR hMonitorBeforeRepos =
- MonitorFromWindow (game_window.hWnd, MONITOR_DEFAULTTONEAREST);
+ bool move_monitors = rb.monitor != rb.next_monitor && rb.next_monitor != 0;
+
+ //HMONITOR hMonitorBeforeRepos =
+ // MonitorFromWindow (game_window.hWnd, MONITOR_DEFAULTTONEAREST);
if (! rb.isTrueFullscreen ())
{
@@ -3619,17 +3647,21 @@ SK_Window_RepositionIfNeeded (void)
SK_Display_ResolutionSelectUI (true);
rb.gsync_state.update (true);
+ // We programatically moved the window to a different monitor, so we need to
+ // send the game a few messages to get the SwapChain to be owned by that
+ // monitor...
+ if (move_monitors || !config.display.monitor_path_ccd.empty ())
// This generally helps (Unity engine games mostly) to apply SwapChain overrides
// immediately, but ATLUS games will respond by moving the game back to the primary
// monitor...
- //if (rb.windows.unity || rb.windows.sdl || rb.windows.unreal)
- if (hMonitorBeforeRepos != rb.monitor && (! rb.windows.atlus))
{
+ if (config.compatibility.allow_fake_size)
PostMessage ( game_window.hWnd, WM_SIZE, SIZE_RESTORED,
MAKELPARAM (game_window.actual.client.right -
game_window.actual.client.left, game_window.actual.client.bottom -
game_window.actual.client.top )
);
+ if (config.compatibility.allow_fake_displaychange)
PostMessage ( game_window.hWnd, WM_DISPLAYCHANGE, 32,
MAKELPARAM (game_window.actual.client.right -
game_window.actual.client.left, game_window.actual.client.bottom -
@@ -3664,6 +3696,12 @@ SK_Window_RepositionIfNeeded (void)
void
SK_AdjustClipRect (void)
{
+ if (game_window.size_move)
+ {
+ SK_ClipCursor (nullptr);
+ return;
+ }
+
// Post-Process Results:
//
// If window is moved as a result of this function, we need to:
@@ -5719,6 +5757,14 @@ SK_DetourWindowProc ( _In_ HWND hWnd,
}
} break;
+ case WM_GETMINMAXINFO:
+ return 0;
+
+ case WM_ENTERSIZEMOVE:
+ case WM_EXITSIZEMOVE:
+ ImGui_WndProcHandler (hWnd, uMsg, wParam, lParam);
+ break;
+
case WM_MOUSEMOVE:
//if (hWnd == game_window.hWnd || hWnd == game_window.child)
{
@@ -5751,12 +5797,11 @@ SK_DetourWindowProc ( _In_ HWND hWnd,
case WM_SETCURSOR:
{
- if ((hWnd == game_window.hWnd || hWnd == game_window.child) && HIWORD (lParam) != WM_NULL)
+ if (hWnd == game_window.hWnd && HIWORD (lParam) != WM_NULL)
{
- if ( LOWORD (lParam) == HTCLIENT ||
- LOWORD (lParam) == HTTRANSPARENT )
+ if (LOWORD (lParam) == HTCLIENT)
{
- if (ImGui_WndProcHandler (hWnd, uMsg, wParam, lParam) != 0 && (ImGui::GetIO ().WantCaptureMouse || SK_ImGui_IsAnythingHovered ()))
+ if (ImGui_WndProcHandler (hWnd, uMsg, wParam, lParam) != 0 && (SK_ImGui_IsAnythingHovered () || SK_ImGui_WantMouseButtonCapture ()))
{
const bool bOrig =
std::exchange (__SK_EnableSetCursor, true);
@@ -5981,7 +6026,7 @@ SK_DetourWindowProc ( _In_ HWND hWnd,
ActivateWindow (hWnd, true);
- if (! SK_ImGui_WantMouseCapture ())
+ if (! SK_ImGui_WantMouseButtonCapture ())
return MA_ACTIVATE; // We don't want it, and the game doesn't expect it
else
return MA_ACTIVATEANDEAT; // We want it, game doesn't need it
@@ -6021,7 +6066,7 @@ SK_DetourWindowProc ( _In_ HWND hWnd,
L"Window Mgr" );
ActivateWindow (hWnd, true);
-
+
if (SK_WantBackgroundRender ())
SK_DetourWindowProc ( hWnd, WM_SETFOCUS, (WPARAM)nullptr, (LPARAM)nullptr );
}
@@ -6039,10 +6084,6 @@ SK_DetourWindowProc ( _In_ HWND hWnd,
game_window.DefWindowProc ( hWnd, uMsg,
wParam, lParam );
- ////SK_COMPAT_SafeCallProc (&game_window,
- //// hWnd, uMsg, TRUE, lParam
- ////);
-
SK_DetourWindowProc ( hWnd, WM_KILLFOCUS, (WPARAM)nullptr, (LPARAM)nullptr );
HWND hWndForeground =
@@ -6076,10 +6117,6 @@ SK_DetourWindowProc ( _In_ HWND hWnd,
game_window.DefWindowProc ( hWnd, uMsg,
wParam, lParam );
- //SK_COMPAT_SafeCallProc (&game_window,
- // hWnd, uMsg, TRUE, 0
- //);
-
SK_DetourWindowProc ( hWnd, WM_KILLFOCUS, (WPARAM)nullptr, (LPARAM)nullptr );
return 0;
@@ -6088,7 +6125,7 @@ SK_DetourWindowProc ( _In_ HWND hWnd,
else if (SK_WantBackgroundRender ())
{
- ActivateWindow (hWnd, true);
+ ActivateWindow ( hWnd, true );
SK_DetourWindowProc ( hWnd, WM_SETFOCUS, (WPARAM)nullptr, (LPARAM)nullptr );
}
}
@@ -6119,11 +6156,12 @@ SK_DetourWindowProc ( _In_ HWND hWnd,
} break;
}
- if (last_active)
+ if (game_window.active)
{
if (! activate)
{
- ActivateWindow (hWnd, activate);
+ if (! (! rb.isTrueFullscreen ()) && SK_WantBackgroundRender () )
+ ActivateWindow (hWnd, activate);
SK_LOG2 ( ( L"Application Deactivated %s", source ),
L"Window Mgr" );
@@ -6146,12 +6184,9 @@ SK_DetourWindowProc ( _In_ HWND hWnd,
if (! activate)
{
game_window.DefWindowProc ( hWnd, uMsg,
- wParam, lParam );
+ wParam, lParam );
- SK_DetourWindowProc ( hWnd, WM_KILLFOCUS, (WPARAM)nullptr, (LPARAM)nullptr );
- ActivateWindow ( hWnd, false );
-
- return 1;
+ return 0;
}
else
@@ -7283,6 +7318,10 @@ SK_MakeWindowHook (WNDPROC class_proc, WNDPROC wnd_proc, HWND hWnd)
}
+ if ( SetWindowDisplayAffinity_Original != nullptr)
+ SetWindowDisplayAffinity_Original (game_window.hWnd, WDA_NONE);
+ else SetWindowDisplayAffinity (game_window.hWnd, WDA_NONE);
+
dll_log->Log ( L"[Window Mgr] Hooking the Window Procedure for "
L"%s Window Class ('%s' - \"%s\" * %x)",
game_window.unicode ? L"Unicode" : L"ANSI",
@@ -7454,7 +7493,9 @@ SK_MakeWindowHook (WNDPROC class_proc, WNDPROC wnd_proc, HWND hWnd)
SK_GetCurrentGameID () == SK_GAME_ID::Persona5 ||
SK_GetCurrentGameID () == SK_GAME_ID::Persona5Strikers)
{
- SK_GetCurrentRenderBackend ().windows.atlus = true;
+ SK_GetCurrentRenderBackend ().windows.atlus = true;
+ config.compatibility.allow_fake_displaychange = false;
+ config.compatibility.allow_fake_size = false;
}
@@ -7931,6 +7972,11 @@ SK_HookWinAPI (void)
GetGUIThreadInfo_Detour,
static_cast_p2p (&GetGUIThreadInfo_Original) );
+ SK_CreateDLLHook2 ( L"user32",
+ "SetWindowDisplayAffinity",
+ SetWindowDisplayAffinity_Detour,
+ static_cast_p2p (&SetWindowDisplayAffinity_Original) );
+
GetWindowBand =
(GetWindowBand_pfn)SK_GetProcAddress (L"user32.dll",
"GetWindowBand");
@@ -8198,7 +8244,7 @@ WINAPI
SK_ClipCursor (const RECT *lpRect)
{
// Do not allow cursor clipping when the game's window is inactive
- if (! game_window.active)
+ if ((! game_window.active) || (game_window.size_move)) // Or being moved
lpRect = nullptr;
return