Compare commits

...

132 Commits

Author SHA1 Message Date
wxvu 06c67b0319 GameDB: Various fixes
GameDB: Various fixes

GameDB: Various fixes

GameDB: Various fixes
2026-06-07 15:25:08 -04:00
Adso Castro c68753d776 Qt: Add blank lines around the macro window title block 2026-06-07 15:24:54 -04:00
Adso Castro 15172303e4 Qt: Use multitap slot names for the first slot too
The binding widget and macro window titles keyed off sioPadIsMultitapSlot(),
which is only true for the multitap-exclusive slots (B/C/D), so the first slot
of each port (1A/2A) was shown without its slot letter while multitap was
enabled. Decide based on whether multitap is enabled for the port instead, so
all four slots are labelled consistently with the side list.
2026-06-07 15:24:54 -04:00
Adso Castro 9017ad626d Qt: Remove translator comments from controller binding titles 2026-06-07 15:24:54 -04:00
Adso Castro ef18567d9f Qt: Show multitap slot names in controller binding titles
The ControllerBindingWidget group box title and the ControllerMacroWidget
window title always read "Controller Port N", ignoring multitap slots. When
a multitap is enabled the side list already shows "Controller Port NA/B/C/D"
(handled in ControllerSettingsWindow), but the per-slot widget titles did not
follow suit, so every multitap slot looked like it referred to the base port.

Use sioPadIsMultitapSlot()/sioConvertPadToPortAndSlot() to render the same
"Controller Port NA" style labels in both titles, mirroring the existing
list-item logic.

Fixes #14529

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 15:24:54 -04:00
SternXD d0c2097cd4 Qt/ImGui: Use macOS keyboard behaviors
Signed-off-by: SternXD <stern@sidestore.io>
2026-06-07 15:02:57 -04:00
SternXD b5ed65ddd6 Qt/ImGui: Add clipboard support and fix modfier keys
Signed-off-by: SternXD <stern@sidestore.io>
2026-06-07 15:02:57 -04:00
Adso Castro 673917ae66 Qt: Fix game list view toggle with an empty game list
When the game list is empty the placeholder page is shown, and showGameList()/
showGameGrid() returned early before persisting the GameListGridView setting, so
toggling the view had no effect. updateToolbar() also derived the button state
from the current stack index, which is always the placeholder page when empty,
so the toolbar never reflected the selected mode.

Persist the preference before the early-out and base the toolbar state on the
saved setting, so switching views works (and is remembered for when games are
added) even while the list is empty.

Fixes #13220

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 14:54:17 -04:00
SternXD e31f57a02f GameList: Create covers directory if missing before downloading covers
Signed-off-by: SternXD <stern@sidestore.io>
2026-06-07 14:53:56 -04:00
SternXD ee57382d6e FullscreenUI: Implement cover download support
Signed-off-by: SternXD <stern@sidestore.io>
2026-06-07 14:53:56 -04:00
SternXD 6683f84da0 Tests: remove stubs that aren't needed
Signed-off-by: SternXD <stern@sidestore.io>
2026-06-07 14:53:56 -04:00
SternXD d2cb0aaf63 GSRunner: Remove noops that aren't needed
Signed-off-by: SternXD <stern@sidestore.io>
2026-06-07 14:53:56 -04:00
SternXD 51a5e10b4e Qt: Remove unneeded BPM handling code
Signed-off-by: SternXD <stern@sidestore.io>
2026-06-07 14:53:56 -04:00
refractionpcsx2 c2dfc10c18 GS/HW: Fix draw offsets in shuffles 2026-06-07 14:41:23 -04:00
refractionpcsx2 6628de5262 GS/HW: Only expand overlaps on page boundaries 2026-06-07 14:41:23 -04:00
refractionpcsx2 37f2837a55 GS/TC: Don't pre-downscale if native palette draw is enabled 2026-06-07 14:41:03 -04:00
refractionpcsx2 4b76157b9e GS/TC: Add new HW Readback option to force full download 2026-06-07 14:39:52 -04:00
refractionpcsx2 3b2962fe1c GS: Fix some more draw buffering edgecases 2026-06-07 14:21:48 -04:00
refractionpcsx2 20721b05fb GS: Fix temp rect handling 2026-06-07 14:21:48 -04:00
refractionpcsx2 75187d69c6 GS: Fix dirty reg handling 2026-06-07 14:21:48 -04:00
chaoticgd 3df128d9f9 PINE: Ignore SIGPIPE properly on macOS 2026-06-06 09:59:21 -04:00
PCSX2 Bot 426d77a932 [ci skip] Qt: Update Base Translation. 2026-06-04 02:56:46 +02:00
lightningterror b3b1ff0f50 GS/GL: Expand fb copy fallbacks.
Add nv extension GLAD_GL_NV_copy_image copy fallback.

Re add fbo copy fallback when no copy extension is supported and expand it for both color and depth.
2026-06-04 02:22:17 +02:00
KamFretoZ 88029a1411 Qt/FSUI: Enable ROV by default 2026-06-03 20:07:26 +02:00
JordanTheToaster 57e46f07fe Deps: Update SDL3 to v3.4.10 2026-06-03 05:38:57 +02:00
TJnotJT 254d955f89 GS/HW: Fix PS selector bits format in debug strings.
Fix the formatting since bit width went from 96 to 128.
2026-06-03 04:52:54 +02:00
TJnotJT e490685b42 GS/HW: Improve unordered access flag handling for RTs.
Only for DX11, which doesn't track resource state otherwise.
2026-06-03 03:26:24 +02:00
TJnotJT 7b0c39a20d GS/GL: Remove ROV support.
Buggy on multiple systems, even with various barrier hacks.
2026-06-03 03:26:24 +02:00
TJnotJT 059d631a6d QT/FSUI: Add ROV options to FSUI and QT.
Co-authored-by: SternXD
2026-06-03 03:26:24 +02:00
TJnotJT 7c255bd58d GS/VK: Fix for broken feedback transitions on Windows RDNA2.
Co-authored-by: TheLastRar
2026-06-03 03:26:24 +02:00
TJnotJT bbcd5ec25e GS/HW: ROV support. 2026-06-03 03:26:24 +02:00
chaoticgd 5369d6b38e CMake: Fix typo in BuildParameters.cmake 2026-06-02 07:14:55 -04:00
chaoticgd b3834427bc PINE: Don't test for a valid VM when checking emulator version 2026-06-01 23:55:19 +02:00
PCSX2 Bot d7002433a2 [ci skip] PAD: Update to latest controller database. 2026-06-01 23:54:08 +02:00
Dreadmoth e1291d5b7c Misc: Correct Hz symbol case 2026-06-01 09:51:12 -04:00
chaoticgd e1fd632ba3 CI: Add a debug build to the Linux build matrix 2026-06-01 09:26:11 -04:00
refractionpcsx2 fbaba52bc2 GS/HW: Fix bad assert causing debug build failure 2026-06-01 12:08:28 +01:00
PCSX2 Bot 224e82f33e [ci skip] Qt: Update Base Translation. 2026-06-01 05:27:17 +02:00
TJnotJT 8df49d7676 GS/HW: Fix a number of compiler warnings.
Missing default case in switch statement.
Signed/unsigned implict conversion.
Unused variables.
Hidden virtual overloaded function.
2026-05-31 22:38:31 +02:00
JordanTheToaster 88d8c561db Settings: Enable Skip Duplicate Frames by default 2026-05-31 15:11:02 -04:00
Tom Pritchard 78697466e0 Cli: Fix gamearg processing when using fast boot 2026-05-31 15:10:35 -04:00
chaoticgd 5e150cd3eb SaveState: Fix compression settings 2026-05-31 15:10:17 -04:00
chaoticgd 23dd23b468 CMake: Don't ship Qt Network on Windows 2026-05-31 15:10:06 -04:00
KamFretoZ 7d47dab728 Translation: Add Azərbaycanca 2026-05-31 15:02:29 -04:00
TJnotJT 74f2f73ce6 GS/HW: Use an enum instead of boolean to specify nearest/bilinear filtering. 2026-05-31 18:43:01 +02:00
TJnotJT 1e2f60a9b8 GS/HW: Ignore HW bilinear flag for shaders that do SW bilinear.
Co-authored-by: TellowKrinkle
2026-05-31 18:43:01 +02:00
TJnotJT bf892e9ece GS/HW: Treat depth input as R32 color input in convert shaders.
Co-authored-by: TellowKrinkle
2026-05-31 18:43:01 +02:00
TJnotJT a44fe80caa GS/HW: Refactor shader copy and texture formats.
Make it easier to add new depth formats, and code cleanup.

Co-authored-by: TellowKrinkle
2026-05-31 18:43:01 +02:00
chaoticgd 093287f6bf Console: Improve logic for outputting color codes 2026-05-31 15:35:22 +02:00
lightningterror e0365c1d10 GS/GL: Discard stencil when not in use while using depth.
Backport from DX12, clear the stencil when it's not used.
2026-05-30 22:02:09 +02:00
Ty 6cb2086dfc GHActions: Don't automatically undraft stable releases 2026-05-30 17:11:07 +02:00
TJnotJT 3f4b424200 GS/TC: Refactor/cleanup preload function. 2026-05-30 10:47:47 -04:00
refractionpcsx2 051fdd55b0 GS: Fix xy_tail buffers when draw buffering is enabled 2026-05-30 15:40:58 +02:00
refractionpcsx2 29f4318ef8 GS/TC: Fix combine targets scale and valid areas 2026-05-30 15:40:44 +02:00
lightningterror 30d7fed0e5 GS/DX12: Discard stencil when not in use while using depth.
Because the same texture is shared and used for both depth and stencil we want to discard when the stencil is not used instead of no access as that gives a validation error.
2026-05-30 15:02:22 +02:00
refractionpcsx2 f0177a879c HW/TC: Only make 8bit target sources temporary if they have MIP levels 2026-05-30 15:00:54 +02:00
refractionpcsx2 88af1e54a4 GS/HW: Downscale target before 8bit conversion 2026-05-30 15:00:54 +02:00
PCSX2 Bot d3ba0542f2 [ci skip] Qt: Update Base Translation. 2026-05-30 14:53:01 +02:00
TJnotJT 4d25bdcabb GS/DX11/GL: Adapt full barrier multidraw FB copy for sampling RT/DS hazards. 2026-05-30 14:52:42 +02:00
TJnotJT 02c5f8f648 GS/HW: Fix offset draw vertex trace/draw rect. 2026-05-29 23:27:33 +02:00
SternXD fc23783224 FullscreenUI: Move AA1 from SW only path 2026-05-29 21:29:07 +02:00
TheLastRar 7ade24fc77 Deps: Workaround MSVC ICE with PlutoVG 2026-05-28 19:49:11 +02:00
Heitof db16fa4403 GameDB: Remove Radio Helicopter II patches 2026-05-27 23:52:23 +02:00
TheLastRar 1bc08722fd GS/DX: Disable IEEE strict maths 2026-05-27 23:49:43 +02:00
wxvu 3a0a9f6705 GameDB: Various fixes for Armored Core series
GameDB: Various fixes for Armored Core series
2026-05-27 23:43:08 +02:00
lightningterror ae0b5834a0 GS/HW: Adjust depth read only handle. 2026-05-24 14:04:39 +02:00
refractionpcsx2 55eddba08f GS/HW/CRC: Optimize IRem CRC to not make unnecessary copies 2026-05-24 13:21:08 +02:00
lightningterror 0783ec1b9c GameDB: Add Tex in RT for Blood Will Tell/Dororo.
Fixes broken shuffles that replaced the shuffle hackfix.
2026-05-23 11:14:46 +02:00
refractionpcsx2 fc77fa1389 GS/HW: More shuffle fixes.
Try to skip more copies when a shuffle isn't a hazard.
Improve channel shuffle handle and remove Blood Will Tell
shuffle hackfix, will need Tex in RT to work.
2026-05-23 11:14:46 +02:00
lightningterror 0f9b8afe04 GS/HW: Further improve tex hazards.
Always enable test and sample depth on vk as well.

Make sure there is no feedback depth when using barriers,
as GL/DX12 have issues with it, so just stick with a plain copy
which is equivalent to depth as rt which we would have to do anyway.

Check for hazards properly for Hitman shuffle.

Better handle depth read only condition, allow for a barrier if it isn't.

Better handle hazard checks in device when doing a copy.

We don't need two or union copies on dx11 for depth as dx11 can't do partial depth
gpu copies.
2026-05-23 11:14:46 +02:00
lightningterror d39457951a GS/HW: Adjust HandleBarrierHazard to return a value. 2026-05-23 11:14:46 +02:00
lightningterror 9fcb526aca GS/HW: Also backport the samplearea copy to VK/DX12. 2026-05-23 11:14:46 +02:00
TJnotJT 9cd0ec1634 GS/HW: Use sampled area for RT/DS sampling hazards. 2026-05-23 11:14:46 +02:00
lightningterror 0e178aecb8 GS/HW: Remove tex is fb specific device checks for copies.
Handled in RendererHW.
2026-05-23 11:14:46 +02:00
lightningterror 66f764cf02 GS/VK: Remove rt and ds hazard check, handled in RendererHW. 2026-05-23 11:14:46 +02:00
lightningterror 63f2d8d880 GS/DX12: Remove rt hazard check, handled in RendererHW. 2026-05-23 11:14:46 +02:00
lightningterror b123f016ab GS/GL: Remove the hazard checks as they are handled in renderer.
tex == rt, tex == ds hazards are handled in RendererHW.
Always enable test and sample depth for GL.
2026-05-23 11:14:46 +02:00
lightningterror f08f679ba7 GS/HW: Handle barrier hazards in RendererHW instead of Device.
Cleaner, easier to track.
2026-05-23 11:14:46 +02:00
refractionpcsx2 054e0509c4 GS/HW: Avoid hazard copy if read and draw don't overlap + fix CSBW typo 2026-05-23 11:14:46 +02:00
TheLastRar f86cd4c3d2 GS/DX12: Init RWTexture as direct queue shader resource 2026-05-21 23:55:22 +02:00
TJnotJT a19b3747ea GS/HW: Add AA1 triangle corner caps and edge extrapolation. 2026-05-20 01:02:00 +02:00
lightningterror 30440099c2 GS/GLSL: Make sure color output is disabled for depth only writes or testing and fix afail typo. 2026-05-19 13:03:35 +02:00
PCSX2 Bot 30dd35a743 [ci skip] Qt: Update Base Translation. 2026-05-19 12:22:03 +02:00
PCSX2 Bot 4f1dab7b5f [ci skip] PAD: Update to latest controller database. 2026-05-18 23:08:41 +02:00
KamFretoZ baad1891eb Qt: Translation Fixes 2026-05-18 07:31:15 -04:00
PCSX2 Bot 6ea9e4a5b0 [ci skip] Qt: Update Base Translation. 2026-05-18 08:42:38 +02:00
TJnotJT 534330aa99 GS/VK: Make sure layout changes are propagated to descriptors. 2026-05-18 08:41:26 +02:00
chaoticgd 58a0ced8be Debugger: Fix parameter symbol creation dialog 2026-05-17 15:12:31 -04:00
PCSX2 Bot e18d5b7183 [ci skip] Qt: Update Base Translation. 2026-05-16 22:52:37 -04:00
Sean Brar b006366ea3 DEV9: Warn about Linux PCAP capabilities 2026-05-16 19:32:13 -04:00
JordanTheToaster 1db914f964 GH: Use VS 2026 runners 2026-05-16 19:29:49 -04:00
JordanTheToaster 6b34999a51 Deps: Update Qt to 6.11.1 2026-05-17 00:29:09 +02:00
JordanTheToaster 85ea218b5d GameDB: The Draw Buffaning 2026-05-17 00:18:55 +02:00
Mrlinkwii 137f4f2666 Github: update PR template to include link to Large Language Models (LLM) Usage Policy 2026-05-17 00:17:47 +02:00
lightningterror 4cc2a81f00 GS/DX11/GL: Fix tex is fb behaviour when doing gpu copies.
When I was doing the clean ups I forgot to include the condition.
2026-05-16 16:01:20 +02:00
JordanTheToaster da340c9e92 ImGuiOverlays: Build fix 2026-05-16 12:26:10 +01:00
JordanTheToaster a7356d3765 3rdparty: Update ImGui to v1.92.8 2026-05-16 12:04:58 +02:00
SternXD 3aa0685786 GS: Track shader compile count and duration for OSD 2026-05-16 11:50:56 +02:00
lightningterror 2f8c98dccf GS/DX11/GL: Fix barrier typo, should check alpha second pass barrier. 2026-05-16 11:48:53 +02:00
lightningterror 59e422c538 GS/GL: Depth isn't written so we can skip a barrier. 2026-05-16 11:48:53 +02:00
lightningterror 5ef5e41e69 GS/DX11: Also check for depth feedback on alpha second pass. 2026-05-16 11:48:53 +02:00
PCSX2 Bot 58facc8ab1 [ci skip] Qt: Update Base Translation. 2026-05-15 10:13:36 +02:00
SternXD 3341514bb4 GS: Add shader compile indicator 2026-05-14 21:57:11 +02:00
PCSX2 Bot 0434aba3a8 [ci skip] Qt: Update Base Translation. 2026-05-14 14:37:43 +02:00
TJnotJT c1cb214a03 GS/HW: Add debug blend setting.
Will enable SW blend and disable many optimizations.
2026-05-13 19:49:07 +02:00
Ty 3233a3cf8f Achievements: Fix crash in WinHTTP timeout
Co-authored-by: salas-dev-max <dren@thePuter.localdomain>
2026-05-13 12:20:43 -04:00
Florin9doi 469a3d60b2 USB: Additional commands for MSAC-US1 2026-05-13 12:17:55 -04:00
Sean Brar bb35bed104 DEV9: Isolate raw PCAP packet IO 2026-05-13 12:17:27 -04:00
chaoticgd 624acf5533 Qt: Fix crash when interacting with per-game achievement settings 2026-05-13 12:17:02 -04:00
SternXD f71f0b9cb0 GS/ImGui: Update ImGui when resizing the swap chain
This allows for the OSD and BPM to stay in sync when resizing heavily

Co-authored-by: GovanifY <me@govanify.com>
2026-05-13 17:03:02 +02:00
SternXD 07279568a6 3rdparty/Deps: Various updates (#14420)
### Description of Changes
Updated a number of dependencies and third-party libraries to newer
versions / commits.

## **Deps:**
* libpng `v1.6.56` -> `v1.6.58`
* harfbuzz `14.0.0` -> `14.2.0`
* agilitysdk `1.619.1` -> `1.619.2`
* rapidyaml `v0.11.1` -> `v0.12.1`
* shaderc `2026.1` -> `2026.2`

## **3rdparty:**
* vixl `e6076e9` -> `3fe1686`
* cubeb `e495bee` -> `6ad18e2`
* xbyak `v7.35.2` -> `v7.37`
* CPUInfo `7364b49` -> `3681f0c`
* LZMA/7zipSDK `25.00` -> `26.01`
* fast_float `v8.1.0` -> `v8.2.5`

### Rationale behind Changes
Security fixes and improvements are good

### Suggested Testing Steps
Test everything (yaml, png, vulkan, cpu information in osd, audio etc)

### Did you use AI to help find, test, or implement this issue or
feature?
Nah.

---------

Signed-off-by: SternXD <stern@sidestore.io>
2026-05-12 12:14:40 -04:00
TJnotJT 4ef84fa51c GS/HW: Fix flat shaded color in AA1 shader. 2026-05-12 14:46:49 +02:00
TheLastRar 38ee1e1e22 GS/DX: Specify shader model directly instead of via feature level 2026-05-11 22:29:45 +02:00
PCSX2 Bot 2b02a5dc78 [ci skip] PAD: Update to latest controller database. 2026-05-11 13:30:19 -04:00
descawed dead00eb62 GameDB: Enable Instant DMA Hack for SLPM-74405 to fix hang 2026-05-10 19:07:21 +02:00
TJnotJT 4fa2b8e45d GS/HW: Fixes/improvements to early scissor/bbox test. 2026-05-09 13:48:42 +02:00
refractionpcsx2 fc90973509 GS/HW/COLCLIP: Check tex mapping is enabled when checking for recursion 2026-05-09 13:47:58 +02:00
Immersion95 ff9176f83e GameDB: fixes wrong title for SLPM-65496 - Hyper Street Fighter II - The Anniversary Edition 2026-05-09 13:46:48 +02:00
refractionpcsx2 63d3dd9978 GS/TC: Update dirty target linked to source when dirty overlaps the read 2026-05-09 13:46:25 +02:00
JordanTheToaster b704c6caaa GameDB: Pump It Up Exceed Fixes 2026-05-08 18:56:51 +02:00
lightningterror a64465681c GS/HW: Disable texture shuffle if there's no tex. 2026-05-08 18:29:05 +02:00
refractionpcsx2 539357436c Build: Clean up a few warnings 2026-05-08 18:17:31 +02:00
refractionpcsx2 22cb6b0c9c GS/HW: Remove zero clear from GSUploadQueue, use transfer_type instead 2026-05-08 18:15:18 +02:00
PCSX2 Bot 81df4e5def [ci skip] Qt: Update Base Translation. 2026-05-07 02:15:53 +02:00
Ziemas a3f3e8733d GS: fix build with libstdc++ 16 2026-05-06 18:05:51 -04:00
SternXD 6fc84f76bb FullscreenUI: Fix RA login state, and add dismiss dialog 2026-05-06 20:55:44 +02:00
TJnotJT 0949f193b8 GS/SW: Adjust bounds in assertion to present false positive.
Account for the fact that bottom/right coordinates are exclusive.
2026-05-06 20:46:51 +02:00
TJnotJT 5f3dc1a76e GS/SW: Early exit optimization for multithreaded horizontal lines. 2026-05-06 20:46:51 +02:00
TJnotJT 9afea55bb6 GS/SW: Adjust bbox to account for AA1 and points/line rounding. 2026-05-06 20:46:51 +02:00
TJnotJT 433614ae85 GS: Adjust primitive bbox in vertex kick to account for AA1. 2026-05-06 20:46:51 +02:00
TJnotJT 00c85c4a8f GS/TC: Use temporary source on invalid TEX0. 2026-05-06 19:18:04 +02:00
PCSX2 Bot f9885315bd [ci skip] Qt: Update Base Translation. 2026-05-06 11:59:56 +02:00
221 changed files with 64587 additions and 17013 deletions
+1 -1
View File
@@ -8,4 +8,4 @@
<!-- If applicable, including examples you've already tested with / recommendations for how to test further is very helpful! -->
### Did you use AI to help find, test, or implement this issue or feature?
<!-- Answer yes or no. If you answer yes, please provide a brief explanation how. -->
<!-- Answer yes or no. If you answer yes, please provide a brief explanation as to how you used it. Please see the Large Language Model (LLM) Usage Policy for more information: https://pcsx2.net/docs/contributing/#large-language-model-llm-usage-policy -->
+12
View File
@@ -20,6 +20,18 @@ jobs:
cmakeflags: ""
buildAppImage: true
secrets: inherit
build_linux_debug:
name: "Debug"
if: github.repository != 'PCSX2/pcsx2' || github.event_name == 'pull_request'
uses: ./.github/workflows/linux_build_qt.yml
with:
jobName: "Debug Build"
artifactPrefixName: "PCSX2-linux-Qt-x64-debug"
compiler: clang
cmakeflags: ""
buildAppImage: true
cmakeBuildType: Debug
secrets: inherit
build_linux_flatpak:
name: "Flatpak"
if: github.repository != 'PCSX2/pcsx2' || github.event_name == 'pull_request'
+5 -1
View File
@@ -39,6 +39,10 @@ on:
required: false
type: boolean
default: false
cmakeBuildType:
required: false
type: string
default: Release
jobs:
build_linux:
@@ -129,7 +133,7 @@ jobs:
ADDITIONAL_CMAKE_ARGS: ${{ inputs.cmakeflags }}
run: |
cmake -B build -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_BUILD_TYPE="${{ inputs.cmakeBuildType }}" \
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
-DCMAKE_PREFIX_PATH="$HOME/deps" \
-DCMAKE_C_COMPILER=clang-17 \
+1
View File
@@ -209,6 +209,7 @@ jobs:
gh release upload "${TAG_VAL}" ${{ github.WORKSPACE }}/ci-artifacts/out/* --repo PCSX2/pcsx2 --clobber
- name: Publish Release
if: github.event_name != 'workflow_dispatch' || inputs.is_prerelease == 'true'
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
@@ -18,28 +18,28 @@ if [ "${INSTALLDIR:0:1}" != "/" ]; then
INSTALLDIR="$PWD/$INSTALLDIR"
fi
QT=6.11.0
QT=6.11.1
QTAPNG=1.3.0
FFMPEG=8.1
LIBBACKTRACE=ad106d5fdd5d960bd33fae1c48a351af567fd075
LIBJPEGTURBO=3.1.4.1
LIBPNG=1.6.56
LIBPNG=1.6.58
LIBWEBP=1.6.0
NVENC=13.0.19.0
SDL=SDL3-3.4.8
SDL=SDL3-3.4.10
LZ4=1.10.0
VULKAN=1.4.328.1
ZSTD=1.5.7
KDDOCKWIDGETS=2.4.0
PLUTOVG=1.3.2
PLUTOSVG=0.0.7
RAPIDYAML=0.11.1
RAPIDYAML=0.12.1
SHADERC=2026.1
SHADERC_GLSLANG=f0bd0257c308b9a26562c1a30c4748a0219cc951
SHADERC_SPIRVHEADERS=04f10f650d514df88b76d25e83db360142c7b174
SHADERC_SPIRVTOOLS=fbe4f3ad913c44fe8700545f8ffe35d1382b7093
SHADERC=2026.2
SHADERC_GLSLANG=275822a6261ee689aadb1da5f09a0ec2f058685c
SHADERC_SPIRVHEADERS=58006c901d1d5c37dece6b6610e9af87fa951375
SHADERC_SPIRVTOOLS=6337eb62cadd7d124ac6789bf39c0f71148f0a73
mkdir -p deps-build
cd deps-build
@@ -47,21 +47,21 @@ cd deps-build
export PKG_CONFIG_PATH="$INSTALLDIR/lib/pkgconfig:$PKG_CONFIG_PATH"
grep . > SHASUMS <<EOF
231ad85979864d914dc9568a1b71c91d6cf20d7b2021d059103bf0eb51cb755e qtbase-everywhere-src-$QT.tar.xz
d3adb02ac5e2fe24068dbdaee0d7cc68cc3fa8553291c1bfce77c9fe8e940cc8 qtimageformats-everywhere-src-$QT.tar.xz
dfa8d653be07087d9407ed4a4ebae847f8953e0b7abd829f089803ab652a30e6 qtsvg-everywhere-src-$QT.tar.xz
cfb1993d7a10848965b01b9cf33a54b8a4ba4e5e3a6d28d59483e73f10d9fc76 qttools-everywhere-src-$QT.tar.xz
54f48b2fe4316892ff930195f170a5385644acc7393505f3155c066b8e1ffe56 qttranslations-everywhere-src-$QT.tar.xz
e710e6e760f92922b86e4dd68f6bbe94ef6510919519d1b0068e874b5ad84d37 qtwayland-everywhere-src-$QT.tar.xz
d9594a31228aa23ad6b531719a29b45f0f3989fe6c136d45767ea179f233c1ac qtbase-everywhere-src-$QT.tar.xz
b2bf6c6845ac175ed7f819145483ba4676f617aaa6a5012c8efee63c8bbac413 qtimageformats-everywhere-src-$QT.tar.xz
7f3cf02f4824bf03c2c5859ea6db173bf1482a1daf24e6cdf7bc78cfa26a8a94 qtsvg-everywhere-src-$QT.tar.xz
8e61835a679c93fa9c6065b142353c2071ba68e297898937c32a03777fcaf50d qttools-everywhere-src-$QT.tar.xz
37c02c81206594c7bb4edca85ac93e8e55a9836b70c960fde6cb0f8623ec5677 qttranslations-everywhere-src-$QT.tar.xz
95788aa502f75441d4edf65932b235f76523084e13dbbb7b9ee2d207b32bd9b3 qtwayland-everywhere-src-$QT.tar.xz
f1d3be3489f758efe1a8f12118a212febbe611aa670af32e0159fa3c1feab2a6 QtApng-$QTAPNG.tar.gz
b072aed6871998cce9b36e7774033105ca29e33632be5b6347f3206898e0756a ffmpeg-$FFMPEG.tar.xz
96e5c2d7f2c482a60d5804da48a2eb9a0db0719b2c65dcc169fbfdcf37f3a45d libbacktrace-$LIBBACKTRACE.tar.gz
ecae8008e2cc9ade2f2c1bb9d5e6d4fb73e7c433866a056bd82980741571a022 libjpeg-turbo-$LIBJPEGTURBO.tar.gz
f7d8bf1601b7804f583a254ab343a6549ca6cf27d255c302c47af2d9d36a6f18 libpng-$LIBPNG.tar.xz
28eb403f51f0f7405249132cecfe82ea5c0ef97f1b32c5a65828814ae0d34775 libpng-$LIBPNG.tar.xz
e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 libwebp-$LIBWEBP.tar.gz
e9fff7467fb60f037e6708da18b25560649e4c63edc2a69bb871b960d9cbfbba $SDL.tar.gz
9ce32d4a2763a2ac5f258726ba2f49e9011327c1ee8c30862a32d0f30889fbe8 libpng-$LIBPNG-apng.patch.gz
12b34280415ec8418c864408b93d008a20a6530687ee613d60bfbd20411f2785 $SDL.tar.gz
eee7dea22ed502868017971c86c63c4ed1e6085de0baebfdcc3d3322f00f3eb0 libpng-$LIBPNG-apng.patch.gz
537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b lz4-$LZ4.tar.gz
13da39edb3a40ed9713ae390ca89faa2f1202c9dda869ef306a8d4383e242bee nv-codec-headers-$NVENC.tar.gz
c465aa56757e7746ac707f582b6e2d51546569a4a2488c1172fb543aa5fdfc2c vulkan-sdk-$VULKAN.tar.gz
@@ -69,12 +69,12 @@ eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar
51dbf24fe72e43dd7cb9a289d3cab47112010f1a2ed69b6fc8ac0dff31991ed2 KDDockWidgets-$KDDOCKWIDGETS.tar.gz
7bd4e79ce18b1d47517e7e91fbb7cf19d4f01942804a519bc7c0bf32b6325dd5 plutovg-$PLUTOVG.tar.gz
78561b571ac224030cdc450ca2986b4de915c2ba7616004a6d71a379bffd15f3 plutosvg-$PLUTOSVG.tar.gz
9d9938269adc25e9a9b84650338b87d130cf469d82685fffc028c325279619c1 rapidyaml-$RAPIDYAML-src.tgz
e9efcdd17f86287748793cf21d106e461fcad8d103a3e5a23632afe93828660d rapidyaml-$RAPIDYAML-src.tgz
245002feccbe7f8361b223545a5654cea69780745886872d7efff50a38d96c66 shaderc-$SHADERC.tar.gz
bd58dca4dac67dcf7640292d7d63e0416274d40ee2200f7301878cec11ac6647 shaderc-glslang-$SHADERC_GLSLANG.tar.gz
1b220e3eec1714f0451b0e3652979bd280edf10893f617837b88e6359a804ded shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz
cabb35f4eef0da3ef72ad9edd596af4191d7507a8f35c05df526d2d5ff889f59 shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz
f924178e75e3293082481b25ed64d5e48a795b479dac3bd3c83d23070855df42 shaderc-$SHADERC.tar.gz
971848a1cc639ce8dc244e778b17efe0f690e32ac398a75e31d1c67ad06d3e0a shaderc-glslang-$SHADERC_GLSLANG.tar.gz
a6cb1b300bb8171795e116457e858e555334749f9cacaed8068ae0ef8681110c shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz
e156be0bd81c8812f1bff8e520422bfa9df61b3045587b9eb483185f1074a7b2 shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz
EOF
if ! shasum -sa 256 --check SHASUMS 2> /dev/null; then
@@ -24,7 +24,7 @@ LZ4=1.10.0
ZSTD=1.5.7
PLUTOVG=1.3.2
PLUTOSVG=0.0.7
RAPIDYAML=0.11.1
RAPIDYAML=0.12.1
SHADERC=2025.4
SHADERC_GLSLANG=7a47e2531cb334982b2a2dd8513dca0a3de4373d
@@ -50,7 +50,7 @@ c693867f10a7760ef1bcf85419d51783586768cc2c601d03841bc6a8b2554b9c shaderc-spirv-
06b0a042f2e121e954badb4fd78c9e2d4bc7ed6087eceb26ab559c23cf94334f shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz
7bd4e79ce18b1d47517e7e91fbb7cf19d4f01942804a519bc7c0bf32b6325dd5 plutovg-$PLUTOVG.tar.gz
78561b571ac224030cdc450ca2986b4de915c2ba7616004a6d71a379bffd15f3 plutosvg-$PLUTOSVG.tar.gz
9d9938269adc25e9a9b84650338b87d130cf469d82685fffc028c325279619c1 rapidyaml-$RAPIDYAML-src.tgz
e9efcdd17f86287748793cf21d106e461fcad8d103a3e5a23632afe93828660d rapidyaml-$RAPIDYAML-src.tgz
EOF
if ! shasum -sa 256 --check SHASUMS 2> /dev/null; then
@@ -14,8 +14,8 @@
"sources": [
{
"type": "archive",
"url": "https://libsdl.org/release/SDL3-3.4.8.tar.gz",
"sha256": "e9fff7467fb60f037e6708da18b25560649e4c63edc2a69bb871b960d9cbfbba"
"url": "https://libsdl.org/release/SDL3-3.4.10.tar.gz",
"sha256": "12b34280415ec8418c864408b93d008a20a6530687ee613d60bfbd20411f2785"
}
],
"cleanup": [
@@ -15,24 +15,24 @@
{
"type": "git",
"url": "https://github.com/google/shaderc.git",
"commit": "301b4ede53d59b68bf55f95bb26412d9233c8187"
"commit": "d5f08ae5c5a9a45165578445cbd0f9adf0223448"
},
{
"type": "archive",
"url": "https://github.com/KhronosGroup/glslang/archive/f0bd0257c308b9a26562c1a30c4748a0219cc951.tar.gz",
"sha256": "bd58dca4dac67dcf7640292d7d63e0416274d40ee2200f7301878cec11ac6647",
"url": "https://github.com/KhronosGroup/glslang/archive/275822a6261ee689aadb1da5f09a0ec2f058685c.tar.gz",
"sha256": "971848a1cc639ce8dc244e778b17efe0f690e32ac398a75e31d1c67ad06d3e0a",
"dest": "third_party/glslang"
},
{
"type": "archive",
"url": "https://github.com/KhronosGroup/SPIRV-Headers/archive/04f10f650d514df88b76d25e83db360142c7b174.tar.gz",
"sha256": "1b220e3eec1714f0451b0e3652979bd280edf10893f617837b88e6359a804ded",
"url": "https://github.com/KhronosGroup/SPIRV-Headers/archive/58006c901d1d5c37dece6b6610e9af87fa951375.tar.gz",
"sha256": "a6cb1b300bb8171795e116457e858e555334749f9cacaed8068ae0ef8681110c",
"dest": "third_party/spirv-headers"
},
{
"type": "archive",
"url": "https://github.com/KhronosGroup/SPIRV-Tools/archive/fbe4f3ad913c44fe8700545f8ffe35d1382b7093.tar.gz",
"sha256": "cabb35f4eef0da3ef72ad9edd596af4191d7507a8f35c05df526d2d5ff889f59",
"url": "https://github.com/KhronosGroup/SPIRV-Tools/archive/6337eb62cadd7d124ac6789bf39c0f71148f0a73.tar.gz",
"sha256": "e156be0bd81c8812f1bff8e520422bfa9df61b3045587b9eb483185f1074a7b2",
"dest": "third_party/spirv-tools"
},
{
@@ -14,21 +14,21 @@
"sources": [
{
"type": "archive",
"url": "https://downloads.sourceforge.net/project/libpng/libpng16/1.6.56/libpng-1.6.56.tar.xz",
"sha256": "f7d8bf1601b7804f583a254ab343a6549ca6cf27d255c302c47af2d9d36a6f18"
"url": "https://downloads.sourceforge.net/project/libpng/libpng16/1.6.58/libpng-1.6.58.tar.xz",
"sha256": "28eb403f51f0f7405249132cecfe82ea5c0ef97f1b32c5a65828814ae0d34775"
},
{
"type": "file",
"url": "https://download.sourceforge.net/libpng-apng/libpng-1.6.56-apng.patch.gz",
"dest-filename": "libpng-1.6.56-apng.patch.gz",
"sha256": "9ce32d4a2763a2ac5f258726ba2f49e9011327c1ee8c30862a32d0f30889fbe8"
"url": "https://download.sourceforge.net/libpng-apng/libpng-1.6.58-apng.patch.gz",
"dest-filename": "libpng-1.6.58-apng.patch.gz",
"sha256": "eee7dea22ed502868017971c86c63c4ed1e6085de0baebfdcc3d3322f00f3eb0"
},
{
"type": "shell",
"commands":
[
"gunzip -f libpng-1.6.56-apng.patch.gz",
"patch -p1 < \"libpng-1.6.56-apng.patch\""
"gunzip -f libpng-1.6.58-apng.patch.gz",
"patch -p1 < \"libpng-1.6.58-apng.patch\""
]
}
],
@@ -12,8 +12,8 @@
{
"type": "git",
"url": "https://github.com/biojppm/rapidyaml.git",
"tag": "v0.11.1",
"commit": "119b6042064d3828819e428e32e5a0f3035d5643"
"tag": "v0.12.1",
"commit": "b56567b0bd24e9ce7beb08d6950a5732f62f6e74"
}
],
"cleanup": [
@@ -43,15 +43,15 @@ if [ "${INSTALLDIR:0:1}" != "/" ]; then
INSTALLDIR="$PWD/$INSTALLDIR"
fi
QT=6.11.0
QT=6.11.1
QTAPNG=1.3.0
FREETYPE=2.14.3
SDL=SDL3-3.4.8
HARFBUZZ=14.0.0
SDL=SDL3-3.4.10
HARFBUZZ=14.2.0
ZSTD=1.5.7
LZ4=1.10.0
LIBPNG=1.6.56
LIBPNG=1.6.58
LIBJPEGTURBO=3.1.4.1
LIBWEBP=1.6.0
FFMPEG=8.1
@@ -59,12 +59,12 @@ MOLTENVK=1.4.1
KDDOCKWIDGETS=2.4.0
PLUTOVG=1.3.2
PLUTOSVG=0.0.7
RAPIDYAML=0.11.1
RAPIDYAML=0.12.1
SHADERC=2026.1
SHADERC_GLSLANG=f0bd0257c308b9a26562c1a30c4748a0219cc951
SHADERC_SPIRVHEADERS=04f10f650d514df88b76d25e83db360142c7b174
SHADERC_SPIRVTOOLS=fbe4f3ad913c44fe8700545f8ffe35d1382b7093
SHADERC=2026.2
SHADERC_GLSLANG=275822a6261ee689aadb1da5f09a0ec2f058685c
SHADERC_SPIRVHEADERS=58006c901d1d5c37dece6b6610e9af87fa951375
SHADERC_SPIRVTOOLS=6337eb62cadd7d124ac6789bf39c0f71148f0a73
mkdir -p deps-build
cd deps-build
@@ -85,33 +85,33 @@ CMAKE_ARCH_ARM64=-DCMAKE_OSX_ARCHITECTURES="arm64"
CMAKE_ARCH_UNIVERSAL=-DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"
grep . > SHASUMS <<EOF
231ad85979864d914dc9568a1b71c91d6cf20d7b2021d059103bf0eb51cb755e qtbase-everywhere-src-$QT.tar.xz
d3adb02ac5e2fe24068dbdaee0d7cc68cc3fa8553291c1bfce77c9fe8e940cc8 qtimageformats-everywhere-src-$QT.tar.xz
dfa8d653be07087d9407ed4a4ebae847f8953e0b7abd829f089803ab652a30e6 qtsvg-everywhere-src-$QT.tar.xz
cfb1993d7a10848965b01b9cf33a54b8a4ba4e5e3a6d28d59483e73f10d9fc76 qttools-everywhere-src-$QT.tar.xz
54f48b2fe4316892ff930195f170a5385644acc7393505f3155c066b8e1ffe56 qttranslations-everywhere-src-$QT.tar.xz
d9594a31228aa23ad6b531719a29b45f0f3989fe6c136d45767ea179f233c1ac qtbase-everywhere-src-$QT.tar.xz
b2bf6c6845ac175ed7f819145483ba4676f617aaa6a5012c8efee63c8bbac413 qtimageformats-everywhere-src-$QT.tar.xz
7f3cf02f4824bf03c2c5859ea6db173bf1482a1daf24e6cdf7bc78cfa26a8a94 qtsvg-everywhere-src-$QT.tar.xz
8e61835a679c93fa9c6065b142353c2071ba68e297898937c32a03777fcaf50d qttools-everywhere-src-$QT.tar.xz
37c02c81206594c7bb4edca85ac93e8e55a9836b70c960fde6cb0f8623ec5677 qttranslations-everywhere-src-$QT.tar.xz
f1d3be3489f758efe1a8f12118a212febbe611aa670af32e0159fa3c1feab2a6 QtApng-$QTAPNG.tar.gz
36bc4f1cc413335368ee656c42afca65c5a3987e8768cc28cf11ba775e785a5f freetype-$FREETYPE.tar.xz
e9fff7467fb60f037e6708da18b25560649e4c63edc2a69bb871b960d9cbfbba $SDL.tar.gz
f29db9470e0ca5cef484e04e27baeec233aa428e8fdabe9e51b0f706c0809d24 harfbuzz-$HARFBUZZ.tar.gz
12b34280415ec8418c864408b93d008a20a6530687ee613d60bfbd20411f2785 $SDL.tar.gz
c652d5d94971031654ab3989891a490a895d3e3f2b71171c62692b28e94b1b93 harfbuzz-$HARFBUZZ.tar.gz
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b lz4-$LZ4.tar.gz
f7d8bf1601b7804f583a254ab343a6549ca6cf27d255c302c47af2d9d36a6f18 libpng-$LIBPNG.tar.xz
28eb403f51f0f7405249132cecfe82ea5c0ef97f1b32c5a65828814ae0d34775 libpng-$LIBPNG.tar.xz
e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 libwebp-$LIBWEBP.tar.gz
9ce32d4a2763a2ac5f258726ba2f49e9011327c1ee8c30862a32d0f30889fbe8 libpng-$LIBPNG-apng.patch.gz
eee7dea22ed502868017971c86c63c4ed1e6085de0baebfdcc3d3322f00f3eb0 libpng-$LIBPNG-apng.patch.gz
ecae8008e2cc9ade2f2c1bb9d5e6d4fb73e7c433866a056bd82980741571a022 libjpeg-turbo-$LIBJPEGTURBO.tar.gz
b072aed6871998cce9b36e7774033105ca29e33632be5b6347f3206898e0756a ffmpeg-$FFMPEG.tar.xz
9985f141902a17de818e264d17c1ce334b748e499ee02fcb4703e4dc0038f89c MoltenVK-$MOLTENVK.tar.gz
51dbf24fe72e43dd7cb9a289d3cab47112010f1a2ed69b6fc8ac0dff31991ed2 KDDockWidgets-$KDDOCKWIDGETS.tar.gz
7bd4e79ce18b1d47517e7e91fbb7cf19d4f01942804a519bc7c0bf32b6325dd5 plutovg-$PLUTOVG.tar.gz
78561b571ac224030cdc450ca2986b4de915c2ba7616004a6d71a379bffd15f3 plutosvg-$PLUTOSVG.tar.gz
9d9938269adc25e9a9b84650338b87d130cf469d82685fffc028c325279619c1 rapidyaml-$RAPIDYAML-src.tgz
e9efcdd17f86287748793cf21d106e461fcad8d103a3e5a23632afe93828660d rapidyaml-$RAPIDYAML-src.tgz
245002feccbe7f8361b223545a5654cea69780745886872d7efff50a38d96c66 shaderc-$SHADERC.tar.gz
bd58dca4dac67dcf7640292d7d63e0416274d40ee2200f7301878cec11ac6647 shaderc-glslang-$SHADERC_GLSLANG.tar.gz
1b220e3eec1714f0451b0e3652979bd280edf10893f617837b88e6359a804ded shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz
cabb35f4eef0da3ef72ad9edd596af4191d7507a8f35c05df526d2d5ff889f59 shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz
f924178e75e3293082481b25ed64d5e48a795b479dac3bd3c83d23070855df42 shaderc-$SHADERC.tar.gz
971848a1cc639ce8dc244e778b17efe0f690e32ac398a75e31d1c67ad06d3e0a shaderc-glslang-$SHADERC_GLSLANG.tar.gz
a6cb1b300bb8171795e116457e858e555334749f9cacaed8068ae0ef8681110c shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz
e156be0bd81c8812f1bff8e520422bfa9df61b3045587b9eb483185f1074a7b2 shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz
EOF
if ! shasum -sa 256 --check SHASUMS 2> /dev/null; then
@@ -20,15 +20,15 @@ if [ "${INSTALLDIR:0:1}" != "/" ]; then
INSTALLDIR="$PWD/$INSTALLDIR"
fi
QT=6.11.0
QT=6.11.1
QTAPNG=1.3.0
FREETYPE=2.14.3
SDL=SDL3-3.4.8
HARFBUZZ=14.0.0
SDL=SDL3-3.4.10
HARFBUZZ=14.2.0
ZSTD=1.5.7
LZ4=1.10.0
LIBPNG=1.6.56
LIBPNG=1.6.58
LIBJPEGTURBO=3.1.4.1
LIBWEBP=1.6.0
FFMPEG=8.1
@@ -36,12 +36,12 @@ MOLTENVK=1.4.1
KDDOCKWIDGETS=2.4.0
PLUTOVG=1.3.2
PLUTOSVG=0.0.7
RAPIDYAML=0.11.1
RAPIDYAML=0.12.1
SHADERC=2026.1
SHADERC_GLSLANG=f0bd0257c308b9a26562c1a30c4748a0219cc951
SHADERC_SPIRVHEADERS=04f10f650d514df88b76d25e83db360142c7b174
SHADERC_SPIRVTOOLS=fbe4f3ad913c44fe8700545f8ffe35d1382b7093
SHADERC=2026.2
SHADERC_GLSLANG=275822a6261ee689aadb1da5f09a0ec2f058685c
SHADERC_SPIRVHEADERS=58006c901d1d5c37dece6b6610e9af87fa951375
SHADERC_SPIRVTOOLS=6337eb62cadd7d124ac6789bf39c0f71148f0a73
mkdir -p deps-build
cd deps-build
@@ -61,33 +61,33 @@ CMAKE_COMMON=(
)
grep . > SHASUMS <<EOF
231ad85979864d914dc9568a1b71c91d6cf20d7b2021d059103bf0eb51cb755e qtbase-everywhere-src-$QT.tar.xz
d3adb02ac5e2fe24068dbdaee0d7cc68cc3fa8553291c1bfce77c9fe8e940cc8 qtimageformats-everywhere-src-$QT.tar.xz
dfa8d653be07087d9407ed4a4ebae847f8953e0b7abd829f089803ab652a30e6 qtsvg-everywhere-src-$QT.tar.xz
cfb1993d7a10848965b01b9cf33a54b8a4ba4e5e3a6d28d59483e73f10d9fc76 qttools-everywhere-src-$QT.tar.xz
54f48b2fe4316892ff930195f170a5385644acc7393505f3155c066b8e1ffe56 qttranslations-everywhere-src-$QT.tar.xz
d9594a31228aa23ad6b531719a29b45f0f3989fe6c136d45767ea179f233c1ac qtbase-everywhere-src-$QT.tar.xz
b2bf6c6845ac175ed7f819145483ba4676f617aaa6a5012c8efee63c8bbac413 qtimageformats-everywhere-src-$QT.tar.xz
7f3cf02f4824bf03c2c5859ea6db173bf1482a1daf24e6cdf7bc78cfa26a8a94 qtsvg-everywhere-src-$QT.tar.xz
8e61835a679c93fa9c6065b142353c2071ba68e297898937c32a03777fcaf50d qttools-everywhere-src-$QT.tar.xz
37c02c81206594c7bb4edca85ac93e8e55a9836b70c960fde6cb0f8623ec5677 qttranslations-everywhere-src-$QT.tar.xz
f1d3be3489f758efe1a8f12118a212febbe611aa670af32e0159fa3c1feab2a6 QtApng-$QTAPNG.tar.gz
36bc4f1cc413335368ee656c42afca65c5a3987e8768cc28cf11ba775e785a5f freetype-$FREETYPE.tar.xz
e9fff7467fb60f037e6708da18b25560649e4c63edc2a69bb871b960d9cbfbba $SDL.tar.gz
f29db9470e0ca5cef484e04e27baeec233aa428e8fdabe9e51b0f706c0809d24 harfbuzz-$HARFBUZZ.tar.gz
12b34280415ec8418c864408b93d008a20a6530687ee613d60bfbd20411f2785 $SDL.tar.gz
c652d5d94971031654ab3989891a490a895d3e3f2b71171c62692b28e94b1b93 harfbuzz-$HARFBUZZ.tar.gz
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b lz4-$LZ4.tar.gz
f7d8bf1601b7804f583a254ab343a6549ca6cf27d255c302c47af2d9d36a6f18 libpng-$LIBPNG.tar.xz
28eb403f51f0f7405249132cecfe82ea5c0ef97f1b32c5a65828814ae0d34775 libpng-$LIBPNG.tar.xz
e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 libwebp-$LIBWEBP.tar.gz
9ce32d4a2763a2ac5f258726ba2f49e9011327c1ee8c30862a32d0f30889fbe8 libpng-$LIBPNG-apng.patch.gz
eee7dea22ed502868017971c86c63c4ed1e6085de0baebfdcc3d3322f00f3eb0 libpng-$LIBPNG-apng.patch.gz
ecae8008e2cc9ade2f2c1bb9d5e6d4fb73e7c433866a056bd82980741571a022 libjpeg-turbo-$LIBJPEGTURBO.tar.gz
b072aed6871998cce9b36e7774033105ca29e33632be5b6347f3206898e0756a ffmpeg-$FFMPEG.tar.xz
9985f141902a17de818e264d17c1ce334b748e499ee02fcb4703e4dc0038f89c v$MOLTENVK.tar.gz
51dbf24fe72e43dd7cb9a289d3cab47112010f1a2ed69b6fc8ac0dff31991ed2 KDDockWidgets-$KDDOCKWIDGETS.tar.gz
7bd4e79ce18b1d47517e7e91fbb7cf19d4f01942804a519bc7c0bf32b6325dd5 plutovg-$PLUTOVG.tar.gz
78561b571ac224030cdc450ca2986b4de915c2ba7616004a6d71a379bffd15f3 plutosvg-$PLUTOSVG.tar.gz
9d9938269adc25e9a9b84650338b87d130cf469d82685fffc028c325279619c1 rapidyaml-$RAPIDYAML-src.tgz
e9efcdd17f86287748793cf21d106e461fcad8d103a3e5a23632afe93828660d rapidyaml-$RAPIDYAML-src.tgz
245002feccbe7f8361b223545a5654cea69780745886872d7efff50a38d96c66 shaderc-$SHADERC.tar.gz
bd58dca4dac67dcf7640292d7d63e0416274d40ee2200f7301878cec11ac6647 shaderc-glslang-$SHADERC_GLSLANG.tar.gz
1b220e3eec1714f0451b0e3652979bd280edf10893f617837b88e6359a804ded shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz
cabb35f4eef0da3ef72ad9edd596af4191d7507a8f35c05df526d2d5ff889f59 shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz
f924178e75e3293082481b25ed64d5e48a795b479dac3bd3c83d23070855df42 shaderc-$SHADERC.tar.gz
971848a1cc639ce8dc244e778b17efe0f690e32ac398a75e31d1c67ad06d3e0a shaderc-glslang-$SHADERC_GLSLANG.tar.gz
a6cb1b300bb8171795e116457e858e555334749f9cacaed8068ae0ef8681110c shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz
e156be0bd81c8812f1bff8e520422bfa9df61b3045587b9eb483185f1074a7b2 shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz
EOF
if ! shasum -sa 256 --check SHASUMS 2> /dev/null; then
@@ -54,16 +54,16 @@ echo INSTALLDIR=%INSTALLDIR%
cd "%BUILDDIR%"
set QT=6.11.0
set QT=6.11.1
set QTMINOR=6.11
set QTAPNG=1.3.0
set FREETYPE=2.14.3
set HARFBUZZ=14.0.0
set SDL=SDL3-3.4.8
set HARFBUZZ=14.2.0
set SDL=SDL3-3.4.10
set LIBJPEGTURBO=3.1.4.1
set LIBPNG=1656
set LIBPNGLONG=1.6.56
set LIBPNG=1658
set LIBPNGLONG=1.6.58
set LZ4=1.10.0
set WEBP=1.6.0
set ZLIB=1.3.2
@@ -72,42 +72,42 @@ set ZSTD=1.5.7
set KDDOCKWIDGETS=2.4.0
set PLUTOVG=1.3.2
set PLUTOSVG=0.0.7
set RAPIDYAML=0.11.1
set RAPIDYAML=0.12.1
set SHADERC=2026.1
set SHADERC_GLSLANG=f0bd0257c308b9a26562c1a30c4748a0219cc951
set SHADERC_SPIRVHEADERS=04f10f650d514df88b76d25e83db360142c7b174
set SHADERC_SPIRVTOOLS=fbe4f3ad913c44fe8700545f8ffe35d1382b7093
set SHADERC=2026.2
set SHADERC_GLSLANG=275822a6261ee689aadb1da5f09a0ec2f058685c
set SHADERC_SPIRVHEADERS=58006c901d1d5c37dece6b6610e9af87fa951375
set SHADERC_SPIRVTOOLS=6337eb62cadd7d124ac6789bf39c0f71148f0a73
set AGILITYSDK=1.619.1
set AGILITYSDK=1.619.2
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 590d5ae246c85fa14d6458a36ff75a11236acfe8987c2475090aab1770acbdf8 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 5dfb3c0cb84d2c935c1716b3b86358ca496fb9216676e7e28fee1357fb4a050e || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" c92e1b46170b8671bbd46c783939f0c2dba4986882c5ebd37aaa9eba5b224fbe || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" ded4420823cb7b1bc49f38c5c56dd43ec27b6577ccbc7f620790abfabcc33b62 || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" f9c4fd4fd73dff51e9043d2825b04361b678f63798ed798021ef47f1ff0bfccf || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 3529cc37297a5a7aae4486843b9fd41c30df1d79a770f85e240b537dcc327ca5 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 37fba768f2780580dfae535ad6654cb9dc0bf2272e71b9b9781988de9ed0dac0 || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 767730188d4610a89bf8da502f87acf1c8881a3ac54f1e0eb167ab1e08b03a75 || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" 2d6ed2a98f458152e3cb17bf0be0494250194933a2d937b5a434e5b2006efca9 || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" eef43700ffd079f5893e435aca1330c8bdbf2a94ae45013e3fc63870df53d3b0 || goto error
call :downloadfile "QtApng-%QTAPNG%.zip" "https://github.com/jurplel/QtApng/archive/refs/tags/%QTAPNG%.zip" 5176082cdd468047a7eb1ec1f106b032f57df207aa318d559b29606b00d159ac || goto error
call :downloadfile "freetype-%FREETYPE%.tar.gz" https://sourceforge.net/projects/freetype/files/freetype2/%FREETYPE%/freetype-%FREETYPE%.tar.gz/download e61b31ab26358b946e767ed7eb7f4bb2e507da1cfefeb7a8861ace7fd5c899a1 || goto error
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip f4b86f4d107bc4f0b005c97d6cde43e548a125ee2810fa00d41844b46b6fe16a || goto error
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1656.zip 1ccf023c5f4ee1a7b75c5624f53acede5066f79b2fb14ddffaa28369adf9baac || goto error
call :downloadfile "lpng%LIBPNG%-apng.patch.gz" https://download.sourceforge.net/libpng-apng/libpng-%LIBPNGLONG%-apng.patch.gz 9ce32d4a2763a2ac5f258726ba2f49e9011327c1ee8c30862a32d0f30889fbe8 || goto error
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip bb2f83255706b1c92d731541c7cefaf98bb5b93e8f76d16f6deda05225ff20ee || goto error
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1658.zip b32f170855dbbe3e6d9e645af40b538137041773672c3ba3e02db5816c82d376 || goto error
call :downloadfile "lpng%LIBPNG%-apng.patch.gz" https://download.sourceforge.net/libpng-apng/libpng-%LIBPNGLONG%-apng.patch.gz eee7dea22ed502868017971c86c63c4ed1e6085de0baebfdcc3d3322f00f3eb0 || goto error
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" ecae8008e2cc9ade2f2c1bb9d5e6d4fb73e7c433866a056bd82980741571a022 || goto error
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 506206e02f90c1f37e048eacaf9e8a3a7dc682fd27783eb0ff15a7d2dcc9c2af || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" be8dafef3ecc956e736cfd1c242c10737f3ad589a866f25ba437b7f2f6d5ced2 || goto error
call :downloadfile "lz4-%LZ4%.zip" "https://github.com/lz4/lz4/archive/refs/tags/v%LZ4%.zip" 3224b4c80f351f194984526ef396f6079bd6332dd9825c72ac0d7a37b3cdc565 || goto error
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://github.com/madler/zlib/releases/download/v%ZLIB%/zlib%ZLIBSHORT%.zip" e8bf55f3017aa181690990cb58a994e77885da140609fc8f94abe9b65d2cae28 || goto error
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 7897bc5d620580d9b7cd3539c44b59d78f3657d33663fe97a145e07b4ebd69a4 || goto error
call :downloadfile "KDDockWidgets-%KDDOCKWIDGETS%.zip" "https://github.com/KDAB/KDDockWidgets/archive/v%KDDOCKWIDGETS%.zip" 47ddb48197872055f0adf8e90a7235f8a3b795ca1ee3a28ac2c504c673ae3806 || goto error
call :downloadfile "plutovg-%PLUTOVG%.zip" "https://github.com/sammycage/plutovg/archive/v%PLUTOVG%.zip" 4fe4e48f28aa80171b2166d45c0976ab0f21eecedb52cd4c3ef73b5afb48fac9 || goto error
call :downloadfile "plutosvg-%PLUTOSVG%.zip" "https://github.com/sammycage/plutosvg/archive/v%PLUTOSVG%.zip" 82dee2c57ad712bdd6d6d81d3e76249d89caa4b5a4214353660fd5adff12201a || goto error
call :downloadfile "agility-sdk-%AGILITYSDK%.nupkg" "https://www.nuget.org/api/v2/package/Microsoft.Direct3D.D3D12/%AGILITYSDK%" 9073a264301e93183844026239c9081717d52d13fb71aae68a0555c576b8de44 || goto error
call :downloadfile "rapidyaml-%RAPIDYAML%-src.zip" "https://github.com/biojppm/rapidyaml/releases/download/v%RAPIDYAML%/rapidyaml-%RAPIDYAML%-src.zip" 30054b74abdf0ba35bf2cb435b6e49fcb6d62a8e78a240a018c36aa60dba765f || goto error
call :downloadfile "agility-sdk-%AGILITYSDK%.nupkg" "https://www.nuget.org/api/v2/package/Microsoft.Direct3D.D3D12/%AGILITYSDK%" eb92d90bb23b2ec23410c41d791e41dbdbec942ab946924d1fdcb31eac6f0735 || goto error
call :downloadfile "rapidyaml-%RAPIDYAML%-src.zip" "https://github.com/biojppm/rapidyaml/releases/download/v%RAPIDYAML%/rapidyaml-%RAPIDYAML%-src.zip" 96276f55b9fa7837ac8f3f72fd52965879cbb5d5d2e6af548c69a177fb078304 || goto error
call :downloadfile "shaderc-%SHADERC%.zip" "https://github.com/google/shaderc/archive/refs/tags/v%SHADERC%.zip" 3ac59c8216d367ab7858684d39c8faf872a64150aeb139335f4e083c5f79dde0 || goto error
call :downloadfile "shaderc-glslang-%SHADERC_GLSLANG%.zip" "https://github.com/KhronosGroup/glslang/archive/%SHADERC_GLSLANG%.zip" 42a30acca4a35955370ed8ff6e54b823b4d4a5a86571baec1203d3fce87da447 || goto error
call :downloadfile "shaderc-spirv-headers-%SHADERC_SPIRVHEADERS%.zip" "https://github.com/KhronosGroup/SPIRV-Headers/archive/%SHADERC_SPIRVHEADERS%.zip" 00ecd73dcaaa956cf2221ce899ce096e9535ba20695483c5277adede462d1bde || goto error
call :downloadfile "shaderc-spirv-tools-%SHADERC_SPIRVTOOLS%.zip" "https://github.com/KhronosGroup/SPIRV-Tools/archive/%SHADERC_SPIRVTOOLS%.zip" 65b23ace0ff0c64daf51f7741ebb6448899fa4aceefc72403e56f5b95607ca8e || goto error
call :downloadfile "shaderc-%SHADERC%.zip" "https://github.com/google/shaderc/archive/refs/tags/v%SHADERC%.zip" f9401cc5cb36c276cd1e072b6595dbd728148e8dba389e50f7339e2d388dbc08 || goto error
call :downloadfile "shaderc-glslang-%SHADERC_GLSLANG%.zip" "https://github.com/KhronosGroup/glslang/archive/%SHADERC_GLSLANG%.zip" 2b63189efad0348d88d410a5e12ec550a612e0b6ceef64624b8f45491269fb9c || goto error
call :downloadfile "shaderc-spirv-headers-%SHADERC_SPIRVHEADERS%.zip" "https://github.com/KhronosGroup/SPIRV-Headers/archive/%SHADERC_SPIRVHEADERS%.zip" d2f071e94c081f5a4606559770ebf1f7d1eac92a1def0c3e10609844aa8b69b2 || goto error
call :downloadfile "shaderc-spirv-tools-%SHADERC_SPIRVTOOLS%.zip" "https://github.com/KhronosGroup/SPIRV-Tools/archive/%SHADERC_SPIRVTOOLS%.zip" 4011be89aa73e3461c9deef73936a62c79a3097590c5135d058041cc9fb99c6f || goto error
if %DEBUG%==1 (
echo Building debug and release libraries...
@@ -61,7 +61,7 @@ set "PATH=%PATH%;%INSTALLDIR%\bin"
cd "%BUILDDIR%"
set QT=6.11.0
set QT=6.11.1
set QTMINOR=6.11
set QTAPNG=1.3.0
@@ -76,11 +76,11 @@ set LIBSVTAV1=4.0.1
set LIBX264=b35605ace3ddf7c1a5d67a2eb553f034aef41d55
set FREETYPE=2.14.3
set HARFBUZZ=14.0.0
set SDL=SDL3-3.4.8
set HARFBUZZ=14.2.0
set SDL=SDL3-3.4.10
set LIBJPEGTURBO=3.1.4.1
set LIBPNG=1656
set LIBPNGLONG=1.6.56
set LIBPNG=1658
set LIBPNGLONG=1.6.58
set LZ4=1.10.0
set WEBP=1.6.0
set ZLIB=1.3.2
@@ -89,20 +89,20 @@ set ZSTD=1.5.7
set KDDOCKWIDGETS=2.4.0
set PLUTOVG=1.3.2
set PLUTOSVG=0.0.7
set RAPIDYAML=0.11.1
set RAPIDYAML=0.12.1
set SHADERC=2026.1
set SHADERC_GLSLANG=f0bd0257c308b9a26562c1a30c4748a0219cc951
set SHADERC_SPIRVHEADERS=04f10f650d514df88b76d25e83db360142c7b174
set SHADERC_SPIRVTOOLS=fbe4f3ad913c44fe8700545f8ffe35d1382b7093
set SHADERC=2026.2
set SHADERC_GLSLANG=275822a6261ee689aadb1da5f09a0ec2f058685c
set SHADERC_SPIRVHEADERS=58006c901d1d5c37dece6b6610e9af87fa951375
set SHADERC_SPIRVTOOLS=6337eb62cadd7d124ac6789bf39c0f71148f0a73
set AGILITYSDK=1.619.1
set AGILITYSDK=1.619.2
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 590d5ae246c85fa14d6458a36ff75a11236acfe8987c2475090aab1770acbdf8 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 5dfb3c0cb84d2c935c1716b3b86358ca496fb9216676e7e28fee1357fb4a050e || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" c92e1b46170b8671bbd46c783939f0c2dba4986882c5ebd37aaa9eba5b224fbe || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" ded4420823cb7b1bc49f38c5c56dd43ec27b6577ccbc7f620790abfabcc33b62 || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" f9c4fd4fd73dff51e9043d2825b04361b678f63798ed798021ef47f1ff0bfccf || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 3529cc37297a5a7aae4486843b9fd41c30df1d79a770f85e240b537dcc327ca5 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 37fba768f2780580dfae535ad6654cb9dc0bf2272e71b9b9781988de9ed0dac0 || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 767730188d4610a89bf8da502f87acf1c8881a3ac54f1e0eb167ab1e08b03a75 || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" 2d6ed2a98f458152e3cb17bf0be0494250194933a2d937b5a434e5b2006efca9 || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" eef43700ffd079f5893e435aca1330c8bdbf2a94ae45013e3fc63870df53d3b0 || goto error
call :downloadfile "QtApng-%QTAPNG%.zip" "https://github.com/jurplel/QtApng/archive/refs/tags/%QTAPNG%.zip" 5176082cdd468047a7eb1ec1f106b032f57df207aa318d559b29606b00d159ac || goto error
call :downloadfile "ffmpeg-%FFMPEG%.tar.xz" "https://ffmpeg.org/releases/ffmpeg-%FFMPEG%.tar.xz" b072aed6871998cce9b36e7774033105ca29e33632be5b6347f3206898e0756a || goto error
@@ -116,25 +116,25 @@ call :downloadfile "SVT-AV1-v%LIBSVTAV1%.zip" "https://gitlab.com/AOMediaCodec/S
call :downloadfile "x264-%LIBX264%.zip" "https://code.videolan.org/videolan/x264/-/archive/%LIBX264%.zip" d95d059eff81cc565165cd058b66e208f0cc9874106a8fe94a811a66cf8a85a2 || goto error
call :downloadfile "freetype-%FREETYPE%.tar.gz" https://sourceforge.net/projects/freetype/files/freetype2/%FREETYPE%/freetype-%FREETYPE%.tar.gz/download e61b31ab26358b946e767ed7eb7f4bb2e507da1cfefeb7a8861ace7fd5c899a1 || goto error
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip f4b86f4d107bc4f0b005c97d6cde43e548a125ee2810fa00d41844b46b6fe16a || goto error
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1656.zip 1ccf023c5f4ee1a7b75c5624f53acede5066f79b2fb14ddffaa28369adf9baac || goto error
call :downloadfile "lpng%LIBPNG%-apng.patch.gz" https://download.sourceforge.net/libpng-apng/libpng-%LIBPNGLONG%-apng.patch.gz 9ce32d4a2763a2ac5f258726ba2f49e9011327c1ee8c30862a32d0f30889fbe8 || goto error
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip bb2f83255706b1c92d731541c7cefaf98bb5b93e8f76d16f6deda05225ff20ee || goto error
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1658.zip b32f170855dbbe3e6d9e645af40b538137041773672c3ba3e02db5816c82d376 || goto error
call :downloadfile "lpng%LIBPNG%-apng.patch.gz" https://download.sourceforge.net/libpng-apng/libpng-%LIBPNGLONG%-apng.patch.gz eee7dea22ed502868017971c86c63c4ed1e6085de0baebfdcc3d3322f00f3eb0 || goto error
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" ecae8008e2cc9ade2f2c1bb9d5e6d4fb73e7c433866a056bd82980741571a022 || goto error
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 506206e02f90c1f37e048eacaf9e8a3a7dc682fd27783eb0ff15a7d2dcc9c2af || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" be8dafef3ecc956e736cfd1c242c10737f3ad589a866f25ba437b7f2f6d5ced2 || goto error
call :downloadfile "lz4-%LZ4%.zip" "https://github.com/lz4/lz4/archive/refs/tags/v%LZ4%.zip" 3224b4c80f351f194984526ef396f6079bd6332dd9825c72ac0d7a37b3cdc565 || goto error
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://github.com/madler/zlib/releases/download/v%ZLIB%/zlib%ZLIBSHORT%.zip" e8bf55f3017aa181690990cb58a994e77885da140609fc8f94abe9b65d2cae28 || goto error
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 7897bc5d620580d9b7cd3539c44b59d78f3657d33663fe97a145e07b4ebd69a4 || goto error
call :downloadfile "KDDockWidgets-%KDDOCKWIDGETS%.zip" "https://github.com/KDAB/KDDockWidgets/archive/v%KDDOCKWIDGETS%.zip" 47ddb48197872055f0adf8e90a7235f8a3b795ca1ee3a28ac2c504c673ae3806 || goto error
call :downloadfile "plutovg-%PLUTOVG%.zip" "https://github.com/sammycage/plutovg/archive/v%PLUTOVG%.zip" 4fe4e48f28aa80171b2166d45c0976ab0f21eecedb52cd4c3ef73b5afb48fac9 || goto error
call :downloadfile "plutosvg-%PLUTOSVG%.zip" "https://github.com/sammycage/plutosvg/archive/v%PLUTOSVG%.zip" 82dee2c57ad712bdd6d6d81d3e76249d89caa4b5a4214353660fd5adff12201a || goto error
call :downloadfile "agility-sdk-%AGILITYSDK%.nupkg" "https://www.nuget.org/api/v2/package/Microsoft.Direct3D.D3D12/%AGILITYSDK%" 9073a264301e93183844026239c9081717d52d13fb71aae68a0555c576b8de44 || goto error
call :downloadfile "rapidyaml-%RAPIDYAML%-src.zip" "https://github.com/biojppm/rapidyaml/releases/download/v%RAPIDYAML%/rapidyaml-%RAPIDYAML%-src.zip" 30054b74abdf0ba35bf2cb435b6e49fcb6d62a8e78a240a018c36aa60dba765f || goto error
call :downloadfile "agility-sdk-%AGILITYSDK%.nupkg" "https://www.nuget.org/api/v2/package/Microsoft.Direct3D.D3D12/%AGILITYSDK%" eb92d90bb23b2ec23410c41d791e41dbdbec942ab946924d1fdcb31eac6f0735 || goto error
call :downloadfile "rapidyaml-%RAPIDYAML%-src.zip" "https://github.com/biojppm/rapidyaml/releases/download/v%RAPIDYAML%/rapidyaml-%RAPIDYAML%-src.zip" 96276f55b9fa7837ac8f3f72fd52965879cbb5d5d2e6af548c69a177fb078304 || goto error
call :downloadfile "shaderc-%SHADERC%.zip" "https://github.com/google/shaderc/archive/refs/tags/v%SHADERC%.zip" 3ac59c8216d367ab7858684d39c8faf872a64150aeb139335f4e083c5f79dde0 || goto error
call :downloadfile "shaderc-glslang-%SHADERC_GLSLANG%.zip" "https://github.com/KhronosGroup/glslang/archive/%SHADERC_GLSLANG%.zip" 42a30acca4a35955370ed8ff6e54b823b4d4a5a86571baec1203d3fce87da447 || goto error
call :downloadfile "shaderc-spirv-headers-%SHADERC_SPIRVHEADERS%.zip" "https://github.com/KhronosGroup/SPIRV-Headers/archive/%SHADERC_SPIRVHEADERS%.zip" 00ecd73dcaaa956cf2221ce899ce096e9535ba20695483c5277adede462d1bde || goto error
call :downloadfile "shaderc-spirv-tools-%SHADERC_SPIRVTOOLS%.zip" "https://github.com/KhronosGroup/SPIRV-Tools/archive/%SHADERC_SPIRVTOOLS%.zip" 65b23ace0ff0c64daf51f7741ebb6448899fa4aceefc72403e56f5b95607ca8e || goto error
call :downloadfile "shaderc-%SHADERC%.zip" "https://github.com/google/shaderc/archive/refs/tags/v%SHADERC%.zip" f9401cc5cb36c276cd1e072b6595dbd728148e8dba389e50f7339e2d388dbc08 || goto error
call :downloadfile "shaderc-glslang-%SHADERC_GLSLANG%.zip" "https://github.com/KhronosGroup/glslang/archive/%SHADERC_GLSLANG%.zip" 2b63189efad0348d88d410a5e12ec550a612e0b6ceef64624b8f45491269fb9c || goto error
call :downloadfile "shaderc-spirv-headers-%SHADERC_SPIRVHEADERS%.zip" "https://github.com/KhronosGroup/SPIRV-Headers/archive/%SHADERC_SPIRVHEADERS%.zip" d2f071e94c081f5a4606559770ebf1f7d1eac92a1def0c3e10609844aa8b69b2 || goto error
call :downloadfile "shaderc-spirv-tools-%SHADERC_SPIRVTOOLS%.zip" "https://github.com/KhronosGroup/SPIRV-Tools/archive/%SHADERC_SPIRVTOOLS%.zip" 4011be89aa73e3461c9deef73936a62c79a3097590c5135d058041cc9fb99c6f || goto error
if %DEBUG%==1 (
echo Building debug and release libraries...
@@ -469,6 +469,7 @@ echo "Building PlutoVG..."
rmdir /S /Q "plutovg-%PLUTOVG%"
%SEVENZIP% x "plutovg-%PLUTOVG%.zip" || goto error
cd "plutovg-%PLUTOVG%" || goto error
%PATCH% -p1 < "%SCRIPTDIR%\plutovg-workaround-msvc-ice.patch" || goto error
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DPLUTOVG_BUILD_EXAMPLES=OFF -B build -G Ninja || goto error
cmake --build build --parallel || goto error
ninja -C build install || goto error
@@ -0,0 +1,52 @@
diff --git a/source/plutovg-font.c b/source/plutovg-font.c
index 0ad89b1..110de7f 100644
--- a/source/plutovg-font.c
+++ b/source/plutovg-font.c
@@ -836,7 +836,8 @@ int plutovg_font_face_cache_load_file(plutovg_font_face_cache_t* cache, const ch
size_t family_index = 0;
if(unicode_family_name) {
const stbtt_uint8* family_name = unicode_family_name;
- while(family_length) {
+ //while(family_length) {
+ for (int i = family_length; i > 0; i -= 2) {
stbtt_uint16 ch = family_name[0] * 256 + family_name[1];
if(ch < 0x80) {
entry->family[family_index++] = ch;
@@ -853,7 +854,8 @@ int plutovg_font_face_cache_load_file(plutovg_font_face_cache_t* cache, const ch
entry->family[family_index++] = (0x80 + ((c) & 0x3f));
family_name += 2;
- family_length -= 2;
+ //family_length -= 2;
+ i -= 2;
} else {
entry->family[family_index++] = (0xe0 + (ch >> 12));
entry->family[family_index++] = (0x80 + ((ch >> 6) & 0x3f));
@@ -861,7 +863,7 @@ int plutovg_font_face_cache_load_file(plutovg_font_face_cache_t* cache, const ch
}
family_name += 2;
- family_length -= 2;
+ //family_length -= 2;
}
entry->family[family_index] = '\0';
@@ -902,7 +904,8 @@ int plutovg_font_face_cache_load_file(plutovg_font_face_cache_t* cache, const ch
};
const stbtt_uint8* family_name = roman_family_name;
- while(family_length) {
+ //while(family_length) {
+ for (int i2 = family_length; i2 > 0; i2--) {
stbtt_uint16 ch = MAC_ROMAN_TABLE[family_name[0]];
if(ch < 0x80) {
entry->family[family_index++] = ch;
@@ -916,7 +919,7 @@ int plutovg_font_face_cache_load_file(plutovg_font_face_cache_t* cache, const ch
}
family_name += 1;
- family_length -= 1;
+ //family_length -= 1;
}
entry->family[family_index] = '\0';
+1 -1
View File
@@ -13,7 +13,7 @@ jobs:
lint_vs_proj_files:
name: Lint VS Project Files
if: github.repository != 'PCSX2/pcsx2' || github.event_name == 'pull_request'
runs-on: windows-2025
runs-on: windows-2025-vs2026
steps:
- name: Checkout Repository
uses: actions/checkout@v6
+1 -1
View File
@@ -12,7 +12,7 @@ on:
os:
required: false
type: string
default: windows-2025
default: windows-2025-vs2026
platform:
required: false
type: string
+4
View File
@@ -11,6 +11,10 @@ obj/
*.pyc
*.pyo
# Bazel-related files
bazel-*
MODULE.bazel.lock
# System files
.DS_Store
.DS_Store?
+1 -1
View File
@@ -42,7 +42,7 @@ ENDMACRO()
MACRO(CPUINFO_TARGET_ENABLE_CXX11 target)
SET_TARGET_PROPERTIES(${target} PROPERTIES
CXX_STANDARD 14
CXX_STANDARD 17
CXX_EXTENSIONS NO)
ENDMACRO()
+3 -3
View File
@@ -1,11 +1,11 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12 FATAL_ERROR)
CMAKE_MINIMUM_REQUIRED(VERSION 3.18 FATAL_ERROR)
PROJECT(googletest-download NONE)
INCLUDE(ExternalProject)
ExternalProject_Add(googletest
URL https://github.com/google/googletest/archive/release-1.8.0.zip
URL_HASH SHA256=f3ed3b58511efd272eb074a3a6d6fb79d7c2e6a0e374323d1e6bcbcc1ef141bf
URL https://github.com/google/googletest/archive/refs/tags/v1.17.0.zip
URL_HASH SHA256=40d4ec942217dcc84a9ebe2a68584ada7d4a33a8ee958755763278ea1c5e18ff
SOURCE_DIR "${CONFU_DEPENDENCIES_SOURCE_DIR}/googletest"
BINARY_DIR "${CONFU_DEPENDENCIES_BINARY_DIR}/googletest"
CONFIGURE_COMMAND ""
+1 -1
View File
@@ -1,4 +1,4 @@
CMAKE_MINIMUM_REQUIRED(VERSION 3.1 FATAL_ERROR)
CMAKE_MINIMUM_REQUIRED(VERSION 3.10 FATAL_ERROR)
INCLUDE(GNUInstallDirs)
+30
View File
@@ -355,6 +355,12 @@ enum cpuinfo_uarch {
cpuinfo_uarch_sunny_cove = 0x0010020C,
/** Intel Willow Cove microarchitecture (10 nm, Tiger Lake). */
cpuinfo_uarch_willow_cove = 0x0010020D,
/** Intel Golden Cove microarchitecture (Sapphire Rapids). */
cpuinfo_uarch_golden_cove = 0x0010020E,
/** Intel Raptor Cove microarchitecture (Emerald Rapids). */
cpuinfo_uarch_raptor_cove = 0x0010020F,
/** Intel Redwood Cove microarchitecture (Granite Rapids). */
cpuinfo_uarch_redwood_cove = 0x00100210,
/** Pentium 4 with Willamette, Northwood, or Foster cores. */
cpuinfo_uarch_willamette = 0x00100300,
@@ -519,6 +525,8 @@ enum cpuinfo_uarch {
cpuinfo_uarch_cortex_a510 = 0x00300551,
/** ARM Cortex-A520. */
cpuinfo_uarch_cortex_a520 = 0x00300552,
/** ARM Cortex-A320. */
cpuinfo_uarch_cortex_a320 = 0x00300553,
/** ARM Cortex-A710. */
cpuinfo_uarch_cortex_a710 = 0x00300571,
/** ARM Cortex-A715. */
@@ -2226,6 +2234,12 @@ struct cpuinfo_riscv_isa {
bool c;
/* Vector Extension. */
bool v;
/* ISA Extensions */
/* Half-Precision Floating-Point Extension. */
bool zfh;
/* Half-Precision Floating-Point Vector Extension. */
bool zvfh;
};
extern struct cpuinfo_riscv_isa cpuinfo_isa;
@@ -2301,6 +2315,22 @@ static inline bool cpuinfo_has_riscv_v(void) {
#endif
}
static inline bool cpuinfo_has_riscv_zfh(void) {
#if CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
return cpuinfo_isa.zfh;
#else
return false;
#endif
}
static inline bool cpuinfo_has_riscv_zvfh(void) {
#if CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
return cpuinfo_isa.zvfh;
#else
return false;
#endif
}
const struct cpuinfo_processor* CPUINFO_ABI cpuinfo_get_processors(void);
const struct cpuinfo_core* CPUINFO_ABI cpuinfo_get_cores(void);
const struct cpuinfo_cluster* CPUINFO_ABI cpuinfo_get_clusters(void);
+1
View File
@@ -13,6 +13,7 @@ enum cpuinfo_android_chipset_property {
cpuinfo_android_chipset_property_ro_arch,
cpuinfo_android_chipset_property_ro_chipname,
cpuinfo_android_chipset_property_ro_hardware_chipname,
cpuinfo_android_chipset_property_ro_soc_model,
cpuinfo_android_chipset_property_max,
};
+3
View File
@@ -63,4 +63,7 @@ void cpuinfo_arm_android_parse_properties(struct cpuinfo_android_properties prop
cpuinfo_android_property_get("ro.hardware.chipname", properties->ro_hardware_chipname);
cpuinfo_log_debug(
"read ro.hardware.chipname = \"%.*s\"", ro_hardware_chipname_length, properties->ro_hardware_chipname);
const int ro_soc_model_length = cpuinfo_android_property_get("ro.soc.model", properties->ro_soc_model);
cpuinfo_log_debug("read ro.soc.model = \"%.*s\"", ro_soc_model_length, properties->ro_soc_model);
}
+1
View File
@@ -45,6 +45,7 @@ enum cpuinfo_arm_chipset_series {
cpuinfo_arm_chipset_series_qualcomm_msm,
cpuinfo_arm_chipset_series_qualcomm_apq,
cpuinfo_arm_chipset_series_qualcomm_snapdragon,
cpuinfo_arm_chipset_series_qualcomm_sm,
cpuinfo_arm_chipset_series_mediatek_mt,
cpuinfo_arm_chipset_series_samsung_exynos,
cpuinfo_arm_chipset_series_hisilicon_k3v,
+3
View File
@@ -29,6 +29,7 @@ struct cpuinfo_android_properties {
char ro_arch[CPUINFO_BUILD_PROP_VALUE_MAX];
char ro_chipname[CPUINFO_BUILD_PROP_VALUE_MAX];
char ro_hardware_chipname[CPUINFO_BUILD_PROP_VALUE_MAX];
char ro_soc_model[CPUINFO_BUILD_PROP_VALUE_MAX];
};
#endif
@@ -364,6 +365,8 @@ CPUINFO_INTERNAL struct cpuinfo_arm_chipset cpuinfo_arm_android_decode_chipset_f
const char ro_chipname[restrict static CPUINFO_BUILD_PROP_VALUE_MAX]);
CPUINFO_INTERNAL struct cpuinfo_arm_chipset cpuinfo_arm_android_decode_chipset_from_ro_hardware_chipname(
const char ro_hardware_chipname[restrict static CPUINFO_BUILD_PROP_VALUE_MAX]);
CPUINFO_INTERNAL struct cpuinfo_arm_chipset cpuinfo_arm_android_decode_chipset_from_ro_soc_model(
const char ro_soc_model[restrict static CPUINFO_BUILD_PROP_VALUE_MAX]);
#else
CPUINFO_INTERNAL struct cpuinfo_arm_chipset cpuinfo_arm_linux_decode_chipset_from_proc_cpuinfo_revision(
const char proc_cpuinfo_revision[restrict static CPUINFO_REVISION_VALUE_MAX]);
+34 -1
View File
@@ -264,7 +264,7 @@ static bool match_sm(const char* start, const char* end, struct cpuinfo_arm_chip
/* Return parsed chipset. */
*chipset = (struct cpuinfo_arm_chipset){
.vendor = cpuinfo_arm_chipset_vendor_qualcomm,
.series = cpuinfo_arm_chipset_series_qualcomm_snapdragon,
.series = cpuinfo_arm_chipset_series_qualcomm_sm,
.model = model,
};
return true;
@@ -3491,6 +3491,36 @@ struct cpuinfo_arm_chipset cpuinfo_arm_android_decode_chipset_from_ro_chipname(
.series = cpuinfo_arm_chipset_series_unknown,
};
}
struct cpuinfo_arm_chipset cpuinfo_arm_android_decode_chipset_from_ro_soc_model(
const char soc_model[restrict static CPUINFO_BUILD_PROP_VALUE_MAX]) {
struct cpuinfo_arm_chipset chipset;
const size_t soc_model_length = strnlen(soc_model, CPUINFO_BUILD_PROP_VALUE_MAX);
const char* soc_model_end = soc_model + soc_model_length;
/* Check Qualcomm SMxxxx signature */
if (match_sm(soc_model, soc_model_end, &chipset)) {
cpuinfo_log_debug(
"matched Qualcomm SM signature in ro.soc.model string \"%.*s\"",
(int)soc_model_length,
soc_model);
return chipset;
}
/* Check Qualcomm MSM/APQ signatures */
if (match_msm_apq(soc_model, soc_model_end, &chipset)) {
cpuinfo_log_debug(
"matched Qualcomm MSM/APQ signature in ro.soc.model string \"%.*s\"",
(int)soc_model_length,
soc_model);
return chipset;
}
return (struct cpuinfo_arm_chipset){
.vendor = cpuinfo_arm_chipset_vendor_unknown,
.series = cpuinfo_arm_chipset_series_unknown,
};
}
#endif /* __ANDROID__ */
/*
@@ -3837,6 +3867,7 @@ static const char* chipset_series_string[cpuinfo_arm_chipset_series_max] = {
[cpuinfo_arm_chipset_series_qualcomm_msm] = "MSM",
[cpuinfo_arm_chipset_series_qualcomm_apq] = "APQ",
[cpuinfo_arm_chipset_series_qualcomm_snapdragon] = "Snapdragon ",
[cpuinfo_arm_chipset_series_qualcomm_sm] = "SM",
[cpuinfo_arm_chipset_series_mediatek_mt] = "MT",
[cpuinfo_arm_chipset_series_samsung_exynos] = "Exynos ",
[cpuinfo_arm_chipset_series_hisilicon_k3v] = "K3V",
@@ -4074,6 +4105,8 @@ struct cpuinfo_arm_chipset cpuinfo_arm_android_decode_chipset(
cpuinfo_arm_android_decode_chipset_from_ro_chipname(properties->ro_chipname),
[cpuinfo_android_chipset_property_ro_hardware_chipname] =
cpuinfo_arm_android_decode_chipset_from_ro_chipname(properties->ro_hardware_chipname),
[cpuinfo_android_chipset_property_ro_soc_model] =
cpuinfo_arm_android_decode_chipset_from_ro_soc_model(properties->ro_soc_model),
};
enum cpuinfo_arm_chipset_vendor vendor = cpuinfo_arm_chipset_vendor_unknown;
for (size_t i = 0; i < cpuinfo_android_chipset_property_max; i++) {
+121 -6
View File
@@ -1,5 +1,7 @@
#include <ctype.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -14,6 +16,92 @@
#include <cpuinfo/log.h>
#include <linux/api.h>
/* Parse a uint32 from sysfs file content */
static bool uint32_parser(const char* filename, const char* text_start, const char* text_end, void* context) {
uint32_t* value_ptr = (uint32_t*)context;
if (text_start == text_end) {
return false;
}
uint32_t value = 0;
for (const char* p = text_start; p < text_end && *p >= '0' && *p <= '9'; p++) {
value = value * 10 + (*p - '0');
}
*value_ptr = value;
return value > 0;
}
/* Parse cache size with K/M suffix from /sys/devices/system/cpu/cpuN/cache/indexN/size (e.g. "2048K", "1M") */
static bool cache_size_parser(const char* filename, const char* text_start, const char* text_end, void* context) {
uint32_t* size_ptr = (uint32_t*)context;
if (text_start == text_end) {
return false;
}
uint32_t value = 0;
const char* p = text_start;
while (p < text_end && *p >= '0' && *p <= '9') {
value = value * 10 + (*p - '0');
p++;
}
if (p == text_start || value == 0) {
return false;
}
uint32_t multiplier = 1024;
if (p < text_end && toupper(*p) == 'M') {
multiplier = 1024 * 1024;
}
*size_ptr = value * multiplier;
return true;
}
/* Check if /sys/devices/system/cpu/cpuN/cache/index2/shared_cpu_list indicates a single CPU (per-core cache) */
static bool shared_cpu_list_parser(const char* filename, const char* text_start, const char* text_end, void* context) {
bool* is_per_core = (bool*)context;
for (const char* p = text_start; p < text_end; p++) {
if (*p == ',' || *p == '-') {
*is_per_core = false;
return true;
}
}
*is_per_core = (text_start != text_end);
return *is_per_core;
}
/*
* Read cache size from sysfs.
*
* ARM CPUs lack a CPUID-equivalent instruction to query cache properties,
* so the library relies on hardcoded values that are often incorrect.
* Linux exposes cache topology via sysfs (existed before 2008, documented 2014):
* https://raw.githubusercontent.com/torvalds/linux/master/Documentation/ABI/testing/sysfs-devices-system-cpu
*
*/
static uint32_t cpuinfo_linux_read_sysfs_cache_size(uint32_t cpu_id, uint32_t cache_level) {
char path[256];
/* Verify the index corresponds to the requested cache level */
snprintf(path, sizeof(path), "/sys/devices/system/cpu/cpu%u/cache/index%u/level", cpu_id, cache_level);
uint32_t actual_level = 0;
if (!cpuinfo_linux_parse_small_file(path, 16, uint32_parser, &actual_level) || actual_level != cache_level) {
return 0;
}
snprintf(path, sizeof(path), "/sys/devices/system/cpu/cpu%u/cache/index%u/size", cpu_id, cache_level);
uint32_t size = 0;
if (!cpuinfo_linux_parse_small_file(path, 32, cache_size_parser, &size)) {
return 0;
}
return size;
}
/* Check if L2 cache is per-core by reading sysfs shared_cpu_list */
static bool cpuinfo_linux_is_l2_per_core(uint32_t cpu_id) {
char path[256];
snprintf(path, sizeof(path), "/sys/devices/system/cpu/cpu%u/cache/index2/shared_cpu_list", cpu_id);
bool is_per_core = false;
cpuinfo_linux_parse_small_file(path, 128, shared_cpu_list_parser, &is_per_core);
return is_per_core;
}
struct cpuinfo_arm_isa cpuinfo_isa = {0};
static struct cpuinfo_package package = {{0}};
@@ -719,11 +807,21 @@ void cpuinfo_arm_linux_init(void) {
*/
shared_l3 = false;
if (temp_l2.size != 0) {
/* Assume L2 is shared by cores in the same
* cluster */
if (arm_linux_processors[i].package_leader_id ==
arm_linux_processors[i].system_processor_id) {
/* Check if L2 is per-core using sysfs */
uint32_t sysfs_l2_size = cpuinfo_linux_read_sysfs_cache_size(
arm_linux_processors[i].system_processor_id, 2);
bool l2_is_per_core = (sysfs_l2_size > 0) &&
cpuinfo_linux_is_l2_per_core(arm_linux_processors[i].system_processor_id);
if (l2_is_per_core) {
/* L2 is private to each core */
l2_count += 1;
} else {
/* Assume L2 is shared by cores in the same cluster */
if (arm_linux_processors[i].package_leader_id ==
arm_linux_processors[i].system_processor_id) {
l2_count += 1;
}
}
}
}
@@ -771,10 +869,27 @@ void cpuinfo_arm_linux_init(void) {
&temp_l2,
&temp_l3);
if (temp_l3.size != 0) {
/* Try to read L2 cache size from sysfs (more accurate) */
uint32_t sysfs_l2_size =
cpuinfo_linux_read_sysfs_cache_size(arm_linux_processors[i].system_processor_id, 2);
if (sysfs_l2_size > 0) {
temp_l2.size = sysfs_l2_size;
/* Recalculate sets to maintain consistency: size = associativity * sets * partitions *
* line_size */
if (temp_l2.associativity > 0 && temp_l2.line_size > 0 && temp_l2.partitions > 0) {
temp_l2.sets = sysfs_l2_size /
(temp_l2.associativity * temp_l2.partitions * temp_l2.line_size);
}
}
/* Check if L2 is per-core by reading sysfs */
bool l2_is_per_core = (sysfs_l2_size > 0) &&
cpuinfo_linux_is_l2_per_core(arm_linux_processors[i].system_processor_id);
if (temp_l3.size != 0 || l2_is_per_core) {
/*
* Assumptions:
* - L2 is private to each core
* - L2 is private to each core (either has L3, or sysfs confirms per-core L2)
* - L3 is shared by cores in the same cluster
* - If cores in different clusters report the same L3,
* it is shared between all cores.
+10 -7
View File
@@ -141,17 +141,20 @@ void cpuinfo_arm_decode_vendor_uarch(
case 0xD87: /* Cortex-A725 */
*uarch = cpuinfo_uarch_cortex_a725;
break;
case 0xD8C:
*uarch = cpuinfo_uarch_lumex_c1_ultra;
break;
case 0xD90:
*uarch = cpuinfo_uarch_lumex_c1_premium;
case 0xD8A:
*uarch = cpuinfo_uarch_lumex_c1_nano;
break;
case 0xD8B:
*uarch = cpuinfo_uarch_lumex_c1_pro;
break;
case 0xD8A:
*uarch = cpuinfo_uarch_lumex_c1_nano;
case 0xD8C:
*uarch = cpuinfo_uarch_lumex_c1_ultra;
break;
case 0xD8F: /* Cortex-A320 */
*uarch = cpuinfo_uarch_cortex_a320;
break;
case 0xD90:
*uarch = cpuinfo_uarch_lumex_c1_premium;
break;
default:
switch (midr_get_part(midr) >> 8) {
+3 -1
View File
@@ -61,11 +61,13 @@ CPUINFO_INTERNAL void cpuinfo_riscv_linux_decode_isa_from_hwcap(struct cpuinfo_r
* @param[processor] - The Linux ID of the target processor.
* @param[vendor] - Reference to the cpuinfo_vendor to populate.
* @param[uarch] - Reference to the cpuinfo_uarch to populate.
* @param[isa] - Reference to the cpuinfo_riscv_isa to populate isa extensions.
*/
CPUINFO_INTERNAL void cpuinfo_riscv_linux_decode_vendor_uarch_from_hwprobe(
uint32_t processor,
enum cpuinfo_vendor vendor[restrict static 1],
enum cpuinfo_uarch uarch[restrict static 1]);
enum cpuinfo_uarch uarch[restrict static 1],
struct cpuinfo_riscv_isa isa[restrict static 1]);
/* Used to determine which uarch is associated with the current thread. */
extern CPUINFO_INTERNAL const uint32_t* cpuinfo_linux_cpu_to_uarch_index_map;
+3 -2
View File
@@ -6,7 +6,7 @@
#include <riscv/linux/api.h>
/* ISA structure to hold supported extensions. */
struct cpuinfo_riscv_isa cpuinfo_isa;
struct cpuinfo_riscv_isa cpuinfo_isa = {0};
/* Helper function to bitmask flags and ensure operator precedence. */
static inline bool bitmask_all(uint32_t flags, uint32_t mask) {
@@ -320,7 +320,8 @@ void cpuinfo_riscv_linux_init(void) {
cpuinfo_riscv_linux_decode_vendor_uarch_from_hwprobe(
processor,
&riscv_linux_processors[processor].core.vendor,
&riscv_linux_processors[processor].core.uarch);
&riscv_linux_processors[processor].core.uarch,
&cpuinfo_isa);
/* Populate frequency information of this core. */
uint32_t frequency = cpuinfo_linux_get_processor_cur_frequency(processor);
+43 -1
View File
@@ -53,6 +53,30 @@ struct riscv_hwprobe {
#define RISCV_HWPROBE_EXT_ZBB (1 << 4)
#define RISCV_HWPROBE_EXT_ZBS (1 << 5)
#define RISCV_HWPROBE_EXT_ZICBOZ (1 << 6)
#define RISCV_HWPROBE_EXT_ZBC (1 << 7)
#define RISCV_HWPROBE_EXT_ZBKB (1 << 8)
#define RISCV_HWPROBE_EXT_ZBKC (1 << 9)
#define RISCV_HWPROBE_EXT_ZBKX (1 << 10)
#define RISCV_HWPROBE_EXT_ZKND (1 << 11)
#define RISCV_HWPROBE_EXT_ZKNE (1 << 12)
#define RISCV_HWPROBE_EXT_ZKNH (1 << 13)
#define RISCV_HWPROBE_EXT_ZKSED (1 << 14)
#define RISCV_HWPROBE_EXT_ZKSH (1 << 15)
#define RISCV_HWPROBE_EXT_ZKT (1 << 16)
#define RISCV_HWPROBE_EXT_ZVBB (1 << 17)
#define RISCV_HWPROBE_EXT_ZVBC (1 << 18)
#define RISCV_HWPROBE_EXT_ZVKB (1 << 19)
#define RISCV_HWPROBE_EXT_ZVKG (1 << 20)
#define RISCV_HWPROBE_EXT_ZVKNED (1 << 21)
#define RISCV_HWPROBE_EXT_ZVKNHA (1 << 22)
#define RISCV_HWPROBE_EXT_ZVKNHB (1 << 23)
#define RISCV_HWPROBE_EXT_ZVKSED (1 << 24)
#define RISCV_HWPROBE_EXT_ZVKSH (1 << 25)
#define RISCV_HWPROBE_EXT_ZVKT (1 << 26)
#define RISCV_HWPROBE_EXT_ZFH (1 << 27)
#define RISCV_HWPROBE_EXT_ZFHMIN (1 << 28)
#define RISCV_HWPROBE_EXT_ZIHINTNTL (1 << 29)
#define RISCV_HWPROBE_EXT_ZVFH (1 << 30)
#define RISCV_HWPROBE_KEY_CPUPERF_0 5
#define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0)
#define RISCV_HWPROBE_MISALIGNED_EMULATED (1 << 0)
@@ -72,7 +96,8 @@ struct riscv_hwprobe {
void cpuinfo_riscv_linux_decode_vendor_uarch_from_hwprobe(
uint32_t processor,
enum cpuinfo_vendor vendor[restrict static 1],
enum cpuinfo_uarch uarch[restrict static 1]) {
enum cpuinfo_uarch uarch[restrict static 1],
struct cpuinfo_riscv_isa isa[restrict static 1]) {
struct riscv_hwprobe pairs[] = {
{
.key = RISCV_HWPROBE_KEY_MVENDORID,
@@ -83,6 +108,9 @@ void cpuinfo_riscv_linux_decode_vendor_uarch_from_hwprobe(
{
.key = RISCV_HWPROBE_KEY_MIMPID,
},
{
.key = RISCV_HWPROBE_KEY_IMA_EXT_0,
},
};
const size_t pairs_count = sizeof(pairs) / sizeof(struct riscv_hwprobe);
@@ -128,6 +156,7 @@ void cpuinfo_riscv_linux_decode_vendor_uarch_from_hwprobe(
uint32_t vendor_id = 0;
uint32_t arch_id = 0;
uint32_t imp_id = 0;
uint64_t ima_ext_0 = 0;
for (size_t pair = 0; pair < pairs_count; pair++) {
switch (pairs[pair].key) {
case RISCV_HWPROBE_KEY_MVENDORID:
@@ -139,6 +168,9 @@ void cpuinfo_riscv_linux_decode_vendor_uarch_from_hwprobe(
case RISCV_HWPROBE_KEY_MIMPID:
imp_id = pairs[pair].value;
break;
case RISCV_HWPROBE_KEY_IMA_EXT_0:
ima_ext_0 = pairs[pair].value;
break;
default:
/* The key value may be -1 if unsupported. */
break;
@@ -146,6 +178,16 @@ void cpuinfo_riscv_linux_decode_vendor_uarch_from_hwprobe(
}
cpuinfo_riscv_decode_vendor_uarch(vendor_id, arch_id, imp_id, vendor, uarch);
/* Parse ISA extensions retrieved. */
if (ima_ext_0 != 0) {
if (ima_ext_0 & RISCV_HWPROBE_EXT_ZFH) {
isa->zfh = true;
}
if (ima_ext_0 & RISCV_HWPROBE_EXT_ZVFH) {
isa->zvfh = true;
}
}
cleanup:
CPU_FREE(cpu_set);
}
+6
View File
@@ -171,6 +171,12 @@ enum cpuinfo_uarch cpuinfo_x86_decode_uarch(
case 0x8C: // Tiger U
case 0x8D: // Tiger H
return cpuinfo_uarch_willow_cove;
case 0x8F: // Sapphire Rapids
return cpuinfo_uarch_golden_cove;
case 0xCF: // Emerald Rapids
return cpuinfo_uarch_raptor_cove;
case 0xAD: // Granite Rapids
return cpuinfo_uarch_redwood_cove;
/* Low-power cores */
case 0x1C: // Diamondville,
// Silverthorne,
+3 -2
View File
@@ -585,8 +585,9 @@ cubeb_destroy(cubeb * context);
NULL if this stream is input only. When input
and output stream parameters are supplied, their
rate has to be the same.
@param latency_frames Stream latency in frames. Valid range
is [1, 96000].
@param latency_frames Requested stream latency in frames. Valid range is
[1, 96000]. The actual latency may differ depending
on the backend, platform, and hardware.
@param data_callback Will be called to preroll data before playback is
started by cubeb_stream_start.
@param state_callback A pointer to a state callback.
+3
View File
@@ -294,6 +294,9 @@ set_timeout(struct timeval * timeout, unsigned int ms)
static void
stream_buffer_decrement(cubeb_stream * stm, long count)
{
if (count < 0 || (snd_pcm_uframes_t)count > stm->bufframes) {
count = stm->bufframes;
}
char * bufremains =
stm->buffer + WRAP(snd_pcm_frames_to_bytes)(stm->pcm, count);
memmove(stm->buffer, bufremains,
+13 -2
View File
@@ -405,12 +405,15 @@ cbjack_process(jack_nframes_t nframes, void * arg)
for (int j = 0; j < MAX_STREAMS; j++) {
cubeb_stream * stm = &ctx->streams[j];
float * bufs_out[stm->out_params.channels];
float * bufs_in[stm->in_params.channels];
if (!stm->in_use)
continue;
float * bufs_out[MAX_CHANNELS] = {};
float * bufs_in[MAX_CHANNELS] = {};
XASSERT(stm->out_params.channels <= MAX_CHANNELS);
XASSERT(stm->in_params.channels <= MAX_CHANNELS);
// handle xruns by skipping audio that should have been played
stm->position += t_jack_xruns * ctx->fragment_size * stm->ratio;
@@ -851,6 +854,14 @@ cbjack_stream_init(cubeb * context, cubeb_stream ** stream,
return CUBEB_ERROR_INVALID_FORMAT;
}
if ((output_stream_params &&
(output_stream_params->channels < 1 ||
output_stream_params->channels > MAX_CHANNELS)) ||
(input_stream_params && (input_stream_params->channels < 1 ||
input_stream_params->channels > MAX_CHANNELS))) {
return CUBEB_ERROR_INVALID_FORMAT;
}
if ((input_device && input_device != JACK_DEFAULT_IN) ||
(output_device && output_device != JACK_DEFAULT_OUT)) {
return CUBEB_ERROR_NOT_SUPPORTED;
+173 -24
View File
@@ -14,6 +14,7 @@
#include <algorithm>
#include <atomic>
#include <audioclient.h>
#include <audiopolicy.h>
#include <avrt.h>
#include <cmath>
#include <devicetopology.h>
@@ -317,6 +318,7 @@ struct cubeb {
};
class wasapi_endpoint_notification_client;
class wasapi_session_notification_client;
/* We have three possible callbacks we can use with a stream:
* - input only
@@ -415,6 +417,10 @@ struct cubeb_stream {
audio device changes and route the audio to the new default audio output
device */
com_ptr<wasapi_endpoint_notification_client> notification_client;
/* Session notification client, to be notified when the audio session is
disconnected (e.g. when an audio device is removed from the system). */
com_ptr<IAudioSessionControl> session_control;
com_ptr<wasapi_session_notification_client> session_notification_client;
/* Main andle to the WASAPI capture stream. */
com_ptr<IAudioClient> input_client;
/* Interface to use the event driven capture interface */
@@ -431,6 +437,10 @@ struct cubeb_stream {
* practice, we read from the input stream in the output callback, so
* this is not used, but it is necessary to start getting input data. */
HANDLE input_available_event = 0;
/* Signaled by stream_start/stream_stop when the active state changes,
so the render thread can promote/demote its MMCSS task accordingly
instead of remaining promoted while idle. */
HANDLE mmcss_event = 0;
/* Each cubeb_stream has its own thread. */
HANDLE thread = 0;
/* The lock protects all members that are touched by the render thread or
@@ -834,6 +844,89 @@ private:
DWORD last_device_change;
};
class wasapi_session_notification_client : public IAudioSessionEvents {
public:
ULONG STDMETHODCALLTYPE AddRef() { return InterlockedIncrement(&ref_count); }
ULONG STDMETHODCALLTYPE Release()
{
ULONG ulRef = InterlockedDecrement(&ref_count);
if (0 == ulRef) {
delete this;
}
return ulRef;
}
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID ** ppvInterface)
{
if (__uuidof(IUnknown) == riid) {
AddRef();
*ppvInterface = (IUnknown *)this;
} else if (__uuidof(IAudioSessionEvents) == riid) {
AddRef();
*ppvInterface = (IAudioSessionEvents *)this;
} else {
*ppvInterface = NULL;
return E_NOINTERFACE;
}
return S_OK;
}
wasapi_session_notification_client(HANDLE event)
: ref_count(1), reconfigure_event(event)
{
}
virtual ~wasapi_session_notification_client() {}
HRESULT STDMETHODCALLTYPE
OnSessionDisconnected(AudioSessionDisconnectReason reason)
{
LOG("session: Audio session disconnected, reason: %d", reason);
BOOL ok = SetEvent(reconfigure_event);
if (!ok) {
LOG("session: SetEvent on reconfigure_event failed: %lx", GetLastError());
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnDisplayNameChanged(LPCWSTR value,
LPCGUID event_context)
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnIconPathChanged(LPCWSTR value,
LPCGUID event_context)
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnSimpleVolumeChanged(float volume, BOOL mute,
LPCGUID event_context)
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnChannelVolumeChanged(DWORD channel_count,
float volumes[],
DWORD changed_channel,
LPCGUID event_context)
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnGroupingParamChanged(LPCGUID grouping_param,
LPCGUID event_context)
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnStateChanged(AudioSessionState state)
{
return S_OK;
}
private:
LONG ref_count;
HANDLE reconfigure_event;
};
namespace {
long
@@ -1414,8 +1507,9 @@ static unsigned int __stdcall wasapi_stream_render_loop(LPVOID stream)
} com;
bool is_playing = true;
HANDLE wait_array[4] = {stm->shutdown_event, stm->reconfigure_event,
stm->refill_event, stm->input_available_event};
HANDLE wait_array[5] = {stm->shutdown_event, stm->mmcss_event,
stm->reconfigure_event, stm->refill_event,
stm->input_available_event};
HANDLE mmcss_handle = NULL;
HRESULT hr = 0;
DWORD mmcss_task_index = 0;
@@ -1428,15 +1522,6 @@ static unsigned int __stdcall wasapi_stream_render_loop(LPVOID stream)
return 0;
}
/* We could consider using "Pro Audio" here for WebAudio and
maybe WebRTC. */
mmcss_handle = AvSetMmThreadCharacteristicsA("Audio", &mmcss_task_index);
if (!mmcss_handle) {
/* This is not fatal, but we might glitch under heavy load. */
LOG("Unable to use mmcss to bump the render thread priority: %lx",
GetLastError());
}
while (is_playing) {
DWORD waitResult = WaitForMultipleObjects(ARRAY_LENGTH(wait_array),
wait_array, FALSE, INFINITE);
@@ -1450,7 +1535,30 @@ static unsigned int __stdcall wasapi_stream_render_loop(LPVOID stream)
}
continue;
}
case WAIT_OBJECT_0 + 1: { /* reconfigure */
case WAIT_OBJECT_0 + 1: { /* mmcss: active state changed */
/* stm->active was set by wasapi_stream_start/_stop before signaling,
and SetEvent provides the necessary memory barrier. */
if (stm->active && !mmcss_handle) {
/* We could consider using "Pro Audio" here for WebAudio and
maybe WebRTC. */
mmcss_handle =
AvSetMmThreadCharacteristicsA("Audio", &mmcss_task_index);
if (!mmcss_handle) {
/* This is not fatal, but we might glitch under heavy load. */
LOG("Unable to use mmcss to bump the render thread priority: %lx",
GetLastError());
} else {
LOG("MMCSS render thread promoted (task index %lu)",
mmcss_task_index);
}
} else if (!stm->active && mmcss_handle) {
AvRevertMmThreadCharacteristics(mmcss_handle);
mmcss_handle = NULL;
LOG("MMCSS render thread demoted");
}
continue;
}
case WAIT_OBJECT_0 + 2: { /* reconfigure */
auto_lock lock(stm->stream_reset_lock);
if (!stm->active) {
/* Avoid reconfiguring, stream start will handle it. */
@@ -1460,13 +1568,12 @@ static unsigned int __stdcall wasapi_stream_render_loop(LPVOID stream)
XASSERT(stm->output_client || stm->input_client);
LOG("Reconfiguring the stream");
/* Close the stream */
bool was_running = false;
if (stm->output_client) {
was_running = stm->output_client->Stop() == S_OK;
stm->output_client->Stop();
LOG("Output stopped.");
}
if (stm->input_client) {
was_running = stm->input_client->Stop() == S_OK;
stm->input_client->Stop();
LOG("Input stopped.");
}
close_wasapi_stream(stm);
@@ -1484,7 +1591,7 @@ static unsigned int __stdcall wasapi_stream_render_loop(LPVOID stream)
}
LOG("Stream setup successfuly.");
XASSERT(stm->output_client || stm->input_client);
if (was_running && stm->output_client) {
if (stm->output_client) {
hr = stm->output_client->Start();
if (FAILED(hr)) {
LOG("Error starting output after reconfigure, error: %lx", hr);
@@ -1493,7 +1600,7 @@ static unsigned int __stdcall wasapi_stream_render_loop(LPVOID stream)
}
LOG("Output started after reconfigure.");
}
if (was_running && stm->input_client) {
if (stm->input_client) {
hr = stm->input_client->Start();
if (FAILED(hr)) {
LOG("Error starting input after reconfiguring, error: %lx", hr);
@@ -1504,12 +1611,12 @@ static unsigned int __stdcall wasapi_stream_render_loop(LPVOID stream)
}
break;
}
case WAIT_OBJECT_0 + 2: /* refill */
case WAIT_OBJECT_0 + 3: /* refill */
XASSERT((has_input(stm) && has_output(stm)) ||
(!has_input(stm) && has_output(stm)));
is_playing = stm->refill_callback(stm);
break;
case WAIT_OBJECT_0 + 3: { /* input available */
case WAIT_OBJECT_0 + 4: { /* input available */
bool rv = get_input_buffer(stm);
if (!rv) {
is_playing = false;
@@ -2643,6 +2750,22 @@ setup_wasapi_stream(cubeb_stream * stm)
return CUBEB_ERROR;
}
hr = stm->output_client->GetService(__uuidof(IAudioSessionControl),
stm->session_control.receive_vpp());
if (SUCCEEDED(hr)) {
stm->session_notification_client.reset(
new wasapi_session_notification_client(stm->reconfigure_event));
hr = stm->session_control->RegisterAudioSessionNotification(
stm->session_notification_client.get());
if (FAILED(hr)) {
LOG("Could not register session notification client: %lx", hr);
stm->session_notification_client = nullptr;
stm->session_control = nullptr;
}
} else {
LOG("Could not get the IAudioSessionControl: %lx", hr);
}
#ifdef CUBEB_WASAPI_USE_IAUDIOSTREAMVOLUME
/* Restore the stream volume over a device change. */
if (stream_set_volume(stm, stm->volume) != CUBEB_OK) {
@@ -2842,6 +2965,12 @@ wasapi_stream_init(cubeb * context, cubeb_stream ** stream,
return CUBEB_ERROR;
}
stm->mmcss_event = CreateEvent(NULL, 0, 0, NULL);
if (!stm->mmcss_event) {
LOG("Can't create the mmcss event, error: %lx", GetLastError());
return CUBEB_ERROR;
}
stm->thread_ready_event = CreateEvent(NULL, 0, 0, NULL);
if (!stm->thread_ready_event) {
LOG("Can't create the thread ready event, error: %lx", GetLastError());
@@ -2906,6 +3035,13 @@ close_wasapi_stream(cubeb_stream * stm)
stm->stream_reset_lock.assert_current_thread_owns();
if (stm->session_control && stm->session_notification_client) {
stm->session_control->UnregisterAudioSessionNotification(
stm->session_notification_client.get());
stm->session_notification_client = nullptr;
stm->session_control = nullptr;
}
#ifdef CUBEB_WASAPI_USE_IAUDIOSTREAMVOLUME
stm->audio_stream_volume = nullptr;
#endif
@@ -2960,6 +3096,7 @@ wasapi_stream_release(cubeb_stream * stm)
CloseHandle(stm->reconfigure_event);
CloseHandle(stm->refill_event);
CloseHandle(stm->input_available_event);
CloseHandle(stm->mmcss_event);
CloseHandle(stm->thread);
@@ -3056,6 +3193,11 @@ wasapi_stream_start(cubeb_stream * stm)
stm->active = true;
if (!SetEvent(stm->mmcss_event)) {
LOG("wasapi_stream_start: SetEvent(mmcss_event) failed: %lx",
GetLastError());
}
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STARTED);
return CUBEB_OK;
@@ -3088,6 +3230,11 @@ wasapi_stream_stop(cubeb_stream * stm)
stm->active = false;
if (!SetEvent(stm->mmcss_event)) {
LOG("wasapi_stream_stop: SetEvent(mmcss_event) failed: %lx",
GetLastError());
}
wasapi_state_callback(stm, stm->user_ptr, CUBEB_STATE_STOPPED);
}
@@ -3563,11 +3710,13 @@ wasapi_register_device_collection_changed(
}
if (collection_changed_callback) {
// Make sure it has been unregistered first.
XASSERT(((devtype & CUBEB_DEVICE_TYPE_INPUT) &&
!context->input_collection_changed_callback) ||
((devtype & CUBEB_DEVICE_TYPE_OUTPUT) &&
!context->output_collection_changed_callback));
if (((devtype & CUBEB_DEVICE_TYPE_INPUT) &&
context->input_collection_changed_callback) ||
((devtype & CUBEB_DEVICE_TYPE_OUTPUT) &&
context->output_collection_changed_callback)) {
LOG("register_device_collection_changed: callback already registered");
return CUBEB_ERROR_INVALID_PARAMETER;
}
// Stop the notification client. Notifications arrive on
// a separate thread. We stop them here to avoid
+40 -10
View File
@@ -3,6 +3,9 @@
[![Ubuntu 22.04 CI (GCC 11)](https://github.com/fastfloat/fast_float/actions/workflows/ubuntu22.yml/badge.svg)](https://github.com/fastfloat/fast_float/actions/workflows/ubuntu22.yml)
*Note: This library is for C++ users. C programmers should consider [ffc.h](https://github.com/kolemannix/ffc.h). It is a high-performance port of fast_float to C.*
The fast_float library provides fast header-only implementations for the C++
from_chars functions for `float` and `double` types as well as integer types.
These functions convert ASCII strings representing decimal values (e.g.,
@@ -10,6 +13,7 @@ These functions convert ASCII strings representing decimal values (e.g.,
even). In our experience, these `fast_float` functions many times faster than
comparable number-parsing functions from existing C++ standard libraries.
Specifically, `fast_float` provides the following two functions to parse
floating-point numbers with a C++17-like syntax (the library itself only
requires C++11):
@@ -18,9 +22,9 @@ requires C++11):
from_chars_result from_chars(char const *first, char const *last, float &value, ...);
from_chars_result from_chars(char const *first, char const *last, double &value, ...);
```
If they are available on your system, we also support fixed-width floating-point types such as `std::float64_t`, `std::float32_t`, `std::float16_t`, and `std::bfloat16_t`.
You can also parse integer types:
You can also parse integer types such as `char`, `short`, `long`, `long long`, `unsigned char`, `unsigned short`, `unsigned long`, `unsigned long long`, `bool` (0/1), `int8_t`, `int16_t`, `int32_t`, `int64_t`, `uint8_t`, `uint16_t`, `uint32_t`, `uint64_t`.
```C++
from_chars_result from_chars(char const *first, char const *last, int &value, ...);
from_chars_result from_chars(char const *first, char const *last, unsigned &value, ...);
@@ -69,7 +73,7 @@ int main() {
}
```
Though the C++17 standard has you do a comparison with `std::errc()` to check whether the conversion worked, you can avoid it by casting the result to a `bool` like so:
Prior to C++26, checking for a successful `std::from_chars` conversion requires comparing the `from_chars_result::ec` member to `std::errc()`. As an extension `fast_float::from_chars` supports the improved C++26 API that allows checking the result by converting it to `bool`, like so:
```cpp
#include "fast_float/fast_float.h"
@@ -83,7 +87,7 @@ int main() {
std::cout << "parsed the number " << result << std::endl;
return EXIT_SUCCESS;
}
std::cerr << "failed to parse " << result << std::endl;
std::cerr << "failed to parse " << input << std::endl;
return EXIT_FAILURE;
}
```
@@ -141,9 +145,12 @@ Furthermore, we have the following restrictions:
fixed-width floating-point types such as `std::float64_t`, `std::float32_t`,
`std::float16_t`, and `std::bfloat16_t`.
* We only support the decimal format: we do not support hexadecimal strings.
* For values that are either very large or very small (e.g., `1e9999`), we
represent it using the infinity or negative infinity value and the returned
* For values that are very large positives or negatives (e.g., `1e9999`), we
represent them using a positive or negative infinity and the returned
`ec` is set to `std::errc::result_out_of_range`.
* For values that are very close to zero (e.g., `1e-9999`), we represent them
using a positive or negative zero and the returned `ec` is set to
`std::errc::result_out_of_range`.
We support Visual Studio, macOS, Linux, freeBSD. We support big and little
endian. We support 32-bit and 64-bit systems.
@@ -401,6 +408,23 @@ except `fast_float::integer_times_pow10()` does not report out-of-range errors,
underflows to zero or overflows to infinity when the resulting value is
out of range.
You can use template overloads to get the result converted to different
supported floating-point types: `float`, `double`, etc.
For example, to get result as `float` use
`fast_float::integer_times_pow10<float>()` specialization:
```C++
const uint64_t W = 12345678;
const int Q = 23;
const float result = fast_float::integer_times_pow10<float>(W, Q);
std::cout.precision(9);
std::cout << "float: " << W << " * 10^" << Q << " = " << result << " ("
<< (result == 12345678e23f ? "==" : "!=") << "expected)\n";
```
outputs
```
float: 12345678 * 10^23 = 1.23456782e+30 (==expected)
```
Overloads of `fast_float::integer_times_pow10()` are provided for
signed and unsigned integer types: `int64_t`, `uint64_t`, etc.
@@ -443,7 +467,7 @@ framework](https://github.com/microsoft/LightGBM).
Packages
------
[![Packaging status](https://repology.org/badge/vertical-allrepos/fastfloat.svg)](https://repology.org/project/fastfloat/versions)
[![Packaging status](https://repology.org/badge/vertical-allrepos/fast-float.svg)](https://repology.org/project/fast-float/versions)
## References
@@ -468,6 +492,7 @@ Packages
[Jackson](https://github.com/FasterXML/jackson-core).
* [There is a C# port of the fast_float
library](https://github.com/CarlVerret/csFastFloat) called `csFastFloat`.
* [There is a plain C port of the fast_float library](https://github.com/kolemannix/ffc.h) called ffc.h
## How fast is it?
@@ -516,7 +541,7 @@ sufficiently recent version of CMake (3.11 or better at least):
FetchContent_Declare(
fast_float
GIT_REPOSITORY https://github.com/fastfloat/fast_float.git
GIT_TAG tags/v8.1.0
GIT_TAG tags/v8.2.5
GIT_SHALLOW TRUE)
FetchContent_MakeAvailable(fast_float)
@@ -532,7 +557,7 @@ You may also use [CPM](https://github.com/cpm-cmake/CPM.cmake), like so:
CPMAddPackage(
NAME fast_float
GITHUB_REPOSITORY "fastfloat/fast_float"
GIT_TAG v8.1.0)
GIT_TAG v8.2.5)
```
## Using as single header
@@ -544,7 +569,7 @@ if desired as described in the command line help.
You may directly download automatically generated single-header files:
<https://github.com/fastfloat/fast_float/releases/download/v8.1.0/fast_float.h>
<https://github.com/fastfloat/fast_float/releases/download/v8.2.5/fast_float.h>
## Benchmarking
@@ -598,6 +623,11 @@ long digits.
The library includes code adapted from Google Wuffs (written by Nigel Tao) which
was originally published under the Apache 2.0 license.
## Stars
[![Star History Chart](https://api.star-history.com/svg?repos=fastfloat/fast_float&type=Date)](https://www.star-history.com/#fastfloat/fast_float&Date)
## License
<sup>
+179 -1
View File
@@ -32,7 +32,7 @@ template <typename UC> fastfloat_really_inline constexpr bool has_simd_opt() {
// able to optimize it well.
template <typename UC>
fastfloat_really_inline constexpr bool is_integer(UC c) noexcept {
return !(c > UC('9') || c < UC('0'));
return (unsigned)(c - UC('0')) <= 9u;
}
fastfloat_really_inline constexpr uint64_t byteswap(uint64_t val) {
@@ -42,6 +42,11 @@ fastfloat_really_inline constexpr uint64_t byteswap(uint64_t val) {
(val & 0x000000000000FF00) << 40 | (val & 0x00000000000000FF) << 56;
}
fastfloat_really_inline constexpr uint32_t byteswap_32(uint32_t val) {
return (val >> 24) | ((val >> 8) & 0x0000FF00u) | ((val << 8) & 0x00FF0000u) |
(val << 24);
}
// Read 8 UC into a u64. Truncates UC if not char.
template <typename UC>
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t
@@ -63,6 +68,25 @@ read8_to_u64(UC const *chars) {
return val;
}
// Read 4 UC into a u32. Truncates UC if not char.
template <typename UC>
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint32_t
read4_to_u32(UC const *chars) {
if (cpp20_and_in_constexpr() || !std::is_same<UC, char>::value) {
uint32_t val = 0;
for (int i = 0; i < 4; ++i) {
val |= uint32_t(uint8_t(*chars)) << (i * 8);
++chars;
}
return val;
}
uint32_t val;
::memcpy(&val, chars, sizeof(uint32_t));
#if FASTFLOAT_IS_BIG_ENDIAN == 1
val = byteswap_32(val);
#endif
return val;
}
#ifdef FASTFLOAT_SSE2
fastfloat_really_inline uint64_t simd_read8_to_u64(__m128i const data) {
@@ -144,6 +168,18 @@ is_made_of_eight_digits_fast(uint64_t val) noexcept {
0x8080808080808080));
}
fastfloat_really_inline constexpr bool
is_made_of_four_digits_fast(uint32_t val) noexcept {
return !((((val + 0x46464646) | (val - 0x30303030)) & 0x80808080));
}
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint32_t
parse_four_digits_unrolled(uint32_t val) noexcept {
val -= 0x30303030;
val = (val * 10) + (val >> 8);
return (((val & 0x00FF00FF) * 0x00640001) >> 16) & 0xFFFF;
}
#ifdef FASTFLOAT_HAS_SIMD
// Call this if chars might not be 8 digits.
@@ -509,6 +545,148 @@ parse_int_string(UC const *p, UC const *pend, T &value,
UC const *const start_digits = p;
FASTFLOAT_IF_CONSTEXPR17((std::is_same<T, std::uint8_t>::value)) {
if (base == 10) {
const size_t len = (size_t)(pend - p);
if (len == 0) {
if (has_leading_zeros) {
value = 0;
answer.ec = std::errc();
answer.ptr = p;
} else {
answer.ec = std::errc::invalid_argument;
answer.ptr = first;
}
return answer;
}
uint32_t digits;
#if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED && FASTFLOAT_HAS_BIT_CAST
if (std::is_constant_evaluated()) {
uint8_t str[4]{};
for (size_t j = 0; j < 4 && j < len; ++j) {
str[j] = static_cast<uint8_t>(p[j]);
}
digits = std::bit_cast<uint32_t>(str);
#if FASTFLOAT_IS_BIG_ENDIAN
digits = byteswap_32(digits);
#endif
}
#else
if (false) {
}
#endif
else if (len >= 4) {
::memcpy(&digits, p, 4);
#if FASTFLOAT_IS_BIG_ENDIAN
digits = byteswap_32(digits);
#endif
} else {
uint32_t b0 = static_cast<uint8_t>(p[0]);
uint32_t b1 = (len > 1) ? static_cast<uint8_t>(p[1]) : 0xFFu;
uint32_t b2 = (len > 2) ? static_cast<uint8_t>(p[2]) : 0xFFu;
uint32_t b3 = 0xFFu;
digits = b0 | (b1 << 8) | (b2 << 16) | (b3 << 24);
}
uint32_t magic =
((digits + 0x46464646u) | (digits - 0x30303030u)) & 0x80808080u;
uint32_t tz = (uint32_t)countr_zero_32(magic); // 7, 15, 23, 31, or 32
uint32_t nd = (tz == 32) ? 4 : (tz >> 3);
nd = (uint32_t)(nd < len ? nd : len);
if (nd == 0) {
if (has_leading_zeros) {
value = 0;
answer.ec = std::errc();
answer.ptr = p;
return answer;
}
answer.ec = std::errc::invalid_argument;
answer.ptr = first;
return answer;
}
if (nd > 3) {
const UC *q = p + nd;
size_t rem = len - nd;
while (rem) {
if (*q < UC('0') || *q > UC('9'))
break;
++q;
--rem;
}
answer.ec = std::errc::result_out_of_range;
answer.ptr = q;
return answer;
}
digits ^= 0x30303030u;
digits <<= ((4 - nd) * 8);
uint32_t check = ((digits >> 24) & 0xff) | ((digits >> 8) & 0xff00) |
((digits << 8) & 0xff0000);
if (check > 0x00020505) {
answer.ec = std::errc::result_out_of_range;
answer.ptr = p + nd;
return answer;
}
value = (uint8_t)((0x640a01 * digits) >> 24);
answer.ec = std::errc();
answer.ptr = p + nd;
return answer;
}
}
FASTFLOAT_IF_CONSTEXPR17((std::is_same<T, std::uint16_t>::value)) {
if (base == 10) {
const size_t len = size_t(pend - p);
if (len == 0) {
if (has_leading_zeros) {
value = 0;
answer.ec = std::errc();
answer.ptr = p;
} else {
answer.ec = std::errc::invalid_argument;
answer.ptr = first;
}
return answer;
}
if (len >= 4) {
uint32_t digits = read4_to_u32(p);
if (is_made_of_four_digits_fast(digits)) {
uint32_t v = parse_four_digits_unrolled(digits);
if (len >= 5 && is_integer(p[4])) {
v = v * 10 + uint32_t(p[4] - '0');
if (len >= 6 && is_integer(p[5])) {
answer.ec = std::errc::result_out_of_range;
const UC *q = p + 5;
while (q != pend && is_integer(*q)) {
q++;
}
answer.ptr = q;
return answer;
}
if (v > 65535) {
answer.ec = std::errc::result_out_of_range;
answer.ptr = p + 5;
return answer;
}
value = uint16_t(v);
answer.ec = std::errc();
answer.ptr = p + 5;
return answer;
}
// 4 digits
value = uint16_t(v);
answer.ec = std::errc();
answer.ptr = p + 4;
return answer;
}
}
}
}
uint64_t i = 0;
if (base == 10) {
loop_parse_if_eight_digits(p, pend, i); // use SIMD if possible
+6 -9
View File
@@ -1,7 +1,6 @@
#ifndef FASTFLOAT_DIGIT_COMPARISON_H
#define FASTFLOAT_DIGIT_COMPARISON_H
#include <algorithm>
#include <cstdint>
#include <cstring>
#include <iterator>
@@ -38,11 +37,8 @@ constexpr static uint64_t powers_of_ten_uint64[] = {1UL,
// this algorithm is not even close to optimized, but it has no practical
// effect on performance: in order to have a faster algorithm, we'd need
// to slow down performance for faster algorithms, and this is still fast.
template <typename UC>
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int32_t
scientific_exponent(parsed_number_string_t<UC> &num) noexcept {
uint64_t mantissa = num.mantissa;
int32_t exponent = int32_t(num.exponent);
scientific_exponent(uint64_t mantissa, int32_t exponent) noexcept {
while (mantissa >= 10000) {
mantissa /= 10000;
exponent += 4;
@@ -112,7 +108,7 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void round(adjusted_mantissa &am,
if (-am.power2 >= mantissa_shift) {
// have a denormal float
int32_t shift = -am.power2 + 1;
cb(am, std::min<int32_t>(shift, 64));
cb(am, (shift < 64 ? shift : 64));
// check for round-up: if rounding-nearest carried us to the hidden bit.
am.power2 = (am.mantissa <
(uint64_t(1) << binary_format<T>::mantissa_explicit_bits()))
@@ -398,7 +394,7 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp(
FASTFLOAT_ASSERT(real_digits.pow2(uint32_t(-pow2_exp)));
}
// compare digits, and use it to director rounding
// compare digits, and use it to direct rounding
int ord = real_digits.compare(theor_digits);
adjusted_mantissa answer = am;
round<T>(answer, [ord](adjusted_mantissa &a, int32_t shift) {
@@ -419,7 +415,7 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp(
return answer;
}
// parse the significant digits as a big integer to unambiguously round the
// parse the significant digits as a big integer to unambiguously round
// the significant digits. here, we are trying to determine how to round
// an extended float representation close to `b+h`, halfway between `b`
// (the float rounded-down) and `b+u`, the next positive float. this
@@ -438,7 +434,8 @@ digit_comp(parsed_number_string_t<UC> &num, adjusted_mantissa am) noexcept {
// remove the invalid exponent bias
am.power2 -= invalid_am_bias;
int32_t sci_exp = scientific_exponent(num);
int32_t sci_exp =
scientific_exponent(num.mantissa, static_cast<int32_t>(num.exponent));
size_t max_digits = binary_format<T>::max_digits();
size_t digits = 0;
bigint bigmant;
+14
View File
@@ -63,6 +63,20 @@ integer_times_pow10(uint64_t mantissa, int decimal_exponent) noexcept;
FASTFLOAT_CONSTEXPR20 inline double
integer_times_pow10(int64_t mantissa, int decimal_exponent) noexcept;
/**
* This function is a template overload of `integer_times_pow10()`
* that returns a floating-point value of type `T` that is one of
* supported floating-point types (e.g. `double`, `float`).
*/
template <typename T>
FASTFLOAT_CONSTEXPR20
typename std::enable_if<is_supported_float_type<T>::value, T>::type
integer_times_pow10(uint64_t mantissa, int decimal_exponent) noexcept;
template <typename T>
FASTFLOAT_CONSTEXPR20
typename std::enable_if<is_supported_float_type<T>::value, T>::type
integer_times_pow10(int64_t mantissa, int decimal_exponent) noexcept;
/**
* from_chars for integer types.
*/
+192 -11
View File
@@ -2,6 +2,7 @@
#define FASTFLOAT_FLOAT_COMMON_H
#include <cfloat>
#include <cstddef>
#include <cstdint>
#include <cassert>
#include <cstring>
@@ -16,8 +17,8 @@
#include "constexpr_feature_detect.h"
#define FASTFLOAT_VERSION_MAJOR 8
#define FASTFLOAT_VERSION_MINOR 1
#define FASTFLOAT_VERSION_PATCH 0
#define FASTFLOAT_VERSION_MINOR 2
#define FASTFLOAT_VERSION_PATCH 5
#define FASTFLOAT_STRINGIZE_IMPL(x) #x
#define FASTFLOAT_STRINGIZE(x) FASTFLOAT_STRINGIZE_IMPL(x)
@@ -267,18 +268,147 @@ struct is_supported_char_type
> {
};
template <typename UC>
inline FASTFLOAT_CONSTEXPR14 bool
fastfloat_strncasecmp3(UC const *actual_mixedcase,
UC const *expected_lowercase) {
uint64_t mask{0};
FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 1) { mask = 0x2020202020202020; }
else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 2) {
mask = 0x0020002000200020;
}
else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 4) {
mask = 0x0000002000000020;
}
else {
return false;
}
uint64_t val1{0}, val2{0};
if (cpp20_and_in_constexpr()) {
for (size_t i = 0; i < 3; i++) {
if ((actual_mixedcase[i] | 32) != expected_lowercase[i]) {
return false;
}
}
return true;
} else {
FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 1 || sizeof(UC) == 2) {
::memcpy(&val1, actual_mixedcase, 3 * sizeof(UC));
::memcpy(&val2, expected_lowercase, 3 * sizeof(UC));
val1 |= mask;
val2 |= mask;
return val1 == val2;
}
else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 4) {
::memcpy(&val1, actual_mixedcase, 2 * sizeof(UC));
::memcpy(&val2, expected_lowercase, 2 * sizeof(UC));
val1 |= mask;
if (val1 != val2) {
return false;
}
return (actual_mixedcase[2] | 32) == (expected_lowercase[2]);
}
else {
return false;
}
}
}
template <typename UC>
inline FASTFLOAT_CONSTEXPR14 bool
fastfloat_strncasecmp5(UC const *actual_mixedcase,
UC const *expected_lowercase) {
uint64_t mask{0};
uint64_t val1{0}, val2{0};
if (cpp20_and_in_constexpr()) {
for (size_t i = 0; i < 5; i++) {
if ((actual_mixedcase[i] | 32) != expected_lowercase[i]) {
return false;
}
}
return true;
} else {
FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 1) {
mask = 0x2020202020202020;
::memcpy(&val1, actual_mixedcase, 5 * sizeof(UC));
::memcpy(&val2, expected_lowercase, 5 * sizeof(UC));
val1 |= mask;
val2 |= mask;
return val1 == val2;
}
else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 2) {
mask = 0x0020002000200020;
::memcpy(&val1, actual_mixedcase, 4 * sizeof(UC));
::memcpy(&val2, expected_lowercase, 4 * sizeof(UC));
val1 |= mask;
if (val1 != val2) {
return false;
}
return (actual_mixedcase[4] | 32) == (expected_lowercase[4]);
}
else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 4) {
mask = 0x0000002000000020;
::memcpy(&val1, actual_mixedcase, 2 * sizeof(UC));
::memcpy(&val2, expected_lowercase, 2 * sizeof(UC));
val1 |= mask;
if (val1 != val2) {
return false;
}
::memcpy(&val1, actual_mixedcase + 2, 2 * sizeof(UC));
::memcpy(&val2, expected_lowercase + 2, 2 * sizeof(UC));
val1 |= mask;
if (val1 != val2) {
return false;
}
return (actual_mixedcase[4] | 32) == (expected_lowercase[4]);
}
else {
return false;
}
}
}
// Compares two ASCII strings in a case insensitive manner.
template <typename UC>
inline FASTFLOAT_CONSTEXPR14 bool
fastfloat_strncasecmp(UC const *actual_mixedcase, UC const *expected_lowercase,
size_t length) {
for (size_t i = 0; i < length; ++i) {
UC const actual = actual_mixedcase[i];
if ((actual < 256 ? actual | 32 : actual) != expected_lowercase[i]) {
return false;
}
uint64_t mask{0};
FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 1) { mask = 0x2020202020202020; }
else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 2) {
mask = 0x0020002000200020;
}
else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 4) {
mask = 0x0000002000000020;
}
else {
return false;
}
if (cpp20_and_in_constexpr()) {
for (size_t i = 0; i < length; i++) {
if ((actual_mixedcase[i] | 32) != expected_lowercase[i]) {
return false;
}
}
return true;
} else {
uint64_t val1{0}, val2{0};
size_t sz{8 / (sizeof(UC))};
for (size_t i = 0; i < length; i += sz) {
val1 = val2 = 0;
sz = sz < (length - i) ? sz : length - i;
::memcpy(&val1, actual_mixedcase + i, sz * sizeof(UC));
::memcpy(&val2, expected_lowercase + i, sz * sizeof(UC));
val1 |= mask;
val2 |= mask;
if (val1 != val2) {
return false;
}
}
return true;
}
return true;
}
#ifndef FLT_EVAL_METHOD
@@ -362,6 +492,52 @@ leading_zeroes(uint64_t input_num) {
#endif
}
/* Helper C++14 constexpr generic implementation of countr_zero for 32-bit */
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int
countr_zero_generic_32(uint32_t input_num) {
if (input_num == 0) {
return 32;
}
int last_bit = 0;
if (!(input_num & 0x0000FFFF)) {
input_num >>= 16;
last_bit |= 16;
}
if (!(input_num & 0x00FF)) {
input_num >>= 8;
last_bit |= 8;
}
if (!(input_num & 0x0F)) {
input_num >>= 4;
last_bit |= 4;
}
if (!(input_num & 0x3)) {
input_num >>= 2;
last_bit |= 2;
}
if (!(input_num & 0x1)) {
last_bit |= 1;
}
return last_bit;
}
/* count trailing zeroes for 32-bit integers */
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 int
countr_zero_32(uint32_t input_num) {
if (cpp20_and_in_constexpr()) {
return countr_zero_generic_32(input_num);
}
#ifdef FASTFLOAT_VISUAL_STUDIO
unsigned long trailing_zero = 0;
if (_BitScanForward(&trailing_zero, input_num)) {
return (int)trailing_zero;
}
return 32;
#else
return input_num == 0 ? 32 : __builtin_ctz(input_num);
#endif
}
// slow emulation routine for 32-bit
fastfloat_really_inline constexpr uint64_t emulu(uint32_t x, uint32_t y) {
return x * (uint64_t)y;
@@ -406,8 +582,8 @@ full_multiplication(uint64_t a, uint64_t b) {
// But MinGW on ARM64 doesn't have native support for 64-bit multiplications
answer.high = __umulh(a, b);
answer.low = a * b;
#elif defined(FASTFLOAT_32BIT) || \
(defined(_WIN64) && !defined(__clang__) && !defined(_M_ARM64))
#elif defined(FASTFLOAT_32BIT) || (defined(_WIN64) && !defined(__clang__) && \
!defined(_M_ARM64) && !defined(__GNUC__))
answer.low = _umul128(a, b, &answer.high); // _umul128 not available on ARM64
#elif defined(FASTFLOAT_64BIT) && defined(__SIZEOF_INT128__)
__uint128_t r = ((__uint128_t)a) * b;
@@ -1166,6 +1342,9 @@ static_assert(std::is_same<equiv_uint_t<std::float64_t>, uint64_t>::value,
static_assert(
std::numeric_limits<std::float64_t>::is_iec559,
"std::float64_t must fulfill the requirements of IEC 559 (IEEE 754)");
template <>
struct binary_format<std::float64_t> : public binary_format<double> {};
#endif // __STDCPP_FLOAT64_T__
#ifdef __STDCPP_FLOAT32_T__
@@ -1174,6 +1353,9 @@ static_assert(std::is_same<equiv_uint_t<std::float32_t>, uint32_t>::value,
static_assert(
std::numeric_limits<std::float32_t>::is_iec559,
"std::float32_t must fulfill the requirements of IEC 559 (IEEE 754)");
template <>
struct binary_format<std::float32_t> : public binary_format<float> {};
#endif // __STDCPP_FLOAT32_T__
#ifdef __STDCPP_FLOAT16_T__
@@ -1245,7 +1427,6 @@ constexpr chars_format adjust_for_feature_macros(chars_format fmt) {
;
}
} // namespace detail
} // namespace fast_float
#endif
+56 -21
View File
@@ -35,7 +35,7 @@ from_chars_result_t<UC>
++first;
}
if (last - first >= 3) {
if (fastfloat_strncasecmp(first, str_const_nan<UC>(), 3)) {
if (fastfloat_strncasecmp3(first, str_const_nan<UC>())) {
answer.ptr = (first += 3);
value = minusSign ? -std::numeric_limits<T>::quiet_NaN()
: std::numeric_limits<T>::quiet_NaN();
@@ -54,9 +54,9 @@ from_chars_result_t<UC>
}
return answer;
}
if (fastfloat_strncasecmp(first, str_const_inf<UC>(), 3)) {
if (fastfloat_strncasecmp3(first, str_const_inf<UC>())) {
if ((last - first >= 8) &&
fastfloat_strncasecmp(first + 3, str_const_inf<UC>() + 3, 5)) {
fastfloat_strncasecmp5(first + 3, str_const_inf<UC>() + 3)) {
answer.ptr = first + 8;
} else {
answer.ptr = first + 3;
@@ -155,7 +155,7 @@ template <> struct from_chars_caller<std::float32_t> {
// if std::float32_t is defined, and we are in C++23 mode; macro set for
// float32; set value to float due to equivalence between float and
// float32_t
float val;
float val = 0.0f;
auto ret = from_chars_advanced(first, last, val, options);
value = val;
return ret;
@@ -172,7 +172,7 @@ template <> struct from_chars_caller<std::float64_t> {
// if std::float64_t is defined, and we are in C++23 mode; macro set for
// float64; set value as double due to equivalence between double and
// float64_t
double val;
double val = 0.0;
auto ret = from_chars_advanced(first, last, val, options);
value = val;
return ret;
@@ -251,7 +251,7 @@ clinger_fast_path_impl(uint64_t mantissa, int64_t exponent, bool is_negative,
* parsing options or other parsing custom function implemented by user.
*/
template <typename T, typename UC>
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
from_chars_advanced(parsed_number_string_t<UC> &pns, T &value) noexcept {
static_assert(is_supported_float_type<T>::value,
"only some floating-point types are supported");
@@ -290,7 +290,7 @@ from_chars_advanced(parsed_number_string_t<UC> &pns, T &value) noexcept {
}
template <typename T, typename UC>
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
from_chars_float_advanced(UC const *first, UC const *last, T &value,
parse_options_t<UC> options) noexcept {
@@ -344,44 +344,79 @@ from_chars(UC const *first, UC const *last, T &value, int base) noexcept {
return from_chars_advanced(first, last, value, options);
}
FASTFLOAT_CONSTEXPR20 inline double
integer_times_pow10(uint64_t mantissa, int decimal_exponent) noexcept {
double value;
template <typename T>
FASTFLOAT_CONSTEXPR20
typename std::enable_if<is_supported_float_type<T>::value, T>::type
integer_times_pow10(uint64_t mantissa, int decimal_exponent) noexcept {
T value;
if (clinger_fast_path_impl(mantissa, decimal_exponent, false, value))
return value;
adjusted_mantissa am =
compute_float<binary_format<double>>(decimal_exponent, mantissa);
compute_float<binary_format<T>>(decimal_exponent, mantissa);
to_float(false, am, value);
return value;
}
FASTFLOAT_CONSTEXPR20 inline double
integer_times_pow10(int64_t mantissa, int decimal_exponent) noexcept {
template <typename T>
FASTFLOAT_CONSTEXPR20
typename std::enable_if<is_supported_float_type<T>::value, T>::type
integer_times_pow10(int64_t mantissa, int decimal_exponent) noexcept {
const bool is_negative = mantissa < 0;
const uint64_t m = static_cast<uint64_t>(is_negative ? -mantissa : mantissa);
double value;
T value;
if (clinger_fast_path_impl(m, decimal_exponent, is_negative, value))
return value;
adjusted_mantissa am =
compute_float<binary_format<double>>(decimal_exponent, m);
adjusted_mantissa am = compute_float<binary_format<T>>(decimal_exponent, m);
to_float(is_negative, am, value);
return value;
}
FASTFLOAT_CONSTEXPR20 inline double
integer_times_pow10(uint64_t mantissa, int decimal_exponent) noexcept {
return integer_times_pow10<double>(mantissa, decimal_exponent);
}
FASTFLOAT_CONSTEXPR20 inline double
integer_times_pow10(int64_t mantissa, int decimal_exponent) noexcept {
return integer_times_pow10<double>(mantissa, decimal_exponent);
}
// the following overloads are here to avoid surprising ambiguity for int,
// unsigned, etc.
template <typename T, typename Int>
FASTFLOAT_CONSTEXPR20
typename std::enable_if<is_supported_float_type<T>::value &&
std::is_integral<Int>::value &&
!std::is_signed<Int>::value,
T>::type
integer_times_pow10(Int mantissa, int decimal_exponent) noexcept {
return integer_times_pow10<T>(static_cast<uint64_t>(mantissa),
decimal_exponent);
}
template <typename T, typename Int>
FASTFLOAT_CONSTEXPR20
typename std::enable_if<is_supported_float_type<T>::value &&
std::is_integral<Int>::value &&
std::is_signed<Int>::value,
T>::type
integer_times_pow10(Int mantissa, int decimal_exponent) noexcept {
return integer_times_pow10<T>(static_cast<int64_t>(mantissa),
decimal_exponent);
}
template <typename Int>
FASTFLOAT_CONSTEXPR20 inline typename std::enable_if<
FASTFLOAT_CONSTEXPR20 typename std::enable_if<
std::is_integral<Int>::value && !std::is_signed<Int>::value, double>::type
integer_times_pow10(Int mantissa, int decimal_exponent) noexcept {
return integer_times_pow10(static_cast<uint64_t>(mantissa), decimal_exponent);
}
template <typename Int>
FASTFLOAT_CONSTEXPR20 inline typename std::enable_if<
FASTFLOAT_CONSTEXPR20 typename std::enable_if<
std::is_integral<Int>::value && std::is_signed<Int>::value, double>::type
integer_times_pow10(Int mantissa, int decimal_exponent) noexcept {
return integer_times_pow10(static_cast<int64_t>(mantissa), decimal_exponent);
@@ -421,7 +456,7 @@ template <size_t TypeIx> struct from_chars_advanced_caller {
template <> struct from_chars_advanced_caller<1> {
template <typename T, typename UC>
FASTFLOAT_CONSTEXPR20 static from_chars_result_t<UC>
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 static from_chars_result_t<UC>
call(UC const *first, UC const *last, T &value,
parse_options_t<UC> options) noexcept {
return from_chars_float_advanced(first, last, value, options);
@@ -430,7 +465,7 @@ template <> struct from_chars_advanced_caller<1> {
template <> struct from_chars_advanced_caller<2> {
template <typename T, typename UC>
FASTFLOAT_CONSTEXPR20 static from_chars_result_t<UC>
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 static from_chars_result_t<UC>
call(UC const *first, UC const *last, T &value,
parse_options_t<UC> options) noexcept {
return from_chars_int_advanced(first, last, value, options);
@@ -438,7 +473,7 @@ template <> struct from_chars_advanced_caller<2> {
};
template <typename T, typename UC>
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
from_chars_advanced(UC const *first, UC const *last, T &value,
parse_options_t<UC> options) noexcept {
return from_chars_advanced_caller<
+191
View File
@@ -39,6 +39,197 @@ HOW TO UPDATE?
and API updates have been a little more frequent lately. They are documented below and in imgui.cpp and should not affect all users.
- Please report any issue!
-----------------------------------------------------------------------
VERSION 1.92.8 (Released 2026-05-12)
-----------------------------------------------------------------------
Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.92.8
Breaking Changes:
- DrawList: swapped the last two arguments of `AddRect()`, `AddPolyline()`, `PathStroke()`.
- Before: `void ImDrawList::AddRect(ImVec2 p_min, ImVec2 p_max, ImU32 col, float rounding = 0.0f, ImDrawFlags flags = 0, float thickness = 1.0f);`
- After: `void ImDrawList::AddRect(ImVec2 p_min, ImVec2 p_max, ImU32 col, float rounding = 0.0f, float thickness = 1.0f, ImDrawFlags flags = 0);`
- Before: `void ImDrawList::AddPolyline(const ImVec2* points, int num_points, ImU32 col, ImDrawFlags flags, float thickness);`
- After: `void ImDrawList::AddPolyline(const ImVec2* points, int num_points, ImU32 col, float thickness, ImDrawFlags flags = 0);`
- Before: `void ImDrawList::PathStroke(ImU32 col, ImDrawFlags flags = 0, float thickness = 1.0f);`
- After: `void ImDrawList::PathStroke(ImU32 col, float thickness = 1.0f, ImDrawFlags flags = 0);`
Added inline redirection functions when IMGUI_DISABLE_OBSOLETE_FUNCTIONS is off.
Marked the old functions are =delete when IMGUI_DISABLE_OBSOLETE_FUNCTIONS is on, to allow for better type-checking.
Effectively the typical call site is changing from:
- Before: `window->DrawList->AddRect(p_min, p_max, color, rounding, ImDrawFlags_None, border_size);`
- After: `window->DrawList->AddRect(p_min, p_max, color, rounding, border_size);`
Notes:
- Users of C++ and other languages with type-checking will be notified at compile-time of any mistakes.
- Users of high-level bindings or languages with no type-checking will be notified at runtime via an assert for invalid flags value.
If you are a binding maintainer consider doing something to facilitate transition or error detection.
- This is perhaps the worst breaking change in our history :( but it makes ImDrawList function signatures consistent.
As we are aiming to add flags and features to variety of ImDrawList functions, that consistency becomes more important.
The new order is also more convenient as `flags` are less frequently used than `thickness` in real code.
- As a general policy in Dear ImGui, all our flags default to 0 so ImDrawFlags_None was likely written 0 in some call sites.
- Consider adding `#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS` in your imconfig.h, even temporarily, to clean up legacy code.
- DrawList: obsoleted `ImDrawCallback_ResetRenderState` in favor of using `ImGui::GetPlatformIO().DrawCallback_ResetRenderState`,
which is part of our new standard draw callbacks. (#9378)
Redirecting the earlier value into the later one when set, so both old and new code should work.
- Backends:
- Vulkan: redesigned to use separate ImageView + Sampler instead of Combined Image Sampler. (#914)
This change allows us to facilitate changing samplers, in line with other backends. [@yaz0r, @ocornut]
- When creating your own descriptor pool (instead of letting backend creates its own):
- Before: need at least `IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE` descriptors of type `VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER`.
- After: need at least `IMGUI_IMPL_VULKAN_MINIMUM_SAMPLED_IMAGE_POOL_SIZE` descriptors of type `VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE`.
+ `IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE` descriptors of type `VK_DESCRIPTOR_TYPE_SAMPLER`.
- When registering custom textures: changed ImGui_ImplVulkan_AddTexture() signature to remove Sampler.
- Before: `ImGui_ImplVulkan_AddTexture(VkSampler, VkImageView, VkImageLayout)`
- After: `ImGui_ImplVulkan_AddTexture(VkImageView, VkImageLayout)`
- Kept inline redirection function that ignores the sampler (will obsolete).
- DirectX10, DirectX11, SDLGPU3, Vulkan: removed samplers from `ImGui_ImplXXXX_RenderState`.
Prefer to use backend-agnostic DrawCallback_SetSamplerLinear which works everywhere! (#9378)
If there is a legit need/request for them or any render state we can always add them back.
Other Changes:
- DrawList:
- Added room in `ImGuiPlatformIO` for standard backend-agnostic draw callbacks. Those callbacks
are setup/provided by the backend and available in most of our standard backends.
They allow backend-agnostic code from e.g. switching to a Nearest/Point sampler without
messing with custom Renderer-specific callbacks.
platform_io.DrawCallback_ResetRenderState; // Request to reset the graphics/render state.
platform_io.DrawCallback_SetSamplerLinear; // Request to set current texture sampling to Linear
platform_io.DrawCallback_SetSamplerNearest; // Request to set current texture sampling to Nearest/Point
Note that some backends might not support all callbacks.
(#9378, #9371, #3590, #8926, #2973, #7485, #7468, #6969, #5118, #7616, #9173, #8322, #7230,
#5999, #6452, #5156, #7342, #7592, #7511)
- Made `AddCallback()` user data default to Null for convenience.
- Added `AddLineH()`, `AddLineV()` helpers to draw horizontal and vertical lines. [@memononen]
- InputText:
- InputTextMultiline: fixed an issue processing deactivation logic when an active
multi-line edit is clipped due to being out of view.
- Fixed a crash when toggling ReadOnly while active. (#9354)
- `CharFilter` callback event sets CursorPos/SelectionStart/SelectionEnd. (#816)
- Tables:
- Fixed issues reporting ideal size to parent window/container: (#9352, #7651)
- When both scrollbars are visible but only one of ScrollX/ScrollY was explicitly requested.
- When vertical scrollbar was not at the top, the computation was often incorrect.
- Windows:
- Fixed a single-axis auto-resizing feedback loop issue with nested containers
and varying scrollbar visibility. (#9352)
- Detect and report error when calling End() instead of EndPopup() on a popup. (#9351)
- Child windows with only `ImGuiChildFlags_AutoResizeY` flag keep using the proportional
default `ItemWidth`. (#9355)
- Using mouse wheel to scroll takes and keeps ownership of the corresponding keys
(e.g. `ImGuiKey_MouseWheelY`) while a wheeling window is locked. (#2604, #3795)
- InputInt, InputFloat, InputScalar:
- Reinstated `ImGuiInputTextFlags_EnterReturnsTrue` support which was removed in 1.91.4.
(#8665, #9299, #8065, #3946, #6284, #9117)
- Fixed the fact that it didn't return true when validating same value.
- Fixed losing value when tabbing out or losing focus.
- Made it that pressing +/- step buttons also return true, which is in line
with 1.91.4 behavior.
- In a majority of cases you should use `IsItemDeactivatedAfterEdit()` instead,
but it still has a few edge cases flaws (to be addressed soon).
- Allow passing a format string that does not display the scalar value.
Parsing input with default format for the type. (#9385) [@FireFox2000000]
- Multi-Select:
- Fixed an issue using Multi-Select within a Table causing column width measurement to
be invalid when trailing column contents is not submitted in the last row. (#9341, #8250)
- Fixed an issue using Multi-Select within a Table with the right-most column visible,
which could lead to an extra vertical offset in the Header row. (#8250)
- Multi-Select + Box-Select:
- Fixed an issue using `ImGuiMultiSelectFlags_BoxSelect1d` mode while scrolling.
Notably, using mouse wheel while holding a box-selection could lead items close to windows
edges from not being correctly unselected. (#7994, #8250, #7821, #7850, #7970)
- Improved dirty/unclip rectangle logic for `ImGuiMultiSelectFlags_BoxSelect2d`.
- Fixed an issue using `ImGuiMultiSelectFlags_BoxSelect2d` mode, where
items out of view wouldn't be properly selected while scrolling while mouse cursor
is hovering outside of selection scope. (#7994, #1861, #6518)
- Fixed an issue where items out of horizontal view would sometimes lead
to incorrect merging of sequential selection requests while also scrolling fast
enough to overlap multiple rows during a frame. (#7994, #1861, #6518)
- Fixed an issue using `ImGuiMultiSelectFlags_BoxSelect2d` mode in a Table
while relying on the `TableNextColumn()` return value to perform coarse clipping. (#7994)
- Disabled merging consecutive selection requests as we have no reliable
way of detecting if user has submitted all consecutive items without clipping gaps,
and `ImGuiSelectionUserData` is technically opaque storage. (#7994, #1861)
(we will probably bring this back as a minor optimization if we have a way to for
user to tell us `ImGuiSelectionUserData` are indices)
- Fixes for using across nested child windows. (#8364)
- Box-Select + Clipper: fixed an issue selecting items while scrolling while a clipper
active. (#7994, #8250, #7821, #7850, #7970)
- Box-Select + Tables: fixed an issue using box-selection in a tables with
items straying out of columns boundaries. (#7994, #2221)
- Box-Select + Tables: fixed an issue when calling `BeginMultiSelect()` in a table
before layout has been locked (first row or headers row submitted). (#8250)
- Menus:
- BeginMenu()/MenuItem(): fixed accidental triggering of child menu items when
opening a menu inside a small host window forcing the child menu window to be
repositioned under the mouse cursor. (#8233, #9394)
Done by reworking `BeginMenu()`/`MenuItem()`: they previously avoiding taking
ActiveID + key/click ownership (in order to allow releasing button on another item).
Now they take them and release them once the mouse is moved outside item boundaries.
- Inputs:
- SetItemKeyOwner(): return true if ownership has been requested, which typically
needs to to checked for gating further tests. This is important as the function
may fail. (#456, #2637, #2620, #2891, #3370, #3724, #4828, #5108, #5242, #5641)
- SetItemKeyOwner(): does not set ownership is key is already taken. Effectively
this makes using `SetItemKeyOwner(ImGuiKey_MouseWheelY)` over an item work as
expected while not having item react if a scroll wheel is actively in progress.
May be subject to further redesign, e.g. conditional flags. Feedback welcome!
- Style:
- Checkbox: added `ImGuiCol_CheckboxSelectedBg` to change or accentuate the
background color of checked/mixed checkboxes. (#9392)
- Added `ImGuiStyleVar_DragDropTargetRounding`. (#9056)
- Fixed vertical scrollbar top coordinates when using thick borders on windows
with no title bar and no menu bar. (#9366)
- Fonts:
- imgui_freetype: add FreeType headers & compiled version in 'About Dear ImGui' details.
- Assert when using MergeMode with an explicit size over a target font with an implicit
size, as scale factor are likely erroneous. (#9361)
- Clipper:
- Improved error reporting when misusing the clipper inside a table (prioritize
reporting the common clipper error over a table sanity check assert). (#9350)
- Tweaked assert triggering when first item height measurement fails, and made it
a better recoverable error. (#9350)
- Misc:
- Minor optimization: reduce redundant label scanning in common widgets.
- Added missing Test Engine hooks for `PlotLines()`, `PlotHistogram()`, `VSliderXXX()`
and `TableHeader()` functions.
- Demo:
- Added simple demo for a scrollable/zoomable image viewer with a grid.
Available in `Examples->Image Viewer` and `Widgets->Images`.
- Backends:
- Added support for new standardized draw callbacks in most backends: (#9378)
- Allegro5: Reset n/a n/a
- DX9: Reset SetSamplerLinear SetSamplerNearest
- DX10: Reset SetSamplerLinear SetSamplerNearest
- DX11: Reset SetSamplerLinear SetSamplerNearest
- DX12: Reset SetSamplerLinear SetSamplerNearest
- Metal: Reset SetSamplerLinear SetSamplerNearest
- OpenGL2: Reset SetSamplerLinear SetSamplerNearest
- OpenGL3+: Reset SetSamplerLinear SetSamplerNearest
- SDLGPU3: Reset SetSamplerLinear SetSamplerNearest
- SDLRenderer2: Reset n/a n/a
- SDLRenderer3: Reset SetSamplerLinear SetSamplerNearest
- Vulkan: Reset SetSamplerLinear SetSamplerNearest
- WebGPU: Reset SetSamplerLinear SetSamplerNearest
(Vulkan backend by @yaz0r, Metal by @ssh4net, others by @ocornut)
- GLFW: added a Win32-specific implementation of `ImGui_ImplGlfw_GetContentScaleXXXX`
functions for legacy GLFW 3.2. (#9003)
- Metal: avoid redundant vertex buffer bind in `SetupRenderState()`, which leads
to validation issue. (#9343) [@Hunam6]
- Metal: use a dedicated `bufferCacheLock` to avoid crashing when `bufferCache` is
replaced by a new object while being used for `@synchronize()`. (#9367) [@andygrundman]
- SDL2: made `ImGui_ImplSDL2_GetContentScaleForWindow()`/`ImGui_ImplSDL2_GetContentScaleForDisplay()`
helpers return a minimum of 1.0f, as some Linux setup seems to report <1.0f value
and this breaks scaling border size. (#9369)
- WebGPU: rework choice/detection of using WGSL/SPIR-V shader on WGVK. (#9316, #9246, #9257, #9387)
- Examples:
- Update VS toolset in all .vcxproj from VS2015 (v140) to VS2017 (v141). The later is the
first that supports vcpkg. Onward we will likely stop testing building the library with VS2015.
- GLFW+Vulkan, SDL2+Vulkan, SDL3+Vulkan, Win32+Vulkan: reworked to create a descriptor pool with:
- `IMGUI_IMPL_VULKAN_MINIMUM_SAMPLED_IMAGE_POOL_SIZE` descriptors of type `VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE`.
- `IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE` descriptors of type `VK_DESCRIPTOR_TYPE_SAMPLER`.
-----------------------------------------------------------------------
VERSION 1.92.7 (Released 2026-04-02)
-----------------------------------------------------------------------
+47 -30
View File
@@ -1,4 +1,4 @@
// dear imgui, v1.92.7
// dear imgui, v1.92.8
// (headers)
// Help:
@@ -29,8 +29,8 @@
// Library Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345')
#define IMGUI_VERSION "1.92.7"
#define IMGUI_VERSION_NUM 19270
#define IMGUI_VERSION "1.92.8"
#define IMGUI_VERSION_NUM 19280
#define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000
#define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198
@@ -1092,10 +1092,11 @@ namespace ImGui
// Inputs Utilities: Key/Input Ownership [BETA]
// - One common use case would be to allow your items to disable standard inputs behaviors such
// as Tab or Alt key handling, Mouse Wheel scrolling, etc.
// e.g. Button(...); SetItemKeyOwner(ImGuiKey_MouseWheelY); to make hovering/activating a button disable wheel for scrolling.
// e.g. `Button(...); if (SetItemKeyOwner(ImGuiKey_MouseWheelY)) { ... }` to make hovering/activating a button disable wheel for scrolling.
// - Reminder ImGuiKey enum include access to mouse buttons and gamepad, so key ownership can apply to them.
// - The return value of SetItemKeyOwner() says if ownership has been requested for the item, which is a shortcut to calling yet non-public TestKeyOwner() function.
// - Many related features are still in imgui_internal.h. For instance, most IsKeyXXX()/IsMouseXXX() functions have an owner-id-aware version.
IMGUI_API void SetItemKeyOwner(ImGuiKey key); // Set key owner to last item ID if it is hovered or active. Equivalent to 'if (IsItemHovered() || IsItemActive()) { SetKeyOwner(key, GetItemID());'.
IMGUI_API bool SetItemKeyOwner(ImGuiKey key); // Set key owner to last item ID if it is hovered or active. Return true when ownership has been set. Roughly equivalent to 'if (TestKeyOwner(key, GetItemID()) && (IsItemHovered() || IsItemActive())) { SetKeyOwner(key, GetItemID());'.
// Inputs Utilities: Mouse
// - To refer to a mouse button, you may use named enums in your code e.g. ImGuiMouseButton_Left, ImGuiMouseButton_Right.
@@ -1401,7 +1402,7 @@ enum ImGuiTabBarFlags_
ImGuiTabBarFlags_DrawSelectedOverline = 1 << 6, // Draw selected overline markers over selected tab
// Fitting/Resize policy
ImGuiTabBarFlags_FittingPolicyMixed = 1 << 7, // Shrink down tabs when they don't fit, until width is style.TabMinWidthShrink, then enable scrolling buttons.
ImGuiTabBarFlags_FittingPolicyMixed = 1 << 7, // Shrink down tabs when they don't fit, until width is style.TabMinWidthShrink, then enable scrolling. Setting TabMinWidthShrink to FLT_MAX makes this behave like ImGuiTabBarFlags_FittingPolicyScroll.
ImGuiTabBarFlags_FittingPolicyShrink = 1 << 8, // Shrink down tabs when they don't fit
ImGuiTabBarFlags_FittingPolicyScroll = 1 << 9, // Enable scrolling buttons when tabs don't fit
ImGuiTabBarFlags_FittingPolicyMask_ = ImGuiTabBarFlags_FittingPolicyMixed | ImGuiTabBarFlags_FittingPolicyShrink | ImGuiTabBarFlags_FittingPolicyScroll,
@@ -1755,6 +1756,7 @@ enum ImGuiCol_
ImGuiCol_ScrollbarGrabHovered,
ImGuiCol_ScrollbarGrabActive,
ImGuiCol_CheckMark, // Checkbox tick and RadioButton circle
ImGuiCol_CheckboxSelectedBg, // Checkbox background when Selected, otherwise use FrameBg
ImGuiCol_SliderGrab,
ImGuiCol_SliderGrabActive,
ImGuiCol_Button,
@@ -1852,6 +1854,7 @@ enum ImGuiStyleVar_
ImGuiStyleVar_TableAngledHeadersTextAlign,// ImVec2 TableAngledHeadersTextAlign
ImGuiStyleVar_TreeLinesSize, // float TreeLinesSize
ImGuiStyleVar_TreeLinesRounding, // float TreeLinesRounding
ImGuiStyleVar_DragDropTargetRounding, // float DragDropTargetRounding
ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign
ImGuiStyleVar_SelectableTextAlign, // ImVec2 SelectableTextAlign
ImGuiStyleVar_SeparatorSize, // float SeparatorSize
@@ -2319,7 +2322,7 @@ struct ImGuiStyle
float TabBorderSize; // Thickness of border around tabs.
float TabMinWidthBase; // Minimum tab width, to make tabs larger than their contents. TabBar buttons are not affected.
float TabMinWidthShrink; // Minimum tab width after shrinking, when using ImGuiTabBarFlags_FittingPolicyMixed policy.
float TabCloseButtonMinWidthSelected; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width.
float TabCloseButtonMinWidthSelected; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width. FLT_MAX: never shrink, will behave like ImGuiTabBarFlags_FittingPolicyScroll.
float TabCloseButtonMinWidthUnselected; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width. FLT_MAX: never show close button when unselected.
float TabBarBorderSize; // Thickness of tab-bar separator, which takes on the tab active color to denote focus.
float TabBarOverlineSize; // Thickness of tab-bar overline, which highlights the selected tab-bar.
@@ -2328,14 +2331,14 @@ struct ImGuiStyle
ImGuiTreeNodeFlags TreeLinesFlags; // Default way to draw lines connecting TreeNode hierarchy. ImGuiTreeNodeFlags_DrawLinesNone or ImGuiTreeNodeFlags_DrawLinesFull or ImGuiTreeNodeFlags_DrawLinesToNodes.
float TreeLinesSize; // Thickness of outlines when using ImGuiTreeNodeFlags_DrawLines.
float TreeLinesRounding; // Radius of lines connecting child nodes to the vertical line.
float DragDropTargetRounding; // Radius of the drag and drop target frame.
float DragDropTargetRounding; // Radius of the drag and drop target frame. When <0.0f: use FrameRounding.
float DragDropTargetBorderSize; // Thickness of the drag and drop target border.
float DragDropTargetPadding; // Size to expand the drag and drop target from actual target item size.
float ColorMarkerSize; // Size of R/G/B/A color markers for ColorEdit4() and for Drags/Sliders when using ImGuiSliderFlags_ColorMarkers.
ImGuiDir ColorButtonPosition; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right.
ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered).
ImVec2 SelectableTextAlign; // Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line.
float SeparatorSize; // Thickness of border in Separator()
float SeparatorSize; // Thickness of border in Separator(). Must be >= 1.0f.
float SeparatorTextBorderSize; // Thickness of border in SeparatorText()
ImVec2 SeparatorTextAlign; // Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center).
ImVec2 SeparatorTextPadding; // Horizontal offset of text from each edge of the separator + spacing on other axis. Generally small values. .y is recommended to be == FramePadding.y.
@@ -2365,7 +2368,7 @@ struct ImGuiStyle
// Functions
IMGUI_API ImGuiStyle();
IMGUI_API void ScaleAllSizes(float scale_factor); // Scale all spacing/padding/thickness values. Do not scale fonts.
IMGUI_API void ScaleAllSizes(float scale_factor); // Scale all spacing/padding/thickness values. Do not scale fonts. See comments in definition. Consider not calling this if your initial scale factor if <1.0.
// Obsolete names
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
@@ -2642,7 +2645,7 @@ struct ImGuiInputTextCallbackData
ImGuiInputTextFlags EventFlag; // One ImGuiInputTextFlags_Callback* // Read-only
ImGuiInputTextFlags Flags; // What user passed to InputText() // Read-only
void* UserData; // What user passed to InputText() // Read-only
ImGuiID ID; // Widget ID // Read-only
ImGuiID ID; // Widget ID // Read-only
// Arguments for the different callback events
// - During Resize callback, Buf will be same as your input buffer.
@@ -2656,9 +2659,9 @@ struct ImGuiInputTextCallbackData
char* Buf; // Text buffer // Read-write // [Resize] Can replace pointer / [Completion,History,Always] Only write to pointed data, don't replace the actual pointer!
int BufTextLen; // Text length (in bytes) // Read-write // [Resize,Completion,History,Always] Exclude zero-terminator storage. In C land: == strlen(some_text), in C++ land: string.length()
int BufSize; // Buffer size (in bytes) = capacity+1 // Read-only // [Resize,Completion,History,Always] Include zero-terminator storage. In C land: == ARRAYSIZE(my_char_array), in C++ land: string.capacity()+1
int CursorPos; // // Read-write // [Completion,History,Always]
int SelectionStart; // // Read-write // [Completion,History,Always] == to SelectionEnd when no selection
int SelectionEnd; // // Read-write // [Completion,History,Always]
int CursorPos; // // Read-write // [Completion,History,Always,CharFilter]
int SelectionStart; // // Read-write // [Completion,History,Always,CharFilter] == to SelectionEnd when no selection
int SelectionEnd; // // Read-write // [Completion,History,Always,CharFilter]
// Helper functions for text manipulation.
// Use those function to benefit from the CallbackResize behaviors. Calling those function reset the selection.
@@ -3166,12 +3169,6 @@ typedef unsigned short ImDrawIdx; // Default: 16-bit (for maximum compatibilit
typedef void (*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* cmd);
#endif
// Special Draw callback value to request renderer backend to reset the graphics/render state.
// The renderer backend needs to handle this special value, otherwise it will crash trying to call a function at this address.
// This is useful, for example, if you submitted callbacks which you know have altered the render state and you want it to be restored.
// Render state is not reset by default because they are many perfectly useful way of altering render state (e.g. changing shader/blending settings before an Image call).
#define ImDrawCallback_ResetRenderState (ImDrawCallback)(-8)
// Typically, 1 command = 1 GPU draw call (unless command is a callback)
// - VtxOffset: When 'io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset' is enabled,
// this fields allow us to render meshes larger than 64K vertices while keeping 16-bit indices.
@@ -3245,16 +3242,15 @@ struct ImDrawListSplitter
};
// Flags for ImDrawList functions
// (Legacy: bit 0 must always correspond to ImDrawFlags_Closed to be backward compatible with old API using a bool. Bits 1..3 must be unused)
enum ImDrawFlags_
{
ImDrawFlags_None = 0,
ImDrawFlags_Closed = 1 << 0, // PathStroke(), AddPolyline(): specify that shape should be closed (Important: this is always == 1 for legacy reason)
ImDrawFlags_RoundCornersTopLeft = 1 << 4, // AddRect(), AddRectFilled(), PathRect(): enable rounding top-left corner only (when rounding > 0.0f, we default to all corners). Was 0x01.
ImDrawFlags_RoundCornersTopRight = 1 << 5, // AddRect(), AddRectFilled(), PathRect(): enable rounding top-right corner only (when rounding > 0.0f, we default to all corners). Was 0x02.
ImDrawFlags_RoundCornersBottomLeft = 1 << 6, // AddRect(), AddRectFilled(), PathRect(): enable rounding bottom-left corner only (when rounding > 0.0f, we default to all corners). Was 0x04.
ImDrawFlags_RoundCornersBottomRight = 1 << 7, // AddRect(), AddRectFilled(), PathRect(): enable rounding bottom-right corner only (when rounding > 0.0f, we default to all corners). Wax 0x08.
ImDrawFlags_RoundCornersNone = 1 << 8, // AddRect(), AddRectFilled(), PathRect(): disable rounding on all corners (when rounding > 0.0f). This is NOT zero, NOT an implicit flag!
ImDrawFlags_Closed = 1 << 9, // PathStroke(), AddPolyline(): specify that shape should be closed (Important: this is always == 1 for legacy reason)
ImDrawFlags_RoundCornersTop = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight,
ImDrawFlags_RoundCornersBottom = ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersBottomRight,
ImDrawFlags_RoundCornersLeft = ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersTopLeft,
@@ -3262,6 +3258,7 @@ enum ImDrawFlags_
ImDrawFlags_RoundCornersAll = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight | ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersBottomRight,
ImDrawFlags_RoundCornersDefault_ = ImDrawFlags_RoundCornersAll, // Default to ALL corners if none of the _RoundCornersXX flags are specified.
ImDrawFlags_RoundCornersMask_ = ImDrawFlags_RoundCornersAll | ImDrawFlags_RoundCornersNone,
ImDrawFlags_InvalidMask_ = (ImDrawFlags)0x8000000F,
};
// Flags for ImDrawList instance. Those are set automatically by ImGui:: functions from ImGuiIO settings, and generally not manipulated directly.
@@ -3327,7 +3324,9 @@ struct ImDrawList
// In future versions we will use textures to provide cheaper and higher-quality circles.
// Use AddNgon() and AddNgonFilled() functions if you need to guarantee a specific number of sides.
IMGUI_API void AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float thickness = 1.0f);
IMGUI_API void AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding = 0.0f, ImDrawFlags flags = 0, float thickness = 1.0f); // a: upper-left, b: lower-right (== upper-left + size)
IMGUI_API void AddLineH(float min_x, float max_x, float y, ImU32 col, float thickness = 1.0f);
IMGUI_API void AddLineV(float x, float min_y, float max_y, ImU32 col, float thickness = 1.0f);
IMGUI_API void AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding = 0.0f, float thickness = 1.0f, ImDrawFlags flags = 0); // a: upper-left, b: lower-right (== upper-left + size)
IMGUI_API void AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding = 0.0f, ImDrawFlags flags = 0); // a: upper-left, b: lower-right (== upper-left + size)
IMGUI_API void AddRectFilledMultiColor(const ImVec2& p_min, const ImVec2& p_max, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left);
IMGUI_API void AddQuad(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness = 1.0f);
@@ -3348,7 +3347,7 @@ struct ImDrawList
// General polygon
// - Only simple polygons are supported by filling functions (no self-intersections, no holes).
// - Concave polygon fill is more expensive than convex one: it has O(N^2) complexity. Provided as a convenience for the user but not used by the main library.
IMGUI_API void AddPolyline(const ImVec2* points, int num_points, ImU32 col, ImDrawFlags flags, float thickness);
IMGUI_API void AddPolyline(const ImVec2* points, int num_points, ImU32 col, float thickness, ImDrawFlags flags = 0);
IMGUI_API void AddConvexPolyFilled(const ImVec2* points, int num_points, ImU32 col);
IMGUI_API void AddConcavePolyFilled(const ImVec2* points, int num_points, ImU32 col);
@@ -3368,7 +3367,7 @@ struct ImDrawList
inline void PathLineToMergeDuplicate(const ImVec2& pos) { if (_Path.Size == 0 || memcmp(&_Path.Data[_Path.Size - 1], &pos, 8) != 0) _Path.push_back(pos); }
inline void PathFillConvex(ImU32 col) { AddConvexPolyFilled(_Path.Data, _Path.Size, col); _Path.Size = 0; }
inline void PathFillConcave(ImU32 col) { AddConcavePolyFilled(_Path.Data, _Path.Size, col); _Path.Size = 0; }
inline void PathStroke(ImU32 col, ImDrawFlags flags = 0, float thickness = 1.0f) { AddPolyline(_Path.Data, _Path.Size, col, flags, thickness); _Path.Size = 0; }
inline void PathStroke(ImU32 col, float thickness = 1.0f, ImDrawFlags flags = 0) { AddPolyline(_Path.Data, _Path.Size, col, thickness, flags); _Path.Size = 0; }
IMGUI_API void PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments = 0);
IMGUI_API void PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12); // Use precomputed angles for a 12 steps circle
IMGUI_API void PathEllipticalArcTo(const ImVec2& center, const ImVec2& radius, float rot, float a_min, float a_max, int num_segments = 0); // Ellipse
@@ -3378,14 +3377,15 @@ struct ImDrawList
// Advanced: Draw Callbacks
// - May be used to alter render state (change sampler, blending, current shader). May be used to emit custom rendering commands (difficult to do correctly, but possible).
// - Use special ImDrawCallback_ResetRenderState callback to instruct backend to reset its render state to the default.
// - Use special GetPlatformIO().DrawCallback_ResetRenderState callback to instruct backend to reset its render state to the default.
// - See other standard callbacks in GetPlatformIO(), which may or not be supported by your backend.
// - Your rendering loop must check for 'UserCallback' in ImDrawCmd and call the function instead of rendering triangles. All standard backends are honoring this.
// - For some backends, the callback may access selected render-states exposed by the backend in a ImGui_ImplXXXX_RenderState structure pointed to by platform_io.Renderer_RenderState.
// - IMPORTANT: please be mindful of the different level of indirection between using size==0 (copying argument) and using size>0 (copying pointed data into a buffer).
// - If userdata_size == 0: we copy/store the 'userdata' argument as-is. It will be available unmodified in ImDrawCmd::UserCallbackData during render.
// - If userdata_size > 0, we copy/store 'userdata_size' bytes pointed to by 'userdata'. We store them in a buffer stored inside the drawlist. ImDrawCmd::UserCallbackData will point inside that buffer so you have to retrieve data from there. Your callback may need to use ImDrawCmd::UserCallbackDataSize if you expect dynamically-sized data.
// - Support for userdata_size > 0 was added in v1.91.4, October 2024. So earlier code always only allowed to copy/store a simple void*.
IMGUI_API void AddCallback(ImDrawCallback callback, void* userdata, size_t userdata_size = 0);
IMGUI_API void AddCallback(ImDrawCallback callback, void* userdata = NULL, size_t userdata_size = 0);
// Advanced: Miscellaneous
IMGUI_API void AddDrawCmd(); // This is useful if you need to forcefully create a new draw call (to allow for dependent rendering / blending). Otherwise primitives are merged into the same draw-call as much as possible
@@ -3415,8 +3415,15 @@ struct ImDrawList
// Obsolete names
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
inline void AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawFlags flags, float thickness) { AddRect(p_min, p_max, col, rounding, thickness, flags); } // OBSOLETED in 1.92.8: NEW FUNCTION SIGNATURE HAS 'thickness' AND 'flags' SWAPPED.
inline void AddPolyline(const ImVec2* points, int num_points, ImU32 col, ImDrawFlags flags, float thickness) { AddPolyline(points, num_points, col, thickness, flags); } // OBSOLETED in 1.92.8: NEW FUNCTION SIGNATURE HAS 'thickness' AND 'flags' SWAPPED.
inline void PathStroke(ImU32 col, ImDrawFlags flags, float thickness) { PathStroke(col, thickness, flags); } // OBSOLETED in 1.92.8: NEW FUNCTION SIGNATURE HAS 'thickness' AND 'flags' SWAPPED.
inline void PushTextureID(ImTextureRef tex_ref) { PushTexture(tex_ref); } // RENAMED in 1.92.0
inline void PopTextureID() { PopTexture(); } // RENAMED in 1.92.0
#else
IMGUI_API void AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding /*= 0.0f*/, ImDrawFlags flags /*= 0*/, float thickness /*= 1.0f*/) = delete;
IMGUI_API void AddPolyline(const ImVec2* points, int num_points, ImU32 col, ImDrawFlags flags, float thickness) = delete;
inline void PathStroke(ImU32 col, ImDrawFlags flags /*= 0*/, float thickness /*= 1.0f*/) = delete;
#endif
//inline void AddEllipse(const ImVec2& center, float radius_x, float radius_y, ImU32 col, float rot = 0.0f, int num_segments = 0, float thickness = 1.0f) { AddEllipse(center, ImVec2(radius_x, radius_y), col, rot, num_segments, thickness); } // OBSOLETED in 1.90.5 (Mar 2024)
//inline void AddEllipseFilled(const ImVec2& center, float radius_x, float radius_y, ImU32 col, float rot = 0.0f, int num_segments = 0) { AddEllipseFilled(center, ImVec2(radius_x, radius_y), col, rot, num_segments); } // OBSOLETED in 1.90.5 (Mar 2024)
@@ -3528,6 +3535,7 @@ struct ImTextureData
bool WantDestroyNextFrame; // rw - // [Internal] Queued to set ImTextureStatus_WantDestroy next frame. May still be used in the current frame.
// Functions
// - If GetPixels() functions asserts while being called by your render loop, it could be caused by calling ImFontAtlas::Clear() instead of ClearFonts()?
ImTextureData() { memset((void*)this, 0, sizeof(*this)); Status = ImTextureStatus_Destroyed; TexID = ImTextureID_Invalid; }
~ImTextureData() { DestroyPixels(); }
IMGUI_API void Create(ImTextureFormat format, int w, int h);
@@ -3684,13 +3692,13 @@ struct ImFontAtlas
IMGUI_API ImFont* AddFontFromMemoryCompressedBase85TTF(const char* compressed_font_data_base85, float size_pixels = 0.0f, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data_base85' still owned by caller. Compress with binary_to_compressed_c.cpp with -base85 parameter.
IMGUI_API void RemoveFont(ImFont* font);
IMGUI_API void Clear(); // Clear everything (input fonts, output glyphs/textures).
IMGUI_API void Clear(); // Clear everything (fonts + textures). Don't call mid-frame!
IMGUI_API void ClearFonts(); // Clear input+output font data/glyphs. You can call this mid-frame if you load new fonts afterwards!
IMGUI_API void CompactCache(); // Compact cached glyphs and texture.
IMGUI_API void SetFontLoader(const ImFontLoader* font_loader); // Change font loader at runtime.
// As we are transitioning toward a new font system, we expect to obsolete those soon:
IMGUI_API void ClearInputData(); // [OBSOLETE] Clear input data (all ImFontConfig structures including sizes, TTF data, glyph ranges, etc.) = all the data used to build the texture and fonts.
IMGUI_API void ClearFonts(); // [OBSOLETE] Clear input+output font data (same as ClearInputData() + glyphs storage, UV coordinates).
IMGUI_API void ClearTexData(); // [OBSOLETE] Clear CPU-side copy of the texture data. Saves RAM once the texture has been copied to graphics memory.
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
@@ -3862,6 +3870,7 @@ enum ImFontFlags_
ImFontFlags_NoLoadError = 1 << 1, // Disable throwing an error/assert when calling AddFontXXX() with missing file/data. Calling code is expected to check AddFontXXX() return value.
ImFontFlags_NoLoadGlyphs = 1 << 2, // [Internal] Disable loading new glyphs.
ImFontFlags_LockBakedSizes = 1 << 3, // [Internal] Disable loading new baked sizes, disable garbage collecting current ones. e.g. if you want to lock a font to a single size. Important: if you use this to preload given sizes, consider the possibility of multiple font density used on Retina display.
ImFontFlags_ImplicitRefSize = 1 << 4, // [Internal] Reference size was not set explicitly.
};
// Font runtime data and rendering
@@ -3876,7 +3885,7 @@ struct ImFont
ImFontAtlas* OwnerAtlas; // 4-8 // What we have been loaded into.
ImFontFlags Flags; // 4 // Font flags.
float CurrentRasterizerDensity; // Current rasterizer density. This is a varying state of the font.
float LineHeight; // 4 // Line Height
float LineHeight; // 4 // Line Height
// [Internal] Members: Cold ~24-52 bytes
// Conceptually Sources[] is the list of font sources merged to create this font.
@@ -4023,6 +4032,12 @@ struct ImGuiPlatformIO
// Written by some backends during ImGui_ImplXXXX_RenderDrawData() call to point backend_specific ImGui_ImplXXXX_RenderState* structure.
void* Renderer_RenderState;
// Standard draw callbacks provided by renderer backend.
ImDrawCallback DrawCallback_ResetRenderState; // Request to reset the graphics/render state.
ImDrawCallback DrawCallback_SetSamplerLinear; // Request backend to set texture sampling to Linear.
ImDrawCallback DrawCallback_SetSamplerNearest; // Request backend to set texture sampling to Nearest/Point.
//ImDrawCallback DrawCallback_SetSamplerCustom; // Request backend to set texture sampling using Backend Specific data.
//------------------------------------------------------------------
// Output
//------------------------------------------------------------------
@@ -4151,6 +4166,8 @@ namespace ImGui
//static inline void SetScrollPosHere() { SetScrollHere(); } // OBSOLETED in 1.42
}
#define ImDrawCallback_ResetRenderState (ImDrawCallback)(-8) // OBSOLETED in 1.92.8: Use ImGui::GetPlatformIO().DrawCallback_ResetRenderState
//-- OBSOLETED in 1.92.0: ImFontAtlasCustomRect becomes ImTextureRect
// - ImFontAtlasCustomRect::X,Y --> ImTextureRect::x,y
// - ImFontAtlasCustomRect::Width,Height --> ImTextureRect::w,h
+22 -6
View File
@@ -1,4 +1,4 @@
// dear imgui, v1.92.7
// dear imgui, v1.92.8
// (internal structures/api)
// You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility.
@@ -252,6 +252,9 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer
#define IMGUI_DEBUG_LOG_FONT(...) do { ImGuiContext* g2 = GImGui; if (g2 && g2->DebugLogFlags & ImGuiDebugLogFlags_EventFont) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) // Called from ImFontAtlas function which may operate without a context.
#define IMGUI_DEBUG_LOG_INPUTROUTING(...) do{if (g.DebugLogFlags & ImGuiDebugLogFlags_EventInputRouting)IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0)
// Debug options (also see ones on top of imgui.cpp)
//#define IMGUI_DEBUG_BOXSELECT
// Static Asserts
#define IM_STATIC_ASSERT(_COND) static_assert(_COND, "")
@@ -506,7 +509,8 @@ inline double ImRsqrt(double x) { return 1.0 / sqrt(x); }
template<typename T> T ImMin(T lhs, T rhs) { return lhs < rhs ? lhs : rhs; }
template<typename T> T ImMax(T lhs, T rhs) { return lhs >= rhs ? lhs : rhs; }
template<typename T> T ImClamp(T v, T mn, T mx) { return (v < mn) ? mn : (v > mx) ? mx : v; }
template<typename T> T ImLerp(T a, T b, float t) { return (T)(a + (b - a) * t); }
template<typename T> T ImLerp(double a, double b, float t) { return (T)(a + (b - a) * (double)t); }
template<typename T> T ImLerp(T a, T b, float t) { return (T)((float)a + (float)(b - a) * t); }
template<typename T> void ImSwap(T& a, T& b) { T tmp = a; a = b; b = tmp; }
template<typename T> T ImAddClampOverflow(T a, T b, T mn, T mx) { if (b < 0 && (a < mn - b)) return mn; if (b > 0 && (a > mx - b)) return mx; return a + b; }
template<typename T> T ImSubClampOverflow(T a, T b, T mn, T mx) { if (b > 0 && (a < mn + b)) return mn; if (b < 0 && (a > mx + b)) return mx; return a - b; }
@@ -603,6 +607,8 @@ struct IMGUI_API ImRect
bool Overlaps(const ImRect& r) const { return r.Min.y < Max.y && r.Max.y > Min.y && r.Min.x < Max.x && r.Max.x > Min.x; }
void Add(const ImVec2& p) { if (Min.x > p.x) Min.x = p.x; if (Min.y > p.y) Min.y = p.y; if (Max.x < p.x) Max.x = p.x; if (Max.y < p.y) Max.y = p.y; }
void Add(const ImRect& r) { if (Min.x > r.Min.x) Min.x = r.Min.x; if (Min.y > r.Min.y) Min.y = r.Min.y; if (Max.x < r.Max.x) Max.x = r.Max.x; if (Max.y < r.Max.y) Max.y = r.Max.y; }
void AddX(float x) { if (Min.x > x) Min.x = x; if (Max.x < x) Max.x = x; }
void AddY(float y) { if (Min.y > y) Min.y = y; if (Max.y < y) Max.y = y; }
void Expand(const float amount) { Min.x -= amount; Min.y -= amount; Max.x += amount; Max.y += amount; }
void Expand(const ImVec2& amount) { Min.x -= amount.x; Min.y -= amount.y; Max.x += amount.x; Max.y += amount.y; }
void Translate(const ImVec2& d) { Min.x += d.x; Min.y += d.y; Max.x += d.x; Max.y += d.y; }
@@ -999,6 +1005,7 @@ enum ImGuiItemStatusFlags_
ImGuiItemStatusFlags_HasClipRect = 1 << 9, // g.LastItemData.ClipRect is valid.
ImGuiItemStatusFlags_HasShortcut = 1 << 10, // g.LastItemData.Shortcut valid. Set by SetNextItemShortcut() -> ItemAdd().
//ImGuiItemStatusFlags_FocusedByTabbing = 1 << 8, // Removed IN 1.90.1 (Dec 2023). The trigger is part of g.NavActivateId. See commit 54c1bdeceb.
ImGuiItemStatusFlags_EditedInternal = 1 << 11, // Similar to ImGuiItemStatusFlags_Edited but bypassing ImGuiItemFlags_NoMarkEdited.
// Additional status + semantic for ImGuiTestEngine
#ifdef IMGUI_ENABLE_TEST_ENGINE
@@ -1204,6 +1211,7 @@ struct IMGUI_API ImGuiMenuColumns
};
// Internal temporary state for deactivating InputText() instances.
// Store as part of ImGuiDeactivatedItemData?
struct IMGUI_API ImGuiInputTextDeactivatedState
{
ImGuiID ID; // widget id owning the text state (which just got deactivated)
@@ -1449,6 +1457,7 @@ struct ImGuiPtrOrIndex
};
// Data used by IsItemDeactivated()/IsItemDeactivatedAfterEdit() functions
// Also see ImGuiInputTextDeactivatedState which is an extension for this for InputText()
struct ImGuiDeactivatedItemData
{
ImGuiID ID;
@@ -1890,6 +1899,7 @@ struct ImGuiBoxSelectState
// Temporary/Transient data
bool UnclipMode; // (Temp/Transient, here in hot area). Set/cleared by the BeginMultiSelect()/EndMultiSelect() owning active box-select.
ImRect UnclipRect; // Rectangle where ItemAdd() clipping may be temporarily disabled. Need support by multi-select supporting widgets.
ImRect UnclipRects[2]; // Per-axis versions.
ImRect BoxSelectRectPrev; // Selection rectangle in absolute coordinates (derived every frame from BoxSelectStartPosRel and MousePos)
ImRect BoxSelectRectCurr;
@@ -1912,7 +1922,8 @@ struct IMGUI_API ImGuiMultiSelectTempData
ImGuiMultiSelectFlags Flags;
ImVec2 ScopeRectMin;
ImVec2 BackupCursorMaxPos;
ImGuiSelectionUserData LastSubmittedItem; // Copy of last submitted item data, used to merge output ranges.
//ImGuiSelectionUserData CurrSubmittedItem; // Copy of last submitted item data, used to merge output ranges.
//ImGuiSelectionUserData PrevSubmittedItem; // Copy of previous submitted item data, used to merge output ranges.
ImGuiID BoxSelectId;
ImGuiKeyChord KeyMods;
ImS8 LoopRequestSetAll; // -1: no operation, 0: clear all, 1: select all.
@@ -2213,6 +2224,7 @@ struct ImGuiContext
float CurrentDpiScale; // Current window/viewport DpiScale == CurrentViewport->DpiScale
ImDrawListSharedData DrawListSharedData;
ImGuiID WithinEndChildID; // Set within EndChild()
ImGuiID WithinEndPopupID; // Set within EndPopup()
void* TestEngine; // Test engine user data
// Inputs
@@ -3205,7 +3217,7 @@ namespace ImGui
IMGUI_API void SetNextWindowRefreshPolicy(ImGuiWindowRefreshFlags flags);
// Fonts, drawing
IMGUI_API void RegisterUserTexture(ImTextureData* tex); // Register external texture. EXPERIMENTAL: DO NOT USE YET.
IMGUI_API void RegisterUserTexture(ImTextureData* tex); // Register external texture. EXPERIMENTAL.
IMGUI_API void UnregisterUserTexture(ImTextureData* tex);
IMGUI_API void RegisterFontAtlas(ImFontAtlas* atlas);
IMGUI_API void UnregisterFontAtlas(ImFontAtlas* atlas);
@@ -3320,6 +3332,7 @@ namespace ImGui
// Childs
IMGUI_API bool BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, ImGuiChildFlags child_flags, ImGuiWindowFlags window_flags);
IMGUI_API ImGuiWindow* FindFrontMostVisibleChildWindow(ImGuiWindow* window);
// Popups, Modals
IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_window_flags);
@@ -3425,7 +3438,7 @@ namespace ImGui
IMGUI_API ImGuiID GetKeyOwner(ImGuiKey key);
IMGUI_API void SetKeyOwner(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags = 0);
IMGUI_API void SetKeyOwnersForKeyChord(ImGuiKeyChord key, ImGuiID owner_id, ImGuiInputFlags flags = 0);
IMGUI_API void SetItemKeyOwner(ImGuiKey key, ImGuiInputFlags flags); // Set key owner to last item if it is hovered or active. Equivalent to 'if (IsItemHovered() || IsItemActive()) { SetKeyOwner(key, GetItemID());'.
IMGUI_API bool SetItemKeyOwner(ImGuiKey key, ImGuiInputFlags flags);
IMGUI_API bool TestKeyOwner(ImGuiKey key, ImGuiID owner_id); // Test that key is either not owned, either owned by 'owner_id'
inline ImGuiKeyOwnerData* GetKeyOwnerData(ImGuiContext* ctx, ImGuiKey key) { if (key & ImGuiMod_Mask_) key = ConvertSingleModFlagToKey(key); IM_ASSERT(IsNamedKey(key)); return &ctx->KeysOwnerData[key - ImGuiKey_NamedKey_BEGIN]; }
@@ -3473,6 +3486,7 @@ namespace ImGui
// We don't use the ID Stack for this as it is common to want them separate.
IMGUI_API void PushFocusScope(ImGuiID id);
IMGUI_API void PopFocusScope();
IMGUI_API bool IsInNavFocusRoute(ImGuiID focus_scope_id);
inline ImGuiID GetCurrentFocusScope() { ImGuiContext& g = *GImGui; return g.CurrentFocusScopeId; } // Focus scope we are outputting into, set by PushFocusScope()
// Drag and Drop
@@ -3482,7 +3496,7 @@ namespace ImGui
IMGUI_API void ClearDragDrop();
IMGUI_API bool IsDragDropPayloadBeingAccepted();
IMGUI_API void RenderDragDropTargetRectForItem(const ImRect& bb);
IMGUI_API void RenderDragDropTargetRectEx(ImDrawList* draw_list, const ImRect& bb);
IMGUI_API void RenderDragDropTargetRectEx(ImDrawList* draw_list, const ImRect& bb, float rounding);
// Typing-Select API
// (provide Windows Explorer style "select items by typing partial name" + "cycle through items by typing same letter" feature)
@@ -3539,6 +3553,7 @@ namespace ImGui
IMGUI_API void TableUpdateLayout(ImGuiTable* table);
IMGUI_API void TableUpdateBorders(ImGuiTable* table);
IMGUI_API void TableUpdateColumnsWeightFromWidth(ImGuiTable* table);
IMGUI_API void TableApplyExternalUnclipRect(ImGuiTable* table, ImRect& rect);
IMGUI_API void TableDrawBorders(ImGuiTable* table);
IMGUI_API void TableDrawDefaultContextMenu(ImGuiTable* table, ImGuiTableFlags flags_for_section_to_display);
IMGUI_API bool TableBeginContextMenuPopup(ImGuiTable* table);
@@ -3964,6 +3979,7 @@ IMGUI_API void ImFontAtlasTextureBlockFill(ImTextureData* dst_tex,
IMGUI_API void ImFontAtlasTextureBlockCopy(ImTextureData* src_tex, int src_x, int src_y, ImTextureData* dst_tex, int dst_x, int dst_y, int w, int h);
IMGUI_API void ImFontAtlasTextureBlockQueueUpload(ImFontAtlas* atlas, ImTextureData* tex, int x, int y, int w, int h);
IMGUI_API void ImTextureDataQueueUpload(ImTextureData* tex, int x, int y, int w, int h);
IMGUI_API int ImTextureDataGetFormatBytesPerPixel(ImTextureFormat format);
IMGUI_API const char* ImTextureDataGetStatusName(ImTextureStatus status);
IMGUI_API const char* ImTextureDataGetFormatName(ImTextureFormat format);
+171 -80
View File
@@ -1,4 +1,4 @@
// dear imgui, v1.92.7
// dear imgui, v1.92.8
// (main code and documentation)
// Help:
@@ -395,6 +395,31 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures:
When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files.
You can read releases logs https://github.com/ocornut/imgui/releases for more details.
- 2026/05/07 (1.92.8) - DrawList: swapped the last two arguments of AddRect(), AddPolyline(), PathStroke().
- Before: void ImDrawList::AddRect(ImVec2 p_min, ImVec2 p_max, ImU32 col, float rounding = 0.0f, ImDrawFlags flags = 0, float thickness = 1.0f);
- After: void ImDrawList::AddRect(ImVec2 p_min, ImVec2 p_max, ImU32 col, float rounding = 0.0f, float thickness = 1.0f, ImDrawFlags flags = 0);
- Before: void ImDrawList::AddPolyline(const ImVec2* points, int num_points, ImU32 col, ImDrawFlags flags, float thickness);
- After: void ImDrawList::AddPolyline(const ImVec2* points, int num_points, ImU32 col, float thickness, ImDrawFlags flags = 0);
- Before: void ImDrawList::PathStroke(ImU32 col, ImDrawFlags flags = 0, float thickness = 1.0f);
- After: void ImDrawList::PathStroke(ImU32 col, float thickness = 1.0f, ImDrawFlags flags = 0);
Added inline redirection functions when IMGUI_DISABLE_OBSOLETE_FUNCTIONS is off.
Marked the old functions are =delete when IMGUI_DISABLE_OBSOLETE_FUNCTIONS is on, to allow for better type-checking.
Effectively the typical call site is changing from:
- Before: window->DrawList->AddRect(p_min, p_max, color, rounding, ImDrawFlags_None, border_size);
- After: window->DrawList->AddRect(p_min, p_max, color, rounding, border_size);
Notes:
- Users of C++ and other languages with type-checking will be notified at compile-time of any mistakes.
- Users of high-level bindings or languages with no type-checking will be notified at runtime via an assert for invalid flags value.
If you are a binding maintainer consider doing something to facilitate transition or error detection.
- This is perhaps the worst breaking change in our history :( but it makes ImDrawList function signatures consistent.
As we are aiming to add flags and features to variety of ImDrawList functions, that consistency becomes more important.
The new order is also more convenient as `flags` are less frequently used than `thickness` in real code.
- As a general policy in Dear ImGui, all our flags default to 0 so ImDrawFlags_None was likely written 0 in some call sites.
- Consider adding `#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS` in your imconfig.h, even temporarily, to clean up legacy code.
- 2026/04/23 (1.92.8) - DrawList: obsoleted `ImDrawCallback_ResetRenderState` in favor of using `ImGui::GetPlatformIO().DrawCallback_ResetRenderState`, which is part of our new standard draw callbacks. (#9378)
- 2026/04/22 (1.92.8) - Backends: Vulkan: redesigned to use separate ImageView + Sampler instead of Combined Image Sampler.
- When registering custom textures: changed ImGui_ImplVulkan_AddTexture() signature to remove Sampler.
- When creating your own descriptor pool (instead of letting backend creates its own): need at least IMGUI_IMPL_VULKAN_MINIMUM_SAMPLED_IMAGE_POOL_SIZE descriptors of type VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE + IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE descriptors of type VK_DESCRIPTOR_TYPE_SAMPLER.
- 2026/03/19 (1.92.7) - MultiSelect: renamed ImGuiMultiSelectFlags_SelectOnClick to ImGuiMultiSelectFlags_SelectOnAuto.
- 2026/02/26 (1.92.7) - Separator: fixed a legacy quirk where Separator() was submitting a zero-height item for layout purpose, even though it draws a 1-pixel separator.
The fix could affect code e.g. computing height from multiple widgets in order to allocate vertical space for a footer or multi-line status bar. (#2657, #9263)
@@ -1495,7 +1520,7 @@ ImGuiStyle::ImGuiStyle()
TabRounding = 5.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs.
TabBorderSize = 0.0f; // Thickness of border around tabs.
TabMinWidthBase = 1.0f; // Minimum tab width, to make tabs larger than their contents. TabBar buttons are not affected.
TabMinWidthShrink = 80.0f; // Minimum tab width after shrinking, when using ImGuiTabBarFlags_FittingPolicyMixed policy.
TabMinWidthShrink = 80.0f; // Minimum tab width after shrinking, when using ImGuiTabBarFlags_FittingPolicyMixed policy. FLT_MAX: never shrink, will behave like ImGuiTabBarFlags_FittingPolicyScroll.
TabCloseButtonMinWidthSelected = -1.0f; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width.
TabCloseButtonMinWidthUnselected = 0.0f; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width. FLT_MAX: never show close button when unselected.
TabBarBorderSize = 1.0f; // Thickness of tab-bar separator, which takes on the tab active color to denote focus.
@@ -1542,6 +1567,7 @@ ImGuiStyle::ImGuiStyle()
// Scale all spacing/padding/thickness values. Do not scale fonts.
// Consider not calling this if your initial scale factor if <1.0.
// Important: This operation is lossy because we round all sizes to integer. If you need to change your scale multiples, call this over a freshly initialized ImGuiStyle structure rather than scaling multiple times.
void ImGuiStyle::ScaleAllSizes(float scale_factor)
{
@@ -3387,9 +3413,6 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper)
if (clipper->ItemsHeight <= 0.0f)
{
IM_ASSERT(data->StepNo == 1);
if (table)
IM_ASSERT(table->RowPosY1 == clipper->StartPosY && table->RowPosY2 == window->DC.CursorPos.y);
bool affected_by_floating_point_precision = ImIsFloatAboveGuaranteedIntegerPrecision((float)clipper->StartPosY) || ImIsFloatAboveGuaranteedIntegerPrecision(window->DC.CursorPos.y);
if (affected_by_floating_point_precision)
{
@@ -3403,7 +3426,14 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper)
}
if (clipper->ItemsHeight == 0.0f && clipper->ItemsCount == INT_MAX) // Accept that no item have been submitted if in indeterminate mode.
return false;
IM_ASSERT(clipper->ItemsHeight > 0.0f && "Unable to calculate item height! First item hasn't moved the cursor vertically!");
if (clipper->ItemsHeight <= 0.0f)
{
IM_ASSERT_USER_ERROR(clipper->ItemsHeight > 0.0f, "ImGuiListClipper: Failed to calculate item height! First item hasn't been submitted by user code, or has not moved the cursor vertically!");
return false;
}
if (table)
IM_ASSERT(table->RowPosY1 == clipper->StartPosY && table->RowPosY2 == window->DC.CursorPos.y);
calc_clipping = true; // If item height had to be calculated, calculate clipping afterwards.
}
@@ -3449,12 +3479,14 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper)
// FIXME: Selectable() use of half-ItemSpacing isn't consistent in matter of layout, as ItemAdd(bb) stray above ItemSize()'s CursorPos.
// RangeSelect's BoxSelect relies on comparing overlap of previous and current rectangle and is sensitive to that.
// As a workaround we currently half ItemSpacing worth on each side.
min_y -= g.Style.ItemSpacing.y;
max_y += g.Style.ItemSpacing.y;
float pad_y = g.Style.ItemSpacing.y;
min_y -= pad_y;
max_y += pad_y;
// Box-select on 2D area requires different clipping.
// (best adding pad_y here than in BeginBoxSelect() as we are closer to current state)
if (bs->UnclipMode)
data->Ranges.push_back(ImGuiListClipperRange::FromPositions(bs->UnclipRect.Min.y, bs->UnclipRect.Max.y, 0, 0));
data->Ranges.push_back(ImGuiListClipperRange::FromPositions(bs->UnclipRect.Min.y - pad_y, bs->UnclipRect.Max.y + pad_y, 0, 0));
}
// Add main visible range
@@ -3648,6 +3680,7 @@ static const ImGuiStyleVarInfo GStyleVarsInfo[] =
{ 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TableAngledHeadersTextAlign)},// ImGuiStyleVar_TableAngledHeadersTextAlign
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TreeLinesSize)}, // ImGuiStyleVar_TreeLinesSize
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TreeLinesRounding)}, // ImGuiStyleVar_TreeLinesRounding
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, DragDropTargetRounding)}, // ImGuiStyleVar_DragDropTargetRounding
{ 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign
{ 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SeparatorSize)}, // ImGuiStyleVar_SeparatorSize
@@ -3748,6 +3781,7 @@ const char* ImGui::GetStyleColorName(ImGuiCol idx)
case ImGuiCol_ScrollbarGrabHovered: return "ScrollbarGrabHovered";
case ImGuiCol_ScrollbarGrabActive: return "ScrollbarGrabActive";
case ImGuiCol_CheckMark: return "CheckMark";
case ImGuiCol_CheckboxSelectedBg: return "CheckboxSelectedBg";
case ImGuiCol_SliderGrab: return "SliderGrab";
case ImGuiCol_SliderGrabActive: return "SliderGrabActive";
case ImGuiCol_Button: return "Button";
@@ -3828,7 +3862,7 @@ void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool
else
{
if (!text_end)
text_end = text + ImStrlen(text); // FIXME-OPT
text_end = text + ImStrlen(text); // FIXME-OPT (not reached by our internal calls)
text_display_end = text_end;
}
@@ -3846,7 +3880,7 @@ void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end
ImGuiWindow* window = g.CurrentWindow;
if (!text_end)
text_end = text + ImStrlen(text); // FIXME-OPT
text_end = text + ImStrlen(text); // FIXME-OPT (not reached by our internal calls)
if (text != text_end)
{
@@ -3915,8 +3949,8 @@ void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, con
text_end_full = FindRenderedTextEnd(text);
const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_end_full, false, 0.0f);
//draw_list->AddLine(ImVec2(pos_max.x, pos_min.y - 4), ImVec2(pos_max.x, pos_max.y + 6), IM_COL32(0, 0, 255, 255));
//draw_list->AddLine(ImVec2(ellipsis_max_x, pos_min.y - 2), ImVec2(ellipsis_max_x, pos_max.y + 3), IM_COL32(0, 255, 0, 255));
//draw_list->AddLineV(pos_max.x, pos_min.y - 4, pos_max.y + 6, IM_COL32(0, 0, 255, 255));
//draw_list->AddLineV(ellipsis_max_x, pos_min.y - 2, pos_max.y + 3, IM_COL32(0, 255, 0, 255));
// FIXME: We could technically remove (last_glyph->AdvanceX - last_glyph->X1) from text_size.x here and save a few pixels.
if (text_size.x > pos_max.x - pos_min.x)
@@ -3961,8 +3995,8 @@ void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool borders
const float border_size = g.Style.FrameBorderSize;
if (borders && border_size > 0.0f)
{
window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, 0, border_size);
window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, 0, border_size);
window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, border_size);
window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, border_size);
}
}
@@ -3973,8 +4007,8 @@ void ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding)
const float border_size = g.Style.FrameBorderSize;
if (border_size > 0.0f)
{
window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, 0, border_size);
window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, 0, border_size);
window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, border_size);
window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, border_size);
}
}
@@ -4009,7 +4043,7 @@ void ImGui::RenderNavCursor(const ImRect& bb, ImGuiID id, ImGuiNavRenderCursorFl
const float thickness = 2.0f;
if (flags & ImGuiNavRenderCursorFlags_Compact)
{
window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavCursor), rounding, 0, thickness);
window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavCursor), rounding, thickness);
}
else
{
@@ -4018,7 +4052,7 @@ void ImGui::RenderNavCursor(const ImRect& bb, ImGuiID id, ImGuiNavRenderCursorFl
bool fully_visible = window->ClipRect.Contains(display_rect);
if (!fully_visible)
window->DrawList->PushClipRect(display_rect.Min, display_rect.Max);
window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavCursor), rounding, 0, thickness);
window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavCursor), rounding, thickness);
if (!fully_visible)
window->DrawList->PopClipRect();
}
@@ -4052,7 +4086,7 @@ void ImGui::RenderMouseCursor(ImVec2 base_pos, float base_scale, ImGuiMouseCurso
float a_min = ImFmod((float)g.Time * 5.0f, 2.0f * IM_PI);
float a_max = a_min + IM_PI * 1.65f;
draw_list->PathArcTo(pos + ImVec2(14, -1) * scale, 6.0f * scale, a_min, a_max);
draw_list->PathStroke(col_fill, ImDrawFlags_None, 3.0f * scale);
draw_list->PathStroke(col_fill, 3.0f * scale);
}
draw_list->PopTexture();
}
@@ -4150,7 +4184,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas)
IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)();
if (shared_font_atlas == NULL)
IO.Fonts->OwnerContext = this;
WithinEndChildID = 0;
WithinEndChildID = WithinEndPopupID = 0;
TestEngine = NULL;
InputEventsNextMouseSource = ImGuiMouseSource_Mouse;
@@ -4686,7 +4720,8 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
g.ActiveIdIsJustActivated = (g.ActiveId != id);
if (g.ActiveIdIsJustActivated)
{
IMGUI_DEBUG_LOG_ACTIVEID("SetActiveID() old:0x%08X (window \"%s\") -> new:0x%08X (window \"%s\")\n", g.ActiveId, g.ActiveIdWindow ? g.ActiveIdWindow->Name : "", id, window ? window->Name : "");
IMGUI_DEBUG_LOG_ACTIVEID("SetActiveID() 0x%08X in \"%s\"%*s(previously 0x%08X in \"%s\")\n", id, window ? window->Name : "",
ImMax(0, 20 - (int)(window ? strlen(window->Name) : 0)), "", g.ActiveId, g.ActiveIdWindow ? g.ActiveIdWindow->Name : "");
g.ActiveIdTimer = 0.0f;
g.ActiveIdHasBeenPressedBefore = false;
g.ActiveIdHasBeenEditedBefore = false;
@@ -4742,8 +4777,12 @@ void ImGui::MarkItemEdited(ImGuiID id)
// This marking is to be able to provide info for IsItemDeactivatedAfterEdit().
// ActiveId might have been released by the time we call this (as in the typical press/release button behavior) but still need to fill the data.
ImGuiContext& g = *GImGui;
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_EditedInternal;
if (g.LastItemData.ItemFlags & ImGuiItemFlags_NoMarkEdited)
return;
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Edited;
if (g.ActiveId == id || g.ActiveId == 0)
{
// FIXME: Can't we fully rely on LastItemData yet?
@@ -4757,9 +4796,6 @@ void ImGui::MarkItemEdited(ImGuiID id)
// We accept 'ActiveIdPreviousFrame == id' for InputText() returning an edit after it has been taken ActiveId away (#4714)
// FIXME: This assert is getting a bit meaningless over time. It helped detect some unusual use cases but eventually it is becoming an unnecessary restriction.
IM_ASSERT(g.DragDropActive || g.ActiveId == id || g.ActiveId == 0 || g.ActiveIdPreviousFrame == id || g.NavJustMovedToId || (g.CurrentMultiSelect != NULL && g.BoxSelectState.IsActive));
//IM_ASSERT(g.CurrentWindow->DC.LastItemId == id);
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Edited;
}
bool ImGui::IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags)
@@ -4924,7 +4960,7 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flag
{
g.HoveredIdPreviousFrameItemCount++;
if (g.DebugDrawIdConflictsId == id)
window->DrawList->AddRect(bb.Min - ImVec2(1,1), bb.Max + ImVec2(1,1), IM_COL32(255, 0, 0, 255), 0.0f, ImDrawFlags_None, 2.0f);
window->DrawList->AddRect(bb.Min - ImVec2(1,1), bb.Max + ImVec2(1,1), IM_COL32(255, 0, 0, 255), 0.0f, 2.0f);
}
#endif
@@ -5721,7 +5757,7 @@ void ImGui::NewFrame()
g.CurrentWindowStack.resize(0);
g.BeginPopupStack.resize(0);
g.ItemFlagsStack.resize(0);
g.ItemFlagsStack.push_back(ImGuiItemFlags_AutoClosePopups); // Default flags
g.ItemFlagsStack.push_back(ImGuiItemFlags_Default_); // Default flags
g.CurrentItemFlags = g.ItemFlagsStack.back();
g.GroupStack.resize(0);
@@ -5956,7 +5992,7 @@ static void ImGui::RenderDimmedBackgrounds()
if (window->DrawList->CmdBuffer.Size == 0)
window->DrawList->AddDrawCmd();
window->DrawList->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size);
window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), window->WindowRounding, 0, 3.0f); // FIXME-DPI
window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), window->WindowRounding, 3.0f); // FIXME-DPI
window->DrawList->PopClipRect();
}
}
@@ -6432,7 +6468,7 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, I
window_flags |= ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_NoTitleBar;
window_flags |= (parent_window->Flags & ImGuiWindowFlags_NoMove); // Inherit the NoMove flag
if (child_flags & (ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize))
window_flags |= ImGuiWindowFlags_AlwaysAutoResize;
window_flags |= ImGuiWindowFlags_AlwaysAutoResize; // FIXME: Would be sane to not make single-axis flag set this. (#9355)
if ((child_flags & (ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY)) == 0)
window_flags |= ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings;
@@ -6581,6 +6617,14 @@ void ImGui::EndChild()
g.LogLinePosY = -FLT_MAX; // To enforce a carriage return
}
ImGuiWindow* ImGui::FindFrontMostVisibleChildWindow(ImGuiWindow* window)
{
for (int n = window->DC.ChildWindows.Size - 1; n >= 0; n--)
if (IsWindowActiveAndVisible(window->DC.ChildWindows[n]))
return FindFrontMostVisibleChildWindow(window->DC.ChildWindows[n]);
return window;
}
static void SetWindowConditionAllowFlags(ImGuiWindow* window, ImGuiCond flags, bool enabled)
{
window->SetWindowPosAllowFlags = enabled ? (window->SetWindowPosAllowFlags | flags) : (window->SetWindowPosAllowFlags & ~flags);
@@ -6744,8 +6788,8 @@ static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_cont
const float decoration_h_without_scrollbars = window->DecoOuterSizeY1 + window->DecoOuterSizeY2 - window->ScrollbarSizes.y;
ImVec2 size_pad = window->WindowPadding * 2.0f;
ImVec2 size_desired;
size_desired[ImGuiAxis_X] = (axis_mask & 1) ? size_contents.x + size_pad.x + decoration_w_without_scrollbars : window->Size.x;
size_desired[ImGuiAxis_Y] = (axis_mask & 2) ? size_contents.y + size_pad.y + decoration_h_without_scrollbars : window->Size.y;
size_desired.x = (axis_mask & 1) ? size_contents.x + size_pad.x + decoration_w_without_scrollbars : window->Size.x;
size_desired.y = (axis_mask & 2) ? size_contents.y + size_pad.y + decoration_h_without_scrollbars : window->Size.y;
// Determine maximum window size
// Child windows are laid within their parent (unless they are also popups/menus) and thus have no restriction
@@ -6764,8 +6808,10 @@ static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_cont
// When the window cannot fit all contents (either because of constraints, either because screen is too small),
// we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than ViewportSize-WindowPadding.
ImVec2 size_auto_fit_after_constraint = CalcWindowSizeAfterConstraint(window, size_auto_fit);
bool will_have_scrollbar_x = (size_auto_fit_after_constraint.x - size_pad.x - decoration_w_without_scrollbars < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar);
bool will_have_scrollbar_y = (size_auto_fit_after_constraint.y - size_pad.y - decoration_h_without_scrollbars < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysVerticalScrollbar);
float size_contents_for_scrollbar_x = (axis_mask & 1) ? size_contents.x : window->ContentSize.x; // See #9352. In theory this should use same logic as `window->ScrollbarY = ...` codepath in Begin(). Needs some plumbling.
float size_contents_for_scrollbar_y = (axis_mask & 2) ? size_contents.y : window->ContentSize.y;
bool will_have_scrollbar_x = (size_auto_fit_after_constraint.x < size_contents_for_scrollbar_x + size_pad.x + decoration_w_without_scrollbars && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar);
bool will_have_scrollbar_y = (size_auto_fit_after_constraint.y < size_contents_for_scrollbar_y + size_pad.y + decoration_h_without_scrollbars && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysVerticalScrollbar);
if (will_have_scrollbar_x)
size_auto_fit.y += style.ScrollbarSize;
if (will_have_scrollbar_y)
@@ -7106,7 +7152,7 @@ static void RenderWindowOuterSingleBorder(ImGuiWindow* window, int border_n, ImU
const ImRect border_r = GetResizeBorderRect(window, border_n, rounding, 0.0f);
window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.SegmentN1) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle - IM_PI * 0.25f, def.OuterAngle);
window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.SegmentN2) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle, def.OuterAngle + IM_PI * 0.25f);
window->DrawList->PathStroke(border_col, ImDrawFlags_None, border_size);
window->DrawList->PathStroke(border_col, border_size);
}
static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window)
@@ -7115,7 +7161,7 @@ static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window)
const float border_size = window->WindowBorderSize;
const ImU32 border_col = GetColorU32(ImGuiCol_Border);
if (border_size > 0.0f && (window->Flags & ImGuiWindowFlags_NoBackground) == 0)
window->DrawList->AddRect(window->Pos, window->Pos + window->Size, border_col, window->WindowRounding, 0, window->WindowBorderSize);
window->DrawList->AddRect(window->Pos, window->Pos + window->Size, border_col, window->WindowRounding, window->WindowBorderSize);
else if (border_size > 0.0f)
{
if (window->ChildFlags & ImGuiChildFlags_ResizeX) // Similar code as 'resize_border_mask' computation in UpdateWindowManualResize() but we specifically only always draw explicit child resize border.
@@ -7132,7 +7178,7 @@ static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window)
if (g.Style.FrameBorderSize > 0 && !(window->Flags & ImGuiWindowFlags_NoTitleBar))
{
float y = window->Pos.y + window->TitleBarHeight - 1;
window->DrawList->AddLine(ImVec2(window->Pos.x + border_size * 0.5f, y), ImVec2(window->Pos.x + window->Size.x - border_size * 0.5f, y), border_col, g.Style.FrameBorderSize);
window->DrawList->AddLineH(window->Pos.x + border_size * 0.5f, window->Pos.x + window->Size.x - border_size * 0.5f, y, border_col, g.Style.FrameBorderSize);
}
}
@@ -7180,7 +7226,7 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar
if (bg_col & IM_COL32_A_MASK)
{
ImRect bg_rect(window->Pos + ImVec2(0, window->TitleBarHeight), window->Pos + window->Size);
ImDrawFlags bg_rounding_flags = (flags & ImGuiWindowFlags_NoTitleBar) ? 0 : ImDrawFlags_RoundCornersBottom;
ImDrawFlags bg_rounding_flags = (flags & ImGuiWindowFlags_NoTitleBar) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersBottom;
ImDrawList* bg_draw_list = window->DrawList;
bg_draw_list->AddRectFilled(bg_rect.Min, bg_rect.Max, bg_col, window_rounding, bg_rounding_flags);
}
@@ -7200,7 +7246,7 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar
menu_bar_rect.ClipWith(window->Rect()); // Soft clipping, in particular child window don't have minimum size covering the menu bar so this is useful for them.
window->DrawList->AddRectFilled(menu_bar_rect.Min, menu_bar_rect.Max, GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawFlags_RoundCornersTop);
if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y)
window->DrawList->AddLine(menu_bar_rect.GetBL() + ImVec2(window_border_size * 0.5f, 0.0f), menu_bar_rect.GetBR() - ImVec2(window_border_size * 0.5f, 0.0f), GetColorU32(ImGuiCol_Border), style.FrameBorderSize);
window->DrawList->AddLineH(menu_bar_rect.Min.x + window_border_size * 0.5f, menu_bar_rect.Max.x - window_border_size * 0.5f, menu_bar_rect.Max.y, GetColorU32(ImGuiCol_Border), style.FrameBorderSize);
}
// Scrollbars
@@ -7844,12 +7890,12 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
ImVec2 avail_size_from_current_frame = ImVec2(window->SizeFull.x, window->SizeFull.y - (window->DecoOuterSizeY1 + window->DecoOuterSizeY2));
ImVec2 avail_size_from_last_frame = window->InnerRect.GetSize() + scrollbar_sizes_from_last_frame;
ImVec2 needed_size_from_last_frame = window_just_created ? ImVec2(0, 0) : window->ContentSize + window->WindowPadding * 2.0f;
float size_x_for_scrollbars = use_current_size_for_scrollbar_x ? avail_size_from_current_frame.x : avail_size_from_last_frame.x;
float size_y_for_scrollbars = use_current_size_for_scrollbar_y ? avail_size_from_current_frame.y : avail_size_from_last_frame.y;
float size_for_scrollbars_x = use_current_size_for_scrollbar_x ? avail_size_from_current_frame.x : avail_size_from_last_frame.x;
float size_for_scrollbars_y = use_current_size_for_scrollbar_y ? avail_size_from_current_frame.y : avail_size_from_last_frame.y;
bool scrollbar_x_prev = window->ScrollbarX;
//bool scrollbar_y_from_last_frame = window->ScrollbarY; // FIXME: May want to use that in the ScrollbarX expression? How many pros vs cons?
window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar));
window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((needed_size_from_last_frame.x > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar));
window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((needed_size_from_last_frame.y > size_for_scrollbars_y) && !(flags & ImGuiWindowFlags_NoScrollbar));
window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((needed_size_from_last_frame.x > size_for_scrollbars_x - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar));
// Track when ScrollbarX visibility keeps toggling, which is a sign of a feedback loop, and stabilize by enforcing visibility (#3285, #8488)
// (Feedback loops of this sort can manifest in various situations, but combining horizontal + vertical scrollbar + using a clipper with varying width items is one frequent cause.
@@ -7864,7 +7910,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->ScrollbarXStabilizeEnabled = scrollbar_x_stabilize;
if (window->ScrollbarX && !window->ScrollbarY)
window->ScrollbarY = (needed_size_from_last_frame.y > size_y_for_scrollbars - style.ScrollbarSize) && !(flags & ImGuiWindowFlags_NoScrollbar);
window->ScrollbarY = (needed_size_from_last_frame.y > size_for_scrollbars_y - style.ScrollbarSize) && !(flags & ImGuiWindowFlags_NoScrollbar);
window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f);
// Amend the partially filled window->DecorationXXX values.
@@ -8029,9 +8075,14 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->DC.LayoutType = ImGuiLayoutType_Vertical;
window->DC.ParentLayoutType = parent_window ? parent_window->DC.LayoutType : ImGuiLayoutType_Vertical;
// Default item width. Make it proportional to window size if window manually resizes
const bool is_resizable_window = (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize));
if (is_resizable_window)
// Default item width. Make it proportional to window size if window can be manually resized.
// (we cannot use AutoFitFramesX/AutoFitFramesY which is a temporary state)
bool is_resizable_width;
if (flags & ImGuiWindowFlags_ChildWindow)
is_resizable_width = (window->Size.x > 0.0f) && !(window->ChildFlags & (ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AlwaysAutoResize));
else
is_resizable_width = (window->Size.x > 0.0f) && !(flags & ImGuiWindowFlags_AlwaysAutoResize);
if (is_resizable_width)
window->DC.ItemWidthDefault = ImTrunc(window->Size.x * 0.65f);
else
window->DC.ItemWidthDefault = ImTrunc(g.FontSize * 16.0f);
@@ -8201,6 +8252,8 @@ void ImGui::End()
ImGuiWindowStackData& window_stack_data = g.CurrentWindowStack.back();
// Error checking: verify that user doesn't directly call End() on a child window.
if (window->Flags & ImGuiWindowFlags_Popup)
IM_ASSERT_USER_ERROR(g.WithinEndPopupID == window->ID, "Must call EndPopup() and not End()!");
if (window->Flags & ImGuiWindowFlags_ChildWindow)
IM_ASSERT_USER_ERROR(g.WithinEndChildID == window->ID, "Must call EndChild() and not End()!");
@@ -8738,6 +8791,17 @@ void ImGui::PopFocusScope()
g.CurrentFocusScopeId = g.FocusScopeStack.Size ? g.FocusScopeStack.back().ID : 0;
}
bool ImGui::IsInNavFocusRoute(ImGuiID focus_scope_id)
{
ImGuiContext& g = *GImGui;
if (g.NavFocusScopeId == focus_scope_id)
return true;
for (const ImGuiFocusScopeData& focus_scope : g.NavFocusRoute)
if (focus_scope.ID == focus_scope_id)
return true;
return false;
}
void ImGui::SetNavFocusScope(ImGuiID focus_scope_id)
{
ImGuiContext& g = *GImGui;
@@ -8972,7 +9036,7 @@ ImFont* ImGui::GetDefaultFont()
return g.IO.FontDefault ? g.IO.FontDefault : atlas->Fonts[0];
}
// EXPERIMENTAL: DO NOT USE YET.
// EXPERIMENTAL. Use ImTextureDataQueueUpload() to queue updates.
void ImGui::RegisterUserTexture(ImTextureData* tex)
{
ImGuiContext& g = *GImGui;
@@ -9094,7 +9158,7 @@ void ImGui::UpdateCurrentFontSize(float restore_font_size_after_scaling)
}
g.FontBaked = (g.Font != NULL && window != NULL) ? g.Font->GetFontBaked(final_size) : NULL;
g.FontBakedScale = (g.Font != NULL && window != NULL) ? (g.FontSize / g.FontBaked->Size) : 0.0f;
g.FontBakedScale = (g.FontBaked != NULL) ? (g.FontSize / g.FontBaked->Size) : 0.0f;
g.DrawListSharedData.FontScale = g.FontBakedScale;
}
@@ -10302,15 +10366,21 @@ void ImGui::UpdateMouseWheel()
LockWheelingWindow(NULL, 0.0f);
}
ImVec2 wheel;
wheel.x = TestKeyOwner(ImGuiKey_MouseWheelX, ImGuiKeyOwner_NoOwner) ? g.IO.MouseWheelH : 0.0f;
wheel.y = TestKeyOwner(ImGuiKey_MouseWheelY, ImGuiKeyOwner_NoOwner) ? g.IO.MouseWheel : 0.0f;
//IMGUI_DEBUG_LOG("MouseWheel X:%.3f Y:%.3f\n", wheel_x, wheel_y);
ImGuiWindow* mouse_window = g.WheelingWindow ? g.WheelingWindow : g.HoveredWindow;
if (!mouse_window || mouse_window->Collapsed)
return;
ImGuiID owner_id = mouse_window->ID;
ImVec2 wheel;
wheel.x = TestKeyOwner(ImGuiKey_MouseWheelX, owner_id) ? g.IO.MouseWheelH : 0.0f;
wheel.y = TestKeyOwner(ImGuiKey_MouseWheelY, owner_id) ? g.IO.MouseWheel : 0.0f;
//IMGUI_DEBUG_LOG("MouseWheel X:%.3f Y:%.3f\n", wheel_x, wheel_y);
if (g.WheelingWindow != NULL)
{
SetKeyOwner(ImGuiKey_MouseWheelX, owner_id);
SetKeyOwner(ImGuiKey_MouseWheelY, owner_id);
}
// Zoom / Scale window
// FIXME-OBSOLETE: This is an old feature, it still works but pretty much nobody is using it and may be best redesigned.
if (wheel.y != 0.0f && g.IO.KeyCtrl && g.IO.FontAllowUserScaling)
@@ -10614,6 +10684,7 @@ bool ImGui::TestKeyOwner(ImGuiKey key, ImGuiID owner_id)
// - SetKeyOwner(..., None) : clears owner
// - SetKeyOwner(..., Any, !Lock) : illegal (assert)
// - SetKeyOwner(..., Any or None, Lock) : set lock
// Ownership is automatically released on the frame after a release, see code in UpdateKeyboardInputs().
void ImGui::SetKeyOwner(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags)
{
ImGuiContext& g = *GImGui;
@@ -10640,30 +10711,34 @@ void ImGui::SetKeyOwnersForKeyChord(ImGuiKeyChord key_chord, ImGuiID owner_id, I
if (key_chord & ~ImGuiMod_Mask_) { SetKeyOwner((ImGuiKey)(key_chord & ~ImGuiMod_Mask_), owner_id, flags); }
}
// This is more or less equivalent to:
// This is more or less equivalent to a fancier version of:
// if (IsItemHovered() || IsItemActive())
// SetKeyOwner(key, GetItemID());
// Extensive uses of that (e.g. many calls for a single item) may want to manually perform the tests once and then call SetKeyOwner() multiple times.
// More advanced usage scenarios may want to call SetKeyOwner() manually based on different condition.
// Worth noting is that only one item can be hovered and only one item can be active, therefore this usage pattern doesn't need to bother with routing and priority.
void ImGui::SetItemKeyOwner(ImGuiKey key, ImGuiInputFlags flags)
bool ImGui::SetItemKeyOwner(ImGuiKey key, ImGuiInputFlags flags)
{
ImGuiContext& g = *GImGui;
ImGuiID id = g.LastItemData.ID;
if (id == 0 || (g.HoveredId != id && g.ActiveId != id))
return;
return false;
if ((flags & ImGuiInputFlags_CondMask_) == 0)
flags |= ImGuiInputFlags_CondDefault_;
if ((g.HoveredId == id && (flags & ImGuiInputFlags_CondHovered)) || (g.ActiveId == id && (flags & ImGuiInputFlags_CondActive)))
{
IM_ASSERT((flags & ~ImGuiInputFlags_SupportedBySetItemKeyOwner) == 0); // Passing flags not supported by this function!
if (!TestKeyOwner(key, id))
return false;
SetKeyOwner(key, id, flags & ~ImGuiInputFlags_CondMask_);
return true;
}
return false;
}
void ImGui::SetItemKeyOwner(ImGuiKey key)
bool ImGui::SetItemKeyOwner(ImGuiKey key)
{
SetItemKeyOwner(key, ImGuiInputFlags_None);
return SetItemKeyOwner(key, ImGuiInputFlags_None);
}
// This is the only public API until we expose owner_id versions of the API as replacements.
@@ -10804,7 +10879,8 @@ bool ImGui::DebugCheckVersionAndDataLayout(const char* version, size_t sz_io, si
// to extend contents size of our parent container (e.g. window contents size, which is used for auto-resizing
// windows, table column contents size used for auto-resizing columns, group size).
// This was causing issues and ambiguities and we needed to retire that.
// From 1.89, extending contents size boundaries REQUIRES AN ITEM TO BE SUBMITTED.
// 2022/08/05 (1.89): extending contents size boundaries REQUIRES AN ITEM TO BE SUBMITTED. However we gated the new logic behind a '#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS' block.
// 2025/06/25 (1.92): removed the legacy path and turned into an assert. It was a mistake that there was a #ifndef before: our obsolescence schedule gets pushed back a bit more :(
//
// Previously this would make the window content size ~200x200:
// Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + End(); // NOT OK ANYMORE
@@ -12413,6 +12489,17 @@ bool ImGui::BeginPopupMenuEx(ImGuiID id, const char* label, ImGuiWindowFlags ext
return false;
}
// As we bypass BeginChild(), set ImGuiChildFlags_AlwaysAutoResize as it is checked independently from ImGuiWindowFlags_AlwaysAutoResize for now (see #9355)
// Ideally we should remove setting ImGuiWindowFlags_AlwaysAutoResize in BeginChild().
if ((extra_window_flags & ImGuiWindowFlags_ChildWindow) && (extra_window_flags & ImGuiWindowFlags_AlwaysAutoResize))
{
if (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasChildFlags)
g.NextWindowData.ChildFlags |= ImGuiChildFlags_AlwaysAutoResize;
else
g.NextWindowData.ChildFlags = ImGuiChildFlags_AlwaysAutoResize;
g.NextWindowData.HasFlags |= ImGuiNextWindowDataFlags_HasChildFlags;
}
char name[128];
IM_ASSERT(extra_window_flags & ImGuiWindowFlags_ChildMenu);
ImFormatString(name, IM_COUNTOF(name), "%s###Menu_%02d", label, g.BeginMenuDepth); // Recycle windows based on depth
@@ -12485,10 +12572,13 @@ void ImGui::EndPopup()
NavMoveRequestTryWrapping(window, ImGuiNavMoveFlags_LoopY);
// Child-popups don't need to be laid out
const ImGuiID backup_within_end_popup_id = g.WithinEndPopupID;
const ImGuiID backup_within_end_child_id = g.WithinEndChildID;
g.WithinEndPopupID = window->ID;
if (window->Flags & ImGuiWindowFlags_ChildWindow)
g.WithinEndChildID = window->ID;
End();
g.WithinEndPopupID = backup_within_end_popup_id;
g.WithinEndChildID = backup_within_end_child_id;
}
@@ -13310,7 +13400,7 @@ static void ImGui::NavProcessItem()
const ImGuiID id = g.LastItemData.ID;
const ImGuiItemFlags item_flags = g.LastItemData.ItemFlags;
// When inside a container that isn't scrollable with Left<>Right, clip NavRect accordingly (#2221, #8816)
// When inside a container that isn't scrollable with Left<>Right, clip NavRect accordingly (#2221, #8816, #7994)
ImRect nav_bb = g.LastItemData.NavRect;
if (window->DC.NavIsScrollPushableX == false)
{
@@ -15074,7 +15164,7 @@ const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDrop
{
ImRect bb = g.DragDropTargetRect;
bb.Expand(-3.5f);
RenderDragDropTargetRectEx(GetForegroundDrawList(), bb);
RenderDragDropTargetRectEx(GetForegroundDrawList(), bb, g.Style.DragDropTargetRounding);
}
else if (draw_target_rect)
{
@@ -15105,16 +15195,16 @@ void ImGui::RenderDragDropTargetRectForItem(const ImRect& bb)
bool push_clip_rect = !window->ClipRect.Contains(bb_display);
if (push_clip_rect)
window->DrawList->PushClipRectFullScreen();
RenderDragDropTargetRectEx(window->DrawList, bb_display);
RenderDragDropTargetRectEx(window->DrawList, bb_display, g.Style.DragDropTargetRounding);
if (push_clip_rect)
window->DrawList->PopClipRect();
}
void ImGui::RenderDragDropTargetRectEx(ImDrawList* draw_list, const ImRect& bb)
void ImGui::RenderDragDropTargetRectEx(ImDrawList* draw_list, const ImRect& bb, float rounding)
{
ImGuiContext& g = *GImGui;
draw_list->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_DragDropTargetBg), g.Style.DragDropTargetRounding, 0);
draw_list->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_DragDropTarget), g.Style.DragDropTargetRounding, 0, g.Style.DragDropTargetBorderSize);
draw_list->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_DragDropTargetBg), rounding, 0);
draw_list->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_DragDropTarget), rounding, g.Style.DragDropTargetBorderSize);
}
const ImGuiPayload* ImGui::GetDragDropPayload()
@@ -15774,6 +15864,7 @@ void ImGuiPlatformIO::ClearRendererHandlers()
{
Renderer_TextureMaxWidth = Renderer_TextureMaxHeight = 0;
Renderer_RenderState = NULL;
DrawCallback_ResetRenderState = DrawCallback_SetSamplerLinear = DrawCallback_SetSamplerNearest = NULL;
}
ImGuiViewport* ImGui::GetMainViewport()
@@ -16215,7 +16306,7 @@ void ImGui::DebugRenderKeyboardPreview(ImDrawList* draw_list)
draw_list->AddRect(key_min, key_max, IM_COL32(24, 24, 24, 255), key_rounding);
ImVec2 face_min = ImVec2(key_min.x + key_face_pos.x, key_min.y + key_face_pos.y);
ImVec2 face_max = ImVec2(face_min.x + key_face_size.x, face_min.y + key_face_size.y);
draw_list->AddRect(face_min, face_max, IM_COL32(193, 193, 193, 255), key_face_rounding, ImDrawFlags_None, 2.0f);
draw_list->AddRect(face_min, face_max, IM_COL32(193, 193, 193, 255), key_face_rounding, 2.0f);
draw_list->AddRectFilled(face_min, face_max, IM_COL32(252, 252, 252, 255), key_face_rounding);
ImVec2 label_min = ImVec2(key_min.x + key_label_pos.x, key_min.y + key_label_pos.y);
draw_list->AddText(label_min, IM_COL32(64, 64, 64, 255), key_data->Label);
@@ -16638,7 +16729,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
BulletText("Table 0x%08X (%d columns, in '%s')", table->ID, table->ColumnsCount, table->OuterWindow->Name);
if (IsItemHovered())
GetForegroundDrawList(table->OuterWindow)->AddRect(table->OuterRect.Min - ImVec2(1, 1), table->OuterRect.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, 0, 2.0f);
GetForegroundDrawList(table->OuterWindow)->AddRect(table->OuterRect.Min - ImVec2(1, 1), table->OuterRect.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, 2.0f);
Indent();
char buf[128];
for (int rect_n = 0; rect_n < TRT_Count; rect_n++)
@@ -16653,7 +16744,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
ImFormatString(buf, IM_COUNTOF(buf), "(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) Col %d %s", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), column_n, trt_rects_names[rect_n]);
Selectable(buf);
if (IsItemHovered())
GetForegroundDrawList(table->OuterWindow)->AddRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, 0, 2.0f);
GetForegroundDrawList(table->OuterWindow)->AddRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, 2.0f);
}
}
else
@@ -16662,7 +16753,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
ImFormatString(buf, IM_COUNTOF(buf), "(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) %s", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), trt_rects_names[rect_n]);
Selectable(buf);
if (IsItemHovered())
GetForegroundDrawList(table->OuterWindow)->AddRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, 0, 2.0f);
GetForegroundDrawList(table->OuterWindow)->AddRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, 2.0f);
}
}
Unindent();
@@ -17070,7 +17161,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
ImRect r = Funcs::GetTableRect(table, cfg->ShowTablesRectsType, column_n);
ImU32 col = (table->HoveredColumnBody == column_n) ? IM_COL32(255, 255, 128, 255) : IM_COL32(255, 0, 128, 255);
float thickness = (table->HoveredColumnBody == column_n) ? 3.0f : 1.0f;
draw_list->AddRect(r.Min, r.Max, col, 0.0f, 0, thickness);
draw_list->AddRect(r.Min, r.Max, col, 0.0f, thickness);
}
}
else
@@ -17247,7 +17338,7 @@ void ImGui::DebugNodeDrawList(ImGuiWindow* window, ImGuiViewportP* viewport, con
{
ImDrawListFlags backup_flags = fg_draw_list->Flags;
fg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles.
fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), ImDrawFlags_Closed, 1.0f);
fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), 1.0f, ImDrawFlags_Closed);
fg_draw_list->Flags = backup_flags;
}
}
@@ -17275,7 +17366,7 @@ void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, co
for (int n = 0; n < 3; n++, idx_n++)
vtxs_rect.Add((triangle[n] = vtx_buffer[idx_buffer ? idx_buffer[idx_n] : idx_n].pos));
if (show_mesh)
out_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), ImDrawFlags_Closed, 1.0f); // In yellow: mesh triangles
out_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), 1.0f, ImDrawFlags_Closed); // In yellow: mesh triangles
}
// Draw bounding boxes
if (show_aabb)
@@ -17556,8 +17647,8 @@ void ImGui::DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label)
{
ImDrawList* draw_list = GetForegroundDrawList(tab_bar->Window);
draw_list->AddRect(tab_bar->BarRect.Min, tab_bar->BarRect.Max, IM_COL32(255, 255, 0, 255));
draw_list->AddLine(ImVec2(tab_bar->ScrollingRectMinX, tab_bar->BarRect.Min.y), ImVec2(tab_bar->ScrollingRectMinX, tab_bar->BarRect.Max.y), IM_COL32(0, 255, 0, 255));
draw_list->AddLine(ImVec2(tab_bar->ScrollingRectMaxX, tab_bar->BarRect.Min.y), ImVec2(tab_bar->ScrollingRectMaxX, tab_bar->BarRect.Max.y), IM_COL32(0, 255, 0, 255));
draw_list->AddLineV(tab_bar->ScrollingRectMinX, tab_bar->BarRect.Min.y, tab_bar->BarRect.Max.y, IM_COL32(0, 255, 0, 255));
draw_list->AddLineV(tab_bar->ScrollingRectMaxX, tab_bar->BarRect.Min.y, tab_bar->BarRect.Max.y, IM_COL32(0, 255, 0, 255));
}
if (open)
{
@@ -17886,8 +17977,8 @@ void ImGui::DebugDrawCursorPos(ImU32 col)
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
ImVec2 pos = window->DC.CursorPos;
window->DrawList->AddLine(ImVec2(pos.x, pos.y - 3.0f), ImVec2(pos.x, pos.y + 4.0f), col, 1.0f);
window->DrawList->AddLine(ImVec2(pos.x - 3.0f, pos.y), ImVec2(pos.x + 4.0f, pos.y), col, 1.0f);
window->DrawList->AddLineV(pos.x, pos.y - 3.0f, pos.y + 4.0f, col, 1.0f);
window->DrawList->AddLineH(pos.x - 3.0f, pos.x + 4.0f, pos.y, col, 1.0f);
}
// Draw a 10px wide rectangle around CurposPos.x using Line Y1/Y2 in current window's DrawList
@@ -17898,9 +17989,9 @@ void ImGui::DebugDrawLineExtents(ImU32 col)
float curr_x = window->DC.CursorPos.x;
float line_y1 = (window->DC.IsSameLine ? window->DC.CursorPosPrevLine.y : window->DC.CursorPos.y);
float line_y2 = line_y1 + (window->DC.IsSameLine ? window->DC.PrevLineSize.y : window->DC.CurrLineSize.y);
window->DrawList->AddLine(ImVec2(curr_x - 5.0f, line_y1), ImVec2(curr_x + 5.0f, line_y1), col, 1.0f);
window->DrawList->AddLine(ImVec2(curr_x - 0.5f, line_y1), ImVec2(curr_x - 0.5f, line_y2), col, 1.0f);
window->DrawList->AddLine(ImVec2(curr_x - 5.0f, line_y2), ImVec2(curr_x + 5.0f, line_y2), col, 1.0f);
window->DrawList->AddLineH(curr_x - 5.0f, curr_x + 5.0f, line_y1, col, 1.0f);
window->DrawList->AddLineV(curr_x - 0.5f, line_y1, line_y2, col, 1.0f);
window->DrawList->AddLineH(curr_x - 5.0f, curr_x + 5.0f, line_y2, col, 1.0f);
}
// Draw last item rect in ForegroundDrawList (so it is always visible)
@@ -18270,7 +18361,7 @@ void ImGui::ShowFontSelector(const char* label)
"- Load additional fonts with io.Fonts->AddFontXXX() functions.\n"
"- The font atlas is built when calling io.Fonts->GetTexDataAsXXXX() or io.Fonts->Build().\n"
"- Read FAQ and docs/FONTS.md for more details.\n"
"- If you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame().");
"- Legacy backend: if you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame().");
}
#endif // #if !defined(IMGUI_DISABLE_DEMO_WINDOWS) || !defined(IMGUI_DISABLE_DEBUG_TOOLS)
+154 -46
View File
@@ -1,4 +1,4 @@
// dear imgui, v1.92.7
// dear imgui, v1.92.8
// (demo code)
// Help:
@@ -73,6 +73,7 @@ Index of this file:
// [SECTION] Demo Window / ShowDemoWindow()
// [SECTION] DemoWindowMenuBar()
// [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor & Multi-Select demos)
// [SECTION] Helpers: ExampleImageViewer
// [SECTION] DemoWindowWidgetsBasic()
// [SECTION] DemoWindowWidgetsBullets()
// [SECTION] DemoWindowWidgetsCollapsingHeaders()
@@ -108,6 +109,7 @@ Index of this file:
// [SECTION] User Guide / ShowUserGuide()
// [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar()
// [SECTION] Example App: Debug Console / ShowExampleAppConsole()
// [SECTION] Example App: Image Viewer / ShowExampleAppImageViewer()
// [SECTION] Example App: Debug Log / ShowExampleAppLog()
// [SECTION] Example App: Simple Layout / ShowExampleAppLayout()
// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor()
@@ -238,6 +240,7 @@ static void ShowExampleAppAssetsBrowser(bool* p_open);
static void ShowExampleAppConsole(bool* p_open);
static void ShowExampleAppCustomRendering(bool* p_open);
static void ShowExampleAppDocuments(bool* p_open);
static void ShowExampleAppImageViewer(bool* p_open);
static void ShowExampleAppLog(bool* p_open);
static void ShowExampleAppLayout(bool* p_open);
static void ShowExampleAppPropertyEditor(bool* p_open, ImGuiDemoWindowData* demo_data);
@@ -308,6 +311,7 @@ struct ImGuiDemoWindowData
bool ShowAppConsole = false;
bool ShowAppCustomRendering = false;
bool ShowAppDocuments = false;
bool ShowAppImageViewer = false;
bool ShowAppLog = false;
bool ShowAppLayout = false;
bool ShowAppPropertyEditor = false;
@@ -353,6 +357,7 @@ void ImGui::ShowDemoWindow(bool* p_open)
if (demo_data.ShowAppAssetsBrowser) { ShowExampleAppAssetsBrowser(&demo_data.ShowAppAssetsBrowser); }
if (demo_data.ShowAppConsole) { ShowExampleAppConsole(&demo_data.ShowAppConsole); }
if (demo_data.ShowAppCustomRendering) { ShowExampleAppCustomRendering(&demo_data.ShowAppCustomRendering); }
if (demo_data.ShowAppImageViewer) { ShowExampleAppImageViewer(&demo_data.ShowAppImageViewer); }
if (demo_data.ShowAppLog) { ShowExampleAppLog(&demo_data.ShowAppLog); }
if (demo_data.ShowAppLayout) { ShowExampleAppLayout(&demo_data.ShowAppLayout); }
if (demo_data.ShowAppPropertyEditor) { ShowExampleAppPropertyEditor(&demo_data.ShowAppPropertyEditor, &demo_data); }
@@ -677,6 +682,7 @@ static void DemoWindowMenuBar(ImGuiDemoWindowData* demo_data)
ImGui::MenuItem("Console", NULL, &demo_data->ShowAppConsole);
ImGui::MenuItem("Custom rendering", NULL, &demo_data->ShowAppCustomRendering);
ImGui::MenuItem("Documents", NULL, &demo_data->ShowAppDocuments);
ImGui::MenuItem("Image Viewer", NULL, &demo_data->ShowAppImageViewer);
ImGui::MenuItem("Log", NULL, &demo_data->ShowAppLog);
ImGui::MenuItem("Property editor", NULL, &demo_data->ShowAppPropertyEditor);
ImGui::MenuItem("Simple layout", NULL, &demo_data->ShowAppLayout);
@@ -708,7 +714,7 @@ static void DemoWindowMenuBar(ImGuiDemoWindowData* demo_data)
ImGui::Checkbox("Highlight ID Conflicts", &io.ConfigDebugHighlightIdConflicts);
ImGui::EndDisabled();
ImGui::Checkbox("Assert on error recovery", &io.ConfigErrorRecoveryEnableAssert);
ImGui::TextDisabled("(see Demo->Configuration for details & more)");
ImGui::TextDisabled("(see Demo->Configuration for more)");
ImGui::EndMenu();
}
ImGui::MenuItem("Debug Log", NULL, &demo_data->ShowDebugLog, has_debug_tools);
@@ -825,6 +831,87 @@ static ExampleTreeNode* ExampleTree_CreateDemoTree()
return node_L0;
}
//-----------------------------------------------------------------------------
// [SECTION] Helpers: ExampleImageViewer
//-----------------------------------------------------------------------------
struct ExampleImageViewerData
{
ImU32 ImageBgColor = IM_COL32(100, 100, 100, 255);
ImU32 GridColor = IM_COL32(255, 255, 255, 100);
bool GridEnabled = true;
bool ViewReset = true;
ImVec2 ViewOffset; // in image space
float Zoom = 10.0f;
float ZoomMin = 1.0f;
float ZoomMax = 10000.0f;
};
static void ExampleImageViewer_DrawOptions(ExampleImageViewerData* data)
{
ImGui::SetNextItemShortcut(ImGuiKey_G, ImGuiInputFlags_Tooltip); // | ImGuiInputFlags_RouteGlobal
ImGui::Checkbox("Grid", &data->GridEnabled);
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 10.0f);
float zoom_100 = data->Zoom * 100.0f;
if (ImGui::DragFloat("##Zoom", &zoom_100, 5.0f, data->ZoomMin * 100.0f, data->ZoomMax * 100.0f, "%.0f%%", ImGuiSliderFlags_AlwaysClamp))
data->Zoom = zoom_100 / 100.0f;
}
static void ExampleImageViewer_DrawCanvas(ExampleImageViewerData* data, ImVec2 canvas_size, ImTextureRef image_tex_ref, int image_w, int image_h)
{
ImGuiIO& io = ImGui::GetIO();
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
ImDrawList* draw_list = ImGui::GetWindowDrawList();
IM_ASSERT(canvas_size.x >= 0.0f && canvas_size.y >= 0.0f);
// Layout canvas
ImGui::InvisibleButton("##Canvas", canvas_size);
ImVec2 canvas_min = ImGui::GetItemRectMin();
ImVec2 canvas_max = ImGui::GetItemRectMax();
if (data->ViewReset)
data->ViewOffset = ImVec2((canvas_size.x * 0.5f / data->Zoom) - 0.5f, (canvas_size.y * 0.5f / data->Zoom) - 0.5f); // Add half a pixel padding
data->ViewReset = false;
// Handle inputs
if (ImGui::SetItemKeyOwner(ImGuiKey_MouseWheelY))
if (io.MouseWheel != 0.0f)
data->Zoom = IM_CLAMP(data->Zoom * (1.0f + io.MouseWheel * 0.10f), data->ZoomMin, data->ZoomMax);
float zoom = data->Zoom; // (float)(int)ViewZoom;
if (ImGui::IsItemActive() && ImGui::IsMouseDragging(0))
{
data->ViewOffset.x -= io.MouseDelta.x / zoom;
data->ViewOffset.y -= io.MouseDelta.y / zoom;
}
// Display image
ImVec2 image_min, image_max;
image_min.x = (float)(int)((canvas_min.x - (data->ViewOffset.x * zoom)) + (canvas_size.x * 0.5f));
image_min.y = (float)(int)((canvas_min.y - (data->ViewOffset.y * zoom)) + (canvas_size.y * 0.5f));
image_max.x = (float)(int)(image_min.x + image_w * zoom);
image_max.y = (float)(int)(image_min.y + image_h * zoom);
draw_list->AddRect(ImVec2(canvas_min.x - 1.0f, canvas_min.y - 1.0f), ImVec2(canvas_max.x + 1.0f, canvas_max.y + 1.0f), IM_COL32(255, 255, 255, 255));
draw_list->PushClipRect(canvas_min, canvas_max, true);
draw_list->AddRectFilled(image_min, image_max, data->ImageBgColor);
if (platform_io.DrawCallback_SetSamplerNearest != NULL)
draw_list->AddCallback(platform_io.DrawCallback_SetSamplerNearest);
draw_list->AddImage(image_tex_ref, image_min, image_max);
if (platform_io.DrawCallback_SetSamplerLinear != NULL)
draw_list->AddCallback(ImGui::GetPlatformIO().DrawCallback_SetSamplerLinear);
// Display grid lines for visible pixels
if (data->GridEnabled && zoom > 6.0f)
{
const float step = (float)zoom;
for (int px = (int)((canvas_min.x - image_min.x) / step); px <= (int)((canvas_max.x - image_min.x) / step); px++)
draw_list->AddLineV(image_min.x + px * step, canvas_min.y, canvas_max.y, data->GridColor, 1.0f);
for (int py = (int)((canvas_min.y - image_min.y) / step); py <= (int)((canvas_max.y - image_min.y) / step); py++)
draw_list->AddLineH(canvas_min.x, canvas_max.x, image_min.y + py * step, data->GridColor, 1.0f);
}
draw_list->PopClipRect();
}
//-----------------------------------------------------------------------------
// [SECTION] DemoWindowWidgetsBasic()
//-----------------------------------------------------------------------------
@@ -1802,40 +1889,29 @@ static void DemoWindowWidgetsImages()
// - Read https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
// Grab the current texture identifier used by the font atlas.
ImTextureRef my_tex_id = io.Fonts->TexRef;
ImFontAtlas* atlas = io.Fonts;
ImTextureRef my_tex_id = atlas->TexRef;
float my_tex_w = (float)atlas->TexData->Width; // Regular user code should never have to care about TexData-> fields, but since we want to display the entire texture here, we pull Width/Height from it.
float my_tex_h = (float)atlas->TexData->Height;
ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h);
// Regular user code should never have to care about TexData-> fields, but since we want to display the entire texture here, we pull Width/Height from it.
float my_tex_w = (float)io.Fonts->TexData->Width;
float my_tex_h = (float)io.Fonts->TexData->Height;
// Basic drawing
ImGui::SeparatorText("Image()/ImageWithBg() function");
ImVec2 uv_min = ImVec2(0.0f, 0.0f); // Top-left
ImVec2 uv_max = ImVec2(1.0f, 1.0f); // Lower-right
ImGui::PushStyleVar(ImGuiStyleVar_ImageBorderSize, IM_MAX(1.0f, ImGui::GetStyle().ImageBorderSize));
ImGui::ImageWithBg(my_tex_id, ImVec2(my_tex_w, my_tex_h), uv_min, uv_max, ImVec4(0.0f, 0.0f, 0.0f, 1.0f));
ImGui::PopStyleVar();
{
ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h);
ImVec2 pos = ImGui::GetCursorScreenPos();
ImVec2 uv_min = ImVec2(0.0f, 0.0f); // Top-left
ImVec2 uv_max = ImVec2(1.0f, 1.0f); // Lower-right
ImGui::PushStyleVar(ImGuiStyleVar_ImageBorderSize, IM_MAX(1.0f, ImGui::GetStyle().ImageBorderSize));
ImGui::ImageWithBg(my_tex_id, ImVec2(my_tex_w, my_tex_h), uv_min, uv_max, ImVec4(0.0f, 0.0f, 0.0f, 1.0f));
if (ImGui::BeginItemTooltip())
{
float region_sz = 32.0f;
float region_x = io.MousePos.x - pos.x - region_sz * 0.5f;
float region_y = io.MousePos.y - pos.y - region_sz * 0.5f;
float zoom = 4.0f;
if (region_x < 0.0f) { region_x = 0.0f; }
else if (region_x > my_tex_w - region_sz) { region_x = my_tex_w - region_sz; }
if (region_y < 0.0f) { region_y = 0.0f; }
else if (region_y > my_tex_h - region_sz) { region_y = my_tex_h - region_sz; }
ImGui::Text("Min: (%.2f, %.2f)", region_x, region_y);
ImGui::Text("Max: (%.2f, %.2f)", region_x + region_sz, region_y + region_sz);
ImVec2 uv0 = ImVec2((region_x) / my_tex_w, (region_y) / my_tex_h);
ImVec2 uv1 = ImVec2((region_x + region_sz) / my_tex_w, (region_y + region_sz) / my_tex_h);
ImGui::ImageWithBg(my_tex_id, ImVec2(region_sz * zoom, region_sz * zoom), uv0, uv1, ImVec4(0.0f, 0.0f, 0.0f, 1.0f));
ImGui::EndTooltip();
}
ImGui::PopStyleVar();
}
// Fancy widget
ImGui::SeparatorText("Interactive Image Viewer");
static ExampleImageViewerData image_viewer;
ImVec2 canvas_size(ImGui::GetContentRegionAvail().x, my_tex_h * 2.0f);
ExampleImageViewer_DrawOptions(&image_viewer);
ExampleImageViewer_DrawCanvas(&image_viewer, canvas_size, my_tex_id, (int)my_tex_w, (int)my_tex_h);
IMGUI_DEMO_MARKER("Widgets/Images/Textured buttons");
ImGui::SeparatorText("Textured Buttons");
ImGui::TextWrapped("And now some textured buttons..");
static int pressed_count = 0;
for (int i = 0; i < 8; i++)
@@ -8827,7 +8903,7 @@ static void ShowExampleMenuFile()
IMGUI_DEMO_MARKER("Examples/Menu/Options");
static bool enabled = true;
ImGui::MenuItem("Enabled", "", &enabled);
ImGui::BeginChild("child", ImVec2(0, 60), ImGuiChildFlags_Borders);
ImGui::BeginChild("child", ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 5.0f), ImGuiChildFlags_Borders);
for (int i = 0; i < 10; i++)
ImGui::Text("Scrolling Text %d", i);
ImGui::EndChild();
@@ -9239,6 +9315,28 @@ static void ShowExampleAppConsole(bool* p_open)
console.Draw("Example: Console", p_open);
}
//-----------------------------------------------------------------------------
// [SECTION] Example App: Image Viewer / ShowExampleAppImageViewer()
//-----------------------------------------------------------------------------
static void ShowExampleAppImageViewer(bool* p_open)
{
ImFontAtlas* atlas = ImGui::GetIO().Fonts;
ImTextureRef tex_ref = atlas->TexRef; // We don't have access to other textures in this demo!
int tex_w = atlas->TexData->Width;
int tex_h = atlas->TexData->Height;
if (ImGui::Begin("Example: Image Viewer", p_open))
{
static ExampleImageViewerData image_viewer;
ExampleImageViewer_DrawOptions(&image_viewer);
ImVec2 canvas_size = ImGui::GetContentRegionAvail();
ImVec2 canvas_min_size = ImGui::IsWindowAppearing() ? ImVec2(3.0f * tex_w, 4.0f * tex_h) : ImVec2(1.0f, 1.0f);
canvas_size = ImVec2(IM_MAX(canvas_size.x, canvas_min_size.x), IM_MAX(canvas_size.y, canvas_min_size.y));
ExampleImageViewer_DrawCanvas(&image_viewer, canvas_size, tex_ref, tex_w, tex_h);
}
ImGui::End();
}
//-----------------------------------------------------------------------------
// [SECTION] Example App: Debug Log / ShowExampleAppLog()
//-----------------------------------------------------------------------------
@@ -10131,20 +10229,20 @@ static void ShowExampleAppCustomRendering(bool* p_open)
draw_list->AddNgon(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, ngon_sides, th); x += sz + spacing; // N-gon
draw_list->AddCircle(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments, th); x += sz + spacing; // Circle
draw_list->AddEllipse(ImVec2(x + sz*0.5f, y + sz*0.5f), ImVec2(sz*0.5f, sz*0.3f), col, -0.3f, circle_segments, th); x += sz + spacing; // Ellipse
draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0f, ImDrawFlags_None, th); x += sz + spacing; // Square
draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, ImDrawFlags_None, th); x += sz + spacing; // Square with all rounded corners
draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, corners_tl_br, th); x += sz + spacing; // Square with two rounded corners
draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0f, th); x += sz + spacing; // Square
draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, th); x += sz + spacing; // Square with all rounded corners
draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, th, corners_tl_br); x += sz + spacing; // Square with two rounded corners
draw_list->AddTriangle(ImVec2(x+sz*0.5f,y), ImVec2(x+sz, y+sz-0.5f), ImVec2(x, y+sz-0.5f), col, th);x += sz + spacing; // Triangle
//draw_list->AddTriangle(ImVec2(x+sz*0.2f,y), ImVec2(x, y+sz-0.5f), ImVec2(x+sz*0.4f, y+sz-0.5f), col, th);x+= sz*0.4f + spacing; // Thin triangle
PathConcaveShape(draw_list, x, y, sz); draw_list->PathStroke(col, ImDrawFlags_Closed, th); x += sz + spacing; // Concave Shape
PathConcaveShape(draw_list, x, y, sz); draw_list->PathStroke(col, th, ImDrawFlags_Closed); x += sz + spacing; // Concave Shape
//draw_list->AddPolyline(concave_shape, IM_COUNTOF(concave_shape), col, ImDrawFlags_Closed, th);
draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y), col, th); x += sz + spacing; // Horizontal line (note: drawing a filled rectangle will be faster!)
draw_list->AddLine(ImVec2(x, y), ImVec2(x, y + sz), col, th); x += spacing; // Vertical line (note: drawing a filled rectangle will be faster!)
draw_list->AddLineH(x, x + sz, y, col, th); x += sz + spacing; // Horizontal line (note: drawing a filled rectangle will be faster!)
draw_list->AddLineV(x, y, y + sz, col, th); x += spacing; // Vertical line (note: drawing a filled rectangle will be faster!)
draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y + sz), col, th); x += sz + spacing; // Diagonal line
// Path
draw_list->PathArcTo(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, 3.141592f, 3.141592f * -0.5f);
draw_list->PathStroke(col, ImDrawFlags_None, th);
draw_list->PathStroke(col, th);
x += sz + spacing;
// Quadratic Bezier Curve (3 control points)
@@ -10278,9 +10376,9 @@ static void ShowExampleAppCustomRendering(bool* p_open)
{
const float GRID_STEP = 64.0f;
for (float x = fmodf(scrolling.x, GRID_STEP); x < canvas_sz.x; x += GRID_STEP)
draw_list->AddLine(ImVec2(canvas_p0.x + x, canvas_p0.y), ImVec2(canvas_p0.x + x, canvas_p1.y), IM_COL32(200, 200, 200, 40));
draw_list->AddLineV(canvas_p0.x + x, canvas_p0.y, canvas_p1.y, IM_COL32(200, 200, 200, 40));
for (float y = fmodf(scrolling.y, GRID_STEP); y < canvas_sz.y; y += GRID_STEP)
draw_list->AddLine(ImVec2(canvas_p0.x, canvas_p0.y + y), ImVec2(canvas_p1.x, canvas_p0.y + y), IM_COL32(200, 200, 200, 40));
draw_list->AddLineH(canvas_p0.x, canvas_p1.x, canvas_p0.y + y, IM_COL32(200, 200, 200, 40));
}
for (int n = 0; n < points.Size; n += 2)
draw_list->AddLine(ImVec2(origin.x + points[n].x, origin.y + points[n].y), ImVec2(origin.x + points[n + 1].x, origin.y + points[n + 1].y), IM_COL32(255, 255, 0, 255), 2.0f);
@@ -10724,10 +10822,11 @@ struct ExampleAssetsBrowser
bool AllowBoxSelect = true; // Will set ImGuiMultiSelectFlags_BoxSelect2d
bool AllowBoxSelectInsideSelection = false; // Will set ImGuiMultiSelectFlags_SelectOnClickAlways
bool AllowDragUnselected = false; // Will set ImGuiMultiSelectFlags_SelectOnClickRelease
float IconSize = 32.0f;
float IconSize = 0;
int IconSpacing = 10;
int IconHitSpacing = 4; // Increase hit-spacing if you want to make it possible to clear or box-select from gaps. Some spacing is required to able to amend with Shift+box-select. Value is small in Explorer.
int IconHitSpacing = 4; // Increase hit-spacing if you want to make it possible to clear or box-select from gaps. Some spacing is required to able to amend with Shift+box-select. Value is small in Explorer.
bool StretchSpacing = true;
bool UseScrollX = false; // Debug: submit twice the number of items per line (overflow horizontally to exercise ScrollX + box-select)
// State
ImVector<ExampleAsset> Items; // Our items
@@ -10778,12 +10877,15 @@ struct ExampleAssetsBrowser
// Layout: calculate number of icon per line and number of lines
LayoutItemSize = ImVec2(floorf(IconSize), floorf(IconSize));
LayoutColumnCount = IM_MAX((int)(avail_width / (LayoutItemSize.x + LayoutItemSpacing)), 1);
LayoutLineCount = (Items.Size + LayoutColumnCount - 1) / LayoutColumnCount;
// Layout: when stretching: allocate remaining space to more spacing. Round before division, so item_spacing may be non-integer.
if (StretchSpacing && LayoutColumnCount > 1)
LayoutItemSpacing = floorf(avail_width - LayoutItemSize.x * LayoutColumnCount) / LayoutColumnCount;
if (UseScrollX)
LayoutColumnCount *= 2;
LayoutLineCount = (Items.Size + LayoutColumnCount - 1) / LayoutColumnCount;
LayoutItemStep = ImVec2(LayoutItemSize.x + LayoutItemSpacing, LayoutItemSize.y + LayoutItemSpacing);
LayoutSelectableSpacing = IM_MAX(floorf(LayoutItemSpacing) - IconHitSpacing, 0.0f);
LayoutOuterPadding = floorf(LayoutItemSpacing * 0.5f);
@@ -10791,6 +10893,9 @@ struct ExampleAssetsBrowser
void Draw(const char* title, bool* p_open)
{
if (IconSize <= 0.0f)
IconSize = ImGui::CalcTextSize("99999").x;
ImGui::SetNextWindowSize(ImVec2(IconSize * 25, IconSize * 15), ImGuiCond_FirstUseEver);
if (!ImGui::Begin(title, p_open, ImGuiWindowFlags_MenuBar))
{
@@ -10840,6 +10945,7 @@ struct ExampleAssetsBrowser
ImGui::SliderInt("Icon Spacing", &IconSpacing, 0, 32);
ImGui::SliderInt("Icon Hit Spacing", &IconHitSpacing, 0, 32);
ImGui::Checkbox("Stretch Spacing", &StretchSpacing);
ImGui::Checkbox("Use ScrollX", &UseScrollX);
ImGui::PopItemWidth();
ImGui::EndMenu();
}
@@ -10869,7 +10975,7 @@ struct ExampleAssetsBrowser
ImGuiIO& io = ImGui::GetIO();
ImGui::SetNextWindowContentSize(ImVec2(0.0f, LayoutOuterPadding + LayoutLineCount * (LayoutItemSize.y + LayoutItemSpacing)));
if (ImGui::BeginChild("Assets", ImVec2(0.0f, -ImGui::GetTextLineHeightWithSpacing()), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove))
if (ImGui::BeginChild("Assets", ImVec2(0.0f, -ImGui::GetTextLineHeightWithSpacing()), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_HorizontalScrollbar))
{
ImDrawList* draw_list = ImGui::GetWindowDrawList();
@@ -11013,6 +11119,8 @@ struct ExampleAssetsBrowser
}
}
clipper.End();
if (Items.Size == 0)
ImGui::Dummy(ImVec2(0, 0));
ImGui::PopStyleVar(); // ImGuiStyleVar_ItemSpacing
// Context menu
+106 -71
View File
@@ -1,4 +1,4 @@
// dear imgui, v1.92.7
// dear imgui, v1.92.8
// (drawing and font code)
/*
@@ -208,6 +208,7 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst)
colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f);
colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.51f, 0.51f, 0.51f, 1.00f);
colors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
colors[ImGuiCol_CheckboxSelectedBg] = ImLerp(colors[ImGuiCol_FrameBg], colors[ImGuiCol_FrameBgHovered], 0.65f);
colors[ImGuiCol_SliderGrab] = ImVec4(0.24f, 0.52f, 0.88f, 1.00f);
colors[ImGuiCol_SliderGrabActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
colors[ImGuiCol_Button] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
@@ -275,6 +276,7 @@ void ImGui::StyleColorsClassic(ImGuiStyle* dst)
colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.80f, 0.40f);
colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.41f, 0.39f, 0.80f, 0.60f);
colors[ImGuiCol_CheckMark] = ImVec4(0.90f, 0.90f, 0.90f, 0.50f);
colors[ImGuiCol_CheckboxSelectedBg] = ImLerp(colors[ImGuiCol_FrameBg], colors[ImGuiCol_FrameBgActive], 0.65f);
colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f);
colors[ImGuiCol_SliderGrabActive] = ImVec4(0.41f, 0.39f, 0.80f, 0.60f);
colors[ImGuiCol_Button] = ImVec4(0.35f, 0.40f, 0.61f, 0.62f);
@@ -343,6 +345,7 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst)
colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.49f, 0.49f, 0.49f, 0.80f);
colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.49f, 0.49f, 0.49f, 1.00f);
colors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
colors[ImGuiCol_CheckboxSelectedBg] = ImVec4(0.95f, 0.97f, 1.00f, 1.00f);
colors[ImGuiCol_SliderGrab] = ImVec4(0.26f, 0.59f, 0.98f, 0.78f);
colors[ImGuiCol_SliderGrabActive] = ImVec4(0.46f, 0.54f, 0.80f, 0.60f);
colors[ImGuiCol_Button] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
@@ -528,9 +531,14 @@ void ImDrawList::_PopUnusedDrawCmd()
void ImDrawList::AddCallback(ImDrawCallback callback, void* userdata, size_t userdata_size)
{
IM_ASSERT(callback != NULL);
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
if (callback == ImDrawCallback_ResetRenderState && _Data->Context != NULL && _Data->Context->PlatformIO.DrawCallback_ResetRenderState != NULL)
callback = _Data->Context->PlatformIO.DrawCallback_ResetRenderState; // == ImGui::GetPlatformIO().DrawCallback_ResetRenderState
#endif
IM_ASSERT_PARANOID(CmdBuffer.Size > 0);
ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
IM_ASSERT(callback != NULL);
IM_ASSERT(curr_cmd->UserCallback == NULL);
if (curr_cmd->ElemCount != 0)
{
@@ -662,7 +670,7 @@ void ImDrawList::PushClipRect(const ImVec2& cr_min, const ImVec2& cr_max, bool i
if (intersect_with_current_clip_rect)
{
ImVec4 current = _CmdHeader.ClipRect;
if (cr.x < current.x) cr.x = current.x;
if (cr.x < current.x) cr.x = current.x; // = ClipWith(). Note that passing inverted range wouldn't be fixed here.
if (cr.y < current.y) cr.y = current.y;
if (cr.z > current.z) cr.z = current.z;
if (cr.w > current.w) cr.w = current.w;
@@ -806,7 +814,7 @@ void ImDrawList::PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, c
// TODO: Thickness anti-aliased lines cap are missing their AA fringe.
// We avoid using the ImVec2 math operators here to reduce cost to a minimum for debug/non-inlined builds.
void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, ImDrawFlags flags, float thickness)
void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, float thickness, ImDrawFlags flags)
{
if (points_count < 2 || (col & IM_COL32_A_MASK) == 0)
return;
@@ -815,6 +823,7 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
const ImVec2 opaque_uv = _Data->TexUvWhitePixel;
const int count = closed ? points_count : points_count - 1; // The number of line segments we need to draw
const bool thick_line = (thickness > _FringeScale);
IM_ASSERT((flags & ImDrawFlags_InvalidMask_) == 0 && "Incorrect parameter. Did you swapped 'thickness' and 'flags'?");
if (Flags & ImDrawListFlags_AntiAliasedLines)
{
@@ -1432,35 +1441,13 @@ void ImDrawList::PathBezierQuadraticCurveTo(const ImVec2& p2, const ImVec2& p3,
}
}
static inline ImDrawFlags FixRectCornerFlags(ImDrawFlags flags)
{
/*
IM_STATIC_ASSERT(ImDrawFlags_RoundCornersTopLeft == (1 << 4));
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
// Obsoleted in 1.82 (from February 2021). This code was stripped/simplified and mostly commented in 1.90 (from September 2023)
// - Legacy Support for hard coded ~0 (used to be a suggested equivalent to ImDrawCornerFlags_All)
if (flags == ~0) { return ImDrawFlags_RoundCornersAll; }
// - Legacy Support for hard coded 0x01 to 0x0F (matching 15 out of 16 old flags combinations). Read details in older version of this code.
if (flags >= 0x01 && flags <= 0x0F) { return (flags << 4); }
// We cannot support hard coded 0x00 with 'float rounding > 0.0f' --> replace with ImDrawFlags_RoundCornersNone or use 'float rounding = 0.0f'
#endif
*/
// If this assert triggers, please update your code replacing hardcoded values with new ImDrawFlags_RoundCorners* values.
// Note that ImDrawFlags_Closed (== 0x01) is an invalid flag for AddRect(), AddRectFilled(), PathRect() etc. anyway.
// See details in 1.82 Changelog as well as 2021/03/12 and 2023/09/08 entries in "API BREAKING CHANGES" section.
IM_ASSERT((flags & 0x0F) == 0 && "Misuse of legacy hardcoded ImDrawCornerFlags values!");
if ((flags & ImDrawFlags_RoundCornersMask_) == 0)
flags |= ImDrawFlags_RoundCornersAll;
return flags;
}
void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, ImDrawFlags flags)
{
if (rounding >= 0.5f)
{
flags = FixRectCornerFlags(flags);
if ((flags & ImDrawFlags_RoundCornersMask_) == 0)
flags |= ImDrawFlags_RoundCornersAll;
rounding = ImMin(rounding, ImFabs(b.x - a.x) * (((flags & ImDrawFlags_RoundCornersTop) == ImDrawFlags_RoundCornersTop) || ((flags & ImDrawFlags_RoundCornersBottom) == ImDrawFlags_RoundCornersBottom) ? 0.5f : 1.0f) - 1.0f);
rounding = ImMin(rounding, ImFabs(b.y - a.y) * (((flags & ImDrawFlags_RoundCornersLeft) == ImDrawFlags_RoundCornersLeft) || ((flags & ImDrawFlags_RoundCornersRight) == ImDrawFlags_RoundCornersRight) ? 0.5f : 1.0f) - 1.0f);
}
@@ -1490,20 +1477,48 @@ void ImDrawList::AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float th
return;
PathLineTo(p1 + ImVec2(0.5f, 0.5f));
PathLineTo(p2 + ImVec2(0.5f, 0.5f));
PathStroke(col, 0, thickness);
PathStroke(col, thickness);
}
void ImDrawList::AddLineH(float min_x, float max_x, float y, ImU32 col, float thickness)
{
if ((col & IM_COL32_A_MASK) == 0)
return;
PathLineTo(ImVec2(min_x + 0.5f, y + 0.5f)); // Same as AddLine() above.
PathLineTo(ImVec2(max_x + 0.5f, y + 0.5f));
PathStroke(col, thickness);
}
void ImDrawList::AddLineV(float x, float min_y, float max_y, ImU32 col, float thickness)
{
if ((col & IM_COL32_A_MASK) == 0)
return;
PathLineTo(ImVec2(x + 0.5f, min_y + 0.5f)); // Same as AddLine() above.
PathLineTo(ImVec2(x + 0.5f, max_y + 0.5f));
PathStroke(col, thickness);
}
// p_min = upper-left, p_max = lower-right
// Note we don't render 1 pixels sized rectangles properly.
void ImDrawList::AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawFlags flags, float thickness)
void ImDrawList::AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, float thickness, ImDrawFlags flags)
{
// If this assert triggers on legacy code:
// - 1.92.8 (2025/04): swapped two last parameters order: flags, thickness --> thickness, flags. This should normally be caught by compile-time type-checking.
// - 1.82.0 (2021/03): changed ImDrawCornerFlags to ImDrawFlags_RoundCornersXXX values.
// If you used hard-coded 1 to 15 or ~0 in flags to configure corner rounding use the new flags!
// - Hard coded support for ~0 == ImDrawFlags_RoundCornersAll.
// - Hard coded support for values 0x01 to 0x0F (matching 15 out of 16 old flags combinations) --> see FixRectCornerFlags() in <1.90 code.
// - Hard coded 0x00 with 'float rounding > 0.0f' --> replace with ImDrawFlags_RoundCornersNone or use 'float rounding = 0.0f'.
// See "API BREAKING CHANGES" section for 1.82 and 1.90.
IM_ASSERT((flags & ImDrawFlags_InvalidMask_) == 0 && "Incorrect parameter. Did you swapped 'thickness' and 'flags'?"); // Or misuse of legacy hard-coded ImDrawCornerFlags values
if ((col & IM_COL32_A_MASK) == 0)
return;
if (Flags & ImDrawListFlags_AntiAliasedLines)
PathRect(p_min + ImVec2(0.50f, 0.50f), p_max - ImVec2(0.50f, 0.50f), rounding, flags);
else
PathRect(p_min + ImVec2(0.50f, 0.50f), p_max - ImVec2(0.49f, 0.49f), rounding, flags); // Better looking lower-right corner and rounded non-AA shapes.
PathStroke(col, ImDrawFlags_Closed, thickness);
PathStroke(col, thickness, ImDrawFlags_Closed);
}
void ImDrawList::AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawFlags flags)
@@ -1547,7 +1562,7 @@ void ImDrawList::AddQuad(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, c
PathLineTo(p2);
PathLineTo(p3);
PathLineTo(p4);
PathStroke(col, ImDrawFlags_Closed, thickness);
PathStroke(col, thickness, ImDrawFlags_Closed);
}
void ImDrawList::AddQuadFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col)
@@ -1570,7 +1585,7 @@ void ImDrawList::AddTriangle(const ImVec2& p1, const ImVec2& p2, const ImVec2& p
PathLineTo(p1);
PathLineTo(p2);
PathLineTo(p3);
PathStroke(col, ImDrawFlags_Closed, thickness);
PathStroke(col, thickness, ImDrawFlags_Closed);
}
void ImDrawList::AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col)
@@ -1605,7 +1620,7 @@ void ImDrawList::AddCircle(const ImVec2& center, float radius, ImU32 col, int nu
PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1);
}
PathStroke(col, ImDrawFlags_Closed, thickness);
PathStroke(col, thickness, ImDrawFlags_Closed);
}
void ImDrawList::AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments)
@@ -1641,7 +1656,7 @@ void ImDrawList::AddNgon(const ImVec2& center, float radius, ImU32 col, int num_
// Because we are filling a closed shape we remove 1 from the count of segments/points
const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1);
PathStroke(col, ImDrawFlags_Closed, thickness);
PathStroke(col, thickness, ImDrawFlags_Closed);
}
// Guaranteed to honor 'num_segments'
@@ -1668,7 +1683,7 @@ void ImDrawList::AddEllipse(const ImVec2& center, const ImVec2& radius, ImU32 co
// Because we are filling a closed shape we remove 1 from the count of segments/points
const float a_max = IM_PI * 2.0f * ((float)num_segments - 1.0f) / (float)num_segments;
PathEllipticalArcTo(center, radius, rot, 0.0f, a_max, num_segments - 1);
PathStroke(col, true, thickness);
PathStroke(col, thickness, ImDrawFlags_Closed);
}
void ImDrawList::AddEllipseFilled(const ImVec2& center, const ImVec2& radius, ImU32 col, float rot, int num_segments)
@@ -1693,7 +1708,7 @@ void ImDrawList::AddBezierCubic(const ImVec2& p1, const ImVec2& p2, const ImVec2
PathLineTo(p1);
PathBezierCubicCurveTo(p2, p3, p4, num_segments);
PathStroke(col, 0, thickness);
PathStroke(col, thickness);
}
// Quadratic Bezier takes 3 controls points
@@ -1704,7 +1719,7 @@ void ImDrawList::AddBezierQuadratic(const ImVec2& p1, const ImVec2& p2, const Im
PathLineTo(p1);
PathBezierQuadraticCurveTo(p2, p3, num_segments);
PathStroke(col, 0, thickness);
PathStroke(col, thickness);
}
void ImDrawList::AddText(ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end, float wrap_width, const ImVec4* cpu_fine_clip_rect)
@@ -1776,7 +1791,10 @@ void ImDrawList::AddImageRounded(ImTextureRef tex_ref, const ImVec2& p_min, cons
if ((col & IM_COL32_A_MASK) == 0)
return;
flags = FixRectCornerFlags(flags);
IM_ASSERT((flags & 0x0F) == 0 && "Misuse of legacy hardcoded ImDrawCornerFlags values!"); // If this assert triggers on legacy code: see comments in ImDrawList::PathRect().
if ((flags & ImDrawFlags_RoundCornersMask_) == 0)
flags |= ImDrawFlags_RoundCornersAll;
if (rounding < 0.5f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone)
{
AddImage(tex_ref, p_min, p_max, uv_min, uv_max, col);
@@ -2502,10 +2520,11 @@ void ImTextureData::DestroyPixels()
// - Default texture data encoded in ASCII
// - ImFontAtlas()
// - ImFontAtlas::Clear()
// - ImFontAtlas::CompactCache()
// - ImFontAtlas::ClearFonts()
// - ImFontAtlas::ClearInputData()
// - ImFontAtlas::ClearTexData()
// - ImFontAtlas::ClearFonts()
// - ImFontAtlas::CompactCache()
// - ImFontAtlas::SetFontLoader()
//-----------------------------------------------------------------------------
// - ImFontAtlasUpdateNewFrame()
// - ImFontAtlasTextureBlockConvert()
@@ -2666,7 +2685,9 @@ ImFontAtlas::~ImFontAtlas()
TexData = NULL;
}
// If you call this mid-frame, you would need to add new font and bind them!
// You probably should not call this directly. It is not well specified.
// If you want to replace all your fonts mid-frame, most likely you should instead call ClearFonts() then load the new fonts.
// Calling this mid-frame will discard the CPU-side copy of the texture data which is generally unreliable as you may have textures queued for creation or updates.
void ImFontAtlas::Clear()
{
bool backup_renderer_has_textures = RendererHasTextures;
@@ -2676,20 +2697,27 @@ void ImFontAtlas::Clear()
RendererHasTextures = backup_renderer_has_textures;
}
void ImFontAtlas::CompactCache()
void ImFontAtlas::ClearFonts()
{
ImFontAtlasTextureCompact(this);
}
void ImFontAtlas::SetFontLoader(const ImFontLoader* font_loader)
{
ImFontAtlasBuildSetupFontLoader(this, font_loader);
// FIXME-NEWATLAS: Illegal to remove currently bound font.
IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!");
for (ImFont* font : Fonts)
ImFontAtlasBuildNotifySetFont(this, font, NULL);
ImFontAtlasBuildDestroy(this);
ClearInputData();
Fonts.clear_delete();
TexIsBuilt = false;
for (ImDrawListSharedData* shared_data : DrawListSharedDatas)
if (shared_data->FontAtlas == this)
{
shared_data->Font = NULL;
shared_data->FontScale = shared_data->FontSize = 0.0f;
}
}
void ImFontAtlas::ClearInputData()
{
IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!");
for (ImFont* font : Fonts)
ImFontAtlasFontDestroyOutput(this, font);
for (ImFontConfig& font_cfg : Sources)
@@ -2713,22 +2741,14 @@ void ImFontAtlas::ClearTexData()
//Locked = true; // Hoped to be able to lock this down but some reload patterns may not be happy with it.
}
void ImFontAtlas::ClearFonts()
void ImFontAtlas::CompactCache()
{
// FIXME-NEWATLAS: Illegal to remove currently bound font.
IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!");
for (ImFont* font : Fonts)
ImFontAtlasBuildNotifySetFont(this, font, NULL);
ImFontAtlasBuildDestroy(this);
ClearInputData();
Fonts.clear_delete();
TexIsBuilt = false;
for (ImDrawListSharedData* shared_data : DrawListSharedDatas)
if (shared_data->FontAtlas == this)
{
shared_data->Font = NULL;
shared_data->FontScale = shared_data->FontSize = 0.0f;
}
ImFontAtlasTextureCompact(this);
}
void ImFontAtlas::SetFontLoader(const ImFontLoader* font_loader)
{
ImFontAtlasBuildSetupFontLoader(this, font_loader);
}
static void ImFontAtlasBuildUpdateRendererHasTexturesFromContext(ImFontAtlas* atlas)
@@ -2962,12 +2982,17 @@ void ImFontAtlasTextureBlockCopy(ImTextureData* src_tex, int src_x, int src_y, I
memcpy(dst_tex->GetPixelsAt(dst_x, dst_y + y), src_tex->GetPixelsAt(src_x, src_y + y), w * dst_tex->BytesPerPixel);
}
// Queue texture block update for renderer backend
void ImFontAtlasTextureBlockQueueUpload(ImFontAtlas* atlas, ImTextureData* tex, int x, int y, int w, int h)
{
ImTextureDataQueueUpload(tex, x, y, w, h);
atlas->TexIsBuilt = false;
}
// Queue texture block update for renderer backend
void ImTextureDataQueueUpload(ImTextureData* tex, int x, int y, int w, int h)
{
IM_ASSERT(tex->Status != ImTextureStatus_WantDestroy && tex->Status != ImTextureStatus_Destroyed);
IM_ASSERT(x >= 0 && x <= 0xFFFF && y >= 0 && y <= 0xFFFF && w >= 0 && x + w <= 0x10000 && h >= 0 && y + h <= 0x10000);
IM_UNUSED(atlas);
ImTextureRect req = { (unsigned short)x, (unsigned short)y, (unsigned short)w, (unsigned short)h };
int new_x1 = ImMax(tex->UpdateRect.w == 0 ? 0 : tex->UpdateRect.x + tex->UpdateRect.w, req.x + req.w);
@@ -2980,7 +3005,6 @@ void ImFontAtlasTextureBlockQueueUpload(ImFontAtlas* atlas, ImTextureData* tex,
tex->UsedRect.y = ImMin(tex->UsedRect.y, req.y);
tex->UsedRect.w = (unsigned short)(ImMax(tex->UsedRect.x + tex->UsedRect.w, req.x + req.w) - tex->UsedRect.x);
tex->UsedRect.h = (unsigned short)(ImMax(tex->UsedRect.y + tex->UsedRect.h, req.y + req.h) - tex->UsedRect.y);
atlas->TexIsBuilt = false;
// No need to queue if status is == ImTextureStatus_WantCreate
if (tex->Status == ImTextureStatus_OK || tex->Status == ImTextureStatus_WantUpdates)
@@ -3052,7 +3076,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg_in)
}
else
{
IM_ASSERT(Fonts.Size > 0 && "Cannot use MergeMode for the first font"); // When using MergeMode make sure that a font has already been added before.
IM_ASSERT(Fonts.Size > 0 && "Cannot use MergeMode for the first font!"); // When using MergeMode make sure that a font has already been added before.
font = font_cfg_in->DstFont ? font_cfg_in->DstFont : Fonts.back();
ImFontAtlasFontDiscardBakes(this, font, 0); // Need to discard bakes if the font was already used, because baked->FontLoaderDatas[] will change size. (#9162)
}
@@ -3080,6 +3104,11 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg_in)
IM_ASSERT(font_cfg->FontLoader->FontBakedLoadGlyph != NULL);
IM_ASSERT(font_cfg->FontLoader->LoaderInit == NULL && font_cfg->FontLoader->LoaderShutdown == NULL); // FIXME-NEWATLAS: Unsupported yet.
}
// | Target w/ Implicit RefSize | Target w/ Explicit RefSize |
// Adding w/ Implicit RefSize: | OK (same scale) | OK (same scale) |
// Adding w/ Explicit RefSize: | KO | OK (custom scale) |
if (font_cfg_in->MergeMode && font_cfg_in->SizePixels > 0)
IM_ASSERT((font->Flags & ImFontFlags_ImplicitRefSize) == 0 && "Cannot use MergeMode with an explicit reference size when the destination font used an implicit reference size!");
IM_ASSERT(font_cfg->FontLoaderData == NULL);
if (!ImFontAtlasFontSourceInit(this, font_cfg))
@@ -3147,7 +3176,10 @@ ImFont* ImFontAtlas::AddFontDefaultBitmap(const ImFontConfig* font_cfg_template)
if (!font_cfg_template)
font_cfg.PixelSnapH = true; // Prevents sub-integer scaling factors at lower-level layers.
if (font_cfg.SizePixels <= 0.0f)
{
font_cfg.SizePixels = 13.0f; // This only serves (1) as a reference for GlyphOffset.y setting and (2) as a default for pre-1.92 backend.
font_cfg.Flags |= ImFontFlags_ImplicitRefSize;
}
if (font_cfg.Name[0] == '\0')
ImFormatString(font_cfg.Name, IM_COUNTOF(font_cfg.Name), "ProggyClean.ttf");
font_cfg.EllipsisChar = (ImWchar)0x0085;
@@ -3172,7 +3204,10 @@ ImFont* ImFontAtlas::AddFontDefaultVector(const ImFontConfig* font_cfg_template)
if (!font_cfg_template)
font_cfg.PixelSnapH = true; // Precisely match ProggyClean, but prevents sub-integer scaling factors at lower-level layers.
if (font_cfg.SizePixels <= 0.0f)
{
font_cfg.SizePixels = 13.0f;
font_cfg.Flags |= ImFontFlags_ImplicitRefSize;
}
if (font_cfg.Name[0] == '\0')
ImFormatString(font_cfg.Name, IM_COUNTOF(font_cfg.Name), "ProggyForever.ttf");
font_cfg.ExtraSizeScale *= 1.015f; // Match ProggyClean
@@ -6016,7 +6051,7 @@ void ImGui::RenderCheckMark(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float
draw_list->PathLineTo(ImVec2(bx - third, by - third));
draw_list->PathLineTo(ImVec2(bx, by));
draw_list->PathLineTo(ImVec2(bx + third * 2.0f, by - third * 2.0f));
draw_list->PathStroke(col, 0, thickness);
draw_list->PathStroke(col, thickness);
}
// Render an arrow. 'pos' is position of the arrow tip. half_sz.x is length from base to tip. half_sz.y is length on each side.
+24 -13
View File
@@ -95,6 +95,10 @@ static void* (*GImGuiFreeTypeAllocFunc)(size_t size, void* user_data) = ImGuiFre
static void (*GImGuiFreeTypeFreeFunc)(void* ptr, void* user_data) = ImGuiFreeTypeDefaultFreeFunc;
static void* GImGuiFreeTypeAllocatorUserData = nullptr;
// Load struct
static ImFontLoader GImGuiFreeTypeLoader;
static char GImGuiFreeTypeLoaderName[48] = "FreeType";
// Lunasvg support
#ifdef IMGUI_ENABLE_FREETYPE_LUNASVG
static FT_Error ImGuiLunasvgPortInit(FT_Pointer* state);
@@ -146,6 +150,7 @@ struct ImGui_ImplFreeType_Data
{
FT_Library Library;
FT_MemoryRec_ MemoryManager;
char BackendName[48];
ImGui_ImplFreeType_Data() { memset((void*)this, 0, sizeof(*this)); }
};
@@ -359,6 +364,11 @@ static bool ImGui_ImplFreeType_LoaderInit(ImFontAtlas* atlas)
return false;
}
// Update ImFontLoader::Name field with linked version
FT_Int ver_linked_major, ver_linked_minor, ver_linked_patch;
FT_Library_Version(bd->Library, &ver_linked_major, &ver_linked_minor, &ver_linked_patch);
snprintf(GImGuiFreeTypeLoaderName, sizeof(GImGuiFreeTypeLoaderName), "FreeType (%d.%d.%d; %d.%d.%d)", FREETYPE_MAJOR, FREETYPE_MINOR, FREETYPE_PATCH, ver_linked_major, ver_linked_minor, ver_linked_patch);
// If you don't call FT_Add_Default_Modules() the rest of code may work, but FreeType won't use our custom allocator.
FT_Add_Default_Modules(bd->Library);
@@ -418,8 +428,9 @@ static bool ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* s
{
IM_UNUSED(atlas);
float size = baked->Size;
const float ref_size = baked->OwnerFont->Sources[0]->SizePixels;
if (src->MergeMode && src->SizePixels != 0.0f)
size *= (src->SizePixels / baked->OwnerFont->Sources[0]->SizePixels);
size *= (src->SizePixels / ref_size);
size *= src->ExtraSizeScale;
ImGui_ImplFreeType_FontSrcData* bd_font_data = (ImGui_ImplFreeType_FontSrcData*)src->FontLoaderData;
@@ -569,18 +580,18 @@ static bool ImGui_ImplFreetype_FontSrcContainsGlyph(ImFontAtlas* atlas, ImFontCo
const ImFontLoader* ImGuiFreeType::GetFontLoader()
{
static ImFontLoader loader;
loader.Name = "FreeType";
loader.LoaderInit = ImGui_ImplFreeType_LoaderInit;
loader.LoaderShutdown = ImGui_ImplFreeType_LoaderShutdown;
loader.FontSrcInit = ImGui_ImplFreeType_FontSrcInit;
loader.FontSrcDestroy = ImGui_ImplFreeType_FontSrcDestroy;
loader.FontSrcContainsGlyph = ImGui_ImplFreetype_FontSrcContainsGlyph;
loader.FontBakedInit = ImGui_ImplFreeType_FontBakedInit;
loader.FontBakedDestroy = ImGui_ImplFreeType_FontBakedDestroy;
loader.FontBakedLoadGlyph = ImGui_ImplFreeType_FontBakedLoadGlyph;
loader.FontBakedSrcLoaderDataSize = sizeof(ImGui_ImplFreeType_FontSrcBakedData);
return &loader;
ImFontLoader* loader = &GImGuiFreeTypeLoader;
loader->Name = GImGuiFreeTypeLoaderName; // Initially "FreeType" then updated during the call to ImGui_ImplFreeType_LoaderInit()
loader->LoaderInit = ImGui_ImplFreeType_LoaderInit;
loader->LoaderShutdown = ImGui_ImplFreeType_LoaderShutdown;
loader->FontSrcInit = ImGui_ImplFreeType_FontSrcInit;
loader->FontSrcDestroy = ImGui_ImplFreeType_FontSrcDestroy;
loader->FontSrcContainsGlyph = ImGui_ImplFreetype_FontSrcContainsGlyph;
loader->FontBakedInit = ImGui_ImplFreeType_FontBakedInit;
loader->FontBakedDestroy = ImGui_ImplFreeType_FontBakedDestroy;
loader->FontBakedLoadGlyph = ImGui_ImplFreeType_FontBakedLoadGlyph;
loader->FontBakedSrcLoaderDataSize = sizeof(ImGui_ImplFreeType_FontSrcBakedData);
return loader;
}
void ImGuiFreeType::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data)
+50 -27
View File
@@ -1,4 +1,4 @@
// dear imgui, v1.92.7
// dear imgui, v1.92.8
// (tables and columns code)
/*
@@ -240,6 +240,7 @@ Index of this file:
#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'int'/'void*', but argument X has type 'unsigned int'/'ImGuiWindow*'
#pragma GCC diagnostic ignored "-Wstrict-overflow"
#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead
#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may change value
#pragma GCC diagnostic ignored "-Wsign-conversion" // warning: conversion to 'xxxx' from 'xxxx' may change the sign of the result
#endif
@@ -1315,14 +1316,32 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
table->InnerWindow->DecoInnerSizeY1 = table_instance->LastFrozenHeight;
table_instance->LastFrozenHeight = 0.0f;
// Initial state
ImGuiWindow* inner_window = table->InnerWindow;
ImGuiBoxSelectState* bs = &g.BoxSelectState;
if (bs->Window == inner_window && bs->UnclipMode)
TableApplyExternalUnclipRect(table, bs->UnclipRect);
// Initial state
if (table->Flags & ImGuiTableFlags_NoClip)
table->DrawSplitter->SetCurrentChannel(inner_window->DrawList, TABLE_DRAW_CHANNEL_NOCLIP);
else
inner_window->DrawList->PushClipRect(inner_window->InnerClipRect.Min, inner_window->InnerClipRect.Max, false); // FIXME: use table->InnerClipRect?
}
// When starting a BeginMultiSelect() after table has been layout we update IsRequestOutput fields.
void ImGui::TableApplyExternalUnclipRect(ImGuiTable* table, ImRect& rect)
{
if (rect.IsInverted())
return;
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
{
ImGuiTableColumn* column = &table->Columns[column_n];
if (!column->IsRequestOutput)
if (rect.Overlaps(ImRect(column->MinX, table->WorkRect.Min.y, column->MaxX, FLT_MAX)))
column->IsRequestOutput = true;
}
}
// Process hit-testing on resizing borders. Actual size change will be applied in EndTable()
// - Set table->HoveredColumnBorder with a short delay/timer to reduce visual feedback noise.
void ImGui::TableUpdateBorders(ImGuiTable* table)
@@ -1436,12 +1455,12 @@ void ImGui::EndTable()
if (table->Flags & ImGuiTableFlags_ScrollX)
{
const float outer_padding_for_border = (table->Flags & ImGuiTableFlags_BordersOuterV) ? TABLE_BORDER_SIZE : 0.0f;
float max_pos_x = table->InnerWindow->DC.CursorMaxPos.x;
float max_pos_x = inner_window->DC.CursorMaxPos.x;
if (table->RightMostEnabledColumn != -1)
max_pos_x = ImMax(max_pos_x, table->Columns[table->RightMostEnabledColumn].WorkMaxX + table->CellPaddingX + table->OuterPaddingX - outer_padding_for_border);
if (table->ResizedColumn != -1)
max_pos_x = ImMax(max_pos_x, table->ResizeLockMinContentsX2);
table->InnerWindow->DC.CursorMaxPos.x = max_pos_x + table->TempData->AngledHeadersExtraWidth;
inner_window->DC.CursorMaxPos.x = max_pos_x + table->TempData->AngledHeadersExtraWidth;
}
// Pop clipping rect
@@ -1550,7 +1569,7 @@ void ImGui::EndTable()
}
else
{
table->InnerWindow->DC.TreeDepth--;
inner_window->DC.TreeDepth--;
ItemSize(table->OuterRect.GetSize());
ItemAdd(table->OuterRect, 0);
}
@@ -1565,13 +1584,12 @@ void ImGui::EndTable()
}
else if (temp_data->UserOuterSize.x <= 0.0f)
{
// Some references for this: #7651 + tests "table_reported_size", "table_reported_size_outer" equivalent Y block
// - Checking for ImGuiTableFlags_ScrollX/ScrollY flag makes us a frame ahead when disabling those flags.
// - FIXME-TABLE: Would make sense to pre-compute expected scrollbar visibility/sizes to generally save a frame of feedback.
const float inner_content_max_x = table->OuterRect.Min.x + table->ColumnsAutoFitWidth; // Slightly misleading name but used for code symmetry with inner_content_max_y
const float decoration_size = table->TempData->AngledHeadersExtraWidth + ((table->Flags & ImGuiTableFlags_ScrollY) ? inner_window->ScrollbarSizes.x : 0.0f);
outer_window->DC.IdealMaxPos.x = ImMax(outer_window->DC.IdealMaxPos.x, inner_content_max_x + decoration_size - temp_data->UserOuterSize.x);
outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, ImMin(table->OuterRect.Max.x, inner_content_max_x + decoration_size));
// Some references for this: #7651 + tests "table_reported_size", "table_reported_size_outer" equivalent Y block, #9352
// - FIXME-TABLE: Would make sense to pre-compute expected scrollbar visibility/sizes to generally save a frame of feedback? See broken test in 'table_reported_size_outer'
const float outer_content_max_x = table->OuterRect.Min.x + table->ColumnsAutoFitWidth;
const float decoration_size = table->TempData->AngledHeadersExtraWidth + ((inner_window != outer_window) ? inner_window->ScrollbarSizes.x : 0.0f);
outer_window->DC.IdealMaxPos.x = ImMax(outer_window->DC.IdealMaxPos.x, outer_content_max_x + decoration_size - temp_data->UserOuterSize.x);
outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, ImMin(table->OuterRect.Max.x, outer_content_max_x + decoration_size));
}
else
{
@@ -1579,9 +1597,12 @@ void ImGui::EndTable()
}
if (temp_data->UserOuterSize.y <= 0.0f)
{
const float decoration_size = (table->Flags & ImGuiTableFlags_ScrollX) ? inner_window->ScrollbarSizes.y : 0.0f;
outer_window->DC.IdealMaxPos.y = ImMax(outer_window->DC.IdealMaxPos.y, inner_content_max_y + decoration_size - temp_data->UserOuterSize.y);
outer_window->DC.CursorMaxPos.y = ImMax(backup_outer_max_pos.y, ImMin(table->OuterRect.Max.y, inner_content_max_y + decoration_size));
// (same comment as above)
const float outer_content_size_y = (inner_window == outer_window) ? (inner_content_max_y - table->InnerRect.Min.y) : (inner_content_max_y - inner_window->DC.CursorStartPos.y);
const float outer_content_max_y = table->OuterRect.Min.y + outer_content_size_y;
const float decoration_size = (inner_window != outer_window ? inner_window->ScrollbarSizes.y : 0.0f);
outer_window->DC.IdealMaxPos.y = ImMax(outer_window->DC.IdealMaxPos.y, outer_content_max_y + decoration_size - temp_data->UserOuterSize.y);
outer_window->DC.CursorMaxPos.y = ImMax(backup_outer_max_pos.y, ImMin(table->OuterRect.Max.y, outer_content_max_y + decoration_size));
}
else
{
@@ -1641,7 +1662,7 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo
ImGuiTable* table = g.CurrentTable;
IM_ASSERT_USER_ERROR_RET(table != NULL, "Call should only be done while in BeginTable() scope!");
IM_ASSERT_USER_ERROR_RET(table->DeclColumnsCount < table->ColumnsCount, "TableSetupColumn(): called too many times!");
IM_ASSERT_USER_ERROR_RET(table->IsLayoutLocked == false, "TableSetupColumn(): need to call before first row!");
IM_ASSERT_USER_ERROR_RET(table->IsLayoutLocked == false, "TableSetupColumn(): need to call before first row!"); // Table layout is locked when submitting a row or when calling BeginMultiSelect() with box-select.
IM_ASSERT((flags & ImGuiTableColumnFlags_StatusMask_) == 0 && "Illegal to pass StatusMask values to TableSetupColumn()");
ImGuiTableColumn* column = &table->Columns[table->DeclColumnsCount];
@@ -2053,11 +2074,11 @@ void ImGui::TableEndRow(ImGuiTable* table)
// Draw top border
if (top_border_col && bg_y1 >= table->BgClipRect.Min.y && bg_y1 < table->BgClipRect.Max.y)
window->DrawList->AddLine(ImVec2(table->BorderX1, bg_y1), ImVec2(table->BorderX2, bg_y1), top_border_col, border_size);
window->DrawList->AddLineH(table->BorderX1, table->BorderX2, bg_y1, top_border_col, border_size);
// Draw bottom border at the row unfreezing mark (always strong)
if (draw_strong_bottom_border && bg_y2 >= table->BgClipRect.Min.y && bg_y2 < table->BgClipRect.Max.y)
window->DrawList->AddLine(ImVec2(table->BorderX1, bg_y2), ImVec2(table->BorderX2, bg_y2), table->BorderColorStrong, border_size);
window->DrawList->AddLineH(table->BorderX1, table->BorderX2, bg_y2, table->BorderColorStrong, border_size);
}
// End frozen rows (when we are past the last frozen row line, teleport cursor and alter clipping rectangle)
@@ -2834,7 +2855,7 @@ void ImGui::TableDrawBorders(ImGuiTable* table)
else if ((table->Flags & (ImGuiTableFlags_NoBordersInBodyUntilResize | ImGuiTableFlags_NoBordersInBody)) == 0)
draw_y2 = draw_y2_body;
if (draw_y2 > draw_y1)
inner_drawlist->AddLine(ImVec2(column->MaxX, draw_y1), ImVec2(column->MaxX, draw_y2), TableGetColumnBorderCol(table, order_n, column_n), border_size);
inner_drawlist->AddLineV(column->MaxX, draw_y1, draw_y2, TableGetColumnBorderCol(table, order_n, column_n), border_size);
}
}
@@ -2851,17 +2872,17 @@ void ImGui::TableDrawBorders(ImGuiTable* table)
const ImU32 outer_col = table->BorderColorStrong;
if ((table->Flags & ImGuiTableFlags_BordersOuter) == ImGuiTableFlags_BordersOuter)
{
inner_drawlist->AddRect(outer_border.Min, outer_border.Max, outer_col, 0.0f, 0, border_size);
inner_drawlist->AddRect(outer_border.Min, outer_border.Max, outer_col, 0.0f, border_size);
}
else if (table->Flags & ImGuiTableFlags_BordersOuterV)
{
inner_drawlist->AddLine(outer_border.Min, ImVec2(outer_border.Min.x, outer_border.Max.y), outer_col, border_size);
inner_drawlist->AddLine(ImVec2(outer_border.Max.x, outer_border.Min.y), outer_border.Max, outer_col, border_size);
inner_drawlist->AddLineV(outer_border.Min.x, outer_border.Min.y, outer_border.Max.y, outer_col, border_size);
inner_drawlist->AddLineV(outer_border.Max.x, outer_border.Min.y, outer_border.Max.y, outer_col, border_size);
}
else if (table->Flags & ImGuiTableFlags_BordersOuterH)
{
inner_drawlist->AddLine(outer_border.Min, ImVec2(outer_border.Max.x, outer_border.Min.y), outer_col, border_size);
inner_drawlist->AddLine(ImVec2(outer_border.Min.x, outer_border.Max.y), outer_border.Max, outer_col, border_size);
inner_drawlist->AddLineH(outer_border.Min.x, outer_border.Max.x, outer_border.Min.y, outer_col, border_size);
inner_drawlist->AddLineH(outer_border.Min.x, outer_border.Max.x, outer_border.Max.y, outer_col, border_size);
}
}
if ((table->Flags & ImGuiTableFlags_BordersInnerH) && table->RowPosY2 < table->OuterRect.Max.y)
@@ -2869,7 +2890,7 @@ void ImGui::TableDrawBorders(ImGuiTable* table)
// Draw bottom-most row border between it is above outer border.
const float border_y = table->RowPosY2;
if (border_y >= table->BgClipRect.Min.y && border_y < table->BgClipRect.Max.y)
inner_drawlist->AddLine(ImVec2(table->BorderX1, border_y), ImVec2(table->BorderX2, border_y), table->BorderColorLight, border_size);
inner_drawlist->AddLineH(table->BorderX1, table->BorderX2, border_y, table->BorderColorLight, border_size);
}
inner_drawlist->PopClipRect();
@@ -3174,7 +3195,7 @@ void ImGui::TableHeader(const char* label)
if (label == NULL)
label = "";
const char* label_end = FindRenderedTextEnd(label);
ImVec2 label_size = CalcTextSize(label, label_end, true);
ImVec2 label_size = CalcTextSize(label, label_end, false);
ImVec2 label_pos = window->DC.CursorPos;
// If we already got a row height, there's use that.
@@ -3293,6 +3314,8 @@ void ImGui::TableHeader(const char* label)
// We don't use BeginPopupContextItem() because we want the popup to stay up even after the column is hidden
if (IsPopupOpenRequestForItem(ImGuiPopupFlags_None, id))
TableOpenContextMenu(column_n);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
}
// Unlike TableHeadersRow() it is not expected that you can reimplement or customize this with custom widgets.
@@ -4595,7 +4618,7 @@ void ImGui::EndColumns()
// Draw column
const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : hovered ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator);
const float xi = IM_TRUNC(x);
window->DrawList->AddLine(ImVec2(xi, y1 + 1.0f), ImVec2(xi, y2), col);
window->DrawList->AddLineV(xi, y1 + 1.0f, y2, col);
}
// Apply dragging after drawing the column lines, so our rendered lines are in sync with how items were displayed during the frame.
+256 -104
View File
@@ -1,4 +1,4 @@
// dear imgui, v1.92.7
// dear imgui, v1.92.8
// (widgets code)
/*
@@ -92,6 +92,7 @@ Index of this file:
#pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when simplifying division / ..when changing X +- C1 cmp C2 to X cmp C2 -+ C1
#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead
#pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers
#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may change value
#pragma GCC diagnostic ignored "-Wsign-conversion" // warning: conversion to 'xxxx' from 'xxxx' may change the sign of the result
#endif
@@ -401,7 +402,8 @@ void ImGui::LabelTextV(const char* label, const char* fmt, va_list args)
const char* value_text_begin, *value_text_end;
ImFormatStringToTempBufferV(&value_text_begin, &value_text_end, fmt, args);
const ImVec2 value_size = CalcTextSize(value_text_begin, value_text_end, false);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const char* label_end = FindRenderedTextEnd(label);
const ImVec2 label_size = CalcTextSize(label, label_end, false);
const ImVec2 pos = window->DC.CursorPos;
const ImRect value_bb(pos, pos + ImVec2(w, value_size.y + style.FramePadding.y * 2));
@@ -413,7 +415,7 @@ void ImGui::LabelTextV(const char* label, const char* fmt, va_list args)
// Render
RenderTextClipped(value_bb.Min + style.FramePadding, value_bb.Max, value_text_begin, value_text_end, &value_size, ImVec2(0.0f, 0.0f));
if (label_size.x > 0.0f)
RenderText(ImVec2(value_bb.Max.x + style.ItemInnerSpacing.x, value_bb.Min.y + style.FramePadding.y), label);
RenderText(ImVec2(value_bb.Max.x + style.ItemInnerSpacing.x, value_bb.Min.y + style.FramePadding.y), label, label_end, false);
}
void ImGui::BulletText(const char* fmt, ...)
@@ -788,7 +790,8 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const char* label_end = FindRenderedTextEnd(label);
const ImVec2 label_size = CalcTextSize(label, label_end, false);
ImVec2 pos = window->DC.CursorPos;
if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag)
@@ -810,7 +813,7 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags
if (g.LogEnabled)
LogSetNextTextDecoration("[", "]");
RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb);
RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, label_end, &label_size, style.ButtonTextAlign, &bb);
// Automatically close popups
//if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))
@@ -975,7 +978,7 @@ ImRect ImGui::GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis)
const float scrollbar_size = window->ScrollbarSizes[axis ^ 1]; // (ScrollbarSizes.x = width of Y scrollbar; ScrollbarSizes.y = height of X scrollbar)
IM_ASSERT(scrollbar_size >= 0.0f);
const float border_size = IM_ROUND(window->WindowBorderSize * 0.5f);
const float border_top = (window->Flags & ImGuiWindowFlags_MenuBar) ? IM_ROUND(g.Style.FrameBorderSize * 0.5f) : 0.0f;
const float border_top = (window->Flags & ImGuiWindowFlags_MenuBar) ? IM_ROUND(g.Style.FrameBorderSize * 0.5f) : (window->Flags & ImGuiWindowFlags_NoTitleBar) ? border_size : 0;
if (axis == ImGuiAxis_X)
return ImRect(inner_rect.Min.x + border_size, ImMax(outer_rect.Min.y + border_size, outer_rect.Max.y - border_size - scrollbar_size), inner_rect.Max.x - border_size, outer_rect.Max.y - border_size);
else
@@ -1148,7 +1151,7 @@ void ImGui::ImageWithBg(ImTextureRef tex_ref, const ImVec2& image_size, const Im
else
window->DrawList->AddImage(tex_ref, bb.Min + padding, bb.Max - padding, uv0, uv1, GetColorU32(tint_col));
if (g.Style.ImageBorderSize > 0.0f)
window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_Border), rounding, ImDrawFlags_None, g.Style.ImageBorderSize);
window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_Border), rounding, g.Style.ImageBorderSize);
}
void ImGui::Image(ImTextureRef tex_ref, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1)
@@ -1243,7 +1246,8 @@ bool ImGui::Checkbox(const char* label, bool* v)
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const char* label_end = FindRenderedTextEnd(label);
const ImVec2 label_size = CalcTextSize(label, label_end, false);
const float square_sz = GetFrameHeight();
const ImVec2 pos = window->DC.CursorPos;
@@ -1284,8 +1288,9 @@ bool ImGui::Checkbox(const char* label, bool* v)
if (is_visible)
{
RenderNavCursor(total_bb, id);
RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding);
ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : (mixed_value || checked) ? ImGuiCol_CheckboxSelectedBg : ImGuiCol_FrameBg);
ImU32 check_col = GetColorU32(ImGuiCol_CheckMark);
RenderFrame(check_bb.Min, check_bb.Max, bg_col, true, style.FrameRounding);
if (mixed_value)
{
// Undocumented tristate/mixed/indeterminate checkbox (#2644)
@@ -1303,7 +1308,7 @@ bool ImGui::Checkbox(const char* label, bool* v)
if (g.LogEnabled)
LogRenderedText(&label_pos, mixed_value ? "[~]" : *v ? "[x]" : "[ ]");
if (is_visible && label_size.x > 0.0f)
RenderText(label_pos, label);
RenderText(label_pos, label, label_end, false);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0));
return pressed;
@@ -1365,7 +1370,8 @@ bool ImGui::RadioButton(const char* label, bool active)
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const char* label_end = FindRenderedTextEnd(label);
const ImVec2 label_size = CalcTextSize(label, label_end, false);
const float square_sz = GetFrameHeight();
const ImVec2 pos = window->DC.CursorPos;
@@ -1404,7 +1410,7 @@ bool ImGui::RadioButton(const char* label, bool active)
if (g.LogEnabled)
LogRenderedText(&label_pos, active ? "(x)" : "( )");
if (label_size.x > 0.0f)
RenderText(label_pos, label);
RenderText(label_pos, label, label_end, false);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
return pressed;
@@ -1520,7 +1526,7 @@ bool ImGui::TextLink(const char* label)
const char* label_end = FindRenderedTextEnd(label);
ImVec2 pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);
ImVec2 size = CalcTextSize(label, label_end, true);
ImVec2 size = CalcTextSize(label, label_end, false);
ImRect bb(pos, pos + size);
ItemSize(size, 0.0f);
if (!ItemAdd(bb, id))
@@ -1551,10 +1557,10 @@ bool ImGui::TextLink(const char* label)
}
float line_y = bb.Max.y + ImFloor(g.FontBaked->Descent * g.FontBakedScale * 0.20f);
window->DrawList->AddLine(ImVec2(bb.Min.x, line_y), ImVec2(bb.Max.x, line_y), GetColorU32(line_colf), 1.0f * (float)(int)g.Style._MainScale); // FIXME-TEXT: Underline mode // FIXME-DPI
window->DrawList->AddLineH(bb.Min.x, bb.Max.x, line_y, GetColorU32(line_colf), 1.0f * (float)(int)g.Style._MainScale); // FIXME-TEXT: Underline mode // FIXME-DPI
PushStyleColor(ImGuiCol_Text, GetColorU32(text_colf));
RenderText(bb.Min, label, label_end);
RenderText(bb.Min, label, label_end, false);
PopStyleColor();
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
@@ -1724,7 +1730,7 @@ void ImGui::Separator()
if (window->DC.CurrentColumns)
flags |= ImGuiSeparatorFlags_SpanAllColumns;
SeparatorEx(flags, g.Style.SeparatorSize);
SeparatorEx(flags, ImMax(g.Style.SeparatorSize, 1.0f));
}
void ImGui::SeparatorTextEx(ImGuiID id, const char* label, const char* label_end, float extra_w)
@@ -1761,9 +1767,9 @@ void ImGui::SeparatorTextEx(ImGuiID id, const char* label, const char* label_end
const float sep1_x2 = label_pos.x - style.ItemSpacing.x;
const float sep2_x1 = label_pos.x + label_size.x + extra_w + style.ItemSpacing.x;
if (sep1_x2 > sep1_x1 && separator_thickness > 0.0f)
window->DrawList->AddLine(ImVec2(sep1_x1, seps_y), ImVec2(sep1_x2, seps_y), separator_col, separator_thickness);
window->DrawList->AddLineH(sep1_x1, sep1_x2, seps_y, separator_col, separator_thickness);
if (sep2_x2 > sep2_x1 && separator_thickness > 0.0f)
window->DrawList->AddLine(ImVec2(sep2_x1, seps_y), ImVec2(sep2_x2, seps_y), separator_col, separator_thickness);
window->DrawList->AddLineH(sep2_x1, sep2_x2, seps_y, separator_col, separator_thickness);
if (g.LogEnabled)
LogSetNextTextDecoration("---", NULL);
RenderTextEllipsis(window->DrawList, label_pos, ImVec2(bb.Max.x, bb.Max.y + style.ItemSpacing.y), bb.Max.x, label, label_end, &label_size);
@@ -1773,7 +1779,7 @@ void ImGui::SeparatorTextEx(ImGuiID id, const char* label, const char* label_end
if (g.LogEnabled)
LogText("---");
if (separator_thickness > 0.0f)
window->DrawList->AddLine(ImVec2(sep1_x1, seps_y), ImVec2(sep2_x2, seps_y), separator_col, separator_thickness);
window->DrawList->AddLineH(sep1_x1, sep2_x2, seps_y, separator_col, separator_thickness);
}
}
@@ -1944,8 +1950,9 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF
IM_ASSERT((flags & (ImGuiComboFlags_NoPreview | (ImGuiComboFlags)ImGuiComboFlags_CustomPreview)) == 0);
const float arrow_size = (flags & ImGuiComboFlags_NoArrowButton) ? 0.0f : GetFrameHeight();
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const float preview_width = ((flags & ImGuiComboFlags_WidthFitPreview) && (preview_value != NULL)) ? CalcTextSize(preview_value, NULL, true).x : 0.0f;
const char* label_end = FindRenderedTextEnd(label);
const ImVec2 label_size = CalcTextSize(label, label_end, false);
const float preview_width = ((flags & ImGuiComboFlags_WidthFitPreview) && (preview_value != NULL)) ? CalcTextSize(preview_value, NULL, false).x : 0.0f;
const float w = (flags & ImGuiComboFlags_NoPreview) ? arrow_size : ((flags & ImGuiComboFlags_WidthFitPreview) ? (arrow_size + preview_width + style.FramePadding.x * 2.0f) : CalcItemWidth());
const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f));
const ImRect total_bb(bb.Min, bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
@@ -1996,7 +2003,7 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF
RenderTextClipped(bb.Min + style.FramePadding, ImVec2(value_x2, bb.Max.y), preview_value, NULL, NULL);
}
if (label_size.x > 0)
RenderText(ImVec2(bb.Max.x + style.ItemInnerSpacing.x, bb.Min.y + style.FramePadding.y), label);
RenderText(ImVec2(bb.Max.x + style.ItemInnerSpacing.x, bb.Min.y + style.FramePadding.y), label, label_end, false);
if (!popup_open)
return false;
@@ -2369,12 +2376,17 @@ bool ImGui::DataTypeApplyFromText(const char* buf, ImGuiDataType data_type, void
// Sanitize format
// - For float/double we have to ignore format with precision (e.g. "%.2f") because sscanf doesn't take them in, so force them into %f and %lf
// - In theory could treat empty format as using default, but this would only cover rare/bizarre case of using InputScalar() + integer + format string without %.
char format_sanitized[32];
if (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double)
{
format = type_info->ScanFmt;
}
else
{
format = ImParseFormatSanitizeForScanning(format, format_sanitized, IM_COUNTOF(format_sanitized));
if (format[0] == '\0')
format = type_info->ScanFmt; // Format doesn't want us to show the number currently, but we still need to parse the resulting input
}
// Small types need a 32-bit buffer to receive the result from scanf()
int v32 = 0;
@@ -2709,7 +2721,8 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data,
const float w = CalcItemWidth();
const ImU32 color_marker = (g.NextItemData.HasFlags & ImGuiNextItemDataFlags_HasColorMarker) ? g.NextItemData.ColorMarker : 0;
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const char* label_end = FindRenderedTextEnd(label);
const ImVec2 label_size = CalcTextSize(label, label_end, false);
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f));
const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
@@ -2785,7 +2798,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data,
RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f));
if (label_size.x > 0.0f)
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label, label_end, false);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | (temp_input_allowed ? ImGuiItemStatusFlags_Inputable : 0));
return value_changed;
@@ -3310,7 +3323,8 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat
const float w = CalcItemWidth();
const ImU32 color_marker = (g.NextItemData.HasFlags & ImGuiNextItemDataFlags_HasColorMarker) ? g.NextItemData.ColorMarker : 0;
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const char* label_end = FindRenderedTextEnd(label);
const ImVec2 label_size = CalcTextSize(label, label_end, false);
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f));
const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
@@ -3382,7 +3396,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat
RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f));
if (label_size.x > 0.0f)
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label, label_end, false);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | (temp_input_allowed ? ImGuiItemStatusFlags_Inputable : 0));
return value_changed;
@@ -3487,7 +3501,8 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d
const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const char* label_end = FindRenderedTextEnd(label);
const ImVec2 label_size = CalcTextSize(label, label_end, false);
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size);
const ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
@@ -3532,8 +3547,9 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d
const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_COUNTOF(value_buf), data_type, p_data, format);
RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.0f));
if (label_size.x > 0.0f)
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label, label_end, false);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
return value_changed;
}
@@ -3556,7 +3572,8 @@ bool ImGui::VSliderInt(const char* label, const ImVec2& size, int* v, int v_min,
// - ImParseFormatSanitizeForPrinting() [Internal]
// - ImParseFormatSanitizeForScanning() [Internal]
// - ImParseFormatPrecision() [Internal]
// - TempInputTextScalar() [Internal]
// - TempInputText() [Internal]
// - TempInputScalar() [Internal]
// - InputScalar()
// - InputScalarN()
// - InputFloat()
@@ -3785,7 +3802,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data
ImGuiContext& g = *GImGui;
ImGuiStyle& style = g.Style;
IM_ASSERT((flags & ImGuiInputTextFlags_EnterReturnsTrue) == 0); // Not supported by InputScalar(). Please open an issue if you this would be useful to you. Otherwise use IsItemDeactivatedAfterEdit()!
//IM_ASSERT((flags & ImGuiInputTextFlags_EnterReturnsTrue) == 0); // Not supported by InputScalar(). Please open an issue if you this would be useful to you. Otherwise use IsItemDeactivatedAfterEdit()!
if (format == NULL)
format = DataTypeGetInfo(data_type)->PrintFmt;
@@ -3822,7 +3839,8 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data
}
// Apply
bool value_changed = ret ? DataTypeApplyFromText(buf, data_type, p_data, format, (flags & ImGuiInputTextFlags_ParseEmptyRefVal) ? p_data_default : NULL) : false;
bool input_edited = (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_EditedInternal) != 0; // We would be using 'ret' if ImGuiInputTextFlags_EnterReturnsTrue was not involved.
bool value_changed = input_edited ? DataTypeApplyFromText(buf, data_type, p_data, format, (flags & ImGuiInputTextFlags_ParseEmptyRefVal) ? p_data_default : NULL) : false;
// Step buttons
if (has_step_buttons)
@@ -3836,13 +3854,13 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data
if (ButtonEx("-", ImVec2(button_size, button_size)))
{
DataTypeApplyOp(data_type, '-', p_data, p_data, g.IO.KeyCtrl && p_step_fast ? p_step_fast : p_step);
value_changed = true;
value_changed = ret = true;
}
SameLine(0, style.ItemInnerSpacing.x);
if (ButtonEx("+", ImVec2(button_size, button_size)))
{
DataTypeApplyOp(data_type, '+', p_data, p_data, g.IO.KeyCtrl && p_step_fast ? p_step_fast : p_step);
value_changed = true;
value_changed = ret = true;
}
PopItemFlag();
if (flags & ImGuiInputTextFlags_ReadOnly)
@@ -3864,6 +3882,8 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data
if (value_changed)
MarkItemEdited(g.LastItemData.ID);
if (flags & ImGuiInputTextFlags_EnterReturnsTrue)
return ret;
return value_changed;
}
@@ -4513,6 +4533,9 @@ static bool InputTextFilterCharacter(ImGuiContext* ctx, ImGuiInputTextState* sta
callback_data.EventFlag = ImGuiInputTextFlags_CallbackCharFilter;
callback_data.EventChar = (ImWchar)c;
callback_data.EventActivated = (g.ActiveId == state->ID && g.ActiveIdIsJustActivated);
callback_data.CursorPos = state->Stb->cursor;
callback_data.SelectionStart = state->Stb->select_start;
callback_data.SelectionEnd = state->Stb->select_end;
callback_data.UserData = user_data;
if (callback(&callback_data) != 0)
return false;
@@ -4561,6 +4584,7 @@ void ImGui::InputTextDeactivateHook(ImGuiID id)
ImGuiInputTextState* state = &g.InputTextState;
if (id == 0 || state->ID != id)
return;
//IMGUI_DEBUG_LOG_ACTIVEID("InputTextDeactivateHook() id = 0x%08X\n", id);
g.InputTextDeactivatedState.ID = state->ID;
if (state->Flags & ImGuiInputTextFlags_ReadOnly)
{
@@ -4695,7 +4719,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
if (is_multiline) // Open group before calling GetID() because groups tracks id created within their scope (including the scrollbar)
BeginGroup();
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const char* label_end = FindRenderedTextEnd(label);
const ImVec2 label_size = CalcTextSize(label, label_end, false);
const ImVec2 frame_size = CalcItemSize(size_arg, CalcItemWidth(), (is_multiline ? g.FontSize * 8.0f : label_size.y) + style.FramePadding.y * 2.0f); // Arbitrary default of 8 lines high for multi-line
const ImVec2 total_size = ImVec2(frame_size.x + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), frame_size.y);
@@ -4709,7 +4734,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
{
ImVec2 backup_pos = window->DC.CursorPos;
ItemSize(total_bb, style.FramePadding.y);
if (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemFlags_Inputable))
bool no_clip = (g.InputTextDeactivatedState.ID == id) || (g.ActiveId == id) || (id == g.NavActivateId); // Mimic some of ItemAdd() logic + add InputTextDeactivatedState.ID check.
if (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemFlags_Inputable) && !no_clip)
{
EndGroup();
return false;
@@ -4735,7 +4761,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
g.NavActivateId = backup_activate_id;
PopStyleVar(3);
PopStyleColor();
if (!child_visible)
if (!child_visible && !no_clip)
{
EndChild();
EndGroup();
@@ -4799,7 +4825,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
float scroll_y = is_multiline ? draw_window->Scroll.y : FLT_MAX;
const bool init_reload_from_user_buf = (state != NULL && state->WantReloadUserBuf);
const bool init_changed_specs = (state != NULL && state->Stb->single_line != !is_multiline); // state != NULL means its our state.
const bool init_changed_specs_multiline = (state != NULL && (state->Stb->single_line != !is_multiline)); // state != NULL means its our state.
const bool init_changed_specs_readonly = (state != NULL && ((state->Flags ^ flags) & ImGuiInputTextFlags_ReadOnly)); // state != NULL means its our state.
const bool init_make_active = (input_requested_by_user || input_requested_by_nav || input_requested_by_reactivate || user_scroll_finish);
if (init_reload_from_user_buf)
{
@@ -4813,7 +4840,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
state->Stb->select_start = state->ReloadSelectionStart;
state->Stb->cursor = state->Stb->select_end = state->ReloadSelectionEnd; // will be clamped to bounds below
}
else if ((init_make_active && g.ActiveId != id) || init_changed_specs)
else if ((init_make_active && g.ActiveId != id) || init_changed_specs_multiline || init_changed_specs_readonly)
{
// Access state even if we don't own it yet.
state = &g.InputTextState;
@@ -4834,8 +4861,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
// Preserve cursor position and undo/redo stack if we come back to same widget
// FIXME: Since we reworked this on 2022/06, may want to differentiate recycle_cursor vs recycle_undostate?
bool recycle_state = (state->ID == id && !init_changed_specs);
if (recycle_state && (state->TextLen != buf_len || (state->TextA.Data == NULL || strncmp(state->TextA.Data, buf, buf_len) != 0)))
bool recycle_state = (state->ID == id && !init_changed_specs_multiline);
if (recycle_state && !init_changed_specs_readonly && (state->TextLen != buf_len || (state->TextA.Data == NULL || strncmp(state->TextA.Data, buf, buf_len) != 0)))
recycle_state = false;
// Start edition
@@ -4873,7 +4900,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
}
const bool is_osx = io.ConfigMacOSXBehaviors;
if (g.ActiveId != id && init_make_active)
if (init_make_active && g.ActiveId != id)
{
IM_ASSERT(state && state->ID == id);
SetActiveID(id, window);
@@ -4944,13 +4971,17 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
if (is_password && !is_displaying_hint)
PushPasswordFont();
// Word-wrapping: attempt to keep cursor in view while resizing frame/parent
// FIXME-WORDWRAP: It would be better to preserve same relative offset.
if (is_wordwrap && state != NULL && state->ID == id && state->WrapWidth != wrap_width)
if (state != NULL && state->ID == id)
{
state->CursorCenterY = true;
state->WrapWidth = wrap_width;
render_cursor = true;
state->Flags = flags;
// Word-wrapping: attempt to keep cursor in view while resizing frame/parent (FIXME-WORDWRAP: would be better to preserve same relative offset)
if (is_wordwrap && state->WrapWidth != wrap_width)
{
state->CursorCenterY = true;
state->WrapWidth = wrap_width;
render_cursor = true;
}
}
// Process mouse inputs and character inputs
@@ -4959,7 +4990,6 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
IM_ASSERT(state != NULL);
state->EditedThisFrame = false;
state->BufCapacity = buf_size;
state->Flags = flags;
state->WrapWidth = wrap_width;
// Although we are active we don't prevent mouse from hovering other elements unless we are interacting right now with the widget.
@@ -5611,7 +5641,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
ImVec2 cursor_screen_pos = ImTrunc(draw_pos + cursor_offset - draw_scroll);
ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y - g.FontSize + 0.5f, cursor_screen_pos.x + 1.0f, cursor_screen_pos.y - 1.5f);
if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect))
draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_InputTextCursor), 1.0f * (float)(int)style._MainScale); // FIXME-DPI: Cursor thickness (#7031)
draw_window->DrawList->AddLineV(cursor_screen_rect.Min.x, cursor_screen_rect.Min.y, cursor_screen_rect.Max.y, GetColorU32(ImGuiCol_InputTextCursor), 1.0f * (float)(int)style._MainScale); // FIXME-DPI: Cursor thickness (#7031)
// Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.)
// This is required for some backends (SDL3) to start emitting character/text inputs.
@@ -5659,7 +5689,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
}
if (label_size.x > 0)
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label, label_end, false);
if (value_changed)
MarkItemEdited(id);
@@ -6325,7 +6355,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
const float a1 = (n+1.0f)/6.0f * 2.0f * IM_PI + aeps;
const int vert_start_idx = draw_list->VtxBuffer.Size;
draw_list->PathArcTo(wheel_center, (wheel_r_inner + wheel_r_outer)*0.5f, a0, a1, segment_per_arc);
draw_list->PathStroke(col_white, 0, wheel_thickness);
draw_list->PathStroke(col_white, wheel_thickness);
const int vert_end_idx = draw_list->VtxBuffer.Size;
// Paint colors over existing vertices
@@ -6469,7 +6499,7 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl
if (g.Style.FrameBorderSize > 0.0f)
RenderFrameBorder(bb.Min, bb.Max, rounding);
else
window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding, 0, 1.0f * (float)(int)g.Style._MainScale); // Color buttons are often in need of some sort of border // FIXME-DPI
window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding, 1.0f * (float)(int)g.Style._MainScale); // Color buttons are often in need of some sort of border // FIXME-DPI
}
// Drag and Drop Source
@@ -7142,11 +7172,11 @@ void ImGui::TreeNodeDrawLineToChildNode(const ImVec2& target_pos)
window->DrawList->PathArcToFast(ImVec2(x1, y - rounding), rounding, 6, 3);
if (x1 < x2)
window->DrawList->PathLineTo(ImVec2(x2, y));
window->DrawList->PathStroke(GetColorU32(ImGuiCol_TreeLines), ImDrawFlags_None, g.Style.TreeLinesSize);
window->DrawList->PathStroke(GetColorU32(ImGuiCol_TreeLines), g.Style.TreeLinesSize);
}
else
{
window->DrawList->AddLine(ImVec2(x1, y), ImVec2(x2, y), GetColorU32(ImGuiCol_TreeLines), g.Style.TreeLinesSize);
window->DrawList->AddLineH(x1, x2, y, GetColorU32(ImGuiCol_TreeLines), g.Style.TreeLinesSize);
}
}
@@ -7172,7 +7202,7 @@ void ImGui::TreeNodeDrawLineToTreePop(const ImGuiTreeNodeStackData* data)
float x = ImTrunc(data->DrawLinesX1);
if (data->DrawLinesTableColumn != -1)
TablePushColumnChannel(data->DrawLinesTableColumn);
window->DrawList->AddLine(ImVec2(x, y1), ImVec2(x, y2), GetColorU32(ImGuiCol_TreeLines), g.Style.TreeLinesSize);
window->DrawList->AddLineV(x, y1, y2, GetColorU32(ImGuiCol_TreeLines), g.Style.TreeLinesSize);
if (data->DrawLinesTableColumn != -1)
TablePopColumnChannel();
}
@@ -7331,7 +7361,8 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
// Submit label or explicit size to ItemSize(), whereas ItemAdd() will submit a larger/spanning rectangle.
ImGuiID id = window->GetID(label);
ImVec2 label_size = CalcTextSize(label, NULL, true);
const char* label_end = FindRenderedTextEnd(label);
ImVec2 label_size = CalcTextSize(label, label_end, false);
ImVec2 size(size_arg.x != 0.0f ? size_arg.x : label_size.x, size_arg.y != 0.0f ? size_arg.y : label_size.y);
ImVec2 pos = window->DC.CursorPos;
pos.y += window->DC.CurrLineTextBaseOffset;
@@ -7486,7 +7517,11 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
// Text stays at the submission position. Alignment/clipping extents ignore SpanAllColumns.
if (is_visible)
RenderTextClipped(pos, ImVec2(ImMin(pos.x + size.x, window->WorkRect.Max.x), pos.y + size.y), label, NULL, &label_size, style.SelectableTextAlign, &bb);
RenderTextClipped(pos, ImVec2(ImMin(pos.x + size.x, window->WorkRect.Max.x), pos.y + size.y), label, label_end, &label_size, style.SelectableTextAlign, &bb);
#ifdef IMGUI_DEBUG_BOXSELECT
if (g.BoxSelectState.UnclipMode) { GetForegroundDrawList()->AddText(pos, IM_COL32(255,255,0,200), label, label_end); }
#endif
// Automatically close popups
if (pressed && !auto_selected && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_NoAutoClosePopups) && (g.LastItemData.ItemFlags & ImGuiItemFlags_AutoClosePopups))
@@ -7803,7 +7838,7 @@ bool ImGui::BeginBoxSelect(const ImRect& scope_rect, ImGuiWindow* window, ImGuiI
return false;
// Current frame absolute prev/current rectangles are used to toggle selection.
// They are derived from positions relative to scrolling space.
// They are derived from positions relative to scrolling space, so "previous" rectangle is reprojected for current frame coordinates.
ImVec2 start_pos_abs = WindowPosRelToAbs(window, bs->StartPosRel);
ImVec2 prev_end_pos_abs = WindowPosRelToAbs(window, bs->EndPosRel); // Clamped already
ImVec2 curr_end_pos_abs = g.IO.MousePos;
@@ -7813,20 +7848,69 @@ bool ImGui::BeginBoxSelect(const ImRect& scope_rect, ImGuiWindow* window, ImGuiI
bs->BoxSelectRectPrev.Max = ImMax(start_pos_abs, prev_end_pos_abs);
bs->BoxSelectRectCurr.Min = ImMin(start_pos_abs, curr_end_pos_abs);
bs->BoxSelectRectCurr.Max = ImMax(start_pos_abs, curr_end_pos_abs);
//IMGUI_DEBUG_LOG("StartPosRel (%.2f,%.2f) EndPosRel (%.2f,%.2f) -> (%.2f,%.2f)\n", bs->StartPosRel.x, bs->StartPosRel.y, bs->EndPosRel.x, bs->EndPosRel.y, WindowPosAbsToRel(window, g.IO.MousePos).x, WindowPosAbsToRel(window, g.IO.MousePos).y);
// Box-select 2D mode detects horizontal changes (vertical ones are already picked by Clipper)
// Storing an extra rect used by widgets supporting box-select.
if (ms_flags & ImGuiMultiSelectFlags_BoxSelect2d)
if (bs->BoxSelectRectPrev.Min.x != bs->BoxSelectRectCurr.Min.x || bs->BoxSelectRectPrev.Max.x != bs->BoxSelectRectCurr.Max.x)
// Box-select 2D mode detects change of the rectangle.
// Storing unclip rects which will be tested by widgets supporting box-select. Always update rectangles when active (even if we don't use them).
// To facilitate understanding this: enable IMGUI_DEBUG_BOXSELECT and visualize all geometry.
if (ms_flags & (ImGuiMultiSelectFlags_BoxSelect1d | ImGuiMultiSelectFlags_BoxSelect2d))
{
// For both sides, compute the area differing between Prev and Curr rectangles.
bs->UnclipRects[0] = bs->UnclipRects[1] = ImRect(+FLT_MAX, +FLT_MAX, -FLT_MAX, -FLT_MAX);
for (int side = 0; side < 2; side++)
{
bs->UnclipMode = true;
bs->UnclipRect = bs->BoxSelectRectPrev; // FIXME-OPT: UnclipRect x coordinates could be intersection of Prev and Curr rect on X axis.
bs->UnclipRect.Add(bs->BoxSelectRectCurr);
ImVec2 d_min = (side == 0) ? ImMin(bs->BoxSelectRectCurr.Min, bs->BoxSelectRectPrev.Min) : ImMin(bs->BoxSelectRectCurr.Max, bs->BoxSelectRectPrev.Max);
ImVec2 d_max = (side == 0) ? ImMax(bs->BoxSelectRectCurr.Min, bs->BoxSelectRectPrev.Min) : ImMax(bs->BoxSelectRectCurr.Max, bs->BoxSelectRectPrev.Max);
if (d_min.x != d_max.x)
{
bs->UnclipRects[0].AddX(d_min.x);
bs->UnclipRects[0].AddX(d_max.x);
}
if (d_min.y != d_max.y)
{
bs->UnclipRects[1].AddY(d_min.y);
bs->UnclipRects[1].AddY(d_max.y);
}
}
//GetForegroundDrawList()->AddRect(bs->UnclipRect.Min, bs->UnclipRect.Max, IM_COL32(255,0,0,200), 0.0f, 0, 3.0f);
ImRect box_select_intersection = bs->BoxSelectRectPrev;
box_select_intersection.Add(bs->BoxSelectRectCurr);
if (ms_flags & ImGuiMultiSelectFlags_BoxSelect2d)
if (bs->BoxSelectRectPrev.Min.x != bs->BoxSelectRectCurr.Min.x || bs->BoxSelectRectPrev.Max.x != bs->BoxSelectRectCurr.Max.x)
{
bs->UnclipRects[0].AddY(box_select_intersection.Min.y);
bs->UnclipRects[0].AddY(box_select_intersection.Max.y);
}
if (ms_flags & (ImGuiMultiSelectFlags_BoxSelect1d | ImGuiMultiSelectFlags_BoxSelect2d))
if (bs->BoxSelectRectPrev.Min.y != bs->BoxSelectRectCurr.Min.y || bs->BoxSelectRectPrev.Max.y != bs->BoxSelectRectCurr.Max.y)
{
bs->UnclipRects[1].AddX(box_select_intersection.Min.x);
bs->UnclipRects[1].AddX(box_select_intersection.Max.x);
}
// Merge both rectangles into one.
// FIXME-OPT: When UnclipRect.Area() is much larger than the sum of UnclipRects[0]/[1] Areas, widgets should
// ideally first use UnclipRect as a first coarse cull layer + the individual ones as a second validation.
bs->UnclipRect = bs->UnclipRects[0];
bs->UnclipRect.Add(bs->UnclipRects[1]);
if (!bs->UnclipRect.IsInverted() && (!window->ClipRect.Contains(bs->UnclipRect.Min) || !window->ClipRect.Contains(bs->UnclipRect.Max))) // !! Don't use Contains(ImRect)
bs->UnclipMode = true;
if (bs->UnclipMode && g.CurrentTable != NULL)
TableApplyExternalUnclipRect(g.CurrentTable, bs->UnclipRect); // No need submitting both
}
#ifdef IMGUI_DEBUG_BOXSELECT
//GetForegroundDrawList()->AddRect(scope_rect.Min, scope_rect.Max, IM_COL32(0, 255, 0, 200), 0.0f, 0, 4.0f);
//GetForegroundDrawList()->AddRect(bs->BoxSelectRectPrev.Min, bs->BoxSelectRectPrev.Max, IM_COL32(255,0,0,200), 0.0f, 0, 3.0f);
//GetForegroundDrawList()->AddRect(bs->BoxSelectRectCurr.Min, bs->BoxSelectRectCurr.Max, IM_COL32(0,255,0,200), 0.0f, 0, 1.0f);
if (ms_flags & (ImGuiMultiSelectFlags_BoxSelect1d | ImGuiMultiSelectFlags_BoxSelect2d))
{
for (ImRect& unclip_r : bs->UnclipRects)
if (!unclip_r.IsInverted())
GetForegroundDrawList()->AddRect(unclip_r.Min, unclip_r.Max, bs->UnclipMode ? IM_COL32(255, 255, 0, 200) : IM_COL32(255, 0, 0, 200), 0.0f, 0, 4.0f);
GetForegroundDrawList()->AddRect(bs->UnclipRect.Min, bs->UnclipRect.Max, bs->UnclipMode ? IM_COL32(255, 255, 0, 200) : IM_COL32(255, 0, 0, 200), 0.0f, 0, 2.0f);
}
#endif
return true;
}
@@ -7842,8 +7926,9 @@ void ImGui::EndBoxSelect(const ImRect& scope_rect, ImGuiMultiSelectFlags ms_flag
bs->EndPosRel = WindowPosAbsToRel(window, ImClamp(g.IO.MousePos, scope_rect.Min, scope_rect.Max)); // Clamp stored position according to current scrolling view
ImRect box_select_r = bs->BoxSelectRectCurr;
box_select_r.ClipWith(scope_rect);
window->DrawList->AddRectFilled(box_select_r.Min, box_select_r.Max, GetColorU32(ImGuiCol_SeparatorHovered, 0.30f)); // FIXME-MULTISELECT: Styling
window->DrawList->AddRect(box_select_r.Min, box_select_r.Max, GetColorU32(ImGuiCol_NavCursor)); // FIXME-MULTISELECT FIXME-DPI: Styling
ImGuiWindow* draw_window = FindFrontMostVisibleChildWindow(window);
draw_window->DrawList->AddRectFilled(box_select_r.Min, box_select_r.Max, GetColorU32(ImGuiCol_SeparatorHovered, 0.30f)); // FIXME-MULTISELECT: Styling
draw_window->DrawList->AddRect(box_select_r.Min, box_select_r.Max, GetColorU32(ImGuiCol_NavCursor)); // FIXME-MULTISELECT FIXME-DPI: Styling
// Scroll
const bool enable_scroll = (ms_flags & ImGuiMultiSelectFlags_ScopeWindow) && (ms_flags & ImGuiMultiSelectFlags_BoxSelectNoScroll) == 0;
@@ -7883,18 +7968,18 @@ static void DebugLogMultiSelectRequests(const char* function, const ImGuiMultiSe
static ImRect CalcScopeRect(ImGuiMultiSelectTempData* ms, ImGuiWindow* window)
{
ImGuiContext& g = *GImGui;
if (ms->Flags & ImGuiMultiSelectFlags_ScopeRect)
{
// Warning: this depends on CursorMaxPos so it means to be called by EndMultiSelect() only
// This probably doesn't work inside a table as there are ample ambiguities related to exact time of calling BeginMultiSelect()/EndMultiSelect().
return ImRect(ms->ScopeRectMin, ImMax(window->DC.CursorMaxPos, ms->ScopeRectMin));
}
else
{
// When a table, pull HostClipRect, which allows us to predict ClipRect before first row/layout is performed. (#7970)
//// When a table, pull HostClipRect, which allows us to predict ClipRect before first row/layout is performed. (#7970)
ImRect scope_rect = window->InnerClipRect;
if (g.CurrentTable != NULL)
scope_rect = g.CurrentTable->HostClipRect;
//if (g.CurrentTable != NULL)
// scope_rect = g.CurrentTable->HostClipRect;
// Add inner table decoration (#7821) // FIXME: Why not baking in InnerClipRect?
scope_rect.Min = ImMin(scope_rect.Min + ImVec2(window->DecoInnerSizeX1, window->DecoInnerSizeY1), scope_rect.Max);
@@ -7930,18 +8015,24 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, int sel
// FIXME: Workaround to the fact we override CursorMaxPos, meaning size measurement are lost. (#8250)
// They should perhaps be stacked properly?
if (ImGuiTable* table = g.CurrentTable)
if (table->CurrentColumn != -1)
{
if (!table->IsLayoutLocked)
TableUpdateLayout(table);
else if (table->CurrentColumn != -1)
TableEndCell(table); // This is currently safe to call multiple time. If that properly is lost we can extract the "save measurement" part of it.
}
// FIXME: BeginFocusScope()
const ImGuiID id = window->IDStack.back();
ms->Clear();
ms->FocusScopeId = id;
ms->Flags = flags;
ms->IsFocused = (ms->FocusScopeId == g.NavFocusScopeId);
ms->BackupCursorMaxPos = window->DC.CursorMaxPos;
ms->ScopeRectMin = window->DC.CursorMaxPos = window->DC.CursorPos;
ms->ScopeRectMin = window->DC.CursorPos;
if (flags & ImGuiMultiSelectFlags_ScopeRect)
window->DC.CursorMaxPos = ms->ScopeRectMin; // CalcScopeRect() for ImGuiMultiSelectFlags_ScopeRect will measure in EndMultiSelect().
PushFocusScope(ms->FocusScopeId);
ms->IsFocused = IsInNavFocusRoute(g.CurrentFocusScopeId);
if (flags & ImGuiMultiSelectFlags_ScopeWindow) // Mark parent child window as navigable into, with highlight. Assume user will always submit interactive items.
window->DC.NavLayersActiveMask |= 1 << ImGuiNavLayer_Main;
@@ -8023,7 +8114,7 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, int sel
storage->LastSelectionSize = 0;
}
ms->LoopRequestSetAll = request_select_all ? 1 : request_clear ? 0 : -1;
ms->LastSubmittedItem = ImGuiSelectionUserData_Invalid;
//ms->PrevSubmittedItem = ImGuiSelectionUserData_Invalid;
if (g.DebugLogFlags & ImGuiDebugLogFlags_EventSelection)
DebugLogMultiSelectRequests("BeginMultiSelect", &ms->IO);
@@ -8069,7 +8160,7 @@ ImGuiMultiSelectIO* ImGui::EndMultiSelect()
// Clear selection when clicking void?
// We specifically test for IsMouseDragPastThreshold(0) == false to allow box-selection!
// The InnerRect test is necessary for non-child/decorated windows.
bool scope_hovered = IsWindowHovered() && window->InnerRect.Contains(g.IO.MousePos);
bool scope_hovered = window->InnerRect.Contains(g.IO.MousePos) && IsWindowHovered(ImGuiHoveredFlags_ChildWindows);
if (scope_hovered && (ms->Flags & ImGuiMultiSelectFlags_ScopeRect))
scope_hovered &= scope_rect.Contains(g.IO.MousePos);
if (scope_hovered && g.HoveredId == 0 && g.ActiveId == 0)
@@ -8095,10 +8186,13 @@ ImGuiMultiSelectIO* ImGui::EndMultiSelect()
if (ms->Flags & ImGuiMultiSelectFlags_NavWrapX)
{
IM_ASSERT(ms->Flags & ImGuiMultiSelectFlags_ScopeWindow); // Only supported at window scope
ImGui::NavMoveRequestTryWrapping(ImGui::GetCurrentWindow(), ImGuiNavMoveFlags_WrapX);
NavMoveRequestTryWrapping(GetCurrentWindow(), ImGuiNavMoveFlags_WrapX);
}
// Unwind
if (ImGuiTable* table = g.CurrentTable)
if (table->IsInsideRow)
TableEndRow(table);
window->DC.CursorMaxPos = ImMax(ms->BackupCursorMaxPos, window->DC.CursorMaxPos);
PopFocusScope();
@@ -8126,6 +8220,8 @@ void ImGui::SetNextItemSelectionUserData(ImGuiSelectionUserData selection_user_d
g.NextItemData.ItemFlags |= ImGuiItemFlags_HasSelectionUserData | ImGuiItemFlags_IsMultiSelect;
if (ms->IO.RangeSrcItem == selection_user_data)
ms->RangeSrcPassedBy = true;
//ms->PrevSubmittedItem = ms->CurrSubmittedItem; // Can't rely on previous g.NextItemData.SelectionUserData because NextItemData is not restored on nested multi-select.
//ms->CurrSubmittedItem = selection_user_data;
}
else
{
@@ -8274,8 +8370,31 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed)
if (ms->BoxSelectId != 0)
if (ImGuiBoxSelectState* bs = GetBoxSelectState(ms->BoxSelectId))
{
const bool rect_overlap_curr = bs->BoxSelectRectCurr.Overlaps(g.LastItemData.Rect);
const bool rect_overlap_prev = bs->BoxSelectRectPrev.Overlaps(g.LastItemData.Rect);
ImRect item_rect = g.LastItemData.Rect;
if (!window->DC.NavIsScrollPushableX) // FIXME: Rename to be more generic.
if (ImGuiTable* table = g.CurrentTable)
if (table->CurrentColumn != -1)
{
// FIXME: We cannot solely use current ClipRect as it includes HostClipRect.
// However we account for ClipRect being larger than current column (e.g. when using SpanAllColumns)
// A more generic version would be nice, but window->WorkRect.Min/Max exclude CellPadding. (#7994, #9383)
ImGuiTableColumn* column = &table->Columns[table->CurrentColumn];
float clip_min_x = (g.LastItemData.ItemFlags & ImGuiItemStatusFlags_HasClipRect) ? g.LastItemData.ClipRect.Min.x : window->ClipRect.Min.x;
float clip_max_x = (g.LastItemData.ItemFlags & ImGuiItemStatusFlags_HasClipRect) ? g.LastItemData.ClipRect.Max.x : window->ClipRect.Max.x;
if (clip_min_x != clip_max_x) // When zero sized we expect that bounds have been clamped and thus are unreliable
{
item_rect.Min.x = ImMax(item_rect.Min.x, ImMin(column->MinX, clip_min_x));
item_rect.Max.x = ImMin(item_rect.Max.x, ImMax(column->MaxX, clip_max_x));
}
else
{
item_rect.Min.x = ImMax(item_rect.Min.x, column->MinX);
item_rect.Max.x = ImMin(item_rect.Max.x, column->MaxX);
}
//GetForegroundDrawList()->AddRect(item_rect.Min, item_rect.Max, IM_COL32(255, 0, 255, 255));
}
const bool rect_overlap_curr = bs->BoxSelectRectCurr.Overlaps(item_rect);
const bool rect_overlap_prev = bs->BoxSelectRectPrev.Overlaps(item_rect);
if ((rect_overlap_curr && !rect_overlap_prev && !selected) || (rect_overlap_prev && !rect_overlap_curr))
{
if (storage->LastSelectionSize <= 0 && bs->IsStartedSetNavIdOnce)
@@ -8287,6 +8406,9 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed)
{
selected = !selected;
MultiSelectAddSetRange(ms, selected, +1, item_data, item_data);
#ifdef IMGUI_DEBUG_BOXSELECT
GetForegroundDrawList()->AddRectFilled(g.LastItemData.Rect.Min, g.LastItemData.Rect.Max, selected ? IM_COL32(0, 255, 0, 200) : IM_COL32(255, 0, 0, 200));
#endif
}
storage->LastSelectionSize = ImMax(storage->LastSelectionSize + 1, 1);
}
@@ -8400,7 +8522,6 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed)
}
if (storage->NavIdItem == item_data)
ms->NavIdPassedBy = true;
ms->LastSubmittedItem = item_data;
*p_selected = selected;
*p_pressed = pressed;
@@ -8416,15 +8537,20 @@ void ImGui::MultiSelectAddSetAll(ImGuiMultiSelectTempData* ms, bool selected)
void ImGui::MultiSelectAddSetRange(ImGuiMultiSelectTempData* ms, bool selected, int range_dir, ImGuiSelectionUserData first_item, ImGuiSelectionUserData last_item)
{
// Merge contiguous spans into same request (unless NoRangeSelect is set which guarantees single-item ranges)
// FIXME-OPT: Disabled on 2026/04/09 as this would break with any form of coarse clipping that we don't know about (e.g. TableNextColumn() return value).
// The low-hanging fruit would be to know that ImGuiSelectionUserData are sequential indices, in which case we can trivially compare PrevSubmittedItem + RangeDir == FirstItem.
// User can always perform this merge if required.
#if 0
if (ms->IO.Requests.Size > 0 && first_item == last_item && (ms->Flags & ImGuiMultiSelectFlags_NoRangeSelect) == 0)
{
ImGuiSelectionRequest* prev = &ms->IO.Requests.Data[ms->IO.Requests.Size - 1];
if (prev->Type == ImGuiSelectionRequestType_SetRange && prev->RangeLastItem == ms->LastSubmittedItem && prev->Selected == selected)
if (prev->Type == ImGuiSelectionRequestType_SetRange && prev->RangeLastItem == ms->PrevSubmittedItem && prev->Selected == selected)
{
prev->RangeLastItem = last_item;
return;
}
}
#endif
ImGuiSelectionRequest req = { ImGuiSelectionRequestType_SetRange, selected, (ImS8)range_dir, (range_dir > 0) ? first_item : last_item, (range_dir > 0) ? last_item : first_item };
ms->IO.Requests.push_back(req); // Add new request
@@ -8662,7 +8788,8 @@ bool ImGui::BeginListBox(const char* label, const ImVec2& size_arg)
const ImGuiStyle& style = g.Style;
const ImGuiID id = GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const char* label_end = FindRenderedTextEnd(label);
const ImVec2 label_size = CalcTextSize(label, label_end, false);
// Size default to hold ~7.25 items.
// Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar.
@@ -8685,7 +8812,7 @@ bool ImGui::BeginListBox(const char* label, const ImVec2& size_arg)
if (label_size.x > 0.0f)
{
ImVec2 label_pos = ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y);
RenderText(label_pos, label);
RenderText(label_pos, label, label_end, false);
window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, label_pos + label_size);
AlignTextToFramePadding();
}
@@ -8766,9 +8893,7 @@ bool ImGui::ListBox(const char* label, int* current_item, const char* (*getter)(
// - PlotHistogram()
//-------------------------------------------------------------------------
// Plot/Graph widgets are not very good.
// Consider writing your own, or using a third-party one, see:
// - ImPlot https://github.com/epezent/implot
// - others https://github.com/ocornut/imgui/wiki/Useful-Extensions
// Consider using ImPlot (https://github.com/epezent/implot) which is much better!
//-------------------------------------------------------------------------
int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, const ImVec2& size_arg)
@@ -8781,7 +8906,8 @@ int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_get
const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const char* label_end = FindRenderedTextEnd(label);
const ImVec2 label_size = CalcTextSize(label, label_end, false);
const ImVec2 frame_size = CalcItemSize(size_arg, CalcItemWidth(), label_size.y + style.FramePadding.y * 2.0f);
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size);
@@ -8880,10 +9006,11 @@ int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_get
RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, overlay_text, NULL, NULL, ImVec2(0.5f, 0.0f));
if (label_size.x > 0.0f)
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label);
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label, label_end, false);
// Return hovered index or -1 if none are hovered.
// This is currently not exposed in the public API because we need a larger redesign of the whole thing, but in the short-term we are making it available in PlotEx().
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
return idx_hovered;
}
@@ -8913,6 +9040,7 @@ void ImGui::PlotLines(const char* label, float (*values_getter)(void* data, int
PlotEx(ImGuiPlotType_Lines, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size);
}
// Plot Histogram (the data provided _is_ histogram data. it doesn't compute the histogram of your data)
void ImGui::PlotHistogram(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride)
{
ImGuiPlotArrayGetterData data(values, stride);
@@ -9245,7 +9373,8 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
// Tag menu as used. Next time BeginMenu() with same ID is called it will append to existing menu
g.MenusIdSubmittedThisFrame.push_back(id);
ImVec2 label_size = CalcTextSize(label, NULL, true);
const char* label_end = FindRenderedTextEnd(label);
ImVec2 label_size = CalcTextSize(label, label_end, false);
// Odd hack to allow hovering across menus of a same menu-set (otherwise we wouldn't be able to hover parent without always being a Child window)
// This is only done for items for the menu set and not the full parent window.
@@ -9264,8 +9393,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
bool pressed;
// We use ImGuiSelectableFlags_NoSetKeyOwner to allow down on one menu item, move, up on another.
const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_NoSetKeyOwner | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_NoAutoClosePopups;
const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_NoAutoClosePopups | (ImGuiSelectableFlags)ImGuiSelectableFlags_SelectOnClick;
ImGuiMenuColumns* offsets = &window->DC.MenuColumns;
if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
{
@@ -9277,7 +9405,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, pos.y + window->DC.CurrLineTextBaseOffset);
pressed = Selectable("", menu_is_open, selectable_flags, label_size);
LogSetNextTextDecoration("[", "]");
RenderText(text_pos, label);
RenderText(text_pos, label, label_end, false);
PopStyleVar();
window->DC.CursorPos.x += IM_TRUNC(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar().
popup_pos = ImVec2(pos.x - 1.0f - IM_TRUNC(style.ItemSpacing.x * 0.5f), text_pos.y - style.FramePadding.y + window->MenuBarHeight);
@@ -9294,7 +9422,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
ImVec2 text_pos(window->DC.CursorPos.x, pos.y + window->DC.CurrLineTextBaseOffset);
pressed = Selectable("", menu_is_open, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, label_size.y));
LogSetNextTextDecoration("", ">");
RenderText(ImVec2(text_pos.x + offsets->OffsetLabel, text_pos.y), label);
RenderText(ImVec2(text_pos.x + offsets->OffsetLabel, text_pos.y), label, label_end, false);
if (icon_w > 0.0f)
RenderText(ImVec2(text_pos.x + offsets->OffsetIcon, text_pos.y), icon);
RenderArrow(window->DrawList, ImVec2(text_pos.x + offsets->OffsetMark + extra_w + g.FontSize * 0.30f, text_pos.y), GetColorU32(ImGuiCol_Text), ImGuiDir_Right);
@@ -9303,6 +9431,14 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
if (!enabled)
EndDisabled();
// Once dragged, release ActiveId + key ownership. This is to allow the idiom of mouse down a menu, dragging elsewhere, up on some other MenuItem(). (#8233, #9394)
// Could move logic into lower-level ImGuiButtonFlags_AutoReleaseActiveId + ImGuiButtonFlags_AutoReleaseKeyOwner? Easier once we get rid of the Selectable() middle-man here.
if (g.ActiveId == id && g.HoveredId != id && g.ActiveIdSource == ImGuiInputSource_Mouse && IsMouseDragging(0))
{
ClearActiveID();
SetKeyOwner(ImGuiKey_MouseLeft, ImGuiKeyOwner_NoOwner);
}
const bool hovered = (g.HoveredId == id) && enabled && !g.NavHighlightItemUnderNav;
if (menuset_is_open)
PopItemFlag();
@@ -9383,6 +9519,9 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Openable | (menu_is_open ? ImGuiItemStatusFlags_Opened : 0));
PopID();
if (g.ActiveId == id && want_open)
g.ActiveIdNoClearOnFocusLoss = true;
if (want_open && !menu_is_open && g.OpenPopupStack.Size > g.BeginPopupStack.Size)
{
// Don't reopen/recycle same menu level in the same frame if it is a different menu ID, first close the other menu and yield for a frame.
@@ -9459,7 +9598,8 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut
ImGuiContext& g = *GImGui;
ImGuiStyle& style = g.Style;
ImVec2 pos = window->DC.CursorPos;
ImVec2 label_size = CalcTextSize(label, NULL, true);
const char* label_end = FindRenderedTextEnd(label);
ImVec2 label_size = CalcTextSize(label, label_end, false);
// See BeginMenuEx() for comments about this.
const bool menuset_is_open = IsRootOfOpenMenuSet();
@@ -9474,7 +9614,7 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut
BeginDisabled();
// We use ImGuiSelectableFlags_NoSetKeyOwner to allow down on one menu item, move, up on another.
const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_SelectOnRelease | ImGuiSelectableFlags_NoSetKeyOwner | ImGuiSelectableFlags_SetNavIdOnHover;
const ImGuiSelectableFlags selectable_flags = (ImGuiSelectableFlags)ImGuiSelectableFlags_SelectOnRelease | (ImGuiSelectableFlags)ImGuiSelectableFlags_SetNavIdOnHover;
ImGuiMenuColumns* offsets = &window->DC.MenuColumns;
if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
{
@@ -9486,7 +9626,7 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut
pressed = Selectable("", selected, selectable_flags, ImVec2(label_size.x, 0.0f));
PopStyleVar();
if (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible)
RenderText(text_pos, label);
RenderText(text_pos, label, label_end, false);
window->DC.CursorPos.x += IM_TRUNC(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar().
}
else
@@ -9503,7 +9643,7 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut
pressed = Selectable("", false, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, label_size.y));
if (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible)
{
RenderText(text_pos + ImVec2(offsets->OffsetLabel, 0.0f), label);
RenderText(text_pos + ImVec2(offsets->OffsetLabel, 0.0f), label, label_end, false);
if (icon_w > 0.0f)
RenderText(text_pos + ImVec2(offsets->OffsetIcon, 0.0f), icon);
if (shortcut_w > 0.0f)
@@ -9517,6 +9657,17 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut
RenderCheckMark(window->DrawList, text_pos + ImVec2(offsets->OffsetMark + stretch_w + g.FontSize * 0.40f, g.FontSize * 0.134f * 0.5f), GetColorU32(ImGuiCol_Text), g.FontSize * 0.866f);
}
}
// Once dragged, release ActiveId + key ownership. This is to allow the idiom of mouse down a menu, dragging elsewhere, up on some other MenuItem(). (#8233, #9394)
// Could move logic into lower-level ImGuiButtonFlags_AutoReleaseActiveId + ImGuiButtonFlags_AutoReleaseKeyOwner? Easier once we get rid of the Selectable() middle-man here.
const ImGuiID id = g.LastItemData.ID;
if (g.ActiveId == id && g.HoveredId != id && g.ActiveIdSource == ImGuiInputSource_Mouse && IsMouseDragging(0))
{
ClearActiveID();
SetKeyOwner(ImGuiKey_MouseLeft, ImGuiKeyOwner_NoOwner);
}
IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (selected ? ImGuiItemStatusFlags_Checked : 0));
if (!enabled)
EndDisabled();
@@ -10557,7 +10708,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
// We don't have CPU clipping primitives to clip the CloseButton (until it becomes a texture), so need to add an extra draw call (temporary in the case of vertical animation)
const bool want_clip_rect = is_central_section && (bb.Min.x < tab_bar->ScrollingRectMinX || bb.Max.x > tab_bar->ScrollingRectMaxX);
if (want_clip_rect)
PushClipRect(ImVec2(ImMax(bb.Min.x, tab_bar->ScrollingRectMinX), bb.Min.y - 1), ImVec2(tab_bar->ScrollingRectMaxX, bb.Max.y), true);
PushClipRect(ImVec2(ImClamp(bb.Min.x, tab_bar->ScrollingRectMinX, tab_bar->ScrollingRectMaxX), bb.Min.y - 1), ImVec2(tab_bar->ScrollingRectMaxX, bb.Max.y), true);
ImVec2 backup_cursor_max_pos = window->DC.CursorMaxPos;
ItemSize(bb.GetSize(), style.FramePadding.y);
@@ -10629,7 +10780,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
float rounding = style.TabRounding;
display_draw_list->PathArcToFast(tl + ImVec2(+rounding, +rounding), rounding, 7, 9);
display_draw_list->PathArcToFast(tr + ImVec2(-rounding, +rounding), rounding, 9, 11);
display_draw_list->PathStroke(overline_col, 0, style.TabBarOverlineSize);
display_draw_list->PathStroke(overline_col, style.TabBarOverlineSize);
}
else
{
@@ -10733,7 +10884,7 @@ void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabI
draw_list->PathArcToFast(ImVec2(bb.Min.x + rounding + 0.5f, y1 + rounding + 0.5f), rounding, 6, 9);
draw_list->PathArcToFast(ImVec2(bb.Max.x - rounding - 0.5f, y1 + rounding + 0.5f), rounding, 9, 12);
draw_list->PathLineTo(ImVec2(bb.Max.x - 0.5f, y2));
draw_list->PathStroke(GetColorU32(ImGuiCol_Border), 0, g.Style.TabBorderSize);
draw_list->PathStroke(GetColorU32(ImGuiCol_Border), g.Style.TabBorderSize);
}
}
@@ -10742,7 +10893,8 @@ void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabI
void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImVec2 frame_padding, const char* label, ImGuiID tab_id, ImGuiID close_button_id, bool is_contents_visible, bool* out_just_closed, bool* out_text_clipped)
{
ImGuiContext& g = *GImGui;
ImVec2 label_size = CalcTextSize(label, NULL, true);
const char* label_end = FindRenderedTextEnd(label);
ImVec2 label_size = CalcTextSize(label, label_end, false);
if (out_just_closed)
*out_just_closed = false;
@@ -10827,7 +10979,7 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb,
}
}
LogSetNextTextDecoration("/", "\\");
RenderTextEllipsis(draw_list, text_ellipsis_clip_bb.Min, text_ellipsis_clip_bb.Max, ellipsis_max_x, label, NULL, &label_size);
RenderTextEllipsis(draw_list, text_ellipsis_clip_bb.Min, text_ellipsis_clip_bb.Max, ellipsis_max_x, label, label_end, &label_size);
#if 0
if (!is_contents_visible)
+1 -2
View File
@@ -1,12 +1,11 @@
/* 7zFile.h -- File IO
2023-03-05 : Igor Pavlov : Public domain */
: Igor Pavlov : Public domain */
#ifndef ZIP7_INC_FILE_H
#define ZIP7_INC_FILE_H
#ifdef _WIN32
#define USE_WINDOWS_FILE
// #include <windows.h>
#endif
#ifdef USE_WINDOWS_FILE
+4 -2
View File
@@ -1,5 +1,5 @@
/* 7zTypes.h -- Basic types
2024-01-24 : Igor Pavlov : Public domain */
: Igor Pavlov : Public domain */
#ifndef ZIP7_7Z_TYPES_H
#define ZIP7_7Z_TYPES_H
@@ -46,8 +46,9 @@ typedef int SRes;
#ifdef _MSC_VER
#define MY_ALIGN_IN_STRUCT(n) __declspec(align(n))
#if _MSC_VER > 1200
#define MY_ALIGN(n) __declspec(align(n))
#define MY_ALIGN(n) MY_ALIGN_IN_STRUCT(n)
#else
#define MY_ALIGN(n)
#endif
@@ -58,6 +59,7 @@ typedef int SRes;
#define MY_ALIGN(n) alignas(n)
*/
#define MY_ALIGN(n) __attribute__ ((aligned(n)))
#define MY_ALIGN_IN_STRUCT(n) MY_ALIGN(n)
#endif
+5 -5
View File
@@ -1,7 +1,7 @@
#define MY_VER_MAJOR 25
#define MY_VER_MINOR 0
#define MY_VER_MAJOR 26
#define MY_VER_MINOR 1
#define MY_VER_BUILD 0
#define MY_VERSION_NUMBERS "25.00"
#define MY_VERSION_NUMBERS "26.01"
#define MY_VERSION MY_VERSION_NUMBERS
#ifdef MY_CPU_NAME
@@ -10,12 +10,12 @@
#define MY_VERSION_CPU MY_VERSION
#endif
#define MY_DATE "2025-07-05"
#define MY_DATE "2026-04-27"
#undef MY_COPYRIGHT
#undef MY_VERSION_COPYRIGHT_DATE
#define MY_AUTHOR_NAME "Igor Pavlov"
#define MY_COPYRIGHT_PD "Igor Pavlov : Public domain"
#define MY_COPYRIGHT_CR "Copyright (c) 1999-2025 Igor Pavlov"
#define MY_COPYRIGHT_CR "Copyright (c) 1999-2026 Igor Pavlov"
#ifdef USE_COPYRIGHT_CR
#define MY_COPYRIGHT MY_COPYRIGHT_CR
+8 -2
View File
@@ -1,11 +1,17 @@
/* 7zWindows.h -- StdAfx
2023-04-02 : Igor Pavlov : Public domain */
/* 7zWindows.h -- Windows.h and related code
Igor Pavlov : Public domain */
#ifndef ZIP7_INC_7Z_WINDOWS_H
#define ZIP7_INC_7Z_WINDOWS_H
#ifdef _WIN32
#if defined(_MSC_VER) && _MSC_VER >= 1950 && !defined(__clang__) // VS2026
// <Windows.h> and some another windows files need that option
// VS2026: wtypesbase.h: warning C4865: 'tagCLSCTX': the underlying type will change from 'int' to 'unsigned int' when '/Zc:enumTypes' is specified on the command line
#pragma warning(disable : 4865)
#endif
#if defined(__clang__)
# pragma clang diagnostic push
#endif
+27 -27
View File
@@ -1,5 +1,5 @@
/* Alloc.h -- Memory allocation functions
2024-01-22 : Igor Pavlov : Public domain */
: Igor Pavlov : Public domain */
#ifndef ZIP7_INC_ALLOC_H
#define ZIP7_INC_ALLOC_H
@@ -25,40 +25,40 @@ void *MyRealloc(void *address, size_t size);
void *z7_AlignedAlloc(size_t size);
void z7_AlignedFree(void *p);
extern const ISzAlloc g_Alloc;
extern const ISzAlloc g_AlignedAlloc;
#ifdef _WIN32
void *MidAlloc(size_t size);
void MidFree(void *address);
extern const ISzAlloc g_MidAlloc;
#else
#define MidAlloc(size) z7_AlignedAlloc(size)
#define MidFree(address) z7_AlignedFree(address)
#define g_MidAlloc g_AlignedAlloc
#endif
#ifdef Z7_LARGE_PAGES
void SetLargePageSize(void);
#endif
void *MidAlloc(size_t size);
void MidFree(void *address);
void *BigAlloc(size_t size);
void BigFree(void *address);
/* #define Z7_BIG_ALLOC_IS_ZERO_FILLED */
#define Z7_LARGE_PAGES_FLAG_USE_HUGEPAGE (1 << 0) // PAGE_ALIGNED / MADV_HUGEPAGE
#define Z7_LARGE_PAGES_FLAG_NO_PAGECODE (1 << 1) // no PAGE_ALIGNED / no madvise
#define Z7_LARGE_PAGES_FLAG_NO_MADVISE (1 << 2) // PAGE_ALIGNED / no madvise : for THP=always
#define Z7_LARGE_PAGES_FLAG_NO_HUGEPAGE (1 << 3) // PAGE_ALIGNED / MADV_NOHUGEPAGE
#define Z7_LARGE_PAGES_FLAG_FAIL_STOP (1 << 15) // for benchmarks
#define Z7_LARGE_PAGES_FLAG_DIRECT_PAGE_SIZE (1 << 16)
#define Z7_LARGE_PAGES_FLAG_DIRECT_THRESHOLD (1 << 17)
void z7_LargePage_Set(UInt32 flags, size_t pageSize, size_t threshold);
void *BigAlloc(size_t size);
void BigFree(void *address);
extern const ISzAlloc g_BigAlloc;
#else
#define MidAlloc(size) z7_AlignedAlloc(size)
#define MidFree(address) z7_AlignedFree(address)
#define BigAlloc(size) z7_AlignedAlloc(size)
#define BigFree(address) z7_AlignedFree(address)
#define BigAlloc(size) MidAlloc(size)
#define BigFree(address) MidFree(address)
#define g_BigAlloc g_MidAlloc
#endif
extern const ISzAlloc g_Alloc;
#ifdef _WIN32
extern const ISzAlloc g_BigAlloc;
extern const ISzAlloc g_MidAlloc;
#else
#define g_BigAlloc g_AlignedAlloc
#define g_MidAlloc g_AlignedAlloc
#endif
extern const ISzAlloc g_AlignedAlloc;
typedef struct
{
+7 -1
View File
@@ -54,6 +54,12 @@
#pragma GCC diagnostic ignored "-Wexcess-padding"
#endif
#if defined(Z7_APPLE_CLANG_VERSION) && __clang_major__ >= 21
// warning: function MyAlloc might be an allocator wrapper
// clang in xcode: clang 21.0.0
#pragma GCC diagnostic ignored "-Wallocator-wrappers"
#endif
#if __clang_major__ >= 16
#pragma GCC diagnostic ignored "-Wunsafe-buffer-usage"
#endif
@@ -72,7 +78,7 @@
#endif // __clang__
#if defined(_WIN32) && defined(__clang__) && __clang_major__ >= 16
#if defined(__clang__) && __clang_major__ >= 16
// #pragma GCC diagnostic ignored "-Wcast-function-type-strict"
#define Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION \
_Pragma("GCC diagnostic ignored \"-Wcast-function-type-strict\"")
+20 -2
View File
@@ -31,7 +31,12 @@ MY_CPU_64BIT means that processor can work with 64-bit registers.
#define MY_CPU_NAME "x32"
#define MY_CPU_SIZEOF_POINTER 4
#else
#define MY_CPU_NAME "x64"
#if defined(__APX_EGPR__) || defined(__EGPR__)
#define MY_CPU_NAME "x64-apx"
#define MY_CPU_AMD64_APX
#else
#define MY_CPU_NAME "x64"
#endif
#define MY_CPU_SIZEOF_POINTER 8
#endif
#define MY_CPU_64BIT
@@ -249,11 +254,12 @@ MY_CPU_64BIT means that processor can work with 64-bit registers.
#endif
// _LITTLE_ENDIAN macro can be defined for big-endian platform with some compilers
#if defined(MY_CPU_X86_OR_AMD64) \
|| defined(MY_CPU_ARM_LE) \
|| defined(MY_CPU_ARM64_LE) \
|| defined(MY_CPU_IA64_LE) \
|| defined(_LITTLE_ENDIAN) \
|| defined(__LITTLE_ENDIAN__) \
|| defined(__ARMEL__) \
|| defined(__THUMBEL__) \
@@ -596,8 +602,20 @@ problem-4 : performace:
#define SetBe32a(p, v) { *(UInt32 *)(void *)(p) = (v); }
#define SetBe16a(p, v) { *(UInt16 *)(void *)(p) = (v); }
// gcc and clang for powerpc can transform load byte access to load reverse word access.
// sp we can use byte access instead of word access. Z7_BSWAP64 cab be slow
#if 1 && defined(Z7_CPU_FAST_BSWAP_SUPPORTED) && defined(MY_CPU_64BIT)
#define GetUi64a(p) Z7_BSWAP64 (*(const UInt64 *)(const void *)(p))
#else
#define GetUi64a(p) GetUi64(p)
#endif
#if 1 && defined(Z7_CPU_FAST_BSWAP_SUPPORTED)
#define GetUi32a(p) Z7_BSWAP32 (*(const UInt32 *)(const void *)(p))
#else
#define GetUi32a(p) GetUi32(p)
#endif
#define GetUi16a(p) GetUi16(p)
#define SetUi32a(p, v) SetUi32(p, v)
#define SetUi16a(p, v) SetUi16(p, v)
+7 -7
View File
@@ -1,5 +1,5 @@
/* Precomp.h -- precompilation file
2024-01-25 : Igor Pavlov : Public domain */
: Igor Pavlov : Public domain */
#ifndef ZIP7_INC_PRECOMP_H
#define ZIP7_INC_PRECOMP_H
@@ -40,18 +40,18 @@
#endif
*/
#ifndef Z7_LARGE_PAGES
#if !defined(Z7_NO_LARGE_PAGES) && !defined(UNDER_CE)
#define Z7_LARGE_PAGES 1
#endif
#endif
#ifdef _WIN32
/*
this "Precomp.h" file must be included before <windows.h>,
if we want to define _WIN32_WINNT before <windows.h>.
*/
#ifndef Z7_LARGE_PAGES
#ifndef Z7_NO_LARGE_PAGES
#define Z7_LARGE_PAGES 1
#endif
#endif
#ifndef Z7_LONG_PATH
#ifndef Z7_NO_LONG_PATH
#define Z7_LONG_PATH 1
+23 -29
View File
@@ -1,5 +1,5 @@
/* 7zArcIn.c -- 7z Input functions
2023-09-07 : Igor Pavlov : Public domain */
: Igor Pavlov : Public domain */
#include "Precomp.h"
@@ -289,9 +289,9 @@ static SRes WaitId(CSzData *sd, UInt32 id)
}
}
static SRes RememberBitVector(CSzData *sd, UInt32 numItems, const Byte **v)
static SRes RememberBitVector(CSzData *sd, size_t numItems, const Byte **v)
{
const UInt32 numBytes = (numItems + 7) >> 3;
const size_t numBytes = (numItems + 7) >> 3;
if (numBytes > sd->Size)
return SZ_ERROR_ARCHIVE;
*v = sd->Data;
@@ -317,11 +317,11 @@ static UInt32 CountDefinedBits(const Byte *bits, UInt32 numItems)
return sum;
}
static Z7_NO_INLINE SRes ReadBitVector(CSzData *sd, UInt32 numItems, Byte **v, ISzAllocPtr alloc)
static Z7_NO_INLINE SRes ReadBitVector(CSzData *sd, size_t numItems, Byte **v, ISzAllocPtr alloc)
{
Byte allAreDefined;
Byte *v2;
const UInt32 numBytes = (numItems + 7) >> 3;
const size_t numBytes = (numItems + 7) >> 3;
*v = NULL;
SZ_READ_BYTE(allAreDefined)
if (numBytes == 0)
@@ -345,9 +345,9 @@ static Z7_NO_INLINE SRes ReadBitVector(CSzData *sd, UInt32 numItems, Byte **v, I
return SZ_OK;
}
static Z7_NO_INLINE SRes ReadUi32s(CSzData *sd2, UInt32 numItems, CSzBitUi32s *crcs, ISzAllocPtr alloc)
static Z7_NO_INLINE SRes ReadUi32s(CSzData *sd2, size_t numItems, CSzBitUi32s *crcs, ISzAllocPtr alloc)
{
UInt32 i;
size_t i;
CSzData sd;
UInt32 *vals;
const Byte *defs;
@@ -366,7 +366,7 @@ static Z7_NO_INLINE SRes ReadUi32s(CSzData *sd2, UInt32 numItems, CSzBitUi32s *c
return SZ_OK;
}
static SRes ReadBitUi32s(CSzData *sd, UInt32 numItems, CSzBitUi32s *crcs, ISzAllocPtr alloc)
static SRes ReadBitUi32s(CSzData *sd, size_t numItems, CSzBitUi32s *crcs, ISzAllocPtr alloc)
{
SzBitUi32s_Free(crcs, alloc);
RINOK(ReadBitVector(sd, numItems, &crcs->Defs, alloc))
@@ -1027,42 +1027,39 @@ static SRes SzReadAndDecodePackedStreams(
return SZ_OK;
}
// (size & 1) == 0
// (data) is aligned for 2-bytes
static SRes SzReadFileNames(const Byte *data, size_t size, UInt32 numFiles, size_t *offsets)
{
size_t pos = 0;
const Byte *p, *lim;
*offsets++ = 0;
if (numFiles == 0)
return (size == 0) ? SZ_OK : SZ_ERROR_ARCHIVE;
if (size < 2)
return SZ_ERROR_ARCHIVE;
if (data[size - 2] != 0 || data[size - 1] != 0)
lim = data + size;
if (*(const UInt16 *)(const void *)(lim - 2))
return SZ_ERROR_ARCHIVE;
p = data;
do
{
const Byte *p;
if (pos == size)
if (p >= lim)
return SZ_ERROR_ARCHIVE;
for (p = data + pos;
#ifdef _WIN32
*(const UInt16 *)(const void *)p != 0
#else
p[0] != 0 || p[1] != 0
#endif
; p += 2);
pos = (size_t)(p - data) + 2;
*offsets++ = (pos >> 1);
for (; *(const UInt16 *)(const void *)p; p += 2);
p += 2;
*offsets++ = (size_t)(p - data) >> 1;
}
while (--numFiles);
return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE;
return (p == lim) ? SZ_OK : SZ_ERROR_ARCHIVE;
}
static Z7_NO_INLINE SRes ReadTime(CSzBitUi64s *p, UInt32 num,
static Z7_NO_INLINE SRes ReadTime(CSzBitUi64s *p, size_t num,
CSzData *sd2,
const CBuf *tempBufs, UInt32 numTempBufs,
ISzAllocPtr alloc)
{
CSzData sd;
UInt32 i;
size_t i;
CNtfsFileTime *vals;
Byte *defs;
Byte external;
@@ -1215,6 +1212,7 @@ static SRes SzReadHeader2(
{
namesSize = (size_t)size - 1;
namesData = sd->Data;
SKIP_DATA(sd, namesSize)
}
else
{
@@ -1226,15 +1224,11 @@ static SRes SzReadHeader2(
namesSize = (tempBufs)[index].size;
}
if ((namesSize & 1) != 0)
if (namesSize & 1)
return SZ_ERROR_ARCHIVE;
MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain)
MY_ALLOC_ZE_AND_CPY(p->FileNames, namesSize, namesData, allocMain)
RINOK(SzReadFileNames(p->FileNames, namesSize, numFiles, p->FileNameOffsets))
if (external == 0)
{
SKIP_DATA(sd, namesSize)
}
break;
}
case k7zIdEmptyStream:
+208 -39
View File
@@ -1,5 +1,5 @@
/* Alloc.c -- Memory allocation functions
2024-02-18 : Igor Pavlov : Public domain */
: Igor Pavlov : Public domain */
#include "Precomp.h"
@@ -24,8 +24,6 @@
#endif
// #define SZ_ALLOC_DEBUG
/* #define SZ_ALLOC_DEBUG */
/* use SZ_ALLOC_DEBUG to debug alloc/free operations */
#ifdef SZ_ALLOC_DEBUG
@@ -34,9 +32,10 @@
static int g_allocCount = 0;
#ifdef _WIN32
static int g_allocCountMid = 0;
#ifdef Z7_LARGE_PAGES
static int g_allocCountBig = 0;
#endif
#endif
#define CONVERT_INT_TO_STR(charType, tempSize) \
char temp[tempSize]; unsigned i = 0; \
@@ -140,8 +139,10 @@ static void PrintAddr(void *p)
#else
#ifdef _WIN32
#ifdef Z7_LARGE_PAGES
#define PRINT_ALLOC(name, cnt, size, ptr)
#endif
#endif
#define PRINT_FREE(name, cnt, ptr)
#define Print(s)
#define PrintLn()
@@ -245,6 +246,7 @@ void MidFree(void *address)
}
#ifdef Z7_LARGE_PAGES
// #pragma message("Z7_LARGE_PAGES")
#ifdef MEM_LARGE_PAGES
#define MY_MEM_LARGE_PAGES MEM_LARGE_PAGES
@@ -253,32 +255,14 @@ void MidFree(void *address)
#endif
extern
SIZE_T g_LargePageSize;
SIZE_T g_LargePageSize = 0;
typedef SIZE_T (WINAPI *Func_GetLargePageMinimum)(VOID);
void SetLargePageSize(void)
{
SIZE_T size;
#ifdef Z7_USE_DYN_GetLargePageMinimum
Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
const
Func_GetLargePageMinimum fn =
(Func_GetLargePageMinimum) Z7_CAST_FUNC_C GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
"GetLargePageMinimum");
if (!fn)
return;
size = fn();
#else
size = GetLargePageMinimum();
#endif
if (size == 0 || (size & (size - 1)) != 0)
return;
g_LargePageSize = size;
}
#endif // Z7_LARGE_PAGES
size_t g_LargePageSize;
size_t g_LargePageSize = 0;
extern
size_t g_LargePageThresholdMin;
size_t g_LargePageThresholdMin = 0;
extern
UInt32 g_LargePageFlags;
UInt32 g_LargePageFlags = 0;
void *BigAlloc(size_t size)
{
@@ -289,12 +273,10 @@ void *BigAlloc(size_t size)
#ifdef Z7_LARGE_PAGES
{
SIZE_T ps = g_LargePageSize;
if (ps != 0 && ps <= (1 << 30) && size > (ps / 2))
const size_t ps = g_LargePageSize - 1;
if (ps < (1u << 30) && size > g_LargePageThresholdMin)
{
size_t size2;
ps--;
size2 = (size + ps) & ~ps;
const size_t size2 = (size + ps) & ~ps;
if (size2 >= size)
{
void *p = VirtualAlloc(NULL, size2, MEM_COMMIT | MY_MEM_LARGE_PAGES, PAGE_READWRITE);
@@ -303,6 +285,8 @@ void *BigAlloc(size_t size)
PRINT_ALLOC("Alloc-BM ", g_allocCountMid, size2, p)
return p;
}
if (g_LargePageFlags & Z7_LARGE_PAGES_FLAG_FAIL_STOP)
return p;
}
}
}
@@ -317,6 +301,7 @@ void BigFree(void *address)
MidFree(address);
}
#endif // Z7_LARGE_PAGES
#endif // _WIN32
@@ -327,9 +312,12 @@ const ISzAlloc g_Alloc = { SzAlloc, SzFree };
#ifdef _WIN32
static void *SzMidAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p) return MidAlloc(size); }
static void SzMidFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p) MidFree(address); }
const ISzAlloc g_MidAlloc = { SzMidAlloc, SzMidFree };
#endif
#if defined(Z7_LARGE_PAGES)
static void *SzBigAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p) return BigAlloc(size); }
static void SzBigFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p) BigFree(address); }
const ISzAlloc g_MidAlloc = { SzMidAlloc, SzMidFree };
const ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
#endif
@@ -371,10 +359,16 @@ typedef
#endif
#if !defined(_WIN32) \
&& (defined(Z7_ALLOC_NO_OFFSET_ALLOCATOR) \
|| defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L))
#ifndef _WIN32
#include <unistd.h> // for _POSIX_ADVISORY_INFO : for some linux
#if (defined(Z7_ALLOC_NO_OFFSET_ALLOCATOR) \
|| defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L) \
|| defined(_POSIX_ADVISORY_INFO) && (_POSIX_ADVISORY_INFO >= 200112L) \
|| defined(__APPLE__) \
/* || defined(__linux__) */)
#define USE_posix_memalign
// #pragma message("USE_posix_memalign")
#endif
#endif
#ifndef USE_posix_memalign
@@ -488,6 +482,181 @@ static void SzAlignedFree(ISzAllocPtr pp, void *address)
#endif
}
#ifndef _WIN32
#ifdef Z7_LARGE_PAGES
#if 0 // 1 for debug
#include <stdio.h>
#include <string.h> // for strerror()
#define PRF(x) x
#else
#define PRF(x)
#endif
#ifdef USE_posix_memalign
/* madvise():
glibc <= 2.19 : _BSD_SOURCE
glibc > 2.19 : _DEFAULT_SOURCE
*/
/* && (defined(_DEFAULT_SOURCE) || defined(_BSD_SOURCE)) */
#if 1 && !defined(Z7_NO_MADVISE) && \
(defined(__linux__) || defined(__unix__) || defined(__APPLE__))
#include <sys/mman.h> // for madvise
// #pragma message("sys/mman.h")
#if (defined(MADV_HUGEPAGE) && defined(MADV_NOHUGEPAGE))
#define Z7_USE_BIG_ALLOC_MADVISE
// #pragma message("Z7_USE_BIG_ALLOC_MADVISE")
#endif
#endif
#endif // USE_posix_memalign
#ifdef Z7_USE_BIG_ALLOC_MADVISE
#define LARGE_PAGE_SIZE_DEFAULT (1 << 21)
#else
#define LARGE_PAGE_SIZE_DEFAULT 0
#endif
extern
size_t g_LargePageSize;
size_t g_LargePageSize = LARGE_PAGE_SIZE_DEFAULT;
extern
size_t g_LargePageThresholdMin;
size_t g_LargePageThresholdMin = LARGE_PAGE_SIZE_DEFAULT / 2;
extern
UInt32 g_LargePageFlags;
UInt32 g_LargePageFlags = 0;
void *BigAlloc(size_t size)
{
if (size == 0)
return NULL;
#ifdef USE_posix_memalign
{
const size_t pageSize = g_LargePageSize;
void *buf = NULL; // on Linux (and other systems), posix_memalign() does not modify memptr on failure (POSIX.1-2008 TC2).
PRF(printf("\nBigAlloc 0x%08x=%5uMB", (unsigned)(size), (unsigned)(size >> 20));)
if (pageSize && size > g_LargePageThresholdMin)
{
int res;
const size_t mask = pageSize - 1;
/* we can allocate aligned size, so data at the end of buffer also will use huge page
if (size2 for madvise() is not aligned for huge page size)
{ Last data block will use small pages. It reduces memory allocation,
but last data block with small pages can work slower.
It's useful, if we have very large HUGE_PAGE: 32MB or 512MB. }
*/
size_t size2 = (size + mask) & ~mask;
if (size2 < size || (size & mask) <= g_LargePageThresholdMin)
size2 = size;
res = posix_memalign(&buf, pageSize, size2);
PRF(printf(" posix_memalign size=0x%08x=%5uMB align=%u",
(unsigned)(size2), (unsigned)(size2 >> 20), (unsigned)pageSize);)
PRF(printf(" buf=%p", (void *)buf);)
if (res == 0)
{
#ifdef Z7_USE_BIG_ALLOC_MADVISE
if ((g_LargePageFlags & Z7_LARGE_PAGES_FLAG_NO_MADVISE) == 0)
{
// Advise the kernel to use huge pages for this memory range
// MADV_HUGEPAGE / MADV_NOHUGEPAGE : since Linux 2.6.38
// madvise() only operates on whole pages, therefore addr must be page-aligned (4KB/8KB/16KB/64KB).
// The value of size is rounded up to a multiple of page size.
PRF(printf(" madvise g_LargePageFlags=%x", (unsigned)g_LargePageFlags);)
res = madvise(buf, size2, (g_LargePageFlags & Z7_LARGE_PAGES_FLAG_NO_HUGEPAGE) ? MADV_NOHUGEPAGE : MADV_HUGEPAGE);
if (res)
{
PRF(printf("\nERROR res=%d, errno=%d=%s\n", res, (int)errno, strerror(errno));)
if (g_LargePageFlags & Z7_LARGE_PAGES_FLAG_FAIL_STOP)
{
free(buf);
return NULL;
}
}
}
#endif // Z7_USE_BIG_ALLOC_MADVISE
PRF(printf("\n");)
return buf;
}
PRF(printf("\nERROR res=%d=%s\n", res, strerror(res));)
if (g_LargePageFlags & Z7_LARGE_PAGES_FLAG_FAIL_STOP)
return NULL;
// (res == ENOMEM) "Out of memory" is possible, if pageSize is too big.
// so we do second attempt with smaller alignment
}
}
#endif // !USE_posix_memalign
PRF(printf(" z7_AlignedAlloc size=0x%08x=%5uMB\n", (unsigned)(size), (unsigned)(size >> 20));)
return z7_AlignedAlloc(size);
}
void BigFree(void *address)
{
z7_AlignedFree(address);
}
#endif // Z7_LARGE_PAGES
#endif // !_WIN32
#ifdef Z7_LARGE_PAGES
void z7_LargePage_Set(UInt32 flags, size_t pageSize, size_t threshold)
{
g_LargePageFlags = flags;
#ifdef _WIN32
if ((flags & Z7_LARGE_PAGES_FLAG_USE_HUGEPAGE) == 0)
{
g_LargePageSize = 0;
g_LargePageThresholdMin = 0;
}
else
{
if ((flags & Z7_LARGE_PAGES_FLAG_DIRECT_PAGE_SIZE) == 0)
{
#ifdef Z7_USE_DYN_GetLargePageMinimum
Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
typedef SIZE_T (WINAPI *Func_GetLargePageMinimum)(VOID);
const
Func_GetLargePageMinimum fn =
(Func_GetLargePageMinimum) Z7_CAST_FUNC_C GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
"GetLargePageMinimum");
if (fn)
pageSize = fn();
else
pageSize = 0;
#else
pageSize = GetLargePageMinimum();
#endif
if (pageSize & (pageSize - 1))
pageSize = 0;
}
g_LargePageSize = pageSize;
if ((flags & Z7_LARGE_PAGES_FLAG_DIRECT_THRESHOLD) == 0)
threshold = pageSize / 2;
g_LargePageThresholdMin = threshold;
}
#else // !_WIN32
if (flags & Z7_LARGE_PAGES_FLAG_NO_PAGECODE)
{
g_LargePageSize = 0;
g_LargePageThresholdMin = 0;
}
else
{
if ((flags & Z7_LARGE_PAGES_FLAG_DIRECT_PAGE_SIZE) == 0)
pageSize = LARGE_PAGE_SIZE_DEFAULT;
g_LargePageSize = pageSize;
if ((flags & Z7_LARGE_PAGES_FLAG_DIRECT_THRESHOLD) == 0)
threshold = pageSize / 2;
g_LargePageThresholdMin = threshold;
}
// PRF(printf("\ng_LargePageSize=%x g_LargePageThresholdMin = %x g_LargePageFlags = %x", (unsigned)g_LargePageSize, (unsigned)g_LargePageThresholdMin, (unsigned)g_LargePageFlags);)
#endif // !_WIN32
}
#endif // Z7_LARGE_PAGES
const ISzAlloc g_AlignedAlloc = { SzAlignedAlloc, SzAlignedFree };
+2 -2
View File
@@ -859,7 +859,7 @@ BoolInt CPU_IsSupported_AES (void) { return APPLE_CRYPTO_SUPPORT_VAL; }
#if defined(__GLIBC__) && (__GLIBC__ * 100 + __GLIBC_MINOR__ >= 216)
#define Z7_GETAUXV_AVAILABLE
#else
#elif !defined(__QNXNTO__)
// #pragma message("=== is not NEW GLIBC === ")
#if defined __has_include
#if __has_include (<sys/auxv.h>)
@@ -877,7 +877,7 @@ BoolInt CPU_IsSupported_AES (void) { return APPLE_CRYPTO_SUPPORT_VAL; }
#ifdef USE_HWCAP
#if defined(__FreeBSD__)
#if defined(__FreeBSD__) || defined(__OpenBSD__)
static unsigned long MY_getauxval(int aux)
{
unsigned long val;
+1 -1
View File
@@ -598,7 +598,7 @@ void MatchFinder_Init(void *_p)
#ifdef MY_CPU_X86_OR_AMD64
#if defined(__clang__) && (__clang_major__ >= 4) \
|| defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40701)
|| defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40900)
// || defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1900)
#define USE_LZFIND_SATUR_SUB_128
+2 -3
View File
@@ -2351,10 +2351,9 @@ static void LzmaEnc_Construct(CLzmaEnc *p)
CLzmaEncHandle LzmaEnc_Create(ISzAllocPtr alloc)
{
void *p;
p = ISzAlloc_Alloc(alloc, sizeof(CLzmaEnc));
CLzmaEncHandle p = (CLzmaEncHandle)ISzAlloc_Alloc(alloc, sizeof(CLzmaEnc));
if (p)
LzmaEnc_Construct((CLzmaEnc *)p);
LzmaEnc_Construct(p);
return p;
}
+18 -4
View File
@@ -153,6 +153,17 @@ static void PrintProcess_Info()
#endif
#endif
/* if we send (stackSize=0) to CreateThread(), it will
use default value PE::SizeOfStackReserve from exe file.
PE::SizeOfStackReserve == 1 MiB in exe file with default linker options.
Windows aligns specified value to the next 64 KB range. */
static const unsigned k_StackSize_ReserveSize =
#ifdef UNDER_CE
1 << 17;
#else
1 << 20;
#endif
WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param)
{
/* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */
@@ -160,12 +171,15 @@ WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param)
#ifdef USE_THREADS_CreateThread
DWORD threadId;
*p = CreateThread(NULL, 0, func, param, 0, &threadId);
*p = CreateThread(NULL, k_StackSize_ReserveSize, func, param, STACK_SIZE_PARAM_IS_A_RESERVATION, &threadId);
#else
#define CALL_beginthreadex(func2, param2, flags, threadIdPtr) \
((HANDLE)(_beginthreadex(NULL, k_StackSize_ReserveSize, func2, param2, (flags) | STACK_SIZE_PARAM_IS_A_RESERVATION, threadIdPtr)))
unsigned threadId;
*p = (HANDLE)(_beginthreadex(NULL, 0, func, param, 0, &threadId));
*p = CALL_beginthreadex(func, param, 0, &threadId);
#if 0 // 1 : for debug
{
@@ -223,7 +237,7 @@ WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param
HANDLE h;
WRes wres;
unsigned threadId;
h = (HANDLE)(_beginthreadex(NULL, 0, func, param, CREATE_SUSPENDED, &threadId));
h = CALL_beginthreadex(func, param, CREATE_SUSPENDED, &threadId);
*p = h;
wres = HandleToWRes(h);
if (h)
@@ -272,7 +286,7 @@ WRes Thread_Create_With_Group(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, u
HANDLE h;
WRes wres;
unsigned threadId;
h = (HANDLE)(_beginthreadex(NULL, 0, func, param, CREATE_SUSPENDED, &threadId));
h = CALL_beginthreadex(func, param, CREATE_SUSPENDED, &threadId);
*p = h;
wres = HandleToWRes(h);
if (h)
+3 -3
View File
@@ -279,7 +279,7 @@ SRes Xz_StateCoder_Bc_SetFromMethod_Func(IStateCoder *p, UInt64 id,
decoder = (CXzBcFilterState *)ISzAlloc_Alloc(alloc, sizeof(CXzBcFilterState));
if (!decoder)
return SZ_ERROR_MEM;
decoder->buf = ISzAlloc_Alloc(alloc, BRA_BUF_SIZE);
decoder->buf = (Byte *)ISzAlloc_Alloc(alloc, BRA_BUF_SIZE);
if (!decoder->buf)
{
ISzAlloc_Free(alloc, decoder);
@@ -1243,7 +1243,7 @@ SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
UInt32 digest32[XZ_CHECK_SIZE_MAX / 4];
p->state = XZ_STATE_BLOCK_HEADER;
p->pos = 0;
if (XzCheck_Final(&p->check, (void *)digest32) && memcmp(digest32, p->buf, checkSize) != 0)
if (XzCheck_Final(&p->check, (Byte *)(void *)digest32) && memcmp(digest32, p->buf, checkSize) != 0)
return SZ_ERROR_CRC;
if (p->decodeOnlyOneBlock)
{
@@ -1292,7 +1292,7 @@ SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
p->state = XZ_STATE_STREAM_INDEX_CRC;
p->indexSize += 4;
p->pos = 0;
Sha256_Final(&p->sha, (void *)digest32);
Sha256_Final(&p->sha, (Byte *)(void *)digest32);
if (memcmp(digest32, p->shaDigest32, SHA256_DIGEST_SIZE) != 0)
return SZ_ERROR_CRC;
}
+3
View File
@@ -7,6 +7,7 @@ add_library(vixl
include/vixl/aarch64/decoder-aarch64.h
include/vixl/aarch64/decoder-constants-aarch64.h
include/vixl/aarch64/decoder-visitor-map-aarch64.h
include/vixl/aarch64/debugger-aarch64.h
include/vixl/aarch64/disasm-aarch64.h
include/vixl/aarch64/instructions-aarch64.h
include/vixl/aarch64/macro-assembler-aarch64.h
@@ -31,6 +32,7 @@ add_library(vixl
src/aarch64/cpu-aarch64.cc
src/aarch64/cpu-features-auditor-aarch64.cc
src/aarch64/decoder-aarch64.cc
src/aarch64/debugger-aarch64.cc
src/aarch64/disasm-aarch64.cc
src/aarch64/instructions-aarch64.cc
src/aarch64/logic-aarch64.cc
@@ -39,6 +41,7 @@ add_library(vixl
src/aarch64/operands-aarch64.cc
src/aarch64/pointer-auth-aarch64.cc
src/aarch64/registers-aarch64.cc
src/aarch64/simulator-aarch64.cc
src/code-buffer-vixl.cc
src/compiler-intrinsics-vixl.cc
src/cpu-features.cc
+116 -48
View File
@@ -1,14 +1,16 @@
VIXL: Armv8 Runtime Code Generation Library, 3.0.0
==================================================
VIXL: Arm Runtime Code Generation Library
=========================================
Contents:
* Overview
* Licence
* Requirements
* Known limitations
* Usage
* [Overview](#overview)
* [Licence](#licence)
* [Requirements](#requirements)
* [Versioning](#versioning)
* [Supported Arm Architecture Features](#supported-arm-architecture-features)
* [Known limitations](#known-limitations)
* [Bug reports](#bug-reports)
* [Usage](#usage)
Overview
========
@@ -16,17 +18,16 @@ Overview
VIXL contains three components.
1. Programmatic **assemblers** to generate A64, A32 or T32 code at runtime. The
assemblers abstract some of the constraints of each ISA; for example, most
assemblers abstract some of the constraints of each ISA; for example, some
instructions support any immediate.
2. **Disassemblers** that can print any instruction emitted by the assemblers.
3. A **simulator** that can simulate any instruction emitted by the A64
3. An **A64 simulator** that can simulate any instruction emitted by the A64
assembler. The simulator allows generated code to be run on another
architecture without the need for a full ISA model.
The VIXL git repository can be found [on 'https://git.linaro.org'][vixl].
The VIXL git repository can be found [on GitLab][vixl].
Changes from previous versions of VIXL can be found in the
[Changelog](doc/changelog.md).
Build status: [![Build Status](https://gitlab.arm.com/runtimes/vixl/badges/main/pipeline.svg)](https://gitlab.arm.com/runtimes/vixl/-/pipelines)
Licence
@@ -35,32 +36,78 @@ Licence
This software is covered by the licence described in the [LICENCE](LICENCE)
file.
Contributions, as pull requests or via other means, are accepted under the terms
of the same [LICENCE](LICENCE).
Requirements
============
To build VIXL the following software is required:
1. Python 2.7
1. Python 3.5+
2. SCons 2.0
3. GCC 4.8+ or Clang 3.4+
3. GCC 4.8+ or Clang 4.0+
A 64-bit host machine is required, implementing an LP64 data model. VIXL has
been tested using GCC on AArch64 Debian, GCC and Clang on amd64 Ubuntu
systems.
To run the linter and code formatting stages of the tests, the following
software is also required:
To run the code formatting stages of the tests, the following software is also required:
1. Git
2. [Google's `cpplint.py`][cpplint]
3. clang-format-3.8
1. clang-format 11+
2. clang-tidy 11+
Refer to the 'Usage' section for details.
Note that in Ubuntu 18.04, clang-tidy-4.0 will only work if the clang-4.0
package is also installed.
Known Limitations for AArch64 code generation
=============================================
Versioning
==========
VIXL uses [Semantic Versioning 2.0.0][semver] - see [VERSIONS](VERSIONS.md) for details.
Supported Arm Architecture Features
===================================
| Feature | VIXL CPUFeatures Flag | Notes |
|------------|-------------------------------|---------------------------------|
| BTI | kBTI | Per-page enabling not supported |
| CSSC | kCSSC | |
| DotProd | kDotProduct | |
| FCMA | kFcma | |
| FHM | kFHM | |
| FP16 | kFPHalf, kNEONHalf | |
| FRINTTS | kFrintToFixedSizedInt | |
| FlagM | kFlagM | |
| FlagM2 | kAXFlag | |
| I8MM | kI8MM | |
| JSCVT | kJSCVT | |
| LOR | kLORegions | |
| LRCPC | kRCpc | |
| LRCPC2 | kRCpcImm | |
| LSE | kAtomics | |
| MOPS | kMOPS | |
| MTE | kMTEInstructions, kMTE, kMTE3 | |
| PAuth | kPAuth, kPAuthGeneric | Not ERETAA, ERETAB |
| RAS | kRAS | |
| RDM | kRDM | |
| SVE | kSVE | |
| SVE2 | kSVE2 | |
| SVEBitPerm | kSVEBitPerm | |
| SVEF32MM | kSVEF32MM | |
| SVEF64MM | kSVEF64MM | |
| SVEI8MM | kSVEI8MM | |
Enable generating code for an architecture feature by combining a flag with
the MacroAssembler's defaults. For example, to generate code for SVE, use
`masm.GetCPUFeatures()->Combine(CPUFeatures::kSVE);`.
See [the cpu features header file](src/cpu-features.h) for more information.
Known Limitations
=================
VIXL was developed for JavaScript engines so a number of features from A64 were
deemed unnecessary:
@@ -79,11 +126,6 @@ builds and mostly works for 32-bit x86 platforms, there are a number of
floating-point operations which do not work correctly, and a number of tests
fail as a result.
VIXL may not build using Clang 3.7, due to a compiler warning. A workaround is
to disable conversion of warnings to errors, or to delete the offending
`return` statement reported and rebuild. This problem will be fixed in the next
release.
Debug Builds
------------
@@ -125,6 +167,45 @@ Instructions affected by these limitations:
`stlxrh`, `stlxr`, `ldaxrb`, `ldaxrh`, `ldaxr`, `stlxp`, `ldaxp`, `stlrb`,
`stlrh`, `stlr`, `ldarb`, `ldarh`, `ldar`, `clrex`.
Security Considerations
-----------------------
VIXL allows callers to generate any code they want. The generated code is
arbitrary, and can therefore call back into any other component in the process.
As with any self-modifying code, vulnerabilities in the client or in VIXL itself
could lead to arbitrary code generation.
For performance reasons, VIXL's Assembler only performs debug-mode checking of
instruction operands (such as immediate field encodability). This can minimise
code-generation overheads for advanced compilers that already model instructions
accurately, and might consider the Assembler's checks to be redundant. The
Assembler should only be used directly where encodability is independently
checked, and where fine control over all generated code is required.
The MacroAssembler synthesises multiple-instruction sequences to support _some_
unencodable operand combinations. The MacroAssembler can provide a useful safety
check in cases where the Assembler's precision is not required; an unexpected
unencodable operand should result in a macro with the correct behaviour, rather
than an invalid instruction.
In general, the MacroAssembler handles operands which are likely to vary with
user-supplied data, but does not usually handle inputs which are likely to be
easily covered by tests. For example, move-immediate arguments are likely to be
data-dependent, but register types (e.g. `x` vs `w`) are not.
We recommend that _all_ users use the MacroAssembler, using `ExactAssemblyScope`
to invoke the Assembler when specific instruction sequences are required. This
approach is recommended even in cases where a compiler can model the
instructions precisely, because, subject to the limitations described above, it
offers an additional layer of protection against logic bugs in instruction
selection.
Bug reports
===========
Bug reports may be made in the Issues section of GitLab, or sent to
vixl@arm.com. Please provide any steps required to recreate a bug, along with
build environment and host system information.
Usage
=====
@@ -137,23 +218,10 @@ with VIXL, in both release and debug mode. It is a useful script for verifying
that all of VIXL's dependencies are in place and that VIXL is working as it
should.
By default, the `tools/test.py` script runs a linter to check that the source
code conforms with the code style guide, and to detect several common errors
that the compiler may not warn about. This is most useful for VIXL developers.
The linter has the following dependencies:
1. Git must be installed, and the VIXL project must be in a valid Git
repository, such as one produced using `git clone`.
2. `cpplint.py`, [as provided by Google][cpplint], must be available (and
executable) on the `PATH`.
It is possible to tell `tools/test.py` to skip the linter stage by passing
`--nolint`. This removes the dependency on `cpplint.py` and Git. The `--nolint`
option is implied if the VIXL project is a snapshot (with no `.git` directory).
Additionally, `tools/test.py` tests code formatting using `clang-format-3.8`.
If you don't have `clang-format-3.8`, disable the test using the
`--noclang-format` option.
By default, `tools/test.py` tests code formatting using `clang-format-4.0`,
and performs static analysis using `clang-tidy-4.0`. If you don't have these
tools, disable the test using `--noclang-format` or `--noclang-tidy`,
respectively.
Also note that the tests for the tracing features depend upon external `diff`
and `sed` tools. If these tools are not available in `PATH`, these tests will
@@ -173,11 +241,11 @@ aarch32_examples` or `scons aarch64_examples` from the root directory, or use
[cpplint]: http://google-styleguide.googlecode.com/svn/trunk/cpplint/cpplint.py
"Google's cpplint.py script."
[vixl]: https://gitlab.arm.com/runtimes/vixl
"The VIXL repository on GitLab."
[vixl]: https://git.linaro.org/arm/vixl.git
"The VIXL repository at 'https://git.linaro.org'."
[semver]: https://semver.org/spec/v2.0.0.html
"Semantic Versioning 2.0.0 Specification"
[getting-started-aarch32]: doc/aarch32/getting-started-aarch32.md
"Introduction to VIXL for AArch32."
+31
View File
@@ -538,12 +538,18 @@ class Assembler : public vixl::internal::AssemblerBase {
// Conditional branch to label.
void b(Label* label, Condition cond);
// Conditional branch consistent to label.
void bc(Label* label, Condition cond);
// Unconditional branch to PC offset.
void b(int64_t imm26);
// Conditional branch to PC offset.
void b(int64_t imm19, Condition cond);
// Conditional branch consistent to PC offset.
void bc(int64_t imm19, Condition cond);
// Branch with link to label.
void bl(Label* label);
@@ -2081,6 +2087,9 @@ class Assembler : public vixl::internal::AssemblerBase {
// Prefetch from pc + imm19 << 2 (allowing unallocated hints).
void prfm(int op, int64_t imm19);
// Yield.
void yield();
// Move instructions. The default shift of -1 indicates that the move
// instruction will calculate an appropriate 16-bit immediate and left shift
// that is equal to the 64-bit immediate argument. If an explicit left shift
@@ -2450,6 +2459,16 @@ class Assembler : public vixl::internal::AssemblerBase {
// FP convert to unsigned integer, round towards +infinity.
void fcvtpu(const VRegister& vd, const VRegister& vn);
// Floating-point convert from single-precision to BFloat16 format (scalar).
void bfcvt(const VRegister& vd, const VRegister& vn);
// Floating-point convert from single-precision to BFloat16 format (vector).
void bfcvtn(const VRegister& vd, const VRegister& vn);
// Floating-point convert from single-precision to BFloat16 format (second
// part).
void bfcvtn2(const VRegister& vd, const VRegister& vn);
// Convert signed integer or fixed point to FP.
void scvtf(const VRegister& fd, const Register& rn, int fbits = 0);
@@ -3732,6 +3751,12 @@ class Assembler : public vixl::internal::AssemblerBase {
const VRegister& vm,
int index);
// SM4 Encode.
void sm4e(const VRegister& vd, const VRegister& vn);
// SM4 Key.
void sm4ekey(const VRegister& vd, const VRegister& vn, const VRegister& vm);
// Scalable Vector Extensions.
// Absolute value (predicated).
@@ -3839,6 +3864,12 @@ class Assembler : public vixl::internal::AssemblerBase {
const PRegisterWithLaneSize& pn,
const PRegisterWithLaneSize& pm);
// Floating-point down convert to BFloat16 format (predicated).
void bfcvt(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn);
// Floating-point down convert and narrow to BFloat16 (top, predicated).
void bfcvtnt(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn);
// Break after first true condition.
void brka(const PRegisterWithLaneSize& pd,
const PRegister& pg,
File diff suppressed because it is too large Load Diff
+1
View File
@@ -173,6 +173,7 @@ class AA64ISAR2 : public IDRegister {
static const Field kRPRES;
static const Field kMOPS;
static const Field kCSSC;
static const Field kHBC;
};
class AA64MMFR0 : public IDRegister {
@@ -111,9 +111,10 @@ class CPUFeaturesAuditor : public DecoderVisitor {
class RecordInstructionFeaturesScope;
#define DECLARE(A) virtual void Visit##A(const Instruction* instr);
VISITOR_LIST(DECLARE)
SIM_AUD_VISITOR_LIST(DECLARE)
#undef DECLARE
void VisitCryptoSM3(const Instruction* instr);
void VisitCryptoSM4(const Instruction* instr);
void LoadStoreHelper(const Instruction* instr);
void LoadStorePairHelper(const Instruction* instr);
+210 -192
View File
@@ -30,240 +30,244 @@
#include <list>
#include <map>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include "../globals-vixl.h"
#include "instructions-aarch64.h"
// List macro containing all visitors needed by the decoder class.
#define VISITOR_LIST_THAT_RETURN(V) \
V(AddSubExtended) \
V(AddSubImmediate) \
V(AddSubShifted) \
V(AddSubWithCarry) \
V(AtomicMemory) \
V(Bitfield) \
V(CompareBranch) \
V(ConditionalBranch) \
V(ConditionalCompareImmediate) \
V(ConditionalCompareRegister) \
V(ConditionalSelect) \
V(Crypto2RegSHA) \
V(Crypto3RegSHA) \
V(CryptoAES) \
V(DataProcessing1Source) \
V(DataProcessing2Source) \
V(DataProcessing3Source) \
V(EvaluateIntoFlags) \
V(Exception) \
V(Extract) \
V(FPCompare) \
V(FPConditionalCompare) \
V(FPConditionalSelect) \
V(FPDataProcessing1Source) \
V(FPDataProcessing2Source) \
V(FPDataProcessing3Source) \
V(FPFixedPointConvert) \
V(FPImmediate) \
V(FPIntegerConvert) \
V(LoadLiteral) \
V(LoadStoreExclusive) \
V(LoadStorePAC) \
V(LoadStorePairNonTemporal) \
V(LoadStorePairOffset) \
V(LoadStorePairPostIndex) \
V(LoadStorePairPreIndex) \
V(LoadStorePostIndex) \
V(LoadStorePreIndex) \
V(LoadStoreRCpcUnscaledOffset) \
V(LoadStoreRegisterOffset) \
V(LoadStoreUnscaledOffset) \
V(LoadStoreUnsignedOffset) \
V(LogicalImmediate) \
V(LogicalShifted) \
V(MoveWideImmediate) \
V(NEON2RegMisc) \
V(NEON2RegMiscFP16) \
V(NEON3Different) \
V(NEON3Same) \
V(NEON3SameExtra) \
V(NEON3SameFP16) \
V(NEONAcrossLanes) \
V(NEONByIndexedElement) \
V(NEONCopy) \
V(NEONExtract) \
V(NEONLoadStoreMultiStruct) \
V(NEONLoadStoreMultiStructPostIndex) \
V(NEONLoadStoreSingleStruct) \
V(NEONLoadStoreSingleStructPostIndex) \
V(NEONModifiedImmediate) \
V(NEONPerm) \
V(NEONScalar2RegMisc) \
#define VISITOR_LIST_THAT_RETURN(V) \
V(SVEBroadcastBitmaskImm) \
V(Unallocated) \
V(Unimplemented)
#define SIM_AUD_VISITOR_LIST_THAT_RETURN(V) \
V(NEONScalar2RegMiscFP16) \
V(NEONScalar3Diff) \
V(NEONScalar3Same) \
V(NEONScalar3SameExtra) \
V(NEONScalar3SameFP16) \
V(NEONScalarByIndexedElement) \
V(NEONScalarCopy) \
V(NEONScalarPairwise) \
V(NEONScalarShiftImmediate) \
V(NEONShiftImmediate) \
V(NEONTable) \
V(PCRelAddressing) \
V(RotateRightIntoFlags) \
V(SVE32BitGatherLoad_ScalarPlus32BitUnscaledOffsets) \
V(SVE32BitGatherLoad_VectorPlusImm) \
V(NEONScalar3SameExtra) \
V(SVE32BitGatherLoadHalfwords_ScalarPlus32BitScaledOffsets) \
V(SVE32BitGatherLoadWords_ScalarPlus32BitScaledOffsets) \
V(SVE32BitGatherLoad_ScalarPlus32BitUnscaledOffsets) \
V(SVE32BitGatherPrefetch_ScalarPlus32BitScaledOffsets) \
V(SVE32BitGatherPrefetch_VectorPlusImm) \
V(SVE32BitScatterStore_ScalarPlus32BitScaledOffsets) \
V(SVE32BitScatterStore_ScalarPlus32BitUnscaledOffsets) \
V(SVE32BitScatterStore_VectorPlusImm) \
V(SVE64BitGatherLoad_ScalarPlus32BitUnpackedScaledOffsets) \
V(SVE64BitGatherLoad_ScalarPlus64BitScaledOffsets) \
V(SVE64BitGatherLoad_ScalarPlus64BitUnscaledOffsets) \
V(SVE64BitGatherLoad_ScalarPlusUnpacked32BitUnscaledOffsets) \
V(SVE64BitGatherLoad_VectorPlusImm) \
V(SVE64BitGatherPrefetch_ScalarPlus64BitScaledOffsets) \
V(SVE64BitGatherPrefetch_ScalarPlusUnpacked32BitScaledOffsets) \
V(SVE64BitGatherPrefetch_VectorPlusImm) \
V(SVE64BitScatterStore_ScalarPlus64BitScaledOffsets) \
V(SVE64BitScatterStore_ScalarPlus64BitUnscaledOffsets) \
V(SVE64BitScatterStore_ScalarPlusUnpacked32BitScaledOffsets) \
V(SVE64BitScatterStore_ScalarPlusUnpacked32BitUnscaledOffsets) \
V(SVE64BitScatterStore_VectorPlusImm) \
V(SVEAddressGeneration) \
V(SVEBitwiseLogicalUnpredicated) \
V(SVEBitwiseShiftUnpredicated) \
V(SVEBitwiseLogical_Predicated) \
V(SVEBitwiseShiftByVector_Predicated) \
V(SVEConditionallyBroadcastElementToVector) \
V(SVEConditionallyExtractElementToSIMDFPScalar) \
V(SVEConstructivePrefix_Unpredicated) \
V(SVEContiguousNonTemporalLoad_ScalarPlusScalar) \
V(SVEContiguousNonTemporalStore_ScalarPlusScalar) \
V(SVEContiguousStore_ScalarPlusScalar) \
V(SVEExtractElementToSIMDFPScalarRegister) \
V(SVEFFRInitialise) \
V(SVEFFRWriteFromPredicate) \
V(SVEFPAccumulatingReduction) \
V(SVEFPArithmeticUnpredicated) \
V(SVEFPCompareVectors) \
V(SVEFPCompareWithZero) \
V(SVEFPComplexAddition) \
V(SVEFPComplexMulAdd) \
V(SVEFPConvertToInt) \
V(SVEInsertSIMDFPScalarRegister) \
V(SVEIntAddSubtractVectors_Predicated) \
V(SVEIntMinMaxDifference_Predicated) \
V(SVEIntMinMaxImm_Unpredicated) \
V(SVEIntMulImm_Unpredicated) \
V(SVEIntMulVectors_Predicated) \
V(SVELoadAndBroadcastQOWord_ScalarPlusScalar) \
V(SVELoadMultipleStructures_ScalarPlusImm) \
V(SVELoadMultipleStructures_ScalarPlusScalar) \
V(SVEPartitionBreakCondition) \
V(SVEPermutePredicateElements) \
V(SVEPredicateFirstActive) \
V(SVEPredicateReadFromFFR_Unpredicated) \
V(SVEPredicateTest) \
V(SVEPredicateZero) \
V(SVEPropagateBreakToNextPartition) \
V(SVEStoreMultipleStructures_ScalarPlusImm) \
V(SVEStoreMultipleStructures_ScalarPlusScalar) \
V(SVETableLookup) \
V(SVEUnpackPredicateElements) \
V(SVEVectorSplice) \
V(SVEFPComplexMulAddIndex) \
V(SVEFPFastReduction) \
V(SVEFPMulIndex) \
V(SVEFPMulAdd) \
V(SVEFPMulAddIndex) \
V(SVEFPUnaryOpUnpredicated) \
V(SVEIncDecByPredicateCount) \
V(SVEIndexGeneration) \
V(SVEIntArithmeticUnpredicated) \
V(SVEIntCompareSignedImm) \
V(SVEIntCompareUnsignedImm) \
V(SVEIntCompareVectors) \
V(SVEIntMulAddPredicated) \
V(SVEIntMulAddUnpredicated) \
V(SVEIntReduction) \
V(SVEIntUnaryArithmeticPredicated) \
V(SVEMovprfx) \
V(SVEMulIndex) \
V(SVEPermuteVectorExtract) \
V(SVEPermuteVectorInterleaving) \
V(SVEPredicateCount) \
V(SVEPredicateLogical) \
V(SVEPredicateNextActive) \
V(SVEPredicateReadFromFFR_Predicated) \
V(SVEPropagateBreak) \
V(SVEStackFrameAdjustment) \
V(SVEStackFrameSize) \
V(SVEVectorSelect) \
V(SVEBitwiseLogical_Predicated) \
V(SVEBitwiseLogicalWithImm_Unpredicated) \
V(SVEBitwiseShiftByImm_Predicated) \
V(SVEBitwiseShiftByVector_Predicated) \
V(SVEBitwiseShiftByWideElements_Predicated) \
V(SVEBroadcastBitmaskImm) \
V(SVEBroadcastFPImm_Unpredicated) \
V(SVEBroadcastGeneralRegister) \
V(SVEBroadcastIndexElement) \
V(SVEBroadcastIntImm_Unpredicated) \
V(SVECompressActiveElements) \
V(SVEConditionallyBroadcastElementToVector) \
V(SVEConditionallyExtractElementToSIMDFPScalar) \
V(SVEConditionallyExtractElementToGeneralRegister) \
V(SVEConditionallyTerminateScalars) \
V(SVEConstructivePrefix_Unpredicated) \
V(SVEContiguousFirstFaultLoad_ScalarPlusScalar) \
V(SVEContiguousLoad_ScalarPlusImm) \
V(SVEContiguousLoad_ScalarPlusScalar) \
V(SVEContiguousNonFaultLoad_ScalarPlusImm) \
V(SVEContiguousNonTemporalLoad_ScalarPlusImm) \
V(SVEContiguousNonTemporalLoad_ScalarPlusScalar) \
V(SVEContiguousNonTemporalStore_ScalarPlusImm) \
V(SVEContiguousNonTemporalStore_ScalarPlusScalar) \
V(SVEContiguousPrefetch_ScalarPlusImm) \
V(SVEContiguousPrefetch_ScalarPlusScalar) \
V(SVEContiguousStore_ScalarPlusImm) \
V(SVEContiguousStore_ScalarPlusScalar) \
V(SVECopySIMDFPScalarRegisterToVector_Predicated) \
V(SVECopyFPImm_Predicated) \
V(SVECopyGeneralRegisterToVector_Predicated) \
V(SVECopyIntImm_Predicated) \
V(SVEElementCount) \
V(SVEExtractElementToSIMDFPScalarRegister) \
V(SVEExtractElementToGeneralRegister) \
V(SVEFPArithmetic_Predicated) \
V(SVEFPArithmeticWithImm_Predicated) \
V(SVEFPConvertPrecision) \
V(SVEFPConvertToInt) \
V(SVEFPExponentialAccelerator) \
V(SVEFPRoundToIntegralValue) \
V(SVEFPTrigMulAddCoefficient) \
V(SVEFPTrigSelectCoefficient) \
V(SVEFPUnaryOp) \
V(SVEIncDecRegisterByElementCount) \
V(SVEIncDecVectorByElementCount) \
V(SVEInsertSIMDFPScalarRegister) \
V(SVEInsertGeneralRegister) \
V(SVEIntAddSubtractImm_Unpredicated) \
V(SVEIntAddSubtractVectors_Predicated) \
V(SVEIntCompareScalarCountAndLimit) \
V(SVEIntConvertToFP) \
V(SVEIntDivideVectors_Predicated) \
V(SVEIntMinMaxImm_Unpredicated) \
V(SVEIntMinMaxDifference_Predicated) \
V(SVEIntMulImm_Unpredicated) \
V(SVEIntMulVectors_Predicated) \
V(SVELoadAndBroadcastElement) \
V(SVELoadAndBroadcastQOWord_ScalarPlusImm) \
V(SVELoadAndBroadcastQOWord_ScalarPlusScalar) \
V(SVELoadMultipleStructures_ScalarPlusImm) \
V(SVELoadMultipleStructures_ScalarPlusScalar) \
V(SVELoadPredicateRegister) \
V(SVELoadVectorRegister) \
V(SVEPartitionBreakCondition) \
V(SVEPermutePredicateElements) \
V(SVEPredicateFirstActive) \
V(RotateRightIntoFlags) \
V(EvaluateIntoFlags) \
V(ConditionalCompareRegister) \
V(ConditionalCompareImmediate) \
V(PCRelAddressing) \
V(UnconditionalBranch) \
V(DataProcessing1Source) \
V(CompareBranch) \
V(TestBranch) \
V(LoadStoreRCpcUnscaledOffset) \
V(LoadStoreUnscaledOffset) \
V(LoadLiteral) \
V(LoadStorePairNonTemporal) \
V(LoadStorePAC) \
V(FPCompare) \
V(FPConditionalCompare) \
V(FPConditionalSelect) \
V(FPDataProcessing2Source) \
V(FPDataProcessing3Source) \
V(FPIntegerConvert) \
V(FPFixedPointConvert) \
V(Exception) \
V(Crypto2RegSHA) \
V(Crypto3RegSHA) \
V(CryptoAES) \
V(NEON2RegMiscFP16) \
V(SVEContiguousLoad_ScalarPlusImm) \
V(SVEPredicateInitialize) \
V(SVEPredicateNextActive) \
V(SVEPredicateReadFromFFR_Predicated) \
V(SVEPredicateReadFromFFR_Unpredicated) \
V(SVEPredicateTest) \
V(SVEPredicateZero) \
V(SVEPropagateBreakToNextPartition) \
V(SVEIndexGeneration) \
V(SVEAddressGeneration) \
V(SVELoadAndBroadcastQOWord_ScalarPlusImm) \
V(SVEIntAddSubtractImm_Unpredicated) \
V(SVEIntCompareScalarCountAndLimit) \
V(FPImmediate) \
V(FPDataProcessing1Source) \
V(NEONModifiedImmediate) \
V(NEONTable) \
V(SVEIntReduction) \
V(SVEMulIndex) \
V(NEON3SameFP16) \
V(NEONLoadStoreSingleStruct) \
V(NEONLoadStoreSingleStructPostIndex) \
V(NEONLoadStoreMultiStructPostIndex) \
V(LoadStorePreIndex) \
V(LoadStorePostIndex) \
V(LoadStoreUnsignedOffset) \
V(LoadStoreRegisterOffset) \
V(LoadStorePairPostIndex) \
V(LoadStorePairOffset) \
V(LoadStorePairPreIndex) \
V(SVEBitwiseShiftByWideElements_Predicated) \
V(NEONScalarPairwise) \
V(SVEFPUnaryOp) \
V(SVEFPRoundToIntegralValue) \
V(SVEFPUnaryOpUnpredicated) \
V(SVEFPMulAdd) \
V(SVEFPFastReduction) \
V(SVEFPComplexMulAdd) \
V(SVEFPComplexAddition) \
V(SVEFPCompareWithZero) \
V(SVEFPCompareVectors) \
V(SVEFPArithmeticUnpredicated) \
V(SVEFPAccumulatingReduction) \
V(SVEIntUnaryArithmeticPredicated) \
V(SVEBitwiseShiftUnpredicated) \
V(SVEUnpackVectorElements) \
V(SVEIntConvertToFP) \
V(SVEReverseWithinElements) \
V(SVEReversePredicateElements) \
V(SVEReverseVectorElements) \
V(SVEReverseWithinElements) \
V(SVESaturatingIncDecRegisterByElementCount) \
V(SVESaturatingIncDecVectorByElementCount) \
V(SVEStoreMultipleStructures_ScalarPlusImm) \
V(SVEStoreMultipleStructures_ScalarPlusScalar) \
V(SVEStorePredicateRegister) \
V(SVEStoreVectorRegister) \
V(SVETableLookup) \
V(SVEUnpackPredicateElements) \
V(SVEUnpackVectorElements) \
V(SVEVectorSplice) \
V(System) \
V(TestBranch) \
V(Unallocated) \
V(UnconditionalBranch) \
V(SVEInsertGeneralRegister) \
V(SVEFPTrigSelectCoefficient) \
V(SVEFPTrigMulAddCoefficient) \
V(SVEFPExponentialAccelerator) \
V(SVEFPArithmetic_Predicated) \
V(SVEFPArithmeticWithImm_Predicated) \
V(SVEBitwiseLogicalWithImm_Unpredicated) \
V(UnconditionalBranchToRegister) \
V(Unimplemented)
V(NEONExtract) \
V(ConditionalSelect) \
V(LogicalImmediate) \
V(AddSubImmediate) \
V(AddSubShifted) \
V(AddSubExtended) \
V(LogicalShifted) \
V(Extract) \
V(DataProcessing2Source) \
V(DataProcessing3Source) \
V(ConditionalBranch) \
V(Bitfield) \
V(AtomicMemory) \
V(SVEVectorSelect) \
V(SVEPredicateLogical) \
V(SVEIntDivideVectors_Predicated) \
V(SVEBroadcastIntImm_Unpredicated) \
V(SVEBroadcastFPImm_Unpredicated) \
V(SVEBroadcastGeneralRegister) \
V(SVECompressActiveElements) \
V(SVEConditionallyTerminateScalars) \
V(SVEConditionallyExtractElementToGeneralRegister) \
V(SVEBitwiseShiftByImm_Predicated) \
V(SVECopyGeneralRegisterToVector_Predicated) \
V(SVECopyIntImm_Predicated) \
V(SVECopySIMDFPScalarRegisterToVector_Predicated) \
V(SVECopyFPImm_Predicated) \
V(SVEExtractElementToGeneralRegister) \
V(SVEIntMulAddUnpredicated) \
V(SVEContiguousStore_ScalarPlusImm) \
V(SVEContiguousPrefetch_ScalarPlusScalar) \
V(SVEContiguousPrefetch_ScalarPlusImm) \
V(SVEContiguousNonFaultLoad_ScalarPlusImm) \
V(SVEBitwiseLogicalUnpredicated) \
V(SVE64BitGatherPrefetch_ScalarPlus64BitScaledOffsets) \
V(SVE64BitGatherPrefetch_ScalarPlusUnpacked32BitScaledOffsets) \
V(SVE64BitGatherPrefetch_VectorPlusImm) \
V(SVE32BitGatherPrefetch_VectorPlusImm) \
V(SVELoadVectorRegister) \
V(SVEStoreVectorRegister) \
V(SVELoadPredicateRegister) \
V(SVEStorePredicateRegister) \
V(SVEFPConvertPrecision) \
V(SVE32BitGatherLoad_VectorPlusImm) \
V(SVE32BitScatterStore_VectorPlusImm) \
V(SVE64BitScatterStore_VectorPlusImm) \
V(SVEContiguousFirstFaultLoad_ScalarPlusScalar) \
V(SVEContiguousNonTemporalLoad_ScalarPlusImm) \
V(SVEContiguousNonTemporalStore_ScalarPlusImm) \
V(SVELoadAndBroadcastElement) \
V(NEONPerm) \
V(NEONLoadStoreMultiStruct) \
V(NEON3Same) \
V(NEON3SameExtra) \
V(NEON2RegMisc) \
V(NEONByIndexedElement) \
V(SVE64BitGatherLoad_VectorPlusImm) \
V(NEONShiftImmediate) \
V(NEONCopy) \
V(NEONScalar2RegMisc) \
V(NEONScalar3Diff) \
V(NEONScalar3Same) \
V(NEONScalarCopy) \
V(NEONScalarByIndexedElement) \
V(NEONAcrossLanes) \
V(NEONScalarShiftImmediate) \
V(NEON3Different) \
V(MoveWideImmediate) \
V(SVEElementCount) \
V(SVEIncDecRegisterByElementCount) \
V(SVEIncDecVectorByElementCount) \
V(SVESaturatingIncDecVectorByElementCount) \
V(SVESaturatingIncDecRegisterByElementCount) \
V(LoadStoreExclusive) \
V(SVEBroadcastIndexElement) \
V(System) \
V(AddSubWithCarry)
#define VISITOR_LIST_THAT_DONT_RETURN(V) V(Reserved)
@@ -271,6 +275,10 @@
VISITOR_LIST_THAT_RETURN(V) \
VISITOR_LIST_THAT_DONT_RETURN(V)
#define SIM_AUD_VISITOR_LIST(V) \
VISITOR_LIST(V) \
SIM_AUD_VISITOR_LIST_THAT_RETURN(V)
namespace vixl {
namespace aarch64 {
@@ -311,7 +319,10 @@ class CompiledDecodeNode;
// handles the instruction.
class Decoder {
public:
Decoder() { ConstructDecodeGraph(); }
Decoder() {
ConstructDecodeGraph();
PopulatePerInstructionUnallocatedMap(&form_to_unalloc_);
}
// Top-level wrappers around the actual decoding function.
void Decode(const Instruction* instr);
@@ -392,6 +403,13 @@ class Decoder {
// Map of node names to DecodeNodes.
std::map<std::string, DecodeNode> decode_nodes_;
// Map from instruction form strings to a mask/value of encodings for that
// form.
using FormToUnallocMap = std::unordered_multimap<uint32_t, uint64_t>;
FormToUnallocMap form_to_unalloc_;
static void PopulatePerInstructionUnallocatedMap(FormToUnallocMap* ftm);
};
typedef void (Decoder::*DecodeFnPtr)(const Instruction*);
@@ -471,7 +489,7 @@ class CompiledDecodeNode {
bool IsLeafNode() const {
VIXL_ASSERT(((instruction_name_ == "node") && (bit_extract_fn_ != NULL)) ||
((instruction_name_ != "node") && (bit_extract_fn_ == NULL)));
return instruction_name_ != "node";
return bit_extract_fn_ == NULL;
}
// Get a pointer to the next node required in the decode process, based on the
@@ -1923,8 +1923,24 @@ static const DecodeMapping kDecodeMapping[] = {
},
{ "_kjsrkm",
{18, 17, 16, 13, 12, 11, 10, 9, 8, 7, 4, 3, 2, 1, 0},
{ {"000000000011111"_b, "_zztypv"},
{11, 10, 9, 8},
{ {"0000"_b, "_flags"},
{"xxx1"_b, "_msrimm"},
{"xx1x"_b, "_msrimm"},
{"x1xx"_b, "_msrimm"},
{"1xxx"_b, "_msrimm"},
},
},
{ "_msrimm",
{13, 12, 4, 3, 2, 1, 0},
{ {"0011111"_b, "msr_si_pstate"},
},
},
{ "_flags",
{18, 17, 16, 13, 12, 7, 4, 3, 2, 1, 0},
{ {"00000011111"_b, "_zztypv"},
},
},
File diff suppressed because it is too large Load Diff
+18 -127
View File
@@ -117,11 +117,17 @@ class Disassembler : public DecoderVisitor {
VISITOR_LIST(DECLARE)
#undef DECLARE
std::string GetMnemonicAlias(const Instruction* instr);
using FormToVisitorFnMap = std::unordered_map<
uint32_t,
std::function<void(Disassembler*, const Instruction*)>>;
static const FormToVisitorFnMap* GetFormToVisitorFnMap();
using FormToStringMap = std::unordered_map<uint32_t, const char*>;
static void PopulateFormToStringMap(FormToStringMap* fts);
FormToStringMap form_to_string_;
std::string mnemonic_;
uint32_t form_hash_;
@@ -132,119 +138,6 @@ class Disassembler : public DecoderVisitor {
}
}
void Disassemble_PdT_PgZ_ZnT_ZmT(const Instruction* instr);
void Disassemble_ZdB_Zn1B_Zn2B_imm(const Instruction* instr);
void Disassemble_ZdB_ZnB_ZmB(const Instruction* instr);
void Disassemble_ZdD_PgM_ZnS(const Instruction* instr);
void Disassemble_ZdD_ZnD_ZmD(const Instruction* instr);
void Disassemble_ZdD_ZnD_ZmD_imm(const Instruction* instr);
void Disassemble_ZdD_ZnS_ZmS_imm(const Instruction* instr);
void Disassemble_ZdH_PgM_ZnS(const Instruction* instr);
void Disassemble_ZdH_ZnH_ZmH_imm(const Instruction* instr);
void Disassemble_ZdS_PgM_ZnD(const Instruction* instr);
void Disassemble_ZdS_PgM_ZnH(const Instruction* instr);
void Disassemble_ZdS_PgM_ZnS(const Instruction* instr);
void Disassemble_ZdS_ZnH_ZmH_imm(const Instruction* instr);
void Disassemble_ZdS_ZnS_ZmS(const Instruction* instr);
void Disassemble_ZdS_ZnS_ZmS_imm(const Instruction* instr);
void Disassemble_ZdT_PgM_ZnT(const Instruction* instr);
void Disassemble_ZdT_PgZ_ZnT_ZmT(const Instruction* instr);
void Disassemble_ZdT_Pg_Zn1T_Zn2T(const Instruction* instr);
void Disassemble_ZdT_Zn1T_Zn2T_ZmT(const Instruction* instr);
void Disassemble_ZdT_ZnT_ZmT(const Instruction* instr);
void Disassemble_ZdT_ZnT_ZmTb(const Instruction* instr);
void Disassemble_ZdT_ZnTb(const Instruction* instr);
void Disassemble_ZdT_ZnTb_ZmTb(const Instruction* instr);
void Disassemble_ZdaD_ZnD_ZmD_imm(const Instruction* instr);
void Disassemble_ZdaD_ZnH_ZmH_imm_const(const Instruction* instr);
void Disassemble_ZdaD_ZnS_ZmS_imm(const Instruction* instr);
void Disassemble_ZdaH_ZnH_ZmH_imm(const Instruction* instr);
void Disassemble_ZdaH_ZnH_ZmH_imm_const(const Instruction* instr);
void Disassemble_ZdaS_ZnB_ZmB_imm_const(const Instruction* instr);
void Disassemble_ZdaS_ZnH_ZmH(const Instruction* instr);
void Disassemble_ZdaS_ZnH_ZmH_imm(const Instruction* instr);
void Disassemble_ZdaS_ZnS_ZmS_imm(const Instruction* instr);
void Disassemble_ZdaS_ZnS_ZmS_imm_const(const Instruction* instr);
void Disassemble_ZdaT_PgM_ZnTb(const Instruction* instr);
void Disassemble_ZdaT_ZnT_ZmT(const Instruction* instr);
void Disassemble_ZdaT_ZnT_ZmT_const(const Instruction* instr);
void Disassemble_ZdaT_ZnT_const(const Instruction* instr);
void Disassemble_ZdaT_ZnTb_ZmTb(const Instruction* instr);
void Disassemble_ZdaT_ZnTb_ZmTb_const(const Instruction* instr);
void Disassemble_ZdnB_ZdnB(const Instruction* instr);
void Disassemble_ZdnB_ZdnB_ZmB(const Instruction* instr);
void Disassemble_ZdnS_ZdnS_ZmS(const Instruction* instr);
void Disassemble_ZdnT_PgM_ZdnT_ZmT(const Instruction* instr);
void Disassemble_ZdnT_PgM_ZdnT_const(const Instruction* instr);
void Disassemble_ZdnT_ZdnT_ZmT_const(const Instruction* instr);
void Disassemble_ZtD_PgZ_ZnD_Xm(const Instruction* instr);
void Disassemble_ZtD_Pg_ZnD_Xm(const Instruction* instr);
void Disassemble_ZtS_PgZ_ZnS_Xm(const Instruction* instr);
void Disassemble_ZtS_Pg_ZnS_Xm(const Instruction* instr);
void Disassemble_ZdaS_ZnB_ZmB(const Instruction* instr);
void Disassemble_Vd4S_Vn16B_Vm16B(const Instruction* instr);
void DisassembleCpy(const Instruction* instr);
void DisassembleSet(const Instruction* instr);
void DisassembleMinMaxImm(const Instruction* instr);
void DisassembleSVEShiftLeftImm(const Instruction* instr);
void DisassembleSVEShiftRightImm(const Instruction* instr);
void DisassembleSVEAddSubCarry(const Instruction* instr);
void DisassembleSVEAddSubHigh(const Instruction* instr);
void DisassembleSVEComplexIntAddition(const Instruction* instr);
void DisassembleSVEBitwiseTernary(const Instruction* instr);
void DisassembleSVEFlogb(const Instruction* instr);
void DisassembleSVEFPPair(const Instruction* instr);
void DisassembleNoArgs(const Instruction* instr);
void DisassembleNEONMulByElementLong(const Instruction* instr);
void DisassembleNEONDotProdByElement(const Instruction* instr);
void DisassembleNEONFPMulByElement(const Instruction* instr);
void DisassembleNEONHalfFPMulByElement(const Instruction* instr);
void DisassembleNEONFPMulByElementLong(const Instruction* instr);
void DisassembleNEONComplexMulByElement(const Instruction* instr);
void DisassembleNEON2RegLogical(const Instruction* instr);
void DisassembleNEON2RegExtract(const Instruction* instr);
void DisassembleNEON2RegAddlp(const Instruction* instr);
void DisassembleNEON2RegCompare(const Instruction* instr);
void DisassembleNEON2RegFPCompare(const Instruction* instr);
void DisassembleNEON2RegFPConvert(const Instruction* instr);
void DisassembleNEON2RegFP(const Instruction* instr);
void DisassembleNEON3SameLogical(const Instruction* instr);
void DisassembleNEON3SameFHM(const Instruction* instr);
void DisassembleNEON3SameNoD(const Instruction* instr);
void DisassembleNEONShiftLeftLongImm(const Instruction* instr);
void DisassembleNEONShiftRightImm(const Instruction* instr);
void DisassembleNEONShiftRightNarrowImm(const Instruction* instr);
void DisassembleNEONScalarSatMulLongIndex(const Instruction* instr);
void DisassembleNEONFPScalarMulIndex(const Instruction* instr);
void DisassembleNEONFPScalar3Same(const Instruction* instr);
void DisassembleNEONScalar3SameOnlyD(const Instruction* instr);
void DisassembleNEONFPAcrossLanes(const Instruction* instr);
void DisassembleNEONFP16AcrossLanes(const Instruction* instr);
void DisassembleNEONScalarShiftImmOnlyD(const Instruction* instr);
void DisassembleNEONScalarShiftRightNarrowImm(const Instruction* instr);
void DisassembleNEONScalar2RegMiscOnlyD(const Instruction* instr);
void DisassembleNEONFPScalar2RegMisc(const Instruction* instr);
void DisassembleNEONPolynomialMul(const Instruction* instr);
void DisassembleNEON4Same(const Instruction* instr);
void DisassembleNEONXar(const Instruction* instr);
void DisassembleNEONRax1(const Instruction* instr);
void DisassembleSHA512(const Instruction* instr);
void DisassembleMTELoadTag(const Instruction* instr);
void DisassembleMTEStoreTag(const Instruction* instr);
void DisassembleMTEStoreTagPair(const Instruction* instr);
void Disassemble_XdSP_XnSP_Xm(const Instruction* instr);
void Disassemble_XdSP_XnSP_uimm6_uimm4(const Instruction* instr);
void Disassemble_Xd_XnSP_Xm(const Instruction* instr);
void Disassemble_Xd_XnSP_XmSP(const Instruction* instr);
void VisitCryptoSM3(const Instruction* instr);
void Format(const Instruction* instr,
const char* mnemonic,
const char* format0,
@@ -253,42 +146,39 @@ class Disassembler : public DecoderVisitor {
const char* format0,
const char* format1 = NULL);
void Substitute(const Instruction* instr, const char* string);
int Substitute(const Instruction* instr, const char* string);
int SubstituteField(const Instruction* instr, const char* format);
int SubstituteRegisterField(const Instruction* instr, const char* format);
int SubstitutePredicateRegisterField(const Instruction* instr,
const char* format);
int SubstituteImmediateField(const Instruction* instr, const char* format);
int SubstituteLiteralField(const Instruction* instr, const char* format);
int SubstituteBitfieldImmediateField(const Instruction* instr,
const char* format);
int SubstituteShiftField(const Instruction* instr, const char* format);
int SubstituteExtendField(const Instruction* instr, const char* format);
int SubstituteConditionField(const Instruction* instr, const char* format);
int SubstitutePCRelAddressField(const Instruction* instr, const char* format);
int SubstituteBranchTargetField(const Instruction* instr, const char* format);
int SubstituteLSRegOffsetField(const Instruction* instr, const char* format);
int SubstitutePrefetchField(const Instruction* instr, const char* format);
int SubstituteBarrierField(const Instruction* instr, const char* format);
int SubstituteSysOpField(const Instruction* instr, const char* format);
int SubstituteCrField(const Instruction* instr, const char* format);
int SubstituteIntField(const Instruction* instr, const char* format);
int SubstituteSVESize(const Instruction* instr, const char* format);
int SubstituteFPField(const Instruction* instr, const char* format);
int SubstituteTernary(const Instruction* instr, const char* format);
int SubstituteConditionalBlock(const Instruction* instr, const char* format);
int SubstituteGenericArray(const Instruction* instr, const char* format);
int SubstituteGenericHash(const Instruction* instr, const char* format);
int SubstituteExpression(const Instruction* instr, const char* format);
int SubstituteEnd(const Instruction* instr, const char* format);
std::pair<unsigned, unsigned> GetRegNumForField(const Instruction* instr,
char reg_prefix,
const char* field);
bool RdIsZROrSP(const Instruction* instr) const {
public:
static bool RdIsZROrSP(const Instruction* instr) {
return (instr->GetRd() == kZeroRegCode);
}
bool RnIsZROrSP(const Instruction* instr) const {
static bool RnIsZROrSP(const Instruction* instr) {
return (instr->GetRn() == kZeroRegCode);
}
bool RmIsZROrSP(const Instruction* instr) const {
static bool RmIsZROrSP(const Instruction* instr) {
return (instr->GetRm() == kZeroRegCode);
}
@@ -298,6 +188,7 @@ class Disassembler : public DecoderVisitor {
bool IsMovzMovnImm(unsigned reg_size, uint64_t value);
private:
int64_t code_address_offset() const { return code_address_offset_; }
protected:
+12 -5
View File
@@ -373,6 +373,7 @@ class Instruction {
std::pair<int, int> GetSVEPermuteIndexAndLaneSizeLog2() const;
std::pair<int, int> GetNEONMulRmAndIndex() const;
std::pair<int, int> GetSVEMulZmAndIndex() const;
std::pair<int, int> GetSVEMulLongZmAndIndex() const;
@@ -855,11 +856,13 @@ class NEONFormatDecoder {
// Set the format mapping for all or individual substitutions.
void SetFormatMaps(const NEONFormatMap* format0,
const NEONFormatMap* format1 = NULL,
const NEONFormatMap* format2 = NULL) {
const NEONFormatMap* format2 = NULL,
const NEONFormatMap* format3 = NULL) {
VIXL_ASSERT(format0 != NULL);
formats_[0] = format0;
formats_[1] = (format1 == NULL) ? formats_[0] : format1;
formats_[2] = (format2 == NULL) ? formats_[1] : format2;
formats_[3] = (format3 == NULL) ? formats_[2] : format3;
}
void SetFormatMap(unsigned index, const NEONFormatMap* format) {
VIXL_ASSERT(index <= ArrayLength(formats_));
@@ -878,12 +881,15 @@ class NEONFormatDecoder {
const char* Substitute(const char* string,
SubstitutionMode mode0 = kFormat,
SubstitutionMode mode1 = kFormat,
SubstitutionMode mode2 = kFormat) {
SubstitutionMode mode2 = kFormat,
SubstitutionMode mode3 = kFormat) {
const char* subst0 = GetSubstitute(0, mode0);
const char* subst1 = GetSubstitute(1, mode1);
const char* subst2 = GetSubstitute(2, mode2);
const char* subst3 = GetSubstitute(3, mode3);
if ((subst0 == NULL) || (subst1 == NULL) || (subst2 == NULL)) {
if ((subst0 == NULL) || (subst1 == NULL) || (subst2 == NULL) ||
(subst3 == NULL)) {
return NULL;
}
@@ -892,7 +898,8 @@ class NEONFormatDecoder {
string,
subst0,
subst1,
subst2);
subst2,
subst3);
return form_buffer_;
}
@@ -1130,7 +1137,7 @@ class NEONFormatDecoder {
}
Instr instrbits_;
const NEONFormatMap* formats_[3];
const NEONFormatMap* formats_[4];
char form_buffer_[64];
char mne_buffer_[16];
};
@@ -1099,11 +1099,24 @@ class MacroAssembler : public Assembler, public MacroAssemblerInterface {
}
}
void B(Label* label);
void B(Label* label, BranchType type, Register reg = NoReg, int bit = -1);
void B(Label* label);
void B(Label* label, Condition cond);
void B(Label* label, Condition cond) {
Bcommon(label, cond, /* use_bc = */ false);
}
void Bc(Label* label, Condition cond) {
Bcommon(label, cond, /* use_bc = */ true);
}
// Aliases that match the instruction set ordering.
void B(Condition cond, Label* label) { B(label, cond); }
void Bc(Condition cond, Label* label) { Bc(label, cond); }
private:
// Common method for B and Bc.
void Bcommon(Label* label, Condition cond, bool use_bc);
public:
void Bfm(const Register& rd,
const Register& rn,
unsigned immr,
@@ -1190,6 +1203,31 @@ class MacroAssembler : public Assembler, public MacroAssemblerInterface {
SingleEmissionCheckScope guard(this);
retab();
}
void Bfcvt(const VRegister& vd, const VRegister& vn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
bfcvt(vd, vn);
}
void Bfcvtn(const VRegister& vd, const VRegister& vn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
bfcvtn(vd, vn);
}
void Bfcvtn2(const VRegister& vd, const VRegister& vn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
bfcvtn2(vd, vn);
}
void Bfcvt(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
bfcvt(zd, pg, zn);
}
void Bfcvtnt(const ZRegister& zd, const PRegisterM& pg, const ZRegister& zn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
bfcvtnt(zd, pg, zn);
}
void Braa(const Register& xn, const Register& xm) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
@@ -2814,6 +2852,7 @@ class MacroAssembler : public Assembler, public MacroAssemblerInterface {
V(shsub, Shsub) \
V(sm3partw1, Sm3partw1) \
V(sm3partw2, Sm3partw2) \
V(sm4ekey, Sm4ekey) \
V(smax, Smax) \
V(smaxp, Smaxp) \
V(smin, Smin) \
@@ -2964,6 +3003,7 @@ class MacroAssembler : public Assembler, public MacroAssemblerInterface {
V(sha1su1, Sha1su1) \
V(sha256su0, Sha256su0) \
V(sha512su0, Sha512su0) \
V(sm4e, Sm4e) \
V(smaxv, Smaxv) \
V(sminv, Sminv) \
V(sqabs, Sqabs) \
@@ -7878,6 +7918,12 @@ class MacroAssembler : public Assembler, public MacroAssemblerInterface {
void Umax(const Register& rd, const Register& rn, const Operand& op);
void Umin(const Register& rd, const Register& rn, const Operand& op);
void Yield() {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
yield();
}
template <typename T>
Literal<T>* CreateLiteralDestroyedWithPool(T value) {
return new Literal<T>(value,
@@ -8249,9 +8295,10 @@ class MacroAssembler : public Assembler, public MacroAssemblerInterface {
UseScratchRegisterScope* scratch_scope);
bool LabelIsOutOfRange(Label* label, ImmBranchType branch_type) {
int64_t offset = label->GetLocation() - GetCursorOffset();
VIXL_ASSERT(IsMultiple(offset, kInstructionSize));
return !Instruction::IsValidImmPCOffset(branch_type,
label->GetLocation() -
GetCursorOffset());
offset / kInstructionSize);
}
void ConfigureSimulatorCPUFeaturesHelper(const CPUFeatures& features,
+133 -51
View File
@@ -643,7 +643,7 @@ class SimVRegister : public SimRegisterBase<kZRegMaxSize> {
class LogicPRegister {
public:
inline LogicPRegister(
SimPRegister& other) // NOLINT(runtime/references)(runtime/explicit)
SimPRegister& other) // NOLINT(google-runtime-references)
: register_(other) {}
// Set a conveniently-sized block to 16 bits as the minimum predicate length
@@ -744,7 +744,7 @@ using vixl_uint128_t = std::pair<uint64_t, uint64_t>;
class LogicVRegister {
public:
inline LogicVRegister(
SimVRegister& other) // NOLINT(runtime/references)(runtime/explicit)
SimVRegister& other) // NOLINT(google-runtime-references)
: register_(other) {
for (size_t i = 0; i < ArrayLength(saturated_); i++) {
saturated_[i] = kNotSaturated;
@@ -872,10 +872,9 @@ class LogicVRegister {
SetUint(vform, index, value.second);
return;
}
// TODO: Extend this to SVE.
VIXL_ASSERT((vform == kFormat1Q) && (index == 0));
SetUint(kFormat2D, 0, value.second);
SetUint(kFormat2D, 1, value.first);
VIXL_ASSERT((vform == kFormat1Q) || (vform == kFormatVnQ));
SetUint(kFormatVnD, 2 * index, value.second);
SetUint(kFormatVnD, 2 * index + 1, value.first);
}
void SetUintArray(VectorFormat vform, const uint64_t* src) const {
@@ -1447,6 +1446,7 @@ class Simulator : public DecoderVisitor {
#define DECLARE(A) virtual void Visit##A(const Instruction* instr);
VISITOR_LIST_THAT_RETURN(DECLARE)
SIM_AUD_VISITOR_LIST_THAT_RETURN(DECLARE)
#undef DECLARE
#define DECLARE(A) \
VIXL_NO_RETURN virtual void Visit##A(const Instruction* instr);
@@ -1504,6 +1504,7 @@ class Simulator : public DecoderVisitor {
void SimulateSVESaturatingMulAddHigh(const Instruction* instr);
void SimulateSVESaturatingMulHighIndex(const Instruction* instr);
void SimulateSVEFPConvertLong(const Instruction* instr);
void SimulateSVEPmull128(const Instruction* instr);
void SimulateMatrixMul(const Instruction* instr);
void SimulateSVEFPMatrixMul(const Instruction* instr);
void SimulateNEONMulByElementLong(const Instruction* instr);
@@ -1532,8 +1533,16 @@ class Simulator : public DecoderVisitor {
void SimulateSignedMinMax(const Instruction* instr);
void SimulateUnsignedMinMax(const Instruction* instr);
void SimulateSHA512(const Instruction* instr);
void SimulateFPConvert(const Instruction* instr);
void SimulateFPRoundInt(const Instruction* instr);
void SimulateFPRoundIntToSize(const Instruction* instr);
void SimulateNEONRoundInt(const Instruction* instr);
void SimulateNEONRoundIntToSize(const Instruction* instr);
void SimulateNEONFPConvert(const Instruction* instr);
void SimulateNEONFP2RegMisc(const Instruction* instr);
void VisitCryptoSM3(const Instruction* instr);
void VisitCryptoSM4(const Instruction* instr);
// Integer register accessors.
@@ -2574,6 +2583,14 @@ class Simulator : public DecoderVisitor {
void PrintPWrite(int rt_code, uintptr_t address) {
PrintPAccess(rt_code, "->", address);
}
void PrintWriteU64(uint64_t x, uintptr_t address) {
fprintf(stream_,
"# 0x%016" PRIx64 " -> %s0x%016" PRIxPTR "%s\n",
x,
clr_memory_address,
address,
clr_normal);
}
// Like Print* (above), but respect GetTraceParameters().
void LogRead(int rt_code, PrintRegisterFormat format, uintptr_t address) {
@@ -2608,6 +2625,9 @@ class Simulator : public DecoderVisitor {
void LogPWrite(int rt_code, uintptr_t address) {
if (ShouldTraceWrites()) PrintPWrite(rt_code, address);
}
void LogWriteU64(uint64_t x, uintptr_t address) {
if (ShouldTraceWrites()) PrintWriteU64(x, address);
}
void LogMemTransfer(uintptr_t dst, uintptr_t src, uint8_t value) {
if (ShouldTraceWrites()) PrintMemTransfer(dst, src, value);
}
@@ -4587,6 +4607,11 @@ class Simulator : public DecoderVisitor {
int index,
bool is_a);
LogicVRegister sm4(LogicVRegister dst,
const LogicVRegister& src1,
const LogicVRegister& src2,
bool is_key);
#define NEON_3VREG_LOGIC_LIST(V) \
V(addhn) \
V(addhn2) \
@@ -4883,6 +4908,12 @@ class Simulator : public DecoderVisitor {
LogicVRegister fcvtxn2(VectorFormat vform,
LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister bfcvtn(VectorFormat vform,
LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister bfcvtn2(VectorFormat vform,
LogicVRegister dst,
const LogicVRegister& src);
LogicVRegister fsqrt(VectorFormat vform,
LogicVRegister dst,
const LogicVRegister& src);
@@ -5000,7 +5031,7 @@ class Simulator : public DecoderVisitor {
uint32_t Crc32Checksum(uint32_t acc, T val, uint32_t poly);
uint32_t Crc32Checksum(uint32_t acc, uint64_t val, uint32_t poly);
void SysOp_W(int op, int64_t val);
bool SysOp_W(int op, int64_t val);
template <typename T>
T FPRecipSqrtEstimate(T op);
@@ -5343,7 +5374,7 @@ class Simulator : public DecoderVisitor {
std::function<void(Simulator*, const Instruction*)>>;
static const FormToVisitorFnMap* GetFormToVisitorFnMap();
uint32_t form_hash_;
uint32_t form_hash_{};
static const PACKey kPACKeyIA;
static const PACKey kPACKeyIB;
@@ -5421,9 +5452,10 @@ class Simulator : public DecoderVisitor {
// in vreg is non-zero. Clear the flag, otherwise. This is almost the opposite
// operation to ExpandToSimVRegister(), except that any non-zero lane is
// interpreted as true.
void ExtractFromSimVRegister(VectorFormat vform,
SimPRegister& pd, // NOLINT(runtime/references)
SimVRegister vreg);
void ExtractFromSimVRegister(
VectorFormat vform,
SimPRegister& pd, // NOLINT(google-runtime-references)
SimVRegister vreg);
bool coloured_trace_;
@@ -5450,6 +5482,9 @@ class Simulator : public DecoderVisitor {
// A configurable size of SVE vector registers.
unsigned vector_length_;
// DC ZVA enable (= 0) status and block size.
unsigned dczid_ = (0 << 4) | 4; // 2^4 words => 64-byte block size.
// Representation of memory attributes such as MTE tagging and BTI page
// protection in addition to branch interceptions.
MetaDataDepot meta_data_;
@@ -5462,19 +5497,54 @@ class Simulator : public DecoderVisitor {
// The Guarded Control Stack is represented using a vector, where the more
// recently stored addresses are at higher-numbered indices.
using GuardedControlStack = std::vector<uint64_t>;
using GuardedControlStackStorage = std::vector<uint64_t>;
public:
struct GuardedControlStack {
GuardedControlStackStorage* ptr;
uint64_t token;
};
private:
// The GCSManager handles the synchronisation of GCS across multiple
// Simulator instances. Each Simulator has its own stack, but all share
// a GCSManager instance. This allows exchanging stacks between Simulators
// in a threaded application.
class GCSManager {
public:
// Allocate a new Guarded Control Stack and add it to the vector of stacks.
// Interface for users outside the Simulator.
// Allocate a new Guarded Control Stack. This method returns a token, which
// uniquely identifies the GCS, and can be passed *once* to the stack
// switching instructions (GSSS*), when the stack has not been used yet.
// Later arguments to the stack switching instructions must either be
// fresh tokens, or return values from the stack switching instructions.
uint64_t AllocateStack() {
GuardedControlStack gcs = AllocateStackInternal();
return gcs.token;
}
// Free a Guarded Control Stack based on its token.
void FreeStack(uint64_t token) {
const std::lock_guard<std::mutex> lock(stacks_mtx_);
uint64_t gcs_index = GetGCSIndexFromToken(token);
GuardedControlStackStorage* gcsptr = stacks_[gcs_index];
if (gcsptr == nullptr) {
VIXL_ABORT_WITH_MSG("Tried to double free GCS ");
} else {
delete gcsptr;
// To ensure other tokens remain valid, we do not remove this element
// but set it to nullptr instead.
stacks_[gcs_index] = nullptr;
}
}
private:
// Allocate a new Guarded Control Stack and add it to the vector of stacks.
GuardedControlStack AllocateStackInternal() {
const std::lock_guard<std::mutex> lock(stacks_mtx_);
GuardedControlStack* new_stack = new GuardedControlStack;
GuardedControlStackStorage* new_stack = new GuardedControlStackStorage;
uint64_t result;
// Put the new stack into the first available slot.
@@ -5490,42 +5560,46 @@ class Simulator : public DecoderVisitor {
stacks_.push_back(new_stack);
}
// Shift the index to look like a stack pointer aligned to a page.
result <<= kPageSizeLog2;
result = GetGCSTokenFromIndex(result);
// Push the tagged index onto the new stack as a seal.
new_stack->push_back(result + 1);
return result;
return {new_stack, result};
}
// Free a Guarded Control Stack and set the stacks_ slot to null.
void FreeStack(uint64_t gcs) {
// Get a pointer to the GCS storage using a GCS index.
GuardedControlStackStorage* GetGCSPtr(uint64_t gcs_index) {
const std::lock_guard<std::mutex> lock(stacks_mtx_);
uint64_t gcs_index = GetGCSIndex(gcs);
GuardedControlStack* gcsptr = stacks_[gcs_index];
if (gcsptr == nullptr) {
VIXL_ABORT_WITH_MSG("Tried to free unallocated GCS ");
} else {
delete gcsptr;
stacks_[gcs_index] = nullptr;
}
return stacks_.at(GetGCSIndexFromToken(gcs_index));
}
// Get a pointer to the GCS vector using a GCS id.
GuardedControlStack* GetGCSPtr(uint64_t gcs) const {
return stacks_[GetGCSIndex(gcs)];
// Get an index into stacks_ given a GCS token.
static uint64_t GetGCSIndexFromToken(uint64_t token) {
return token >> kPageSizeLog2;
}
private:
uint64_t GetGCSIndex(uint64_t gcs) const { return gcs >> 12; }
// Get a GCS token from an index into stacks_.
static uint64_t GetGCSTokenFromIndex(uint64_t index) {
// Shift the index to look like a stack pointer aligned to a page.
return index << kPageSizeLog2;
}
std::vector<GuardedControlStack*> stacks_;
std::vector<GuardedControlStackStorage*> stacks_;
std::mutex stacks_mtx_;
friend class Simulator;
};
GuardedControlStackStorage* GetGCSStorage() { return gcs_.ptr; }
uint64_t GetGCSToken() { return gcs_.token; }
// A GCS id indicating no GCS has been allocated.
static const uint64_t kGCSNoStack = kPageSize - 1;
uint64_t gcs_;
// We cache both the GCS token, and the pointer to the GCS underlying
// storage, which allows us to avoid calls into GCSManager that
// would require synchronisation.
GuardedControlStack gcs_;
bool gcs_enabled_;
public:
@@ -5539,37 +5613,45 @@ class Simulator : public DecoderVisitor {
bool IsGCSCheckEnabled() const { return gcs_enabled_; }
private:
bool IsAllocatedGCS(uint64_t gcs) const { return gcs != kGCSNoStack; }
void ResetGCSState() {
GCSManager& m = GetGCSManager();
if (IsAllocatedGCS(gcs_)) {
m.FreeStack(gcs_);
// This method is also called in the constructor, before we have set up the
// GCS, so the call to FreeStack must be conditional.
if (GetGCSStorage() != nullptr) {
m.FreeStack(GetGCSToken());
}
ActivateGCS(m.AllocateStack());
ActivateGCS(m.AllocateStackInternal());
GCSPop(); // Remove seal.
}
GuardedControlStack* GetGCSPtr(uint64_t gcs) {
GuardedControlStackStorage* GetGCSPtr(uint64_t gcs) {
GCSManager& m = GetGCSManager();
GuardedControlStack* result = m.GetGCSPtr(gcs);
GuardedControlStackStorage* result = m.GetGCSPtr(gcs);
return result;
}
GuardedControlStack* GetActiveGCSPtr() { return GetGCSPtr(gcs_); }
uint64_t ActivateGCS(uint64_t gcs) {
uint64_t outgoing_gcs = gcs_;
gcs_ = gcs;
return outgoing_gcs;
GuardedControlStack ActivateGCS(GuardedControlStack incoming) {
GuardedControlStack outgoing = gcs_;
gcs_ = incoming;
return outgoing;
}
GuardedControlStack ActivateGCS(uint64_t token) {
GuardedControlStack incoming = {GetGCSPtr(token), token};
GuardedControlStack outgoing = gcs_;
gcs_ = incoming;
return outgoing;
}
void GCSPush(uint64_t addr) {
GetActiveGCSPtr()->push_back(addr);
size_t entry = GetActiveGCSPtr()->size() - 1;
GuardedControlStackStorage* gcs = GetGCSStorage();
gcs->push_back(addr);
size_t entry = gcs->size() - 1;
LogGCS(/* is_push = */ true, addr, entry);
}
uint64_t GCSPop() {
GuardedControlStack* gcs = GetActiveGCSPtr();
GuardedControlStackStorage* gcs = GetGCSStorage();
if (gcs->empty()) {
return 0;
}
@@ -5581,7 +5663,7 @@ class Simulator : public DecoderVisitor {
}
uint64_t GCSPeek() {
GuardedControlStack* gcs = GetActiveGCSPtr();
GuardedControlStackStorage* gcs = GetGCSStorage();
if (gcs->empty()) {
return 0;
}
@@ -5590,8 +5672,8 @@ class Simulator : public DecoderVisitor {
}
void ReportGCSFailure(const char* msg) {
GuardedControlStackStorage* gcs = GetGCSStorage();
if (IsGCSCheckEnabled()) {
GuardedControlStack* gcs = GetActiveGCSPtr();
printf("%s", msg);
if (gcs == nullptr) {
printf("GCS pointer is null\n");
@@ -5604,7 +5686,7 @@ class Simulator : public DecoderVisitor {
gcs->pop_back();
int index = most_recent_index - i;
printf(" gcs%" PRIu64 "[%d]: 0x%016" PRIx64 "\n",
gcs_,
GCSManager::GetGCSIndexFromToken(GetGCSToken()),
index,
entry);
}
+2 -1
View File
@@ -202,7 +202,8 @@ namespace vixl {
V(kEBF16, "EBF16", "ebf16") \
V(kSVE_EBF16, "EBF16 (SVE)", "sveebf16") \
V(kCSSC, "CSSC", "cssc") \
V(kGCS, "GCS", "gcs")
V(kGCS, "GCS", "gcs") \
V(kHBC, "HBC", "hbc")
// clang-format on
+40 -7
View File
@@ -49,7 +49,7 @@ namespace vixl {
#ifdef __GNUC__
#define VIXL_HAS_DEPRECATED_WITH_MSG
#elif defined(__clang__)
#if __has_extension(attribute_deprecated_with_message)
#ifdef __has_extension(attribute_deprecated_with_message)
#define VIXL_HAS_DEPRECATED_WITH_MSG
#endif
#endif
@@ -258,9 +258,22 @@ class Float16 {
uint16_t rawbits_;
};
// Floating point representation.
uint16_t Float16ToRawbits(Float16 value);
Float16 RawbitsToFloat16(uint16_t bits);
class BFloat16 {
public:
explicit BFloat16(float value);
BFloat16() : rawbits_(0) {}
friend uint16_t BFloat16ToRawbits(BFloat16 value);
friend BFloat16 RawbitsToBFloat16(uint16_t bits);
protected:
uint16_t rawbits_;
};
uint16_t BFloat16ToRawbits(BFloat16 value);
BFloat16 RawbitsToBFloat16(uint16_t bits);
uint32_t FloatToRawbits(float value);
VIXL_DEPRECATED("FloatToRawbits",
@@ -274,8 +287,6 @@ VIXL_DEPRECATED("DoubleToRawbits",
return DoubleToRawbits(value);
}
Float16 RawbitsToFloat16(uint16_t bits);
float RawbitsToFloat(uint32_t bits);
VIXL_DEPRECATED("RawbitsToFloat",
inline float rawbits_to_float(uint32_t bits)) {
@@ -629,8 +640,8 @@ bool IsRepeatingPattern(T value) {
VIXL_ASSERT(IsMultiple(sizeof(value) * kBitsPerByte, BITS));
VIXL_ASSERT(IsMultiple(BITS, 2));
VIXL_STATIC_ASSERT(BITS >= 2);
#if (defined(__x86_64__) || defined(__i386)) && \
__clang_major__ >= 17 && __clang_major__ <= 19
#if (defined(__x86_64__) || defined(__i386)) && __clang_major__ >= 17 && \
__clang_major__ <= 19
// Workaround for https://github.com/llvm/llvm-project/issues/108722
unsigned hbits = BITS / 2;
T midmask = (~static_cast<T>(0) >> BITS) << hbits;
@@ -1132,6 +1143,8 @@ const unsigned kFloatMantissaBits = 23;
const unsigned kFloatExponentBits = 8;
const unsigned kFloat16MantissaBits = 10;
const unsigned kFloat16ExponentBits = 5;
const unsigned kBFloat16MantissaBits = 7;
const unsigned kBFloat16ExponentBits = kFloatExponentBits;
enum FPRounding {
// The first four values are encodable directly by FPCR<RMode>.
@@ -1388,6 +1401,16 @@ static inline float FPRoundToFloat(int64_t sign,
return RawbitsToFloat(bits);
}
// See FPRound for a description of this function.
static inline BFloat16 FPRoundToBFloat16(int64_t sign,
int64_t exponent,
uint64_t mantissa,
FPRounding round_mode) {
return RawbitsToBFloat16(
FPRound<uint16_t, kBFloat16ExponentBits, kBFloat16MantissaBits>(
sign, exponent, mantissa, round_mode));
}
float FPToFloat(Float16 value, UseDefaultNaN DN, bool* exception = NULL);
float FPToFloat(double value,
@@ -1408,6 +1431,16 @@ Float16 FPToFloat16(double value,
UseDefaultNaN DN,
bool* exception = NULL);
BFloat16 FPToBFloat16(float value,
FPRounding round_mode,
UseDefaultNaN DN,
bool* exception = NULL);
BFloat16 FPToBFloat16(double value,
FPRounding round_mode,
UseDefaultNaN DN,
bool* exception = NULL);
// Like static_cast<T>(value), but with specialisations for the Float16 type.
template <typename T, typename F>
T StaticCastFPTo(F value) {
@@ -1480,7 +1513,7 @@ constexpr uint32_t Hash(const char* str, uint32_t hash = 0) {
}
}
constexpr uint32_t operator"" _h(const char* x, size_t) { return Hash(x); }
constexpr uint32_t operator""_h(const char* x, size_t) { return Hash(x); }
} // namespace vixl
+49 -1
View File
@@ -263,6 +263,10 @@ void Assembler::b(int64_t imm19, Condition cond) {
Emit(B_cond | ImmCondBranch(imm19) | cond);
}
void Assembler::bc(int64_t imm19, Condition cond) {
VIXL_ASSERT(CPUHas(CPUFeatures::kHBC));
Emit(B_cond | ImmCondBranch(imm19) | (1 << 4) | cond);
}
void Assembler::b(Label* label) {
int64_t offset = LinkAndGetInstructionOffsetTo(label);
@@ -277,6 +281,11 @@ void Assembler::b(Label* label, Condition cond) {
b(static_cast<int>(offset), cond);
}
void Assembler::bc(Label* label, Condition cond) {
int64_t offset = LinkAndGetInstructionOffsetTo(label);
VIXL_ASSERT(Instruction::IsValidImmPCOffset(CondBranchType, offset));
bc(static_cast<int>(offset), cond);
}
void Assembler::bl(int64_t imm26) { Emit(BL | ImmUncondBranch(imm26)); }
@@ -3689,6 +3698,23 @@ void Assembler::fjcvtzs(const Register& rd, const VRegister& vn) {
Emit(FJCVTZS | Rn(vn) | Rd(rd));
}
void Assembler::bfcvt(const VRegister& vd, const VRegister& vn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kFP, CPUFeatures::kBF16));
VIXL_ASSERT(vd.Is1H() && vn.Is1S());
Emit(0x1e634000 | Rn(vn) | Rd(vd));
}
void Assembler::bfcvtn(const VRegister& vd, const VRegister& vn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, CPUFeatures::kBF16));
VIXL_ASSERT(vn.Is4S() && vd.Is4H());
Emit(0x0ea16800 | Rn(vn) | Rd(vd));
}
void Assembler::bfcvtn2(const VRegister& vd, const VRegister& vn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, CPUFeatures::kBF16));
VIXL_ASSERT(vn.Is4S() && vd.Is8H());
Emit(0x4ea16800 | Rn(vn) | Rd(vd));
}
void Assembler::NEONFPConvertToInt(const Register& rd,
const VRegister& vn,
@@ -4527,7 +4553,10 @@ void Assembler::fcmla(const VRegister& vd,
VIXL_ASSERT(vd.IsVector() && AreSameFormat(vd, vn));
VIXL_ASSERT((vm.IsH() && (vd.Is8H() || vd.Is4H())) ||
(vm.IsS() && vd.Is4S()));
if (vd.IsLaneSizeH()) VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));
if (vd.IsLaneSizeH()) {
VIXL_ASSERT(CPUHas(CPUFeatures::kNEONHalf));
VIXL_ASSERT(vd.Is8H() || (vm_index <= 1));
}
int index_num_bits = vd.Is4S() ? 1 : 2;
Emit(VFormat(vd) | Rm(vm) | NEON_FCMLA_byelement |
ImmNEONHLM(vm_index, index_num_bits) | ImmRotFcmlaSca(rot) | Rn(vn) |
@@ -6117,6 +6146,24 @@ void Assembler::sm3tt2b(const VRegister& vd, const VRegister& vn, const VRegiste
Emit(0xce408c00 | Rd(vd) | Rn(vn) | Rm(vm) | i);
}
void Assembler::sm4e(const VRegister& vd, const VRegister& vn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
VIXL_ASSERT(CPUHas(CPUFeatures::kSM4));
VIXL_ASSERT(vd.Is4S() && vn.Is4S());
Emit(0xcec08400 | Rd(vd) | Rn(vn));
}
void Assembler::sm4ekey(const VRegister& vd, const VRegister& vn, const VRegister& vm) {
VIXL_ASSERT(CPUHas(CPUFeatures::kNEON));
VIXL_ASSERT(CPUHas(CPUFeatures::kSM4));
VIXL_ASSERT(vd.Is4S() && vn.Is4S() && vm.Is4S());
Emit(0xce60c800 | Rd(vd) | Rn(vn) | Rm(vm));
}
void Assembler::yield() { hint(YIELD); }
// Note:
// For all ToImm instructions below, a difference in case
// for the same letter indicates a negated bit.
@@ -7161,6 +7208,7 @@ bool Assembler::CPUHas(SystemRegister sysreg) const {
return CPUHas(CPUFeatures::kRNG);
case FPCR:
case NZCV:
case DCZID_EL0:
break;
}
return true;
+26 -6
View File
@@ -7410,13 +7410,13 @@ void Assembler::pmullb(const ZRegister& zd,
// size<23:22> | Zm<20:16> | op<12> | U<11> | T<10> | Zn<9:5> | Zd<4:0>
VIXL_ASSERT(CPUHas(CPUFeatures::kSVE2));
VIXL_ASSERT(CPUHas(CPUFeatures::kSVEPmull128) || !zd.IsLaneSizeQ());
VIXL_ASSERT(AreSameLaneSize(zn, zm));
VIXL_ASSERT(!zd.IsLaneSizeB() && !zd.IsLaneSizeS());
VIXL_ASSERT(zd.GetLaneSizeInBytes() == zn.GetLaneSizeInBytes() * 2);
// SVEPmull128 is not supported
VIXL_ASSERT(!zd.IsLaneSizeQ());
Instr size = zd.IsLaneSizeQ() ? 0 : SVESize(zd);
Emit(0x45006800 | SVESize(zd) | Rd(zd) | Rn(zn) | Rm(zm));
Emit(0x45006800 | size | Rd(zd) | Rn(zn) | Rm(zm));
}
void Assembler::pmullt(const ZRegister& zd,
@@ -7427,13 +7427,13 @@ void Assembler::pmullt(const ZRegister& zd,
// size<23:22> | Zm<20:16> | op<12> | U<11> | T<10> | Zn<9:5> | Zd<4:0>
VIXL_ASSERT(CPUHas(CPUFeatures::kSVE2));
VIXL_ASSERT(CPUHas(CPUFeatures::kSVEPmull128) || !zd.IsLaneSizeQ());
VIXL_ASSERT(AreSameLaneSize(zn, zm));
VIXL_ASSERT(!zd.IsLaneSizeB() && !zd.IsLaneSizeS());
VIXL_ASSERT(zd.GetLaneSizeInBytes() == zn.GetLaneSizeInBytes() * 2);
// SVEPmull128 is not supported
VIXL_ASSERT(!zd.IsLaneSizeQ());
Instr size = zd.IsLaneSizeQ() ? 0 : SVESize(zd);
Emit(0x45006c00 | SVESize(zd) | Rd(zd) | Rn(zn) | Rm(zm));
Emit(0x45006c00 | size | Rd(zd) | Rn(zn) | Rm(zm));
}
void Assembler::raddhnb(const ZRegister& zd,
@@ -9895,5 +9895,25 @@ void Assembler::sudot(const ZRegister& zda,
Emit(0x44a01c00 | Rx<18, 16>(zm) | (index << 19) | Rd(zda) | Rn(zn));
}
void Assembler::bfcvt(const ZRegister& zd,
const PRegisterM& pg,
const ZRegister& zn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kSVE));
VIXL_ASSERT(CPUHas(CPUFeatures::kBF16));
VIXL_ASSERT(zd.IsLaneSizeH() && zn.IsLaneSizeS());
Emit(0x658aa000 | Rd(zd) | PgLow8(pg) | Rn(zn));
}
void Assembler::bfcvtnt(const ZRegister& zd,
const PRegisterM& pg,
const ZRegister& zn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kSVE));
VIXL_ASSERT(CPUHas(CPUFeatures::kBF16));
VIXL_ASSERT(zd.IsLaneSizeH() && zn.IsLaneSizeS());
Emit(0x648aa000 | Rd(zd) | PgLow8(pg) | Rn(zn));
}
} // namespace aarch64
} // namespace vixl
+2
View File
@@ -82,6 +82,7 @@ const IDRegister::Field AA64ISAR1::kI8MM(52);
const IDRegister::Field AA64ISAR2::kWFXT(0);
const IDRegister::Field AA64ISAR2::kRPRES(4);
const IDRegister::Field AA64ISAR2::kMOPS(16);
const IDRegister::Field AA64ISAR2::kHBC(20);
const IDRegister::Field AA64ISAR2::kCSSC(52);
const IDRegister::Field AA64MMFR0::kECV(60);
@@ -198,6 +199,7 @@ CPUFeatures AA64ISAR2::GetCPUFeatures() const {
if (Get(kWFXT) >= 2) f.Combine(CPUFeatures::kWFXT);
if (Get(kRPRES) >= 1) f.Combine(CPUFeatures::kRPRES);
if (Get(kMOPS) >= 1) f.Combine(CPUFeatures::kMOPS);
if (Get(kHBC) >= 1) f.Combine(CPUFeatures::kHBC);
if (Get(kCSSC) >= 1) f.Combine(CPUFeatures::kCSSC);
return f;
}
@@ -41,6 +41,111 @@ CPUFeaturesAuditor::GetFormToVisitorFnMap() {
static const FormToVisitorFnMap form_to_visitor = {
DEFAULT_FORM_TO_VISITOR_MAP(CPUFeaturesAuditor),
SIM_AUD_VISITOR_MAP(CPUFeaturesAuditor),
{"fcvt_dh_floatdp1"_h, &CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"fcvt_ds_floatdp1"_h, &CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"fcvt_hd_floatdp1"_h, &CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"fcvt_hs_floatdp1"_h, &CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"fcvt_sd_floatdp1"_h, &CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"fcvt_sh_floatdp1"_h, &CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"fmov_d_floatdp1"_h, &CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"fmov_h_floatdp1"_h, &CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"fmov_s_floatdp1"_h, &CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"frint32x_d_floatdp1"_h,
&CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"frint32x_s_floatdp1"_h,
&CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"frint32z_d_floatdp1"_h,
&CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"frint32z_s_floatdp1"_h,
&CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"frint64x_d_floatdp1"_h,
&CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"frint64x_s_floatdp1"_h,
&CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"frint64z_d_floatdp1"_h,
&CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"frint64z_s_floatdp1"_h,
&CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"frinta_d_floatdp1"_h,
&CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"frinta_h_floatdp1"_h,
&CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"frinta_s_floatdp1"_h,
&CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"frinti_d_floatdp1"_h,
&CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"frinti_h_floatdp1"_h,
&CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"frinti_s_floatdp1"_h,
&CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"frintm_d_floatdp1"_h,
&CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"frintm_h_floatdp1"_h,
&CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"frintm_s_floatdp1"_h,
&CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"frintn_d_floatdp1"_h,
&CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"frintn_h_floatdp1"_h,
&CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"frintn_s_floatdp1"_h,
&CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"frintp_d_floatdp1"_h,
&CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"frintp_h_floatdp1"_h,
&CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"frintp_s_floatdp1"_h,
&CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"frintx_d_floatdp1"_h,
&CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"frintx_h_floatdp1"_h,
&CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"frintx_s_floatdp1"_h,
&CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"frintz_d_floatdp1"_h,
&CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"frintz_h_floatdp1"_h,
&CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"frintz_s_floatdp1"_h,
&CPUFeaturesAuditor::VisitFPDataProcessing1Source},
{"frint32x_asimdmisc_r"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"frint32z_asimdmisc_r"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"frint64x_asimdmisc_r"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"frint64z_asimdmisc_r"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"frinta_asimdmisc_r"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"frinti_asimdmisc_r"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"frintm_asimdmisc_r"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"frintn_asimdmisc_r"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"frintp_asimdmisc_r"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"frintx_asimdmisc_r"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"frintz_asimdmisc_r"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"fcvtas_asimdmisc_r"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"fcvtau_asimdmisc_r"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"fcvtl_asimdmisc_l"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"fcvtms_asimdmisc_r"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"fcvtmu_asimdmisc_r"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"fcvtns_asimdmisc_r"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"fcvtnu_asimdmisc_r"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"fcvtn_asimdmisc_n"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"fcvtps_asimdmisc_r"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"fcvtpu_asimdmisc_r"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"fcvtxn_asimdmisc_n"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"fcvtzs_asimdmisc_r"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"fcvtzu_asimdmisc_r"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"fabs_asimdmisc_r"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"fcmeq_asimdmisc_fz"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"fcmge_asimdmisc_fz"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"fcmgt_asimdmisc_fz"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"fcmle_asimdmisc_fz"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"fcmlt_asimdmisc_fz"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"fneg_asimdmisc_r"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"frecpe_asimdmisc_r"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"frsqrte_asimdmisc_r"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"fsqrt_asimdmisc_r"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"scvtf_asimdmisc_r"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"ucvtf_asimdmisc_r"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"urecpe_asimdmisc_r"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"ursqrte_asimdmisc_r"_h, &CPUFeaturesAuditor::VisitNEON2RegMisc},
{"fcmla_asimdelem_c_h"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
{"fcmla_asimdelem_c_s"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
{"fmlal2_asimdelem_lh"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
@@ -226,6 +331,9 @@ void CPUFeaturesAuditor::VisitCompareBranch(const Instruction* instr) {
void CPUFeaturesAuditor::VisitConditionalBranch(const Instruction* instr) {
RecordInstructionFeaturesScope scope(this);
USE(instr);
if (form_hash_ == "bc_only_condbranch"_h) {
scope.Record(CPUFeatures::kHBC);
}
}
void CPUFeaturesAuditor::VisitConditionalCompareImmediate(
@@ -285,6 +393,12 @@ void CPUFeaturesAuditor::VisitCryptoSM3(const Instruction* instr) {
USE(instr);
}
void CPUFeaturesAuditor::VisitCryptoSM4(const Instruction* instr) {
RecordInstructionFeaturesScope scope(this);
scope.Record(CPUFeatures::kNEON, CPUFeatures::kSM4);
USE(instr);
}
void CPUFeaturesAuditor::VisitDataProcessing1Source(const Instruction* instr) {
RecordInstructionFeaturesScope scope(this);
switch (instr->Mask(DataProcessing1SourceMask)) {
@@ -1876,6 +1990,18 @@ void CPUFeaturesAuditor::Visit(Metadata* metadata, const Instruction* instr) {
CPUFeatures(CPUFeatures::kNEON, CPUFeatures::kSHA512)},
{"sha512su1_vvv2_cryptosha512_3"_h,
CPUFeatures(CPUFeatures::kNEON, CPUFeatures::kSHA512)},
{"pmullb_z_zz_q"_h,
CPUFeatures(CPUFeatures::kSVE2, CPUFeatures::kSVEPmull128)},
{"pmullt_z_zz_q"_h,
CPUFeatures(CPUFeatures::kSVE2, CPUFeatures::kSVEPmull128)},
{"bfcvt_bs_floatdp1"_h,
CPUFeatures(CPUFeatures::kFP, CPUFeatures::kBF16)},
{"bfcvtn_asimdmisc_4s"_h,
CPUFeatures(CPUFeatures::kNEON, CPUFeatures::kBF16)},
{"bfcvt_z_p_z_s2bf"_h,
CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kBF16)},
{"bfcvtnt_z_p_z_s2bf"_h,
CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kBF16)},
};
if (features.count(form_hash_) > 0) {
+498
View File
@@ -0,0 +1,498 @@
// Copyright 2023, VIXL authors
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of ARM Limited nor the names of its contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
#include "debugger-aarch64.h"
#include <cerrno>
#include <cmath>
#include <cstring>
#include <errno.h>
#include <limits>
namespace vixl {
namespace aarch64 {
Debugger::Debugger(Simulator* sim)
: sim_(sim), input_stream_(&std::cin), ostream_(sim->GetOutputStream()) {
// Register all basic debugger commands.
RegisterCmd<HelpCmd>();
RegisterCmd<BreakCmd>();
RegisterCmd<StepCmd>();
RegisterCmd<ContinueCmd>();
RegisterCmd<PrintCmd>();
RegisterCmd<TraceCmd>();
RegisterCmd<GdbCmd>();
}
template <class T>
void Debugger::RegisterCmd() {
auto new_command = std::make_unique<T>(sim_);
// Check that the new command word and alias, don't already exist.
std::string_view new_cmd_word = new_command->GetCommandWord();
std::string_view new_cmd_alias = new_command->GetCommandAlias();
for (const auto& cmd : debugger_cmds_) {
std::string_view cmd_word = cmd->GetCommandWord();
std::string_view cmd_alias = cmd->GetCommandAlias();
if (new_cmd_word == cmd_word) {
VIXL_ABORT_WITH_MSG("Command word matches an existing command word.");
} else if (new_cmd_word == cmd_alias) {
VIXL_ABORT_WITH_MSG("Command word matches an existing command alias.");
}
if (new_cmd_alias != "") {
if (new_cmd_alias == cmd_word) {
VIXL_ABORT_WITH_MSG("Command alias matches an existing command word.");
} else if (new_cmd_alias == cmd_alias) {
VIXL_ABORT_WITH_MSG("Command alias matches an existing command alias.");
}
}
}
debugger_cmds_.push_back(std::move(new_command));
}
bool Debugger::IsAtBreakpoint() const {
return IsBreakpoint(reinterpret_cast<uint64_t>(sim_->ReadPc()));
}
void Debugger::Debug() {
DebugReturn done = DebugContinue;
while (done == DebugContinue) {
// Disassemble the next instruction to execute.
PrintDisassembler print_disasm = PrintDisassembler(ostream_);
print_disasm.Disassemble(sim_->ReadPc());
// Read the command line.
fprintf(ostream_, "sim> ");
std::string line;
std::getline(*input_stream_, line);
// Remove all control characters from the command string.
line.erase(std::remove_if(line.begin(),
line.end(),
[](char c) { return std::iscntrl(c); }),
line.end());
// Assume input from std::cin has already been output (e.g: by a terminal)
// but input from elsewhere (e.g: from a testing input stream) has not.
if (input_stream_ != &std::cin) {
fprintf(ostream_, "%s\n", line.c_str());
}
// Parse the command into tokens.
std::vector<std::string> tokenized_cmd = Tokenize(line);
if (!tokenized_cmd.empty()) {
done = ExecDebugCommand(tokenized_cmd);
}
}
}
std::optional<uint64_t> Debugger::ParseUint64String(std::string_view uint64_str,
int base) {
// Clear any previous errors.
errno = 0;
// strtoull uses 0 to indicate that no conversion was possible so first
// check that the string isn't zero.
if (IsZeroUint64String(uint64_str, base)) {
return 0;
}
// Cannot use stoi as it might not be possible to use exceptions.
char* end;
uint64_t value = std::strtoull(uint64_str.data(), &end, base);
if (value == 0 || *end != '\0' || errno == ERANGE) {
return std::nullopt;
}
return value;
}
std::optional<Debugger::RegisterParsedFormat> Debugger::ParseRegString(
std::string_view reg_str) {
// A register should only have 2 (e.g: X0) or 3 (e.g: X31) characters.
if (reg_str.size() < 2 || reg_str.size() > 3) {
return std::nullopt;
}
// Check for aliases of registers.
if (reg_str == "lr") {
return {{'X', kLinkRegCode}};
} else if (reg_str == "sp") {
return {{'X', kSpRegCode}};
}
unsigned max_reg_num;
char reg_prefix = std::toupper(reg_str.front());
switch (reg_prefix) {
case 'W':
VIXL_FALLTHROUGH();
case 'X':
max_reg_num = kNumberOfRegisters - 1;
break;
case 'V':
max_reg_num = kNumberOfVRegisters - 1;
break;
case 'Z':
max_reg_num = kNumberOfZRegisters - 1;
break;
case 'P':
max_reg_num = kNumberOfPRegisters - 1;
break;
default:
return std::nullopt;
}
std::string_view str_code = reg_str.substr(1, reg_str.size());
auto reg_code = ParseUint64String(str_code, 10);
if (!reg_code) {
return std::nullopt;
}
if (*reg_code > max_reg_num) {
return std::nullopt;
}
return {{reg_prefix, static_cast<unsigned int>(*reg_code)}};
}
void Debugger::PrintUsage() {
for (const auto& cmd : debugger_cmds_) {
// Print commands in the following format:
// foo / f
// foo <arg>
// A description of the foo command.
//
std::string_view cmd_word = cmd->GetCommandWord();
std::string_view cmd_alias = cmd->GetCommandAlias();
if (cmd_alias != "") {
fprintf(ostream_, "%s / %s\n", cmd_word.data(), cmd_alias.data());
} else {
fprintf(ostream_, "%s\n", cmd_word.data());
}
std::string_view args_str = cmd->GetArgsString();
if (args_str != "") {
fprintf(ostream_, "\t%s %s\n", cmd_word.data(), args_str.data());
}
std::string_view description = cmd->GetDescription();
if (description != "") {
fprintf(ostream_, "\t%s\n", description.data());
}
}
}
std::vector<std::string> Debugger::Tokenize(std::string_view input_line,
char separator) {
std::vector<std::string> words;
if (input_line.empty()) {
return words;
}
for (auto separator_pos = input_line.find(separator);
separator_pos != input_line.npos;
separator_pos = input_line.find(separator)) {
// Skip consecutive, repeated separators.
if (separator_pos != 0) {
words.push_back(std::string{input_line.substr(0, separator_pos)});
}
// Remove characters up to and including the separator.
input_line.remove_prefix(separator_pos + 1);
}
// Add the rest of the string to the vector.
words.push_back(std::string{input_line});
return words;
}
DebugReturn Debugger::ExecDebugCommand(
const std::vector<std::string>& tokenized_cmd) {
std::string cmd_word = tokenized_cmd.front();
for (const auto& cmd : debugger_cmds_) {
if (cmd_word == cmd->GetCommandWord() ||
cmd_word == cmd->GetCommandAlias()) {
const std::vector<std::string> args(tokenized_cmd.begin() + 1,
tokenized_cmd.end());
// Call the handler for the command and pass the arguments.
return cmd->Action(args);
}
}
fprintf(ostream_, "Error: command '%s' not found\n", cmd_word.c_str());
return DebugContinue;
}
bool Debugger::IsZeroUint64String(std::string_view uint64_str, int base) {
// Remove any hex prefixes.
if (base == 0 || base == 16) {
std::string_view prefix = uint64_str.substr(0, 2);
if (prefix == "0x" || prefix == "0X") {
uint64_str.remove_prefix(2);
}
}
if (uint64_str.empty()) {
return false;
}
// Check all remaining digits in the string for anything other than zero.
for (char c : uint64_str) {
if (c != '0') {
return false;
}
}
return true;
}
DebuggerCmd::DebuggerCmd(Simulator* sim,
std::string cmd_word,
std::string cmd_alias,
std::string args_str,
std::string description)
: sim_(sim),
ostream_(sim->GetOutputStream()),
command_word_(cmd_word),
command_alias_(cmd_alias),
args_str_(args_str),
description_(description) {}
DebugReturn HelpCmd::Action(const std::vector<std::string>& args) {
USE(args);
sim_->GetDebugger()->PrintUsage();
return DebugContinue;
}
DebugReturn BreakCmd::Action(const std::vector<std::string>& args) {
if (args.size() != 1) {
fprintf(ostream_, "Error: Use `break <address>` to set a breakpoint\n");
return DebugContinue;
}
std::string arg = args.front();
auto break_addr = Debugger::ParseUint64String(arg);
if (!break_addr) {
fprintf(ostream_, "Error: Use `break <address>` to set a breakpoint\n");
return DebugContinue;
}
if (sim_->GetDebugger()->IsBreakpoint(*break_addr)) {
sim_->GetDebugger()->RemoveBreakpoint(*break_addr);
fprintf(ostream_,
"Breakpoint successfully removed at: 0x%" PRIx64 "\n",
*break_addr);
} else {
sim_->GetDebugger()->RegisterBreakpoint(*break_addr);
fprintf(ostream_,
"Breakpoint successfully added at: 0x%" PRIx64 "\n",
*break_addr);
}
return DebugContinue;
}
DebugReturn StepCmd::Action(const std::vector<std::string>& args) {
if (args.size() > 1) {
fprintf(ostream_,
"Error: use `step [number]` to step an optional number of"
" instructions\n");
return DebugContinue;
}
// Step 1 instruction by default.
std::optional<uint64_t> number_of_instructions_to_execute{1};
if (args.size() == 1) {
// Parse the argument to step that number of instructions.
std::string arg = args.front();
number_of_instructions_to_execute = Debugger::ParseUint64String(arg);
if (!number_of_instructions_to_execute) {
fprintf(ostream_,
"Error: use `step [number]` to step an optional number of"
" instructions\n");
return DebugContinue;
}
}
while (!sim_->IsSimulationFinished() &&
*number_of_instructions_to_execute > 0) {
sim_->ExecuteInstruction();
(*number_of_instructions_to_execute)--;
// The first instruction has already been printed by Debug() so only
// enable instruction tracing after the first instruction has been
// executed.
sim_->SetTraceParameters(sim_->GetTraceParameters() | LOG_DISASM);
}
// Disable instruction tracing after all instructions have been executed.
sim_->SetTraceParameters(sim_->GetTraceParameters() & ~LOG_DISASM);
if (sim_->IsSimulationFinished()) {
fprintf(ostream_,
"Debugger at the end of simulation, leaving simulator...\n");
return DebugExit;
}
return DebugContinue;
}
DebugReturn ContinueCmd::Action(const std::vector<std::string>& args) {
USE(args);
fprintf(ostream_, "Continuing...\n");
if (sim_->GetDebugger()->IsAtBreakpoint()) {
// This breakpoint has already been hit, so execute it before continuing.
sim_->ExecuteInstruction();
}
return DebugExit;
}
DebugReturn PrintCmd::Action(const std::vector<std::string>& args) {
if (args.size() != 1) {
fprintf(ostream_,
"Error: use `print <register|all>` to print the contents of a"
" specific register or all registers.\n");
return DebugContinue;
}
if (args.front() == "all") {
sim_->PrintRegisters();
sim_->PrintZRegisters();
} else if (args.front() == "system") {
sim_->PrintSystemRegisters();
} else if (args.front() == "ffr") {
sim_->PrintFFR();
} else {
auto reg = Debugger::ParseRegString(args.front());
if (!reg) {
fprintf(ostream_,
"Error: incorrect register format, use e.g: X0, x0, etc...\n");
return DebugContinue;
}
// Ensure the stack pointer is printed instead of the zero register.
if ((*reg).second == kSpRegCode) {
(*reg).second = kSPRegInternalCode;
}
// Registers are printed in different ways depending on their type.
switch ((*reg).first) {
case 'W':
sim_->PrintRegister(
(*reg).second,
static_cast<Simulator::PrintRegisterFormat>(
Simulator::PrintRegisterFormat::kPrintWReg |
Simulator::PrintRegisterFormat::kPrintRegPartial));
break;
case 'X':
sim_->PrintRegister((*reg).second,
Simulator::PrintRegisterFormat::kPrintXReg);
break;
case 'V':
sim_->PrintVRegister((*reg).second);
break;
case 'Z':
sim_->PrintZRegister((*reg).second);
break;
case 'P':
sim_->PrintPRegister((*reg).second);
break;
default:
// ParseRegString should only allow valid register characters.
VIXL_UNREACHABLE();
}
}
return DebugContinue;
}
DebugReturn TraceCmd::Action(const std::vector<std::string>& args) {
if (args.size() != 0) {
fprintf(ostream_, "Error: use `trace` to toggle tracing of registers.\n");
return DebugContinue;
}
int trace_params = sim_->GetTraceParameters();
if ((trace_params & LOG_ALL) != LOG_ALL) {
fprintf(ostream_,
"Enabling disassembly, registers and memory write tracing\n");
sim_->SetTraceParameters(trace_params | LOG_ALL);
} else {
fprintf(ostream_,
"Disabling disassembly, registers and memory write tracing\n");
sim_->SetTraceParameters(trace_params & ~LOG_ALL);
}
return DebugContinue;
}
DebugReturn GdbCmd::Action(const std::vector<std::string>& args) {
if (args.size() != 0) {
fprintf(ostream_,
"Error: use `gdb` to enter GDB from the simulator debugger.\n");
return DebugContinue;
}
HostBreakpoint();
return DebugContinue;
}
} // namespace aarch64
} // namespace vixl
#endif // VIXL_INCLUDE_SIMULATOR_AARCH64
+846
View File
@@ -138,11 +138,854 @@ void Decoder::VisitNamedInstruction(const Instruction* instr,
const std::string& name) {
std::list<DecoderVisitor*>::iterator it;
Metadata m = {{"form", name}};
uint32_t form_hash = Hash(name.c_str());
// If an encoding is unallocated for this form, add the information to the
// metadata.
auto range = form_to_unalloc_.equal_range(form_hash);
for (auto itu = range.first; itu != range.second; ++itu) {
uint32_t mask = itu->second >> 32;
uint32_t value = itu->second & 0xffffffff;
if (instr->Mask(mask) == value) {
m.insert({"unallocated", ""});
break;
}
}
for (it = visitors_.begin(); it != visitors_.end(); it++) {
(*it)->Visit(&m, instr);
}
}
void Decoder::PopulatePerInstructionUnallocatedMap(FormToUnallocMap* ftm) {
using UnallocToFormMap =
std::unordered_map<uint64_t, std::unordered_set<uint32_t>>;
// Map from mask/value (as uint64) to instruction form. Given an encoding,
// if, after applying the bitmask (top 32 bits), the resulting encoding equals
// bottom 32 bits, then the encoding is unallocated for the instructions
// indexed by the mask/value. On object construction, this is used to build a
// map from instruction to mask/value, allowing fast lookup during
// disassembly.
static const UnallocToFormMap forms =
{{0x00000001'00000001,
{"casp_cp32_ldstexcl"_h,
"caspa_cp32_ldstexcl"_h,
"caspl_cp32_ldstexcl"_h,
"caspal_cp32_ldstexcl"_h,
"casp_cp64_ldstexcl"_h,
"caspa_cp64_ldstexcl"_h,
"caspl_cp64_ldstexcl"_h,
"caspal_cp64_ldstexcl"_h}},
{0x0000001f'0000001f,
{"cpyen_cpy_memcms"_h, "cpyern_cpy_memcms"_h, "cpyewn_cpy_memcms"_h,
"cpye_cpy_memcms"_h, "cpyfen_cpy_memcms"_h, "cpyfern_cpy_memcms"_h,
"cpyfewn_cpy_memcms"_h, "cpyfe_cpy_memcms"_h, "cpyfmn_cpy_memcms"_h,
"cpyfmrn_cpy_memcms"_h, "cpyfmwn_cpy_memcms"_h, "cpyfm_cpy_memcms"_h,
"cpyfpn_cpy_memcms"_h, "cpyfprn_cpy_memcms"_h, "cpyfpwn_cpy_memcms"_h,
"cpyfp_cpy_memcms"_h, "cpymn_cpy_memcms"_h, "cpymrn_cpy_memcms"_h,
"cpymwn_cpy_memcms"_h, "cpym_cpy_memcms"_h, "cpypn_cpy_memcms"_h,
"cpyprn_cpy_memcms"_h, "cpypwn_cpy_memcms"_h, "cpyp_cpy_memcms"_h,
"seten_set_memcms"_h, "sete_set_memcms"_h, "setgen_set_memcms"_h,
"setge_set_memcms"_h, "setgmn_set_memcms"_h, "setgm_set_memcms"_h,
"setgpn_set_memcms"_h, "setgp_set_memcms"_h, "setmn_set_memcms"_h,
"setm_set_memcms"_h, "setpn_set_memcms"_h, "setp_set_memcms"_h}},
{0x000003e0'000003e0,
{"cpyen_cpy_memcms"_h, "cpyern_cpy_memcms"_h, "cpyewn_cpy_memcms"_h,
"cpye_cpy_memcms"_h, "cpyfen_cpy_memcms"_h, "cpyfern_cpy_memcms"_h,
"cpyfewn_cpy_memcms"_h, "cpyfe_cpy_memcms"_h, "cpyfmn_cpy_memcms"_h,
"cpyfmrn_cpy_memcms"_h, "cpyfmwn_cpy_memcms"_h, "cpyfm_cpy_memcms"_h,
"cpyfpn_cpy_memcms"_h, "cpyfprn_cpy_memcms"_h, "cpyfpwn_cpy_memcms"_h,
"cpyfp_cpy_memcms"_h, "cpymn_cpy_memcms"_h, "cpymrn_cpy_memcms"_h,
"cpymwn_cpy_memcms"_h, "cpym_cpy_memcms"_h, "cpypn_cpy_memcms"_h,
"cpyprn_cpy_memcms"_h, "cpypwn_cpy_memcms"_h, "cpyp_cpy_memcms"_h,
"seten_set_memcms"_h, "sete_set_memcms"_h, "setgen_set_memcms"_h,
"setge_set_memcms"_h, "setgmn_set_memcms"_h, "setgm_set_memcms"_h,
"setgpn_set_memcms"_h, "setgp_set_memcms"_h, "setmn_set_memcms"_h,
"setm_set_memcms"_h, "setpn_set_memcms"_h, "setp_set_memcms"_h}},
{0x00001c00'00001400,
{"add_32_addsub_ext"_h,
"add_64_addsub_ext"_h,
"subs_32s_addsub_ext"_h,
"subs_64s_addsub_ext"_h,
"sub_32_addsub_ext"_h,
"sub_64_addsub_ext"_h}},
{0x00001800'00001800,
{"add_32_addsub_ext"_h,
"add_64_addsub_ext"_h,
"subs_32s_addsub_ext"_h,
"subs_64s_addsub_ext"_h,
"sub_32_addsub_ext"_h,
"sub_64_addsub_ext"_h}},
{0x00010000'00010000,
{"casp_cp32_ldstexcl"_h,
"caspa_cp32_ldstexcl"_h,
"caspl_cp32_ldstexcl"_h,
"caspal_cp32_ldstexcl"_h,
"casp_cp64_ldstexcl"_h,
"caspa_cp64_ldstexcl"_h,
"caspl_cp64_ldstexcl"_h,
"caspal_cp64_ldstexcl"_h}},
{0x000207e0'000007c0, {"and_z_zi"_h, "eor_z_zi"_h, "orr_z_zi"_h}},
{0x000207e0'000007e0, {"and_z_zi"_h, "eor_z_zi"_h, "orr_z_zi"_h}},
{0x00030000'00000000, {"smov_asimdins_w_w"_h}},
{0x00070000'00000000, {"smov_asimdins_x_x"_h, "umov_asimdins_w_w"_h}},
{0x000f0000'00000000,
{"umov_asimdins_w_w"_h,
"umov_asimdins_x_x"_h,
"dup_asimdins_dv_v"_h,
"dup_asimdins_dr_r"_h,
"ins_asimdins_iv_v"_h,
"ins_asimdins_ir_r"_h}},
{0x001f0000'00000000, {"dup_z_zi"_h}},
{0x001f0000'001f0000,
{"prfb_i_p_br_s"_h, "prfd_i_p_br_s"_h, "prfh_i_p_br_s"_h,
"prfw_i_p_br_s"_h, "cpyen_cpy_memcms"_h, "cpyern_cpy_memcms"_h,
"cpyewn_cpy_memcms"_h, "cpye_cpy_memcms"_h, "cpyfen_cpy_memcms"_h,
"cpyfern_cpy_memcms"_h, "cpyfewn_cpy_memcms"_h, "cpyfe_cpy_memcms"_h,
"cpyfmn_cpy_memcms"_h, "cpyfmrn_cpy_memcms"_h, "cpyfmwn_cpy_memcms"_h,
"cpyfm_cpy_memcms"_h, "cpyfpn_cpy_memcms"_h, "cpyfprn_cpy_memcms"_h,
"cpyfpwn_cpy_memcms"_h, "cpyfp_cpy_memcms"_h, "cpymn_cpy_memcms"_h,
"cpymrn_cpy_memcms"_h, "cpymwn_cpy_memcms"_h, "cpym_cpy_memcms"_h,
"cpypn_cpy_memcms"_h, "cpyprn_cpy_memcms"_h, "cpypwn_cpy_memcms"_h,
"cpyp_cpy_memcms"_h}},
{0x0040f800'0000f800,
{"ands_32s_log_imm"_h,
"ands_64s_log_imm"_h,
"and_32_log_imm"_h,
"and_64_log_imm"_h,
"eor_32_log_imm"_h,
"eor_64_log_imm"_h,
"orr_32_log_imm"_h,
"orr_64_log_imm"_h}},
{0x0040fc00'00007c00,
{"ands_32s_log_imm"_h,
"ands_64s_log_imm"_h,
"and_32_log_imm"_h,
"and_64_log_imm"_h,
"eor_32_log_imm"_h,
"eor_64_log_imm"_h,
"orr_32_log_imm"_h,
"orr_64_log_imm"_h}},
{0x0040fc00'0000bc00,
{"ands_32s_log_imm"_h,
"ands_64s_log_imm"_h,
"and_32_log_imm"_h,
"and_64_log_imm"_h,
"eor_32_log_imm"_h,
"eor_64_log_imm"_h,
"orr_32_log_imm"_h,
"orr_64_log_imm"_h}},
{0x0040fc00'0000dc00,
{"ands_32s_log_imm"_h,
"ands_64s_log_imm"_h,
"and_32_log_imm"_h,
"and_64_log_imm"_h,
"eor_32_log_imm"_h,
"eor_64_log_imm"_h,
"orr_32_log_imm"_h,
"orr_64_log_imm"_h}},
{0x0040fc00'0000ec00,
{"ands_32s_log_imm"_h,
"ands_64s_log_imm"_h,
"and_32_log_imm"_h,
"and_64_log_imm"_h,
"eor_32_log_imm"_h,
"eor_64_log_imm"_h,
"orr_32_log_imm"_h,
"orr_64_log_imm"_h}},
{0x0040fc00'0000f400,
{"ands_32s_log_imm"_h,
"ands_64s_log_imm"_h,
"and_32_log_imm"_h,
"and_64_log_imm"_h,
"eor_32_log_imm"_h,
"eor_64_log_imm"_h,
"orr_32_log_imm"_h,
"orr_64_log_imm"_h}},
{0x00200000'00200000, {"fcmla_asimdelem_c_s"_h}},
{0x00400000'00000000,
{"shl_asisdshf_r"_h,
"sli_asisdshf_r"_h,
"sri_asisdshf_r"_h,
"srshr_asisdshf_r"_h,
"srsra_asisdshf_r"_h,
"sshr_asisdshf_r"_h,
"ssra_asisdshf_r"_h,
"urshr_asisdshf_r"_h,
"ursra_asisdshf_r"_h,
"ushr_asisdshf_r"_h,
"usra_asisdshf_r"_h,
"pmullb_z_zz"_h,
"pmullt_z_zz"_h,
"fcvtxn_asisdmisc_n"_h,
"fcvtxn_asimdmisc_n"_h}},
{0x00400000'00400000, {"urecpe_asimdmisc_r"_h, "ursqrte_asimdmisc_r"_h,
"cnt_asimdmisc_r"_h, "rev16_asimdmisc_r"_h,
"shrn_asimdshf_n"_h, "rshrn_asimdshf_n"_h,
"sqshrn_asimdshf_n"_h, "sqrshrn_asimdshf_n"_h,
"sqshrun_asimdshf_n"_h, "sqrshrun_asimdshf_n"_h,
"uqshrn_asimdshf_n"_h, "uqrshrn_asimdshf_n"_h,
"sshll_asimdshf_l"_h, "ushll_asimdshf_l"_h,
"sqrshrn_asisdshf_n"_h, "sqrshrun_asisdshf_n"_h,
"sqshrn_asisdshf_n"_h, "sqshrun_asisdshf_n"_h,
"uqrshrn_asisdshf_n"_h, "uqshrn_asisdshf_n"_h}},
{0x00060000'00000000, {"flogb_z_p_z"_h}},
{0x00580000'00000000,
{"rshrnb_z_zi"_h, "rshrnt_z_zi"_h, "shrnb_z_zi"_h,
"shrnt_z_zi"_h, "sqrshrnb_z_zi"_h, "sqrshrnt_z_zi"_h,
"sqrshrunb_z_zi"_h, "sqrshrunt_z_zi"_h, "sqshrnb_z_zi"_h,
"sqshrnt_z_zi"_h, "sqshrunb_z_zi"_h, "sqshrunt_z_zi"_h,
"uqrshrnb_z_zi"_h, "uqrshrnt_z_zi"_h, "uqshrnb_z_zi"_h,
"uqshrnt_z_zi"_h, "sshllb_z_zi"_h, "sshllt_z_zi"_h,
"ushllb_z_zi"_h, "ushllt_z_zi"_h, "sqxtnb_z_zz"_h,
"sqxtnt_z_zz"_h, "sqxtunb_z_zz"_h, "sqxtunt_z_zz"_h,
"uqxtnb_z_zz"_h, "uqxtnt_z_zz"_h}},
{0x00580000'00180000,
{"sqxtnb_z_zz"_h,
"sqxtnt_z_zz"_h,
"sqxtunb_z_zz"_h,
"sqxtunt_z_zz"_h,
"uqxtnb_z_zz"_h,
"uqxtnt_z_zz"_h}},
{0x00580000'00480000,
{"sqxtnb_z_zz"_h,
"sqxtnt_z_zz"_h,
"sqxtunb_z_zz"_h,
"sqxtunt_z_zz"_h,
"uqxtnb_z_zz"_h,
"uqxtnt_z_zz"_h}},
{0x00580000'00500000,
{"sqxtnb_z_zz"_h,
"sqxtnt_z_zz"_h,
"sqxtunb_z_zz"_h,
"sqxtunt_z_zz"_h,
"uqxtnb_z_zz"_h,
"uqxtnt_z_zz"_h}},
{0x00580000'00580000,
{"sqxtnb_z_zz"_h,
"sqxtnt_z_zz"_h,
"sqxtunb_z_zz"_h,
"sqxtunt_z_zz"_h,
"uqxtnb_z_zz"_h,
"uqxtnt_z_zz"_h}},
{0x00600000'00600000,
{"fmla_asimdelem_r_sd"_h,
"fmls_asimdelem_r_sd"_h,
"fmulx_asimdelem_r_sd"_h,
"fmul_asimdelem_r_sd"_h}},
{0x00700000'00000000,
{"fcvtzs_asisdshf_c"_h,
"fcvtzu_asisdshf_c"_h,
"scvtf_asisdshf_c"_h,
"ucvtf_asisdshf_c"_h}},
{0x00780000'00000000,
{"sqrshrn_asisdshf_n"_h,
"sqrshrun_asisdshf_n"_h,
"sqshrn_asisdshf_n"_h,
"sqshrun_asisdshf_n"_h,
"uqrshrn_asisdshf_n"_h,
"uqshrn_asisdshf_n"_h}},
{0x00780000'00080000,
{"scvtf_asimdshf_c"_h,
"ucvtf_asimdshf_c"_h,
"fcvtzs_asimdshf_c"_h,
"fcvtzu_asimdshf_c"_h}},
{0x00800000'00000000,
{"compact_z_p_z"_h, "sdot_z_zzz"_h, "udot_z_zzz"_h}},
{0x00800000'00800000,
{"cnt_asimdmisc_r"_h, "rev16_asimdmisc_r"_h, "rev32_asimdmisc_r"_h}},
{0x00c00000'00000000,
{"smlalb_z_zzz"_h,
"smlalt_z_zzz"_h,
"smlslb_z_zzz"_h,
"smlslt_z_zzz"_h,
"sqdmlalb_z_zzz"_h,
"sqdmlalbt_z_zzz"_h,
"sqdmlalt_z_zzz"_h,
"sqdmlslb_z_zzz"_h,
"sqdmlslbt_z_zzz"_h,
"sqdmlslt_z_zzz"_h,
"umlalb_z_zzz"_h,
"umlalt_z_zzz"_h,
"umlslb_z_zzz"_h,
"umlslt_z_zzz"_h,
"faddp_z_p_zz"_h,
"fmaxnmp_z_p_zz"_h,
"fmaxp_z_p_zz"_h,
"fminnmp_z_p_zz"_h,
"fminp_z_p_zz"_h,
"urecpe_z_p_z"_h,
"ursqrte_z_p_z"_h,
"saddwb_z_zz"_h,
"saddwt_z_zz"_h,
"ssubwb_z_zz"_h,
"ssubwt_z_zz"_h,
"uaddwb_z_zz"_h,
"uaddwt_z_zz"_h,
"usubwb_z_zz"_h,
"usubwt_z_zz"_h,
"sadalp_z_p_z"_h,
"uadalp_z_p_z"_h,
"sabalb_z_zzz"_h,
"sabalt_z_zzz"_h,
"sabdlb_z_zz"_h,
"sabdlt_z_zz"_h,
"saddlb_z_zz"_h,
"saddlbt_z_zz"_h,
"saddlt_z_zz"_h,
"smullb_z_zz"_h,
"smullt_z_zz"_h,
"sqdmullb_z_zz"_h,
"sqdmullt_z_zz"_h,
"ssublb_z_zz"_h,
"ssublbt_z_zz"_h,
"ssublt_z_zz"_h,
"ssubltb_z_zz"_h,
"uabalb_z_zzz"_h,
"uabalt_z_zzz"_h,
"uabdlb_z_zz"_h,
"uabdlt_z_zz"_h,
"uaddlb_z_zz"_h,
"uaddlt_z_zz"_h,
"umullb_z_zz"_h,
"umullt_z_zz"_h,
"usublb_z_zz"_h,
"usublt_z_zz"_h,
"addhnb_z_zz"_h,
"addhnt_z_zz"_h,
"raddhnb_z_zz"_h,
"raddhnt_z_zz"_h,
"rsubhnb_z_zz"_h,
"rsubhnt_z_zz"_h,
"subhnb_z_zz"_h,
"subhnt_z_zz"_h,
"cmeq_asisdsame_only"_h,
"cmge_asisdsame_only"_h,
"cmgt_asisdsame_only"_h,
"cmhi_asisdsame_only"_h,
"cmhs_asisdsame_only"_h,
"cmtst_asisdsame_only"_h,
"add_asisdsame_only"_h,
"sub_asisdsame_only"_h,
"addp_asisdpair_only"_h,
"frinta_z_p_z"_h,
"frinti_z_p_z"_h,
"frintm_z_p_z"_h,
"frintn_z_p_z"_h,
"frintp_z_p_z"_h,
"frintx_z_p_z"_h,
"frintz_z_p_z"_h,
"frecpx_z_p_z"_h,
"fsqrt_z_p_z"_h,
"frecpe_z_z"_h,
"frsqrte_z_z"_h,
"fmad_z_p_zzz"_h,
"fmla_z_p_zzz"_h,
"fmls_z_p_zzz"_h,
"fmsb_z_p_zzz"_h,
"fnmad_z_p_zzz"_h,
"fnmla_z_p_zzz"_h,
"fnmls_z_p_zzz"_h,
"fnmsb_z_p_zzz"_h,
"faddv_v_p_z"_h,
"fmaxnmv_v_p_z"_h,
"fmaxv_v_p_z"_h,
"fminnmv_v_p_z"_h,
"fminv_v_p_z"_h,
"fcmla_z_p_zzz"_h,
"fcadd_z_p_zz"_h,
"fcmeq_p_p_z0"_h,
"fcmge_p_p_z0"_h,
"fcmgt_p_p_z0"_h,
"fcmle_p_p_z0"_h,
"fcmlt_p_p_z0"_h,
"fcmne_p_p_z0"_h,
"facge_p_p_zz"_h,
"facgt_p_p_zz"_h,
"fcmeq_p_p_zz"_h,
"fcmge_p_p_zz"_h,
"fcmgt_p_p_zz"_h,
"fcmne_p_p_zz"_h,
"fcmuo_p_p_zz"_h,
"fadd_z_zz"_h,
"fmul_z_zz"_h,
"frecps_z_zz"_h,
"frsqrts_z_zz"_h,
"fsub_z_zz"_h,
"ftsmul_z_zz"_h,
"fadda_v_p_z"_h,
"sxtw_z_p_z"_h,
"uxtw_z_p_z"_h,
"sxth_z_p_z"_h,
"uxth_z_p_z"_h,
"sxtb_z_p_z"_h,
"uxtb_z_p_z"_h,
"fabs_z_p_z"_h,
"fneg_z_p_z"_h,
"sunpkhi_z_z"_h,
"sunpklo_z_z"_h,
"uunpkhi_z_z"_h,
"uunpklo_z_z"_h,
"revb_z_z"_h,
"revh_z_z"_h,
"revw_z_z"_h,
"ftssel_z_zz"_h,
"ftmad_z_zzi"_h,
"fexpa_z_z"_h,
"fabd_z_p_zz"_h,
"fadd_z_p_zz"_h,
"fdivr_z_p_zz"_h,
"fdiv_z_p_zz"_h,
"fmaxnm_z_p_zz"_h,
"fmax_z_p_zz"_h,
"fminnm_z_p_zz"_h,
"fmin_z_p_zz"_h,
"fmulx_z_p_zz"_h,
"fmul_z_p_zz"_h,
"fscale_z_p_zz"_h,
"fsubr_z_p_zz"_h,
"fsub_z_p_zz"_h,
"fadd_z_p_zs"_h,
"fmaxnm_z_p_zs"_h,
"fmax_z_p_zs"_h,
"fminnm_z_p_zs"_h,
"fmin_z_p_zs"_h,
"fmul_z_p_zs"_h,
"fsubr_z_p_zs"_h,
"fsub_z_p_zs"_h,
"abs_asisdmisc_r"_h,
"neg_asisdmisc_r"_h,
"cmeq_asisdmisc_z"_h,
"cmge_asisdmisc_z"_h,
"cmgt_asisdmisc_z"_h,
"cmle_asisdmisc_z"_h,
"cmlt_asisdmisc_z"_h,
"cdot_z_zzz"_h,
"histcnt_z_p_zz"_h,
"sdiv_z_p_zz"_h,
"sdivr_z_p_zz"_h,
"udiv_z_p_zz"_h,
"udivr_z_p_zz"_h,
"fdup_z_i"_h,
"fcpy_z_p_i"_h,
"sqdmulh_asimdsame_only"_h,
"sqrdmulh_asimdsame_only"_h,
"fcmla_asimdsame2_c"_h,
"fcadd_asimdsame2_c"_h,
"sqrdmlah_asimdsame2_only"_h,
"sqrdmlsh_asimdsame2_only"_h,
"sdot_asimdsame2_d"_h,
"udot_asimdsame2_d"_h,
"mla_asimdelem_r"_h,
"mls_asimdelem_r"_h,
"mul_asimdelem_r"_h,
"sqdmulh_asimdelem_r"_h,
"sqrdmlah_asimdelem_r"_h,
"sqrdmlsh_asimdelem_r"_h,
"sqrdmulh_asimdelem_r"_h,
"sqdmlal_asisddiff_only"_h,
"sqdmlsl_asisddiff_only"_h,
"sqdmull_asisddiff_only"_h,
"sqdmulh_asisdsame_only"_h,
"sqrdmulh_asisdsame_only"_h,
"sqrdmlah_asisdsame2_only"_h,
"sqrdmlsh_asisdsame2_only"_h,
"srshl_asisdsame_only"_h,
"urshl_asisdsame_only"_h,
"sshl_asisdsame_only"_h,
"ushl_asisdsame_only"_h,
"sqdmulh_asisdelem_r"_h,
"sqrdmlah_asisdelem_r"_h,
"sqrdmlsh_asisdelem_r"_h,
"sqrdmulh_asisdelem_r"_h,
"sqdmlal_asisdelem_l"_h,
"sqdmlsl_asisdelem_l"_h,
"sqdmull_asisdelem_l"_h,
"smlal_asimdelem_l"_h,
"smlsl_asimdelem_l"_h,
"smull_asimdelem_l"_h,
"umlal_asimdelem_l"_h,
"umlsl_asimdelem_l"_h,
"umull_asimdelem_l"_h,
"sqdmull_asimdelem_l"_h,
"sqdmlal_asimdelem_l"_h,
"sqdmlsl_asimdelem_l"_h,
"sqdmlal_asimddiff_l"_h,
"sqdmlsl_asimddiff_l"_h,
"sqdmull_asimddiff_l"_h}},
{0x00c00300'00000000,
{"asr_z_p_zi"_h,
"asrd_z_p_zi"_h,
"lsl_z_p_zi"_h,
"lsr_z_p_zi"_h,
"sqshl_z_p_zi"_h,
"sqshlu_z_p_zi"_h,
"srshr_z_p_zi"_h,
"uqshl_z_p_zi"_h,
"urshr_z_p_zi"_h}},
{0x00c00000'00400000,
{"urecpe_z_p_z"_h,
"ursqrte_z_p_z"_h,
"histseg_z_zz"_h,
"pmul_z_zz"_h,
"cmeq_asisdsame_only"_h,
"cmge_asisdsame_only"_h,
"cmgt_asisdsame_only"_h,
"cmhi_asisdsame_only"_h,
"cmhs_asisdsame_only"_h,
"cmtst_asisdsame_only"_h,
"add_asisdsame_only"_h,
"sub_asisdsame_only"_h,
"addp_asisdpair_only"_h,
"sxtw_z_p_z"_h,
"uxtw_z_p_z"_h,
"sxth_z_p_z"_h,
"uxth_z_p_z"_h,
"revh_z_z"_h,
"revw_z_z"_h,
"pmul_asimdsame_only"_h,
"abs_asisdmisc_r"_h,
"neg_asisdmisc_r"_h,
"cmeq_asisdmisc_z"_h,
"cmge_asisdmisc_z"_h,
"cmgt_asisdmisc_z"_h,
"cmle_asisdmisc_z"_h,
"cmlt_asisdmisc_z"_h,
"cdot_z_zzz"_h,
"histcnt_z_p_zz"_h,
"pmull_asimddiff_l"_h,
"sdot_asimdsame2_d"_h,
"udot_asimdsame2_d"_h,
"srshl_asisdsame_only"_h,
"urshl_asisdsame_only"_h,
"sshl_asisdsame_only"_h,
"ushl_asisdsame_only"_h}},
{0x00c00000'00800000,
{"histseg_z_zz"_h, "pmul_z_zz"_h,
"cmeq_asisdsame_only"_h, "cmge_asisdsame_only"_h,
"cmgt_asisdsame_only"_h, "cmhi_asisdsame_only"_h,
"cmhs_asisdsame_only"_h, "cmtst_asisdsame_only"_h,
"add_asisdsame_only"_h, "sub_asisdsame_only"_h,
"addp_asisdpair_only"_h, "sxtw_z_p_z"_h,
"uxtw_z_p_z"_h, "revw_z_z"_h,
"pmul_asimdsame_only"_h, "abs_asisdmisc_r"_h,
"neg_asisdmisc_r"_h, "cmeq_asisdmisc_z"_h,
"cmge_asisdmisc_z"_h, "cmgt_asisdmisc_z"_h,
"cmle_asisdmisc_z"_h, "cmlt_asisdmisc_z"_h,
"match_p_p_zz"_h, "nmatch_p_p_zz"_h,
"pmull_asimddiff_l"_h, "srshl_asisdsame_only"_h,
"urshl_asisdsame_only"_h, "sshl_asisdsame_only"_h,
"ushl_asisdsame_only"_h}},
{0x00c00000'00c00000,
{"asr_z_p_zw"_h,
"lsl_z_p_zw"_h,
"lsr_z_p_zw"_h,
"urecpe_z_p_z"_h,
"ursqrte_z_p_z"_h,
"histseg_z_zz"_h,
"pmul_z_zz"_h,
"asr_z_zw"_h,
"lsl_z_zw"_h,
"lsr_z_zw"_h,
"pmul_asimdsame_only"_h,
"match_p_p_zz"_h,
"nmatch_p_p_zz"_h,
"adds_32_addsub_shift"_h,
"adds_64_addsub_shift"_h,
"add_32_addsub_shift"_h,
"add_64_addsub_shift"_h,
"subs_32_addsub_shift"_h,
"subs_64_addsub_shift"_h,
"sub_32_addsub_shift"_h,
"sub_64_addsub_shift"_h,
"mla_asimdsame_only"_h,
"mls_asimdsame_only"_h,
"mul_asimdsame_only"_h,
"saba_asimdsame_only"_h,
"sabd_asimdsame_only"_h,
"shadd_asimdsame_only"_h,
"shsub_asimdsame_only"_h,
"smaxp_asimdsame_only"_h,
"smax_asimdsame_only"_h,
"sminp_asimdsame_only"_h,
"smin_asimdsame_only"_h,
"srhadd_asimdsame_only"_h,
"uaba_asimdsame_only"_h,
"uabd_asimdsame_only"_h,
"uhadd_asimdsame_only"_h,
"uhsub_asimdsame_only"_h,
"umaxp_asimdsame_only"_h,
"umax_asimdsame_only"_h,
"uminp_asimdsame_only"_h,
"umin_asimdsame_only"_h,
"urhadd_asimdsame_only"_h,
"sqdmulh_asimdsame_only"_h,
"sqrdmulh_asimdsame_only"_h,
"sqrdmlah_asimdsame2_only"_h,
"sqrdmlsh_asimdsame2_only"_h,
"sdot_asimdsame2_d"_h,
"udot_asimdsame2_d"_h,
"clz_asimdmisc_r"_h,
"cls_asimdmisc_r"_h,
"rev64_asimdmisc_r"_h,
"mla_asimdelem_r"_h,
"mls_asimdelem_r"_h,
"mul_asimdelem_r"_h,
"sqdmulh_asimdelem_r"_h,
"sqrdmlah_asimdelem_r"_h,
"sqrdmlsh_asimdelem_r"_h,
"sqrdmulh_asimdelem_r"_h,
"sqxtn_asisdmisc_n"_h,
"sqxtun_asisdmisc_n"_h,
"uqxtn_asisdmisc_n"_h,
"sqdmlal_asisddiff_only"_h,
"sqdmlsl_asisddiff_only"_h,
"sqdmull_asisddiff_only"_h,
"sqdmulh_asisdsame_only"_h,
"sqrdmulh_asisdsame_only"_h,
"sqrdmlah_asisdsame2_only"_h,
"sqrdmlsh_asisdsame2_only"_h,
"sqdmulh_asisdelem_r"_h,
"sqrdmlah_asisdelem_r"_h,
"sqrdmlsh_asisdelem_r"_h,
"sqrdmulh_asisdelem_r"_h,
"sqdmlal_asisdelem_l"_h,
"sqdmlsl_asisdelem_l"_h,
"sqdmull_asisdelem_l"_h,
"shll_asimdmisc_s"_h,
"xtn_asimdmisc_n"_h,
"sqxtn_asimdmisc_n"_h,
"uqxtn_asimdmisc_n"_h,
"sqxtun_asimdmisc_n"_h,
"smlal_asimdelem_l"_h,
"smlsl_asimdelem_l"_h,
"smull_asimdelem_l"_h,
"umlal_asimdelem_l"_h,
"umlsl_asimdelem_l"_h,
"umull_asimdelem_l"_h,
"sqdmull_asimdelem_l"_h,
"sqdmlal_asimdelem_l"_h,
"sqdmlsl_asimdelem_l"_h,
"saddlv_asimdall_only"_h,
"uaddlv_asimdall_only"_h,
"addv_asimdall_only"_h,
"smaxv_asimdall_only"_h,
"sminv_asimdall_only"_h,
"umaxv_asimdall_only"_h,
"uminv_asimdall_only"_h,
"sabal_asimddiff_l"_h,
"sabdl_asimddiff_l"_h,
"saddl_asimddiff_l"_h,
"smlal_asimddiff_l"_h,
"smlsl_asimddiff_l"_h,
"smull_asimddiff_l"_h,
"ssubl_asimddiff_l"_h,
"uabal_asimddiff_l"_h,
"uabdl_asimddiff_l"_h,
"uaddl_asimddiff_l"_h,
"umlal_asimddiff_l"_h,
"umlsl_asimddiff_l"_h,
"umull_asimddiff_l"_h,
"usubl_asimddiff_l"_h,
"saddw_asimddiff_w"_h,
"ssubw_asimddiff_w"_h,
"uaddw_asimddiff_w"_h,
"usubw_asimddiff_w"_h
"addhn_asimddiff_n"_h,
"raddhn_asimddiff_n"_h,
"rsubhn_asimddiff_n"_h,
"subhn_asimddiff_n"_h,
"sqdmlal_asimddiff_l"_h,
"sqdmlsl_asimddiff_l"_h,
"sqdmull_asimddiff_l"_h}},
{0x00c02000'00002000, {"dup_z_i"_h}},
{0x00d80000'00000000,
{"xar_z_zzi"_h,
"asr_z_zi"_h,
"lsr_z_zi"_h,
"sri_z_zzi"_h,
"srsra_z_zi"_h,
"ssra_z_zi"_h,
"ursra_z_zi"_h,
"usra_z_zi"_h,
"lsl_z_zi"_h,
"sli_z_zzi"_h}},
{0x40000000'00000000, {"fcmla_asimdelem_c_s"_h}},
{0x40000800'00000800, {"fcmla_asimdelem_c_h"_h}},
{0x40000c00'00000c00,
{"ld2_asisdlse_r2"_h,
"ld2_asisdlsep_i2_i"_h,
"ld2_asisdlsep_r2_r"_h,
"st2_asisdlse_r2"_h,
"st2_asisdlsep_i2_i"_h,
"st2_asisdlsep_r2_r"_h,
"ld3_asisdlse_r3"_h,
"ld3_asisdlsep_i3_i"_h,
"ld3_asisdlsep_r3_r"_h,
"st3_asisdlse_r3"_h,
"st3_asisdlsep_i3_i"_h,
"st3_asisdlsep_r3_r"_h,
"ld4_asisdlse_r4"_h,
"ld4_asisdlsep_i4_i"_h,
"ld4_asisdlsep_r4_r"_h,
"st4_asisdlse_r4"_h,
"st4_asisdlsep_i4_i"_h,
"st4_asisdlsep_r4_r"_h}},
{0x40004000'00004000, {"ext_asimdext_only"_h}},
{0x400f0000'00080000, {"dup_asimdins_dv_v"_h, "dup_asimdins_dr_d"_h}},
{0x40400000'00000000,
{"fmaxnmv_asimdall_only_sd"_h,
"fminnmv_asimdall_only_sd"_h,
"fmaxv_asimdall_only_sd"_h,
"fminv_asimdall_only_sd"_h}},
{0x40400000'00400000,
{"fabs_asimdmisc_r"_h, "fcvtas_asimdmisc_r"_h,
"fcvtau_asimdmisc_r"_h, "fcvtms_asimdmisc_r"_h,
"fcvtmu_asimdmisc_r"_h, "fcvtns_asimdmisc_r"_h,
"fcvtnu_asimdmisc_r"_h, "fcvtps_asimdmisc_r"_h,
"fcvtpu_asimdmisc_r"_h, "fcvtzs_asimdmisc_r"_h,
"fcvtzu_asimdmisc_r"_h, "fneg_asimdmisc_r"_h,
"frecpe_asimdmisc_r"_h, "frint32x_asimdmisc_r"_h,
"frint32z_asimdmisc_r"_h, "frint64x_asimdmisc_r"_h,
"frint64z_asimdmisc_r"_h, "frinta_asimdmisc_r"_h,
"frinti_asimdmisc_r"_h, "frintm_asimdmisc_r"_h,
"frintn_asimdmisc_r"_h, "frintp_asimdmisc_r"_h,
"frintx_asimdmisc_r"_h, "frintz_asimdmisc_r"_h,
"frsqrte_asimdmisc_r"_h, "fsqrt_asimdmisc_r"_h,
"scvtf_asimdmisc_r"_h, "ucvtf_asimdmisc_r"_h,
"fmaxnmv_asimdall_only_sd"_h, "fminnmv_asimdall_only_sd"_h,
"fmaxv_asimdall_only_sd"_h, "fminv_asimdall_only_sd"_h,
"fcmeq_asimdmisc_fz"_h, "fcmge_asimdmisc_fz"_h,
"fcmgt_asimdmisc_fz"_h, "fcmle_asimdmisc_fz"_h,
"fcmlt_asimdmisc_fz"_h, "fabd_asimdsame_only"_h,
"facge_asimdsame_only"_h, "facgt_asimdsame_only"_h,
"faddp_asimdsame_only"_h, "fadd_asimdsame_only"_h,
"fcmeq_asimdsame_only"_h, "fcmge_asimdsame_only"_h,
"fcmgt_asimdsame_only"_h, "fdiv_asimdsame_only"_h,
"fmaxnmp_asimdsame_only"_h, "fmaxnm_asimdsame_only"_h,
"fmaxp_asimdsame_only"_h, "fmax_asimdsame_only"_h,
"fminnmp_asimdsame_only"_h, "fminnm_asimdsame_only"_h,
"fminp_asimdsame_only"_h, "fmin_asimdsame_only"_h,
"fmla_asimdsame_only"_h, "fmls_asimdsame_only"_h,
"fmulx_asimdsame_only"_h, "fmul_asimdsame_only"_h,
"frecps_asimdsame_only"_h, "frsqrts_asimdsame_only"_h,
"fsub_asimdsame_only"_h, "fmla_asimdelem_r_sd"_h,
"fmls_asimdelem_r_sd"_h, "fmulx_asimdelem_r_sd"_h,
"fmul_asimdelem_r_sd"_h, "sri_asimdshf_r"_h,
"srshr_asimdshf_r"_h, "srsra_asimdshf_r"_h,
"sshr_asimdshf_r"_h, "ssra_asimdshf_r"_h,
"urshr_asimdshf_r"_h, "ursra_asimdshf_r"_h,
"ushr_asimdshf_r"_h, "usra_asimdshf_r"_h,
"scvtf_asimdshf_c"_h, "ucvtf_asimdshf_c"_h,
"fcvtzs_asimdshf_c"_h, "fcvtzu_asimdshf_c"_h}},
{0x40400000'40400000,
{"fmaxnmv_asimdall_only_sd"_h,
"fminnmv_asimdall_only_sd"_h,
"fmaxv_asimdall_only_sd"_h,
"fminv_asimdall_only_sd"_h}},
{0x40c00000'00800000,
{"saddlv_asimdall_only"_h,
"uaddlv_asimdall_only"_h,
"addv_asimdall_only"_h,
"smaxv_asimdall_only"_h,
"sminv_asimdall_only"_h,
"umaxv_asimdall_only"_h,
"uminv_asimdall_only"_h}},
{0x40c00000'00c00000,
{"cmeq_asimdmisc_z"_h, "cmge_asimdmisc_z"_h,
"cmgt_asimdmisc_z"_h, "cmle_asimdmisc_z"_h,
"cmlt_asimdmisc_z"_h, "addp_asimdsame_only"_h,
"add_asimdsame_only"_h, "cmeq_asimdsame_only"_h,
"cmge_asimdsame_only"_h, "cmgt_asimdsame_only"_h,
"cmhi_asimdsame_only"_h, "cmhs_asimdsame_only"_h,
"cmtst_asimdsame_only"_h, "sqadd_asimdsame_only"_h,
"sqdmulh_asimdsame_only"_h, "sqrdmulh_asimdsame_only"_h,
"sqrshl_asimdsame_only"_h, "sqshl_asimdsame_only"_h,
"sqsub_asimdsame_only"_h, "srshl_asimdsame_only"_h,
"sshl_asimdsame_only"_h, "sub_asimdsame_only"_h,
"uqadd_asimdsame_only"_h, "uqrshl_asimdsame_only"_h,
"uqshl_asimdsame_only"_h, "uqsub_asimdsame_only"_h,
"urshl_asimdsame_only"_h, "ushl_asimdsame_only"_h,
"trn1_asimdperm_only"_h, "trn2_asimdperm_only"_h,
"uzp1_asimdperm_only"_h, "uzp2_asimdperm_only"_h,
"zip1_asimdperm_only"_h, "zip2_asimdperm_only"_h,
"fcmla_asimdsame2_c"_h, "fcadd_asimdsame2_c"_h}},
{0x80200000'00200000,
{"sbfm_64m_bitfield"_h,
"sbfm_32m_bitfield"_h,
"ubfm_32m_bitfield"_h,
"ubfm_64m_bitfield"_h,
"bfm_32m_bitfield"_h,
"bfm_64m_bitfield"_h}},
{0x80008000'00000000,
{"scvtf_d32_float2fix"_h,
"scvtf_d64_float2fix"_h,
"scvtf_h32_float2fix"_h,
"scvtf_h64_float2fix"_h,
"scvtf_s32_float2fix"_h,
"scvtf_s64_float2fix"_h,
"ucvtf_d32_float2fix"_h,
"ucvtf_d64_float2fix"_h,
"ucvtf_h32_float2fix"_h,
"ucvtf_h64_float2fix"_h,
"ucvtf_s32_float2fix"_h,
"ucvtf_s64_float2fix"_h}},
{0x80008000'00008000,
{"sbfm_64m_bitfield"_h,
"sbfm_32m_bitfield"_h,
"ubfm_32m_bitfield"_h,
"ubfm_64m_bitfield"_h,
"bfm_32m_bitfield"_h,
"bfm_64m_bitfield"_h}},
{0xc0000000'40000000,
{"cpyen_cpy_memcms"_h, "cpyern_cpy_memcms"_h, "cpyewn_cpy_memcms"_h,
"cpye_cpy_memcms"_h, "cpyfen_cpy_memcms"_h, "cpyfern_cpy_memcms"_h,
"cpyfewn_cpy_memcms"_h, "cpyfe_cpy_memcms"_h, "cpyfmn_cpy_memcms"_h,
"cpyfmrn_cpy_memcms"_h, "cpyfmwn_cpy_memcms"_h, "cpyfm_cpy_memcms"_h,
"cpyfpn_cpy_memcms"_h, "cpyfprn_cpy_memcms"_h, "cpyfpwn_cpy_memcms"_h,
"cpyfp_cpy_memcms"_h, "cpymn_cpy_memcms"_h, "cpymrn_cpy_memcms"_h,
"cpymwn_cpy_memcms"_h, "cpym_cpy_memcms"_h, "cpypn_cpy_memcms"_h,
"cpyprn_cpy_memcms"_h, "cpypwn_cpy_memcms"_h, "cpyp_cpy_memcms"_h,
"seten_set_memcms"_h, "sete_set_memcms"_h, "setgen_set_memcms"_h,
"setge_set_memcms"_h, "setgmn_set_memcms"_h, "setgm_set_memcms"_h,
"setgpn_set_memcms"_h, "setgp_set_memcms"_h, "setmn_set_memcms"_h,
"setm_set_memcms"_h, "setpn_set_memcms"_h, "setp_set_memcms"_h}},
{0xc0000000'80000000,
{"cpyen_cpy_memcms"_h, "cpyern_cpy_memcms"_h, "cpyewn_cpy_memcms"_h,
"cpye_cpy_memcms"_h, "cpyfen_cpy_memcms"_h, "cpyfern_cpy_memcms"_h,
"cpyfewn_cpy_memcms"_h, "cpyfe_cpy_memcms"_h, "cpyfmn_cpy_memcms"_h,
"cpyfmrn_cpy_memcms"_h, "cpyfmwn_cpy_memcms"_h, "cpyfm_cpy_memcms"_h,
"cpyfpn_cpy_memcms"_h, "cpyfprn_cpy_memcms"_h, "cpyfpwn_cpy_memcms"_h,
"cpyfp_cpy_memcms"_h, "cpymn_cpy_memcms"_h, "cpymrn_cpy_memcms"_h,
"cpymwn_cpy_memcms"_h, "cpym_cpy_memcms"_h, "cpypn_cpy_memcms"_h,
"cpyprn_cpy_memcms"_h, "cpypwn_cpy_memcms"_h, "cpyp_cpy_memcms"_h,
"seten_set_memcms"_h, "sete_set_memcms"_h, "setgen_set_memcms"_h,
"setge_set_memcms"_h, "setgmn_set_memcms"_h, "setgm_set_memcms"_h,
"setgpn_set_memcms"_h, "setgp_set_memcms"_h, "setmn_set_memcms"_h,
"setm_set_memcms"_h, "setpn_set_memcms"_h, "setp_set_memcms"_h}},
{0xc0000000'c0000000,
{"cpyen_cpy_memcms"_h, "cpyern_cpy_memcms"_h, "cpyewn_cpy_memcms"_h,
"cpye_cpy_memcms"_h, "cpyfen_cpy_memcms"_h, "cpyfern_cpy_memcms"_h,
"cpyfewn_cpy_memcms"_h, "cpyfe_cpy_memcms"_h, "cpyfmn_cpy_memcms"_h,
"cpyfmrn_cpy_memcms"_h, "cpyfmwn_cpy_memcms"_h, "cpyfm_cpy_memcms"_h,
"cpyfpn_cpy_memcms"_h, "cpyfprn_cpy_memcms"_h, "cpyfpwn_cpy_memcms"_h,
"cpyfp_cpy_memcms"_h, "cpymn_cpy_memcms"_h, "cpymrn_cpy_memcms"_h,
"cpymwn_cpy_memcms"_h, "cpym_cpy_memcms"_h, "cpypn_cpy_memcms"_h,
"cpyprn_cpy_memcms"_h, "cpypwn_cpy_memcms"_h, "cpyp_cpy_memcms"_h,
"seten_set_memcms"_h, "sete_set_memcms"_h, "setgen_set_memcms"_h,
"setge_set_memcms"_h, "setgmn_set_memcms"_h, "setgm_set_memcms"_h,
"setgpn_set_memcms"_h, "setgp_set_memcms"_h, "setmn_set_memcms"_h,
"setm_set_memcms"_h, "setpn_set_memcms"_h, "setp_set_memcms"_h}}};
for (auto& itm : forms) {
const std::unordered_set<uint32_t>& s = forms.at(itm.first);
for (const uint32_t& its : s) {
ftm->insert(std::make_pair(its, itm.first));
}
}
}
// Initialise empty vectors for sampled bits and pattern table.
const std::vector<uint8_t> DecodeNode::kEmptySampledBits;
const std::vector<DecodePattern> DecodeNode::kEmptyPatternTable;
@@ -190,6 +1033,7 @@ BitExtractFn DecodeNode::GetBitExtractFunctionHelper(uint32_t x, uint32_t y) {
INSTANTIATE_TEMPLATE_M(00000800);
INSTANTIATE_TEMPLATE_M(00000c00);
INSTANTIATE_TEMPLATE_M(00000c10);
INSTANTIATE_TEMPLATE_M(00000f00);
INSTANTIATE_TEMPLATE_M(00000fc0);
INSTANTIATE_TEMPLATE_M(00001000);
INSTANTIATE_TEMPLATE_M(00001400);
@@ -324,11 +1168,13 @@ BitExtractFn DecodeNode::GetBitExtractFunctionHelper(uint32_t x, uint32_t y) {
INSTANTIATE_TEMPLATE_MV(00003000, 00002000);
INSTANTIATE_TEMPLATE_MV(00003000, 00003000);
INSTANTIATE_TEMPLATE_MV(00003010, 00000000);
INSTANTIATE_TEMPLATE_MV(0000301f, 0000001f);
INSTANTIATE_TEMPLATE_MV(00003c00, 00003c00);
INSTANTIATE_TEMPLATE_MV(00040010, 00000000);
INSTANTIATE_TEMPLATE_MV(00060000, 00000000);
INSTANTIATE_TEMPLATE_MV(00061000, 00000000);
INSTANTIATE_TEMPLATE_MV(00070000, 00030000);
INSTANTIATE_TEMPLATE_MV(0007309f, 0000001f);
INSTANTIATE_TEMPLATE_MV(00073ee0, 00033060);
INSTANTIATE_TEMPLATE_MV(00073f9f, 0000001f);
INSTANTIATE_TEMPLATE_MV(000f0000, 00000000);
+3779 -6818
View File
File diff suppressed because it is too large Load Diff
+24
View File
@@ -603,6 +603,28 @@ std::pair<int, int> Instruction::GetSVEMulLongZmAndIndex() const {
return std::make_pair(reg_code, index);
}
// Get the register and index for NEON indexed multiplies.
std::pair<int, int> Instruction::GetNEONMulRmAndIndex() const {
int reg_code = GetRm();
int index = (GetNEONH() << 2) | (GetNEONL() << 1) | GetNEONM();
switch (GetNEONSize()) {
case 0: // FP H-sized elements.
case 1: // Integer H-sized elements.
// 4-bit Rm, 3-bit index.
reg_code &= 0xf;
break;
case 2: // S-sized elements.
// 5-bit Rm, 2-bit index.
index >>= 1;
break;
case 3: // FP D-sized elements.
// 5-bit Rm, 1-bit index.
index >>= 2;
break;
}
return std::make_pair(reg_code, index);
}
// Logical immediates can't encode zero, so a return value of zero is used to
// indicate a failure case. Specifically, where the constraints on imm_s are
// not met.
@@ -1025,6 +1047,8 @@ VectorFormat VectorFormatHalfWidth(VectorFormat vform) {
return kFormatVnH;
case kFormatVnD:
return kFormatVnS;
case kFormatVnQ:
return kFormatVnD;
default:
VIXL_UNREACHABLE();
return kFormatUndefined;
+123 -9
View File
@@ -6118,6 +6118,42 @@ LogicVRegister Simulator::fcvtxn2(VectorFormat vform,
return dst;
}
LogicVRegister Simulator::bfcvtn(VectorFormat vform,
LogicVRegister dst,
const LogicVRegister& src) {
SimVRegister tmp;
LogicVRegister srctmp = mov(kFormatVnD, tmp, src);
int input_lane_count = LaneCountFromFormat(vform);
if (IsSVEFormat(vform)) {
input_lane_count /= 2;
}
dst.ClearForWrite(vform);
VIXL_ASSERT(LaneSizeInBitsFromFormat(vform) == kHRegSize);
for (int i = 0; i < input_lane_count; i++) {
dst.SetFloat(i,
BFloat16ToRawbits(FPToBFloat16(srctmp.Float<float>(i),
FPTieEven,
ReadDN())));
}
return dst;
}
LogicVRegister Simulator::bfcvtn2(VectorFormat vform,
LogicVRegister dst,
const LogicVRegister& src) {
VIXL_ASSERT(LaneSizeInBitsFromFormat(vform) == kHRegSize);
dst.ClearForWrite(vform);
int lane_count = LaneCountFromFormat(vform) / 2;
for (int i = lane_count - 1; i >= 0; i--) {
dst.SetFloat(i + lane_count,
BFloat16ToRawbits(
FPToBFloat16(src.Float<float>(i), FPTieEven, ReadDN())));
}
return dst;
}
// Based on reference C function recip_sqrt_estimate from ARM ARM.
double Simulator::recip_sqrt_estimate(double a) {
@@ -7853,16 +7889,26 @@ LogicVRegister Simulator::matmul(VectorFormat vform_dst,
//
// Are stored in the input vector registers as:
//
// 3 2 1 0
// src1 = [ d | c | b | a ]
// src2 = [ D | B | C | A ]
// 3 2 1 0
// src1 = [ d | c | b | a ]
// src2 = [ D | B | C | A ] nb. transposition
//
// Giving:
// 3 2 1 0
// result = [ w | z | y | x ]
//
// Where:
//
// x = (a * A) + (b * C) + a
// y = (a * B) + (b * D) + b
// z = (c * A) + (d * C) + c
// w = (c * B) + (d * D) + d
template <typename T>
LogicVRegister Simulator::fmatmul(VectorFormat vform,
LogicVRegister srcdst,
const LogicVRegister& src1,
const LogicVRegister& src2) {
T result[kZRegMaxSizeInBytes / sizeof(T)];
T result[kZRegMaxSizeInBytes / sizeof(T)] = {};
int T_per_segment = 4;
int segment_count = GetVectorLengthInBytes() / (T_per_segment * sizeof(T));
for (int seg = 0; seg < segment_count; seg++) {
@@ -7879,12 +7925,9 @@ LogicVRegister Simulator::fmatmul(VectorFormat vform,
}
}
for (int i = 0; i < LaneCountFromFormat(vform); i++) {
// Elements outside a multiple of 4T are set to zero. This happens only
// for double precision operations, when the VL is a multiple of 128 bits,
// but not a multiple of 256 bits.
T value = (i < (T_per_segment * segment_count)) ? result[i] : 0;
srcdst.SetFloat<T>(vform, i, value);
srcdst.SetFloat<T>(vform, i, result[i]);
}
return srcdst;
}
@@ -8477,6 +8520,77 @@ LogicVRegister Simulator::sm3tt2(LogicVRegister srcdst,
return srcdst;
}
static uint64_t SM4SBox(uint64_t x) {
static const uint8_t sbox[256] = {
0x48, 0x39, 0xcb, 0xd7, 0x3e, 0x5f, 0xee, 0x79, 0x20, 0x4d, 0xdc, 0x3a,
0xec, 0x7d, 0xf0, 0x18, 0x84, 0xc6, 0x6e, 0xc5, 0x09, 0xf1, 0xb9, 0x65,
0x7e, 0x77, 0x96, 0x0c, 0x4a, 0x97, 0x69, 0x89, 0xb0, 0xb4, 0xe5, 0xb8,
0x12, 0xd0, 0x74, 0x2d, 0xbd, 0x7b, 0xcd, 0xa5, 0x88, 0x31, 0xc1, 0x0a,
0xd8, 0x5a, 0x10, 0x1f, 0x41, 0x5c, 0xd9, 0x11, 0x7f, 0xbc, 0xdd, 0xbb,
0x92, 0xaf, 0x1b, 0x8d, 0x51, 0x5b, 0x6c, 0x6d, 0x72, 0x6a, 0xff, 0x03,
0x2f, 0x8e, 0xfd, 0xde, 0x45, 0x37, 0xdb, 0xd5, 0x6f, 0x4e, 0x53, 0x0d,
0xab, 0x23, 0x29, 0xc0, 0x60, 0xca, 0x66, 0x82, 0x2e, 0xe2, 0xf6, 0x1d,
0xe3, 0xb1, 0x8c, 0xf5, 0x30, 0x32, 0x93, 0xad, 0x55, 0x1a, 0x34, 0x9b,
0xa4, 0x5d, 0xae, 0xe0, 0xa1, 0x15, 0x61, 0xf9, 0xce, 0xf2, 0xf7, 0xa3,
0xb5, 0x38, 0xc7, 0x40, 0xd2, 0x8a, 0xbf, 0xea, 0x9e, 0xc8, 0xc4, 0xa0,
0xe7, 0x02, 0x36, 0x4c, 0x52, 0x27, 0xd3, 0x9f, 0x57, 0x46, 0x00, 0xd4,
0x87, 0x78, 0x21, 0x01, 0x3b, 0x7c, 0x22, 0x25, 0xa2, 0xd1, 0x58, 0x63,
0x5e, 0x0e, 0x24, 0x1e, 0x35, 0x9d, 0x56, 0x70, 0x4b, 0x0f, 0xeb, 0xf8,
0x8b, 0xda, 0x64, 0x71, 0xb2, 0x81, 0x6b, 0x68, 0xa8, 0x4f, 0x85, 0xe6,
0x19, 0x3c, 0x59, 0x83, 0xba, 0x17, 0x73, 0xf3, 0xfc, 0xa7, 0x07, 0x47,
0xa6, 0x3f, 0x8f, 0x75, 0xfa, 0x94, 0xdf, 0x80, 0x95, 0xe8, 0x08, 0xc9,
0xa9, 0x1c, 0xb3, 0xe4, 0x62, 0xac, 0xcf, 0xed, 0x43, 0x0b, 0x54, 0x33,
0x7a, 0x98, 0xef, 0x91, 0xf4, 0x50, 0x42, 0x9c, 0x99, 0x06, 0x86, 0x49,
0x26, 0x13, 0x44, 0xaa, 0xc3, 0x04, 0xbe, 0x2a, 0x76, 0x9a, 0x67, 0x2b,
0x05, 0x2c, 0xfb, 0x28, 0xc2, 0x14, 0xb6, 0x16, 0xb7, 0x3d, 0xe1, 0xcc,
0xfe, 0xe9, 0x90, 0xd6,
};
uint64_t result = 0;
for (int j = 24; j >= 0; j -= 8) {
uint8_t s = 255 - ((x >> j) & 0xff);
result = (result << 8) | sbox[s];
}
return result;
}
LogicVRegister Simulator::sm4(LogicVRegister srcdst,
const LogicVRegister& src1,
const LogicVRegister& src2,
bool is_key) {
using namespace std::placeholders;
auto ROL = std::bind(RotateLeft, _1, _2, kSRegSize);
VectorFormat vf = kFormat4S;
uint64_t result[4] = {};
if (is_key) {
src1.UintArray(vf, result);
} else {
srcdst.UintArray(vf, result);
}
for (int i = 0; i < 4; i++) {
uint64_t k = is_key ? src2.Uint(vf, i) : src1.Uint(vf, i);
uint64_t intval = result[3] ^ result[2] ^ result[1] ^ k;
intval = SM4SBox(intval);
if (is_key) {
intval ^= ROL(intval, 13) ^ ROL(intval, 23);
} else {
intval ^=
ROL(intval, 2) ^ ROL(intval, 10) ^ ROL(intval, 18) ^ ROL(intval, 24);
}
intval ^= result[0];
result[0] = result[1];
result[1] = result[2];
result[2] = result[3];
result[3] = intval;
}
srcdst.SetUintArray(vf, result);
return srcdst;
}
} // namespace aarch64
} // namespace vixl
+11 -4
View File
@@ -550,8 +550,7 @@ void MacroAssembler::B(Label* label) {
b(label);
}
void MacroAssembler::B(Label* label, Condition cond) {
void MacroAssembler::Bcommon(Label* label, Condition cond, bool use_bc) {
// We don't need to check the size of the literal pool, because the size of
// the literal pool is already bounded by the literal range, which is smaller
// than the range of this branch.
@@ -563,7 +562,11 @@ void MacroAssembler::B(Label* label, Condition cond) {
if (label->IsBound() && LabelIsOutOfRange(label, CondBranchType)) {
Label done;
b(&done, InvertCondition(cond));
if (use_bc) {
bc(&done, InvertCondition(cond));
} else {
b(&done, InvertCondition(cond));
}
b(label);
bind(&done);
} else {
@@ -572,7 +575,11 @@ void MacroAssembler::B(Label* label, Condition cond) {
label,
CondBranchType);
}
b(label, cond);
if (use_bc) {
bc(label, cond);
} else {
b(label, cond);
}
}
}
File diff suppressed because it is too large Load Diff
+92
View File
@@ -34,14 +34,19 @@ namespace vixl {
const double kFP64DefaultNaN = RawbitsToDouble(UINT64_C(0x7ff8000000000000));
const float kFP32DefaultNaN = RawbitsToFloat(0x7fc00000);
const Float16 kFP16DefaultNaN = RawbitsToFloat16(0x7e00);
const BFloat16 kBFP16DefaultNaN = RawbitsToBFloat16(0x7fc0);
// Floating-point zero values.
const Float16 kFP16PositiveZero = RawbitsToFloat16(0x0);
const Float16 kFP16NegativeZero = RawbitsToFloat16(0x8000);
const BFloat16 kBFP16PositiveZero = RawbitsToBFloat16(0x0);
const BFloat16 kBFP16NegativeZero = RawbitsToBFloat16(0x8000);
// Floating-point infinity values.
const Float16 kFP16PositiveInfinity = RawbitsToFloat16(0x7c00);
const Float16 kFP16NegativeInfinity = RawbitsToFloat16(0xfc00);
const BFloat16 kBFP16PositiveInfinity = RawbitsToBFloat16(0x7f80);
const BFloat16 kBFP16NegativeInfinity = RawbitsToBFloat16(0xff80);
const float kFP32PositiveInfinity = RawbitsToFloat(0x7f800000);
const float kFP32NegativeInfinity = RawbitsToFloat(0xff800000);
const double kFP64PositiveInfinity =
@@ -57,6 +62,14 @@ bool IsZero(Float16 value) {
uint16_t Float16ToRawbits(Float16 value) { return value.rawbits_; }
bool IsZero(BFloat16 value) {
uint16_t bits = BFloat16ToRawbits(value);
return (bits == BFloat16ToRawbits(kBFP16PositiveZero) ||
bits == BFloat16ToRawbits(kBFP16NegativeZero));
}
uint16_t BFloat16ToRawbits(BFloat16 value) { return value.rawbits_; }
uint32_t FloatToRawbits(float value) {
uint32_t bits = 0;
memcpy(&bits, &value, 4);
@@ -78,6 +91,13 @@ Float16 RawbitsToFloat16(uint16_t bits) {
}
BFloat16 RawbitsToBFloat16(uint16_t bits) {
BFloat16 f;
f.rawbits_ = bits;
return f;
}
float RawbitsToFloat(uint32_t bits) {
float value = 0.0;
memcpy(&value, &bits, 4);
@@ -552,4 +572,76 @@ Float16 FPToFloat16(double value,
return kFP16PositiveZero;
}
BFloat16 FPToBFloat16(float value,
FPRounding round_mode,
UseDefaultNaN DN,
bool* exception) {
// Only the FPTieEven rounding mode is implemented.
VIXL_ASSERT(round_mode == FPTieEven);
USE(round_mode);
uint32_t raw = FloatToRawbits(value);
int32_t sign = raw >> 31;
int32_t exponent =
static_cast<int32_t>(ExtractUnsignedBitfield32(30, 23, raw)) - 127;
uint32_t mantissa = ExtractUnsignedBitfield32(22, 0, raw);
switch (std::fpclassify(value)) {
case FP_NAN: {
if (IsSignallingNaN(value)) {
if (exception != NULL) {
*exception = true;
}
}
if (DN == kUseDefaultNaN) return kBFP16DefaultNaN;
// Convert NaNs as the processor would:
// - The sign is propagated.
// - The payload (mantissa) is transferred as much as possible, except
// that the top bit is forced to '1', making the result a quiet NaN.
uint16_t result = (sign == 0) ? BFloat16ToRawbits(kBFP16PositiveInfinity)
: BFloat16ToRawbits(kBFP16NegativeInfinity);
result |= mantissa >> (kFloatMantissaBits - kBFloat16MantissaBits);
result |= (1 << 6); // Force a quiet NaN;
return RawbitsToBFloat16(result);
}
case FP_ZERO:
return (sign == 0) ? kBFP16PositiveZero : kBFP16NegativeZero;
case FP_INFINITE:
return (sign == 0) ? kBFP16PositiveInfinity : kBFP16NegativeInfinity;
case FP_NORMAL:
// Add the implicit '1' bit to the mantissa.
mantissa += (1 << 23);
break;
case FP_SUBNORMAL:
// Reduce exponent to account for MSB of mantissa.
int32_t leading_mantissa_bits =
CountLeadingZeros(mantissa) - (32 - kFloatMantissaBits);
exponent -= leading_mantissa_bits;
break;
}
// Convert float-to-half as the processor would, assuming that FPCR.FZ
// (flush-to-zero) is not set.
return FPRoundToBFloat16(sign, exponent, mantissa, round_mode);
}
BFloat16 FPToBFloat16(double value,
FPRounding round_mode,
UseDefaultNaN DN,
bool* exception) {
USE(value);
USE(round_mode);
USE(DN);
USE(exception);
// TODO: Implement this for correct conversion of doubles to BFloat (without
// implicit NaN silencing.)
VIXL_UNIMPLEMENTED();
return kBFP16PositiveZero;
}
} // namespace vixl
+2
View File
@@ -76,6 +76,7 @@
<ClCompile Include="src\aarch64\cpu-aarch64.cc" />
<ClCompile Include="src\aarch64\cpu-features-auditor-aarch64.cc" />
<ClCompile Include="src\aarch64\decoder-aarch64.cc" />
<ClCompile Include="src\aarch64\debugger-aarch64.cc" />
<ClCompile Include="src\aarch64\disasm-aarch64.cc" />
<ClCompile Include="src\aarch64\instructions-aarch64.cc" />
<ClCompile Include="src\aarch64\logic-aarch64.cc" />
@@ -84,6 +85,7 @@
<ClCompile Include="src\aarch64\operands-aarch64.cc" />
<ClCompile Include="src\aarch64\pointer-auth-aarch64.cc" />
<ClCompile Include="src\aarch64\registers-aarch64.cc" />
<ClCompile Include="src\aarch64\simulator-aarch64.cc" />
<ClCompile Include="src\code-buffer-vixl.cc" />
<ClCompile Include="src\compiler-intrinsics-vixl.cc" />
<ClCompile Include="src\cpu-features.cc" />
+6
View File
@@ -65,6 +65,9 @@
<ClCompile Include="src\aarch64\decoder-aarch64.cc">
<Filter>aarch64</Filter>
</ClCompile>
<ClCompile Include="src\aarch64\debugger-aarch64.cc">
<Filter>aarch64</Filter>
</ClCompile>
<ClCompile Include="src\aarch64\disasm-aarch64.cc">
<Filter>aarch64</Filter>
</ClCompile>
@@ -89,6 +92,9 @@
<ClCompile Include="src\aarch64\registers-aarch64.cc">
<Filter>aarch64</Filter>
</ClCompile>
<ClCompile Include="src\aarch64\simulator-aarch64.cc">
<Filter>aarch64</Filter>
</ClCompile>
<ClCompile Include="src\aarch64\assembler-aarch64.cc">
<Filter>aarch64</Filter>
</ClCompile>
+23 -16
View File
@@ -15,7 +15,7 @@
#include <stdio.h> // for debug print
#include <assert.h>
#include <list>
#include <vector>
#include <string>
#include <algorithm>
#ifndef NDEBUG
@@ -116,10 +116,12 @@
#undef XBYAK_USE_MEMFD
#endif
#if defined(_WIN64) || defined(__MINGW64__) || (defined(__CYGWIN__) && defined(__x86_64__))
#define XBYAK64_WIN
#elif defined(__x86_64__)
#define XBYAK64_GCC
#if !defined(XBYAK64_WIN) && !defined(XBYAK64_GCC)
#if defined(_WIN64) || defined(__MINGW64__) || (defined(__CYGWIN__) && defined(__x86_64__))
#define XBYAK64_WIN
#elif defined(__x86_64__)
#define XBYAK64_GCC
#endif
#endif
#if !defined(XBYAK64) && !defined(XBYAK32)
#if defined(XBYAK64_GCC) || defined(XBYAK64_WIN)
@@ -174,7 +176,7 @@ namespace Xbyak {
enum {
DEFAULT_MAX_CODE_SIZE = 4096,
VERSION = 0x7352 /* 0xABCD = A.BC(.D) */
VERSION = 0x7370 /* 0xABCD = A.BC(.D) */
};
#ifndef MIE_INTEGER_TYPE_DEFINED
@@ -1074,7 +1076,7 @@ public:
}
}
friend RegExp operator+(const RegExp& a, const RegExp& b);
friend RegExp operator+(const RegExp& e, size_t disp);
friend RegExp operator+(const RegExp& e, unsigned long long disp);
friend RegExp operator-(const RegExp& e, size_t disp);
private:
/*
@@ -1128,15 +1130,19 @@ inline RegExp operator*(int scale, const Reg& r)
// backward compatibility for eax+&x (pointer address)
inline RegExp operator+(const RegExp& a, const void* b) { return a + RegExp(b); }
// overload for integer literals (e.g. eax+0) to avoid ambiguity with the void* overload
inline RegExp operator+(const RegExp& e, int disp) { return e + size_t(disp); }
inline RegExp operator+(const RegExp& e, size_t disp)
// since what size_t is typedef'd to depends on the implementation, use unsigned long long (assume u64) for the implementation.
inline RegExp operator+(const RegExp& e, unsigned long long disp)
{
RegExp ret = e;
ret.disp_ += disp;
ret.disp_ += static_cast<size_t>(disp);
return ret;
}
// overload for integer literals (e.g. eax+0) to avoid ambiguity with the void* overload
inline RegExp operator+(const RegExp& e, int disp) { return e + static_cast<unsigned long long>(disp); }
inline RegExp operator+(const RegExp& e, long disp) { return e + static_cast<unsigned long long>(disp); }
inline RegExp operator+(const RegExp& e, long long disp) { return e + static_cast<unsigned long long>(disp); }
inline RegExp operator+(const RegExp& e, unsigned int disp) { return e + static_cast<unsigned long long>(disp); }
inline RegExp operator+(const RegExp& e, unsigned long disp) { return e + static_cast<unsigned long long>(disp); }
inline RegExp operator-(const RegExp& e, size_t disp)
{
@@ -1172,7 +1178,7 @@ class CodeArray {
return disp;
}
};
typedef std::list<AddrInfo> AddrInfoList;
typedef std::vector<AddrInfo> AddrInfoList;
AddrInfoList addrInfoList_;
const Type type_;
#ifdef XBYAK_USE_MMAP_ALLOCATOR
@@ -1319,7 +1325,7 @@ public:
*/
void rewrite(size_t offset, uint64_t disp, size_t size)
{
assert(offset < maxSize_);
if (offset >= maxSize_ || size > maxSize_ - offset) XBYAK_THROW(ERR_OFFSET_IS_TOO_BIG)
if (size != 1 && size != 2 && size != 4 && size != 8) XBYAK_THROW(ERR_BAD_PARAMETER)
uint8_t *const data = top_ + offset;
for (size_t i = 0; i < size; i++) {
@@ -1363,7 +1369,7 @@ public:
DWORD oldProtect;
return VirtualProtect(const_cast<void*>(addr), size, mode, &oldProtect) != 0;
#elif defined(__GNUC__)
size_t pageSize = sysconf(_SC_PAGESIZE);
size_t pageSize = inner::getPageSize();
size_t iaddr = reinterpret_cast<size_t>(addr);
size_t roundAddr = iaddr & ~(pageSize - static_cast<size_t>(1));
return mprotect(reinterpret_cast<void*>(roundAddr), size + (iaddr - roundAddr), mode) == 0;
@@ -1548,7 +1554,8 @@ class LabelManager {
SlabelDefList defList;
SlabelUndefList undefList;
};
typedef std::list<SlabelState> StateList;
// SlabelState is cheap to move, so std::vector is preferred over std::list.
typedef std::vector<SlabelState> StateList;
// for Label class
struct ClabelVal {
ClabelVal(size_t offset = 0) : offset(offset), refCount(1) {}
+6 -13
View File
@@ -1,4 +1,4 @@
const char *getVersionString() const { return "7.35.2"; }
const char *getVersionString() const { return "7.37"; }
void aadd(const Address& addr, const Reg32e &reg) { opMR(addr, reg, T_0F38, 0x0FC, T_APX); }
void aand(const Address& addr, const Reg32e &reg) { opMR(addr, reg, T_0F38|T_66, 0x0FC, T_APX|T_66); }
void adc(const Operand& op, uint32_t imm) { opOI(op, imm, 0x10, 2); }
@@ -853,7 +853,6 @@ void prefetcht0(const Address& addr) { opMR(addr, Reg32(1), T_0F, 0x18); }
void prefetcht1(const Address& addr) { opMR(addr, Reg32(2), T_0F, 0x18); }
void prefetcht2(const Address& addr) { opMR(addr, Reg32(3), T_0F, 0x18); }
void prefetchw(const Address& addr) { opMR(addr, Reg32(1), T_0F, 0x0D); }
void prefetchwt1(const Address& addr) { opMR(addr, Reg32(2), T_0F, 0x0D); }
void psadbw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0xF6); }
void pshufb(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x00, T_0F38, T_66); }
void pshufd(const Mmx& mmx, const Operand& op, uint8_t imm8) { opMMX(mmx, op, 0x70, T_0F, T_66, imm8); }
@@ -2036,10 +2035,6 @@ void kxorb(const Opmask& r1, const Opmask& r2, const Opmask& r3) { opVex(r1, &r2
void kxord(const Opmask& r1, const Opmask& r2, const Opmask& r3) { opVex(r1, &r2, r3, T_L1 | T_0F | T_66 | T_W1, 0x47); }
void kxorq(const Opmask& r1, const Opmask& r2, const Opmask& r3) { opVex(r1, &r2, r3, T_L1 | T_0F | T_W1, 0x47); }
void kxorw(const Opmask& r1, const Opmask& r2, const Opmask& r3) { opVex(r1, &r2, r3, T_L1 | T_0F | T_W0, 0x47); }
void v4fmaddps(const Zmm& z1, const Zmm& z2, const Address& addr) { opAVX_X_X_XM(z1, z2, addr, T_0F38 | T_F2 | T_W0 | T_YMM | T_MUST_EVEX | T_N16, 0x9A); }
void v4fmaddss(const Xmm& x1, const Xmm& x2, const Address& addr) { opAVX_X_X_XM(x1, x2, addr, T_0F38 | T_F2 | T_W0 | T_MUST_EVEX | T_N16, 0x9B); }
void v4fnmaddps(const Zmm& z1, const Zmm& z2, const Address& addr) { opAVX_X_X_XM(z1, z2, addr, T_0F38 | T_F2 | T_W0 | T_YMM | T_MUST_EVEX | T_N16, 0xAA); }
void v4fnmaddss(const Xmm& x1, const Xmm& x2, const Address& addr) { opAVX_X_X_XM(x1, x2, addr, T_0F38 | T_F2 | T_W0 | T_MUST_EVEX | T_N16, 0xAB); }
void vaddbf16(const Xmm& x1, const Xmm& x2, const Operand& op) { opAVX_X_X_XM(x1, x2, op, T_66|T_MAP5|T_W0|T_YMM|T_MUST_EVEX|T_B16, 0x58); }
void vaddph(const Xmm& xmm, const Operand& op1, const Operand& op2 = Operand()) { opAVX_X_X_XM(xmm, op1, op2, T_MAP5 | T_W0 | T_YMM | T_MUST_EVEX | T_ER_Z | T_B16, 0x58); }
void vaddsh(const Xmm& xmm, const Operand& op1, const Operand& op2 = Operand()) { opAVX_X_X_XM(xmm, op1, op2, T_MAP5 | T_F3 | T_W0 | T_MUST_EVEX | T_ER_X | T_N2, 0x58); }
@@ -2199,10 +2194,10 @@ void vcompressps(const Operand& op, const Xmm& x) { opAVX_X_XM_IMM(x, op, T_N4|T
void vcomxsd(const Xmm& x, const Operand& op) { opAVX_X_XM_IMM(x, op, T_N8|T_F2|T_0F|T_EW1|T_SAE_X|T_MUST_EVEX, 0x2F); }
void vcomxsh(const Xmm& x, const Operand& op) { opAVX_X_XM_IMM(x, op, T_N2|T_F3|T_MAP5|T_W0|T_SAE_X|T_MUST_EVEX, 0x2F); }
void vcomxss(const Xmm& x, const Operand& op) { opAVX_X_XM_IMM(x, op, T_N4|T_F3|T_0F|T_W0|T_SAE_X|T_MUST_EVEX, 0x2F); }
void vcvt2ph2bf8(const Xmm& x1, const Xmm& x2, const Operand& op) { opAVX_X_X_XM(x1, x2, op, T_N1|T_F2|T_0F38|T_W0|T_YMM|T_MUST_EVEX|T_B16, 0x74); }
void vcvt2ph2bf8s(const Xmm& x1, const Xmm& x2, const Operand& op) { opAVX_X_X_XM(x1, x2, op, T_N1|T_F2|T_MAP5|T_W0|T_YMM|T_MUST_EVEX|T_B16, 0x74); }
void vcvt2ph2hf8(const Xmm& x1, const Xmm& x2, const Operand& op) { opAVX_X_X_XM(x1, x2, op, T_N1|T_F2|T_MAP5|T_W0|T_YMM|T_MUST_EVEX|T_B16, 0x18); }
void vcvt2ph2hf8s(const Xmm& x1, const Xmm& x2, const Operand& op) { opAVX_X_X_XM(x1, x2, op, T_N1|T_F2|T_MAP5|T_W0|T_YMM|T_MUST_EVEX|T_B16, 0x1B); }
void vcvt2ph2bf8(const Xmm& x1, const Xmm& x2, const Operand& op) { opAVX_X_X_XM(x1, x2, op, T_N16|T_N_VL|T_F2|T_0F38|T_W0|T_YMM|T_MUST_EVEX|T_B16, 0x74); }
void vcvt2ph2bf8s(const Xmm& x1, const Xmm& x2, const Operand& op) { opAVX_X_X_XM(x1, x2, op, T_N16|T_N_VL|T_F2|T_MAP5|T_W0|T_YMM|T_MUST_EVEX|T_B16, 0x74); }
void vcvt2ph2hf8(const Xmm& x1, const Xmm& x2, const Operand& op) { opAVX_X_X_XM(x1, x2, op, T_N16|T_N_VL|T_F2|T_MAP5|T_W0|T_YMM|T_MUST_EVEX|T_B16, 0x18); }
void vcvt2ph2hf8s(const Xmm& x1, const Xmm& x2, const Operand& op) { opAVX_X_X_XM(x1, x2, op, T_N16|T_N_VL|T_F2|T_MAP5|T_W0|T_YMM|T_MUST_EVEX|T_B16, 0x1B); }
void vcvt2ps2phx(const Xmm& x1, const Xmm& x2, const Operand& op) { opAVX_X_X_XM(x1, x2, op, T_66|T_0F38|T_W0|T_YMM|T_ER_Z|T_MUST_EVEX|T_B32, 0x67); }
void vcvtbf162ibs(const Xmm& x, const Operand& op) { opAVX_X_XM_IMM(x, op, T_F2|T_MAP5|T_W0|T_YMM|T_MUST_EVEX|T_B16, 0x69); }
void vcvtbf162iubs(const Xmm& x, const Operand& op) { opAVX_X_XM_IMM(x, op, T_F2|T_MAP5|T_W0|T_YMM|T_MUST_EVEX|T_B16, 0x6B); }
@@ -2211,7 +2206,7 @@ void vcvtbiasph2bf8s(const Xmm& x1, const Xmm& x2, const Operand& op) { opCvt6(x
void vcvtbiasph2hf8(const Xmm& x1, const Xmm& x2, const Operand& op) { opCvt6(x1, x2, op, T_MAP5|T_W0|T_YMM|T_MUST_EVEX|T_B16, 0x18); }
void vcvtbiasph2hf8s(const Xmm& x1, const Xmm& x2, const Operand& op) { opCvt6(x1, x2, op, T_MAP5|T_W0|T_YMM|T_MUST_EVEX|T_B16, 0x1B); }
void vcvtdq2ph(const Xmm& x, const Operand& op) { checkCvt4(x, op); opCvt(x, op, T_N16|T_N_VL|T_MAP5|T_W0|T_YMM|T_ER_Z|T_MUST_EVEX|T_B32, 0x5B); }
void vcvthf82ph(const Xmm& x, const Operand& op) { checkCvt1(x, op); opVex(x, 0, op, T_MUST_EVEX | T_F2 | T_MAP5 | T_W0 | T_YMM | T_N1, 0x1E); }
void vcvthf82ph(const Xmm& x, const Operand& op) { checkCvt1(x, op); opVex(x, 0, op, T_MUST_EVEX|T_F2|T_MAP5|T_W0|T_YMM|T_N8|T_N_VL, 0x1E); }
void vcvtne2ps2bf16(const Xmm& x1, const Xmm& x2, const Operand& op) { opAVX_X_X_XM(x1, x2, op, T_F2|T_0F38|T_W0|T_YMM|T_SAE_Z|T_MUST_EVEX|T_B32, 0x72); }
void vcvtpd2ph(const Xmm& x, const Operand& op) { opCvt5(x, op, T_N16|T_N_VL|T_66|T_MAP5|T_EW1|T_ER_Z|T_MUST_EVEX|T_B64, 0x5A); }
void vcvtpd2qq(const Xmm& x, const Operand& op) { opAVX_X_XM_IMM(x, op, T_66|T_0F|T_EW1|T_YMM|T_ER_Z|T_MUST_EVEX|T_B64, 0x7B); }
@@ -2437,8 +2432,6 @@ void vmulph(const Xmm& xmm, const Operand& op1, const Operand& op2 = Operand())
void vmulsh(const Xmm& xmm, const Operand& op1, const Operand& op2 = Operand()) { opAVX_X_X_XM(xmm, op1, op2, T_MAP5 | T_F3 | T_W0 | T_MUST_EVEX | T_ER_X | T_N2, 0x59); }
void vp2intersectd(const Opmask& k, const Xmm& x, const Operand& op) { if (k.getOpmaskIdx() != 0) XBYAK_THROW(ERR_OPMASK_IS_ALREADY_SET) opAVX_K_X_XM(k, x, op, T_F2 | T_0F38 | T_YMM | T_EVEX | T_W0 | T_B32, 0x68); }
void vp2intersectq(const Opmask& k, const Xmm& x, const Operand& op) { if (k.getOpmaskIdx() != 0) XBYAK_THROW(ERR_OPMASK_IS_ALREADY_SET) opAVX_K_X_XM(k, x, op, T_F2 | T_0F38 | T_YMM | T_EVEX | T_EW1 | T_B64, 0x68); }
void vp4dpwssd(const Zmm& z1, const Zmm& z2, const Address& addr) { opAVX_X_X_XM(z1, z2, addr, T_0F38 | T_F2 | T_W0 | T_YMM | T_MUST_EVEX | T_N16, 0x52); }
void vp4dpwssds(const Zmm& z1, const Zmm& z2, const Address& addr) { opAVX_X_X_XM(z1, z2, addr, T_0F38 | T_F2 | T_W0 | T_YMM | T_MUST_EVEX | T_N16, 0x53); }
void vpabsq(const Xmm& x, const Operand& op) { opAVX_X_XM_IMM(x, op, T_66 | T_0F38 | T_MUST_EVEX | T_EW1 | T_B64 | T_YMM, 0x1F); }
void vpandd(const Xmm& x1, const Xmm& x2, const Operand& op) { opAVX_X_X_XM(x1, x2, op, T_66|T_0F|T_W0|T_YMM|T_MUST_EVEX|T_B32, 0xDB); }
void vpandnd(const Xmm& x1, const Xmm& x2, const Operand& op) { opAVX_X_X_XM(x1, x2, op, T_66|T_0F|T_W0|T_YMM|T_MUST_EVEX|T_B32, 0xDF); }
+237 -77
View File
@@ -101,6 +101,8 @@
#endif
#ifdef _WIN32
#include <windows.h>
#else
#include <sched.h>
#endif
namespace Xbyak { namespace util {
class CpuTopology;
@@ -526,16 +528,16 @@ public:
XBYAK_DEFINE_TYPE(36, tAVX512DQ);
XBYAK_DEFINE_TYPE(37, tAVX512_IFMA);
XBYAK_DEFINE_TYPE(37, tAVX512IFMA);// = tAVX512_IFMA;
XBYAK_DEFINE_TYPE(38, tAVX512PF);
XBYAK_DEFINE_TYPE(39, tAVX512ER);
// XBYAK_DEFINE_TYPE(38, tAVX512PF); // Xeon Phi only
// XBYAK_DEFINE_TYPE(39, tAVX512ER);
XBYAK_DEFINE_TYPE(40, tAVX512CD);
XBYAK_DEFINE_TYPE(41, tAVX512BW);
XBYAK_DEFINE_TYPE(42, tAVX512VL);
XBYAK_DEFINE_TYPE(43, tAVX512_VBMI);
XBYAK_DEFINE_TYPE(43, tAVX512VBMI); // = tAVX512_VBMI; // changed by Intel's manual
XBYAK_DEFINE_TYPE(44, tAVX512_4VNNIW);
XBYAK_DEFINE_TYPE(45, tAVX512_4FMAPS);
XBYAK_DEFINE_TYPE(46, tPREFETCHWT1);
// XBYAK_DEFINE_TYPE(44, tAVX512_4VNNIW);
// XBYAK_DEFINE_TYPE(45, tAVX512_4FMAPS);
// XBYAK_DEFINE_TYPE(46, tPREFETCHWT1);
XBYAK_DEFINE_TYPE(47, tPREFETCHW);
XBYAK_DEFINE_TYPE(48, tSHA);
XBYAK_DEFINE_TYPE(49, tMPX);
@@ -587,6 +589,7 @@ public:
XBYAK_DEFINE_TYPE(95, tAMX_FP8);
XBYAK_DEFINE_TYPE(96, tMOVRS);
XBYAK_DEFINE_TYPE(97, tHYBRID);
XBYAK_DEFINE_TYPE(98, tAMX_COMPLEX);
#undef XBYAK_SPLIT_ID
#undef XBYAK_DEFINE_TYPE
@@ -679,8 +682,6 @@ public:
if (type_ & tAVX512F) {
if (ebx & (1U << 17)) type_ |= tAVX512DQ;
if (ebx & (1U << 21)) type_ |= tAVX512_IFMA;
if (ebx & (1U << 26)) type_ |= tAVX512PF;
if (ebx & (1U << 27)) type_ |= tAVX512ER;
if (ebx & (1U << 28)) type_ |= tAVX512CD;
if (ebx & (1U << 30)) type_ |= tAVX512BW;
if (ebx & (1U << 31)) type_ |= tAVX512VL;
@@ -689,8 +690,6 @@ public:
if (ecx & (1U << 11)) type_ |= tAVX512_VNNI;
if (ecx & (1U << 12)) type_ |= tAVX512_BITALG;
if (ecx & (1U << 14)) type_ |= tAVX512_VPOPCNTDQ;
if (edx & (1U << 2)) type_ |= tAVX512_4VNNIW;
if (edx & (1U << 3)) type_ |= tAVX512_4FMAPS;
if (edx & (1U << 8)) type_ |= tAVX512_VP2INTERSECT;
if ((type_ & tAVX512BW) && (edx & (1U << 23))) type_ |= tAVX512_FP16;
}
@@ -713,7 +712,6 @@ public:
if (ebx & (1U << 23)) type_ |= tCLFLUSHOPT;
if (ebx & (1U << 24)) type_ |= tCLWB;
if (ebx & (1U << 29)) type_ |= tSHA;
if (ecx & (1U << 0)) type_ |= tPREFETCHWT1;
if (ecx & (1U << 5)) type_ |= tWAITPKG;
if (ecx & (1U << 8)) type_ |= tGFNI;
if (ecx & (1U << 9)) type_ |= tVAES;
@@ -745,6 +743,7 @@ public:
if (eax & (1U << 31)) type_ |= tMOVRS;
if (edx & (1U << 4)) type_ |= tAVX_VNNI_INT8;
if (edx & (1U << 5)) type_ |= tAVX_NE_CONVERT;
if (edx & (1U << 8)) type_ |= tAMX_COMPLEX;
if (edx & (1U << 10)) type_ |= tAVX_VNNI_INT16;
if (edx & (1U << 14)) type_ |= tPREFETCHITI;
if (edx & (1U << 19)) type_ |= tAVX10;
@@ -1296,11 +1295,57 @@ inline uint32_t popcnt(uint64_t mask)
#endif
}
// fall back to CPUID leaf 0x1A
inline CoreType getCoreType()
{
uint32_t data[4] = {};
Cpu::getCpuidEx(0x1A, 0, data);
const uint32_t coreTypeField = (data[0] >> 24) & 0xFF;
if (coreTypeField == 0x40) return Performance; // P-core
if (coreTypeField == 0x20) return Efficient; // E-core
return Standard;
}
#ifdef _WIN32
typedef std::vector<uint32_t> U32Vec;
#if (defined(NTDDI_VERSION) && NTDDI_VERSION >= 0x06010000) || (defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0601)
#define XBYAK_WINSDK_HAS_RELATIONSHIP_GROUP_AFFINITY 1
#else
#define XBYAK_WINSDK_HAS_RELATIONSHIP_GROUP_AFFINITY 0
#endif
#if (defined(NTDDI_VERSION) && NTDDI_VERSION >= 0x0A000000) || (defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0A00)
#define XBYAK_WINSDK_HAS_EFFICIENCY_CLASS 1
#else
#define XBYAK_WINSDK_HAS_EFFICIENCY_CLASS 0
#endif
// GroupMasks[] / GroupCount on CACHE_RELATIONSHIP added in Win10 20H1 (SDK 10.0.19041, NTDDI_WIN10_VB)
// NOTE: _WIN32_WINNT has no sub-version granularity for Win10, so only
// NTDDI_VERSION can distinguish 20H1 (0x0A00000C) from earlier Win10 builds.
// If NTDDI_VERSION is not set, this macro will be 0 (safe/conservative fallback).
#if defined(NTDDI_VERSION) && NTDDI_VERSION >= 0x0A00000C
#define XBYAK_WINSDK_HAS_CACHE_RELATIONSHIP_GROUPMASKS 1
#else
#define XBYAK_WINSDK_HAS_CACHE_RELATIONSHIP_GROUPMASKS 0
#endif
#if XBYAK_WINSDK_HAS_RELATIONSHIP_GROUP_AFFINITY
typedef SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX ProcInfo;
inline CoreType getCoreTypeForAffinity(const GROUP_AFFINITY& affinity)
{
GROUP_AFFINITY previousMask = {};
if (!SetThreadGroupAffinity(GetCurrentThread(), &affinity, &previousMask)) {
return Standard;
}
CoreType type = impl::getCoreType();
SetThreadGroupAffinity(GetCurrentThread(), &previousMask, NULL);
return type;
}
// return total logical cpus if sucessful, 0 if failed
inline uint32_t getGroupAcc(U32Vec& v)
{
@@ -1346,10 +1391,12 @@ static inline uint32_t getCores(std::vector<LogicalCpu>& cpus, bool isHybrid, co
cpu.coreId = coreIdx++;
if (!isHybrid) {
cpu.coreType = Standard;
} else if (core.EfficiencyClass > 0) {
cpu.coreType = Performance;
} else {
cpu.coreType = Efficient;
#if XBYAK_WINSDK_HAS_EFFICIENCY_CLASS
cpu.coreType = core.EfficiencyClass > 0 ? Performance : Efficient;
#else
cpu.coreType = getCoreTypeForAffinity(core.GroupMask[0]);
#endif
}
const GROUP_AFFINITY* masks = core.GroupMask;
@@ -1374,13 +1421,19 @@ static inline uint32_t getCores(std::vector<LogicalCpu>& cpus, bool isHybrid, co
inline bool convertMask(CpuMask& mask, const U32Vec& groupAcc, const CACHE_RELATIONSHIP& cache)
{
const GROUP_AFFINITY* masks = cache.GroupMasks;
for (WORD i = 0; i < cache.GroupCount; i++) {
const WORD group = masks[i].Group;
const KAFFINITY m = masks[i].Mask;
const uint32_t base = groupAcc[group];
#if XBYAK_WINSDK_HAS_CACHE_RELATIONSHIP_GROUPMASKS
const WORD count = cache.GroupCount;
#else
const WORD count = 1;
#endif
for (WORD i = 0; i < count; i++) {
#if XBYAK_WINSDK_HAS_CACHE_RELATIONSHIP_GROUPMASKS
const GROUP_AFFINITY& cg = cache.GroupMasks[i];
#else
const GROUP_AFFINITY& cg = cache.GroupMask;
#endif
const KAFFINITY m = cg.Mask;
const uint32_t base = groupAcc[cg.Group];
for (uint32_t b = 0; b < sizeof(KAFFINITY) * 8; b++) {
if (m & (KAFFINITY(1) << b)) {
if (!mask.append(base + b)) return false;
@@ -1441,7 +1494,17 @@ inline bool initCpuTopology(CpuTopology& cpuTopo)
}
return true;
}
#else
inline bool initCpuTopology(CpuTopology& cpuTopo)
{
(void)cpuTopo;
return false;
}
#endif
// unset WinSDK version macros to avoid Macro pollution
#undef XBYAK_WINSDK_HAS_RELATIONSHIP_GROUP_AFFINITY
#undef XBYAK_WINSDK_HAS_EFFICIENCY_CLASS
#undef XBYAK_WINSDK_HAS_CACHE_RELATIONSHIP_GROUPMASKS
#elif defined(__linux__) // Linux
struct WrapFILE {
@@ -1471,6 +1534,15 @@ inline bool parseCpuList(CpuMask& mask, const char* path) {
return setStr(mask, buf);
}
inline CoreType setAffinityAndGetCoreType(uint32_t cpu)
{
cpu_set_t cpuMask;
CPU_ZERO(&cpuMask);
CPU_SET(cpu, &cpuMask);
if (sched_setaffinity(0, sizeof(cpu_set_t), &cpuMask)) return Standard;
return impl::getCoreType();
}
inline bool initCpuTopology(CpuTopology& cpuTopo)
{
const uint32_t logicalCpuNum = sysconf(_SC_NPROCESSORS_ONLN);
@@ -1564,9 +1636,10 @@ inline bool initCpuTopology(CpuTopology& cpuTopo)
// Assign core types for hybrid architectures
const bool isHybrid = cpuTopo.isHybrid();
if (isHybrid) {
// For hybrid systems, read P-core and E-core lists from sysfs
// For hybrid systems, try toread P-core and E-core lists from sysfs first
CpuMask pCoreMask;
if (parseCpuList(pCoreMask, "/sys/devices/cpu_core/cpus")) {
const bool hasPCoreSysfs = parseCpuList(pCoreMask, "/sys/devices/cpu_core/cpus");
if (hasPCoreSysfs) {
// Set Performance core types
for (CpuMask::const_iterator it = pCoreMask.begin(); it != pCoreMask.end(); ++it) {
uint32_t cpuIdx = *it;
@@ -1576,7 +1649,8 @@ inline bool initCpuTopology(CpuTopology& cpuTopo)
}
}
CpuMask eCoreMask;
if (parseCpuList(eCoreMask, "/sys/devices/cpu_atom/cpus")) {
const bool hasECoreSysfs = parseCpuList(eCoreMask, "/sys/devices/cpu_atom/cpus");
if (hasECoreSysfs) {
// Set Efficient core types
for (CpuMask::const_iterator it = eCoreMask.begin(); it != eCoreMask.end(); ++it) {
uint32_t cpuIdx = *it;
@@ -1585,6 +1659,17 @@ inline bool initCpuTopology(CpuTopology& cpuTopo)
}
}
}
// Fallback: if either sysfs paths are unavailable, detect both core type per-CPU
if (!hasPCoreSysfs || !hasECoreSysfs) {
cpu_set_t originalMask;
CPU_ZERO(&originalMask);
if (sched_getaffinity(0, sizeof(cpu_set_t), &originalMask) == 0) {
for (uint32_t cpu = 0; cpu < logicalCpuNum; cpu++) {
cpuTopo.logicalCpus_[cpu].coreType = impl::setAffinityAndGetCoreType(cpu);
}
sched_setaffinity(0, sizeof(cpu_set_t), &originalMask);
}
}
}
// Read coherency line size
@@ -1645,8 +1730,6 @@ private:
};
#ifdef XBYAK64
const int UseRCX = 1 << 6;
const int UseRDX = 1 << 7;
class Pack {
static const size_t maxTblNum = 15;
@@ -1745,28 +1828,35 @@ public:
}
};
// start from a bit position larger than the number of GPRs
const int UseRBP = 1 << 5;
const int UseRCX = 1 << 6;
const int UseRDX = 1 << 7;
const int UseRSI = 1 << 8;
const int UseRDI = 1 << 9;
const int UseRBPAsFramePointer = UseRBP | (1 << 10);
class StackFrame {
#ifdef XBYAK64_WIN
static const int noSaveNum = 6;
static const int rcxPos = 0;
static const int rdxPos = 1;
#else
static const int noSaveNum = 8;
static const int rcxPos = 3;
static const int rdxPos = 2;
#endif
static const int maxPnum = 4;
static const int maxRegNum = 14; // maxRegNum = 16 - rsp - rax
static const int calleeSaveNum = maxRegNum - noSaveNum;
static const int UseMASK = UseRCX|UseRDX|UseRSI|UseRDI|UseRBP;
Xbyak::CodeGenerator *code_;
Xbyak::Reg64 pTbl_[4];
Xbyak::Reg64 pTbl_[maxPnum];
Xbyak::Reg64 tTbl_[maxRegNum];
Pack p_;
Pack t_;
int pNum_;
int tNum_;
int useRegs_;
int saveNum_;
int saveRegs_[calleeSaveNum];
int P_;
bool useRcx_;
bool useRdx_;
bool makeEpilog_;
StackFrame(const StackFrame&);
void operator=(const StackFrame&);
@@ -1776,45 +1866,69 @@ public:
/*
make stack frame
@param sf [in] this
@param pNum [in] num of function parameter(0 <= pNum <= 4)
@param tNum [in] num of temporary register(0 <= tNum, with UseRCX, UseRDX) #{pNum + tNum [+rcx] + [rdx]} <= 14
@param pNum [in] number of function parameters(0 <= pNum <= 4)
@param tNum [in] number of temporary registers(0 <= tNum, can be OR-ed with Use{RCX,RDX,RSI,RDI,RBP}, e.g., 3|UseRCX)
@param stackSizeByte [in] local stack size
@param makeEpilog [in] automatically call close() if true
pNum + tNum + #Use must be <= 14
you can use
rax
gp0, ..., gp(pNum - 1)
gt0, ..., gt(tNum-1)
rcx if tNum & UseRCX
rdx if tNum & UseRDX
rsp[0..stackSizeByte - 1]
p[0], ..., p[pNum-1] as function parameters
t[0], ..., t[tNum-1] as temporary registers
{rcx,rdx,rsi,rdi,rbp} are explicitly available by specifying Use{RCX,RDX,RSI,RDI,RBP} in tNum
rsp[0..stackSizeByte-1] if stackSizeByte > 0
*/
StackFrame(Xbyak::CodeGenerator *code, int pNum, int tNum = 0, int stackSizeByte = 0, bool makeEpilog = true)
: code_(code)
, pNum_(pNum)
, tNum_(tNum & ~(UseRCX | UseRDX))
, tNum_(tNum & ~(UseMASK|UseRBPAsFramePointer))
, useRegs_(tNum & UseMASK) // drop UseRBPAsFramePointer bit
, saveNum_(0)
, P_(0)
, useRcx_((tNum & UseRCX) != 0)
, useRdx_((tNum & UseRDX) != 0)
, makeEpilog_(makeEpilog)
, p(p_)
, t(t_)
{
using namespace Xbyak;
if (pNum < 0 || pNum > 4) XBYAK_THROW(ERR_BAD_PNUM)
const int allRegNum = pNum + tNum_ + (useRcx_ ? 1 : 0) + (useRdx_ ? 1 : 0);
if (tNum_ < 0 || allRegNum > maxRegNum) XBYAK_THROW(ERR_BAD_TNUM)
const Reg64& _rsp = code->rsp;
saveNum_ = local::max_(0, allRegNum - noSaveNum);
const int *tbl = getOrderTbl() + noSaveNum;
for (int i = 0; i < saveNum_; i++) {
code->push(Reg64(tbl[i]));
if (tNum < 0) XBYAK_THROW(ERR_BAD_TNUM)
const int *const fullTbl = getRegEntryTbl();
const int *const calleeTbl = fullTbl + noSaveNum;
int callerUseNum = 0;
int calleeUseNum = 0;
for (int i = 0; i < maxRegNum; i++) {
if (useRegs_ & useFlagOf(fullTbl[i])) {
if (i < noSaveNum) {
callerUseNum++;
} else {
calleeUseNum++;
}
}
}
const int useNum = callerUseNum + calleeUseNum;
if (pNum + tNum_ + useNum > maxRegNum) XBYAK_THROW(ERR_BAD_TNUM)
const int baseSaveNum = local::max_(0, pNum + tNum_ + useNum - noSaveNum);
bool pushedRbp = false;
if (useRegs_ & UseRBP) {
code->push(rbp);
saveRegs_[saveNum_++] = Operand::RBP;
pushedRbp = true;
if ((tNum & UseRBPAsFramePointer) == UseRBPAsFramePointer) code->mov(rbp, rsp);
}
for (int i = 0; i < calleeSaveNum; i++) {
int r = calleeTbl[i];
if (i < baseSaveNum || isUseReg(r)) {
if (pushedRbp && r == Operand::RBP) continue;
saveRegs_[saveNum_++] = r;
code->push(Reg64(r));
}
}
P_ = (stackSizeByte + 7) / 8;
if (P_ > 0 && (P_ & 1) == (saveNum_ & 1)) P_++; // (rsp % 16) == 8, then increment P_ for 16 byte alignment
// (rsp % 16) == 8, then increment P_ for 16 byte alignment
if (P_ > 0 && (P_ & 1) == (saveNum_ & 1)) P_++;
P_ *= 8;
if (P_ > 0) code->sub(_rsp, P_);
if (P_ > 0) code->sub(rsp, P_);
int pos = 0;
for (int i = 0; i < pNum; i++) {
pTbl_[i] = Xbyak::Reg64(getRegIdx(pos));
@@ -1822,8 +1936,13 @@ public:
for (int i = 0; i < tNum_; i++) {
tTbl_[i] = Xbyak::Reg64(getRegIdx(pos));
}
if (useRcx_ && rcxPos < pNum) code_->mov(code_->r10, code_->rcx);
if (useRdx_ && rdxPos < pNum) code_->mov(code_->r11, code_->rdx);
// replace reserved reg with backup reg if needed
for (size_t i = 0; i < maxPnum; i++) {
const RegSlot& rp = getRegSlotTbl()[i];
if (isUseReg(rp.target) && rp.pos < pNum && rp.alt >= 0) {
code->mov(Xbyak::Reg64(rp.alt), Xbyak::Reg64(rp.target));
}
}
p_.init(pTbl_, pNum);
t_.init(tTbl_, tNum_);
}
@@ -1833,14 +1952,10 @@ public:
*/
void close(bool callRet = true)
{
using namespace Xbyak;
const Reg64& _rsp = code_->rsp;
const int *tbl = getOrderTbl() + noSaveNum;
if (P_ > 0) code_->add(_rsp, P_);
for (int i = 0; i < saveNum_; i++) {
code_->pop(Reg64(tbl[saveNum_ - 1 - i]));
if (P_ > 0) code_->add(code_->rsp, P_);
for (int i = saveNum_ - 1; i >= 0; i--) {
code_->pop(Reg64(saveRegs_[i]));
}
if (callRet) code_->ret();
}
~StackFrame()
@@ -1849,10 +1964,48 @@ public:
close();
}
private:
const int *getOrderTbl() const
static int useFlagOf(int r)
{
using namespace Xbyak;
static const int tbl[] = {
switch (r) {
case Operand::RCX: return UseRCX;
case Operand::RDX: return UseRDX;
case Operand::RSI: return UseRSI;
case Operand::RDI: return UseRDI;
case Operand::RBP: return UseRBP;
default: return 0;
}
}
bool isUseReg(int r) const { return (useRegs_ & useFlagOf(r)) != 0; }
// Register allocation for the first 4 function parameters
struct RegSlot {
int target;
int pos; // position of target in getRegEntryTbl()
int alt; // alternative if target is used for parameter. -1 means no alternative.
};
const RegSlot *getRegSlotTbl() const
{
// Win: p[] = rcx(r10), rdx(r11), r8, r9:
// Linux: p[] = rdi(r8), rsi(r9), rdx(r11), rcx(r10)
// reg(alt) means a reserved reg if Use<reg> is used.
static const RegSlot tbl[maxPnum] = {
#ifdef XBYAK64_WIN
{ Operand::RCX, 0, Operand::R10 },
{ Operand::RDX, 1, Operand::R11 },
{ Operand::RDI, 6, -1 },
{ Operand::RSI, 7, -1 },
#else
{ Operand::RCX, 3, Operand::R10 },
{ Operand::RDX, 2, Operand::R11 },
{ Operand::RDI, 0, Operand::R8 },
{ Operand::RSI, 1, Operand::R9 },
#endif
};
return tbl;
}
const int *getRegEntryTbl() const
{
static const int tbl[maxRegNum] = {
#ifdef XBYAK64_WIN
Operand::RCX, Operand::RDX, Operand::R8, Operand::R9, Operand::R10, Operand::R11, Operand::RDI, Operand::RSI,
#else
@@ -1862,21 +2015,28 @@ private:
};
return &tbl[0];
}
// get an available register index from tbl, skipping reserved registers
int getRegIdx(int& pos) const
{
assert(pos < maxRegNum);
using namespace Xbyak;
const int *tbl = getOrderTbl();
int r = tbl[pos++];
if (useRcx_) {
if (r == Operand::RCX) { return Operand::R10; }
if (r == Operand::R10) { r = tbl[pos++]; }
const int *tbl = getRegEntryTbl();
const RegSlot *slotTbl = getRegSlotTbl();
for (;;) {
NEXT:;
assert(pos < maxRegNum);
int r = tbl[pos++];
// if r is a Use*** target with alt, return alt as backup
// otherwise skip Use*** targets, their alts, and UseRBP's rbp
for (size_t i = 0; i < maxPnum; i++) {
const RegSlot& slot = slotTbl[i];
if (!isUseReg(slot.target)) continue;
if (r == slot.alt) goto NEXT;
if (r == slot.target) {
if (slot.alt >= 0) return slot.alt;
goto NEXT;
}
}
if (!isUseReg(r)) return r;
}
if (useRdx_) {
if (r == Operand::RDX) { return Operand::R11; }
if (r == Operand::R11) { return tbl[pos++]; }
}
return r;
}
};
#endif
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More