Skip to content

Commit 15c58e9

Browse files
cursoragenttimfox
andcommitted
Vulkan RT: gate extensions on GPU features and enable device feature chain
- Load vkGetPhysicalDeviceFeatures2; require bufferDeviceAddress, accelerationStructure, and rayTracingPipeline before enabling RT extensions. - Chain VkPhysicalDeviceFeatures2 + KHR BDA/AS/ray-tracing feature structs into VkDeviceCreateInfo when RT is on (valid device creation with these extensions). - Avoid duplicate buffer-device-address feature struct in _DEBUG when RT active. - Log RT status from vk.rtxExtensionsEnabled; update RENDERERS_FUTURE, TODO_TRIAGE, CLAUDE.md; remove stale README ray-tracing disclaimer. Co-authored-by: Tim Fox <timfox@outlook.com>
1 parent 8d6297b commit 15c58e9

9 files changed

Lines changed: 108 additions & 20 deletions

File tree

CLAUDE.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ This document serves as the **constitutional contract** for the idTech3 engine f
2828
-**Performance**: Minimal overhead when disabled
2929

3030
#### Ray Tracing (RTX)
31-
- 🔶 **Planned**: Vulkan `VK_KHR_ray_tracing_pipeline` scaffolding; extensions probed
31+
- 🔶 **In progress**: With `USE_VULKAN_RTX=ON`, the Vulkan device enables **KHR buffer device address**, **acceleration structure**, and **ray tracing pipeline** when the GPU reports the required features (not extension names alone).
3232
-**Hardware Support**: NVIDIA RTX / AMD RDNA2+ via Vulkan RT or DXR
3333
-**Quality Levels**: Multiple presets (performance/balanced/quality)
3434
-**Fallback**: Graceful degradation on non-RT hardware
35-
-**Integration**: Hybrid raster + RT (shadows/reflections) or full RT path
35+
-**Integration**: BLAS/TLAS, shader binding table, and hybrid raster + RT frame path
3636
- See [docs/RENDERERS_FUTURE.md](docs/RENDERERS_FUTURE.md)
3737

3838
#### Modern C/C++ Standards

README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ Modern id Tech 3: **Vulkan-first renderer with PBR**, optional OpenGL fallback,
1212
2. **Tooling** - GPU detection, validation layers, performance HUD, safe mode, CI matrix builds, smoke tests and shader validation in the build.
1313
3. **Platform** - Linux, Windows, macOS, Android; IPv4/IPv6 networking, modern codecs and asset loaders.
1414

15-
Ray tracing (Vulkan RT) is **scaffolded / in progress** - see `docs/RENDERERS_FUTURE.md` and `CLAUDE.md` for status, not a headline guarantee.
16-
1715
### Features (by area)
1816

1917
**Rendering**:

docs/RENDERERS_FUTURE.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ This document outlines the architecture and implementation plan for three render
88
|---------|--------|-------|
99
| **Vulkan** | ✅ Complete | Primary renderer, ~18k LOC |
1010
| **OpenGL** | ✅ Complete | Fallback renderer |
11-
| **Vulkan RTX** | 🔶 Stub only | Ray tracing extensions probed; no pipeline |
11+
| **Vulkan RTX** | 🔶 Device path | With `USE_VULKAN_RTX=ON`, extensions plus **buffer device address**, **acceleration structure**, and **ray tracing pipeline** features are enabled when the GPU supports them (`vkGetPhysicalDeviceFeatures2` gate). BLAS/TLAS, SBT, and hybrid frame integration remain to be wired. |
1212
| **Metal** | ❌ Not started | Native Apple Silicon / macOS |
1313
| **DXR** | ❌ Not started | DirectX 12 + DirectX Raytracing (Windows) |
1414

@@ -26,10 +26,10 @@ This document outlines the architecture and implementation plan for three render
2626

2727
### Implementation Phases
2828

