diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 0eda66f31f..331458b716 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,7 +3,7 @@ "isRoot": true, "tools": { "jetbrains.resharper.globaltools": { - "version": "2025.2.3", + "version": "2026.1.0.1", "commands": [ "jb" ], diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7dd71c2599..1fba56a1a3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,7 +51,7 @@ jobs: exit $exit_code - name: InspectCode - uses: JetBrains/ReSharper-InspectCode@v0.11 + uses: JetBrains/ReSharper-InspectCode@v0.12 with: # this is WTF tier but if you don't specify *both* of these the defaults assume `build: true` build: false @@ -59,6 +59,7 @@ jobs: solution: ./osu-framework.Desktop.slnf caches-home: inspectcode verbosity: WARN + tool-version: 2026.1.0.1 test: name: Test diff --git a/README.md b/README.md index 860433ec12..1da6192725 100644 --- a/README.md +++ b/README.md @@ -81,13 +81,42 @@ This fork ([winnerspiros/osu-framework](https://github.com/winnerspiros/osu-fram ### iOS build configuration - `SupportedOSPlatformVersion` remains at **13.4**. -- Trim analysis warnings in test code fixed with `[DynamicallyAccessedMembers]` and `[UnconditionalSuppressMessage]` annotations. +- Trim analysis warnings (`IL2026`/`IL2045`/`IL2060`/`IL2070`/`IL2072`/`IL2075`/`IL2091`/`IL2104`) in framework and test code suppressed with `[DynamicallyAccessedMembers]`, `[UnconditionalSuppressMessage]` annotations, and `` in `osu.Framework.iOS.props`. ### Performance optimisations - Hot-path LINQ allocations eliminated across the framework (replaced with `for` loops, span-based code, and cached collections). - `object`-based locks migrated to `System.Threading.Lock` for lower overhead on modern runtimes. - BASS audio, GL state-change, shader warm-up, texture upload, and mobile vertex-batching improvements. +- **GridContainer cell sizing** uses `RequiredParentSizeToFit` instead of `BoundingBox`, avoiding redundant matrix-to-parent-space transforms on every layout pass ([upstream Issue #3215](https://github.com/ppy/osu-framework/issues/3215)). + +### Direct3D 12 renderer support + +- Added `RendererType.Direct3D12` / `RendererType.Deferred_Direct3D12` and `GraphicsSurfaceType.Direct3D12`. +- Full pipeline: `VeldridDevice.CreateD3D12` swapchain creation, `LogD3D12` diagnostics (adapter info, Enhanced Barriers, Mesh Shaders, VRS, Raytracing support), and `PersistentStagingBuffer` staging. +- D3D12 is included in the Windows renderer fallback order (after D3D11, before OpenGL). +- Leverages the [winnerspiros/veldrid](https://github.com/winnerspiros/veldrid) submodule which contains a full D3D12 backend. + +### Low-latency rendering infrastructure + +- Generic `ILowLatencyProvider` interface for GPU-side latency reduction (NVIDIA Reflex, LatencyFlex, or any future API). + - `IDirect3D11LowLatencyProvider` (D3D11-specific) extends `ILowLatencyProvider`. + - `NoOpLowLatencyProvider` (default no-op) and `NoOpDirect3D11LowLatencyProvider` included. +- Latency markers (`SimulationStart/End`, `RenderSubmitStart/End`, `PresentStart/End`, `InputSample`, `TriggerFlash`) inserted into `GameHost.UpdateFrame()` and `GameHost.DrawFrame()`. +- `FrameSleep()` called at the start of each update frame for provider-controlled sleep (Reflex Boost mode). +- Provider auto-initialises on the draw thread using the native D3D11 or D3D12 device handle from Veldrid's `BackendInfoD3D11` / `BackendInfoD3D12`. +- `LatencyMode` setting (`Off` / `On` / `Boost`) added to `FrameworkConfigManager`. +- Inspired by [upstream PR #6666](https://github.com/ppy/osu-framework/pull/6666). + +### Frame rate limiter enhancements + +- **Unbuffered VSync (`UVSync`)**: Limits both draw *and* update threads to the exact display refresh rate. Useful for VRR/G-Sync/FreeSync displays where regular VSync introduces unwanted buffering ([upstream PR #6696](https://github.com/ppy/osu-framework/pull/6696)). +- **Custom FPS limiter**: `FrameSync.Custom` mode with a `CustomDrawLimit` setting (0–1000 Hz). When set to 0, the draw thread is unlimited. Update thread runs at max Hz. Useful for benchmarking or VRR-specific tuning ([upstream PR #6725](https://github.com/ppy/osu-framework/pull/6725)). + +### Input latency improvements + +- **Raw keyboard input on Windows**: `SDL_HINT_WINDOWS_RAW_KEYBOARD` enabled by default, bypassing the Windows message translation layer for lower-latency key events ([upstream PR #6507](https://github.com/ppy/osu-framework/pull/6507)). +- **Async keyboard event handling**: When text input (IME) is not active, keyboard events (`KEY_DOWN`/`KEY_UP`) are handled directly in SDL's event filter (`HandleEventFromFilter`), bypassing the SDL event queue for reduced input-to-render latency ([upstream PR #6506](https://github.com/ppy/osu-framework/pull/6506)). ### Code quality diff --git a/osu-framework.Desktop.slnf b/osu-framework.Desktop.slnf index 25c106d659..3b0eb822e3 100644 --- a/osu-framework.Desktop.slnf +++ b/osu-framework.Desktop.slnf @@ -17,7 +17,10 @@ "osu.Framework.Tests\\osu.Framework.Tests.csproj", "osu.Framework\\osu.Framework.csproj", "SampleGame.Desktop\\SampleGame.Desktop.csproj", - "SampleGame\\SampleGame.csproj" + "SampleGame\\SampleGame.csproj", + "submodules\\veldrid\\src\\Veldrid\\Veldrid.csproj", + "submodules\\veldrid\\src\\Veldrid.MetalBindings\\Veldrid.MetalBindings.csproj", + "submodules\\veldrid\\src\\Veldrid.OpenGLBindings\\Veldrid.OpenGLBindings.csproj" ] } } \ No newline at end of file diff --git a/osu-framework.sln b/osu-framework.sln index 3ba713ce6a..4214b980ea 100644 --- a/osu-framework.sln +++ b/osu-framework.sln @@ -76,130 +76,379 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CodeAnalysis", "CodeAnalysi CodeAnalysis\BannedSymbols.txt = CodeAnalysis\BannedSymbols.txt EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "submodules", "submodules", "{B3415621-5EBA-1A55-0B57-0078FEC59DC7}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "veldrid", "veldrid", "{3DDCF21F-A4AC-2952-3A5E-46AAD7F00BF1}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E00BDB6B-4D28-95B9-EEF8-DB6484FA30AD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Veldrid", "submodules\veldrid\src\Veldrid\Veldrid.csproj", "{5D0C3B33-2DCA-4912-AA53-B05CD80A60CE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Veldrid.MetalBindings", "submodules\veldrid\src\Veldrid.MetalBindings\Veldrid.MetalBindings.csproj", "{A88F62DA-DD29-4FD3-BF1E-9C8783C4C892}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Veldrid.OpenGLBindings", "submodules\veldrid\src\Veldrid.OpenGLBindings\Veldrid.OpenGLBindings.csproj", "{F7B982C2-014C-4AFD-8A9B-51809242482C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Debug|x64.ActiveCfg = Debug|Any CPU + {C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Debug|x64.Build.0 = Debug|Any CPU + {C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Debug|x86.ActiveCfg = Debug|Any CPU + {C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Debug|x86.Build.0 = Debug|Any CPU {C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Release|Any CPU.ActiveCfg = Release|Any CPU {C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Release|Any CPU.Build.0 = Release|Any CPU + {C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Release|x64.ActiveCfg = Release|Any CPU + {C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Release|x64.Build.0 = Release|Any CPU + {C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Release|x86.ActiveCfg = Release|Any CPU + {C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Release|x86.Build.0 = Release|Any CPU {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|x64.ActiveCfg = Debug|Any CPU + {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|x64.Build.0 = Debug|Any CPU + {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|x86.ActiveCfg = Debug|Any CPU + {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|x86.Build.0 = Debug|Any CPU {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|Any CPU.ActiveCfg = Release|Any CPU {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|Any CPU.Build.0 = Release|Any CPU + {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|x64.ActiveCfg = Release|Any CPU + {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|x64.Build.0 = Release|Any CPU + {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|x86.ActiveCfg = Release|Any CPU + {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|x86.Build.0 = Release|Any CPU {79803407-6F50-484F-93F5-641911EABD8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {79803407-6F50-484F-93F5-641911EABD8A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {79803407-6F50-484F-93F5-641911EABD8A}.Debug|x64.ActiveCfg = Debug|Any CPU + {79803407-6F50-484F-93F5-641911EABD8A}.Debug|x64.Build.0 = Debug|Any CPU + {79803407-6F50-484F-93F5-641911EABD8A}.Debug|x86.ActiveCfg = Debug|Any CPU + {79803407-6F50-484F-93F5-641911EABD8A}.Debug|x86.Build.0 = Debug|Any CPU {79803407-6F50-484F-93F5-641911EABD8A}.Release|Any CPU.ActiveCfg = Release|Any CPU {79803407-6F50-484F-93F5-641911EABD8A}.Release|Any CPU.Build.0 = Release|Any CPU + {79803407-6F50-484F-93F5-641911EABD8A}.Release|x64.ActiveCfg = Release|Any CPU + {79803407-6F50-484F-93F5-641911EABD8A}.Release|x64.Build.0 = Release|Any CPU + {79803407-6F50-484F-93F5-641911EABD8A}.Release|x86.ActiveCfg = Release|Any CPU + {79803407-6F50-484F-93F5-641911EABD8A}.Release|x86.Build.0 = Release|Any CPU {2AD6EA6F-CD5A-4348-86F1-5E228B11617D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2AD6EA6F-CD5A-4348-86F1-5E228B11617D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2AD6EA6F-CD5A-4348-86F1-5E228B11617D}.Debug|x64.ActiveCfg = Debug|Any CPU + {2AD6EA6F-CD5A-4348-86F1-5E228B11617D}.Debug|x64.Build.0 = Debug|Any CPU + {2AD6EA6F-CD5A-4348-86F1-5E228B11617D}.Debug|x86.ActiveCfg = Debug|Any CPU + {2AD6EA6F-CD5A-4348-86F1-5E228B11617D}.Debug|x86.Build.0 = Debug|Any CPU {2AD6EA6F-CD5A-4348-86F1-5E228B11617D}.Release|Any CPU.ActiveCfg = Release|Any CPU {2AD6EA6F-CD5A-4348-86F1-5E228B11617D}.Release|Any CPU.Build.0 = Release|Any CPU + {2AD6EA6F-CD5A-4348-86F1-5E228B11617D}.Release|x64.ActiveCfg = Release|Any CPU + {2AD6EA6F-CD5A-4348-86F1-5E228B11617D}.Release|x64.Build.0 = Release|Any CPU + {2AD6EA6F-CD5A-4348-86F1-5E228B11617D}.Release|x86.ActiveCfg = Release|Any CPU + {2AD6EA6F-CD5A-4348-86F1-5E228B11617D}.Release|x86.Build.0 = Release|Any CPU {F853B4BB-CB83-4169-8FD2-72EEB4A88C32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F853B4BB-CB83-4169-8FD2-72EEB4A88C32}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F853B4BB-CB83-4169-8FD2-72EEB4A88C32}.Debug|x64.ActiveCfg = Debug|Any CPU + {F853B4BB-CB83-4169-8FD2-72EEB4A88C32}.Debug|x64.Build.0 = Debug|Any CPU + {F853B4BB-CB83-4169-8FD2-72EEB4A88C32}.Debug|x86.ActiveCfg = Debug|Any CPU + {F853B4BB-CB83-4169-8FD2-72EEB4A88C32}.Debug|x86.Build.0 = Debug|Any CPU {F853B4BB-CB83-4169-8FD2-72EEB4A88C32}.Release|Any CPU.ActiveCfg = Release|Any CPU {F853B4BB-CB83-4169-8FD2-72EEB4A88C32}.Release|Any CPU.Build.0 = Release|Any CPU + {F853B4BB-CB83-4169-8FD2-72EEB4A88C32}.Release|x64.ActiveCfg = Release|Any CPU + {F853B4BB-CB83-4169-8FD2-72EEB4A88C32}.Release|x64.Build.0 = Release|Any CPU + {F853B4BB-CB83-4169-8FD2-72EEB4A88C32}.Release|x86.ActiveCfg = Release|Any CPU + {F853B4BB-CB83-4169-8FD2-72EEB4A88C32}.Release|x86.Build.0 = Release|Any CPU {BBC0D18F-8595-43A6-AE61-5BF36A072CCE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BBC0D18F-8595-43A6-AE61-5BF36A072CCE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BBC0D18F-8595-43A6-AE61-5BF36A072CCE}.Debug|x64.ActiveCfg = Debug|Any CPU + {BBC0D18F-8595-43A6-AE61-5BF36A072CCE}.Debug|x64.Build.0 = Debug|Any CPU + {BBC0D18F-8595-43A6-AE61-5BF36A072CCE}.Debug|x86.ActiveCfg = Debug|Any CPU + {BBC0D18F-8595-43A6-AE61-5BF36A072CCE}.Debug|x86.Build.0 = Debug|Any CPU {BBC0D18F-8595-43A6-AE61-5BF36A072CCE}.Release|Any CPU.ActiveCfg = Release|Any CPU {BBC0D18F-8595-43A6-AE61-5BF36A072CCE}.Release|Any CPU.Build.0 = Release|Any CPU + {BBC0D18F-8595-43A6-AE61-5BF36A072CCE}.Release|x64.ActiveCfg = Release|Any CPU + {BBC0D18F-8595-43A6-AE61-5BF36A072CCE}.Release|x64.Build.0 = Release|Any CPU + {BBC0D18F-8595-43A6-AE61-5BF36A072CCE}.Release|x86.ActiveCfg = Release|Any CPU + {BBC0D18F-8595-43A6-AE61-5BF36A072CCE}.Release|x86.Build.0 = Release|Any CPU {529D5E2E-774A-4831-9C9E-59E3E8DFF155}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {529D5E2E-774A-4831-9C9E-59E3E8DFF155}.Debug|Any CPU.Build.0 = Debug|Any CPU + {529D5E2E-774A-4831-9C9E-59E3E8DFF155}.Debug|x64.ActiveCfg = Debug|Any CPU + {529D5E2E-774A-4831-9C9E-59E3E8DFF155}.Debug|x64.Build.0 = Debug|Any CPU + {529D5E2E-774A-4831-9C9E-59E3E8DFF155}.Debug|x86.ActiveCfg = Debug|Any CPU + {529D5E2E-774A-4831-9C9E-59E3E8DFF155}.Debug|x86.Build.0 = Debug|Any CPU {529D5E2E-774A-4831-9C9E-59E3E8DFF155}.Release|Any CPU.ActiveCfg = Release|Any CPU {529D5E2E-774A-4831-9C9E-59E3E8DFF155}.Release|Any CPU.Build.0 = Release|Any CPU + {529D5E2E-774A-4831-9C9E-59E3E8DFF155}.Release|x64.ActiveCfg = Release|Any CPU + {529D5E2E-774A-4831-9C9E-59E3E8DFF155}.Release|x64.Build.0 = Release|Any CPU + {529D5E2E-774A-4831-9C9E-59E3E8DFF155}.Release|x86.ActiveCfg = Release|Any CPU + {529D5E2E-774A-4831-9C9E-59E3E8DFF155}.Release|x86.Build.0 = Release|Any CPU {D972753E-45FC-4B82-B017-34BDE485F1BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D972753E-45FC-4B82-B017-34BDE485F1BB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D972753E-45FC-4B82-B017-34BDE485F1BB}.Debug|x64.ActiveCfg = Debug|Any CPU + {D972753E-45FC-4B82-B017-34BDE485F1BB}.Debug|x64.Build.0 = Debug|Any CPU + {D972753E-45FC-4B82-B017-34BDE485F1BB}.Debug|x86.ActiveCfg = Debug|Any CPU + {D972753E-45FC-4B82-B017-34BDE485F1BB}.Debug|x86.Build.0 = Debug|Any CPU {D972753E-45FC-4B82-B017-34BDE485F1BB}.Release|Any CPU.ActiveCfg = Release|Any CPU {D972753E-45FC-4B82-B017-34BDE485F1BB}.Release|Any CPU.Build.0 = Release|Any CPU + {D972753E-45FC-4B82-B017-34BDE485F1BB}.Release|x64.ActiveCfg = Release|Any CPU + {D972753E-45FC-4B82-B017-34BDE485F1BB}.Release|x64.Build.0 = Release|Any CPU + {D972753E-45FC-4B82-B017-34BDE485F1BB}.Release|x86.ActiveCfg = Release|Any CPU + {D972753E-45FC-4B82-B017-34BDE485F1BB}.Release|x86.Build.0 = Release|Any CPU {4D112E30-462B-4264-B44D-53B61ABB185E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4D112E30-462B-4264-B44D-53B61ABB185E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4D112E30-462B-4264-B44D-53B61ABB185E}.Debug|x64.ActiveCfg = Debug|Any CPU + {4D112E30-462B-4264-B44D-53B61ABB185E}.Debug|x64.Build.0 = Debug|Any CPU + {4D112E30-462B-4264-B44D-53B61ABB185E}.Debug|x86.ActiveCfg = Debug|Any CPU + {4D112E30-462B-4264-B44D-53B61ABB185E}.Debug|x86.Build.0 = Debug|Any CPU {4D112E30-462B-4264-B44D-53B61ABB185E}.Release|Any CPU.ActiveCfg = Release|Any CPU {4D112E30-462B-4264-B44D-53B61ABB185E}.Release|Any CPU.Build.0 = Release|Any CPU + {4D112E30-462B-4264-B44D-53B61ABB185E}.Release|x64.ActiveCfg = Release|Any CPU + {4D112E30-462B-4264-B44D-53B61ABB185E}.Release|x64.Build.0 = Release|Any CPU + {4D112E30-462B-4264-B44D-53B61ABB185E}.Release|x86.ActiveCfg = Release|Any CPU + {4D112E30-462B-4264-B44D-53B61ABB185E}.Release|x86.Build.0 = Release|Any CPU {5A378BB7-11D6-4008-980E-A67507CD9969}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5A378BB7-11D6-4008-980E-A67507CD9969}.Debug|Any CPU.Build.0 = Debug|Any CPU {5A378BB7-11D6-4008-980E-A67507CD9969}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {5A378BB7-11D6-4008-980E-A67507CD9969}.Debug|x64.ActiveCfg = Debug|Any CPU + {5A378BB7-11D6-4008-980E-A67507CD9969}.Debug|x64.Build.0 = Debug|Any CPU + {5A378BB7-11D6-4008-980E-A67507CD9969}.Debug|x86.ActiveCfg = Debug|Any CPU + {5A378BB7-11D6-4008-980E-A67507CD9969}.Debug|x86.Build.0 = Debug|Any CPU {5A378BB7-11D6-4008-980E-A67507CD9969}.Release|Any CPU.ActiveCfg = Release|Any CPU {5A378BB7-11D6-4008-980E-A67507CD9969}.Release|Any CPU.Build.0 = Release|Any CPU {5A378BB7-11D6-4008-980E-A67507CD9969}.Release|Any CPU.Deploy.0 = Release|Any CPU + {5A378BB7-11D6-4008-980E-A67507CD9969}.Release|x64.ActiveCfg = Release|Any CPU + {5A378BB7-11D6-4008-980E-A67507CD9969}.Release|x64.Build.0 = Release|Any CPU + {5A378BB7-11D6-4008-980E-A67507CD9969}.Release|x86.ActiveCfg = Release|Any CPU + {5A378BB7-11D6-4008-980E-A67507CD9969}.Release|x86.Build.0 = Release|Any CPU {320089C6-A141-4D3E-BD5F-C4A6CE9E567B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {320089C6-A141-4D3E-BD5F-C4A6CE9E567B}.Debug|Any CPU.Build.0 = Debug|Any CPU {320089C6-A141-4D3E-BD5F-C4A6CE9E567B}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {320089C6-A141-4D3E-BD5F-C4A6CE9E567B}.Debug|x64.ActiveCfg = Debug|Any CPU + {320089C6-A141-4D3E-BD5F-C4A6CE9E567B}.Debug|x64.Build.0 = Debug|Any CPU + {320089C6-A141-4D3E-BD5F-C4A6CE9E567B}.Debug|x86.ActiveCfg = Debug|Any CPU + {320089C6-A141-4D3E-BD5F-C4A6CE9E567B}.Debug|x86.Build.0 = Debug|Any CPU {320089C6-A141-4D3E-BD5F-C4A6CE9E567B}.Release|Any CPU.ActiveCfg = Release|Any CPU {320089C6-A141-4D3E-BD5F-C4A6CE9E567B}.Release|Any CPU.Build.0 = Release|Any CPU {320089C6-A141-4D3E-BD5F-C4A6CE9E567B}.Release|Any CPU.Deploy.0 = Release|Any CPU + {320089C6-A141-4D3E-BD5F-C4A6CE9E567B}.Release|x64.ActiveCfg = Release|Any CPU + {320089C6-A141-4D3E-BD5F-C4A6CE9E567B}.Release|x64.Build.0 = Release|Any CPU + {320089C6-A141-4D3E-BD5F-C4A6CE9E567B}.Release|x86.ActiveCfg = Release|Any CPU + {320089C6-A141-4D3E-BD5F-C4A6CE9E567B}.Release|x86.Build.0 = Release|Any CPU {F294C804-8AE2-4020-841A-AF0D97FBE80C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F294C804-8AE2-4020-841A-AF0D97FBE80C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F294C804-8AE2-4020-841A-AF0D97FBE80C}.Debug|x64.ActiveCfg = Debug|Any CPU + {F294C804-8AE2-4020-841A-AF0D97FBE80C}.Debug|x64.Build.0 = Debug|Any CPU + {F294C804-8AE2-4020-841A-AF0D97FBE80C}.Debug|x86.ActiveCfg = Debug|Any CPU + {F294C804-8AE2-4020-841A-AF0D97FBE80C}.Debug|x86.Build.0 = Debug|Any CPU {F294C804-8AE2-4020-841A-AF0D97FBE80C}.Release|Any CPU.ActiveCfg = Release|Any CPU {F294C804-8AE2-4020-841A-AF0D97FBE80C}.Release|Any CPU.Build.0 = Release|Any CPU + {F294C804-8AE2-4020-841A-AF0D97FBE80C}.Release|x64.ActiveCfg = Release|Any CPU + {F294C804-8AE2-4020-841A-AF0D97FBE80C}.Release|x64.Build.0 = Release|Any CPU + {F294C804-8AE2-4020-841A-AF0D97FBE80C}.Release|x86.ActiveCfg = Release|Any CPU + {F294C804-8AE2-4020-841A-AF0D97FBE80C}.Release|x86.Build.0 = Release|Any CPU {A95175BB-95D0-44B4-8B82-EABD166943DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A95175BB-95D0-44B4-8B82-EABD166943DA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A95175BB-95D0-44B4-8B82-EABD166943DA}.Debug|x64.ActiveCfg = Debug|Any CPU + {A95175BB-95D0-44B4-8B82-EABD166943DA}.Debug|x64.Build.0 = Debug|Any CPU + {A95175BB-95D0-44B4-8B82-EABD166943DA}.Debug|x86.ActiveCfg = Debug|Any CPU + {A95175BB-95D0-44B4-8B82-EABD166943DA}.Debug|x86.Build.0 = Debug|Any CPU {A95175BB-95D0-44B4-8B82-EABD166943DA}.Release|Any CPU.ActiveCfg = Release|Any CPU {A95175BB-95D0-44B4-8B82-EABD166943DA}.Release|Any CPU.Build.0 = Release|Any CPU - {7AA1DB5D-78DB-4693-AE50-D6078F5A0CAB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7AA1DB5D-78DB-4693-AE50-D6078F5A0CAB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7AA1DB5D-78DB-4693-AE50-D6078F5A0CAB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7AA1DB5D-78DB-4693-AE50-D6078F5A0CAB}.Release|Any CPU.Build.0 = Release|Any CPU - {48783186-230D-4048-A97A-E4F1DF43BF5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {48783186-230D-4048-A97A-E4F1DF43BF5C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {48783186-230D-4048-A97A-E4F1DF43BF5C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {48783186-230D-4048-A97A-E4F1DF43BF5C}.Release|Any CPU.Build.0 = Release|Any CPU + {A95175BB-95D0-44B4-8B82-EABD166943DA}.Release|x64.ActiveCfg = Release|Any CPU + {A95175BB-95D0-44B4-8B82-EABD166943DA}.Release|x64.Build.0 = Release|Any CPU + {A95175BB-95D0-44B4-8B82-EABD166943DA}.Release|x86.ActiveCfg = Release|Any CPU + {A95175BB-95D0-44B4-8B82-EABD166943DA}.Release|x86.Build.0 = Release|Any CPU {6BEB95A6-0673-4AF5-892E-9146FF8B0948}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6BEB95A6-0673-4AF5-892E-9146FF8B0948}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6BEB95A6-0673-4AF5-892E-9146FF8B0948}.Debug|x64.ActiveCfg = Debug|Any CPU + {6BEB95A6-0673-4AF5-892E-9146FF8B0948}.Debug|x64.Build.0 = Debug|Any CPU + {6BEB95A6-0673-4AF5-892E-9146FF8B0948}.Debug|x86.ActiveCfg = Debug|Any CPU + {6BEB95A6-0673-4AF5-892E-9146FF8B0948}.Debug|x86.Build.0 = Debug|Any CPU {6BEB95A6-0673-4AF5-892E-9146FF8B0948}.Release|Any CPU.ActiveCfg = Release|Any CPU {6BEB95A6-0673-4AF5-892E-9146FF8B0948}.Release|Any CPU.Build.0 = Release|Any CPU + {6BEB95A6-0673-4AF5-892E-9146FF8B0948}.Release|x64.ActiveCfg = Release|Any CPU + {6BEB95A6-0673-4AF5-892E-9146FF8B0948}.Release|x64.Build.0 = Release|Any CPU + {6BEB95A6-0673-4AF5-892E-9146FF8B0948}.Release|x86.ActiveCfg = Release|Any CPU + {6BEB95A6-0673-4AF5-892E-9146FF8B0948}.Release|x86.Build.0 = Release|Any CPU + {FC0A9040-7BAF-4524-B398-8C7A1C7DDEE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FC0A9040-7BAF-4524-B398-8C7A1C7DDEE9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FC0A9040-7BAF-4524-B398-8C7A1C7DDEE9}.Debug|x64.ActiveCfg = Debug|Any CPU + {FC0A9040-7BAF-4524-B398-8C7A1C7DDEE9}.Debug|x64.Build.0 = Debug|Any CPU + {FC0A9040-7BAF-4524-B398-8C7A1C7DDEE9}.Debug|x86.ActiveCfg = Debug|Any CPU + {FC0A9040-7BAF-4524-B398-8C7A1C7DDEE9}.Debug|x86.Build.0 = Debug|Any CPU + {FC0A9040-7BAF-4524-B398-8C7A1C7DDEE9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FC0A9040-7BAF-4524-B398-8C7A1C7DDEE9}.Release|Any CPU.Build.0 = Release|Any CPU + {FC0A9040-7BAF-4524-B398-8C7A1C7DDEE9}.Release|x64.ActiveCfg = Release|Any CPU + {FC0A9040-7BAF-4524-B398-8C7A1C7DDEE9}.Release|x64.Build.0 = Release|Any CPU + {FC0A9040-7BAF-4524-B398-8C7A1C7DDEE9}.Release|x86.ActiveCfg = Release|Any CPU + {FC0A9040-7BAF-4524-B398-8C7A1C7DDEE9}.Release|x86.Build.0 = Release|Any CPU {6E3EBF71-8664-49D7-BD0D-2B21B3EEC540}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6E3EBF71-8664-49D7-BD0D-2B21B3EEC540}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6E3EBF71-8664-49D7-BD0D-2B21B3EEC540}.Debug|x64.ActiveCfg = Debug|Any CPU + {6E3EBF71-8664-49D7-BD0D-2B21B3EEC540}.Debug|x64.Build.0 = Debug|Any CPU + {6E3EBF71-8664-49D7-BD0D-2B21B3EEC540}.Debug|x86.ActiveCfg = Debug|Any CPU + {6E3EBF71-8664-49D7-BD0D-2B21B3EEC540}.Debug|x86.Build.0 = Debug|Any CPU {6E3EBF71-8664-49D7-BD0D-2B21B3EEC540}.Release|Any CPU.ActiveCfg = Release|Any CPU {6E3EBF71-8664-49D7-BD0D-2B21B3EEC540}.Release|Any CPU.Build.0 = Release|Any CPU + {6E3EBF71-8664-49D7-BD0D-2B21B3EEC540}.Release|x64.ActiveCfg = Release|Any CPU + {6E3EBF71-8664-49D7-BD0D-2B21B3EEC540}.Release|x64.Build.0 = Release|Any CPU + {6E3EBF71-8664-49D7-BD0D-2B21B3EEC540}.Release|x86.ActiveCfg = Release|Any CPU + {6E3EBF71-8664-49D7-BD0D-2B21B3EEC540}.Release|x86.Build.0 = Release|Any CPU {55AB973D-ECA0-422B-B367-24BC47DA081B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {55AB973D-ECA0-422B-B367-24BC47DA081B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {55AB973D-ECA0-422B-B367-24BC47DA081B}.Debug|x64.ActiveCfg = Debug|Any CPU + {55AB973D-ECA0-422B-B367-24BC47DA081B}.Debug|x64.Build.0 = Debug|Any CPU + {55AB973D-ECA0-422B-B367-24BC47DA081B}.Debug|x86.ActiveCfg = Debug|Any CPU + {55AB973D-ECA0-422B-B367-24BC47DA081B}.Debug|x86.Build.0 = Debug|Any CPU {55AB973D-ECA0-422B-B367-24BC47DA081B}.Release|Any CPU.ActiveCfg = Release|Any CPU {55AB973D-ECA0-422B-B367-24BC47DA081B}.Release|Any CPU.Build.0 = Release|Any CPU - {FC0A9040-7BAF-4524-B398-8C7A1C7DDEE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FC0A9040-7BAF-4524-B398-8C7A1C7DDEE9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FC0A9040-7BAF-4524-B398-8C7A1C7DDEE9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FC0A9040-7BAF-4524-B398-8C7A1C7DDEE9}.Release|Any CPU.Build.0 = Release|Any CPU - {7809CB42-8FED-4BB7-8C68-7638357B94A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7809CB42-8FED-4BB7-8C68-7638357B94A6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7809CB42-8FED-4BB7-8C68-7638357B94A6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7809CB42-8FED-4BB7-8C68-7638357B94A6}.Release|Any CPU.Build.0 = Release|Any CPU + {55AB973D-ECA0-422B-B367-24BC47DA081B}.Release|x64.ActiveCfg = Release|Any CPU + {55AB973D-ECA0-422B-B367-24BC47DA081B}.Release|x64.Build.0 = Release|Any CPU + {55AB973D-ECA0-422B-B367-24BC47DA081B}.Release|x86.ActiveCfg = Release|Any CPU + {55AB973D-ECA0-422B-B367-24BC47DA081B}.Release|x86.Build.0 = Release|Any CPU {4C728441-4C3D-4AE4-9C0F-EA91E2C70965}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4C728441-4C3D-4AE4-9C0F-EA91E2C70965}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4C728441-4C3D-4AE4-9C0F-EA91E2C70965}.Debug|x64.ActiveCfg = Debug|Any CPU + {4C728441-4C3D-4AE4-9C0F-EA91E2C70965}.Debug|x64.Build.0 = Debug|Any CPU + {4C728441-4C3D-4AE4-9C0F-EA91E2C70965}.Debug|x86.ActiveCfg = Debug|Any CPU + {4C728441-4C3D-4AE4-9C0F-EA91E2C70965}.Debug|x86.Build.0 = Debug|Any CPU {4C728441-4C3D-4AE4-9C0F-EA91E2C70965}.Release|Any CPU.ActiveCfg = Release|Any CPU {4C728441-4C3D-4AE4-9C0F-EA91E2C70965}.Release|Any CPU.Build.0 = Release|Any CPU - {0309CF11-621A-4F23-8FBA-A583303A8531}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0309CF11-621A-4F23-8FBA-A583303A8531}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0309CF11-621A-4F23-8FBA-A583303A8531}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0309CF11-621A-4F23-8FBA-A583303A8531}.Release|Any CPU.Build.0 = Release|Any CPU + {4C728441-4C3D-4AE4-9C0F-EA91E2C70965}.Release|x64.ActiveCfg = Release|Any CPU + {4C728441-4C3D-4AE4-9C0F-EA91E2C70965}.Release|x64.Build.0 = Release|Any CPU + {4C728441-4C3D-4AE4-9C0F-EA91E2C70965}.Release|x86.ActiveCfg = Release|Any CPU + {4C728441-4C3D-4AE4-9C0F-EA91E2C70965}.Release|x86.Build.0 = Release|Any CPU + {7809CB42-8FED-4BB7-8C68-7638357B94A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7809CB42-8FED-4BB7-8C68-7638357B94A6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7809CB42-8FED-4BB7-8C68-7638357B94A6}.Debug|x64.ActiveCfg = Debug|Any CPU + {7809CB42-8FED-4BB7-8C68-7638357B94A6}.Debug|x64.Build.0 = Debug|Any CPU + {7809CB42-8FED-4BB7-8C68-7638357B94A6}.Debug|x86.ActiveCfg = Debug|Any CPU + {7809CB42-8FED-4BB7-8C68-7638357B94A6}.Debug|x86.Build.0 = Debug|Any CPU + {7809CB42-8FED-4BB7-8C68-7638357B94A6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7809CB42-8FED-4BB7-8C68-7638357B94A6}.Release|Any CPU.Build.0 = Release|Any CPU + {7809CB42-8FED-4BB7-8C68-7638357B94A6}.Release|x64.ActiveCfg = Release|Any CPU + {7809CB42-8FED-4BB7-8C68-7638357B94A6}.Release|x64.Build.0 = Release|Any CPU + {7809CB42-8FED-4BB7-8C68-7638357B94A6}.Release|x86.ActiveCfg = Release|Any CPU + {7809CB42-8FED-4BB7-8C68-7638357B94A6}.Release|x86.Build.0 = Release|Any CPU {9E4B69EE-34E6-47CF-8346-2A66D1714FCD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9E4B69EE-34E6-47CF-8346-2A66D1714FCD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9E4B69EE-34E6-47CF-8346-2A66D1714FCD}.Debug|x64.ActiveCfg = Debug|Any CPU + {9E4B69EE-34E6-47CF-8346-2A66D1714FCD}.Debug|x64.Build.0 = Debug|Any CPU + {9E4B69EE-34E6-47CF-8346-2A66D1714FCD}.Debug|x86.ActiveCfg = Debug|Any CPU + {9E4B69EE-34E6-47CF-8346-2A66D1714FCD}.Debug|x86.Build.0 = Debug|Any CPU {9E4B69EE-34E6-47CF-8346-2A66D1714FCD}.Release|Any CPU.ActiveCfg = Release|Any CPU {9E4B69EE-34E6-47CF-8346-2A66D1714FCD}.Release|Any CPU.Build.0 = Release|Any CPU + {9E4B69EE-34E6-47CF-8346-2A66D1714FCD}.Release|x64.ActiveCfg = Release|Any CPU + {9E4B69EE-34E6-47CF-8346-2A66D1714FCD}.Release|x64.Build.0 = Release|Any CPU + {9E4B69EE-34E6-47CF-8346-2A66D1714FCD}.Release|x86.ActiveCfg = Release|Any CPU + {9E4B69EE-34E6-47CF-8346-2A66D1714FCD}.Release|x86.Build.0 = Release|Any CPU + {0309CF11-621A-4F23-8FBA-A583303A8531}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0309CF11-621A-4F23-8FBA-A583303A8531}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0309CF11-621A-4F23-8FBA-A583303A8531}.Debug|x64.ActiveCfg = Debug|Any CPU + {0309CF11-621A-4F23-8FBA-A583303A8531}.Debug|x64.Build.0 = Debug|Any CPU + {0309CF11-621A-4F23-8FBA-A583303A8531}.Debug|x86.ActiveCfg = Debug|Any CPU + {0309CF11-621A-4F23-8FBA-A583303A8531}.Debug|x86.Build.0 = Debug|Any CPU + {0309CF11-621A-4F23-8FBA-A583303A8531}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0309CF11-621A-4F23-8FBA-A583303A8531}.Release|Any CPU.Build.0 = Release|Any CPU + {0309CF11-621A-4F23-8FBA-A583303A8531}.Release|x64.ActiveCfg = Release|Any CPU + {0309CF11-621A-4F23-8FBA-A583303A8531}.Release|x64.Build.0 = Release|Any CPU + {0309CF11-621A-4F23-8FBA-A583303A8531}.Release|x86.ActiveCfg = Release|Any CPU + {0309CF11-621A-4F23-8FBA-A583303A8531}.Release|x86.Build.0 = Release|Any CPU + {7AA1DB5D-78DB-4693-AE50-D6078F5A0CAB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7AA1DB5D-78DB-4693-AE50-D6078F5A0CAB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7AA1DB5D-78DB-4693-AE50-D6078F5A0CAB}.Debug|x64.ActiveCfg = Debug|Any CPU + {7AA1DB5D-78DB-4693-AE50-D6078F5A0CAB}.Debug|x64.Build.0 = Debug|Any CPU + {7AA1DB5D-78DB-4693-AE50-D6078F5A0CAB}.Debug|x86.ActiveCfg = Debug|Any CPU + {7AA1DB5D-78DB-4693-AE50-D6078F5A0CAB}.Debug|x86.Build.0 = Debug|Any CPU + {7AA1DB5D-78DB-4693-AE50-D6078F5A0CAB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7AA1DB5D-78DB-4693-AE50-D6078F5A0CAB}.Release|Any CPU.Build.0 = Release|Any CPU + {7AA1DB5D-78DB-4693-AE50-D6078F5A0CAB}.Release|x64.ActiveCfg = Release|Any CPU + {7AA1DB5D-78DB-4693-AE50-D6078F5A0CAB}.Release|x64.Build.0 = Release|Any CPU + {7AA1DB5D-78DB-4693-AE50-D6078F5A0CAB}.Release|x86.ActiveCfg = Release|Any CPU + {7AA1DB5D-78DB-4693-AE50-D6078F5A0CAB}.Release|x86.Build.0 = Release|Any CPU + {48783186-230D-4048-A97A-E4F1DF43BF5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {48783186-230D-4048-A97A-E4F1DF43BF5C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {48783186-230D-4048-A97A-E4F1DF43BF5C}.Debug|x64.ActiveCfg = Debug|Any CPU + {48783186-230D-4048-A97A-E4F1DF43BF5C}.Debug|x64.Build.0 = Debug|Any CPU + {48783186-230D-4048-A97A-E4F1DF43BF5C}.Debug|x86.ActiveCfg = Debug|Any CPU + {48783186-230D-4048-A97A-E4F1DF43BF5C}.Debug|x86.Build.0 = Debug|Any CPU + {48783186-230D-4048-A97A-E4F1DF43BF5C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {48783186-230D-4048-A97A-E4F1DF43BF5C}.Release|Any CPU.Build.0 = Release|Any CPU + {48783186-230D-4048-A97A-E4F1DF43BF5C}.Release|x64.ActiveCfg = Release|Any CPU + {48783186-230D-4048-A97A-E4F1DF43BF5C}.Release|x64.Build.0 = Release|Any CPU + {48783186-230D-4048-A97A-E4F1DF43BF5C}.Release|x86.ActiveCfg = Release|Any CPU + {48783186-230D-4048-A97A-E4F1DF43BF5C}.Release|x86.Build.0 = Release|Any CPU {BCFABDF9-AC1B-41B6-959E-04676F0C20F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BCFABDF9-AC1B-41B6-959E-04676F0C20F8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BCFABDF9-AC1B-41B6-959E-04676F0C20F8}.Debug|x64.ActiveCfg = Debug|Any CPU + {BCFABDF9-AC1B-41B6-959E-04676F0C20F8}.Debug|x64.Build.0 = Debug|Any CPU + {BCFABDF9-AC1B-41B6-959E-04676F0C20F8}.Debug|x86.ActiveCfg = Debug|Any CPU + {BCFABDF9-AC1B-41B6-959E-04676F0C20F8}.Debug|x86.Build.0 = Debug|Any CPU {BCFABDF9-AC1B-41B6-959E-04676F0C20F8}.Release|Any CPU.ActiveCfg = Release|Any CPU {BCFABDF9-AC1B-41B6-959E-04676F0C20F8}.Release|Any CPU.Build.0 = Release|Any CPU + {BCFABDF9-AC1B-41B6-959E-04676F0C20F8}.Release|x64.ActiveCfg = Release|Any CPU + {BCFABDF9-AC1B-41B6-959E-04676F0C20F8}.Release|x64.Build.0 = Release|Any CPU + {BCFABDF9-AC1B-41B6-959E-04676F0C20F8}.Release|x86.ActiveCfg = Release|Any CPU + {BCFABDF9-AC1B-41B6-959E-04676F0C20F8}.Release|x86.Build.0 = Release|Any CPU {A0DDCF0A-A352-4CC6-8E6E-0E16CAA50CDD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A0DDCF0A-A352-4CC6-8E6E-0E16CAA50CDD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A0DDCF0A-A352-4CC6-8E6E-0E16CAA50CDD}.Debug|x64.ActiveCfg = Debug|Any CPU + {A0DDCF0A-A352-4CC6-8E6E-0E16CAA50CDD}.Debug|x64.Build.0 = Debug|Any CPU + {A0DDCF0A-A352-4CC6-8E6E-0E16CAA50CDD}.Debug|x86.ActiveCfg = Debug|Any CPU + {A0DDCF0A-A352-4CC6-8E6E-0E16CAA50CDD}.Debug|x86.Build.0 = Debug|Any CPU {A0DDCF0A-A352-4CC6-8E6E-0E16CAA50CDD}.Release|Any CPU.ActiveCfg = Release|Any CPU {A0DDCF0A-A352-4CC6-8E6E-0E16CAA50CDD}.Release|Any CPU.Build.0 = Release|Any CPU + {A0DDCF0A-A352-4CC6-8E6E-0E16CAA50CDD}.Release|x64.ActiveCfg = Release|Any CPU + {A0DDCF0A-A352-4CC6-8E6E-0E16CAA50CDD}.Release|x64.Build.0 = Release|Any CPU + {A0DDCF0A-A352-4CC6-8E6E-0E16CAA50CDD}.Release|x86.ActiveCfg = Release|Any CPU + {A0DDCF0A-A352-4CC6-8E6E-0E16CAA50CDD}.Release|x86.Build.0 = Release|Any CPU + {5D0C3B33-2DCA-4912-AA53-B05CD80A60CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5D0C3B33-2DCA-4912-AA53-B05CD80A60CE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5D0C3B33-2DCA-4912-AA53-B05CD80A60CE}.Debug|x64.ActiveCfg = Debug|Any CPU + {5D0C3B33-2DCA-4912-AA53-B05CD80A60CE}.Debug|x64.Build.0 = Debug|Any CPU + {5D0C3B33-2DCA-4912-AA53-B05CD80A60CE}.Debug|x86.ActiveCfg = Debug|Any CPU + {5D0C3B33-2DCA-4912-AA53-B05CD80A60CE}.Debug|x86.Build.0 = Debug|Any CPU + {5D0C3B33-2DCA-4912-AA53-B05CD80A60CE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5D0C3B33-2DCA-4912-AA53-B05CD80A60CE}.Release|Any CPU.Build.0 = Release|Any CPU + {5D0C3B33-2DCA-4912-AA53-B05CD80A60CE}.Release|x64.ActiveCfg = Release|Any CPU + {5D0C3B33-2DCA-4912-AA53-B05CD80A60CE}.Release|x64.Build.0 = Release|Any CPU + {5D0C3B33-2DCA-4912-AA53-B05CD80A60CE}.Release|x86.ActiveCfg = Release|Any CPU + {5D0C3B33-2DCA-4912-AA53-B05CD80A60CE}.Release|x86.Build.0 = Release|Any CPU + {A88F62DA-DD29-4FD3-BF1E-9C8783C4C892}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A88F62DA-DD29-4FD3-BF1E-9C8783C4C892}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A88F62DA-DD29-4FD3-BF1E-9C8783C4C892}.Debug|x64.ActiveCfg = Debug|Any CPU + {A88F62DA-DD29-4FD3-BF1E-9C8783C4C892}.Debug|x64.Build.0 = Debug|Any CPU + {A88F62DA-DD29-4FD3-BF1E-9C8783C4C892}.Debug|x86.ActiveCfg = Debug|Any CPU + {A88F62DA-DD29-4FD3-BF1E-9C8783C4C892}.Debug|x86.Build.0 = Debug|Any CPU + {A88F62DA-DD29-4FD3-BF1E-9C8783C4C892}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A88F62DA-DD29-4FD3-BF1E-9C8783C4C892}.Release|Any CPU.Build.0 = Release|Any CPU + {A88F62DA-DD29-4FD3-BF1E-9C8783C4C892}.Release|x64.ActiveCfg = Release|Any CPU + {A88F62DA-DD29-4FD3-BF1E-9C8783C4C892}.Release|x64.Build.0 = Release|Any CPU + {A88F62DA-DD29-4FD3-BF1E-9C8783C4C892}.Release|x86.ActiveCfg = Release|Any CPU + {A88F62DA-DD29-4FD3-BF1E-9C8783C4C892}.Release|x86.Build.0 = Release|Any CPU + {F7B982C2-014C-4AFD-8A9B-51809242482C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F7B982C2-014C-4AFD-8A9B-51809242482C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F7B982C2-014C-4AFD-8A9B-51809242482C}.Debug|x64.ActiveCfg = Debug|Any CPU + {F7B982C2-014C-4AFD-8A9B-51809242482C}.Debug|x64.Build.0 = Debug|Any CPU + {F7B982C2-014C-4AFD-8A9B-51809242482C}.Debug|x86.ActiveCfg = Debug|Any CPU + {F7B982C2-014C-4AFD-8A9B-51809242482C}.Debug|x86.Build.0 = Debug|Any CPU + {F7B982C2-014C-4AFD-8A9B-51809242482C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F7B982C2-014C-4AFD-8A9B-51809242482C}.Release|Any CPU.Build.0 = Release|Any CPU + {F7B982C2-014C-4AFD-8A9B-51809242482C}.Release|x64.ActiveCfg = Release|Any CPU + {F7B982C2-014C-4AFD-8A9B-51809242482C}.Release|x64.Build.0 = Release|Any CPU + {F7B982C2-014C-4AFD-8A9B-51809242482C}.Release|x86.ActiveCfg = Release|Any CPU + {F7B982C2-014C-4AFD-8A9B-51809242482C}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {27D12E10-E38E-4ECE-8DD1-77E8C387B2DD} - EndGlobalSection GlobalSection(NestedProjects) = preSolution {A95175BB-95D0-44B4-8B82-EABD166943DA} = {454655D7-6244-47A2-A379-3D019FBD6DD2} - {5307589D-87A1-459B-BBD2-1077AA25EB1E} = {454655D7-6244-47A2-A379-3D019FBD6DD2} - {55AB973D-ECA0-422B-B367-24BC47DA081B} = {5307589D-87A1-459B-BBD2-1077AA25EB1E} {6BEB95A6-0673-4AF5-892E-9146FF8B0948} = {5307589D-87A1-459B-BBD2-1077AA25EB1E} {FC0A9040-7BAF-4524-B398-8C7A1C7DDEE9} = {5307589D-87A1-459B-BBD2-1077AA25EB1E} {6E3EBF71-8664-49D7-BD0D-2B21B3EEC540} = {5307589D-87A1-459B-BBD2-1077AA25EB1E} + {55AB973D-ECA0-422B-B367-24BC47DA081B} = {5307589D-87A1-459B-BBD2-1077AA25EB1E} + {5307589D-87A1-459B-BBD2-1077AA25EB1E} = {454655D7-6244-47A2-A379-3D019FBD6DD2} {139F6FAA-EF59-4ADC-A69B-33CA7D1C1D4E} = {454655D7-6244-47A2-A379-3D019FBD6DD2} {4C728441-4C3D-4AE4-9C0F-EA91E2C70965} = {139F6FAA-EF59-4ADC-A69B-33CA7D1C1D4E} {7809CB42-8FED-4BB7-8C68-7638357B94A6} = {139F6FAA-EF59-4ADC-A69B-33CA7D1C1D4E} @@ -208,5 +457,13 @@ Global {7AA1DB5D-78DB-4693-AE50-D6078F5A0CAB} = {5307589D-87A1-459B-BBD2-1077AA25EB1E} {48783186-230D-4048-A97A-E4F1DF43BF5C} = {139F6FAA-EF59-4ADC-A69B-33CA7D1C1D4E} {50334A1F-990D-45FA-A1FE-C92F1994D97B} = {D29A2153-C171-457E-A147-720976BA430F} + {3DDCF21F-A4AC-2952-3A5E-46AAD7F00BF1} = {B3415621-5EBA-1A55-0B57-0078FEC59DC7} + {E00BDB6B-4D28-95B9-EEF8-DB6484FA30AD} = {3DDCF21F-A4AC-2952-3A5E-46AAD7F00BF1} + {5D0C3B33-2DCA-4912-AA53-B05CD80A60CE} = {E00BDB6B-4D28-95B9-EEF8-DB6484FA30AD} + {A88F62DA-DD29-4FD3-BF1E-9C8783C4C892} = {E00BDB6B-4D28-95B9-EEF8-DB6484FA30AD} + {F7B982C2-014C-4AFD-8A9B-51809242482C} = {E00BDB6B-4D28-95B9-EEF8-DB6484FA30AD} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {27D12E10-E38E-4ECE-8DD1-77E8C387B2DD} EndGlobalSection EndGlobal diff --git a/osu.Framework.Android.props b/osu.Framework.Android.props index 49d48dfb58..1969bfaa38 100644 --- a/osu.Framework.Android.props +++ b/osu.Framework.Android.props @@ -7,7 +7,7 @@ true true - $(NoWarn);XA4218 + $(NoWarn);XA4218;JAVAC diff --git a/osu.Framework.Android/AndroidGameHost.cs b/osu.Framework.Android/AndroidGameHost.cs index b6d3106c35..cc7777eb98 100644 --- a/osu.Framework.Android/AndroidGameHost.cs +++ b/osu.Framework.Android/AndroidGameHost.cs @@ -40,6 +40,24 @@ protected override void SetupConfig(IDictionary defaul base.SetupConfig(defaultOverrides); } + protected override void SetupForRun() + { + base.SetupForRun(); + + // Set the main thread to THREAD_PRIORITY_DISPLAY (-4) for scheduler prioritisation. + // In SingleThread mode (the default on Android), the main thread handles all game threads + // including rendering. This gives the rendering work higher scheduler priority. + try + { + global::Android.OS.Process.SetThreadPriority(global::Android.OS.ThreadPriority.Display); + Logger.Log("Android thread priority set to THREAD_PRIORITY_DISPLAY.", LoggingTarget.Runtime, LogLevel.Important); + } + catch (Exception ex) + { + Logger.Log($"Failed to set Android thread priority: {ex.Message}", LoggingTarget.Runtime, LogLevel.Debug); + } + } + protected override IWindow CreateWindow(GraphicsSurfaceType preferredSurface) => new AndroidGameWindow(preferredSurface, Options.FriendlyGameName); protected override void DrawFrame() diff --git a/osu.Framework.Tests/Bindables/BindableNumberTest.cs b/osu.Framework.Tests/Bindables/BindableNumberTest.cs index e91e7f6fe6..21dbfe1511 100644 --- a/osu.Framework.Tests/Bindables/BindableNumberTest.cs +++ b/osu.Framework.Tests/Bindables/BindableNumberTest.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Reflection; using NUnit.Framework; using osu.Framework.Bindables; @@ -41,6 +42,8 @@ public void TestConstruction(Type type) /// Tests that value can be set on all supported types. /// [TestCaseSource(nameof(typeSource))] + [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Test types are always preserved.")] + [UnconditionalSuppressMessage("Trimming", "IL2060", Justification = "Test types are always preserved.")] public void TestSetValue(Type type) { object expectedValue = Convert.ChangeType(1, type); @@ -87,6 +90,8 @@ public void TestDecimalPrecision() /// Tests that value can be added to on all supported types. /// [TestCaseSource(nameof(typeSource))] + [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Test types are always preserved.")] + [UnconditionalSuppressMessage("Trimming", "IL2060", Justification = "Test types are always preserved.")] public void TestAddValue(Type type) { object expectedValue = Convert.ChangeType(1, type); @@ -139,6 +144,8 @@ public void TestValueChangeEventOccursAfterPrecisionChangeEvent() Assert.That(bindable1ValueChange, Is.EqualTo(4)); } + [UnconditionalSuppressMessage("Trimming", "IL2091", Justification = "Test types are always preserved.")] + [UnconditionalSuppressMessage("Trimming", "IL2070", Justification = "Test types are always preserved.")] private object createBindable(Type type) => Activator.CreateInstance(typeof(BindableNumber<>).MakeGenericType(type), Convert.ChangeType(0, type)); } } diff --git a/osu.Framework.Tests/Bindables/BindableTest.cs b/osu.Framework.Tests/Bindables/BindableTest.cs index ab00765ac9..3baebc994e 100644 --- a/osu.Framework.Tests/Bindables/BindableTest.cs +++ b/osu.Framework.Tests/Bindables/BindableTest.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Reflection; using NUnit.Framework; @@ -96,6 +97,9 @@ public void TestParseBindableOfMatchingInterfaceType() } [TestCaseSource(nameof(getParsingConversionTests))] + [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Test types are always preserved.")] + [UnconditionalSuppressMessage("Trimming", "IL2072", Justification = "Test types are always preserved.")] + [UnconditionalSuppressMessage("Trimming", "IL2070", Justification = "Test types are always preserved.")] public void TestParse(Type type, object input, object output) { object bindable = Activator.CreateInstance(typeof(Bindable<>).MakeGenericType(type), type == typeof(string) ? "" : Activator.CreateInstance(type)); diff --git a/osu.Framework.Tests/Extensions/TestIsNullableTypeExtensions.cs b/osu.Framework.Tests/Extensions/TestIsNullableTypeExtensions.cs index 8c1fdd4719..150b41387b 100644 --- a/osu.Framework.Tests/Extensions/TestIsNullableTypeExtensions.cs +++ b/osu.Framework.Tests/Extensions/TestIsNullableTypeExtensions.cs @@ -16,6 +16,7 @@ namespace osu.Framework.Tests.Extensions [SuppressMessage("ReSharper", "UnassignedGetOnlyAutoProperty")] [SuppressMessage("ReSharper", "ValueParameterNotUsed")] [SuppressMessage("ReSharper", "UnusedParameter.Local")] + [UnconditionalSuppressMessage("Trimming", "IL2070", Justification = "Test types are always preserved.")] public class TestIsNullableTypeExtensions { private const BindingFlags binding_flags = BindingFlags.Instance | BindingFlags.NonPublic; diff --git a/osu.Framework.Tests/IO/TestWebRequest.cs b/osu.Framework.Tests/IO/TestWebRequest.cs index b87305df15..5caa67181a 100644 --- a/osu.Framework.Tests/IO/TestWebRequest.cs +++ b/osu.Framework.Tests/IO/TestWebRequest.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Net; using System.Net.Http; using System.Reflection; @@ -509,6 +510,7 @@ public void TestFailTimeout() /// Tests being able to abort + restart a request. /// [Test, Retry(5)] + [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Test types are always preserved.")] public void TestEventUnbindOnCompletion([Values(true, false)] bool async) { var request = new JsonWebRequest($"{default_protocol}://{host}/get") @@ -536,6 +538,7 @@ public void TestEventUnbindOnCompletion([Values(true, false)] bool async) /// Tests being able to abort + restart a request. /// [Test, Retry(5)] + [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Test types are always preserved.")] public void TestUnbindOnDispose([Values(true, false)] bool async) { var request = new JsonWebRequest($"{default_protocol}://{host}/get") @@ -631,6 +634,7 @@ public void TestPostWithJsonResponse([Values(true, false)] bool async) } [Test, Retry(5)] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Test types are always preserved.")] public void TestPostWithJsonRequest([Values(true, false)] bool async) { var request = new JsonWebRequest($"{default_protocol}://{host}/post") @@ -658,6 +662,7 @@ public void TestPostWithJsonRequest([Values(true, false)] bool async) } [Test, Retry(5)] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Test types are always preserved.")] public void TestNoContentPost([Values(true, false)] bool async) { var request = new WebRequest($"{default_protocol}://{host}/post") diff --git a/osu.Framework.iOS.props b/osu.Framework.iOS.props index 502cfb3184..7240d04721 100644 --- a/osu.Framework.iOS.props +++ b/osu.Framework.iOS.props @@ -5,7 +5,12 @@ - $(NoWarn);MT7091 + + $(NoWarn);MT7091;IL2104;IL2026;IL2045 diff --git a/osu.Framework/Allocation/BackgroundDependencyLoaderAttribute.cs b/osu.Framework/Allocation/BackgroundDependencyLoaderAttribute.cs index 7ce37be9d2..bae9bea79f 100644 --- a/osu.Framework/Allocation/BackgroundDependencyLoaderAttribute.cs +++ b/osu.Framework/Allocation/BackgroundDependencyLoaderAttribute.cs @@ -5,6 +5,7 @@ using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Runtime.ExceptionServices; @@ -44,6 +45,7 @@ public BackgroundDependencyLoaderAttribute(bool permitNulls) this.permitNulls = permitNulls; } + [UnconditionalSuppressMessage("Trimming", "IL2070", Justification = "Types used with DI are preserved by the framework's dependency container.")] internal static InjectDependencyDelegate CreateActivator(Type type) { count_reflection_attributes.Value++; diff --git a/osu.Framework/Allocation/CachedAttribute.cs b/osu.Framework/Allocation/CachedAttribute.cs index e5d20911cd..dc1cc04d4c 100644 --- a/osu.Framework/Allocation/CachedAttribute.cs +++ b/osu.Framework/Allocation/CachedAttribute.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; @@ -122,6 +123,7 @@ public CachedAttribute(Type type = null, string name = null) Name = name; } + [UnconditionalSuppressMessage("Trimming", "IL2070", Justification = "Types used with DI are preserved by the framework's dependency container.")] internal static CacheDependencyDelegate CreateActivator(Type type) { count_reflection_attributes.Value++; diff --git a/osu.Framework/Allocation/CachedModelDependencyContainer.cs b/osu.Framework/Allocation/CachedModelDependencyContainer.cs index ad1716b830..7421d8744a 100644 --- a/osu.Framework/Allocation/CachedModelDependencyContainer.cs +++ b/osu.Framework/Allocation/CachedModelDependencyContainer.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Diagnostics.CodeAnalysis; using System.Reflection; using osu.Framework.Bindables; using osu.Framework.Extensions.TypeExtensions; @@ -84,6 +85,7 @@ private TModel createChildShadowModel() /// The shadow model to update. /// The model to unbind from. /// The model to bind to. + [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Types used with DI are preserved by the framework's dependency container.")] private void updateShadowModel(TModel targetShadowModel, TModel? lastModel, TModel newModel) { if (lastModel != null) diff --git a/osu.Framework/Allocation/ResolvedAttribute.cs b/osu.Framework/Allocation/ResolvedAttribute.cs index 07e5dcda7c..52e40a976b 100644 --- a/osu.Framework/Allocation/ResolvedAttribute.cs +++ b/osu.Framework/Allocation/ResolvedAttribute.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using JetBrains.Annotations; @@ -74,6 +75,7 @@ public ResolvedAttribute(Type parent = null, string name = null, bool canBeNull CanBeNull = canBeNull; } + [UnconditionalSuppressMessage("Trimming", "IL2070", Justification = "Types used with DI are preserved by the framework's dependency container.")] internal static InjectDependencyDelegate CreateActivator(Type type) { count_reflection_attributes.Value++; diff --git a/osu.Framework/Bindables/IBindableWithCurrent.cs b/osu.Framework/Bindables/IBindableWithCurrent.cs index df1c97018f..a82e66a663 100644 --- a/osu.Framework/Bindables/IBindableWithCurrent.cs +++ b/osu.Framework/Bindables/IBindableWithCurrent.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using System.Diagnostics.CodeAnalysis; using osu.Framework.Graphics.UserInterface; using osu.Framework.Utils; @@ -16,6 +17,7 @@ public interface IBindableWithCurrent : IBindable, IHasCurrentValue /// If the value type is one supported by the , an instance of will be returned. /// Otherwise an instance of will be returned instead. /// + [UnconditionalSuppressMessage("Trimming", "IL2091", Justification = "Types used with DI are preserved by the framework's dependency container.")] static IBindableWithCurrent Create() { if (Validation.IsSupportedBindableNumberType()) diff --git a/osu.Framework/Configuration/FrameSync.cs b/osu.Framework/Configuration/FrameSync.cs index 2630c2b06c..5eddce96ef 100644 --- a/osu.Framework/Configuration/FrameSync.cs +++ b/osu.Framework/Configuration/FrameSync.cs @@ -12,6 +12,9 @@ public enum FrameSync { VSync, + [Description("VSync Unbuffered")] + UVSync, + [Description("2x refresh rate")] Limit2x, @@ -23,5 +26,8 @@ public enum FrameSync [Description("Basically unlimited")] Unlimited, + + [Description("Custom")] + Custom, } } diff --git a/osu.Framework/Configuration/FrameworkConfigManager.cs b/osu.Framework/Configuration/FrameworkConfigManager.cs index 8a1f261ab0..b3867831ee 100644 --- a/osu.Framework/Configuration/FrameworkConfigManager.cs +++ b/osu.Framework/Configuration/FrameworkConfigManager.cs @@ -8,6 +8,7 @@ using System.Drawing; using osu.Framework.Configuration.Tracking; using osu.Framework.Extensions; +using osu.Framework.Graphics.Rendering.LowLatency; using osu.Framework.Graphics.Video; using osu.Framework.Input; using osu.Framework.Platform; @@ -40,8 +41,10 @@ protected override void InitialiseDefaults() SetDefault(FrameworkSetting.SizeFullscreen, new Size(9999, 9999), new Size(320, 240)); SetDefault(FrameworkSetting.MinimiseOnFocusLossInFullscreen, RuntimeInfo.IsDesktop); SetDefault(FrameworkSetting.FrameSync, FrameSync.Limit2x); + SetDefault(FrameworkSetting.CustomDrawLimit, 0, 0, 1000); SetDefault(FrameworkSetting.WindowMode, WindowMode.Windowed); SetDefault(FrameworkSetting.Renderer, RendererType.Automatic); + SetDefault(FrameworkSetting.LatencyMode, LatencyMode.Off); SetDefault(FrameworkSetting.ShowUnicode, false); SetDefault(FrameworkSetting.Locale, string.Empty); @@ -101,8 +104,10 @@ public enum FrameworkSetting Renderer, WindowMode, + LatencyMode, ConfineMouseMode, FrameSync, + CustomDrawLimit, ExecutionMode, ShowUnicode, diff --git a/osu.Framework/Configuration/InputConfigManager.cs b/osu.Framework/Configuration/InputConfigManager.cs index 577baa9316..38397f255e 100644 --- a/osu.Framework/Configuration/InputConfigManager.cs +++ b/osu.Framework/Configuration/InputConfigManager.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Reflection; @@ -44,6 +45,7 @@ public InputConfigManager(Storage storage, IReadOnlyList inputHand bindToHandlersBindables(); } + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Serialization types are preserved by the framework.")] protected override bool PerformSave() { try @@ -63,6 +65,7 @@ protected override bool PerformSave() return false; } + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Serialization types are preserved by the framework.")] protected override void PerformLoad() { if (storage.Exists(FILENAME)) @@ -90,6 +93,7 @@ protected override void PerformLoad() /// Binds to all s that the expose, /// and calls when their values change. /// + [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Reflection is used on types that are always preserved at runtime.")] private void bindToHandlersBindables() { foreach (var handler in InputHandlers) diff --git a/osu.Framework/Configuration/RendererType.cs b/osu.Framework/Configuration/RendererType.cs index 6a6f6b14b4..c67799a83f 100644 --- a/osu.Framework/Configuration/RendererType.cs +++ b/osu.Framework/Configuration/RendererType.cs @@ -24,6 +24,9 @@ public enum RendererType [Description("Direct3D 11")] Direct3D11, + [Description("Direct3D 12")] + Direct3D12, + /// /// Uses . /// @@ -44,6 +47,9 @@ public enum RendererType [Description("Direct3D 11 (Experimental)")] Deferred_Direct3D11, + [Description("Direct3D 12 (Experimental)")] + Deferred_Direct3D12, + [Description("OpenGL (Experimental)")] Deferred_OpenGL } diff --git a/osu.Framework/Configuration/TypedRepopulatingConverter.cs b/osu.Framework/Configuration/TypedRepopulatingConverter.cs index b041895f36..0b93f5a687 100644 --- a/osu.Framework/Configuration/TypedRepopulatingConverter.cs +++ b/osu.Framework/Configuration/TypedRepopulatingConverter.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -39,6 +40,7 @@ public override IReadOnlyList ReadJson(JsonReader reader, Type objectType, IR return existingList; } + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Configuration types are preserved by the framework.")] public override void WriteJson(JsonWriter writer, IReadOnlyList value, JsonSerializer serializer) { var objects = new List(); diff --git a/osu.Framework/Development/DebugUtils.cs b/osu.Framework/Development/DebugUtils.cs index d8e8112357..7b32af0da0 100644 --- a/osu.Framework/Development/DebugUtils.cs +++ b/osu.Framework/Development/DebugUtils.cs @@ -3,6 +3,7 @@ using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using NUnit.Framework; @@ -59,14 +60,16 @@ public static class DebugUtils internal static Assembly NUnitTestAssembly => nunit_test_assembly.Value; - private static readonly Lazy nunit_test_assembly = new Lazy(() => - { - Debug.Assert(IsNUnitRunning); + private static readonly Lazy nunit_test_assembly = new Lazy(findNUnitTestAssembly); - string testName = TestContext.CurrentContext.Test.ClassName.AsNonNull(); - return AppDomain.CurrentDomain.GetAssemblies().First(asm => asm.GetType(testName) != null); - } - ); + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Debug/runtime inspection code; types are available at runtime.")] + private static Assembly findNUnitTestAssembly() + { + Debug.Assert(IsNUnitRunning); + + string testName = TestContext.CurrentContext.Test.ClassName.AsNonNull(); + return AppDomain.CurrentDomain.GetAssemblies().First(asm => asm.GetType(testName) != null); + } public static bool IsDebugBuild => is_debug_build.Value; diff --git a/osu.Framework/Development/ReflectionUtils.cs b/osu.Framework/Development/ReflectionUtils.cs index 4cc44a9c60..4c7f961771 100644 --- a/osu.Framework/Development/ReflectionUtils.cs +++ b/osu.Framework/Development/ReflectionUtils.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using osu.Framework.Extensions.TypeExtensions; @@ -46,7 +47,7 @@ internal static class ReflectionUtils /// The type to examine. /// Only methods to which this attribute is applied will be returned. /// Specifies whether to search the fixture type inheritance chain. - internal static MethodInfo[] GetMethodsWithAttribute(Type fixtureType, Type attributeType, bool inherit) + internal static MethodInfo[] GetMethodsWithAttribute([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] Type fixtureType, Type attributeType, bool inherit) { if (!inherit) { diff --git a/osu.Framework/Extensions/ExtensionMethods.cs b/osu.Framework/Extensions/ExtensionMethods.cs index aa9d29bdf8..f963b1704b 100644 --- a/osu.Framework/Extensions/ExtensionMethods.cs +++ b/osu.Framework/Extensions/ExtensionMethods.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Drawing; using System.IO; using System.Linq; @@ -147,6 +148,7 @@ public static T[][] ToJagged(this T[,] rectangular) public static string ToResolutionString(this Size size) => $"{size.Width}x{size.Height}"; + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Reflection is used on types that are always preserved at runtime.")] public static Type[] GetLoadableTypes(this Assembly assembly) { ArgumentNullException.ThrowIfNull(assembly); @@ -179,6 +181,8 @@ public static Type[] GetLoadableTypes(this Assembly assembly) /// When the specified in the /// does not match any of the existing members in . /// + [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Reflection is used on types that are always preserved at runtime.")] + [UnconditionalSuppressMessage("Trimming", "IL2080", Justification = "Reflection is used on types that are always preserved at runtime.")] public static LocalisableString GetLocalisableDescription(this T value) { if (value is LocalisableString localisable) @@ -236,6 +240,7 @@ public static LocalisableString GetLocalisableDescription(this T value) /// /// If the passed value is already of type , it will be returned. /// + [UnconditionalSuppressMessage("Trimming", "IL2070", Justification = "Reflection is used on types that are always preserved at runtime.")] public static string GetDescription(this object value) { if (value is string description) diff --git a/osu.Framework/Extensions/OSPlatformExtensions.cs b/osu.Framework/Extensions/OSPlatformExtensions.cs index f9b4370453..3b6d82866b 100644 --- a/osu.Framework/Extensions/OSPlatformExtensions.cs +++ b/osu.Framework/Extensions/OSPlatformExtensions.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Runtime.Versioning; @@ -19,6 +20,7 @@ public static class OSPlatformExtensions /// /// This is only a naive check of attributes defined directly on this member, and doesn't account for the (un)supported platforms of the containing class or assembly. /// + [UnconditionalSuppressMessage("Trimming", "IL2045", Justification = "Platform attributes are always preserved by the runtime.")] public static bool IsSupportedOnCurrentOSPlatform(this MemberInfo member) { var supported = member.GetCustomAttributes().ToArray(); diff --git a/osu.Framework/Graphics/Containers/CompositeDrawable.cs b/osu.Framework/Graphics/Containers/CompositeDrawable.cs index b56fca7551..fb6afab8ca 100644 --- a/osu.Framework/Graphics/Containers/CompositeDrawable.cs +++ b/osu.Framework/Graphics/Containers/CompositeDrawable.cs @@ -6,11 +6,12 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Runtime.ExceptionServices; using System.Threading; using System.Threading.Tasks; -using JetBrains.Annotations; +using NotNullAttribute = JetBrains.Annotations.NotNullAttribute; using osu.Framework.Allocation; using osu.Framework.Development; using osu.Framework.Extensions.EnumExtensions; @@ -247,6 +248,7 @@ private void loadComponents(List components, IReadOnlyDepe } [BackgroundDependencyLoader(true)] + [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Drawable types are preserved by the framework's scene graph.")] private void load(ShaderManager shaders, CancellationToken? cancellation) { hasCustomDrawNode = GetType().GetMethod(nameof(CreateDrawNode))?.DeclaringType != typeof(CompositeDrawable); diff --git a/osu.Framework/Graphics/Containers/GridContainer.cs b/osu.Framework/Graphics/Containers/GridContainer.cs index 9062df8b1a..943c9e61ba 100644 --- a/osu.Framework/Graphics/Containers/GridContainer.cs +++ b/osu.Framework/Graphics/Containers/GridContainer.cs @@ -310,8 +310,8 @@ private float[] getCellSizesAlongAxis(Axes axis, float spanLength) } private static bool shouldConsiderCell(Drawable cell) => cell != null && cell.IsAlive && cell.IsPresent; - private static float getCellWidth(Drawable cell) => shouldConsiderCell(cell) ? cell.BoundingBox.Width : 0; - private static float getCellHeight(Drawable cell) => shouldConsiderCell(cell) ? cell.BoundingBox.Height : 0; + private static float getCellWidth(Drawable cell) => shouldConsiderCell(cell) ? cell.RequiredParentSizeToFit.X : 0; + private static float getCellHeight(Drawable cell) => shouldConsiderCell(cell) ? cell.RequiredParentSizeToFit.Y : 0; /// /// Distributes any available length along all distributed dimensions, if required. diff --git a/osu.Framework/Graphics/Drawable.HandleInputCache.cs b/osu.Framework/Graphics/Drawable.HandleInputCache.cs index d8ee55b081..88039d1c6b 100644 --- a/osu.Framework/Graphics/Drawable.HandleInputCache.cs +++ b/osu.Framework/Graphics/Drawable.HandleInputCache.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Concurrent; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Reflection; using osu.Framework.Graphics.Cursor; using osu.Framework.Input; @@ -115,6 +116,7 @@ private static bool getViaReflection(Drawable drawable, ConcurrentDictionary internal virtual void UnbindAllBindablesSubTree() => UnbindAllBindables(); + [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Drawable types are preserved by the framework's scene graph.")] private Action getUnbindAction() { Type ourType = GetType(); diff --git a/osu.Framework/Graphics/OpenGL/Buffers/GLVertexUtils.cs b/osu.Framework/Graphics/OpenGL/Buffers/GLVertexUtils.cs index b9bbe5d07d..7a991c1eeb 100644 --- a/osu.Framework/Graphics/OpenGL/Buffers/GLVertexUtils.cs +++ b/osu.Framework/Graphics/OpenGL/Buffers/GLVertexUtils.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.InteropServices; using osu.Framework.Graphics.Rendering.Vertices; @@ -30,6 +31,7 @@ static GLVertexUtils() addAttributesRecursive(typeof(T), 0); } + [UnconditionalSuppressMessage("Trimming", "IL2070", Justification = "Reflection is used on types that are always preserved at runtime.")] private static void addAttributesRecursive(Type type, int currentOffset) { foreach (FieldInfo field in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) diff --git a/osu.Framework/Graphics/Rendering/LowLatency/IDirect3D11LowLatencyProvider.cs b/osu.Framework/Graphics/Rendering/LowLatency/IDirect3D11LowLatencyProvider.cs new file mode 100644 index 0000000000..21789572de --- /dev/null +++ b/osu.Framework/Graphics/Rendering/LowLatency/IDirect3D11LowLatencyProvider.cs @@ -0,0 +1,12 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Framework.Graphics.Rendering.LowLatency +{ + /// + /// Low-latency provider specifically for Direct3D 11 backends (e.g. NVIDIA Reflex via D3D11). + /// + public interface IDirect3D11LowLatencyProvider : ILowLatencyProvider + { + } +} diff --git a/osu.Framework/Graphics/Rendering/LowLatency/ILowLatencyProvider.cs b/osu.Framework/Graphics/Rendering/LowLatency/ILowLatencyProvider.cs new file mode 100644 index 0000000000..45c5967aeb --- /dev/null +++ b/osu.Framework/Graphics/Rendering/LowLatency/ILowLatencyProvider.cs @@ -0,0 +1,24 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; + +namespace osu.Framework.Graphics.Rendering.LowLatency +{ + /// + /// Generic low-latency provider interface supporting any graphics backend. + /// Implementations may use NVIDIA Reflex, LatencyFlex, or other latency reduction APIs. + /// + public interface ILowLatencyProvider + { + bool IsAvailable { get; } + + void Initialize(IntPtr nativeDeviceHandle); + + void SetMode(LatencyMode mode); + + void SetMarker(LatencyMarker marker, ulong frameId); + + void FrameSleep(); + } +} diff --git a/osu.Framework/Graphics/Rendering/LowLatency/LatencyMarker.cs b/osu.Framework/Graphics/Rendering/LowLatency/LatencyMarker.cs new file mode 100644 index 0000000000..65b9e2a2ce --- /dev/null +++ b/osu.Framework/Graphics/Rendering/LowLatency/LatencyMarker.cs @@ -0,0 +1,17 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Framework.Graphics.Rendering.LowLatency +{ + public enum LatencyMarker + { + SimulationStart, + SimulationEnd, + RenderSubmitStart, + RenderSubmitEnd, + PresentStart, + PresentEnd, + InputSample, + TriggerFlash + } +} diff --git a/osu.Framework/Graphics/Rendering/LowLatency/LatencyMode.cs b/osu.Framework/Graphics/Rendering/LowLatency/LatencyMode.cs new file mode 100644 index 0000000000..0cf129e20a --- /dev/null +++ b/osu.Framework/Graphics/Rendering/LowLatency/LatencyMode.cs @@ -0,0 +1,12 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Framework.Graphics.Rendering.LowLatency +{ + public enum LatencyMode + { + Off = 0, + On = 1, + Boost = 2 + } +} diff --git a/osu.Framework/Graphics/Rendering/LowLatency/NoOpDirect3D11LowLatencyProvider.cs b/osu.Framework/Graphics/Rendering/LowLatency/NoOpDirect3D11LowLatencyProvider.cs new file mode 100644 index 0000000000..f5274751ee --- /dev/null +++ b/osu.Framework/Graphics/Rendering/LowLatency/NoOpDirect3D11LowLatencyProvider.cs @@ -0,0 +1,22 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; + +namespace osu.Framework.Graphics.Rendering.LowLatency +{ + internal sealed class NoOpDirect3D11LowLatencyProvider : IDirect3D11LowLatencyProvider + { + public static readonly NoOpDirect3D11LowLatencyProvider INSTANCE = new NoOpDirect3D11LowLatencyProvider(); + + public bool IsAvailable => false; + + public void Initialize(IntPtr deviceHandle) { } + + public void SetMode(LatencyMode mode) { } + + public void SetMarker(LatencyMarker marker, ulong frameId) { } + + public void FrameSleep() { } + } +} diff --git a/osu.Framework/Graphics/Rendering/LowLatency/NoOpLowLatencyProvider.cs b/osu.Framework/Graphics/Rendering/LowLatency/NoOpLowLatencyProvider.cs new file mode 100644 index 0000000000..0a4ff460e6 --- /dev/null +++ b/osu.Framework/Graphics/Rendering/LowLatency/NoOpLowLatencyProvider.cs @@ -0,0 +1,22 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; + +namespace osu.Framework.Graphics.Rendering.LowLatency +{ + internal sealed class NoOpLowLatencyProvider : ILowLatencyProvider + { + public static readonly NoOpLowLatencyProvider INSTANCE = new NoOpLowLatencyProvider(); + + public bool IsAvailable => false; + + public void Initialize(IntPtr deviceHandle) { } + + public void SetMode(LatencyMode mode) { } + + public void SetMarker(LatencyMarker marker, ulong frameId) { } + + public void FrameSleep() { } + } +} diff --git a/osu.Framework/Graphics/Rendering/Renderer.cs b/osu.Framework/Graphics/Rendering/Renderer.cs index 89ae7ee781..118ee7cd56 100644 --- a/osu.Framework/Graphics/Rendering/Renderer.cs +++ b/osu.Framework/Graphics/Rendering/Renderer.cs @@ -5,6 +5,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; @@ -1292,6 +1293,7 @@ IShaderStorageBufferObject IRenderer.CreateShaderStorageBufferObject(uboSize, ssboSize); } + [UnconditionalSuppressMessage("Trimming", "IL2090", Justification = "Uniform layout types are compile-time constants and always preserved.")] private void validateUniformLayout() { if (validUboTypes.Contains(typeof(TData))) diff --git a/osu.Framework/Graphics/Shaders/ShaderCompilationStore.cs b/osu.Framework/Graphics/Shaders/ShaderCompilationStore.cs index 344bee31e2..3701df65b4 100644 --- a/osu.Framework/Graphics/Shaders/ShaderCompilationStore.cs +++ b/osu.Framework/Graphics/Shaders/ShaderCompilationStore.cs @@ -80,6 +80,7 @@ public ComputeProgramCompilation CompileCompute(string programText, CrossCompile return compilation; } + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Shader compilation types are known and preserved.")] private bool tryGetCached(string filename, [NotNullWhen(true)] out T? compilation) where T : class { @@ -126,6 +127,7 @@ private bool tryGetCached(string filename, [NotNullWhen(true)] out T? compila private static readonly Lock save_lock = new(); + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Shader compilation types are known and preserved.")] private void saveToCache(string filename, object compilation) { // Multiple save operations could happen in parallel due to the asynchronous diff --git a/osu.Framework/Graphics/Transforms/TransformCustom.cs b/osu.Framework/Graphics/Transforms/TransformCustom.cs index 919120f4dd..9d4630c05f 100644 --- a/osu.Framework/Graphics/Transforms/TransformCustom.cs +++ b/osu.Framework/Graphics/Transforms/TransformCustom.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Concurrent; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; @@ -81,6 +82,7 @@ private static WriteFunc createPropertySetter(MethodInfo setter) return setter.CreateDelegate(); } + [UnconditionalSuppressMessage("Trimming", "IL2070", Justification = "Transform target types are preserved by the framework.")] private static Accessor findAccessor(Type type, string propertyOrFieldName) { PropertyInfo property = type.GetProperty(propertyOrFieldName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); diff --git a/osu.Framework/Graphics/Veldrid/VeldridDevice.cs b/osu.Framework/Graphics/Veldrid/VeldridDevice.cs index 02dce1f944..bb49edd272 100644 --- a/osu.Framework/Graphics/Veldrid/VeldridDevice.cs +++ b/osu.Framework/Graphics/Veldrid/VeldridDevice.cs @@ -207,6 +207,13 @@ public VeldridDevice(IGraphicsSurface graphicsSurface) #pragma warning restore CA1416 break; + case GraphicsSurfaceType.Direct3D12: +#pragma warning disable CA1416 // D3D12 is only reachable on Windows via the GraphicsSurfaceType switch + Device = GraphicsDevice.CreateD3D12(options, swapchain); + Device.LogD3D12(out maxTextureSize); +#pragma warning restore CA1416 + break; + case GraphicsSurfaceType.Metal: Device = GraphicsDevice.CreateMetal(options, swapchain); Device.LogMetal(out maxTextureSize); diff --git a/osu.Framework/Graphics/Veldrid/VeldridExtensions.cs b/osu.Framework/Graphics/Veldrid/VeldridExtensions.cs index 7d3131032b..d729d9fff5 100644 --- a/osu.Framework/Graphics/Veldrid/VeldridExtensions.cs +++ b/osu.Framework/Graphics/Veldrid/VeldridExtensions.cs @@ -364,6 +364,49 @@ public static void LogD3D11(this GraphicsDevice device, out int maxTextureSize) Direct3D 11 Shared System Memory: {dxgiAdapter.Description.SharedSystemMemory / 1024 / 1024} MB"); } + [System.Runtime.Versioning.SupportedOSPlatform("windows")] + public static void LogD3D12(this GraphicsDevice device, out int maxTextureSize) + { + Debug.Assert(device.BackendType == GraphicsBackend.Direct3D12); + + var info = device.GetD3D12Info(); + + // D3D12 uses the same DXGI factory; query the adapter via the factory pointer. + var dxgiFactory = MarshallingHelpers.FromPointer(info.DxgiFactory).AsNonNull(); + + string adapterDescription = "Unknown"; + long dedicatedVideoMemory = 0; + long dedicatedSystemMemory = 0; + long sharedSystemMemory = 0; + + if (dxgiFactory.EnumAdapters(0, out IDXGIAdapter? adapter).Success && adapter != null) + { + var desc = adapter.Description; + adapterDescription = desc.Description; + dedicatedVideoMemory = desc.DedicatedVideoMemory / 1024 / 1024; + dedicatedSystemMemory = desc.DedicatedSystemMemory / 1024 / 1024; + sharedSystemMemory = desc.SharedSystemMemory / 1024 / 1024; + } + + // D3D12 max texture size is 16384 (D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION) + maxTextureSize = 16384; + + bool supportsEnhancedBarriers = info.SupportsEnhancedBarriers; + bool supportsMeshShaders = info.SupportsMeshShaders; + bool supportsVRS = info.SupportsVariableRateShading; + bool supportsRaytracing = info.SupportsRaytracing; + + Logger.Log($@"Direct3D 12 Initialized + Direct3D 12 Adapter: {adapterDescription} + Direct3D 12 Dedicated Video Memory: {dedicatedVideoMemory} MB + Direct3D 12 Dedicated System Memory: {dedicatedSystemMemory} MB + Direct3D 12 Shared System Memory: {sharedSystemMemory} MB + Direct3D 12 Enhanced Barriers: {supportsEnhancedBarriers} + Direct3D 12 Mesh Shaders: {supportsMeshShaders} + Direct3D 12 Variable Rate Shading: {supportsVRS} + Direct3D 12 Raytracing: {supportsRaytracing}"); + } + public static unsafe void LogOpenGL(this GraphicsDevice device, out int maxTextureSize) { var info = device.GetOpenGLInfo(); diff --git a/osu.Framework/Graphics/Veldrid/VeldridRenderer.cs b/osu.Framework/Graphics/Veldrid/VeldridRenderer.cs index c27b008505..6b2085df22 100644 --- a/osu.Framework/Graphics/Veldrid/VeldridRenderer.cs +++ b/osu.Framework/Graphics/Veldrid/VeldridRenderer.cs @@ -347,6 +347,7 @@ internal IStagingBuffer CreateStagingBuffer(uint count) switch (Device.BackendType) { case GraphicsBackend.Direct3D11: + case GraphicsBackend.Direct3D12: case GraphicsBackend.Vulkan: return new PersistentStagingBuffer(this, count); diff --git a/osu.Framework/Graphics/Veldrid/Vertices/VeldridVertexUtils.cs b/osu.Framework/Graphics/Veldrid/Vertices/VeldridVertexUtils.cs index d863c078a5..2cd7e99499 100644 --- a/osu.Framework/Graphics/Veldrid/Vertices/VeldridVertexUtils.cs +++ b/osu.Framework/Graphics/Veldrid/Vertices/VeldridVertexUtils.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.InteropServices; using osu.Framework.Graphics.Rendering.Vertices; @@ -35,6 +36,7 @@ static VeldridVertexUtils() Layout = new VertexLayoutDescription(elements.ToArray()); } + [UnconditionalSuppressMessage("Trimming", "IL2070", Justification = "Vertex types are compile-time constants and always preserved.")] private static void addAttributesRecursive(Type type, int currentOffset) { foreach (FieldInfo field in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) diff --git a/osu.Framework/Graphics/Visualisation/DrawVisualiser.cs b/osu.Framework/Graphics/Visualisation/DrawVisualiser.cs index be282edc81..a12217e0d1 100644 --- a/osu.Framework/Graphics/Visualisation/DrawVisualiser.cs +++ b/osu.Framework/Graphics/Visualisation/DrawVisualiser.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using osu.Framework.Allocation; @@ -241,6 +242,7 @@ protected override void Update() private static readonly Dictionary is_type_valid_target_cache = new Dictionary(); + [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Drawable types are preserved by the framework's scene graph.")] private void updateCursorTarget() { Drawable drawableTarget = null; diff --git a/osu.Framework/Graphics/Visualisation/PropertyDisplay.cs b/osu.Framework/Graphics/Visualisation/PropertyDisplay.cs index c9e3b45132..973647eff6 100644 --- a/osu.Framework/Graphics/Visualisation/PropertyDisplay.cs +++ b/osu.Framework/Graphics/Visualisation/PropertyDisplay.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; @@ -68,6 +69,7 @@ protected override void LoadComplete() inspectedDrawable.BindValueChanged(inspected => updateProperties(inspected.NewValue), true); } + [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Property display is a debug tool; types are available at runtime.")] private void updateProperties(IDrawable source) { Clear(); diff --git a/osu.Framework/IO/Network/JsonWebRequest.cs b/osu.Framework/IO/Network/JsonWebRequest.cs index e97ea4eca4..e228fcdf6c 100644 --- a/osu.Framework/IO/Network/JsonWebRequest.cs +++ b/osu.Framework/IO/Network/JsonWebRequest.cs @@ -3,6 +3,7 @@ #nullable disable +using System.Diagnostics.CodeAnalysis; using Newtonsoft.Json; namespace osu.Framework.IO.Network @@ -20,6 +21,7 @@ public JsonWebRequest(string url = null, params object[] args) { } + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Serialization types are preserved by the framework.")] protected override void ProcessResponse() { string response = GetResponseString(); diff --git a/osu.Framework/IO/Serialization/BindableJsonConverter.cs b/osu.Framework/IO/Serialization/BindableJsonConverter.cs index efb5394335..c4077b49a2 100644 --- a/osu.Framework/IO/Serialization/BindableJsonConverter.cs +++ b/osu.Framework/IO/Serialization/BindableJsonConverter.cs @@ -5,6 +5,7 @@ using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using Newtonsoft.Json; using osu.Framework.Bindables; @@ -18,6 +19,7 @@ internal class BindableJsonConverter : JsonConverter public override void WriteJson(JsonWriter writer, ISerializableBindable value, JsonSerializer serializer) => value.SerializeTo(writer, serializer); + [UnconditionalSuppressMessage("Trimming", "IL2067", Justification = "Serialization types are preserved by the framework.")] public override ISerializableBindable ReadJson(JsonReader reader, Type objectType, ISerializableBindable existingValue, bool hasExistingValue, JsonSerializer serializer) { var bindable = existingValue ?? (ISerializableBindable)Activator.CreateInstance(objectType, true); diff --git a/osu.Framework/IO/Serialization/SortedListJsonConverter.cs b/osu.Framework/IO/Serialization/SortedListJsonConverter.cs index 7e4137e654..0af9f7f5fa 100644 --- a/osu.Framework/IO/Serialization/SortedListJsonConverter.cs +++ b/osu.Framework/IO/Serialization/SortedListJsonConverter.cs @@ -5,6 +5,7 @@ using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using Newtonsoft.Json; using osu.Framework.Lists; @@ -18,6 +19,7 @@ internal class SortedListJsonConverter : JsonConverter public override void WriteJson(JsonWriter writer, ISerializableSortedList value, JsonSerializer serializer) => value.SerializeTo(writer, serializer); + [UnconditionalSuppressMessage("Trimming", "IL2067", Justification = "Sorted list types are preserved by the serialization framework.")] public override ISerializableSortedList ReadJson(JsonReader reader, Type objectType, ISerializableSortedList existingValue, bool hasExistingValue, JsonSerializer serializer) { var iList = existingValue ?? (ISerializableSortedList)Activator.CreateInstance(objectType); diff --git a/osu.Framework/IO/Stores/DllResourceStore.cs b/osu.Framework/IO/Stores/DllResourceStore.cs index 1ec6bf0004..e2777cc7e6 100644 --- a/osu.Framework/IO/Stores/DllResourceStore.cs +++ b/osu.Framework/IO/Stores/DllResourceStore.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Reflection; @@ -20,6 +21,7 @@ public class DllResourceStore : IResourceStore private readonly Assembly assembly; private readonly string prefix; + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Reflection is used on types that are always preserved at runtime.")] public DllResourceStore(string dllName) { string filePath = Path.Combine(Path.GetDirectoryName(Assembly.GetCallingAssembly().Location).AsNonNull(), dllName); diff --git a/osu.Framework/Platform/GameHost.cs b/osu.Framework/Platform/GameHost.cs index 1d8fd32e74..0b397ed659 100644 --- a/osu.Framework/Platform/GameHost.cs +++ b/osu.Framework/Platform/GameHost.cs @@ -29,6 +29,7 @@ using osu.Framework.Graphics.OpenGL; using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Rendering.Deferred; +using osu.Framework.Graphics.Rendering.LowLatency; using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Veldrid; using osu.Framework.Graphics.Video; @@ -459,14 +460,21 @@ protected virtual void OnExited() Exited?.Invoke(); } - private readonly TripleBuffer drawRoots = new TripleBuffer(); + private readonly TripleBuffer drawRoots = new TripleBuffer(); internal Container Root { get; private set; } private ulong frameCount; + private class DrawBufferData + { + public DrawNode Node; + public ulong FrameCount; + } + protected virtual void UpdateFrame() { + FrameSleep(); if (Root == null) return; frameCount++; @@ -484,11 +492,19 @@ protected virtual void UpdateFrame() TypePerformanceMonitor.NewFrame(); + LatencyMark(LatencyMarker.SimulationStart, frameCount); + Root.UpdateSubTree(); Root.UpdateSubTreeMasking(); using (var buffer = drawRoots.GetForWrite()) - buffer.Object = Root.GenerateDrawNodeSubtree(frameCount, buffer.Index, false); + { + buffer.Object ??= new DrawBufferData(); + buffer.Object.Node = Root.GenerateDrawNodeSubtree(frameCount, buffer.Index, false); + buffer.Object.FrameCount = frameCount; + } + + LatencyMark(LatencyMarker.SimulationEnd, frameCount); } private bool didRenderFrame; @@ -508,7 +524,7 @@ protected virtual void DrawFrame() Renderer.AllowTearing = windowMode.Value == WindowMode.Fullscreen; - TripleBuffer.Buffer buffer; + TripleBuffer.Buffer buffer; using (drawMonitor.BeginCollecting(PerformanceCollectionType.Sleep)) { @@ -519,16 +535,22 @@ protected virtual void DrawFrame() Renderer.WaitUntilNextFrameReady(); didRenderFrame = false; - buffer = drawRoots.GetForRead(IsActive.Value ? TripleBuffer.DEFAULT_READ_TIMEOUT : 0); + buffer = drawRoots.GetForRead(IsActive.Value ? TripleBuffer.DEFAULT_READ_TIMEOUT : 0); } if (buffer == null) return; - Debug.Assert(buffer.Object != null); - try { + if (buffer.Object is not DrawBufferData data) + return; + + DrawNode rootNode = data.Node; + ulong bufferFrameCount = data.FrameCount; + + LatencyMark(LatencyMarker.RenderSubmitStart, bufferFrameCount); + using (drawMonitor.BeginCollecting(PerformanceCollectionType.DrawReset)) Renderer.BeginFrame(new Vector2(Window.ClientSize.Width, Window.ClientSize.Height)); @@ -540,7 +562,7 @@ protected virtual void DrawFrame() Renderer.PushDepthInfo(DepthInfo.Default); // Front pass - DrawNode.DrawOtherOpaqueInterior(buffer.Object, Renderer); + DrawNode.DrawOtherOpaqueInterior(rootNode, Renderer); Renderer.PopDepthInfo(); Renderer.SetBlendMask(BlendingMask.All); @@ -555,14 +577,20 @@ protected virtual void DrawFrame() } // Back pass - DrawNode.DrawOther(buffer.Object, Renderer); + DrawNode.DrawOther(rootNode, Renderer); Renderer.PopDepthInfo(); Renderer.FinishFrame(); + LatencyMark(LatencyMarker.RenderSubmitEnd, bufferFrameCount); + using (drawMonitor.BeginCollecting(PerformanceCollectionType.SwapBuffer)) + { + LatencyMark(LatencyMarker.PresentStart, bufferFrameCount); Swap(); + LatencyMark(LatencyMarker.PresentEnd, bufferFrameCount); + } Window.OnDraw(); didRenderFrame = true; @@ -847,7 +875,9 @@ public IEnumerable GetPreferredRenderersForCurrentPlatform() { case RuntimeInfo.Platform.Windows: yield return RendererType.Direct3D11; + yield return RendererType.Direct3D12; yield return RendererType.Deferred_Direct3D11; + yield return RendererType.Deferred_Direct3D12; yield return RendererType.OpenGL; yield return RendererType.Deferred_Vulkan; @@ -926,6 +956,7 @@ protected virtual void ChooseAndSetupRenderer() case RendererType.Deferred_Metal: case RendererType.Deferred_Vulkan: case RendererType.Deferred_Direct3D11: + case RendererType.Deferred_Direct3D12: case RendererType.Deferred_OpenGL: SetupRendererAndWindow(new DeferredRenderer(), rendererToGraphicsSurfaceType(type)); break; @@ -974,6 +1005,11 @@ private static GraphicsSurfaceType rendererToGraphicsSurfaceType(RendererType re surface = GraphicsSurfaceType.Direct3D11; break; + case RendererType.Deferred_Direct3D12: + case RendererType.Direct3D12: + surface = GraphicsSurfaceType.Direct3D12; + break; + case RendererType.Deferred_OpenGL: case RendererType.OpenGL: surface = GraphicsSurfaceType.OpenGL; @@ -1213,6 +1249,8 @@ private void bootstrapSceneGraph(Game game) private Bindable frameSyncMode; + private Bindable latencyMode; + private IBindable currentDisplayMode; private Bindable ignoredInputHandlers; @@ -1251,6 +1289,9 @@ protected virtual void SetupConfig(IDictionary default frameSyncMode = Config.GetBindable(FrameworkSetting.FrameSync); frameSyncMode.ValueChanged += _ => updateFrameSyncMode(); + latencyMode = Config.GetBindable(FrameworkSetting.LatencyMode); + latencyMode.BindValueChanged(mode => setLowLatencyMode(mode.NewValue), true); + #pragma warning disable 618 // pragma region can be removed 20210911 ignoredInputHandlers = Config.GetBindable(FrameworkSetting.IgnoredInputHandlers); @@ -1350,6 +1391,11 @@ private void updateFrameSyncMode() updateLimiter *= 2; break; + case FrameSync.UVSync: + drawLimiter = refreshRate; + updateLimiter = refreshRate; + break; + case FrameSync.Limit2x: drawLimiter *= 2; updateLimiter *= 2; @@ -1369,6 +1415,19 @@ private void updateFrameSyncMode() drawLimiter = int.MaxValue; updateLimiter = int.MaxValue; break; + + case FrameSync.Custom: + drawLimiter = Config.GetBindable(FrameworkSetting.CustomDrawLimit).Value; + updateLimiter = int.MaxValue; + break; + } + + // If low latency is enabled, we want to limit the draw thread to refresh rate as anything above is unnecessary. + // Keep Update thread at 1000hz for input & audio responsiveness. + if (lowLatencyInitialized && latencyMode.Value != LatencyMode.Off) + { + drawLimiter = refreshRate; + updateLimiter = int.MaxValue; } if (!AllowBenchmarkUnlimitedFrames) @@ -1388,6 +1447,103 @@ private void setVSyncMode() DrawThread.Scheduler.Add(() => Renderer.VerticalSync = frameSyncMode.Value == FrameSync.VSync); } + private ILowLatencyProvider lowLatencyProvider = NoOpLowLatencyProvider.INSTANCE; + private bool lowLatencyInitialized; + + /// + /// Set the low latency provider to be used by this host. + /// Accepts any , including D3D11-specific and D3D12-specific implementations. + /// + /// The to use. + public void SetLowLatencyProvider(ILowLatencyProvider provider) + { + lowLatencyProvider = provider ?? NoOpLowLatencyProvider.INSTANCE; + Logger.Log("Low latency provider set to: " + lowLatencyProvider.GetType().ReadableName()); + TryInitializeLowLatencyProvider(); + } + + /// + /// Attempts to initialize the low latency provider if it has not already been initialized. + /// Supports both D3D11 and D3D12 backends — obtains the native device handle from whichever is active. + /// + internal void TryInitializeLowLatencyProvider() + { + if (lowLatencyInitialized || lowLatencyProvider is NoOpLowLatencyProvider) return; + if (Renderer is not IVeldridRenderer veldridRenderer || !Renderer.IsInitialised) return; + + try + { + Logger.Log("Attempting to initialize low latency provider..."); + + IntPtr deviceHandle = IntPtr.Zero; + + switch (veldridRenderer.Device.BackendType) + { + case Veldrid.GraphicsBackend.Direct3D11: +#pragma warning disable CA1416 // BackendInfoD3D11 is only reachable on Windows via Direct3D11 backend + deviceHandle = veldridRenderer.Device.GetD3D11Info().Device; +#pragma warning restore CA1416 + break; + + case Veldrid.GraphicsBackend.Direct3D12: +#pragma warning disable CA1416 // BackendInfoD3D12 is only reachable on Windows via Direct3D12 backend + deviceHandle = veldridRenderer.Device.GetD3D12Info().Device; +#pragma warning restore CA1416 + break; + } + + if (deviceHandle == IntPtr.Zero) return; + + lowLatencyProvider.Initialize(deviceHandle); + setLowLatencyMode(latencyMode.Value); + lowLatencyInitialized = true; + + Logger.Log($"Low latency provider initialized for {veldridRenderer.Device.BackendType}."); + } + catch (Exception e) + { + // Intentionally not logged as an error, as failure is expected (this method can be run before renderer initialization). + Logger.Log("Failed to initialize low latency provider: " + e, level: LogLevel.Important); + } + } + + private void setLowLatencyMode(LatencyMode mode) + { + try + { + lowLatencyProvider.SetMode(mode); + } + catch (Exception e) + { + logException(e, "unobserved"); + } + } + + internal void LatencyMark(LatencyMarker marker, ulong frameId) + { + try + { + lowLatencyProvider.SetMarker(marker, frameId); + } + catch (Exception) + { + // WARNING: Do not log anything here or otherwise catch the error. + // This method is called extremely frequently (multiple times per frame) and doing so could cause massive performance degradation. + } + } + + internal void FrameSleep() + { + try + { + lowLatencyProvider.FrameSleep(); + } + catch (Exception e) + { + logException(e, "unobserved"); + } + } + /// /// Construct all input handlers for this host. The order here decides the priority given to handlers, with the earliest occurring having higher priority. /// diff --git a/osu.Framework/Platform/GraphicsSurfaceType.cs b/osu.Framework/Platform/GraphicsSurfaceType.cs index 35323deeba..dc4008b78d 100644 --- a/osu.Framework/Platform/GraphicsSurfaceType.cs +++ b/osu.Framework/Platform/GraphicsSurfaceType.cs @@ -33,5 +33,11 @@ public enum GraphicsSurfaceType /// [Description("Direct3D 11")] Direct3D11, + + /// + /// A Direct3D12 graphics surface. + /// + [Description("Direct3D 12")] + Direct3D12, } } diff --git a/osu.Framework/Platform/NamedPipeIpcProvider.cs b/osu.Framework/Platform/NamedPipeIpcProvider.cs index 088cee4dac..5217e5a24a 100644 --- a/osu.Framework/Platform/NamedPipeIpcProvider.cs +++ b/osu.Framework/Platform/NamedPipeIpcProvider.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.IO.Pipes; using System.Text; @@ -159,6 +160,7 @@ public async Task SendMessageAsync(IpcMessage message) } } + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "IPC serialization uses known types at runtime.")] private static async Task send(Stream stream, IpcMessage message) { string str = JsonConvert.SerializeObject(message, Formatting.None); @@ -170,6 +172,8 @@ private static async Task send(Stream stream, IpcMessage message) await stream.FlushAsync().ConfigureAwait(false); } + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "IPC serialization uses known types at runtime.")] + [UnconditionalSuppressMessage("Trimming", "IL2057", Justification = "IPC serialization uses known types at runtime.")] private static async Task receive(Stream stream, CancellationToken cancellationToken = default) { const int header_length = sizeof(int); diff --git a/osu.Framework/Platform/NativeStorage.cs b/osu.Framework/Platform/NativeStorage.cs index ec02f7b042..58e786c1c8 100644 --- a/osu.Framework/Platform/NativeStorage.cs +++ b/osu.Framework/Platform/NativeStorage.cs @@ -5,9 +5,10 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; -using JetBrains.Annotations; +using NotNullAttribute = JetBrains.Annotations.NotNullAttribute; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Utils; @@ -109,6 +110,7 @@ public override Stream GetStream(string path, FileAccess access = FileAccess.Rea } } + [UnconditionalSuppressMessage("Trimming", "IL2072", Justification = "Reflection is used on types that are always preserved at runtime.")] public override Storage GetStorageForDirectory([NotNull] string path) { ArgumentNullException.ThrowIfNull(path); diff --git a/osu.Framework/Platform/SDL2/SDL2GraphicsSurface.cs b/osu.Framework/Platform/SDL2/SDL2GraphicsSurface.cs index c0f5e0b7d9..e95b162b23 100644 --- a/osu.Framework/Platform/SDL2/SDL2GraphicsSurface.cs +++ b/osu.Framework/Platform/SDL2/SDL2GraphicsSurface.cs @@ -3,6 +3,7 @@ using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Drawing; using System.Linq; using System.Reflection; @@ -102,6 +103,7 @@ private void loadBindings() loadEntryPoints(new GL()); } + [UnconditionalSuppressMessage("Trimming", "IL2072", Justification = "OpenGL binding entry points are always available at runtime.")] private unsafe void loadEntryPoints(GraphicsBindingsBase bindings) { var type = bindings.GetType(); diff --git a/osu.Framework/Platform/SDL3/SDL3GraphicsSurface.cs b/osu.Framework/Platform/SDL3/SDL3GraphicsSurface.cs index fc63b4d29c..18409dd343 100644 --- a/osu.Framework/Platform/SDL3/SDL3GraphicsSurface.cs +++ b/osu.Framework/Platform/SDL3/SDL3GraphicsSurface.cs @@ -3,11 +3,13 @@ using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Drawing; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Runtime.Versioning; +using osu.Framework.Logging; using osuTK.Graphics; using osuTK.Graphics.ES30; using SDL; @@ -44,6 +46,7 @@ public SDL3GraphicsSurface(SDL3Window window, GraphicsSurfaceType surfaceType) case GraphicsSurfaceType.Vulkan: case GraphicsSurfaceType.Metal: case GraphicsSurfaceType.Direct3D11: + case GraphicsSurfaceType.Direct3D12: break; default: @@ -94,9 +97,65 @@ private void initialiseOpenGL() SDL_GL_MakeCurrent(window.SDLWindowHandle, context).ThrowIfFailed(); + if (OperatingSystem.IsAndroid()) + tryEnableEglFrontBufferAutoRefresh(); + loadBindings(); } + /// + /// Attempts to enable EGL_ANDROID_front_buffer_auto_refresh on the current EGL surface. + /// When enabled, the display auto-refreshes from the front buffer, reducing latency + /// in unlocked frame rate (non-VSync) scenarios on Android. + /// + [SupportedOSPlatform("android")] + private void tryEnableEglFrontBufferAutoRefresh() + { + const int egl_extensions = 3; + const int egl_true = 1; + const int egl_front_buffer_auto_refresh_android = 0x314C; + + try + { + IntPtr eglDisplay = SDL_EGL_GetCurrentDisplay(); + IntPtr eglSurface = SDL_EGL_GetWindowSurface(window.SDLWindowHandle); + + if (eglDisplay == IntPtr.Zero || eglSurface == IntPtr.Zero) + { + Logger.Log("EGL front buffer auto-refresh: could not obtain EGL display/surface.", LoggingTarget.Runtime, LogLevel.Debug); + return; + } + + // Check extension availability before calling eglSurfaceAttrib. + IntPtr extensionsPtr = eglQueryString(eglDisplay, egl_extensions); + + if (extensionsPtr == IntPtr.Zero) + return; + + string? extensions = Marshal.PtrToStringAnsi(extensionsPtr); + + if (extensions == null || !extensions.Contains("EGL_ANDROID_front_buffer_auto_refresh")) + { + Logger.Log("EGL_ANDROID_front_buffer_auto_refresh extension not available.", LoggingTarget.Runtime, LogLevel.Debug); + return; + } + + int result = eglSurfaceAttrib(eglDisplay, eglSurface, egl_front_buffer_auto_refresh_android, egl_true); + + Logger.Log($"EGL front buffer auto-refresh: {(result != 0 ? "enabled" : "failed to enable")}.", LoggingTarget.Runtime, LogLevel.Important); + } + catch (Exception ex) + { + Logger.Log($"EGL front buffer auto-refresh: exception during setup: {ex.Message}", LoggingTarget.Runtime, LogLevel.Debug); + } + } + + [DllImport("libEGL", EntryPoint = "eglSurfaceAttrib")] + private static extern int eglSurfaceAttrib(IntPtr display, IntPtr surface, int attribute, int value); + + [DllImport("libEGL", EntryPoint = "eglQueryString")] + private static extern IntPtr eglQueryString(IntPtr display, int name); + private void loadBindings() { loadEntryPoints(new osuTK.Graphics.OpenGL.GL()); @@ -106,6 +165,7 @@ private void loadBindings() loadEntryPoints(new GL()); } + [UnconditionalSuppressMessage("Trimming", "IL2072", Justification = "OpenGL binding entry points are always available at runtime.")] private void loadEntryPoints(GraphicsBindingsBase bindings) { var type = bindings.GetType(); diff --git a/osu.Framework/Platform/SDL3/SDL3Window.cs b/osu.Framework/Platform/SDL3/SDL3Window.cs index 168552de28..02efd9dd1b 100644 --- a/osu.Framework/Platform/SDL3/SDL3Window.cs +++ b/osu.Framework/Platform/SDL3/SDL3Window.cs @@ -222,6 +222,7 @@ public virtual void Create() SDL_SetHint(SDL_HINT_PEN_TOUCH_EVENTS, "0"u8).LogErrorIfFailed(); SDL_SetHint(SDL_HINT_PEN_MOUSE_EVENTS, "0"u8).LogErrorIfFailed(); SDL_SetHint(SDL_HINT_IME_IMPLEMENTED_UI, "composition"u8).LogErrorIfFailed(); + SDL_SetHint(SDL_HINT_WINDOWS_RAW_KEYBOARD, "1"u8).LogErrorIfFailed(); SDLWindowHandle = SDL_CreateWindow(Title, Size.Width, Size.Height, flags); @@ -321,6 +322,18 @@ protected virtual bool HandleEventFromFilter(SDL_Event e) LowOnMemory?.Invoke(); break; + // When text input is disabled, handle keyboard events asynchronously in the event filter + // to bypass the SDL event queue for lower latency (matches raw keyboard input path). + case SDL_EventType.SDL_EVENT_KEY_DOWN: + case SDL_EventType.SDL_EVENT_KEY_UP: + if (!SDL_TextInputActive(SDLWindowHandle)) + { + handleKeyboardEvent(e.key); + return false; + } + + break; + case SDL_EventType.SDL_EVENT_MOUSE_MOTION: handleMouseMotionEvent(e.motion); return false; diff --git a/osu.Framework/Platform/Storage.cs b/osu.Framework/Platform/Storage.cs index 5312431d95..aa5ae1de5d 100644 --- a/osu.Framework/Platform/Storage.cs +++ b/osu.Framework/Platform/Storage.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.IO; using osu.Framework.Extensions.ObjectExtensions; @@ -85,6 +86,7 @@ static string filenameStrip(string entry) /// /// The subdirectory to use as a root. /// A more specific storage. + [UnconditionalSuppressMessage("Trimming", "IL2072", Justification = "Storage subclass types are preserved by the framework.")] public virtual Storage GetStorageForDirectory(string path) { if (string.IsNullOrEmpty(path)) diff --git a/osu.Framework/Platform/TcpIpcProvider.cs b/osu.Framework/Platform/TcpIpcProvider.cs index 66d77af699..9319cff150 100644 --- a/osu.Framework/Platform/TcpIpcProvider.cs +++ b/osu.Framework/Platform/TcpIpcProvider.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Net; using System.Net.Sockets; @@ -167,6 +168,7 @@ public async Task SendMessageAsync(IpcMessage message) } } + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "IPC serialization uses known types at runtime.")] private async Task send(Stream stream, IpcMessage message) { string str = JsonConvert.SerializeObject(message, Formatting.None); @@ -178,6 +180,8 @@ private async Task send(Stream stream, IpcMessage message) await stream.FlushAsync().ConfigureAwait(false); } + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "IPC serialization uses known types at runtime.")] + [UnconditionalSuppressMessage("Trimming", "IL2057", Justification = "IPC serialization uses known types at runtime.")] private async Task receive(Stream stream, CancellationToken cancellationToken = default) { const int header_length = sizeof(int); diff --git a/osu.Framework/Statistics/DotNetRuntimeListener.cs b/osu.Framework/Statistics/DotNetRuntimeListener.cs index 8633609303..deb91a68fc 100644 --- a/osu.Framework/Statistics/DotNetRuntimeListener.cs +++ b/osu.Framework/Statistics/DotNetRuntimeListener.cs @@ -5,6 +5,7 @@ using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Tracing; using System.Reflection; using osu.Framework.Extensions.TypeExtensions; @@ -43,6 +44,7 @@ protected override void OnEventSourceCreated(EventSource eventSource) private readonly GlobalStatistic statRented = GlobalStatistics.Get(arraypool_statistics_grouping, "Rented"); private readonly GlobalStatistic statReturned = GlobalStatistics.Get(arraypool_statistics_grouping, "Returned"); + [UnconditionalSuppressMessage("Trimming", "IL2057", Justification = "Debug/runtime inspection code; types are available at runtime.")] protected override void OnEventWritten(EventWrittenEventArgs data) { switch (data.EventSource.Name) diff --git a/osu.Framework/Testing/MenuTestScene.cs b/osu.Framework/Testing/MenuTestScene.cs index 5ccf6fb4ab..0ea51c482f 100644 --- a/osu.Framework/Testing/MenuTestScene.cs +++ b/osu.Framework/Testing/MenuTestScene.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -64,6 +65,7 @@ public MenuStructure(Menu menu) /// Finds the index in the represented by this that /// has set to . /// + [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Test types are always preserved.")] public int GetSelectedIndex() { var items = GetMenuItems(); @@ -83,6 +85,7 @@ public int GetSelectedIndex() /// /// The index of the to set the state of. /// The state to be set. + [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Test types are always preserved.")] public void SetSelectedState(int index, MenuItemState state) { var item = GetMenuItems()[index]; diff --git a/osu.Framework/Testing/TestBrowser.cs b/osu.Framework/Testing/TestBrowser.cs index c8f1bb3d66..a705e63a4c 100644 --- a/osu.Framework/Testing/TestBrowser.cs +++ b/osu.Framework/Testing/TestBrowser.cs @@ -7,6 +7,7 @@ using System.Collections; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using NUnit.Framework; @@ -347,6 +348,7 @@ public void OnReleased(KeyBindingReleaseEvent e) { } + [UnconditionalSuppressMessage("Trimming", "IL2067", Justification = "Test types are preserved by the test framework.")] public void LoadTest(Type testType = null, Action onCompletion = null, bool isHotReload = false) { if (CurrentTest?.Parent != null) @@ -387,6 +389,8 @@ private void resetRecording() RecordState.Value = Testing.RecordState.Normal; } + [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Test types are preserved by the test framework.")] + [UnconditionalSuppressMessage("Trimming", "IL2072", Justification = "Test types are preserved by the test framework.")] private void finishLoad(TestScene newTest, Action onCompletion) { if (CurrentTest != newTest) @@ -528,6 +532,8 @@ void handleTestMethod(MethodInfo methodInfo, params object[] arguments) } } + [UnconditionalSuppressMessage("Trimming", "IL2072:Target parameter of method", Justification = "Test source types are preserved by the test framework.")] + [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Test source types are preserved by the test framework.")] private static IEnumerable getTestCaseSourceValue(MethodInfo testMethod, TestCaseSourceAttribute tcs) { var sourceDeclaringType = tcs.SourceType ?? testMethod.DeclaringType; diff --git a/osu.Framework/Testing/TestScene.cs b/osu.Framework/Testing/TestScene.cs index 8b724f166f..5395e80098 100644 --- a/osu.Framework/Testing/TestScene.cs +++ b/osu.Framework/Testing/TestScene.cs @@ -5,11 +5,13 @@ using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Numerics; using System.Threading; using System.Threading.Tasks; using JetBrains.Annotations; +using NotNullAttribute = JetBrains.Annotations.NotNullAttribute; using NUnit.Framework; using NUnit.Framework.Constraints; using NUnit.Framework.Interfaces; @@ -442,6 +444,7 @@ protected void AddAssert([NotNull] string description, [NotNull] ActualValueD }); } + [UnconditionalSuppressMessage("Trimming", "IL2072", Justification = "Test types are always preserved.")] internal void RunSetUpSteps() { addStepsAsSetupSteps = true; @@ -450,6 +453,7 @@ internal void RunSetUpSteps() addStepsAsSetupSteps = false; } + [UnconditionalSuppressMessage("Trimming", "IL2072", Justification = "Test types are always preserved.")] internal void RunTearDownSteps() { foreach (var method in ReflectionUtils.GetMethodsWithAttribute(GetType(), typeof(TearDownStepsAttribute), true)) diff --git a/osu.Framework/Threading/DrawThread.cs b/osu.Framework/Threading/DrawThread.cs index 39308a686e..6175d20303 100644 --- a/osu.Framework/Threading/DrawThread.cs +++ b/osu.Framework/Threading/DrawThread.cs @@ -30,6 +30,8 @@ protected sealed override void OnInitialize() { host.Renderer.BeginFrame(new Vector2(window.ClientSize.Width, window.ClientSize.Height)); host.Renderer.FinishFrame(); + + host.TryInitializeLowLatencyProvider(); } } diff --git a/submodules/veldrid b/submodules/veldrid index 2202b40b30..db70f1b793 160000 --- a/submodules/veldrid +++ b/submodules/veldrid @@ -1 +1 @@ -Subproject commit 2202b40b30203111c424dccad9aa75e5f9fc5e06 +Subproject commit db70f1b79383a096c423ef25fea67d636c26306f