├── .gitignore ├── .gitmodules ├── source ├── resources │ └── VersionInfo.rc ├── DXHRDC-GFX.def ├── HookInit.cpp ├── VersionInfo.lua ├── effects │ ├── Lighting.h │ ├── Bloom.h │ ├── Metadata.h │ ├── ColorGrading.h │ ├── Lighting.cpp │ ├── Metadata.cpp │ ├── Bloom.cpp │ └── ColorGrading.cpp ├── WrappedExtension.h ├── imgui │ ├── imgui_impl_dx11.h │ ├── imgui_impl_win32.h │ ├── imconfig.h │ └── imstb_rectpack.h ├── DXHRDC-GFX.cpp ├── wil │ ├── wrl.h │ ├── stl.h │ ├── result_originate.h │ ├── rpc_helpers.h │ ├── cppwinrt.h │ ├── registry.h │ ├── wistd_functional.h │ ├── safecast.h │ └── wistd_config.h ├── WrappedDXGI.h └── WrappedDXGI.cpp ├── README.md ├── LICENSE └── premake5.lua /.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "source/Utils"] 2 | path = source/Utils 3 | url = https://github.com/CookiePLMonster/ModUtils.git 4 | -------------------------------------------------------------------------------- /source/resources/VersionInfo.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CookiePLMonster/DXHRDC-GFX/HEAD/source/resources/VersionInfo.rc -------------------------------------------------------------------------------- /source/DXHRDC-GFX.def: -------------------------------------------------------------------------------- 1 | LIBRARY D3D11 2 | EXPORTS 3 | D3D11CreateDevice=D3D11CreateDevice_Export 4 | CreateDXGIFactory=CreateDXGIFactory_Export -------------------------------------------------------------------------------- /source/HookInit.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define HOOKED_FUNCTION GetCommandLineA 4 | #define HOOKED_LIBRARY "KERNEL32.DLL" 5 | 6 | #include "Utils/HookInit.hpp" 7 | -------------------------------------------------------------------------------- /source/VersionInfo.lua: -------------------------------------------------------------------------------- 1 | defines { 2 | "rsc_FullName=\"DXHR DC - Gold Filter Restoration\"", 3 | "rsc_MinorVersion=0", 4 | "rsc_RevisionID=4", 5 | "rsc_BuildID=0", 6 | "rsc_Copyright=\"2020-2021\"", 7 | "rsc_UpdateURL=\"https://github.com/CookiePLMonster/DXHRDC-GFX/releases\"" 8 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deus Ex: Human Revolution Director's Cut - Gold Filter Restoration 2 | 3 | A plugin for Deus Ex: Human Revolution Director's Cut, restoring the gold filter, post processing and shading from the original Deus Ex: Human Revolution. 4 | 5 | With this plugin, you can freely choose what elements of the game's visuals should be changed. The following options are available: 6 | 7 | * Color grading - enabled, disabled 8 | * Bloom - DC style, HR style 9 | * Lighting - DC style, DC style with fixes, HR style 10 | 11 | The configuration menu also allows to freely modify color grading attributes or select from 3 presets based on the data taken directly from DXHR. 12 | 13 | [![Gold Filter Comparison](http://img.youtube.com/vi/b42mzApkaCw/0.jpg)](http://www.youtube.com/watch?v=b42mzApkaCw "Gold Filter Comparison") -------------------------------------------------------------------------------- /source/effects/Lighting.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "Metadata.h" 7 | 8 | using namespace Microsoft::WRL; 9 | 10 | namespace Effects 11 | { 12 | 13 | // Heuristics of bloom changes: 14 | // For LightShader1 and LightShader2, just create alternate resources and swap out pixel shaders accordingly 15 | // For LightShader3, swap out pixel shader and swap SRV0 with SRV1 16 | class Lighting 17 | { 18 | public: 19 | Lighting( ID3D11Device* device ) 20 | : m_device( device ) 21 | { 22 | } 23 | 24 | void CreateAlternatePixelShader( ID3D11PixelShader* shader ); 25 | 26 | bool OnDrawIndexed( ID3D11DeviceContext* context, UINT IndexCount, UINT StartIndexLocation, INT BaseVertexLocation ); 27 | ComPtr BeforePixelShaderSet( ID3D11DeviceContext* context, ID3D11PixelShader* shader ); 28 | 29 | private: 30 | ID3D11Device* m_device; // Effect cannot outlive the device 31 | bool m_swapSRVs = false; // For LightingShader3 32 | }; 33 | 34 | } -------------------------------------------------------------------------------- /source/WrappedExtension.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | 8 | // Tiny extension interface for D3D11/DXGI wrappers so they can be "aware" 9 | // of each other's extensions and query for the real underlying interface 10 | 11 | __interface __declspec(uuid("5F7408E6-77F3-4668-B1F0-9969E803BD9A")) IWrapperObject : public IUnknown 12 | { 13 | virtual HRESULT STDMETHODCALLTYPE GetUnderlyingInterface(REFIID riid, void** ppvObject); 14 | }; 15 | 16 | 17 | // Convenience wrapper for wil::unique_hmodule, so we let it leak if the interface it wraps is still referenced somewhere 18 | class SafeUniqueHmodule final 19 | { 20 | public: 21 | SafeUniqueHmodule( wil::unique_hmodule module, Microsoft::WRL::ComPtr instance ) 22 | : m_module( std::move(module) ), m_instance( std::move(instance) ) 23 | { 24 | } 25 | 26 | ~SafeUniqueHmodule() 27 | { 28 | ULONG ref = m_instance.Reset(); 29 | if ( ref != 0 ) 30 | { 31 | // Let the module leak 32 | m_module.release(); 33 | } 34 | } 35 | 36 | private: 37 | wil::unique_hmodule m_module; 38 | Microsoft::WRL::ComPtr m_instance; 39 | }; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020-2021 Adrian Zdanowicz (Silent) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /source/imgui/imgui_impl_dx11.h: -------------------------------------------------------------------------------- 1 | // dear imgui: Renderer for DirectX11 2 | // This needs to be used along with a Platform Binding (e.g. Win32) 3 | 4 | // Implemented features: 5 | // [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID! 6 | // [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices. 7 | 8 | // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. 9 | // If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. 10 | // https://github.com/ocornut/imgui 11 | 12 | #pragma once 13 | #include "imgui.h" // IMGUI_IMPL_API 14 | 15 | struct ID3D11Device; 16 | struct ID3D11DeviceContext; 17 | 18 | IMGUI_IMPL_API bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context); 19 | IMGUI_IMPL_API void ImGui_ImplDX11_Shutdown(); 20 | IMGUI_IMPL_API void ImGui_ImplDX11_NewFrame(); 21 | IMGUI_IMPL_API void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data); 22 | 23 | // Use if you want to reset your rendering device without losing Dear ImGui state. 24 | IMGUI_IMPL_API void ImGui_ImplDX11_InvalidateDeviceObjects(); 25 | IMGUI_IMPL_API bool ImGui_ImplDX11_CreateDeviceObjects(); 26 | -------------------------------------------------------------------------------- /source/effects/Bloom.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "Metadata.h" 7 | 8 | using namespace Microsoft::WRL; 9 | 10 | namespace Effects 11 | { 12 | 13 | // Heuristics of bloom changes: 14 | // Changes to bloom consist of 2 separate parts: 15 | // - DXHR bloom consists of 4 distinct shaders, DXHR DC - of 3 16 | // - Constant buffers are different for draw 1 and 4 17 | // - Merger shader is different and has different inputs 18 | class Bloom 19 | { 20 | public: 21 | Bloom( ID3D11Device* device ) 22 | : m_device( device ) 23 | { 24 | } 25 | 26 | void CreateAlternatePixelShader( ID3D11PixelShader* shader ); 27 | 28 | // Machine state functions 29 | ComPtr BeforePixelShaderSet( ID3D11DeviceContext* context, ID3D11PixelShader* shader ); 30 | bool OnDraw( ID3D11DeviceContext* context, UINT VertexCount, UINT StartVertexLocation ); 31 | 32 | private: 33 | enum class State 34 | { 35 | Initial, 36 | Bloom2Set, 37 | Bloom2Drawn, 38 | 39 | MergerPSFound, 40 | }; 41 | 42 | State m_state = State::Initial; 43 | ID3D11Device* m_device; // Effect cannot outlive the device 44 | 45 | ComPtr m_bloom3PS; // Used instead of shader2 in the second draw 46 | ComPtr m_shader1CB; // (1.5, 0.0, 0.0, 0.0) 47 | ComPtr m_shader4CB; // (1.5, 1.5, 1.0, 0.0) 48 | }; 49 | 50 | }; -------------------------------------------------------------------------------- /source/DXHRDC-GFX.cpp: -------------------------------------------------------------------------------- 1 | #include "Utils/MemoryMgr.h" 2 | #include "Utils/Patterns.h" 3 | 4 | #include 5 | 6 | #pragma comment(lib, "Shlwapi.lib") 7 | 8 | wchar_t wcModulePath[MAX_PATH]; 9 | static HMODULE hDLLModule; 10 | 11 | HMODULE WINAPI LoadLibraryA_SelfReference( LPCSTR /*lpLibFileName*/ ) 12 | { 13 | HMODULE lib; 14 | GetModuleHandleEx( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast(&LoadLibraryA_SelfReference), &lib ); 15 | return lib; 16 | } 17 | static auto* const pLoadLibraryA_SelfReference = LoadLibraryA_SelfReference; 18 | 19 | static HMODULE (WINAPI** orgLoadLibraryA)(LPCSTR); 20 | HMODULE WINAPI LoadLibraryA_DXHR( LPCSTR lpLibFileName ) 21 | { 22 | return std::invoke( *orgLoadLibraryA, lpLibFileName ); 23 | } 24 | 25 | void OnInitializeHook() 26 | { 27 | GetModuleFileNameW(hDLLModule, wcModulePath, _countof(wcModulePath) - 3); // Minus max required space for extension 28 | PathRenameExtensionW(wcModulePath, L".ini"); 29 | 30 | using namespace Memory::VP; 31 | using namespace hook; 32 | 33 | // Make the game use this module instead of dxgi.dll/d3d11.dll when asked for it 34 | { 35 | auto loadLibrary = get_pattern( "8B 3D ? ? ? ? 68 ? ? ? ? FF D7", 2 ); 36 | orgLoadLibraryA = *loadLibrary; 37 | Patch( loadLibrary, &pLoadLibraryA_SelfReference ); 38 | } 39 | } 40 | 41 | BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) 42 | { 43 | UNREFERENCED_PARAMETER(lpvReserved); 44 | 45 | if ( fdwReason == DLL_PROCESS_ATTACH ) 46 | { 47 | hDLLModule = hinstDLL; 48 | } 49 | return TRUE; 50 | } 51 | -------------------------------------------------------------------------------- /premake5.lua: -------------------------------------------------------------------------------- 1 | workspace "DXHRDC-GFX" 2 | platforms { "Win32" } 3 | 4 | project "DXHRDC-GFX" 5 | kind "SharedLib" 6 | targetextension ".asi" 7 | language "C++" 8 | 9 | include "source/VersionInfo.lua" 10 | files { "**/MemoryMgr.h", "**/Patterns.*", "**/HookInit.hpp" } 11 | 12 | 13 | workspace "*" 14 | configurations { "Debug", "Release", "Master" } 15 | location "build" 16 | 17 | vpaths { ["Headers/*"] = "source/**.h", 18 | ["Sources/*"] = { "source/**.c", "source/**.cpp" }, 19 | ["Resources"] = "source/**.rc" 20 | } 21 | 22 | files { "source/*.h", "source/*.cpp", "source/resources/*.rc", "source/wil/*", "source/*.def", 23 | "source/effects/*", "source/imgui/*" } 24 | 25 | -- Disable exceptions in WIL 26 | defines { "WIL_SUPPRESS_EXCEPTIONS" } 27 | 28 | -- Disable linking XInput in Dear ImGui and IME functions 29 | defines { "IMGUI_IMPL_WIN32_DISABLE_GAMEPAD", "IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS" } 30 | 31 | cppdialect "C++17" 32 | staticruntime "on" 33 | buildoptions { "/sdl" } 34 | warnings "Extra" 35 | 36 | -- Automated defines for resources 37 | defines { "rsc_Extension=\"%{prj.targetextension}\"", 38 | "rsc_Name=\"%{prj.name}\"" } 39 | 40 | filter "configurations:Debug" 41 | defines { "DEBUG" } 42 | runtime "Debug" 43 | 44 | filter "configurations:Master" 45 | defines { "NDEBUG" } 46 | symbols "Off" 47 | 48 | filter "configurations:not Debug" 49 | optimize "Speed" 50 | functionlevellinking "on" 51 | flags { "LinkTimeOptimization" } 52 | 53 | filter { "platforms:Win32" } 54 | system "Windows" 55 | architecture "x86" 56 | 57 | filter { "platforms:Win64" } 58 | system "Windows" 59 | architecture "x86_64" 60 | 61 | filter { "toolset:*_xp"} 62 | defines { "WINVER=0x0501", "_WIN32_WINNT=0x0501" } -- Target WinXP 63 | buildoptions { "/Zc:threadSafeInit-" } 64 | 65 | filter { "toolset:not *_xp"} 66 | defines { "WINVER=0x0601", "_WIN32_WINNT=0x0601" } -- Target Win7 67 | buildoptions { "/permissive-" } -------------------------------------------------------------------------------- /source/effects/Metadata.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace Effects 7 | { 8 | 9 | // Private data we attach to "interesting" resources 10 | struct __declspec(uuid("5383C3EB-9DE8-48FC-8C88-8721759EA8E6")) ResourceMetadata 11 | { 12 | // Found by hashing 13 | enum class Type 14 | { 15 | None, 16 | 17 | BloomMergerShader, 18 | BloomShader1, // Different in DXHR 19 | BloomShader2, // Same in DXHR, but holds an additional "BloomShader3" as an additional resource 20 | BloomShader4, // Different in DXHR 21 | 22 | LightingShader1, 23 | LightingShader2, 24 | LightingShader3, 25 | LightingShader4, 26 | 27 | EdgeAA, // More than one shader, but we don't need to differentiate them 28 | }; 29 | 30 | Type m_type; 31 | }; 32 | static_assert(std::is_trivial_v); // Private data is memcpy'd around and destructed by freeing memory only 33 | 34 | // Shader annotator 35 | void AnnotatePixelShader( ID3D11PixelShader* shader, ResourceMetadata::Type type, bool replacement ); 36 | void AnnotatePixelShader( ID3D11PixelShader* shader, const void* bytecode, SIZE_T length ); 37 | ResourceMetadata GetPixelShaderAnnotation( ID3D11PixelShader* shader ); 38 | 39 | // {2BBE62D5-AB9D-47B1-AED2-F40C375BDD0F} 40 | static const GUID GUID_AlternateResource = 41 | { 0x2bbe62d5, 0xab9d, 0x47b1, { 0xae, 0xd2, 0xf4, 0xc, 0x37, 0x5b, 0xdd, 0xf } }; 42 | 43 | 44 | // Global options, controlled by UI and mostly saved to INI 45 | struct Settings 46 | { 47 | // Those don't save 48 | bool isShown = false; 49 | bool colorGradingDirty = true; 50 | 51 | // Those save 52 | bool colorGradingEnabled; 53 | int bloomType; // 0 - stock, 1 - DXHR 54 | int lightingType; // 0 - stock, 1 - stock fixed, 2 - DXHR 55 | 56 | float colorGradingAttributes[5][4] {}; 57 | }; 58 | 59 | extern Settings SETTINGS; 60 | 61 | // Color grading presets 62 | extern const float COLOR_GRADING_PRESETS[3][4][4]; 63 | extern const float VIGNETTE_PRESET[4]; 64 | 65 | int GetSelectedPreset( float attribs[4][4] ); 66 | 67 | void SaveSettings(); 68 | void LoadSettings(); 69 | 70 | }; -------------------------------------------------------------------------------- /source/imgui/imgui_impl_win32.h: -------------------------------------------------------------------------------- 1 | // dear imgui: Platform Binding for Windows (standard windows API for 32 and 64 bits applications) 2 | // This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) 3 | 4 | // Implemented features: 5 | // [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui) 6 | // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. 7 | // [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE). 8 | // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. 9 | 10 | #pragma once 11 | #include "imgui.h" // IMGUI_IMPL_API 12 | 13 | IMGUI_IMPL_API bool ImGui_ImplWin32_Init(void* hwnd); 14 | IMGUI_IMPL_API void ImGui_ImplWin32_Shutdown(); 15 | IMGUI_IMPL_API void ImGui_ImplWin32_NewFrame(); 16 | 17 | // Configuration 18 | // - Disable gamepad support or linking with xinput.lib 19 | //#define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD 20 | //#define IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT 21 | 22 | // Win32 message handler your application need to call. 23 | // - Intentionally commented out in a '#if 0' block to avoid dragging dependencies on from this helper. 24 | // - You should COPY the line below into your .cpp code to forward declare the function and then you can call it. 25 | #if 0 26 | extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); 27 | #endif 28 | 29 | // DPI-related helpers (optional) 30 | // - Use to enable DPI awareness without having to create an application manifest. 31 | // - Your own app may already do this via a manifest or explicit calls. This is mostly useful for our examples/ apps. 32 | // - In theory we could call simple functions from Windows SDK such as SetProcessDPIAware(), SetProcessDpiAwareness(), etc. 33 | // but most of the functions provided by Microsoft require Windows 8.1/10+ SDK at compile time and Windows 8/10+ at runtime, 34 | // neither we want to require the user to have. So we dynamically select and load those functions to avoid dependencies. 35 | IMGUI_IMPL_API void ImGui_ImplWin32_EnableDpiAwareness(); 36 | IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd); // HWND hwnd 37 | IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor); // HMONITOR monitor 38 | -------------------------------------------------------------------------------- /source/effects/ColorGrading.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include "Metadata.h" 11 | 12 | using namespace Microsoft::WRL; 13 | 14 | namespace Effects 15 | { 16 | 17 | 18 | // Heuristics of color grading: 19 | // 1. Find the bloom merger call 20 | // 2. From this draw call, save the following - vertex shader, input layout, rasterizer state, blend state (DS state seems to be same) 21 | // 3. Skip until the first blend state change - entire postprocessing uses the same blend state, subtitles/UI do not 22 | // 4. Output RT of the draw call to follow is the output we need to apply color grading on 23 | // TODO: CopyResource can be skipped if AA is performed - need to cache input of the bloom merger call and re-route the next non-indexed Draw call, 24 | // then apply color grading 25 | class ColorGrading 26 | { 27 | public: 28 | ColorGrading(ID3D11Device* device); 29 | 30 | // Machine state functions 31 | void OnPixelShaderSet( ID3D11PixelShader* shader ); 32 | void BeforeDraw( ID3D11DeviceContext* context, UINT VertexCount, UINT StartVertexLocation ); 33 | void BeforeOMSetBlendState( ID3D11DeviceContext* context, ID3D11BlendState* pBlendState ); 34 | void BeforeOMSetRenderTargets( ID3D11DeviceContext* context, UINT NumViews, ID3D11RenderTargetView* const* ppRenderTargetViews, ID3D11DepthStencilView* pDepthStencilView ); 35 | void BeforeClearRenderTargetView( ID3D11DeviceContext* context, ID3D11RenderTargetView* pRenderTargetView, const FLOAT ColorRGBA[4] ); 36 | void ClearState(); 37 | 38 | private: 39 | void DrawColorFilter( ID3D11DeviceContext* context, const ComPtr& target ); 40 | 41 | enum class State 42 | { 43 | Initial, 44 | MergerCallFound, 45 | ResourcesGathered, 46 | }; 47 | 48 | State m_state = State::Initial; 49 | ID3D11Device* m_device; // Effect cannot outlive the device 50 | 51 | ComPtr m_pixelShader; 52 | ComPtr m_constantBuffer; 53 | 54 | // Persistent data - created on demand and invalidated only on resolution/settings change 55 | struct PersistentData 56 | { 57 | 58 | // Flushed if RTV doesn't match the current output 59 | ComPtr m_lastOutputRT; 60 | ComPtr m_lastOutputSRV; 61 | 62 | // Flushed if RT dimensions don't match the current output 63 | std::tuple< ComPtr, UINT, UINT > m_tempRT; // RT, Width, Height 64 | ComPtr m_tempRTV; 65 | }; 66 | 67 | // Volatile data - references obtained and released every frame, used for draw detection 68 | struct VolatileData 69 | { 70 | bool m_edgeAADetected = false; 71 | ComPtr m_vertexShader; 72 | ComPtr m_inputLayout; 73 | ComPtr m_rasterizerState; 74 | ComPtr m_blendState; 75 | std::tuple< ComPtr, UINT, UINT, UINT > m_vertexBuffer; // Buffer, Stride, Offset, StartLocation 76 | ComPtr m_lastUnboundRTV; // We might need to re-bind an unbound RTV 77 | }; 78 | 79 | std::optional m_persistentData; 80 | std::optional m_volatileData; 81 | }; 82 | 83 | }; -------------------------------------------------------------------------------- /source/wil/wrl.h: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License. 5 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 6 | // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 7 | // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 8 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. 9 | // 10 | //********************************************************* 11 | #ifndef __WIL_WRL_INCLUDED 12 | #define __WIL_WRL_INCLUDED 13 | 14 | #include 15 | #include "result.h" 16 | #include "common.h" // wistd type_traits helpers 17 | 18 | namespace wil 19 | { 20 | 21 | #ifdef WIL_ENABLE_EXCEPTIONS 22 | #pragma region Object construction helpers that throw exceptions 23 | 24 | /** Used to construct a RuntimeClass based object that uses 2 phase construction. 25 | Construct a RuntimeClass based object that uses 2 phase construction (by implementing 26 | RuntimeClassInitialize() and returning error codes for failures. 27 | ~~~~ 28 | // SomeClass uses 2 phase initialization by implementing RuntimeClassInitialize() 29 | auto someClass = MakeAndInitializeOrThrow(L"input", true); 30 | ~~~~ */ 31 | 32 | template 33 | Microsoft::WRL::ComPtr MakeAndInitializeOrThrow(TArgs&&... args) 34 | { 35 | Microsoft::WRL::ComPtr obj; 36 | THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&obj, Microsoft::WRL::Details::Forward(args)...)); 37 | return obj; 38 | } 39 | 40 | /** Used to construct an RuntimeClass based object that uses exceptions in its constructor (and does 41 | not require 2 phase construction). 42 | ~~~~ 43 | // SomeClass uses exceptions for error handling in its constructor. 44 | auto someClass = MakeOrThrow(L"input", true); 45 | ~~~~ */ 46 | 47 | template 48 | Microsoft::WRL::ComPtr MakeOrThrow(TArgs&&... args) 49 | { 50 | // This is how you can detect the presence of RuntimeClassInitialize() and find dangerous use. 51 | // Unfortunately this produces false positives as all RuntimeClass derived classes have 52 | // a RuntimeClassInitialize() method from their base class. 53 | // static_assert(!std::is_member_function_pointer::value, 54 | // "class has a RuntimeClassInitialize member, use MakeAndInitializeOrThrow instead"); 55 | auto obj = Microsoft::WRL::Make(Microsoft::WRL::Details::Forward(args)...); 56 | THROW_IF_NULL_ALLOC(obj.Get()); 57 | return obj; 58 | } 59 | #pragma endregion 60 | 61 | #endif // WIL_ENABLE_EXCEPTIONS 62 | 63 | /** By default WRL Callback objects are not agile, use this to make an agile one. Replace use of Callback<> with MakeAgileCallback<>. 64 | Will return null on failure, translate that into E_OUTOFMEMORY using XXX_IF_NULL_ALLOC() 65 | from wil\result.h to test the result. */ 66 | template 67 | ::Microsoft::WRL::ComPtr MakeAgileCallbackNoThrow(Args&&... args) WI_NOEXCEPT 68 | { 69 | using namespace Microsoft::WRL; 70 | return Callback, TDelegateInterface, FtmBase>>(wistd::forward(args)...); 71 | } 72 | 73 | #ifdef WIL_ENABLE_EXCEPTIONS 74 | template 75 | ::Microsoft::WRL::ComPtr MakeAgileCallback(Args&&... args) 76 | { 77 | auto result = MakeAgileCallbackNoThrow(wistd::forward(args)...); 78 | THROW_IF_NULL_ALLOC(result); 79 | return result; 80 | } 81 | #endif // WIL_ENABLE_EXCEPTIONS 82 | } // namespace wil 83 | 84 | #endif // __WIL_WRL_INCLUDED 85 | -------------------------------------------------------------------------------- /source/wil/stl.h: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License. 5 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 6 | // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 7 | // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 8 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. 9 | // 10 | //********************************************************* 11 | #ifndef __WIL_STL_INCLUDED 12 | #define __WIL_STL_INCLUDED 13 | 14 | #include "common.h" 15 | #include "resource.h" 16 | #include 17 | #include 18 | #include 19 | 20 | #if defined(WIL_ENABLE_EXCEPTIONS) 21 | 22 | namespace wil 23 | { 24 | /** Secure allocator for STL containers. 25 | The `wil::secure_allocator` allocator calls `SecureZeroMemory` before deallocating 26 | memory. This provides a mechanism for secure STL containers such as `wil::secure_vector`, 27 | `wil::secure_string`, and `wil::secure_wstring`. */ 28 | template 29 | struct secure_allocator 30 | : public std::allocator 31 | { 32 | template 33 | struct rebind 34 | { 35 | typedef secure_allocator other; 36 | }; 37 | 38 | secure_allocator() 39 | : std::allocator() 40 | { 41 | } 42 | 43 | ~secure_allocator() = default; 44 | 45 | secure_allocator(const secure_allocator& a) 46 | : std::allocator(a) 47 | { 48 | } 49 | 50 | template 51 | secure_allocator(const secure_allocator& a) 52 | : std::allocator(a) 53 | { 54 | } 55 | 56 | T* allocate(size_t n) 57 | { 58 | return std::allocator::allocate(n); 59 | } 60 | 61 | void deallocate(T* p, size_t n) 62 | { 63 | SecureZeroMemory(p, sizeof(T) * n); 64 | std::allocator::deallocate(p, n); 65 | } 66 | }; 67 | 68 | //! `wil::secure_vector` will be securely zeroed before deallocation. 69 | template 70 | using secure_vector = std::vector>; 71 | //! `wil::secure_wstring` will be securely zeroed before deallocation. 72 | using secure_wstring = std::basic_string, wil::secure_allocator>; 73 | //! `wil::secure_string` will be securely zeroed before deallocation. 74 | using secure_string = std::basic_string, wil::secure_allocator>; 75 | 76 | /// @cond 77 | namespace details 78 | { 79 | template<> struct string_maker 80 | { 81 | HRESULT make(_In_reads_opt_(length) PCWSTR source, size_t length) WI_NOEXCEPT try 82 | { 83 | m_value = source ? std::wstring(source, length) : std::wstring(length, L'\0'); 84 | return S_OK; 85 | } 86 | catch (...) 87 | { 88 | return E_OUTOFMEMORY; 89 | } 90 | 91 | wchar_t* buffer() { return &m_value[0]; } 92 | 93 | std::wstring release() { return std::wstring(std::move(m_value)); } 94 | 95 | static PCWSTR get(const std::wstring& value) { return value.c_str(); } 96 | 97 | private: 98 | std::wstring m_value; 99 | }; 100 | } 101 | /// @endcond 102 | 103 | // str_raw_ptr is an overloaded function that retrieves a const pointer to the first character in a string's buffer. 104 | // This is the overload for std::wstring. Other overloads available in resource.h. 105 | inline PCWSTR str_raw_ptr(const std::wstring& str) 106 | { 107 | return str.c_str(); 108 | } 109 | 110 | } // namespace wil 111 | 112 | #endif // WIL_ENABLE_EXCEPTIONS 113 | 114 | #endif // __WIL_STL_INCLUDED 115 | -------------------------------------------------------------------------------- /source/effects/Lighting.cpp: -------------------------------------------------------------------------------- 1 | #include "Lighting.h" 2 | 3 | #include 4 | 5 | #include "../wil/resource.h" 6 | 7 | #include "Lighting_shader.h" 8 | 9 | void Effects::Lighting::CreateAlternatePixelShader(ID3D11PixelShader* shader) 10 | { 11 | const ResourceMetadata::Type shaderType = GetPixelShaderAnnotation( shader ).m_type; 12 | 13 | if ( shaderType == ResourceMetadata::Type::LightingShader1 ) 14 | { 15 | // Create an alternate shader 16 | ComPtr alternateShader; 17 | if ( SUCCEEDED(m_device->CreatePixelShader( LIGHTING1_PS_BYTECODE, sizeof(LIGHTING1_PS_BYTECODE), nullptr, alternateShader.GetAddressOf() )) ) 18 | { 19 | shader->SetPrivateDataInterface( GUID_AlternateResource, alternateShader.Get() ); 20 | } 21 | return; 22 | } 23 | 24 | if ( shaderType == ResourceMetadata::Type::LightingShader2 ) 25 | { 26 | // Create an alternate shader 27 | ComPtr alternateShader; 28 | if ( SUCCEEDED(m_device->CreatePixelShader( LIGHTING2_PS_BYTECODE, sizeof(LIGHTING2_PS_BYTECODE), nullptr, alternateShader.GetAddressOf() )) ) 29 | { 30 | shader->SetPrivateDataInterface( GUID_AlternateResource, alternateShader.Get() ); 31 | } 32 | return; 33 | } 34 | 35 | if ( shaderType == ResourceMetadata::Type::LightingShader3 ) 36 | { 37 | // Create an alternate shader 38 | ComPtr alternateShader; 39 | if ( SUCCEEDED(m_device->CreatePixelShader( LIGHTING3_PS_BYTECODE, sizeof(LIGHTING3_PS_BYTECODE), nullptr, alternateShader.GetAddressOf() )) ) 40 | { 41 | shader->SetPrivateDataInterface( GUID_AlternateResource, alternateShader.Get() ); 42 | } 43 | return; 44 | } 45 | 46 | if ( shaderType == ResourceMetadata::Type::LightingShader4 ) 47 | { 48 | // Create an alternate shader 49 | ComPtr alternateShader; 50 | if ( SUCCEEDED(m_device->CreatePixelShader( LIGHTING4_PS_BYTECODE, sizeof(LIGHTING4_PS_BYTECODE), nullptr, alternateShader.GetAddressOf() )) ) 51 | { 52 | shader->SetPrivateDataInterface( GUID_AlternateResource, alternateShader.Get() ); 53 | } 54 | return; 55 | } 56 | } 57 | 58 | bool Effects::Lighting::OnDrawIndexed(ID3D11DeviceContext* context, UINT IndexCount, UINT StartIndexLocation, INT BaseVertexLocation) 59 | { 60 | if ( m_swapSRVs ) 61 | { 62 | // Swap SRV0 and SRV1 around, then restore 63 | ID3D11ShaderResourceView* resources[2]; // Warning - raw pointers! 64 | context->PSGetShaderResources( 0, _countof(resources), resources ); 65 | auto restore = wil::scope_exit([&] { 66 | context->PSSetShaderResources( 0, _countof(resources), resources ); 67 | for ( auto* r : resources ) 68 | { 69 | if ( r != nullptr ) 70 | { 71 | r->Release(); 72 | } 73 | } 74 | }); 75 | 76 | ID3D11ShaderResourceView* const swappedResources[2] = { resources[1], resources[0] }; // Warning - raw pointers! 77 | context->PSSetShaderResources( 0, _countof(swappedResources), swappedResources ); 78 | 79 | context->DrawIndexed( IndexCount, StartIndexLocation, BaseVertexLocation ); 80 | return true; 81 | } 82 | return false; 83 | } 84 | 85 | ComPtr Effects::Lighting::BeforePixelShaderSet(ID3D11DeviceContext* context, ID3D11PixelShader* shader) 86 | { 87 | ComPtr result(shader); 88 | m_swapSRVs = false; 89 | 90 | if ( SETTINGS.lightingType == 0 || !shader ) return result; 91 | 92 | ResourceMetadata meta; 93 | UINT size = sizeof(meta); 94 | if ( SUCCEEDED(shader->GetPrivateData(__uuidof(meta), &size, &meta)) ) 95 | { 96 | if ( (meta.m_type == ResourceMetadata::Type::LightingShader1 || meta.m_type == ResourceMetadata::Type::LightingShader4) || 97 | (SETTINGS.lightingType == 2 && (meta.m_type == ResourceMetadata::Type::LightingShader2 || meta.m_type == ResourceMetadata::Type::LightingShader3)) ) 98 | { 99 | ComPtr replacedShader; 100 | size = sizeof(ID3D11PixelShader*); 101 | if ( SUCCEEDED(shader->GetPrivateData(GUID_AlternateResource, &size, replacedShader.GetAddressOf())) ) 102 | { 103 | result = std::move(replacedShader); 104 | m_swapSRVs = meta.m_type == ResourceMetadata::Type::LightingShader3; 105 | } 106 | } 107 | } 108 | 109 | return result; 110 | } 111 | -------------------------------------------------------------------------------- /source/WrappedDXGI.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include "wil/resource.h" 8 | 9 | #include "WrappedExtension.h" 10 | 11 | using namespace Microsoft::WRL; 12 | 13 | 14 | // Wrapped DXGI interfaces which are mostly passthrough, but they are also 15 | // aware of our D3D11 wrappers 16 | 17 | class DXGIFactory final : public RuntimeClass< RuntimeClassFlags, ChainInterfaces, IWrapperObject > 18 | { 19 | public: 20 | DXGIFactory( wil::unique_hmodule module, ComPtr factory ); 21 | 22 | virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) override; // Overload to allow DXGI to query for internal, undocumented interfaces 23 | 24 | // IDXGIFactory 25 | virtual HRESULT STDMETHODCALLTYPE SetPrivateData(REFGUID Name, UINT DataSize, const void* pData) override; 26 | virtual HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(REFGUID Name, const IUnknown* pUnknown) override; 27 | virtual HRESULT STDMETHODCALLTYPE GetPrivateData(REFGUID Name, UINT* pDataSize, void* pData) override; 28 | virtual HRESULT STDMETHODCALLTYPE GetParent(REFIID riid, void** ppParent) override; 29 | virtual HRESULT STDMETHODCALLTYPE EnumAdapters(UINT Adapter, IDXGIAdapter** ppAdapter) override; 30 | virtual HRESULT STDMETHODCALLTYPE MakeWindowAssociation(HWND WindowHandle, UINT Flags) override; 31 | virtual HRESULT STDMETHODCALLTYPE GetWindowAssociation(HWND* pWindowHandle) override; 32 | virtual HRESULT STDMETHODCALLTYPE CreateSwapChain(IUnknown* pDevice, DXGI_SWAP_CHAIN_DESC* pDesc, IDXGISwapChain** ppSwapChain) override; 33 | virtual HRESULT STDMETHODCALLTYPE CreateSoftwareAdapter(HMODULE Module, IDXGIAdapter** ppAdapter) override; 34 | 35 | // IWrapperObject 36 | virtual HRESULT STDMETHODCALLTYPE GetUnderlyingInterface(REFIID riid, void** ppvObject) override; 37 | 38 | private: 39 | SafeUniqueHmodule m_dxgiModule; 40 | ComPtr m_orig; 41 | }; 42 | 43 | class DXGISwapChain final : public RuntimeClass< RuntimeClassFlags, ChainInterfaces, IWrapperObject > 44 | { 45 | public: 46 | DXGISwapChain(ComPtr swapChain, ComPtr factory, ComPtr device, const DXGI_SWAP_CHAIN_DESC* desc); 47 | virtual ~DXGISwapChain() override; 48 | 49 | virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) override; // Overload to allow DXGI to query for internal, undocumented interfaces 50 | 51 | // IDXGISwapChain 52 | virtual HRESULT STDMETHODCALLTYPE SetPrivateData(REFGUID Name, UINT DataSize, const void* pData) override; 53 | virtual HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(REFGUID Name, const IUnknown* pUnknown) override; 54 | virtual HRESULT STDMETHODCALLTYPE GetPrivateData(REFGUID Name, UINT* pDataSize, void* pData) override; 55 | virtual HRESULT STDMETHODCALLTYPE GetParent(REFIID riid, void** ppParent) override; 56 | virtual HRESULT STDMETHODCALLTYPE GetDevice(REFIID riid, void** ppDevice) override; 57 | virtual HRESULT STDMETHODCALLTYPE Present(UINT SyncInterval, UINT Flags) override; 58 | virtual HRESULT STDMETHODCALLTYPE GetBuffer(UINT Buffer, REFIID riid, void** ppSurface) override; 59 | virtual HRESULT STDMETHODCALLTYPE SetFullscreenState(BOOL Fullscreen, IDXGIOutput* pTarget) override; 60 | virtual HRESULT STDMETHODCALLTYPE GetFullscreenState(BOOL* pFullscreen, IDXGIOutput** ppTarget) override; 61 | virtual HRESULT STDMETHODCALLTYPE GetDesc(DXGI_SWAP_CHAIN_DESC* pDesc) override; 62 | virtual HRESULT STDMETHODCALLTYPE ResizeBuffers(UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags) override; 63 | virtual HRESULT STDMETHODCALLTYPE ResizeTarget(const DXGI_MODE_DESC* pNewTargetParameters) override; 64 | virtual HRESULT STDMETHODCALLTYPE GetContainingOutput(IDXGIOutput** ppOutput) override; 65 | virtual HRESULT STDMETHODCALLTYPE GetFrameStatistics(DXGI_FRAME_STATISTICS* pStats) override; 66 | virtual HRESULT STDMETHODCALLTYPE GetLastPresentCount(UINT* pLastPresentCount) override; 67 | 68 | // IWrapperObject 69 | virtual HRESULT STDMETHODCALLTYPE GetUnderlyingInterface(REFIID riid, void** ppvObject) override; 70 | 71 | private: 72 | ComPtr m_factory; 73 | ComPtr m_device; 74 | ComPtr m_orig; 75 | }; -------------------------------------------------------------------------------- /source/effects/Metadata.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Metadata.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | extern wchar_t wcModulePath[MAX_PATH]; 10 | 11 | Effects::Settings Effects::SETTINGS; 12 | 13 | const float Effects::COLOR_GRADING_PRESETS[3][4][4] = { 14 | { 15 | { 0.85f, 0.75f, 1.25f }, 16 | { 0.25098f, 0.31373f, 0.28235f }, 17 | { 0.60392f, 0.52627f, 0.4098f }, 18 | { 0.52941f, 0.52941f, 0.52941f } 19 | }, 20 | 21 | { 22 | { 0.8f, 0.8f, 1.35f }, 23 | { 0.37255f, 0.43922f, 0.54902f }, 24 | { 0.62745f, 0.57647f, 0.31373f }, 25 | { 0.54902f, 0.51765f, 0.41569f } 26 | }, 27 | 28 | { 29 | { 1.0f, 0.72f, 1.4f }, 30 | { 0.31765f, 0.43137f, 0.40392f }, 31 | { 0.58824f, 0.54902f, 0.41961f }, 32 | { 0.54902f, 0.52157f, 0.44314f } 33 | }, 34 | }; 35 | 36 | const float Effects::VIGNETTE_PRESET[4] = { 1.0f, 0.0f, 0.7f, 0.7f }; 37 | 38 | void Effects::AnnotatePixelShader( ID3D11PixelShader* shader, ResourceMetadata::Type type, bool /*replacement*/ ) 39 | { 40 | ResourceMetadata resource; 41 | resource.m_type = type; 42 | shader->SetPrivateData( __uuidof(resource), sizeof(resource), &resource ); 43 | } 44 | 45 | void Effects::AnnotatePixelShader( ID3D11PixelShader* shader, const void* bytecode, SIZE_T length ) 46 | { 47 | static constexpr std::pair< std::array, ResourceMetadata::Type > importantShaders[] = { 48 | { { 0xf3896ba8, 0x4f0671da, 0xa690e62a, 0xc9168288 }, ResourceMetadata::Type::BloomMergerShader }, 49 | { { 0x1e94a642, 0x771834d4, 0xf7c2a424, 0x583be5c8 }, ResourceMetadata::Type::BloomShader1 }, 50 | { { 0xaf000e64, 0x2766c2fc, 0xe3aa8a2c, 0x2f0ee3af }, ResourceMetadata::Type::BloomShader2 }, 51 | { { 0x32976b21, 0x3bec6292, 0x89f5d21c, 0xed6bd65f }, ResourceMetadata::Type::BloomShader4 }, 52 | 53 | { { 0x4abe618c, 0xa282fa5b, 0xdcde9b8b, 0xaf4aa8fb }, ResourceMetadata::Type::LightingShader1 }, 54 | { { 0x65ae0cbf, 0x89721070, 0x6078754d, 0xa3a24d48 }, ResourceMetadata::Type::LightingShader2 }, 55 | { { 0x2ede696f, 0x36c567e9, 0xaacac074, 0xb5f3ad15 }, ResourceMetadata::Type::LightingShader3 }, 56 | { { 0x4ee86a1e, 0xbf1eba8f, 0x48e4cf30, 0x635dc3f9 }, ResourceMetadata::Type::LightingShader4 }, 57 | 58 | { { 0x4e0ff42d, 0x6cc1abc1, 0x3b4ac407, 0xc70f5d7e }, ResourceMetadata::Type::EdgeAA }, 59 | { { 0x0b4857ad, 0x5efeb1e9, 0x76a173d2, 0xfd56ff9f }, ResourceMetadata::Type::EdgeAA }, 60 | }; 61 | 62 | if ( length >= 4 + 16 ) 63 | { 64 | const uint32_t* hash = reinterpret_cast(reinterpret_cast(bytecode) + 4); 65 | for ( const auto& sh : importantShaders ) 66 | { 67 | if ( std::equal( sh.first.begin(), sh.first.end(), hash ) ) 68 | { 69 | AnnotatePixelShader( shader, sh.second, false ); 70 | return; 71 | } 72 | 73 | } 74 | } 75 | } 76 | 77 | auto Effects::GetPixelShaderAnnotation(ID3D11PixelShader* shader) -> ResourceMetadata 78 | { 79 | ResourceMetadata result; 80 | UINT size = sizeof(result); 81 | if ( FAILED(shader->GetPrivateData(__uuidof(result), &size, &result)) ) 82 | { 83 | result.m_type = ResourceMetadata::Type::None; 84 | } 85 | return result; 86 | } 87 | 88 | int Effects::GetSelectedPreset( float attribs[4][4] ) 89 | { 90 | const int numPresets = _countof( COLOR_GRADING_PRESETS ); 91 | for ( int i = 0; i < numPresets; i++ ) 92 | { 93 | if ( memcmp( attribs, COLOR_GRADING_PRESETS[i], sizeof(COLOR_GRADING_PRESETS[i]) ) == 0 ) 94 | { 95 | return i; 96 | } 97 | } 98 | 99 | return -1; 100 | } 101 | 102 | void Effects::SaveSettings() 103 | { 104 | wchar_t buffer[16]; 105 | 106 | // Basic 107 | swprintf_s( buffer, L"%d", SETTINGS.colorGradingEnabled ); 108 | WritePrivateProfileStringW( L"Basic", L"EnableColorGrading", buffer, wcModulePath ); 109 | 110 | swprintf_s( buffer, L"%d", SETTINGS.bloomType ); 111 | WritePrivateProfileStringW( L"Basic", L"BloomStyle", buffer, wcModulePath ); 112 | 113 | swprintf_s( buffer, L"%d", SETTINGS.lightingType ); 114 | WritePrivateProfileStringW( L"Basic", L"LightingStyle", buffer, wcModulePath ); 115 | 116 | // Advanced 117 | WritePrivateProfileStructW( L"Advanced", L"Attribs", &SETTINGS.colorGradingAttributes[0], sizeof(float) * 3, wcModulePath ); 118 | WritePrivateProfileStructW( L"Advanced", L"Color1", &SETTINGS.colorGradingAttributes[1], sizeof(float) * 3, wcModulePath ); 119 | WritePrivateProfileStructW( L"Advanced", L"Color2", &SETTINGS.colorGradingAttributes[2], sizeof(float) * 3, wcModulePath ); 120 | WritePrivateProfileStructW( L"Advanced", L"Color3", &SETTINGS.colorGradingAttributes[3], sizeof(float) * 3, wcModulePath ); 121 | WritePrivateProfileStructW( L"Advanced", L"Vignette", &SETTINGS.colorGradingAttributes[4], sizeof(float) * 4, wcModulePath ); 122 | } 123 | 124 | void Effects::LoadSettings() 125 | { 126 | SETTINGS.colorGradingEnabled = GetPrivateProfileIntW( L"Basic", L"EnableColorGrading", 1, wcModulePath ); 127 | SETTINGS.bloomType = GetPrivateProfileIntW( L"Basic", L"BloomStyle", 1, wcModulePath ); 128 | SETTINGS.lightingType = GetPrivateProfileIntW( L"Basic", L"LightingStyle", 1, wcModulePath ); 129 | 130 | // If color grading fails to load, reset it all, but leave vignette separate 131 | if ( 132 | GetPrivateProfileStructW( L"Advanced", L"Attribs", &SETTINGS.colorGradingAttributes[0], sizeof(float) * 3, wcModulePath ) == FALSE || 133 | GetPrivateProfileStructW( L"Advanced", L"Color1", &SETTINGS.colorGradingAttributes[1], sizeof(float) * 3, wcModulePath ) == FALSE || 134 | GetPrivateProfileStructW( L"Advanced", L"Color2", &SETTINGS.colorGradingAttributes[2], sizeof(float) * 3, wcModulePath ) == FALSE || 135 | GetPrivateProfileStructW( L"Advanced", L"Color3", &SETTINGS.colorGradingAttributes[3], sizeof(float) * 3, wcModulePath ) == FALSE ) 136 | { 137 | memcpy( &SETTINGS.colorGradingAttributes[0], COLOR_GRADING_PRESETS[0], sizeof(COLOR_GRADING_PRESETS[0]) ); 138 | } 139 | 140 | if ( GetPrivateProfileStructW( L"Advanced", L"Vignette", &SETTINGS.colorGradingAttributes[4], sizeof(float) * 4, wcModulePath ) == FALSE ) 141 | { 142 | memcpy( &SETTINGS.colorGradingAttributes[4], Effects::VIGNETTE_PRESET, sizeof(Effects::VIGNETTE_PRESET) ); 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /source/effects/Bloom.cpp: -------------------------------------------------------------------------------- 1 | #include "Bloom.h" 2 | 3 | #include 4 | 5 | #include "../wil/resource.h" 6 | 7 | #include "Bloom_shader.h" 8 | 9 | void Effects::Bloom::CreateAlternatePixelShader( ID3D11PixelShader* shader ) 10 | { 11 | const ResourceMetadata::Type shaderType = GetPixelShaderAnnotation( shader ).m_type; 12 | 13 | if ( shaderType == ResourceMetadata::Type::BloomShader1 ) 14 | { 15 | // Create an alternate shader 16 | ComPtr alternateShader; 17 | if ( SUCCEEDED(m_device->CreatePixelShader( BLOOM1_PS_BYTECODE, sizeof(BLOOM1_PS_BYTECODE), nullptr, alternateShader.GetAddressOf() )) ) 18 | { 19 | shader->SetPrivateDataInterface( GUID_AlternateResource, alternateShader.Get() ); 20 | 21 | // CB used by this shader 22 | const float data[128] = { 1.5f, 0.0f, 0.0f, 0.0f }; // Only 16 bytes are used but shader was defined to use 512 bytes 23 | 24 | D3D11_BUFFER_DESC cbDesc {}; 25 | cbDesc.ByteWidth = sizeof(data); 26 | cbDesc.Usage = D3D11_USAGE_IMMUTABLE; 27 | cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; 28 | 29 | D3D11_SUBRESOURCE_DATA initialData {}; 30 | initialData.pSysMem = data; 31 | m_device->CreateBuffer( &cbDesc, &initialData, m_shader1CB.ReleaseAndGetAddressOf() ); 32 | } 33 | return; 34 | } 35 | 36 | if ( shaderType == ResourceMetadata::Type::BloomShader2 ) 37 | { 38 | // Alternate shader is not used instead of this one during the first draw, but it is during the following draw with the same shader 39 | m_device->CreatePixelShader( BLOOM3_PS_BYTECODE, sizeof(BLOOM3_PS_BYTECODE), nullptr, m_bloom3PS.ReleaseAndGetAddressOf() ); 40 | return; 41 | } 42 | 43 | if ( shaderType == ResourceMetadata::Type::BloomShader4 ) 44 | { 45 | // Create an alternate shader 46 | ComPtr alternateShader; 47 | if ( SUCCEEDED(m_device->CreatePixelShader( BLOOM4_PS_BYTECODE, sizeof(BLOOM4_PS_BYTECODE), nullptr, alternateShader.GetAddressOf() )) ) 48 | { 49 | shader->SetPrivateDataInterface( GUID_AlternateResource, alternateShader.Get() ); 50 | 51 | // CB used by this shader 52 | const float data[128] = { 1.5f, 1.5f, 1.0f, 0.0f }; // Only 16 bytes are used but shader was defined to use 512 bytes 53 | 54 | D3D11_BUFFER_DESC cbDesc {}; 55 | cbDesc.ByteWidth = sizeof(data); 56 | cbDesc.Usage = D3D11_USAGE_IMMUTABLE; 57 | cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; 58 | 59 | D3D11_SUBRESOURCE_DATA initialData {}; 60 | initialData.pSysMem = data; 61 | m_device->CreateBuffer( &cbDesc, &initialData, m_shader4CB.ReleaseAndGetAddressOf() ); 62 | } 63 | return; 64 | } 65 | 66 | if ( shaderType == ResourceMetadata::Type::BloomMergerShader ) 67 | { 68 | // Create an alternate shader and also annotate it as a blur merger shader 69 | ComPtr alternateShader; 70 | if ( SUCCEEDED(m_device->CreatePixelShader( BLOOM_MERGER_PS_BYTECODE, sizeof(BLOOM_MERGER_PS_BYTECODE), nullptr, alternateShader.GetAddressOf() )) ) 71 | { 72 | shader->SetPrivateDataInterface( GUID_AlternateResource, alternateShader.Get() ); 73 | AnnotatePixelShader( alternateShader.Get(), shaderType, true ); 74 | } 75 | return; 76 | } 77 | } 78 | 79 | ComPtr Effects::Bloom::BeforePixelShaderSet( ID3D11DeviceContext* context, ID3D11PixelShader* shader ) 80 | { 81 | ComPtr result(shader); 82 | 83 | if ( SETTINGS.bloomType == 0 || !shader ) return result; 84 | 85 | m_state = State::Initial; 86 | 87 | ResourceMetadata meta; 88 | UINT size = sizeof(meta); 89 | if ( SUCCEEDED(shader->GetPrivateData(__uuidof(meta), &size, &meta)) ) 90 | { 91 | if ( meta.m_type == ResourceMetadata::Type::BloomShader1 ) // Bloom shader 1 - replace shader and bind a custom constant buffer 92 | { 93 | ComPtr replacedShader; 94 | size = sizeof(ID3D11PixelShader*); 95 | if ( SUCCEEDED(shader->GetPrivateData(GUID_AlternateResource, &size, replacedShader.GetAddressOf())) ) 96 | { 97 | result = std::move(replacedShader); 98 | 99 | context->PSSetConstantBuffers( 3, 1, m_shader1CB.GetAddressOf() ); 100 | } 101 | } 102 | else if ( meta.m_type == ResourceMetadata::Type::BloomShader2 ) // Bloom shader 2 - don't replace, but advance the state machine 103 | { 104 | m_state = State::Bloom2Set; 105 | } 106 | else if ( meta.m_type == ResourceMetadata::Type::BloomShader4 ) // Bloom shader 4 - replace shader and bind a custom constant buffer 107 | { 108 | ComPtr replacedShader; 109 | size = sizeof(ID3D11PixelShader*); 110 | if ( SUCCEEDED(shader->GetPrivateData(GUID_AlternateResource, &size, replacedShader.GetAddressOf())) ) 111 | { 112 | result = std::move(replacedShader); 113 | 114 | context->PSSetConstantBuffers( 3, 1, m_shader4CB.GetAddressOf() ); 115 | } 116 | } 117 | else if ( meta.m_type == ResourceMetadata::Type::BloomMergerShader ) // Bloom merger - replace shader, then rebind inputs before drawing 118 | { 119 | ComPtr replacedShader; 120 | size = sizeof(ID3D11PixelShader*); 121 | if ( SUCCEEDED(shader->GetPrivateData(GUID_AlternateResource, &size, replacedShader.GetAddressOf())) ) 122 | { 123 | result = std::move(replacedShader); 124 | 125 | m_state = State::MergerPSFound; 126 | } 127 | } 128 | } 129 | return result; 130 | } 131 | 132 | bool Effects::Bloom::OnDraw( ID3D11DeviceContext* context, UINT VertexCount, UINT StartVertexLocation ) 133 | { 134 | if ( m_state == State::Bloom2Drawn ) 135 | { 136 | m_state = State::Initial; 137 | 138 | // Replace with an alternate bloom3 shader 139 | context->PSSetShader( m_bloom3PS.Get(), nullptr, 0 ); 140 | } 141 | else if ( m_state == State::MergerPSFound ) 142 | { 143 | m_state = State::Initial; 144 | 145 | // Rebind inputs to match the modified shader 146 | ID3D11ShaderResourceView* view[3]; // Warning - raw pointers! 147 | context->PSGetShaderResources( 0, 3, view ); 148 | auto releaseSRV = wil::scope_exit([&] { 149 | for ( auto* r : view ) 150 | { 151 | if ( r != nullptr ) 152 | { 153 | r->Release(); 154 | } 155 | } 156 | }); 157 | 158 | // SRV2 goes to SRV0, SRV0 goes to SRV1 159 | ID3D11ShaderResourceView* const reboundSRV[] = { view[2], view[0] }; 160 | context->PSSetShaderResources( 0, _countof(reboundSRV), reboundSRV ); 161 | 162 | ID3D11Buffer* cb[3]; // Warning - raw pointers! 163 | context->PSGetConstantBuffers( 3, 3, cb ); 164 | auto releaseCB = wil::scope_exit([&] { 165 | for ( auto* r : cb ) 166 | { 167 | if ( r != nullptr ) 168 | { 169 | r->Release(); 170 | } 171 | } 172 | }); 173 | 174 | // CB5 goes to CB3 175 | context->PSSetConstantBuffers( 3, 1, &cb[2] ); 176 | 177 | // Rebind the original resources after the draw 178 | auto restore = wil::scope_exit([&] { 179 | context->PSSetConstantBuffers( 3, 1, &cb[0] ); 180 | 181 | context->PSSetShaderResources( 0, _countof(view), view ); 182 | }); 183 | 184 | context->Draw( VertexCount, StartVertexLocation ); 185 | return true; 186 | } 187 | else if ( m_state == State::Bloom2Set ) 188 | { 189 | m_state = State::Bloom2Drawn; 190 | } 191 | 192 | return false; 193 | } 194 | 195 | -------------------------------------------------------------------------------- /source/wil/result_originate.h: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License. 5 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 6 | // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 7 | // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 8 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. 9 | // 10 | //********************************************************* 11 | 12 | // Note: When origination is enabled by including this file, origination is done as part of the RETURN_* and THROW_* macros. Before originating 13 | // a new error we will observe whether there is already an error payload associated with the current thread. If there is, and the HRESULTs match, 14 | // then a new error will not be originated. Otherwise we will overwrite it with a new origination. The ABI boundary for WinRT APIs will check the 15 | // per-thread error information. The act of checking the error clears it, so there should be minimal risk of failing to originate distinct errors 16 | // simply because the HRESULTs match. 17 | // 18 | // For THROW_ macros we will examine the thread-local error storage once per throw. So typically once, with additional calls if the exception is 19 | // caught and re-thrown. 20 | // 21 | // For RETURN_ macros we will have to examine the thread-local error storage once per frame as the call stack unwinds. Because error conditions 22 | // -should- be uncommon the performance impact of checking TLS should be minimal. The more expensive part is originating the error because it must 23 | // capture the entire stack and some additional data. 24 | 25 | #ifndef __WIL_RESULT_ORIGINATE_INCLUDED 26 | #define __WIL_RESULT_ORIGINATE_INCLUDED 27 | 28 | #include "result.h" 29 | #include // RestrictedErrorInfo uses BSTRs :( 30 | #include "resource.h" 31 | #include "com.h" 32 | #include 33 | 34 | #ifndef __cplusplus_winrt // The CX runtime likes to originate errors already so we would conflict with them. 35 | namespace wil 36 | { 37 | namespace details 38 | { 39 | // Note: The name must begin with "Raise" so that the !analyze auto-bucketing will ignore this stack frame. Otherwise this line of code gets all the blame. 40 | inline void __stdcall RaiseRoOriginateOnWilExceptions(wil::FailureInfo const& failure) WI_NOEXCEPT 41 | { 42 | if ((failure.type == FailureType::Return) || (failure.type == FailureType::Exception)) 43 | { 44 | bool shouldOriginate = true; 45 | 46 | wil::com_ptr_nothrow restrictedErrorInformation; 47 | if (GetRestrictedErrorInfo(&restrictedErrorInformation) == S_OK) 48 | { 49 | // This thread already has an error origination payload. Don't originate again if it has the same HRESULT that we are 50 | // observing right now. 51 | wil::unique_bstr descriptionUnused; 52 | HRESULT existingHr = failure.hr; 53 | wil::unique_bstr restrictedDescriptionUnused; 54 | wil::unique_bstr capabilitySidUnused; 55 | if (SUCCEEDED(restrictedErrorInformation->GetErrorDetails(&descriptionUnused, &existingHr, &restrictedDescriptionUnused, &capabilitySidUnused))) 56 | { 57 | shouldOriginate = (failure.hr != existingHr); 58 | } 59 | } 60 | 61 | if (shouldOriginate) 62 | { 63 | #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) 64 | wil::unique_hmodule errorModule; 65 | if (GetModuleHandleExW(0, L"api-ms-win-core-winrt-error-l1-1-1.dll", &errorModule)) 66 | { 67 | auto pfn = reinterpret_cast(GetProcAddress(errorModule.get(), "RoOriginateError")); 68 | if (pfn != nullptr) 69 | { 70 | pfn(failure.hr, nullptr); 71 | } 72 | } 73 | #else // DESKTOP | SYSTEM 74 | ::RoOriginateError(failure.hr, nullptr); 75 | #endif // DESKTOP | SYSTEM 76 | } 77 | else if (restrictedErrorInformation) 78 | { 79 | // GetRestrictedErrorInfo returns ownership of the error information. If we aren't originating, and an error was already present, 80 | // then we need to restore the error information for later observation. 81 | SetRestrictedErrorInfo(restrictedErrorInformation.get()); 82 | } 83 | } 84 | } 85 | 86 | // This method will check for the presence of stowed exception data on the current thread. If such data exists, and the HRESULT 87 | // matches the current failure, then we will call RoFailFastWithErrorContext. RoFailFastWithErrorContext in this situation will 88 | // result in -VASTLY- improved crash bucketing. It is hard to express just how much better. In other cases we just return and 89 | // the calling method fails fast the same way it always has. 90 | inline void __stdcall FailfastWithContextCallback(wil::FailureInfo const& failure) WI_NOEXCEPT 91 | { 92 | wil::com_ptr_nothrow restrictedErrorInformation; 93 | if (GetRestrictedErrorInfo(&restrictedErrorInformation) == S_OK) 94 | { 95 | wil::unique_bstr descriptionUnused; 96 | HRESULT existingHr = failure.hr; 97 | wil::unique_bstr restrictedDescriptionUnused; 98 | wil::unique_bstr capabilitySidUnused; 99 | if (SUCCEEDED(restrictedErrorInformation->GetErrorDetails(&descriptionUnused, &existingHr, &restrictedDescriptionUnused, &capabilitySidUnused)) && 100 | (existingHr == failure.hr)) 101 | { 102 | // GetRestrictedErrorInfo returns ownership of the error information. We want it to be available for RoFailFastWithErrorContext 103 | // so we must restore it via SetRestrictedErrorInfo first. 104 | SetRestrictedErrorInfo(restrictedErrorInformation.get()); 105 | RoFailFastWithErrorContext(existingHr); 106 | } 107 | else 108 | { 109 | // The error didn't match the current failure. Put it back in thread-local storage even though we aren't failing fast 110 | // in this method, so it is available in the debugger just-in-case. 111 | SetRestrictedErrorInfo(restrictedErrorInformation.get()); 112 | } 113 | } 114 | } 115 | } // namespace details 116 | } // namespace wil 117 | 118 | // Automatically call RoOriginateError upon error origination by including this file 119 | WI_HEADER_INITITALIZATION_FUNCTION(ResultStowedExceptionInitialize, [] 120 | { 121 | ::wil::SetOriginateErrorCallback(::wil::details::RaiseRoOriginateOnWilExceptions); 122 | ::wil::SetFailfastWithContextCallback(::wil::details::FailfastWithContextCallback); 123 | return 1; 124 | }); 125 | #endif // __cplusplus_winrt 126 | 127 | #endif // __WIL_RESULT_ORIGINATE_INCLUDED 128 | -------------------------------------------------------------------------------- /source/imgui/imconfig.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // COMPILE-TIME OPTIONS FOR DEAR IMGUI 3 | // Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure. 4 | // You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions. 5 | //----------------------------------------------------------------------------- 6 | // A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/branch with your modifications to imconfig.h) 7 | // B) or add configuration directives in your own file and compile with #define IMGUI_USER_CONFIG "myfilename.h" 8 | // If you do so you need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include 9 | // the imgui*.cpp files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures. 10 | // Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts. 11 | // Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using. 12 | //----------------------------------------------------------------------------- 13 | 14 | #pragma once 15 | 16 | //---- Define assertion handler. Defaults to calling assert(). 17 | // If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement. 18 | //#define IM_ASSERT(_EXPR) MyAssert(_EXPR) 19 | //#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts 20 | 21 | //---- Define attributes of all API symbols declarations, e.g. for DLL under Windows 22 | // Using dear imgui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility. 23 | //#define IMGUI_API __declspec( dllexport ) 24 | //#define IMGUI_API __declspec( dllimport ) 25 | 26 | //---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names. 27 | //#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS 28 | 29 | //---- Disable all of Dear ImGui or don't implement standard windows. 30 | // It is very strongly recommended to NOT disable the demo windows during development. Please read comments in imgui_demo.cpp. 31 | //#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty. 32 | //#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. Not recommended. 33 | //#define IMGUI_DISABLE_METRICS_WINDOW // Disable debug/metrics window: ShowMetricsWindow() will be empty. 34 | 35 | //---- Don't implement some functions to reduce linkage requirements. 36 | //#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. 37 | //#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] Don't implement default IME handler. Won't use and link with ImmGetContext/ImmSetCompositionWindow. 38 | //#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime). 39 | //#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default). 40 | //#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf) 41 | //#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself. 42 | //#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function. 43 | //#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). 44 | 45 | //---- Include imgui_user.h at the end of imgui.h as a convenience 46 | //#define IMGUI_INCLUDE_IMGUI_USER_H 47 | 48 | //---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another) 49 | //#define IMGUI_USE_BGRA_PACKED_COLOR 50 | 51 | //---- Use 32-bit for ImWchar (default is 16-bit) to support full unicode code points. 52 | //#define IMGUI_USE_WCHAR32 53 | 54 | //---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version 55 | // By default the embedded implementations are declared static and not available outside of imgui cpp files. 56 | //#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" 57 | //#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" 58 | //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION 59 | //#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION 60 | 61 | //---- Unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined, use the much faster STB sprintf library implementation of vsnprintf instead of the one from the default C library. 62 | // Note that stb_sprintf.h is meant to be provided by the user and available in the include path at compile time. Also, the compatibility checks of the arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by STB sprintf. 63 | // #define IMGUI_USE_STB_SPRINTF 64 | 65 | //---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4. 66 | // This will be inlined as part of ImVec2 and ImVec4 class declarations. 67 | /* 68 | #define IM_VEC2_CLASS_EXTRA \ 69 | ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \ 70 | operator MyVec2() const { return MyVec2(x,y); } 71 | 72 | #define IM_VEC4_CLASS_EXTRA \ 73 | ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \ 74 | operator MyVec4() const { return MyVec4(x,y,z,w); } 75 | */ 76 | 77 | //---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices. 78 | // Your renderer back-end will need to support it (most example renderer back-ends support both 16/32-bit indices). 79 | // Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer. 80 | // Read about ImGuiBackendFlags_RendererHasVtxOffset for details. 81 | //#define ImDrawIdx unsigned int 82 | 83 | //---- Override ImDrawCallback signature (will need to modify renderer back-ends accordingly) 84 | //struct ImDrawList; 85 | //struct ImDrawCmd; 86 | //typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data); 87 | //#define ImDrawCallback MyImDrawCallback 88 | 89 | //---- Debug Tools: Macro to break in Debugger 90 | // (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.) 91 | //#define IM_DEBUG_BREAK IM_ASSERT(0) 92 | //#define IM_DEBUG_BREAK __debugbreak() 93 | 94 | //---- Debug Tools: Have the Item Picker break in the ItemAdd() function instead of ItemHoverable(), 95 | // (which comes earlier in the code, will catch a few extra items, allow picking items other than Hovered one.) 96 | // This adds a small runtime cost which is why it is not enabled by default. 97 | //#define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX 98 | 99 | //---- Debug Tools: Enable slower asserts 100 | //#define IMGUI_DEBUG_PARANOID 101 | 102 | //---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files. 103 | /* 104 | namespace ImGui 105 | { 106 | void MyFunction(const char* name, const MyMatrix44& v); 107 | } 108 | */ 109 | -------------------------------------------------------------------------------- /source/wil/rpc_helpers.h: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License. 5 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 6 | // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 7 | // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 8 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. 9 | // 10 | //********************************************************* 11 | #ifndef __WIL_RPC_HELPERS_INCLUDED 12 | #define __WIL_RPC_HELPERS_INCLUDED 13 | 14 | #include "result.h" 15 | #include "resource.h" 16 | #include "wistd_functional.h" 17 | #include "wistd_type_traits.h" 18 | 19 | namespace wil 20 | { 21 | 22 | /// @cond 23 | namespace details 24 | { 25 | // This call-adapter template converts a void-returning 'wistd::invoke' into 26 | // an HRESULT-returning 'wistd::invoke' that emits S_OK. It can be eliminated 27 | // with 'if constexpr' when C++17 is in wide use. 28 | template struct call_adapter 29 | { 30 | template static HRESULT call(TArgs&& ... args) 31 | { 32 | return wistd::invoke(wistd::forward(args)...); 33 | } 34 | }; 35 | 36 | template<> struct call_adapter 37 | { 38 | template static HRESULT call(TArgs&& ... args) 39 | { 40 | wistd::invoke(wistd::forward(args)...); 41 | return S_OK; 42 | } 43 | }; 44 | 45 | // Some RPC exceptions are already HRESULTs. Others are in the regular Win32 46 | // error space. If the incoming exception code isn't an HRESULT, wrap it. 47 | constexpr HRESULT map_rpc_exception(DWORD code) 48 | { 49 | return IS_ERROR(code) ? code : __HRESULT_FROM_WIN32(code); 50 | } 51 | } 52 | /// @endcond 53 | 54 | /** Invokes an RPC method, mapping structured exceptions to HRESULTs 55 | Failures encountered by the RPC infrastructure (such as server crashes, authentication 56 | errors, client parameter issues, etc.) are emitted by raising a structured exception from 57 | within the RPC machinery. This method wraps the requested call in the usual RpcTryExcept, 58 | RpcTryCatch, and RpcEndExcept sequence then maps the exceptions to HRESULTs for the usual 59 | flow control machinery to use. 60 | 61 | Many RPC methods are defined as returning HRESULT themselves, where the HRESULT indicates 62 | the result of the _work_. HRESULTs returned by a successful completion of the _call_ are 63 | returned as-is. 64 | 65 | RPC methods that have a return type of 'void' are mapped to returning S_OK when the _call_ 66 | completes successfully. 67 | 68 | For example, consider an RPC interface method defined in idl as: 69 | ~~~ 70 | HRESULT GetKittenState([in, ref, string] const wchar_t* name, [out, retval] KittenState** state); 71 | ~~~ 72 | To call this method, use: 73 | ~~~ 74 | wil::unique_rpc_binding binding = // typically gotten elsewhere; 75 | wil::unique_midl_ptr state; 76 | HRESULT hr = wil::invoke_rpc_nothrow(GetKittenState, binding.get(), L"fluffy", state.put()); 77 | RETURN_IF_FAILED(hr); 78 | ~~~ 79 | */ 80 | template HRESULT invoke_rpc_nothrow(TCall&&... args) WI_NOEXCEPT 81 | { 82 | RpcTryExcept 83 | { 84 | // Note: this helper type can be removed with C++17 enabled via 85 | // 'if constexpr(wistd::is_same_v)' 86 | using result_t = typename wistd::__invoke_of::type; 87 | RETURN_IF_FAILED(details::call_adapter::call(wistd::forward(args)...)); 88 | return S_OK; 89 | } 90 | RpcExcept(RpcExceptionFilter(RpcExceptionCode())) 91 | { 92 | RETURN_HR(details::map_rpc_exception(RpcExceptionCode())); 93 | } 94 | RpcEndExcept 95 | } 96 | 97 | /** Invokes an RPC method, mapping structured exceptions to HRESULTs 98 | Failures encountered by the RPC infrastructure (such as server crashes, authentication 99 | errors, client parameter issues, etc.) are emitted by raising a structured exception from 100 | within the RPC machinery. This method wraps the requested call in the usual RpcTryExcept, 101 | RpcTryCatch, and RpcEndExcept sequence then maps the exceptions to HRESULTs for the usual 102 | flow control machinery to use. 103 | 104 | Some RPC methods return results (such as a state enumeration or other value) directly in 105 | their signature. This adapter writes that result into a caller-provided object then 106 | returns S_OK. 107 | 108 | For example, consider an RPC interface method defined in idl as: 109 | ~~~ 110 | GUID GetKittenId([in, ref, string] const wchar_t* name); 111 | ~~~ 112 | To call this method, use: 113 | ~~~ 114 | wil::unique_rpc_binding binding = // typically gotten elsewhere; 115 | GUID id; 116 | HRESULT hr = wil::invoke_rpc_result_nothrow(id, GetKittenId, binding.get(), L"fluffy"); 117 | RETURN_IF_FAILED(hr); 118 | ~~~ 119 | */ 120 | template HRESULT invoke_rpc_result_nothrow(TResult& result, TCall&&... args) WI_NOEXCEPT 121 | { 122 | RpcTryExcept 123 | { 124 | result = wistd::invoke(wistd::forward(args)...); 125 | return S_OK; 126 | } 127 | RpcExcept(RpcExceptionFilter(RpcExceptionCode())) 128 | { 129 | RETURN_HR(details::map_rpc_exception(RpcExceptionCode())); 130 | } 131 | RpcEndExcept 132 | } 133 | 134 | namespace details 135 | { 136 | // Provides an adapter around calling the context-handle-close method on an 137 | // RPC interface, which itself is an RPC call. 138 | template 139 | struct rpc_closer_t 140 | { 141 | static void Close(TStorage arg) WI_NOEXCEPT 142 | { 143 | LOG_IF_FAILED(invoke_rpc_nothrow(close_fn, &arg)); 144 | } 145 | }; 146 | } 147 | 148 | /** Manages explicit RPC context handles 149 | Explicit RPC context handles are used in many RPC interfaces. Most interfaces with 150 | context handles have an explicit `FooClose([in, out] CONTEXT*)` method that lets 151 | the server close out the context handle. As the close method itself is an RPC call, 152 | it can fail and raise a structured exception. 153 | 154 | This type routes the context-handle-specific `Close` call through the `invoke_rpc_nothrow` 155 | helper, ensuring correct cleanup and lifecycle management. 156 | ~~~ 157 | // Assume the interface has two methods: 158 | // HRESULT OpenFoo([in] handle_t binding, [out] FOO_CONTEXT*); 159 | // HRESULT UseFoo([in] FOO_CONTEXT context; 160 | // void CloseFoo([in, out] PFOO_CONTEXT); 161 | using unique_foo_context = wil::unique_rpc_context_handle; 162 | unique_foo_context context; 163 | RETURN_IF_FAILED(wil::invoke_rpc_nothrow(OpenFoo, m_binding.get(), context.put())); 164 | RETURN_IF_FAILED(wil::invoke_rpc_nothrow(UseFoo, context.get())); 165 | context.reset(); 166 | ~~~ 167 | */ 168 | template 169 | using unique_rpc_context_handle = unique_any::Close), details::rpc_closer_t::Close>; 170 | 171 | #ifdef WIL_ENABLE_EXCEPTIONS 172 | /** Invokes an RPC method, mapping structured exceptions to C++ exceptions 173 | See `wil::invoke_rpc_nothrow` for additional information. Failures during the _call_ 174 | and those returned by the _method_ are mapped to HRESULTs and thrown inside a 175 | wil::ResultException. Using the example RPC method provided above: 176 | ~~~ 177 | wil::unique_midl_ptr state; 178 | wil::invoke_rpc(GetKittenState, binding.get(), L"fluffy", state.put()); 179 | // use 'state' 180 | ~~~ 181 | */ 182 | template void invoke_rpc(TCall&& ... args) 183 | { 184 | THROW_IF_FAILED(invoke_rpc_nothrow(wistd::forward(args)...)); 185 | } 186 | 187 | /** Invokes an RPC method, mapping structured exceptions to C++ exceptions 188 | See `wil::invoke_rpc_result_nothrow` for additional information. Failures during the 189 | _call_ are mapped to HRESULTs and thrown inside a `wil::ResultException`. Using the 190 | example RPC method provided above: 191 | ~~~ 192 | GUID id = wil::invoke_rpc_result(GetKittenId, binding.get()); 193 | // use 'id' 194 | ~~~ 195 | */ 196 | template auto invoke_rpc_result(TCall&& ... args) 197 | { 198 | using result_t = typename wistd::__invoke_of::type; 199 | result_t result{}; 200 | THROW_IF_FAILED(invoke_rpc_result_nothrow(result, wistd::forward(args)...)); 201 | return result; 202 | } 203 | #endif 204 | } 205 | 206 | #endif 207 | -------------------------------------------------------------------------------- /source/wil/cppwinrt.h: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License. 5 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 6 | // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 7 | // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 8 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. 9 | // 10 | //********************************************************* 11 | #ifndef __WIL_CPPWINRT_INCLUDED 12 | #define __WIL_CPPWINRT_INCLUDED 13 | 14 | #include "common.h" 15 | #include 16 | #include 17 | #include 18 | 19 | // WIL and C++/WinRT use two different exception types for communicating HRESULT failures. Thus, both libraries need to 20 | // understand how to translate these exception types into the correct HRESULT values at the ABI boundary. Prior to 21 | // C++/WinRT "2.0" this was accomplished by injecting the WINRT_EXTERNAL_CATCH_CLAUSE macro - that WIL defines below - 22 | // into its exception handler (winrt::to_hresult). Starting with C++/WinRT "2.0" this mechanism has shifted to a global 23 | // function pointer - winrt_to_hresult_handler - that WIL sets automatically when this header is included and 24 | // 'CPPWINRT_SUPPRESS_STATIC_INITIALIZERS' is not defined. 25 | 26 | /// @cond 27 | namespace wil::details 28 | { 29 | // Since the C++/WinRT version macro is a string... 30 | inline constexpr int major_version_from_string(const char* versionString) 31 | { 32 | int result = 0; 33 | auto str = versionString; 34 | while ((*str >= '0') && (*str <= '9')) 35 | { 36 | result = result * 10 + (*str - '0'); 37 | ++str; 38 | } 39 | 40 | return result; 41 | } 42 | } 43 | /// @endcond 44 | 45 | #ifdef CPPWINRT_VERSION 46 | // Prior to C++/WinRT "2.0" this header needed to be included before 'winrt/base.h' so that our definition of 47 | // 'WINRT_EXTERNAL_CATCH_CLAUSE' would get picked up in the implementation of 'winrt::to_hresult'. This is no longer 48 | // problematic, so only emit an error when using a version of C++/WinRT prior to 2.0 49 | static_assert(::wil::details::major_version_from_string(CPPWINRT_VERSION) >= 2, 50 | "Please include wil/cppwinrt.h before including any C++/WinRT headers"); 51 | #endif 52 | 53 | // NOTE: Will eventually be removed once C++/WinRT 2.0 use can be assumed 54 | #ifdef WINRT_EXTERNAL_CATCH_CLAUSE 55 | #define __WI_CONFLICTING_WINRT_EXTERNAL_CATCH_CLAUSE 1 56 | #else 57 | #define WINRT_EXTERNAL_CATCH_CLAUSE \ 58 | catch (const wil::ResultException& e) \ 59 | { \ 60 | return winrt::hresult_error(e.GetErrorCode(), winrt::to_hstring(e.what())).to_abi(); \ 61 | } 62 | #endif 63 | 64 | #include "result_macros.h" 65 | #include 66 | 67 | #if __WI_CONFLICTING_WINRT_EXTERNAL_CATCH_CLAUSE 68 | static_assert(::wil::details::major_version_from_string(CPPWINRT_VERSION) >= 2, 69 | "C++/WinRT external catch clause already defined outside of WIL"); 70 | #endif 71 | 72 | // In C++/WinRT 2.0 and beyond, this function pointer exists. In earlier versions it does not. It's much easier to avoid 73 | // linker errors than it is to SFINAE on variable existence, so we declare the variable here, but are careful not to 74 | // use it unless the version of C++/WinRT is high enough 75 | extern std::int32_t(__stdcall* winrt_to_hresult_handler)(void*) noexcept; 76 | 77 | /// @cond 78 | namespace wil::details 79 | { 80 | inline void MaybeGetExceptionString( 81 | const winrt::hresult_error& exception, 82 | _Out_writes_opt_(debugStringChars) PWSTR debugString, 83 | _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars) 84 | { 85 | if (debugString) 86 | { 87 | StringCchPrintfW(debugString, debugStringChars, L"winrt::hresult_error: %ls", exception.message().c_str()); 88 | } 89 | } 90 | 91 | inline HRESULT __stdcall ResultFromCaughtException_CppWinRt( 92 | _Inout_updates_opt_(debugStringChars) PWSTR debugString, 93 | _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars, 94 | _Inout_ bool* isNormalized) noexcept 95 | { 96 | if (g_pfnResultFromCaughtException) 97 | { 98 | try 99 | { 100 | throw; 101 | } 102 | catch (const ResultException& exception) 103 | { 104 | *isNormalized = true; 105 | MaybeGetExceptionString(exception, debugString, debugStringChars); 106 | return exception.GetErrorCode(); 107 | } 108 | catch (const winrt::hresult_error& exception) 109 | { 110 | MaybeGetExceptionString(exception, debugString, debugStringChars); 111 | return exception.to_abi(); 112 | } 113 | catch (const std::bad_alloc& exception) 114 | { 115 | MaybeGetExceptionString(exception, debugString, debugStringChars); 116 | return E_OUTOFMEMORY; 117 | } 118 | catch (const std::out_of_range& exception) 119 | { 120 | MaybeGetExceptionString(exception, debugString, debugStringChars); 121 | return E_BOUNDS; 122 | } 123 | catch (const std::invalid_argument& exception) 124 | { 125 | MaybeGetExceptionString(exception, debugString, debugStringChars); 126 | return E_INVALIDARG; 127 | } 128 | catch (...) 129 | { 130 | auto hr = RecognizeCaughtExceptionFromCallback(debugString, debugStringChars); 131 | if (FAILED(hr)) 132 | { 133 | return hr; 134 | } 135 | } 136 | } 137 | else 138 | { 139 | try 140 | { 141 | throw; 142 | } 143 | catch (const ResultException& exception) 144 | { 145 | *isNormalized = true; 146 | MaybeGetExceptionString(exception, debugString, debugStringChars); 147 | return exception.GetErrorCode(); 148 | } 149 | catch (const winrt::hresult_error& exception) 150 | { 151 | MaybeGetExceptionString(exception, debugString, debugStringChars); 152 | return exception.to_abi(); 153 | } 154 | catch (const std::bad_alloc& exception) 155 | { 156 | MaybeGetExceptionString(exception, debugString, debugStringChars); 157 | return E_OUTOFMEMORY; 158 | } 159 | catch (const std::out_of_range& exception) 160 | { 161 | MaybeGetExceptionString(exception, debugString, debugStringChars); 162 | return E_BOUNDS; 163 | } 164 | catch (const std::invalid_argument& exception) 165 | { 166 | MaybeGetExceptionString(exception, debugString, debugStringChars); 167 | return E_INVALIDARG; 168 | } 169 | catch (const std::exception& exception) 170 | { 171 | MaybeGetExceptionString(exception, debugString, debugStringChars); 172 | return HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION); 173 | } 174 | catch (...) 175 | { 176 | // Fall through to returning 'S_OK' below 177 | } 178 | } 179 | 180 | // Tell the caller that we were unable to map the exception by succeeding... 181 | return S_OK; 182 | } 183 | } 184 | /// @endcond 185 | 186 | namespace wil 187 | { 188 | inline std::int32_t __stdcall winrt_to_hresult(void* returnAddress) noexcept 189 | { 190 | // C++/WinRT only gives us the return address (caller), so pass along an empty 'DiagnosticsInfo' since we don't 191 | // have accurate file/line/etc. information 192 | return static_cast(details::ReportFailure_CaughtException(__R_DIAGNOSTICS_RA(DiagnosticsInfo{}, returnAddress))); 193 | } 194 | 195 | inline void WilInitialize_CppWinRT() 196 | { 197 | details::g_pfnResultFromCaughtException_CppWinRt = details::ResultFromCaughtException_CppWinRt; 198 | if constexpr (details::major_version_from_string(CPPWINRT_VERSION) >= 2) 199 | { 200 | WI_ASSERT(winrt_to_hresult_handler == nullptr); 201 | winrt_to_hresult_handler = winrt_to_hresult; 202 | } 203 | } 204 | 205 | /// @cond 206 | namespace details 207 | { 208 | #ifndef CPPWINRT_SUPPRESS_STATIC_INITIALIZERS 209 | WI_ODR_PRAGMA("CPPWINRT_SUPPRESS_STATIC_INITIALIZERS", "0") 210 | WI_HEADER_INITITALIZATION_FUNCTION(WilInitialize_CppWinRT, [] 211 | { 212 | ::wil::WilInitialize_CppWinRT(); 213 | return 1; 214 | }); 215 | #else 216 | WI_ODR_PRAGMA("CPPWINRT_SUPPRESS_STATIC_INITIALIZERS", "1") 217 | #endif 218 | } 219 | /// @endcond 220 | 221 | // Provides an overload of verify_hresult so that the WIL macros can recognize winrt::hresult as a valid "hresult" type. 222 | inline long verify_hresult(winrt::hresult hr) noexcept 223 | { 224 | return hr; 225 | } 226 | 227 | // Provides versions of get_abi and put_abi for genericity that directly use HSTRING for convenience. 228 | template 229 | auto get_abi(T const& object) noexcept 230 | { 231 | return winrt::get_abi(object); 232 | } 233 | 234 | inline auto get_abi(winrt::hstring const& object) noexcept 235 | { 236 | return static_cast(winrt::get_abi(object)); 237 | } 238 | 239 | template 240 | auto put_abi(T& object) noexcept 241 | { 242 | return winrt::put_abi(object); 243 | } 244 | 245 | inline auto put_abi(winrt::hstring& object) noexcept 246 | { 247 | return reinterpret_cast(winrt::put_abi(object)); 248 | } 249 | } 250 | 251 | #endif // __WIL_CPPWINRT_INCLUDED 252 | -------------------------------------------------------------------------------- /source/effects/ColorGrading.cpp: -------------------------------------------------------------------------------- 1 | #include "ColorGrading.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "../wil/resource.h" 7 | 8 | #include "ColorGrading_shader.h" 9 | 10 | #define DEBUG_COLOR_GRADING_CALLS 0 11 | 12 | #if DEBUG_COLOR_GRADING_CALLS 13 | #include 14 | #endif 15 | 16 | static D3D11_TEXTURE2D_DESC GetTextureResourceDesc(const ComPtr& resource) 17 | { 18 | D3D11_TEXTURE2D_DESC desc; 19 | 20 | ComPtr curTexture; 21 | resource.As(&curTexture); 22 | 23 | curTexture->GetDesc( &desc ); 24 | return desc; 25 | } 26 | 27 | Effects::ColorGrading::ColorGrading(ID3D11Device* device) 28 | : m_device(device) 29 | { 30 | m_device->CreatePixelShader( COLOR_GRADING_PS_BYTECODE, sizeof(COLOR_GRADING_PS_BYTECODE), nullptr, m_pixelShader.GetAddressOf() ); 31 | 32 | D3D11_BUFFER_DESC cbDesc {}; 33 | cbDesc.ByteWidth = 512; 34 | cbDesc.Usage = D3D11_USAGE_DYNAMIC; 35 | cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; 36 | cbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; 37 | 38 | m_device->CreateBuffer( &cbDesc, nullptr, m_constantBuffer.GetAddressOf() ); 39 | } 40 | 41 | void Effects::ColorGrading::OnPixelShaderSet(ID3D11PixelShader* shader) 42 | { 43 | if ( !SETTINGS.colorGradingEnabled || !shader ) return; 44 | 45 | const ResourceMetadata::Type shaderType = GetPixelShaderAnnotation( shader ).m_type; 46 | 47 | if ( shaderType == ResourceMetadata::Type::BloomMergerShader ) 48 | { 49 | m_state = State::MergerCallFound; 50 | return; 51 | } 52 | 53 | if ( m_state == State::MergerCallFound ) 54 | { 55 | m_state = State::Initial; // Reset in case the required shader was "found" but changed before it was used 56 | return; 57 | } 58 | 59 | if ( m_state == State::ResourcesGathered ) 60 | { 61 | // If setting to use Edge AA, ignore blend state changes 62 | m_volatileData->m_edgeAADetected = shaderType == ResourceMetadata::Type::EdgeAA; 63 | } 64 | } 65 | 66 | void Effects::ColorGrading::BeforeDraw( ID3D11DeviceContext* context, UINT VertexCount, UINT StartVertexLocation ) 67 | { 68 | if ( m_state == State::MergerCallFound ) 69 | { 70 | if ( VertexCount != 6 ) 71 | { 72 | // Something went wrong, this draw call is not bloom postfx 73 | m_state = State::Initial; 74 | return; 75 | } 76 | 77 | m_state = State::ResourcesGathered; 78 | 79 | m_volatileData = std::make_optional(); 80 | 81 | context->VSGetShader( m_volatileData->m_vertexShader.GetAddressOf(), nullptr, nullptr ); 82 | context->IAGetInputLayout( m_volatileData->m_inputLayout.GetAddressOf() ); 83 | context->RSGetState( m_volatileData->m_rasterizerState.GetAddressOf() ); 84 | context->OMGetBlendState( m_volatileData->m_blendState.GetAddressOf(), nullptr, nullptr ); 85 | context->IAGetVertexBuffers( 0, 1, std::get<0>(m_volatileData->m_vertexBuffer).ReleaseAndGetAddressOf(), 86 | &std::get<1>(m_volatileData->m_vertexBuffer), &std::get<2>(m_volatileData->m_vertexBuffer) ); 87 | std::get<3>(m_volatileData->m_vertexBuffer) = StartVertexLocation; 88 | 89 | if ( !m_persistentData.has_value() ) 90 | { 91 | m_persistentData = std::make_optional(); 92 | } 93 | } 94 | } 95 | 96 | void Effects::ColorGrading::BeforeOMSetBlendState(ID3D11DeviceContext* context, ID3D11BlendState* pBlendState) 97 | { 98 | if ( m_state == State::ResourcesGathered ) 99 | { 100 | // If setting to a different blend state to what we saved, draw 101 | if ( !m_volatileData->m_edgeAADetected && m_volatileData->m_blendState.Get() != pBlendState ) 102 | { 103 | // Draw to current RTV0 104 | ComPtr curRTV; 105 | ComPtr curDSV; 106 | context->OMGetRenderTargets( 1, curRTV.GetAddressOf(), curDSV.GetAddressOf() ); 107 | auto restoreRTV = wil::scope_exit([&] { 108 | context->OMSetRenderTargets( 1, curRTV.GetAddressOf(), curDSV.Get() ); 109 | }); 110 | 111 | #if DEBUG_COLOR_GRADING_CALLS 112 | ComPtr annotation; 113 | if (SUCCEEDED(context->QueryInterface(IID_PPV_ARGS(annotation.GetAddressOf())))) 114 | { 115 | annotation->SetMarker( L"BeforeOMSetBlendState" ); 116 | } 117 | #endif 118 | 119 | DrawColorFilter( context, curRTV ); 120 | } 121 | } 122 | } 123 | 124 | void Effects::ColorGrading::BeforeOMSetRenderTargets(ID3D11DeviceContext* context, UINT NumViews, ID3D11RenderTargetView* const* ppRenderTargetViews, ID3D11DepthStencilView* pDepthStencilView) 125 | { 126 | if ( m_state == State::ResourcesGathered ) 127 | { 128 | // If unbinding the RTV, save it in case we need to render using our special case for additional blur 129 | if ( NumViews == 0 && pDepthStencilView == nullptr ) 130 | { 131 | context->OMGetRenderTargets( 1, m_volatileData->m_lastUnboundRTV.ReleaseAndGetAddressOf(), nullptr ); 132 | return; 133 | } 134 | 135 | // If setting a single render target to something smaller than the gathered render target, draw 136 | if ( NumViews == 1 && ppRenderTargetViews != nullptr && pDepthStencilView == nullptr ) 137 | { 138 | ComPtr curRT; 139 | ppRenderTargetViews[0]->GetResource( curRT.GetAddressOf() ); 140 | 141 | const D3D11_TEXTURE2D_DESC desc = GetTextureResourceDesc( curRT ); 142 | 143 | if ( desc.Width < std::get<1>(m_persistentData->m_tempRT) && desc.Height < std::get<2>(m_persistentData->m_tempRT) ) 144 | { 145 | // Draw to "last" RTV0 146 | // No need to save/restore render targets as they will be overwritten 147 | #if DEBUG_COLOR_GRADING_CALLS 148 | ComPtr annotation; 149 | if (SUCCEEDED(context->QueryInterface(IID_PPV_ARGS(annotation.GetAddressOf())))) 150 | { 151 | annotation->SetMarker( L"BeforeOMSetRenderTargets" ); 152 | } 153 | #endif 154 | 155 | DrawColorFilter( context, m_volatileData->m_lastUnboundRTV ); 156 | } 157 | return; 158 | } 159 | } 160 | } 161 | 162 | void Effects::ColorGrading::BeforeClearRenderTargetView(ID3D11DeviceContext* context, ID3D11RenderTargetView* /*pRenderTargetView*/, const FLOAT /*ColorRGBA*/[4]) 163 | { 164 | if ( m_state == State::ResourcesGathered ) 165 | { 166 | // If we got there before the other code paths, subtitles are disabled and we'd end up drawing the filter too late otherwise 167 | #if DEBUG_COLOR_GRADING_CALLS 168 | ComPtr annotation; 169 | if (SUCCEEDED(context->QueryInterface(IID_PPV_ARGS(annotation.GetAddressOf())))) 170 | { 171 | annotation->SetMarker( L"BeforeClearRenderTargetView" ); 172 | } 173 | #endif 174 | 175 | // Need to restore RTV/DSV afterwards in this case 176 | ComPtr curRTV; 177 | ComPtr curDSV; 178 | context->OMGetRenderTargets( 1, curRTV.GetAddressOf(), curDSV.GetAddressOf() ); 179 | auto restoreRTV = wil::scope_exit([&] { 180 | context->OMSetRenderTargets( 1, curRTV.GetAddressOf(), curDSV.Get() ); 181 | }); 182 | 183 | DrawColorFilter( context, m_volatileData->m_lastUnboundRTV ); 184 | } 185 | } 186 | 187 | void Effects::ColorGrading::ClearState() 188 | { 189 | m_persistentData.reset(); 190 | m_volatileData.reset(); 191 | m_state = State::Initial; 192 | } 193 | 194 | void Effects::ColorGrading::DrawColorFilter(ID3D11DeviceContext* context, const ComPtr& target) 195 | { 196 | m_state = State::Initial; 197 | 198 | ComPtr targetResource; 199 | target->GetResource(targetResource.GetAddressOf()); 200 | 201 | const D3D11_TEXTURE2D_DESC desc = GetTextureResourceDesc( targetResource ); 202 | 203 | // Recreate the temporary RT if dimensions don't match 204 | if ( std::get<1>(m_persistentData->m_tempRT) != desc.Width || std::get<2>(m_persistentData->m_tempRT) != desc.Height ) 205 | { 206 | m_device->CreateTexture2D( &desc, nullptr, std::get<0>(m_persistentData->m_tempRT).ReleaseAndGetAddressOf() ); 207 | m_device->CreateRenderTargetView( std::get<0>(m_persistentData->m_tempRT).Get(), nullptr, m_persistentData->m_tempRTV.ReleaseAndGetAddressOf() ); 208 | 209 | std::get<1>(m_persistentData->m_tempRT) = desc.Width; 210 | std::get<2>(m_persistentData->m_tempRT) = desc.Height; 211 | } 212 | 213 | // Recreate the SRV if cached RT doesn't match 214 | // It should be cheap to recreate so such low effort caching should be enough 215 | if ( m_persistentData->m_lastOutputRT == nullptr || m_persistentData->m_lastOutputRT != targetResource ) 216 | { 217 | m_persistentData->m_lastOutputRT = targetResource; 218 | m_device->CreateShaderResourceView( targetResource.Get(), nullptr, m_persistentData->m_lastOutputSRV.ReleaseAndGetAddressOf() ); 219 | } 220 | 221 | 222 | // Save states to restore them after drawing 223 | ComPtr savedVertexShader; 224 | ComPtr savedPixelShader; 225 | ComPtr savedInputLayout; 226 | ComPtr savedRasterizerState; 227 | ComPtr savedSRV; 228 | std::tuple< ComPtr, UINT, UINT > savedInputBuffer; 229 | ComPtr savedConstantBuffer; 230 | 231 | context->VSGetShader( savedVertexShader.GetAddressOf(), nullptr, nullptr ); 232 | context->PSGetShader( savedPixelShader.GetAddressOf(), nullptr, nullptr ); 233 | context->IAGetInputLayout( savedInputLayout.GetAddressOf() ); 234 | context->RSGetState( savedRasterizerState.GetAddressOf() ); 235 | context->PSGetShaderResources( 0, 1, savedSRV.GetAddressOf() ); 236 | context->IAGetVertexBuffers( 0, 1, std::get<0>(savedInputBuffer).GetAddressOf(), &std::get<1>(savedInputBuffer), &std::get<2>(savedInputBuffer) ); 237 | context->PSGetConstantBuffers( 5, 1, savedConstantBuffer.ReleaseAndGetAddressOf() ); 238 | 239 | auto restore = wil::scope_exit([&] { 240 | context->PSSetConstantBuffers( 5, 1, savedConstantBuffer.GetAddressOf() ); 241 | context->IASetVertexBuffers( 0, 1, std::get<0>(savedInputBuffer).GetAddressOf(), &std::get<1>(savedInputBuffer), &std::get<2>(savedInputBuffer) ); 242 | context->PSSetShaderResources( 0, 1, savedSRV.GetAddressOf() ); 243 | context->RSSetState( savedRasterizerState.Get() ); 244 | context->IASetInputLayout( savedInputLayout.Get() ); 245 | context->PSSetShader( savedPixelShader.Get(), nullptr, 0 ); 246 | context->VSSetShader( savedVertexShader.Get(), nullptr, 0 ); 247 | }); 248 | 249 | #if DEBUG_COLOR_GRADING_CALLS 250 | ComPtr annotation; 251 | auto endEvent = wil::scope_exit([&] { 252 | if (annotation) 253 | { 254 | annotation->EndEvent(); 255 | } 256 | }); 257 | 258 | 259 | if (SUCCEEDED(context->QueryInterface(IID_PPV_ARGS(annotation.GetAddressOf())))) 260 | { 261 | annotation->BeginEvent( L"DrawColorFilter" ); 262 | } 263 | #endif 264 | 265 | context->VSSetShader( m_volatileData->m_vertexShader.Get(), nullptr, 0 ); 266 | context->PSSetShader( m_pixelShader.Get(), nullptr, 0 ); 267 | context->IASetInputLayout( m_volatileData->m_inputLayout.Get() ); 268 | context->RSSetState( m_volatileData->m_rasterizerState.Get() ); 269 | 270 | context->OMSetRenderTargets( 1, m_persistentData->m_tempRTV.GetAddressOf(), nullptr ); 271 | 272 | context->IASetVertexBuffers( 0, 1, std::get<0>(m_volatileData->m_vertexBuffer).GetAddressOf(), 273 | &std::get<1>(m_volatileData->m_vertexBuffer), &std::get<2>(m_volatileData->m_vertexBuffer) ); 274 | context->PSSetConstantBuffers( 5, 1, m_constantBuffer.GetAddressOf() ); 275 | context->PSSetShaderResources( 0, 1, m_persistentData->m_lastOutputSRV.GetAddressOf() ); 276 | 277 | if ( std::exchange(SETTINGS.colorGradingDirty, false) ) 278 | { 279 | D3D11_MAPPED_SUBRESOURCE mapped; 280 | if ( SUCCEEDED(context->Map( m_constantBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped )) ) 281 | { 282 | memcpy( mapped.pData, SETTINGS.colorGradingAttributes, sizeof(SETTINGS.colorGradingAttributes) ); 283 | context->Unmap( m_constantBuffer.Get(), 0 ); 284 | } 285 | } 286 | 287 | context->Draw( 6, std::get<3>(m_volatileData->m_vertexBuffer) ); 288 | context->CopyResource( targetResource.Get(), std::get<0>(m_persistentData->m_tempRT).Get() ); 289 | 290 | m_volatileData.reset(); 291 | } 292 | 293 | -------------------------------------------------------------------------------- /source/wil/registry.h: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License. 5 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 6 | // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 7 | // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 8 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. 9 | // 10 | //********************************************************* 11 | #ifndef __WIL_REGISTRY_INCLUDED 12 | #define __WIL_REGISTRY_INCLUDED 13 | 14 | #ifdef _KERNEL_MODE 15 | #error This header is not supported in kernel-mode. 16 | #endif 17 | 18 | #include 19 | #include // new(std::nothrow) 20 | #include "resource.h" // unique_hkey 21 | 22 | namespace wil 23 | { 24 | //! The key name includes the absolute path of the key in the registry, always starting at a 25 | //! base key, for example, HKEY_LOCAL_MACHINE. 26 | size_t const max_registry_key_name_length = 255; 27 | 28 | //! The maximum number of characters allowed in a registry value's name. 29 | size_t const max_registry_value_name_length = 16383; 30 | 31 | // unique_registry_watcher/unique_registry_watcher_nothrow/unique_registry_watcher_failfast 32 | // These classes make it easy to execute a provided function when a 33 | // registry key changes (optionally recursively). Specify the key 34 | // either as a root key + path, or an open registry handle as wil::unique_hkey 35 | // or a raw HKEY value (that will be duplicated). 36 | // 37 | // Example use with exceptions base error handling: 38 | // auto watcher = wil::make_registry_watcher(HKEY_CURRENT_USER, L"Software\\MyApp", true, wil::RegistryChangeKind changeKind[] 39 | // { 40 | // if (changeKind == RegistryChangeKind::Delete) 41 | // { 42 | // watcher.reset(); 43 | // } 44 | // // invalidate cached registry data here 45 | // }); 46 | // 47 | // Example use with error code base error handling: 48 | // auto watcher = wil::make_registry_watcher_nothrow(HKEY_CURRENT_USER, L"Software\\MyApp", true, wil::RegistryChangeKind[] 49 | // { 50 | // // invalidate cached registry data here 51 | // }); 52 | // RETURN_IF_NULL_ALLOC(watcher); 53 | 54 | enum class RegistryChangeKind 55 | { 56 | Modify = 0, 57 | Delete = 1, 58 | }; 59 | 60 | /// @cond 61 | namespace details 62 | { 63 | struct registry_watcher_state 64 | { 65 | registry_watcher_state(unique_hkey &&keyToWatch, bool isRecursive, wistd::function &&callback) 66 | : m_callback(wistd::move(callback)), m_keyToWatch(wistd::move(keyToWatch)), m_isRecursive(isRecursive) 67 | { 68 | } 69 | wistd::function m_callback; 70 | unique_hkey m_keyToWatch; 71 | unique_event_nothrow m_eventHandle; 72 | 73 | // While not strictly needed since this is ref counted the thread pool wait 74 | // should be last to ensure that the other members are valid 75 | // when it is destructed as it will reference them. 76 | unique_threadpool_wait m_threadPoolWait; 77 | bool m_isRecursive; 78 | 79 | volatile long m_refCount = 1; 80 | srwlock m_lock; 81 | 82 | // Returns true if the refcount can be increased from a non zero value, 83 | // false it was zero impling that the object is in or on the way to the destructor. 84 | // In this case ReleaseFromCallback() should not be called. 85 | bool TryAddRef() 86 | { 87 | return ::InterlockedIncrement(&m_refCount) > 1; 88 | } 89 | 90 | void Release() 91 | { 92 | auto lock = m_lock.lock_exclusive(); 93 | if (0 == ::InterlockedDecrement(&m_refCount)) 94 | { 95 | lock.reset(); // leave the lock before deleting it. 96 | delete this; 97 | } 98 | } 99 | 100 | void ReleaseFromCallback(bool rearm) 101 | { 102 | auto lock = m_lock.lock_exclusive(); 103 | if (0 == ::InterlockedDecrement(&m_refCount)) 104 | { 105 | // Destroy the thread pool wait now to avoid the wait that would occur in the 106 | // destructor. That wait would cause a deadlock since we are doing this from the callback. 107 | ::CloseThreadpoolWait(m_threadPoolWait.release()); 108 | lock.reset(); // leave the lock before deleting it. 109 | delete this; 110 | // Sleep(1); // Enable for testing to find use after free bugs. 111 | } 112 | else if (rearm) 113 | { 114 | ::SetThreadpoolWait(m_threadPoolWait.get(), m_eventHandle.get(), nullptr); 115 | } 116 | } 117 | }; 118 | 119 | inline void delete_registry_watcher_state(_In_opt_ registry_watcher_state *watcherStorage) { watcherStorage->Release(); } 120 | 121 | typedef resource_policy registry_watcher_state_resource_policy; 123 | } 124 | /// @endcond 125 | 126 | template 127 | class registry_watcher_t : public storage_t 128 | { 129 | public: 130 | // forward all base class constructors... 131 | template 132 | explicit registry_watcher_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) {} 133 | 134 | // HRESULT or void error handling... 135 | typedef typename err_policy::result result; 136 | 137 | // Exception-based constructors 138 | registry_watcher_t(HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, wistd::function &&callback) 139 | { 140 | static_assert(wistd::is_same::value, "this constructor requires exceptions; use the create method"); 141 | create(rootKey, subKey, isRecursive, wistd::move(callback)); 142 | } 143 | 144 | registry_watcher_t(unique_hkey &&keyToWatch, bool isRecursive, wistd::function &&callback) 145 | { 146 | static_assert(wistd::is_same::value, "this constructor requires exceptions; use the create method"); 147 | create(wistd::move(keyToWatch), isRecursive, wistd::move(callback)); 148 | } 149 | 150 | // Pass a root key, sub key pair or use an empty string to use rootKey as the key to watch. 151 | result create(HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, wistd::function &&callback) 152 | { 153 | // Most use will want to create the key, consider adding an option for open as a future design change. 154 | unique_hkey keyToWatch; 155 | HRESULT hr = HRESULT_FROM_WIN32(RegCreateKeyExW(rootKey, subKey, 0, nullptr, 0, KEY_NOTIFY, nullptr, &keyToWatch, nullptr)); 156 | if (FAILED(hr)) 157 | { 158 | return err_policy::HResult(hr); 159 | } 160 | return err_policy::HResult(create_common(wistd::move(keyToWatch), isRecursive, wistd::move(callback))); 161 | } 162 | 163 | result create(unique_hkey &&keyToWatch, bool isRecursive, wistd::function &&callback) 164 | { 165 | return err_policy::HResult(create_common(wistd::move(keyToWatch), isRecursive, wistd::move(callback))); 166 | } 167 | 168 | private: 169 | // Factored into a standalone function to support Clang which does not support conversion of stateless lambdas 170 | // to __stdcall 171 | static void __stdcall callback(PTP_CALLBACK_INSTANCE, void *context, TP_WAIT *, TP_WAIT_RESULT) 172 | { 173 | #ifndef __WIL_REGISTRY_CHANGE_CALLBACK_TEST 174 | #define __WIL_REGISTRY_CHANGE_CALLBACK_TEST 175 | #endif 176 | __WIL_REGISTRY_CHANGE_CALLBACK_TEST 177 | auto watcherState = static_cast(context); 178 | if (watcherState->TryAddRef()) 179 | { 180 | // using auto reset event so don't need to manually reset. 181 | 182 | // failure here is a programming error. 183 | const LSTATUS error = RegNotifyChangeKeyValue(watcherState->m_keyToWatch.get(), watcherState->m_isRecursive, 184 | REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_THREAD_AGNOSTIC, 185 | watcherState->m_eventHandle.get(), TRUE); 186 | 187 | // Call the client before re-arming to ensure that multiple callbacks don't 188 | // run concurrently. 189 | switch (error) 190 | { 191 | case ERROR_SUCCESS: 192 | case ERROR_ACCESS_DENIED: 193 | // Normal modification: send RegistryChangeKind::Modify and re-arm. 194 | watcherState->m_callback(RegistryChangeKind::Modify); 195 | watcherState->ReleaseFromCallback(true); 196 | break; 197 | 198 | case ERROR_KEY_DELETED: 199 | // Key deleted, send RegistryChangeKind::Delete, do not re-arm. 200 | watcherState->m_callback(RegistryChangeKind::Delete); 201 | watcherState->ReleaseFromCallback(false); 202 | break; 203 | 204 | case ERROR_HANDLE_REVOKED: 205 | // Handle revoked. This can occur if the user session ends before 206 | // the watcher shuts-down. Disarm silently since there is generally no way to respond. 207 | watcherState->ReleaseFromCallback(false); 208 | break; 209 | 210 | default: 211 | FAIL_FAST_HR(HRESULT_FROM_WIN32(error)); 212 | } 213 | } 214 | } 215 | 216 | // This function exists to avoid template expansion of this code based on err_policy. 217 | HRESULT create_common(unique_hkey &&keyToWatch, bool isRecursive, wistd::function &&callback) 218 | { 219 | wistd::unique_ptr watcherState(new(std::nothrow) details::registry_watcher_state( 220 | wistd::move(keyToWatch), isRecursive, wistd::move(callback))); 221 | RETURN_IF_NULL_ALLOC(watcherState); 222 | RETURN_IF_FAILED(watcherState->m_eventHandle.create()); 223 | RETURN_IF_WIN32_ERROR(RegNotifyChangeKeyValue(watcherState->m_keyToWatch.get(), 224 | watcherState->m_isRecursive, REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_THREAD_AGNOSTIC, 225 | watcherState->m_eventHandle.get(), TRUE)); 226 | 227 | watcherState->m_threadPoolWait.reset(CreateThreadpoolWait(®istry_watcher_t::callback, watcherState.get(), nullptr)); 228 | RETURN_LAST_ERROR_IF(!watcherState->m_threadPoolWait); 229 | storage_t::reset(watcherState.release()); // no more failures after this, pass ownership 230 | SetThreadpoolWait(storage_t::get()->m_threadPoolWait.get(), storage_t::get()->m_eventHandle.get(), nullptr); 231 | return S_OK; 232 | } 233 | }; 234 | 235 | typedef unique_any_t, err_returncode_policy>> unique_registry_watcher_nothrow; 236 | typedef unique_any_t, err_failfast_policy>> unique_registry_watcher_failfast; 237 | 238 | inline unique_registry_watcher_nothrow make_registry_watcher_nothrow(HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, wistd::function &&callback) WI_NOEXCEPT 239 | { 240 | unique_registry_watcher_nothrow watcher; 241 | watcher.create(rootKey, subKey, isRecursive, wistd::move(callback)); 242 | return watcher; // caller must test for success using if (watcher) 243 | } 244 | 245 | inline unique_registry_watcher_nothrow make_registry_watcher_nothrow(unique_hkey &&keyToWatch, bool isRecursive, wistd::function &&callback) WI_NOEXCEPT 246 | { 247 | unique_registry_watcher_nothrow watcher; 248 | watcher.create(wistd::move(keyToWatch), isRecursive, wistd::move(callback)); 249 | return watcher; // caller must test for success using if (watcher) 250 | } 251 | 252 | inline unique_registry_watcher_failfast make_registry_watcher_failfast(HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, wistd::function &&callback) 253 | { 254 | return unique_registry_watcher_failfast(rootKey, subKey, isRecursive, wistd::move(callback)); 255 | } 256 | 257 | inline unique_registry_watcher_failfast make_registry_watcher_failfast(unique_hkey &&keyToWatch, bool isRecursive, wistd::function &&callback) 258 | { 259 | return unique_registry_watcher_failfast(wistd::move(keyToWatch), isRecursive, wistd::move(callback)); 260 | } 261 | 262 | #ifdef WIL_ENABLE_EXCEPTIONS 263 | typedef unique_any_t, err_exception_policy >> unique_registry_watcher; 264 | 265 | inline unique_registry_watcher make_registry_watcher(HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, wistd::function &&callback) 266 | { 267 | return unique_registry_watcher(rootKey, subKey, isRecursive, wistd::move(callback)); 268 | } 269 | 270 | inline unique_registry_watcher make_registry_watcher(unique_hkey &&keyToWatch, bool isRecursive, wistd::function &&callback) 271 | { 272 | return unique_registry_watcher(wistd::move(keyToWatch), isRecursive, wistd::move(callback)); 273 | } 274 | #endif // WIL_ENABLE_EXCEPTIONS 275 | } // namespace wil 276 | 277 | #endif 278 | -------------------------------------------------------------------------------- /source/wil/wistd_functional.h: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | //===------------------------ functional ----------------------------------===// 3 | // 4 | // The LLVM Compiler Infrastructure 5 | // 6 | // This file is dual licensed under the MIT and the University of Illinois Open 7 | // Source Licenses. See LICENSE.TXT for details. 8 | // 9 | //===----------------------------------------------------------------------===// 10 | 11 | // STL common functionality 12 | // 13 | // Some aspects of STL are core language concepts that should be used from all C++ code, regardless 14 | // of whether exceptions are enabled in the component. Common library code that expects to be used 15 | // from exception-free components want these concepts, but including STL headers directly introduces 16 | // friction as it requires components not using STL to declare their STL version. Doing so creates 17 | // ambiguity around whether STL use is safe in a particular component and implicitly brings in 18 | // a long list of headers (including ) which can create further ambiguity around throwing new 19 | // support (some routines pulled in may expect it). Secondarily, pulling in these headers also has 20 | // the potential to create naming conflicts or other implied dependencies. 21 | // 22 | // To promote the use of these core language concepts outside of STL-based binaries, this file is 23 | // selectively pulling those concepts *directly* from corresponding STL headers. The corresponding 24 | // "std::" namespace STL functions and types should be preferred over these in code that is bound to 25 | // STL. The implementation and naming of all functions are taken directly from STL, instead using 26 | // "wistd" (Windows Implementation std) as the namespace. 27 | // 28 | // Routines in this namespace should always be considered a reflection of the *current* STL implementation 29 | // of those routines. Updates from STL should be taken, but no "bugs" should be fixed here. 30 | // 31 | // New, exception-based code should not use this namespace, but instead should prefer the std:: implementation. 32 | // Only code that is not exception-based and libraries that expect to be utilized across both exception 33 | // and non-exception based code should utilize this functionality. 34 | 35 | #ifndef _WISTD_FUNCTIONAL_H_ 36 | #define _WISTD_FUNCTIONAL_H_ 37 | 38 | // DO NOT add *any* additional includes to this file -- there should be no dependencies from its usage 39 | #include "wistd_memory.h" 40 | #include // For __fastfail 41 | #include // For placement new 42 | 43 | #if !defined(__WI_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 44 | #pragma GCC system_header 45 | #endif 46 | 47 | #pragma warning(push) 48 | #pragma warning(disable: 4324) 49 | #pragma warning(disable: 4800) 50 | 51 | /// @cond 52 | namespace wistd // ("Windows Implementation" std) 53 | { 54 | // wistd::function 55 | // 56 | // All of the code below is in direct support of wistd::function. This class is identical to std::function 57 | // with the following exceptions: 58 | // 59 | // 1) It never allocates and is safe to use from exception-free code (custom allocators are not supported) 60 | // 2) It's slightly bigger on the stack (64 bytes, rather than 24 for 32bit) 61 | // 3) There is an explicit static-assert if a lambda becomes too large to hold in the internal buffer (rather than an allocation) 62 | 63 | template 64 | struct __invoke_void_return_wrapper 65 | { 66 | #ifndef __WI_LIBCPP_CXX03_LANG 67 | template 68 | static _Ret __call(_Args&&... __args) { 69 | return __invoke(wistd::forward<_Args>(__args)...); 70 | } 71 | #else 72 | template 73 | static _Ret __call(_Fn __f) { 74 | return __invoke(__f); 75 | } 76 | 77 | template 78 | static _Ret __call(_Fn __f, _A0& __a0) { 79 | return __invoke(__f, __a0); 80 | } 81 | 82 | template 83 | static _Ret __call(_Fn __f, _A0& __a0, _A1& __a1) { 84 | return __invoke(__f, __a0, __a1); 85 | } 86 | 87 | template 88 | static _Ret __call(_Fn __f, _A0& __a0, _A1& __a1, _A2& __a2){ 89 | return __invoke(__f, __a0, __a1, __a2); 90 | } 91 | #endif 92 | }; 93 | 94 | template <> 95 | struct __invoke_void_return_wrapper 96 | { 97 | #ifndef __WI_LIBCPP_CXX03_LANG 98 | template 99 | static void __call(_Args&&... __args) { 100 | (void)__invoke(wistd::forward<_Args>(__args)...); 101 | } 102 | #else 103 | template 104 | static void __call(_Fn __f) { 105 | __invoke(__f); 106 | } 107 | 108 | template 109 | static void __call(_Fn __f, _A0& __a0) { 110 | __invoke(__f, __a0); 111 | } 112 | 113 | template 114 | static void __call(_Fn __f, _A0& __a0, _A1& __a1) { 115 | __invoke(__f, __a0, __a1); 116 | } 117 | 118 | template 119 | static void __call(_Fn __f, _A0& __a0, _A1& __a1, _A2& __a2) { 120 | __invoke(__f, __a0, __a1, __a2); 121 | } 122 | #endif 123 | }; 124 | 125 | //////////////////////////////////////////////////////////////////////////////// 126 | // FUNCTION 127 | //============================================================================== 128 | 129 | // bad_function_call 130 | 131 | __WI_LIBCPP_NORETURN inline __WI_LIBCPP_INLINE_VISIBILITY 132 | void __throw_bad_function_call() 133 | { 134 | __fastfail(7); // FAST_FAIL_FATAL_APP_EXIT 135 | } 136 | 137 | template class __WI_LIBCPP_TEMPLATE_VIS function; // undefined 138 | 139 | namespace __function 140 | { 141 | 142 | template 143 | struct __maybe_derive_from_unary_function 144 | { 145 | }; 146 | 147 | template 148 | struct __maybe_derive_from_unary_function<_Rp(_A1)> 149 | : public unary_function<_A1, _Rp> 150 | { 151 | }; 152 | 153 | template 154 | struct __maybe_derive_from_binary_function 155 | { 156 | }; 157 | 158 | template 159 | struct __maybe_derive_from_binary_function<_Rp(_A1, _A2)> 160 | : public binary_function<_A1, _A2, _Rp> 161 | { 162 | }; 163 | 164 | template 165 | __WI_LIBCPP_INLINE_VISIBILITY 166 | bool __not_null(_Fp const&) { return true; } 167 | 168 | template 169 | __WI_LIBCPP_INLINE_VISIBILITY 170 | bool __not_null(_Fp* __ptr) { return __ptr; } 171 | 172 | template 173 | __WI_LIBCPP_INLINE_VISIBILITY 174 | bool __not_null(_Ret _Class::*__ptr) { return __ptr; } 175 | 176 | template 177 | __WI_LIBCPP_INLINE_VISIBILITY 178 | bool __not_null(function<_Fp> const& __f) { return !!__f; } 179 | 180 | } // namespace __function 181 | 182 | #ifndef __WI_LIBCPP_CXX03_LANG 183 | 184 | namespace __function { 185 | 186 | template class __base; 187 | 188 | template 189 | class __base<_Rp(_ArgTypes...)> 190 | { 191 | __base(const __base&); 192 | __base& operator=(const __base&); 193 | public: 194 | __WI_LIBCPP_INLINE_VISIBILITY __base() {} 195 | __WI_LIBCPP_INLINE_VISIBILITY virtual ~__base() {} 196 | virtual void __clone(__base*) const = 0; 197 | virtual void __move(__base*) = 0; 198 | virtual void destroy() WI_NOEXCEPT = 0; 199 | virtual _Rp operator()(_ArgTypes&& ...) = 0; 200 | }; 201 | 202 | template class __func; 203 | 204 | template 205 | class __func<_Fp, _Rp(_ArgTypes...)> 206 | : public __base<_Rp(_ArgTypes...)> 207 | { 208 | _Fp __f_; 209 | public: 210 | __WI_LIBCPP_INLINE_VISIBILITY 211 | explicit __func(_Fp&& __f) 212 | : __f_(wistd::move(__f)) {} 213 | 214 | __WI_LIBCPP_INLINE_VISIBILITY 215 | explicit __func(const _Fp& __f) 216 | : __f_(__f) {} 217 | 218 | virtual void __clone(__base<_Rp(_ArgTypes...)>*) const; 219 | virtual void __move(__base<_Rp(_ArgTypes...)>*); 220 | virtual void destroy() WI_NOEXCEPT; 221 | virtual _Rp operator()(_ArgTypes&& ... __arg); 222 | }; 223 | 224 | template 225 | void 226 | __func<_Fp, _Rp(_ArgTypes...)>::__clone(__base<_Rp(_ArgTypes...)>* __p) const 227 | { 228 | ::new (__p) __func(__f_); 229 | } 230 | 231 | template 232 | void 233 | __func<_Fp, _Rp(_ArgTypes...)>::__move(__base<_Rp(_ArgTypes...)>* __p) 234 | { 235 | ::new (__p) __func(wistd::move(__f_)); 236 | } 237 | 238 | template 239 | void 240 | __func<_Fp, _Rp(_ArgTypes...)>::destroy() WI_NOEXCEPT 241 | { 242 | __f_.~_Fp(); 243 | } 244 | 245 | template 246 | _Rp 247 | __func<_Fp, _Rp(_ArgTypes...)>::operator()(_ArgTypes&& ... __arg) 248 | { 249 | typedef __invoke_void_return_wrapper<_Rp> _Invoker; 250 | return _Invoker::__call(__f_, wistd::forward<_ArgTypes>(__arg)...); 251 | } 252 | 253 | } // __function 254 | 255 | template 256 | class __WI_LIBCPP_TEMPLATE_VIS function<_Rp(_ArgTypes...)> 257 | : public __function::__maybe_derive_from_unary_function<_Rp(_ArgTypes...)>, 258 | public __function::__maybe_derive_from_binary_function<_Rp(_ArgTypes...)> 259 | { 260 | // 'wistd::function' is most similar to 'inplace_function' in that it _only_ permits holding function objects 261 | // that can fit within its internal buffer. Therefore, we expand this size to accommodate space for at least 12 262 | // pointers (__base vtable takes an additional one). 263 | static constexpr size_t __buffer_size = 13 * sizeof(void*); 264 | 265 | typedef __function::__base<_Rp(_ArgTypes...)> __base; 266 | __WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS 267 | typename aligned_storage<__buffer_size>::type __buf_; 268 | __base* __f_; 269 | 270 | __WI_LIBCPP_NO_CFI static __base *__as_base(void *p) { 271 | return reinterpret_cast<__base*>(p); 272 | } 273 | 274 | template 275 | struct __callable_imp 276 | { 277 | static const bool value = is_same::value || 278 | is_convertible::type, 279 | _Rp>::value; 280 | }; 281 | 282 | template 283 | struct __callable_imp<_Fp, false> 284 | { 285 | static const bool value = false; 286 | }; 287 | 288 | template 289 | struct __callable 290 | { 291 | static const bool value = __callable_imp<_Fp, __lazy_and< 292 | integral_constant, function>::value>, 293 | __invokable<_Fp&, _ArgTypes...> 294 | >::value>::value; 295 | }; 296 | 297 | template 298 | using _EnableIfCallable = typename enable_if<__callable<_Fp>::value>::type; 299 | public: 300 | typedef _Rp result_type; 301 | 302 | // construct/copy/destroy: 303 | __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS 304 | function() WI_NOEXCEPT : __f_(0) {} 305 | __WI_LIBCPP_INLINE_VISIBILITY 306 | function(nullptr_t) WI_NOEXCEPT : __f_(0) {} 307 | function(const function&); 308 | function(function&&); 309 | template> 310 | function(_Fp); 311 | 312 | function& operator=(const function&); 313 | function& operator=(function&&); 314 | function& operator=(nullptr_t) WI_NOEXCEPT; 315 | template> 316 | function& operator=(_Fp&&); 317 | 318 | ~function(); 319 | 320 | // function modifiers: 321 | void swap(function&); 322 | 323 | // function capacity: 324 | __WI_LIBCPP_INLINE_VISIBILITY 325 | __WI_LIBCPP_EXPLICIT operator bool() const WI_NOEXCEPT {return __f_;} 326 | 327 | // deleted overloads close possible hole in the type system 328 | template 329 | bool operator==(const function<_R2(_ArgTypes2...)>&) const = delete; 330 | template 331 | bool operator!=(const function<_R2(_ArgTypes2...)>&) const = delete; 332 | public: 333 | // function invocation: 334 | _Rp operator()(_ArgTypes...) const; 335 | 336 | // NOTE: type_info is very compiler specific, and on top of that, we're operating in a namespace other than 337 | // 'std' so all functions requiring RTTI have been removed 338 | }; 339 | 340 | template 341 | __WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS 342 | function<_Rp(_ArgTypes...)>::function(const function& __f) 343 | { 344 | if (__f.__f_ == 0) 345 | __f_ = 0; 346 | else 347 | { 348 | __f_ = __as_base(&__buf_); 349 | __f.__f_->__clone(__f_); 350 | } 351 | } 352 | 353 | template 354 | __WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS __WI_LIBCPP_SUPPRESS_NOEXCEPT_ANALYSIS 355 | function<_Rp(_ArgTypes...)>::function(function&& __f) 356 | { 357 | if (__f.__f_ == 0) 358 | __f_ = 0; 359 | else 360 | { 361 | __f_ = __as_base(&__buf_); 362 | __f.__f_->__move(__f_); 363 | __f.__f_->destroy(); 364 | __f.__f_ = 0; 365 | } 366 | } 367 | 368 | template 369 | template 370 | __WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS 371 | function<_Rp(_ArgTypes...)>::function(_Fp __f) 372 | : __f_(0) 373 | { 374 | if (__function::__not_null(__f)) 375 | { 376 | typedef __function::__func<_Fp, _Rp(_ArgTypes...)> _FF; 377 | static_assert(sizeof(_FF) <= sizeof(__buf_), 378 | "The sizeof(wistd::function) has grown too large for the reserved buffer (12 pointers). Refactor to reduce size of the capture."); 379 | __f_ = ::new((void*)&__buf_) _FF(wistd::move(__f)); 380 | } 381 | } 382 | 383 | template 384 | function<_Rp(_ArgTypes...)>& 385 | function<_Rp(_ArgTypes...)>::operator=(const function& __f) 386 | { 387 | *this = nullptr; 388 | if (__f.__f_) 389 | { 390 | __f_ = __as_base(&__buf_); 391 | __f.__f_->__clone(__f_); 392 | } 393 | return *this; 394 | } 395 | 396 | template 397 | function<_Rp(_ArgTypes...)>& 398 | function<_Rp(_ArgTypes...)>::operator=(function&& __f) 399 | { 400 | *this = nullptr; 401 | if (__f.__f_) 402 | { 403 | __f_ = __as_base(&__buf_); 404 | __f.__f_->__move(__f_); 405 | __f.__f_->destroy(); 406 | __f.__f_ = 0; 407 | } 408 | return *this; 409 | } 410 | 411 | template 412 | function<_Rp(_ArgTypes...)>& 413 | function<_Rp(_ArgTypes...)>::operator=(nullptr_t) WI_NOEXCEPT 414 | { 415 | __base* __t = __f_; 416 | __f_ = 0; 417 | if (__t) 418 | __t->destroy(); 419 | return *this; 420 | } 421 | 422 | template 423 | template 424 | function<_Rp(_ArgTypes...)>& 425 | function<_Rp(_ArgTypes...)>::operator=(_Fp&& __f) 426 | { 427 | *this = nullptr; 428 | if (__function::__not_null(__f)) 429 | { 430 | typedef __function::__func::type, _Rp(_ArgTypes...)> _FF; 431 | static_assert(sizeof(_FF) <= sizeof(__buf_), 432 | "The sizeof(wistd::function) has grown too large for the reserved buffer (12 pointers). Refactor to reduce size of the capture."); 433 | __f_ = ::new((void*)&__buf_) _FF(wistd::move(__f)); 434 | } 435 | 436 | return *this; 437 | } 438 | 439 | template 440 | function<_Rp(_ArgTypes...)>::~function() 441 | { 442 | if (__f_) 443 | __f_->destroy(); 444 | } 445 | 446 | template 447 | void 448 | function<_Rp(_ArgTypes...)>::swap(function& __f) 449 | { 450 | if (wistd::addressof(__f) == this) 451 | return; 452 | if (__f_ && __f.__f_) 453 | { 454 | typename aligned_storage::type __tempbuf; 455 | __base* __t = __as_base(&__tempbuf); 456 | __f_->__move(__t); 457 | __f_->destroy(); 458 | __f_ = 0; 459 | __f.__f_->__move(__as_base(&__buf_)); 460 | __f.__f_->destroy(); 461 | __f.__f_ = 0; 462 | __f_ = __as_base(&__buf_); 463 | __t->__move(__as_base(&__f.__buf_)); 464 | __t->destroy(); 465 | __f.__f_ = __as_base(&__f.__buf_); 466 | } 467 | else if (__f_) 468 | { 469 | __f_->__move(__as_base(&__f.__buf_)); 470 | __f_->destroy(); 471 | __f_ = 0; 472 | __f.__f_ = __as_base(&__f.__buf_); 473 | } 474 | else if (__f.__f_) 475 | { 476 | __f.__f_->__move(__as_base(&__buf_)); 477 | __f.__f_->destroy(); 478 | __f.__f_ = 0; 479 | __f_ = __as_base(&__buf_); 480 | } 481 | } 482 | 483 | template 484 | _Rp 485 | function<_Rp(_ArgTypes...)>::operator()(_ArgTypes... __arg) const 486 | { 487 | if (__f_ == 0) 488 | __throw_bad_function_call(); 489 | return (*__f_)(wistd::forward<_ArgTypes>(__arg)...); 490 | } 491 | 492 | template 493 | inline __WI_LIBCPP_INLINE_VISIBILITY 494 | bool 495 | operator==(const function<_Rp(_ArgTypes...)>& __f, nullptr_t) WI_NOEXCEPT {return !__f;} 496 | 497 | template 498 | inline __WI_LIBCPP_INLINE_VISIBILITY 499 | bool 500 | operator==(nullptr_t, const function<_Rp(_ArgTypes...)>& __f) WI_NOEXCEPT {return !__f;} 501 | 502 | template 503 | inline __WI_LIBCPP_INLINE_VISIBILITY 504 | bool 505 | operator!=(const function<_Rp(_ArgTypes...)>& __f, nullptr_t) WI_NOEXCEPT {return (bool)__f;} 506 | 507 | template 508 | inline __WI_LIBCPP_INLINE_VISIBILITY 509 | bool 510 | operator!=(nullptr_t, const function<_Rp(_ArgTypes...)>& __f) WI_NOEXCEPT {return (bool)__f;} 511 | 512 | // Provide both 'swap_wil' and 'swap' since we now have two ADL scenarios that we need to work 513 | template 514 | inline __WI_LIBCPP_INLINE_VISIBILITY 515 | void 516 | swap(function<_Rp(_ArgTypes...)>& __x, function<_Rp(_ArgTypes...)>& __y) 517 | {return __x.swap(__y);} 518 | 519 | template 520 | inline __WI_LIBCPP_INLINE_VISIBILITY 521 | void 522 | swap_wil(function<_Rp(_ArgTypes...)>& __x, function<_Rp(_ArgTypes...)>& __y) 523 | {return __x.swap(__y);} 524 | 525 | // std::invoke 526 | template 527 | typename __invoke_of<_Fn, _Args...>::type 528 | invoke(_Fn&& __f, _Args&&... __args) 529 | __WI_NOEXCEPT_((__nothrow_invokable<_Fn, _Args...>::value)) 530 | { 531 | return wistd::__invoke(wistd::forward<_Fn>(__f), wistd::forward<_Args>(__args)...); 532 | } 533 | 534 | #else // __WI_LIBCPP_CXX03_LANG 535 | 536 | #error wistd::function and wistd::invoke not implemented for pre-C++11 537 | 538 | #endif 539 | } 540 | /// @endcond 541 | 542 | #pragma warning(pop) 543 | 544 | #endif // _WISTD_FUNCTIONAL_H_ 545 | -------------------------------------------------------------------------------- /source/wil/safecast.h: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License. 5 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 6 | // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 7 | // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 8 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. 9 | // 10 | //********************************************************* 11 | #ifndef __WIL_SAFECAST_INCLUDED 12 | #define __WIL_SAFECAST_INCLUDED 13 | 14 | #include "result_macros.h" 15 | #include 16 | #include "wistd_config.h" 17 | #include "wistd_type_traits.h" 18 | 19 | namespace wil 20 | { 21 | namespace details 22 | { 23 | // Default error case for undefined conversions in intsafe.h 24 | template constexpr wistd::nullptr_t intsafe_conversion = nullptr; 25 | 26 | // is_known_safe_static_cast_v determines if a conversion is known to be safe or not. Known 27 | // safe conversions can be handled by static_cast, this includes conversions between the same 28 | // type, when the new type is larger than the old type but is not a signed to unsigned 29 | // conversion, and when the two types are the same size and signed/unsigned. All other 30 | // conversions will be assumed to be potentially unsafe, and the conversion must be handled 31 | // by intsafe and checked. 32 | template 33 | constexpr bool is_known_safe_static_cast_v = 34 | (sizeof(NewT) > sizeof(OldT) && !(wistd::is_signed_v && wistd::is_unsigned_v)) || 35 | (sizeof(NewT) == sizeof(OldT) && ((wistd::is_signed_v && wistd::is_signed_v) || (wistd::is_unsigned_v && wistd::is_unsigned_v))); 36 | 37 | // Helper template to determine that NewT and OldT are both integral types. The safe_cast 38 | // operation only supports conversions between integral types. 39 | template 40 | constexpr bool both_integral_v = wistd::is_integral::value && wistd::is_integral::value; 41 | 42 | // Note on native wchar_t (__wchar_t): 43 | // Intsafe.h does not currently handle native wchar_t. When compiling with /Zc:wchar_t-, this is fine as wchar_t is 44 | // typedef'd to unsigned short. However, when compiling with /Zc:wchar_t or wchar_t as a native type, the lack of 45 | // support for native wchar_t in intsafe.h becomes an issue. To work around this, we treat native wchar_t as an 46 | // unsigned short when passing it to intsafe.h, because the two on the Windows platform are the same size and 47 | // share the same range according to MSDN. If the cast is to a native wchar_t, the result from intsafe.h is cast 48 | // to a native wchar_t. 49 | 50 | // Intsafe does not have a defined conversion for native wchar_t 51 | template 52 | constexpr bool neither_native_wchar_v = !wistd::is_same::value && !wistd::is_same::value; 53 | 54 | // Check to see if the cast is a conversion to native wchar_t 55 | template 56 | constexpr bool is_cast_to_wchar_v = wistd::is_same::value && !wistd::is_same::value; 57 | 58 | // Check to see if the cast is a conversion from native wchar_t 59 | template 60 | constexpr bool is_cast_from_wchar_v = !wistd::is_same::value && wistd::is_same::value; 61 | 62 | // Validate the conversion to be performed has a defined mapping to an intsafe conversion 63 | template 64 | constexpr bool is_supported_intsafe_cast_v = intsafe_conversion != nullptr; 65 | 66 | // True when the conversion is between integral types and can be handled by static_cast 67 | template 68 | constexpr bool is_supported_safe_static_cast_v = both_integral_v && is_known_safe_static_cast_v; 69 | 70 | // True when the conversion is between integral types, does not involve native wchar, has 71 | // a mapped intsafe conversion, and is unsafe. 72 | template 73 | constexpr bool is_supported_unsafe_cast_no_wchar_v = 74 | both_integral_v && 75 | !is_known_safe_static_cast_v && 76 | neither_native_wchar_v && 77 | is_supported_intsafe_cast_v; 78 | 79 | // True when the conversion is between integral types, is a cast to native wchar_t, has 80 | // a mapped intsafe conversion, and is unsafe. 81 | template 82 | constexpr bool is_supported_unsafe_cast_to_wchar_v = 83 | both_integral_v && 84 | !is_known_safe_static_cast_v && 85 | is_cast_to_wchar_v && 86 | is_supported_intsafe_cast_v; 87 | 88 | // True when the conversion is between integral types, is a cast from native wchar_t, has 89 | // a mapped intsafe conversion, and is unsafe. 90 | template 91 | constexpr bool is_supported_unsafe_cast_from_wchar_v = 92 | both_integral_v && 93 | !is_known_safe_static_cast_v && 94 | is_cast_from_wchar_v && 95 | is_supported_intsafe_cast_v; 96 | 97 | // True when the conversion is supported and unsafe, and may or may not involve 98 | // native wchar_t. 99 | template 100 | constexpr bool is_supported_unsafe_cast_v = 101 | is_supported_unsafe_cast_no_wchar_v || 102 | is_supported_unsafe_cast_to_wchar_v || 103 | is_supported_unsafe_cast_from_wchar_v; 104 | 105 | // True when T is any one of the primitive types that the variably sized types are defined as. 106 | template 107 | constexpr bool is_potentially_variably_sized_type_v = 108 | wistd::is_same::value || 109 | wistd::is_same::value || 110 | wistd::is_same::value || 111 | wistd::is_same::value || 112 | wistd::is_same::value || 113 | wistd::is_same::value; 114 | 115 | // True when either type is potentialy variably sized (e.g. size_t, ptrdiff_t) 116 | template 117 | constexpr bool is_potentially_variably_sized_cast_v = 118 | is_potentially_variably_sized_type_v || 119 | is_potentially_variably_sized_type_v; 120 | 121 | // Mappings of all conversions defined in intsafe.h to intsafe_conversion 122 | // Note: Uppercase types (UINT, DWORD, SIZE_T, etc) and architecture dependent types resolve 123 | // to the base types. The base types are used since they do not vary based on architecture. 124 | template<> constexpr auto intsafe_conversion<__int64, char> = LongLongToChar; 125 | template<> constexpr auto intsafe_conversion<__int64, int> = LongLongToInt; 126 | template<> constexpr auto intsafe_conversion<__int64, long> = LongLongToLong; 127 | template<> constexpr auto intsafe_conversion<__int64, short> = LongLongToShort; 128 | template<> constexpr auto intsafe_conversion<__int64, signed char> = LongLongToInt8; 129 | template<> constexpr auto intsafe_conversion<__int64, unsigned __int64> = LongLongToULongLong; 130 | template<> constexpr auto intsafe_conversion<__int64, unsigned char> = LongLongToUChar; 131 | template<> constexpr auto intsafe_conversion<__int64, unsigned int> = LongLongToUInt; 132 | template<> constexpr auto intsafe_conversion<__int64, unsigned long> = LongLongToULong; 133 | template<> constexpr auto intsafe_conversion<__int64, unsigned short> = LongLongToUShort; 134 | template<> constexpr auto intsafe_conversion = IntToChar; 135 | template<> constexpr auto intsafe_conversion = IntToShort; 136 | template<> constexpr auto intsafe_conversion = IntToInt8; 137 | template<> constexpr auto intsafe_conversion = IntToULongLong; 138 | template<> constexpr auto intsafe_conversion = IntToUChar; 139 | template<> constexpr auto intsafe_conversion = IntToUInt; 140 | template<> constexpr auto intsafe_conversion = IntToULong; 141 | template<> constexpr auto intsafe_conversion = IntToUShort; 142 | template<> constexpr auto intsafe_conversion = LongToChar; 143 | template<> constexpr auto intsafe_conversion = LongToInt; 144 | template<> constexpr auto intsafe_conversion = LongToShort; 145 | template<> constexpr auto intsafe_conversion = LongToInt8; 146 | template<> constexpr auto intsafe_conversion = LongToULongLong; 147 | template<> constexpr auto intsafe_conversion = LongToUChar; 148 | template<> constexpr auto intsafe_conversion = LongToUInt; 149 | template<> constexpr auto intsafe_conversion = LongToULong; 150 | template<> constexpr auto intsafe_conversion = LongToUShort; 151 | template<> constexpr auto intsafe_conversion = ShortToChar; 152 | template<> constexpr auto intsafe_conversion = ShortToInt8; 153 | template<> constexpr auto intsafe_conversion = ShortToULongLong; 154 | template<> constexpr auto intsafe_conversion = ShortToUChar; 155 | template<> constexpr auto intsafe_conversion = ShortToUInt; 156 | template<> constexpr auto intsafe_conversion = ShortToULong; 157 | template<> constexpr auto intsafe_conversion = ShortToUShort; 158 | template<> constexpr auto intsafe_conversion = Int8ToULongLong; 159 | template<> constexpr auto intsafe_conversion = Int8ToUChar; 160 | template<> constexpr auto intsafe_conversion = Int8ToUInt; 161 | template<> constexpr auto intsafe_conversion = Int8ToULong; 162 | template<> constexpr auto intsafe_conversion = Int8ToUShort; 163 | template<> constexpr auto intsafe_conversion = ULongLongToLongLong; 164 | template<> constexpr auto intsafe_conversion = ULongLongToChar; 165 | template<> constexpr auto intsafe_conversion = ULongLongToInt; 166 | template<> constexpr auto intsafe_conversion = ULongLongToLong; 167 | template<> constexpr auto intsafe_conversion = ULongLongToShort; 168 | template<> constexpr auto intsafe_conversion = ULongLongToInt8; 169 | template<> constexpr auto intsafe_conversion = ULongLongToUChar; 170 | template<> constexpr auto intsafe_conversion = ULongLongToUInt; 171 | template<> constexpr auto intsafe_conversion = ULongLongToULong; 172 | template<> constexpr auto intsafe_conversion = ULongLongToUShort; 173 | template<> constexpr auto intsafe_conversion = UInt8ToChar; 174 | template<> constexpr auto intsafe_conversion = UIntToInt8; 175 | template<> constexpr auto intsafe_conversion = UIntToChar; 176 | template<> constexpr auto intsafe_conversion = UIntToInt; 177 | template<> constexpr auto intsafe_conversion = UIntToLong; 178 | template<> constexpr auto intsafe_conversion = UIntToShort; 179 | template<> constexpr auto intsafe_conversion = UIntToInt8; 180 | template<> constexpr auto intsafe_conversion = UIntToUChar; 181 | template<> constexpr auto intsafe_conversion = UIntToUShort; 182 | template<> constexpr auto intsafe_conversion = ULongToChar; 183 | template<> constexpr auto intsafe_conversion = ULongToInt; 184 | template<> constexpr auto intsafe_conversion = ULongToLong; 185 | template<> constexpr auto intsafe_conversion = ULongToShort; 186 | template<> constexpr auto intsafe_conversion = ULongToInt8; 187 | template<> constexpr auto intsafe_conversion = ULongToUChar; 188 | template<> constexpr auto intsafe_conversion = ULongToUInt; 189 | template<> constexpr auto intsafe_conversion = ULongToUShort; 190 | template<> constexpr auto intsafe_conversion = UShortToChar; 191 | template<> constexpr auto intsafe_conversion = UShortToShort; 192 | template<> constexpr auto intsafe_conversion = UShortToInt8; 193 | template<> constexpr auto intsafe_conversion = UShortToUChar; 194 | } 195 | 196 | // Unsafe conversion where failure results in fail fast. 197 | template < 198 | typename NewT, 199 | typename OldT, 200 | wistd::enable_if_t, int> = 0 201 | > 202 | NewT safe_cast_failfast(const OldT var) 203 | { 204 | NewT newVar; 205 | FAIL_FAST_IF_FAILED((details::intsafe_conversion(var, &newVar))); 206 | return newVar; 207 | } 208 | 209 | // Unsafe conversion where failure results in fail fast. 210 | template < 211 | typename NewT, 212 | typename OldT, 213 | wistd::enable_if_t, int> = 0 214 | > 215 | NewT safe_cast_failfast(const OldT var) 216 | { 217 | NewT newVar; 218 | FAIL_FAST_IF_FAILED((details::intsafe_conversion(static_cast(var), &newVar))); 219 | return newVar; 220 | } 221 | 222 | // Unsafe conversion where failure results in fail fast. 223 | template < 224 | typename NewT, 225 | typename OldT, 226 | wistd::enable_if_t, int> = 0 227 | > 228 | NewT safe_cast_failfast(const OldT var) 229 | { 230 | unsigned short newVar; 231 | FAIL_FAST_IF_FAILED((details::intsafe_conversion(var, &newVar))); 232 | return static_cast<__wchar_t>(newVar); 233 | } 234 | 235 | // This conversion is always safe, therefore a static_cast is fine. 236 | template < 237 | typename NewT, 238 | typename OldT, 239 | wistd::enable_if_t, int> = 0 240 | > 241 | NewT safe_cast_failfast(const OldT var) 242 | { 243 | return static_cast(var); 244 | } 245 | 246 | #ifdef WIL_ENABLE_EXCEPTIONS 247 | // Unsafe conversion where failure results in a thrown exception. 248 | template < 249 | typename NewT, 250 | typename OldT, 251 | wistd::enable_if_t, int> = 0 252 | > 253 | NewT safe_cast(const OldT var) 254 | { 255 | NewT newVar; 256 | THROW_IF_FAILED((details::intsafe_conversion(var, &newVar))); 257 | return newVar; 258 | } 259 | 260 | // Unsafe conversion where failure results in a thrown exception. 261 | template < 262 | typename NewT, 263 | typename OldT, 264 | wistd::enable_if_t, int> = 0 265 | > 266 | NewT safe_cast(const OldT var) 267 | { 268 | NewT newVar; 269 | THROW_IF_FAILED((details::intsafe_conversion(static_cast(var), &newVar))); 270 | return newVar; 271 | } 272 | 273 | // Unsafe conversion where failure results in a thrown exception. 274 | template < 275 | typename NewT, 276 | typename OldT, 277 | wistd::enable_if_t, int> = 0 278 | > 279 | NewT safe_cast(const OldT var) 280 | { 281 | unsigned short newVar; 282 | THROW_IF_FAILED((details::intsafe_conversion(var, &newVar))); 283 | return static_cast<__wchar_t>(newVar); 284 | } 285 | 286 | // This conversion is always safe, therefore a static_cast is fine. 287 | template < 288 | typename NewT, 289 | typename OldT, 290 | wistd::enable_if_t, int> = 0 291 | > 292 | NewT safe_cast(const OldT var) 293 | { 294 | return static_cast(var); 295 | } 296 | #endif 297 | 298 | // This conversion is unsafe, therefore the two parameter version of safe_cast_nothrow must be used 299 | template < 300 | typename NewT, 301 | typename OldT, 302 | wistd::enable_if_t, int> = 0 303 | > 304 | NewT safe_cast_nothrow(const OldT /*var*/) 305 | { 306 | static_assert(!wistd::is_same_v, "This cast has the potential to fail, use the two parameter safe_cast_nothrow instead"); 307 | } 308 | 309 | // This conversion is always safe, therefore a static_cast is fine. 310 | template < 311 | typename NewT, 312 | typename OldT, 313 | wistd::enable_if_t, int> = 0 314 | > 315 | NewT safe_cast_nothrow(const OldT var) 316 | { 317 | return static_cast(var); 318 | } 319 | 320 | // Unsafe conversion where an HRESULT is returned. It is up to the callee to check and handle the HRESULT 321 | template < 322 | typename NewT, 323 | typename OldT, 324 | wistd::enable_if_t, int> = 0 325 | > 326 | HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult) 327 | { 328 | return details::intsafe_conversion(var, newTResult); 329 | } 330 | 331 | // Unsafe conversion where an HRESULT is returned. It is up to the callee to check and handle the HRESULT 332 | template < 333 | typename NewT, 334 | typename OldT, 335 | wistd::enable_if_t, int> = 0 336 | > 337 | HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult) 338 | { 339 | return details::intsafe_conversion(static_cast(var), newTResult); 340 | } 341 | 342 | // Unsafe conversion where an HRESULT is returned. It is up to the callee to check and handle the HRESULT 343 | template < 344 | typename NewT, 345 | typename OldT, 346 | wistd::enable_if_t, int> = 0 347 | > 348 | HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult) 349 | { 350 | return details::intsafe_conversion(var, reinterpret_cast(newTResult)); 351 | } 352 | 353 | // This conversion is always safe, therefore a static_cast is fine. If it can be determined the conversion 354 | // does not involve a variably sized type, then the compilation will fail and say the single parameter version 355 | // of safe_cast_nothrow should be used instead. 356 | template < 357 | typename NewT, 358 | typename OldT, 359 | wistd::enable_if_t, int> = 0 360 | > 361 | HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult) 362 | { 363 | static_assert(details::is_potentially_variably_sized_cast_v, "This cast is always safe; use safe_cast_nothrow(value) to avoid unnecessary error handling."); 364 | *newTResult = static_cast(var); 365 | return S_OK; 366 | } 367 | } 368 | 369 | #endif // __WIL_SAFECAST_INCLUDED 370 | -------------------------------------------------------------------------------- /source/wil/wistd_config.h: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | //===--------------------------- __config ---------------------------------===// 3 | // 4 | // The LLVM Compiler Infrastructure 5 | // 6 | // This file is dual licensed under the MIT and the University of Illinois Open 7 | // Source Licenses. See LICENSE.TXT for details. 8 | // 9 | //===----------------------------------------------------------------------===// 10 | 11 | // STL common functionality 12 | // 13 | // Some aspects of STL are core language concepts that should be used from all C++ code, regardless 14 | // of whether exceptions are enabled in the component. Common library code that expects to be used 15 | // from exception-free components want these concepts, but including STL headers directly introduces 16 | // friction as it requires components not using STL to declare their STL version. Doing so creates 17 | // ambiguity around whether STL use is safe in a particular component and implicitly brings in 18 | // a long list of headers (including ) which can create further ambiguity around throwing new 19 | // support (some routines pulled in may expect it). Secondarily, pulling in these headers also has 20 | // the potential to create naming conflicts or other implied dependencies. 21 | // 22 | // To promote the use of these core language concepts outside of STL-based binaries, this file is 23 | // selectively pulling those concepts *directly* from corresponding STL headers. The corresponding 24 | // "std::" namespace STL functions and types should be preferred over these in code that is bound to 25 | // STL. The implementation and naming of all functions are taken directly from STL, instead using 26 | // "wistd" (Windows Implementation std) as the namespace. 27 | // 28 | // Routines in this namespace should always be considered a reflection of the *current* STL implementation 29 | // of those routines. Updates from STL should be taken, but no "bugs" should be fixed here. 30 | // 31 | // New, exception-based code should not use this namespace, but instead should prefer the std:: implementation. 32 | // Only code that is not exception-based and libraries that expect to be utilized across both exception 33 | // and non-exception based code should utilize this functionality. 34 | 35 | // This header mimics libc++'s '__config' header to the extent necessary to get the wistd::* definitions compiling. Note 36 | // that this has a few key differences since libc++'s MSVC compatability is currently not functional and a bit behind 37 | 38 | #ifndef _WISTD_CONFIG_H_ 39 | #define _WISTD_CONFIG_H_ 40 | 41 | // DO NOT add *any* additional includes to this file -- there should be no dependencies from its usage 42 | #include // For size_t and other necessary types 43 | 44 | /// @cond 45 | #if defined(_MSC_VER) && !defined(__clang__) 46 | # if !defined(__WI_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 47 | # define __WI_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER 48 | # endif 49 | #endif 50 | 51 | #ifndef __WI_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER 52 | #pragma GCC system_header 53 | #endif 54 | 55 | #ifdef __GNUC__ 56 | # define __WI_GNUC_VER (__GNUC__ * 100 + __GNUC_MINOR__) 57 | // The __WI_GNUC_VER_NEW macro better represents the new GCC versioning scheme 58 | // introduced in GCC 5.0. 59 | # define __WI_GNUC_VER_NEW (__WI_GNUC_VER * 10 + __GNUC_PATCHLEVEL__) 60 | #else 61 | # define __WI_GNUC_VER 0 62 | # define __WI_GNUC_VER_NEW 0 63 | #endif 64 | 65 | // _MSVC_LANG is the more accurate way to get the C++ version in MSVC 66 | #if defined(_MSVC_LANG) && (_MSVC_LANG > __cplusplus) 67 | #define __WI_CPLUSPLUS _MSVC_LANG 68 | #else 69 | #define __WI_CPLUSPLUS __cplusplus 70 | #endif 71 | 72 | #ifndef __WI_LIBCPP_STD_VER 73 | # if __WI_CPLUSPLUS <= 201103L 74 | # define __WI_LIBCPP_STD_VER 11 75 | # elif __WI_CPLUSPLUS <= 201402L 76 | # define __WI_LIBCPP_STD_VER 14 77 | # elif __WI_CPLUSPLUS <= 201703L 78 | # define __WI_LIBCPP_STD_VER 17 79 | # else 80 | # define __WI_LIBCPP_STD_VER 18 // current year, or date of c++2a ratification 81 | # endif 82 | #endif // __WI_LIBCPP_STD_VER 83 | 84 | #if __WI_CPLUSPLUS < 201103L 85 | #define __WI_LIBCPP_CXX03_LANG 86 | #endif 87 | 88 | #if defined(__ELF__) 89 | # define __WI_LIBCPP_OBJECT_FORMAT_ELF 1 90 | #elif defined(__MACH__) 91 | # define __WI_LIBCPP_OBJECT_FORMAT_MACHO 1 92 | #elif defined(_WIN32) 93 | # define __WI_LIBCPP_OBJECT_FORMAT_COFF 1 94 | #elif defined(__wasm__) 95 | # define __WI_LIBCPP_OBJECT_FORMAT_WASM 1 96 | #else 97 | # error Unknown object file format 98 | #endif 99 | 100 | #if defined(__clang__) 101 | # define __WI_LIBCPP_COMPILER_CLANG 102 | #elif defined(__GNUC__) 103 | # define __WI_LIBCPP_COMPILER_GCC 104 | #elif defined(_MSC_VER) 105 | # define __WI_LIBCPP_COMPILER_MSVC 106 | #elif defined(__IBMCPP__) 107 | # define __WI_LIBCPP_COMPILER_IBM 108 | #endif 109 | 110 | // NOTE: MSVC, which is what we primarily target, is severly underrepresented in libc++ and checks such as 111 | // __has_feature(...) are always false for MSVC, even when the feature being tested _is_ present in MSVC. Therefore, we 112 | // instead modify all checks to be __WI_HAS_FEATURE_IS_UNION, etc., which provides the correct value for MSVC and falls 113 | // back to the __has_feature(...), etc. value otherwise. We intentionally leave '__has_feature', etc. undefined for MSVC 114 | // so that we don't accidentally use the incorrect behavior 115 | #ifndef __WI_LIBCPP_COMPILER_MSVC 116 | 117 | #ifndef __has_feature 118 | #define __has_feature(__x) 0 119 | #endif 120 | 121 | // '__is_identifier' returns '0' if '__x' is a reserved identifier provided by 122 | // the compiler and '1' otherwise. 123 | #ifndef __is_identifier 124 | #define __is_identifier(__x) 1 125 | #endif 126 | 127 | #ifndef __has_cpp_attribute 128 | #define __has_cpp_attribute(__x) 0 129 | #endif 130 | 131 | #ifndef __has_attribute 132 | #define __has_attribute(__x) 0 133 | #endif 134 | 135 | #ifndef __has_builtin 136 | #define __has_builtin(__x) 0 137 | #endif 138 | 139 | #if __has_feature(cxx_alignas) 140 | # define __WI_ALIGNAS_TYPE(x) alignas(x) 141 | # define __WI_ALIGNAS(x) alignas(x) 142 | #else 143 | # define __WI_ALIGNAS_TYPE(x) __attribute__((__aligned__(__alignof(x)))) 144 | # define __WI_ALIGNAS(x) __attribute__((__aligned__(x))) 145 | #endif 146 | 147 | #if __has_feature(cxx_explicit_conversions) || defined(__IBMCPP__) || \ 148 | (!defined(__WI_LIBCPP_CXX03_LANG) && defined(__GNUC__)) // All supported GCC versions 149 | # define __WI_LIBCPP_EXPLICIT explicit 150 | #else 151 | # define __WI_LIBCPP_EXPLICIT 152 | #endif 153 | 154 | #if __has_feature(cxx_attributes) 155 | # define __WI_LIBCPP_NORETURN [[noreturn]] 156 | #else 157 | # define __WI_LIBCPP_NORETURN __attribute__ ((noreturn)) 158 | #endif 159 | 160 | #define __WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS 161 | #define __WI_LIBCPP_SUPPRESS_NOEXCEPT_ANALYSIS 162 | 163 | // The __WI_LIBCPP_NODISCARD_ATTRIBUTE should only be used to define other 164 | // NODISCARD macros to the correct attribute. 165 | #if __has_cpp_attribute(nodiscard) 166 | # define __WI_LIBCPP_NODISCARD_ATTRIBUTE [[nodiscard]] 167 | #elif defined(__WI_LIBCPP_COMPILER_CLANG) && !defined(__WI_LIBCPP_CXX03_LANG) 168 | # define __WI_LIBCPP_NODISCARD_ATTRIBUTE [[clang::warn_unused_result]] 169 | #else 170 | // We can't use GCC's [[gnu::warn_unused_result]] and 171 | // __attribute__((warn_unused_result)), because GCC does not silence them via 172 | // (void) cast. 173 | # define __WI_LIBCPP_NODISCARD_ATTRIBUTE 174 | #endif 175 | 176 | #define __WI_HAS_FEATURE_IS_UNION __has_feature(is_union) 177 | #define __WI_HAS_FEATURE_IS_CLASS __has_feature(is_class) 178 | #define __WI_HAS_FEATURE_IS_ENUM __has_feature(is_enum) 179 | #define __WI_HAS_FEATURE_IS_CONVERTIBLE_TO __has_feature(is_convertible_to) 180 | #define __WI_HAS_FEATURE_IS_EMPTY __has_feature(is_empty) 181 | #define __WI_HAS_FEATURE_IS_POLYMORPHIC __has_feature(is_polymorphic) 182 | #define __WI_HAS_FEATURE_HAS_VIRTUAL_DESTRUCTOR __has_feature(has_virtual_destructor) 183 | #define __WI_HAS_FEATURE_REFERENCE_QUALIFIED_FUNCTIONS __has_feature(cxx_reference_qualified_functions) 184 | #define __WI_HAS_FEATURE_IS_CONSTRUCTIBLE __has_feature(is_constructible) 185 | #define __WI_HAS_FEATURE_IS_TRIVIALLY_CONSTRUCTIBLE __has_feature(is_trivially_constructible) 186 | #define __WI_HAS_FEATURE_IS_TRIVIALLY_ASSIGNABLE __has_feature(is_trivially_assignable) 187 | #define __WI_HAS_FEATURE_HAS_TRIVIAL_DESTRUCTOR __has_feature(has_trivial_destructor) 188 | #define __WI_HAS_FEATURE_NOEXCEPT __has_feature(cxx_noexcept) 189 | #define __WI_HAS_FEATURE_IS_POD __has_feature(is_pod) 190 | #define __WI_HAS_FEATURE_IS_STANDARD_LAYOUT __has_feature(is_standard_layout) 191 | #define __WI_HAS_FEATURE_IS_TRIVIALLY_COPYABLE __has_feature(is_trivially_copyable) 192 | #define __WI_HAS_FEATURE_IS_TRIVIAL __has_feature(is_trivial) 193 | #define __WI_HAS_FEATURE_HAS_TRIVIAL_CONSTRUCTOR __has_feature(has_trivial_constructor) || (__WI_GNUC_VER >= 403) 194 | #define __WI_HAS_FEATURE_HAS_NOTHROW_CONSTRUCTOR __has_feature(has_nothrow_constructor) || (__WI_GNUC_VER >= 403) 195 | #define __WI_HAS_FEATURE_HAS_NOTHROW_COPY __has_feature(has_nothrow_copy) || (__WI_GNUC_VER >= 403) 196 | #define __WI_HAS_FEATURE_HAS_NOTHROW_ASSIGN __has_feature(has_nothrow_assign) || (__WI_GNUC_VER >= 403) 197 | 198 | #if !(__has_feature(cxx_noexcept)) 199 | #define __WI_LIBCPP_HAS_NO_NOEXCEPT 200 | #endif 201 | 202 | #if !__is_identifier(__has_unique_object_representations) || __WI_GNUC_VER >= 700 203 | #define __WI_LIBCPP_HAS_UNIQUE_OBJECT_REPRESENTATIONS 204 | #endif 205 | 206 | #if !(__has_feature(cxx_variadic_templates)) 207 | #define __WI_LIBCPP_HAS_NO_VARIADICS 208 | #endif 209 | 210 | #if __has_feature(is_literal) || __WI_GNUC_VER >= 407 211 | #define __WI_LIBCPP_IS_LITERAL(T) __is_literal(T) 212 | #endif 213 | 214 | #if __has_feature(underlying_type) || __WI_GNUC_VER >= 407 215 | #define __WI_LIBCPP_UNDERLYING_TYPE(T) __underlying_type(T) 216 | #endif 217 | 218 | #if __has_feature(is_final) || __WI_GNUC_VER >= 407 219 | #define __WI_LIBCPP_HAS_IS_FINAL 220 | #endif 221 | 222 | #if __has_feature(is_base_of) || defined(__GNUC__) && __WI_GNUC_VER >= 403 223 | #define __WI_LIBCPP_HAS_IS_BASE_OF 224 | #endif 225 | 226 | #if __is_identifier(__is_aggregate) && (__WI_GNUC_VER_NEW < 7001) 227 | #define __WI_LIBCPP_HAS_NO_IS_AGGREGATE 228 | #endif 229 | 230 | #if !(__has_feature(cxx_rtti)) && !defined(__WI_LIBCPP_NO_RTTI) 231 | #define __WI_LIBCPP_NO_RTTI 232 | #endif 233 | 234 | #if !(__has_feature(cxx_variable_templates)) 235 | #define __WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES 236 | #endif 237 | 238 | #if !(__has_feature(cxx_relaxed_constexpr)) 239 | #define __WI_LIBCPP_HAS_NO_CXX14_CONSTEXPR 240 | #endif 241 | 242 | #if !__has_builtin(__builtin_addressof) && _GNUC_VER < 700 243 | #define __WI_LIBCPP_HAS_NO_BUILTIN_ADDRESSOF 244 | #endif 245 | 246 | #if __has_attribute(__no_sanitize__) && !defined(__WI_LIBCPP_COMPILER_GCC) 247 | # define __WI_LIBCPP_NO_CFI __attribute__((__no_sanitize__("cfi"))) 248 | #else 249 | # define __WI_LIBCPP_NO_CFI 250 | #endif 251 | 252 | #define __WI_LIBCPP_ALWAYS_INLINE __attribute__ ((__always_inline__)) 253 | 254 | #if __has_attribute(internal_linkage) 255 | # define __WI_LIBCPP_INTERNAL_LINKAGE __attribute__ ((internal_linkage)) 256 | #else 257 | # define __WI_LIBCPP_INTERNAL_LINKAGE __WI_LIBCPP_ALWAYS_INLINE 258 | #endif 259 | 260 | #else 261 | 262 | // NOTE: Much of the following assumes a decently recent version of MSVC. Past versions can be supported, but will need 263 | // to be updated to contain the proper _MSC_VER check 264 | #define __WI_ALIGNAS_TYPE(x) alignas(x) 265 | #define __WI_ALIGNAS(x) alignas(x) 266 | #define __alignof__ __alignof 267 | 268 | #define __WI_LIBCPP_EXPLICIT explicit 269 | #define __WI_LIBCPP_NORETURN [[noreturn]] 270 | #define __WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS __pragma(warning(suppress:26495)) 271 | #define __WI_LIBCPP_SUPPRESS_NOEXCEPT_ANALYSIS __pragma(warning(suppress:26439)) 272 | 273 | 274 | #if __WI_LIBCPP_STD_VER > 14 275 | #define __WI_LIBCPP_NODISCARD_ATTRIBUTE [[nodiscard]] 276 | #else 277 | #define __WI_LIBCPP_NODISCARD_ATTRIBUTE _Check_return_ 278 | #endif 279 | 280 | #define __WI_HAS_FEATURE_IS_UNION 1 281 | #define __WI_HAS_FEATURE_IS_CLASS 1 282 | #define __WI_HAS_FEATURE_IS_ENUM 1 283 | #define __WI_HAS_FEATURE_IS_CONVERTIBLE_TO 1 284 | #define __WI_HAS_FEATURE_IS_EMPTY 1 285 | #define __WI_HAS_FEATURE_IS_POLYMORPHIC 1 286 | #define __WI_HAS_FEATURE_HAS_VIRTUAL_DESTRUCTOR 1 287 | #define __WI_LIBCPP_HAS_UNIQUE_OBJECT_REPRESENTATIONS 1 288 | #define __WI_HAS_FEATURE_REFERENCE_QUALIFIED_FUNCTIONS 1 289 | #define __WI_HAS_FEATURE_IS_CONSTRUCTIBLE 1 290 | #define __WI_HAS_FEATURE_IS_TRIVIALLY_CONSTRUCTIBLE 1 291 | #define __WI_HAS_FEATURE_IS_TRIVIALLY_ASSIGNABLE 1 292 | #define __WI_HAS_FEATURE_HAS_TRIVIAL_DESTRUCTOR 1 293 | #define __WI_HAS_FEATURE_NOEXCEPT 1 294 | #define __WI_HAS_FEATURE_IS_POD 1 295 | #define __WI_HAS_FEATURE_IS_STANDARD_LAYOUT 1 296 | #define __WI_HAS_FEATURE_IS_TRIVIALLY_COPYABLE 1 297 | #define __WI_HAS_FEATURE_IS_TRIVIAL 1 298 | #define __WI_HAS_FEATURE_HAS_TRIVIAL_CONSTRUCTOR 1 299 | #define __WI_HAS_FEATURE_HAS_NOTHROW_CONSTRUCTOR 1 300 | #define __WI_HAS_FEATURE_HAS_NOTHROW_COPY 1 301 | #define __WI_HAS_FEATURE_HAS_NOTHROW_ASSIGN 1 302 | #define __WI_HAS_FEATURE_IS_DESTRUCTIBLE 1 303 | 304 | #if !defined(_CPPRTTI) && !defined(__WI_LIBCPP_NO_RTTI) 305 | #define __WI_LIBCPP_NO_RTTI 306 | #endif 307 | 308 | #define __WI_LIBCPP_IS_LITERAL(T) __is_literal_type(T) 309 | #define __WI_LIBCPP_UNDERLYING_TYPE(T) __underlying_type(T) 310 | #define __WI_LIBCPP_HAS_IS_FINAL 311 | #define __WI_LIBCPP_HAS_IS_BASE_OF 312 | 313 | #if __WI_LIBCPP_STD_VER < 14 314 | #define __WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES 315 | #endif 316 | 317 | #define __WI_LIBCPP_HAS_NO_BUILTIN_ADDRESSOF 318 | #define __WI_LIBCPP_NO_CFI 319 | 320 | #define __WI_LIBCPP_ALWAYS_INLINE __forceinline 321 | #define __WI_LIBCPP_INTERNAL_LINKAGE 322 | 323 | #endif 324 | 325 | #ifndef _WIN32 326 | 327 | #ifdef __LITTLE_ENDIAN__ 328 | # if __LITTLE_ENDIAN__ 329 | # define __WI_LIBCPP_LITTLE_ENDIAN 330 | # endif // __LITTLE_ENDIAN__ 331 | #endif // __LITTLE_ENDIAN__ 332 | 333 | #ifdef __BIG_ENDIAN__ 334 | # if __BIG_ENDIAN__ 335 | # define __WI_LIBCPP_BIG_ENDIAN 336 | # endif // __BIG_ENDIAN__ 337 | #endif // __BIG_ENDIAN__ 338 | 339 | #ifdef __BYTE_ORDER__ 340 | # if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 341 | # define __WI_LIBCPP_LITTLE_ENDIAN 342 | # elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 343 | # define __WI_LIBCPP_BIG_ENDIAN 344 | # endif // __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 345 | #endif // __BYTE_ORDER__ 346 | 347 | #if !defined(__WI_LIBCPP_LITTLE_ENDIAN) && !defined(__WI_LIBCPP_BIG_ENDIAN) 348 | # include 349 | # if __BYTE_ORDER == __LITTLE_ENDIAN 350 | # define __WI_LIBCPP_LITTLE_ENDIAN 351 | # elif __BYTE_ORDER == __BIG_ENDIAN 352 | # define __WI_LIBCPP_BIG_ENDIAN 353 | # else // __BYTE_ORDER == __BIG_ENDIAN 354 | # error unable to determine endian 355 | # endif 356 | #endif // !defined(__WI_LIBCPP_LITTLE_ENDIAN) && !defined(__WI_LIBCPP_BIG_ENDIAN) 357 | 358 | #else // _WIN32 359 | 360 | #define __WI_LIBCPP_LITTLE_ENDIAN 361 | 362 | #endif // _WIN32 363 | 364 | #ifdef __WI_LIBCPP_HAS_NO_CONSTEXPR 365 | # define __WI_LIBCPP_CONSTEXPR 366 | #else 367 | # define __WI_LIBCPP_CONSTEXPR constexpr 368 | #endif 369 | 370 | #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_CXX14_CONSTEXPR) 371 | # define __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 constexpr 372 | #else 373 | # define __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 374 | #endif 375 | 376 | #if __WI_LIBCPP_STD_VER > 14 && !defined(__WI_LIBCPP_HAS_NO_CXX14_CONSTEXPR) 377 | # define __WI_LIBCPP_CONSTEXPR_AFTER_CXX14 constexpr 378 | #else 379 | # define __WI_LIBCPP_CONSTEXPR_AFTER_CXX14 380 | #endif 381 | 382 | #if __WI_LIBCPP_STD_VER > 17 && !defined(__WI_LIBCPP_HAS_NO_CXX14_CONSTEXPR) 383 | # define __WI_LIBCPP_CONSTEXPR_AFTER_CXX17 constexpr 384 | #else 385 | # define __WI_LIBCPP_CONSTEXPR_AFTER_CXX17 386 | #endif 387 | 388 | #if !defined(__WI_LIBCPP_DISABLE_NODISCARD_AFTER_CXX17) && \ 389 | (__WI_LIBCPP_STD_VER > 17 || defined(__WI_LIBCPP_ENABLE_NODISCARD)) 390 | # define __WI_LIBCPP_NODISCARD_AFTER_CXX17 __WI_LIBCPP_NODISCARD_ATTRIBUTE 391 | #else 392 | # define __WI_LIBCPP_NODISCARD_AFTER_CXX17 393 | #endif 394 | 395 | #if __WI_LIBCPP_STD_VER > 14 && defined(__cpp_inline_variables) && (__cpp_inline_variables >= 201606L) 396 | # define __WI_LIBCPP_INLINE_VAR inline 397 | #else 398 | # define __WI_LIBCPP_INLINE_VAR 399 | #endif 400 | 401 | #ifdef __WI_LIBCPP_CXX03_LANG 402 | #define __WI_LIBCPP_HAS_NO_UNICODE_CHARS 403 | #define __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES 404 | #endif 405 | 406 | #ifndef __SIZEOF_INT128__ 407 | #define __WI_LIBCPP_HAS_NO_INT128 408 | #endif 409 | 410 | #if !__WI_HAS_FEATURE_NOEXCEPT && !defined(__WI_LIBCPP_HAS_NO_NOEXCEPT) 411 | #define __WI_LIBCPP_HAS_NO_NOEXCEPT 412 | #endif 413 | 414 | #ifndef __WI_LIBCPP_HAS_NO_NOEXCEPT 415 | # define WI_NOEXCEPT noexcept 416 | # define __WI_NOEXCEPT_(x) noexcept(x) 417 | #else 418 | # define WI_NOEXCEPT throw() 419 | # define __WI_NOEXCEPT_(x) 420 | #endif 421 | 422 | #if defined(__WI_LIBCPP_OBJECT_FORMAT_COFF) 423 | #define __WI_LIBCPP_HIDDEN 424 | #define __WI_LIBCPP_TEMPLATE_VIS 425 | #endif // defined(__WI_LIBCPP_OBJECT_FORMAT_COFF) 426 | 427 | #ifndef __WI_LIBCPP_HIDDEN 428 | # if !defined(__WI_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS) 429 | # define __WI_LIBCPP_HIDDEN __attribute__ ((__visibility__("hidden"))) 430 | # else 431 | # define __WI_LIBCPP_HIDDEN 432 | # endif 433 | #endif 434 | 435 | #ifndef __WI_LIBCPP_TEMPLATE_VIS 436 | # if !defined(__WI_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS) && !defined(__WI_LIBCPP_COMPILER_MSVC) 437 | # if __has_attribute(__type_visibility__) 438 | # define __WI_LIBCPP_TEMPLATE_VIS __attribute__ ((__type_visibility__("default"))) 439 | # else 440 | # define __WI_LIBCPP_TEMPLATE_VIS __attribute__ ((__visibility__("default"))) 441 | # endif 442 | # else 443 | # define __WI_LIBCPP_TEMPLATE_VIS 444 | # endif 445 | #endif 446 | 447 | #define __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_HIDDEN __WI_LIBCPP_INTERNAL_LINKAGE 448 | 449 | namespace wistd // ("Windows Implementation" std) 450 | { 451 | typedef decltype(__nullptr) nullptr_t; 452 | 453 | template 454 | struct __less 455 | { 456 | __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 457 | bool operator()(const _T1& __x, const _T1& __y) const {return __x < __y;} 458 | 459 | __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 460 | bool operator()(const _T1& __x, const _T2& __y) const {return __x < __y;} 461 | 462 | __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 463 | bool operator()(const _T2& __x, const _T1& __y) const {return __x < __y;} 464 | 465 | __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 466 | bool operator()(const _T2& __x, const _T2& __y) const {return __x < __y;} 467 | }; 468 | 469 | template 470 | struct __less<_T1, _T1> 471 | { 472 | __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 473 | bool operator()(const _T1& __x, const _T1& __y) const {return __x < __y;} 474 | }; 475 | 476 | template 477 | struct __less 478 | { 479 | __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 480 | bool operator()(const _T1& __x, const _T1& __y) const {return __x < __y;} 481 | }; 482 | 483 | template 484 | struct __less<_T1, const _T1> 485 | { 486 | __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 487 | bool operator()(const _T1& __x, const _T1& __y) const {return __x < __y;} 488 | }; 489 | 490 | // These are added to wistd to enable use of min/max without having to use the windows.h min/max 491 | // macros that some clients might not have access to. Note: the STL versions of these have debug 492 | // checking for the less than operator and support for iterators that these implementations lack. 493 | // Use the STL versions when you require use of those features. 494 | 495 | // min 496 | 497 | template 498 | inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 499 | const _Tp& 500 | (min)(const _Tp& __a, const _Tp& __b, _Compare __comp) 501 | { 502 | return __comp(__b, __a) ? __b : __a; 503 | } 504 | 505 | template 506 | inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 507 | const _Tp& 508 | (min)(const _Tp& __a, const _Tp& __b) 509 | { 510 | return (min)(__a, __b, __less<_Tp>()); 511 | } 512 | 513 | // max 514 | 515 | template 516 | inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 517 | const _Tp& 518 | (max)(const _Tp& __a, const _Tp& __b, _Compare __comp) 519 | { 520 | return __comp(__a, __b) ? __b : __a; 521 | } 522 | 523 | template 524 | inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 525 | const _Tp& 526 | (max)(const _Tp& __a, const _Tp& __b) 527 | { 528 | return (max)(__a, __b, __less<_Tp>()); 529 | } 530 | 531 | template 532 | struct __WI_LIBCPP_TEMPLATE_VIS unary_function 533 | { 534 | typedef _Arg argument_type; 535 | typedef _Result result_type; 536 | }; 537 | 538 | template 539 | struct __WI_LIBCPP_TEMPLATE_VIS binary_function 540 | { 541 | typedef _Arg1 first_argument_type; 542 | typedef _Arg2 second_argument_type; 543 | typedef _Result result_type; 544 | }; 545 | } 546 | /// @endcond 547 | 548 | #endif _WISTD_CONFIG_H_ 549 | -------------------------------------------------------------------------------- /source/WrappedDXGI.cpp: -------------------------------------------------------------------------------- 1 | #include "WrappedDXGI.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "imgui/imgui.h" 7 | #include "imgui/imgui_impl_win32.h" 8 | #include "imgui/imgui_impl_dx11.h" 9 | 10 | #include "effects/Metadata.h" 11 | 12 | extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); 13 | 14 | // Functions specific to ImGui 15 | namespace UI 16 | { 17 | 18 | static bool imguiInitialized = false; 19 | static WNDPROC orgWndProc; 20 | LRESULT WINAPI UIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 21 | { 22 | LRESULT imguiResult = ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam); 23 | if ( imguiResult != 0 ) return imguiResult; 24 | 25 | const ImGuiIO& io = ImGui::GetIO(); 26 | const bool captureMouse = io.WantCaptureMouse || io.MouseDrawCursor; 27 | const bool captureKeyboard = io.WantCaptureKeyboard; 28 | if ( captureMouse || captureKeyboard ) 29 | { 30 | if ( captureMouse && (msg >= WM_MOUSEFIRST && msg <= WM_MOUSELAST) ) return imguiResult; 31 | if ( captureKeyboard && (msg >= WM_KEYFIRST && msg <= WM_KEYLAST) ) return imguiResult; 32 | 33 | // Filter Raw Input 34 | if ( msg == WM_INPUT ) 35 | { 36 | RAWINPUTHEADER header; 37 | UINT size = sizeof(header); 38 | 39 | if ( GetRawInputData( reinterpret_cast(lParam), RID_HEADER, &header, &size, sizeof(RAWINPUTHEADER) ) != -1 ) 40 | { 41 | if ( (captureMouse && header.dwType == RIM_TYPEMOUSE) || (captureKeyboard && header.dwType == RIM_TYPEKEYBOARD) ) 42 | { 43 | // Let the OS perform cleanup 44 | return DefWindowProc(hWnd, msg, wParam, lParam); 45 | } 46 | } 47 | } 48 | } 49 | 50 | return CallWindowProc(orgWndProc, hWnd, msg, wParam, lParam); 51 | } 52 | 53 | static void SetUpImGuiStyle() 54 | { 55 | ImGuiStyle* style = &ImGui::GetStyle(); 56 | ImVec4* colors = style->Colors; 57 | 58 | colors[ImGuiCol_Text] = ImVec4(0.92f, 0.92f, 0.92f, 1.00f); 59 | colors[ImGuiCol_TextDisabled] = ImVec4(0.44f, 0.44f, 0.44f, 1.00f); 60 | colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 1.00f); 61 | colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); 62 | colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f); 63 | colors[ImGuiCol_Border] = ImVec4(0.51f, 0.36f, 0.15f, 1.00f); 64 | colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); 65 | colors[ImGuiCol_FrameBg] = ImVec4(0.11f, 0.11f, 0.11f, 1.00f); 66 | colors[ImGuiCol_FrameBgHovered] = ImVec4(0.51f, 0.36f, 0.15f, 1.00f); 67 | colors[ImGuiCol_FrameBgActive] = ImVec4(0.78f, 0.55f, 0.21f, 1.00f); 68 | colors[ImGuiCol_TitleBg] = ImVec4(0.51f, 0.36f, 0.15f, 1.00f); 69 | colors[ImGuiCol_TitleBgActive] = ImVec4(0.91f, 0.64f, 0.13f, 1.00f); 70 | colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f); 71 | colors[ImGuiCol_MenuBarBg] = ImVec4(0.11f, 0.11f, 0.11f, 1.00f); 72 | colors[ImGuiCol_ScrollbarBg] = ImVec4(0.06f, 0.06f, 0.06f, 0.53f); 73 | colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.21f, 0.21f, 0.21f, 1.00f); 74 | colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.47f, 0.47f, 0.47f, 1.00f); 75 | colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.81f, 0.83f, 0.81f, 1.00f); 76 | colors[ImGuiCol_CheckMark] = ImVec4(0.78f, 0.55f, 0.21f, 1.00f); 77 | colors[ImGuiCol_SliderGrab] = ImVec4(0.91f, 0.64f, 0.13f, 1.00f); 78 | colors[ImGuiCol_SliderGrabActive] = ImVec4(0.91f, 0.64f, 0.13f, 1.00f); 79 | colors[ImGuiCol_Button] = ImVec4(0.51f, 0.36f, 0.15f, 1.00f); 80 | colors[ImGuiCol_ButtonHovered] = ImVec4(0.91f, 0.64f, 0.13f, 1.00f); 81 | colors[ImGuiCol_ButtonActive] = ImVec4(0.78f, 0.55f, 0.21f, 1.00f); 82 | colors[ImGuiCol_Header] = ImVec4(0.51f, 0.36f, 0.15f, 1.00f); 83 | colors[ImGuiCol_HeaderHovered] = ImVec4(0.91f, 0.64f, 0.13f, 1.00f); 84 | colors[ImGuiCol_HeaderActive] = ImVec4(0.93f, 0.65f, 0.14f, 1.00f); 85 | colors[ImGuiCol_Separator] = ImVec4(0.21f, 0.21f, 0.21f, 1.00f); 86 | colors[ImGuiCol_SeparatorHovered] = ImVec4(0.91f, 0.64f, 0.13f, 1.00f); 87 | colors[ImGuiCol_SeparatorActive] = ImVec4(0.78f, 0.55f, 0.21f, 1.00f); 88 | colors[ImGuiCol_ResizeGrip] = ImVec4(0.21f, 0.21f, 0.21f, 1.00f); 89 | colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.91f, 0.64f, 0.13f, 1.00f); 90 | colors[ImGuiCol_ResizeGripActive] = ImVec4(0.78f, 0.55f, 0.21f, 1.00f); 91 | colors[ImGuiCol_Tab] = ImVec4(0.51f, 0.36f, 0.15f, 1.00f); 92 | colors[ImGuiCol_TabHovered] = ImVec4(0.91f, 0.64f, 0.13f, 1.00f); 93 | colors[ImGuiCol_TabActive] = ImVec4(0.78f, 0.55f, 0.21f, 1.00f); 94 | colors[ImGuiCol_TabUnfocused] = ImVec4(0.07f, 0.10f, 0.15f, 0.97f); 95 | colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.14f, 0.26f, 0.42f, 1.00f); 96 | colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f); 97 | colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); 98 | colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); 99 | colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); 100 | colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); 101 | colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); 102 | colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); 103 | colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); 104 | colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); 105 | colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f); 106 | 107 | style->FramePadding = ImVec2(4, 2); 108 | style->ItemSpacing = ImVec2(10, 2); 109 | style->IndentSpacing = 12; 110 | style->ScrollbarSize = 10; 111 | 112 | style->WindowRounding = 4; 113 | style->FrameRounding = 4; 114 | style->PopupRounding = 4; 115 | style->ScrollbarRounding = 6; 116 | style->GrabRounding = 4; 117 | style->TabRounding = 4; 118 | 119 | style->WindowTitleAlign = ImVec2(1.0f, 0.5f); 120 | style->WindowMenuButtonPosition = ImGuiDir_Right; 121 | 122 | style->DisplaySafeAreaPadding = ImVec2(4, 4); 123 | } 124 | 125 | } 126 | 127 | extern HMODULE WINAPI LoadLibraryA_DXHR( LPCSTR lpLibFileName ); 128 | 129 | HRESULT WINAPI CreateDXGIFactory_Export( REFIID riid, void** ppFactory ) 130 | { 131 | *ppFactory = nullptr; 132 | 133 | // Try to load a real dxgi.dll, DXGIFactory will claim ownership of its reference if created successfully 134 | wil::unique_hmodule dxgiModule( LoadLibraryA_DXHR("dxgi") ); 135 | if ( dxgiModule.is_valid() ) 136 | { 137 | auto factoryFn = reinterpret_cast(GetProcAddress( dxgiModule.get(), "CreateDXGIFactory" )); 138 | if ( factoryFn != nullptr ) 139 | { 140 | ComPtr factory; 141 | HRESULT hr = factoryFn( IID_PPV_ARGS(factory.GetAddressOf()) ); 142 | if ( SUCCEEDED(hr) ) 143 | { 144 | ComPtr wrappedFactory = Make( std::move(dxgiModule), std::move(factory) ); 145 | wrappedFactory.CopyTo( riid, ppFactory ); 146 | } 147 | return hr; 148 | } 149 | } 150 | 151 | return DXGI_ERROR_SDK_COMPONENT_MISSING; // If either LoadLibrary or GetProcAddress fails 152 | } 153 | 154 | // ==================================================== 155 | 156 | DXGIFactory::DXGIFactory(wil::unique_hmodule module, ComPtr factory) 157 | : m_dxgiModule( std::move(module), factory ), m_orig( std::move(factory) ) 158 | { 159 | } 160 | 161 | HRESULT STDMETHODCALLTYPE DXGIFactory::QueryInterface(REFIID riid, void** ppvObject) 162 | { 163 | HRESULT hr = __super::QueryInterface(riid, ppvObject); 164 | if ( FAILED(hr) ) 165 | { 166 | hr = m_orig->QueryInterface(riid, ppvObject); 167 | } 168 | return hr; 169 | } 170 | 171 | HRESULT STDMETHODCALLTYPE DXGIFactory::SetPrivateData(REFGUID Name, UINT DataSize, const void* pData) 172 | { 173 | return m_orig->SetPrivateData(Name, DataSize, pData); 174 | } 175 | 176 | HRESULT STDMETHODCALLTYPE DXGIFactory::SetPrivateDataInterface(REFGUID Name, const IUnknown* pUnknown) 177 | { 178 | return m_orig->SetPrivateDataInterface(Name, pUnknown); 179 | } 180 | 181 | HRESULT STDMETHODCALLTYPE DXGIFactory::GetPrivateData(REFGUID Name, UINT* pDataSize, void* pData) 182 | { 183 | return m_orig->GetPrivateData(Name, pDataSize, pData); 184 | } 185 | 186 | HRESULT STDMETHODCALLTYPE DXGIFactory::GetParent(REFIID riid, void** ppParent) 187 | { 188 | return m_orig->GetParent(riid, ppParent); 189 | } 190 | 191 | HRESULT STDMETHODCALLTYPE DXGIFactory::EnumAdapters(UINT Adapter, IDXGIAdapter** ppAdapter) 192 | { 193 | return m_orig->EnumAdapters(Adapter, ppAdapter); 194 | } 195 | 196 | HRESULT STDMETHODCALLTYPE DXGIFactory::MakeWindowAssociation(HWND WindowHandle, UINT Flags) 197 | { 198 | return m_orig->MakeWindowAssociation(WindowHandle, Flags); 199 | } 200 | 201 | HRESULT STDMETHODCALLTYPE DXGIFactory::GetWindowAssociation(HWND* pWindowHandle) 202 | { 203 | return m_orig->GetWindowAssociation(pWindowHandle); 204 | } 205 | 206 | HRESULT STDMETHODCALLTYPE DXGIFactory::CreateSwapChain(IUnknown* pDevice, DXGI_SWAP_CHAIN_DESC* pDesc, IDXGISwapChain** ppSwapChain) 207 | { 208 | if ( pDevice == nullptr || pDesc == nullptr || ppSwapChain == nullptr ) return DXGI_ERROR_INVALID_CALL; 209 | *ppSwapChain = nullptr; 210 | 211 | ComPtr swapChain; 212 | HRESULT hr = S_OK; 213 | bool created = false; 214 | 215 | ComPtr wrapper; 216 | if ( SUCCEEDED(pDevice->QueryInterface(IID_PPV_ARGS(wrapper.GetAddressOf()))) ) 217 | { 218 | ComPtr underlyingInterface; 219 | if ( SUCCEEDED(wrapper->GetUnderlyingInterface(IID_PPV_ARGS(underlyingInterface.GetAddressOf()))) ) 220 | { 221 | hr = m_orig->CreateSwapChain(underlyingInterface.Get(), pDesc, swapChain.GetAddressOf()); 222 | created = true; 223 | } 224 | } 225 | 226 | if ( !created ) 227 | { 228 | hr = m_orig->CreateSwapChain(pDevice, pDesc, swapChain.GetAddressOf()); 229 | } 230 | 231 | if ( SUCCEEDED(hr) ) 232 | { 233 | ComPtr wrappedSwapChain = Make( std::move(swapChain), this, pDevice, pDesc ); 234 | *ppSwapChain = wrappedSwapChain.Detach(); 235 | } 236 | return hr; 237 | } 238 | 239 | HRESULT STDMETHODCALLTYPE DXGIFactory::CreateSoftwareAdapter(HMODULE Module, IDXGIAdapter** ppAdapter) 240 | { 241 | return m_orig->CreateSoftwareAdapter(Module, ppAdapter); 242 | } 243 | 244 | HRESULT STDMETHODCALLTYPE DXGIFactory::GetUnderlyingInterface(REFIID riid, void** ppvObject) 245 | { 246 | return m_orig.CopyTo(riid, ppvObject); 247 | } 248 | 249 | // ==================================================== 250 | 251 | DXGISwapChain::DXGISwapChain(ComPtr swapChain, ComPtr factory, ComPtr device, const DXGI_SWAP_CHAIN_DESC* desc) 252 | : m_factory( std::move(factory) ), m_device( std::move(device) ), m_orig( std::move(swapChain) ) 253 | { 254 | // We set up Dear Imgui in swapchain constructor, don't tear it down as it's pointless 255 | if ( !std::exchange(UI::imguiInitialized, true) ) 256 | { 257 | IMGUI_CHECKVERSION(); 258 | ImGui::CreateContext(); 259 | 260 | ImGuiIO& io = ImGui::GetIO(); 261 | io.IniFilename = nullptr; 262 | io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange; 263 | 264 | // Setup Dear ImGui style 265 | UI::SetUpImGuiStyle(); 266 | 267 | // Hook into the window proc 268 | UI::orgWndProc = reinterpret_cast(GetWindowLongPtr( desc->OutputWindow, GWLP_WNDPROC )); 269 | SetWindowLongPtr( desc->OutputWindow, GWLP_WNDPROC, reinterpret_cast(UI::UIWndProc) ); 270 | } 271 | 272 | // Setup Platform/Renderer bindings 273 | ImGui_ImplWin32_Init(desc->OutputWindow); 274 | 275 | ComPtr d3dDevice; 276 | if ( SUCCEEDED(m_device.As(&d3dDevice)) ) 277 | { 278 | ComPtr d3dDeviceContext; 279 | d3dDevice->GetImmediateContext( d3dDeviceContext.GetAddressOf() ); 280 | 281 | ImGui_ImplDX11_Init(d3dDevice.Get(), d3dDeviceContext.Get()); // Init holds a reference to both 282 | } 283 | 284 | // Immediately start a new frame - we'll be starting new frames after each Present 285 | ImGui_ImplDX11_NewFrame(); 286 | ImGui_ImplWin32_NewFrame(); 287 | ImGui::NewFrame(); 288 | } 289 | 290 | DXGISwapChain::~DXGISwapChain() 291 | { 292 | ImGui::EndFrame(); 293 | 294 | ImGui_ImplDX11_Shutdown(); 295 | ImGui_ImplWin32_Shutdown(); 296 | } 297 | 298 | HRESULT STDMETHODCALLTYPE DXGISwapChain::QueryInterface(REFIID riid, void** ppvObject) 299 | { 300 | HRESULT hr = __super::QueryInterface(riid, ppvObject); 301 | if ( FAILED(hr) ) 302 | { 303 | hr = m_orig->QueryInterface(riid, ppvObject); 304 | } 305 | return hr; 306 | } 307 | 308 | HRESULT STDMETHODCALLTYPE DXGISwapChain::SetPrivateData(REFGUID Name, UINT DataSize, const void* pData) 309 | { 310 | return m_orig->SetPrivateData(Name, DataSize, pData); 311 | } 312 | 313 | HRESULT STDMETHODCALLTYPE DXGISwapChain::SetPrivateDataInterface(REFGUID Name, const IUnknown* pUnknown) 314 | { 315 | return m_orig->SetPrivateDataInterface(Name, pUnknown); 316 | } 317 | 318 | HRESULT STDMETHODCALLTYPE DXGISwapChain::GetPrivateData(REFGUID Name, UINT* pDataSize, void* pData) 319 | { 320 | return m_orig->GetPrivateData(Name, pDataSize, pData); 321 | } 322 | 323 | HRESULT STDMETHODCALLTYPE DXGISwapChain::GetParent(REFIID riid, void** ppParent) 324 | { 325 | return m_factory.CopyTo(riid, ppParent); 326 | } 327 | 328 | HRESULT STDMETHODCALLTYPE DXGISwapChain::GetDevice(REFIID riid, void** ppDevice) 329 | { 330 | return m_device.CopyTo(riid, ppDevice); 331 | } 332 | 333 | HRESULT STDMETHODCALLTYPE DXGISwapChain::Present(UINT SyncInterval, UINT Flags) 334 | { 335 | // Draw all UI widgets 336 | { 337 | using namespace Effects; 338 | 339 | ImGuiIO& io = ImGui::GetIO(); 340 | 341 | static bool keyPressed = false; 342 | if ( io.KeysDown[VK_F11] ) 343 | { 344 | if ( !keyPressed ) 345 | { 346 | SETTINGS.isShown = !SETTINGS.isShown; 347 | keyPressed = true; 348 | } 349 | } 350 | else 351 | { 352 | keyPressed = false; 353 | } 354 | 355 | if ( SETTINGS.isShown ) 356 | { 357 | //ImGui::ShowDemoWindow(); 358 | constexpr float DIST_FROM_CORNER = 20.0f; 359 | const ImVec2 window_pos = ImVec2(io.DisplaySize.x - DIST_FROM_CORNER, DIST_FROM_CORNER); 360 | ImGui::SetNextWindowPos(window_pos, ImGuiCond_Once, ImVec2(1.0f, 0.0f)); 361 | if ( ImGui::Begin( "DXHRDC-GFX Settings", &SETTINGS.isShown, ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_AlwaysVerticalScrollbar ) ) 362 | { 363 | bool needsToSave = false; 364 | 365 | int id = 0; 366 | 367 | needsToSave |= ImGui::Checkbox("Enable Gold Filter", &SETTINGS.colorGradingEnabled); 368 | 369 | ImGui::PushID(id++); 370 | ImGui::Text( "Bloom Style" ); 371 | needsToSave |= ImGui::RadioButton("DX:HR", &SETTINGS.bloomType, 1); ImGui::SameLine(); 372 | needsToSave |= ImGui::RadioButton("DX:HR DC", &SETTINGS.bloomType, 0); 373 | ImGui::PopID(); 374 | 375 | ImGui::PushID(id++); 376 | ImGui::Text( "Lighting Style" ); 377 | needsToSave |= ImGui::RadioButton("DX:HR", &SETTINGS.lightingType, 2); 378 | needsToSave |= ImGui::RadioButton("DX:HR DC (Fixed)", &SETTINGS.lightingType, 1); ImGui::SameLine(); 379 | needsToSave |= ImGui::RadioButton("DX:HR DC", &SETTINGS.lightingType, 0); 380 | ImGui::PopID(); 381 | 382 | ImGui::Separator(); 383 | 384 | if ( SETTINGS.colorGradingEnabled ) 385 | { 386 | bool colorGradingDirty = false; 387 | 388 | ImGui::Text( "Gold Filter Settings:" ); 389 | 390 | // Presets 391 | const int curPreset = GetSelectedPreset( SETTINGS.colorGradingAttributes ); 392 | 393 | const int numPresets = _countof( COLOR_GRADING_PRESETS ); 394 | for ( int i = 0; i < numPresets; i++ ) 395 | { 396 | char buf[16]; 397 | sprintf_s( buf, "Preset %u", i + 1 ); 398 | if ( ImGui::RadioButton( buf, curPreset == i ) ) 399 | { 400 | memcpy( &SETTINGS.colorGradingAttributes[0], COLOR_GRADING_PRESETS[i], sizeof(COLOR_GRADING_PRESETS[i]) ); 401 | colorGradingDirty = true; 402 | } 403 | ImGui::SameLine(); 404 | } 405 | ImGui::NewLine(); 406 | 407 | if ( ImGui::CollapsingHeader( "Advanced settings" ) ) 408 | { 409 | ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.45f); 410 | colorGradingDirty |= ImGui::DragFloat( "Intensity", &SETTINGS.colorGradingAttributes[0][0], 0.005f, 0.0f, FLT_MAX ); 411 | colorGradingDirty |= ImGui::DragFloat( "Saturation", &SETTINGS.colorGradingAttributes[0][1], 0.005f, 0.0f, FLT_MAX ); 412 | colorGradingDirty |= ImGui::DragFloat( "Temp. threshold", &SETTINGS.colorGradingAttributes[0][2], 0.005f, 0.0f, FLT_MAX ); 413 | ImGui::PopItemWidth(); 414 | 415 | 416 | ImGui::NewLine(); 417 | colorGradingDirty |= ImGui::ColorEdit3( "Cold", SETTINGS.colorGradingAttributes[1] ); 418 | colorGradingDirty |= ImGui::ColorEdit3( "Moderate", SETTINGS.colorGradingAttributes[2] ); 419 | colorGradingDirty |= ImGui::ColorEdit3( "Warm", SETTINGS.colorGradingAttributes[3] ); 420 | if ( ImGui::Button( "Restore defaults##Colors" ) ) 421 | { 422 | memcpy( &SETTINGS.colorGradingAttributes[0], COLOR_GRADING_PRESETS[0], sizeof(COLOR_GRADING_PRESETS[0]) ); 423 | colorGradingDirty = true; 424 | } 425 | 426 | ImGui::NewLine(); 427 | colorGradingDirty |= ImGui::DragFloat4( "Vignette", SETTINGS.colorGradingAttributes[4], 0.05f, 0.0f, FLT_MAX, "%.2f" ); 428 | if ( ImGui::Button( "Restore defaults##Vignette" ) ) 429 | { 430 | memcpy( &SETTINGS.colorGradingAttributes[4], Effects::VIGNETTE_PRESET, sizeof(Effects::VIGNETTE_PRESET) ); 431 | colorGradingDirty = true; 432 | } 433 | } 434 | 435 | SETTINGS.colorGradingDirty |= colorGradingDirty; 436 | needsToSave |= colorGradingDirty; 437 | 438 | ImGui::Dummy( ImVec2(0.0f, 20.0f) ); 439 | } 440 | 441 | if ( needsToSave ) 442 | { 443 | SaveSettings(); 444 | } 445 | } 446 | 447 | ImGui::End(); 448 | } 449 | 450 | io.MouseDrawCursor = SETTINGS.isShown; 451 | } 452 | 453 | ImGui::Render(); 454 | 455 | ImDrawData* drawData = ImGui::GetDrawData(); 456 | if ( drawData->TotalVtxCount > 0 ) 457 | { 458 | // Only do this relatively heavy work if we actually render something 459 | ComPtr d3dDevice; 460 | if ( SUCCEEDED(m_device.As(&d3dDevice)) ) 461 | { 462 | ComPtr renderTarget; 463 | if ( SUCCEEDED(GetBuffer(0, IID_PPV_ARGS(renderTarget.GetAddressOf()))) ) 464 | { 465 | ComPtr rtv; 466 | if ( SUCCEEDED(d3dDevice->CreateRenderTargetView( renderTarget.Get(), nullptr, rtv.GetAddressOf()) ) ) 467 | { 468 | ComPtr d3dDeviceContext; 469 | d3dDevice->GetImmediateContext( d3dDeviceContext.GetAddressOf() ); 470 | 471 | d3dDeviceContext->OMSetRenderTargets( 1, rtv.GetAddressOf(), nullptr ); 472 | } 473 | } 474 | } 475 | } 476 | 477 | ImGui_ImplDX11_RenderDrawData(drawData); 478 | 479 | HRESULT hr = m_orig->Present(SyncInterval, Flags); 480 | 481 | // Start the Dear ImGui frame 482 | ImGui_ImplDX11_NewFrame(); 483 | ImGui_ImplWin32_NewFrame(); 484 | ImGui::NewFrame(); 485 | 486 | return hr; 487 | } 488 | 489 | HRESULT STDMETHODCALLTYPE DXGISwapChain::GetBuffer(UINT Buffer, REFIID riid, void** ppSurface) 490 | { 491 | return m_orig->GetBuffer(Buffer, riid, ppSurface); 492 | } 493 | 494 | HRESULT STDMETHODCALLTYPE DXGISwapChain::SetFullscreenState(BOOL Fullscreen, IDXGIOutput* pTarget) 495 | { 496 | return m_orig->SetFullscreenState(Fullscreen, pTarget); 497 | } 498 | 499 | HRESULT STDMETHODCALLTYPE DXGISwapChain::GetFullscreenState(BOOL* pFullscreen, IDXGIOutput** ppTarget) 500 | { 501 | return m_orig->GetFullscreenState(pFullscreen, ppTarget); 502 | } 503 | 504 | HRESULT STDMETHODCALLTYPE DXGISwapChain::GetDesc(DXGI_SWAP_CHAIN_DESC* pDesc) 505 | { 506 | return m_orig->GetDesc(pDesc); 507 | } 508 | 509 | HRESULT STDMETHODCALLTYPE DXGISwapChain::ResizeBuffers(UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags) 510 | { 511 | return m_orig->ResizeBuffers(BufferCount, Width, Height, NewFormat, SwapChainFlags); 512 | } 513 | 514 | HRESULT STDMETHODCALLTYPE DXGISwapChain::ResizeTarget(const DXGI_MODE_DESC* pNewTargetParameters) 515 | { 516 | return m_orig->ResizeTarget(pNewTargetParameters); 517 | } 518 | 519 | HRESULT STDMETHODCALLTYPE DXGISwapChain::GetContainingOutput(IDXGIOutput** ppOutput) 520 | { 521 | return m_orig->GetContainingOutput(ppOutput); 522 | } 523 | 524 | HRESULT STDMETHODCALLTYPE DXGISwapChain::GetFrameStatistics(DXGI_FRAME_STATISTICS* pStats) 525 | { 526 | return m_orig->GetFrameStatistics(pStats); 527 | } 528 | 529 | HRESULT STDMETHODCALLTYPE DXGISwapChain::GetLastPresentCount(UINT* pLastPresentCount) 530 | { 531 | return m_orig->GetLastPresentCount(pLastPresentCount); 532 | } 533 | 534 | HRESULT STDMETHODCALLTYPE DXGISwapChain::GetUnderlyingInterface(REFIID riid, void** ppvObject) 535 | { 536 | return m_orig.CopyTo(riid, ppvObject); 537 | } -------------------------------------------------------------------------------- /source/imgui/imstb_rectpack.h: -------------------------------------------------------------------------------- 1 | // [DEAR IMGUI] 2 | // This is a slightly modified version of stb_rect_pack.h 1.00. 3 | // Those changes would need to be pushed into nothings/stb: 4 | // - Added STBRP__CDECL 5 | // Grep for [DEAR IMGUI] to find the changes. 6 | 7 | // stb_rect_pack.h - v1.00 - public domain - rectangle packing 8 | // Sean Barrett 2014 9 | // 10 | // Useful for e.g. packing rectangular textures into an atlas. 11 | // Does not do rotation. 12 | // 13 | // Not necessarily the awesomest packing method, but better than 14 | // the totally naive one in stb_truetype (which is primarily what 15 | // this is meant to replace). 16 | // 17 | // Has only had a few tests run, may have issues. 18 | // 19 | // More docs to come. 20 | // 21 | // No memory allocations; uses qsort() and assert() from stdlib. 22 | // Can override those by defining STBRP_SORT and STBRP_ASSERT. 23 | // 24 | // This library currently uses the Skyline Bottom-Left algorithm. 25 | // 26 | // Please note: better rectangle packers are welcome! Please 27 | // implement them to the same API, but with a different init 28 | // function. 29 | // 30 | // Credits 31 | // 32 | // Library 33 | // Sean Barrett 34 | // Minor features 35 | // Martins Mozeiko 36 | // github:IntellectualKitty 37 | // 38 | // Bugfixes / warning fixes 39 | // Jeremy Jaussaud 40 | // Fabian Giesen 41 | // 42 | // Version history: 43 | // 44 | // 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles 45 | // 0.99 (2019-02-07) warning fixes 46 | // 0.11 (2017-03-03) return packing success/fail result 47 | // 0.10 (2016-10-25) remove cast-away-const to avoid warnings 48 | // 0.09 (2016-08-27) fix compiler warnings 49 | // 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0) 50 | // 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0) 51 | // 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort 52 | // 0.05: added STBRP_ASSERT to allow replacing assert 53 | // 0.04: fixed minor bug in STBRP_LARGE_RECTS support 54 | // 0.01: initial release 55 | // 56 | // LICENSE 57 | // 58 | // See end of file for license information. 59 | 60 | ////////////////////////////////////////////////////////////////////////////// 61 | // 62 | // INCLUDE SECTION 63 | // 64 | 65 | #ifndef STB_INCLUDE_STB_RECT_PACK_H 66 | #define STB_INCLUDE_STB_RECT_PACK_H 67 | 68 | #define STB_RECT_PACK_VERSION 1 69 | 70 | #ifdef STBRP_STATIC 71 | #define STBRP_DEF static 72 | #else 73 | #define STBRP_DEF extern 74 | #endif 75 | 76 | #ifdef __cplusplus 77 | extern "C" { 78 | #endif 79 | 80 | typedef struct stbrp_context stbrp_context; 81 | typedef struct stbrp_node stbrp_node; 82 | typedef struct stbrp_rect stbrp_rect; 83 | 84 | #ifdef STBRP_LARGE_RECTS 85 | typedef int stbrp_coord; 86 | #else 87 | typedef unsigned short stbrp_coord; 88 | #endif 89 | 90 | STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects); 91 | // Assign packed locations to rectangles. The rectangles are of type 92 | // 'stbrp_rect' defined below, stored in the array 'rects', and there 93 | // are 'num_rects' many of them. 94 | // 95 | // Rectangles which are successfully packed have the 'was_packed' flag 96 | // set to a non-zero value and 'x' and 'y' store the minimum location 97 | // on each axis (i.e. bottom-left in cartesian coordinates, top-left 98 | // if you imagine y increasing downwards). Rectangles which do not fit 99 | // have the 'was_packed' flag set to 0. 100 | // 101 | // You should not try to access the 'rects' array from another thread 102 | // while this function is running, as the function temporarily reorders 103 | // the array while it executes. 104 | // 105 | // To pack into another rectangle, you need to call stbrp_init_target 106 | // again. To continue packing into the same rectangle, you can call 107 | // this function again. Calling this multiple times with multiple rect 108 | // arrays will probably produce worse packing results than calling it 109 | // a single time with the full rectangle array, but the option is 110 | // available. 111 | // 112 | // The function returns 1 if all of the rectangles were successfully 113 | // packed and 0 otherwise. 114 | 115 | struct stbrp_rect 116 | { 117 | // reserved for your use: 118 | int id; 119 | 120 | // input: 121 | stbrp_coord w, h; 122 | 123 | // output: 124 | stbrp_coord x, y; 125 | int was_packed; // non-zero if valid packing 126 | 127 | }; // 16 bytes, nominally 128 | 129 | 130 | STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes); 131 | // Initialize a rectangle packer to: 132 | // pack a rectangle that is 'width' by 'height' in dimensions 133 | // using temporary storage provided by the array 'nodes', which is 'num_nodes' long 134 | // 135 | // You must call this function every time you start packing into a new target. 136 | // 137 | // There is no "shutdown" function. The 'nodes' memory must stay valid for 138 | // the following stbrp_pack_rects() call (or calls), but can be freed after 139 | // the call (or calls) finish. 140 | // 141 | // Note: to guarantee best results, either: 142 | // 1. make sure 'num_nodes' >= 'width' 143 | // or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1' 144 | // 145 | // If you don't do either of the above things, widths will be quantized to multiples 146 | // of small integers to guarantee the algorithm doesn't run out of temporary storage. 147 | // 148 | // If you do #2, then the non-quantized algorithm will be used, but the algorithm 149 | // may run out of temporary storage and be unable to pack some rectangles. 150 | 151 | STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem); 152 | // Optionally call this function after init but before doing any packing to 153 | // change the handling of the out-of-temp-memory scenario, described above. 154 | // If you call init again, this will be reset to the default (false). 155 | 156 | 157 | STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic); 158 | // Optionally select which packing heuristic the library should use. Different 159 | // heuristics will produce better/worse results for different data sets. 160 | // If you call init again, this will be reset to the default. 161 | 162 | enum 163 | { 164 | STBRP_HEURISTIC_Skyline_default=0, 165 | STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default, 166 | STBRP_HEURISTIC_Skyline_BF_sortHeight 167 | }; 168 | 169 | 170 | ////////////////////////////////////////////////////////////////////////////// 171 | // 172 | // the details of the following structures don't matter to you, but they must 173 | // be visible so you can handle the memory allocations for them 174 | 175 | struct stbrp_node 176 | { 177 | stbrp_coord x,y; 178 | stbrp_node *next; 179 | }; 180 | 181 | struct stbrp_context 182 | { 183 | int width; 184 | int height; 185 | int align; 186 | int init_mode; 187 | int heuristic; 188 | int num_nodes; 189 | stbrp_node *active_head; 190 | stbrp_node *free_head; 191 | stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2' 192 | }; 193 | 194 | #ifdef __cplusplus 195 | } 196 | #endif 197 | 198 | #endif 199 | 200 | ////////////////////////////////////////////////////////////////////////////// 201 | // 202 | // IMPLEMENTATION SECTION 203 | // 204 | 205 | #ifdef STB_RECT_PACK_IMPLEMENTATION 206 | #ifndef STBRP_SORT 207 | #include 208 | #define STBRP_SORT qsort 209 | #endif 210 | 211 | #ifndef STBRP_ASSERT 212 | #include 213 | #define STBRP_ASSERT assert 214 | #endif 215 | 216 | // [DEAR IMGUI] Added STBRP__CDECL 217 | #ifdef _MSC_VER 218 | #define STBRP__NOTUSED(v) (void)(v) 219 | #define STBRP__CDECL __cdecl 220 | #else 221 | #define STBRP__NOTUSED(v) (void)sizeof(v) 222 | #define STBRP__CDECL 223 | #endif 224 | 225 | enum 226 | { 227 | STBRP__INIT_skyline = 1 228 | }; 229 | 230 | STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic) 231 | { 232 | switch (context->init_mode) { 233 | case STBRP__INIT_skyline: 234 | STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight); 235 | context->heuristic = heuristic; 236 | break; 237 | default: 238 | STBRP_ASSERT(0); 239 | } 240 | } 241 | 242 | STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem) 243 | { 244 | if (allow_out_of_mem) 245 | // if it's ok to run out of memory, then don't bother aligning them; 246 | // this gives better packing, but may fail due to OOM (even though 247 | // the rectangles easily fit). @TODO a smarter approach would be to only 248 | // quantize once we've hit OOM, then we could get rid of this parameter. 249 | context->align = 1; 250 | else { 251 | // if it's not ok to run out of memory, then quantize the widths 252 | // so that num_nodes is always enough nodes. 253 | // 254 | // I.e. num_nodes * align >= width 255 | // align >= width / num_nodes 256 | // align = ceil(width/num_nodes) 257 | 258 | context->align = (context->width + context->num_nodes-1) / context->num_nodes; 259 | } 260 | } 261 | 262 | STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes) 263 | { 264 | int i; 265 | #ifndef STBRP_LARGE_RECTS 266 | STBRP_ASSERT(width <= 0xffff && height <= 0xffff); 267 | #endif 268 | 269 | for (i=0; i < num_nodes-1; ++i) 270 | nodes[i].next = &nodes[i+1]; 271 | nodes[i].next = NULL; 272 | context->init_mode = STBRP__INIT_skyline; 273 | context->heuristic = STBRP_HEURISTIC_Skyline_default; 274 | context->free_head = &nodes[0]; 275 | context->active_head = &context->extra[0]; 276 | context->width = width; 277 | context->height = height; 278 | context->num_nodes = num_nodes; 279 | stbrp_setup_allow_out_of_mem(context, 0); 280 | 281 | // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly) 282 | context->extra[0].x = 0; 283 | context->extra[0].y = 0; 284 | context->extra[0].next = &context->extra[1]; 285 | context->extra[1].x = (stbrp_coord) width; 286 | #ifdef STBRP_LARGE_RECTS 287 | context->extra[1].y = (1<<30); 288 | #else 289 | context->extra[1].y = 65535; 290 | #endif 291 | context->extra[1].next = NULL; 292 | } 293 | 294 | // find minimum y position if it starts at x1 295 | static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste) 296 | { 297 | stbrp_node *node = first; 298 | int x1 = x0 + width; 299 | int min_y, visited_width, waste_area; 300 | 301 | STBRP__NOTUSED(c); 302 | 303 | STBRP_ASSERT(first->x <= x0); 304 | 305 | #if 0 306 | // skip in case we're past the node 307 | while (node->next->x <= x0) 308 | ++node; 309 | #else 310 | STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency 311 | #endif 312 | 313 | STBRP_ASSERT(node->x <= x0); 314 | 315 | min_y = 0; 316 | waste_area = 0; 317 | visited_width = 0; 318 | while (node->x < x1) { 319 | if (node->y > min_y) { 320 | // raise min_y higher. 321 | // we've accounted for all waste up to min_y, 322 | // but we'll now add more waste for everything we've visted 323 | waste_area += visited_width * (node->y - min_y); 324 | min_y = node->y; 325 | // the first time through, visited_width might be reduced 326 | if (node->x < x0) 327 | visited_width += node->next->x - x0; 328 | else 329 | visited_width += node->next->x - node->x; 330 | } else { 331 | // add waste area 332 | int under_width = node->next->x - node->x; 333 | if (under_width + visited_width > width) 334 | under_width = width - visited_width; 335 | waste_area += under_width * (min_y - node->y); 336 | visited_width += under_width; 337 | } 338 | node = node->next; 339 | } 340 | 341 | *pwaste = waste_area; 342 | return min_y; 343 | } 344 | 345 | typedef struct 346 | { 347 | int x,y; 348 | stbrp_node **prev_link; 349 | } stbrp__findresult; 350 | 351 | static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height) 352 | { 353 | int best_waste = (1<<30), best_x, best_y = (1 << 30); 354 | stbrp__findresult fr; 355 | stbrp_node **prev, *node, *tail, **best = NULL; 356 | 357 | // align to multiple of c->align 358 | width = (width + c->align - 1); 359 | width -= width % c->align; 360 | STBRP_ASSERT(width % c->align == 0); 361 | 362 | // if it can't possibly fit, bail immediately 363 | if (width > c->width || height > c->height) { 364 | fr.prev_link = NULL; 365 | fr.x = fr.y = 0; 366 | return fr; 367 | } 368 | 369 | node = c->active_head; 370 | prev = &c->active_head; 371 | while (node->x + width <= c->width) { 372 | int y,waste; 373 | y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste); 374 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL 375 | // bottom left 376 | if (y < best_y) { 377 | best_y = y; 378 | best = prev; 379 | } 380 | } else { 381 | // best-fit 382 | if (y + height <= c->height) { 383 | // can only use it if it first vertically 384 | if (y < best_y || (y == best_y && waste < best_waste)) { 385 | best_y = y; 386 | best_waste = waste; 387 | best = prev; 388 | } 389 | } 390 | } 391 | prev = &node->next; 392 | node = node->next; 393 | } 394 | 395 | best_x = (best == NULL) ? 0 : (*best)->x; 396 | 397 | // if doing best-fit (BF), we also have to try aligning right edge to each node position 398 | // 399 | // e.g, if fitting 400 | // 401 | // ____________________ 402 | // |____________________| 403 | // 404 | // into 405 | // 406 | // | | 407 | // | ____________| 408 | // |____________| 409 | // 410 | // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned 411 | // 412 | // This makes BF take about 2x the time 413 | 414 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) { 415 | tail = c->active_head; 416 | node = c->active_head; 417 | prev = &c->active_head; 418 | // find first node that's admissible 419 | while (tail->x < width) 420 | tail = tail->next; 421 | while (tail) { 422 | int xpos = tail->x - width; 423 | int y,waste; 424 | STBRP_ASSERT(xpos >= 0); 425 | // find the left position that matches this 426 | while (node->next->x <= xpos) { 427 | prev = &node->next; 428 | node = node->next; 429 | } 430 | STBRP_ASSERT(node->next->x > xpos && node->x <= xpos); 431 | y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste); 432 | if (y + height <= c->height) { 433 | if (y <= best_y) { 434 | if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) { 435 | best_x = xpos; 436 | STBRP_ASSERT(y <= best_y); 437 | best_y = y; 438 | best_waste = waste; 439 | best = prev; 440 | } 441 | } 442 | } 443 | tail = tail->next; 444 | } 445 | } 446 | 447 | fr.prev_link = best; 448 | fr.x = best_x; 449 | fr.y = best_y; 450 | return fr; 451 | } 452 | 453 | static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height) 454 | { 455 | // find best position according to heuristic 456 | stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height); 457 | stbrp_node *node, *cur; 458 | 459 | // bail if: 460 | // 1. it failed 461 | // 2. the best node doesn't fit (we don't always check this) 462 | // 3. we're out of memory 463 | if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) { 464 | res.prev_link = NULL; 465 | return res; 466 | } 467 | 468 | // on success, create new node 469 | node = context->free_head; 470 | node->x = (stbrp_coord) res.x; 471 | node->y = (stbrp_coord) (res.y + height); 472 | 473 | context->free_head = node->next; 474 | 475 | // insert the new node into the right starting point, and 476 | // let 'cur' point to the remaining nodes needing to be 477 | // stiched back in 478 | 479 | cur = *res.prev_link; 480 | if (cur->x < res.x) { 481 | // preserve the existing one, so start testing with the next one 482 | stbrp_node *next = cur->next; 483 | cur->next = node; 484 | cur = next; 485 | } else { 486 | *res.prev_link = node; 487 | } 488 | 489 | // from here, traverse cur and free the nodes, until we get to one 490 | // that shouldn't be freed 491 | while (cur->next && cur->next->x <= res.x + width) { 492 | stbrp_node *next = cur->next; 493 | // move the current node to the free list 494 | cur->next = context->free_head; 495 | context->free_head = cur; 496 | cur = next; 497 | } 498 | 499 | // stitch the list back in 500 | node->next = cur; 501 | 502 | if (cur->x < res.x + width) 503 | cur->x = (stbrp_coord) (res.x + width); 504 | 505 | #ifdef _DEBUG 506 | cur = context->active_head; 507 | while (cur->x < context->width) { 508 | STBRP_ASSERT(cur->x < cur->next->x); 509 | cur = cur->next; 510 | } 511 | STBRP_ASSERT(cur->next == NULL); 512 | 513 | { 514 | int count=0; 515 | cur = context->active_head; 516 | while (cur) { 517 | cur = cur->next; 518 | ++count; 519 | } 520 | cur = context->free_head; 521 | while (cur) { 522 | cur = cur->next; 523 | ++count; 524 | } 525 | STBRP_ASSERT(count == context->num_nodes+2); 526 | } 527 | #endif 528 | 529 | return res; 530 | } 531 | 532 | // [DEAR IMGUI] Added STBRP__CDECL 533 | static int STBRP__CDECL rect_height_compare(const void *a, const void *b) 534 | { 535 | const stbrp_rect *p = (const stbrp_rect *) a; 536 | const stbrp_rect *q = (const stbrp_rect *) b; 537 | if (p->h > q->h) 538 | return -1; 539 | if (p->h < q->h) 540 | return 1; 541 | return (p->w > q->w) ? -1 : (p->w < q->w); 542 | } 543 | 544 | // [DEAR IMGUI] Added STBRP__CDECL 545 | static int STBRP__CDECL rect_original_order(const void *a, const void *b) 546 | { 547 | const stbrp_rect *p = (const stbrp_rect *) a; 548 | const stbrp_rect *q = (const stbrp_rect *) b; 549 | return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed); 550 | } 551 | 552 | #ifdef STBRP_LARGE_RECTS 553 | #define STBRP__MAXVAL 0xffffffff 554 | #else 555 | #define STBRP__MAXVAL 0xffff 556 | #endif 557 | 558 | STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects) 559 | { 560 | int i, all_rects_packed = 1; 561 | 562 | // we use the 'was_packed' field internally to allow sorting/unsorting 563 | for (i=0; i < num_rects; ++i) { 564 | rects[i].was_packed = i; 565 | } 566 | 567 | // sort according to heuristic 568 | STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare); 569 | 570 | for (i=0; i < num_rects; ++i) { 571 | if (rects[i].w == 0 || rects[i].h == 0) { 572 | rects[i].x = rects[i].y = 0; // empty rect needs no space 573 | } else { 574 | stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h); 575 | if (fr.prev_link) { 576 | rects[i].x = (stbrp_coord) fr.x; 577 | rects[i].y = (stbrp_coord) fr.y; 578 | } else { 579 | rects[i].x = rects[i].y = STBRP__MAXVAL; 580 | } 581 | } 582 | } 583 | 584 | // unsort 585 | STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order); 586 | 587 | // set was_packed flags and all_rects_packed status 588 | for (i=0; i < num_rects; ++i) { 589 | rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL); 590 | if (!rects[i].was_packed) 591 | all_rects_packed = 0; 592 | } 593 | 594 | // return the all_rects_packed status 595 | return all_rects_packed; 596 | } 597 | #endif 598 | 599 | /* 600 | ------------------------------------------------------------------------------ 601 | This software is available under 2 licenses -- choose whichever you prefer. 602 | ------------------------------------------------------------------------------ 603 | ALTERNATIVE A - MIT License 604 | Copyright (c) 2017 Sean Barrett 605 | Permission is hereby granted, free of charge, to any person obtaining a copy of 606 | this software and associated documentation files (the "Software"), to deal in 607 | the Software without restriction, including without limitation the rights to 608 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 609 | of the Software, and to permit persons to whom the Software is furnished to do 610 | so, subject to the following conditions: 611 | The above copyright notice and this permission notice shall be included in all 612 | copies or substantial portions of the Software. 613 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 614 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 615 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 616 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 617 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 618 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 619 | SOFTWARE. 620 | ------------------------------------------------------------------------------ 621 | ALTERNATIVE B - Public Domain (www.unlicense.org) 622 | This is free and unencumbered software released into the public domain. 623 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 624 | software, either in source code form or as a compiled binary, for any purpose, 625 | commercial or non-commercial, and by any means. 626 | In jurisdictions that recognize copyright laws, the author or authors of this 627 | software dedicate any and all copyright interest in the software to the public 628 | domain. We make this dedication for the benefit of the public at large and to 629 | the detriment of our heirs and successors. We intend this dedication to be an 630 | overt act of relinquishment in perpetuity of all present and future rights to 631 | this software under copyright law. 632 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 633 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 634 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 635 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 636 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 637 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 638 | ------------------------------------------------------------------------------ 639 | */ 640 | --------------------------------------------------------------------------------