Skip to content

Vulkan in fred - #7697

Open
The-E wants to merge 8 commits into
qtfred-post-processingfrom
vulkan-in-fred
Open

The-E wants to merge 8 commits into
qtfred-post-processingfrom
vulkan-in-fred

Conversation

@The-E

@The-E The-E commented Aug 7, 2026

Copy link
Copy Markdown
Member

Recreated from #7673 as part of the stack master ← #7652 ← #7653 ← #7671 ← this (moved to a same-repo branch so gh stack link can register a real GitHub Stack). See #7673 for original review history.


Adds vulkan support to qtFRED. Based on the qtFRED post-processing PR and should be merged after that PR.

@The-E
The-E force-pushed the vulkan-in-fred branch 2 times, most recently from 6f6dd5a to a8bb085 Compare August 20, 2026 14:35
@The-E The-E added qtfred A feature or issue related to qtFred. graphics A feature or issue related to graphics (2d and 3d) labels Aug 25, 2026
@github-project-automation github-project-automation Bot moved this to Work In Progress (PRs) in qtFRED2 Aug 25, 2026
@The-E
The-E force-pushed the vulkan-in-fred branch 2 times, most recently from 81e0cc5 to 68b8365 Compare August 29, 2026 09:17
The-E and others added 3 commits September 14, 2026 18:36
This commit introduces `gr_end_offscreen_frame()` to manage per-frame state recycling for renders that skip `gr_flip()`. It adds generation-based sub-allocation tracking in `VulkanBuffer` to prevent stale memory access after allocator rewinds. Improves resource management, resolves memory growth issues in non-flipping workflows (e.g., qtFRED briefing map), and ensures consistent handling of uniform segments and descriptor pools.

Integrate Vulkan render backend in qtFRED with updated rendering workflows, multi-target support, and enhanced resource lifecycle management.
bindDescriptorSet took a bare const uint32_t*, and the number of entries
vkCmdBindDescriptorSets would read off it came from the set layout, not
from the caller -- so a caller passing too few was undetectable and read
past the end of its own array. Every call site got the length right by
convention: either a *_DYNAMIC_OFFSET_COUNT-sized array or the writer's
storage.

Take ArrayView<uint32_t> instead, which the subsystem already has for
exactly this (VulkanConstants.h, used three lines away in bindSets), and
assert size >= getDynamicOffsetCount(). DescriptorWriter::dynamicOffsets()
returns a view for the same reason. No call site needed touching -- both
the fixed-size arrays and the writer's std::array convert implicitly,
which is the argument for the type.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The-E and others added 5 commits September 14, 2026 18:36
Multi-viewport support introduced a real new concept -- a presentable
surface and everything sized to it -- but gave it nowhere to live. The
struct sat in VulkanRenderer.h and its lifecycle in VulkanRendererSetup.cpp
next to unrelated instance/physical-device/logical-device bring-up, which
pushed that file from 1217 to 1420 lines and VulkanRenderer.cpp past 1000
for the first time.

Move VulkanSurfaceHandle, VulkanPresentTarget and FrameSyncPoint into
VulkanPresentTarget.h, and everything that builds or tears one down into
VulkanPresentTarget.cpp: the surface, swap chain, depth/composition
resources, framebuffers, per-target sync objects, and the choose* helpers
that only createSwapChain/recreateSwapChain ever used. This is the split
VulkanRenderFrame.{h,cpp} already sets the precedent for.

checkSwapChainSupport stops being anonymous-namespace: it is now shared
between the target path and isDeviceUnsuitable, which stays behind with
device selection.

Pure code movement, no behavior change -- verified by diffing the line
multiset of the three original files against all five afterwards. Also
drops a now-dead SDL3/SDL_vulkan.h include, orphaned when the surface
calls moved behind os::VulkanSurfaceProvider.

  VulkanRendererSetup.cpp  1420 -> 935  (master: 1217)
  VulkanRenderer.cpp       1015 -> 806  (master:  956)
  VulkanRenderer.h          787 -> 656  (master:  488)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
