1#!/bin/bash 2 3# This script validates shaders (if successfully compiled) using spirv-val. 4# It is not meant to preclude the possible addition of the validator to 5# glslang. 6 7declare -r EXE='../build/install/bin/glslang' 8 9# search common locations for spirv-tools: keep first one 10for toolsdir in '../External/spirv-tools/build/tools' '../../SPIRV-Tools/build/tools/bin' '/usr/local/bin'; do 11 [[ -z "$VAL" && -x "${toolsdir}/spirv-val" ]] && declare -r VAL="${toolsdir}/spirv-val" 12 [[ -z "$DIS" && -x "${toolsdir}/spirv-dis" ]] && declare -r DIS="${toolsdir}/spirv-dis" 13done 14 15declare -r gtests='../gtests/Hlsl.FromFile.cpp ../gtests/Spv.FromFile.cpp' 16 17declare -r targetenv='vulkan1.0' 18 19function fatal() { echo "ERROR: $@"; exit 5; } 20 21function usage 22{ 23 echo 24 echo "Usage: $(basename $0) [options...] shaders..." 25 echo 26 echo " Validates shaders (if successfully compiled) through spirv-val." 27 echo 28 echo "General options:" 29 echo " --help prints this text" 30 echo " --no-color disables output colorization" 31 echo " --dump-asm dumps all successfully compiled shader assemblies" 32 echo " --dump-val dumps all validation results" 33 echo " --dump-comp dumps all compilation logs" 34 echo "Spam reduction options:" 35 echo " --no-summary disables result summaries" 36 echo " --skip-ok do not print successful validations" 37 echo " --skip-comperr do not print compilation errors" 38 echo " --skip-valerr do not print validation errors" 39 echo " --quiet synonym for --skip-ok --skip-comperr --skip-valerr --no-summary" 40 echo " --terse print terse single line progress summary" 41 echo "Disassembly options:" 42 echo " --raw-id uses raw ids for disassembly" 43 echo 44 echo "Usage examples. Note most non-hlsl tests fail to compile for expected reasons." 45 echo " Exercise all hlsl.* files:" 46 echo " $(basename $0) hlsl.*" 47 echo " Exercise all hlsl.* files, tersely:" 48 echo " $(basename $0) --terse hlsl.*" 49 echo " Print validator output for myfile.frag:" 50 echo " $(basename $0) --quiet --dump-val myfile.frag" 51 echo " Exercise hlsl.* files, only printing validation errors:" 52 echo " $(basename $0) --skip-ok --skip-comperr hlsl.*" 53 54 exit 5 55} 56 57function status() 58{ 59 printf "%-40s: %b\n" "$1" "$2" 60} 61 62# make sure we can find glslang 63[[ -x "$EXE" ]] || fatal "Unable to locate $(basename "$EXE") executable" 64[[ -x "$VAL" ]] || fatal "Unable to locate spirv-val executable" 65[[ -x "$DIS" ]] || fatal "Unable to locate spirv-dis executable" 66 67for gtest in $gtests; do 68 [[ -r "$gtest" ]] || fatal "Unable to locate source file: $(basename $gtest)" 69done 70 71# temp files 72declare -r spvfile='out.spv' \ 73 complog='comp.out' \ 74 vallog='val.out' \ 75 dislog='dis.out' \ 76 77# options 78declare opt_vallog=false \ 79 opt_complog=false \ 80 opt_dislog=false \ 81 opt_summary=true \ 82 opt_stat_comperr=true \ 83 opt_stat_ok=true \ 84 opt_stat_valerr=true \ 85 opt_color=true \ 86 opt_raw_id=false \ 87 opt_quiet=false \ 88 opt_terse=false 89 90# clean up on exit 91trap "rm -f ${spvfile} ${complog} ${vallog} ${dislog}" EXIT 92 93# Language guesser: there is no fixed mapping from filenames to language, 94# so this examines the file and return one of: 95# hlsl 96# glsl 97# bin 98# unknown 99# This is easier WRT future expansion than a big explicit list. 100function FindLanguage() 101{ 102 local test="$1" 103 104 # If it starts with hlsl, assume it's hlsl. 105 if [[ "$test" == *hlsl.* ]]; then 106 echo hlsl 107 return 108 fi 109 110 if [[ "$test" == *.spv ]]; then 111 echo bin 112 return; 113 fi 114 115 # If it doesn't start with spv., assume it's GLSL. 116 if [[ ! "$test" == spv.* && ! "$test" == remap.* ]]; then 117 echo glsl 118 return 119 fi 120 121 # Otherwise, attempt to guess from shader contents, since there's no 122 # fixed mapping of filenames to languages. 123 local contents="$(cat "$test")" 124 125 if [[ "$contents" == *#version* ]]; then 126 echo glsl 127 return 128 fi 129 130 if [[ "$contents" == *SamplerState* || 131 "$contents" == *cbuffer* || 132 "$contents" == *SV_* ]]; then 133 echo hlsl 134 return 135 fi 136 137 echo unknown 138} 139 140# Attempt to discover entry point 141function FindEntryPoint() 142{ 143 local test="$1" 144 145 # if it's not hlsl, always use main 146 if [[ "$language" != 'hlsl' ]]; then 147 echo 'main' 148 return 149 fi 150 151 # Try to find it in test sources 152 awk -F '[ (){",]+' -e "\$2 == \"${test}\" { print \$3; found=1; } END { if (found==0) print \"main\"; } " $gtests 153} 154 155# command line options 156while [ $# -gt 0 ] 157do 158 case "$1" in 159 # -c) glslang="$2"; shift 2;; 160 --help|-?) usage;; 161 --no-color) opt_color=false; shift;; 162 --no-summary) opt_summary=false; shift;; 163 --skip-ok) opt_stat_ok=false; shift;; 164 --skip-comperr) opt_stat_comperr=false; shift;; 165 --skip-valerr) opt_stat_valerr=false; shift;; 166 --dump-asm) opt_dislog=true; shift;; 167 --dump-val) opt_vallog=true; shift;; 168 --dump-comp) opt_complog=true; shift;; 169 --raw-id) opt_raw_id=true; shift;; 170 --quiet) opt_quiet=true; shift;; 171 --terse) opt_quiet=true 172 opt_terse=true 173 shift;; 174 --*) fatal "Unknown command line option: $1";; 175 *) break;; 176 esac 177done 178 179# this is what quiet means 180if $opt_quiet; then 181 opt_stat_ok=false 182 opt_stat_comperr=false 183 opt_stat_valerr=false 184 $opt_terse || opt_summary=false 185fi 186 187if $opt_color; then 188 declare -r white="\e[1;37m" cyan="\e[1;36m" red="\e[0;31m" no_color="\e[0m" 189else 190 declare -r white="" cyan="" red="" no_color="" 191fi 192 193# stats 194declare -i count_ok=0 count_err=0 count_nocomp=0 count_total=0 195 196declare -r dashsep='------------------------------------------------------------------------' 197 198testfiles=(${@}) 199# if no shaders given, look for everything in current directory 200[[ ${#testfiles[*]} == 0 ]] && testfiles=(*.frag *.vert *.tesc *.tese *.geom *.comp) 201 202$opt_summary && printf "\nValidating: ${#testfiles[*]} shaders\n\n" 203 204# Loop through the shaders we were given, compiling them if we can. 205for test in ${testfiles[*]} 206do 207 if [[ ! -r "$test" ]]; then 208 $opt_quiet || status "$test" "${red}FILE NOT FOUND${no_color}" 209 continue 210 fi 211 212 ((++count_total)) 213 214 $opt_terse && printf "\r[%-3d/%-3d : ${white}comperr=%-3d ${red}valerr=%-3d ${cyan}ok=%-3d${no_color}]" \ 215 ${count_total} ${#testfiles[*]} ${count_nocomp} ${count_err} ${count_ok} 216 217 language="$(FindLanguage $test)" 218 entry="$(FindEntryPoint $test)" 219 langops='' 220 221 case "$language" in 222 hlsl) langops='-D --hlsl-iomap --hlsl-offsets';; 223 glsl) ;; 224 bin) continue;; # skip binaries 225 *) $opt_quiet || status "$test" "${red}UNKNOWN LANGUAGE${no_color}"; continue;; 226 esac 227 228 # compile the test file 229 if compout=$("$EXE" -e "$entry" $langops -V -o "$spvfile" "$test" 2>&1) 230 then 231 # successful compilation: validate 232 if valout=$("$VAL" --target-env ${targetenv} "$spvfile" 2>&1) 233 then 234 # validated OK 235 $opt_stat_ok && status "$test" "${cyan}OK${no_color}" 236 ((++count_ok)) 237 else 238 # validation failure 239 $opt_stat_valerr && status "$test" "${red}VAL ERROR${no_color}" 240 printf "%s\n%s:\n%s\n" "$dashsep" "$test" "$valout" >> "$vallog" 241 ((++count_err)) 242 fi 243 244 if $opt_dislog; then 245 printf "%s\n%s:\n" "$dashsep" "$test" >> "$dislog" 246 $opt_raw_id && id_opt=--raw-id 247 "$DIS" ${id_opt} "$spvfile" >> "$dislog" 248 fi 249 else 250 # compile failure 251 $opt_stat_comperr && status "$test" "${white}COMP ERROR${no_color}" 252 printf "%s\n%s\n" "$dashsep" "$compout" >> "$complog" 253 ((++count_nocomp)) 254 fi 255done 256 257$opt_terse && echo 258 259# summarize 260$opt_summary && printf "\nSummary: ${white}${count_nocomp} compile errors${no_color}, ${red}${count_err} validation errors${no_color}, ${cyan}${count_ok} successes${no_color}\n" 261 262# dump logs 263$opt_vallog && [[ -r $vallog ]] && cat "$vallog" 264$opt_complog && [[ -r $complog ]] && cat "$complog" 265$opt_dislog && [[ -r $dislog ]] && cat "$dislog" 266 267# exit code 268[[ ${count_err} -gt 0 ]] && exit 1 269exit 0 270