Commit Graph
2038 Commits
Author SHA1 Message Date
LuytenKy e76e844d02 Vulkan: Skip MSAA resolve when no deferred pass is active (#7854)
* stub check for msaa

* initialize viewport variables
2026-10-15 18:04:32 +02:00
BMagnu 88669e4518 Fix VR cursor issues and warn about crash hazard (#7868)
* Add warning for OpenXR toolkit

* Properly handle mouse position

* GCC 9 issue
2026-10-15 00:48:46 +00:00
BMagnu f6f1aac574 Fix fullscreen with resolutions not available for modesetting (#7867) 2026-10-15 02:01:11 +02:00
Fabian Woltermann 115491f8a9 Refactor RT shadow handling and Vulkan depth operations (#7685)
- Introduced `shadow_ray_params` to simplify ray origin and cull mask management.
- Shifted shadow ray origins to TLAS-relative space for improved precision and consistency, especially for cockpit rendering.
- Refactored cascade bind functions, adding `shadow_cascade_params_bind_deferred()` for consolidated offset/count handling in deferred lighting.
- Expanded TLAS to include cockpits and additional object types, ensuring parity with rasterized shadows.
- Introduced per-instance cull masks to address cockpit self-shadowing issues.
- Improved Vulkan depth isolation for cockpit rendering via backup/restore mechanism, ensuring correct depth sampling in later passes.
- Extracted reusable helper functions for cockpit rendering state logic.
2026-09-21 05:12:55 +02:00
Fabian Woltermann 74fc04f7af silly claude, that's not how shields work (#7785) 2026-09-15 06:28:06 +02:00
Goober5000 bd5972c0ec Merge pull request #7781 from Goober5000/fix/mem_leak
Fix three memory leaks and make the debug leak check accurate
2026-09-14 21:49:21 -04:00
Goober5000andClaude Opus 5 519e3aef21 Fix three memory leaks and make the debug leak check accurate
Report leaks after static destruction via _CRTDBG_LEAK_CHECK_DF instead of calling _CrtDumpMemoryLeaks() at the end of main(), which incorrectly reported every global container as a memory leak.

Also fix the three remaining real leaks which were discovered after all the noise was cleared up:
- Mc_point_list was never freed, because its atexit cleanup was only registered by code that no longer runs.  But the list was only a temporary array of pointers used while building the collision tree, so remove it and have model_collide_parse_bsp_defpoints() copy the vertices directly into the tree's point list.
- model_batch_buffer's Mem_alloc copy was never freed.  But the copy is actually not necessary, so remove it and pass Submodel_matrices directly.
- Goal_target_names strings were only freed when the next mission was parsed, so the last mission's names leaked at exit.  Hold them in SCP_vm_unique_ptr so they are freed with the vector.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-09-13 14:25:01 -04:00
Goober5000andClaude Opus 5 e2be023f84 Replace the Cockpit_active global with computed predicates
Cockpit_active was latched inside ship_render_player_ship(), which only
runs when Viewer_obj is non-null.  External, chase, warp-chase, topdown,
free-camera and dead views all null Viewer_obj, so the flag froze at its
last cockpit-view value and cockpitinactive HUD gauges vanished.  It was
also read before being written each frame (by the show-ship check and the
shadow helpers), so those decisions lagged a frame on any transition.

Replace it with three functions computed on demand:
- ship_cockpit_enabled(sip): the ship has a cockpit model and cockpits
  aren't disabled; used by the Show_ship_only_if_cockpits_enabled checks
- ship_render_player_cockpit(sip): the above, outside topdown view;
  replaces three duplicated copies of that expression
- ship_render_player_cockpit_active(): whether the viewer's cockpit is
  being rendered this frame; used by the HUD cockpit-view-choice checks

With the predicate correct, the VM_CHASE special cases added for #4804
are no longer needed and are removed.  In chase view, cockpitinactive
gauges now also respect pop-up state, No_ets, and setRenderOverride,
which the early return in HudGauge::canRender() used to bypass.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-09-11 23:39:05 -04:00
Goober5000andClaude Opus 5 1fdb67649c Clear cockpit depth mask each frame so lightshafts don't use a stale one (#7775)
Views that don't render the cockpit (external, chase, topdown, etc.) left
Cockpit_depth_texture holding the last cockpit-view frame, so the lightshaft
pass painted that silhouette.  Fixes #7568.

Co-authored-by: Claude Opus 5 <[email protected]>
2026-09-12 02:59:38 +02:00
Fabian WoltermannandClaude Opus 5 9ec157833b Add command-line option overrides to options system (#7561)
* Add command-line option overrides to options system

- Extend `OptionsManager` to support storing and displaying reasons for overrides.
- Update related code paths to prioritize command-line overrides, ensure correct option resolution, and display override details in the UI.
- Add unit tests for override behavior and round-trip validation.
- Remove unused legacy functions (`removeVSyncOption`, `removeWindowModeOption`) in favor of the new system.

* Add unit tests for `Graphics.Anisotropy` option validation with and without OpenGL

* Add support for associating command-line option names to `OptionsManager` overrides

- Update HDR, shadow rendering, and graphics API option overrides to include their respective command-line flag names.
- Refactor `Graphics.RenderAPI` to use the `GraphicsAPI` enum instead of raw integers for better type safety and clarity.
- Ensure Vulkan support logic and fallback behavior function correctly with the updated options system.
- Update unit tests to validate override functionality and enum-based API configuration.

* Remove unused `removeVSyncOption` function

* Apply the PR review feedback for the command-line option overrides

Delete the unit-test run artifacts that this branch committed by mistake, and
add .gitignore rules for the files that the unittests binary writes.

Give an override priority over an in-session edit again. The options UI now
shows a disabled control for an overridden option, and setConfigValue()
refuses an edit for an overridden key. Before this change, a save wrote the
edit to the config file and applied it to the bound global, but getValue()
kept returning the override. The game and the options menu then showed
different values for the rest of the session.

Add a setOverride() overload that takes a JSON value. Every command-line flag
now builds its override with json_integer, json_real, json_true, json_false
or json_pack, in place of a hand-formatted string.

Make Graphics.CockpitFOV and Graphics.CockpitFOVToggle independent of the
order in which the options manager loads them, and remove the forced override
on the player's toggle preference. The toggle listener also replaces an
identical bind_to() call that made the listener dead code.

Add 16 to the values of Graphics.MSAASamples. The -msaa flag accepts 16, so an
override with that value made printValues() report an invalid value.

Keep the render API that the caller gives to gr_init(). Only a Default value
now comes from the Graphics.RenderAPI option, so FRED and the unit tests keep
the backend that they ask for.

Make the default_func of Graphics.Shadows and Graphics.ShadowRenderMethod
return their global. A constant discarded the value that -enable_shadows and
the mod table set. Set Max_rt_shadow_local_lights to 4, because 3 is not one
of the values that the option offers.

Also: resolve -lang one time, share the render API name with version.cpp,
correct the stale comments, and add unit tests with a fixture that clears the
overrides after each test.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UGh4ZM2u4oUGSbrP122Uyr

* Fix the order-dependent crash in the MSAA option test

The test `MsaaOverrideAcceptsEverySampleCountTheFlagAllows` calls
`getValidValues()`. `Option<T>` makes a display string for each value, and the
display function of `Graphics.MSAASamples` calls `XSTR()`. `XSTR()` runs
`Int3()` if `lcl_xstr_init()` did not run before. Only `FSTestFixture` runs it,
and `Xstr_inited` stays set for the remainder of the process. Thus the shuffled
test order decided if the test passed or if it stopped the test binary with
SIGILL.

Move that one test to a new fixture that derives from `FSTestFixture`. The
fixture initializes localization, and it also clears the overrides after each
test. Refresh the comment that told that the test binary never runs
`lcl_init()`.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UGh4ZM2u4oUGSbrP122Uyr

---------

Co-authored-by: Claude Opus 5 <[email protected]>
2026-09-10 13:14:18 +02:00
Shivansps 8e60b69922 Fix unused param warnings when compiling with openxr off (#7770) 2026-09-08 10:48:50 -04:00
BMagnu a73e2565c8 Add Vulkan + Wayland init logic for OpenXR (#7767)
* Add Vulkan + Wayland init logic for OpenXR

* typo

* clang tidy
2026-09-08 10:48:33 -04:00
Goober5000andClaude Opus 4.8 f3817c80fa Scale font line and tab advance by the font scale factor
Multi-line and tabbed strings drawn with a scaleMultiplier != 1 overlapped
or misaligned because the font code advanced newlines and tabs by the
unscaled font height/tab width -- most visible in FRED's viewport labels
now that they honor an adjustable font scale.

Scale the newline and tab advance in both the rendering and measurement
paths of each backend: the NVG path (gr_string and NVGFont::getStringSize)
and the VFNT path (gr_string_old and VFNTFont::getStringSize), which also
gains tab handling.  The tab width is hoisted onto the shared FSFont base
so both backends share it.

While here, pass the FSFont wrapper to gr_string_old instead of a bag of
scalars, make its font pointer const, and consolidate the
get_char_width_old externs into a single declaration in font_internal.h.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-09-03 01:55:03 -04:00
Goober5000andClaude Opus 4.7 ba7aa70794 Fix 32-bit truncation in the flagset u64 round-trip
Mission flags are saved to the mission file as the full 64-bit flagset value, but three issues prevented anything larger than 32 bits from being saved as intended:

 * `stuff_flagset` parsed the value with `stuff_long`, where `atol` clamps anything above `LONG_MAX`
 * `flagset::from_u64` cast the incoming value to `unsigned long`, truncating bits 32-63
 * `flagset::to_u64` used `bitset::to_ulong` where it should use `bitset::to_ullong`

Fix these issues and add `static_assert` in the flagset functions to defend against future issues.  Also use the proper UINT64_T_ARG where it should be used.

This was first triggered by `Limited_support_rearm_pool`, the first mission flag to occupy bit 31.  Only mission flags are affected; the other flagset serialization paths were audited and are safe.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
2026-08-30 16:46:11 -04:00
Fabian Woltermann 234219d88b Fix invalid model/instance access for OBJ_RAW_POF and OBJ_PROP (#7733)
Ensure proper checks for model_num and instance validity when accessing OBJ_RAW_POF and OBJ_PROP objects. Prevents crashes from out-of-bounds or missing data in Pof_objects and Props.
2026-08-23 13:34:44 +02:00
BMagnu 09de3f1fb8 Fix deferred lighting on vulkan (#7682) 2026-08-03 15:52:34 +02:00
Fabian Woltermann cb284b7f13 Update shader logic for shadow handling and Vulkan large shader configurations (#7659)
Refactor shadow flag handling in shaders to improve compatibility with small-shader mode. Add support for Vulkan's `-no_large_shaders` switch to split model ubershaders for better driver compatibility. Adjust related comments and preprocessor checks for clarity.
2026-08-02 06:29:02 +02:00
BMagnu 9320ed7e19 Reasonably generic mouse position handling (#7674) 2026-08-01 19:46:57 +02:00
Fabian Woltermann 09ab04193b Merge pull request #7651 from The-E/fix/resolution-initialization-on-empty-config
Fix resolution_default to handle uninitialized SDL video subsystem
2026-07-24 21:16:10 +02:00
Fabian Woltermann d0cefc87bd Fix inverted scpui icons and 3d ship/weapon select models rendering in the wrong place (#7647)
* Fix Vulkan render target readback orientation to match OpenGL behavior

* Add render target pass resumption after Vulkan shadow rendering

Ensure that Vulkan render targets resume rendering properly after shadow passes, particularly for off-screen targets like SCPUI's 3D previews, to prevent unintended content leakage onto the screen.

* Skip alpha writes for additive batched bitmaps in render targets to preserve coverage and prevent opaque artifacts.

* Add external subpass dependencies to Vulkan render passes to fix read/write hazards

Introduce explicit memory dependencies for color attachments sampled between passes to prevent flickering and graphical artifacts caused by read-after-write and write-after-read hazards.

* Support fractional alpha values in createColor function and preserve 0-255 compatibility
2026-07-24 21:10:13 +02:00
the-e 9eb11aec7f Fix resolution_default to handle uninitialized SDL video subsystem
Ensure SDL video is temporarily initialized if needed during startup to safely query desktop display mode, preventing reliance on a potentially dead subsystem and avoiding silent fallback to invalid resolutions.
2026-07-24 20:38:14 +02:00
Fabian Woltermann 6ae666d10a Merge pull request #7643 from Shivansps/vulkan-etc2
ETC2 textures support in Vulkan
2026-07-24 17:43:16 +02:00
Taylor Richards 039880491a port to SDL3 (#7220)
Basic port from SDL2 to SDL3. Also updates imgui to 1.92.5.
2026-07-23 15:52:27 +02:00
Fabian Woltermann 1abbea499b Merge pull request #7640 from The-E/fix/various-scpui-issues-in-vulkan
Fix various issues in SCPUI when using Vulkan
2026-07-23 09:12:20 +02:00
Salvador Cipolla a40868497e ETC2 textures support in vulkan 2026-07-22 19:45:29 -03:00
Fabian Woltermann 2c3e052ec6 Fix Vulkan FXAA/SMAA handling and ensure proper Scene_ldr transitions (#7639)
Address FXAA/SMAA shader selection logic by aligning it with the current anti-aliasing mode. Fix undefined behavior for discarded non-edge pixels during the FXAA main pass by transitioning Scene_ldr to a load-preserving layout. Optimize compatibility across IMR and tiled GPUs, preventing visual artifacts.
2026-07-23 00:38:44 +02:00
the-e 1e5bf66c84 Remove unsupported graphics options for non-raytracing renderers
Disable raytraced-shadow and HDR settings in the options menu when unsupported by the current renderer, reducing UI clutter and ensuring only relevant options are displayed.
2026-07-22 20:41:24 +02:00
the-e 0d64f7f237 Add load-variant render pass support for Vulkan render targets
Introduce load-variant render passes to Vulkan textures, enabling content preservation during mid-frame readbacks. Changes include creating `renderPassLoad`, flushing command buffers for readbacks, and resuming rendering into targets with `loadOp=eLoad` to avoid clearing previously rendered content.
2026-07-22 19:57:10 +02:00
the-e 334682c44d Add depth/stencil support to Vulkan render targets
This commit introduces optional depth/stencil attachments for Vulkan render targets, enabling z-testing and addressing earlier limitations where depth-tested geometry rendered in submission order without depth attachments. Changes include resource allocation, attachment handling, and layout transitions.
2026-07-22 19:18:01 +02:00
b26b9cf743 Add Vulkan rendering backend, with HDR10 output and raytraced shadows (#7554)
* Shadow overhaul round 2: PCSS, dynamic cascades, cockpit/instanced shadows

Squashed snapshot of lafiel/shadow_overhaul_2's continuation work
(d3922aa87..010f9d2d9), which has no separate upstream PR of its own.

* Add Vulkan rendering backend

Squashed snapshot of the Vulkan backend as vendored into this branch
(ce2d1e85f..6ce539463, authored by Mara van der Laan with build/CI
fixes by Taylor Richards). This work has its own upstream PR #7553
(notimaginative:vulkan-pr-new) and is not otherwise original to true-hdr.

* Add true HDR output, RT shadows, and PCSS shadows for Vulkan

Squashed snapshot of true-hdr's own integration work: true HDR
framebuffer output, wiring the shadow overhaul into the Vulkan
backend (raytraced + cascaded shadow maps), logging refactors, log
filter UI, and CI/build fixes.

* refactor: update Vulkan logging calls to use `nprintf` for scoped logging

* fix: correct shadow cascade count in Vulkan logging calls

* fix: fall back to PATH-resolved ccache when CCACHE_PATH is stale

CI hardcodes /usr/local/bin/ccache, but macOS runners on Apple Silicon
hosts install Homebrew (and ccache) under /opt/homebrew instead,
causing all four Mac configs to fail with "No such file or directory".

* Fix vulkan texture readback to correctly handle transparent pipelines

* Put the pixel swizzles into a util file

* OOB safety check

* Fix fog handling

* Fix MSAA in Vulkan

* fix: enable SMAA for vulkan

* adapt the post-processing AA shaders to hdr

* fix clang-tidy warnings: concatenate nested namespaces, static methods

pixel_swizzle.{h,cpp}: collapse `namespace graphics { namespace util {`
into `namespace graphics::util {` (modernize-concat-nested-namespaces).

VulkanState.h/VulkanDraw.h: getClearColor()/setClearColor() only touch
gr_screen and other globals, no instance state, so make them static
(readability-convert-member-functions-to-static) and drop the
top-level const on getClearColor()'s return type
(readability-const-return-type).

* fix clang-tidy warning

* Extend raytraced shadows to all directional lights

RT shadows previously only shadowed the first directional light in the
scene, even though multi-sun missions push more than one directional
light into the engine. The TLAS raytraced shadows query against is
already light-agnostic, so this extends both the deferred lighting
pass and the forward MODEL shader to shadow every directional light
(capped by a new Max Raytraced Shadow Lights option, configurable via
the in-game Options menu or the Lab's Scene rendering options).

Cascaded shadow maps are untouched: they're built for a single light
only, so the deferred pass still limits itself to one shadowed
directional light whenever CSM (not raytracing) is the active method.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_016DA6JHJ3twz2oHGQcZ1Udc

* refactor: improve shader flag handling and render target finalization in Vulkan backend

- Consolidate shader flag setup logic in VulkanPostProcessingLighting to simplify configuration.
- Fix dead field usage in VulkanDraw by ensuring correct image view selection for environment maps.
- Add mip chain regeneration in VulkanRenderer::endRenderTarget to ensure correct mip levels for cubemaps.

* fix: ensure correct mip chain initialization in cubemap rendering

- Add mip chain generation to VulkanDraw for cubemaps with multiple mip levels.
- Fix potential issue with uninitialized mip levels above level 0 in deferred-f.sdr sampling paths.

* fix: don't crash on startup when environment locale is unavailable

std::locale("") pulls in the process's environment locale categories
(LC_CTYPE, LC_MONETARY, LC_PAPER, etc.), and throws std::runtime_error
if any of them names a locale not installed on the host (e.g.
mismatched regional-format overrides). Since SCP_default_locale is
constructed during static initialization, before main() and before any
of our own exception handling exists, an uncaught throw here aborted
the whole process before the game even started. Fall back to the
classic "C" locale instead, which is sufficient since this locale is
only ever used for ASCII case-folding (SCP_toupper/tolower/isdigit).

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

* `feat: add raytraced shadows for local lights and optimize TLAS management`

* Make the Commandline authoritative for -res and -vulkan / -opengl

* address BMagnu's comments on the original PR

* update prebuilt version hash to 62c89ef6

* refactor: standardize graphics API handling and document Vulkan limitations in qtFRED

- Updated `AboutDialogModel.cpp` to use `GraphicsAPI` enum for better clarity.
- Ensured qtFRED falls back to OpenGL when Vulkan is requested.
- Added detailed documentation in `qtfred/README.md` regarding Vulkan backend limitations and requirements.

* chore: include cmdline library in main and mission management modules

* docs: add known issue for blank render viewport under Wayland in README.md

* fix CI issues

* chore: add `GR_DEBUG_SCOPE` markers across Vulkan post-processing and rendering paths for improved debugging

* feat: improve Vulkan HDR pipeline with separate encode paths for SDR and HDR10

- Added an HDR10-specific output encode pass in `VulkanRenderer` and `VulkanPostProcessor` that applies PQ/BT.2020 transfer.
- Introduced an optimized SDR fallback path with direct blit support for devices that can skip shader draws.
- Updated `m_sceneLdrCompressed` to provide [0,1]-clamped proxies for HDR edge detection.
- Refactored `copyImageToImage` and added `blitImageToImage` to allow format conversions and optimized transfers.
- Replaced `hdr_mode` with explicit HDR10 flags and data structures for clearer state handling.

* refactor: encapsulate SMAA processing and refactor VulkanPostProcessor

- Moved SMAA-specific logic into `VulkanSMAA` class for better separation of concerns.
- Simplified `initSMAA`, `shutdownSMAA`, and `executeSMAA` logic by leveraging `VulkanLDR` and `PostProcessContext` abstractions.
- Improved initialization and cleanup code with clearer resource lifecycle management.
- Updated debug markers and messages to reference `VulkanSMAA`.
- Enhanced flexibility of fullscreen triangle rendering API with additional parameters (`sampleCount`, `bindGlobalSet`).

* Update Vulkan porting credits in AboutDialogModel

* fix CI issues again

* fix: correct Y-flip in viewport setup for Vulkan light volumes

- Adjusted viewport height to negative value to account for G-buffer render pass's negative Y-axis convention.
- Ensured proper alignment of point and tube light volumes with actual light positions.

* feat: add user-adjustable gamma correction to SDR and HDR10 output paths

- Added gamma correction to HDR10 path, applying user settings before PQ/BT.2020 encode.
- Replaced the SDR blit-only path with an encode pass that applies gamma correction, ensuring consistent behavior across devices.
- Refactored VulkanPostProcessor and associated shaders to support gamma slider adjustments for both SDR and HDR output.

* fix: ensure proper uniform and cull mode setup for Vulkan sphere rendering

- Added uniform buffer setup and default material uniforms in `vulkan_draw_sphere`.
- Disabled face culling in material definition for sphere rendering to align behavior with OpenGL.

* Ensure memory flushes after UBO updates and add explicit pipeline barrier for MoltenVK compatibility.

* fix: add clear pass for SMAA edge detection to prevent persistent artifacts

* feat: add Vulkan debug-utils messenger, opt-in sync validation, frame diagnostics

Groundwork for the renderer-review fix series (.agents/plans/
vulkan-renderer-review-fixes.md, Phase 0):

- Register a VK_EXT_debug_utils messenger (preferred) instead of only the
  deprecated VK_EXT_debug_report callback, which is kept as a fallback for
  loaders without debug-utils. The messenger config is also chained into
  instance creation so vkCreateInstance-time messages are captured.
  Validation errors/warnings now go to the main log via mprintf.
- New -gr_sync_validation cmdline flag (implies -gr_debug): chains
  VkValidationFeaturesEXT with synchronization validation into instance
  creation when VK_LAYER_KHRONOS_validation is available. This is the
  regression net for the synchronization fixes in the following commits.
- Frame stats now report descriptor sets/writes allocated per frame and the
  total pipeline count (descriptor-manager counters; DescriptorWriter::flush
  moved out-of-line to report into the manager).

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

* refactor: unify Vulkan render-pass begins, clamp in-pass clears, add per-frame UBO ring

Phase 1 of the renderer-review fix series: shared helpers that the
correctness fixes build on.

- New VulkanRenderer::beginTrackedRenderPass(PassBeginDesc): every render-pass
  begin on the frame command buffer now records vkCmdBeginRenderPass and
  updates the state tracker (pass, color attachment count, sample count,
  render area, viewport) in one place. Converted: setupFrame,
  beginSceneRendering (both branches), resumeSceneRendering,
  endSceneRendering, beginRenderTarget (viewport kept for gr_set_viewport),
  resumeSwapChainPass, plus new resumeScenePassAfterCopy() shared by
  copyEffectTexture/copySceneDepthForParticles and
  rebeginSwapChainPassAfterReadback() shared by both readbackFramebuffer
  exits (~200 lines of duplicated begin/clear/viewport blocks removed).
- The state tracker records the active render area; all four
  vkCmdClearAttachments sites clamp their rects against it and skip empty
  results. Previously gr_screen-sized clear rects could exceed a smaller
  off-screen render target's render area, which is invalid API usage.
- New PerFrameUboRing utility (VulkanPerFrameUbo.h/.cpp): a persistently
  mapped uniform buffer with one slot region per frame in flight and a
  self-flushing alloc(). Used by the next commit to fix the cross-frame
  UBO races.

Deliberate behavior deltas (all safe-direction): the helper always sets
colorAttachmentCount/sampleCount (some sites previously inherited stale
values), and resumeSwapChainPass/resumeSceneRendering now also reset the
standard flipped viewport instead of leaving the previous one.

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

* fix: eliminate Vulkan cross-frame UBO/buffer races, make gr_sync honest

Phase 2 of the renderer-review fix series: with two frames in flight, several
host-visible resources were rewritten by the CPU while the previous frame's
GPU work could still be reading them.

- The post-processing scratch UBO is now a PerFrameUboRing (per-frame-in-
  flight slot regions, persistently mapped, self-flushing alloc). All the
  per-pass map/unmap/cursor bookkeeping in bloom/LDR/fog/SMAA is deleted;
  the cursor resets exactly once per frame via the new
  VulkanPostProcessor::beginFrame() hook in setupFrame.
  This also fixes two latent bugs: (a) fog consumed scratch slots mid-scene
  and bloom's later same-frame cursor reset overwrote them before submission
  whenever fog+bloom were both active; (b) volumetric_fog_data (288 bytes)
  overflowed the 256-byte slots - the memcpy spilled into the neighboring
  slot and the shader's bound range ended before the aspect/fov/noise
  fields. Slots are now 512 bytes (static_assert at the fog call site) and
  the per-frame budget is 32 slots.
- The dedicated tonemap, output-encode, and MSAA-resolve UBOs (each a single
  instance rewritten per frame, i.e. racy; the MSAA one also never flushed)
  are deleted entirely - those passes build their structs on the stack and
  allocate from the scratch ring.
- Static-buffer rewrites orphan instead of racing: getVkBuffer() stamps a
  last-used frame number, and a full-content updateBufferData() on a Static
  buffer used within the last MAX_FRAMES_IN_FLIGHT frames defers the old
  VkBuffer to the deletion queue and writes a fresh one. Offset writes
  (GPU-heap appends to fresh regions) and PersistentMapping buffers (the
  engine holds their mapped pointer and syncs via gr_sync) are exempt.
- gr_sync_wait now honors its contract: VulkanRenderFrame::waitForFinish
  takes a timeout and reports expiry without consuming the fence;
  VulkanRenderer::waitForFrame returns false for fences taken during the
  still-recording frame (previously it waited on a stale or idle slot and
  reported success) and resolves the frame->slot mapping correctly. This
  makes UniformBufferManager's segment-fence throttling actually protective
  on Vulkan for the first time.

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

* Refactor framebuffer and target lifecycle: centralized creation/resizing logic, improved resource management across Vulkan post-processing subsystems.

* Improve Vulkan cross-frame sync with explicit access masks and validation updates

- Unified Vulkan validation flag handling in setup, separating engine debug output from synchronization validation.
- Specified access masks and stage flags to address cross-frame WRITE_AFTER_WRITE vulnerabilities, notably in G-buffer, post-processing, and MSAA resolve paths.
- Adjusted subpass dependencies and image layout transitions to prevent read-after-write and write-after-write hazards, detected using `-gr_sync_validation`.
- Fixed uniform buffer and barrier transitions to ensure proper ordering in render passes across frames.

* Refactor Vulkan render-pass dependencies and sync stages for clarity and future testing

- Clarified dependency logic for cross-pass and cross-frame synchronization, ensuring explicit stage and access flag comments match observed behavior.
- Adjusted subpass dependencies to decouple render-pass compatibility definitions from dependency assumptions.
- Highlighted MoltenVK-specific issues and retained workarounds with notes for re-testing on macOS hardware.
- Updated synchronization barriers and validation notes to address historical inconsistencies across platforms.

* Remove transfer queue support; consolidate all operations into the graphics queue

- Removed transfer queue handling, simplifying buffer and queue logic to use the graphics queue for all transfer operations.
- Updated buffer sharing modes and removed related code paths and parameters for transfer queue families.
- Introduced exclusive buffer access, noting async transfer and queue ownership transfers are future work.
- Limited enabled device features to only those actively used by the renderer, reducing unnecessary feature requests (e.g., robustBufferAccess).

* Refactor frame advancement and descriptor management in VulkanRenderer

- Removed `endFrame()` from `VulkanDescriptorManager`, replacing it with `setCurrentFrame(frameIndex)` for explicit frame synchronization.
- Centralized frame index advancement within `VulkanRenderer` to ensure consistency across components.
- Invalidated cached descriptor set bindings at render-pass boundaries to handle raw recorder staleness correctly.
- Optimized pipeline descriptor rebind logic by removing redundant clears during pipeline changes.

* Refactor `PipelineConfig::hash` and Global descriptor set management for improved hashing and memoization efficiency

- Replaced inefficient shift-based hashing in `PipelineConfig::hash` with a robust `hashCombine` strategy to minimize bucket collisions.
- Introduced `maskBits` helper to streamline bitmask creation for boolean fields.
- Implemented memoization for Global (Set 0) descriptor sets, reducing redundant rebuilds across frames and improving performance.
- Added dirty state tracking (`m_globalSetDirty`) and invalidation logic for Global set updates following relevant input changes (e.g., TLAS or UBO modifications).

* Refactor Vulkan post-processing output logic: extracted shared `encodeToSwapChainPass` method to streamline HDR and SDR output paths.

* Optimize Vulkan descriptor set management with per-frame memoization

- Added memoization for Material (Set 1) and PerDraw (Set 2) descriptor sets to reuse cached sets across frames if inputs remain unchanged.
- Implemented precise input tracking for Material and PerDraw descriptor sets to detect and rebuild only when necessary.
- Reduced redundant Vulkan descriptor allocations and writes, improving performance on repeated or batched draw calls.

* Fix Vulkan access masks for G-buffer and scene pass transitions

- Added `eColorAttachmentRead` to access masks in multiple barriers to ensure proper synchronization for load operations (e.g., `loadOp=eLoad`) across render passes.
- Prevented `READ_AFTER_WRITE` synchronization validation issues in deferred and multi-pass rendering scenarios.
- Updated comments to clarify the reasoning behind the access mask changes and load dependencies.

* Refactor Vulkan resource management and indexed draw logic

- Consolidated destruction queue methods in `VulkanDeletionQueue` using a shared `queueHandle` template to reduce redundancy.
- Introduced `ModelDrawParams` structure and `computeModelDrawParams` function to unify indexed draw parameters for models and shadows.
- Simplified draw logic by eliminating repeated calculation of indexed draw parameters and improving code reuse.

* Add `releaseAnimationSlotRef` for ref-count handling of shared animation texture arrays

- Introduced `releaseAnimationSlotRef` to manage reference counting for shared animation texture-array slots, preventing premature destruction of shared resources.
- Updated `flushTextures` and related methods to integrate `releaseAnimationSlotRef` for shared slot cleanup.
- Refactored staging buffer creation into `createStagingBuffer` for 3D texture uploads and shared path consistency.
- Enhanced texture upload logic with improved tracking and logging for re-upload cases, aiding preloading gap analysis.
- Added instrumentation for on-demand mid-frame texture uploads in `FrameStats`.

* Refactor Vulkan resource and texture management, extend debug logging

- Updated smart pointer usage for consistency across Vulkan resource managers (`std::make_unique`).
- Removed redundant `cubeImageView` member and related cleanup logic; unified sampling view management.
- Added per-instance debug log counters (avoiding static state) for Vulkan texture uploads and bindings, improving visibility during initialization and run-time.
- Optimized `VulkanRenderer` property/feature getters by caching physical device properties and features during device creation.
- Improved memory region flushing logic for out-of-date offsets, aligning with Vulkan Memory Allocator behavior.
- Refactored render pass state tracking to reapply dynamic state reliably after mid-frame render passes.
- Enhanced validation and error handling for mismatched update texture formats.

* fix CI build warning

* Fix on-demand YUV texture locking and set alpha uniform for movie rendering in Vulkan

- Corrected bitmap lock type from `BMP_TEX_OTHER` to `BMP_AABITMAP` for YUV textures during on-demand loading.
- Updated movie rendering to bind alpha from the `MovieData` UBO (set 2, binding 4) for Vulkan, aligning behavior with OpenGL implementation.

* revert inadvertent changes introduced by a squash commit

* address ci issues

* remove wip stuff from code comments that make no sense to people who aren't me

* Remove unused LD_LIBRARY_PATH export and fix shader shadow map sampling.

* Refactor batched rendering uniform setup in Vulkan

- Removed unused fields from `genericData` uniform block, simplifying shader definitions.
- Updated Vulkan material uniform handling to align with OpenGL's batched rendering logic.
- Introduced `batched_data` struct for streamlined UBO updates, improving maintainability and clarity.

* Add `-hdr` command-line option for HDR nits configuration

- Introduced `-hdr` parameter to set paper white and peak luminance in nits, overriding in-game HDR settings.
- Added input validation with error feedback for incorrect format.

* Remove unused `MODEL_SDR_FLAG_SHADOW_MAP` macro from shader flags

* clean up unrelated changes

* Invalidate Vulkan state tracker bindings after external command buffer modifications

- Added `invalidateExternalBindings()` to `VulkanStateTracker` to handle stale pipelines, descriptors, and dynamic states caused by external Vulkan commands (e.g., ImGui renders mid-pass).
- Updated ImGui rendering flow to call `invalidateExternalBindings()` post-draw, ensuring consistent pipeline state for subsequent engine renders.
- Adjusted image usage flags to account for `eTransferSrc` in texture readbacks.
- Fixed barrier `dstAccessMask` and pipeline stage flags to ensure proper synchronization for image transitions.

* Add a few more generically useful lines to the log

* Simplify Qt deployment logic and improve handling for system-installed Qt on Linux

* add cmdline headers to make qtFred compile

* use VK_KHR_synchronization2 for sync and barrier purposes

* Simplify and clean up Qt deployment logic in CMake for qtfred

* update get_bitmap_from_texture to match the new API

* Enhance `-hdr` command-line option to force HDR output and support optional nits configuration with improved input validation and overrides.

* Improve Vulkan robustness, add device feature checks, and refine memory/logging.

- Added depth clamping support gated by device feature checks, with fallback where unsupported.
- Improved deferred lighting UBO overflow handling with user-accessible warnings and buffer size adjustments.
- Enhanced Vulkan logging for validation, allocation, and debugging:
  - Automatic logging for descriptor pool exhaustion/fragmentation.
  - Vertex format and resource destruction checks.
  - Notifications for generic layout transitions and volumetric texture uploads.
- Consolidated shader logic to ensure Vulkan and OpenGL parity.

* Remove HDR10 encode shader and consolidate gamma correction logic for SDR and HDR10. Replace `Verify` assertions with `Assert`

* Add braces to conditional in object lighting logic for clarity

* Refine Vulkan memory allocation checks with `Verification` for improved error handling and messaging.

* Refine VulkanBuffer resize logic to preserve contents with CPU-side copy and add safeguards for non-coherent memory scenarios.

* Add detailed comments explaining descriptor array capacity constants in VulkanDescriptorManager

* Gate shadow support on depth clamp feature availability and clarify its necessity with improved comments.

---------

Co-authored-by: BMagnu <[email protected]>
Co-authored-by: Mara van der Laan <[email protected]>
Co-authored-by: Claude <[email protected]>
2026-07-21 16:58:21 +00:00
Goober5000andClaude Fable 5 7b241812ed make ship move-correct
Ship's implicit move operations compiled but were semantically broken in
two ways: moving copied the subsys_list sentinel's links verbatim,
leaving the bookend nodes of the intrusive subsystem list pointing at
the old sentinel address; and the raw owning warpin_effect /
warpout_effect pointers were copied without nulling the source, so a
vacated Ships[] slot aliased live WarpEffects that ship::clear() (on
slot reuse) or ship_close() (which walks every slot) would delete out
from under the destination ship.

Fix both at the member level so the compiler-generated moves are
correct by composition:

- Add ship_subsys_sentinel, derived from ship_subsys, whose move
  operations re-link the bookend nodes (handling the null-linked,
  self-referential-empty, and populated source states) and leave the
  moved-from sentinel as an initialized empty list.  Copying is
  deleted.  Public inheritance keeps &ship::subsys_list convertible to
  ship_subsys*, so list_init, GET_FIRST, and every other call site is
  unchanged.

- Convert warpin_effect and warpout_effect to std::unique_ptr.  The
  delete-and-null blocks in ship::clear(), ship_close(), and
  ship_set_warp_effects() collapse into reset(); call sites that borrow
  the pointer into a raw local now use get().

With the members handling themselves, declare ship's special member
functions: defaulted default constructor and moves, deleted copies
(previously implicit via the unique_ptr members, now stated intent).
The moves are deliberately not declared noexcept because members like
SCP_map and std::deque do not have standard-guaranteed nothrow moves;
the computed exception specification is used instead.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-20 23:04:56 -04:00
Goober5000andClaude Fable 5 35312d379c Check texture bind results in the volumetric nebula pass
gr_opengl_tcache_set() leaves the previous binding active when it
fails, so the glTexParameteri calls that follow would modify the filter
state of an unrelated texture.  Only set the parameter when the volume
texture actually bound.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-19 00:12:21 -04:00
Goober5000andClaude Fable 5 61a217c462 Exempt user bitmaps from texture detail culling
At texture detail below maximum, opengl_create_texture() culls texture
dimensions on upload, but user bitmaps are streaming surfaces
(streamed animations, video) whose frames are updated through
gr_update_texture() with the bitmap's own dimensions.  Once culled, the
glTexSubImage3D update exceeds the texture's actual size, so OpenGL
rejects it with GL_INVALID_VALUE and the animation silently freezes on
its first, downsampled frame.  Culling them also saves nothing, since
full-size frame data is streamed every frame regardless.

Also assert in gr_opengl_update_texture() that the update dimensions
match the texture, so any future mismatch of this kind is caught in
debug builds instead of failing silently.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-19 00:12:21 -04:00
Goober5000andClaude Fable 5 6f4825c45e Fix heap overrun in texture readback for the model transparency scan (#7616)
* Fix heap overrun in texture readback for the model transparency scan

gr_opengl_get_bitmap_from_texture() sized its readback buffer from the
texture cache slot dimensions and the bmpman frame count, but
glGetTexImage() returns whatever the bound GL texture actually contains.
When texture detail below maximum culls textures on upload, the two can
disagree, and the readback overruns the buffer (observed as heap
corruption when loading Zeus.pof with Texture Detail: Minimum).  Size
the readback from the dimensions and layer count OpenGL itself reports
for the texture, and pad the staging buffer to 4x4 block granularity in
case a driver writes tiny compressed mips back in whole blocks.

The readback now also allocates the returned buffer and reports the
dimensions of the data it returns, because the second half of the bug
was on the consumer side: bitmap_lookup indexed the readback data by
the bitmap's own dimensions, so with any culling in effect the
transparency scan read mostly uninitialized memory.  bitmap_lookup (and
its cache) now carries the actual readback dimensions, and it skips the
texture cleanly if the readback fails.

Also pairs the cache's vm_malloc allocations with vm_free instead of
free, and no longer ignores a failed tcache_set before reading back.

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

* Harden the transparency-scan texture readback

Return fully opaque from bitmap_lookup::get_channel_alpha() when the
bitmap has no alpha channel, since indexing channel 3 of a 3-channel
buffer reads out of bounds (currently unreachable because the only
caller checks bm_has_alpha_channel() first, but no longer a trap).

Per review, also assert at maximum texture detail, where no culling
occurs on upload, that the readback dimensions OpenGL reports match the
texture cache slot, so any future slot mismatch is caught immediately
in debug builds instead of surfacing as corruption.

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

* Fix inverted dimension check in opengl_export_render_target

The validation rejected the export only if both the width and the
height mismatched the texture cache slot, so a texture wrong in one
dimension passed through into opengl_get_texture, which trusts the
caller-supplied dimensions for its mipmap loop.

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

---------

Co-authored-by: Claude Fable 5 <[email protected]>
2026-07-18 09:50:46 +02:00
Fabian WoltermannandClaude Fable 5 583192b9f8 Add intermediate framebuffer for gamma correction to prevent flickering (#7589)
* Add intermediate framebuffer for gamma correction to prevent flickering

* Fix frozen SCPUI briefing screen by resetting color mask before gamma pass

A masked draw pass inside the briefing map render leaves the GL color
mask fully disabled, and the Rocket UI material path never restores it.
Before cc63bfa7 this didn't matter: the frame was presented with a pure
glBlitFramebuffer, which ignores the color mask. The gamma-by-shader
change turned presentation into a regular draw, which respects the
mask, so every flip wrote nothing and the screen froze on stale
swapchain content while the engine kept rendering correctly underneath.
Hovering a briefing icon appended draws whose materials re-enabled
color writes, which is why the screen only updated while hovering.

Neutralize color mask and stencil state before the gamma draw, matching
the blend and depth-buffer neutralization already done there.

Fixes #7590

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

* Skip the gamma-correction pass when gamma is 1.0

The gamma shader is an identity transform at gamma 1.0, so present
Back_framebuffer directly via glBlitFramebuffer in that case (the same
present path used before the gamma shader was introduced), saving a
fullscreen draw per frame. The shader pass through GammaBlit_framebuffer
only runs when the effective gamma actually differs from 1.0.

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

* Reuse Scene_ldr_texture as the gamma-correction pass target

Scene_ldr_texture is dead scratch by flip time: all of its consumers
(tonemap, FXAA/SMAA, the final post-process pass) write before reading
within gr_opengl_post_process_end(), which completes before the flip,
and the gamma pass fully overwrites it before blitting it to the
window. Attaching it to GammaBlit_framebuffer instead of allocating a
dedicated texture saves a screen-sized RGBA8 allocation (~8 MB at
1080p, ~33 MB at 4K).

The dedicated allocation remains as a fallback for the case where the
scene textures were clamped to GL_max_renderbuffer_size and don't cover
the screen.

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

---------

Co-authored-by: Claude Fable 5 <[email protected]>
2026-07-14 07:28:41 +00:00
Goober5000andClaude Opus 4.8 bed228d264 avoid undefined behavior from UNREACHABLE on reachable code paths (#7555)
* avoid undefined behavior from UNREACHABLE on reachable code paths

UNREACHABLE expands to __assume(false) / __builtin_unreachable() in
release builds, which is undefined behavior if the code is ever actually
reached. Many UNREACHABLE sites only guard against unexpected-but-
possible runtime states (values from tables, mission/save files, network
packets, scripting, or user input), so reaching them should degrade
gracefully rather than invoke UB.

Replace UNREACHABLE with Assertion(false, ...) at all such sites. It
still pops an error in debug builds, but in release it is a harmless
no-op that simply falls through to the following code. Sites that are
genuinely unreachable by local invariants (e.g. a switch over a bounded
random number) are left as UNREACHABLE.

A few converted sites had no safe fall-through -- an uninitialized read,
null dereference, or null call would have followed -- so they also get a
minimal recovery: initialize the value, guard the dereference, return
early, or skip the offending item.

Where the converted site was a simple guard of the form
    if (x) { Assertion(false, ...); return; }
hoist the check onto the invariant instead:
    Assertion(!x, ...);
    if (x) { return; }
This states the expectation directly and shows the offending value in
the debug popup, while keeping the same graceful runtime degradation.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

* addendum

After consultation with Lafiel, use UNREACHABLE in situations that are effectively impossible even if not provably impossible.  UNREACHABLE = "this shouldn't ever happen"; Assertion = "if this ever happens, it's a coding error".  Also fix a few other sites and change a couple to Warnings.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
2026-07-09 11:20:25 +09:00
Goober5000andClaude Fable 5 a733748615 fix geometry_batcher copy semantics and add move operations
clone() allocated fresh vert/radius_list buffers without freeing the
ones already owned, so assigning over a live batcher leaked both.  It
also never copied buffer_offset, and the copy constructor called it
with no member initialization at all -- so every copy-constructed
batcher carried an uninitialized buffer_offset.  Free the existing
buffers in clone(), copy buffer_offset, and delegate the copy
constructor to the default constructor so clone() sees initialized
members (which is also what makes its new frees safe on that path).

Also add noexcept move operations, which the user-declared copy
operations had suppressed, so by-value handling can transfer the
buffers instead of deep-copying them.

None of these defects were reachable from current callers (the static
batch maps mutate entries in place); this closes the latent hazards.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-06 13:33:49 -04:00
BMagnu 25eebd96de Shadow Overhaul (#7529)
* Extract shadows into own shader and render pass

# Conflicts:
#	code/def_files/data/effects/main-g.sdr

* Consolidate render queue code

* More cleanup

* Fix missing clear of shadow buffer inter frame

* Request capability for viewport layer rendering

* instanced shadows

* Fix issues

* Switch to PCF+PCSS and proper textures for it

* Smooth PCSS toggle

* Fix for windows

* Fix OGL error

* Cleanup of old flag

* Expose shadow smoothness

* Fix missing uniform

* Make number of shadow cascades dynamic

* Progress on cockpit shadow integration

* Wrangle Cockpit and show-ship shadows into correct behaviour

* Cleanup

* make player ship shadow table options more intuitive

* Cleanup

* Only read from correct set of shadow maps, also stretch first main-scene map to 0

* Remove now non-necessary validation

* Make shadow cascade buffer more typesafe and less wasteful

* Don't allocate cockpit cascades if not used

* Cleanup

* Final fixes

* Fix Warnings

* clang tidy

* Fix missing fallback for shader precaching

* That weird FOV multiplier that always ruins your day

* Avoid shadow geometry artifacts by using hardware depth clamping

* Correctly handle shadow cascade overrides with hardcoded length

* GCC9 and its sad state of C++17 support.

* Address Feedback

# Conflicts:
#	code/graphics/shadows.cpp
2026-07-04 16:08:41 +02:00
BMagnu cc63bfa7c1 Gamma by Shader (#7484)
* Replace SDL gamma with a blit shader gamma

* Window_res comment

* Fixes

* Gamma command line flag
2026-07-04 15:28:52 +02:00
BMagnu 7afbed8a3b Fix shadow artifacts by employing hardware clamping (#7532) 2026-06-18 00:46:33 +02:00
Shivansps 3bd934ee96 Add glClampColor() and GL_DEPTH24_STENCIL8 (#7478) 2026-05-29 09:44:52 +09:00
BMagnuandGoober5000 20c8417e8b Fullneb Revamp (#7352)
* change to new fog system

* Fix fog conversion issues

* remove unused old neb values

* Update scripting API

* temporary old-value round trip

* Rewrite nebula fog with four explicit parameters

Replace the legacy `+Fog Near Mult` / `+Fog Far Mult` model — which
depended on fixed engine constants — with four parameters that map
directly to renderer behavior:

  +Fog 1000m Visibility    fraction of light surviving 1000m of fog
  +Fog Near Distance       meters from camera where fog begins
  +Fog Skybox Clip Distance  max render distance for the skybox in fog
  +Fog Clip Distance       max render distance for the scene in fog

The deferred-lighting fog shader, material system, model renderer,
object sort, and the Lua mission API all consume the new parameters
directly. The legacy `Neb2_fog_near_mult` / `Neb2_fog_far_mult`
globals are removed.

Mission parsing accepts either the legacy keys or the modern keys.
Legacy values are converted to the modern set at parse time, and a
per-mission flag (`Neb2_fog_use_legacy_values`) records which keys to
write back on save. The flag is cleared only when something actually
changes, so opening and OK'ing an unmodified legacy mission preserves
its on-disk format. Saving uses `optional_string_fred` to preserve
user comments through edit cycles.

FRED2 and QtFRED background editors both expose the four parameters
in place of the old multipliers, with friendly labels and tooltips.
Both editors validate input (visibility clamped to [0, 1]; near
distance must be > 0; skybox and scene clip distances may be 0 to
disable fog at that range) and use a snapshot-and-compare at close
time so that a no-op open-then-OK never spuriously rewrites a legacy
mission in the modern format.

FRED2's background dialog is also reorganized so that "Display bg
bitmaps in nebula", "Override nebula fog palette", the RGB row, and
the four fog parameters all sit inside the Nebula group box; the
"Old Nebula" group box is restored below it with its Pattern, Color,
Pitch, Bank, and Heading controls back inside the frame. The dialog
now overrides PreTranslateMessage so that the new fog tooltips —
and the previously broken "Save sun/bitmap angles in correct format"
tooltip — actually fire.

QtFRED's BackgroundEditor.ui adds four QDoubleSpinBox controls in
the existing nebula form layout, with per-field decimals chosen to
avoid scientific notation, and per-field min/max declaring the
validation rules. The QtFRED help page is updated to describe the
new fields.

* fix tooltips

* restore forward-renderer fog

* Clang Tidy

* address feedback

* Refine nebula fog rewrite

- Rename Neb2_fog_use_legacy_values to Neb2_fog_save_legacy_values
  to reflect that the flag governs save format, not runtime
  behavior.
- Decide both the save flag and the legacy-to-modern conversion
  purely from whether the file contains modern fog keys, dropping
  the prior heuristic based on required_fso_version. A mission
  without modern keys (legacy- or retail-format) converts on load
  and saves back in legacy format; missions with modern keys are
  saved as modern.
- Snapshot the four fog values as floats at editor open and use
  fl_equal for the no-change comparison in both FRED2 and QtFRED,
  replacing the FRED2 CString comparison and the QtFRED strict
  inequality.
- Document the on-disk invariant in missionsave: when not saving
  legacy keys, the four modern keys must always be written (never
  gated on "only if non-default"), since the parser uses their
  presence to decide whether to run the conversion on next load.

---------

Co-authored-by: Goober5000 <[email protected]>
2026-05-28 14:43:48 +09:00
Shivansps fe18b474a9 KTX1 / ETC2 Compressed textures support (#7070)
* Initial KTX1/ETC2 support

* Conditional glad include

* remove unused function

* define glenum for non opengl build

* remove unused param

* fix qtbuild

* change ktx format to enum

* use nullptr

* ktx: support the same etc2 formats available in amd compressonator

* add comments and missing include

* correct flag type

* clarify variable name for clang

* cleanup

* update glad loader to GL4.3
2026-05-26 12:21:43 +02:00
Goober5000 4e0ae62e13 FRED and qtFRED quality-of-life improvements for highlighted models
A few visual improvements requested on Discord:
1. Use a configurable LOD to draw the outline wireframe, defaulting to LOD 1
2. Draw subsystem names with a dark outline to make them more visible
3. Draw the subsystem boundary boxes with thicker lines
2026-05-25 23:33:32 -04:00
Mike Nelson 85f00be6f0 Optimize UI model instance (#7246)
* UI model caching feature

* do this with frames instead of timestamp
2026-05-25 01:31:21 +02:00
Mike Nelson 0ffc33c50b fix clipping issues on mirrored bitmaps (#7465) 2026-05-25 01:31:08 +02:00
Shivansps ff892b2ca7 Add OpenGL ES Compatibility Layer (#7137)
* initial changes

* add GLAD_ES loader

* Implement basic es compatibility header

* re-add accidentally deleted break

* Add GLES BC7 extension to glad and improve extension support report

* fix some enum mappings

* Use the ARB name for geo shader check

* Add es espand shader includes

* Fix glbufferstorage mapping

* fix some gl errors on opengl es

* Enable GL_CLIP_DISTANCE

* Add format conversions

* add bgba 8888 to rgba 8888 converter

* disable GLAD_GL_ARB_timer_query

* Properly handle wgl + opengl es on windows

* initial enable imgui gles

* add GL_BGR to GL_RGBA conversion

* inform opengl es on menu

* small corrections to the es header

* small refactor of glTexSubImage3D

* remove expandincludes, existing code already did that better

* change default graphic values for opengl es

* compile imgui with opengl es 3 on linux

* allow qtfred to run on opengl es

* improve es compatibility header and remove shader precision quantification

* add compiler hints

* remove unused structs

* Fix imgui crashing on windows with gles, use angle lib

* Do not use MSAA under OpenGL ES, at least for now

MSAA will need an alternative path for GL ES using GL_EXT_multisampled_render_to_texture and GL_EXT_multisampled_render_to_texture2

* add missing profile handler

* cleanup

* revert color_attachment_4/5 fbo workarounds

* Adjustments to log output and enable GL_BLEND

* Implement glGetQueryObjectui64v on es layer

* Fix deferred and decals support

Also added glGetTexImage(), glQueryCounter() and some additional comments

* Revert changes to default values of graphics options

* Minor improvements to glTexSubImage3D()
2026-05-25 01:30:42 +02:00
wookieejedi 0018f55c55 Fix edge case in switching from None AA to MSAA (#7454)
If you set AA level to None, save, then close the game, then re-enter the game and switch the AA mode to an MSAA mode, then the screen will just be black until the game is restarted. This does not happen when switching from None to FXAA because FXAA works because its post-pass uses `Scene_luminance_texture` and `Scene_ldr_texture`, which are always created as part of standard scene setup.

There are two ways to fix this, either require AA mode to require a game restart (though that may complicate the lab) or allow resource allocation for SMAA always.

Honestly I like the idea of keeping the lower-end machines optimized and not allocating for SMAA but simply running it always but for this PR have just allowed it always run.

Happy to discuss whichever option folks think is best!
2026-05-15 08:46:28 -04:00
Goober5000andClaude Opus 4.6 3f85d6172a use std::move() for local variables that are copied but not reused (#7308)
* use std::move() for local variables that are copied but not reused

Addresses ~140 Coverity "Variable copied when it could be moved"
defects across 74 files.  Every std::move() targets a local variable
whose value is consumed by push_back, emplace, assignment, lambda
capture, or a function call and is never read again afterward.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* clang: use std::make_shared

* clang: use std::make_unique

* address feedback

---------

Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
2026-05-07 14:40:38 +09:00
Goober5000 7e74e35240 Merge pull request #7258 from Goober5000/split_str_once_preliminary_cleanup
preliminary cleanup for split_str_once refactor
2026-04-29 21:53:12 -04:00