VulkanDrawManager grew a third hand-rolled memoization cache with the
shadow pass, each one a key struct plus a set handle plus a valid flag,
each with its own comparison, its own store, and its own line in
resetFrameStats() and invalidateDrawStateCaches(). Three copies of a
pattern is where "did we forget to invalidate one" stops being answerable
by reading.

Fold them into MemoizedDescriptorSet<Inputs, Payload>. The payload is a
parameter because the shadow pass memoizes all three of its sets against a
single key while applyMaterial memoizes one set per key; that grouping is
now expressed as a ShadowSets struct rather than three parallel members.

store() refuses an incomplete payload, which is slightly stronger than
what it replaces: allocateFrameSet() returns a null handle on pool
exhaustion and the Assert() catching it is gone in release builds, so the
old code could cache a null set and hand it to every later draw. The old
read-time null check covered Material and PerDraw but not the shadow sets
at all.

The Global set's cache is deliberately left alone -- it is a dirty-flag
shape with no key struct and does not fit.

Verified in-mission: peak descriptor sets/frame 144 -> 139 with zero
descriptor-pool growth, i.e. the cache still hits.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…location handling.

Unified Vulkan buffer management with `getVkBufferForBinding` to handle outlived streaming bindings safely. Eliminated `clearPendingUniformBindings` to prevent premature state cleanup. Introduced `isFrameAllocCurrent` tracking to avoid stale memory access across frames, ensuring consistent fallback to placeholder buffers for deleted or recycled allocations. Updated descriptor writes and shadow cascades to rely on these safeguards. Fixed various out-of-lifecycle issues in deferred rendering paths and external consumers like qtFRED.
Introduced fallback shadow map textures and samplers for `sampler2DArrayShadow` bindings. Implemented `createFallbackShadowTexture` to generate depth-format fallback textures cleared to the far plane for undefined sampling scenarios. Updated descriptor manager to handle depth-comparison bindings, ensuring correct default behavior when no shadow map is bound. Enhanced lifecycle management for shadow samplers and views.
The rebase onto master brought in "Add Vulkan + Wayland init logic for OpenXR"
(a73e256). Two of its conflicts went to the upstream side, which put back
code that this branch had moved or deleted:

- VulkanRenderer.cpp and VulkanRendererSetup.cpp got a second copy of every
  function that "Give the present target its own home" moved into
  VulkanPresentTarget.cpp, and a second copy of the surface-format, present-mode
  and extent helpers.
- The renderer got its m_swapChain* members back, and the frame loop read them
  again instead of the current target. Several of them no longer existed, so the
  branch did not compile.
- gr_vulkan.cpp got back the OpenXR stubs and stub_use_viewport, which the
  function pointer table no longer points at.

Delete the duplicates and point every reader back at the current target.

The render extent is a new concept from that commit, not a leftover: it is the
size the engine draws at, which -window_res (and therefore -vr) keeps apart from
the window size. Give each present target its own renderExtent so the
distinction survives the refactor. The main target follows the upstream rule and
keeps the value captured before the window existed; qtFRED's extra viewports
draw at their own swap chain extent, because useViewport() resizes gr_screen to
whichever one is current.

Let each target measure its own window as well, so a surface that reports no
extent (Wayland) sizes qtFRED's second window from that window and not from the
main one.

Keep one accessor for the current target's presented size: getSwapChainExtent()
now answers what getCurrentTargetExtent() did, which the upstream commit had
duplicated.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SdYEgS3eTvxWbjkQQp7yvM
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

graphics A feature or issue related to graphics (2d and 3d) qtfred A feature or issue related to qtFred.

Projects

Status: Work In Progress (PRs)

Development

Successfully merging this pull request may close these issues.

1 participant