|
| 1 | +#!/usr/bin/env bash |
| 2 | +# Regression coverage for optional VK_NV_mesh_shader device setup. |
| 3 | +set -euo pipefail |
| 4 | + |
| 5 | +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" |
| 6 | +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" |
| 7 | + |
| 8 | +fail() { |
| 9 | + echo "FAIL: $*" >&2 |
| 10 | + exit 1 |
| 11 | +} |
| 12 | + |
| 13 | +assert_contains() { |
| 14 | + local haystack="$1" |
| 15 | + local needle="$2" |
| 16 | + local context="$3" |
| 17 | + if [[ "$haystack" != *"$needle"* ]]; then |
| 18 | + fail "$context: expected '$needle'" |
| 19 | + fi |
| 20 | +} |
| 21 | + |
| 22 | +line_of() { |
| 23 | + local file="$1" |
| 24 | + local needle="$2" |
| 25 | + awk -v needle="$needle" 'index($0, needle) { print NR; found=1; exit } END { if (!found) exit 1 }' "$file" |
| 26 | +} |
| 27 | + |
| 28 | +line_count() { |
| 29 | + local file="$1" |
| 30 | + local needle="$2" |
| 31 | + awk -v needle="$needle" 'index($0, needle) { count++ } END { print count + 0 }' "$file" |
| 32 | +} |
| 33 | + |
| 34 | +VK_INSTANCE="$PROJECT_ROOT/src/renderers/vulkan/vk_instance.c" |
| 35 | +TR_INIT="$PROJECT_ROOT/src/renderers/vulkan/tr_init.c" |
| 36 | +TR_LOCAL="$PROJECT_ROOT/src/renderers/vulkan/tr_local.h" |
| 37 | +VK_HEADER="$PROJECT_ROOT/src/renderers/vulkan/vk.h" |
| 38 | + |
| 39 | +for required in "$VK_INSTANCE" "$TR_INIT" "$TR_LOCAL" "$VK_HEADER"; do |
| 40 | + [[ -f "$required" ]] || fail "required source file missing: $required" |
| 41 | +done |
| 42 | + |
| 43 | +vk_instance="$(<"$VK_INSTANCE")" |
| 44 | +tr_init="$(<"$TR_INIT")" |
| 45 | +tr_local="$(<"$TR_LOCAL")" |
| 46 | +vk_header="$(<"$VK_HEADER")" |
| 47 | + |
| 48 | +assert_contains "$tr_init" 'r_vk_meshShaderNV = ri.Cvar_Get( "r_vk_meshShaderNV", "0", CVAR_ARCHIVE_ND | CVAR_LATCH );' "mesh shader cvar default and flags" |
| 49 | +assert_contains "$tr_init" 'ri.Cvar_CheckRange( r_vk_meshShaderNV, "0", "1", CV_INTEGER );' "mesh shader cvar range" |
| 50 | +assert_contains "$tr_init" 'Requires vid_restart.' "mesh shader cvar restart documentation" |
| 51 | +assert_contains "$tr_init" 'ri.Cvar_SetGroup( r_vk_meshShaderNV, CVG_RENDERER );' "mesh shader cvar renderer group" |
| 52 | +assert_contains "$tr_local" 'extern cvar_t *r_vk_meshShaderNV;' "mesh shader cvar declaration" |
| 53 | +assert_contains "$vk_header" 'qboolean meshShaderNV;' "mesh shader device state" |
| 54 | + |
| 55 | +assert_contains "$vk_instance" 'qboolean nvMeshShader = qfalse;' "mesh shader extension detection default" |
| 56 | +assert_contains "$vk_instance" 'strcmp( ext, VK_NV_MESH_SHADER_EXTENSION_NAME ) == 0' "mesh shader extension detection" |
| 57 | +assert_contains "$vk_instance" 'vk.meshShaderNV = qfalse;' "mesh shader state reset" |
| 58 | +assert_contains "$vk_instance" 'if ( nvMeshShader && r_vk_meshShaderNV && r_vk_meshShaderNV->integer &&' "mesh shader opt-in gate" |
| 59 | +assert_contains "$vk_instance" 'device_extension_count < ARRAY_LEN( device_extension_list )' "mesh shader extension capacity guard" |
| 60 | +assert_contains "$vk_instance" 'device_extension_list[ device_extension_count++ ] = VK_NV_MESH_SHADER_EXTENSION_NAME;' "mesh shader extension append" |
| 61 | +assert_contains "$vk_instance" 'vk.meshShaderNV = qtrue;' "mesh shader enabled state" |
| 62 | +assert_contains "$vk_instance" '[VK] VK_NV_mesh_shader enabled (experimental; no mesh draw path yet)' "mesh shader startup log" |
| 63 | + |
| 64 | +assert_contains "$vk_instance" '/* Chain last so _DEBUG / host_query pNext lists stay valid. */' "mesh shader pNext chain placement comment" |
| 65 | +assert_contains "$vk_instance" 'if ( vk.meshShaderNV ) {' "mesh shader feature chain gate" |
| 66 | +assert_contains "$vk_instance" 'mesh_shader_features_nv.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV;' "mesh shader feature sType" |
| 67 | +assert_contains "$vk_instance" 'mesh_shader_features_nv.pNext = (void *)(uintptr_t)device_desc.pNext;' "mesh shader preserves previous pNext" |
| 68 | +assert_contains "$vk_instance" 'mesh_shader_features_nv.taskShader = VK_FALSE;' "mesh shader keeps task shaders disabled" |
| 69 | +assert_contains "$vk_instance" 'mesh_shader_features_nv.meshShader = VK_TRUE;' "mesh shader enables only mesh shader feature" |
| 70 | +assert_contains "$vk_instance" 'device_desc.pNext = &mesh_shader_features_nv;' "mesh shader pNext head" |
| 71 | + |
| 72 | +extension_append_count="$(line_count "$VK_INSTANCE" 'VK_NV_MESH_SHADER_EXTENSION_NAME')" |
| 73 | +[[ "$extension_append_count" -eq 2 ]] || fail "expected one detection and one append of VK_NV_mesh_shader; saw $extension_append_count occurrences" |
| 74 | + |
| 75 | +gate_line="$(line_of "$VK_INSTANCE" 'if ( nvMeshShader && r_vk_meshShaderNV && r_vk_meshShaderNV->integer &&')" |
| 76 | +append_line="$(line_of "$VK_INSTANCE" 'device_extension_list[ device_extension_count++ ] = VK_NV_MESH_SHADER_EXTENSION_NAME;')" |
| 77 | +state_line="$(line_of "$VK_INSTANCE" 'vk.meshShaderNV = qtrue;')" |
| 78 | +feature_line="$(line_of "$VK_INSTANCE" 'if ( vk.meshShaderNV ) {')" |
| 79 | +create_line="$(line_of "$VK_INSTANCE" 'qvkCreateDevice( physical_device, &device_desc, NULL, &vk.device )')" |
| 80 | + |
| 81 | +(( gate_line < append_line )) || fail "mesh shader extension append must remain inside the opt-in gate" |
| 82 | +(( append_line < state_line )) || fail "mesh shader state should be set after appending the extension" |
| 83 | +(( state_line < feature_line )) || fail "mesh shader feature chaining must happen after state is set" |
| 84 | +(( feature_line < create_line )) || fail "mesh shader features must be chained before vkCreateDevice" |
| 85 | + |
| 86 | +echo "PASS: test_vulkan_mesh_shader_opt_in" |
0 commit comments