29-
1. **Extension enablement** (`vk_instance.c` / `vk_device.c` device creation)
30-
- Add ray tracing extensions to `device_extension_list` when available
31-
- Query `VkPhysicalDeviceRayTracingPipelinePropertiesKHR`
32-
- Load `vkCreateRayTracingPipelinesKHR`, `vkCmdTraceRaysKHR`, etc.
29+
1. **Extension + feature enablement** (`vk_instance.c` device creation)
30+
- Add ray tracing extensions to `device_extension_list` when available **and** `vkGetPhysicalDeviceFeatures2` reports `bufferDeviceAddress`, `accelerationStructure`, and `rayTracingPipeline`
31+
- Chain `VkPhysicalDeviceFeatures2` + `VkPhysicalDeviceBufferDeviceAddressFeaturesKHR` + `VkPhysicalDeviceAccelerationStructureFeaturesKHR` + `VkPhysicalDeviceRayTracingPipelineFeaturesKHR` into `VkDeviceCreateInfo` (required for valid device creation with these extensions)
32+
- Next: query `VkPhysicalDeviceRayTracingPipelinePropertiesKHR`, load `vkCreateRayTracingPipelinesKHR`, `vkCmdTraceRaysKHR`, etc.
3333

3434
2. **Acceleration structures**
3535
- **BLAS**: Build from BSP world geometry + entity models (vertex/index buffers)

