Open
Conversation
Move the pure-math vertex/index generation out of `gropengldeferred.cpp` into graphics/util/primitives so it can be reused by the Vulkan backend. Modernize to use `SCP_vector` instead of `vm_malloc`/`vm_free` for automatic memory management.
Replace direct `ImGui_ImplOpenGL3` calls in game code with backend-agnostic `gr_imgui_new_frame` and `gr_imgui_render_draw_data` function pointers, matching the pattern used by all other `gr_*` functions. This makes it possible for the Vulkan backend to provide its own ImGui implemantation.
`bm_close` calls `gf_bm_free_data` for each bitmap slot, which needs the graphics backend (Vulkan texture manager, OpenGL context) to still be alive. Move `bm_close` before the backend cleanup switch in `gr_close`.
`gr_flash_internal` used int vertices with `SCREEN_POS` (`VK_FORMAT_R32G32_SINT`) but the default-material vertex shader expects vec4 float at location 0. OpenGL silently converts via glVertexAttribPointer; Vulkan requires exact type matching. Use float vertices with `POSITION2` format instead. There should be no difference in behavior.
The `SCREEN_POS` vertex format is no longer used after the only use in `gr_flash` was removed. Remove it entirely.
Deduplicate compressed texture block-size mapping and mip-size calculation into two inline helpers in `ddsutils.h`, replacing repeated inline formulas in `ddsutils.cpp` and `gropengltexture.cpp`.
Add a render system capability to indicate whether GPU timestamp query handles can be immediately reused after reading. When queries are not reusable, `free_query_object` returns handles to the backend via `gr_delete_query_object` instead of the tracing free list, letting the backend manage its own reset lifecycle. This greatly simplifies query management for Vulkan. Also change shutdown to discard gpu_events for backends where queries aren't reusable (no more frames will be submitted to make them available).
Move `output_uniform_debug_data` before `gr_reset_immediate_buffer` so debug text is rendered while the immediate buffer still contains valid data. The previous ordering read from a buffer that was already reset to offset 0, which is logically wrong for any backend and a hard failure for deferred-submission backends.
`gr_set_proj_matrix` already branches on rendering_to_texture to choose top-left (RTT) vs bottom-left (screen) viewport origin. `gr_end_2d_matrix` should match, but it unconditionally used the bottom-left formula. Add the same `rendering_to_texture` branch so the viewport is restored correctly when rendering to a texture.
Change `bool clipEnabled` to `uint clipEnabled` in the default-material shader UBO. GLSL bool has implementation-defined std140 layout; uint is portable and matches the SPIR-V decompiled output. Add an else-branch writing `gl_ClipDistance[0] = 1.0` when clipping is disabled. Without this, gl_ClipDistance is undefined and some drivers cull geometry unexpectedly.
…ration
Introduce SHADERS_GL_SHARED and SHADERS_NEED_STRUCT_GEN lists to control
which shaders get GLSL decompilation and C++ struct generation. Currently
all four shaders are in both lists, so behavior is identical. This
prepares for adding Vulkan-only shaders that need SPIR-V compilation but
not GLSL decompilation or struct generation.
Removes the decompiled vulkan shaders (as they're not actually shared
with GL), and Vulkan shader structs (never used).
Fix typo: MAIN_DEPENDENCY referenced undefined ${shader} instead of the
loop variable ${_shader}, silently breaking the dependency tracking for
shader recompilation.
Memcpy from a `const void*` to `void*` is trivial enough. However, this case was missing, resulting in a false positive compilation error.
Implement a Vulkan 1.1 renderer that replaces the previous stub with a fully functional backend, mostly matching the OpenGL backend's rendering capabilities. Core rendering infrastructure: - `VulkanMemory`: Custom allocator with sub-allocation from device-local and host-visible memory pools - `VulkanBuffer`: Per-frame bump allocator for streaming uniform/vertex/index data (persistently mapped, double-buffered, auto-growing) - `VulkanTexture`: Full texture management including 2D, 2D-array, 3D, and cubemap types with automatic mipmap generation and sampler caching - `VulkanPipeline`: Lazy pipeline creation from hashed render state, with persistent VkPipelineCache for cross-session reuse - `VulkanShader`: SPIR-V shader loading (main, deferred, effects, post-processing, shadows, decals, fog, MSAA resolve, etc.) - `VulkanDescriptorManager`: 3-set descriptor layout (Global/Material/PerDraw) with per-frame pool allocation, auto-grow, and batched updates - `VulkanDeletionQueue`: Deferred resource destruction synchronized to frame-in-flight fences Design choices: - Two frames in flight with fence-based synchronization - Asynchronous texture upload, no `waitIdle` in hot path - Single command buffer per frame; render passes begun/ended as needed for the multi-pass deferred pipeline - Per-frame descriptor pools - All descriptor bindings pre-initialized with fallback resources (zero UBO + 1x1 white texture) so partial updates never leave undefined state - Streaming data uses a bump allocator (one large VkBuffer per frame) - Pipeline cache persisted to disk for fast startup on subsequent runs Some notable Vulkan vs OpenGL differences are: - Depth range is [0,1] not [-1,1]: shadow projection matrices adjusted, shaders that linearize depth need isinf/zero guards at depth boundaries where OpenGL gives finite values - gl_ClipDistance is always evaluated: must write 1.0 when clipping is disabled (OpenGL allows leaving it uninitialized) - Swap chain is B8G8R8A8: screenshot/save_screen paths swizzle to RGBA - Vulkan render target is "upside down", y-flip for render target is handled through negative viewport height, as is common - Texture addressing for AABITMAP/INTERFACE/CUBEMAP forced to clamp (OpenGL's sampler state happens to do this implicitly) - Render pass architecture requires explicit transitions between G-buffer, shadow, decal, light accumulation, fog, and post-processing passes (OpenGL just switches FBO bindings)
Member
|
Thanks for the PR! |
Member
|
Okay, played around with it a little. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implement a Vulkan 1.1 renderer that replaces the previous stub with a fully functional backend, mostly matching the OpenGL backend's rendering capabilities. The game should be playable with minimal divergence from OpenGL rendering.
This is, most likely, too big to go in all at once, but just filing it here for reference because it's reached a testable state.
Core rendering infrastructure. The code lives under
code/graphics/vulkan:VulkanMemory: Custom allocator with sub-allocation from device-local and host-visible memory poolsVulkanBuffer: Per-frame bump allocator for streaming uniform/vertex/index data (persistently mapped, double-buffered, auto-growing)VulkanTexture: Full texture management including 2D, 2D-array, 3D, and cubemap types with automatic mipmap generation and sampler cachingVulkanPipeline: Lazy pipeline creation from hashed render state, with persistent VkPipelineCacheVulkanShader: SPIR-V shader loading (main, deferred, effects, post-processing, shadows, decals, fog, MSAA resolve, etc.)VulkanDescriptorManager: 3-set descriptor layout (Global/Material/PerDraw) with per-frame pool allocation, auto-grow, and batched updatesVulkanDeletionQueue: Deferred resource destruction synchronized to frame-in-flight fencesDesign choices:
waitIdleor other CPU-on-GPU blocking in hot pathSome notable Vulkan vs OpenGL differences are:
Preparation patches to common game code (these commits need to go in first):
SCREEN_POSvertex format: Cleanup after previous commitvoid *, const void*What's possibly left to be done:
Unify OpenGL and Vulkan shaders where possible: the only shader shared with OpenGL (defined in the buid system's
SHADERS_GL_SHARED) is still the default material. Although the Vulkan backend does some things differently, it would definitely be possible to share more code. But i didn't want to accidentally break OpenGL in some way.Integrate VMA (Vulkan Memory Allocator). Some of the memory handling could be simplified by importing this dependency.
OpenXR anything. This is currently not implemented at all.
Build steps:
To run (with maximum debugging and Vulkan layer validation):
Full disclosure: i used Claude Opus 4.6 while developing this. However, the overall direction and design is my own, and i've paid careful attention to the code.