Commit Graph
67 Commits
Author SHA1 Message Date
Fabian WoltermannandClaude Opus 5.5 8ef44a411d ImGui frame profiler overlay, and Vulkan per-draw descriptor set churn fix (#7694)
* chore: vendor ImPlot library

Adds ImPlot as a build dependency, to be used for the upcoming ImGui
frame profiler overlay's frametime graph and pie chart.

* feat: add ImGui frame profiler overlay

Replaces the old text-dump frame profile display (-profile_frame_time)
with a runtime-toggleable ImGui/ImPlot overlay showing average/median
frametime, a scrolling frametime graph, and a pie chart of the top
contributors to frame time. Toggled via a new "Frame Profiler Overlay"
option, which also seeds from -profile_frame_time for backward
compatibility and now drives frame profiling collection at runtime
instead of only at startup.

* Add graphics and Vulkan debug stats to ImGui profiler overlay

- Integrated per-backend diagnostic counters into the ImGui frame profiler overlay, triggered by `-gr_debug`.
- Consolidated and cleaned up Vulkan rendering state and descriptor management for compatibility with ImGui's Vulkan pipeline.
- Enabled uniform buffer and draw statistics reporting for enhanced performance insights during debugging.

* Update ImPlot to v1.1 WIP and improve internal consistency

- Adjust copyright notices for extended license coverage (2025-2026).
- Modernize constants with `constexpr` replacements, improving type safety and clarity.
- Enforce `nullptr` usage over `NULL` throughout, aligning with modern C++ practices.
- Add various enhancements to ImPlot legends, markers, and axes behavior.
- Introduce additional helper methods for time handling and timestamp calculations.
- Address UI and typo improvements in comments and documentation, refining accuracy.

* Refactor frame profiler to use per-category self-time accumulation

- Introduced `accumulate_self_times` for single-pass exclusive time computation, improving performance and accuracy.
- Updated `FrameProfiler` and overlay snapshot logic to leverage `Category`'s stable `getId` and `getCount`.
- Replaced pie chart with a stacked bar for frame budget visualization, optimizing rendering cost.
- Cached `get_tid` and `get_pid` with thread-local storage to minimize syscall overhead.
- Added support for unit testing frame profiling functionality and included new test cases.
- Improved code comments and clarified documentation.

* Use dynamic uniform buffers to stop per-draw descriptor set churn in Vulkan

The Material and PerDraw descriptor sets were reallocated and fully rewritten on
essentially every draw call. model_draw_list::render_buffer rebinds ModelData with
a fresh uniform buffer offset for each queued draw, and that offset was part of the
Material set's memoization key, so the cache in VulkanDrawManager::applyMaterial
missed every time - taking a frame-pool allocation, a full template write, the
16-entry material texture resolution and a vkUpdateDescriptorSets with it.
GenericData/Matrices did the same to the PerDraw set. renderShadowDraw was worse
still: all three sets allocated and rewritten per shadow draw, with no memoization
at all.

A large asteroid field (Solaris m21) measured 2566 descriptor sets and 19107
descriptor writes per frame at 1606 model draws, and grew an extra descriptor pool
chunk every frame.

Declare the bindings whose offset moves per draw - MaterialBinding::ModelData,
MaterialBinding::ShadowMapData, PerDrawBinding::GenericData and
PerDrawBinding::Matrices - as eUniformBufferDynamic. DescriptorWriter::setBuffer
now splits a dynamic binding's offset out of the descriptor, writing
{buffer, 0, range} and stashing the offset for vkCmdBindDescriptorSets'
pDynamicOffsets, so an offset-only change leaves the set's contents identical and
the memoization caches start hitting. Shader sources are unchanged.

VulkanStateTracker::bindDescriptorSet now compares the dynamic offsets as well as
the set handle. This is required, not an optimization: the common case is now the
same set rebound with a new offset, and the old handle-only redundancy check would
have skipped that bind and fed every draw the previous draw's uniforms.

renderShadowDraw memoizes its three sets the way applyMaterial does. It does not
invalidate applyMaterial's caches - those record what a set contains, the shadow
pass allocates its own sets rather than overwriting theirs, and it binds through
the state tracker, so the next material cache hit still rebinds correctly.

Also switch allocateFrameSet to the non-allocating allocateDescriptorSets overload;
the vector-returning one heap-allocated once per set, thousands of times a frame.
MAX_SETS_PER_POOL stays at 1024 - the per-frame pool growth it used to log was a
symptom of the churn, and one chunk now covers the scene outright.

Measured on that mission in a Debug build, A/B on the same tree with and without
this change:

  descriptor sets/frame  @ ~1370 draws  2566   -> 250-345
  descriptor writes/frame                19107 -> ~1700-2300
  median frametime                       92.9/83.6 ms -> 72.0/66.5 ms
  Render Buffer (profiler overlay)       24.68 ms (30.8%) -> 12.73 ms (18.4%)
  Build Shadow Map                       5.44 ms -> off the top-5 entirely

Release builds already inlined most of this away and are unchanged, as expected.
Verified with the validation layers (sync validation enabled): no new VUIDs versus
the same build without the change.

Co-Authored-By: Claude Opus 5 <[email protected]>

* Refactor Vulkan descriptor set binding to reduce dynamic offset churn

- Consolidated dynamic descriptor offset logic into `DescriptorWriter::bindSets`, replacing repetitive `vkCmdBindDescriptorSets` patterns across Vulkan modules.
- Eliminated redundant descriptor binding operations for Material and PerDraw sets by centralizing logic in `bindSets`.
- Simplified descriptors by directly splitting offset changes from descriptor contents, avoiding unnecessary updates.
- Updated comments and documentation to align with the new approach while maintaining reference consistency.
- Applied optimizations across Vulkan modules (`VulkanPostProcessing`, `VulkanDescriptorManager`, etc.) to reduce per-draw overhead and improve readability.

* Enable primitive restart for supported topologies in Vulkan pipeline

- Added `topologySupportsPrimitiveRestart` to determine restart eligibility for each topology.
- Updated `primitiveRestartEnable` to be conditionally set based on topology, addressing compatibility issues with Metal/MoltenVK.
- Prevented crash scenarios on macOS by ensuring pipelines are valid for strip/fan topologies requiring primitive restart.

* Enable VK_KHR_portability_subset for compatibility

* Replace exception with sentinel for non-dynamic Vulkan descriptor bindings

- Introduced `DYNAMIC_SLOT_INVALID` sentinel to replace the throw in `dynamic_offset_slot` for MSVC compatibility.
- Added `static_assert` checks to validate binding constants, ensuring compile-time validation for dynamic offsets.
- Updated comments to clarify design rationale and avoid potential misuse.

* Add memory statistics and tracking to profiler overlay

* fix ci issues

* Add OpenGL memory statistics to the profiler overlay

The memory panel showed no texture bytes and no geometry bytes under
OpenGL. Only the depth renderbuffers went into the render target group.
All three groups now give a value.

Textures: GL_texture_bytes_used holds the bytes of every live texture
cache slot. opengl_texture_release_bytes() removes the bytes of a slot at
each site that drops its texture data. The bitmap render targets record
the bytes of their color texture.

Geometry: the unused GL_vertex_data_in global becomes
GL_geometry_bytes_used, which counts only vertex and index buffers. This
matches the geometry group of the Vulkan backend.
gr_opengl_delete_buffer() sets the size of the buffer to 0, because
opengl_destroy_all_buffers() calls it a second time for a buffer that the
game already deleted.

Render targets: three new functions add the scene textures, the
post-processing textures, and the shadow map to the group. They sum the
bytes at the moment of the call from the textures that exist, thus they
need no bookkeeping at the create and delete sites.

Co-Authored-By: Claude Opus 5 <[email protected]>

* Fix profiler overlay crash on a category that is not a static

The category registry kept a Category pointer for each id. The comment said that all categories
are global statics, but that is not correct. The Lua API tracing_category constructs a Category
and copies it into a script-owned object. The registry then kept a pointer to the dead temporary.
build_overlay_snapshot called getName() on that pointer, made an SCP_string from the garbage
char*, and the process stopped with SIGABRT.

The registry now keeps the name by value and never keeps a Category pointer. getById() becomes
getNameById(), which is all that build_overlay_snapshot needs. A copy of a Category keeps the id
of the original, which stays correct because the id only selects a name.

Add two tests: one shows that the name stays available after the Category object is dead, and one
drives the full path that failed, from processEvent to the overlay snapshot.

Co-Authored-By: Claude Opus 5 <[email protected]>

* Replace category pointers with IDs to prevent use-after-free

- Updated `trace_event` to store `category_id` instead of a pointer to prevent dangling references to category objects that may already be destroyed.
- Modified all references to category names to use `Category::getNameById()` instead of dereferencing pointers.
- Expanded memory statistics in the profiler overlay with new sound, Lua, and OS-level memory usage tracking.
- Added new tests to verify proper use of category IDs in frame profiling and event tracing.
- Improved memory safety and stability across tracing, profiling, and overlay systems.

* Refactor profiler overlay to use snapshot-based frame timing

* Address review feedback on the profiler overlay

Skip complete::end for a scope that did not start. This fixes a crash
when Lua turns the overlay on while a scope is open. Track the GPU begin
event so that turning the overlay off mid-scope still closes it.

Use XSTR 1936 and 1937 for the overlay option. Master now uses 1932
and 1933.

Remove the default value of dynamicOffsets in bindDescriptorSet. Use the
PerDraw binding constants in the PerDraw key.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>

* Use wall-clock frame time and read the history without a copy

The Avg and FPS line used traced self-time, which reads too high.
Measure the time between overlay frames instead. Draw the graph with
PlotLineG so the history deque needs no per-frame copy.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>

* Address second round of review feedback on the profiler overlay

- Make the category registry thread-safe and give categories with the
  same name one id, so the registry does not grow without limit.
- Add tests that toggle the profiler inside an open trace scope.
- Correct the next free XSTR id note to 1938.
- Use the existing Windows include block for psapi.h in osapi.cpp.
- Use list_range in ship_get_num_ships() and shorten some comments.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* Return size_t from Category::getCount() and tidy the registry code

- Use structured bindings and std::scoped_lock in the category registry.
- Return size_t from getCount() and update its callers and tests.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* Address third round of review feedback on the profiler overlay

- Move the overlay option strings to XSTR 1940 and 1941. The touch
  overlay on master uses 1936 to 1939.
- Give FrameProfiler the main thread ID when it is made. Before, it
  used the thread of the first event, which was a race.
- Let mouse motion go to the game while the pointer is over the
  overlay, so that mouse flight does not stop there.
- Find the dynamic bindings of the PerDraw key with
  dynamic_offset_slot(), as the other call sites do.
- Make disable_inside_open_scope count the GPU timestamp queries, so
  that it fails if end() does not close the GPU event.
- Make the copy test copy the category, not bind a reference.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* apply review suggestions

---------

Co-authored-by: Claude Opus 5 <[email protected]>
2026-11-11 08:16:33 +01:00
Mike Nelson 4d39287de1 LuaLS meta file generation (scripting.lua) (#6516) 2025-06-08 11:29:30 -04:00
Birk Magnussen d9b9863e2a Clang Tidy 2025-02-01 22:26:11 +01:00
Birk Magnussen 540d841f06 Remove any and variant libs 2025-02-01 13:26:28 +01:00
BMagnu 01bb406b3d Allow overriding low-level keypresses (#6174)
* Clean unneeded properties

* properly queue-ify keys

* Refactor key checking to use functions instead of globals

* Update hooks and cache checked-against key

* Documentation and Naming

* match tilde

* only remove control not debug
2024-05-31 14:53:39 +02:00
Goober5000 1403301b65 add variable to prevent any hooks from running until OnGameInit has run 2024-01-23 14:51:06 -05:00
BMagnu 43afcd5ea6 VR Lua interface (#5858)
* Allow lua to check whether VR is enabled

* Add global hook condition

* Add missing descriptionm
2023-12-04 20:39:26 +00:00
Birk Magnussen 3447b76736 Also change header 2023-11-05 22:23:06 +01:00
BMagnu 8731ad1448 Add option to deprecate hooks (#5184)
* Add hook deprecation to calls

* Deprecate hooks properly

* Change OnSplashScreen hook callig

* Check for deprecated hooks at script time

* include hooks directly

* Check deprecation for lua added hooks

* Write deprecation notice to docs

* rescope Target_version

* fix typo
2023-02-15 17:12:25 +09:00
BMagnu af1f0eaeca Rework Script Conditions (#4960)
* add skeleton for hook condition API

* Begin Scripting Hook refactor

* Program Hook Conditions for current new-style hooks

* Replace more hooks

* Fully transition global hooks

* Convert legacy hooks pt. 1

* Convert legacy hooks pt. 2

* Convert legacy hooks pt. 3

* Post-conversion cleanup

* restore parsing

* Add Documentation and fix parsing

* Fixup engine ingame hook adding

* Fixup engine ingame hook adding again

* Fix warnings

* Fix GCC unqualified template base lookup

* unqualified lookup v2

* Virtual Destrcutors

* Fix Clang

* Fix ship objp hook condition shadow

* Remove global hook include in ship.h

* Incorporate Feedback

* Incorporate Feedback 2

* Add revision to inline version specififer
2022-12-14 03:51:27 +09:00
Goober5000 8bc4064670 small hook refactor
Basically just changing some parameter names.
2022-09-11 15:07:17 -04:00
Fabian Woltermann a1b48d0a9e defer adding new scripting hooks until after hook processing is done 2022-09-01 18:30:48 +02:00
BMagnu 269bb1b221 Add scripting API and conditions for executing on server only (#4548)
* Add scripting API and conditions for executing on server only

* feedback
2022-08-18 21:13:05 +09:00
Goober5000 165db5d28b Merge pull request #4400 from Goober5000/lua_frame_cleanup
clean up Lua frame handling a bit
2022-08-12 21:29:20 -04:00
David Gibson 73736280f9 Clean up the lua stack after EvalStringWithReturn's function creation 2022-07-27 19:18:26 -05:00
Goober5000 826dfd01fc clean up Lua frame handling a bit
There's no need to keep all this infrastructure to run every frame for a barely used situation.  This cleans it up a bit and does the position reset in the actual drawString function.
2022-07-08 18:59:10 -04:00
Goober5000 9acbd9bc94 enhance ActiveActions to accommodate both old-style and new-style script hooks 2022-06-06 17:26:07 -04:00
Goober5000 3a4794305f Convert some Lua hooks to the new style to add documentation
This takes a few of the existing hooks and converts them to the new style of hook definition which can include more extensive documentation and enumeration of supported hook variables.

This is an updated version of #3151 to work with the latest codebase.

NOTE: Before this can be integrated into the codebase, it needs an implementation for `bool script_state::IsActiveAction(int hookId)` which apparently only has support for old-style script hooks.
2022-06-05 16:38:03 -04:00
Goober5000 69e0f66d4b fix up conditions for script hooks
For script hooks which use conditions, be more consistent about evaluating both objects involved, as well as evaluating the different types of objects.

Fixes #3874.
2022-04-29 22:37:30 -04:00
Goober5000 b0c3b4098e migrate and augment mission/state end hooks
1) migrate On Mission End and On State End to the new hook system
2) add On Mission About To End and On State About To End
2021-10-16 21:56:20 -04:00
PhantomHoover 84b25b52d7 Be smarter about when we try to run scripting hooks: don't even bother trying if no scripts are even registered to run on them. (#3538) 2021-07-02 22:50:53 -04:00
David Gibson 743989525b Implemented index caching for hooks refering to ship or weapon info objects. 2021-04-10 20:41:22 -05:00
David Gibson 5bca1417c2 Vectorized the hook condition lists and began chaching information inside the hook at creation to avoid string comparisons in play. CHC_VERSION, CHC_STATE, and CHC_APPLICATION converted. 2021-04-10 20:18:29 -05:00
asarium bb0631ab6e Support vararg specifiers in Lua documentation
This was the last thing that was missing for complete support of all
function parameter declarations.

To ensure parameter lists stay valid a unit test was added that will
validate the argument lists and cause the test to fail if they cannot be
parsed.
2020-10-12 17:59:57 +02:00
asarium f71a86f2db Use a stack for scripting hook variables
Previously, if a script called a function that called another scripting
hook, some hook variables might be removed. This was the case since
after executing the hook the code would remove the set hook variables
again. If these variables had the same name as previously set variables,
they would overwrite and corrupt the state the original script expected.

This was unexpected behavior for script writers so this puts values on a
stack and only adds or removes from the stack instead of overwriting
values. This should make the hook variable state consistent for scripts
even if scripting hooks are called indirectly.
2020-10-03 15:37:20 +02:00
asarium 492fe461b0 Allow overwriting hook variables
The previous version used the wrong function for the map and so values
added later were not written to the map and so not available to Lua.

This fixes that by using the simple array operator.
2020-09-03 20:24:22 +02:00
asarium 2303785717 Improve scripting hook variable system
The previous system was kind of hacky and made things a bit inflexible.
This improves that system quite a bit and also adds unit tests for the
hook variable functionality.
2020-08-29 10:27:41 +02:00
asarium b94f12092b Fix various issues of an unbalanced Lua stack
This fixes three issues where the Lua stack was not cleaned up properly:
- On hook execution, the return value was left on the stack
- For ADE initialization, the global tables were left on the stack
- In libRocket, a metatable was left on the stack
2020-08-11 09:45:25 +02:00
asarium 31dfa49ebc Capture Ade skip arguments locally
These variables can be used for changing the behavior of the ade_ API
functions. However, they apply to all the ade_get calls so if there is a
call to ade_get_args from an ade_get_args call then it will reuse the
previously set values and produce incorrect results.

This captures those variables as soon as possible and then resets them
so that subsequent calls start with the default values for those
variables.
2020-08-10 09:39:08 +02:00
asarium 33f3b72be1 Add comment about new hooks system to legacy hook list
Since the old system is deprecated it needs to be made obvious that new
hooks should not be added using that system.
2020-07-30 17:15:53 +02:00
asarium 4a6628e16f Unify and clean up Lua documentation generation
I added a pretty generic container structure for the scripting
documentation when adding JSON output. However, I did not use that new
structure for the HTML output since that was just too much work.

This moves the HTML output over to the new structure so now the
scripting API handling code is independent from how the resulting
documentation is generated. I also moved that code out of the main
scripting code which removes quite a lot of clutter in those files.

This is mostly a straight port of the old code with no significant
changes (except the changes to make it use the new data).
2020-06-13 16:46:26 +02:00
asarium ca27ae16f2 Use Antlr for generating argument list parser
This adds an Antlr grammar for parsing argument lists instead of using a
hand written parser. This allows to write much more complicated syntax
constructs and have all the code being auto-generated. It will also
produce a much more correct parser instead of having all those hacks in
the hand-written one.

This also adds (in addition to supporting the previous syntax) support
for function types along with support for them in HTML and JSON output
formats.

The ANTLR generated parser is included in source form so that it is not
necessary to have an ANTLR installation around if you are not going to
change the grammar. Also includes the necessary runtime code from Antlr.
2020-06-11 21:57:52 +02:00
m!m 25d16c3102 Merge pull request #2446 from asarium/feature/scriptingArgParsing
Add parser for scripting argument documentation
2020-06-07 12:06:28 +02:00
asarium d54d7d41e6 Output parameter information to JSON
Also fixes the parameter strings which currently could not be parsed by
the argument parser.
2020-06-06 23:45:36 +02:00
asarium 016c07dc3a Add feature to execute Lua coroutines at specific points
This adds a mechanism for running generic operations at specific points
of the frame execution. This can be used by any part of the code an not
just Lua since it simply executes std::functions. It also adds an
"execution context" concept that specifies in which situation an
operation should be executed.

This is then used by the Lua Coroutines code for resuming coroutines at
specific points instead of always when the awaited promise resolves.
2020-06-06 21:29:48 +02:00
asarium 04174e00f8 Ensure Lua functions are executed in correct state
This will ensure that Lua functions will always be executed in the
correct Lua state. Since we now have multiple threads (which are
different lua_State objects) it is possible that the current code could
execute a Lua function in the main state instead of the thread that is
currently executing. This can lead to weird behavior and probably also
to issues inside Lua.
2020-06-06 14:00:23 +02:00
asarium ebcf686cf7 Add Lua API for promises and async coroutines
This adds a Lua API for representing asynchronous operations and running
coroutines based on those operations comfortably. This is very similar
to features other languages have introduced such as C# or JavaScript. In
fact, the whole "promise" thing is derived from how JavaScript
represents these operations.

This is the initial and very basic system for supporting async
coroutines in Lua. There is no native support for running these
operations at specific points (they run whenever the awaited promise
resolved) or making sure they do not leak through different game states.
2020-05-24 12:36:01 +02:00
asarium 544029f66f Add capability to have a pure lua script
This adds the capability to have a Lua script that does not need to use
our table syntax at all but instead defines the hooks by calling API
functions. This also makes it possible to add hook functions at runtime
if the script requires that.

Also clean up some unused debug stuff.
2020-05-03 14:33:42 +02:00
asarium 1c12349990 Add extended scripting hook system
This moves towards defining the hooks in the code module that executes
them. Also provides the API necessary for better documentation of hooks.
This only covers a few hooks as a test and demonstration of the new API.
If no issues are found with this it can be extended in the future.
2020-04-13 14:45:19 +02:00
Goober5000 a7063152b7 add scripting hook for briefing stage 2020-02-17 00:58:56 -05:00
asarium b825f57bf4 Add scripting API support for model paths
This adds a scripting API for querying the paths of a model.
2019-12-14 09:15:44 +01:00
asarium 4ca589a61c Make Lua documentation generation more generic
This adds JSON as an additional scripting documentation output format.
This can be used by external tools to examine the scripting
documentation and generate interface declarations or documentation for
any language. The existing documentation code is left largely in place.
2019-12-01 12:53:51 +01:00
wookieejedi ea021c6fe3 Add On Goals Cleared Scripting Hook
Adds 'On Goals Cleared' hook variable for scripting system. Previosly there was not scripting or sexp method to determine if a ship had all of it's goals cleared.
2019-11-25 21:12:40 -05:00
Goober5000 8365f0abb7 add $On Subsystem Destroyed scripting hook
Implements the feature request from issue #610.

As an aside, this PR also patches the `ship_set_subsystem_strength` function (which is only used by the debug console and in the event you fire at your training instructor) to use the same code as the `set-subystem-strength` sexp.  This properly handles submodels blown off, sounds, etc.
2019-05-08 19:55:03 -04:00
wookieejedi 7dd1788aee Add 'On Waypoint Done' Hook
Adds 'On Waypoint Done' hook variable for scripting system.
2019-02-03 13:26:35 -05:00
asarium 211110d415 Add Lua state destruction event
This can be used by the various subsystems for cleaning up Lua
references before the Lua state is destroyed. This avoids having
dangling references to the Lua state which would cause segfaults later
on.

The first subsystem to use this is the dynamic SEXP system which had
dangling references due to keeping Lua references to the SEXP functions.

This fixes #1954.
2018-12-27 14:14:34 +01:00
TRBlount 30866afbd6 Add On Weapon Created Hook 2018-12-02 01:10:22 -07:00
asarium 651268eeea Fix rvalue reference issue in SetHookVar 2018-11-18 12:43:39 +01:00
wookieejedi 791e22bc1d Add On Ship Depart Conditional Hook 2018-10-18 17:50:22 -04:00
wookieejedi 9fcd96ff97 Adds Accept Mission Outcome as new Conditional Hook (#1893)
* Adds Accept Mission Outcome Event to Game Events

Adds Accept Mission Outcome Event to Game Events, so scritps and other things can be called only when a campaign mission is accepted.

* Fixed double entry

* Define CHA_CMISSIONACCEPT

Adds line to define new conditional hook, CHA_CMISSIONACCEPT

* Add flag_def_list for On Campaign Mission Accept

Adds the proper flag_def_list for "On Campaign Mission Accept" CHA_CMISSIONACCEPT

* Runs New Conditional Hook

Runs the new conditional hook for "On Campaign Mission Accept"

* Reverts event changes

* Reverts state changese

* Reverts post_event change
2018-10-08 18:13:02 +02:00