Compare commits

..

406 Commits

Author SHA1 Message Date
Stenzek
113614c2f5 WIP 2025-01-07 21:54:15 +10:00
Stenzek
ac41ace972 GPUDevice: Add stencil testing support 2025-01-07 19:39:40 +10:00
Stenzek
ebe782e4f4 Common: Add Vector4i xyxy(Vector2i) 2025-01-07 19:38:58 +10:00
Stenzek
e7439c1503 GPUDevice: Move size-matches check into ResizeTexture() 2025-01-07 19:25:11 +10:00
Stenzek
fda87de7e7 GPU/HW: Slight re-shuffling of field offsets
Free up some bits in the middle.
2025-01-07 19:25:11 +10:00
Stenzek
116bc83d09 GPUDevice: Ensure 16 byte minimum UBO alignment 2025-01-07 19:25:11 +10:00
Stenzek
ddffc055b9 GPU/HW: Use sized tristrips instead of fullscreen quads 2025-01-07 19:25:11 +10:00
Stenzek
1063c3da7f Qt: Add 'Enable Touchpad' to Controller Settings
Have to shuffle a few other things around to fit in 768p.
2025-01-07 13:42:45 +10:00
Stenzek
0a124ee839 SDLInputSource: Support forwarding touchpad to pointer 2025-01-07 13:40:42 +10:00
Stenzek
2b7b3d8729 SDLInputSource: Allow inverting pad axes
Not really sure where this would happen, but whatever.
2025-01-07 13:01:37 +10:00
Stenzek
dacbb7c718 Qt: Behaviour -> Behavior
US English is used everywhere else, consistency > *.
2025-01-07 12:50:48 +10:00
Stenzek
6318223f58 Qt: Remove Apperance/Update settings from Game Properties 2025-01-07 12:48:27 +10:00
Stenzek
092e819a07 ImGuiFullscreen: Move texture loading to async tasks
Two threads instead of one, speeds things up a bit.
2025-01-07 12:40:08 +10:00
Stenzek
cae1ddc971 GPU: Ensure batches are flushed before presenting frame
Fixes occasional assertion failing when using the debugger.
2025-01-07 12:28:15 +10:00
Stenzek
dc9cdddd4c Qt: Add zst/xz GPU dumps to file filter 2025-01-06 21:18:13 +10:00
Stenzek
0960160589 System: Don't check for subchannel with GPU dump 2025-01-06 21:17:27 +10:00
Stenzek
1765590a6f Qt: Add 'Disable Window Rounded Corners' option 2025-01-05 16:39:57 +10:00
Stenzek
9f41ef9eac Scripts: Add release commit generation script 2025-01-05 16:00:15 +10:00
Stenzek
5ee069fc63 FullscreenUI: Add option to display PS buttons instead of Xbox 2025-01-05 16:00:15 +10:00
Stenzek
4d6124d41b Platform: Fix AppImage dbus library mismatch 2025-01-05 14:08:22 +10:00
Stenzek
a5d90c0b22 Deps: Bump to SDL2 2.30.11 2025-01-04 21:18:34 +10:00
Stenzek
6043b2331f Platform: Fix incorrect dbus shared library name
Fixes screensaver inhibit on Linux.
2025-01-04 21:14:46 +10:00
Stenzek
886040b257 Qt: Display 'No Image' instead of 0x0 in status 2025-01-04 19:21:47 +10:00
Stenzek
8353a33e89 X11Tools: Fix refresh rate query failing with XLib handle 2025-01-04 18:35:15 +10:00
Stenzek
076f4a6293 Qt: Fix delay in progress dialog opening
Applies to updater, verify, etc.
2025-01-04 16:59:33 +10:00
Stenzek
920f25427e Qt: Simplify Fullscreen UI state tracking
Fixes application closing if the system was shut down while fullscreen.
2025-01-04 16:09:35 +10:00
Stenzek
78ccbc710c Cheats: Fix error while exporting 2025-01-04 12:52:26 +10:00
Anderson Cardoso
548f1da5af Atualização Português do Brasil (#3350) 2025-01-04 12:51:08 +10:00
Stenzek
9054801341 ImGuiManager: Update viewport and display size
Fixes the single frame of incorrect draw size when resizing
the window with the Big Picture UI.
2025-01-03 20:16:38 +10:00
Stenzek
80855090d5 Qt: Rewrite cover loading/generation
This was always wrong, QPixmaps shouldn't be manipulated outside of
the UI thread, and it used to crash in debug builds.

Also uses a placeholder image instead of a black image while covers
are loading/generating.
2025-01-03 20:16:38 +10:00
Stenzek
db14824d61 System: Use task queue for saving states/screenshots/gpudumps
System shutdown no longer needs to block. Gets rid of the slight
hitch when shutting down and saving state with the Big Picture UI.
2025-01-03 20:16:38 +10:00
Stenzek
547601559c Common: Add TaskQueue class 2025-01-03 20:16:37 +10:00
Stenzek
52e6e8ff1e PostProcessing: Compile warning fix 2025-01-03 18:19:12 +10:00
Stenzek
f9bb413a40 Qt: Enable clear button on hotkey search 2025-01-03 15:28:43 +10:00
Stenzek
dda10d3576 Qt: Add search box to hotkey settings 2025-01-03 14:58:50 +10:00
Stenzek
b2c8d25638 GPUBackend: Only display CPU thread blocked messages if queueing 2025-01-03 14:49:53 +10:00
Stenzek
88cd086633 Cheats: Eliminate extra newlines during code editing 2025-01-03 13:36:58 +10:00
Daniel Nylander
e096827df8 Updated Swedish translation (#3349) 2025-01-03 13:36:40 +10:00
Stenzek
e08dda0a0a CPU: Declare state with constinit 2025-01-02 21:42:41 +10:00
Stenzek
87e367076d PostProcessing: Get rid of Timer global 2025-01-02 21:40:01 +10:00
Stenzek
ba15a76d7b ImGuiManager: Pack state in struct 2025-01-02 21:33:53 +10:00
Stenzek
d3fe1dfc2c ImGuiManager: Separate debug and OSD fonts
Don't need to rasterize the former if it's not used, and saves blowing
up the debug window font size if the OSD scale is not 100%.
2025-01-02 21:25:25 +10:00
Stenzek
fc5553a8c7 GTE: Improve reverse transform freecam
Transform the move direction, that way it behaves more FPS-camera like.
2025-01-02 20:56:22 +10:00
Stenzek
90cb266886 Common: Small tidy-up and constexpr-ify GSMatrix4x4 2025-01-02 20:52:19 +10:00
Stenzek
83b4757788 Qt: Controller Test should be disabled while running 2025-01-02 02:11:50 +10:00
Stenzek
08cd649187 InputManager: Fix pointer-bound bind movement
i.e. psmouse

Regression from c4e0e7fade
2025-01-02 02:10:31 +10:00
Stenzek
cd873eb6c1 GTE: Add 'Reverse Transform Order' option to freecam 2025-01-02 02:09:02 +10:00
Stenzek
3a64c5e4b3 FullscreenUI: Improve field alignment in achievements login 2025-01-02 01:07:18 +10:00
Stenzek
b21312867b FullscreenUI: Fix popup sizes for postfx settings 2025-01-02 01:07:11 +10:00
Stenzek
179e2f1999 FullscrenUI: Fix field spacing scaling in game list view 2025-01-02 00:52:40 +10:00
Stenzek
0fdf984b71 GTE: Disable freecam on Android
Freecam is disabled on Android because there's no windowed UI for it.
And because users can't be trusted to not crash games and complain.
2025-01-02 00:38:29 +10:00
Stenzek
e036318559 Qt: Add 'Controller Test' to tools menu 2025-01-02 00:31:15 +10:00
Stenzek
c11468b9f1 Qt: Drop log messages if rate is too high
Prevents the application locking up and memory usage going bananas
if log messages do end up spammed at crazy rates.
2025-01-02 00:14:11 +10:00
Stenzek
37e5e64ddc System: Move state display updates to call sites
Fixes black frames when changing settings with runahead/rewind enabled.
2025-01-01 23:05:08 +10:00
Stenzek
f3b7686457 System: Fix crash with memory save states + renderer switch 2025-01-01 22:55:31 +10:00
Stenzek
5ac5a1d246 Hotkeys: Fix resolution scale with memory save states 2025-01-01 22:02:55 +10:00
Stenzek
1d63648d68 Qt: Forward text input to aux render windows
Fixes text input in freecam window.
2025-01-01 22:02:55 +10:00
Stenzek
dcd439e7d8 GTE: Add 'Free Camera' feature 2025-01-01 22:02:55 +10:00
Stenzek
22202f1607 Common: Fix vector blend32() and dot() on SSE2 2025-01-01 22:02:55 +10:00
Stenzek
d0e1efb1fd Common: Add more GSMatrix ops 2025-01-01 21:28:16 +10:00
Stenzek
f51dda3e66 GPUDevice: Allow this-frame pooled textures when not uploading data
It won't break the render pass.
2025-01-01 19:38:48 +10:00
Stenzek
a08acdb93a System: Improve texture recycling when changing rewind/runahead settings
Fix suprious failures when changing rewind settings when low on VRAM.
2025-01-01 19:33:01 +10:00
Stenzek
8605722cdf GameDB: GTA does not support analog mode 2025-01-01 17:15:19 +10:00
Stenzek
57be62ffd1 FullscreenUI: Remove a couple of untranslated titles 2025-01-01 14:28:05 +10:00
Stenzek
884459d1cf FullscreenUI: Fade alpha change when switching to postfx settings 2025-01-01 14:25:56 +10:00
Stenzek
ffef0c2e38 CPU/CodeCache: Don't compile invalid jumps via block links 2025-01-01 14:10:55 +10:00
Stenzek
d69d25431e VulkanDevice: Hopefully fix init under Vulkan 1.0 drivers 2024-12-31 23:43:38 +10:00
Stenzek
f25302c847 CPU/Recompiler: Actually use fetch ticks for uncached EXP1 2024-12-31 17:29:40 +10:00
Stenzek
34f2600f99 CPU/Recompiler: Fix ICache update codegen on RISCV64 2024-12-31 16:12:19 +10:00
Stenzek
4c08c716c4 CPU/Recompiler: Fix dispatcher crash on RISCV64 2024-12-31 15:33:34 +10:00
Stenzek
a4b359672c Common: Switch fastjmp.cpp asm to tabs
Consistency.
2024-12-31 15:33:17 +10:00
Stenzek
79b0533df2 Common: Fix RISC-V/64 fastjmp buffer size 2024-12-31 15:30:26 +10:00
Stenzek
b76618fdf4 System: Should call PGXP Reset not Initialize() in InternalReset() 2024-12-31 15:24:36 +10:00
Stenzek
1bf076c74f VulkanDevice: Fix crash on shutdown if swapchain creation fails 2024-12-31 15:10:55 +10:00
Stenzek
e0877c1922 System: Add IsUsingPS2BIOS() 2024-12-31 14:58:31 +10:00
Stenzek
69826f2101 FullscreenUI: Fix incorrect section for Deinterlacing Mode 2024-12-31 14:15:42 +10:00
Stenzek
a3645f3173 GameDB: Gokujou Parodius Da! Deluxe Pack 2024-12-31 14:13:49 +10:00
Stenzek
7228f6f1cf System: Don't fail startup if cpuinfo init fails 2024-12-30 18:11:56 +10:00
Stenzek
3c5db39ee4 GPU/SW: Remove polygon size checks from backend
It's already checked before the draw is handed off.
2024-12-30 18:11:52 +10:00
Stenzek
4d4523dc04 GPU: Use same early culling rules for lines as polygons 2024-12-30 18:11:52 +10:00
Stenzek
c5bd4101b3 GPU: Refactor and simplify deinterlacing
Both HW and SW deal with half-height buffers coming in now.
2024-12-30 14:36:17 +10:00
Stenzek
9cd9042563 CMake: Fix RISC-V building with LLVM 2024-12-30 02:58:16 +10:00
Stenzek
4e928d7ce1 Common: Work around LLVM LTO inline asm issue
LLVM bug 61991.
2024-12-30 02:57:22 +10:00
Stenzek
d65ae6ce00 Scripts: Add cross-compiled AppImage generator 2024-12-30 02:09:32 +10:00
Stenzek
401582bb2b PlatformMisc: Load libdbus at runtime
The static library can't link to the ARM binary when cross-compiling.
2024-12-30 01:57:08 +10:00
Stenzek
a08bd43000 CMake: Fix incorrect message for cache line size 2024-12-30 01:57:08 +10:00
Stenzek
156b3f989b Scripts: Add Linux cross-compile deps script 2024-12-30 01:57:07 +10:00
Stenzek
9cba1decad GPU/HW: Compiler warning fix 2024-12-29 22:34:39 +10:00
Stenzek
468c907fd6 Cheats: Compiler warning fix 2024-12-29 22:34:31 +10:00
Stenzek
d4e393f1a8 Common: Fix write overflow with nosimd vector 2024-12-29 22:34:14 +10:00
Stenzek
ab107722f7 Scripts: Add -only-download option to Linux deps 2024-12-29 20:21:34 +10:00
Stenzek
242561debf CPU/Recompiler: Align dispatchers and JIT blocks
A couple of percent difference if we're lucky. Practically probably <1%.
2024-12-29 18:11:58 +10:00
Stenzek
82a843c121 RegTest: Log state and RAM hashes on exit
Useful for checking determinism.
2024-12-29 17:25:55 +10:00
Stenzek
1ed9e609a5 RegTest: Support replaying GPU dumps 2024-12-29 17:25:55 +10:00
Stenzek
b7832e609f GPU/HW: Vectorize flipped sprite handling 2024-12-29 17:25:55 +10:00
Stenzek
1a211e0a21 GPU/HW: Fix mask bit regression from FF8 fix
Fixes overbright polygons appearing in Silent Hill.
2024-12-29 17:25:54 +10:00
Stenzek
0e6ade067c FileSystem: Add error reporting to DeleteDirectory() 2024-12-29 17:25:54 +10:00
Stenzek
5c3abb490d Common: Fix vector sse2_max_u16()
Fixes UV clamping in SSE2 build, e.g. Jumping Flash.
2024-12-29 13:56:10 +10:00
Stenzek
799f5bdf97 GPU: Assume vertex commands are 8-byte aligned 2024-12-28 20:24:22 +10:00
Stenzek
8c807118c0 GPUDevice: End timer on command flush
Fixes incorrect GPU usage readings in OpenGL, D3D11 is still
problematic, at least on AMD.
2024-12-28 20:24:21 +10:00
Stenzek
7bb0c7d1fb InputManager: Fix pointer scale loading 2024-12-28 20:24:21 +10:00
Stenzek
c2589461e9 GPU/HW: Remove extra debug group pop 2024-12-28 20:24:21 +10:00
Stenzek
74fd217afb GPU/HW: Always update/load/save CLUT
We have the headroom with multithreading now, and it prevents issues
saving/loading state in loading screens in some games.
2024-12-28 20:24:21 +10:00
Stenzek
25b0bb752a GPU/HW: Try truncating culled vertices
What is this monstrosity? Final Fantasy VIII relies on X coordinates
being truncated during scanline drawing, with negative coordinates
becoming positive and vice versa. Fortunately the bits that we need
are consistent across the entire polygon, so we can get away with
truncating the vertices. However, we can't do this to all vertices,
because other game's vertices break in various ways. For example,
+1024 becomes -1024, which is a valid vertex position as the ending
coordinate is exclusive. Therefore, 1024 is never truncated, only
1023. Luckily, FF8's vertices get culled as they do not intersect
with the clip rectangle, so we can do this fixup only when culled,
and everything seems happy.
2024-12-28 20:24:21 +10:00
Stenzek
c99625e4c3 GPU: Move vertex culling to GPU thread
i.e. push all primitives through unless they are oversized, which the
GPU will definitely skip.

Needed because of coordinate truncation in Final Fantasy VIII, these
scenes will now render correctly with the software renderer again.
2024-12-28 20:24:09 +10:00
Stenzek
58b0ccf3fc Common: Add 2D vector formatters 2024-12-28 19:59:25 +10:00
Stenzek
69ed6e5e58 Hotkeys: Screenshot should not be present on Android
Since it saves to app-private, users would complain that the app is
using too much data.
2024-12-27 19:39:23 +10:00
Stenzek
2da692b341 CPU/Recompiler: Swap bl{x,r} for b{x,r} on ARM
Not a subroutine call.
2024-12-27 15:02:40 +10:00
Stenzek
2a8cfc7922 CPU/CodeCache: Simplify code LUT addressing
One more instruction on x86/ARM32, no additional instructions on ARM64.

Worth it so that the application doesn't crash if the game jumps to an
invalid PC. Note that the lower 2 bits are truncated, so an unaligned
jump will round down to the closest instruction. Obviously not correct,
but if a game ends up doing this, it's a lost cause anyway.
2024-12-27 15:02:40 +10:00
Stenzek
4e5b4ba071 CPU: Fix AdEL/IBE on instruction fetch
CAUSE and EPC were swapped for the latter.
2024-12-27 15:02:40 +10:00
Stenzek
4b34825afd CPU/CodeCache: Remove InstructionInfo pc field
No longer needed since oldrecs are gone.
2024-12-27 15:02:40 +10:00
Stenzek
ce71b168c3 CPU/CodeCache: Add static to a couple of missing functions 2024-12-27 15:02:40 +10:00
Stenzek
a44dd1882f RegTest: Update CLI help 2024-12-27 15:02:40 +10:00
Anderson Cardoso
7b9664d6f2 Atualização Português do Brasil (#3348)
Atualizado para a última versão.
2024-12-27 15:02:31 +10:00
Stenzek
9921d2074c Achievements: Fix serialization on Linux 2024-12-26 18:00:29 +10:00
Stenzek
5c83bbe5c5 FullscreenUI: Slight tidy-up to achievements login dialog 2024-12-26 18:00:29 +10:00
Stenzek
272aa4f933 ImGuiManager: Add Begin/EndTextInput() 2024-12-26 18:00:29 +10:00
Stenzek
55c5e17fdc GameDB: Driver 2 settings 2024-12-26 18:00:29 +10:00
Stenzek
750dd1cb87 dep/rcheevos: Bump to 3a91a58 2024-12-26 15:00:55 +10:00
Stenzek
fa993849f7 Qt: Update English/Plural strings 2024-12-26 01:58:24 +10:00
Stenzek
6903abba55 CDROM: Adjust missed INT1 sector behaviour
Max Power Racing and C3 Racing are slow with their DMAs out,
and get confused when an additional INT1 comes inbetween reading
the sector header and data.

Fixes these games crashing during loading. 5000 cycles is more in
line with what the real mech would do anyway, it's pretty slow.
2024-12-26 01:55:55 +10:00
Stenzek
0528ce567c Achievement: Fix glitchy fade indicator animation 2024-12-25 23:01:58 +10:00
Stenzek
00eb54cd15 Achievements: Refactor state serialization
Fix load failures, and eliminate the buffer copy.
2024-12-25 22:23:09 +10:00
Stenzek
d360564cef GameList: Fix lock not re-acquired on failure 2024-12-25 21:55:19 +10:00
Stenzek
8c2fe430d8 GPU/TextureCache: Apply 'Dump Replaced Textures' option to backgrounds too 2024-12-25 15:53:53 +10:00
Stenzek
b03127b206 GPU: Move background dumping to HW+GPU thread
And only dump when the mask bit check is not enabled.

The replacements are gated by the mask bit check anyway, so there's
no point dumping anything that can't be replaced.
2024-12-25 15:53:53 +10:00
Stenzek
6f3e9913f5 GPU/HW: Fix VRAM write dumping only first row
Still has race conditions.
2024-12-25 15:53:53 +10:00
Stenzek
dd180f2fd6 System: Fix dump VRAM writes not updating on GPU thread 2024-12-25 15:53:53 +10:00
Stenzek
b33aa31db8 FullscreenUI: Update translation strings
I always forget to do this...
2024-12-25 15:53:46 +10:00
Stenzek
8f6db2c8fa Qt: Add missing icon to System Display 2024-12-25 15:13:50 +10:00
Stenzek
b81c87958f Qt: Fix F3 getting intercepted when game/FSUI active 2024-12-25 15:11:40 +10:00
Stenzek
d010f768c4 FullscreenUI: Fix smooth scrolling in game/state/etc lists 2024-12-25 15:02:09 +10:00
Stenzek
ad7318f5f9 FullscreenUI: Fix spacing in game list 2024-12-25 14:37:26 +10:00
Stenzek
e7ff547f1b GameDB: Street Fighter games
Disable upscaling because they use a stupidly large UV range and
relies on junk texels not being sampled, which happens at 1x.

That and they're 2D anyway.
2024-12-25 14:25:55 +10:00
Stenzek
0565320036 ImGuiFullscreen: Enable smooth scrolling for file/choice selectors 2024-12-24 13:54:23 +10:00
Stenzek
c4e0e7fade InputManager: Fix mouse-mapped axes getting stuck
Regression from f0deab2.
2024-12-24 13:52:04 +10:00
Stenzek
dc18ce2c2a System: Warn if fastmem mode is not optimal 2024-12-24 13:16:37 +10:00
Stenzek
f4265edb2d SmallString: Add append_vformat() 2024-12-24 13:16:12 +10:00
Stenzek
86d78e5eca GPU/TextureCache: Only use shader bilinear for initial pagefill
Make bilinear replacements behave the same as nearest.
2024-12-24 13:05:38 +10:00
Stenzek
33083cfae1 Settings: Add missing bitfield width 2024-12-24 01:21:07 +10:00
Stenzek
00278fa905 PIO: Fix failure to load state with different cart type 2024-12-24 00:24:37 +10:00
Stenzek
b8fa97e1a7 GPU: Fix sprite texture filtering with TC enabled 2024-12-24 00:24:37 +10:00
Stenzek
89f11095bc CPU: GTE completion cycle should be reset/serialized
Yay more determinism breakage...
2024-12-24 00:24:37 +10:00
Stenzek
9f73e690ad CPU: Debug mode flag should be updated on state load 2024-12-24 00:24:36 +10:00
Stenzek
ac05c35292 CPU: Fix DCIC not being cleared on reset
Stops interpreter mode being unintentionally forced after
restarting some games.
2024-12-24 00:24:36 +10:00
Stenzek
18c509a679 CPU/Recompiler: Exit block early on DCIC/BPCM change
Fixes booting Xplorer cartridge with recompiler.
2024-12-24 00:24:36 +10:00
Stenzek
307bd86b72 SPU: Fix determinism loss when loading state where IRQs differ 2024-12-24 00:24:36 +10:00
Anderson Cardoso
2aa466d1c6 Atualização Português do Brasil (#3347)
Atualizado para a última versão.
2024-12-24 00:24:23 +10:00
Stenzek
9a22ac3c70 GPU/HW: Download VRAM when enabling sw-for-readbacks 2024-12-23 17:55:47 +10:00
Stenzek
8e254c4baf GPUBackend: Fix VRAM loss with runahead/rewind 2024-12-23 17:55:33 +10:00
Stenzek
f3f99f7eac FullscreenUI: Support renderer swapping without restart 2024-12-23 14:37:38 +10:00
Stenzek
406cd1b6a1 Qt: Shuffle a couple of graphics options
Save a tiny bit of vertical space.
2024-12-23 14:24:17 +10:00
Stenzek
9e04b0bf55 GPU/TextureCache: Add 'Always Track Uploads' option 2024-12-23 13:52:23 +10:00
Stenzek
a8361f985e GPU: CLUT should not be saved on CPU thread memory state 2024-12-22 16:48:45 +10:00
Stenzek
7f1ebd3767 PageFaultHandler: Warning fix 2024-12-22 16:48:45 +10:00
Stenzek
448009f4ef CPU/CodeCache: Fastmem RAM faults are always writes 2024-12-22 16:48:45 +10:00
Stenzek
515a4d07fb System: Fix pre-frame sleep getting stuck 2024-12-22 16:48:45 +10:00
Stenzek
0b4e302c22 GPU: Implement PGXP for lines 2024-12-22 16:48:45 +10:00
Stenzek
b81287efd2 GPUBackend: Remove duplicate num_vertices 2024-12-22 16:48:45 +10:00
Stenzek
9b62632951 Achievements: Re-add NeedsIdleUpdate()
Forgot I needed this on Android..
2024-12-22 16:48:24 +10:00
Anderson Cardoso
556a53e564 Fix Typo in Russian tr (#3346) 2024-12-22 16:48:00 +10:00
Stenzek
a919fa71aa GameDB: PGXP-CPU for Wipeout games
Improves sprite jitter.
2024-12-21 23:08:09 +10:00
Stenzek
080d30bf0c GPU: Slightly adjust PAL active range
Gets the PAR closer to the expected value of 59/94 with a divider of 4.
2024-12-21 23:05:30 +10:00
Stenzek
ad980a7004 GPU: Fix 480i resolution display in OSD 2024-12-21 22:20:41 +10:00
Stenzek
0aa89ec7b0 System: Fix some GPU settings not updating 2024-12-21 18:29:56 +10:00
Stenzek
9b97bd5924 Packaging: Add scripts to include libc/libstdc++ in AppImage 2024-12-21 18:29:56 +10:00
Stenzek
e1bd5690ac Misc: Slightly reduce include pollution from settings.h 2024-12-21 15:28:27 +10:00
Stenzek
01dfc9ae51 GameDB: PGXP-CPU for Muppet Monster Adventure 2024-12-21 14:54:37 +10:00
Stenzek
62285dcf33 Settings: Split into GPU and main settings
That way the GPU thread copy doesn't need fields it never touches.
2024-12-21 14:53:15 +10:00
Stenzek
6b754e6759 FullscreenUI: Fix CPU/GPU thread race on achievements toggle 2024-12-21 14:40:24 +10:00
Stenzek
26db661a05 GPU: Remove global indirection 2024-12-21 14:35:12 +10:00
Stenzek
c4b0430d5e System: Remove unused SetExpansionROM() 2024-12-19 23:32:15 +10:00
Stenzek
7826c258b0 System: Frame step after runahead
Makes it behave as expected.
2024-12-19 23:32:15 +10:00
Stenzek
2d659fc3eb GPU: Move backend work off CPU thread 2024-12-19 23:32:15 +10:00
Stenzek
831c982f3b System: Rewrite memory save state handling
Makes it more friendly to GPU thread.
2024-12-19 22:42:28 +10:00
Stenzek
6993e6c31f GPU/SW: Fix double draws of polyline vertices 2024-12-19 22:42:02 +10:00
Stenzek
10e2079ee4 CPU/Recompiler: Don't use far code for mtc0 cache check
Redundant for a few instructions.
2024-12-19 18:44:08 +10:00
Stenzek
fe1fa765f7 CPU/Recompiler: Don't back up value to stack in mtc0
Fixes misaligned stack that could crash in log messages.
2024-12-19 18:44:08 +10:00
Stenzek
568667753d CPU/CodeCache: Avoid log calls in faults outside of JIT code
Could be in other functions that are unsafe to call log functions from.
2024-12-19 18:44:08 +10:00
Stenzek
7116a80435 Common: Add RESTRICT macro
Gotta coerce the compiler into generating better code.
2024-12-19 16:50:03 +10:00
Stenzek
31c1cfa650 Achievements: Remove unused NeedsIdleUpdate() 2024-12-19 12:46:59 +10:00
Stenzek
2f5bdc9651 GameDB: Crash Team Racing supports JogCon 2024-12-19 12:43:02 +10:00
Stenzek
7442ec2f19 JogCon: Implement command 0x44 2024-12-19 12:42:01 +10:00
Daniel Nylander
fa2442deaf Updating Swedish translation (#3345)
* Updated Swedish translation
2024-12-19 12:06:06 +10:00
Anderson Cardoso
8df2a2c446 Atualização Português do Brasil (#3344)
Atualizado para última versão
2024-12-17 14:28:15 +10:00
Stenzek
f010d81652 ISOReader: Add XA and raw extraction modes 2024-12-17 14:19:41 +10:00
Stenzek
b68370dff7 Mouse: Move s8 clamp to after subtraction
Stops the mouse from accumulating long distances which are applied
over several frames. Seems to "feel" slightly better.
2024-12-16 01:53:03 +10:00
Stenzek
cc52320dfe FullscreenUI: Update translation string list 2024-12-16 01:30:20 +10:00
Daniel Nylander
4216eef420 Updated Swedish translation (#3343) 2024-12-16 01:29:24 +10:00
Stenzek
585b13fbd9 GameDB: Remove AnalogController from Point Blank 2
Apparently it does not support it. Not that you'd be using anything
other than a lightgun ;)
2024-12-16 01:28:04 +10:00
Stenzek
b634eecd21 System: Allow separate configuration for multi-disc games 2024-12-16 01:22:48 +10:00
Stenzek
23c221be01 GameDB: Fix serial for Dino Crisis (Japan) 2024-12-16 01:20:22 +10:00
Stenzek
edfeffd820 GameDB: Hash for Aquanaut's Holiday 2024-12-16 01:20:10 +10:00
Stenzek
fda10a6978 FullscreenUI: Remove legacy 'Enable Cheats' option
It did nothing.
2024-12-16 01:02:04 +10:00
Stenzek
43af57d735 System: Fix UpdateGTEAspectRatio() during initialization 2024-12-15 22:12:43 +10:00
Stenzek
1f1a664908 InputManager: Add missing call to UpdateHostMouseMode() 2024-12-15 22:12:43 +10:00
Stenzek
6e2223b517 OpenGLDevice: Fix surfaceless context switch 2024-12-15 22:09:21 +10:00
Stenzek
fbb411a946 OpenGLDevice: Blacklist fbfetch on PowerVR as well
Apparently it's broken, and I don't have any devices with this chip
so I can't find a potential workaround anyway.
2024-12-15 22:07:47 +10:00
Stenzek
4e1e07a93c Qt: Shrink BIOS settings page height
Move open/refresh buttons.
2024-12-15 16:09:02 +10:00
Stenzek
9d52e27e16 CPU/Recompiler: Use condition select for ICache updates
Tidy ~4% perf boost.
2024-12-15 16:00:25 +10:00
Stenzek
666fee2df7 GameDB: Enable ICache for Crash 3
Sound effects during the intro can be lost if the CPU runs too fast.
2024-12-15 15:16:53 +10:00
Stenzek
2603ce5976 GameDB: Merge all 8 discs of Tokimeki Memorial 2 2024-12-15 15:09:48 +10:00
Stenzek
03e24637af Qt: Simplify Host::CommitBaseSettingChanges() 2024-12-15 13:00:08 +10:00
Stenzek
d00627b44b GameDB: Alnam no Kiba - Juuzoku Juuni Shinto Densetsu 2024-12-15 12:59:51 +10:00
Stenzek
5e21234966 Qt: Fix deadlock in Game Properties -> Post-Processing 2024-12-15 12:59:30 +10:00
Stenzek
90e9634c19 FullscreenUI: Enable DrawStringListSetting() 2024-12-14 18:07:33 +10:00
Stenzek
c0c2e69b59 CPU/Recompiler: Document ARM32 code size
Yikes, it's huge..
2024-12-14 16:43:29 +10:00
Stenzek
5cbb6b6163 Qt: Purge unused {start,stop}dumpingAudio 2024-12-14 16:00:13 +10:00
Stenzek
e91ae5f1b9 GPU/HW: Only compile page texture shaders if TC is enabled
Knocks about 1/4 off the total pipelines with the default config.
2024-12-14 15:56:46 +10:00
Stenzek
dcaee9b87e Qt: Add ISO Browser to Tools menu 2024-12-14 14:10:07 +10:00
Stenzek
726aa67d1b CPU/CodeCache: Only cache EXP1 blocks up to 0x1F060000
Neither cart type has code mapped above this address.

Saves ~91MB of memory.
2024-12-14 14:10:06 +10:00
Anderson Cardoso
b99fb22522 Atualização Português do Brasil (#3342)
atualizado para a última versão
2024-12-14 13:47:46 +10:00
Stenzek
b832dfbb3a CDROM: Zero out seek start/end after read 2024-12-14 13:47:20 +10:00
Stenzek
c25c0067af CDROM: Handle repeated SeekL to same target
Fixes more lockups in Resident Evil 3.
2024-12-14 13:36:20 +10:00
Stenzek
e683c89770 CPU/Recompiler: Fix ICache updates on ARM32 2024-12-14 01:05:42 +10:00
Stenzek
5687dd22bd PIO: Add basic flash cartridge support 2024-12-13 23:22:57 +10:00
Stenzek
2f6eaa1d43 CPU/Interpreter: Address ICache lines in words
Might help on ARM32, because no unaligned access.

Otherwise, ~23% perf boost in debug builds. But this is pretty
meaningless.
2024-12-13 23:22:57 +10:00
Stenzek
0dbab167a8 GameDB: Disable widescreen in Fear Effect
FMV backgrounds.
2024-12-13 23:22:57 +10:00
Stenzek
ceef778891 GameDB: Disable multitap for Fear Effect games 2024-12-13 18:41:00 +10:00
Stenzek
25ffc5a248 GameDatabase: Warn if multitap enabled on unsupported game
Fear Effect sends a multitap read command, but doesn't know how to
handle it. There's probably others.

Also add a DisableMultitap trait for these games to force it off.
2024-12-13 18:41:00 +10:00
Stenzek
50fbaf90e6 Qt: Add debug menu options for log sinks/timestamps 2024-12-13 18:08:44 +10:00
Stenzek
8f19912c64 GPU/ShaderGen: Use sample instead of load at 1x as well
Consistency. Mali ends up ever-so-slightly faster with sample versus
texel loads, apparently.

Also fixes compile errors when using texture filtering on GLSL ES.
2024-12-13 14:36:21 +10:00
Stenzek
db848d1381 System: Remove redundant GameDB lookup 2024-12-12 17:43:00 +10:00
Stenzek
5577328f35 Controller: Allow !compatsettings to always start in analog mode 2024-12-12 17:42:37 +10:00
Stenzek
99f133223c CPU/Recompiler: Create block links for self-looping blocks
This way invalidation will rewrite the jump back to the compiler.
Otherwise a SMC block can end up looping itself indefinitely.

Might help with Spyro 2/3. I can't seem to make them crash anymore.
2024-12-12 16:28:51 +10:00
Stenzek
2e805d56dd CPU/CodeCache: Always backpatch KSEG2 writes 2024-12-12 16:24:54 +10:00
Stenzek
c3a2156c79 CPU/CodeCache: Fix event kicking for Cached Interpreter 2024-12-12 16:24:19 +10:00
Stenzek
cdcf05a878 CPU/Recompiler: Only truncate block for future writes
If we overwrite an instruction that has already executed, it
should invalidate the block next time.
2024-12-12 16:23:32 +10:00
Stenzek
e507fdcb1f System: Load state before calling OnSystemStarted()
Needed for transitent state cleanup on Android.
2024-12-11 22:04:21 +10:00
Stenzek
d8af8e4a60 GPU/HW: Fix possibly-stale display with MSAA+Show VRAM 2024-12-11 22:04:21 +10:00
Stenzek
9743ce01a0 OpenGLDevice: Support GLES 3.0
Android emulator still doesn't have GLES 3.1...
2024-12-11 22:04:21 +10:00
Stenzek
69947fb907 GPU/TextureCache: Look for replacements outside of subdirectory
i.e. old setups that do not have the `replacements` subdirectory.
2024-12-11 15:02:55 +10:00
Stenzek
d871c17f3f Settings: Set sprite texture filter on reset 2024-12-11 14:54:26 +10:00
Stenzek
5eac1e4800 VulkanDevice: Blacklist FSI on AMD Windows
Yay for random GPU resets, it's fine on NVIDIA.
2024-12-11 12:46:25 +10:00
Stenzek
1edcc8c0ac System: Merge system taints with state taints on load 2024-12-10 20:19:27 +10:00
Stenzek
cc567d9498 Cheats: Fix hash-suffixed files incorrectly loading 2024-12-10 20:19:26 +10:00
Stenzek
e137d3b5c7 Common: Fix rectangle rempty() on ARM32 2024-12-10 16:49:45 +10:00
Stenzek
5767397231 Qt: Remove 'Enable Cheats' from Console Settings
This was moved to Game Properties ages ago.
2024-12-10 13:19:08 +10:00
Stenzek
0bb83f6fd7 OpenGLDevice: Fix inverted cache file lock 2024-12-10 13:17:06 +10:00
Stenzek
1e839224e8 CDROM: Fix physical disc reading without SubQ on Linux 2024-12-10 02:28:02 +10:00
Stenzek
2e6deca76f FileSystem: Don't use POSIX locks on Android
Requires SDK 24, and it's pointless anyway.
2024-12-10 02:26:54 +10:00
Stenzek
b814666134 CPU/Recompiler: Fix ARM32 build (again) 2024-12-10 02:26:45 +10:00
Stenzek
1bea8817f1 Host: Add ConfirmMessageAsync() 2024-12-10 02:26:45 +10:00
Stenzek
42535591bc HTTPDownloader: Log errors on request failure 2024-12-10 02:26:45 +10:00
Stenzek
a1928de4d0 ImGuiOverlays: Pack SaveStateSelectorUI state 2024-12-09 15:35:07 +10:00
Stenzek
8bb013540d GameDB: Remove redundant codes sections 2024-12-09 15:32:31 +10:00
Stenzek
09ba2ed181 GameDB: Remove duplicate code entries 2024-12-09 15:25:48 +10:00
Stenzek
765a46fc88 FullscreenUI: Pack state in struct 2024-12-09 15:02:05 +10:00
Stenzek
53c08c52ed ImGuiFullscreen: Pack state in struct 2024-12-09 15:01:57 +10:00
Stenzek
5d7cb6c5dc System: Move state compression/writing to worker thread
Reduce hitches when saving.
2024-12-09 14:16:55 +10:00
Stenzek
a4af88bc52 GameDB: More PSX.EXE hashes 2024-12-09 13:50:47 +10:00
Stenzek
31d953dac2 System: Prevent memcard blocking resume state save
Because otherwise you end up with a stale/old resume state, which is
arguably worse.
2024-12-09 13:42:41 +10:00
Stenzek
9b0a906297 GameDB: Add more missing hash entries 2024-12-08 19:45:28 +10:00
Stenzek
5bf7227790 CPU/CodeCache: Use code buffer section on Android 2024-12-08 19:44:27 +10:00
Stenzek
1adf36ccb2 Build: Fix out-of-tree CMake scmversion extraction on Windows 2024-12-08 19:44:27 +10:00
Stenzek
b6eb41e2cf Qt: Improve binding widget tooltip 2024-12-08 19:44:27 +10:00
Stenzek
2999f15d7a StringUtil: Add UTF-16 encoding/decoding functions 2024-12-08 19:44:27 +10:00
Stenzek
7f3687de81 Common: Report assertion failure/panic message for Android 2024-12-08 14:19:25 +10:00
Stenzek
3a661a1c3d Cheats: Move file clearing into core
Needed for Android.
2024-12-08 02:58:50 +10:00
Stenzek
d5432da082 Settings: Disable runahead/rewind in Safe Mode 2024-12-08 02:58:50 +10:00
Stenzek
f9155e5ce7 Settings: Fix incorrect data type for rewind slots 2024-12-08 02:58:50 +10:00
Stenzek
5725a0360b GPU: Use A1BGR5 format for SW/HashCache if available 2024-12-06 18:28:09 +10:00
Stenzek
8c5fadafba GPUTexture: Add A1BGR5 format
Needed for GLES, since RGB5A1 + BGRA + REV isn't listed as
a valid format.
2024-12-06 18:28:09 +10:00
Stenzek
dbba8deb4b Packaging: Fix path in pkgbuild/spec 2024-12-06 18:28:09 +10:00
Anderson Cardoso
c3a9ab3cc8 Atualização Português do Brasil (#3341)
Atualizado para a última versão
2024-12-06 18:27:58 +10:00
Stenzek
f0c456893c GPUDevice: Support pre-rotating swap chains 2024-12-06 15:38:51 +10:00
Stenzek
acf04ed67a GPUDevice: Use row-major matrix packing
With column vectors. mul() turns into dot products instead of madds.
2024-12-06 15:10:15 +10:00
Stenzek
e22d67f4aa GSVector: Add 4x4 matrix class 2024-12-06 15:10:15 +10:00
Stenzek
9c327af280 GPUDevice: Typedef auto-recycled texture 2024-12-06 15:10:15 +10:00
Stenzek
52feb1a37d PostProcessing: Improve compile error reporting 2024-12-06 15:10:15 +10:00
Stenzek
c9c4307871 FileSystem: Android build fix 2024-12-06 15:10:15 +10:00
Stenzek
042a2d72f7 Threading: Add IsCallingThread() to ThreadHandle 2024-12-06 15:10:15 +10:00
Stenzek
5c4d95fd51 Settings: Add missing GPU feature disables 2024-12-06 15:07:56 +10:00
Stenzek
6d080c1a3f GPU: Fix additional GL_POP() causing validation errors 2024-12-06 14:51:57 +10:00
Stenzek
3670c131e3 Qt: Hook up extract button in ISO browser 2024-12-05 18:59:32 +10:00
Stenzek
ea632665c1 Qt: Fix possible game settings save error with sliders 2024-12-05 18:57:35 +10:00
Stenzek
0c7636b3c3 System: Add missing safe mode disable messages 2024-12-05 17:04:09 +10:00
Stenzek
541985fb70 Qt: Add ISO Browser 2024-12-05 16:30:21 +10:00
Stenzek
58f5d7e1ba Qt: Fix missing status message on delayed progress show 2024-12-05 16:30:21 +10:00
Stenzek
e9644c7eeb ISOReader: Add file extraction helpers 2024-12-05 16:30:21 +10:00
Víctor "IlDucci
20df4ec14e Spanish (Spain) update 2024/12/03 (#3340)
Translation of latest changes.
2024-12-05 16:30:09 +10:00
Stenzek
fe3b4154b7 PostProcessing: Fix crash on UI open with OpenGL 2024-12-03 22:35:49 +10:00
Stenzek
3ca2579882 Qt: Add additional early SSE4.1 check on Windows
reshadefx uses roundss in std::unordered_map initializers, no other way
to stop this. If it's not reshade, it'll probably be something else.
2024-12-03 19:13:35 +10:00
Stenzek
84a1e209ea OpenGLDevice: Lock pipeline cache on Linux
Prevents multiple processes from trampling on one another.
2024-12-03 17:35:07 +10:00
Stenzek
04e472d088 FileSystem: Add non-blocking option to POSIXLock 2024-12-03 17:29:47 +10:00
Stenzek
d93c713fb7 FileSystem: Make POSIXLock moveable 2024-12-03 17:29:47 +10:00
Stenzek
5b6e3a952c System: Reset code cache on fastmem mode change
Fixes excess backpatching and potential crashes when changing mode.
2024-12-03 17:29:47 +10:00
Stenzek
0a2facfaeb Settings: Don't enable fastmem without recompiler
Don't need to bother allocating memory otherwise.
2024-12-03 16:54:42 +10:00
Stenzek
d3ceda0c5b CPU/CodeCache: Improve block host size heuristics
Codegen is much better these days, especially with NewRec.
2024-12-03 16:54:28 +10:00
Stenzek
9a5ee3aae6 Qt: Fix horizontal scrollbar showing in summary track list 2024-12-03 16:16:38 +10:00
Anderson Cardoso
03eb4a6bf9 Atualização Português do Brasil (#3339) 2024-12-03 14:45:36 +10:00
Stenzek
25063d4018 Achievements: Fix overlay stacking 2024-12-03 14:13:04 +10:00
Stenzek
14ff89d0c0 MetalDevice: Fix incorrect pixel format for RGB5A1 2024-12-03 13:28:19 +10:00
Stenzek
297165d1ee Deps: Fix MacOS build 2024-12-03 13:21:01 +10:00
Stenzek
cbc22a89f7 GPU/HW: Fix TC + SW-For-Readbacks combo 2024-12-02 20:45:02 +10:00
Stenzek
ac79e43cc0 Deps: Bump versions
- Qt to 6.8.1.
- Harfbuzz to 10.1.0.
- libzip to 11.11.2.
2024-12-02 20:45:02 +10:00
Stenzek
3959c83bd4 GPU/TextureCache: Fix split writes not dumping 2024-12-02 20:12:40 +10:00
Stenzek
22edf23269 GPU: Fix parameter logging of some commands 2024-12-02 17:24:18 +10:00
Stenzek
6756c96fa2 CDROM: Improve SeekL -> ReadN timing
See comments - Mech stops at target Data - 2, or SubQ target.
2024-12-02 17:24:16 +10:00
Stenzek
71e1032605 GameDB: Army Men: Sarge's Heroes 2024-12-02 17:24:15 +10:00
Stenzek
2f70d1bd9c CPU: Write trace log to data directory 2024-12-01 23:21:33 +10:00
Stenzek
e9848a6182 Misc: Collapse more niche log channels 2024-12-01 23:21:33 +10:00
Stenzek
9df59713da GPUDevice: Put debug messages/scopes behind conditions
And completely compile them out in Release builds.

Gets Devel close to Release in terms of performance.
2024-12-01 23:21:33 +10:00
Stenzek
0faa9cf650 Build: Add Devel configuration
Gets you debug assertions and logging, while still producing an
optimized executable.
2024-12-01 23:21:33 +10:00
Stenzek
2a7625e67c CI: Add workflow dispatch triggers for all jobs
Useful for running just one platform on a branch.
2024-12-01 23:21:13 +10:00
Stenzek
4aa9857c53 Qt: Fix fallback binding layout not including motors 2024-12-01 21:17:54 +10:00
Stenzek
aff623b772 GameDB: JogCon games 2024-12-01 21:17:54 +10:00
Stenzek
7c627a8c83 Controller: Add JogCon
This is probably wrong, but I have no way of testing it with an actual
force feedback wheel.

PRs welcome to improve it further.
2024-12-01 21:17:54 +10:00
Stenzek
f9c125c1a1 InputManager: Add ForceFeedbackDevice interface 2024-12-01 21:08:52 +10:00
Stenzek
d7d028ac5c GameDB: Recompiler ICache for Resident Evil 3
CD code gets super screwed up and sends multiple commands without
waiting for them to finish.
2024-12-01 18:16:59 +10:00
Stenzek
b87c6dde6c CDROM: More logging tidy-up 2024-12-01 18:15:42 +10:00
Stenzek
4fe3e1147d Controller: Add GetPortDisplayName() that takes pad index 2024-12-01 17:47:55 +10:00
Stenzek
9fc9f4b9e9 Settings: Fix hash cache fields not being compared 2024-12-01 16:53:29 +10:00
Stenzek
00132c6070 AnalogController: Fix more log spam 2024-12-01 14:49:38 +10:00
Stenzek
9c2244f40e Qt: CustomizeWindowHint should be set for no-close-button 2024-12-01 14:39:26 +10:00
Stenzek
42c5f9169f CI: Merge all packaging scripts to one directory 2024-12-01 14:39:26 +10:00
Stenzek
c6746e76f1 CPU/Intepreter: Raise #RI on invalid COP0 move 2024-12-01 14:27:24 +10:00
Stenzek
62414b0c4c CPU/Interpreter: IBE should not set BD/BT
Apparently. Nothing relies on this. :P
2024-12-01 14:27:24 +10:00
Stenzek
67041d217b Qt: Improve shortcuts
- CTRL/+, CTRL/- no longer show in menu for zooming, but still activate.
- CTRL+O will open a new disc/game from file.
- F5 will refresh the game list (i.e. scan for new games).
- F3/CTRL+F will send focus to the game list search box.
- Pressing Enter in the search box will send focus to the first game
  list row.
- ALT+ENTER in the game list will open Game Properties.
2024-12-01 14:27:24 +10:00
Stenzek
145ad2db27 GameList: Fix scanning of ELF files 2024-12-01 13:10:20 +10:00
Stenzek
9dec34c8c0 Settings: Disable texture replacements if TC disabled
Stops replacements being enumerated in the software renderer as well.
2024-11-30 14:42:51 +10:00
Stenzek
f1435dcf67 Settings: Bump maximum hash cache size
Hopefully mobile will be okay with it.. I know Adreno GL
craps out around 8,000 texture objects.
2024-11-30 14:36:07 +10:00
Stenzek
53008eb34a GPU/HW: Allow use of RGB5A1 for texture cache
Reduces bandwidth and storage requirements by 50%.
2024-11-30 14:36:07 +10:00
Stenzek
c6e2235ee2 GPU/HW: Vectorize texture conversion routines
~100% speed up for RGBA8, ~50% for RGB5A1.
2024-11-30 14:36:07 +10:00
Stenzek
fa4dc381ed GPUDevice: Rename RGBA5551 to RGB5A1
And fix the incorrect format for Vulkan.
2024-11-30 14:36:07 +10:00
Stenzek
dfacf9e8db VulkanDevice: Only create swap chain framebuffer without dynamic rendering 2024-11-30 01:09:41 +10:00
Stenzek
ee750b44e3 Settings: Normalize texture replacment option titles 2024-11-30 01:09:41 +10:00
Stenzek
0f51472d64 Misc: Android build fix 2024-11-30 01:09:41 +10:00
Stenzek
b7fff840c8 System: Move thread name init to host
Prevents funky thread names for regtest on Linux.
2024-11-29 21:21:27 +10:00
Stenzek
cbc16bee9e GPU: Display scanout resolution regardless of crop mode 2024-11-29 21:05:01 +10:00
Stenzek
b059cda8d5 Achievements: Pack state in struct 2024-11-29 20:13:37 +10:00
Stenzek
aafc029682 Misc: Un-namespace Timer 2024-11-29 20:13:37 +10:00
Stenzek
ae18db9271 RegTest: Use filename instead of database title 2024-11-29 19:10:21 +10:00
Stenzek
682ba71319 GPU: Fix aspect ratio with Show VRAM enabled 2024-11-29 18:36:32 +10:00
Stenzek
d5b9b54a69 GPU/SW: Vectorize VRAM writes/copies 2024-11-29 18:05:52 +10:00
Stenzek
19eee76aec AnalogController: Reduce log spam 2024-11-29 17:30:53 +10:00
Stenzek
6cbfab6eca MetalDevice: Warning fix 2024-11-29 17:13:21 +10:00
Stenzek
9970944da2 Achievements: Add encryption of login tokens in ini
Super simple key derived from the machine's UUID.

The idea isn't to provide a ton of security, but prevent users from
accidentially exposing their tokens when sharing their ini for debugging
purposes.

The use of the machine UUID is disabled in portable mode for those who
actually move it between computers. Instead, the key is derived from the
username alone, which is trivially computable.
2024-11-29 17:13:21 +10:00
Stenzek
5401dc8d52 Settings: Add EmuFolders::IsRunningInPortableMode() 2024-11-29 17:06:40 +10:00
Stenzek
ff3214b8f7 SmallString: Add span helpers 2024-11-29 17:06:20 +10:00
Stenzek
d3246deb77 ThirdParty: Add aes.cpp 2024-11-29 17:06:06 +10:00
Stenzek
83274c7e3b ThirdParty/SmallVector: Compile fixes 2024-11-29 17:05:18 +10:00
Stenzek
b39f1558ec StringUtil: Add Base64 decode/encode functions 2024-11-29 17:05:02 +10:00
Stenzek
c0b4627c11 StringUtil: Drop old MacOS workaround 2024-11-29 15:25:36 +10:00
Stenzek
bbe6612b25 Common: Add SHA256Digest 2024-11-29 15:20:33 +10:00
Stenzek
da501b9294 StringUtil: Add ParseFixedHexString() 2024-11-29 15:04:25 +10:00
Stenzek
2e31a40dda Qt: Zero spacer size hints in Graphics Settings
Fixes the window size changing depending on which tab is selected.
2024-11-29 14:06:22 +10:00
Stenzek
dac5dd562b HTTPDownloader: Improve error reporting
Give something human-readable when an error occurs.
2024-11-29 14:00:55 +10:00
Stenzek
6d72a48708 Qt: Disable All Enhancements -> Safe Mode in Debug menu 2024-11-29 13:20:50 +10:00
Stenzek
3ed6cc2ba8 GameList: Fix crash loading custom language options 2024-11-29 13:17:07 +10:00
Stenzek
6be242449b AnalogController: Simplify rumble config
And fix some variables not being saved to state, yay determinism issues.
2024-11-29 13:11:25 +10:00
Stenzek
eeee1e691a Cheats: Support importing native format
Compared to only replacing the .cht file.
2024-11-29 13:10:59 +10:00
Stenzek
208e6c4b35 Cheats: Strip whitespace from code names 2024-11-29 12:49:51 +10:00
Anderson Cardoso
c4d4a7a774 Fix Missing Flag (#3338)
* Atualização Português do Brasil

Atualizado para a última versão.

* Flag fix

Added reference for the missing flag Spanish Latin America

* Update Flag

As discussed in discord with @Hipnosis183 told us that is better change to Mexico flag instead for his lang option.
2024-11-29 12:49:33 +10:00
Daniel Nylander
73dc52ac98 Adding Swedish flags to UI (#3337)
* Updated Swedish translation

* Updating Swedish translation

Now I feel happy with it for some time.

* Adding Swedish flags

* Adding Swedish flags from Wikipedia 

Source https://sv.wikipedia.org/wiki/Fil:Sweden_flag_orb_icon.svg

* Final update for Swedish translation
2024-11-29 12:49:16 +10:00
Stenzek
cd216d91db Qt: Re-enable download button on update failure 2024-11-28 01:07:40 +10:00
Anderson Cardoso
2e0825a363 Atualização Português do Brasil (#3336)
Atualizado para a última versão.
2024-11-28 01:05:37 +10:00
Daniel Nylander
b81d6718f4 Updated Swedish translation (#3335)
* Updated Swedish translation

* Updating Swedish translation

Now I feel happy with it for some time.
2024-11-28 01:05:30 +10:00
dreamsyntax
4e43b1ec8c Debugger/MemoryScanner: Add 'Freeze Selected' (#3334) 2024-11-27 18:30:02 +10:00
Stenzek
a879c11c34 Qt: Prevent multiple update download button clicks 2024-11-27 18:28:29 +10:00
Stenzek
97700b85de GPU/HW: Clear ROV depth on fill/copy/write
It wasn't being specified before, whoops.
2024-11-27 17:52:31 +10:00
Stenzek
eb390a9b5d GPU/TextureCache: Specify max hash cache size/memory in config 2024-11-27 17:52:31 +10:00
Stenzek
b28ca2b78a Qt: Improve updater error reporting
And swap from Qt file functions to our own.
2024-11-27 17:52:31 +10:00
Stenzek
57d3aa4850 FileSystem: Add Error parameter to StatFile() 2024-11-27 17:50:43 +10:00
Stenzek
1434507b41 FileSystem: Add span overload for WriteBinaryFile()
And normalize filename -> path parameter names.
2024-11-27 17:50:43 +10:00
Stenzek
b97788a35a PostProcessing/FX: Force native paths for includes 2024-11-27 13:18:11 +10:00
Stenzek
4edae3cdd0 GPU/HW: Depth buffer needs to be a RT in ROV mode 2024-11-27 12:56:01 +10:00
Stenzek
d1b904a1da Qt: Fix game properties crash opening non-DB game 2024-11-27 12:43:15 +10:00
Stenzek
0befbf8021 GPU: Add Uncorrected Borders crop mode
Should behave the same as the old "All Borders" mode.
The pixel aspect ratio WILL BE WRONG.

Also fixes the size of screenshots in internal resolution mode.
2024-11-26 18:00:19 +10:00
Stenzek
be7a20fef2 GPU/TextureCache: Map replacement non-255 alpha to fully transparent
That way if during the scaling process you end up with interpolated
colours, the cutout alpha is preserved.

Ideally we'd blend it, but that tends to create more problems than it
solves on PSX.
2024-11-26 13:08:32 +10:00
Stenzek
5fd79254bd GPU: Fix crash when toggling software renderer 2024-11-26 12:58:12 +10:00
Stenzek
57595c47af GPU/TextureCache: Move replacement cache onto the GPU
And enforce a maximum. Should sort out the upload spam.
2024-11-25 19:37:28 +10:00
Stenzek
4a650fcce2 GPUDevice: Fix VRAM usage calculation for compressed textures 2024-11-25 18:44:35 +10:00
Stenzek
982dccb990 D3D12Device: Clang warning fixes 2024-11-25 16:30:23 +10:00
Stenzek
b180b26728 GPU: Rework "All Borders" cropping to be aspect correct
The "All Borders" crop mode was previously creating an aspect ratio that
was completely incorrect when using modes outside of Auto/4:3. We now
scale the aspect ratio relative to the PAL/NTSC aspect ratio to account
for this, regardless of how much of a border the game configures.

Overscan cropping also produced an incorrect aspect ratio outside of 4:3
mode, resulting in minor horizontal stretching. It is now correct,
however, this results in black borders being added in 16:9 for most
games.

To remove these borders, you have two options:

 - Use the "Stretch to Fill" aspect ratio. This will scale the GTE
   aspect ratio to fill the screen.

 - Use the "Only Overscan Area (Aspect Uncorrected)" crop mode. This
   mode retains the "old" behaviour, resulting in a stretched image.
2024-11-25 16:26:16 +10:00
Stenzek
dec468966c GPU/HW: Fix sprite mode triggering on screen-aligned UVs
Some polygons just end up being perfect. For example, Croc 2
minecart level.
2024-11-25 15:39:45 +10:00
Stenzek
a804801a1b GPU/HW: Support filtering with texture cache 2024-11-25 13:23:39 +10:00
Stenzek
0ae8fcced3 GPU/HW: Fix incorrect sampling at 1x with TC 2024-11-25 13:15:07 +10:00
Stenzek
0076af6974 SPU: Zero out upper ADPCM filters
Also in CD-ROM.
2024-11-25 01:33:11 +10:00
Stenzek
40a1bee9ea CDROM: Fix incorrect clmap in XA-ADPCM decoding
Fixes crunchy audio in GT2: A-Spec.
2024-11-25 01:05:10 +10:00
Stenzek
9fa8fee193 Achievements: Use rc_client for pause throttling 2024-11-24 23:56:16 +10:00
Stenzek
852239ec8a Qt: Add game list language override option 2024-11-24 23:29:29 +10:00
Stenzek
70a4b5c9f2 GameDatabase: Add missing flags 2024-11-24 23:29:29 +10:00
Stenzek
7b230dc4c1 GPU/HW: MSAA samples change needs to recreate pipelines
Otherwise Metal/Vulkan go boom boom.
2024-11-24 23:29:29 +10:00
Stenzek
ae14c8715d Image: Support decompressing BC1-7 2024-11-24 23:29:29 +10:00
Stenzek
8567293103 Util: Add TextureDecompress 2024-11-24 23:29:29 +10:00
Stenzek
7eb1d4e092 GPUDevice: Support compressed textures 2024-11-24 23:29:29 +10:00
Stenzek
24dfd30839 Image: Refactor to a more generic class 2024-11-24 23:29:29 +10:00
Stenzek
3ff1b04576 GPUDevice: Support generating mipmaps 2024-11-24 23:29:28 +10:00
Stenzek
e647192437 GPUDevice: Add compute shader support 2024-11-24 23:29:28 +10:00
Stenzek
affbdfc350 Timer: Fix >1 second sleeps on MacOS 2024-11-24 23:29:28 +10:00
Daniel Nylander
ff010686f8 Updated Swedish translation (#3333) 2024-11-24 21:55:06 +10:00
Stenzek
c970740d12 InputManager: Workaround macro chord trigger issue 2024-11-24 21:54:43 +10:00
Stenzek
e987b56aae Log: Remove unused ISOReader channel 2024-11-23 18:59:10 +10:00
Stenzek
88836c431e GameDB: King's Field I/II (Japan) 2024-11-23 18:59:01 +10:00
Stenzek
5bcf99fc11 CDImage: Merge bin/ecm handling into one class
Means that cuesheets with ECM tracks will now load as expected.
2024-11-23 18:52:46 +10:00
Stenzek
5261cfe8e4 CPU/Recompiler: Tidy up type names
And reduce global namespace pollution.
2024-11-23 18:52:46 +10:00
Stenzek
f67eacc071 CPU: Default to new recompiler/remove old recompiler 2024-11-23 18:52:46 +10:00
Stenzek
d2d06adeeb CPU/NewRec/ARM32: Shifts need to be explicitly masked 2024-11-23 18:52:45 +10:00
Stenzek
5c03e1d940 Misc: Fix alignment errors on ARM32 2024-11-23 18:52:45 +10:00
Stenzek
bb24d406f2 Pad: GCC compile fix 2024-11-23 18:52:45 +10:00
Stenzek
d26fc89aac dep/imgui: RISC-V compile fix 2024-11-23 18:52:45 +10:00
Stenzek
5d8519897d Image: Fix uninitialized read without SIMD 2024-11-23 18:52:45 +10:00
Stenzek
b984f343ae System: Fix audio CD images not showing title 2024-11-23 18:52:45 +10:00
Stenzek
0079f7a285 CDImageCue: Support reading .wav files (WAVE cuesheet files) 2024-11-23 18:52:43 +10:00
Stenzek
e6892e0a54 Common: Fix incorrect condition in PreviousPow2/NextPow2 2024-11-21 12:31:00 +10:00
445 changed files with 47524 additions and 39345 deletions

View File

@@ -2,6 +2,7 @@ name: 🐧 Linux AppImage
on:
workflow_call:
workflow_dispatch:
jobs:
linux-x64-appimage-build:
@@ -14,7 +15,7 @@ jobs:
fetch-depth: 0
- name: Install Packages
run: scripts/appimage/install-packages.sh
run: scripts/packaging/appimage/install-packages.sh
- name: Cache Dependencies
id: cache-deps
@@ -66,7 +67,7 @@ jobs:
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -DCMAKE_PREFIX_PATH="$HOME/deps" -DCMAKE_C_COMPILER=clang-18 -DCMAKE_CXX_COMPILER=clang++-18 -DCMAKE_EXE_LINKER_FLAGS_INIT="-fuse-ld=lld" -DCMAKE_MODULE_LINKER_FLAGS_INIT="-fuse-ld=lld" -DCMAKE_SHARED_LINKER_FLAGS_INIT="-fuse-ld=lld" ..
cmake --build . --parallel
cd ..
scripts/appimage/make-appimage.sh $(realpath .) $(realpath ./build) $HOME/deps DuckStation-x64
scripts/packaging/appimage/make-appimage.sh $(realpath .) $(realpath ./build) $HOME/deps DuckStation-x64
- name: Upload Qt AppImage
uses: actions/upload-artifact@v4.3.3
@@ -85,7 +86,7 @@ jobs:
fetch-depth: 0
- name: Install Packages
run: scripts/appimage/install-packages.sh
run: scripts/packaging/appimage/install-packages.sh
- name: Cache Dependencies
id: cache-deps
@@ -137,7 +138,7 @@ jobs:
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DDISABLE_SSE4=ON -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -DCMAKE_PREFIX_PATH="$HOME/deps" -DCMAKE_C_COMPILER=clang-18 -DCMAKE_CXX_COMPILER=clang++-18 -DCMAKE_EXE_LINKER_FLAGS_INIT="-fuse-ld=lld" -DCMAKE_MODULE_LINKER_FLAGS_INIT="-fuse-ld=lld" -DCMAKE_SHARED_LINKER_FLAGS_INIT="-fuse-ld=lld" ..
cmake --build . --parallel
cd ..
scripts/appimage/make-appimage.sh $(realpath .) $(realpath ./build) $HOME/deps DuckStation-x64-SSE2
scripts/packaging/appimage/make-appimage.sh $(realpath .) $(realpath ./build) $HOME/deps DuckStation-x64-SSE2
- name: Upload Qt AppImage
uses: actions/upload-artifact@v4.3.3

View File

@@ -11,6 +11,7 @@ on:
required: false
type: string
default: "stable"
workflow_dispatch:
jobs:
linux-flatpak-build:
@@ -59,21 +60,21 @@ jobs:
- name: Generate AppStream XML
run: |
scripts/generate-metainfo.sh scripts/flatpak
cat scripts/flatpak/org.duckstation.DuckStation.metainfo.xml
scripts/packaging/generate-metainfo.sh scripts/packaging/flatpak
cat scripts/packaging/flatpak/org.duckstation.DuckStation.metainfo.xml
- name: Validate AppStream XML
run: flatpak-builder-lint appstream scripts/flatpak/org.duckstation.DuckStation.metainfo.xml
run: flatpak-builder-lint appstream scripts/packaging/flatpak/org.duckstation.DuckStation.metainfo.xml
- name: Validate Manifest
run: flatpak-builder-lint manifest scripts/flatpak/org.duckstation.DuckStation.yaml
run: flatpak-builder-lint manifest scripts/packaging/flatpak/org.duckstation.DuckStation.yaml
- name: Build Flatpak
uses: flathub-infra/flatpak-github-actions/flatpak-builder@23796715b3dfa4c86ddf50cf29c3cc8b3c82dca8
with:
bundle: duckstation-x64.flatpak
upload-artifact: false
manifest-path: scripts/flatpak/org.duckstation.DuckStation.yaml
manifest-path: scripts/packaging/flatpak/org.duckstation.DuckStation.yaml
arch: x86_64
build-bundle: true
verbose: true
@@ -81,7 +82,7 @@ jobs:
branch: stable
cache: true
restore-cache: true
cache-key: flatpak-x64-${{ hashFiles('scripts/flatpak/**/*.yaml') }}
cache-key: flatpak-x64-${{ hashFiles('scripts/packaging/flatpak/**/*.yaml') }}
- name: Validate Build
run: |

View File

@@ -2,6 +2,7 @@ name: 🍎 MacOS
on:
workflow_call:
workflow_dispatch:
jobs:
macos-build:
@@ -13,8 +14,8 @@ jobs:
with:
fetch-depth: 0
- name: Use Xcode 15.4
run: sudo xcode-select -s /Applications/Xcode_15.4.app
- name: Use Xcode 16.1
run: sudo xcode-select -s /Applications/Xcode_16.1.app
- name: Install packages
shell: bash

View File

@@ -1,6 +1,7 @@
name: Automated Builds
on:
workflow_dispatch:
pull_request:
paths-ignore:
- '**.md'

View File

@@ -2,6 +2,7 @@ name: 💻 Windows
on:
workflow_call:
workflow_dispatch:
jobs:
windows-x64-build:

View File

@@ -42,10 +42,6 @@ if(LINUX OR BSD)
set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
endif()
# Set _DEBUG macro for Debug builds.
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG")
# Release build optimizations for MSVC.
if(MSVC)
add_definitions("/D_CRT_SECURE_NO_WARNINGS")
@@ -59,14 +55,18 @@ if(MSVC)
# RelWithDebInfo is set to Ob1 instead of Ob2.
string(REPLACE "/Ob1" "/Ob2" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
string(REPLACE "/Ob1" "/Ob2" CMAKE_C_FLAGS_DEVEL "${CMAKE_C_FLAGS_DEVEL}")
string(REPLACE "/Ob1" "/Ob2" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
string(REPLACE "/Ob1" "/Ob2" CMAKE_CXX_FLAGS_DEVEL "${CMAKE_CXX_FLAGS_DEVEL}")
# Disable incremental linking in RelWithDebInfo.
string(REPLACE "/INCREMENTAL" "/INCREMENTAL:NO" CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}")
string(REPLACE "/INCREMENTAL" "/INCREMENTAL:NO" CMAKE_EXE_LINKER_FLAGS_DEVEL "${CMAKE_EXE_LINKER_FLAGS_DEVEL}")
# COMDAT folding/remove unused functions.
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /OPT:REF /OPT:ICF")
set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} /OPT:REF /OPT:ICF")
set(CMAKE_EXE_LINKER_FLAGS_DEVEL "${CMAKE_EXE_LINKER_FLAGS_DEVEL} /OPT:REF /OPT:ICF")
endif()
# Warning disables.

View File

@@ -16,3 +16,17 @@ endif()
if(APPLE)
option(SKIP_POSTPROCESS_BUNDLE "Disable bundle post-processing, including Qt additions" OFF)
endif()
# Set _DEBUG macro for Debug builds.
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG")
# Create the Devel build type based on RelWithDebInfo.
set(CMAKE_C_FLAGS_DEVEL "${CMAKE_C_FLAGS_RELWITHDEBINFO} -D_DEVEL" CACHE STRING "Flags used by the C compiler during DEVEL builds." FORCE)
set(CMAKE_CXX_FLAGS_DEVEL "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -D_DEVEL" CACHE STRING "Flags used by the CXX compiler during DEVEL builds." FORCE)
set(CMAKE_EXE_LINKER_FLAGS_DEVEL "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}" CACHE STRING "Flags used for the linker during DEVEL builds." FORCE)
set(CMAKE_MODULE_LINKER_FLAGS_DEVEL "${CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO}" CACHE STRING "Flags used by the linker during the creation of modules during DEVEL builds." FORCE)
set(CMAKE_SHARED_LINKER_FLAGS_DEVEL "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO}" CACHE STRING "Flags used by the linker during the creation of shared libraries during DEVEL builds." FORCE)
set(CMAKE_STATIC_LINKER_FLAGS_DEVEL "${CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO}" CACHE STRING "Flags used by the linker during the creation of static libraries during DEVEL builds." FORCE)
list(APPEND CMAKE_CONFIGURATION_TYPES "Devel")
mark_as_advanced(CMAKE_C_FLAGS_DEVEL CMAKE_CXX_FLAGS_DEVEL CMAKE_EXE_LINKER_FLAGS_DEVEL CMAKE_MODULE_LINKER_FLAGS_DEVEL CMAKE_SHARED_LINKER_FLAGS_DEVEL CMAKE_STATIC_LINKER_FLAGS_DEVEL)

View File

@@ -92,17 +92,22 @@ function(detect_architecture)
elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "riscv64")
message(STATUS "Building RISC-V 64 binaries.")
set(CPU_ARCH_RISCV64 TRUE PARENT_SCOPE)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -finline-atomics" PARENT_SCOPE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -finline-atomics" PARENT_SCOPE)
# Still need this, apparently.
link_libraries("-latomic")
# Don't want function calls for atomics.
if(COMPILER_GCC)
set(EXTRA_CFLAGS "${EXTRA_CFLAGS} -finline-atomics")
# Still need this, apparently.
link_libraries("-latomic")
endif()
if(NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
# Frame pointers generate an annoying amount of code on leaf functions.
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fomit-frame-pointer" PARENT_SCOPE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fomit-frame-pointer" PARENT_SCOPE)
set(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fomit-frame-pointer")
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}" PARENT_SCOPE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS}" PARENT_SCOPE)
else()
message(FATAL_ERROR "Unknown system processor: ${CMAKE_SYSTEM_PROCESSOR}")
endif()
@@ -121,8 +126,8 @@ function(detect_page_size)
return()
endif()
if(HOST_MIN_PAGE_SIZE OR HOST_MAX_PAGE_SIZE)
if(NOT HOST_MIN_PAGE_SIZE OR NOT HOST_MAX_PAGE_SIZE)
if(DEFINED HOST_MIN_PAGE_SIZE OR DEFINED HOST_MAX_PAGE_SIZE)
if(NOT DEFINED HOST_MIN_PAGE_SIZE OR NOT DEFINED HOST_MAX_PAGE_SIZE)
message(FATAL_ERROR "Both HOST_MIN_PAGE_SIZE and HOST_MAX_PAGE_SIZE must be defined.")
endif()
return()
@@ -172,7 +177,7 @@ function(detect_cache_line_size)
endif()
if(CMAKE_CROSSCOMPILING)
message(WARNING "Cross-compiling and can't determine page size, assuming default.")
message(WARNING "Cross-compiling and can't determine cache line size, assuming default.")
return()
endif()

File diff suppressed because it is too large Load Diff

View File

Before

Width:  |  Height:  |  Size: 241 B

After

Width:  |  Height:  |  Size: 241 B

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 9 6" width="900" height="600"><rect fill="#fff" width="9" height="3"/><rect fill="#d52b1e" y="3" width="9" height="3"/><rect fill="#0039a6" y="2" width="9" height="2"/></svg>

After

Width:  |  Height:  |  Size: 266 B

View File

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="800" viewBox="0 -30000 90000 60000">
<title>Flag of Turkey</title>
<path fill="#e30a17" d="m0-30000h90000v60000H0z"/>
<path fill="#fff" d="m41750 0 13568-4408-8386 11541V-7133l8386 11541zm925 8021a15000 15000 0 1 1 0-16042 12000 12000 0 1 0 0 16042z"/>
</svg>

After

Width:  |  Height:  |  Size: 323 B

View File

@@ -4,7 +4,7 @@ Czech.svg: https://commons.wikimedia.org/wiki/Flag_of_the_Czech_Republic.svg
Danish.svg: https://commons.wikimedia.org/wiki/Flag_of_Denmark.svg
Dutch.svg: https://commons.wikimedia.org/wiki/Flag_of_the_Netherlands.svg
English.svg: https://commons.wikimedia.org/wiki/Flag_of_the_United_Kingdom_(1-2).svg
Finish.svg: https://commons.wikimedia.org/wiki/File:Flag_of_Finland.svg
Finnish.svg: https://commons.wikimedia.org/wiki/File:Flag_of_Finland.svg
French.svg: https://commons.wikimedia.org/wiki/File:Flag_of_France.svg
German.svg: https://commons.wikimedia.org/wiki/File:Flag_of_Germany.svg
Greek.svg: https://commons.wikimedia.org/wiki/Flag_of_Greece.svg
@@ -17,4 +17,5 @@ Polish.svg: https://commons.wikimedia.org/wiki/Flag_of_Poland.svg
Portuguese.svg: https://commons.wikimedia.org/wiki/File:Flag_of_Portugal.svg
Spanish.svg: https://commons.wikimedia.org/wiki/File:Flag_of_Spain.svg
Swedish.svg: https://commons.wikimedia.org/wiki/File:Flag_of_Sweden.svg
Russian.svg: https://commons.wikimedia.org/wiki/File:Flag_of_Russia.svg
Other.svg: https://en.wikipedia.org/wiki/File:Flag_with_question_mark.svg

View File

@@ -1,124 +0,0 @@
#version 460 core
// EPX.glc
// Copyright 2020 Morgan McGuire & Mara Gagiu,
// provided under the Open Source MIT license https://opensource.org/licenses/MIT
// Implementation of Eric Johnston and Andrea Mazzoleni's
// EPX aka Scale2X algorithm based on https://www.scale2x.it/algorithm
#define ABGR8 uint
UNIFORM_BLOCK_LAYOUT uniform UBOBlock {
ivec2 src_size;
ivec2 dst_size;
};
TEXTURE_LAYOUT(0) uniform sampler2D samp0;
IMAGE_LAYOUT(0, rgba8) uniform restrict writeonly image2D dst_image;
ABGR8 src(int x, int y) {
return packUnorm4x8(texelFetch(samp0, ivec2(x, y), 0));
}
void dst(int x, int y, ABGR8 value) {
imageStore(dst_image, ivec2(x, y), unpackUnorm4x8(value));
}
uint luma(ABGR8 C) {
uint alpha = (C & 0xFF000000u) >> 24;
return (((C & 0x00FF0000u) >> 16) + ((C & 0x0000FF00u) >> 8) + (C & 0x000000FFu) + 1u) * (256u - alpha);
}
bool all_eq2(ABGR8 B, ABGR8 A0, ABGR8 A1) {
return ((B ^ A0) | (B ^ A1)) == 0u;
}
bool all_eq3(ABGR8 B, ABGR8 A0, ABGR8 A1, ABGR8 A2) {
return ((B ^ A0) | (B ^ A1) | (B ^ A2)) == 0u;
}
bool all_eq4(ABGR8 B, ABGR8 A0, ABGR8 A1, ABGR8 A2, ABGR8 A3) {
return ((B ^ A0) | (B ^ A1) | (B ^ A2) | (B ^ A3)) == 0u;
}
bool any_eq3(ABGR8 B, ABGR8 A0, ABGR8 A1, ABGR8 A2) {
return B == A0 || B == A1 || B == A2;
}
bool none_eq2(ABGR8 B, ABGR8 A0, ABGR8 A1) {
return (B != A0) && (B != A1);
}
bool none_eq4(ABGR8 B, ABGR8 A0, ABGR8 A1, ABGR8 A2, ABGR8 A3) {
return B != A0 && B != A1 && B != A2 && B != A3;
}
layout(local_size_x = 8, local_size_y = 8) in;
void main () {
// EPX first falls back to Nearest Neighbour
int srcX = int(gl_GlobalInvocationID.x);
int srcY = int(gl_GlobalInvocationID.y);
if (srcX >= src_size.x || srcY >= src_size.y)
return;
ABGR8 A = src(srcX - 1, srcY - 1), B = src(srcX, srcY - 1), C = src(srcX + 1, srcY - 1);
ABGR8 D = src(srcX - 1, srcY + 0), E = src(srcX, srcY + 0), F = src(srcX + 1, srcY + 0);
ABGR8 G = src(srcX - 1, srcY + 1), H = src(srcX, srcY + 1), I = src(srcX + 1, srcY + 1);
ABGR8 J = E, K = E, L = E, M = E;
if (((A ^ E) | (B ^ E) | (C ^ E) | (D ^ E) | (F ^ E) | (G ^ E) | (H ^ E) | (I ^ E)) != 0u) {
ABGR8 P = src(srcX, srcY - 2), S = src(srcX, srcY + 2);
ABGR8 Q = src(srcX - 2, srcY), R = src(srcX + 2, srcY);
ABGR8 Bl = luma(B), Dl = luma(D), El = luma(E), Fl = luma(F), Hl = luma(H);
// 1:1 slope rules
if ((D == B && D != H && D != F) && (El >= Dl || E == A) && any_eq3(E, A, C, G) && ((El < Dl) || A != D || E != P || E != Q)) J = D;
if ((B == F && B != D && B != H) && (El >= Bl || E == C) && any_eq3(E, A, C, I) && ((El < Bl) || C != B || E != P || E != R)) K = B;
if ((H == D && H != F && H != B) && (El >= Hl || E == G) && any_eq3(E, A, G, I) && ((El < Hl) || G != H || E != S || E != Q)) L = H;
if ((F == H && F != B && F != D) && (El >= Fl || E == I) && any_eq3(E, C, G, I) && ((El < Fl) || I != H || E != R || E != S)) M = F;
// Intersection rules
if ((E != F && all_eq4(E, C, I, D, Q) && all_eq2(F, B, H)) && (F != src(srcX + 3, srcY))) K = M = F;
if ((E != D && all_eq4(E, A, G, F, R) && all_eq2(D, B, H)) && (D != src(srcX - 3, srcY))) J = L = D;
if ((E != H && all_eq4(E, G, I, B, P) && all_eq2(H, D, F)) && (H != src(srcX, srcY + 3))) L = M = H;
if ((E != B && all_eq4(E, A, C, H, S) && all_eq2(B, D, F)) && (B != src(srcX, srcY - 3))) J = K = B;
if (Bl < El && all_eq4(E, G, H, I, S) && none_eq4(E, A, D, C, F)) J = K = B;
if (Hl < El && all_eq4(E, A, B, C, P) && none_eq4(E, D, G, I, F)) L = M = H;
if (Fl < El && all_eq4(E, A, D, G, Q) && none_eq4(E, B, C, I, H)) K = M = F;
if (Dl < El && all_eq4(E, C, F, I, R) && none_eq4(E, B, A, G, H)) J = L = D;
// 2:1 slope rules
if (H != B) {
if (H != A && H != E && H != C) {
if (all_eq3(H, G, F, R) && none_eq2(H, D, src(srcX + 2, srcY - 1))) L = M;
if (all_eq3(H, I, D, Q) && none_eq2(H, F, src(srcX - 2, srcY - 1))) M = L;
}
if (B != I && B != G && B != E) {
if (all_eq3(B, A, F, R) && none_eq2(B, D, src(srcX + 2, srcY + 1))) J = K;
if (all_eq3(B, C, D, Q) && none_eq2(B, F, src(srcX - 2, srcY + 1))) K = J;
}
} // H !== B
if (F != D) {
if (D != I && D != E && D != C) {
if (all_eq3(D, A, H, S) && none_eq2(D, B, src(srcX + 1, srcY + 2))) J = L;
if (all_eq3(D, G, B, P) && none_eq2(D, H, src(srcX + 1, srcY - 2))) L = J;
}
if (F != E && F != A && F != G) {
if (all_eq3(F, C, H, S) && none_eq2(F, B, src(srcX - 1, srcY + 2))) K = M;
if (all_eq3(F, I, B, P) && none_eq2(F, H, src(srcX - 1, srcY - 2))) M = K;
}
} // F !== D
} // not constant
// Write four pixels at once
dst(srcX * 2, srcY * 2, J);
dst(srcX * 2 + 1, srcY * 2, K);
dst(srcX * 2, srcY * 2 + 1, L);
dst(srcX * 2 + 1, srcY * 2 + 1, M);
}

View File

@@ -1,55 +0,0 @@
#version 460 core
// EPX.glc
// Copyright 2020 Morgan McGuire & Mara Gagiu,
// provided under the Open Source MIT license https://opensource.org/licenses/MIT
// Implementation of Eric Johnston and Andrea Mazzoleni's
// EPX aka Scale2X algorithm based on https://www.scale2x.it/algorithm
#define ABGR8 uint
UNIFORM_BLOCK_LAYOUT uniform UBOBlock {
ivec2 src_size;
ivec2 dst_size;
};
TEXTURE_LAYOUT(0) uniform sampler2D samp0;
IMAGE_LAYOUT(0, rgba8) uniform restrict writeonly image2D dst_image;
ABGR8 src(int x, int y) {
return packUnorm4x8(texelFetch(samp0, ivec2(x, y), 0));
}
void dst(int x, int y, ABGR8 value) {
imageStore(dst_image, ivec2(x, y), unpackUnorm4x8(value));
}
layout(local_size_x = 8, local_size_y = 8) in;
void main () {
// EPX first falls back to Nearest Neighbour
int srcX = int(gl_GlobalInvocationID.x);
int srcY = int(gl_GlobalInvocationID.y);
if (srcX >= src_size.x || srcY >= src_size.y)
return;
ABGR8 E = src(srcX, srcY);
ABGR8 J = E, K = E, L = E, M = E;
ABGR8 B = src(srcX + 0, srcY - 1);
ABGR8 D = src(srcX - 1, srcY + 0);
ABGR8 F = src(srcX + 1, srcY + 0);
ABGR8 H = src(srcX + 0, srcY + 1);
if (D == B && B != F && D != H) J = D;
if (B == F && D != F && H != F) K = F;
if (H == D && F != D && B != D) L = D;
if (H == F && D != H && B != F) M = F;
// Write four pixels at once
dst(srcX * 2, srcY * 2, J);
dst(srcX * 2 + 1, srcY * 2, K);
dst(srcX * 2, srcY * 2 + 1, L);
dst(srcX * 2 + 1, srcY * 2 + 1, M);
}

View File

@@ -1,248 +0,0 @@
#version 460 core
layout(location = 0) in VertexData {
vec2 v_tex0;
};
layout(location = 0) out vec4 dest;
TEXTURE_LAYOUT(0) uniform sampler2D samp0;
vec4 SrcGet(vec2 uv)
{
return texelFetch(samp0, ivec2(uv), 0);
}
// XBR.pix
// Copyright 2020 Morgan McGuire & Mara Gagiu,
// provided under the Open Source MIT license https://opensource.org/licenses/MIT
#define XBR_Y_WEIGHT 48.0
#define XBR_EQ_THRESHOLD 15.0
#define XBR_LV1_COEFFICIENT 0.5
#define XBR_LV2_COEFFICIENT 2.0
// END PARAMETERS //
// XBR GLSL implementation source:
// https://github.com/libretro/glsl-shaders/blob/master/xbr/shaders/xbr-lv2.glsl
/*
Hyllian's xBR-lv2 Shader
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Incorporates some of the ideas from SABR shader. Thanks to Joshua Street.
*/
// Uncomment just one of the three params below to choose the corner detection
#define CORNER_A
//#define CORNER_B
//#define CORNER_C
//#define CORNER_D
#ifndef CORNER_A
#define SMOOTH_TIPS
#endif
#define XBR_SCALE 2.0
#define lv2_cf XBR_LV2_COEFFICIENT
//=================================================================================
// XBR Helper Functions
//=================================================================================
const float coef = 2.0;
const vec3 rgbw = vec3(14.352, 28.176, 5.472);
const vec4 eq_threshold = vec4(15.0, 15.0, 15.0, 15.0);
const vec4 delta = vec4(1.0/XBR_SCALE, 1.0/XBR_SCALE, 1.0/XBR_SCALE, 1.0/XBR_SCALE);
const vec4 delta_l = vec4(0.5/XBR_SCALE, 1.0/XBR_SCALE, 0.5/XBR_SCALE, 1.0/XBR_SCALE);
const vec4 delta_u = delta_l.yxwz;
const vec4 Ao = vec4( 1.0, -1.0, -1.0, 1.0 );
const vec4 Bo = vec4( 1.0, 1.0, -1.0,-1.0 );
const vec4 Co = vec4( 1.5, 0.5, -0.5, 0.5 );
const vec4 Ax = vec4( 1.0, -1.0, -1.0, 1.0 );
const vec4 Bx = vec4( 0.5, 2.0, -0.5,-2.0 );
const vec4 Cx = vec4( 1.0, 1.0, -0.5, 0.0 );
const vec4 Ay = vec4( 1.0, -1.0, -1.0, 1.0 );
const vec4 By = vec4( 2.0, 0.5, -2.0,-0.5 );
const vec4 Cy = vec4( 2.0, 0.0, -1.0, 0.5 );
const vec4 Ci = vec4(0.25, 0.25, 0.25, 0.25);
// Difference between vector components.
vec4 df(vec4 A, vec4 B)
{
return vec4(abs(A-B));
}
// Compare two vectors and return their components are different.
vec4 diff(vec4 A, vec4 B)
{
return vec4(notEqual(A, B));
}
// Determine if two vector components are equal based on a threshold.
vec4 eq(vec4 A, vec4 B)
{
return (step(df(A, B), vec4(XBR_EQ_THRESHOLD)));
}
// Determine if two vector components are NOT equal based on a threshold.
vec4 neq(vec4 A, vec4 B)
{
return (vec4(1.0, 1.0, 1.0, 1.0) - eq(A, B));
}
// Weighted distance.
vec4 wd(vec4 a, vec4 b, vec4 c, vec4 d, vec4 e, vec4 f, vec4 g, vec4 h)
{
return (df(a,b) + df(a,c) + df(d,e) + df(d,f) + 4.0*df(g,h));
}
float c_df(vec3 c1, vec3 c2)
{
vec3 df = abs(c1 - c2);
return df.r + df.g + df.b;
}
vec4 XBR()
{
vec4 proxy_dest = vec4(0, 0, 0, 1);
ivec2 tex_fetch_coords = ivec2(gl_FragCoord.xy / 2.0);
ivec2 tex_coords = ivec2(gl_FragCoord.xy);
vec4 edri, edr, edr_l, edr_u, px; // px = pixel, edr = edge detection rule
vec4 irlv0, irlv1, irlv2l, irlv2u, block_3d;
vec4 fx, fx_l, fx_u; // inequations of straight lines.
vec2 fp = fract(gl_FragCoord.xy / 2.0);
vec3 A1 = SrcGet(tex_fetch_coords + ivec2(-1, -2)).xyz;
vec3 B1 = SrcGet(tex_fetch_coords + ivec2( 0, -2)).xyz;
vec3 C1 = SrcGet(tex_fetch_coords + ivec2(+1, -2)).xyz;
vec3 A = SrcGet(tex_fetch_coords + ivec2(-1, -1)).xyz;
vec3 B = SrcGet(tex_fetch_coords + ivec2( 0, -1)).xyz;
vec3 C = SrcGet(tex_fetch_coords + ivec2(+1, -1)).xyz;
vec3 D = SrcGet(tex_fetch_coords + ivec2(-1, 0)).xyz;
vec4 Eo = SrcGet(tex_fetch_coords);
vec3 E = Eo.xyz;
vec3 F = SrcGet(tex_fetch_coords + ivec2(+1, 0)).xyz;
vec3 G = SrcGet(tex_fetch_coords + ivec2(-1, +1)).xyz;
vec3 H = SrcGet(tex_fetch_coords + ivec2( 0, +1)).xyz;
vec3 I = SrcGet(tex_fetch_coords + ivec2(+1, +1)).xyz;
vec3 G5 = SrcGet(tex_fetch_coords + ivec2(-1, +2)).xyz;
vec3 H5 = SrcGet(tex_fetch_coords + ivec2( 0, +2) ).xyz;
vec3 I5 = SrcGet(tex_fetch_coords + ivec2(+1, +2)).xyz;
vec3 A0 = SrcGet(tex_fetch_coords + ivec2(-2, -1)).xyz;
vec3 D0 = SrcGet(tex_fetch_coords + ivec2(-2, 0)).xyz;
vec3 G0 = SrcGet(tex_fetch_coords + ivec2(-2, +1)).xyz;
vec3 C4 = SrcGet(tex_fetch_coords + ivec2(+2, -1)).xyz;
vec3 F4 = SrcGet(tex_fetch_coords + ivec2(+2, 0)).xyz;
vec3 I4 = SrcGet(tex_fetch_coords + ivec2(+2, +1)).xyz;
vec4 b = vec4(dot(B ,rgbw), dot(D ,rgbw), dot(H ,rgbw), dot(F ,rgbw));
vec4 c = vec4(dot(C ,rgbw), dot(A ,rgbw), dot(G ,rgbw), dot(I ,rgbw));
vec4 d = b.yzwx;
vec4 e = vec4(dot(E,rgbw));
vec4 f = b.wxyz;
vec4 g = c.zwxy;
vec4 h = b.zwxy;
vec4 i = c.wxyz;
vec4 i4 = vec4(dot(I4,rgbw), dot(C1,rgbw), dot(A0,rgbw), dot(G5,rgbw));
vec4 i5 = vec4(dot(I5,rgbw), dot(C4,rgbw), dot(A1,rgbw), dot(G0,rgbw));
vec4 h5 = vec4(dot(H5,rgbw), dot(F4,rgbw), dot(B1,rgbw), dot(D0,rgbw));
vec4 f4 = h5.yzwx;
// These inequations define the line below which interpolation occurs.
fx = (Ao*fp.y+Bo*fp.x);
fx_l = (Ax*fp.y+Bx*fp.x);
fx_u = (Ay*fp.y+By*fp.x);
irlv1 = irlv0 = diff(e,f) * diff(e,h);
#ifdef CORNER_B
// E1/K case (X odd, Y even)
irlv1 = (irlv0 * ( neq(f,b) * neq(h,d) + eq(e,i) * neq(f,i4) * neq(h,i5) + eq(e,g) + eq(e,c) ) );
#endif
#ifdef CORNER_D
// E3/M case (X odd, Y odd)
vec4 c1 = i4.yzwx;
vec4 g0 = i5.wxyz;
irlv1 = (irlv0 * ( neq(f,b) * neq(h,d) + eq(e,i) * neq(f,i4) * neq(h,i5) + eq(e,g) + eq(e,c) ) * (diff(f,f4) * diff(f,i) + diff(h,h5) * diff(h,i) + diff(h,g) + diff(f,c) + eq(b,c1) * eq(d,g0)));
#endif
#ifdef CORNER_C
irlv1 = (irlv0 * ( neq(f,b) * neq(f,c) + neq(h,d) * neq(h,g) + eq(e,i) * (neq(f,f4) * neq(f,i4) + neq(h,h5) * neq(h,i5)) + eq(e,g) + eq(e,c)) );
#endif
irlv2l = diff(e,g) * diff(d,g);
irlv2u = diff(e,c) * diff(b,c);
vec4 fx45i = clamp((fx + delta -Co - Ci)/(2.0*delta ), 0.0, 1.0);
vec4 fx45 = clamp((fx + delta -Co )/(2.0*delta ), 0.0, 1.0);
vec4 fx30 = clamp((fx_l + delta_l -Cx )/(2.0*delta_l), 0.0, 1.0);
vec4 fx60 = clamp((fx_u + delta_u -Cy )/(2.0*delta_u), 0.0, 1.0);
vec4 wd1 = wd( e, c, g, i, h5, f4, h, f);
vec4 wd2 = wd( h, d, i5, f, i4, b, e, i);
edri = step(wd1, wd2) * irlv0;
edr = step(wd1 + vec4(0.1, 0.1, 0.1, 0.1), wd2) * step(vec4(0.5, 0.5, 0.5, 0.5), irlv1);
edr_l = step( lv2_cf*df(f,g), df(h,c) ) * irlv2l * edr;
edr_u = step( lv2_cf*df(h,c), df(f,g) ) * irlv2u * edr;
fx45 = edr * fx45;
fx30 = edr_l * fx30;
fx60 = edr_u * fx60;
fx45i = edri * fx45i;
px = step(df(e,f), df(e,h));
#ifdef SMOOTH_TIPS
//vec4 maximos = max(max(fx30, fx60), max(fx45, fx45i));
#endif
#ifndef SMOOTH_TIPS
vec4 maximos = max(max(fx30, fx60), fx45);
#endif
vec3 res1 = E;
res1 = mix(res1, mix(H, F, px.x), maximos.x);
res1 = mix(res1, mix(B, D, px.z), maximos.z);
vec3 res2 = E;
res2 = mix(res2, mix(F, B, px.y), maximos.y);
res2 = mix(res2, mix(D, H, px.w), maximos.w);
vec3 res = mix(res1, res2, step(c_df(E, res1), c_df(E, res2)));
proxy_dest.rgb = res;
proxy_dest.a = Eo.a;
return proxy_dest;
}
void main () {
dest = XBR();
}

View File

@@ -1,14 +0,0 @@
#version 460 core
layout(location = 0) out VertexData {
vec2 v_tex0;
};
void main()
{
v_tex0 = vec2(float((gl_VertexIndex << 1) & 2), float(gl_VertexIndex & 2u));
gl_Position = vec4(v_tex0 * vec2(2.0f, -2.0f) + vec2(-1.0f, 1.0f), 0.0f, 1.0f);
#if API_OPENGL || API_OPENGL_ES || API_VULKAN
gl_Position.y = -gl_Position.y;
#endif
}

View File

@@ -2563,6 +2563,31 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
</pre>
<h3>Texture Decompression Routines</h3>
<pre>
Copyright (C) 2009 Benjamin Dobell, Glass Echidna
Copyright (C) 2012 - 2022, Matthäus G. "Anteru" Chajdas (https://anteru.net)
Copyright (C) 2020 Richard Geldreich, Jr.
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
</pre>
Some shaders provided with the application are sourced from:
<ul>
<li><a href="https://github.com/Matsilagi/RSRetroArch/">https://github.com/Matsilagi/RSRetroArch/</a></li>

View File

@@ -230,7 +230,7 @@ STBSP__PUBLICDEC void STB_SPRINTF_DECORATE(set_separators)(char comma, char peri
#define stbsp__uint16 unsigned short
#ifndef stbsp__uintptr
#if defined(__ppc64__) || defined(__powerpc64__) || defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64) || defined(__s390x__)
#if defined(__ppc64__) || defined(__powerpc64__) || defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64) || defined(__s390x__) || (defined(__riscv) && __riscv_xlen == 64)
#define stbsp__uintptr stbsp__uint64
#else
#define stbsp__uintptr stbsp__uint32

View File

@@ -82,4 +82,9 @@
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="$(Configuration.Contains(Devel))">
<ClCompile>
<PreprocessorDefinitions>_DEVEL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
</Project>

View File

@@ -57,6 +57,14 @@
<Configuration>Release-Clang</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Devel-Clang|ARM64">
<Configuration>Devel-Clang</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Devel-Clang|x64">
<Configuration>Devel-Clang</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">

View File

@@ -93,6 +93,7 @@ enum {
RC_CONSOLE_NINTENDO_DSI = 78,
RC_CONSOLE_TI83 = 79,
RC_CONSOLE_UZEBOX = 80,
RC_CONSOLE_FAMICOM_DISK_SYSTEM = 81,
RC_CONSOLE_HUBS = 100,
RC_CONSOLE_EVENTS = 101,

View File

@@ -46,7 +46,6 @@ typedef struct rc_runtime_trigger_t {
rc_memref_t* invalid_memref;
uint8_t md5[16];
int32_t serialized_size;
uint8_t owns_memrefs;
}
rc_runtime_trigger_t;
@@ -58,16 +57,13 @@ typedef struct rc_runtime_lboard_t {
rc_memref_t* invalid_memref;
uint8_t md5[16];
uint32_t serialized_size;
uint8_t owns_memrefs;
}
rc_runtime_lboard_t;
typedef struct rc_runtime_richpresence_t {
rc_richpresence_t* richpresence;
void* buffer;
struct rc_runtime_richpresence_t* previous;
uint8_t md5[16];
uint8_t owns_memrefs;
}
rc_runtime_richpresence_t;
@@ -82,11 +78,7 @@ typedef struct rc_runtime_t {
rc_runtime_richpresence_t* richpresence;
rc_memref_t* memrefs;
rc_memref_t** next_memref;
rc_value_t* variables;
rc_value_t** next_variable;
struct rc_memrefs_t* memrefs;
uint8_t owns_self;
}

View File

@@ -29,7 +29,7 @@ typedef struct rc_value_t rc_value_t;
* num_bytes is greater than 1, the value is read in little-endian from
* memory.
*/
typedef uint32_t(RC_CCONV *rc_peek_t)(uint32_t address, uint32_t num_bytes, void* ud);
typedef uint32_t(RC_CCONV* rc_peek_t)(uint32_t address, uint32_t num_bytes, void* ud);
/*****************************************************************************\
| Memory References |
@@ -70,15 +70,14 @@ typedef struct rc_memref_value_t {
/* The last differing value of this memory reference. */
uint32_t prior;
/* The size of the value. */
/* The size of the value. (RC_MEMSIZE_*) */
uint8_t size;
/* True if the value changed this frame. */
uint8_t changed;
/* The value type of the value (for variables) */
/* The value type of the value. (RC_VALUE_TYPE_*) */
uint8_t type;
/* True if the reference will be used in indirection.
* NOTE: This is actually a property of the rc_memref_t, but we put it here to save space */
uint8_t is_indirect;
/* The type of memref (RC_MEMREF_TYPE_*) */
uint8_t memref_type;
}
rc_memref_value_t;
@@ -88,9 +87,6 @@ struct rc_memref_t {
/* The memory address of this variable. */
uint32_t address;
/* The next memory reference in the chain. */
rc_memref_t* next;
};
/*****************************************************************************\
@@ -125,11 +121,14 @@ typedef struct rc_operand_t {
int luafunc;
} value;
/* specifies which member of the value union is being used */
/* specifies which member of the value union is being used (RC_OPERAND_*) */
uint8_t type;
/* the actual RC_MEMSIZE of the operand - memref.size may differ */
/* the RC_MEMSIZE of the operand specified in the condition definition - memref.size may differ */
uint8_t size;
/* specifies how to read the memref for some types (RC_OPERAND_*) */
uint8_t memref_access_type;
}
rc_operand_t;
@@ -141,23 +140,16 @@ RC_EXPORT int RC_CCONV rc_operand_is_memref(const rc_operand_t* operand);
/* types */
enum {
/* NOTE: this enum is ordered to optimize the switch statements in rc_test_condset_internal. the values may change between releases */
/* non-combining conditions (third switch) */
RC_CONDITION_STANDARD, /* this should always be 0 */
RC_CONDITION_PAUSE_IF,
RC_CONDITION_RESET_IF,
RC_CONDITION_MEASURED_IF,
RC_CONDITION_TRIGGER,
RC_CONDITION_MEASURED, /* measured also appears in the first switch, so place it at the border between them */
/* modifiers (first switch) */
RC_CONDITION_ADD_SOURCE, /* everything from this point on affects the condition after it */
RC_CONDITION_MEASURED,
RC_CONDITION_ADD_SOURCE,
RC_CONDITION_SUB_SOURCE,
RC_CONDITION_ADD_ADDRESS,
RC_CONDITION_REMEMBER,
/* logic flags (second switch) */
RC_CONDITION_ADD_HITS,
RC_CONDITION_SUB_HITS,
RC_CONDITION_RESET_NEXT_IF,
@@ -180,7 +172,10 @@ enum {
RC_OPERATOR_XOR,
RC_OPERATOR_MOD,
RC_OPERATOR_ADD,
RC_OPERATOR_SUB
RC_OPERATOR_SUB,
RC_OPERATOR_SUB_PARENT, /* internal use */
RC_OPERATOR_INDIRECT_READ /* internal use */
};
typedef struct rc_condition_t rc_condition_t;
@@ -204,9 +199,6 @@ struct rc_condition_t {
/* The comparison operator to use. (RC_OPERATOR_*) */
uint8_t oper; /* operator is a reserved word in C++. */
/* Set if the condition needs to processed as part of the "check if paused" pass. (bool) */
uint8_t pause;
/* Whether or not the condition evaluated true on the last check. (bool) */
uint8_t is_true;
@@ -224,17 +216,32 @@ struct rc_condset_t {
/* The next condition set in the chain. */
rc_condset_t* next;
/* The list of conditions in this condition set. */
/* The first condition in this condition set. Then follow ->next chain. */
rc_condition_t* conditions;
/* True if any condition in the set is a pause condition. */
uint8_t has_pause;
/* The number of pause conditions in this condition set. */
/* The first pause condition is at "this + RC_ALIGN(sizeof(this)). */
uint16_t num_pause_conditions;
/* The number of reset conditions in this condition set. */
uint16_t num_reset_conditions;
/* The number of hittarget conditions in this condition set. */
uint16_t num_hittarget_conditions;
/* The number of non-hittarget measured conditions in this condition set. */
uint16_t num_measured_conditions;
/* The number of other conditions in this condition set. */
uint16_t num_other_conditions;
/* The number of indirect conditions in this condition set. */
uint16_t num_indirect_conditions;
/* True if any condition in the set is a pause condition. */
uint8_t has_pause; /* DEPRECATED - just check num_pause_conditions != 0 */
/* True if the set is currently paused. */
uint8_t is_paused;
/* True if the set has indirect memory references. */
uint8_t has_indirect_memrefs;
};
/*****************************************************************************\
@@ -259,9 +266,6 @@ struct rc_trigger_t {
/* The list of sub condition sets in this test. */
rc_condset_t* alternative;
/* The memory references required by the trigger. */
rc_memref_t* memrefs;
/* The current state of the MEASURED condition. */
uint32_t measured_value;
@@ -274,11 +278,11 @@ struct rc_trigger_t {
/* True if at least one condition has a non-zero hit count */
uint8_t has_hits;
/* True if at least one condition has a non-zero required hit count */
uint8_t has_required_hits;
/* True if the measured value should be displayed as a percentage */
uint8_t measured_as_percent;
/* True if the trigger has its own rc_memrefs_t */
uint8_t has_memrefs;
};
RC_EXPORT int RC_CCONV rc_trigger_size(const char* memaddr);
@@ -297,11 +301,11 @@ struct rc_value_t {
/* The current value of the variable. */
rc_memref_value_t value;
/* The list of conditions to evaluate. */
rc_condset_t* conditions;
/* True if the value has its own rc_memrefs_t */
uint8_t has_memrefs;
/* The memory references required by the variable. */
rc_memref_t* memrefs;
/* The list of possible values (traverse next chain, pick max). */
rc_condset_t* conditions;
/* The name of the variable. */
const char* name;
@@ -335,9 +339,9 @@ struct rc_lboard_t {
rc_trigger_t cancel;
rc_value_t value;
rc_value_t* progress;
rc_memref_t* memrefs;
uint8_t state;
uint8_t has_memrefs;
};
RC_EXPORT int RC_CCONV rc_lboard_size(const char* memaddr);
@@ -406,7 +410,7 @@ struct rc_richpresence_display_part_t {
rc_richpresence_display_part_t* next;
const char* text;
rc_richpresence_lookup_t* lookup;
rc_memref_value_t *value;
rc_operand_t value;
uint8_t display_type;
};
@@ -416,13 +420,14 @@ struct rc_richpresence_display_t {
rc_trigger_t trigger;
rc_richpresence_display_t* next;
rc_richpresence_display_part_t* display;
uint8_t has_required_hits;
};
struct rc_richpresence_t {
rc_richpresence_display_t* first_display;
rc_richpresence_lookup_t* first_lookup;
rc_memref_t* memrefs;
rc_value_t* variables;
rc_value_t* values;
uint8_t has_memrefs;
};
RC_EXPORT int RC_CCONV rc_richpresence_size(const char* script);

View File

@@ -48,6 +48,10 @@
<ClInclude Include="src\rc_version.h" />
<ClInclude Include="src\rhash\md5.h" />
</ItemGroup>
<ItemGroup>
<Natvis Include="src\rcheevos\rc_runtime_types.natvis" />
<Natvis Include="src\rc_client_types.natvis" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}</ProjectGuid>
</PropertyGroup>

View File

@@ -138,4 +138,10 @@
<Filter>include</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Natvis Include="src\rc_client_types.natvis" />
<Natvis Include="src\rcheevos\rc_runtime_types.natvis">
<Filter>rcheevos</Filter>
</Natvis>
</ItemGroup>
</Project>

View File

@@ -91,6 +91,70 @@ static void rc_client_award_achievement_retry(rc_client_scheduled_callback_data_
static int rc_client_is_award_achievement_pending(const rc_client_t* client, uint32_t achievement_id);
static void rc_client_submit_leaderboard_entry_retry(rc_client_scheduled_callback_data_t* callback_data, rc_client_t* client, rc_clock_t now);
/* ===== natvis extensions ===== */
typedef struct __rc_client_achievement_state_enum_t { uint8_t value; } __rc_client_achievement_state_enum_t;
typedef struct __rc_client_achievement_category_enum_t { uint8_t value; } __rc_client_achievement_category_enum_t;
typedef struct __rc_client_achievement_type_enum_t { uint8_t value; } __rc_client_achievement_type_enum_t;
typedef struct __rc_client_achievement_bucket_enum_t { uint8_t value; } __rc_client_achievement_bucket_enum_t;
typedef struct __rc_client_achievement_unlocked_enum_t { uint8_t value; } __rc_client_achievement_unlocked_enum_t;
typedef struct __rc_client_leaderboard_state_enum_t { uint8_t value; } __rc_client_leaderboard_state_enum_t;
typedef struct __rc_client_leaderboard_format_enum_t { uint8_t value; } __rc_client_leaderboard_format_enum_t;
typedef struct __rc_client_log_level_enum_t { uint8_t value; } __rc_client_log_level_enum_t;
typedef struct __rc_client_event_type_enum_t { uint8_t value; } __rc_client_event_type_enum_t;
typedef struct __rc_client_load_game_state_enum_t { uint8_t value; } __rc_client_load_game_state_enum_t;
typedef struct __rc_client_user_state_enum_t { uint8_t value; } __rc_client_user_state_enum_t;
typedef struct __rc_client_mastery_state_enum_t { uint8_t value; } __rc_client_mastery_state_enum_t;
typedef struct __rc_client_spectator_mode_enum_t { uint8_t value; } __rc_client_spectator_mode_enum_t;
typedef struct __rc_client_disconnect_enum_t { uint8_t value; } __rc_client_disconnect_enum_t;
typedef struct __rc_client_leaderboard_tracker_list_t { rc_client_leaderboard_tracker_info_t* first; } __rc_client_leaderboard_tracker_list_t;
typedef struct __rc_client_subset_info_list_t { rc_client_subset_info_t* first; } __rc_client_subset_info_list_t;
typedef struct __rc_client_media_hash_list_t { rc_client_media_hash_t* first; } __rc_client_media_hash_list_t;
typedef struct __rc_client_subset_info_achievements_list_t { rc_client_subset_info_t info; } __rc_client_subset_info_achievements_list_t;
typedef struct __rc_client_subset_info_leaderboards_list_t { rc_client_subset_info_t info; } __rc_client_subset_info_leaderboards_list_t;
typedef struct __rc_client_scheduled_callback_list_t { rc_client_state_t state; } __rc_client_scheduled_callback_list_t;
typedef struct __rc_client_game_hash_list_t { rc_client_t client; } __rc_client_game_hash_list_t;
static void rc_client_natvis_helper(const rc_client_event_t* event, rc_client_t* client)
{
struct natvis_extensions {
__rc_client_achievement_state_enum_t achievement_state;
__rc_client_achievement_category_enum_t achievement_category;
__rc_client_achievement_type_enum_t achievement_type;
__rc_client_achievement_bucket_enum_t achievement_bucket;
__rc_client_achievement_unlocked_enum_t achievement_unlocked;
__rc_client_leaderboard_state_enum_t leaderboard_state;
__rc_client_leaderboard_format_enum_t leaderboard_format;
__rc_client_log_level_enum_t log_level;
__rc_client_event_type_enum_t event_type;
__rc_client_load_game_state_enum_t load_game_state;
__rc_client_user_state_enum_t user_state;
__rc_client_mastery_state_enum_t mastery_state;
__rc_client_spectator_mode_enum_t spectator_mode;
__rc_client_disconnect_enum_t disconnect;
__rc_client_leaderboard_tracker_list_t leaderboard_tracker_list;
__rc_client_subset_info_list_t subset_info_list;
__rc_client_media_hash_list_t media_hash_list;
__rc_client_subset_info_achievements_list_t subset_info_achievements_list;
__rc_client_subset_info_leaderboards_list_t subset_info_leaderboards_list;
__rc_client_scheduled_callback_list_t scheduled_callback_list;
__rc_client_game_hash_list_t client_game_hash_list;
} natvis;
memset(&natvis, 0, sizeof(natvis));
(void)event;
(void)client;
/* this code should never be executed. it just ensures these constants get defined for
* the natvis VisualStudio extension as they're not used directly in the code. */
natvis.achievement_type.value = RC_CLIENT_ACHIEVEMENT_TYPE_STANDARD;
natvis.achievement_type.value = RC_CLIENT_ACHIEVEMENT_TYPE_MISSABLE;
natvis.achievement_type.value = RC_CLIENT_ACHIEVEMENT_TYPE_PROGRESSION;
natvis.achievement_type.value = RC_CLIENT_ACHIEVEMENT_TYPE_WIN;
natvis.achievement_category.value = RC_CLIENT_ACHIEVEMENT_CATEGORY_NONE;
natvis.event_type.value = RC_CLIENT_EVENT_TYPE_NONE;
}
/* ===== Construction/Destruction ===== */
static void rc_client_dummy_event_handler(const rc_client_event_t* event, rc_client_t* client)
@@ -110,6 +174,7 @@ rc_client_t* rc_client_create(rc_client_read_memory_func_t read_memory_function,
client->callbacks.read_memory = read_memory_function;
client->callbacks.server_call = server_call_function;
client->callbacks.event_handler = rc_client_natvis_helper;
client->callbacks.event_handler = rc_client_dummy_event_handler;
rc_client_set_legacy_peek(client, RC_CLIENT_LEGACY_PEEK_AUTO);
rc_client_set_get_time_millisecs_function(client, NULL);
@@ -180,7 +245,7 @@ static void rc_client_log_message_va(const rc_client_t* client, const char* form
if (client->callbacks.log_call) {
char buffer[2048];
#ifdef __STDC_WANT_SECURE_LIB__
#ifdef __STDC_SECURE_LIB__
vsprintf_s(buffer, sizeof(buffer), format, args);
#elif __STDC_VERSION__ >= 199901L /* vsnprintf requires c99 */
vsnprintf(buffer, sizeof(buffer), format, args);
@@ -1071,27 +1136,23 @@ static void rc_client_validate_addresses(rc_client_game_info_t* game, rc_client_
uint32_t total_count = 0;
uint32_t invalid_count = 0;
rc_memref_t** last_memref = &game->runtime.memrefs;
rc_memref_t* memref = game->runtime.memrefs;
for (; memref; memref = memref->next) {
if (!memref->value.is_indirect) {
total_count++;
rc_memref_list_t* memref_list = &game->runtime.memrefs->memrefs;
for (; memref_list; memref_list = memref_list->next) {
rc_memref_t* memref = memref_list->items;
const rc_memref_t* memref_end = memref + memref_list->count;
total_count += memref_list->count;
for (; memref < memref_end; ++memref) {
if (memref->address > max_address ||
client->callbacks.read_memory(memref->address, buffer, 1, client) == 0) {
/* invalid address, remove from chain so we don't have to evaluate it in the future.
* it's still there, so anything referencing it will always fetch 0. */
*last_memref = memref->next;
client->callbacks.read_memory(memref->address, buffer, 1, client) == 0) {
memref->value.type = RC_VALUE_TYPE_NONE;
rc_client_invalidate_memref_achievements(game, client, memref);
rc_client_invalidate_memref_leaderboards(game, client, memref);
invalid_count++;
continue;
}
}
last_memref = &memref->next;
}
game->max_valid_address = max_address;
@@ -1654,9 +1715,10 @@ static void rc_client_copy_achievements(rc_client_load_state_t* load_state,
rc_client_achievement_info_t* achievement;
rc_client_achievement_info_t* scan;
rc_buffer_t* buffer;
rc_parse_state_t parse;
rc_preparse_state_t preparse;
const char* memaddr;
size_t size;
rc_trigger_t* trigger;
int trigger_size;
subset->achievements = NULL;
@@ -1686,11 +1748,11 @@ static void rc_client_copy_achievements(rc_client_load_state_t* load_state,
+ sizeof(rc_trigger_t) + sizeof(rc_condset_t) * 2 /* trigger container */
+ sizeof(rc_condition_t) * 8 /* assume average trigger length of 8 conditions */
+ sizeof(rc_client_achievement_info_t);
rc_buffer_reserve(&load_state->game->buffer, size * num_achievements);
buffer = &load_state->game->buffer;
rc_buffer_reserve(buffer, size * num_achievements);
/* allocate the achievement array */
size = sizeof(rc_client_achievement_info_t) * num_achievements;
buffer = &load_state->game->buffer;
achievement = achievements = rc_buffer_alloc(buffer, size);
memset(achievements, 0, size);
@@ -1713,7 +1775,12 @@ static void rc_client_copy_achievements(rc_client_load_state_t* load_state,
memaddr = read->definition;
rc_runtime_checksum(memaddr, achievement->md5);
trigger_size = rc_trigger_size(memaddr);
rc_init_preparse_state(&preparse, NULL, 0);
preparse.parse.existing_memrefs = load_state->game->runtime.memrefs;
trigger = RC_ALLOC(rc_trigger_t, &preparse.parse);
rc_parse_trigger_internal(trigger, &memaddr, &preparse.parse);
trigger_size = preparse.parse.offset;
if (trigger_size < 0) {
RC_CLIENT_LOG_WARN_FORMATTED(load_state->client, "Parse error %d processing achievement %u", trigger_size, read->id);
achievement->public_.state = RC_CLIENT_ACHIEVEMENT_STATE_DISABLED;
@@ -1721,23 +1788,22 @@ static void rc_client_copy_achievements(rc_client_load_state_t* load_state,
}
else {
/* populate the item, using the communal memrefs pool */
rc_init_parse_state(&parse, rc_buffer_reserve(buffer, trigger_size), NULL, 0);
parse.first_memref = &load_state->game->runtime.memrefs;
parse.variables = &load_state->game->runtime.variables;
achievement->trigger = RC_ALLOC(rc_trigger_t, &parse);
rc_parse_trigger_internal(achievement->trigger, &memaddr, &parse);
rc_reset_parse_state(&preparse.parse, rc_buffer_reserve(buffer, trigger_size), NULL, 0);
rc_preparse_reserve_memrefs(&preparse, load_state->game->runtime.memrefs);
achievement->trigger = RC_ALLOC(rc_trigger_t, &preparse.parse);
memaddr = read->definition;
rc_parse_trigger_internal(achievement->trigger, &memaddr, &preparse.parse);
if (parse.offset < 0) {
RC_CLIENT_LOG_WARN_FORMATTED(load_state->client, "Parse error %d processing achievement %u", parse.offset, read->id);
if (preparse.parse.offset < 0) {
RC_CLIENT_LOG_WARN_FORMATTED(load_state->client, "Parse error %d processing achievement %u", preparse.parse.offset, read->id);
achievement->public_.state = RC_CLIENT_ACHIEVEMENT_STATE_DISABLED;
achievement->public_.bucket = RC_CLIENT_ACHIEVEMENT_BUCKET_UNSUPPORTED;
}
else {
rc_buffer_consume(buffer, parse.buffer, (uint8_t*)parse.buffer + parse.offset);
achievement->trigger->memrefs = NULL; /* memrefs managed by runtime */
rc_buffer_consume(buffer, preparse.parse.buffer, (uint8_t*)preparse.parse.buffer + preparse.parse.offset);
}
rc_destroy_parse_state(&parse);
rc_destroy_preparse_state(&preparse);
}
achievement->created_time = read->created;
@@ -1801,10 +1867,11 @@ static void rc_client_copy_leaderboards(rc_client_load_state_t* load_state,
rc_client_leaderboard_info_t* leaderboards;
rc_client_leaderboard_info_t* leaderboard;
rc_buffer_t* buffer;
rc_parse_state_t parse;
rc_preparse_state_t preparse;
const char* memaddr;
const char* ptr;
size_t size;
rc_lboard_t* lboard;
int lboard_size;
subset->leaderboards = NULL;
@@ -1854,29 +1921,32 @@ static void rc_client_copy_leaderboards(rc_client_load_state_t* load_state,
leaderboard->value_djb2 = hash;
}
lboard_size = rc_lboard_size(memaddr);
rc_init_preparse_state(&preparse, NULL, 0);
preparse.parse.existing_memrefs = load_state->game->runtime.memrefs;
lboard = RC_ALLOC(rc_lboard_t, &preparse.parse);
rc_parse_lboard_internal(lboard, memaddr, &preparse.parse);
lboard_size = preparse.parse.offset;
if (lboard_size < 0) {
RC_CLIENT_LOG_WARN_FORMATTED(load_state->client, "Parse error %d processing leaderboard %u", lboard_size, read->id);
leaderboard->public_.state = RC_CLIENT_LEADERBOARD_STATE_DISABLED;
}
else {
/* populate the item, using the communal memrefs pool */
rc_init_parse_state(&parse, rc_buffer_reserve(buffer, lboard_size), NULL, 0);
parse.first_memref = &load_state->game->runtime.memrefs;
parse.variables = &load_state->game->runtime.variables;
leaderboard->lboard = RC_ALLOC(rc_lboard_t, &parse);
rc_parse_lboard_internal(leaderboard->lboard, memaddr, &parse);
rc_reset_parse_state(&preparse.parse, rc_buffer_reserve(buffer, lboard_size), NULL, 0);
rc_preparse_reserve_memrefs(&preparse, load_state->game->runtime.memrefs);
leaderboard->lboard = RC_ALLOC(rc_lboard_t, &preparse.parse);
rc_parse_lboard_internal(leaderboard->lboard, memaddr, &preparse.parse);
if (parse.offset < 0) {
RC_CLIENT_LOG_WARN_FORMATTED(load_state->client, "Parse error %d processing leaderboard %u", parse.offset, read->id);
if (preparse.parse.offset < 0) {
RC_CLIENT_LOG_WARN_FORMATTED(load_state->client, "Parse error %d processing leaderboard %u", preparse.parse.offset, read->id);
leaderboard->public_.state = RC_CLIENT_LEADERBOARD_STATE_DISABLED;
}
else {
rc_buffer_consume(buffer, parse.buffer, (uint8_t*)parse.buffer + parse.offset);
leaderboard->lboard->memrefs = NULL; /* memrefs managed by runtime */
rc_buffer_consume(buffer, preparse.parse.buffer, (uint8_t*)preparse.parse.buffer + preparse.parse.offset);
}
rc_destroy_parse_state(&parse);
rc_destroy_preparse_state(&preparse);
}
++leaderboard;
@@ -4801,22 +4871,11 @@ void rc_client_set_read_memory_function(rc_client_t* client, rc_client_read_memo
static void rc_client_invalidate_processing_memref(rc_client_t* client)
{
rc_memref_t** next_memref = &client->game->runtime.memrefs;
rc_memref_t* memref;
/* if processing_memref is not set, this occurred following a pointer chain. ignore it. */
if (!client->state.processing_memref)
return;
/* invalid memref. remove from chain so we don't have to evaluate it in the future.
* it's still there, so anything referencing it will always fetch the current value. */
while ((memref = *next_memref) != NULL) {
if (memref == client->state.processing_memref) {
*next_memref = memref->next;
break;
}
next_memref = &memref->next;
}
client->state.processing_memref->value.type = RC_VALUE_TYPE_NONE;
rc_client_invalidate_memref_achievements(client->game, client, client->state.processing_memref);
rc_client_invalidate_memref_leaderboards(client->game, client, client->state.processing_memref);
@@ -4924,31 +4983,57 @@ int rc_client_is_processing_required(rc_client_t* client)
return (client->game->runtime.richpresence && client->game->runtime.richpresence->richpresence);
}
static void rc_client_update_memref_values(rc_client_t* client)
{
rc_memref_t* memref = client->game->runtime.memrefs;
uint32_t value;
static void rc_client_update_memref_values(rc_client_t* client) {
rc_memrefs_t* memrefs = client->game->runtime.memrefs;
rc_memref_list_t* memref_list;
rc_modified_memref_list_t* modified_memref_list;
int invalidated_memref = 0;
for (; memref; memref = memref->next) {
if (memref->value.is_indirect)
continue;
memref_list = &memrefs->memrefs;
do {
rc_memref_t* memref = memref_list->items;
const rc_memref_t* memref_stop = memref + memref_list->count;
uint32_t value;
client->state.processing_memref = memref;
for (; memref < memref_stop; ++memref) {
if (memref->value.type == RC_VALUE_TYPE_NONE)
continue;
value = rc_peek_value(memref->address, memref->value.size, client->state.legacy_peek, client);
/* if processing_memref is set, and the memory read fails, all dependent achievements will be disabled */
client->state.processing_memref = memref;
if (client->state.processing_memref) {
rc_update_memref_value(&memref->value, value);
value = rc_peek_value(memref->address, memref->value.size, client->state.legacy_peek, client);
if (client->state.processing_memref) {
rc_update_memref_value(&memref->value, value);
}
else {
/* if the peek function cleared the processing_memref, the memref was invalidated */
invalidated_memref = 1;
}
}
else {
/* if the peek function cleared the processing_memref, the memref was invalidated */
invalidated_memref = 1;
}
}
memref_list = memref_list->next;
} while (memref_list);
client->state.processing_memref = NULL;
modified_memref_list = &memrefs->modified_memrefs;
if (modified_memref_list->count) {
do {
rc_modified_memref_t* modified_memref = modified_memref_list->items;
const rc_modified_memref_t* modified_memref_stop = modified_memref + modified_memref_list->count;
for (; modified_memref < modified_memref_stop; ++modified_memref)
rc_update_memref_value(&modified_memref->memref.value, rc_get_modified_memref_value(modified_memref, client->state.legacy_peek, client));
modified_memref_list = modified_memref_list->next;
} while (modified_memref_list);
}
if (client->game->runtime.richpresence && client->game->runtime.richpresence->richpresence)
rc_update_values(client->game->runtime.richpresence->richpresence->values, client->state.legacy_peek, client, NULL);
if (invalidated_memref)
rc_client_update_active_achievements(client->game);
}
@@ -5362,7 +5447,6 @@ void rc_client_do_frame(rc_client_t* client)
rc_client_reset_pending_events(client);
rc_client_update_memref_values(client);
rc_update_variables(client->game->runtime.variables, client->state.legacy_peek, client, NULL);
client->game->progress_tracker.progress = 0.0;
for (subset = client->game->subsets; subset; subset = subset->next) {
@@ -5534,9 +5618,8 @@ static void rc_client_reset_richpresence(rc_client_t* client)
static void rc_client_reset_variables(rc_client_t* client)
{
rc_value_t* variable = client->game->runtime.variables;
for (; variable; variable = variable->next)
rc_reset_value(variable);
if (client->game->runtime.richpresence && client->game->runtime.richpresence->richpresence)
rc_reset_values(client->game->runtime.richpresence->richpresence->values);
}
static void rc_client_reset_all(rc_client_t* client)

View File

@@ -6,6 +6,24 @@
#ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION
/* ===== natvis extensions ===== */
typedef struct __rc_client_raintegration_event_enum_t { uint8_t value; } __rc_client_raintegration_event_enum_t;
static void rc_client_raintegration_natvis_helper(void)
{
struct natvis_extensions {
__rc_client_raintegration_event_enum_t raintegration_event_type;
} natvis;
natvis.raintegration_event_type.value = RC_CLIENT_RAINTEGRATION_EVENT_TYPE_NONE;
natvis.raintegration_event_type.value = RC_CLIENT_RAINTEGRATION_EVENT_MENUITEM_CHECKED_CHANGED;
natvis.raintegration_event_type.value = RC_CLIENT_RAINTEGRATION_EVENT_HARDCORE_CHANGED;
natvis.raintegration_event_type.value = RC_CLIENT_RAINTEGRATION_EVENT_PAUSE;
natvis.raintegration_event_type.value = RC_CLIENT_RAINTEGRATION_EVENT_MENU_CHANGED;
}
/* ============================= */
static void rc_client_raintegration_load_dll(rc_client_t* client,
const wchar_t* search_directory, rc_client_callback_t callback, void* callback_userdata)
{
@@ -89,6 +107,9 @@ static void rc_client_raintegration_load_dll(rc_client_t* client,
FreeLibrary(hDLL);
callback(RC_ABORTED, "One or more required exports was not found in RA_Integration.dll", client, callback_userdata);
/* dummy reference to natvis helper to ensure extensions get compiled in. */
raintegration->shutdown = rc_client_raintegration_natvis_helper;
}
else {
rc_mutex_lock(&client->state.mutex);

View File

@@ -0,0 +1,394 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<!-- https://learn.microsoft.com/en-us/visualstudio/debugger/create-custom-views-of-native-objects?view=vs-2022 -->
<!-- https://learn.microsoft.com/en-us/visualstudio/debugger/format-specifiers-in-cpp?view=vs-2022 -->
<Type Name="rc_client_user_t">
<DisplayString>{{display_name={display_name,s} score={score}}}</DisplayString>
</Type>
<Type Name="rc_client_game_t">
<DisplayString>{{title={title,s} id={id}}}</DisplayString>
</Type>
<Type Name="rc_client_subset_t">
<DisplayString>{{title={title,s} id={id}}}</DisplayString>
</Type>
<Type Name="__rc_client_achievement_state_enum_t">
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_STATE_INACTIVE">{RC_CLIENT_ACHIEVEMENT_STATE_INACTIVE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_STATE_ACTIVE">{RC_CLIENT_ACHIEVEMENT_STATE_ACTIVE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_STATE_UNLOCKED">{RC_CLIENT_ACHIEVEMENT_STATE_UNLOCKED}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_STATE_DISABLED">{RC_CLIENT_ACHIEVEMENT_STATE_DISABLED}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="__rc_client_achievement_category_enum_t">
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_CATEGORY_NONE">{RC_CLIENT_ACHIEVEMENT_CATEGORY_NONE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_CATEGORY_CORE">{RC_CLIENT_ACHIEVEMENT_CATEGORY_CORE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_CATEGORY_UNOFFICIAL">{RC_CLIENT_ACHIEVEMENT_CATEGORY_UNOFFICIAL}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_CATEGORY_CORE_AND_UNOFFICIAL">{RC_CLIENT_ACHIEVEMENT_CATEGORY_CORE_AND_UNOFFICIAL}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="__rc_client_achievement_type_enum_t">
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_TYPE_STANDARD">{RC_CLIENT_ACHIEVEMENT_TYPE_STANDARD}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_TYPE_MISSABLE">{RC_CLIENT_ACHIEVEMENT_TYPE_MISSABLE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_TYPE_PROGRESSION">{RC_CLIENT_ACHIEVEMENT_TYPE_PROGRESSION}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_TYPE_WIN">{RC_CLIENT_ACHIEVEMENT_TYPE_WIN}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="__rc_client_achievement_bucket_enum_t">
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_BUCKET_UNKNOWN">{RC_CLIENT_ACHIEVEMENT_BUCKET_UNKNOWN}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_BUCKET_LOCKED">{RC_CLIENT_ACHIEVEMENT_BUCKET_LOCKED}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_BUCKET_UNLOCKED">{RC_CLIENT_ACHIEVEMENT_BUCKET_UNLOCKED}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_BUCKET_UNSUPPORTED">{RC_CLIENT_ACHIEVEMENT_BUCKET_UNSUPPORTED}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_BUCKET_UNOFFICIAL">{RC_CLIENT_ACHIEVEMENT_BUCKET_UNOFFICIAL}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_BUCKET_RECENTLY_UNLOCKED">{RC_CLIENT_ACHIEVEMENT_BUCKET_RECENTLY_UNLOCKED}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_BUCKET_ACTIVE_CHALLENGE">{RC_CLIENT_ACHIEVEMENT_BUCKET_ACTIVE_CHALLENGE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_BUCKET_UNSUPPORTED">{RC_CLIENT_ACHIEVEMENT_BUCKET_ALMOST_THERE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_BUCKET_UNSYNCED">{RC_CLIENT_ACHIEVEMENT_BUCKET_UNSYNCED}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="__rc_client_achievement_unlocked_enum_t">
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_UNLOCKED_NONE">{RC_CLIENT_ACHIEVEMENT_UNLOCKED_NONE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_UNLOCKED_SOFTCORE">{RC_CLIENT_ACHIEVEMENT_UNLOCKED_SOFTCORE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_UNLOCKED_HARDCORE">{RC_CLIENT_ACHIEVEMENT_UNLOCKED_HARDCORE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_ACHIEVEMENT_UNLOCKED_BOTH">{RC_CLIENT_ACHIEVEMENT_UNLOCKED_BOTH}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="rc_client_achievement_t">
<DisplayString>{{title={title,s} id={id}}}</DisplayString>
<Expand>
<Item Name="title">title</Item>
<Item Name="description">description</Item>
<Item Name="points">points</Item>
<Item Name="id">id</Item>
<Item Name="state">*((__rc_client_achievement_state_enum_t*)&amp;state)</Item>
<Item Name="type">*((__rc_client_achievement_type_enum_t*)&amp;state)</Item>
<Item Name="category">*((__rc_client_achievement_category_enum_t*)&amp;category)</Item>
<Item Name="bucket">*((__rc_client_achievement_state_enum_t*)&amp;bucket)</Item>
<Item Name="unlocked">*((__rc_client_achievement_unlocked_enum_t*)&amp;unlocked)</Item>
</Expand>
</Type>
<Type Name="rc_client_achievement_bucket_t">
<DisplayString>{{label={label,s} count={num_achievements}}}</DisplayString>
<Expand>
<IndexListItems>
<Size>num_achievements</Size>
<ValueNode>achievements[$i]</ValueNode>
</IndexListItems>
</Expand>
</Type>
<Type Name="rc_client_achievement_list_t">
<DisplayString>{{count={num_buckets}}}</DisplayString>
<Expand>
<IndexListItems>
<Size>num_buckets</Size>
<ValueNode>buckets[$i]</ValueNode>
</IndexListItems>
</Expand>
</Type>
<Type Name="__rc_client_leaderboard_state_enum_t">
<DisplayString Condition="value==RC_CLIENT_LEADERBOARD_STATE_INACTIVE">{RC_CLIENT_LEADERBOARD_STATE_INACTIVE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_LEADERBOARD_STATE_ACTIVE">{RC_CLIENT_LEADERBOARD_STATE_ACTIVE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_LEADERBOARD_STATE_TRACKING">{RC_CLIENT_LEADERBOARD_STATE_TRACKING}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_LEADERBOARD_STATE_DISABLED">{RC_CLIENT_LEADERBOARD_STATE_DISABLED}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="__rc_client_leaderboard_format_enum_t">
<DisplayString Condition="value==RC_CLIENT_LEADERBOARD_FORMAT_TIME">{RC_CLIENT_LEADERBOARD_FORMAT_TIME}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_LEADERBOARD_FORMAT_SCORE">{RC_CLIENT_LEADERBOARD_FORMAT_SCORE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_LEADERBOARD_FORMAT_VALUE">{RC_CLIENT_LEADERBOARD_FORMAT_VALUE}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="rc_client_leaderboard_t">
<DisplayString>{{title={title,s} id={id}}}</DisplayString>
<Expand>
<Item Name="title">title</Item>
<Item Name="description">description</Item>
<Item Name="tracker_value">tracker_value</Item>
<Item Name="id">id</Item>
<Item Name="state">*((__rc_client_leaderboard_state_enum_t*)&amp;state)</Item>
<Item Name="format">*((__rc_client_leaderboard_format_enum_t*)&amp;format)</Item>
<Item Name="lower_is_better">*((__rc_bool_enum_t*)&amp;lower_is_better)</Item>
</Expand>
</Type>
<Type Name="rc_client_leaderboard_bucket_t">
<DisplayString>{{label={label,s} count={num_leaderboards}}}</DisplayString>
<Expand>
<IndexListItems>
<Size>num_leaderboards</Size>
<ValueNode>leaderboards[$i]</ValueNode>
</IndexListItems>
</Expand>
</Type>
<Type Name="rc_client_leaderboard_list_t">
<DisplayString>{{count={num_buckets}}}</DisplayString>
<Expand>
<IndexListItems>
<Size>num_buckets</Size>
<ValueNode>buckets[$i]</ValueNode>
</IndexListItems>
</Expand>
</Type>
<Type Name="rc_client_leaderboard_scoreboard_entry_t">
<DisplayString>{{rank={rank} score={score,s} username={username}}}</DisplayString>
</Type>
<Type Name="rc_client_leaderboard_scoreboard_t">
<DisplayString>{{leaderboard_id={leaderboard_id} num_entries={num_entries}}}</DisplayString>
<Expand>
<Item Name="leaderboard_id">leaderboard_id</Item>
<Item Name="submitted_score">submitted_score</Item>
<Item Name="best_score">best_score</Item>
<Item Name="new_rank">new_rank</Item>
<Item Name="num_entries">num_entries</Item>
<IndexListItems>
<Size>num_top_entries</Size>
<ValueNode>top_entries[$i]</ValueNode>
</IndexListItems>
</Expand>
</Type>
<Type Name="__rc_client_event_type_enum_t">
<DisplayString Condition="value==RC_CLIENT_EVENT_TYPE_NONE">{RC_CLIENT_EVENT_TYPE_NONE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_ACHIEVEMENT_TRIGGERED">{RC_CLIENT_EVENT_ACHIEVEMENT_TRIGGERED}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_LEADERBOARD_STARTED">{RC_CLIENT_EVENT_LEADERBOARD_STARTED}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_LEADERBOARD_FAILED">{RC_CLIENT_EVENT_LEADERBOARD_FAILED}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_LEADERBOARD_SUBMITTED">{RC_CLIENT_EVENT_LEADERBOARD_SUBMITTED}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_ACHIEVEMENT_CHALLENGE_INDICATOR_SHOW">{RC_CLIENT_EVENT_ACHIEVEMENT_CHALLENGE_INDICATOR_SHOW}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_ACHIEVEMENT_CHALLENGE_INDICATOR_HIDE">{RC_CLIENT_EVENT_ACHIEVEMENT_CHALLENGE_INDICATOR_HIDE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_ACHIEVEMENT_PROGRESS_INDICATOR_SHOW">{RC_CLIENT_EVENT_ACHIEVEMENT_PROGRESS_INDICATOR_SHOW}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_ACHIEVEMENT_PROGRESS_INDICATOR_HIDE">{RC_CLIENT_EVENT_ACHIEVEMENT_PROGRESS_INDICATOR_HIDE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_ACHIEVEMENT_PROGRESS_INDICATOR_UPDATE">{RC_CLIENT_EVENT_ACHIEVEMENT_PROGRESS_INDICATOR_UPDATE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_LEADERBOARD_TRACKER_SHOW">{RC_CLIENT_EVENT_LEADERBOARD_TRACKER_SHOW}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_LEADERBOARD_TRACKER_HIDE">{RC_CLIENT_EVENT_LEADERBOARD_TRACKER_HIDE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_LEADERBOARD_TRACKER_UPDATE">{RC_CLIENT_EVENT_LEADERBOARD_TRACKER_UPDATE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_LEADERBOARD_SCOREBOARD">{RC_CLIENT_EVENT_LEADERBOARD_SCOREBOARD}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_RESET">{RC_CLIENT_EVENT_RESET}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_GAME_COMPLETED">{RC_CLIENT_EVENT_GAME_COMPLETED}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_SERVER_ERROR">{RC_CLIENT_EVENT_SERVER_ERROR}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_DISCONNECTED">{RC_CLIENT_EVENT_DISCONNECTED}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_EVENT_RECONNECTED">{RC_CLIENT_EVENT_RECONNECTED}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="rc_client_event_t">
<DisplayString>{{type={*((__rc_client_event_type_enum_t*)&amp;type)}}}</DisplayString>
<Expand>
<Item Name="type">*((__rc_client_event_type_enum_t*)&amp;type)</Item>
<Item Condition="type==RC_CLIENT_EVENT_ACHIEVEMENT_TRIGGERED" Name="achievement">*achievement</Item>
<Item Condition="type==RC_CLIENT_EVENT_LEADERBOARD_STARTED" Name="leaderboard">*leaderboard</Item>
<Item Condition="type==RC_CLIENT_EVENT_LEADERBOARD_FAILED" Name="leaderboard">*leaderboard</Item>
<Item Condition="type==RC_CLIENT_EVENT_LEADERBOARD_SUBMITTED" Name="leaderboard">*leaderboard</Item>
<Item Condition="type==RC_CLIENT_EVENT_ACHIEVEMENT_CHALLENGE_INDICATOR_SHOW" Name="achievement">*achievement</Item>
<Item Condition="type==RC_CLIENT_EVENT_ACHIEVEMENT_CHALLENGE_INDICATOR_HIDE" Name="achievement">*achievement</Item>
<Item Condition="type==RC_CLIENT_EVENT_ACHIEVEMENT_PROGRESS_INDICATOR_SHOW" Name="achievement">*achievement</Item>
<Item Condition="type==RC_CLIENT_EVENT_ACHIEVEMENT_PROGRESS_INDICATOR_HIDE" Name="achievement">*achievement</Item>
<Item Condition="type==RC_CLIENT_EVENT_ACHIEVEMENT_PROGRESS_INDICATOR_UPDATE" Name="achievement">*achievement</Item>
<Item Condition="type==RC_CLIENT_EVENT_LEADERBOARD_TRACKER_SHOW" Name="leaderboard_tracker">*leaderboard_tracker</Item>
<Item Condition="type==RC_CLIENT_EVENT_LEADERBOARD_TRACKER_HIDE" Name="leaderboard_tracker">*leaderboard_tracker</Item>
<Item Condition="type==RC_CLIENT_EVENT_LEADERBOARD_TRACKER_UPDATE" Name="leaderboard_tracker">*leaderboard_tracker</Item>
<Item Condition="type==RC_CLIENT_EVENT_LEADERBOARD_SCOREBOARD" Name="leaderboard_scoreboard">*leaderboard_scoreboard</Item>
<Item Condition="type==RC_CLIENT_EVENT_LEADERBOARD_SCOREBOARD" Name="leaderboard">*leaderboard</Item>
<Item Condition="type==RC_CLIENT_EVENT_SERVER_ERROR" Name="server_error">*server_error</Item>
</Expand>
</Type>
<Type Name="__rc_client_subset_info_achievements_list_t">
<DisplayString>{{count={info.public_.num_achievements}}}</DisplayString>
<Expand>
<IndexListItems>
<Size>info.public_.num_achievements</Size>
<ValueNode>info.achievements[$i]</ValueNode>
</IndexListItems>
</Expand>
</Type>
<Type Name="__rc_client_subset_info_leaderboards_list_t">
<DisplayString>{{count={info.public_.num_leaderboards}}}</DisplayString>
<Expand>
<IndexListItems>
<Size>info.public_.num_leaderboards</Size>
<ValueNode>info.leaderboards[$i]</ValueNode>
</IndexListItems>
</Expand>
</Type>
<Type Name="__rc_client_mastery_state_enum_t">
<DisplayString Condition="value==RC_CLIENT_MASTERY_STATE_NONE">{RC_CLIENT_MASTERY_STATE_NONE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_MASTERY_STATE_PENDING">{RC_CLIENT_MASTERY_STATE_PENDING}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_MASTERY_STATE_SHOWN">{RC_CLIENT_MASTERY_STATE_SHOWN}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="rc_client_subset_info_t">
<DisplayString>{{title={public_.title,s} id={public_.id}}}</DisplayString>
<Expand>
<Item Name="public_">public_</Item>
<Item Name="active">*((__rc_bool_enum_t*)&amp;active)</Item>
<Item Name="mastery">*((__rc_client_mastery_state_enum_t*)&amp;mastery)</Item>
<Item Name="achievements">*((__rc_client_subset_info_achievements_list_t*)this)</Item>
<Item Name="leaderboards">*((__rc_client_subset_info_leaderboards_list_t*)this)</Item>
</Expand>
</Type>
<Type Name="__rc_client_leaderboard_tracker_list_t">
<DisplayString Condition="first==0">{{NULL}}</DisplayString>
<DisplayString>{(void**)&amp;first,na}</DisplayString>
<Expand>
<LinkedListItems>
<HeadPointer>first</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="__rc_client_subset_info_list_t">
<DisplayString Condition="first==0">{{NULL}}</DisplayString>
<DisplayString>{(void**)&amp;first,na}</DisplayString>
<Expand>
<LinkedListItems>
<HeadPointer>first</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="__rc_client_media_hash_list_t">
<DisplayString Condition="first==0">{{NULL}}</DisplayString>
<DisplayString>{(void**)&amp;first,na}</DisplayString>
<Expand>
<LinkedListItems>
<HeadPointer>first</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="rc_client_achievement_info_t">
<DisplayString>{{title={public_.title,s} id={public_.id}}}</DisplayString>
</Type>
<Type Name="rc_client_leaderboard_info_t">
<DisplayString>{{title={public_.title,s} id={public_.id}}}</DisplayString>
</Type>
<Type Name="rc_client_game_info_t">
<DisplayString>{{title={public_.title,s} id={public_.id}}}</DisplayString>
<Expand>
<Item Name="public_">public_</Item>
<Item Name="subsets">*((__rc_client_subset_info_list_t*)&amp;subsets)</Item>
<Item Name="media_hash">*((__rc_client_media_hash_list_t*)&amp;media_hash)</Item>
<Item Name="leaderboard_trackers">*((__rc_client_leaderboard_tracker_list_t*)&amp;leaderboard_trackers)</Item>
<Item Name="progress_tracker">progress_tracker</Item>
<Item Name="runtime">runtime</Item>
</Expand>
</Type>
<Type Name="rc_client_game_hash_t">
<DisplayString>{{hash={hash,s} game_id={game_id}}}</DisplayString>
</Type>
<Type Name="__rc_client_game_hash_list_t">
<DisplayString>{client.hashes}</DisplayString>
<Expand>
<LinkedListItems>
<HeadPointer>client.hashes</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>*this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="__rc_client_load_game_state_enum_t">
<DisplayString Condition="value==RC_CLIENT_LOAD_GAME_STATE_NONE">{RC_CLIENT_LOAD_GAME_STATE_NONE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_LOAD_GAME_STATE_IDENTIFYING_GAME">{RC_CLIENT_LOAD_GAME_STATE_IDENTIFYING_GAME}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_LOAD_GAME_STATE_AWAIT_LOGIN">{RC_CLIENT_LOAD_GAME_STATE_AWAIT_LOGIN}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_LOAD_GAME_STATE_FETCHING_GAME_DATA">{RC_CLIENT_LOAD_GAME_STATE_FETCHING_GAME_DATA}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_LOAD_GAME_STATE_STARTING_SESSION">{RC_CLIENT_LOAD_GAME_STATE_STARTING_SESSION}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_LOAD_GAME_STATE_DONE">{RC_CLIENT_LOAD_GAME_STATE_DONE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_LOAD_GAME_STATE_ABORTED">{RC_CLIENT_LOAD_GAME_STATE_ABORTED}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="rc_client_load_state_t">
<Expand>
<Item Name="progress">*((__rc_client_load_game_state_enum_t*)&amp;progress)</Item>
<Item Name="game">*game</Item>
<Item Name="subset">subset</Item>
<Item Name="hash">*hash</Item>
<Item Name="pending_media">pending_media</Item>
<Item Name="start_session_response">start_session_response</Item>
<Item Name="outstanding_requests">(int)outstanding_requests</Item>
</Expand>
</Type>
<Type Name="rc_client_scheduled_callback_data_t">
<DisplayString>{{when={when} callback={callback,na}}}</DisplayString>
</Type>
<Type Name="__rc_client_scheduled_callback_list_t">
<DisplayString>{state.scheduled_callbacks}</DisplayString>
<Expand>
<LinkedListItems>
<HeadPointer>state.scheduled_callbacks</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>*this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="__rc_client_log_level_enum_t">
<DisplayString Condition="value==RC_CLIENT_LOG_LEVEL_NONE">{RC_CLIENT_LOG_LEVEL_NONE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_LOG_LEVEL_ERROR">{RC_CLIENT_LOG_LEVEL_ERROR}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_LOG_LEVEL_WARN">{RC_CLIENT_LOG_LEVEL_WARN}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_LOG_LEVEL_INFO">{RC_CLIENT_LOG_LEVEL_INFO}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_LOG_LEVEL_VERBOSE">{RC_CLIENT_LOG_LEVEL_VERBOSE}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="__rc_client_user_state_enum_t">
<DisplayString Condition="value==RC_CLIENT_USER_STATE_NONE">{RC_CLIENT_USER_STATE_NONE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_USER_STATE_LOGIN_REQUESTED">{RC_CLIENT_USER_STATE_LOGIN_REQUESTED}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_USER_STATE_LOGGED_IN">{RC_CLIENT_USER_STATE_LOGGED_IN}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="__rc_client_spectator_mode_enum_t">
<DisplayString Condition="value==RC_CLIENT_SPECTATOR_MODE_OFF">{RC_CLIENT_SPECTATOR_MODE_OFF}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_SPECTATOR_MODE_ON">{RC_CLIENT_SPECTATOR_MODE_ON}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_SPECTATOR_MODE_LOCKED">{RC_CLIENT_SPECTATOR_MODE_LOCKED}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="__rc_client_disconnect_enum_t">
<DisplayString Condition="value==RC_CLIENT_DISCONNECT_HIDDEN">{RC_CLIENT_DISCONNECT_HIDDEN}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_DISCONNECT_VISIBLE">{RC_CLIENT_DISCONNECT_VISIBLE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_DISCONNECT_SHOW_PENDING">{RC_CLIENT_DISCONNECT_SHOW_PENDING}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_DISCONNECT_HIDE_PENDING">{RC_CLIENT_DISCONNECT_HIDE_PENDING}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_DISCONNECT_VISIBLE|RC_CLIENT_DISCONNECT_HIDE_PENDING">{RC_CLIENT_DISCONNECT_VISIBLE|RC_CLIENT_DISCONNECT_HIDE_PENDING}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="rc_client_state_t">
<Expand>
<Item Name="hardcore">*((__rc_bool_enum_t*)&amp;hardcore)</Item>
<Item Name="unofficial_enabled">*((__rc_bool_enum_t*)&amp;unofficial_enabled)</Item>
<Item Name="encore_mode">*((__rc_bool_enum_t*)&amp;encore_mode)</Item>
<Item Name="spectator_mode">*((__rc_client_spectator_mode_enum_t*)&amp;spectator_mode)</Item>
<Item Name="disconnect">*((__rc_client_disconnect_enum_t*)&amp;disconnect)</Item>
<Item Name="log_level">*((__rc_client_log_level_enum_t*)&amp;log_level)</Item>
<Item Name="user">*((__rc_client_user_state_enum_t*)&amp;user)</Item>
<Item Name="scheduled_callbacks">*((__rc_client_scheduled_callback_list_t*)this)</Item>
<Item Name="load">load</Item>
</Expand>
</Type>
<Type Name="rc_client_t">
<Expand>
<Item Name="game">game</Item>
<Item Name="hashes">*((__rc_client_game_hash_list_t*)&amp;hashes)</Item>
<Item Name="user">user</Item>
<Item Name="callbacks">callbacks</Item>
<Item Name="state">state</Item>
</Expand>
</Type>
<Type Name="rc_client_raintegration_menu_t">
<DisplayString>{{count={num_items}}}</DisplayString>
<Expand>
<IndexListItems>
<Size>num_items</Size>
<ValueNode>items[$i]</ValueNode>
</IndexListItems>
</Expand>
</Type>
<Type Name="__rc_client_raintegration_event_enum_t">
<DisplayString Condition="value==RC_CLIENT_RAINTEGRATION_EVENT_TYPE_NONE">{RC_CLIENT_RAINTEGRATION_EVENT_TYPE_NONE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_RAINTEGRATION_EVENT_MENUITEM_CHECKED_CHANGED">{RC_CLIENT_RAINTEGRATION_EVENT_MENUITEM_CHECKED_CHANGED}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_RAINTEGRATION_EVENT_HARDCORE_CHANGED">{RC_CLIENT_RAINTEGRATION_EVENT_HARDCORE_CHANGED}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_RAINTEGRATION_EVENT_PAUSE">{RC_CLIENT_RAINTEGRATION_EVENT_PAUSE}</DisplayString>
<DisplayString Condition="value==RC_CLIENT_RAINTEGRATION_EVENT_MENU_CHANGED">{RC_CLIENT_RAINTEGRATION_EVENT_MENU_CHANGED}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="rc_client_raintegration_event_t">
<DisplayString>{{type={*((__rc_client_raintegration_event_enum_t*)&amp;type)}}}</DisplayString>
<Expand>
<Item Name="type">*((__rc_client_raintegration_event_enum_t*)&amp;type)</Item>
<Item Condition="type==RC_CLIENT_RAINTEGRATION_EVENT_MENUITEM_CHECKED_CHANGED" Name="menu_item">menu_item</Item>
</Expand>
</Type>
</AutoVisualizer>

View File

@@ -1,5 +1,15 @@
#if !defined(RC_NO_THREADS) && !defined(_WIN32) && !defined(GEKKO) && !defined(_3DS) && (!defined(_XOPEN_SOURCE) || (_XOPEN_SOURCE - 0) < 500)
/* We'll want to use pthread_mutexattr_settype/PTHREAD_MUTEX_RECURSIVE, but glibc only conditionally exposes pthread_mutexattr_settype and PTHREAD_MUTEX_RECURSIVE depending on feature flags
* Defining _XOPEN_SOURCE must be done at the top of the source file, before including any headers
* pthread_mutexattr_settype/PTHREAD_MUTEX_RECURSIVE are specified the Single UNIX Specification (Version 2, 1997), along with POSIX later on (IEEE Standard 1003.1-2008), so should cover practically any pthread implementation
*/
#undef _XOPEN_SOURCE
#define _XOPEN_SOURCE 500
#endif
#include "rc_compat.h"
#include <assert.h>
#include <ctype.h>
#include <stdarg.h>
@@ -58,7 +68,7 @@ int rc_snprintf(char* buffer, size_t size, const char* format, ...)
va_start(args, format);
#ifdef __STDC_WANT_SECURE_LIB__
#ifdef __STDC_SECURE_LIB__
result = vsprintf_s(buffer, size, format, args);
#else
/* assume buffer is large enough and ignore size */
@@ -73,7 +83,7 @@ int rc_snprintf(char* buffer, size_t size, const char* format, ...)
#endif
#ifndef __STDC_WANT_SECURE_LIB__
#ifndef __STDC_SECURE_LIB__
struct tm* rc_gmtime_s(struct tm* buf, const time_t* timer)
{
@@ -88,61 +98,138 @@ struct tm* rc_gmtime_s(struct tm* buf, const time_t* timer)
#if defined(_WIN32)
/* https://gist.github.com/roxlu/1c1af99f92bafff9d8d9 */
/* https://learn.microsoft.com/en-us/archive/msdn-magazine/2012/november/windows-with-c-the-evolution-of-synchronization-in-windows-and-c */
/* implementation largely taken from https://github.com/libsdl-org/SDL/blob/0fc3574/src/thread/windows/SDL_sysmutex.c */
#if defined(WINVER) && WINVER >= 0x0600
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
void rc_mutex_init(rc_mutex_t* mutex)
{
/* default security, not owned by calling thread, unnamed */
mutex->handle = CreateMutex(NULL, FALSE, NULL);
InitializeSRWLock(&mutex->srw_lock);
/* https://learn.microsoft.com/en-us/windows/win32/procthread/thread-handles-and-identifiers */
/* thread ids are never 0 */
mutex->owner = 0;
mutex->count = 0;
}
void rc_mutex_destroy(rc_mutex_t* mutex)
{
CloseHandle(mutex->handle);
/* Nothing to do here */
(void)mutex;
}
void rc_mutex_lock(rc_mutex_t* mutex)
{
WaitForSingleObject(mutex->handle, 0xFFFFFFFF);
DWORD current_thread = GetCurrentThreadId();
if (mutex->owner == current_thread) {
++mutex->count;
assert(mutex->count > 0);
}
else {
AcquireSRWLockExclusive(&mutex->srw_lock);
assert(mutex->owner == 0 && mutex->count == 0);
mutex->owner = current_thread;
mutex->count = 1;
}
}
void rc_mutex_unlock(rc_mutex_t* mutex)
{
ReleaseMutex(mutex->handle);
if (mutex->owner == GetCurrentThreadId()) {
assert(mutex->count > 0);
if (--mutex->count == 0) {
mutex->owner = 0;
ReleaseSRWLockExclusive(&mutex->srw_lock);
}
}
else {
assert(!"Tried to unlock unowned mutex");
}
}
#else
void rc_mutex_init(rc_mutex_t* mutex)
{
InitializeCriticalSection(&mutex->critical_section);
}
void rc_mutex_destroy(rc_mutex_t* mutex)
{
DeleteCriticalSection(&mutex->critical_section);
}
void rc_mutex_lock(rc_mutex_t* mutex)
{
EnterCriticalSection(&mutex->critical_section);
}
void rc_mutex_unlock(rc_mutex_t* mutex)
{
LeaveCriticalSection(&mutex->critical_section);
}
#endif
#elif defined(GEKKO)
/* https://github.com/libretro/RetroArch/pull/16116 */
void rc_mutex_init(rc_mutex_t* mutex)
{
LWP_MutexInit(mutex, NULL);
/* LWP_MutexInit has the handle passed by reference */
/* Other LWP_Mutex* calls have the handle passed by value */
LWP_MutexInit(&mutex->handle, 1);
}
void rc_mutex_destroy(rc_mutex_t* mutex)
{
LWP_MutexDestroy(mutex);
LWP_MutexDestroy(mutex->handle);
}
void rc_mutex_lock(rc_mutex_t* mutex)
{
LWP_MutexLock(mutex);
LWP_MutexLock(mutex->handle);
}
void rc_mutex_unlock(rc_mutex_t* mutex)
{
LWP_MutexUnlock(mutex);
LWP_MutexUnlock(mutex->handle);
}
#elif defined(_3DS)
void rc_mutex_init(rc_mutex_t* mutex)
{
RecursiveLock_Init(mutex);
}
void rc_mutex_destroy(rc_mutex_t* mutex)
{
/* Nothing to do here */
(void)mutex;
}
void rc_mutex_lock(rc_mutex_t* mutex)
{
RecursiveLock_Lock(mutex);
}
void rc_mutex_unlock(rc_mutex_t* mutex)
{
RecursiveLock_Unlock(mutex);
}
#else
void rc_mutex_init(rc_mutex_t* mutex)
{
pthread_mutex_init(mutex, NULL);
/* Define the mutex as recursive, for consistent semantics against other rc_mutex_t implementations */
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(mutex, &attr);
pthread_mutexattr_destroy(&attr);
}
void rc_mutex_destroy(rc_mutex_t* mutex)

View File

@@ -1,6 +1,13 @@
#ifndef RC_COMPAT_H
#define RC_COMPAT_H
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#endif
#include "rc_export.h"
#include <stdio.h>
@@ -58,7 +65,7 @@ RC_BEGIN_C_DECLS
#endif /* __STDC_VERSION__ < 199901L */
#ifndef __STDC_WANT_SECURE_LIB__
#ifndef __STDC_SECURE_LIB__
/* _CRT_SECURE_NO_WARNINGS redefinitions */
#define strcpy_s(dest, sz, src) strcpy(dest, src)
#define sscanf_s sscanf
@@ -77,10 +84,27 @@ RC_BEGIN_C_DECLS
#define rc_mutex_lock(mutex)
#define rc_mutex_unlock(mutex)
#else
#ifdef _WIN32
#if defined(_WIN32)
typedef struct rc_mutex_t {
#if defined(WINVER) && WINVER >= 0x0600
/* Windows Vista and later can use a slim reader/writer (SRW) lock */
SRWLOCK srw_lock;
/* Current thread owner needs to be tracked (for recursive mutex usage) */
DWORD owner;
DWORD count;
#else
/* Pre-Vista must use a critical section */
CRITICAL_SECTION critical_section;
#endif
} rc_mutex_t;
#elif defined(GEKKO)
#include <ogcsys.h>
typedef struct rc_mutex_t {
void* handle; /* HANDLE is defined as "void*" */
mutex_t handle;
} rc_mutex_t;
#elif defined(_3DS)
#include <3ds/synchronization.h>
typedef RecursiveLock rc_mutex_t;
#else
#include <pthread.h>
typedef pthread_mutex_t rc_mutex_t;

View File

@@ -124,7 +124,7 @@ static const rc_disallowed_setting_t _rc_disallowed_neocd_settings[] = {
};
static const rc_disallowed_setting_t _rc_disallowed_pcsx_rearmed_settings[] = {
{ "pcsx_rearmed_psxclock", "<55" },
{ "pcsx_rearmed_psxclock", ",!auto,<55" },
{ "pcsx_rearmed_region", "pal" },
{ NULL, NULL }
};
@@ -202,14 +202,14 @@ static const rc_disallowed_core_settings_t rc_disallowed_core_settings[] = {
{ NULL, NULL }
};
static int rc_libretro_string_equal_nocase_wildcard(const char* test, const char* value) {
static int rc_libretro_string_equal_nocase_wildcard(const char* test, const char* match) {
char c1, c2;
while ((c1 = *test++)) {
if (tolower(c1) != tolower(c2 = *value++) && c2 != '?')
if (tolower(c1) != tolower(c2 = *match++) && c2 != '?')
return (c2 == '*');
}
return (*value == '\0');
return (*match == '\0');
}
static int rc_libretro_numeric_less_than(const char* test, const char* value) {
@@ -218,7 +218,50 @@ static int rc_libretro_numeric_less_than(const char* test, const char* value) {
return (test_num < value_num);
}
static int rc_libretro_match_token(const char* val, const char* token, size_t size, int* result) {
if (*token == '!') {
/* !X => if X is a match, it's explicitly allowed. match with result = false */
if (rc_libretro_match_token(val, token + 1, size - 1, result)) {
*result = 0;
return 1;
}
}
if (*token == '<') {
/* if val < token, match with result = true */
char buffer[128];
memcpy(buffer, token + 1, size - 1);
buffer[size - 1] = '\0';
if (rc_libretro_numeric_less_than(val, buffer)) {
*result = 1;
return 1;
}
}
if (memcmp(token, val, size) == 0 && val[size] == 0) {
/* exact match, match with result = true */
*result = 1;
return 1;
}
else {
/* check for case insensitive match */
char buffer[128];
memcpy(buffer, token, size);
buffer[size] = '\0';
if (rc_libretro_string_equal_nocase_wildcard(val, buffer)) {
/* case insensitive match, match with result = true */
*result = 1;
return 1;
}
}
/* no match */
return 0;
}
static int rc_libretro_match_value(const char* val, const char* match) {
int result = 0;
/* if value starts with a comma, it's a CSV list of potential matches */
if (*match == ',') {
do {
@@ -229,33 +272,23 @@ static int rc_libretro_match_value(const char* val, const char* match) {
++match;
size = match - ptr;
if (val[size] == '\0') {
if (memcmp(ptr, val, size) == 0) {
return 1;
}
else {
char buffer[128];
memcpy(buffer, ptr, size);
buffer[size] = '\0';
if (rc_libretro_string_equal_nocase_wildcard(buffer, val))
return 1;
}
}
} while (*match == ',');
if (rc_libretro_match_token(val, ptr, size, &result))
return result;
return 0;
} while (*match == ',');
}
else {
/* a leading exclamation point means the provided value(s) are not forbidden (are allowed) */
if (*match == '!')
return !rc_libretro_match_value(val, &match[1]);
/* just a single value, attempt to match it */
if (rc_libretro_match_token(val, match, strlen(match), &result))
return result;
}
/* a leading exclamation point means the provided value(s) are not forbidden (are allowed) */
if (*match == '!')
return !rc_libretro_match_value(val, &match[1]);
/* a leading less tahn means the provided value is the minimum allowed */
if (*match == '<')
return rc_libretro_numeric_less_than(val, &match[1]);
/* just a single value, attempt to match it */
return rc_libretro_string_equal_nocase_wildcard(val, match);
/* value did not match filters, assume it's allowed */
return 0;
}
int rc_libretro_is_setting_allowed(const rc_disallowed_setting_t* disallowed_settings, const char* setting, const char* value) {

View File

@@ -38,6 +38,9 @@ void rc_buffer_destroy(rc_buffer_t* buffer)
total += (int)(chunk->end - chunk->start);
wasted += (int)(chunk->end - chunk->write);
++count;
#endif
#ifdef DEBUG_BUFFERS
printf("< free %p.%p\n", (void*)buffer, (void*)chunk);
#endif
free(chunk);
chunk = next;
@@ -70,6 +73,10 @@ uint8_t* rc_buffer_reserve(rc_buffer_t* buffer, size_t amount)
if (!chunk->next)
break;
#ifdef DEBUG_BUFFERS
printf("> alloc %p.%p\n", (void*)buffer, (void*)chunk->next);
#endif
chunk->next->start = (uint8_t*)chunk->next + chunk_header_size;
chunk->next->write = chunk->next->start;
chunk->next->end = (uint8_t*)chunk->next + alloc_size;

View File

@@ -35,11 +35,11 @@ void* rc_alloc(void* pointer, int32_t* offset, uint32_t size, uint32_t alignment
if (pointer != 0) {
/* valid buffer, grab the next chunk */
ptr = (void*)((char*)pointer + *offset);
ptr = (void*)((uint8_t*)pointer + *offset);
}
else if (scratch != 0 && scratch_object_pointer_offset < sizeof(scratch->objs)) {
/* only allocate one instance of each object type (indentified by scratch_object_pointer_offset) */
void** scratch_object_pointer = (void**)((char*)&scratch->objs + scratch_object_pointer_offset);
void** scratch_object_pointer = (void**)((uint8_t*)&scratch->objs + scratch_object_pointer_offset);
ptr = *scratch_object_pointer;
if (!ptr) {
int32_t used;
@@ -94,22 +94,223 @@ char* rc_alloc_str(rc_parse_state_t* parse, const char* text, size_t length) {
return ptr;
}
void rc_init_preparse_state(rc_preparse_state_t* preparse, lua_State* L, int funcs_ndx)
{
rc_init_parse_state(&preparse->parse, NULL, L, funcs_ndx);
rc_init_parse_state_memrefs(&preparse->parse, &preparse->memrefs);
}
void rc_destroy_preparse_state(rc_preparse_state_t* preparse)
{
rc_destroy_parse_state(&preparse->parse);
}
void rc_preparse_alloc_memrefs(rc_memrefs_t* memrefs, rc_preparse_state_t* preparse)
{
const uint32_t num_memrefs = rc_memrefs_count_memrefs(&preparse->memrefs);
const uint32_t num_modified_memrefs = rc_memrefs_count_modified_memrefs(&preparse->memrefs);
if (preparse->parse.offset < 0)
return;
if (memrefs) {
memset(memrefs, 0, sizeof(*memrefs));
preparse->parse.memrefs = memrefs;
}
if (num_memrefs) {
rc_memref_t* memref_items = RC_ALLOC_ARRAY(rc_memref_t, num_memrefs, &preparse->parse);
if (memrefs) {
memrefs->memrefs.capacity = num_memrefs;
memrefs->memrefs.items = memref_items;
}
}
if (num_modified_memrefs) {
rc_modified_memref_t* modified_memref_items =
RC_ALLOC_ARRAY(rc_modified_memref_t, num_modified_memrefs, &preparse->parse);
if (memrefs) {
memrefs->modified_memrefs.capacity = num_modified_memrefs;
memrefs->modified_memrefs.items = modified_memref_items;
}
}
/* when preparsing, this structure will be allocated at the end. when it's allocated earlier
* in the buffer, it could be followed by something aligned at 8 bytes. force the offset to
* an 8-byte boundary */
if (!memrefs) {
rc_alloc(preparse->parse.buffer, &preparse->parse.offset, 0, 8, &preparse->parse.scratch, 0);
}
}
static uint32_t rc_preparse_array_size(uint32_t needed, uint32_t minimum)
{
while (minimum < needed)
minimum <<= 1;
return minimum;
}
void rc_preparse_reserve_memrefs(rc_preparse_state_t* preparse, rc_memrefs_t* memrefs)
{
uint32_t num_memrefs = rc_memrefs_count_memrefs(&preparse->memrefs);
uint32_t num_modified_memrefs = rc_memrefs_count_modified_memrefs(&preparse->memrefs);
uint32_t available;
if (preparse->parse.offset < 0)
return;
if (num_memrefs) {
rc_memref_list_t* memref_list = &memrefs->memrefs;
while (memref_list->count == memref_list->capacity) {
if (!memref_list->next)
break;
memref_list = memref_list->next;
}
available = memref_list->capacity - memref_list->count;
if (available < num_memrefs) {
rc_memref_list_t* new_memref_list = (rc_memref_list_t*)calloc(1, sizeof(rc_memref_list_t));
if (!new_memref_list)
return;
new_memref_list->capacity = rc_preparse_array_size(num_memrefs - available, 16);
new_memref_list->items = (rc_memref_t*)malloc(new_memref_list->capacity * sizeof(rc_memref_t));
new_memref_list->allocated = 1;
memref_list->next = new_memref_list;
}
}
if (num_modified_memrefs) {
rc_modified_memref_list_t* modified_memref_list = &memrefs->modified_memrefs;
while (modified_memref_list->count == modified_memref_list->capacity) {
if (!modified_memref_list->next)
break;
modified_memref_list = modified_memref_list->next;
}
available = modified_memref_list->capacity - modified_memref_list->count;
if (available < num_modified_memrefs) {
rc_modified_memref_list_t* new_modified_memref_list = (rc_modified_memref_list_t*)calloc(1, sizeof(rc_modified_memref_list_t));
if (!new_modified_memref_list)
return;
new_modified_memref_list->capacity = rc_preparse_array_size(num_modified_memrefs - available, 8);
new_modified_memref_list->items = (rc_modified_memref_t*)malloc(new_modified_memref_list->capacity * sizeof(rc_modified_memref_t));
new_modified_memref_list->allocated = 1;
modified_memref_list->next = new_modified_memref_list;
}
}
preparse->parse.memrefs = memrefs;
}
static void rc_preparse_sync_operand(rc_operand_t* operand, rc_parse_state_t* parse, const rc_memrefs_t* memrefs)
{
if (rc_operand_is_memref(operand) || rc_operand_is_recall(operand)) {
const rc_memref_t* src_memref = operand->value.memref;
if (src_memref->value.memref_type == RC_MEMREF_TYPE_MODIFIED_MEMREF) {
const rc_modified_memref_list_t* modified_memref_list = &memrefs->modified_memrefs;
for (; modified_memref_list; modified_memref_list = modified_memref_list->next) {
const rc_modified_memref_t* modified_memref = modified_memref_list->items;
const rc_modified_memref_t* modified_memref_end = modified_memref + modified_memref_list->count;
for (; modified_memref < modified_memref_end; ++modified_memref) {
if ((const rc_modified_memref_t*)src_memref == modified_memref) {
rc_modified_memref_t* dst_modified_memref = rc_alloc_modified_memref(parse, modified_memref->memref.value.size,
&modified_memref->parent, modified_memref->modifier_type, &modified_memref->modifier);
operand->value.memref = &dst_modified_memref->memref;
return;
}
}
}
}
else {
const rc_memref_list_t* memref_list = &memrefs->memrefs;
for (; memref_list; memref_list = memref_list->next) {
const rc_memref_t* memref = memref_list->items;
const rc_memref_t* memref_end = memref + memref_list->count;
for (; memref < memref_end; ++memref) {
if (src_memref == memref) {
operand->value.memref = rc_alloc_memref(parse, memref->address, memref->value.size);
return;
}
}
}
}
}
}
void rc_preparse_copy_memrefs(rc_parse_state_t* parse, rc_memrefs_t* memrefs)
{
const rc_memref_list_t* memref_list = &memrefs->memrefs;
const rc_modified_memref_list_t* modified_memref_list = &memrefs->modified_memrefs;
for (; memref_list; memref_list = memref_list->next) {
const rc_memref_t* memref = memref_list->items;
const rc_memref_t* memref_end = memref + memref_list->count;
for (; memref < memref_end; ++memref)
rc_alloc_memref(parse, memref->address, memref->value.size);
}
for (; modified_memref_list; modified_memref_list = modified_memref_list->next) {
rc_modified_memref_t* modified_memref = modified_memref_list->items;
const rc_modified_memref_t* modified_memref_end = modified_memref + modified_memref_list->count;
for (; modified_memref < modified_memref_end; ++modified_memref) {
rc_preparse_sync_operand(&modified_memref->parent, parse, memrefs);
rc_preparse_sync_operand(&modified_memref->modifier, parse, memrefs);
rc_alloc_modified_memref(parse, modified_memref->memref.value.size,
&modified_memref->parent, modified_memref->modifier_type, &modified_memref->modifier);
}
}
}
void rc_reset_parse_state(rc_parse_state_t* parse, void* buffer, lua_State* L, int funcs_ndx)
{
#ifndef RC_DISABLE_LUA
parse->L = L;
parse->funcs_ndx = funcs_ndx;
#else
(void)L;
(void)funcs_ndx;
#endif
parse->buffer = buffer;
parse->offset = 0;
parse->memrefs = NULL;
parse->existing_memrefs = NULL;
parse->variables = NULL;
parse->measured_target = 0;
parse->lines_read = 0;
parse->addsource_oper = RC_OPERATOR_NONE;
parse->addsource_parent.type = RC_OPERAND_NONE;
parse->indirect_parent.type = RC_OPERAND_NONE;
parse->remember.type = RC_OPERAND_NONE;
parse->is_value = 0;
parse->has_required_hits = 0;
parse->measured_as_percent = 0;
parse->scratch.strings = NULL;
}
void rc_init_parse_state(rc_parse_state_t* parse, void* buffer, lua_State* L, int funcs_ndx)
{
/* could use memset here, but rc_parse_state_t contains a 512 byte buffer that doesn't need to be initialized */
parse->offset = 0;
parse->L = L;
parse->funcs_ndx = funcs_ndx;
parse->buffer = buffer;
parse->scratch.strings = NULL;
rc_buffer_init(&parse->scratch.buffer);
memset(&parse->scratch.objs, 0, sizeof(parse->scratch.objs));
parse->first_memref = 0;
parse->variables = 0;
parse->measured_target = 0;
parse->lines_read = 0;
parse->has_required_hits = 0;
parse->measured_as_percent = 0;
rc_reset_parse_state(parse, buffer, L, funcs_ndx);
}
void rc_destroy_parse_state(rc_parse_state_t* parse)

View File

@@ -1,6 +1,7 @@
#include "rc_internal.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
static int rc_test_condition_compare(uint32_t value1, uint32_t value2, uint8_t oper) {
@@ -15,7 +16,7 @@ static int rc_test_condition_compare(uint32_t value1, uint32_t value2, uint8_t o
}
}
static char rc_condition_determine_comparator(const rc_condition_t* self) {
static uint8_t rc_condition_determine_comparator(const rc_condition_t* self) {
switch (self->oper) {
case RC_OPERATOR_EQ:
case RC_OPERATOR_NE:
@@ -31,7 +32,8 @@ static char rc_condition_determine_comparator(const rc_condition_t* self) {
}
if ((self->operand1.type == RC_OPERAND_ADDRESS || self->operand1.type == RC_OPERAND_DELTA) &&
!self->operand1.value.memref->value.is_indirect && !rc_operand_is_float(&self->operand1)) {
/* TODO: allow modified memref comparisons */
self->operand1.value.memref->value.memref_type == RC_MEMREF_TYPE_MEMREF && !rc_operand_is_float(&self->operand1)) {
/* left side is an integer memory reference */
int needs_translate = (self->operand1.size != self->operand1.value.memref->value.size);
@@ -43,7 +45,7 @@ static char rc_condition_determine_comparator(const rc_condition_t* self) {
return needs_translate ? RC_PROCESSING_COMPARE_DELTA_TO_CONST_TRANSFORMED : RC_PROCESSING_COMPARE_DELTA_TO_CONST;
}
else if ((self->operand2.type == RC_OPERAND_ADDRESS || self->operand2.type == RC_OPERAND_DELTA) &&
!self->operand2.value.memref->value.is_indirect && !rc_operand_is_float(&self->operand2)) {
self->operand2.value.memref->value.memref_type == RC_MEMREF_TYPE_MEMREF && !rc_operand_is_float(&self->operand2)) {
/* right side is an integer memory reference */
const int is_same_memref = (self->operand1.value.memref == self->operand2.value.memref);
needs_translate |= (self->operand2.size != self->operand2.value.memref->value.size);
@@ -161,17 +163,45 @@ static int rc_parse_operator(const char** memaddr) {
}
}
rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse, uint8_t is_indirect) {
rc_condition_t* self;
void rc_condition_convert_to_operand(const rc_condition_t* condition, rc_operand_t* operand, rc_parse_state_t* parse) {
if (condition->oper == RC_OPERATOR_NONE) {
if (operand != &condition->operand1)
memcpy(operand, &condition->operand1, sizeof(*operand));
}
else {
uint8_t new_size = RC_MEMSIZE_32_BITS;
if (rc_operand_is_float(&condition->operand1) || rc_operand_is_float(&condition->operand2))
new_size = RC_MEMSIZE_FLOAT;
/* NOTE: this makes the operand include the modification, but we have to also
* leave the modification in the condition so the condition reflects the actual
* definition. This doesn't affect the evaluation logic since this method is only
* called for combining conditions and Measured, and the Measured handling function
* ignores the operator assuming it's been handled by a modified memref chain */
operand->value.memref = (rc_memref_t*)rc_alloc_modified_memref(parse,
new_size, &condition->operand1, condition->oper, &condition->operand2);
/* not actually an address, just a non-delta memref read */
operand->type = operand->memref_access_type = RC_OPERAND_ADDRESS;
operand->size = new_size;
}
}
rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse) {
rc_condition_t * self = RC_ALLOC(rc_condition_t, parse);
rc_parse_condition_internal(self, memaddr, parse);
return (parse->offset < 0) ? NULL : self;
}
void rc_parse_condition_internal(rc_condition_t* self, const char** memaddr, rc_parse_state_t* parse) {
const char* aux;
int result;
int can_modify = 0;
aux = *memaddr;
self = RC_ALLOC(rc_condition_t, parse);
self->current_hits = 0;
self->is_true = 0;
self->pause = 0;
self->optimized_comparator = RC_PROCESSING_COMPARE_DEFAULT;
if (*aux != 0 && aux[1] == ':') {
@@ -194,8 +224,11 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
parse->measured_as_percent = 1;
self->type = RC_CONDITION_MEASURED;
break;
/* e f h j l s u v w x y */
default: parse->offset = RC_INVALID_CONDITION_TYPE; return 0;
default:
parse->offset = RC_INVALID_CONDITION_TYPE;
return;
}
aux += 2;
@@ -204,79 +237,63 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
self->type = RC_CONDITION_STANDARD;
}
result = rc_parse_operand(&self->operand1, &aux, is_indirect, parse);
result = rc_parse_operand(&self->operand1, &aux, parse);
if (result < 0) {
parse->offset = result;
return 0;
return;
}
result = rc_parse_operator(&aux);
if (result < 0) {
parse->offset = result;
return 0;
return;
}
self->oper = (char)result;
switch (self->oper) {
case RC_OPERATOR_NONE:
/* non-modifying statements must have a second operand */
if (!can_modify) {
/* measured does not require a second operand when used in a value */
if (self->type != RC_CONDITION_MEASURED) {
parse->offset = RC_INVALID_OPERATOR;
return 0;
}
self->oper = (uint8_t)result;
if (self->oper == RC_OPERATOR_NONE) {
/* non-modifying statements must have a second operand */
if (!can_modify) {
/* measured does not require a second operand when used in a value */
if (self->type != RC_CONDITION_MEASURED) {
parse->offset = RC_INVALID_OPERATOR;
return;
}
}
/* provide dummy operand of '1' and no required hits */
self->operand2.type = RC_OPERAND_CONST;
self->operand2.value.num = 1;
self->required_hits = 0;
*memaddr = aux;
return self;
/* provide dummy operand of '1' and no required hits */
rc_operand_set_const(&self->operand2, 1);
self->required_hits = 0;
*memaddr = aux;
return;
}
case RC_OPERATOR_MULT:
case RC_OPERATOR_DIV:
case RC_OPERATOR_AND:
case RC_OPERATOR_XOR:
case RC_OPERATOR_MOD:
case RC_OPERATOR_ADD:
case RC_OPERATOR_SUB:
/* modifying operators are only valid on modifying statements */
if (can_modify)
if (can_modify && !rc_operator_is_modifying(self->oper)) {
/* comparison operators are not valid on modifying statements */
switch (self->type) {
case RC_CONDITION_ADD_SOURCE:
case RC_CONDITION_SUB_SOURCE:
case RC_CONDITION_ADD_ADDRESS:
case RC_CONDITION_REMEMBER:
/* prevent parse errors on legacy achievements where a condition was present before changing the type */
self->oper = RC_OPERATOR_NONE;
break;
/* fallthrough */
default:
/* comparison operators are not valid on modifying statements */
if (can_modify) {
switch (self->type) {
case RC_CONDITION_ADD_SOURCE:
case RC_CONDITION_SUB_SOURCE:
case RC_CONDITION_ADD_ADDRESS:
case RC_CONDITION_REMEMBER:
/* prevent parse errors on legacy achievements where a condition was present before changing the type */
self->oper = RC_OPERATOR_NONE;
break;
default:
parse->offset = RC_INVALID_OPERATOR;
return 0;
}
}
break;
default:
parse->offset = RC_INVALID_OPERATOR;
return;
}
}
result = rc_parse_operand(&self->operand2, &aux, is_indirect, parse);
result = rc_parse_operand(&self->operand2, &aux, parse);
if (result < 0) {
parse->offset = result;
return 0;
return;
}
if (self->oper == RC_OPERATOR_NONE) {
/* if operator is none, explicitly clear out the right side */
self->operand2.type = RC_OPERAND_CONST;
self->operand2.value.num = 0;
rc_operand_set_const(&self->operand2, 0);
}
if (*aux == '(') {
@@ -285,7 +302,7 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
if (end == aux || *end != ')') {
parse->offset = RC_INVALID_REQUIRED_HITS;
return 0;
return;
}
/* if operator is none, explicitly clear out the required hits */
@@ -302,7 +319,7 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
if (end == aux || *end != '.') {
parse->offset = RC_INVALID_REQUIRED_HITS;
return 0;
return;
}
/* if operator is none, explicitly clear out the required hits */
@@ -321,7 +338,140 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
self->optimized_comparator = rc_condition_determine_comparator(self);
*memaddr = aux;
return self;
}
void rc_condition_update_parse_state(rc_condition_t* condition, rc_parse_state_t* parse) {
/* type of values in the chain are determined by the parent.
* the last element of a chain is determined by the operand
*
* 1 + 1.5 + 1.75 + 1.0 => (int)1 + (int)1 + (int)1 + (float)1 = (float)4.0
* 1.0 + 1.5 + 1.75 + 1.0 => (float)1.0 + (float)1.5 + (float)1.75 + (float)1.0 = (float)5.25
* 1.0 + 1.5 + 1.75 + 1 => (float)1.0 + (float)1.5 + (float)1.75 + (int)1 = (int)5
*/
switch (condition->type) {
case RC_CONDITION_ADD_ADDRESS:
if (condition->oper != RC_OPERAND_NONE)
rc_condition_convert_to_operand(condition, &parse->indirect_parent, parse);
else
memcpy(&parse->indirect_parent, &condition->operand1, sizeof(parse->indirect_parent));
break;
case RC_CONDITION_ADD_SOURCE:
if (parse->addsource_parent.type == RC_OPERAND_NONE) {
rc_condition_convert_to_operand(condition, &parse->addsource_parent, parse);
}
else {
rc_operand_t cond_operand;
/* type determined by parent */
const uint8_t new_size = rc_operand_is_float(&parse->addsource_parent) ? RC_MEMSIZE_FLOAT : RC_MEMSIZE_32_BITS;
rc_condition_convert_to_operand(condition, &cond_operand, parse);
rc_operand_addsource(&cond_operand, parse, new_size);
memcpy(&parse->addsource_parent, &cond_operand, sizeof(cond_operand));
}
parse->addsource_oper = RC_OPERATOR_ADD;
parse->indirect_parent.type = RC_OPERAND_NONE;
break;
case RC_CONDITION_SUB_SOURCE:
if (parse->addsource_parent.type == RC_OPERAND_NONE) {
rc_condition_convert_to_operand(condition, &parse->addsource_parent, parse);
parse->addsource_oper = RC_OPERATOR_SUB_PARENT;
}
else {
rc_operand_t cond_operand;
/* type determined by parent */
const uint8_t new_size = rc_operand_is_float(&parse->addsource_parent) ? RC_MEMSIZE_FLOAT : RC_MEMSIZE_32_BITS;
if (parse->addsource_oper == RC_OPERATOR_ADD && !rc_operand_is_memref(&parse->addsource_parent)) {
/* if the previous element was a constant we have to turn it into a memref by adding zero */
rc_modified_memref_t* memref;
rc_operand_t zero;
rc_operand_set_const(&zero, 0);
memref = rc_alloc_modified_memref(parse,
parse->addsource_parent.size, &parse->addsource_parent, RC_OPERATOR_ADD, &zero);
parse->addsource_parent.value.memref = (rc_memref_t*)memref;
parse->addsource_parent.type = RC_OPERAND_ADDRESS;
}
else if (parse->addsource_oper == RC_OPERATOR_SUB_PARENT) {
/* if the previous element was also a SubSource, we have to insert a 0 and start subtracting from there */
rc_modified_memref_t* negate;
rc_operand_t zero;
if (rc_operand_is_float(&parse->addsource_parent))
rc_operand_set_float_const(&zero, 0.0);
else
rc_operand_set_const(&zero, 0);
negate = rc_alloc_modified_memref(parse, new_size, &parse->addsource_parent, RC_OPERATOR_SUB_PARENT, &zero);
parse->addsource_parent.value.memref = (rc_memref_t*)negate;
parse->addsource_parent.size = zero.size;
}
/* subtract the condition from the chain */
parse->addsource_oper = rc_operand_is_memref(&parse->addsource_parent) ? RC_OPERATOR_SUB : RC_OPERATOR_SUB_PARENT;
rc_condition_convert_to_operand(condition, &cond_operand, parse);
rc_operand_addsource(&cond_operand, parse, new_size);
memcpy(&parse->addsource_parent, &cond_operand, sizeof(cond_operand));
/* indicate the next value can be added to the chain */
parse->addsource_oper = RC_OPERATOR_ADD;
}
parse->indirect_parent.type = RC_OPERAND_NONE;
break;
case RC_CONDITION_REMEMBER:
rc_condition_convert_to_operand(condition, &condition->operand1, parse);
if (parse->addsource_parent.type != RC_OPERAND_NONE) {
/* type determined by leaf */
rc_operand_addsource(&condition->operand1, parse, condition->operand1.size);
}
memcpy(&parse->remember, &condition->operand1, sizeof(parse->remember));
parse->addsource_parent.type = RC_OPERAND_NONE;
parse->indirect_parent.type = RC_OPERAND_NONE;
break;
case RC_CONDITION_MEASURED:
/* Measured condition can have modifiers in values */
if (parse->is_value) {
switch (condition->oper) {
case RC_OPERATOR_AND:
case RC_OPERATOR_XOR:
case RC_OPERATOR_DIV:
case RC_OPERATOR_MULT:
case RC_OPERATOR_MOD:
case RC_OPERATOR_ADD:
case RC_OPERATOR_SUB:
rc_condition_convert_to_operand(condition, &condition->operand1, parse);
break;
default:
break;
}
}
/* fallthrough */ /* to default */
default:
if (parse->addsource_parent.type != RC_OPERAND_NONE) {
/* type determined by leaf */
rc_operand_addsource(&condition->operand1, parse, condition->operand1.size);
if (parse->buffer)
condition->optimized_comparator = rc_condition_determine_comparator(condition);
}
parse->addsource_parent.type = RC_OPERAND_NONE;
parse->indirect_parent.type = RC_OPERAND_NONE;
break;
}
}
int rc_condition_is_combining(const rc_condition_t* self) {
@@ -500,41 +650,35 @@ static int rc_test_condition_compare_delta_to_memref_transformed(rc_condition_t*
int rc_test_condition(rc_condition_t* self, rc_eval_state_t* eval_state) {
rc_typed_value_t value1, value2;
if (eval_state->add_value.type != RC_VALUE_TYPE_NONE) {
/* if there's an accumulator, we can't use the optimized comparators */
rc_evaluate_operand(&value1, &self->operand1, eval_state);
rc_typed_value_add(&value1, &eval_state->add_value);
} else {
/* use an optimized comparator whenever possible */
switch (self->optimized_comparator) {
case RC_PROCESSING_COMPARE_MEMREF_TO_CONST:
return rc_test_condition_compare_memref_to_const(self);
case RC_PROCESSING_COMPARE_MEMREF_TO_DELTA:
return rc_test_condition_compare_memref_to_delta(self);
case RC_PROCESSING_COMPARE_MEMREF_TO_MEMREF:
return rc_test_condition_compare_memref_to_memref(self);
case RC_PROCESSING_COMPARE_DELTA_TO_CONST:
return rc_test_condition_compare_delta_to_const(self);
case RC_PROCESSING_COMPARE_DELTA_TO_MEMREF:
return rc_test_condition_compare_delta_to_memref(self);
case RC_PROCESSING_COMPARE_MEMREF_TO_CONST_TRANSFORMED:
return rc_test_condition_compare_memref_to_const_transformed(self);
case RC_PROCESSING_COMPARE_MEMREF_TO_DELTA_TRANSFORMED:
return rc_test_condition_compare_memref_to_delta_transformed(self);
case RC_PROCESSING_COMPARE_MEMREF_TO_MEMREF_TRANSFORMED:
return rc_test_condition_compare_memref_to_memref_transformed(self);
case RC_PROCESSING_COMPARE_DELTA_TO_CONST_TRANSFORMED:
return rc_test_condition_compare_delta_to_const_transformed(self);
case RC_PROCESSING_COMPARE_DELTA_TO_MEMREF_TRANSFORMED:
return rc_test_condition_compare_delta_to_memref_transformed(self);
case RC_PROCESSING_COMPARE_ALWAYS_TRUE:
return 1;
case RC_PROCESSING_COMPARE_ALWAYS_FALSE:
return 0;
default:
rc_evaluate_operand(&value1, &self->operand1, eval_state);
break;
}
/* use an optimized comparator whenever possible */
switch (self->optimized_comparator) {
case RC_PROCESSING_COMPARE_MEMREF_TO_CONST:
return rc_test_condition_compare_memref_to_const(self);
case RC_PROCESSING_COMPARE_MEMREF_TO_DELTA:
return rc_test_condition_compare_memref_to_delta(self);
case RC_PROCESSING_COMPARE_MEMREF_TO_MEMREF:
return rc_test_condition_compare_memref_to_memref(self);
case RC_PROCESSING_COMPARE_DELTA_TO_CONST:
return rc_test_condition_compare_delta_to_const(self);
case RC_PROCESSING_COMPARE_DELTA_TO_MEMREF:
return rc_test_condition_compare_delta_to_memref(self);
case RC_PROCESSING_COMPARE_MEMREF_TO_CONST_TRANSFORMED:
return rc_test_condition_compare_memref_to_const_transformed(self);
case RC_PROCESSING_COMPARE_MEMREF_TO_DELTA_TRANSFORMED:
return rc_test_condition_compare_memref_to_delta_transformed(self);
case RC_PROCESSING_COMPARE_MEMREF_TO_MEMREF_TRANSFORMED:
return rc_test_condition_compare_memref_to_memref_transformed(self);
case RC_PROCESSING_COMPARE_DELTA_TO_CONST_TRANSFORMED:
return rc_test_condition_compare_delta_to_const_transformed(self);
case RC_PROCESSING_COMPARE_DELTA_TO_MEMREF_TRANSFORMED:
return rc_test_condition_compare_delta_to_memref_transformed(self);
case RC_PROCESSING_COMPARE_ALWAYS_TRUE:
return 1;
case RC_PROCESSING_COMPARE_ALWAYS_FALSE:
return 0;
default:
rc_evaluate_operand(&value1, &self->operand1, eval_state);
break;
}
rc_evaluate_operand(&value2, &self->operand2, eval_state);
@@ -548,38 +692,5 @@ void rc_evaluate_condition_value(rc_typed_value_t* value, rc_condition_t* self,
rc_evaluate_operand(value, &self->operand1, eval_state);
rc_evaluate_operand(&amount, &self->operand2, eval_state);
switch (self->oper) {
case RC_OPERATOR_MULT:
rc_typed_value_multiply(value, &amount);
break;
case RC_OPERATOR_DIV:
rc_typed_value_divide(value, &amount);
break;
case RC_OPERATOR_AND:
rc_typed_value_convert(value, RC_VALUE_TYPE_UNSIGNED);
rc_typed_value_convert(&amount, RC_VALUE_TYPE_UNSIGNED);
value->value.u32 &= amount.value.u32;
break;
case RC_OPERATOR_XOR:
rc_typed_value_convert(value, RC_VALUE_TYPE_UNSIGNED);
rc_typed_value_convert(&amount, RC_VALUE_TYPE_UNSIGNED);
value->value.u32 ^= amount.value.u32;
break;
case RC_OPERATOR_MOD:
rc_typed_value_modulus(value, &amount);
break;
case RC_OPERATOR_ADD:
rc_typed_value_add(value, &amount);
break;
case RC_OPERATOR_SUB:
rc_typed_value_negate(&amount);
rc_typed_value_add(value, &amount);
break;
}
rc_typed_value_combine(value, &amount, self->oper);
}

File diff suppressed because it is too large Load Diff

View File

@@ -72,6 +72,9 @@ const char* rc_console_name(uint32_t console_id)
case RC_CONSOLE_FAIRCHILD_CHANNEL_F:
return "Fairchild Channel F";
case RC_CONSOLE_FAMICOM_DISK_SYSTEM:
return "Famicom Disk System";
case RC_CONSOLE_FM_TOWNS:
return "FM Towns";
@@ -380,14 +383,18 @@ static const rc_memory_regions_t rc_memory_regions_colecovision = { _rc_memory_r
/* ===== Commodore 64 ===== */
/* https://www.c64-wiki.com/wiki/Memory_Map */
/* https://sta.c64.org/cbm64mem.html */
/* NOTE: Several blocks of C64 memory can be bank-switched for ROM data (see https://www.c64-wiki.com/wiki/Bank_Switching).
* Achievement triggers rely on values changing, so we don't really need to look at the ROM data.
* The achievement logic assumes the RAM data is always present in the bankable blocks. As such,
* clients providing memory to achievements should always return the RAM values at the queried address. */
static const rc_memory_region_t _rc_memory_regions_c64[] = {
{ 0x000000U, 0x0003FFU, 0x000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Kernel RAM" },
{ 0x000400U, 0x0007FFU, 0x000400U, RC_MEMORY_TYPE_VIDEO_RAM, "Screen RAM" },
{ 0x000800U, 0x009FFFU, 0x000800U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }, /* BASIC Program Storage Area */
{ 0x00A000U, 0x00BFFFU, 0x00A000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }, /* Machine Language Storage Area / BASIC ROM Area */
{ 0x00C000U, 0x00CFFFU, 0x00C000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }, /* Machine Language Storage Area */
{ 0x00D000U, 0x00DFFFU, 0x00D000U, RC_MEMORY_TYPE_SYSTEM_RAM, "I/O Area" }, /* also Character ROM */
{ 0x00E000U, 0x00FFFFU, 0x00E000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }, /* Machine Language Storage Area / Kernal ROM */
{ 0x000800U, 0x009FFFU, 0x000800U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }, /* BASIC area. $8000-$9FFF can bank to cartridge ROM */
{ 0x00A000U, 0x00BFFFU, 0x00A000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }, /* can bank to BASIC ROM or cartridge ROM */
{ 0x00C000U, 0x00CFFFU, 0x00C000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
{ 0x00D000U, 0x00DFFFU, 0x00D000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }, /* can bank to I/O Area or character ROM */
{ 0x00E000U, 0x00FFFFU, 0x00E000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }, /* can bank to kernel ROM */
};
static const rc_memory_regions_t rc_memory_regions_c64 = { _rc_memory_regions_c64, 7 };
@@ -423,6 +430,24 @@ static const rc_memory_region_t _rc_memory_regions_fairchild_channel_f[] = {
};
static const rc_memory_regions_t rc_memory_regions_fairchild_channel_f = { _rc_memory_regions_fairchild_channel_f, 4 };
/* ===== Famicon Disk System ===== */
/* https://fms.komkon.org/EMUL8/NES.html */
static const rc_memory_region_t _rc_memory_regions_famicom_disk_system[] = {
{ 0x0000U, 0x07FFU, 0x0000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
{ 0x0800U, 0x0FFFU, 0x0000U, RC_MEMORY_TYPE_VIRTUAL_RAM, "Mirror RAM" }, /* duplicates memory from $0000-$07FF */
{ 0x1000U, 0x17FFU, 0x0000U, RC_MEMORY_TYPE_VIRTUAL_RAM, "Mirror RAM" }, /* duplicates memory from $0000-$07FF */
{ 0x1800U, 0x1FFFU, 0x0000U, RC_MEMORY_TYPE_VIRTUAL_RAM, "Mirror RAM" }, /* duplicates memory from $0000-$07FF */
{ 0x2000U, 0x2007U, 0x2000U, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "PPU Register" },
{ 0x2008U, 0x3FFFU, 0x2008U, RC_MEMORY_TYPE_VIRTUAL_RAM, "Mirrored PPU Register" }, /* repeats every 8 bytes */
{ 0x4000U, 0x4017U, 0x4000U, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "APU and I/O register" },
{ 0x4018U, 0x401FU, 0x4018U, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "APU and I/O test register" },
{ 0x4020U, 0x40FFU, 0x4020U, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "FDS I/O registers"},
{ 0x4100U, 0x5FFFU, 0x4100U, RC_MEMORY_TYPE_READONLY, "Cartridge data"}, /* varies by mapper */
{ 0x6000U, 0xDFFFU, 0x6000U, RC_MEMORY_TYPE_SYSTEM_RAM, "FDS RAM"},
{ 0xE000U, 0xFFFFU, 0xE000U, RC_MEMORY_TYPE_READONLY, "FDS BIOS ROM"},
};
static const rc_memory_regions_t rc_memory_regions_famicom_disk_system = { _rc_memory_regions_famicom_disk_system, 12 };
/* ===== GameBoy / MegaDuck ===== */
static const rc_memory_region_t _rc_memory_regions_gameboy[] = {
{ 0x000000U, 0x0000FFU, 0x000000U, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "Interrupt vector" },
@@ -694,18 +719,6 @@ static const rc_memory_region_t _rc_memory_regions_nes[] = {
{ 0x4020U, 0x5FFFU, 0x4020U, RC_MEMORY_TYPE_READONLY, "Cartridge data"}, /* varies by mapper */
{ 0x6000U, 0x7FFFU, 0x6000U, RC_MEMORY_TYPE_SAVE_RAM, "Cartridge RAM"},
{ 0x8000U, 0xFFFFU, 0x8000U, RC_MEMORY_TYPE_READONLY, "Cartridge ROM"},
/* NOTE: these are the correct mappings for FDS: https://fms.komkon.org/EMUL8/NES.html
* 0x6000-0xDFFF is RAM on the FDS system and 0xE000-0xFFFF is FDS BIOS.
* If the core implements a memory map, we should still be able to translate the addresses
* correctly as we only use the classifications when a memory map is not provided
{ 0x4020U, 0x40FFU, 0x4020U, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "FDS I/O registers"},
{ 0x4100U, 0x5FFFU, 0x4100U, RC_MEMORY_TYPE_READONLY, "Cartridge data"}, // varies by mapper
{ 0x6000U, 0xDFFFU, 0x6000U, RC_MEMORY_TYPE_SYSTEM_RAM, "FDS RAM"},
{ 0xE000U, 0xFFFFU, 0xE000U, RC_MEMORY_TYPE_READONLY, "FDS BIOS ROM"},
*/
};
static const rc_memory_regions_t rc_memory_regions_nes = { _rc_memory_regions_nes, 11 };
@@ -868,10 +881,18 @@ static const rc_memory_regions_t rc_memory_regions_scv = { _rc_memory_regions_sc
/* ===== Super Nintendo ===== */
/* https://en.wikibooks.org/wiki/Super_NES_Programming/SNES_memory_map#LoROM */
static const rc_memory_region_t _rc_memory_regions_snes[] = {
{ 0x000000U, 0x01FFFFU, 0x7E0000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
{ 0x020000U, 0x03FFFFU, 0xFE0000U, RC_MEMORY_TYPE_SAVE_RAM, "Cartridge RAM" }
{ 0x000000U, 0x01FFFFU, 0x07E0000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
/* Cartridge RAM here could be in a variety of places in SNES memory, depending on the ROM type.
* Due to this, we place Cartridge RAM outside of the possible native addressing space.
* Note that this also covers SA-1 BW-RAM (which is exposed as RETRO_MEMORY_SAVE_RAM for libretro).
*/
{ 0x020000U, 0x09FFFFU, 0x1000000U, RC_MEMORY_TYPE_SAVE_RAM, "Cartridge RAM" },
/* I-RAM on the SA-1 is normally at 0x003000. However, this address typically just has a mirror of System RAM for other ROM types.
* To avoid conflicts, don't use 0x003000, instead map it outside of the possible native addressing space.
*/
{ 0x0A0000U, 0x0A07FFU, 0x1080000U, RC_MEMORY_TYPE_SYSTEM_RAM, "I-RAM (SA-1)" }
};
static const rc_memory_regions_t rc_memory_regions_snes = { _rc_memory_regions_snes, 2 };
static const rc_memory_regions_t rc_memory_regions_snes = { _rc_memory_regions_snes, 3 };
/* ===== Thomson TO8 ===== */
/* https://github.com/mamedev/mame/blob/master/src/mame/drivers/thomson.cpp#L1617 */
@@ -1046,7 +1067,10 @@ const rc_memory_regions_t* rc_console_memory_regions(uint32_t console_id)
case RC_CONSOLE_FAIRCHILD_CHANNEL_F:
return &rc_memory_regions_fairchild_channel_f;
case RC_CONSOLE_FAMICOM_DISK_SYSTEM:
return &rc_memory_regions_famicom_disk_system;
case RC_CONSOLE_GAMEBOY:
return &rc_memory_regions_gameboy;

View File

@@ -29,7 +29,6 @@ void rc_parse_lboard_internal(rc_lboard_t* self, const char* memaddr, rc_parse_s
if (*memaddr && *memaddr != ':') {
found |= RC_LBOARD_START;
rc_parse_trigger_internal(&self->start, &memaddr, parse);
self->start.memrefs = 0;
}
}
else if ((memaddr[0] == 'c' || memaddr[0] == 'C') &&
@@ -44,7 +43,6 @@ void rc_parse_lboard_internal(rc_lboard_t* self, const char* memaddr, rc_parse_s
if (*memaddr && *memaddr != ':') {
found |= RC_LBOARD_CANCEL;
rc_parse_trigger_internal(&self->cancel, &memaddr, parse);
self->cancel.memrefs = 0;
}
}
else if ((memaddr[0] == 's' || memaddr[0] == 'S') &&
@@ -59,7 +57,6 @@ void rc_parse_lboard_internal(rc_lboard_t* self, const char* memaddr, rc_parse_s
if (*memaddr && *memaddr != ':') {
found |= RC_LBOARD_SUBMIT;
rc_parse_trigger_internal(&self->submit, &memaddr, parse);
self->submit.memrefs = 0;
}
}
else if ((memaddr[0] == 'v' || memaddr[0] == 'V') &&
@@ -74,7 +71,6 @@ void rc_parse_lboard_internal(rc_lboard_t* self, const char* memaddr, rc_parse_s
if (*memaddr && *memaddr != ':') {
found |= RC_LBOARD_VALUE;
rc_parse_value_internal(&self->value, &memaddr, parse);
self->value.memrefs = 0;
}
}
else if ((memaddr[0] == 'p' || memaddr[0] == 'P') &&
@@ -91,7 +87,6 @@ void rc_parse_lboard_internal(rc_lboard_t* self, const char* memaddr, rc_parse_s
self->progress = RC_ALLOC(rc_value_t, parse);
rc_parse_value_internal(self->progress, &memaddr, parse);
self->progress->memrefs = 0;
}
}
@@ -130,44 +125,55 @@ void rc_parse_lboard_internal(rc_lboard_t* self, const char* memaddr, rc_parse_s
}
self->state = RC_LBOARD_STATE_WAITING;
self->has_memrefs = 0;
}
int rc_lboard_size(const char* memaddr) {
rc_lboard_t* self;
rc_parse_state_t parse;
rc_memref_t* first_memref;
rc_init_parse_state(&parse, 0, 0, 0);
rc_init_parse_state_memrefs(&parse, &first_memref);
rc_lboard_with_memrefs_t* lboard;
rc_preparse_state_t preparse;
rc_init_preparse_state(&preparse, NULL, 0);
self = RC_ALLOC(rc_lboard_t, &parse);
rc_parse_lboard_internal(self, memaddr, &parse);
lboard = RC_ALLOC(rc_lboard_with_memrefs_t, &preparse.parse);
rc_parse_lboard_internal(&lboard->lboard, memaddr, &preparse.parse);
rc_preparse_alloc_memrefs(NULL, &preparse);
rc_destroy_parse_state(&parse);
return parse.offset;
rc_destroy_preparse_state(&preparse);
return preparse.parse.offset;
}
rc_lboard_t* rc_parse_lboard(void* buffer, const char* memaddr, lua_State* L, int funcs_ndx) {
rc_lboard_t* self;
rc_parse_state_t parse;
rc_lboard_with_memrefs_t* lboard;
rc_preparse_state_t preparse;
if (!buffer || !memaddr)
return 0;
rc_init_parse_state(&parse, buffer, L, funcs_ndx);
rc_init_preparse_state(&preparse, L, funcs_ndx);
lboard = RC_ALLOC(rc_lboard_with_memrefs_t, &preparse.parse);
rc_parse_lboard_internal(&lboard->lboard, memaddr, &preparse.parse);
self = RC_ALLOC(rc_lboard_t, &parse);
rc_init_parse_state_memrefs(&parse, &self->memrefs);
rc_reset_parse_state(&preparse.parse, buffer, L, funcs_ndx);
lboard = RC_ALLOC(rc_lboard_with_memrefs_t, &preparse.parse);
rc_preparse_alloc_memrefs(&lboard->memrefs, &preparse);
rc_parse_lboard_internal(self, memaddr, &parse);
rc_parse_lboard_internal(&lboard->lboard, memaddr, &preparse.parse);
lboard->lboard.has_memrefs = 1;
rc_destroy_parse_state(&parse);
return (parse.offset >= 0) ? self : 0;
rc_destroy_preparse_state(&preparse);
return (preparse.parse.offset >= 0) ? &lboard->lboard : NULL;
}
static void rc_update_lboard_memrefs(rc_lboard_t* self, rc_peek_t peek, void* ud) {
if (self->has_memrefs) {
rc_lboard_with_memrefs_t* lboard = (rc_lboard_with_memrefs_t*)self;
rc_update_memref_values(&lboard->memrefs, peek, ud);
}
}
int rc_evaluate_lboard(rc_lboard_t* self, int32_t* value, rc_peek_t peek, void* peek_ud, lua_State* L) {
int start_ok, cancel_ok, submit_ok;
rc_update_memref_values(self->memrefs, peek, peek_ud);
rc_update_lboard_memrefs(self, peek, peek_ud);
if (self->state == RC_LBOARD_STATE_INACTIVE || self->state == RC_LBOARD_STATE_DISABLED)
return RC_LBOARD_STATE_INACTIVE;

View File

@@ -6,41 +6,232 @@
#define MEMREF_PLACEHOLDER_ADDRESS 0xFFFFFFFF
rc_memref_t* rc_alloc_memref(rc_parse_state_t* parse, uint32_t address, uint8_t size, uint8_t is_indirect) {
rc_memref_t** next_memref;
rc_memref_t* memref;
rc_memref_t* rc_alloc_memref(rc_parse_state_t* parse, uint32_t address, uint8_t size) {
rc_memref_list_t* memref_list = NULL;
rc_memref_t* memref = NULL;
int i;
if (!is_indirect) {
/* attempt to find an existing memref that can be shared */
next_memref = parse->first_memref;
while (*next_memref) {
memref = *next_memref;
if (!memref->value.is_indirect && memref->address == address && memref->value.size == size)
return memref;
for (i = 0; i < 2; i++) {
if (i == 0) {
if (!parse->existing_memrefs)
continue;
next_memref = &memref->next;
memref_list = &parse->existing_memrefs->memrefs;
}
else {
memref_list = &parse->memrefs->memrefs;
}
/* no match found, create a new entry */
memref = RC_ALLOC_SCRATCH(rc_memref_t, parse);
*next_memref = memref;
do
{
const rc_memref_t* memref_stop;
memref = memref_list->items;
memref_stop = memref + memref_list->count;
for (; memref < memref_stop; ++memref) {
if (memref->address == address && memref->value.size == size)
return memref;
}
if (!memref_list->next)
break;
memref_list = memref_list->next;
} while (1);
}
else {
/* indirect references always create a new entry because we can't guarantee that the
* indirection amount will be the same between references. because they aren't shared,
* don't bother putting them in the chain.
*/
memref = RC_ALLOC(rc_memref_t, parse);
/* no match found, find a place to put the new entry */
memref_list = &parse->memrefs->memrefs;
while (memref_list->count == memref_list->capacity && memref_list->next)
memref_list = memref_list->next;
/* create a new entry */
if (memref_list->count < memref_list->capacity) {
memref = &memref_list->items[memref_list->count++];
} else {
const int32_t old_offset = parse->offset;
if (memref_list->capacity != 0) {
memref_list = memref_list->next = RC_ALLOC_SCRATCH(rc_memref_list_t, parse);
memref_list->next = NULL;
}
memref_list->items = RC_ALLOC_ARRAY_SCRATCH(rc_memref_t, 8, parse);
memref_list->count = 1;
memref_list->capacity = 8;
memref_list->allocated = 0;
memref = memref_list->items;
/* in preparse mode, don't count this memory, we'll do a single allocation once we have
* the final total */
if (!parse->buffer)
parse->offset = old_offset;
}
memset(memref, 0, sizeof(*memref));
memref->address = address;
memref->value.memref_type = RC_MEMREF_TYPE_MEMREF;
memref->value.type = RC_VALUE_TYPE_UNSIGNED;
memref->value.size = size;
memref->value.is_indirect = is_indirect;
memref->address = address;
return memref;
}
rc_modified_memref_t* rc_alloc_modified_memref(rc_parse_state_t* parse, uint8_t size, const rc_operand_t* parent,
uint8_t modifier_type, const rc_operand_t* modifier) {
rc_modified_memref_list_t* modified_memref_list = NULL;
rc_modified_memref_t* modified_memref = NULL;
int i = 0;
for (i = 0; i < 2; i++) {
if (i == 0) {
if (!parse->existing_memrefs)
continue;
modified_memref_list = &parse->existing_memrefs->modified_memrefs;
}
else {
modified_memref_list = &parse->memrefs->modified_memrefs;
}
do {
const rc_modified_memref_t* memref_stop;
modified_memref = modified_memref_list->items;
memref_stop = modified_memref + modified_memref_list->count;
for (; modified_memref < memref_stop; ++modified_memref) {
if (modified_memref->memref.value.size == size &&
modified_memref->modifier_type == modifier_type &&
rc_operands_are_equal(&modified_memref->parent, parent) &&
rc_operands_are_equal(&modified_memref->modifier, modifier)) {
return modified_memref;
}
}
if (!modified_memref_list->next)
break;
modified_memref_list = modified_memref_list->next;
} while (1);
}
/* no match found, find a place to put the new entry */
modified_memref_list = &parse->memrefs->modified_memrefs;
while (modified_memref_list->count == modified_memref_list->capacity && modified_memref_list->next)
modified_memref_list = modified_memref_list->next;
/* create a new entry */
if (modified_memref_list->count < modified_memref_list->capacity) {
modified_memref = &modified_memref_list->items[modified_memref_list->count++];
} else {
const int32_t old_offset = parse->offset;
if (modified_memref_list->capacity != 0) {
modified_memref_list = modified_memref_list->next = RC_ALLOC_SCRATCH(rc_modified_memref_list_t, parse);
modified_memref_list->next = NULL;
}
modified_memref_list->items = RC_ALLOC_ARRAY_SCRATCH(rc_modified_memref_t, 8, parse);
modified_memref_list->count = 1;
modified_memref_list->capacity = 8;
modified_memref_list->allocated = 0;
modified_memref = modified_memref_list->items;
/* in preparse mode, don't count this memory, we'll do a single allocation once we have
* the final total */
if (!parse->buffer)
parse->offset = old_offset;
}
memset(modified_memref, 0, sizeof(*modified_memref));
modified_memref->memref.value.memref_type = RC_MEMREF_TYPE_MODIFIED_MEMREF;
modified_memref->memref.value.size = size;
modified_memref->memref.value.type = (size == RC_MEMSIZE_FLOAT) ? RC_VALUE_TYPE_FLOAT : RC_VALUE_TYPE_UNSIGNED;
memcpy(&modified_memref->parent, parent, sizeof(modified_memref->parent));
memcpy(&modified_memref->modifier, modifier, sizeof(modified_memref->modifier));
modified_memref->modifier_type = modifier_type;
modified_memref->memref.address = rc_operand_is_memref(modifier) ? modifier->value.memref->address : modifier->value.num;
return modified_memref;
}
void rc_memrefs_init(rc_memrefs_t* memrefs)
{
memset(memrefs, 0, sizeof(*memrefs));
memrefs->memrefs.capacity = 32;
memrefs->memrefs.items =
(rc_memref_t*)malloc(memrefs->memrefs.capacity * sizeof(rc_memref_t));
memrefs->memrefs.allocated = 1;
memrefs->modified_memrefs.capacity = 16;
memrefs->modified_memrefs.items =
(rc_modified_memref_t*)malloc(memrefs->modified_memrefs.capacity * sizeof(rc_modified_memref_t));
memrefs->modified_memrefs.allocated = 1;
}
void rc_memrefs_destroy(rc_memrefs_t* memrefs)
{
rc_memref_list_t* memref_list = &memrefs->memrefs;
rc_modified_memref_list_t* modified_memref_list = &memrefs->modified_memrefs;
do {
rc_memref_list_t* current_memref_list = memref_list;
memref_list = memref_list->next;
if (current_memref_list->allocated) {
if (current_memref_list->items)
free(current_memref_list->items);
if (current_memref_list != &memrefs->memrefs)
free(current_memref_list);
}
} while (memref_list);
do {
rc_modified_memref_list_t* current_modified_memref_list = modified_memref_list;
modified_memref_list = modified_memref_list->next;
if (current_modified_memref_list->allocated) {
if (current_modified_memref_list->items)
free(current_modified_memref_list->items);
if (current_modified_memref_list != &memrefs->modified_memrefs)
free(current_modified_memref_list);
}
} while (modified_memref_list);
free(memrefs);
}
uint32_t rc_memrefs_count_memrefs(const rc_memrefs_t* memrefs)
{
uint32_t count = 0;
const rc_memref_list_t* memref_list = &memrefs->memrefs;
while (memref_list) {
count += memref_list->count;
memref_list = memref_list->next;
}
return count;
}
uint32_t rc_memrefs_count_modified_memrefs(const rc_memrefs_t* memrefs)
{
uint32_t count = 0;
const rc_modified_memref_list_t* modified_memref_list = &memrefs->modified_memrefs;
while (modified_memref_list) {
count += modified_memref_list->count;
modified_memref_list = modified_memref_list->next;
}
return count;
}
int rc_parse_memref(const char** memaddr, uint8_t* size, uint32_t* address) {
const char* aux = *memaddr;
char* end;
@@ -77,7 +268,12 @@ int rc_parse_memref(const char** memaddr, uint8_t* size, uint32_t* address) {
/* case 'y': case 'Y': 64 bit? */
/* case 'z': case 'Z': 128 bit? */
case '0': case '1': case '2': case '3': case '4':
case '0':
if (*aux == 'x') /* user mistyped an extra 0x: 0x0xabcd */
return RC_INVALID_MEMORY_OPERAND;
/* fallthrough */
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
@@ -485,19 +681,12 @@ void rc_update_memref_value(rc_memref_value_t* memref, uint32_t new_value) {
}
}
void rc_update_memref_values(rc_memref_t* memref, rc_peek_t peek, void* ud) {
while (memref) {
/* indirect memory references are not shared and will be updated in rc_get_memref_value */
if (!memref->value.is_indirect)
rc_update_memref_value(&memref->value, rc_peek_value(memref->address, memref->value.size, peek, ud));
void rc_init_parse_state_memrefs(rc_parse_state_t* parse, rc_memrefs_t* memrefs)
{
if (memrefs)
memset(memrefs, 0, sizeof(*memrefs));
memref = memref->next;
}
}
void rc_init_parse_state_memrefs(rc_parse_state_t* parse, rc_memref_t** memrefs) {
parse->first_memref = memrefs;
*memrefs = 0;
parse->memrefs = memrefs;
}
static uint32_t rc_get_memref_value_value(const rc_memref_value_t* memref, int operand_type) {
@@ -520,12 +709,68 @@ static uint32_t rc_get_memref_value_value(const rc_memref_value_t* memref, int o
}
}
uint32_t rc_get_memref_value(rc_memref_t* memref, int operand_type, rc_eval_state_t* eval_state) {
/* if this is an indirect reference, handle the indirection. */
if (memref->value.is_indirect) {
const uint32_t new_address = memref->address + eval_state->add_address;
rc_update_memref_value(&memref->value, rc_peek_value(new_address, memref->value.size, eval_state->peek, eval_state->peek_userdata));
void rc_get_memref_value(rc_typed_value_t* value, rc_memref_t* memref, int operand_type) {
value->type = memref->value.type;
value->value.u32 = rc_get_memref_value_value(&memref->value, operand_type);
}
uint32_t rc_get_modified_memref_value(const rc_modified_memref_t* memref, rc_peek_t peek, void* ud) {
rc_typed_value_t value, modifier;
rc_evaluate_operand(&value, &memref->parent, NULL);
rc_evaluate_operand(&modifier, &memref->modifier, NULL);
switch (memref->modifier_type) {
case RC_OPERATOR_INDIRECT_READ:
rc_typed_value_add(&value, &modifier);
rc_typed_value_convert(&value, RC_VALUE_TYPE_UNSIGNED);
value.value.u32 = rc_peek_value(value.value.u32, memref->memref.value.size, peek, ud);
value.type = memref->memref.value.type;
break;
case RC_OPERATOR_SUB_PARENT:
rc_typed_value_negate(&value);
rc_typed_value_add(&value, &modifier);
rc_typed_value_convert(&value, memref->memref.value.type);
break;
default:
rc_typed_value_combine(&value, &modifier, memref->modifier_type);
rc_typed_value_convert(&value, memref->memref.value.type);
break;
}
return rc_get_memref_value_value(&memref->value, operand_type);
return value.value.u32;
}
void rc_update_memref_values(rc_memrefs_t* memrefs, rc_peek_t peek, void* ud) {
rc_memref_list_t* memref_list;
rc_modified_memref_list_t* modified_memref_list;
memref_list = &memrefs->memrefs;
do
{
rc_memref_t* memref = memref_list->items;
const rc_memref_t* memref_stop = memref + memref_list->count;
for (; memref < memref_stop; ++memref) {
if (memref->value.type != RC_VALUE_TYPE_NONE)
rc_update_memref_value(&memref->value, rc_peek_value(memref->address, memref->value.size, peek, ud));
}
memref_list = memref_list->next;
} while (memref_list);
modified_memref_list = &memrefs->modified_memrefs;
if (modified_memref_list->count) {
do {
rc_modified_memref_t* modified_memref = modified_memref_list->items;
const rc_modified_memref_t* modified_memref_stop = modified_memref + modified_memref_list->count;
for (; modified_memref < modified_memref_stop; ++modified_memref)
rc_update_memref_value(&modified_memref->memref.value, rc_get_modified_memref_value(modified_memref, peek, ud));
modified_memref_list = modified_memref_list->next;
} while (modified_memref_list);
}
}

View File

@@ -61,11 +61,13 @@ static int rc_parse_operand_lua(rc_operand_t* self, const char** memaddr, rc_par
#endif /* RC_DISABLE_LUA */
self->type = RC_OPERAND_LUA;
self->size = RC_MEMSIZE_32_BITS;
self->memref_access_type = RC_OPERAND_ADDRESS;
*memaddr = aux;
return RC_OK;
}
static int rc_parse_operand_variable(rc_operand_t* self, const char** memaddr) {
static int rc_parse_operand_variable(rc_operand_t* self, const char** memaddr, rc_parse_state_t* parse) {
const char* aux = *memaddr;
size_t i;
char varName[RC_VALUE_MAX_NAME_LENGTH + 1] = { 0 };
@@ -86,6 +88,15 @@ static int rc_parse_operand_variable(rc_operand_t* self, const char** memaddr) {
++aux;
if (strcmp(varName, "recall") == 0) {
if (parse->remember.type == RC_OPERAND_NONE) {
self->value.memref = NULL;
self->size = RC_MEMSIZE_32_BITS;
self->memref_access_type = RC_OPERAND_ADDRESS;
}
else {
memcpy(self, &parse->remember, sizeof(*self));
self->memref_access_type = self->type;
}
self->type = RC_OPERAND_RECALL;
}
else { /* process named variable when feature is available.*/
@@ -96,7 +107,7 @@ static int rc_parse_operand_variable(rc_operand_t* self, const char** memaddr) {
return RC_OK;
}
static int rc_parse_operand_memory(rc_operand_t* self, const char** memaddr, rc_parse_state_t* parse, uint8_t is_indirect) {
static int rc_parse_operand_memory(rc_operand_t* self, const char** memaddr, rc_parse_state_t* parse) {
const char* aux = *memaddr;
uint32_t address;
uint8_t size;
@@ -128,6 +139,8 @@ static int rc_parse_operand_memory(rc_operand_t* self, const char** memaddr, rc_
break;
}
self->memref_access_type = self->type;
ret = rc_parse_memref(&aux, &self->size, &address);
if (ret != RC_OK)
return ret;
@@ -137,13 +150,28 @@ static int rc_parse_operand_memory(rc_operand_t* self, const char** memaddr, rc_
/* if the shared size differs from the requested size and it's a prior operation, we
* have to check to make sure both sizes use the same mask, or the prior value may be
* updated when bits outside the mask are modified, which would make it look like the
* current value once the mask is applied. if the mask differs, create a new
* current value once the mask is applied. if the mask differs, create a new
* non-shared record for tracking the prior data. */
if (rc_memref_mask(size) != rc_memref_mask(self->size))
size = self->size;
}
self->value.memref = rc_alloc_memref(parse, address, size, is_indirect);
if (parse->indirect_parent.type != RC_OPERAND_NONE) {
if (parse->indirect_parent.type == RC_OPERAND_CONST) {
self->value.memref = rc_alloc_memref(parse, address + parse->indirect_parent.value.num, size);
}
else {
rc_operand_t offset;
rc_operand_set_const(&offset, address);
self->value.memref = (rc_memref_t*)rc_alloc_modified_memref(parse,
size, &parse->indirect_parent, RC_OPERATOR_INDIRECT_READ, &offset);
}
}
else {
self->value.memref = rc_alloc_memref(parse, address, size);
}
if (parse->offset < 0)
return parse->offset;
@@ -151,7 +179,7 @@ static int rc_parse_operand_memory(rc_operand_t* self, const char** memaddr, rc_
return RC_OK;
}
int rc_parse_operand(rc_operand_t* self, const char** memaddr, uint8_t is_indirect, rc_parse_state_t* parse) {
int rc_parse_operand(rc_operand_t* self, const char** memaddr, rc_parse_state_t* parse) {
const char* aux = *memaddr;
char* end;
int ret;
@@ -159,8 +187,6 @@ int rc_parse_operand(rc_operand_t* self, const char** memaddr, uint8_t is_indire
int negative;
int allow_decimal = 0;
self->size = RC_MEMSIZE_32_BITS;
switch (*aux) {
case 'h': case 'H': /* hex constant */
if (aux[2] == 'x' || aux[2] == 'X') {
@@ -175,15 +201,14 @@ int rc_parse_operand(rc_operand_t* self, const char** memaddr, uint8_t is_indire
if (value > 0xffffffffU)
value = 0xffffffffU;
self->type = RC_OPERAND_CONST;
self->value.num = (unsigned)value;
rc_operand_set_const(self, (unsigned)value);
aux = end;
break;
case 'f': case 'F': /* floating point constant */
if (isalpha((unsigned char)aux[1])) {
ret = rc_parse_operand_memory(self, &aux, parse, is_indirect);
ret = rc_parse_operand_memory(self, &aux, parse);
if (ret < 0)
return ret;
@@ -211,6 +236,7 @@ int rc_parse_operand(rc_operand_t* self, const char** memaddr, uint8_t is_indire
/* custom parser for decimal values to ignore locale */
unsigned long shift = 1;
unsigned long fraction = 0;
double dbl_val;
aux = end + 1;
if (*aux < '0' || *aux > '9')
@@ -231,19 +257,19 @@ int rc_parse_operand(rc_operand_t* self, const char** memaddr, uint8_t is_indire
/* non-zero fractional part, convert to double and merge in integer portion */
const double dbl_fraction = ((double)fraction) / ((double)shift);
if (negative)
self->value.dbl = ((double)(-((long)value))) - dbl_fraction;
dbl_val = ((double)(-((long)value))) - dbl_fraction;
else
self->value.dbl = (double)value + dbl_fraction;
dbl_val = (double)value + dbl_fraction;
}
else {
/* fractional part is 0, just convert the integer portion */
if (negative)
self->value.dbl = (double)(-((long)value));
dbl_val = (double)(-((long)value));
else
self->value.dbl = (double)value;
dbl_val = (double)value;
}
self->type = RC_OPERAND_FP;
rc_operand_set_float_const(self, dbl_val);
}
else {
/* not a floating point value, make sure something was read and advance the read pointer */
@@ -255,17 +281,15 @@ int rc_parse_operand(rc_operand_t* self, const char** memaddr, uint8_t is_indire
if (value > 0x7fffffffU)
value = 0x7fffffffU;
self->type = RC_OPERAND_CONST;
if (negative)
self->value.num = (unsigned)(-((long)value));
rc_operand_set_const(self, (unsigned)(-((long)value)));
else
self->value.num = (unsigned)value;
rc_operand_set_const(self, (unsigned)value);
}
break;
case '{': /* variable */
++aux;
ret = rc_parse_operand_variable(self, &aux);
ret = rc_parse_operand_variable(self, &aux, parse);
if (ret < 0)
return ret;
@@ -275,7 +299,7 @@ int rc_parse_operand(rc_operand_t* self, const char** memaddr, uint8_t is_indire
if (aux[1] == 'x' || aux[1] == 'X') { /* hex integer constant */
/* fallthrough */ /* to default */
default:
ret = rc_parse_operand_memory(self, &aux, parse, is_indirect);
ret = rc_parse_operand_memory(self, &aux, parse);
if (ret < 0)
return ret;
@@ -292,8 +316,7 @@ int rc_parse_operand(rc_operand_t* self, const char** memaddr, uint8_t is_indire
if (value > 0xffffffffU)
value = 0xffffffffU;
self->type = RC_OPERAND_CONST;
self->value.num = (unsigned)value;
rc_operand_set_const(self, (unsigned)value);
aux = end;
break;
@@ -332,8 +355,74 @@ static int rc_luapeek(lua_State* L) {
#endif /* RC_DISABLE_LUA */
int rc_operand_is_float_memref(const rc_operand_t* self) {
switch (self->size) {
void rc_operand_set_const(rc_operand_t* self, uint32_t value) {
self->size = RC_MEMSIZE_32_BITS;
self->type = RC_OPERAND_CONST;
self->memref_access_type = RC_OPERAND_NONE;
self->value.num = value;
}
void rc_operand_set_float_const(rc_operand_t* self, double value) {
self->size = RC_MEMSIZE_FLOAT;
self->type = RC_OPERAND_FP;
self->memref_access_type = RC_OPERAND_NONE;
self->value.dbl = value;
}
int rc_operands_are_equal(const rc_operand_t* left, const rc_operand_t* right) {
if (left->type != right->type)
return 0;
switch (left->type) {
case RC_OPERAND_CONST:
return (left->value.num == right->value.num);
case RC_OPERAND_FP:
return (left->value.dbl == right->value.dbl);
case RC_OPERAND_RECALL:
return 1;
default:
break;
}
/* comparing two memrefs - look for exact matches on type and size */
if (left->size != right->size || left->value.memref->value.memref_type != right->value.memref->value.memref_type)
return 0;
switch (left->value.memref->value.memref_type) {
case RC_MEMREF_TYPE_MODIFIED_MEMREF:
{
const rc_modified_memref_t* left_memref = (const rc_modified_memref_t*)left->value.memref;
const rc_modified_memref_t* right_memref = (const rc_modified_memref_t*)right->value.memref;
return (left_memref->modifier_type == right_memref->modifier_type &&
rc_operands_are_equal(&left_memref->parent, &right_memref->parent) &&
rc_operands_are_equal(&left_memref->modifier, &right_memref->modifier));
}
default:
return (left->value.memref->address == right->value.memref->address &&
left->value.memref->value.size == right->value.memref->value.size);
}
}
int rc_operator_is_modifying(int oper) {
switch (oper) {
case RC_OPERATOR_AND:
case RC_OPERATOR_XOR:
case RC_OPERATOR_DIV:
case RC_OPERATOR_MULT:
case RC_OPERATOR_MOD:
case RC_OPERATOR_ADD:
case RC_OPERATOR_SUB:
case RC_OPERATOR_NONE: /* NONE operator implies "* 1" */
return 1;
default:
return 0;
}
}
static int rc_memsize_is_float(uint8_t size) {
switch (size) {
case RC_MEMSIZE_FLOAT:
case RC_MEMSIZE_FLOAT_BE:
case RC_MEMSIZE_DOUBLE32:
@@ -347,8 +436,24 @@ int rc_operand_is_float_memref(const rc_operand_t* self) {
}
}
int rc_operand_is_memref(const rc_operand_t* self) {
switch (self->type) {
int rc_operand_is_float_memref(const rc_operand_t* self) {
if (!rc_operand_is_memref(self))
return 0;
if (self->type == RC_OPERAND_RECALL)
return rc_memsize_is_float(self->memref_access_type);
if (self->value.memref->value.memref_type == RC_MEMREF_TYPE_MODIFIED_MEMREF) {
const rc_modified_memref_t* memref = (const rc_modified_memref_t*)self->value.memref;
if (memref->modifier_type != RC_OPERATOR_INDIRECT_READ)
return rc_memsize_is_float(self->value.memref->value.size);
}
return rc_memsize_is_float(self->size);
}
int rc_operand_type_is_memref(uint8_t type) {
switch (type) {
case RC_OPERAND_CONST:
case RC_OPERAND_FP:
case RC_OPERAND_LUA:
@@ -360,6 +465,10 @@ int rc_operand_is_memref(const rc_operand_t* self) {
}
}
int rc_operand_is_memref(const rc_operand_t* self) {
return rc_operand_type_is_memref(self->type);
}
int rc_operand_is_recall(const rc_operand_t* self) {
switch (self->type) {
case RC_OPERAND_RECALL:
@@ -377,7 +486,7 @@ int rc_operand_is_float(const rc_operand_t* self) {
return rc_operand_is_float_memref(self);
}
uint32_t rc_transform_operand_value(uint32_t value, const rc_operand_t* self) {
static uint32_t rc_transform_operand_value(uint32_t value, const rc_operand_t* self) {
switch (self->type)
{
case RC_OPERAND_BCD:
@@ -465,7 +574,44 @@ uint32_t rc_transform_operand_value(uint32_t value, const rc_operand_t* self) {
return value;
}
void rc_evaluate_operand(rc_typed_value_t* result, rc_operand_t* self, rc_eval_state_t* eval_state) {
void rc_operand_addsource(rc_operand_t* self, rc_parse_state_t* parse, uint8_t new_size) {
rc_modified_memref_t* modified_memref;
if (rc_operand_is_memref(&parse->addsource_parent)) {
rc_operand_t modifier;
if ((self->type == RC_OPERAND_DELTA || self->type == RC_OPERAND_PRIOR) &&
self->type == parse->addsource_parent.type) {
/* if adding prev(x) and prev(y), just add x and y and take the prev of that */
memcpy(&modifier, self, sizeof(modifier));
modifier.type = parse->addsource_parent.type = RC_OPERAND_ADDRESS;
modified_memref = rc_alloc_modified_memref(parse,
new_size, &parse->addsource_parent, parse->addsource_oper, &modifier);
}
else {
modified_memref = rc_alloc_modified_memref(parse,
new_size, &parse->addsource_parent, parse->addsource_oper, self);
}
}
else {
/* N + A => A + N */
/* -N + A => A - N */
modified_memref = rc_alloc_modified_memref(parse,
new_size, &parse->addsource_parent, parse->addsource_oper, self);
}
self->value.memref = (rc_memref_t*)modified_memref;
/* if adding a constant, change the type to be address (current value) */
if (!rc_operand_is_memref(self))
self->type = self->memref_access_type = RC_OPERAND_ADDRESS;
/* result of an AddSource operation is always a 32-bit integer (even if parent or modifier is a float) */
self->size = RC_MEMSIZE_32_BITS;
}
void rc_evaluate_operand(rc_typed_value_t* result, const rc_operand_t* self, rc_eval_state_t* eval_state) {
#ifndef RC_DISABLE_LUA
rc_luapeek_t luapeek;
#endif /* RC_DISABLE_LUA */
@@ -510,16 +656,28 @@ void rc_evaluate_operand(rc_typed_value_t* result, rc_operand_t* self, rc_eval_s
#endif /* RC_DISABLE_LUA */
break;
case RC_OPERAND_RECALL:
result->type = eval_state->recall_value.type;
result->value = eval_state->recall_value.value;
return;
case RC_OPERAND_RECALL:
if (!rc_operand_type_is_memref(self->memref_access_type)) {
rc_operand_t recall;
memcpy(&recall, self, sizeof(recall));
recall.type = self->memref_access_type;
rc_evaluate_operand(result, &recall, eval_state);
return;
}
if (!self->value.memref) {
result->type = RC_VALUE_TYPE_UNSIGNED;
result->value.u32 = 0;
return;
}
rc_get_memref_value(result, self->value.memref, self->memref_access_type);
break;
default:
result->type = RC_VALUE_TYPE_UNSIGNED;
result->value.u32 = rc_get_memref_value(self->value.memref, self->type, eval_state);
rc_get_memref_value(result, self->value.memref, self->type);
break;
}

View File

@@ -13,27 +13,115 @@ typedef struct rc_scratch_string {
}
rc_scratch_string_t;
#define RC_ALLOW_ALIGN(T) struct __align_ ## T { char ch; T t; };
typedef struct rc_modified_memref_t {
rc_memref_t memref; /* for compatibility with rc_operand_t.value.memref */
rc_operand_t parent; /* The parent memref this memref is derived from (type will always be a memref type) */
rc_operand_t modifier; /* The modifier to apply to the parent. */
uint8_t modifier_type; /* How to apply the modifier to the parent. (RC_OPERATOR_*) */
}
rc_modified_memref_t;
typedef struct rc_memref_list_t {
rc_memref_t* items;
struct rc_memref_list_t* next;
uint16_t count;
uint16_t capacity;
uint8_t allocated;
} rc_memref_list_t;
typedef struct rc_modified_memref_list_t {
rc_modified_memref_t* items;
struct rc_modified_memref_list_t* next;
uint16_t count;
uint16_t capacity;
uint8_t allocated;
} rc_modified_memref_list_t;
typedef struct rc_memrefs_t {
rc_memref_list_t memrefs;
rc_modified_memref_list_t modified_memrefs;
} rc_memrefs_t;
typedef struct rc_trigger_with_memrefs_t {
rc_trigger_t trigger;
rc_memrefs_t memrefs;
} rc_trigger_with_memrefs_t;
typedef struct rc_lboard_with_memrefs_t {
rc_lboard_t lboard;
rc_memrefs_t memrefs;
} rc_lboard_with_memrefs_t;
typedef struct rc_richpresence_with_memrefs_t {
rc_richpresence_t richpresence;
rc_memrefs_t memrefs;
} rc_richpresence_with_memrefs_t;
typedef struct rc_value_with_memrefs_t {
rc_value_t value;
rc_memrefs_t memrefs;
} rc_value_with_memrefs_t;
/* enum helpers for natvis expansion. Have to use a struct to define the mapping,
* and a single field to allow the conditional logic to switch on the value */
typedef struct __rc_bool_enum_t { uint8_t value; } __rc_bool_enum_t;
typedef struct __rc_memsize_enum_t { uint8_t value; } __rc_memsize_enum_t;
typedef struct __rc_memsize_enum_func_t { uint8_t value; } __rc_memsize_enum_func_t;
typedef struct __rc_operand_enum_t { uint8_t value; } __rc_operand_enum_t;
typedef struct __rc_value_type_enum_t { uint8_t value; } __rc_value_type_enum_t;
typedef struct __rc_memref_type_enum_t { uint8_t value; } __rc_memref_type_enum_t;
typedef struct __rc_condition_enum_t { uint8_t value; } __rc_condition_enum_t;
typedef struct __rc_condition_enum_str_t { uint8_t value; } __rc_condition_enum_str_t;
typedef struct __rc_condset_list_t { rc_condset_t* first_condset; } __rc_condset_list_t;
typedef struct __rc_operator_enum_t { uint8_t value; } __rc_operator_enum_t;
typedef struct __rc_operator_enum_str_t { uint8_t value; } __rc_operator_enum_str_t;
typedef struct __rc_operand_memref_t { rc_operand_t operand; } __rc_operand_memref_t; /* requires &rc_operand_t to be the same as &rc_operand_t.value.memref */
typedef struct __rc_value_list_t { rc_value_t* first_value; } __rc_value_list_t;
typedef struct __rc_trigger_state_enum_t { uint8_t value; } __rc_trigger_state_enum_t;
typedef struct __rc_lboard_state_enum_t { uint8_t value; } __rc_lboard_state_enum_t;
typedef struct __rc_richpresence_display_list_t { rc_richpresence_display_t* first_display; } __rc_richpresence_display_list_t;
typedef struct __rc_richpresence_display_part_list_t { rc_richpresence_display_part_t* display; } __rc_richpresence_display_part_list_t;
typedef struct __rc_richpresence_lookup_list_t { rc_richpresence_lookup_t* first_lookup; } __rc_richpresence_lookup_list_t;
typedef struct __rc_format_enum_t { uint8_t value; } __rc_format_enum_t;
#define RC_ALLOW_ALIGN(T) struct __align_ ## T { uint8_t ch; T t; };
RC_ALLOW_ALIGN(rc_condition_t)
RC_ALLOW_ALIGN(rc_condset_t)
RC_ALLOW_ALIGN(rc_modified_memref_t)
RC_ALLOW_ALIGN(rc_lboard_t)
RC_ALLOW_ALIGN(rc_lboard_with_memrefs_t)
RC_ALLOW_ALIGN(rc_memref_t)
RC_ALLOW_ALIGN(rc_memref_list_t)
RC_ALLOW_ALIGN(rc_memrefs_t)
RC_ALLOW_ALIGN(rc_modified_memref_list_t)
RC_ALLOW_ALIGN(rc_operand_t)
RC_ALLOW_ALIGN(rc_richpresence_t)
RC_ALLOW_ALIGN(rc_richpresence_display_t)
RC_ALLOW_ALIGN(rc_richpresence_display_part_t)
RC_ALLOW_ALIGN(rc_richpresence_lookup_t)
RC_ALLOW_ALIGN(rc_richpresence_lookup_item_t)
RC_ALLOW_ALIGN(rc_richpresence_with_memrefs_t)
RC_ALLOW_ALIGN(rc_scratch_string_t)
RC_ALLOW_ALIGN(rc_trigger_t)
RC_ALLOW_ALIGN(rc_trigger_with_memrefs_t)
RC_ALLOW_ALIGN(rc_value_t)
RC_ALLOW_ALIGN(rc_value_with_memrefs_t)
RC_ALLOW_ALIGN(char)
#define RC_ALIGNOF(T) (sizeof(struct __align_ ## T) - sizeof(T))
#define RC_OFFSETOF(o, t) (int)((char*)&(o.t) - (char*)&(o))
#define RC_OFFSETOF(o, t) (int)((uint8_t*)&(o.t) - (uint8_t*)&(o))
#define RC_ALLOC(t, p) ((t*)rc_alloc((p)->buffer, &(p)->offset, sizeof(t), RC_ALIGNOF(t), &(p)->scratch, RC_OFFSETOF((p)->scratch.objs, __ ## t)))
#define RC_ALLOC_SCRATCH(t, p) ((t*)rc_alloc_scratch((p)->buffer, &(p)->offset, sizeof(t), RC_ALIGNOF(t), &(p)->scratch, RC_OFFSETOF((p)->scratch.objs, __ ## t)))
#define RC_ALLOC_ARRAY(t, n, p) ((t*)rc_alloc((p)->buffer, &(p)->offset, (n) * sizeof(t), RC_ALIGNOF(t), &(p)->scratch, RC_OFFSETOF((p)->scratch.objs, __ ## t)))
#define RC_ALLOC_ARRAY_SCRATCH(t, n, p) ((t*)rc_alloc_scratch((p)->buffer, &(p)->offset, (n) * sizeof(t), RC_ALIGNOF(t), &(p)->scratch, RC_OFFSETOF((p)->scratch.objs, __ ## t)))
#define RC_ALLOC_WITH_TRAILING(container_type, trailing_type, trailing_field, trailing_count, parse) ((container_type*)rc_alloc(\
(parse)->buffer, &(parse)->offset, \
RC_OFFSETOF((*(container_type*)NULL),trailing_field) + trailing_count * sizeof(trailing_type), \
RC_ALIGNOF(container_type), &(parse)->scratch, 0))
#define RC_GET_TRAILING(container_pointer, container_type, trailing_type, trailing_field) (trailing_type*)(&((container_type*)(container_pointer))->trailing_field)
/* force alignment to 4 bytes on 32-bit systems, or 8 bytes on 64-bit systems */
#define RC_ALIGN(n) (((n) + (sizeof(void*)-1)) & ~(sizeof(void*)-1))
@@ -45,17 +133,49 @@ typedef struct {
struct objs {
rc_condition_t* __rc_condition_t;
rc_condset_t* __rc_condset_t;
rc_modified_memref_t* __rc_modified_memref_t;
rc_lboard_t* __rc_lboard_t;
rc_lboard_with_memrefs_t* __rc_lboard_with_memrefs_t;
rc_memref_t* __rc_memref_t;
rc_memref_list_t* __rc_memref_list_t;
rc_memrefs_t* __rc_memrefs_t;
rc_modified_memref_list_t* __rc_modified_memref_list_t;
rc_operand_t* __rc_operand_t;
rc_richpresence_t* __rc_richpresence_t;
rc_richpresence_display_t* __rc_richpresence_display_t;
rc_richpresence_display_part_t* __rc_richpresence_display_part_t;
rc_richpresence_lookup_t* __rc_richpresence_lookup_t;
rc_richpresence_lookup_item_t* __rc_richpresence_lookup_item_t;
rc_richpresence_with_memrefs_t* __rc_richpresence_with_memrefs_t;
rc_scratch_string_t __rc_scratch_string_t;
rc_trigger_t* __rc_trigger_t;
rc_trigger_with_memrefs_t* __rc_trigger_with_memrefs_t;
rc_value_t* __rc_value_t;
rc_value_with_memrefs_t* __rc_value_with_memrefs_t;
/* these fields aren't actually used by the code, but they force the
* virtual enum wrapper types to exist so natvis can use them */
union {
__rc_bool_enum_t boolean;
__rc_memsize_enum_t memsize;
__rc_memsize_enum_func_t memsize_func;
__rc_operand_enum_t operand;
__rc_value_type_enum_t value_type;
__rc_memref_type_enum_t memref_type;
__rc_condition_enum_t condition;
__rc_condition_enum_str_t condition_str;
__rc_condset_list_t condset_list;
__rc_operator_enum_t oper;
__rc_operator_enum_str_t oper_str;
__rc_operand_memref_t operand_memref;
__rc_value_list_t value_list;
__rc_trigger_state_enum_t trigger_state;
__rc_lboard_state_enum_t lboard_state;
__rc_richpresence_display_list_t richpresence_display_list;
__rc_richpresence_display_part_list_t richpresence_display_part_list;
__rc_richpresence_lookup_list_t richpresence_lookup_list;
__rc_format_enum_t format;
} natvis_extension;
} objs;
}
rc_scratch_t;
@@ -78,72 +198,128 @@ typedef struct {
}
rc_typed_value_t;
enum {
RC_MEMREF_TYPE_MEMREF, /* rc_memref_t */
RC_MEMREF_TYPE_MODIFIED_MEMREF, /* rc_modified_memref_t */
RC_MEMREF_TYPE_VALUE /* rc_value_t */
};
#define RC_MEASURED_UNKNOWN 0xFFFFFFFF
#define RC_OPERAND_NONE 0xFF
typedef struct {
rc_typed_value_t add_value;/* AddSource/SubSource */
int32_t add_hits; /* AddHits */
uint32_t add_address; /* AddAddress */
/* memory accessors */
rc_peek_t peek;
void* peek_userdata;
#ifndef RC_DISABLE_LUA
lua_State* L;
#endif
rc_typed_value_t measured_value; /* Measured */
rc_typed_value_t recall_value; /* Set by RC_CONDITION_REMEMBER */
uint8_t was_reset; /* ResetIf triggered */
uint8_t has_hits; /* one of more hit counts is non-zero */
uint8_t primed; /* true if all non-Trigger conditions are true */
/* processing state */
rc_typed_value_t measured_value; /* captured Measured value */
int32_t add_hits; /* AddHits/SubHits accumulator */
uint8_t is_true; /* true if all conditions are true */
uint8_t is_primed; /* true if all non-Trigger conditions are true */
uint8_t is_paused; /* true if one or more PauseIf conditions is true */
uint8_t can_measure; /* false if the measured value should be ignored */
uint8_t measured_from_hits; /* true if the measured_value came from a condition's hit count */
uint8_t was_cond_reset; /* ResetNextIf triggered */
uint8_t and_next; /* true if the previous condition was AndNext true */
uint8_t or_next; /* true if the previous condition was OrNext true */
uint8_t reset_next; /* true if the previous condition was ResetNextIf true */
uint8_t stop_processing; /* true to abort the processing loop */
/* result state */
uint8_t has_hits; /* true if one of more hit counts is non-zero */
uint8_t was_reset; /* true if one or more ResetIf conditions is true */
uint8_t was_cond_reset; /* true if one or more ResetNextIf conditions is true */
/* control settings */
uint8_t can_short_curcuit; /* allows logic processing to stop as soon as a false condition is encountered */
}
rc_eval_state_t;
typedef struct {
int32_t offset;
#ifndef RC_DISABLE_LUA
lua_State* L;
int funcs_ndx;
#endif
void* buffer;
rc_scratch_t scratch;
rc_memref_t** first_memref;
rc_memrefs_t* memrefs;
rc_memrefs_t* existing_memrefs;
rc_value_t** variables;
uint32_t measured_target;
int lines_read;
rc_operand_t addsource_parent;
rc_operand_t indirect_parent;
rc_operand_t remember;
uint8_t addsource_oper;
uint8_t is_value;
uint8_t has_required_hits;
uint8_t measured_as_percent;
}
rc_parse_state_t;
typedef struct rc_preparse_state_t {
rc_parse_state_t parse;
rc_memrefs_t memrefs;
} rc_preparse_state_t;
void rc_init_parse_state(rc_parse_state_t* parse, void* buffer, lua_State* L, int funcs_ndx);
void rc_init_parse_state_memrefs(rc_parse_state_t* parse, rc_memref_t** memrefs);
void rc_init_parse_state_variables(rc_parse_state_t* parse, rc_value_t** variables);
void rc_init_parse_state_memrefs(rc_parse_state_t* parse, rc_memrefs_t* memrefs);
void rc_reset_parse_state(rc_parse_state_t* parse, void* buffer, lua_State* L, int funcs_ndx);
void rc_destroy_parse_state(rc_parse_state_t* parse);
void rc_init_preparse_state(rc_preparse_state_t* preparse, lua_State* L, int funcs_ndx);
void rc_preparse_alloc_memrefs(rc_memrefs_t* memrefs, rc_preparse_state_t* preparse);
void rc_preparse_reserve_memrefs(rc_preparse_state_t* preparse, rc_memrefs_t* memrefs);
void rc_preparse_copy_memrefs(rc_parse_state_t* parse, rc_memrefs_t* memrefs);
void rc_destroy_preparse_state(rc_preparse_state_t *preparse);
void rc_copy_memrefs_into_parse_state(rc_parse_state_t* parse, rc_memref_t* memrefs);
void rc_sync_operand(rc_operand_t* operand, rc_parse_state_t* parse, const rc_memref_t* memrefs);
void* rc_alloc(void* pointer, int32_t* offset, uint32_t size, uint32_t alignment, rc_scratch_t* scratch, uint32_t scratch_object_pointer_offset);
void* rc_alloc_scratch(void* pointer, int32_t* offset, uint32_t size, uint32_t alignment, rc_scratch_t* scratch, uint32_t scratch_object_pointer_offset);
char* rc_alloc_str(rc_parse_state_t* parse, const char* text, size_t length);
rc_memref_t* rc_alloc_memref(rc_parse_state_t* parse, uint32_t address, uint8_t size, uint8_t is_indirect);
rc_memref_t* rc_alloc_memref(rc_parse_state_t* parse, uint32_t address, uint8_t size);
rc_modified_memref_t* rc_alloc_modified_memref(rc_parse_state_t* parse, uint8_t size, const rc_operand_t* parent,
uint8_t modifier_type, const rc_operand_t* modifier);
int rc_parse_memref(const char** memaddr, uint8_t* size, uint32_t* address);
void rc_update_memref_values(rc_memref_t* memref, rc_peek_t peek, void* ud);
void rc_update_memref_values(rc_memrefs_t* memrefs, rc_peek_t peek, void* ud);
void rc_update_memref_value(rc_memref_value_t* memref, uint32_t value);
uint32_t rc_get_memref_value(rc_memref_t* memref, int operand_type, rc_eval_state_t* eval_state);
void rc_get_memref_value(rc_typed_value_t* value, rc_memref_t* memref, int operand_type);
uint32_t rc_get_modified_memref_value(const rc_modified_memref_t* memref, rc_peek_t peek, void* ud);
uint8_t rc_memref_shared_size(uint8_t size);
uint32_t rc_memref_mask(uint8_t size);
void rc_transform_memref_value(rc_typed_value_t* value, uint8_t size);
uint32_t rc_peek_value(uint32_t address, uint8_t size, rc_peek_t peek, void* ud);
void rc_memrefs_init(rc_memrefs_t* memrefs);
void rc_memrefs_destroy(rc_memrefs_t* memrefs);
uint32_t rc_memrefs_count_memrefs(const rc_memrefs_t* memrefs);
uint32_t rc_memrefs_count_modified_memrefs(const rc_memrefs_t* memrefs);
void rc_parse_trigger_internal(rc_trigger_t* self, const char** memaddr, rc_parse_state_t* parse);
int rc_trigger_state_active(int state);
rc_memrefs_t* rc_trigger_get_memrefs(rc_trigger_t* self);
rc_condset_t* rc_parse_condset(const char** memaddr, rc_parse_state_t* parse, int is_value);
typedef struct rc_condset_with_trailing_conditions_t {
rc_condset_t condset;
rc_condition_t conditions[2];
} rc_condset_with_trailing_conditions_t;
RC_ALLOW_ALIGN(rc_condset_with_trailing_conditions_t)
rc_condset_t* rc_parse_condset(const char** memaddr, rc_parse_state_t* parse);
int rc_test_condset(rc_condset_t* self, rc_eval_state_t* eval_state);
void rc_reset_condset(rc_condset_t* self);
rc_condition_t* rc_condset_get_conditions(rc_condset_t* self);
enum {
RC_PROCESSING_COMPARE_DEFAULT = 0,
@@ -161,24 +337,35 @@ enum {
RC_PROCESSING_COMPARE_ALWAYS_FALSE
};
rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse, uint8_t is_indirect);
rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse);
void rc_parse_condition_internal(rc_condition_t* self, const char** memaddr, rc_parse_state_t* parse);
void rc_condition_update_parse_state(rc_condition_t* condition, rc_parse_state_t* parse);
int rc_test_condition(rc_condition_t* self, rc_eval_state_t* eval_state);
void rc_evaluate_condition_value(rc_typed_value_t* value, rc_condition_t* self, rc_eval_state_t* eval_state);
int rc_condition_is_combining(const rc_condition_t* self);
void rc_condition_convert_to_operand(const rc_condition_t* condition, rc_operand_t* operand, rc_parse_state_t* parse);
int rc_parse_operand(rc_operand_t* self, const char** memaddr, uint8_t is_indirect, rc_parse_state_t* parse);
void rc_evaluate_operand(rc_typed_value_t* value, rc_operand_t* self, rc_eval_state_t* eval_state);
int rc_parse_operand(rc_operand_t* self, const char** memaddr, rc_parse_state_t* parse);
void rc_evaluate_operand(rc_typed_value_t* value, const rc_operand_t* self, rc_eval_state_t* eval_state);
int rc_operator_is_modifying(int oper);
int rc_operand_is_float_memref(const rc_operand_t* self);
int rc_operand_is_float(const rc_operand_t* self);
int rc_operand_is_recall(const rc_operand_t* self);
int rc_operand_type_is_memref(uint8_t type);
int rc_operands_are_equal(const rc_operand_t* left, const rc_operand_t* right);
void rc_operand_addsource(rc_operand_t* self, rc_parse_state_t* parse, uint8_t new_size);
void rc_operand_set_const(rc_operand_t* self, uint32_t value);
void rc_operand_set_float_const(rc_operand_t* self, double value);
int rc_is_valid_variable_character(char ch, int is_first);
void rc_parse_value_internal(rc_value_t* self, const char** memaddr, rc_parse_state_t* parse);
int rc_evaluate_value_typed(rc_value_t* self, rc_typed_value_t* value, rc_peek_t peek, void* ud, lua_State* L);
void rc_reset_value(rc_value_t* self);
int rc_value_from_hits(rc_value_t* self);
rc_value_t* rc_alloc_helper_variable(const char* memaddr, size_t memaddr_len, rc_parse_state_t* parse);
void rc_update_variables(rc_value_t* variable, rc_peek_t peek, void* ud, lua_State* L);
rc_value_t* rc_alloc_variable(const char* memaddr, size_t memaddr_len, rc_parse_state_t* parse);
uint32_t rc_count_values(const rc_value_t* values);
void rc_update_values(rc_value_t* values, rc_peek_t peek, void* ud, lua_State* L);
void rc_reset_values(rc_value_t* values);
void rc_typed_value_convert(rc_typed_value_t* value, char new_type);
void rc_typed_value_add(rc_typed_value_t* value, const rc_typed_value_t* amount);
@@ -187,6 +374,7 @@ void rc_typed_value_divide(rc_typed_value_t* value, const rc_typed_value_t* amou
void rc_typed_value_modulus(rc_typed_value_t* value, const rc_typed_value_t* amount);
void rc_typed_value_negate(rc_typed_value_t* value);
int rc_typed_value_compare(const rc_typed_value_t* value1, const rc_typed_value_t* value2, char oper);
void rc_typed_value_combine(rc_typed_value_t* value, rc_typed_value_t* amount, uint8_t oper);
void rc_typed_value_from_memref_value(rc_typed_value_t* value, const rc_memref_value_t* memref);
int rc_format_typed_value(char* buffer, size_t size, const rc_typed_value_t* value, int format);
@@ -195,6 +383,11 @@ void rc_parse_lboard_internal(rc_lboard_t* self, const char* memaddr, rc_parse_s
int rc_lboard_state_active(int state);
void rc_parse_richpresence_internal(rc_richpresence_t* self, const char* script, rc_parse_state_t* parse);
rc_memrefs_t* rc_richpresence_get_memrefs(rc_richpresence_t* self);
void rc_reset_richpresence_triggers(rc_richpresence_t* self);
int rc_validate_memrefs(const rc_memrefs_t* memrefs, char result[], const size_t result_size, uint32_t max_address);
int rc_validate_memrefs_for_console(const rc_memrefs_t* memrefs, char result[], const size_t result_size, uint32_t console_id);
RC_END_C_DECLS

View File

@@ -0,0 +1,539 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<!-- https://learn.microsoft.com/en-us/visualstudio/debugger/create-custom-views-of-native-objects?view=vs-2022 -->
<!-- https://learn.microsoft.com/en-us/visualstudio/debugger/format-specifiers-in-cpp?view=vs-2022 -->
<Type Name="rc_typed_value_t">
<DisplayString Condition="type==RC_VALUE_TYPE_UNSIGNED">{value.u32} (RC_VALUE_TYPE_UNSIGNED)</DisplayString>
<DisplayString Condition="type==RC_VALUE_TYPE_FLOAT">{value.f32} (RC_VALUE_TYPE_FLOAT)</DisplayString>
<DisplayString Condition="type==RC_VALUE_TYPE_SIGNED">{value.i32} (RC_VALUE_TYPE_SIGNED)</DisplayString>
<DisplayString Condition="type==RC_VALUE_TYPE_NONE">none (RC_VALUE_TYPE_NONE)</DisplayString>
<DisplayString>{value.i32} (unknown)</DisplayString>
</Type>
<Type Name="__rc_bool_enum_t">
<DisplayString Condition="value==0">false</DisplayString>
<DisplayString Condition="value==1">true</DisplayString>
<DisplayString>true ({value})</DisplayString>
</Type>
<Type Name="__rc_memsize_enum_t">
<DisplayString Condition="value==RC_MEMSIZE_8_BITS">{RC_MEMSIZE_8_BITS}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_16_BITS">{RC_MEMSIZE_16_BITS}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_24_BITS">{RC_MEMSIZE_24_BITS}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_32_BITS">{RC_MEMSIZE_32_BITS}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_LOW">{RC_MEMSIZE_LOW}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_HIGH">{RC_MEMSIZE_HIGH}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_0">{RC_MEMSIZE_BIT_0}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_1">{RC_MEMSIZE_BIT_1}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_2">{RC_MEMSIZE_BIT_2}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_3">{RC_MEMSIZE_BIT_3}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_4">{RC_MEMSIZE_BIT_4}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_5">{RC_MEMSIZE_BIT_5}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_6">{RC_MEMSIZE_BIT_6}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_7">{RC_MEMSIZE_BIT_7}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BITCOUNT">{RC_MEMSIZE_BITCOUNT}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_16_BITS_BE">{RC_MEMSIZE_16_BITS_BE}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_24_BITS_BE">{RC_MEMSIZE_24_BITS_BE}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_32_BITS_BE">{RC_MEMSIZE_32_BITS_BE}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_FLOAT">{RC_MEMSIZE_FLOAT}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_MBF32">{RC_MEMSIZE_MBF32}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_MBF32_LE">{RC_MEMSIZE_MBF32_LE}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_FLOAT_BE">{RC_MEMSIZE_FLOAT_BE}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_DOUBLE32">{RC_MEMSIZE_DOUBLE32}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_DOUBLE32_BE">{RC_MEMSIZE_DOUBLE32_BE}</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_VARIABLE">{RC_MEMSIZE_VARIABLE}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="__rc_value_type_enum_t">
<DisplayString Condition="value==RC_VALUE_TYPE_NONE">{RC_VALUE_TYPE_NONE}</DisplayString>
<DisplayString Condition="value==RC_VALUE_TYPE_UNSIGNED">{RC_VALUE_TYPE_UNSIGNED}</DisplayString>
<DisplayString Condition="value==RC_VALUE_TYPE_SIGNED">{RC_VALUE_TYPE_SIGNED}</DisplayString>
<DisplayString Condition="value==RC_VALUE_TYPE_FLOAT">{RC_VALUE_TYPE_FLOAT}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="__rc_memref_type_enum_t">
<DisplayString Condition="value==RC_MEMREF_TYPE_MEMREF">{RC_MEMREF_TYPE_MEMREF}</DisplayString>
<DisplayString Condition="value==RC_MEMREF_TYPE_MODIFIED_MEMREF">{RC_MEMREF_TYPE_MODIFIED_MEMREF}</DisplayString>
<DisplayString Condition="value==RC_MEMREF_TYPE_VALUE">RC_MEMREF_TYPE_VALUE</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="__rc_memsize_enum_func_t">
<DisplayString Condition="value==RC_MEMSIZE_8_BITS">byte</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_16_BITS">word</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_24_BITS">tbyte</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_32_BITS">dword</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_LOW">lower4</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_HIGH">upper4</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_0">bit0</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_1">bit1</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_2">bit2</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_3">bit3</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_4">bit4</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_5">bit5</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_6">bit6</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BIT_7">bit7</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_BITCOUNT">bitcount</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_16_BITS_BE">word_be</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_24_BITS_BE">tbyte_be</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_32_BITS_BE">dword_be</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_FLOAT">float</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_MBF32">mbf32</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_MBF32_LE">mbf32_le</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_FLOAT_BE">float_be</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_DOUBLE32">double32</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_DOUBLE32_BE">double32_be</DisplayString>
<DisplayString Condition="value==RC_MEMSIZE_VARIABLE">var</DisplayString>
<DisplayString>unknown</DisplayString>
</Type>
<Type Name="rc_memref_value_t">
<DisplayString Condition="type==RC_VALUE_TYPE_FLOAT">{{value={(float)*((float*)&amp;value)} prior={(float)*((float*)&amp;prior)}}}</DisplayString>
<DisplayString Condition="type==RC_VALUE_TYPE_SIGNED">{{value={(int)value} prior={(int)prior}}}</DisplayString>
<DisplayString>{{value={value,x} prior={prior,x}}}</DisplayString>
<Expand>
<Item Name="value">value</Item>
<Item Name="prior">prior</Item>
<Item Name="size">*((__rc_memsize_enum_t*)&amp;size)</Item>
<Item Name="changed">*((__rc_bool_enum_t*)&amp;changed)</Item>
<Item Name="type">*((__rc_value_type_enum_t*)&amp;type)</Item>
<Item Name="memref_type">*((__rc_memref_type_enum_t*)&amp;memref_type)</Item>
</Expand>
</Type>
<Type Name="rc_memref_t">
<DisplayString Condition="value.memref_type==RC_MEMREF_TYPE_MODIFIED_MEMREF">{*(rc_modified_memref_t*)&amp;value}</DisplayString>
<DisplayString Condition="value.memref_type==RC_MEMREF_TYPE_VALUE">{*(rc_value_t*)&amp;value}</DisplayString>
<DisplayString Condition="value.size==RC_MEMSIZE_VARIABLE">var</DisplayString>
<DisplayString>{*((__rc_memsize_enum_func_t*)&amp;value.size)}({address,x})</DisplayString>
<Expand>
<Item Name="[rc_modified_memref_t]" Condition="value.memref_type==RC_MEMREF_TYPE_MODIFIED_MEMREF">(rc_modified_memref_t*)&amp;value</Item>
<Item Name="value">value</Item>
<Item Name="address">address</Item>
</Expand>
</Type>
<Type Name="rc_memref_list_t">
<DisplayString>{{count = {count}}}</DisplayString>
<Expand>
<Item Name="next" Condition="next!=0">next</Item>
<Item Name="count">count</Item>
<Item Name="capacity">capacity</Item>
<ArrayItems>
<Size>count</Size>
<ValuePointer>items</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="__rc_operand_memref_t">
<DisplayString Condition="operand.value.memref->value.memref_type==RC_MEMREF_TYPE_MODIFIED_MEMREF">... {*((__rc_memsize_enum_func_t*)&amp;operand.size)} {operand.value.memref->address,x}</DisplayString>
<DisplayString Condition="operand.value.memref->value.memref_type==RC_MEMREF_TYPE_VALUE">value {((rc_value_t*)operand.value.memref)->name,s}</DisplayString>
<DisplayString>{*((__rc_memsize_enum_func_t*)&amp;operand.size)} {operand.value.memref->address,x}</DisplayString>
<Expand>
<Item Name="[rc_modified_memref_t]" Condition="operand.value.memref->value.memref_type==RC_MEMREF_TYPE_MODIFIED_MEMREF">(rc_modified_memref_t*)&amp;operand.value</Item>
<Item Name="value">operand.value.memref->value</Item>
<Item Name="address">operand.value.memref->address</Item>
</Expand>
</Type>
<Type Name="__rc_operand_enum_t">
<DisplayString Condition="value==RC_OPERAND_ADDRESS">{RC_OPERAND_ADDRESS}</DisplayString>
<DisplayString Condition="value==RC_OPERAND_DELTA">{RC_OPERAND_DELTA}</DisplayString>
<DisplayString Condition="value==RC_OPERAND_CONST">{RC_OPERAND_CONST}</DisplayString>
<DisplayString Condition="value==RC_OPERAND_FP">{RC_OPERAND_FP}</DisplayString>
<DisplayString Condition="value==RC_OPERAND_LUA">{RC_OPERAND_LUA}</DisplayString>
<DisplayString Condition="value==RC_OPERAND_PRIOR">{RC_OPERAND_PRIOR}</DisplayString>
<DisplayString Condition="value==RC_OPERAND_BCD">{RC_OPERAND_BCD}</DisplayString>
<DisplayString Condition="value==RC_OPERAND_INVERTED">{RC_OPERAND_INVERTED}</DisplayString>
<DisplayString Condition="value==RC_OPERAND_RECALL">{RC_OPERAND_RECALL}</DisplayString>
<DisplayString Condition="value==0xFF">RC_OPERAND_NONE (255)</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="rc_operand_t">
<DisplayString Condition="type==RC_OPERAND_ADDRESS">{{{*(__rc_operand_memref_t*)&amp;value.memref}}}</DisplayString>
<DisplayString Condition="type==RC_OPERAND_DELTA">{{delta {*(__rc_operand_memref_t*)&amp;value.memref}}}</DisplayString>
<DisplayString Condition="type==RC_OPERAND_PRIOR">{{prior {*(__rc_operand_memref_t*)&amp;value.memref}}}</DisplayString>
<DisplayString Condition="type==RC_OPERAND_BCD">{{bcd {*(__rc_operand_memref_t*)&amp;value.memref}}}</DisplayString>
<DisplayString Condition="type==RC_OPERAND_INVERTED">{{inverted {*(__rc_operand_memref_t*)&amp;value.memref}}}</DisplayString>
<DisplayString Condition="type==RC_OPERAND_CONST &amp;&amp; value.num &gt; 0xFFFF0000">{{value {(int)value.num}}}</DisplayString>
<DisplayString Condition="type==RC_OPERAND_CONST &amp;&amp; value.num &gt; 0x01000000">{{value {value.num,x}}}</DisplayString>
<DisplayString Condition="type==RC_OPERAND_CONST">{{value {value.num}}}</DisplayString>
<DisplayString Condition="type==RC_OPERAND_FP">{{value {value.dbl}}}</DisplayString>
<DisplayString Condition="type==RC_OPERAND_RECALL">{{recall}}</DisplayString>
<DisplayString Condition="type==RC_OPERAND_LUA">{{lua @{value.luafunc}}}</DisplayString>
<DisplayString Condition="type==0xFF">{{none}}</DisplayString>
<DisplayString>{{unknown}}</DisplayString>
<Expand>
<Item Name="value" Condition="type==RC_OPERAND_CONST">value.num</Item>
<Item Name="value" Condition="type==RC_OPERAND_FP">value.dbl</Item>
<Item Name="value" Condition="type==RC_OPERAND_RECALL &amp;&amp; memref_access_type==RC_OPERAND_CONST">value.num</Item>
<Item Name="value" Condition="type==RC_OPERAND_RECALL &amp;&amp; memref_access_type==RC_OPERAND_FP">value.dbl</Item>
<Item Name="value" Condition="type!=RC_OPERAND_CONST &amp;&amp; type!=RC_OPERAND_FP &amp;&amp; value.memref==0">value.memref</Item>
<Item Name="value" Condition="type!=RC_OPERAND_CONST &amp;&amp; type!=RC_OPERAND_FP &amp;&amp; ((rc_memref_t*)value.memref)->value.memref_type!=RC_MEMREF_TYPE_MODIFIED_MEMREF">value.memref</Item>
<Item Name="value" Condition="type!=RC_OPERAND_CONST &amp;&amp; type!=RC_OPERAND_FP &amp;&amp; ((rc_memref_t*)value.memref)->value.memref_type==RC_MEMREF_TYPE_MODIFIED_MEMREF">(rc_modified_memref_t*)value.memref</Item>
<Item Name="type">*((__rc_operand_enum_t*)&amp;type)</Item>
<Item Name="size">*((__rc_memsize_enum_t*)&amp;size)</Item>
<Item Name="memref_access_type">*((__rc_operand_enum_t*)&amp;memref_access_type)</Item>
</Expand>
</Type>
<Type Name="__rc_condition_enum_t">
<DisplayString Condition="value==RC_CONDITION_STANDARD">{RC_CONDITION_STANDARD}</DisplayString>
<DisplayString Condition="value==RC_CONDITION_PAUSE_IF">{RC_CONDITION_PAUSE_IF}</DisplayString>
<DisplayString Condition="value==RC_CONDITION_RESET_IF">{RC_CONDITION_RESET_IF}</DisplayString>
<DisplayString Condition="value==RC_CONDITION_MEASURED_IF">{RC_CONDITION_MEASURED_IF}</DisplayString>
<DisplayString Condition="value==RC_CONDITION_TRIGGER">{RC_CONDITION_TRIGGER}</DisplayString>
<DisplayString Condition="value==RC_CONDITION_MEASURED">{RC_CONDITION_MEASURED}</DisplayString>
<DisplayString Condition="value==RC_CONDITION_ADD_SOURCE">{RC_CONDITION_ADD_SOURCE}</DisplayString>
<DisplayString Condition="value==RC_CONDITION_SUB_SOURCE">{RC_CONDITION_SUB_SOURCE}</DisplayString>
<DisplayString Condition="value==RC_CONDITION_ADD_ADDRESS">{RC_CONDITION_ADD_ADDRESS}</DisplayString>
<DisplayString Condition="value==RC_CONDITION_REMEMBER">{RC_CONDITION_REMEMBER}</DisplayString>
<DisplayString Condition="value==RC_CONDITION_ADD_HITS">{RC_CONDITION_ADD_HITS}</DisplayString>
<DisplayString Condition="value==RC_CONDITION_SUB_HITS">{RC_CONDITION_SUB_HITS}</DisplayString>
<DisplayString Condition="value==RC_CONDITION_RESET_NEXT_IF">{RC_CONDITION_RESET_NEXT_IF}</DisplayString>
<DisplayString Condition="value==RC_CONDITION_AND_NEXT">{RC_CONDITION_AND_NEXT}</DisplayString>
<DisplayString Condition="value==RC_CONDITION_OR_NEXT">{RC_CONDITION_OR_NEXT}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="__rc_condition_enum_str_t">
<DisplayString Condition="value==RC_CONDITION_STANDARD"></DisplayString>
<DisplayString Condition="value==RC_CONDITION_PAUSE_IF">PauseIf </DisplayString>
<DisplayString Condition="value==RC_CONDITION_RESET_IF">ResetIf </DisplayString>
<DisplayString Condition="value==RC_CONDITION_MEASURED_IF">MeasuredIf </DisplayString>
<DisplayString Condition="value==RC_CONDITION_TRIGGER">Trigger </DisplayString>
<DisplayString Condition="value==RC_CONDITION_MEASURED">Measured </DisplayString>
<DisplayString Condition="value==RC_CONDITION_ADD_SOURCE">AddSource </DisplayString>
<DisplayString Condition="value==RC_CONDITION_SUB_SOURCE">SubSource </DisplayString>
<DisplayString Condition="value==RC_CONDITION_ADD_ADDRESS">AddAddress </DisplayString>
<DisplayString Condition="value==RC_CONDITION_REMEMBER">Remember </DisplayString>
<DisplayString Condition="value==RC_CONDITION_ADD_HITS">AddHits </DisplayString>
<DisplayString Condition="value==RC_CONDITION_SUB_HITS">SubHits </DisplayString>
<DisplayString Condition="value==RC_CONDITION_RESET_NEXT_IF">ResetNextIf </DisplayString>
<DisplayString Condition="value==RC_CONDITION_AND_NEXT">AndNext </DisplayString>
<DisplayString Condition="value==RC_CONDITION_OR_NEXT">OrNext </DisplayString>
<DisplayString>{value} </DisplayString>
</Type>
<Type Name="__rc_operator_enum_t">
<DisplayString Condition="value==RC_OPERATOR_EQ">{RC_OPERATOR_EQ}</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_LT">{RC_OPERATOR_LT}</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_LE">{RC_OPERATOR_LE}</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_GT">{RC_OPERATOR_GT}</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_GE">{RC_OPERATOR_GE}</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_NE">{RC_OPERATOR_NE}</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_NONE">{RC_OPERATOR_NONE}</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_MULT">{RC_OPERATOR_MULT}</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_DIV">{RC_OPERATOR_DIV}</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_AND">{RC_OPERATOR_AND}</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_XOR">{RC_OPERATOR_XOR}</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_MOD">{RC_OPERATOR_MOD}</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_ADD">{RC_OPERATOR_ADD}</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_SUB">{RC_OPERATOR_SUB}</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_SUB_PARENT">{RC_OPERATOR_SUB_PARENT}</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_INDIRECT_READ">{RC_OPERATOR_INDIRECT_READ}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="__rc_operator_enum_str_t">
<DisplayString Condition="value==RC_OPERATOR_EQ">==</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_LT">&lt;</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_LE">&lt;=</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_GT">&gt;</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_GE">&gt;=</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_NE">!=</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_NONE"> </DisplayString>
<DisplayString Condition="value==RC_OPERATOR_MULT">*</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_DIV">/</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_AND">&amp;</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_XOR">^</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_MOD">%</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_ADD">+</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_SUB">-</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_SUB_PARENT">subtracted from</DisplayString>
<DisplayString Condition="value==RC_OPERATOR_INDIRECT_READ">$</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="rc_condition_t">
<DisplayString Condition="oper==RC_OPERATOR_NONE &amp;&amp; required_hits==0">{*((__rc_condition_enum_str_t*)&amp;type)} {operand1}</DisplayString>
<DisplayString Condition="oper==RC_OPERATOR_NONE">{*((__rc_condition_enum_str_t*)&amp;type)} {operand1} ({required_hits})</DisplayString>
<DisplayString Condition="required_hits==0">{*((__rc_condition_enum_str_t*)&amp;type)} {operand1} {*((__rc_operator_enum_str_t*)&amp;oper)} {operand2}</DisplayString>
<DisplayString>{*((__rc_condition_enum_str_t*)&amp;type)} {operand1} {*((__rc_operator_enum_str_t*)&amp;oper)} {operand2} ({required_hits})</DisplayString>
<Expand>
<Item Name="type">*((__rc_condition_enum_t*)&amp;type)</Item>
<Item Name="operand1">operand1</Item>
<Item Name="oper">*((__rc_operator_enum_t*)&amp;oper)</Item>
<Item Name="operand2">operand2</Item>
<Item Name="required_hits">required_hits</Item>
<Item Name="current_hits">current_hits</Item>
<Item Name="next">next</Item>
</Expand>
</Type>
<Type Name="rc_condset_t">
<DisplayString>{{count={num_pause_conditions+num_reset_conditions+num_hittarget_conditions+num_measured_conditions+num_other_conditions+num_indirect_conditions}}}</DisplayString>
<Expand>
<LinkedListItems>
<HeadPointer>conditions</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="__rc_condset_list_t">
<DisplayString Condition="first_condset==0">{{}}</DisplayString>
<Expand>
<LinkedListItems>
<HeadPointer>first_condset</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="rc_modified_memref_t">
<DisplayString Condition="modifier_type==RC_OPERATOR_INDIRECT_READ">$({parent} + {modifier})</DisplayString>
<DisplayString Condition="modifier_type==RC_OPERATOR_SUB_PARENT">({modifier} - {parent})</DisplayString>
<DisplayString>({parent} {*((__rc_operator_enum_str_t*)&amp;modifier_type)} {modifier})</DisplayString>
<Expand>
<Item Name="value">memref.value</Item>
<Item Name="parent">parent</Item>
<Item Name="modifier_type">*((__rc_operator_enum_t*)&amp;modifier_type)</Item>
<Item Name="modifier">modifier</Item>
</Expand>
</Type>
<Type Name="rc_modified_memref_list_t">
<DisplayString>{{count = {count}}}</DisplayString>
<Expand>
<Item Name="next" Condition="next!=0">next</Item>
<Item Name="count">count</Item>
<Item Name="capacity">capacity</Item>
<ArrayItems>
<Size>count</Size>
<ValuePointer>items</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="__rc_trigger_state_enum_t">
<DisplayString Condition="value==RC_TRIGGER_STATE_INACTIVE">{RC_TRIGGER_STATE_INACTIVE}</DisplayString>
<DisplayString Condition="value==RC_TRIGGER_STATE_WAITING">{RC_TRIGGER_STATE_WAITING}</DisplayString>
<DisplayString Condition="value==RC_TRIGGER_STATE_ACTIVE">{RC_TRIGGER_STATE_ACTIVE}</DisplayString>
<DisplayString Condition="value==RC_TRIGGER_STATE_PAUSED">{RC_TRIGGER_STATE_PAUSED}</DisplayString>
<DisplayString Condition="value==RC_TRIGGER_STATE_RESET">{RC_TRIGGER_STATE_RESET}</DisplayString>
<DisplayString Condition="value==RC_TRIGGER_STATE_TRIGGERED">{RC_TRIGGER_STATE_TRIGGERED}</DisplayString>
<DisplayString Condition="value==RC_TRIGGER_STATE_PRIMED">{RC_TRIGGER_STATE_PRIMED}</DisplayString>
<DisplayString Condition="value==RC_TRIGGER_STATE_DISABLED">{RC_TRIGGER_STATE_DISABLED}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="rc_trigger_t">
<Expand>
<Item Name="state">*((__rc_trigger_state_enum_t*)&amp;state)</Item>
<Item Name="has_hits">*((__rc_bool_enum_t*)&amp;has_hits)</Item>
<Item Name="measured_as_percent">*((__rc_bool_enum_t*)&amp;measured_as_percent)</Item>
<Item Name="requirement">requirement</Item>
<Item Name="alternative">*((__rc_condset_list_t*)&amp;alternative)</Item>
</Expand>
</Type>
<Type Name="rc_value_t">
<DisplayString>{value} {name,s}</DisplayString>
<Expand>
<Item Name="value">value</Item>
<Item Name="conditions">conditions</Item>
<Item Name="name">name</Item>
</Expand>
</Type>
<Type Name="rc_value_list_t">
<DisplayString>{{count = {count}}}</DisplayString>
<Expand>
<Item Name="count">count</Item>
<Item Name="capacity">capacity</Item>
<ArrayItems>
<Size>count</Size>
<ValuePointer>items</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="__rc_lboard_state_enum_t">
<DisplayString Condition="value==RC_LBOARD_STATE_INACTIVE">{RC_LBOARD_STATE_INACTIVE}</DisplayString>
<DisplayString Condition="value==RC_LBOARD_STATE_WAITING">{RC_LBOARD_STATE_WAITING}</DisplayString>
<DisplayString Condition="value==RC_LBOARD_STATE_ACTIVE">{RC_LBOARD_STATE_ACTIVE}</DisplayString>
<DisplayString Condition="value==RC_LBOARD_STATE_STARTED">{RC_LBOARD_STATE_STARTED}</DisplayString>
<DisplayString Condition="value==RC_LBOARD_STATE_CANCELED">{RC_LBOARD_STATE_CANCELED}</DisplayString>
<DisplayString Condition="value==RC_LBOARD_STATE_TRIGGERED">{RC_LBOARD_STATE_TRIGGERED}</DisplayString>
<DisplayString Condition="value==RC_LBOARD_STATE_DISABLED">{RC_LBOARD_STATE_DISABLED}</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="rc_lboard_t">
<Expand>
<Item Name="state">*((__rc_lboard_state_enum_t*)&amp;state)</Item>
<Item Name="start">start</Item>
<Item Name="submit">submit</Item>
<Item Name="cancel">cancel</Item>
<Item Name="value">value</Item>
</Expand>
</Type>
<Type Name="__rc_format_enum_t">
<DisplayString Condition="value==RC_FORMAT_FRAMES">{RC_FORMAT_FRAMES}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_SECONDS">{RC_FORMAT_SECONDS}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_CENTISECS">{RC_FORMAT_CENTISECS}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_SCORE">{RC_FORMAT_SCORE}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_VALUE">{RC_FORMAT_VALUE}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_MINUTES">{RC_FORMAT_MINUTES}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_SECONDS_AS_MINUTES">{RC_FORMAT_SECONDS_AS_MINUTES}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_FLOAT1">{RC_FORMAT_FLOAT1}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_FLOAT2">{RC_FORMAT_FLOAT2}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_FLOAT3">{RC_FORMAT_FLOAT3}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_FLOAT4">{RC_FORMAT_FLOAT4}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_FLOAT5">{RC_FORMAT_FLOAT5}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_FLOAT6">{RC_FORMAT_FLOAT6}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_FIXED1">{RC_FORMAT_FIXED1}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_FIXED2">{RC_FORMAT_FIXED2}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_FIXED3">{RC_FORMAT_FIXED3}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_TENS">{RC_FORMAT_TENS}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_HUNDREDS">{RC_FORMAT_HUNDREDS}</DisplayString>
<DisplayString Condition="value==RC_FORMAT_THOUSANDS">{RC_FORMAT_THOUSANDS}</DisplayString>
<DisplayString Condition="value==101">RC_FORMAT_STRING (101)</DisplayString>
<DisplayString Condition="value==102">RC_FORMAT_LOOKUP (102)</DisplayString>
<DisplayString Condition="value==103">RC_FORMAT_UNKNOWN_MACRO (103)</DisplayString>
<DisplayString Condition="value==104">RC_FORMAT_ASCIICHAR (104)</DisplayString>
<DisplayString Condition="value==105">RC_FORMAT_UNICODECHAR (105)</DisplayString>
<DisplayString>unknown ({value})</DisplayString>
</Type>
<Type Name="rc_richpresence_display_part_t">
<DisplayString Condition="display_type==101">{text,s}</DisplayString>
<DisplayString Condition="display_type==103">[Unknown macro]{text,sb}</DisplayString>
<DisplayString Condition="lookup==0">@{text,sb}({value,na})</DisplayString>
<DisplayString>@{lookup->name,sb}({value,na})</DisplayString>
<Expand>
<Item Name="text" Condition="display_type==101||display_type==103">text</Item>
<Item Name="lookup" Condition="display_type!=101&amp;&amp;display_type!=103">lookup</Item>
<Item Name="value" Condition="display_type!=101&amp;&amp;display_type!=103">value</Item>
<Item Name="display_type">*((__rc_format_enum_t*)&amp;display_type)</Item>
</Expand>
</Type>
<Type Name="__rc_richpresence_display_part_list_t">
<DisplayString Condition="display->next->next!=0">{display,na} {display->next,na} {display->next->next,na}</DisplayString>
<DisplayString Condition="display->next!=0">{display,na} {display->next,na}</DisplayString>
<DisplayString>{display,na}</DisplayString>
<Expand>
<LinkedListItems>
<HeadPointer>display</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="rc_richpresence_display_t">
<Expand>
<Item Name="displays">*((__rc_richpresence_display_part_list_t*)&amp;display)</Item>
<Item Name="trigger">trigger</Item>
</Expand>
</Type>
<Type Name="__rc_richpresence_display_list_t">
<DisplayString Condition="first_display==0">{{NULL}}</DisplayString>
<DisplayString>{(void*)&amp;first_display,na}</DisplayString>
<Expand>
<LinkedListItems>
<HeadPointer>first_display</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="rc_richpresence_lookup_item_t">
<DisplayString Condition="first==last">{first}: {label,na}</DisplayString>
<DisplayString>{first}-{last}: {label,na}</DisplayString>
</Type>
<Type Name="rc_richpresence_lookup_t">
<DisplayString>{name,na}</DisplayString>
<Expand>
<Item Name="name">name</Item>
<Item Name="format">*((__rc_format_enum_t*)&amp;format)</Item>
<Item Name="default_label" Condition="format>101">default_label</Item>
<TreeItems>
<HeadPointer>root</HeadPointer>
<LeftPointer>left</LeftPointer>
<RightPointer>right</RightPointer>
<ValueNode>this</ValueNode>
</TreeItems>
</Expand>
</Type>
<Type Name="__rc_richpresence_lookup_list_t">
<DisplayString Condition="first_lookup==0">{{NULL}}</DisplayString>
<DisplayString>{(void*)&amp;first_lookup,na}</DisplayString>
<Expand>
<LinkedListItems>
<HeadPointer>first_lookup</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="rc_richpresence_t">
<Expand>
<Item Name="displays">((__rc_richpresence_display_list_t*)&amp;first_display)</Item>
<Item Name="lookups">((__rc_richpresence_lookup_list_t*)&amp;first_lookup)</Item>
</Expand>
</Type>
<Type Name="__rc_value_list_t">
<DisplayString Condition="first_value==0">{{NULL}}</DisplayString>
<DisplayString>{(void*)&amp;first_value,na}</DisplayString>
<Expand>
<LinkedListItems>
<HeadPointer>first_value</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="rc_parse_state_t">
<DisplayString>{{offset={offset} addsource_parent={addsource_parent} indirect_parent={indirect_parent}}}</DisplayString>
<Expand>
<Item Name="offset">offset</Item>
<Item Name="memrefs">memrefs</Item>
<Item Name="existing_memrefs">existing_memrefs</Item>
<Item Name="variables" Condition="variables==0">variables</Item>
<Item Name="variables" Condition="variables!=0">((__rc_value_list_t*)&amp;variables)</Item>
<Item Name="addsource_parent">addsource_parent</Item>
<Item Name="addsource_oper">*((__rc_operator_enum_t*)&amp;addsource_oper)</Item>
<Item Name="indirect_parent">indirect_parent</Item>
<Item Name="remember">remember</Item>
<Item Name="is_value">*((__rc_bool_enum_t*)&amp;is_value)</Item>
<Item Name="has_required_hits">*((__rc_bool_enum_t*)&amp;has_required_hits)</Item>
<Item Name="measured_as_percent">*((__rc_bool_enum_t*)&amp;measured_as_percent)</Item>
</Expand>
</Type>
<Type Name="rc_buffer_chunk_t">
<DisplayString>{{used={write-start} size={end-start}}}</DisplayString>
<Expand>
<Item Name="[size]">end-start</Item>
<Item Name="[used]">write-start</Item>
<Item Name="[available]">end-write</Item>
<Item Name="next">next</Item>
</Expand>
</Type>
<Type Name="rc_buffer_t">
<DisplayString></DisplayString>
<Expand>
<LinkedListItems>
<HeadPointer>&amp;chunk</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="__rc_runtime_trigger_list_t">
<DisplayString>{{count={runtime.trigger_count}}}</DisplayString>
<Expand>
<IndexListItems>
<Size>runtime.trigger_count</Size>
<ValueNode>runtime.triggers[$i]</ValueNode>
</IndexListItems>
</Expand>
</Type>
<Type Name="__rc_runtime_lboard_list_t">
<DisplayString>{{count={runtime.lboard_count}}}</DisplayString>
<Expand>
<IndexListItems>
<Size>runtime.lboard_count</Size>
<ValueNode>runtime.lboards[$i]</ValueNode>
</IndexListItems>
</Expand>
</Type>
<Type Name="rc_runtime_t">
<DisplayString>{{trigger_count={trigger_count} lboard_count={lboard_count}}}</DisplayString>
<Expand>
<Item Name="triggers">*((__rc_runtime_trigger_list_t*)this)</Item>
<Item Name="lboards">*((__rc_runtime_lboard_list_t*)this)</Item>
<Item Name="richpresence">richpresence</Item>
<Item Name="memrefs">memrefs</Item>
</Expand>
</Type>
</AutoVisualizer>

View File

@@ -17,6 +17,7 @@ static int rc_validate_memref(const rc_memref_t* memref, char result[], const si
switch (console_id) {
case RC_CONSOLE_NINTENDO:
case RC_CONSOLE_FAMICOM_DISK_SYSTEM:
if (memref->address >= 0x0800 && memref->address <= 0x1FFF) {
snprintf(result, result_size, "Mirror RAM may not be exposed by emulator (address %04X)", memref->address);
return 0;
@@ -42,14 +43,19 @@ static int rc_validate_memref(const rc_memref_t* memref, char result[], const si
return 1;
}
int rc_validate_memrefs(const rc_memref_t* memref, char result[], const size_t result_size, uint32_t max_address)
int rc_validate_memrefs(const rc_memrefs_t* memrefs, char result[], const size_t result_size, uint32_t max_address)
{
while (memref) {
if (!rc_validate_memref(memref, result, result_size, 0, max_address))
return 0;
const rc_memref_list_t* memref_list = &memrefs->memrefs;
do {
const rc_memref_t* memref = memref_list->items;
const rc_memref_t* memref_stop = memref + memref_list->count;
for (; memref < memref_stop; ++memref) {
if (!rc_validate_memref(memref, result, result_size, 0, max_address))
return 0;
}
memref = memref->next;
}
memref_list = memref_list->next;
} while (memref_list);
return 1;
}
@@ -64,15 +70,22 @@ static uint32_t rc_console_max_address(uint32_t console_id)
return 0xFFFFFFFF;
}
int rc_validate_memrefs_for_console(const rc_memref_t* memref, char result[], const size_t result_size, uint32_t console_id)
int rc_validate_memrefs_for_console(const rc_memrefs_t* memrefs, char result[], const size_t result_size, uint32_t console_id)
{
const uint32_t max_address = rc_console_max_address(console_id);
while (memref) {
if (!rc_validate_memref(memref, result, result_size, console_id, max_address))
return 0;
const rc_memref_list_t* memref_list = &memrefs->memrefs;
do
{
const rc_memref_t* memref = memref_list->items;
const rc_memref_t* memref_stop = memref + memref_list->count;
for (; memref < memref_stop; ++memref)
{
if (!rc_validate_memref(memref, result, result_size, console_id, max_address))
return 0;
}
memref = memref->next;
}
memref_list = memref_list->next;
} while (memref_list);
return 1;
}
@@ -104,6 +117,7 @@ static uint32_t rc_max_value(const rc_operand_t* operand)
return 8;
case RC_MEMSIZE_8_BITS:
/* NOTE: BCD should max out at 0x99, but because each digit can be 15, it actually maxes at 15*10 + 15 */
return (operand->type == RC_OPERAND_BCD) ? 165 : 0xFF;
case RC_MEMSIZE_16_BITS:
@@ -160,10 +174,18 @@ static uint32_t rc_scale_value(uint32_t value, uint8_t oper, const rc_operand_t*
case RC_OPERATOR_SUB:
{
if (operand->type == RC_OPERAND_CONST)
return value - operand->value.num;
else if (value > rc_max_value(operand))
return value - rc_max_value(operand);
const uint32_t op_max = (operand->type == RC_OPERAND_CONST) ? operand->value.num : rc_max_value(operand);
if (value > op_max)
return value - op_max;
return 0xFFFFFFFF;
}
case RC_OPERATOR_SUB_PARENT:
{
const uint32_t op_max = (operand->type == RC_OPERAND_CONST) ? operand->value.num : rc_max_value(operand);
if (op_max > value)
return op_max - value;
return 0xFFFFFFFF;
}
@@ -173,6 +195,17 @@ static uint32_t rc_scale_value(uint32_t value, uint8_t oper, const rc_operand_t*
}
}
static uint32_t rc_max_chain_value(const rc_operand_t* operand)
{
if (rc_operand_is_memref(operand) && operand->value.memref->value.memref_type == RC_MEMREF_TYPE_MODIFIED_MEMREF) {
const rc_modified_memref_t* modified_memref = (const rc_modified_memref_t*)operand->value.memref;
const uint32_t op_max = rc_max_chain_value(&modified_memref->parent);
return rc_scale_value(op_max, modified_memref->modifier_type, &modified_memref->modifier);
}
return rc_max_value(operand);
}
static int rc_validate_get_condition_index(const rc_condset_t* condset, const rc_condition_t* condition)
{
int index = 1;
@@ -256,18 +289,14 @@ static int rc_validate_range(uint32_t min_val, uint32_t max_val, char oper, uint
return 1;
}
int rc_validate_condset_internal(const rc_condset_t* condset, char result[], const size_t result_size, uint32_t console_id, uint32_t max_address)
static int rc_validate_condset_internal(const rc_condset_t* condset, char result[], const size_t result_size, uint32_t console_id, uint32_t max_address)
{
const rc_condition_t* cond;
char buffer[128];
uint32_t max_val;
int index = 1;
unsigned long long add_source_max = 0;
int in_add_hits = 0;
int in_add_address = 0;
int is_combining = 0;
int remember_used = 0;
int remember_used_in_pause = 0;
if (!condset) {
*result = '\0';
@@ -275,10 +304,8 @@ int rc_validate_condset_internal(const rc_condset_t* condset, char result[], con
}
for (cond = condset->conditions; cond; cond = cond->next, ++index) {
uint32_t max = rc_max_value(&cond->operand1);
const int is_memref1 = rc_operand_is_memref(&cond->operand1);
const int is_memref2 = rc_operand_is_memref(&cond->operand2);
const int uses_recall = rc_operand_is_recall(&cond->operand1) || rc_operand_is_recall(&cond->operand2);
if (!in_add_address) {
if (is_memref1 && !rc_validate_memref(cond->operand1.value.memref, buffer, sizeof(buffer), console_id, max_address)) {
@@ -294,39 +321,24 @@ int rc_validate_condset_internal(const rc_condset_t* condset, char result[], con
in_add_address = 0;
}
if (!remember_used && uses_recall) {
if (!cond->pause && condset->has_pause) {
/* pause conditions will be processed before non-pause conditions.
* scan forward for any remembers in yet-to-be-processed pause conditions */
const rc_condition_t* cond_rem_pause_check = cond->next;
for (; cond_rem_pause_check; cond_rem_pause_check = cond_rem_pause_check->next) {
if (cond_rem_pause_check->type == RC_CONDITION_REMEMBER && cond_rem_pause_check->pause) {
remember_used = 1; /* do not set remember_used_in_pause here because we don't know at which poing in the pause processing this remember is occurring. */
break;
}
}
}
if (!remember_used) {
if (rc_operand_is_recall(&cond->operand1)) {
if (rc_operand_type_is_memref(cond->operand1.memref_access_type) && !cond->operand1.value.memref) {
snprintf(result, result_size, "Condition %d: Recall used before Remember", index);
return 0;
}
}
else if (cond->pause && uses_recall && !remember_used_in_pause) {
snprintf(result, result_size, "Condition %d: Recall used in Pause processing before Remember was used in Pause processing", index);
return 0;
if (rc_operand_is_recall(&cond->operand2)) {
if (rc_operand_type_is_memref(cond->operand2.memref_access_type) && !cond->operand2.value.memref) {
snprintf(result, result_size, "Condition %d: Recall used before Remember", index);
return 0;
}
}
switch (cond->type) {
case RC_CONDITION_ADD_SOURCE:
max = rc_scale_value(max, cond->oper, &cond->operand2);
add_source_max += max;
is_combining = 1;
continue;
case RC_CONDITION_SUB_SOURCE:
max = rc_scale_value(max, cond->oper, &cond->operand2);
if (add_source_max < max) /* potential underflow - may be expected */
add_source_max = 0xFFFFFFFF;
case RC_CONDITION_REMEMBER:
is_combining = 1;
continue;
@@ -339,12 +351,6 @@ int rc_validate_condset_internal(const rc_condset_t* condset, char result[], con
is_combining = 1;
continue;
case RC_CONDITION_REMEMBER:
is_combining = 1;
remember_used = 1;
remember_used_in_pause += cond->pause;
continue;
case RC_CONDITION_ADD_HITS:
case RC_CONDITION_SUB_HITS:
in_add_hits = 1;
@@ -377,18 +383,11 @@ int rc_validate_condset_internal(const rc_condset_t* condset, char result[], con
break;
}
/* if we're in an add source chain, check for overflow */
if (add_source_max) {
const unsigned long long overflow = add_source_max + max;
if (overflow > 0xFFFFFFFFUL)
max = 0xFFFFFFFF;
else
max += (unsigned)add_source_max;
}
/* check for comparing two differently sized memrefs */
max_val = rc_max_value(&cond->operand2);
if (max_val != max && add_source_max == 0 && is_memref1 && is_memref2) {
if (is_memref1 && is_memref2 &&
cond->operand1.value.memref->value.memref_type == RC_MEMREF_TYPE_MEMREF &&
cond->operand2.value.memref->value.memref_type == RC_MEMREF_TYPE_MEMREF &&
rc_max_value(&cond->operand1) != rc_max_value(&cond->operand2)) {
snprintf(result, result_size, "Condition %d: Comparing different memory sizes", index);
return 0;
}
@@ -396,19 +395,23 @@ int rc_validate_condset_internal(const rc_condset_t* condset, char result[], con
if (is_memref1 && rc_operand_is_float(&cond->operand1)) {
/* if left side is a float, right side will be converted to a float, so don't do range validation */
}
else if (is_memref1 || is_memref2 || add_source_max) {
/* if either side is a memref, or there's a running add source chain, check for impossible comparisons */
else if (is_memref1 || is_memref2) {
/* if either side is a memref, check for impossible comparisons */
const size_t prefix_length = snprintf(result, result_size, "Condition %d: ", index);
const rc_operand_t* operand1 = &cond->operand1;
const rc_operand_t* operand2 = &cond->operand2;
uint8_t oper = cond->oper;
uint32_t max = rc_max_chain_value(operand1);
uint32_t max_val = rc_max_value(operand2);
uint32_t min_val;
if (!is_memref1 && !add_source_max) {
if (!is_memref1) {
/* pretend constant was on right side */
operand1 = &cond->operand2;
operand2 = &cond->operand1;
max = max_val;
max_val = max;
max = rc_max_value(&cond->operand2);
switch (oper) {
case RC_OPERATOR_LT: oper = RC_OPERATOR_GT; break;
case RC_OPERATOR_LE: oper = RC_OPERATOR_GE; break;
@@ -426,8 +429,7 @@ int rc_validate_condset_internal(const rc_condset_t* condset, char result[], con
min_val = (int)operand2->value.dbl;
/* cannot compare an integer memory reference to a non-integral floating point value */
if (!add_source_max && !rc_operand_is_float_memref(operand1) &&
(float)min_val != operand2->value.dbl) {
if (!rc_operand_is_float_memref(operand1) && (float)min_val != operand2->value.dbl) {
switch (oper) {
case RC_OPERATOR_EQ:
snprintf(result + prefix_length, result_size - prefix_length, "Comparison is never true");
@@ -455,8 +457,6 @@ int rc_validate_condset_internal(const rc_condset_t* condset, char result[], con
if (!rc_validate_range(min_val, max_val, oper, max, result + prefix_length, result_size - prefix_length))
return 0;
}
add_source_max = 0;
}
if (is_combining) {
@@ -697,24 +697,6 @@ static int rc_validate_comparison_overlap(int comparison1, uint32_t value1, int
return RC_OVERLAP_NONE;
}
static int rc_validate_are_operands_equal(const rc_operand_t* oper1, const rc_operand_t* oper2)
{
if (oper1->type != oper2->type)
return 0;
switch (oper1->type)
{
case RC_OPERAND_CONST:
return (oper1->value.num == oper2->value.num);
case RC_OPERAND_FP:
return (oper1->value.dbl == oper2->value.dbl);
case RC_OPERAND_RECALL:
return (oper2->type == RC_OPERAND_RECALL);
default:
return (oper1->value.memref->address == oper2->value.memref->address && oper1->size == oper2->size);
}
}
static int rc_validate_conflicting_conditions(const rc_condset_t* conditions, const rc_condset_t* compare_conditions,
const char* prefix, const char* compare_prefix, char result[], const size_t result_size)
{
@@ -736,7 +718,7 @@ static int rc_validate_conflicting_conditions(const rc_condset_t* conditions, co
for (condition = conditions->conditions; condition != NULL; condition = condition->next)
{
condition_chain_start = condition;
while (rc_condition_is_combining(condition))
while (condition && rc_condition_is_combining(condition))
condition = condition->next;
if (!condition)
break;
@@ -787,14 +769,14 @@ static int rc_validate_conflicting_conditions(const rc_condset_t* conditions, co
if (compare_condition->type != condition_chain_iter->type ||
compare_condition->oper != condition_chain_iter->oper ||
compare_condition->required_hits != condition_chain_iter->required_hits ||
!rc_validate_are_operands_equal(&compare_condition->operand1, &condition_chain_iter->operand1))
!rc_operands_are_equal(&compare_condition->operand1, &condition_chain_iter->operand1))
{
chain_matches = 0;
break;
}
if (compare_condition->oper != RC_OPERATOR_NONE &&
!rc_validate_are_operands_equal(&compare_condition->operand2, &condition_chain_iter->operand2))
!rc_operands_are_equal(&compare_condition->operand2, &condition_chain_iter->operand2))
{
chain_matches = 0;
break;

View File

@@ -7,13 +7,9 @@
RC_BEGIN_C_DECLS
int rc_validate_memrefs(const rc_memref_t* memref, char result[], const size_t result_size, uint32_t max_address);
int rc_validate_condset(const rc_condset_t* condset, char result[], const size_t result_size, uint32_t max_address);
int rc_validate_trigger(const rc_trigger_t* trigger, char result[], const size_t result_size, uint32_t max_address);
int rc_validate_memrefs_for_console(const rc_memref_t* memref, char result[], const size_t result_size, uint32_t console_id);
int rc_validate_condset_for_console(const rc_condset_t* condset, char result[], const size_t result_size, uint32_t console_id);
int rc_validate_trigger_for_console(const rc_trigger_t* trigger, char result[], const size_t result_size, uint32_t console_id);

View File

@@ -13,29 +13,67 @@ enum {
RC_FORMAT_UNICODECHAR = 105
};
static rc_memref_value_t* rc_alloc_helper_variable_memref_value(const char* memaddr, int memaddr_len, rc_parse_state_t* parse) {
const char* end;
rc_value_t* variable;
uint32_t address;
uint8_t size;
static void rc_alloc_helper_variable_memref_value(rc_richpresence_display_part_t* part, const char* memaddr, int memaddr_len, rc_parse_state_t* parse) {
rc_preparse_state_t preparse;
const char* test_memaddr = memaddr;
rc_condset_t* condset;
rc_value_t* value;
int32_t size;
/* single memory reference lookups without a modifier flag can be handled without a variable */
end = memaddr;
if (rc_parse_memref(&end, &size, &address) == RC_OK) {
/* make sure the entire memaddr was consumed. if not, there's an operator and it's a comparison, not a memory reference */
if (end == &memaddr[memaddr_len]) {
/* if it's not a derived size, we can reference the memref directly */
if (rc_memref_shared_size(size) == size)
return &rc_alloc_memref(parse, address, size, 0)->value;
part->value.type = RC_OPERAND_NONE;
/* if the expression can be represented as just a memory reference, do so */
rc_init_preparse_state(&preparse, NULL, 0);
preparse.parse.existing_memrefs = parse->memrefs;
value = RC_ALLOC(rc_value_t, &preparse.parse);
rc_parse_value_internal(value, &test_memaddr, &preparse.parse);
size = preparse.parse.offset;
if (size < 0) {
parse->offset = size;
rc_destroy_preparse_state(&preparse);
return;
}
/* ensure new needed memrefs are allocated in the primary buffer */
rc_preparse_copy_memrefs(parse, &preparse.memrefs);
/* parse the value into the scratch buffer so we can look at it */
rc_reset_parse_state(&preparse.parse, rc_buffer_alloc(&preparse.parse.scratch.buffer, (size_t)size), NULL, 0);
preparse.parse.memrefs = parse->memrefs;
preparse.parse.existing_memrefs = parse->existing_memrefs;
value = RC_ALLOC(rc_value_t, &preparse.parse);
test_memaddr = memaddr;
rc_parse_value_internal(value, &test_memaddr, &preparse.parse);
condset = value->conditions;
if (condset && !condset->next) {
/* single value - if it's only "measured" and "indirect" conditions, we can simplify to a memref */
if (condset->num_measured_conditions &&
!condset->num_pause_conditions && !condset->num_reset_conditions &&
!condset->num_other_conditions && !condset->num_hittarget_conditions) {
rc_condition_t* condition = condset->conditions;
for (; condition; condition = condition->next) {
if (condition->type == RC_CONDITION_MEASURED && condition->required_hits == 0) {
memcpy(&part->value, &condition->operand1, sizeof(condition->operand1));
break;
}
}
}
}
/* not a simple memory reference, need to create a variable */
variable = rc_alloc_helper_variable(memaddr, memaddr_len, parse);
if (!variable)
return NULL;
rc_destroy_preparse_state(&preparse);
return &variable->value;
/* could not express value with just a memory reference, create a helper variable */
if (part->value.type == RC_OPERAND_NONE) {
value = rc_alloc_variable(memaddr, memaddr_len, parse);
if (value) {
part->value.value.memref = (rc_memref_t*)&value->value;
part->value.type = RC_OPERAND_ADDRESS;
part->value.size = RC_MEMSIZE_32_BITS;
part->value.memref_access_type = RC_OPERAND_ADDRESS;
}
}
}
static const char* rc_parse_line(const char* line, const char** end, rc_parse_state_t* parse) {
@@ -220,7 +258,7 @@ static rc_richpresence_display_t* rc_parse_richpresence_display_internal(const c
part->text = rc_alloc_str(parse, in, (int)(ptr - in));
}
else if (part->display_type != RC_FORMAT_UNKNOWN_MACRO) {
part->value = rc_alloc_helper_variable_memref_value(line, (int)(ptr - line), parse);
rc_alloc_helper_variable_memref_value(part, line, (int)(ptr - line), parse);
if (parse->offset < 0)
return 0;
@@ -468,6 +506,8 @@ void rc_parse_richpresence_internal(rc_richpresence_t* self, const char* script,
int display_line = 0;
int chars;
self->values = NULL;
/* special case for empty script to return 1 line read */
if (!*script) {
parse->lines_read = 1;
@@ -558,11 +598,20 @@ void rc_parse_richpresence_internal(rc_richpresence_t* self, const char* script,
*nextdisplay = rc_parse_richpresence_display_internal(ptr + 1, endline, parse, firstlookup);
if (parse->offset < 0)
return;
trigger = &((*nextdisplay)->trigger);
rc_parse_trigger_internal(trigger, &line, parse);
trigger->memrefs = 0;
if (parse->offset < 0)
return;
if (line != ptr) {
/* incomplete read */
parse->offset = RC_INVALID_OPERATOR;
return;
}
(*nextdisplay)->has_required_hits = parse->has_required_hits;
if (parse->buffer)
nextdisplay = &((*nextdisplay)->next);
}
@@ -593,6 +642,7 @@ void rc_parse_richpresence_internal(rc_richpresence_t* self, const char* script,
/* finalize */
*nextdisplay = 0;
self->has_memrefs = 0;
if (!hasdisplay && parse->offset > 0) {
parse->offset = RC_MISSING_DISPLAY_STRING;
@@ -600,22 +650,20 @@ void rc_parse_richpresence_internal(rc_richpresence_t* self, const char* script,
}
int rc_richpresence_size_lines(const char* script, int* lines_read) {
rc_richpresence_t* self;
rc_parse_state_t parse;
rc_memref_t* first_memref;
rc_value_t* variables;
rc_init_parse_state(&parse, 0, 0, 0);
rc_init_parse_state_memrefs(&parse, &first_memref);
rc_init_parse_state_variables(&parse, &variables);
rc_richpresence_with_memrefs_t* richpresence;
rc_preparse_state_t preparse;
rc_init_preparse_state(&preparse, NULL, 0);
self = RC_ALLOC(rc_richpresence_t, &parse);
rc_parse_richpresence_internal(self, script, &parse);
richpresence = RC_ALLOC(rc_richpresence_with_memrefs_t, &preparse.parse);
preparse.parse.variables = &richpresence->richpresence.values;
rc_parse_richpresence_internal(&richpresence->richpresence, script, &preparse.parse);
rc_preparse_alloc_memrefs(NULL, &preparse);
if (lines_read)
*lines_read = parse.lines_read;
*lines_read = preparse.parse.lines_read;
rc_destroy_parse_state(&parse);
return parse.offset;
rc_destroy_preparse_state(&preparse);
return preparse.parse.offset;
}
int rc_richpresence_size(const char* script) {
@@ -623,32 +671,53 @@ int rc_richpresence_size(const char* script) {
}
rc_richpresence_t* rc_parse_richpresence(void* buffer, const char* script, lua_State* L, int funcs_ndx) {
rc_richpresence_t* self;
rc_parse_state_t parse;
rc_richpresence_with_memrefs_t* richpresence;
rc_preparse_state_t preparse;
if (!buffer || !script)
return NULL;
rc_init_parse_state(&parse, buffer, L, funcs_ndx);
rc_init_preparse_state(&preparse, L, funcs_ndx);
richpresence = RC_ALLOC(rc_richpresence_with_memrefs_t, &preparse.parse);
preparse.parse.variables = &richpresence->richpresence.values;
rc_parse_richpresence_internal(&richpresence->richpresence, script, &preparse.parse);
self = RC_ALLOC(rc_richpresence_t, &parse);
rc_init_parse_state_memrefs(&parse, &self->memrefs);
rc_init_parse_state_variables(&parse, &self->variables);
rc_reset_parse_state(&preparse.parse, buffer, L, funcs_ndx);
richpresence = RC_ALLOC(rc_richpresence_with_memrefs_t, &preparse.parse);
preparse.parse.variables = &richpresence->richpresence.values;
rc_preparse_alloc_memrefs(&richpresence->memrefs, &preparse);
rc_parse_richpresence_internal(self, script, &parse);
rc_parse_richpresence_internal(&richpresence->richpresence, script, &preparse.parse);
richpresence->richpresence.has_memrefs = 1;
rc_destroy_parse_state(&parse);
return (parse.offset >= 0) ? self : NULL;
rc_destroy_preparse_state(&preparse);
return (preparse.parse.offset >= 0) ? &richpresence->richpresence : NULL;
}
static void rc_update_richpresence_memrefs(rc_richpresence_t* self, rc_peek_t peek, void* ud) {
if (self->has_memrefs) {
rc_richpresence_with_memrefs_t* richpresence = (rc_richpresence_with_memrefs_t*)self;
rc_update_memref_values(&richpresence->memrefs, peek, ud);
}
}
rc_memrefs_t* rc_richpresence_get_memrefs(rc_richpresence_t* self) {
if (self->has_memrefs) {
rc_richpresence_with_memrefs_t* richpresence = (rc_richpresence_with_memrefs_t*)self;
return &richpresence->memrefs;
}
return NULL;
}
void rc_update_richpresence(rc_richpresence_t* richpresence, rc_peek_t peek, void* peek_ud, lua_State* L) {
rc_richpresence_display_t* display;
rc_update_memref_values(richpresence->memrefs, peek, peek_ud);
rc_update_variables(richpresence->variables, peek, peek_ud, L);
rc_update_richpresence_memrefs(richpresence, peek, peek_ud);
rc_update_values(richpresence->values, peek, peek_ud, L);
for (display = richpresence->first_display; display; display = display->next) {
if (display->trigger.has_required_hits)
if (display->has_required_hits)
rc_test_trigger(&display->trigger, peek, peek_ud, L);
}
}
@@ -671,7 +740,7 @@ static int rc_evaluate_richpresence_display(rc_richpresence_display_part_t* part
break;
case RC_FORMAT_LOOKUP:
rc_typed_value_from_memref_value(&value, part->value);
rc_evaluate_operand(&value, &part->value, NULL);
rc_typed_value_convert(&value, RC_VALUE_TYPE_UNSIGNED);
text = part->lookup->default_label;
@@ -698,7 +767,7 @@ static int rc_evaluate_richpresence_display(rc_richpresence_display_part_t* part
value.type = RC_VALUE_TYPE_UNSIGNED;
do {
value.value.u32 = part->value->value;
rc_evaluate_operand(&value, &part->value, NULL);
if (value.value.u32 == 0) {
/* null terminator - skip over remaining character macros */
while (part->next && part->next->display_type == RC_FORMAT_ASCIICHAR)
@@ -725,7 +794,7 @@ static int rc_evaluate_richpresence_display(rc_richpresence_display_part_t* part
value.type = RC_VALUE_TYPE_UNSIGNED;
do {
value.value.u32 = part->value->value;
rc_evaluate_operand(&value, &part->value, NULL);
if (value.value.u32 == 0) {
/* null terminator - skip over remaining character macros */
while (part->next && part->next->display_type == RC_FORMAT_UNICODECHAR)
@@ -770,7 +839,7 @@ static int rc_evaluate_richpresence_display(rc_richpresence_display_part_t* part
break;
default:
rc_typed_value_from_memref_value(&value, part->value);
rc_evaluate_operand(&value, &part->value, NULL);
chars = rc_format_typed_value(tmp, sizeof(tmp), &value, part->display_type);
text = tmp;
break;
@@ -806,7 +875,7 @@ int rc_get_richpresence_display_string(rc_richpresence_t* richpresence, char* bu
return rc_evaluate_richpresence_display(display->display, buffer, buffersize);
/* triggers with required hits will be updated in rc_update_richpresence */
if (!display->trigger.has_required_hits)
if (!display->has_required_hits)
rc_test_trigger(&display->trigger, peek, peek_ud, L);
/* if we've found a valid condition, process it */
@@ -823,15 +892,16 @@ int rc_evaluate_richpresence(rc_richpresence_t* richpresence, char* buffer, size
return rc_get_richpresence_display_string(richpresence, buffer, buffersize, peek, peek_ud, L);
}
void rc_reset_richpresence(rc_richpresence_t* self) {
void rc_reset_richpresence_triggers(rc_richpresence_t* self) {
rc_richpresence_display_t* display;
rc_value_t* variable;
for (display = self->first_display; display; display = display->next)
rc_reset_trigger(&display->trigger);
}
for (variable = self->variables; variable; variable = variable->next)
rc_reset_value(variable);
void rc_reset_richpresence(rc_richpresence_t* self) {
rc_reset_richpresence_triggers(self);
rc_reset_values(self->values);
}
static int rc_get_richpresence_strings_has_string(const char** buffer, size_t written, const char* search) {

View File

@@ -9,8 +9,34 @@
#define RC_RICHPRESENCE_DISPLAY_BUFFER_SIZE 256
/* ===== natvis extensions ===== */
typedef struct __rc_runtime_trigger_list_t { rc_runtime_t runtime; } __rc_runtime_trigger_list_t;
typedef struct __rc_runtime_lboard_list_t { rc_runtime_t runtime; } __rc_runtime_lboard_list_t;
static void rc_runtime_natvis_helper(const rc_runtime_event_t* runtime_event)
{
struct natvis_extensions {
__rc_runtime_trigger_list_t trigger_list;
__rc_runtime_lboard_list_t lboard_list;
} natvis;
memset(&natvis, 0, sizeof(natvis));
(void)runtime_event;
natvis.lboard_list.runtime.lboard_count = 0;
}
/* ============================= */
rc_runtime_t* rc_runtime_alloc(void) {
rc_runtime_t* self = malloc(sizeof(rc_runtime_t));
rc_runtime_t* self;
/* create a reference to rc_runtime_natvis_helper so the extensions get compiled in. */
rc_runtime_event_handler_t unused = &rc_runtime_natvis_helper;
(void)unused;
self = malloc(sizeof(rc_runtime_t));
if (self) {
rc_runtime_init(self);
@@ -22,16 +48,19 @@ rc_runtime_t* rc_runtime_alloc(void) {
void rc_runtime_init(rc_runtime_t* self) {
memset(self, 0, sizeof(rc_runtime_t));
self->next_memref = &self->memrefs;
self->next_variable = &self->variables;
self->memrefs = (rc_memrefs_t*)malloc(sizeof(*self->memrefs));
rc_memrefs_init(self->memrefs);
}
void rc_runtime_destroy(rc_runtime_t* self) {
uint32_t i;
if (self->triggers) {
for (i = 0; i < self->trigger_count; ++i)
free(self->triggers[i].buffer);
for (i = 0; i < self->trigger_count; ++i) {
if (self->triggers[i].buffer)
free(self->triggers[i].buffer);
}
free(self->triggers);
self->triggers = NULL;
@@ -40,8 +69,10 @@ void rc_runtime_destroy(rc_runtime_t* self) {
}
if (self->lboards) {
for (i = 0; i < self->lboard_count; ++i)
free(self->lboards[i].buffer);
for (i = 0; i < self->lboard_count; ++i) {
if (self->lboards[i].buffer)
free(self->lboards[i].buffer);
}
free(self->lboards);
self->lboards = NULL;
@@ -49,20 +80,17 @@ void rc_runtime_destroy(rc_runtime_t* self) {
self->lboard_count = self->lboard_capacity = 0;
}
while (self->richpresence) {
rc_runtime_richpresence_t* previous = self->richpresence->previous;
free(self->richpresence->buffer);
if (self->richpresence) {
if (self->richpresence->buffer)
free(self->richpresence->buffer);
free(self->richpresence);
self->richpresence = previous;
}
self->next_memref = 0;
self->memrefs = 0;
if (self->memrefs)
rc_memrefs_destroy(self->memrefs);
if (self->owns_self) {
if (self->owns_self)
free(self);
}
}
void rc_runtime_checksum(const char* memaddr, uint8_t* md5) {
@@ -72,45 +100,12 @@ void rc_runtime_checksum(const char* memaddr, uint8_t* md5) {
md5_finish(&state, md5);
}
static char rc_runtime_allocated_memrefs(rc_runtime_t* self) {
char owns_memref = 0;
/* if at least one memref was allocated within the object, we can't free the buffer when the object is deactivated */
if (*self->next_memref != NULL) {
owns_memref = 1;
/* advance through the new memrefs so we're ready for the next allocation */
do {
self->next_memref = &(*self->next_memref)->next;
} while (*self->next_memref != NULL);
}
/* if at least one variable was allocated within the object, we can't free the buffer when the object is deactivated */
if (*self->next_variable != NULL) {
owns_memref = 1;
/* advance through the new variables so we're ready for the next allocation */
do {
self->next_variable = &(*self->next_variable)->next;
} while (*self->next_variable != NULL);
}
return owns_memref;
}
static void rc_runtime_deactivate_trigger_by_index(rc_runtime_t* self, uint32_t index) {
if (self->triggers[index].owns_memrefs) {
/* if the trigger has one or more memrefs in its buffer, we can't free the buffer.
* just null out the trigger so the runtime processor will skip it
*/
rc_reset_trigger(self->triggers[index].trigger);
self->triggers[index].trigger = NULL;
}
else {
/* trigger doesn't own any memrefs, go ahead and free it, then replace it with the last trigger */
free(self->triggers[index].buffer);
/* free the trigger, then replace it with the last trigger */
free(self->triggers[index].buffer);
if (--self->trigger_count > index)
memcpy(&self->triggers[index], &self->triggers[self->trigger_count], sizeof(rc_runtime_trigger_t));
}
if (--self->trigger_count > index)
memcpy(&self->triggers[index], &self->triggers[self->trigger_count], sizeof(rc_runtime_trigger_t));
}
void rc_runtime_deactivate_achievement(rc_runtime_t* self, uint32_t id) {
@@ -126,7 +121,8 @@ int rc_runtime_activate_achievement(rc_runtime_t* self, uint32_t id, const char*
void* trigger_buffer;
rc_trigger_t* trigger;
rc_runtime_trigger_t* runtime_trigger;
rc_parse_state_t parse;
rc_preparse_state_t preparse;
const char* preparse_memaddr = memaddr;
uint8_t md5[16];
int32_t size;
uint32_t i;
@@ -169,7 +165,12 @@ int rc_runtime_activate_achievement(rc_runtime_t* self, uint32_t id, const char*
}
/* item has not been previously registered, determine how much space we need for it, and allocate it */
size = rc_trigger_size(memaddr);
rc_init_preparse_state(&preparse, NULL, 0);
preparse.parse.existing_memrefs = self->memrefs;
trigger = RC_ALLOC(rc_trigger_t, &preparse.parse);
rc_parse_trigger_internal(trigger, &preparse_memaddr, &preparse.parse);
size = preparse.parse.offset;
if (size < 0)
return size;
@@ -178,16 +179,15 @@ int rc_runtime_activate_achievement(rc_runtime_t* self, uint32_t id, const char*
return RC_OUT_OF_MEMORY;
/* populate the item, using the communal memrefs pool */
rc_init_parse_state(&parse, trigger_buffer, L, funcs_idx);
parse.first_memref = &self->memrefs;
trigger = RC_ALLOC(rc_trigger_t, &parse);
rc_parse_trigger_internal(trigger, &memaddr, &parse);
rc_destroy_parse_state(&parse);
rc_reset_parse_state(&preparse.parse, trigger_buffer, L, funcs_idx);
rc_preparse_reserve_memrefs(&preparse, self->memrefs);
trigger = RC_ALLOC(rc_trigger_t, &preparse.parse);
rc_parse_trigger_internal(trigger, &memaddr, &preparse.parse);
rc_destroy_preparse_state(&preparse);
if (parse.offset < 0) {
if (preparse.parse.offset < 0) {
free(trigger_buffer);
*self->next_memref = NULL; /* disassociate any memrefs allocated by the failed parse */
return parse.offset;
return preparse.parse.offset;
}
/* grow the trigger buffer if necessary */
@@ -200,7 +200,6 @@ int rc_runtime_activate_achievement(rc_runtime_t* self, uint32_t id, const char*
if (!self->triggers) {
free(trigger_buffer);
*self->next_memref = NULL; /* disassociate any memrefs allocated by the failed parse */
return RC_OUT_OF_MEMORY;
}
}
@@ -213,11 +212,9 @@ int rc_runtime_activate_achievement(rc_runtime_t* self, uint32_t id, const char*
runtime_trigger->invalid_memref = NULL;
memcpy(runtime_trigger->md5, md5, 16);
runtime_trigger->serialized_size = 0;
runtime_trigger->owns_memrefs = rc_runtime_allocated_memrefs(self);
++self->trigger_count;
/* reset it, and return it */
trigger->memrefs = NULL;
rc_reset_trigger(trigger);
return RC_OK;
}
@@ -285,20 +282,11 @@ int rc_runtime_format_achievement_measured(const rc_runtime_t* runtime, uint32_t
}
static void rc_runtime_deactivate_lboard_by_index(rc_runtime_t* self, uint32_t index) {
if (self->lboards[index].owns_memrefs) {
/* if the lboard has one or more memrefs in its buffer, we can't free the buffer.
* just null out the lboard so the runtime processor will skip it
*/
rc_reset_lboard(self->lboards[index].lboard);
self->lboards[index].lboard = NULL;
}
else {
/* lboard doesn't own any memrefs, go ahead and free it, then replace it with the last lboard */
free(self->lboards[index].buffer);
/* free the lboard, then replace it with the last lboard */
free(self->lboards[index].buffer);
if (--self->lboard_count > index)
memcpy(&self->lboards[index], &self->lboards[self->lboard_count], sizeof(rc_runtime_lboard_t));
}
if (--self->lboard_count > index)
memcpy(&self->lboards[index], &self->lboards[self->lboard_count], sizeof(rc_runtime_lboard_t));
}
void rc_runtime_deactivate_lboard(rc_runtime_t* self, uint32_t id) {
@@ -314,7 +302,7 @@ int rc_runtime_activate_lboard(rc_runtime_t* self, uint32_t id, const char* mema
void* lboard_buffer;
uint8_t md5[16];
rc_lboard_t* lboard;
rc_parse_state_t parse;
rc_preparse_state_t preparse;
rc_runtime_lboard_t* runtime_lboard;
int size;
uint32_t i;
@@ -357,7 +345,12 @@ int rc_runtime_activate_lboard(rc_runtime_t* self, uint32_t id, const char* mema
}
/* item has not been previously registered, determine how much space we need for it, and allocate it */
size = rc_lboard_size(memaddr);
rc_init_preparse_state(&preparse, NULL, 0);
preparse.parse.existing_memrefs = self->memrefs;
lboard = RC_ALLOC(rc_lboard_t, &preparse.parse);
rc_parse_lboard_internal(lboard, memaddr, &preparse.parse);
size = preparse.parse.offset;
if (size < 0)
return size;
@@ -366,16 +359,15 @@ int rc_runtime_activate_lboard(rc_runtime_t* self, uint32_t id, const char* mema
return RC_OUT_OF_MEMORY;
/* populate the item, using the communal memrefs pool */
rc_init_parse_state(&parse, lboard_buffer, L, funcs_idx);
lboard = RC_ALLOC(rc_lboard_t, &parse);
parse.first_memref = &self->memrefs;
rc_parse_lboard_internal(lboard, memaddr, &parse);
rc_destroy_parse_state(&parse);
rc_reset_parse_state(&preparse.parse, lboard_buffer, L, funcs_idx);
rc_preparse_reserve_memrefs(&preparse, self->memrefs);
lboard = RC_ALLOC(rc_lboard_t, &preparse.parse);
rc_parse_lboard_internal(lboard, memaddr, &preparse.parse);
rc_destroy_preparse_state(&preparse);
if (parse.offset < 0) {
if (preparse.parse.offset < 0) {
free(lboard_buffer);
*self->next_memref = NULL; /* disassociate any memrefs allocated by the failed parse */
return parse.offset;
return preparse.parse.offset;
}
/* grow the lboard buffer if necessary */
@@ -388,7 +380,6 @@ int rc_runtime_activate_lboard(rc_runtime_t* self, uint32_t id, const char* mema
if (!self->lboards) {
free(lboard_buffer);
*self->next_memref = NULL; /* disassociate any memrefs allocated by the failed parse */
return RC_OUT_OF_MEMORY;
}
}
@@ -402,10 +393,8 @@ int rc_runtime_activate_lboard(rc_runtime_t* self, uint32_t id, const char* mema
runtime_lboard->invalid_memref = NULL;
memcpy(runtime_lboard->md5, md5, 16);
runtime_lboard->serialized_size = 0;
runtime_lboard->owns_memrefs = rc_runtime_allocated_memrefs(self);
/* reset it, and return it */
lboard->memrefs = NULL;
rc_reset_lboard(lboard);
return RC_OK;
}
@@ -429,9 +418,7 @@ int rc_runtime_format_lboard_value(char* buffer, int size, int32_t value, int fo
int rc_runtime_activate_richpresence(rc_runtime_t* self, const char* script, lua_State* L, int funcs_idx) {
rc_richpresence_t* richpresence;
rc_runtime_richpresence_t* previous;
rc_runtime_richpresence_t** previous_ptr;
rc_parse_state_t parse;
rc_preparse_state_t preparse;
uint8_t md5[16];
int size;
@@ -441,47 +428,29 @@ int rc_runtime_activate_richpresence(rc_runtime_t* self, const char* script, lua
rc_runtime_checksum(script, md5);
/* look for existing match */
previous_ptr = NULL;
previous = self->richpresence;
while (previous) {
if (previous && self->richpresence->richpresence && memcmp(self->richpresence->md5, md5, 16) == 0) {
/* unchanged. reset all of the conditions */
rc_reset_richpresence(self->richpresence->richpresence);
if (self->richpresence && self->richpresence->richpresence && memcmp(self->richpresence->md5, md5, 16) == 0) {
/* unchanged. reset all of the conditions */
rc_reset_richpresence(self->richpresence->richpresence);
/* move to front of linked list*/
if (previous_ptr) {
*previous_ptr = previous->previous;
if (!self->richpresence->owns_memrefs) {
free(self->richpresence->buffer);
previous->previous = self->richpresence->previous;
}
else {
previous->previous = self->richpresence;
}
self->richpresence = previous;
}
/* return success*/
return RC_OK;
}
previous_ptr = &previous->previous;
previous = previous->previous;
/* return success*/
return RC_OK;
}
/* no existing match found, parse script */
size = rc_richpresence_size(script);
rc_init_preparse_state(&preparse, NULL, 0);
preparse.parse.existing_memrefs = self->memrefs;
richpresence = RC_ALLOC(rc_richpresence_t, &preparse.parse);
preparse.parse.variables = &richpresence->values;
rc_parse_richpresence_internal(richpresence, script, &preparse.parse);
size = preparse.parse.offset;
if (size < 0)
return size;
/* if the previous script doesn't have any memrefs, free it */
previous = self->richpresence;
if (previous) {
if (!previous->owns_memrefs) {
free(previous->buffer);
previous = previous->previous;
}
/* if there's a previous script, free it */
if (self->richpresence) {
free(self->richpresence->buffer);
free(self->richpresence);
}
/* allocate and process the new script */
@@ -489,34 +458,26 @@ int rc_runtime_activate_richpresence(rc_runtime_t* self, const char* script, lua
if (!self->richpresence)
return RC_OUT_OF_MEMORY;
self->richpresence->previous = previous;
self->richpresence->owns_memrefs = 0;
memcpy(self->richpresence->md5, md5, sizeof(md5));
self->richpresence->buffer = malloc(size);
self->richpresence->buffer = malloc(size);
if (!self->richpresence->buffer)
return RC_OUT_OF_MEMORY;
rc_init_parse_state(&parse, self->richpresence->buffer, L, funcs_idx);
self->richpresence->richpresence = richpresence = RC_ALLOC(rc_richpresence_t, &parse);
parse.first_memref = &self->memrefs;
parse.variables = &self->variables;
rc_parse_richpresence_internal(richpresence, script, &parse);
rc_destroy_parse_state(&parse);
rc_reset_parse_state(&preparse.parse, self->richpresence->buffer, L, funcs_idx);
rc_preparse_reserve_memrefs(&preparse, self->memrefs);
richpresence = RC_ALLOC(rc_richpresence_t, &preparse.parse);
preparse.parse.variables = &richpresence->values;
rc_parse_richpresence_internal(richpresence, script, &preparse.parse);
rc_destroy_preparse_state(&preparse);
if (parse.offset < 0) {
if (preparse.parse.offset < 0) {
free(self->richpresence->buffer);
free(self->richpresence);
self->richpresence = previous;
*self->next_memref = NULL; /* disassociate any memrefs allocated by the failed parse */
return parse.offset;
self->richpresence = NULL;
return preparse.parse.offset;
}
self->richpresence->owns_memrefs = rc_runtime_allocated_memrefs(self);
richpresence->memrefs = NULL;
richpresence->variables = NULL;
if (!richpresence->first_display || !richpresence->first_display->display) {
/* non-existant rich presence */
self->richpresence->richpresence = NULL;
@@ -524,6 +485,7 @@ int rc_runtime_activate_richpresence(rc_runtime_t* self, const char* script, lua
else {
/* reset all of the conditions */
rc_reset_richpresence(richpresence);
self->richpresence->richpresence = richpresence;
}
return RC_OK;
@@ -555,7 +517,6 @@ void rc_runtime_do_frame(rc_runtime_t* self, rc_runtime_event_handler_t event_ha
runtime_event.value = 0;
rc_update_memref_values(self->memrefs, peek, ud);
rc_update_variables(self->variables, peek, ud, L);
for (i = self->trigger_count - 1; i >= 0; --i) {
rc_trigger_t* trigger = self->triggers[i].trigger;
@@ -725,7 +686,6 @@ void rc_runtime_do_frame(rc_runtime_t* self, rc_runtime_event_handler_t event_ha
}
void rc_runtime_reset(rc_runtime_t* self) {
rc_value_t* variable;
uint32_t i;
for (i = 0; i < self->trigger_count; ++i) {
@@ -740,9 +700,6 @@ void rc_runtime_reset(rc_runtime_t* self) {
if (self->richpresence && self->richpresence->richpresence)
rc_reset_richpresence(self->richpresence->richpresence);
for (variable = self->variables; variable; variable = variable->next)
rc_reset_value(variable);
}
static int rc_condset_contains_memref(const rc_condset_t* condset, const rc_memref_t* memref) {
@@ -826,47 +783,41 @@ static void rc_runtime_invalidate_memref(rc_runtime_t* self, rc_memref_t* memref
}
void rc_runtime_invalidate_address(rc_runtime_t* self, uint32_t address) {
rc_memref_t** last_memref = &self->memrefs;
rc_memref_t* memref = self->memrefs;
rc_memref_list_t* memref_list = &self->memrefs->memrefs;
do {
rc_memref_t* memref = memref_list->items;
const rc_memref_t* memref_stop = memref + memref_list->count;
while (memref) {
if (memref->address == address && !memref->value.is_indirect) {
/* remove the invalid memref from the chain so we don't try to evaluate it in the future.
* it's still there, so anything referencing it will continue to fetch 0.
*/
*last_memref = memref->next;
rc_runtime_invalidate_memref(self, memref);
break;
for (; memref < memref_stop; ++memref) {
if (memref->address == address) {
memref->value.type = RC_VALUE_TYPE_NONE;
rc_runtime_invalidate_memref(self, memref);
}
}
last_memref = &memref->next;
memref = *last_memref;
}
memref_list = memref_list->next;
} while (memref_list);
}
void rc_runtime_validate_addresses(rc_runtime_t* self, rc_runtime_event_handler_t event_handler,
rc_runtime_validate_address_t validate_handler) {
rc_memref_t** last_memref = &self->memrefs;
rc_memref_t* memref = self->memrefs;
int num_invalid = 0;
rc_memref_list_t* memref_list = &self->memrefs->memrefs;
do {
rc_memref_t* memref = memref_list->items;
const rc_memref_t* memref_stop = memref + memref_list->count;
while (memref) {
if (!memref->value.is_indirect && !validate_handler(memref->address)) {
/* remove the invalid memref from the chain so we don't try to evaluate it in the future.
* it's still there, so anything referencing it will continue to fetch 0.
*/
*last_memref = memref->next;
for (; memref < memref_stop; ++memref) {
if (!validate_handler(memref->address)) {
memref->value.type = RC_VALUE_TYPE_NONE;
rc_runtime_invalidate_memref(self, memref);
rc_runtime_invalidate_memref(self, memref);
++num_invalid;
}
else {
last_memref = &memref->next;
++num_invalid;
}
}
memref = *last_memref;
}
memref_list = memref_list->next;
} while (memref_list);
if (num_invalid) {
rc_runtime_event_t runtime_event;

View File

@@ -127,11 +127,7 @@ static void rc_runtime_progress_init(rc_runtime_progress_t* progress, const rc_r
static int rc_runtime_progress_write_memrefs(rc_runtime_progress_t* progress)
{
rc_memref_t* memref;
uint32_t count = 0;
for (memref = progress->runtime->memrefs; memref; memref = memref->next)
++count;
uint32_t count = rc_memrefs_count_memrefs(progress->runtime->memrefs);
if (count == 0)
return RC_OK;
@@ -145,15 +141,24 @@ static int rc_runtime_progress_write_memrefs(rc_runtime_progress_t* progress)
}
else {
uint32_t flags = 0;
for (memref = progress->runtime->memrefs; memref; memref = memref->next) {
flags = memref->value.size;
if (memref->value.changed)
flags |= RC_MEMREF_FLAG_CHANGED_THIS_FRAME;
const rc_memref_list_t* memref_list = &progress->runtime->memrefs->memrefs;
const rc_memref_t* memref;
rc_runtime_progress_write_uint(progress, memref->address);
rc_runtime_progress_write_uint(progress, flags);
rc_runtime_progress_write_uint(progress, memref->value.value);
rc_runtime_progress_write_uint(progress, memref->value.prior);
for (; memref_list; memref_list = memref_list->next) {
const rc_memref_t* memref_end;
memref = memref_list->items;
memref_end = memref + memref_list->count;
for (; memref < memref_end; ++memref) {
flags = memref->value.size;
if (memref->value.changed)
flags |= RC_MEMREF_FLAG_CHANGED_THIS_FRAME;
rc_runtime_progress_write_uint(progress, memref->address);
rc_runtime_progress_write_uint(progress, flags);
rc_runtime_progress_write_uint(progress, memref->value.value);
rc_runtime_progress_write_uint(progress, memref->value.prior);
}
}
}
@@ -162,13 +167,77 @@ static int rc_runtime_progress_write_memrefs(rc_runtime_progress_t* progress)
return RC_OK;
}
static void rc_runtime_progress_update_modified_memrefs(rc_runtime_progress_t* progress)
{
rc_typed_value_t value, prior_value, modifier, prior_modifier;
rc_modified_memref_list_t* modified_memref_list;
rc_modified_memref_t* modified_memref;
rc_operand_t prior_parent_operand, prior_modifier_operand;
rc_memref_t prior_parent_memref, prior_modifier_memref;
modified_memref_list = &progress->runtime->memrefs->modified_memrefs;
for (; modified_memref_list; modified_memref_list = modified_memref_list->next) {
const rc_modified_memref_t* modified_memref_end;
modified_memref = modified_memref_list->items;
modified_memref_end = modified_memref + modified_memref_list->count;
for (; modified_memref < modified_memref_end; ++modified_memref) {
modified_memref->memref.value.changed = 0;
/* indirect memref values are stored in conditions */
if (modified_memref->modifier_type == RC_OPERATOR_INDIRECT_READ)
continue;
/* non-indirect memref values can be reconstructed from the parents */
memcpy(&prior_parent_operand, &modified_memref->parent, sizeof(prior_parent_operand));
if (rc_operand_is_memref(&prior_parent_operand)) {
memcpy(&prior_parent_memref, modified_memref->parent.value.memref, sizeof(prior_parent_memref));
prior_parent_memref.value.value = prior_parent_memref.value.prior;
modified_memref->memref.value.changed |= prior_parent_memref.value.changed;
prior_parent_operand.value.memref = &prior_parent_memref;
}
memcpy(&prior_modifier_operand, &modified_memref->modifier, sizeof(prior_modifier_operand));
if (rc_operand_is_memref(&prior_modifier_operand)) {
memcpy(&prior_modifier_memref, modified_memref->modifier.value.memref, sizeof(prior_modifier_memref));
prior_modifier_memref.value.value = prior_modifier_memref.value.prior;
modified_memref->memref.value.changed |= prior_modifier_memref.value.changed;
prior_modifier_operand.value.memref = &prior_modifier_memref;
}
rc_evaluate_operand(&value, &modified_memref->parent, NULL);
rc_evaluate_operand(&modifier, &modified_memref->modifier, NULL);
rc_evaluate_operand(&prior_value, &prior_parent_operand, NULL);
rc_evaluate_operand(&prior_modifier, &prior_modifier_operand, NULL);
if (modified_memref->modifier_type == RC_OPERATOR_SUB_PARENT) {
rc_typed_value_negate(&value);
rc_typed_value_add(&value, &modifier);
rc_typed_value_negate(&prior_value);
rc_typed_value_add(&prior_value, &prior_modifier);
}
else {
rc_typed_value_combine(&value, &modifier, modified_memref->modifier_type);
rc_typed_value_combine(&prior_value, &prior_modifier, modified_memref->modifier_type);
}
rc_typed_value_convert(&value, modified_memref->memref.value.type);
modified_memref->memref.value.value = value.value.u32;
rc_typed_value_convert(&prior_value, modified_memref->memref.value.type);
modified_memref->memref.value.prior = prior_value.value.u32;
}
}
}
static int rc_runtime_progress_read_memrefs(rc_runtime_progress_t* progress)
{
uint32_t entries;
uint32_t address, flags, value, prior;
uint8_t size;
rc_memref_list_t* unmatched_memref_list = &progress->runtime->memrefs->memrefs;
rc_memref_t* first_unmatched_memref = unmatched_memref_list->items;
rc_memref_t* memref;
rc_memref_t* first_unmatched_memref = progress->runtime->memrefs;
/* re-read the chunk size to determine how many memrefs are present */
progress->offset -= 4;
@@ -183,24 +252,46 @@ static int rc_runtime_progress_read_memrefs(rc_runtime_progress_t* progress)
size = flags & 0xFF;
memref = first_unmatched_memref;
while (memref) {
if (memref->address == address && memref->value.size == size) {
memref->value.value = value;
memref->value.changed = (flags & RC_MEMREF_FLAG_CHANGED_THIS_FRAME) ? 1 : 0;
memref->value.prior = prior;
if (memref->address == address && memref->value.size == size) {
memref->value.value = value;
memref->value.changed = (flags & RC_MEMREF_FLAG_CHANGED_THIS_FRAME) ? 1 : 0;
memref->value.prior = prior;
if (memref == first_unmatched_memref)
first_unmatched_memref = memref->next;
break;
first_unmatched_memref++;
if (first_unmatched_memref >= unmatched_memref_list->items + unmatched_memref_list->count) {
unmatched_memref_list = unmatched_memref_list->next;
if (!unmatched_memref_list)
break;
first_unmatched_memref = unmatched_memref_list->items;
}
}
else {
rc_memref_list_t* memref_list = unmatched_memref_list;
do {
++memref;
if (memref >= memref_list->items + memref_list->count) {
memref_list = memref_list->next;
if (!memref_list)
break;
memref = memref->next;
memref = memref_list->items;
}
if (memref->address == address && memref->value.size == size) {
memref->value.value = value;
memref->value.changed = (flags & RC_MEMREF_FLAG_CHANGED_THIS_FRAME) ? 1 : 0;
memref->value.prior = prior;
break;
}
} while (1);
}
--entries;
}
rc_runtime_progress_update_modified_memrefs(progress);
return RC_OK;
}
@@ -215,7 +306,10 @@ static int rc_runtime_progress_is_indirect_memref(rc_operand_t* oper)
return 0;
default:
return oper->value.memref->value.is_indirect;
if (oper->value.memref->value.memref_type != RC_MEMREF_TYPE_MODIFIED_MEMREF)
return 0;
return ((const rc_modified_memref_t*)oper->value.memref)->modifier_type == RC_OPERATOR_INDIRECT_READ;
}
}
@@ -317,8 +411,8 @@ static uint32_t rc_runtime_progress_should_serialize_variable_condset(const rc_c
{
const rc_condition_t* condition;
/* predetermined presence of pause flag or indirect memrefs - must serialize */
if (conditions->has_pause || conditions->has_indirect_memrefs)
/* predetermined presence of pause flag - must serialize */
if (conditions->has_pause)
return RC_VAR_FLAG_HAS_COND_DATA;
/* if any conditions has required hits, must serialize */
@@ -358,12 +452,15 @@ static int rc_runtime_progress_write_variable(rc_runtime_progress_t* progress, c
static int rc_runtime_progress_write_variables(rc_runtime_progress_t* progress)
{
uint32_t count = 0;
const rc_value_t* variable;
uint32_t count;
const rc_value_t* value;
int result;
for (variable = progress->runtime->variables; variable; variable = variable->next)
++count;
if (!progress->runtime->richpresence || !progress->runtime->richpresence->richpresence)
return RC_OK;
value = progress->runtime->richpresence->richpresence->values;
count = rc_count_values(value);
if (count == 0)
return RC_OK;
@@ -374,14 +471,14 @@ static int rc_runtime_progress_write_variables(rc_runtime_progress_t* progress)
rc_runtime_progress_start_chunk(progress, RC_RUNTIME_CHUNK_VARIABLES);
rc_runtime_progress_write_uint(progress, count);
for (variable = progress->runtime->variables; variable; variable = variable->next) {
uint32_t djb2 = rc_djb2(variable->name);
for (; value; value = value->next) {
const uint32_t djb2 = rc_djb2(value->name);
if (progress->offset + 16 > progress->buffer_size)
return RC_INSUFFICIENT_BUFFER;
rc_runtime_progress_write_uint(progress, djb2);
result = rc_runtime_progress_write_variable(progress, variable);
result = rc_runtime_progress_write_variable(progress, value);
if (result != RC_OK)
return result;
}
@@ -418,19 +515,20 @@ static int rc_runtime_progress_read_variables(rc_runtime_progress_t* progress)
};
struct rc_pending_value_t local_pending_variables[32];
struct rc_pending_value_t* pending_variables;
rc_value_t* variable;
rc_value_t* value;
uint32_t count, serialized_count;
int result;
uint32_t i;
int32_t i;
serialized_count = rc_runtime_progress_read_uint(progress);
if (serialized_count == 0)
return RC_OK;
count = 0;
for (variable = progress->runtime->variables; variable; variable = variable->next)
++count;
if (!progress->runtime->richpresence || !progress->runtime->richpresence->richpresence)
return RC_OK;
value = progress->runtime->richpresence->richpresence->values;
count = rc_count_values(value);
if (count == 0)
return RC_OK;
@@ -443,22 +541,22 @@ static int rc_runtime_progress_read_variables(rc_runtime_progress_t* progress)
return RC_OUT_OF_MEMORY;
}
count = 0;
for (variable = progress->runtime->variables; variable; variable = variable->next) {
pending_variables[count].variable = variable;
pending_variables[count].djb2 = rc_djb2(variable->name);
++count;
i = (int32_t)count;
for (; value; value = value->next) {
--i;
pending_variables[i].variable = value;
pending_variables[i].djb2 = rc_djb2(value->name);
}
result = RC_OK;
for (; serialized_count > 0 && result == RC_OK; --serialized_count) {
uint32_t djb2 = rc_runtime_progress_read_uint(progress);
for (i = 0; i < count; ++i) {
for (i = (int32_t)count - 1; i >= 0; --i) {
if (pending_variables[i].djb2 == djb2) {
variable = pending_variables[i].variable;
result = rc_runtime_progress_read_variable(progress, variable);
value = pending_variables[i].variable;
result = rc_runtime_progress_read_variable(progress, value);
if (result == RC_OK) {
if (i < count - 1)
if (i < (int32_t)count - 1)
memcpy(&pending_variables[i], &pending_variables[count - 1], sizeof(struct rc_pending_value_t));
count--;
}
@@ -742,7 +840,7 @@ static int rc_runtime_progress_read_rich_presence(rc_runtime_progress_t* progres
return RC_OK;
if (!rc_runtime_progress_match_md5(progress, progress->runtime->richpresence->md5)) {
rc_reset_richpresence(progress->runtime->richpresence->richpresence);
rc_reset_richpresence_triggers(progress->runtime->richpresence->richpresence);
return RC_OK;
}
@@ -958,7 +1056,7 @@ int rc_runtime_deserialize_progress_sized(rc_runtime_t* runtime, const uint8_t*
}
if (!seen_rich_presence && runtime->richpresence && runtime->richpresence->richpresence)
rc_reset_richpresence(runtime->richpresence->richpresence);
rc_reset_richpresence_triggers(runtime->richpresence->richpresence);
}
return result;

View File

@@ -16,21 +16,20 @@ void rc_parse_trigger_internal(rc_trigger_t* self, const char** memaddr, rc_pars
parse->measured_as_percent = 0;
if (*aux == 's' || *aux == 'S') {
self->requirement = 0;
self->requirement = NULL;
}
else {
self->requirement = rc_parse_condset(&aux, parse, 0);
self->requirement = rc_parse_condset(&aux, parse);
if (parse->offset < 0) {
if (parse->offset < 0)
return;
}
self->requirement->next = 0;
self->requirement->next = NULL;
}
while (*aux == 's' || *aux == 'S') {
aux++;
*next = rc_parse_condset(&aux, parse, 0);
*next = rc_parse_condset(&aux, parse);
if (parse->offset < 0) {
return;
@@ -39,7 +38,7 @@ void rc_parse_trigger_internal(rc_trigger_t* self, const char** memaddr, rc_pars
next = &(*next)->next;
}
*next = 0;
*next = NULL;
*memaddr = aux;
self->measured_target = parse->measured_target;
@@ -47,39 +46,46 @@ void rc_parse_trigger_internal(rc_trigger_t* self, const char** memaddr, rc_pars
self->measured_as_percent = parse->measured_as_percent;
self->state = RC_TRIGGER_STATE_WAITING;
self->has_hits = 0;
self->has_required_hits = parse->has_required_hits;
self->has_memrefs = 0;
}
int rc_trigger_size(const char* memaddr) {
rc_trigger_t* self;
rc_parse_state_t parse;
rc_memref_t* memrefs;
rc_init_parse_state(&parse, 0, 0, 0);
rc_init_parse_state_memrefs(&parse, &memrefs);
rc_trigger_with_memrefs_t* trigger;
rc_preparse_state_t preparse;
rc_init_preparse_state(&preparse, NULL, 0);
self = RC_ALLOC(rc_trigger_t, &parse);
rc_parse_trigger_internal(self, &memaddr, &parse);
trigger = RC_ALLOC(rc_trigger_with_memrefs_t, &preparse.parse);
rc_parse_trigger_internal(&trigger->trigger, &memaddr, &preparse.parse);
rc_preparse_alloc_memrefs(NULL, &preparse);
rc_destroy_parse_state(&parse);
return parse.offset;
rc_destroy_preparse_state(&preparse);
return preparse.parse.offset;
}
rc_trigger_t* rc_parse_trigger(void* buffer, const char* memaddr, lua_State* L, int funcs_ndx) {
rc_trigger_t* self;
rc_parse_state_t parse;
rc_trigger_with_memrefs_t* trigger;
rc_preparse_state_t preparse;
const char* preparse_memaddr = memaddr;
if (!buffer || !memaddr)
return NULL;
rc_init_parse_state(&parse, buffer, L, funcs_ndx);
/* first pass : determine how many memrefs are needed */
rc_init_preparse_state(&preparse, L, funcs_ndx);
trigger = RC_ALLOC(rc_trigger_with_memrefs_t, &preparse.parse);
rc_parse_trigger_internal(&trigger->trigger, &preparse_memaddr, &preparse.parse);
self = RC_ALLOC(rc_trigger_t, &parse);
rc_init_parse_state_memrefs(&parse, &self->memrefs);
/* allocate the trigger and memrefs */
rc_reset_parse_state(&preparse.parse, buffer, L, funcs_ndx);
trigger = RC_ALLOC(rc_trigger_with_memrefs_t, &preparse.parse);
rc_preparse_alloc_memrefs(&trigger->memrefs, &preparse);
rc_parse_trigger_internal(self, &memaddr, &parse);
/* parse the trigger */
rc_parse_trigger_internal(&trigger->trigger, &memaddr, &preparse.parse);
trigger->trigger.has_memrefs = 1;
rc_destroy_parse_state(&parse);
return (parse.offset >= 0) ? self : NULL;
rc_destroy_preparse_state(&preparse);
return (preparse.parse.offset >= 0) ? &trigger->trigger : NULL;
}
int rc_trigger_state_active(int state)
@@ -124,9 +130,27 @@ static void rc_reset_trigger_hitcounts(rc_trigger_t* self) {
}
}
static void rc_update_trigger_memrefs(rc_trigger_t* self, rc_peek_t peek, void* ud) {
if (self->has_memrefs) {
rc_trigger_with_memrefs_t* trigger = (rc_trigger_with_memrefs_t*)self;
rc_update_memref_values(&trigger->memrefs, peek, ud);
}
}
rc_memrefs_t* rc_trigger_get_memrefs(rc_trigger_t* self) {
if (self->has_memrefs) {
rc_trigger_with_memrefs_t* trigger = (rc_trigger_with_memrefs_t*)self;
return &trigger->memrefs;
}
return NULL;
}
int rc_evaluate_trigger(rc_trigger_t* self, rc_peek_t peek, void* ud, lua_State* L) {
rc_eval_state_t eval_state;
rc_condset_t* condset;
rc_typed_value_t measured_value;
int measured_from_hits = 0;
int ret;
char is_paused;
char is_primed;
@@ -143,7 +167,7 @@ int rc_evaluate_trigger(rc_trigger_t* self, rc_peek_t peek, void* ud, lua_State*
case RC_TRIGGER_STATE_INACTIVE:
/* not yet active. update the memrefs so deltas are correct when it becomes active, then return INACTIVE */
rc_update_memref_values(self->memrefs, peek, ud);
rc_update_trigger_memrefs(self, peek, ud);
return RC_TRIGGER_STATE_INACTIVE;
default:
@@ -151,18 +175,29 @@ int rc_evaluate_trigger(rc_trigger_t* self, rc_peek_t peek, void* ud, lua_State*
}
/* update the memory references */
rc_update_memref_values(self->memrefs, peek, ud);
rc_update_trigger_memrefs(self, peek, ud);
/* process the trigger */
memset(&eval_state, 0, sizeof(eval_state));
eval_state.peek = peek;
eval_state.peek_userdata = ud;
#ifndef RC_DISABLE_LUA
eval_state.L = L;
#else
(void)L;
#endif
measured_value.type = RC_VALUE_TYPE_NONE;
if (self->requirement != NULL) {
ret = rc_test_condset(self->requirement, &eval_state);
is_paused = self->requirement->is_paused;
is_primed = eval_state.primed;
is_paused = eval_state.is_paused;
is_primed = eval_state.is_primed;
if (eval_state.measured_value.type != RC_VALUE_TYPE_NONE) {
memcpy(&measured_value, &eval_state.measured_value, sizeof(measured_value));
measured_from_hits = eval_state.measured_from_hits;
}
} else {
ret = 1;
is_paused = 0;
@@ -177,8 +212,17 @@ int rc_evaluate_trigger(rc_trigger_t* self, rc_peek_t peek, void* ud, lua_State*
do {
sub |= rc_test_condset(condset, &eval_state);
sub_paused &= condset->is_paused;
sub_primed |= eval_state.primed;
sub_paused &= eval_state.is_paused;
sub_primed |= eval_state.is_primed;
if (eval_state.measured_value.type != RC_VALUE_TYPE_NONE) {
/* if no previous Measured value was captured, or the new one is greater, keep the new one */
if (measured_value.type == RC_VALUE_TYPE_NONE ||
rc_typed_value_compare(&eval_state.measured_value, &measured_value, RC_OPERATOR_GT)) {
memcpy(&measured_value, &eval_state.measured_value, sizeof(measured_value));
measured_from_hits = eval_state.measured_from_hits;
}
}
condset = condset->next;
} while (condset);
@@ -193,15 +237,15 @@ int rc_evaluate_trigger(rc_trigger_t* self, rc_peek_t peek, void* ud, lua_State*
/* if paused, the measured value may not be captured, keep the old value */
if (!is_paused) {
rc_typed_value_convert(&eval_state.measured_value, RC_VALUE_TYPE_UNSIGNED);
self->measured_value = eval_state.measured_value.value.u32;
rc_typed_value_convert(&measured_value, RC_VALUE_TYPE_UNSIGNED);
self->measured_value = measured_value.value.u32;
}
/* if any ResetIf condition was true, reset the hit counts */
if (eval_state.was_reset) {
/* if the measured value came from a hit count, reset it. do this before calling
* rc_reset_trigger_hitcounts in case we need to call rc_condset_is_measured_from_hitcount */
if (eval_state.measured_from_hits) {
if (measured_from_hits) {
self->measured_value = 0;
}
else if (is_paused && self->measured_value) {

View File

@@ -5,8 +5,6 @@
#include <float.h> /* FLT_EPSILON */
#include <math.h> /* fmod */
int rc_is_valid_variable_character(char ch, int is_first) {
if (is_first) {
if (!isalpha((unsigned char)ch))
@@ -27,7 +25,7 @@ static void rc_parse_cond_value(rc_value_t* self, const char** memaddr, rc_parse
do
{
parse->measured_target = 0; /* passing is_value=1 should prevent any conflicts, but clear it out anyway */
*next_clause = rc_parse_condset(memaddr, parse, 1);
*next_clause = rc_parse_condset(memaddr, parse);
if (parse->offset < 0) {
return;
}
@@ -52,174 +50,238 @@ static void rc_parse_cond_value(rc_value_t* self, const char** memaddr, rc_parse
(*next_clause)->next = 0;
}
void rc_parse_legacy_value(rc_value_t* self, const char** memaddr, rc_parse_state_t* parse) {
static void rc_parse_legacy_value(rc_value_t* self, const char** memaddr, rc_parse_state_t* parse) {
rc_condset_with_trailing_conditions_t* condset_with_conditions;
rc_condition_t** next;
rc_condset_t** next_clause;
rc_condset_t* condset;
rc_condition_t local_cond;
rc_condition_t* cond;
uint32_t num_measured_conditions;
char buffer[64] = "A:";
const char* buffer_ptr;
char* ptr;
char c;
/* convert legacy format into condset */
self->conditions = RC_ALLOC(rc_condset_t, parse);
memset(self->conditions, 0, sizeof(rc_condset_t));
next_clause = &self->conditions;
do {
num_measured_conditions = 0;
next = &self->conditions->conditions;
next_clause = &self->conditions->next;
for (;; ++(*memaddr)) {
buffer[0] = 'A'; /* reset to AddSource */
ptr = &buffer[2];
/* extract the next clause */
for (;; ++(*memaddr)) {
switch (**memaddr) {
case '_': /* add next */
case '$': /* maximum of */
case '\0': /* end of string */
case ':': /* end of leaderboard clause */
case ')': /* end of rich presence macro */
*ptr = '\0';
break;
case '*':
*ptr++ = '*';
buffer_ptr = *memaddr + 1;
if (*buffer_ptr == '-') {
buffer[0] = 'B'; /* change to SubSource */
++(*memaddr); /* don't copy sign */
++buffer_ptr; /* ignore sign when doing floating point check */
}
else if (*buffer_ptr == '+') {
++buffer_ptr; /* ignore sign when doing floating point check */
}
/* if it looks like a floating point number, add the 'f' prefix */
while (isdigit((unsigned char)*buffer_ptr))
++buffer_ptr;
if (*buffer_ptr == '.')
*ptr++ = 'f';
continue;
default:
*ptr++ = **memaddr;
continue;
/* count the number of joiners and add one to determine the number of clauses. */
num_measured_conditions = 1;
buffer_ptr = *memaddr;
while ((c = *buffer_ptr++) && c != '$') {
if (c == '_') {
++num_measured_conditions;
buffer[0] = 'A'; /* reset to AddSource */
}
else if (c == '*' && *buffer_ptr == '-') {
/* multiplication by a negative number will convert to SubSource */
++buffer_ptr;
buffer[0] = 'B';
}
break;
}
/* process the clause */
buffer_ptr = buffer;
cond = rc_parse_condition(&buffer_ptr, parse, 0);
/* if last condition is SubSource, we'll need to add a dummy condition for the Measured */
if (buffer[0] == 'B')
++num_measured_conditions;
condset_with_conditions = RC_ALLOC_WITH_TRAILING(rc_condset_with_trailing_conditions_t,
rc_condition_t, conditions, num_measured_conditions, parse);
if (parse->offset < 0)
return;
if (*buffer_ptr) {
/* whatever we copied as a single condition was not fully consumed */
parse->offset = RC_INVALID_COMPARISON;
return;
}
condset = (rc_condset_t*)condset_with_conditions;
memset(condset, 0, sizeof(*condset));
condset->num_measured_conditions = num_measured_conditions;
cond = &condset_with_conditions->conditions[0];
next = &condset->conditions;
for (;; ++(*memaddr)) {
buffer[0] = 'A'; /* reset to AddSource */
ptr = &buffer[2];
/* extract the next clause */
for (;; ++(*memaddr)) {
switch (**memaddr) {
case '_': /* add next */
case '$': /* maximum of */
case '\0': /* end of string */
case ':': /* end of leaderboard clause */
case ')': /* end of rich presence macro */
*ptr = '\0';
break;
case '*':
*ptr++ = '*';
buffer_ptr = *memaddr + 1;
if (*buffer_ptr == '-') {
buffer[0] = 'B'; /* change to SubSource */
++(*memaddr); /* don't copy sign */
++buffer_ptr; /* ignore sign when doing floating point check */
}
else if (*buffer_ptr == '+') {
++buffer_ptr; /* ignore sign when doing floating point check */
}
/* if it looks like a floating point number, add the 'f' prefix */
while (isdigit((unsigned char)*buffer_ptr))
++buffer_ptr;
if (*buffer_ptr == '.')
*ptr++ = 'f';
continue;
default:
*ptr++ = **memaddr;
continue;
}
switch (cond->oper) {
case RC_OPERATOR_MULT:
case RC_OPERATOR_DIV:
case RC_OPERATOR_AND:
case RC_OPERATOR_XOR:
case RC_OPERATOR_MOD:
case RC_OPERATOR_ADD:
case RC_OPERATOR_SUB:
case RC_OPERATOR_NONE:
break;
}
default:
/* process the clause */
if (!parse->buffer)
cond = &local_cond;
buffer_ptr = buffer;
rc_parse_condition_internal(cond, &buffer_ptr, parse);
if (parse->offset < 0)
return;
if (*buffer_ptr) {
/* whatever we copied as a single condition was not fully consumed */
parse->offset = RC_INVALID_COMPARISON;
return;
}
if (!rc_operator_is_modifying(cond->oper)) {
parse->offset = RC_INVALID_OPERATOR;
return;
}
}
*next = cond;
if (**memaddr == '_') {
/* add next */
*next = cond;
next = &cond->next;
continue;
if (**memaddr != '_') /* add next */
break;
rc_condition_update_parse_state(cond, parse);
++cond;
}
/* end of clause */
if (cond->type == RC_CONDITION_SUB_SOURCE) {
/* cannot change SubSource to Measured. add a dummy condition */
next = &cond->next;
rc_condition_update_parse_state(cond, parse);
if (parse->buffer)
++cond;
buffer_ptr = "A:0";
cond = rc_parse_condition(&buffer_ptr, parse, 0);
rc_parse_condition_internal(cond, &buffer_ptr, parse);
*next = cond;
next = &cond->next;
}
/* convert final AddSource condition to Measured */
cond->type = RC_CONDITION_MEASURED;
cond->next = 0;
cond->next = NULL;
rc_condition_update_parse_state(cond, parse);
/* finalize clause */
*next_clause = condset;
next_clause = &condset->next;
if (**memaddr != '$') {
/* end of valid string */
*next_clause = 0;
*next_clause = NULL;
break;
}
/* max of ($), start a new clause */
*next_clause = RC_ALLOC(rc_condset_t, parse);
if (parse->buffer) /* don't clear in sizing mode or pointer will break */
memset(*next_clause, 0, sizeof(rc_condset_t));
next = &(*next_clause)->conditions;
next_clause = &(*next_clause)->next;
}
++(*memaddr);
} while (1);
}
void rc_parse_value_internal(rc_value_t* self, const char** memaddr, rc_parse_state_t* parse) {
const uint8_t was_value = parse->is_value;
const rc_condition_t* condition;
parse->is_value = 1;
/* if it starts with a condition flag (M: A: B: C:), parse the conditions */
if ((*memaddr)[1] == ':') {
if ((*memaddr)[1] == ':')
rc_parse_cond_value(self, memaddr, parse);
}
else {
else
rc_parse_legacy_value(self, memaddr, parse);
if (parse->offset >= 0 && parse->buffer) {
self->name = "(unnamed)";
self->value.value = self->value.prior = 0;
self->value.memref_type = RC_MEMREF_TYPE_VALUE;
self->value.changed = 0;
self->has_memrefs = 0;
for (condition = self->conditions->conditions; condition; condition = condition->next) {
if (condition->type == RC_CONDITION_MEASURED) {
if (rc_operand_is_float(&condition->operand1)) {
self->value.size = RC_MEMSIZE_FLOAT;
self->value.type = RC_VALUE_TYPE_FLOAT;
}
else {
self->value.size = RC_MEMSIZE_32_BITS;
self->value.type = RC_VALUE_TYPE_UNSIGNED;
}
break;
}
}
}
self->name = "(unnamed)";
self->value.value = self->value.prior = 0;
self->value.changed = 0;
self->next = 0;
parse->is_value = was_value;
}
int rc_value_size(const char* memaddr) {
rc_value_t* self;
rc_parse_state_t parse;
rc_memref_t* first_memref;
rc_init_parse_state(&parse, 0, 0, 0);
rc_init_parse_state_memrefs(&parse, &first_memref);
rc_value_with_memrefs_t* value;
rc_preparse_state_t preparse;
rc_init_preparse_state(&preparse, NULL, 0);
self = RC_ALLOC(rc_value_t, &parse);
rc_parse_value_internal(self, &memaddr, &parse);
value = RC_ALLOC(rc_value_with_memrefs_t, &preparse.parse);
rc_parse_value_internal(&value->value, &memaddr, &preparse.parse);
rc_preparse_alloc_memrefs(NULL, &preparse);
rc_destroy_parse_state(&parse);
return parse.offset;
rc_destroy_preparse_state(&preparse);
return preparse.parse.offset;
}
rc_value_t* rc_parse_value(void* buffer, const char* memaddr, lua_State* L, int funcs_ndx) {
rc_value_t* self;
rc_parse_state_t parse;
rc_value_with_memrefs_t* value;
rc_preparse_state_t preparse;
const char* preparse_memaddr = memaddr;
if (!buffer || !memaddr)
return NULL;
rc_init_parse_state(&parse, buffer, L, funcs_ndx);
rc_init_preparse_state(&preparse, L, funcs_ndx);
value = RC_ALLOC(rc_value_with_memrefs_t, &preparse.parse);
rc_parse_value_internal(&value->value, &preparse_memaddr, &preparse.parse);
self = RC_ALLOC(rc_value_t, &parse);
rc_init_parse_state_memrefs(&parse, &self->memrefs);
rc_reset_parse_state(&preparse.parse, buffer, L, funcs_ndx);
value = RC_ALLOC(rc_value_with_memrefs_t, &preparse.parse);
rc_preparse_alloc_memrefs(&value->memrefs, &preparse);
rc_parse_value_internal(self, &memaddr, &parse);
rc_parse_value_internal(&value->value, &memaddr, &preparse.parse);
value->value.has_memrefs = 1;
rc_destroy_parse_state(&parse);
return (parse.offset >= 0) ? self : NULL;
rc_destroy_preparse_state(&preparse);
return (preparse.parse.offset >= 0) ? &value->value : NULL;
}
static void rc_update_value_memrefs(rc_value_t* self, rc_peek_t peek, void* ud) {
if (self->has_memrefs) {
rc_value_with_memrefs_t* value = (rc_value_with_memrefs_t*)self;
rc_update_memref_values(&value->memrefs, peek, ud);
}
}
int rc_evaluate_value_typed(rc_value_t* self, rc_typed_value_t* value, rc_peek_t peek, void* ud, lua_State* L) {
@@ -227,7 +289,7 @@ int rc_evaluate_value_typed(rc_value_t* self, rc_typed_value_t* value, rc_peek_t
rc_condset_t* condset;
int valid = 0;
rc_update_memref_values(self->memrefs, peek, ud);
rc_update_value_memrefs(self, peek, ud);
value->value.i32 = 0;
value->type = RC_VALUE_TYPE_SIGNED;
@@ -236,7 +298,11 @@ int rc_evaluate_value_typed(rc_value_t* self, rc_typed_value_t* value, rc_peek_t
memset(&eval_state, 0, sizeof(eval_state));
eval_state.peek = peek;
eval_state.peek_userdata = ud;
#ifndef RC_DISABLE_LUA
eval_state.L = L;
#else
(void)L;
#endif
rc_test_condset(condset, &eval_state);
@@ -248,25 +314,21 @@ int rc_evaluate_value_typed(rc_value_t* self, rc_typed_value_t* value, rc_peek_t
* NOTE: ResetIf only affects the current condset when used in values!
*/
rc_reset_condset(condset);
/* if the measured value came from a hit count, reset it too */
if (eval_state.measured_from_hits) {
eval_state.measured_value.value.u32 = 0;
eval_state.measured_value.type = RC_VALUE_TYPE_UNSIGNED;
}
}
if (!valid) {
/* capture the first valid measurement */
memcpy(value, &eval_state.measured_value, sizeof(*value));
valid = 1;
}
else {
/* multiple condsets are currently only used for the MAX_OF operation.
* only keep the condset's value if it's higher than the current highest value.
*/
if (rc_typed_value_compare(&eval_state.measured_value, value, RC_OPERATOR_GT))
if (eval_state.measured_value.type != RC_VALUE_TYPE_NONE) {
if (!valid) {
/* capture the first valid measurement, which may be negative */
memcpy(value, &eval_state.measured_value, sizeof(*value));
valid = 1;
}
else {
/* multiple condsets are currently only used for the MAX_OF operation.
* only keep the condset's value if it's higher than the current highest value.
*/
if (rc_typed_value_compare(&eval_state.measured_value, value, RC_OPERATOR_GT))
memcpy(value, &eval_state.measured_value, sizeof(*value));
}
}
}
@@ -317,84 +379,81 @@ int rc_value_from_hits(rc_value_t* self)
return 0;
}
void rc_init_parse_state_variables(rc_parse_state_t* parse, rc_value_t** variables) {
parse->variables = variables;
*variables = 0;
}
rc_value_t* rc_alloc_helper_variable(const char* memaddr, size_t memaddr_len, rc_parse_state_t* parse)
{
rc_value_t** variables = parse->variables;
rc_value_t* rc_alloc_variable(const char* memaddr, size_t memaddr_len, rc_parse_state_t* parse) {
rc_value_t** value_ptr = parse->variables;
rc_value_t* value;
const char* name;
uint32_t measured_target;
while ((value = *variables) != NULL) {
if (!value_ptr)
return NULL;
while (*value_ptr) {
value = *value_ptr;
if (strncmp(value->name, memaddr, memaddr_len) == 0 && value->name[memaddr_len] == 0)
return value;
variables = &value->next;
value_ptr = &value->next;
}
value = RC_ALLOC_SCRATCH(rc_value_t, parse);
memset(&value->value, 0, sizeof(value->value));
value->value.size = RC_MEMSIZE_VARIABLE;
value->memrefs = NULL;
/* capture name before calling parse as parse will update memaddr pointer */
name = rc_alloc_str(parse, memaddr, memaddr_len);
if (!name)
return NULL;
/* no match found, create a new entry */
value = RC_ALLOC_SCRATCH(rc_value_t, parse);
memset(value, 0, sizeof(value->value));
value->value.size = RC_MEMSIZE_VARIABLE;
value->next = NULL;
/* the helper variable likely has a Measured condition. capture the current measured_target so we can restore it
* after generating the variable so the variable's Measured target doesn't conflict with the rest of the trigger. */
measured_target = parse->measured_target;
/* disable variable resolution when defining a variable to prevent infinite recursion */
variables = parse->variables;
parse->variables = NULL;
rc_parse_value_internal(value, &memaddr, parse);
parse->variables = variables;
/* restore the measured target */
parse->measured_target = measured_target;
/* store name after calling parse as parse will set name to (unnamed) */
value->name = name;
/* append the new variable to the end of the list (have to re-evaluate in case any others were added) */
while (*variables != NULL)
variables = &(*variables)->next;
*variables = value;
*value_ptr = value;
return value;
}
void rc_update_variables(rc_value_t* variable, rc_peek_t peek, void* ud, lua_State* L) {
uint32_t rc_count_values(const rc_value_t* values) {
uint32_t count = 0;
while (values) {
++count;
values = values->next;
}
return count;
}
void rc_update_values(rc_value_t* values, rc_peek_t peek, void* ud, lua_State* L) {
rc_typed_value_t result;
while (variable) {
if (rc_evaluate_value_typed(variable, &result, peek, ud, L)) {
rc_value_t* value = values;
for (; value; value = value->next) {
if (rc_evaluate_value_typed(value, &result, peek, ud, L)) {
/* store the raw bytes and type to be restored by rc_typed_value_from_memref_value */
rc_update_memref_value(&variable->value, result.value.u32);
variable->value.type = result.type;
rc_update_memref_value(&value->value, result.value.u32);
value->value.type = result.type;
}
variable = variable->next;
}
}
void rc_typed_value_from_memref_value(rc_typed_value_t* value, const rc_memref_value_t* memref) {
value->value.u32 = memref->value;
void rc_reset_values(rc_value_t* values) {
rc_value_t* value = values;
if (memref->size == RC_MEMSIZE_VARIABLE) {
/* a variable can be any of the supported types, but the raw data was copied into u32 */
value->type = memref->type;
}
else {
/* not a variable, only u32 is supported */
value->type = RC_VALUE_TYPE_UNSIGNED;
}
for (; value; value = value->next)
rc_reset_value(value);
}
void rc_typed_value_from_memref_value(rc_typed_value_t* value, const rc_memref_value_t* memref) {
/* raw value is always u32, type can mark it as something else */
value->value.u32 = memref->value;
value->type = memref->type;
}
void rc_typed_value_convert(rc_typed_value_t* value, char new_type) {
@@ -483,8 +542,12 @@ void rc_typed_value_negate(rc_typed_value_t* value) {
void rc_typed_value_add(rc_typed_value_t* value, const rc_typed_value_t* amount) {
rc_typed_value_t converted;
if (amount->type != value->type && value->type != RC_VALUE_TYPE_NONE)
amount = rc_typed_value_convert_into(&converted, amount, value->type);
if (amount->type != value->type && value->type != RC_VALUE_TYPE_NONE) {
if (amount->type == RC_VALUE_TYPE_FLOAT)
rc_typed_value_convert(value, RC_VALUE_TYPE_FLOAT);
else
amount = rc_typed_value_convert_into(&converted, amount, value->type);
}
switch (value->type)
{
@@ -651,56 +714,56 @@ void rc_typed_value_modulus(rc_typed_value_t* value, const rc_typed_value_t* amo
switch (amount->type)
{
case RC_VALUE_TYPE_UNSIGNED:
if (amount->value.u32 == 0) { /* divide by zero */
value->type = RC_VALUE_TYPE_NONE;
return;
}
case RC_VALUE_TYPE_UNSIGNED:
if (amount->value.u32 == 0) { /* divide by zero */
value->type = RC_VALUE_TYPE_NONE;
return;
}
switch (value->type) {
case RC_VALUE_TYPE_UNSIGNED: /* integer math */
value->value.u32 %= amount->value.u32;
return;
case RC_VALUE_TYPE_SIGNED: /* integer math */
value->value.i32 %= (int)amount->value.u32;
return;
case RC_VALUE_TYPE_FLOAT:
amount = rc_typed_value_convert_into(&converted, amount, RC_VALUE_TYPE_FLOAT);
switch (value->type) {
case RC_VALUE_TYPE_UNSIGNED: /* integer math */
value->value.u32 %= amount->value.u32;
return;
case RC_VALUE_TYPE_SIGNED: /* integer math */
value->value.i32 %= (int)amount->value.u32;
return;
case RC_VALUE_TYPE_FLOAT:
amount = rc_typed_value_convert_into(&converted, amount, RC_VALUE_TYPE_FLOAT);
break;
default:
value->type = RC_VALUE_TYPE_NONE;
return;
}
break;
case RC_VALUE_TYPE_SIGNED:
if (amount->value.i32 == 0) { /* divide by zero */
value->type = RC_VALUE_TYPE_NONE;
return;
}
switch (value->type) {
case RC_VALUE_TYPE_SIGNED: /* integer math */
value->value.i32 %= amount->value.i32;
return;
case RC_VALUE_TYPE_UNSIGNED: /* integer math */
value->value.u32 %= (unsigned)amount->value.i32;
return;
case RC_VALUE_TYPE_FLOAT:
amount = rc_typed_value_convert_into(&converted, amount, RC_VALUE_TYPE_FLOAT);
break;
default:
value->type = RC_VALUE_TYPE_NONE;
return;
}
break;
case RC_VALUE_TYPE_FLOAT:
break;
default:
value->type = RC_VALUE_TYPE_NONE;
return;
}
break;
case RC_VALUE_TYPE_SIGNED:
if (amount->value.i32 == 0) { /* divide by zero */
value->type = RC_VALUE_TYPE_NONE;
return;
}
switch (value->type) {
case RC_VALUE_TYPE_SIGNED: /* integer math */
value->value.i32 %= amount->value.i32;
return;
case RC_VALUE_TYPE_UNSIGNED: /* integer math */
value->value.u32 %= (unsigned)amount->value.i32;
return;
case RC_VALUE_TYPE_FLOAT:
amount = rc_typed_value_convert_into(&converted, amount, RC_VALUE_TYPE_FLOAT);
break;
default:
value->type = RC_VALUE_TYPE_NONE;
return;
}
break;
case RC_VALUE_TYPE_FLOAT:
break;
default:
value->type = RC_VALUE_TYPE_NONE;
return;
}
if (amount->value.f32 == 0.0) { /* divide by zero */
@@ -712,6 +775,44 @@ void rc_typed_value_modulus(rc_typed_value_t* value, const rc_typed_value_t* amo
value->value.f32 = (float)fmod(value->value.f32, amount->value.f32);
}
void rc_typed_value_combine(rc_typed_value_t* value, rc_typed_value_t* amount, uint8_t oper) {
switch (oper) {
case RC_OPERATOR_MULT:
rc_typed_value_multiply(value, amount);
break;
case RC_OPERATOR_DIV:
rc_typed_value_divide(value, amount);
break;
case RC_OPERATOR_AND:
rc_typed_value_convert(value, RC_VALUE_TYPE_UNSIGNED);
rc_typed_value_convert(amount, RC_VALUE_TYPE_UNSIGNED);
value->value.u32 &= amount->value.u32;
break;
case RC_OPERATOR_XOR:
rc_typed_value_convert(value, RC_VALUE_TYPE_UNSIGNED);
rc_typed_value_convert(amount, RC_VALUE_TYPE_UNSIGNED);
value->value.u32 ^= amount->value.u32;
break;
case RC_OPERATOR_MOD:
rc_typed_value_modulus(value, amount);
break;
case RC_OPERATOR_ADD:
rc_typed_value_add(value, amount);
break;
case RC_OPERATOR_SUB:
rc_typed_value_negate(amount);
rc_typed_value_add(value, amount);
break;
}
}
static int rc_typed_value_compare_floats(float f1, float f2, char oper) {
if (f1 == f2) {
/* exactly equal */

View File

@@ -77,7 +77,7 @@ static void* filereader_open(const char* path)
return NULL;
}
#if defined(__STDC_WANT_SECURE_LIB__)
#if defined(__STDC_SECURE_LIB__)
/* have to use _SH_DENYNO because some cores lock the file while its loaded */
fp = _wfsopen(wpath, L"rb", _SH_DENYNO);
#else
@@ -90,7 +90,7 @@ static void* filereader_open(const char* path)
#else /* !WINVER >= 0x0500 */
static void* filereader_open(const char* path)
{
#if defined(__STDC_WANT_SECURE_LIB__)
#if defined(__STDC_SECURE_LIB__)
#if defined(WINVER)
/* have to use _SH_DENYNO because some cores lock the file while its loaded */
return _fsopen(path, "rb", _SH_DENYNO);
@@ -99,7 +99,7 @@ static void* filereader_open(const char* path)
fopen_s(&fp, path, "rb");
return fp;
#endif
#else /* !__STDC_WANT_SECURE_LIB__ */
#else /* !__STDC_SECURE_LIB__ */
return fopen(path, "rb");
#endif
}
@@ -2513,6 +2513,7 @@ int rc_hash_generate_from_buffer(char hash[33], uint32_t console_id, const uint8
case RC_CONSOLE_ATARI_LYNX:
return rc_hash_lynx(hash, buffer, buffer_size);
case RC_CONSOLE_FAMICOM_DISK_SYSTEM:
case RC_CONSOLE_NINTENDO:
return rc_hash_nes(hash, buffer, buffer_size);
@@ -2818,6 +2819,7 @@ int rc_hash_generate_from_file(char hash[33], uint32_t console_id, const char* p
case RC_CONSOLE_ARDUBOY:
case RC_CONSOLE_ATARI_7800:
case RC_CONSOLE_ATARI_LYNX:
case RC_CONSOLE_FAMICOM_DISK_SYSTEM:
case RC_CONSOLE_NINTENDO:
case RC_CONSOLE_PC_ENGINE:
case RC_CONSOLE_SUPER_CASSETTEVISION:
@@ -3015,7 +3017,11 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
break;
case 'a':
if (rc_path_compare_extension(ext, "a78"))
if (rc_path_compare_extension(ext, "a26"))
{
iterator->consoles[0] = RC_CONSOLE_ATARI_2600;
}
else if (rc_path_compare_extension(ext, "a78"))
{
iterator->consoles[0] = RC_CONSOLE_ATARI_7800;
}
@@ -3157,7 +3163,7 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
}
else if (rc_path_compare_extension(ext, "fds"))
{
iterator->consoles[0] = RC_CONSOLE_NINTENDO;
iterator->consoles[0] = RC_CONSOLE_FAMICOM_DISK_SYSTEM;
}
else if (rc_path_compare_extension(ext, "fd"))
{

View File

@@ -67,6 +67,8 @@ Global
DebugFast|x64 = DebugFast|x64
DebugFast-Clang|ARM64 = DebugFast-Clang|ARM64
DebugFast-Clang|x64 = DebugFast-Clang|x64
Devel-Clang|ARM64 = Devel-Clang|ARM64
Devel-Clang|x64 = Devel-Clang|x64
Release|ARM64 = Release|ARM64
Release|x64 = Release|x64
Release-Clang|ARM64 = Release-Clang|ARM64
@@ -79,6 +81,44 @@ Global
ReleaseLTCG-Clang-SSE2|x64 = ReleaseLTCG-Clang-SSE2|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug|ARM64.ActiveCfg = Debug-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug|x64.ActiveCfg = Debug|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug|x64.Build.0 = Debug|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang|ARM64.ActiveCfg = Debug-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang|ARM64.Build.0 = Debug-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang|x64.ActiveCfg = Debug-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang|x64.Build.0 = Debug-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang-SSE2|ARM64.ActiveCfg = Debug-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang-SSE2|x64.ActiveCfg = Debug-Clang-SSE2|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang-SSE2|x64.Build.0 = Debug-Clang-SSE2|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast|ARM64.ActiveCfg = DebugFast-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast|x64.ActiveCfg = DebugFast|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast|x64.Build.0 = DebugFast|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast-Clang|ARM64.ActiveCfg = DebugFast-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release|x64.ActiveCfg = Release|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release|x64.Build.0 = Release|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release-Clang|ARM64.ActiveCfg = Release-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release-Clang|ARM64.Build.0 = Release-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release-Clang|x64.ActiveCfg = Release-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release-Clang|x64.Build.0 = Release-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG|ARM64.ActiveCfg = ReleaseLTCG-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG|x64.ActiveCfg = ReleaseLTCG|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG|x64.Build.0 = ReleaseLTCG|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang|ARM64.ActiveCfg = ReleaseLTCG-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang|ARM64.Build.0 = ReleaseLTCG-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang|x64.ActiveCfg = ReleaseLTCG-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang|x64.Build.0 = ReleaseLTCG-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang-SSE2|ARM64.ActiveCfg = ReleaseLTCG-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang-SSE2|x64.ActiveCfg = ReleaseLTCG-Clang-SSE2|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang-SSE2|x64.Build.0 = ReleaseLTCG-Clang-SSE2|x64
{43540154-9E1E-409C-834F-B84BE5621388}.Debug|ARM64.ActiveCfg = Debug-Clang|ARM64
{43540154-9E1E-409C-834F-B84BE5621388}.Debug|x64.ActiveCfg = Debug|x64
{43540154-9E1E-409C-834F-B84BE5621388}.Debug|x64.Build.0 = Debug|x64
@@ -96,6 +136,10 @@ Global
{43540154-9E1E-409C-834F-B84BE5621388}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{43540154-9E1E-409C-834F-B84BE5621388}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{43540154-9E1E-409C-834F-B84BE5621388}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{43540154-9E1E-409C-834F-B84BE5621388}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{43540154-9E1E-409C-834F-B84BE5621388}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{43540154-9E1E-409C-834F-B84BE5621388}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{43540154-9E1E-409C-834F-B84BE5621388}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{43540154-9E1E-409C-834F-B84BE5621388}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{43540154-9E1E-409C-834F-B84BE5621388}.Release|x64.ActiveCfg = Release|x64
{43540154-9E1E-409C-834F-B84BE5621388}.Release|x64.Build.0 = Release|x64
@@ -130,6 +174,10 @@ Global
{BB08260F-6FBC-46AF-8924-090EE71360C6}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.Release|x64.ActiveCfg = Release|x64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.Release|x64.Build.0 = Release|x64
@@ -164,6 +212,10 @@ Global
{EE054E08-3799-4A59-A422-18259C105FFD}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{EE054E08-3799-4A59-A422-18259C105FFD}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{EE054E08-3799-4A59-A422-18259C105FFD}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{EE054E08-3799-4A59-A422-18259C105FFD}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{EE054E08-3799-4A59-A422-18259C105FFD}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{EE054E08-3799-4A59-A422-18259C105FFD}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{EE054E08-3799-4A59-A422-18259C105FFD}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{EE054E08-3799-4A59-A422-18259C105FFD}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{EE054E08-3799-4A59-A422-18259C105FFD}.Release|x64.ActiveCfg = Release|x64
{EE054E08-3799-4A59-A422-18259C105FFD}.Release|x64.Build.0 = Release|x64
@@ -198,6 +250,10 @@ Global
{868B98C8-65A1-494B-8346-250A73A48C0A}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{868B98C8-65A1-494B-8346-250A73A48C0A}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{868B98C8-65A1-494B-8346-250A73A48C0A}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{868B98C8-65A1-494B-8346-250A73A48C0A}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{868B98C8-65A1-494B-8346-250A73A48C0A}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{868B98C8-65A1-494B-8346-250A73A48C0A}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{868B98C8-65A1-494B-8346-250A73A48C0A}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{868B98C8-65A1-494B-8346-250A73A48C0A}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{868B98C8-65A1-494B-8346-250A73A48C0A}.Release|x64.ActiveCfg = Release|x64
{868B98C8-65A1-494B-8346-250A73A48C0A}.Release|x64.Build.0 = Release|x64
@@ -232,6 +288,10 @@ Global
{3773F4CC-614E-4028-8595-22E08CA649E3}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{3773F4CC-614E-4028-8595-22E08CA649E3}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{3773F4CC-614E-4028-8595-22E08CA649E3}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{3773F4CC-614E-4028-8595-22E08CA649E3}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{3773F4CC-614E-4028-8595-22E08CA649E3}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{3773F4CC-614E-4028-8595-22E08CA649E3}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{3773F4CC-614E-4028-8595-22E08CA649E3}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{3773F4CC-614E-4028-8595-22E08CA649E3}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{3773F4CC-614E-4028-8595-22E08CA649E3}.Release|x64.ActiveCfg = Release|x64
{3773F4CC-614E-4028-8595-22E08CA649E3}.Release|x64.Build.0 = Release|x64
@@ -249,40 +309,6 @@ Global
{3773F4CC-614E-4028-8595-22E08CA649E3}.ReleaseLTCG-Clang-SSE2|ARM64.ActiveCfg = ReleaseLTCG-Clang|ARM64
{3773F4CC-614E-4028-8595-22E08CA649E3}.ReleaseLTCG-Clang-SSE2|x64.ActiveCfg = ReleaseLTCG-Clang-SSE2|x64
{3773F4CC-614E-4028-8595-22E08CA649E3}.ReleaseLTCG-Clang-SSE2|x64.Build.0 = ReleaseLTCG-Clang-SSE2|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug|ARM64.ActiveCfg = Debug-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug|x64.ActiveCfg = Debug|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug|x64.Build.0 = Debug|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang|ARM64.ActiveCfg = Debug-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang|ARM64.Build.0 = Debug-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang|x64.ActiveCfg = Debug-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang|x64.Build.0 = Debug-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang-SSE2|ARM64.ActiveCfg = Debug-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang-SSE2|x64.ActiveCfg = Debug-Clang-SSE2|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang-SSE2|x64.Build.0 = Debug-Clang-SSE2|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast|ARM64.ActiveCfg = DebugFast-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast|x64.ActiveCfg = DebugFast|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast|x64.Build.0 = DebugFast|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast-Clang|ARM64.ActiveCfg = DebugFast-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release|x64.ActiveCfg = Release|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release|x64.Build.0 = Release|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release-Clang|ARM64.ActiveCfg = Release-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release-Clang|ARM64.Build.0 = Release-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release-Clang|x64.ActiveCfg = Release-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release-Clang|x64.Build.0 = Release-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG|ARM64.ActiveCfg = ReleaseLTCG-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG|x64.ActiveCfg = ReleaseLTCG|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG|x64.Build.0 = ReleaseLTCG|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang|ARM64.ActiveCfg = ReleaseLTCG-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang|ARM64.Build.0 = ReleaseLTCG-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang|x64.ActiveCfg = ReleaseLTCG-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang|x64.Build.0 = ReleaseLTCG-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang-SSE2|ARM64.ActiveCfg = ReleaseLTCG-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang-SSE2|x64.ActiveCfg = ReleaseLTCG-Clang-SSE2|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang-SSE2|x64.Build.0 = ReleaseLTCG-Clang-SSE2|x64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.Debug|ARM64.ActiveCfg = Debug-Clang|ARM64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.Debug|x64.ActiveCfg = Debug|x64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.Debug|x64.Build.0 = Debug|x64
@@ -300,6 +326,10 @@ Global
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.Release|x64.ActiveCfg = Release|x64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.Release|x64.Build.0 = Release|x64
@@ -334,6 +364,10 @@ Global
{8BDA439C-6358-45FB-9994-2FF083BABE06}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.Release|x64.ActiveCfg = Release|x64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.Release|x64.Build.0 = Release|x64
@@ -368,6 +402,10 @@ Global
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.Release|x64.ActiveCfg = Release|x64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.Release|x64.Build.0 = Release|x64
@@ -402,6 +440,10 @@ Global
{DD944834-7899-4C1C-A4C1-064B5009D239}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{DD944834-7899-4C1C-A4C1-064B5009D239}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{DD944834-7899-4C1C-A4C1-064B5009D239}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{DD944834-7899-4C1C-A4C1-064B5009D239}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{DD944834-7899-4C1C-A4C1-064B5009D239}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{DD944834-7899-4C1C-A4C1-064B5009D239}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{DD944834-7899-4C1C-A4C1-064B5009D239}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{DD944834-7899-4C1C-A4C1-064B5009D239}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{DD944834-7899-4C1C-A4C1-064B5009D239}.Release|x64.ActiveCfg = Release|x64
{DD944834-7899-4C1C-A4C1-064B5009D239}.Release|x64.Build.0 = Release|x64
@@ -436,6 +478,10 @@ Global
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.Release|x64.ActiveCfg = Release|x64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.Release|x64.Build.0 = Release|x64
@@ -470,6 +516,10 @@ Global
{49953E1B-2EF7-46A4-B88B-1BF9E099093B}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{49953E1B-2EF7-46A4-B88B-1BF9E099093B}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{49953E1B-2EF7-46A4-B88B-1BF9E099093B}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{49953E1B-2EF7-46A4-B88B-1BF9E099093B}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{49953E1B-2EF7-46A4-B88B-1BF9E099093B}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{49953E1B-2EF7-46A4-B88B-1BF9E099093B}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{49953E1B-2EF7-46A4-B88B-1BF9E099093B}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{49953E1B-2EF7-46A4-B88B-1BF9E099093B}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{49953E1B-2EF7-46A4-B88B-1BF9E099093B}.Release|x64.ActiveCfg = Release|x64
{49953E1B-2EF7-46A4-B88B-1BF9E099093B}.Release|x64.Build.0 = Release|x64
@@ -497,6 +547,8 @@ Global
{EA2B9C7A-B8CC-42F9-879B-191A98680C10}.DebugFast|x64.ActiveCfg = DebugFast|x64
{EA2B9C7A-B8CC-42F9-879B-191A98680C10}.DebugFast-Clang|ARM64.ActiveCfg = DebugFast-Clang|ARM64
{EA2B9C7A-B8CC-42F9-879B-191A98680C10}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{EA2B9C7A-B8CC-42F9-879B-191A98680C10}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{EA2B9C7A-B8CC-42F9-879B-191A98680C10}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{EA2B9C7A-B8CC-42F9-879B-191A98680C10}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{EA2B9C7A-B8CC-42F9-879B-191A98680C10}.Release|x64.ActiveCfg = Release|x64
{EA2B9C7A-B8CC-42F9-879B-191A98680C10}.Release-Clang|ARM64.ActiveCfg = Release-Clang|ARM64
@@ -524,6 +576,10 @@ Global
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.Release|x64.ActiveCfg = Release|x64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.Release|x64.Build.0 = Release|x64
@@ -551,6 +607,8 @@ Global
{32EEAF44-57F8-4C6C-A6F0-DE5667123DD5}.DebugFast|x64.ActiveCfg = DebugFast|x64
{32EEAF44-57F8-4C6C-A6F0-DE5667123DD5}.DebugFast-Clang|ARM64.ActiveCfg = DebugFast-Clang|ARM64
{32EEAF44-57F8-4C6C-A6F0-DE5667123DD5}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{32EEAF44-57F8-4C6C-A6F0-DE5667123DD5}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{32EEAF44-57F8-4C6C-A6F0-DE5667123DD5}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{32EEAF44-57F8-4C6C-A6F0-DE5667123DD5}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{32EEAF44-57F8-4C6C-A6F0-DE5667123DD5}.Release|x64.ActiveCfg = Release|x64
{32EEAF44-57F8-4C6C-A6F0-DE5667123DD5}.Release-Clang|ARM64.ActiveCfg = Release-Clang|ARM64
@@ -576,6 +634,9 @@ Global
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.DebugFast-Clang|ARM64.ActiveCfg = DebugFast-Clang|ARM64
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.Release|x64.ActiveCfg = Release|x64
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.Release-Clang|ARM64.ActiveCfg = Release-Clang|ARM64
@@ -605,6 +666,10 @@ Global
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.Release|x64.ActiveCfg = Release|x64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.Release|x64.Build.0 = Release|x64
@@ -633,6 +698,8 @@ Global
{3029310E-4211-4C87-801A-72E130A648EF}.DebugFast-Clang|ARM64.ActiveCfg = DebugFast-Clang|ARM64
{3029310E-4211-4C87-801A-72E130A648EF}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{3029310E-4211-4C87-801A-72E130A648EF}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{3029310E-4211-4C87-801A-72E130A648EF}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{3029310E-4211-4C87-801A-72E130A648EF}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{3029310E-4211-4C87-801A-72E130A648EF}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{3029310E-4211-4C87-801A-72E130A648EF}.Release|x64.ActiveCfg = Release|x64
{3029310E-4211-4C87-801A-72E130A648EF}.Release-Clang|ARM64.ActiveCfg = Release-Clang|ARM64
@@ -661,6 +728,10 @@ Global
{E4357877-D459-45C7-B8F6-DCBB587BB528}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{E4357877-D459-45C7-B8F6-DCBB587BB528}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{E4357877-D459-45C7-B8F6-DCBB587BB528}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Release|x64.ActiveCfg = Release|x64
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Release|x64.Build.0 = Release|x64
@@ -695,6 +766,10 @@ Global
{8BE398E6-B882-4248-9065-FECC8728E038}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{8BE398E6-B882-4248-9065-FECC8728E038}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{8BE398E6-B882-4248-9065-FECC8728E038}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{8BE398E6-B882-4248-9065-FECC8728E038}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{8BE398E6-B882-4248-9065-FECC8728E038}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{8BE398E6-B882-4248-9065-FECC8728E038}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{8BE398E6-B882-4248-9065-FECC8728E038}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{8BE398E6-B882-4248-9065-FECC8728E038}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{8BE398E6-B882-4248-9065-FECC8728E038}.Release|x64.ActiveCfg = Release|x64
{8BE398E6-B882-4248-9065-FECC8728E038}.Release|x64.Build.0 = Release|x64
@@ -729,6 +804,10 @@ Global
{57F6206D-F264-4B07-BAF8-11B9BBE1F455}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{57F6206D-F264-4B07-BAF8-11B9BBE1F455}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{57F6206D-F264-4B07-BAF8-11B9BBE1F455}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{57F6206D-F264-4B07-BAF8-11B9BBE1F455}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{57F6206D-F264-4B07-BAF8-11B9BBE1F455}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{57F6206D-F264-4B07-BAF8-11B9BBE1F455}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{57F6206D-F264-4B07-BAF8-11B9BBE1F455}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{57F6206D-F264-4B07-BAF8-11B9BBE1F455}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{57F6206D-F264-4B07-BAF8-11B9BBE1F455}.Release|x64.ActiveCfg = Release|x64
{57F6206D-F264-4B07-BAF8-11B9BBE1F455}.Release|x64.Build.0 = Release|x64
@@ -761,6 +840,9 @@ Global
{C51A346A-86B2-46DF-9BB3-D0AA7E5D8699}.DebugFast-Clang|ARM64.ActiveCfg = DebugFast-Clang|ARM64
{C51A346A-86B2-46DF-9BB3-D0AA7E5D8699}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{C51A346A-86B2-46DF-9BB3-D0AA7E5D8699}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{C51A346A-86B2-46DF-9BB3-D0AA7E5D8699}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{C51A346A-86B2-46DF-9BB3-D0AA7E5D8699}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{C51A346A-86B2-46DF-9BB3-D0AA7E5D8699}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{C51A346A-86B2-46DF-9BB3-D0AA7E5D8699}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{C51A346A-86B2-46DF-9BB3-D0AA7E5D8699}.Release|x64.ActiveCfg = Release|x64
{C51A346A-86B2-46DF-9BB3-D0AA7E5D8699}.Release-Clang|ARM64.ActiveCfg = Release-Clang|ARM64
@@ -788,6 +870,10 @@ Global
{F351C4D8-594A-4850-B77B-3C1249812CCE}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{F351C4D8-594A-4850-B77B-3C1249812CCE}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{F351C4D8-594A-4850-B77B-3C1249812CCE}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{F351C4D8-594A-4850-B77B-3C1249812CCE}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{F351C4D8-594A-4850-B77B-3C1249812CCE}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{F351C4D8-594A-4850-B77B-3C1249812CCE}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{F351C4D8-594A-4850-B77B-3C1249812CCE}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{F351C4D8-594A-4850-B77B-3C1249812CCE}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{F351C4D8-594A-4850-B77B-3C1249812CCE}.Release|x64.ActiveCfg = Release|x64
{F351C4D8-594A-4850-B77B-3C1249812CCE}.Release|x64.Build.0 = Release|x64
@@ -822,6 +908,10 @@ Global
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.Release|x64.ActiveCfg = Release|x64
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.Release|x64.Build.0 = Release|x64
@@ -856,6 +946,10 @@ Global
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Release|x64.ActiveCfg = Release|x64
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Release|x64.Build.0 = Release|x64

View File

@@ -1,5 +0,0 @@
set(CMAKE_C_COMPILER /usr/bin/clang-16)
set(CMAKE_CXX_COMPILER /usr/bin/clang++-16)
set(CMAKE_EXE_LINKER_FLAGS_INIT "-fuse-ld=lld")
set(CMAKE_MODULE_LINKER_FLAGS_INIT "-fuse-ld=lld")
set(CMAKE_SHARED_LINKER_FLAGS_INIT "-fuse-ld=lld")

View File

@@ -0,0 +1,519 @@
#!/usr/bin/env bash
# SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
# SPDX-License-Identifier: CC-BY-NC-ND-4.0
set -e
if [ "$#" -lt 4 ]; then
echo "Syntax: $0 [-system-freetype] [-system-harfbuzz] [-system-libjpeg] [-system-libpng] [-system-libwebp] [-system-libzip] [-system-zstd] [-system-qt] [-skip-download] [-skip-cleanup] [-only-download] <host directory> <cross architecture> <cross chroot> <output directory>"
exit 1
fi
for arg in "$@"; do
if [ "$arg" == "-system-freetype" ]; then
echo "Skipping building FreeType."
SKIP_FREETYPE=true
shift
elif [ "$arg" == "-system-harfbuzz" ]; then
echo "Skipping building HarfBuzz."
SKIP_HARFBUZZ=true
shift
elif [ "$arg" == "-system-libjpeg" ]; then
echo "Skipping building libjpeg."
SKIP_LIBJPEG=true
shift
elif [ "$arg" == "-system-libpng" ]; then
echo "Skipping building libpng."
SKIP_LIBPNG=true
shift
elif [ "$arg" == "-system-libwebp" ]; then
echo "Skipping building libwebp."
SKIP_LIBWEBP=true
shift
elif [ "$arg" == "-system-libzip" ]; then
echo "Skipping building libzip."
SKIP_LIBZIP=true
shift
elif [ "$arg" == "-system-zstd" ]; then
echo "Skipping building zstd."
SKIP_ZSTD=true
shift
elif [ "$arg" == "-system-qt" ]; then
echo "Skipping building Qt."
SKIP_QT=true
shift
elif [ "$arg" == "-skip-download" ]; then
echo "Not downloading sources."
SKIP_DOWNLOAD=true
shift
elif [ "$arg" == "-skip-cleanup" ]; then
echo "Not removing build directory."
SKIP_CLEANUP=true
shift
elif [ "$arg" == "-only-download" ]; then
echo "Only downloading sources."
ONLY_DOWNLOAD=true
shift
fi
done
SCRIPTDIR=$(realpath $(dirname "${BASH_SOURCE[0]}"))
NPROCS="$(getconf _NPROCESSORS_ONLN)"
HOSTDIR="$1"
if [ "${HOSTDIR:0:1}" != "/" ]; then
HOSTDIR="$PWD/$HOSTDIR"
fi
CROSSARCH="$2"
SYSROOTDIR="$3"
if [ "${SYSROOTDIR:0:1}" != "/" ]; then
SYSROOTDIR="$PWD/$SYSROOTDIR"
fi
INSTALLDIR="$4"
if [ "${INSTALLDIR:0:1}" != "/" ]; then
INSTALLDIR="$PWD/$INSTALLDIR"
fi
TOOLCHAINFILE="$INSTALLDIR/toolchain.cmake"
CMAKE_COMMON=(
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_TOOLCHAIN_FILE="$TOOLCHAINFILE"
-DCMAKE_PREFIX_PATH="$INSTALLDIR"
-DCMAKE_INSTALL_PREFIX="$INSTALLDIR"
)
# TODO: Pull all of this from the main file.
FREETYPE=2.13.3
HARFBUZZ=10.1.0
LIBBACKTRACE=86885d14049fab06ef8a33aac51664230ca09200
LIBJPEGTURBO=3.0.4
LIBPNG=1.6.44
LIBWEBP=1.4.0
LIBZIP=1.11.2
SDL2=2.30.11
QT=6.8.1
ZSTD=1.5.6
CPUINFO=7524ad504fdcfcf75a18a133da6abd75c5d48053
DISCORD_RPC=144f3a3f1209994d8d9e8a87964a989cb9911c1e
LUNASVG=9af1ac7b90658a279b372add52d6f77a4ebb482c
SHADERC=1c0d3d18819aa75ec74f1fbd9ff0461e1b69a4d6
SOUNDTOUCH=463ade388f3a51da078dc9ed062bf28e4ba29da7
SPIRV_CROSS=vulkan-sdk-1.3.290.0
mkdir -p "${INSTALLDIR}"
mkdir -p deps-build
cd deps-build
if [ "$SKIP_DOWNLOAD" != true ]; then
curl -C - -L \
-O "https://github.com/ianlancetaylor/libbacktrace/archive/$LIBBACKTRACE.tar.gz" \
-O "https://github.com/libsdl-org/SDL/releases/download/release-$SDL2/SDL2-$SDL2.tar.gz" \
-o "cpuinfo-$CPUINFO.tar.gz" "https://github.com/stenzek/cpuinfo/archive/$CPUINFO.tar.gz" \
-o "discord-rpc-$DISCORD_RPC.tar.gz" "https://github.com/stenzek/discord-rpc/archive/$DISCORD_RPC.tar.gz" \
-o "lunasvg-$LUNASVG.tar.gz" "https://github.com/stenzek/lunasvg/archive/$LUNASVG.tar.gz" \
-o "shaderc-$SHADERC.tar.gz" "https://github.com/stenzek/shaderc/archive/$SHADERC.tar.gz" \
-o "soundtouch-$SOUNDTOUCH.tar.gz" "https://github.com/stenzek/soundtouch/archive/$SOUNDTOUCH.tar.gz"
fi
cat > SHASUMS <<EOF
baf8aebd22002b762d803ba0e1e389b6b4415159334e9d34bba1a938f6de8ce6 $LIBBACKTRACE.tar.gz
8b8d4aef2038533da814965220f88f77d60dfa0f32685f80ead65e501337da7f SDL2-$SDL2.tar.gz
e1351218d270db49c3dddcba04fb2153b09731ea3fa6830e423f5952f44585be cpuinfo-$CPUINFO.tar.gz
3eea5ccce6670c126282f1ba4d32c19d486db49a1a5cbfb8d6f48774784d310c discord-rpc-$DISCORD_RPC.tar.gz
3998b024b0d442614a9ee270e76e018bb37a17b8c6941212171731123cbbcac7 lunasvg-$LUNASVG.tar.gz
3826d86f8a13564be1c047ac105041a3c5d0dc0bf826fe47cc582fe17a2ce7b1 shaderc-$SHADERC.tar.gz
fe45c2af99f6102d2704277d392c1c83b55180a70bfd17fb888cc84a54b70573 soundtouch-$SOUNDTOUCH.tar.gz
EOF
if [ "$SKIP_FREETYPE" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
curl -C - -L -o "freetype-$FREETYPE.tar.xz" "https://sourceforge.net/projects/freetype/files/freetype2/$FREETYPE/freetype-$FREETYPE.tar.xz/download"
fi
cat >> SHASUMS <<EOF
0550350666d427c74daeb85d5ac7bb353acba5f76956395995311a9c6f063289 freetype-$FREETYPE.tar.xz
EOF
fi
if [ "$SKIP_HARFBUZZ" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
curl -C - -L -o "harfbuzz-$HARFBUZZ.tar.gz" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/$HARFBUZZ.tar.gz"
fi
cat >> SHASUMS <<EOF
c758fdce8587641b00403ee0df2cd5d30cbea7803d43c65fddd76224f7b49b88 harfbuzz-$HARFBUZZ.tar.gz
EOF
fi
if [ "$SKIP_LIBJPEG" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
curl -C - -L -O "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/$LIBJPEGTURBO/libjpeg-turbo-$LIBJPEGTURBO.tar.gz"
fi
cat >> SHASUMS <<EOF
99130559e7d62e8d695f2c0eaeef912c5828d5b84a0537dcb24c9678c9d5b76b libjpeg-turbo-$LIBJPEGTURBO.tar.gz
EOF
fi
if [ "$SKIP_LIBPNG" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
curl -C - -L -O "https://downloads.sourceforge.net/project/libpng/libpng16/$LIBPNG/libpng-$LIBPNG.tar.xz"
fi
cat >> SHASUMS <<EOF
60c4da1d5b7f0aa8d158da48e8f8afa9773c1c8baa5d21974df61f1886b8ce8e libpng-$LIBPNG.tar.xz
EOF
fi
if [ "$SKIP_LIBWEBP" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
curl -C - -L -O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz"
fi
cat >> SHASUMS <<EOF
61f873ec69e3be1b99535634340d5bde750b2e4447caa1db9f61be3fd49ab1e5 libwebp-$LIBWEBP.tar.gz
EOF
fi
if [ "$SKIP_LIBZIP" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
curl -C - -L -O "https://github.com/nih-at/libzip/releases/download/v$LIBZIP/libzip-$LIBZIP.tar.xz"
fi
cat >> SHASUMS <<EOF
5d471308cef4c4752bbcf973d9cd37ba4cb53739116c30349d4764ba1410dfc1 libzip-$LIBZIP.tar.xz
EOF
fi
if [ "$SKIP_ZSTD" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
curl -C - -L -O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz"
fi
cat >> SHASUMS <<EOF
8c29e06cf42aacc1eafc4077ae2ec6c6fcb96a626157e0593d5e82a34fd403c1 zstd-$ZSTD.tar.gz
EOF
fi
if [ "$SKIP_QT" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
curl -C - -L \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtbase-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtimageformats-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtsvg-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttools-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttranslations-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtwayland-everywhere-src-$QT.tar.xz"
fi
cat >> SHASUMS <<EOF
40b14562ef3bd779bc0e0418ea2ae08fa28235f8ea6e8c0cb3bce1d6ad58dcaf qtbase-everywhere-src-$QT.tar.xz
138cc2909aa98f5ff7283e36eb3936eb5e625d3ca3b4febae2ca21d8903dd237 qtimageformats-everywhere-src-$QT.tar.xz
3d0de73596e36b2daa7c48d77c4426bb091752856912fba720215f756c560dd0 qtsvg-everywhere-src-$QT.tar.xz
9d43d409be08b8681a0155a9c65114b69c9a3fc11aef6487bb7fdc5b283c432d qttools-everywhere-src-$QT.tar.xz
635a6093e99152243b807de51077485ceadd4786d4acb135b9340b2303035a4a qttranslations-everywhere-src-$QT.tar.xz
2226fbde4e2ddd12f8bf4b239c8f38fd706a54e789e63467dfddc77129eca203 qtwayland-everywhere-src-$QT.tar.xz
EOF
fi
shasum -a 256 --check SHASUMS
# Have to clone with git, because it does version detection.
if [ "$SKIP_DOWNLOAD" != true ]; then
if [ ! -d "SPIRV-Cross" ]; then
git clone https://github.com/KhronosGroup/SPIRV-Cross/ -b $SPIRV_CROSS --depth 1
fi
fi
# Only downloading sources?
if [ "$ONLY_DOWNLOAD" == true ]; then
exit 0
fi
# Stop pkg-config picking up host files.
export PKG_CONFIG_PATH=${SYSROOTDIR}/usr/lib/${CROSSARCH}-linux-gnu/pkgconfig:${SYSROOTDIR}/usr/lib/pkgconfig:${SYSROOTDIR}/usr/share/pkgconfig
export PKG_CONFIG_SYSROOT_DIR=${SYSROOTDIR}
# Generate cmake toolchain file.
cat > "$TOOLCHAINFILE" << EOF
set(CMAKE_CROSSCOMPILING TRUE)
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR ${CROSSARCH})
set(CMAKE_C_COMPILER "/usr/bin/${CROSSARCH}-linux-gnu-gcc")
set(CMAKE_C_COMPILER_TARGET "${CROSSARCH}-linux-gnu")
set(CMAKE_C_COMPILER_AR "/usr/bin/${CROSSARCH}-linux-gnu-ar")
set(CMAKE_C_COMPILER_RANLIB "/usr/bin/${CROSSARCH}-linux-gnu-ranlib")
set(CMAKE_CXX_COMPILER "/usr/bin/${CROSSARCH}-linux-gnu-g++")
set(CMAKE_CXX_COMPILER_TARGET "${CROSSARCH}-linux-gnu")
set(CMAKE_CXX_COMPILER_AR "/usr/bin/${CROSSARCH}-linux-gnu-ar")
set(CMAKE_CXX_COMPILER_RANLIB "/usr/bin/${CROSSARCH}-linux-gnu-ranlib")
set(CMAKE_FIND_ROOT_PATH "${INSTALLDIR};${SYSROOTDIR}")
set(CMAKE_SYSROOT "${SYSROOTDIR}")
set(CMAKE_PKG_CONFIG_PC_PATH "${PKG_CONFIG_PATH}")
set(CMAKE_PKG_CONFIG_SYSROOT_DIR "${PKG_CONFIG_SYSROOT_DIR}")
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
EOF
# NOTE: Must be a shared library because otherwise aarch64 libgcc symbols are missing when building with clang.
echo "Building libbacktrace..."
rm -fr "libbacktrace-$LIBBACKTRACE"
tar xf "$LIBBACKTRACE.tar.gz"
cd "libbacktrace-$LIBBACKTRACE"
./configure --prefix="$INSTALLDIR" --build=x86_64-linux-gnu --host="${CROSSARCH}-linux-gnu" --with-pic --enable-shared --disable-static
make
make install
cd ..
if [ "$SKIP_LIBPNG" != true ]; then
echo "Building libpng..."
rm -fr "libpng-$LIBPNG"
tar xf "libpng-$LIBPNG.tar.xz"
cd "libpng-$LIBPNG"
cmake "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -DPNG_TESTS=OFF -DPNG_STATIC=OFF -DPNG_SHARED=ON -DPNG_TOOLS=OFF -B build -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
fi
if [ "$SKIP_LIBJPEG" != true ]; then
echo "Building libjpeg..."
rm -fr "libjpeg-turbo-$LIBJPEGTURBO"
tar xf "libjpeg-turbo-$LIBJPEGTURBO.tar.gz"
cd "libjpeg-turbo-$LIBJPEGTURBO"
cmake "${CMAKE_COMMON[@]}" -DENABLE_STATIC=OFF -DENABLE_SHARED=ON -B build -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
fi
if [ "$SKIP_ZSTD" != true ]; then
echo "Building Zstandard..."
rm -fr "zstd-$ZSTD"
tar xf "zstd-$ZSTD.tar.gz"
cd "zstd-$ZSTD"
cmake "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -DZSTD_BUILD_SHARED=ON -DZSTD_BUILD_STATIC=OFF -DZSTD_BUILD_PROGRAMS=OFF -B build -G Ninja build/cmake
cmake --build build --parallel
ninja -C build install
cd ..
fi
if [ "$SKIP_LIBWEBP" != true ]; then
echo "Building WebP..."
rm -fr "libwebp-$LIBWEBP"
tar xf "libwebp-$LIBWEBP.tar.gz"
cd "libwebp-$LIBWEBP"
cmake "${CMAKE_COMMON[@]}" -B build -G Ninja \
-DWEBP_BUILD_ANIM_UTILS=OFF -DWEBP_BUILD_CWEBP=OFF -DWEBP_BUILD_DWEBP=OFF -DWEBP_BUILD_GIF2WEBP=OFF -DWEBP_BUILD_IMG2WEBP=OFF \
-DWEBP_BUILD_VWEBP=OFF -DWEBP_BUILD_WEBPINFO=OFF -DWEBP_BUILD_WEBPMUX=OFF -DWEBP_BUILD_EXTRAS=OFF -DBUILD_SHARED_LIBS=ON
cmake --build build --parallel
ninja -C build install
cd ..
fi
if [ "$SKIP_LIBZIP" != true ]; then
echo "Building libzip..."
rm -fr "libzip-$LIBZIP"
tar xf "libzip-$LIBZIP.tar.xz"
cd "libzip-$LIBZIP"
cmake "${CMAKE_COMMON[@]}" -B build -G Ninja \
-DENABLE_COMMONCRYPTO=OFF -DENABLE_GNUTLS=OFF -DENABLE_MBEDTLS=OFF -DENABLE_OPENSSL=OFF -DENABLE_WINDOWS_CRYPTO=OFF \
-DENABLE_BZIP2=OFF -DENABLE_LZMA=OFF -DENABLE_ZSTD=ON -DBUILD_SHARED_LIBS=ON -DLIBZIP_DO_INSTALL=ON \
-DBUILD_TOOLS=OFF -DBUILD_REGRESS=OFF -DBUILD_OSSFUZZ=OFF -DBUILD_EXAMPLES=OFF -DBUILD_DOC=OFF
cmake --build build --parallel
ninja -C build install
cd ..
fi
if [ "$SKIP_FREETYPE" != true ]; then
if [ "$SKIP_HARFBUZZ" != true ]; then
echo "Building FreeType without HarfBuzz..."
rm -fr "freetype-$FREETYPE"
tar xf "freetype-$FREETYPE.tar.xz"
cd "freetype-$FREETYPE"
cmake "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -DFT_REQUIRE_ZLIB=ON -DFT_REQUIRE_PNG=ON -DFT_DISABLE_BZIP2=TRUE -DFT_DISABLE_BROTLI=TRUE -DFT_DISABLE_HARFBUZZ=TRUE -B build -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
echo "Building HarfBuzz..."
rm -fr "harfbuzz-$HARFBUZZ"
tar xf "harfbuzz-$HARFBUZZ.tar.gz"
cd "harfbuzz-$HARFBUZZ"
cmake "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -DHB_BUILD_UTILS=OFF -B build -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
fi
echo "Building FreeType with HarfBuzz..."
rm -fr "freetype-$FREETYPE"
tar xf "freetype-$FREETYPE.tar.xz"
cd "freetype-$FREETYPE"
cmake "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -DFT_REQUIRE_ZLIB=ON -DFT_REQUIRE_PNG=ON -DFT_DISABLE_BZIP2=TRUE -DFT_DISABLE_BROTLI=TRUE -DFT_REQUIRE_HARFBUZZ=TRUE -B build -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
fi
echo "Building SDL2..."
rm -fr "SDL2-$SDL2"
tar xf "SDL2-$SDL2.tar.gz"
cd "SDL2-$SDL2"
# needed because -Isystem with chroot/usr/include breaks
patch -p1 < "$SCRIPTDIR/sdl2-disable-isystem.patch"
cmake -B build "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
if [ "$SKIP_QT" != true ]; then
# Couple notes:
# -fontconfig is needed otherwise Qt Widgets render only boxes.
# -qt-doubleconversion avoids a dependency on libdouble-conversion.
# ICU avoids pulling in a bunch of large libraries, and hopefully we can get away without it.
# OpenGL is needed to render window decorations in Wayland, apparently.
# dbus-runtime and linked off to avoid a relocation error (different to host.. probably should change that).
echo "Building Qt Base..."
rm -fr "qtbase-everywhere-src-$QT"
tar xf "qtbase-everywhere-src-$QT.tar.xz"
cd "qtbase-everywhere-src-$QT"
patch -p1 < "$SCRIPTDIR/qtbase-disable-pcre2-jit.patch"
mkdir build
cd build
../configure -prefix "$INSTALLDIR" -extprefix "$INSTALLDIR" -qt-host-path "$HOSTDIR" -release -dbus runtime -gui -widgets -fontconfig -qt-doubleconversion -ssl -openssl-runtime -opengl desktop -qpa xcb,wayland -xkbcommon -xcb -gtk -- -DCMAKE_TOOLCHAIN_FILE="$TOOLCHAINFILE" -DFEATURE_cups=OFF -DFEATURE_dbus=ON -DFEATURE_dbus_linked=OFF -DFEATURE_icu=OFF -DFEATURE_sql=OFF -DFEATURE_system_png=ON -DFEATURE_system_jpeg=ON -DFEATURE_system_zlib=ON -DFEATURE_system_freetype=ON -DFEATURE_system_harfbuzz=ON
cmake --build . --parallel
ninja install
cd ../../
echo "Building Qt SVG..."
rm -fr "qtsvg-everywhere-src-$QT"
tar xf "qtsvg-everywhere-src-$QT.tar.xz"
cd "qtsvg-everywhere-src-$QT"
mkdir build
cd build
"$INSTALLDIR/bin/qt-configure-module" .. -- -DCMAKE_PREFIX_PATH="$INSTALLDIR"
cmake --build . --parallel
ninja install
cd ../../
echo "Building Qt Image Formats..."
rm -fr "qtimageformats-everywhere-src-$QT"
tar xf "qtimageformats-everywhere-src-$QT.tar.xz"
cd "qtimageformats-everywhere-src-$QT"
mkdir build
cd build
"$INSTALLDIR/bin/qt-configure-module" .. -- -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DFEATURE_system_webp=ON
cmake --build . --parallel
ninja install
cd ../../
echo "Building Qt Wayland..."
rm -fr "qtwayland-everywhere-src-$QT"
tar xf "qtwayland-everywhere-src-$QT.tar.xz"
cd "qtwayland-everywhere-src-$QT"
mkdir build
cd build
"$INSTALLDIR/bin/qt-configure-module" .. -- -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DFEATURE_wayland_server=OFF
cmake --build . --parallel
ninja install
cd ../../
echo "Installing Qt Tools..."
rm -fr "qttools-everywhere-src-$QT"
tar xf "qttools-everywhere-src-$QT.tar.xz"
cd "qttools-everywhere-src-$QT"
# Force disable clang scanning, it gets very confused.
patch -u configure.cmake <<EOF
--- configure.cmake
+++ configure.cmake
@@ -14,12 +14,12 @@
# Presumably because 6.0 ClangConfig.cmake files are not good enough?
# In any case explicitly request a minimum version of 8.x for now, otherwise
# building with CMake will fail at compilation time.
-qt_find_package(WrapLibClang 8 PROVIDED_TARGETS WrapLibClang::WrapLibClang)
+#qt_find_package(WrapLibClang 8 PROVIDED_TARGETS WrapLibClang::WrapLibClang)
# special case end
-if(TARGET WrapLibClang::WrapLibClang)
- set(TEST_libclang "ON" CACHE BOOL "Required libclang version found." FORCE)
-endif()
+#if(TARGET WrapLibClang::WrapLibClang)
+# set(TEST_libclang "ON" CACHE BOOL "Required libclang version found." FORCE)
+#endif()
EOF
mkdir build
cd build
"$INSTALLDIR/bin/qt-configure-module" .. -- -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DFEATURE_assistant=OFF -DFEATURE_clang=OFF -DFEATURE_designer=ON -DFEATURE_kmap2qmap=OFF -DFEATURE_pixeltool=OFF -DFEATURE_pkg_config=OFF -DFEATURE_qev=OFF -DFEATURE_qtattributionsscanner=OFF -DFEATURE_qtdiag=OFF -DFEATURE_qtplugininfo=OFF
cmake --build . --parallel
ninja install
cd ../../
echo "Installing Qt Translations..."
rm -fr "qttranslations-everywhere-src-$QT"
tar xf "qttranslations-everywhere-src-$QT.tar.xz"
cd "qttranslations-everywhere-src-$QT"
mkdir build
cd build
"$INSTALLDIR/bin/qt-configure-module" .. -- -DCMAKE_PREFIX_PATH="$INSTALLDIR"
cmake --build . --parallel
ninja install
cd ../../
fi
echo "Building shaderc..."
rm -fr "shaderc-$SHADERC"
tar xf "shaderc-$SHADERC.tar.gz"
cd "shaderc-$SHADERC"
cmake "${CMAKE_COMMON[@]}" -DSHADERC_SKIP_TESTS=ON -DSHADERC_SKIP_EXAMPLES=ON -DSHADERC_SKIP_COPYRIGHT_CHECK=ON -B build -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
echo "Building SPIRV-Cross..."
cd SPIRV-Cross
rm -fr build
cmake "${CMAKE_COMMON[@]}" -DSPIRV_CROSS_SHARED=ON -DSPIRV_CROSS_STATIC=OFF -DSPIRV_CROSS_CLI=OFF -DSPIRV_CROSS_ENABLE_TESTS=OFF -DSPIRV_CROSS_ENABLE_GLSL=ON -DSPIRV_CROSS_ENABLE_HLSL=OFF -DSPIRV_CROSS_ENABLE_MSL=OFF -DSPIRV_CROSS_ENABLE_CPP=OFF -DSPIRV_CROSS_ENABLE_REFLECT=OFF -DSPIRV_CROSS_ENABLE_C_API=ON -DSPIRV_CROSS_ENABLE_UTIL=ON -B build -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
echo "Building cpuinfo..."
rm -fr "cpuinfo-$CPUINFO"
tar xf "cpuinfo-$CPUINFO.tar.gz"
cd "cpuinfo-$CPUINFO"
cmake "${CMAKE_COMMON[@]}" -DCPUINFO_LIBRARY_TYPE=shared -DCPUINFO_RUNTIME_TYPE=shared -DCPUINFO_LOG_LEVEL=error -DCPUINFO_LOG_TO_STDIO=ON -DCPUINFO_BUILD_TOOLS=OFF -DCPUINFO_BUILD_UNIT_TESTS=OFF -DCPUINFO_BUILD_MOCK_TESTS=OFF -DCPUINFO_BUILD_BENCHMARKS=OFF -DUSE_SYSTEM_LIBS=ON -B build -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
echo "Building discord-rpc..."
rm -fr "discord-rpc-$DISCORD_RPC"
tar xf "discord-rpc-$DISCORD_RPC.tar.gz"
cd "discord-rpc-$DISCORD_RPC"
cmake "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -B build -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
echo "Building lunasvg..."
rm -fr "lunasvg-$LUNASVG"
tar xf "lunasvg-$LUNASVG.tar.gz"
cd "lunasvg-$LUNASVG"
cmake "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -DLUNASVG_BUILD_EXAMPLES=OFF -B build -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
echo "Building soundtouch..."
rm -fr "soundtouch-$SOUNDTOUCH"
tar xf "soundtouch-$SOUNDTOUCH.tar.gz"
cd "soundtouch-$SOUNDTOUCH"
cmake "${CMAKE_COMMON[@]}" -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -B build -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
if [ "$SKIP_CLEANUP" != true ]; then
echo "Cleaning up..."
cd ..
rm -fr deps-build
fi

View File

@@ -6,7 +6,7 @@
set -e
if [ "$#" -lt 1 ]; then
echo "Syntax: $0 [-system-freetype] [-system-harfbuzz] [-system-libjpeg] [-system-libpng] [-system-libwebp] [-system-libzip] [-system-zstd] [-system-qt] [-skip-download] [-skip-cleanup] <output directory>"
echo "Syntax: $0 [-system-freetype] [-system-harfbuzz] [-system-libjpeg] [-system-libpng] [-system-libwebp] [-system-libzip] [-system-zstd] [-system-qt] [-skip-download] [-skip-cleanup] [-only-download] <output directory>"
exit 1
fi
@@ -51,6 +51,10 @@ for arg in "$@"; do
echo "Not removing build directory."
SKIP_CLEANUP=true
shift
elif [ "$arg" == "-only-download" ]; then
echo "Only downloading sources."
ONLY_DOWNLOAD=true
shift
fi
done
@@ -62,14 +66,14 @@ if [ "${INSTALLDIR:0:1}" != "/" ]; then
fi
FREETYPE=2.13.3
HARFBUZZ=10.0.1
HARFBUZZ=10.1.0
LIBBACKTRACE=86885d14049fab06ef8a33aac51664230ca09200
LIBJPEGTURBO=3.0.4
LIBPNG=1.6.44
LIBWEBP=1.4.0
LIBZIP=1.11.1
SDL2=2.30.9
QT=6.8.0
LIBZIP=1.11.2
SDL2=2.30.11
QT=6.8.1
ZSTD=1.5.6
CPUINFO=7524ad504fdcfcf75a18a133da6abd75c5d48053
@@ -95,7 +99,7 @@ fi
cat > SHASUMS <<EOF
baf8aebd22002b762d803ba0e1e389b6b4415159334e9d34bba1a938f6de8ce6 $LIBBACKTRACE.tar.gz
24b574f71c87a763f50704bbb630cbe38298d544a1f890f099a4696b1d6beba4 SDL2-$SDL2.tar.gz
8b8d4aef2038533da814965220f88f77d60dfa0f32685f80ead65e501337da7f SDL2-$SDL2.tar.gz
e1351218d270db49c3dddcba04fb2153b09731ea3fa6830e423f5952f44585be cpuinfo-$CPUINFO.tar.gz
3eea5ccce6670c126282f1ba4d32c19d486db49a1a5cbfb8d6f48774784d310c discord-rpc-$DISCORD_RPC.tar.gz
3998b024b0d442614a9ee270e76e018bb37a17b8c6941212171731123cbbcac7 lunasvg-$LUNASVG.tar.gz
@@ -116,7 +120,7 @@ if [ "$SKIP_HARFBUZZ" != true ]; then
curl -C - -L -o "harfbuzz-$HARFBUZZ.tar.gz" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/$HARFBUZZ.tar.gz"
fi
cat >> SHASUMS <<EOF
e7358ea86fe10fb9261931af6f010d4358dac64f7074420ca9bc94aae2bdd542 harfbuzz-$HARFBUZZ.tar.gz
c758fdce8587641b00403ee0df2cd5d30cbea7803d43c65fddd76224f7b49b88 harfbuzz-$HARFBUZZ.tar.gz
EOF
fi
if [ "$SKIP_LIBJPEG" != true ]; then
@@ -148,7 +152,7 @@ if [ "$SKIP_LIBZIP" != true ]; then
curl -C - -L -O "https://github.com/nih-at/libzip/releases/download/v$LIBZIP/libzip-$LIBZIP.tar.xz"
fi
cat >> SHASUMS <<EOF
721e0e4e851073b508c243fd75eda04e4c5006158a900441de10ce274cc3b633 libzip-$LIBZIP.tar.xz
5d471308cef4c4752bbcf973d9cd37ba4cb53739116c30349d4764ba1410dfc1 libzip-$LIBZIP.tar.xz
EOF
fi
if [ "$SKIP_ZSTD" != true ]; then
@@ -170,12 +174,12 @@ if [ "$SKIP_QT" != true ]; then
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtwayland-everywhere-src-$QT.tar.xz"
fi
cat >> SHASUMS <<EOF
1bad481710aa27f872de6c9f72651f89a6107f0077003d0ebfcc9fd15cba3c75 qtbase-everywhere-src-$QT.tar.xz
595bf8557b91e1f8ebc726f1e09868a3c7e610ff5045068f2d4ea2428c49a5d4 qtimageformats-everywhere-src-$QT.tar.xz
cf7a593d5e520f8177240610d9e55d5b75b0887fe5f385554ff64377f1646199 qtsvg-everywhere-src-$QT.tar.xz
403115d8268503c6cc6e43310c8ae28eb9e605072a5d04e4a2de8b6af39981f7 qttools-everywhere-src-$QT.tar.xz
84bf2b67c243cd0c50a08acd7bfa9df2b1965028511815c1b6b65a0687437cb6 qttranslations-everywhere-src-$QT.tar.xz
175758591638ebf1c6fbb66ac11c7fa0eb8d4ed52e9243cc59075d06a6a2060a qtwayland-everywhere-src-$QT.tar.xz
40b14562ef3bd779bc0e0418ea2ae08fa28235f8ea6e8c0cb3bce1d6ad58dcaf qtbase-everywhere-src-$QT.tar.xz
138cc2909aa98f5ff7283e36eb3936eb5e625d3ca3b4febae2ca21d8903dd237 qtimageformats-everywhere-src-$QT.tar.xz
3d0de73596e36b2daa7c48d77c4426bb091752856912fba720215f756c560dd0 qtsvg-everywhere-src-$QT.tar.xz
9d43d409be08b8681a0155a9c65114b69c9a3fc11aef6487bb7fdc5b283c432d qttools-everywhere-src-$QT.tar.xz
635a6093e99152243b807de51077485ceadd4786d4acb135b9340b2303035a4a qttranslations-everywhere-src-$QT.tar.xz
2226fbde4e2ddd12f8bf4b239c8f38fd706a54e789e63467dfddc77129eca203 qtwayland-everywhere-src-$QT.tar.xz
EOF
fi
@@ -188,6 +192,11 @@ if [ "$SKIP_DOWNLOAD" != true ]; then
fi
fi
# Only downloading sources?
if [ "$ONLY_DOWNLOAD" == true ]; then
exit 0
fi
echo "Building libbacktrace..."
rm -fr "libbacktrace-$LIBBACKTRACE"
tar xf "$LIBBACKTRACE.tar.gz"

View File

@@ -37,16 +37,16 @@ if [ "${INSTALLDIR:0:1}" != "/" ]; then
fi
FREETYPE=2.13.3
HARFBUZZ=10.0.1
SDL2=2.30.9
HARFBUZZ=10.1.0
SDL2=2.30.11
ZSTD=1.5.6
LIBPNG=1.6.44
LIBJPEGTURBO=3.0.4
LIBWEBP=1.4.0
LIBZIP=1.11.1
FFMPEG=7.0.2
LIBZIP=1.11.2
FFMPEG=7.1
MOLTENVK=1.2.9
QT=6.8.0
QT=6.8.1
CPUINFO=7524ad504fdcfcf75a18a133da6abd75c5d48053
DISCORD_RPC=144f3a3f1209994d8d9e8a87964a989cb9911c1e
@@ -73,22 +73,28 @@ CMAKE_ARCH_X64=-DCMAKE_OSX_ARCHITECTURES="x86_64"
CMAKE_ARCH_ARM64=-DCMAKE_OSX_ARCHITECTURES="arm64"
CMAKE_ARCH_UNIVERSAL=-DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"
# SBOM generation appears to be broken on MacOS, and I can't be arsed to debug it.
CMAKE_COMMON_QT=(
-DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"
-DQT_GENERATE_SBOM=OFF
)
cat > SHASUMS <<EOF
0550350666d427c74daeb85d5ac7bb353acba5f76956395995311a9c6f063289 freetype-$FREETYPE.tar.xz
e7358ea86fe10fb9261931af6f010d4358dac64f7074420ca9bc94aae2bdd542 harfbuzz-$HARFBUZZ.tar.gz
c758fdce8587641b00403ee0df2cd5d30cbea7803d43c65fddd76224f7b49b88 harfbuzz-$HARFBUZZ.tar.gz
60c4da1d5b7f0aa8d158da48e8f8afa9773c1c8baa5d21974df61f1886b8ce8e libpng-$LIBPNG.tar.xz
99130559e7d62e8d695f2c0eaeef912c5828d5b84a0537dcb24c9678c9d5b76b libjpeg-turbo-$LIBJPEGTURBO.tar.gz
61f873ec69e3be1b99535634340d5bde750b2e4447caa1db9f61be3fd49ab1e5 libwebp-$LIBWEBP.tar.gz
721e0e4e851073b508c243fd75eda04e4c5006158a900441de10ce274cc3b633 libzip-$LIBZIP.tar.xz
24b574f71c87a763f50704bbb630cbe38298d544a1f890f099a4696b1d6beba4 SDL2-$SDL2.tar.gz
5d471308cef4c4752bbcf973d9cd37ba4cb53739116c30349d4764ba1410dfc1 libzip-$LIBZIP.tar.xz
8b8d4aef2038533da814965220f88f77d60dfa0f32685f80ead65e501337da7f SDL2-$SDL2.tar.gz
8c29e06cf42aacc1eafc4077ae2ec6c6fcb96a626157e0593d5e82a34fd403c1 zstd-$ZSTD.tar.gz
8646515b638a3ad303e23af6a3587734447cb8fc0a0c064ecdb8e95c4fd8b389 ffmpeg-$FFMPEG.tar.xz
40973d44970dbc83ef302b0609f2e74982be2d85916dd2ee7472d30678a7abe6 ffmpeg-$FFMPEG.tar.xz
f415a09385030c6510a936155ce211f617c31506db5fbc563e804345f1ecf56e v$MOLTENVK.tar.gz
1bad481710aa27f872de6c9f72651f89a6107f0077003d0ebfcc9fd15cba3c75 qtbase-everywhere-src-$QT.tar.xz
595bf8557b91e1f8ebc726f1e09868a3c7e610ff5045068f2d4ea2428c49a5d4 qtimageformats-everywhere-src-$QT.tar.xz
cf7a593d5e520f8177240610d9e55d5b75b0887fe5f385554ff64377f1646199 qtsvg-everywhere-src-$QT.tar.xz
403115d8268503c6cc6e43310c8ae28eb9e605072a5d04e4a2de8b6af39981f7 qttools-everywhere-src-$QT.tar.xz
84bf2b67c243cd0c50a08acd7bfa9df2b1965028511815c1b6b65a0687437cb6 qttranslations-everywhere-src-$QT.tar.xz
40b14562ef3bd779bc0e0418ea2ae08fa28235f8ea6e8c0cb3bce1d6ad58dcaf qtbase-everywhere-src-$QT.tar.xz
138cc2909aa98f5ff7283e36eb3936eb5e625d3ca3b4febae2ca21d8903dd237 qtimageformats-everywhere-src-$QT.tar.xz
3d0de73596e36b2daa7c48d77c4426bb091752856912fba720215f756c560dd0 qtsvg-everywhere-src-$QT.tar.xz
9d43d409be08b8681a0155a9c65114b69c9a3fc11aef6487bb7fdc5b283c432d qttools-everywhere-src-$QT.tar.xz
635a6093e99152243b807de51077485ceadd4786d4acb135b9340b2303035a4a qttranslations-everywhere-src-$QT.tar.xz
e1351218d270db49c3dddcba04fb2153b09731ea3fa6830e423f5952f44585be cpuinfo-$CPUINFO.tar.gz
3eea5ccce6670c126282f1ba4d32c19d486db49a1a5cbfb8d6f48774784d310c discord-rpc-$DISCORD_RPC.tar.gz
3998b024b0d442614a9ee270e76e018bb37a17b8c6941212171731123cbbcac7 lunasvg-$LUNASVG.tar.gz
@@ -301,7 +307,7 @@ patch -u src/tools/macdeployqt/shared/shared.cpp <<EOF
// Platforminputcontext plugins if QtGui is in use
EOF
cmake -B build "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL" -DFEATURE_dbus=OFF -DFEATURE_framework=OFF -DFEATURE_icu=OFF -DFEATURE_opengl=OFF -DFEATURE_sql=OFF -DFEATURE_gssapi=OFF -DFEATURE_system_png=ON -DFEATURE_system_jpeg=ON -DFEATURE_system_zlib=ON -DFEATURE_system_freetype=ON -DFEATURE_system_harfbuzz=ON
cmake -B build "${CMAKE_COMMON[@]}" "${CMAKE_COMMON_QT[@]}" -DFEATURE_dbus=OFF -DFEATURE_framework=OFF -DFEATURE_icu=OFF -DFEATURE_opengl=OFF -DFEATURE_sql=OFF -DFEATURE_gssapi=OFF -DFEATURE_system_png=ON -DFEATURE_system_jpeg=ON -DFEATURE_system_zlib=ON -DFEATURE_system_freetype=ON -DFEATURE_system_harfbuzz=ON
make -C build "-j$NPROCS"
make -C build install
cd ..
@@ -312,7 +318,7 @@ tar xf "qtsvg-everywhere-src-$QT.tar.xz"
cd "qtsvg-everywhere-src-$QT"
mkdir build
cd build
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL"
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}" "${CMAKE_COMMON_QT[@]}"
make "-j$NPROCS"
make install
cd ../..
@@ -323,7 +329,7 @@ tar xf "qtimageformats-everywhere-src-$QT.tar.xz"
cd "qtimageformats-everywhere-src-$QT"
mkdir build
cd build
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL" -DFEATURE_system_webp=ON
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}" "${CMAKE_COMMON_QT[@]}" -DFEATURE_system_webp=ON
make "-j$NPROCS"
make install
cd ../..
@@ -334,7 +340,7 @@ tar xf "qttools-everywhere-src-$QT.tar.xz"
cd "qttools-everywhere-src-$QT"
mkdir build
cd build
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL" -DFEATURE_assistant=OFF -DFEATURE_clang=OFF -DFEATURE_designer=ON -DFEATURE_kmap2qmap=OFF -DFEATURE_linguist=ON -DFEATURE_pixeltool=OFF -DFEATURE_pkg_config=OFF -DFEATURE_qev=OFF -DFEATURE_qtattributionsscanner=OFF -DFEATURE_qtdiag=OFF -DFEATURE_qtplugininfo=OFF
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}" "${CMAKE_COMMON_QT[@]}" -DFEATURE_assistant=OFF -DFEATURE_clang=OFF -DFEATURE_designer=ON -DFEATURE_kmap2qmap=OFF -DFEATURE_linguist=ON -DFEATURE_pixeltool=OFF -DFEATURE_pkg_config=OFF -DFEATURE_qev=OFF -DFEATURE_qtattributionsscanner=OFF -DFEATURE_qtdiag=OFF -DFEATURE_qtplugininfo=OFF
make "-j$NPROCS"
make install
cd ../..
@@ -345,7 +351,7 @@ tar xf "qttranslations-everywhere-src-$QT.tar.xz"
cd "qttranslations-everywhere-src-$QT"
mkdir build
cd build
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL"
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}" "${CMAKE_COMMON_QT[@]}"
make "-j$NPROCS"
make install
cd ../..

View File

@@ -46,14 +46,14 @@ echo INSTALLDIR=%INSTALLDIR%
cd "%BUILDDIR%"
set FREETYPE=2.13.3
set HARFBUZZ=10.0.1
set HARFBUZZ=10.1.0
set LIBJPEGTURBO=3.0.4
set LIBPNG=1644
set QT=6.8.0
set QT=6.8.1
set QTMINOR=6.8
set SDL2=2.30.9
set SDL2=2.30.11
set WEBP=1.4.0
set LIBZIP=1.11.1
set LIBZIP=1.11.2
set ZLIB=1.3.1
set ZLIBSHORT=131
set ZSTD=1.5.6
@@ -68,20 +68,20 @@ set DXCOMPILER=1.8.2407.12
set DXAGILITY=1.614.1
call :downloadfile "freetype-%FREETYPE%.tar.gz" "https://download.savannah.gnu.org/releases/freetype/freetype-%FREETYPE%.tar.gz" 5c3a8e78f7b24c20b25b54ee575d6daa40007a5f4eea2845861c3409b3021747 || goto error
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip" 8adf9f5a4b6022aa2744f45c89ce347df46fea8403e99f01d650b11c417d0aa8 || goto error
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip" f93ff7ec6f2fcb9242256976a7e6d1da2588b5e57a559fb71a025b74bd1f5539 || goto error
call :downloadfile "lpng%LIBPNG%.zip" "https://download.sourceforge.net/libpng/lpng%LIBPNG%.zip" 7d7571a1faa1898b69888716dfdea0e4d466f1a5cf518e6aa626df2242bbadbe || goto error
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 99130559e7d62e8d695f2c0eaeef912c5828d5b84a0537dcb24c9678c9d5b76b || goto error
call :downloadfile "SDL2-%SDL2%.zip" "https://github.com/libsdl-org/SDL/releases/download/release-%SDL2%/SDL2-%SDL2%.zip" ec855bcd815b4b63d0c958c42c2923311c656227d6e0c1ae1e721406d346444b || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" c3b41915341d853b6374cf93f1fcced2c8e4be9360f29c656960e1d0d15046a3 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 809081a7bdf7e48262fbe9437e4e756df6ad2649433e803c4040026e650d7c91 || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 89f1ef4595f68c3d34c63a7c1c4ce475e701e103f0473f3fd0718a2e5234de6e || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" 3f813f49d6d28c532dc4b104084f60ff382337f184698fcd6e70ab9efad977c1 || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 91c33d9946279c9c613b02e52a33df610cc01d13ea6e321b4c4d8ee708b9a03e || goto error
call :downloadfile "SDL2-%SDL2%.zip" "https://github.com/libsdl-org/SDL/releases/download/release-%SDL2%/SDL2-%SDL2%.zip" a0b3e7ac5f708042683ff0f22e069bdf75563540c615f9854ecc9bc8913e2488 || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" e22d997bd15b795a176c8da62c8c1da0a674eb534e02f7c01ca507bf11bce0c3 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 247a0a58039275a5a4fb499a600a90f66dc6e00321bb6f86a9b8d8020344d853 || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 57bd332e5550ff70a852560c591b786b6ba587c5e41cb5ef91038d82db137ab9 || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" c65a89140f5d68137ffec67d631ec97002fb37077d9b4eb4ee45cbec39b1c38a || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 30a8e7773e1f274557e049a97f158b808f344247da03ae5240e4956c81d51cd5 || goto error
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" 61f873ec69e3be1b99535634340d5bde750b2e4447caa1db9f61be3fd49ab1e5 || goto error
call :downloadfile "libzip-%LIBZIP%.tar.gz" "https://github.com/nih-at/libzip/releases/download/v%LIBZIP%/libzip-%LIBZIP%.tar.gz" c0e6fa52a62ba11efd30262290dc6970947aef32e0cc294ee50e9005ceac092a || goto error
call :downloadfile "libzip-%LIBZIP%.tar.gz" "https://github.com/nih-at/libzip/releases/download/v%LIBZIP%/libzip-%LIBZIP%.tar.gz" 6b2a43837005e1c23fdfee532b78f806863e412d2089b9c42b49ab08cbcd7665 || goto error
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://zlib.net/zlib%ZLIBSHORT%.zip" 72af66d44fcc14c22013b46b814d5d2514673dda3d115e64b690c1ad636e7b17 || goto error
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 3b1c3b46e416d36931efd34663122d7f51b550c87f74de2d38249516fe7d8be5 || goto error
call :downloadfile "zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" https://github.com/facebook/zstd/commit/fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch 675f144b11f8ab2424b64bed8ccdca5d3f35b9326046fa7a883925dd180f0651 || goto error
call :downloadfile "zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" https://github.com/facebook/zstd/commit/fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch 8df152f4969b308546306c074628de761f0b80265de7de534e3822fab22d7535 || goto error
call :downloadfile "cpuinfo-%CPUINFO%.zip" "https://github.com/pytorch/cpuinfo/archive/%CPUINFO%.zip" 13146ae7983d767a678dd01b0d6af591e77cec82babd41264b9164ab808d7d41 || goto error
call :downloadfile "discord-rpc-%DISCORD_RPC%.zip" "https://github.com/stenzek/discord-rpc/archive/%DISCORD_RPC%.zip" 61e185e75d37b360c314125bcdf4697192d15e2d5209db3306ed6cd736d508b3 || goto error

View File

@@ -44,14 +44,14 @@ set "PATH=%PATH%;%INSTALLDIR%\bin"
cd "%BUILDDIR%"
set FREETYPE=2.13.3
set HARFBUZZ=10.0.1
set HARFBUZZ=10.1.0
set LIBJPEGTURBO=3.0.4
set LIBPNG=1644
set QT=6.8.0
set QT=6.8.1
set QTMINOR=6.8
set SDL2=2.30.9
set SDL2=2.30.11
set WEBP=1.4.0
set LIBZIP=1.11.1
set LIBZIP=1.11.2
set ZLIB=1.3.1
set ZLIBSHORT=131
set ZSTD=1.5.6
@@ -66,20 +66,20 @@ set DXCOMPILER=1.8.2407.12
set DXAGILITY=1.614.1
call :downloadfile "freetype-%FREETYPE%.tar.gz" "https://download.savannah.gnu.org/releases/freetype/freetype-%FREETYPE%.tar.gz" 5c3a8e78f7b24c20b25b54ee575d6daa40007a5f4eea2845861c3409b3021747 || goto error
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip" 8adf9f5a4b6022aa2744f45c89ce347df46fea8403e99f01d650b11c417d0aa8 || goto error
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip" f93ff7ec6f2fcb9242256976a7e6d1da2588b5e57a559fb71a025b74bd1f5539 || goto error
call :downloadfile "lpng%LIBPNG%.zip" "https://download.sourceforge.net/libpng/lpng%LIBPNG%.zip" 7d7571a1faa1898b69888716dfdea0e4d466f1a5cf518e6aa626df2242bbadbe || goto error
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 99130559e7d62e8d695f2c0eaeef912c5828d5b84a0537dcb24c9678c9d5b76b || goto error
call :downloadfile "SDL2-%SDL2%.zip" "https://github.com/libsdl-org/SDL/releases/download/release-%SDL2%/SDL2-%SDL2%.zip" ec855bcd815b4b63d0c958c42c2923311c656227d6e0c1ae1e721406d346444b || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" c3b41915341d853b6374cf93f1fcced2c8e4be9360f29c656960e1d0d15046a3 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 809081a7bdf7e48262fbe9437e4e756df6ad2649433e803c4040026e650d7c91 || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 89f1ef4595f68c3d34c63a7c1c4ce475e701e103f0473f3fd0718a2e5234de6e || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" 3f813f49d6d28c532dc4b104084f60ff382337f184698fcd6e70ab9efad977c1 || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 91c33d9946279c9c613b02e52a33df610cc01d13ea6e321b4c4d8ee708b9a03e || goto error
call :downloadfile "SDL2-%SDL2%.zip" "https://github.com/libsdl-org/SDL/releases/download/release-%SDL2%/SDL2-%SDL2%.zip" a0b3e7ac5f708042683ff0f22e069bdf75563540c615f9854ecc9bc8913e2488 || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" e22d997bd15b795a176c8da62c8c1da0a674eb534e02f7c01ca507bf11bce0c3 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 247a0a58039275a5a4fb499a600a90f66dc6e00321bb6f86a9b8d8020344d853 || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 57bd332e5550ff70a852560c591b786b6ba587c5e41cb5ef91038d82db137ab9 || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" c65a89140f5d68137ffec67d631ec97002fb37077d9b4eb4ee45cbec39b1c38a || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 30a8e7773e1f274557e049a97f158b808f344247da03ae5240e4956c81d51cd5 || goto error
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" 61f873ec69e3be1b99535634340d5bde750b2e4447caa1db9f61be3fd49ab1e5 || goto error
call :downloadfile "libzip-%LIBZIP%.tar.gz" "https://github.com/nih-at/libzip/releases/download/v%LIBZIP%/libzip-%LIBZIP%.tar.gz" c0e6fa52a62ba11efd30262290dc6970947aef32e0cc294ee50e9005ceac092a || goto error
call :downloadfile "libzip-%LIBZIP%.tar.gz" "https://github.com/nih-at/libzip/releases/download/v%LIBZIP%/libzip-%LIBZIP%.tar.gz" 6b2a43837005e1c23fdfee532b78f806863e412d2089b9c42b49ab08cbcd7665 || goto error
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://zlib.net/zlib%ZLIBSHORT%.zip" 72af66d44fcc14c22013b46b814d5d2514673dda3d115e64b690c1ad636e7b17 || goto error
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 3b1c3b46e416d36931efd34663122d7f51b550c87f74de2d38249516fe7d8be5 || goto error
call :downloadfile "zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" https://github.com/facebook/zstd/commit/fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch 675f144b11f8ab2424b64bed8ccdca5d3f35b9326046fa7a883925dd180f0651 || goto error
call :downloadfile "zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" https://github.com/facebook/zstd/commit/fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch 8df152f4969b308546306c074628de761f0b80265de7de534e3822fab22d7535 || goto error
call :downloadfile "cpuinfo-%CPUINFO%.zip" "https://github.com/pytorch/cpuinfo/archive/%CPUINFO%.zip" 13146ae7983d767a678dd01b0d6af591e77cec82babd41264b9164ab808d7d41 || goto error
call :downloadfile "discord-rpc-%DISCORD_RPC%.zip" "https://github.com/stenzek/discord-rpc/archive/%DISCORD_RPC%.zip" 61e185e75d37b360c314125bcdf4697192d15e2d5209db3306ed6cd736d508b3 || goto error

View File

@@ -0,0 +1,13 @@
--- a/CMakeLists.txt 2024-12-29 21:34:43.219279282 +1000
+++ b/CMakeLists.txt 2024-12-29 21:34:59.495612349 +1000
@@ -3047,10 +3047,6 @@
listtostr(EXTRA_CFLAGS _EXTRA_CFLAGS)
set(EXTRA_CFLAGS ${_EXTRA_CFLAGS})
-if(USE_GCC OR USE_CLANG)
- string(REGEX REPLACE "(^| )-I" "\\1 -isystem" EXTRA_CFLAGS "${EXTRA_CFLAGS}")
-endif()
-
# Compat helpers for the configuration files
if(EXISTS "${PROJECT_SOURCE_DIR}/VERSION.txt")

View File

@@ -0,0 +1,15 @@
#!/usr/bin/env bash
if [ "$#" -ne 1 ]; then
echo "Syntax: $0 <commit range, start..end>"
exit 1
fi
IFS="
"
printf "## Commits\n"
for i in $(git log --oneline --reverse "$1"); do
printf -- "- %s\n" "$i"
done

View File

@@ -0,0 +1,21 @@
#! /usr/bin/env bash
# autogenerated by linuxdeploy
# make sure errors in sourced scripts will cause this script to stop
set -e
this_dir="$(readlink -f "$(dirname "$0")")"
# generated by linuxdeploy-plugin-qt
# try to make Qt apps more "native looking" on Gtk-based desktops, if possible
# see https://github.com/AppImage/AppImageKit/issues/977#issue-462374883
case "${XDG_CURRENT_DESKTOP}" in
*GNOME*|*gnome*|*XFCE*)
export QT_QPA_PLATFORMTHEME=gtk3
;;
esac
exec "$this_dir"/AppRun.wrapped "$@"

View File

@@ -0,0 +1,29 @@
#!/usr/bin/env bash
REQUIRED_GLIBC_VERSION="__REQ_GLIBC_VERSION__"
this_dir="$(readlink -f "$(dirname "$0")")"
APPBIN="${this_dir}/usr/bin/__APPNAME__"
RUNTIME_DIR="${this_dir}/libc-runtime"
LOADER_BIN="${this_dir}/usr/bin/ld-linux"
GLIBC_VERSION=$(ldd --version | head -1 | sed -e 's/.* \([0-9.]\)/\1/')
echo "Detected glibc version ${GLIBC_VERSION}."
if [[ -z "${GLIBC_VERSION}" || ! "${GLIBC_VERSION}" < "${REQUIRED_GLIBC_VERSION}" ]]; then
echo "Using system libc/libstdc++."
exec "${APPBIN}" "$@"
fi
echo "Using bundled libc/libstdc++ from ${RUNTIME_DIR}."
if [ -z "$LD_LIBRARY_PATH" ]; then
export LD_LIBRARY_PATH="${RUNTIME_DIR}"
else
export LD_LIBRARY_PATH="${RUNTIME_DIR}:${LD_LIBRARY_PATH}"
fi
exec "${LOADER_BIN}" "${APPBIN}" "$@"

View File

@@ -0,0 +1,81 @@
#!/usr/bin/env bash
set -e
function retry_command {
# Package servers tend to be unreliable at times..
# Retry a bunch of times.
local RETRIES=10
for i in $(seq 1 "$RETRIES"); do
"$@" && break
if [ "$i" == "$RETRIES" ]; then
echo "Command \"$@\" failed after ${RETRIES} retries."
exit 1
fi
done
}
this_dir="$(readlink -f "$(dirname "$0")")"
if [ "$#" -ne 5 ]; then
echo "Syntax: $0 <path to AppDir> <.deb arch> <triple> <ubuntu mirror> <binary to run>"
echo "e.g. $0 DuckStation.AppDir amd64 x86_64-linux-gnu https://archive.ubuntu.com/ubuntu/ duckstation-qt"
exit 1
fi
APPDIR=$1
DEBARCH=$2
TRIPLE=$3
MIRROR=$4
APPNAME=$5
LIBC_PACKAGE_URL="${MIRROR}/pool/main/g/glibc/libc6_2.35-0ubuntu3.8_${DEBARCH}.deb"
LIBGCCS_PACKAGE_URL="${MIRROR}/pool/main/g/gcc-12/libgcc-s1_12.3.0-1ubuntu1~22.04_${DEBARCH}.deb"
LIBSTDCXX_PACKAGE_URL="${MIRROR}/pool/main/g/gcc-12/libstdc++6_12.3.0-1ubuntu1~22.04_${DEBARCH}.deb"
GLIBC_VERSION=2.35
mkdir "temp"
cd "temp"
retry_command wget -O "libc.deb" "${LIBC_PACKAGE_URL}"
retry_command wget -O "libgccs.deb" "${LIBGCCS_PACKAGE_URL}"
retry_command wget -O "libstdc++.deb" "${LIBSTDCXX_PACKAGE_URL}"
dpkg -x "libc.deb" .
dpkg -x "libgccs.deb" .
dpkg -x "libstdc++.deb" .
# Copy everything into AppDir
RUNTIME="${APPDIR}/libc-runtime"
mkdir -p "${RUNTIME}"
# libc.so.6 and friends
cd "lib/${TRIPLE}"
cp -v * "${RUNTIME}"
cd ../../
# libstdc++
cd "usr/lib/${TRIPLE}"
cp -v * "${RUNTIME}" || true
cd ../../..
# done with temps now
cd ..
rm -fr temp
# Not risking mixing resolvers...
cd "${RUNTIME}"
rm -vf libnss_*
# Move ld-linux.so.2 into the binary directory so we can preserve arg0's directory
mv -v "ld-linux-"*.so.* "${APPDIR}/usr/bin/ld-linux"
# Set up the replacement apprun script
cd "${APPDIR}"
rm -f AppRun.wrapped
cp "${this_dir}/inject-libc-apprun.sh" AppRun.wrapped
sed -i -e "s/__APPNAME__/${APPNAME}/" AppRun.wrapped
sed -i -e "s/__REQ_GLIBC_VERSION__/${GLIBC_VERSION}/" AppRun.wrapped
echo Done.

View File

@@ -127,8 +127,8 @@ DEPLOY_PLATFORM_THEMES="1" \
QMAKE="$DEPSDIR/bin/qmake" \
NO_STRIP="1" \
$LINUXDEPLOY --plugin qt --appdir="$OUTDIR" --executable="$BUILDDIR/bin/duckstation-qt" ${EXTRA_LIBS_ARGS[@]} \
--desktop-file="$ROOTDIR/scripts/org.duckstation.DuckStation.desktop" \
--icon-file="$ROOTDIR/scripts/org.duckstation.DuckStation.png" \
--desktop-file="$ROOTDIR/scripts/packaging/org.duckstation.DuckStation.desktop" \
--icon-file="$ROOTDIR/scripts/packaging/org.duckstation.DuckStation.png" \
echo "Copying resources into AppDir..."
cp -a "$BUILDDIR/bin/resources" "$OUTDIR/usr/bin"

View File

@@ -0,0 +1,334 @@
#!/usr/bin/env bash
# SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
# SPDX-License-Identifier: CC-BY-NC-ND-4.0
SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}")
function retry_command {
# Package servers tend to be unreliable at times..
# Retry a bunch of times.
local RETRIES=10
for i in $(seq 1 "$RETRIES"); do
"$@" && break
if [ "$i" == "$RETRIES" ]; then
echo "Command \"$@\" failed after ${RETRIES} retries."
exit 1
fi
done
}
if [ "$1" == "-inject-libc" ]; then
echo "Injecting libc/libstdc++"
INJECT_LIBC=true
shift
fi
if [ "$#" -ne 5 ]; then
echo "Syntax: $0 [-inject-libc] <target arch> <path to build directory> <deps prefix> <chroot dir> <output name>"
exit 1
fi
ARCH=$1
BUILDDIR=$2
DEPSDIR=$3
CHROOTDIR=$4
NAME=$5
BINARY=duckstation-qt
APPDIRNAME=DuckStation.AppDir
STRIP=llvm-strip
TRIPLE="${ARCH}-linux-gnu"
declare -a SYSLIBS=(
"libatk-1.0.so.0"
"libatk-bridge-2.0.so.0"
"libatspi.so.0"
"libblkid.so.1"
"libbrotlicommon.so.1"
"libbrotlidec.so.1"
"libbsd.so.0"
"libcairo-gobject.so.2"
"libcairo.so.2"
"libcap.so.2"
"libcrypto.so.3"
"libcurl.so.4"
"libdatrie.so.1"
"libdbus-1.so.3"
"libdeflate.so.0"
"libepoxy.so.0"
"libffi.so.8"
"libgcrypt.so.20"
"libgdk-3.so.0"
"libgdk_pixbuf-2.0.so.0"
"libgio-2.0.so.0"
"libglib-2.0.so.0"
"libgmodule-2.0.so.0"
"libgnutls.so.30"
"libgobject-2.0.so.0"
"libgraphite2.so.3"
"libgssapi_krb5.so.2"
"libgtk-3.so.0"
"libhogweed.so.6"
"libidn2.so.0"
"libjbig.so.0"
"libk5crypto.so.3"
"libkeyutils.so.1"
"libkrb5.so.3"
"libkrb5support.so.0"
"liblber-2.5.so.0"
"libldap-2.5.so.0"
"liblz4.so.1"
"liblzma.so.5"
"libmd.so.0"
"libmount.so.1"
"libnettle.so.8"
"libnghttp2.so.14"
"libp11-kit.so.0"
"libpango-1.0.so.0"
"libpangocairo-1.0.so.0"
"libpangoft2-1.0.so.0"
"libpcre2-16.so.0"
"libpcre2-8.so.0"
"libpcre.so.3"
"libpixman-1.so.0"
"libpsl.so.5"
"librtmp.so.1"
"libsasl2.so.2"
"libselinux.so.1"
"libssh.so.4"
"libssl.so.3"
"libsystemd.so.0"
"libtasn1.so.6"
"libtiff.so.5"
"libudev.so.1"
"libunistring.so.2"
"libXau.so.6"
"libxcb-cursor.so.0"
"libxcb-glx.so.0"
"libxcb-icccm.so.4"
"libxcb-image.so.0"
"libxcb-keysyms.so.1"
"libxcb-randr.so.0"
"libxcb-render.so.0"
"libxcb-render-util.so.0"
"libxcb-shape.so.0"
"libxcb-shm.so.0"
"libxcb-sync.so.1"
"libxcb-util.so.1"
"libxcb-xfixes.so.0"
"libxcb-xkb.so.1"
"libXcomposite.so.1"
"libXcursor.so.1"
"libXdamage.so.1"
"libXdmcp.so.6"
"libXext.so.6"
"libXfixes.so.3"
"libXinerama.so.1"
"libXi.so.6"
"libxkbcommon.so.0"
"libxkbcommon-x11.so.0"
"libXrandr.so.2"
"libXrender.so.1"
)
declare -a DEPLIBS=(
"libbacktrace.so.0"
"libfreetype.so.6"
"libharfbuzz.so"
"libjpeg.so.62"
"libpng16.so.16"
"libSDL2-2.0.so.0"
"libsharpyuv.so.0"
"libwebpdemux.so.2"
"libwebpmux.so.3"
"libwebp.so.7"
"libzip.so.5"
"libzstd.so.1"
"libcpuinfo.so"
"libdiscord-rpc.so"
"liblunasvg.so"
"libshaderc_ds.so"
"libsoundtouch.so.2"
"libspirv-cross-c-shared.so.0"
#"libavcodec.so.61"
#"libavformat.so.61"
#"libavutil.so.59"
#"libswscale.so.8"
#"libswresample.so.5"
#"libva-drm.so.2"
#"libva.so.2"
)
declare -a QTLIBS=(
"libQt6Core.so.6"
"libQt6DBus.so.6"
"libQt6Gui.so.6"
"libQt6OpenGL.so.6"
"libQt6Svg.so.6"
"libQt6WaylandClient.so.6"
"libQt6WaylandEglClientHwIntegration.so.6"
"libQt6Widgets.so.6"
"libQt6XcbQpa.so.6"
)
declare -a QTPLUGINS=(
"plugins/iconengines"
"plugins/imageformats"
"plugins/platforminputcontexts"
"plugins/platforms"
"plugins/platformthemes"
"plugins/wayland-decoration-client"
"plugins/wayland-graphics-integration-client"
"plugins/wayland-shell-integration"
"plugins/xcbglintegrations"
)
set -e
IFS="
"
APPIMAGETOOL=./appimagetool-x86_64
APPIMAGERUNTIME=./runtime-${ARCH}
PATCHELF=patchelf
if [ ! -f "$APPIMAGETOOL" ]; then
retry_command wget -O "$APPIMAGETOOL" https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
chmod +x "$APPIMAGETOOL"
fi
if [ ! -f "$APPIMAGERUNTIME" ]; then
retry_command wget -O "$APPIMAGERUNTIME" https://github.com/stenzek/type2-runtime/releases/download/continuous/runtime-${ARCH}
fi
OUTDIR=$(realpath "./$APPDIRNAME")
rm -fr "$OUTDIR"
mkdir "$OUTDIR"
mkdir -p "$OUTDIR/usr/bin" "$OUTDIR/usr/lib"
echo "Copying binary and resources..."
cp -a "$BUILDDIR/bin/$BINARY" "$BUILDDIR/bin/resources" "$BUILDDIR/bin/translations" "$OUTDIR/usr/bin"
# Currently we leave the main binary unstripped, uncomment if this is not desired.
# NOTE: Strip must come before patchelf, otherwise shit breaks.
$STRIP "$OUTDIR/usr/bin/$BINARY"
# Patch RPATH so the binary goes hunting for shared libraries in the AppDir instead of system.
echo "Patching RPATH in ${BINARY}..."
patchelf --set-rpath '$ORIGIN/../lib' "$OUTDIR/usr/bin/$BINARY"
# Libraries we pull in from the system.
echo "Copying system libraries..."
for lib in "${SYSLIBS[@]}"; do
blib=$(basename "$lib")
echo "$CHROOTDIR/lib/$TRIPLE/$lib"
if [ -f "$CHROOTDIR/lib/$TRIPLE/$lib" ]; then
cp "$CHROOTDIR/lib/$TRIPLE/$lib" "$OUTDIR/usr/lib/$blib"
elif [ -f "$CHROOTDIR/usr/lib/$TRIPLE/$lib" ]; then
cp "$CHROOTDIR/usr/lib/$TRIPLE/$lib" "$OUTDIR/usr/lib/$blib"
elif [ -f "$CHROOTDIR/lib/$lib" ]; then
cp "$CHROOTDIR/lib/$lib" "$OUTDIR/usr/lib/$blib"
elif [ -f "$CHROOTDIR/usr/lib/$lib" ]; then
cp "$CHROOTDIR/usr/lib/$lib" "$OUTDIR/usr/lib/$blib"
else
echo "*** Failed to find '$blib'"
exit 1
fi
$STRIP $OUTDIR/usr/lib/$blib
done
echo "Copying local libraries..."
for lib in "${DEPLIBS[@]}"; do
blib=$(basename "$lib")
echo "$DEPSDIR/lib/$lib"
if [ -f "$DEPSDIR/lib/$lib" ]; then
cp "$DEPSDIR/lib/$lib" "$OUTDIR/usr/lib/$blib"
else
echo "*** Failed to find '$blib'"
exit 1
fi
$STRIP "$OUTDIR/usr/lib/$blib"
done
echo "Copying Qt libraries..."
for lib in "${QTLIBS[@]}"; do
cp -avL "$DEPSDIR/lib/$lib" "$OUTDIR/usr/lib"
$STRIP "$OUTDIR/usr/lib/$lib"
done
echo "Copying Qt plugins..."
mkdir -p $OUTDIR/usr/lib/plugins
for plugin in "${QTPLUGINS[@]}"; do
mkdir -p "$OUTDIR/usr/lib/$plugin"
cp -avL "$DEPSDIR/$plugin/"*.so "$OUTDIR/usr/lib/$plugin/"
done
for so in $(find $OUTDIR/usr/lib/plugins -iname '*.so'); do
# This is ../../ because it's usually plugins/group/name.so
echo "Patching RPATH in ${so}..."
patchelf --set-rpath '$ORIGIN/../..' "$so"
$STRIP "$so"
done
for so in $(find $OUTDIR/usr/lib -maxdepth 1); do
if [ -f "$so" ]; then
echo "Patching RPATH in ${so}"
patchelf --set-rpath '$ORIGIN' "$so"
fi
done
echo "Creating qt.conf..."
cat > "$OUTDIR/usr/bin/qt.conf" << EOF
[Paths]
Plugins = ../lib/plugins
EOF
# Copy desktop/icon
echo "Copying desktop/icon..."
mkdir -p "$OUTDIR/usr/share/applications"
mkdir -p "$OUTDIR/usr/share/icons/hicolor/512x512/apps"
cp -v "$SCRIPTDIR/../org.duckstation.DuckStation.desktop" "$OUTDIR/usr/share/applications"
cp -v "$SCRIPTDIR/../org.duckstation.DuckStation.png" "$OUTDIR/usr/share/icons/hicolor/512x512/apps"
ln -s "usr/share/applications/org.duckstation.DuckStation.desktop" "$OUTDIR"
ln -s "usr/share/icons/hicolor/512x512/apps/org.duckstation.DuckStation.png" "$OUTDIR"
# Generate AppStream meta-info.
echo "Generating AppStream metainfo..."
mkdir -p "$OUTDIR/usr/share/metainfo"
"$SCRIPTDIR/../generate-metainfo.sh" "$OUTDIR/usr/share/metainfo"
# Copy AppRun
cp "$SCRIPTDIR/apprun-cross.sh" "$OUTDIR/AppRun"
chmod +x "$OUTDIR/AppRun"
ln -s "usr/bin/$BINARY" "$OUTDIR/AppRun.wrapped"
# Copy in AppRun hooks.
echo "Copying AppRun hooks..."
mkdir -p "$OUTDIR/apprun-hooks"
for hookpath in "$SCRIPTDIR/apprun-hooks"/*; do
hookname=$(basename "$hookpath")
cp -v "$hookpath" "$OUTDIR/apprun-hooks/$hookname"
sed -i -e 's/exec /source "$this_dir"\/apprun-hooks\/"'"$hookname"'"\nexec /' "$OUTDIR/AppRun"
done
# Optionally inject libc
if [ "$INJECT_LIBC" == true ]; then
echo "Injecting libc/libc++..."
if [ "$ARCH" == "aarch64" ]; then
DEBARCH="arm64"
else
echo "Unknown arch for libc injection."
exit 1
fi
"$SCRIPTDIR/inject-libc.sh" "$OUTDIR" "$DEBARCH" "$TRIPLE" "https://ports.ubuntu.com" "$BINARY"
fi
echo "Generating AppImage..."
rm -f "$NAME.AppImage"
"$APPIMAGETOOL" -v --runtime-file "$APPIMAGERUNTIME" "$OUTDIR" "$NAME.AppImage"

View File

@@ -120,8 +120,8 @@ package() {
install -Dm755 scripts/packaging/duckstation-qt "${pkgdir}/usr/bin/duckstation-qt"
# install desktop file and icon
install -Dm644 scripts/${_desktopname}.desktop "${pkgdir}/usr/share/applications/${_desktopname}.desktop"
install -Dm644 scripts/${_desktopname}.png "${pkgdir}/usr/share/icons/hicolor/512x512/apps/${_desktopname}.png"
install -Dm644 scripts/packaging/${_desktopname}.desktop "${pkgdir}/usr/share/applications/${_desktopname}.desktop"
install -Dm644 scripts/packaging/${_desktopname}.png "${pkgdir}/usr/share/icons/hicolor/512x512/apps/${_desktopname}.png"
# install license
install -Dm644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"

View File

@@ -71,8 +71,8 @@ ninja -C build %{?_smp_mflags}
rm -fr %{buildroot}
ninja -C build install
install -Dm755 scripts/packaging/duckstation-qt %{buildroot}/usr/bin/duckstation-qt
install -Dm644 scripts/org.duckstation.DuckStation.png %{buildroot}/usr/share/icons/hicolor/512x512/apps/org.duckstation.DuckStation.png
install -Dm644 scripts/org.duckstation.DuckStation.desktop %{buildroot}/usr/share/applications/org.duckstation.DuckStation.desktop
install -Dm644 scripts/packaging/org.duckstation.DuckStation.png %{buildroot}/usr/share/icons/hicolor/512x512/apps/org.duckstation.DuckStation.png
install -Dm644 scripts/packaging/org.duckstation.DuckStation.desktop %{buildroot}/usr/share/applications/org.duckstation.DuckStation.desktop
%files
%license LICENSE

View File

@@ -26,7 +26,7 @@ build-options:
sources:
- type: git
url: "https://github.com/nih-at/libzip.git"
commit: "9c8b818a1de143a4a8ee445351fb8f92115e33e1"
commit: "64b62d6b1a686a1b0bac1b6b9dcb635be0499afb"
cleanup:
- /bin
- /include

View File

@@ -80,21 +80,21 @@ modules:
- "-DCMAKE_SHARED_LINKER_FLAGS_INIT=-fuse-ld=lld"
sources:
- type: dir
path: ../..
path: ../../..
post-install:
# Manually copy desktop file/metadata, it's not done as part of the regular build.
- >-
install -Dm644
"${FLATPAK_BUILDER_BUILDDIR}/scripts/org.duckstation.DuckStation.png"
"${FLATPAK_BUILDER_BUILDDIR}/scripts/packaging/org.duckstation.DuckStation.png"
"${FLATPAK_DEST}/share/icons/hicolor/512x512/apps/org.duckstation.DuckStation.png"
- >-
install -Dm644
"${FLATPAK_BUILDER_BUILDDIR}/scripts/org.duckstation.DuckStation.desktop"
"${FLATPAK_BUILDER_BUILDDIR}/scripts/packaging/org.duckstation.DuckStation.desktop"
"${FLATPAK_DEST}/share/applications/org.duckstation.DuckStation.desktop"
- >-
install -Dm644
"${FLATPAK_BUILDER_BUILDDIR}/scripts/flatpak/org.duckstation.DuckStation.metainfo.xml"
"${FLATPAK_BUILDER_BUILDDIR}/scripts/packaging/flatpak/org.duckstation.DuckStation.metainfo.xml"
"${FLATPAK_DEST}/share/metainfo/org.duckstation.DuckStation.metainfo.xml"
# Ensure ffmpeg-full mount point exists.

View File

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

View File

@@ -6,13 +6,12 @@ import subprocess
import multiprocessing
from functools import partial
def is_game_path(path):
idx = path.rfind('.')
if idx < 0:
return False
extension = path[idx + 1:].strip().lower()
return extension in ["cue", "chd"]
def is_game_path(path:str):
lpath = path.lower()
for extension in ["cue", "chd", "psxgpu", "psxgpu.zst", "psxgpu.xz"]:
if path.endswith(extension):
return True
return False
def run_regression_test(runner, destdir, dump_interval, frames, renderer, cargs, gamepath):
@@ -31,8 +30,10 @@ def run_regression_test(runner, destdir, dump_interval, frames, renderer, cargs,
return os.path.basename(gamepath)
def run_regression_tests(runner, gamedir, destdir, dump_interval, frames, parallel, renderer, cargs):
paths = glob.glob(gamedir + "/*.*", recursive=True)
def run_regression_tests(runner, gamedirs, destdir, dump_interval, frames, parallel, renderer, cargs):
paths = []
for gamedir in gamedirs:
paths += glob.glob(os.path.realpath(gamedir) + "/*.*", recursive=True)
gamepaths = list(filter(is_game_path, paths))
try:
@@ -64,7 +65,7 @@ def run_regression_tests(runner, gamedir, destdir, dump_interval, frames, parall
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Generate frame dump images for regression tests")
parser.add_argument("-runner", action="store", required=True, help="Path to DuckStation regression test runner")
parser.add_argument("-gamedir", action="store", required=True, help="Directory containing game images")
parser.add_argument("-gamedir", action="append", required=True, help="Directory containing game images")
parser.add_argument("-destdir", action="store", required=True, help="Base directory to dump frames to")
parser.add_argument("-dumpinterval", action="store", type=int, default=600, help="Interval to dump frames at")
parser.add_argument("-frames", action="store", type=int, default=36000, help="Number of frames to run")
@@ -86,7 +87,7 @@ if __name__ == "__main__":
if (args.cpu is not None):
cargs += ["-cpu", args.cpu]
if not run_regression_tests(args.runner, os.path.realpath(args.gamedir), os.path.realpath(args.destdir), args.dumpinterval, args.frames, args.parallel, args.renderer, cargs):
if not run_regression_tests(args.runner, args.gamedir, os.path.realpath(args.destdir), args.dumpinterval, args.frames, args.parallel, args.renderer, cargs):
sys.exit(1)
else:
sys.exit(0)

View File

@@ -4,6 +4,7 @@ add_executable(common-tests
gsvector_yuvtorgb_test.cpp
path_tests.cpp
rectangle_tests.cpp
sha256_tests.cpp
string_tests.cpp
)

View File

@@ -7,6 +7,7 @@
<ClCompile Include="file_system_tests.cpp" />
<ClCompile Include="path_tests.cpp" />
<ClCompile Include="rectangle_tests.cpp" />
<ClCompile Include="sha256_tests.cpp" />
<ClCompile Include="string_tests.cpp" />
<ClCompile Include="gsvector_yuvtorgb_test.cpp" />
</ItemGroup>

View File

@@ -8,5 +8,6 @@
<ClCompile Include="path_tests.cpp" />
<ClCompile Include="string_tests.cpp" />
<ClCompile Include="gsvector_yuvtorgb_test.cpp" />
<ClCompile Include="sha256_tests.cpp" />
</ItemGroup>
</Project>

View File

@@ -15,8 +15,8 @@ static void YUVToRGB_Vector(const std::array<s16, 64>& Crblk, const std::array<s
const GSVector4i addval = signed_output ? GSVector4i::cxpr(0) : GSVector4i::cxpr(0x80808080);
for (u32 y = 0; y < 8; y++)
{
const GSVector4i Cr = GSVector4i::loadl(&Crblk[(y / 2) * 8]).s16to32();
const GSVector4i Cb = GSVector4i::loadl(&Cbblk[(y / 2) * 8]).s16to32();
const GSVector4i Cr = GSVector4i::loadl<false>(&Crblk[(y / 2) * 8]).s16to32();
const GSVector4i Cb = GSVector4i::loadl<false>(&Cbblk[(y / 2) * 8]).s16to32();
const GSVector4i Y = GSVector4i::load<true>(&Yblk[y * 8]);
// BT.601 YUV->RGB coefficients, rounding formula from Mednafen.

View File

@@ -78,3 +78,59 @@ TEST(Rectangle, RelationalOperators)
ASSERT_FALSE(r1.eq(r2));
}
TEST(Rectangle, ValidRectangles)
{
static constexpr GSVector4i cases[] = {
GSVector4i::cxpr(1, 2, 3, 4),
GSVector4i::cxpr(-5, -10, -1, -2),
GSVector4i::cxpr(0, 0, 1, 1),
GSVector4i::cxpr(100, 200, 300, 400),
GSVector4i::cxpr(-1000, -2000, 500, 600),
GSVector4i::cxpr(5, 10, 6, 12),
GSVector4i::cxpr(-10, -20, -5, -15),
GSVector4i::cxpr(-5, 0, 5, 10),
GSVector4i::cxpr(-100, -200, 100, 200),
GSVector4i::cxpr(-1, -2, 0, 1),
};
for (GSVector4i tcase : cases)
{
ASSERT_TRUE(tcase.rvalid());
ASSERT_FALSE(tcase.rempty());
}
}
TEST(Rectangle, InvalidRectangles)
{
static constexpr GSVector4i cases[] = {
// left < right but not top < bottom
GSVector4i::cxpr(1, 4, 3, 2),
GSVector4i::cxpr(-5, -2, -1, -10),
GSVector4i::cxpr(0, 1, 1, 0),
GSVector4i::cxpr(100, 400, 300, 200),
GSVector4i::cxpr(-1000, 600, 500, -2000),
GSVector4i::cxpr(5, 12, 6, 10),
GSVector4i::cxpr(-10, -15, -5, -20),
GSVector4i::cxpr(-5, 10, 5, 0),
GSVector4i::cxpr(-100, 200, 100, -200),
GSVector4i::cxpr(-1, 1, 0, -2),
// not left < right but top < bottom
GSVector4i::cxpr(3, 2, 1, 4),
GSVector4i::cxpr(-1, -10, -5, -2),
GSVector4i::cxpr(1, 0, 0, 1),
GSVector4i::cxpr(300, 200, 100, 400),
GSVector4i::cxpr(500, -2000, -1000, 600),
GSVector4i::cxpr(6, 10, 5, 12),
GSVector4i::cxpr(-5, -20, -10, -15),
GSVector4i::cxpr(5, 0, -5, 10),
GSVector4i::cxpr(100, -200, -100, 200),
GSVector4i::cxpr(0, -2, -1, 1),
};
for (GSVector4i tcase : cases)
{
ASSERT_FALSE(tcase.rvalid());
ASSERT_TRUE(tcase.rempty());
}
}

View File

@@ -0,0 +1,34 @@
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
#include "common/sha256_digest.h"
#include <gtest/gtest.h>
TEST(SHA256Digest, Simple)
{
// https://github.com/B-Con/crypto-algorithms/blob/master/sha256_test.c
static constexpr const char text1[] = "abc";
static constexpr const char text2[] = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
static constexpr const char text3[] = "aaaaaaaaaa";
static constexpr SHA256Digest::Digest hash1 = {{0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40,
0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17,
0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}};
static constexpr SHA256Digest::Digest hash2 = {{0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26,
0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff,
0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1}};
static constexpr SHA256Digest::Digest hash3 = {{0xcd, 0xc7, 0x6e, 0x5c, 0x99, 0x14, 0xfb, 0x92, 0x81, 0xa1, 0xc7,
0xe2, 0x84, 0xd7, 0x3e, 0x67, 0xf1, 0x80, 0x9a, 0x48, 0xa4, 0x97,
0x20, 0x0e, 0x04, 0x6d, 0x39, 0xcc, 0xc7, 0x11, 0x2c, 0xd0}};
ASSERT_EQ(SHA256Digest::GetDigest(text1, std::size(text1) - 1), hash1);
ASSERT_EQ(SHA256Digest::GetDigest(text2, std::size(text2) - 1), hash2);
SHA256Digest ldigest;
for (u32 i = 0; i < 100000; i++)
ldigest.Update(text3, std::size(text3) - 1);
ASSERT_EQ(ldigest.Final(), hash3);
}

View File

@@ -33,3 +33,41 @@ TEST(StringUtil, EllipsiseInPlace)
StringUtil::EllipsiseInPlace(s, 10, "...");
ASSERT_EQ(s, "Hello");
}
TEST(StringUtil, Base64EncodeDecode)
{
struct TestCase
{
const char* hexString;
const char* base64String;
};
static const TestCase testCases[] = {
{"33326a6f646933326a68663937683732383368", "MzJqb2RpMzJqaGY5N2g3MjgzaA=="},
{"32753965333268756979386672677537366967723839683432703075693132393065755c5d0931325c335c31323439303438753839333272",
"MnU5ZTMyaHVpeThmcmd1NzZpZ3I4OWg0MnAwdWkxMjkwZXVcXQkxMlwzXDEyNDkwNDh1ODkzMnI="},
{"3332726a33323738676838666233326830393233386637683938323139", "MzJyajMyNzhnaDhmYjMyaDA5MjM4ZjdoOTgyMTk="},
{"9956967BE9C96E10B27FF8897A5B768A2F4B103CE934718D020FE6B5B770", "mVaWe+nJbhCyf/iJelt2ii9LEDzpNHGNAg/mtbdw"},
{"BC94251814827A5D503D62D5EE6CBAB0FD55D2E2FCEDBB2261D6010084B95DD648766D8983F03AFA3908956D8201E26BB09FE52B515A61A9E"
"1D3ADC207BD9E622128F22929CDED456B595A410F7168B0BA6370289E6291E38E47C18278561C79A7297C21D23C06BB2F694DC2F65FAAF994"
"59E3FC14B1FA415A3320AF00ACE54C00BE",
"vJQlGBSCel1QPWLV7my6sP1V0uL87bsiYdYBAIS5XdZIdm2Jg/A6+jkIlW2CAeJrsJ/"
"lK1FaYanh063CB72eYiEo8ikpze1Fa1laQQ9xaLC6Y3AonmKR445HwYJ4Vhx5pyl8IdI8BrsvaU3C9l+q+ZRZ4/wUsfpBWjMgrwCs5UwAvg=="},
{"192B42CB0F66F69BE8A5", "GStCyw9m9pvopQ=="},
{"38ABD400F3BB6960EB60C056719B5362", "OKvUAPO7aWDrYMBWcZtTYg=="},
{"776FAB27DC7F8DA86F298D55B69F8C278D53871F8CBCCF", "d2+rJ9x/jahvKY1Vtp+MJ41Thx+MvM8="},
{"B1ED3EA2E35EE69C7E16707B05042A", "se0+ouNe5px+FnB7BQQq"},
};
for (const TestCase& tc : testCases)
{
std::optional<std::vector<u8>> bytes = StringUtil::DecodeHex(tc.hexString);
ASSERT_TRUE(bytes.has_value());
std::string encoded_b64 = StringUtil::EncodeBase64(bytes.value());
ASSERT_EQ(encoded_b64, tc.base64String);
std::optional<std::vector<u8>> dbytes = StringUtil::DecodeBase64(tc.base64String);
ASSERT_TRUE(dbytes.has_value());
ASSERT_EQ(dbytes.value(), bytes.value());
}
}

View File

@@ -50,12 +50,18 @@ add_library(common
settings_interface.h
sha1_digest.cpp
sha1_digest.h
sha256_digest.cpp
sha256_digest.h
small_string.cpp
small_string.h
string_util.cpp
string_util.h
thirdparty/SmallVector.cpp
thirdparty/SmallVector.h
thirdparty/aes.cpp
thirdparty/aes.h
task_queue.cpp
task_queue.h
threading.cpp
threading.h
timer.cpp

View File

@@ -58,14 +58,17 @@ constexpr T PreviousPow2(T value)
value |= (value >> 1);
value |= (value >> 2);
value |= (value >> 4);
if constexpr (sizeof(T) >= 16)
if constexpr (sizeof(T) >= 2)
value |= (value >> 8);
if constexpr (sizeof(T) >= 32)
if constexpr (sizeof(T) >= 4)
value |= (value >> 16);
if constexpr (sizeof(T) >= 64)
if constexpr (sizeof(T) >= 8)
value |= (value >> 32);
return value - (value >> 1);
return (value >> 1) + 1;
}
/// NOTE: Undefined for values greater than (1 << BITS-1), i.e. 0x80000000 for 32-bit.
template<typename T>
constexpr T NextPow2(T value)
{
@@ -77,11 +80,11 @@ constexpr T NextPow2(T value)
value |= (value >> 1);
value |= (value >> 2);
value |= (value >> 4);
if constexpr (sizeof(T) >= 16)
if constexpr (sizeof(T) >= 2)
value |= (value >> 8);
if constexpr (sizeof(T) >= 32)
if constexpr (sizeof(T) >= 4)
value |= (value >> 16);
if constexpr (sizeof(T) >= 64)
if constexpr (sizeof(T) >= 8)
value |= (value >> 32);
value++;
return value;

View File

@@ -3,15 +3,17 @@
#include "assert.h"
#include "crash_handler.h"
#include <cstdio>
#include <cstdlib>
#include <mutex>
#if defined(_WIN32)
#ifdef _WIN32
#include "windows_headers.h"
#include <intrin.h>
#include <tlhelp32.h>
#endif
#include <mutex>
#ifdef __clang__
#pragma clang diagnostic ignored "-Winvalid-noreturn"
@@ -19,9 +21,8 @@
static std::mutex s_AssertFailedMutex;
static inline void FreezeThreads(void** ppHandle)
static HANDLE FreezeThreads()
{
#if defined(_WIN32)
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (hSnapshot != INVALID_HANDLE_VALUE)
{
@@ -43,17 +44,12 @@ static inline void FreezeThreads(void** ppHandle)
}
}
*ppHandle = (void*)hSnapshot;
#else
*ppHandle = nullptr;
#endif
return hSnapshot;
}
static inline void ResumeThreads(void* pHandle)
static void ResumeThreads(HANDLE hSnapshot)
{
#if defined(_WIN32)
HANDLE hSnapshot = (HANDLE)pHandle;
if (pHandle != INVALID_HANDLE_VALUE)
if (hSnapshot != INVALID_HANDLE_VALUE)
{
THREADENTRY32 threadEntry;
if (Thread32First(hSnapshot, &threadEntry))
@@ -73,21 +69,42 @@ static inline void ResumeThreads(void* pHandle)
}
CloseHandle(hSnapshot);
}
}
#else
#ifdef __ANDROID__
// Define as a weak symbol for ancient devices that don't have it.
extern "C" __attribute__((weak)) void android_set_abort_message(const char*);
#endif
[[noreturn]] ALWAYS_INLINE static void AbortWithMessage(const char* szMsg)
{
#ifndef __ANDROID__
std::fputs(szMsg, stderr);
CrashHandler::WriteDumpForCaller();
std::fputs("Aborting application.\n", stderr);
std::fflush(stderr);
std::abort();
#else
if (&android_set_abort_message)
android_set_abort_message(szMsg);
std::abort();
#endif
}
#endif // _WIN32
void Y_OnAssertFailed(const char* szMessage, const char* szFunction, const char* szFile, unsigned uLine)
{
std::lock_guard<std::mutex> guard(s_AssertFailedMutex);
void* pHandle;
FreezeThreads(&pHandle);
char szMsg[512];
std::snprintf(szMsg, sizeof(szMsg), "%s in function %s (%s:%u)\n", szMessage, szFunction, szFile, uLine);
#if defined(_WIN32)
std::unique_lock lock(s_AssertFailedMutex);
HANDLE pHandle = FreezeThreads();
SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
WriteConsoleA(GetStdHandle(STD_ERROR_HANDLE), szMsg, static_cast<DWORD>(std::strlen(szMsg)), NULL, NULL);
OutputDebugStringA(szMsg);
@@ -107,28 +124,22 @@ void Y_OnAssertFailed(const char* szMessage, const char* szFunction, const char*
CrashHandler::WriteDumpForCaller();
TerminateProcess(GetCurrentProcess(), 0xBAADC0DE);
}
#else
std::fputs(szMsg, stderr);
CrashHandler::WriteDumpForCaller();
std::fputs("Aborting application.\n", stderr);
std::fflush(stderr);
std::abort();
#endif
ResumeThreads(pHandle);
#else
AbortWithMessage(szMsg);
#endif
}
[[noreturn]] void Y_OnPanicReached(const char* szMessage, const char* szFunction, const char* szFile, unsigned uLine)
{
std::lock_guard<std::mutex> guard(s_AssertFailedMutex);
void* pHandle;
FreezeThreads(&pHandle);
char szMsg[512];
std::snprintf(szMsg, sizeof(szMsg), "%s in function %s (%s:%u)\n", szMessage, szFunction, szFile, uLine);
#if defined(_WIN32)
std::unique_lock guard(s_AssertFailedMutex);
HANDLE pHandle = FreezeThreads();
SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
WriteConsoleA(GetStdHandle(STD_ERROR_HANDLE), szMsg, static_cast<DWORD>(std::strlen(szMsg)), NULL, NULL);
OutputDebugStringA(szMsg);
@@ -145,13 +156,9 @@ void Y_OnAssertFailed(const char* szMessage, const char* szFunction, const char*
CrashHandler::WriteDumpForCaller();
TerminateProcess(GetCurrentProcess(), 0xBAADC0DE);
#else
std::fputs(szMsg, stderr);
CrashHandler::WriteDumpForCaller();
std::fputs("Aborting application.\n", stderr);
std::fflush(stderr);
std::abort();
#endif
ResumeThreads(pHandle);
#else
AbortWithMessage(szMsg);
#endif
}

View File

@@ -9,27 +9,31 @@ void Y_OnAssertFailed(const char* szMessage, const char* szFunction, const char*
[[noreturn]] void Y_OnPanicReached(const char* szMessage, const char* szFunction, const char* szFile, unsigned uLine);
#define Assert(expr) \
if (!(expr)) \
do \
{ \
Y_OnAssertFailed("Assertion failed: '" #expr "'", __FUNCTION__, __FILE__, __LINE__); \
}
if (!(expr)) \
Y_OnAssertFailed("Assertion failed: '" #expr "'", __FUNCTION__, __FILE__, __LINE__); \
} while (0)
#define AssertMsg(expr, msg) \
if (!(expr)) \
do \
{ \
Y_OnAssertFailed("Assertion failed: '" msg "'", __FUNCTION__, __FILE__, __LINE__); \
}
if (!(expr)) \
Y_OnAssertFailed("Assertion failed: '" msg "'", __FUNCTION__, __FILE__, __LINE__); \
} while (0)
#ifdef _DEBUG
#if defined(_DEBUG) || defined(_DEVEL)
#define DebugAssert(expr) \
if (!(expr)) \
do \
{ \
Y_OnAssertFailed("Debug assertion failed: '" #expr "'", __FUNCTION__, __FILE__, __LINE__); \
}
if (!(expr)) \
Y_OnAssertFailed("Debug assertion failed: '" #expr "'", __FUNCTION__, __FILE__, __LINE__); \
} while (0)
#define DebugAssertMsg(expr, msg) \
if (!(expr)) \
do \
{ \
Y_OnAssertFailed("Debug assertion failed: '" msg "'", __FUNCTION__, __FILE__, __LINE__); \
}
if (!(expr)) \
Y_OnAssertFailed("Debug assertion failed: '" msg "'", __FUNCTION__, __FILE__, __LINE__); \
} while (0)
#else
#define DebugAssert(expr)
#define DebugAssertMsg(expr, msg)
@@ -41,7 +45,7 @@ void Y_OnAssertFailed(const char* szMessage, const char* szFunction, const char*
// Kills the application, indicating a pure function call that should not have happened.
#define PureCall() Y_OnPanicReached("PureCall encountered", __FUNCTION__, __FILE__, __LINE__)
#ifdef _DEBUG
#if defined(_DEBUG) || defined(_DEVEL)
// Kills the application, indicating that code that was never supposed to be reached has been executed.
#define UnreachableCode() Y_OnPanicReached("Unreachable code reached", __FUNCTION__, __FILE__, __LINE__)
#else

View File

@@ -36,13 +36,16 @@
<ClInclude Include="scoped_guard.h" />
<ClInclude Include="settings_interface.h" />
<ClInclude Include="sha1_digest.h" />
<ClInclude Include="sha256_digest.h" />
<ClInclude Include="small_string.h" />
<ClInclude Include="heterogeneous_containers.h" />
<ClInclude Include="binary_reader_writer.h" />
<ClInclude Include="string_util.h" />
<ClInclude Include="thirdparty\aes.h" />
<ClInclude Include="thirdparty\SmallVector.h" />
<ClInclude Include="thirdparty\StackWalker.h" />
<ClInclude Include="threading.h" />
<ClInclude Include="task_queue.h" />
<ClInclude Include="timer.h" />
<ClInclude Include="types.h" />
<ClInclude Include="minizip_helpers.h" />
@@ -64,12 +67,15 @@
<ClCompile Include="perf_scope.cpp" />
<ClCompile Include="progress_callback.cpp" />
<ClCompile Include="sha1_digest.cpp" />
<ClCompile Include="sha256_digest.cpp" />
<ClCompile Include="small_string.cpp" />
<ClCompile Include="binary_reader_writer.cpp" />
<ClCompile Include="string_util.cpp" />
<ClCompile Include="thirdparty\aes.cpp" />
<ClCompile Include="thirdparty\SmallVector.cpp" />
<ClCompile Include="thirdparty\StackWalker.cpp" />
<ClCompile Include="threading.cpp" />
<ClCompile Include="task_queue.cpp" />
<ClCompile Include="timer.cpp" />
</ItemGroup>
<ItemGroup>

View File

@@ -50,6 +50,9 @@
<ClInclude Include="gsvector_nosimd.h" />
<ClInclude Include="ryml_helpers.h" />
<ClInclude Include="log_channels.h" />
<ClInclude Include="sha256_digest.h" />
<ClInclude Include="thirdparty\aes.h" />
<ClInclude Include="task_queue.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="small_string.cpp" />
@@ -78,6 +81,9 @@
<ClCompile Include="dynamic_library.cpp" />
<ClCompile Include="binary_reader_writer.cpp" />
<ClCompile Include="gsvector.cpp" />
<ClCompile Include="sha256_digest.cpp" />
<ClCompile Include="thirdparty\aes.cpp" />
<ClCompile Include="task_queue.cpp" />
</ItemGroup>
<ItemGroup>
<Natvis Include="bitfield.natvis" />

View File

@@ -367,7 +367,7 @@ void CrashHandler::WriteDumpForCaller()
LogCallstack(0, nullptr);
}
#else
#elif !defined(__ANDROID__)
bool CrashHandler::Install(CleanupHandler cleanup_handler)
{

View File

@@ -141,6 +141,6 @@ private:
void AddPrefixFmtArgs(fmt::string_view fmt, fmt::format_args args);
void AddSuffixFmtArgs(fmt::string_view fmt, fmt::format_args args);
Type m_type = Type::None;
std::string m_description;
Type m_type = Type::None;
};

View File

@@ -12,13 +12,14 @@
#define PREFIX ""
#endif
// clang-format off
#if defined(__x86_64__)
asm("\t.global " PREFIX "fastjmp_set\n"
"\t.global " PREFIX "fastjmp_jmp\n"
"\t.text\n"
"\t" PREFIX "fastjmp_set:"
R"(
"\t.global " PREFIX "fastjmp_jmp\n"
"\t.text\n"
"\t" PREFIX "fastjmp_set:" R"(
movq 0(%rsp), %rax
movq %rsp, %rdx # fixup stack pointer, so it doesn't include the call to fastjmp_set
addq $8, %rdx
@@ -33,8 +34,7 @@ asm("\t.global " PREFIX "fastjmp_set\n"
xorl %eax, %eax
ret
)"
"\t" PREFIX "fastjmp_jmp:"
R"(
"\t" PREFIX "fastjmp_jmp:" R"(
movl %esi, %eax
movq 0(%rdi), %rdx # actually rip
movq 8(%rdi), %rbx
@@ -95,20 +95,20 @@ asm(
"\t.global " PREFIX "fastjmp_jmp\n"
"\t.text\n"
"\t" PREFIX "fastjmp_set:" R"(
vstmia r0!, {d8-d15}
stmia r0!, {r4-r14}
fmrx r1, fpscr
str r1, [r0]
mov r0, #0
bx lr
vstmia r0!, {d8-d15}
stmia r0!, {r4-r14}
fmrx r1, fpscr
str r1, [r0]
mov r0, #0
bx lr
)"
"\t" PREFIX "fastjmp_jmp:" R"(
vldmia r0!, {d8-d15}
ldmia r0!, {r4-r14}
vldmia r0!, {d8-d15}
ldmia r0!, {r4-r14}
ldr r0, [r0]
fmxr fpscr, r0
mov r0, r1
mov r0, r1
bx lr
)");
@@ -117,68 +117,69 @@ asm(
asm(
"\t.global " PREFIX "fastjmp_set\n"
"\t.global " PREFIX "fastjmp_jmp\n"
"\t.attribute arch, \"rv64gc\"\n"
"\t.text\n"
"\t.align 16\n"
"\t" PREFIX "fastjmp_set:" R"(
sd sp, 0(a0)
sd s0, 8(a0)
sd s1, 16(a0)
sd s2, 24(a0)
sd s3, 32(a0)
sd s4, 40(a0)
sd s5, 48(a0)
sd s6, 56(a0)
sd s7, 64(a0)
sd s8, 72(a0)
sd s9, 80(a0)
sd s10, 88(a0)
sd s11, 96(a0)
fsd fs0, 104(a0)
fsd fs1, 112(a0)
fsd fs2, 120(a0)
fsd fs3, 128(a0)
fsd fs4, 136(a0)
fsd fs5, 144(a0)
fsd fs6, 152(a0)
fsd fs7, 160(a0)
fsd fs8, 168(a0)
fsd fs9, 176(a0)
fsd fs10, 184(a0)
fsd fs11, 192(a0)
sd ra, 208(a0)
li a0, 0
jr ra
sd sp, 0(a0)
sd s0, 8(a0)
sd s1, 16(a0)
sd s2, 24(a0)
sd s3, 32(a0)
sd s4, 40(a0)
sd s5, 48(a0)
sd s6, 56(a0)
sd s7, 64(a0)
sd s8, 72(a0)
sd s9, 80(a0)
sd s10, 88(a0)
sd s11, 96(a0)
fsd fs0, 104(a0)
fsd fs1, 112(a0)
fsd fs2, 120(a0)
fsd fs3, 128(a0)
fsd fs4, 136(a0)
fsd fs5, 144(a0)
fsd fs6, 152(a0)
fsd fs7, 160(a0)
fsd fs8, 168(a0)
fsd fs9, 176(a0)
fsd fs10, 184(a0)
fsd fs11, 192(a0)
sd ra, 208(a0)
li a0, 0
jr ra
)"
".align 16\n"
"\t" PREFIX "fastjmp_jmp:" R"(
ld ra, 208(a0)
fld fs11, 192(a0)
fld fs10, 184(a0)
fld fs9, 176(a0)
fld fs8, 168(a0)
fld fs7, 160(a0)
fld fs6, 152(a0)
fld fs5, 144(a0)
fld fs4, 136(a0)
fld fs3, 128(a0)
fld fs2, 120(a0)
fld fs1, 112(a0)
fld fs0, 104(a0)
ld s11, 96(a0)
ld s10, 88(a0)
ld s9, 80(a0)
ld s8, 72(a0)
ld s7, 64(a0)
ld s6, 56(a0)
ld s5, 48(a0)
ld s4, 40(a0)
ld s3, 32(a0)
ld s2, 24(a0)
ld s1, 16(a0)
ld s0, 8(a0)
ld sp, 0(a0)
mv a0, a1
jr ra
ld ra, 208(a0)
fld fs11, 192(a0)
fld fs10, 184(a0)
fld fs9, 176(a0)
fld fs8, 168(a0)
fld fs7, 160(a0)
fld fs6, 152(a0)
fld fs5, 144(a0)
fld fs4, 136(a0)
fld fs3, 128(a0)
fld fs2, 120(a0)
fld fs1, 112(a0)
fld fs0, 104(a0)
ld s11, 96(a0)
ld s10, 88(a0)
ld s9, 80(a0)
ld s8, 72(a0)
ld s7, 64(a0)
ld s6, 56(a0)
ld s5, 48(a0)
ld s4, 40(a0)
ld s3, 32(a0)
ld s2, 24(a0)
ld s1, 16(a0)
ld s0, 8(a0)
ld sp, 0(a0)
mv a0, a1
jr ra
)");
@@ -188,4 +189,6 @@ asm(
#endif
// clang-format on
#endif // __WIN32

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