docs/TODO_TRIAGE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ TODOs/FIXMEs in `src/external/` are from third-party code (duktape, zstd, cjson,
6262
| r_renderMode 1/2 | tr_init.c | Deferred / alternate-pipeline placeholders (`r_renderMode`); not wired to Vulkan **optional** Forward+ (`r_forwardPlus`). Real deferred still needs G-buffers, etc. Documented in cvar description. |
6363
| r_hdr 3 64-bit output | `vk_post_process_pipeline.c`, HDR format helpers | Infrastructure in place (vk_hdr64_active, _hdr64 modules, pipeline selection). glslangValidator rejects dvec4/f64vec4 fragment shader outputs. Falls back to RGBA32F. When glslang adds support, compile HDR64 variants and return RGBA64F from get_hdr_format. |
6464
| Vegetation wind draw | `vk_vegetation_wind.c` + draw path | Compute **dispatch** now runs **after** each `SURF_VEGETATION` tess batch (staging was previously uploaded *after* the misplaced `vk_begin_frame` dispatch, so GPU saw 0 verts). **Vertex shader still does not read** `vegwind_vertex_buffer` - deformed positions are not yet applied on draw. |
65-
| Vulkan RTX | CMake `USE_VULKAN_RTX`, renderer init | Extensions can be requested when `USE_VULKAN_RTX=ON` and GPU supports them. Pipeline (BLAS/TLAS, shaders) not yet implemented. See `docs/RENDERERS_FUTURE.md`. |
65+
| Vulkan RTX | CMake `USE_VULKAN_RTX`, `vk_instance.c` | Device creation enables KHR RT extensions when present **and** `vkGetPhysicalDeviceFeatures2` reports buffer-device-address + acceleration-structure + ray-tracing-pipeline features; `VkDeviceCreateInfo` chains the required feature structs. BLAS/TLAS, SBT, and frame integration still TODO. See `docs/RENDERERS_FUTURE.md`. |
6666

6767
## Subsystem audit log (rolling)
6868

src/renderers/vulkan/vk.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1144,6 +1144,7 @@ typedef struct {
11441144
qboolean debugMarkers;
11451145
qboolean colorWriteMaskDynamic;
11461146
qboolean meshShaderNV; /* VK_NV_mesh_shader enabled at device create (r_vk_meshShaderNV); no mesh pipelines yet */
1147+
qboolean rtxExtensionsEnabled; /* USE_VULKAN_RTX: KHR AS + RT pipeline + deferred host ops + buffer device address enabled at device create */
11471148

11481149
float maxAnisotropy;
11491150
float maxLod;

src/renderers/vulkan/vk_init_device.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -426,10 +426,14 @@ void vk_initialize( void )
426426
features.multiViewport ? "yes" : "no" );
427427
ri.Printf( PRINT_ALL, "[VK] Sampler Anisotropy : %s\n",
428428
features.samplerAnisotropy ? "yes" : "no" );
429-
#ifdef VK_KHR_RAY_TRACING_PIPELINE
430-
ri.Printf( PRINT_ALL, "[VK] Ray Tracing : available\n" );
429+
#ifdef USE_VULKAN_RTX
430+
if ( vk.rtxExtensionsEnabled ) {
431+
ri.Printf( PRINT_ALL, "[VK] Ray Tracing : enabled (KHR AS + RT pipeline + buffer device address)\n" );
432+
} else {
433+
ri.Printf( PRINT_ALL, "[VK] Ray Tracing : build on, GPU/extensions unavailable\n" );
434+
}
431435
#else
432-
ri.Printf( PRINT_ALL, "[VK] Ray Tracing : not available\n" );
436+
ri.Printf( PRINT_ALL, "[VK] Ray Tracing : not built (enable USE_VULKAN_RTX)\n" );
433437
#endif
434438
ri.Printf( PRINT_ALL, "[VK] Compute Pipelines : enabled\n" );
435439
ri.Printf( PRINT_ALL, "[VK] First Person Rendering : enabled (r_firstPersonFov, r_firstPersonScale, r_firstPersonZNear)\n" );

src/renderers/vulkan/vk_instance.c

Lines changed: 90 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,12 @@ static qboolean vk_create_device( VkPhysicalDevice physical_device, int device_i
188188
VkPhysicalDevice8BitStorageFeatures storage_8bit_features;
189189
#endif
190190
VkPhysicalDeviceMeshShaderFeaturesNV mesh_shader_features_nv;
191+
#ifdef USE_VULKAN_RTX
192+
VkPhysicalDeviceFeatures2 rtx_device_features2;
193+
VkPhysicalDeviceBufferDeviceAddressFeaturesKHR rtx_bda_features;
194+
VkPhysicalDeviceAccelerationStructureFeaturesKHR rtx_as_features;
195+
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtx_rtp_features;
196+
#endif
191197

192198
ri.Printf( PRINT_ALL, "...selected physical device: %i\n", device_index );
193199

@@ -502,13 +508,52 @@ static qboolean vk_create_device( VkPhysicalDevice physical_device, int device_i
502508
vk.colorWriteMaskDynamic = qfalse;
503509
}
504510
#ifdef USE_VULKAN_RTX
505-
if ( rtxAccelStruct && rtxPipeline && rtxDeferredHostOps && rtxBufferDeviceAddress && memoryRequirements2 ) {
506-
device_extension_list[ device_extension_count++ ] = VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME;
507-
device_extension_list[ device_extension_count++ ] = "VK_KHR_deferred_host_operations";
508-
device_extension_list[ device_extension_count++ ] = VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME;
509-
device_extension_list[ device_extension_count++ ] = VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME;
510-
ri.Printf( PRINT_ALL, "[VK] Ray tracing extensions enabled (r_rtx available)\n" );
511+
{
512+
const qboolean rtxExtPresent = rtxAccelStruct && rtxPipeline && rtxDeferredHostOps && rtxBufferDeviceAddress && memoryRequirements2;
513+
qboolean rtxGpuCapable = qfalse;
514+
515+
if ( rtxExtPresent && qvkGetPhysicalDeviceFeatures2 != NULL ) {
516+
VkPhysicalDeviceFeatures2 qf2;
517+
VkPhysicalDeviceBufferDeviceAddressFeaturesKHR qbda;
518+
VkPhysicalDeviceAccelerationStructureFeaturesKHR qas;
519+
VkPhysicalDeviceRayTracingPipelineFeaturesKHR qrtp;
520+
521+
Com_Memset( &qf2, 0, sizeof( qf2 ) );
522+
Com_Memset( &qbda, 0, sizeof( qbda ) );
523+
Com_Memset( &qas, 0, sizeof( qas ) );
524+
Com_Memset( &qrtp, 0, sizeof( qrtp ) );
525+
qf2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
526+
qf2.pNext = &qbda;
527+
qbda.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR;
528+
qbda.pNext = &qas;
529+
qas.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR;
530+
qas.pNext = &qrtp;
531+
qrtp.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR;
532+
qrtp.pNext = NULL;
533+
qvkGetPhysicalDeviceFeatures2( physical_device, &qf2 );
534+
rtxGpuCapable = ( qbda.bufferDeviceAddress && qas.accelerationStructure && qrtp.rayTracingPipeline ) ? qtrue : qfalse;
535+
if ( !rtxGpuCapable ) {
536+
ri.Printf( PRINT_DEVELOPER, "[VK] Ray tracing extensions present but required GPU features are off "
537+
"(bufferDeviceAddress=%u accelerationStructure=%u rayTracingPipeline=%u); RT disabled\n",
538+
(unsigned)qbda.bufferDeviceAddress, (unsigned)qas.accelerationStructure, (unsigned)qrtp.rayTracingPipeline );
539+
}
540+
} else if ( rtxExtPresent && qvkGetPhysicalDeviceFeatures2 == NULL ) {
541+
ri.Printf( PRINT_WARNING, "[VK] Ray tracing extensions present but vkGetPhysicalDeviceFeatures2 is unavailable; RT disabled\n" );
542+
}
543+
544+
if ( rtxExtPresent && rtxGpuCapable ) {
545+
device_extension_list[ device_extension_count++ ] = VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME;
546+
device_extension_list[ device_extension_count++ ] = VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME;
547+
device_extension_list[ device_extension_count++ ] = VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME;
548+
device_extension_list[ device_extension_count++ ] = VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME;
549+
vk.rtxExtensionsEnabled = qtrue;
550+
ri.Printf( PRINT_ALL, "[VK] Ray tracing path: KHR extensions + GPU features enabled (buffer device address, acceleration structure, ray tracing pipeline)\n" );
551+
} else {
552+
vk.rtxExtensionsEnabled = qfalse;
553+
}
511554
}
555+
#else
556+
vk.rtxExtensionsEnabled = qfalse;
512557
#endif
513558
if ( nvMeshShader && r_vk_meshShaderNV && r_vk_meshShaderNV->integer &&
514559
device_extension_count < ARRAY_LEN( device_extension_list ) ) {
@@ -606,7 +651,11 @@ static qboolean vk_create_device( VkPhysicalDevice physical_device, int device_i
606651
pNextPtr = (const void **)&memory_model.pNext;
607652
}
608653

609-
if ( devAddrFeat ) {
654+
if ( devAddrFeat
655+
#ifdef USE_VULKAN_RTX
656+
&& !vk.rtxExtensionsEnabled
657+
#endif
658+
) {
610659
*pNextPtr = &devaddr_features;
611660
devaddr_features.pNext = NULL;
612661
devaddr_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES;
@@ -646,6 +695,39 @@ static qboolean vk_create_device( VkPhysicalDevice physical_device, int device_i
646695
device_desc.pNext = &mesh_shader_features_nv;
647696
}
648697

698+
#ifdef USE_VULKAN_RTX
699+
if ( vk.rtxExtensionsEnabled ) {
700+
Com_Memset( &rtx_device_features2, 0, sizeof( rtx_device_features2 ) );
701+
Com_Memset( &rtx_bda_features, 0, sizeof( rtx_bda_features ) );
702+
Com_Memset( &rtx_as_features, 0, sizeof( rtx_as_features ) );
703+
Com_Memset( &rtx_rtp_features, 0, sizeof( rtx_rtp_features ) );
704+
Com_Memcpy( &rtx_device_features2.features, &features, sizeof( features ) );
705+
rtx_device_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
706+
rtx_device_features2.pNext = &rtx_bda_features;
707+
rtx_bda_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR;
708+
rtx_bda_features.pNext = &rtx_as_features;
709+
rtx_bda_features.bufferDeviceAddress = VK_TRUE;
710+
rtx_bda_features.bufferDeviceAddressCaptureReplay = VK_FALSE;
711+
rtx_bda_features.bufferDeviceAddressMultiDevice = VK_FALSE;
712+
rtx_as_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR;
713+
rtx_as_features.pNext = &rtx_rtp_features;
714+
rtx_as_features.accelerationStructure = VK_TRUE;
715+
rtx_as_features.accelerationStructureCaptureReplay = VK_FALSE;
716+
rtx_as_features.accelerationStructureIndirectBuild = VK_FALSE;
717+
rtx_as_features.accelerationStructureHostCommands = VK_FALSE;
718+
rtx_as_features.descriptorBindingAccelerationStructureUpdateAfterBind = VK_FALSE;
719+
rtx_rtp_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR;
720+
rtx_rtp_features.pNext = (void *)(uintptr_t)device_desc.pNext;
721+
rtx_rtp_features.rayTracingPipeline = VK_TRUE;
722+
rtx_rtp_features.rayTracingPipelineShaderGroupHandleCaptureReplay = VK_FALSE;
723+
rtx_rtp_features.rayTracingPipelineShaderGroupHandleCaptureReplayMixed = VK_FALSE;
724+
rtx_rtp_features.rayTracingPipelineTraceRaysIndirect = VK_FALSE;
725+
rtx_rtp_features.rayTraversalPrimitiveCulling = VK_FALSE;
726+
device_desc.pNext = &rtx_device_features2;
727+
device_desc.pEnabledFeatures = NULL;
728+
}
729+
#endif
730+
649731
res = qvkCreateDevice( physical_device, &device_desc, NULL, &vk.device );
650732
if ( res < 0 ) {
651733
ri.Printf( PRINT_ERROR, "vkCreateDevice returned %s\n", vk_result_string( res ) );
@@ -709,6 +791,7 @@ void vk_init_vulkan_library( void )
709791
INIT_INSTANCE_FUNCTION( vkEnumeratePhysicalDevices )
710792
INIT_INSTANCE_FUNCTION( vkGetDeviceProcAddr )
711793
INIT_INSTANCE_FUNCTION( vkGetPhysicalDeviceFeatures )
794+
INIT_INSTANCE_FUNCTION_EXT( vkGetPhysicalDeviceFeatures2 )
712795
INIT_INSTANCE_FUNCTION( vkGetPhysicalDeviceFormatProperties )
713796
INIT_INSTANCE_FUNCTION( vkGetPhysicalDeviceMemoryProperties )
714797
INIT_INSTANCE_FUNCTION( vkGetPhysicalDeviceProperties )

src/renderers/vulkan/vk_procs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ PFN_vkEnumerateDeviceExtensionProperties qvkEnumerateDeviceExtensionProperties
2020
PFN_vkEnumeratePhysicalDevices qvkEnumeratePhysicalDevices;
2121
PFN_vkGetDeviceProcAddr qvkGetDeviceProcAddr;
2222
PFN_vkGetPhysicalDeviceFeatures qvkGetPhysicalDeviceFeatures;
23+
PFN_vkGetPhysicalDeviceFeatures2 qvkGetPhysicalDeviceFeatures2;
2324
PFN_vkGetPhysicalDeviceFormatProperties qvkGetPhysicalDeviceFormatProperties;
2425
PFN_vkGetPhysicalDeviceMemoryProperties qvkGetPhysicalDeviceMemoryProperties;
2526
PFN_vkGetPhysicalDeviceProperties qvkGetPhysicalDeviceProperties;

src/renderers/vulkan/vk_procs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ extern PFN_vkEnumerateDeviceExtensionProperties qvkEnumerateDeviceExtensionPro
1414
extern PFN_vkEnumeratePhysicalDevices qvkEnumeratePhysicalDevices;
1515
extern PFN_vkGetDeviceProcAddr qvkGetDeviceProcAddr;
1616
extern PFN_vkGetPhysicalDeviceFeatures qvkGetPhysicalDeviceFeatures;
17+
extern PFN_vkGetPhysicalDeviceFeatures2 qvkGetPhysicalDeviceFeatures2;
1718
extern PFN_vkGetPhysicalDeviceFormatProperties qvkGetPhysicalDeviceFormatProperties;
1819
extern PFN_vkGetPhysicalDeviceMemoryProperties qvkGetPhysicalDeviceMemoryProperties;
1920
extern PFN_vkGetPhysicalDeviceProperties qvkGetPhysicalDeviceProperties;

0 commit comments

Comments
 (0)