1617a3babSopenharmony_ci#!/bin/bash
2617a3babSopenharmony_ci
3617a3babSopenharmony_ci# This script validates shaders (if successfully compiled) using spirv-val.
4617a3babSopenharmony_ci# It is not meant to preclude the possible addition of the validator to
5617a3babSopenharmony_ci# glslang.
6617a3babSopenharmony_ci
7617a3babSopenharmony_cideclare -r EXE='../build/install/bin/glslang'
8617a3babSopenharmony_ci
9617a3babSopenharmony_ci# search common locations for spirv-tools: keep first one
10617a3babSopenharmony_cifor toolsdir in '../External/spirv-tools/build/tools' '../../SPIRV-Tools/build/tools/bin' '/usr/local/bin'; do
11617a3babSopenharmony_ci    [[ -z "$VAL" && -x "${toolsdir}/spirv-val" ]] && declare -r VAL="${toolsdir}/spirv-val"
12617a3babSopenharmony_ci    [[ -z "$DIS" && -x "${toolsdir}/spirv-dis" ]] && declare -r DIS="${toolsdir}/spirv-dis"
13617a3babSopenharmony_cidone
14617a3babSopenharmony_ci
15617a3babSopenharmony_cideclare -r gtests='../gtests/Hlsl.FromFile.cpp ../gtests/Spv.FromFile.cpp'
16617a3babSopenharmony_ci
17617a3babSopenharmony_cideclare -r targetenv='vulkan1.0'
18617a3babSopenharmony_ci
19617a3babSopenharmony_cifunction fatal() { echo "ERROR: $@"; exit 5; }
20617a3babSopenharmony_ci
21617a3babSopenharmony_cifunction usage
22617a3babSopenharmony_ci{
23617a3babSopenharmony_ci    echo
24617a3babSopenharmony_ci    echo "Usage: $(basename $0) [options...] shaders..."
25617a3babSopenharmony_ci    echo
26617a3babSopenharmony_ci    echo "   Validates shaders (if successfully compiled) through spirv-val."
27617a3babSopenharmony_ci    echo
28617a3babSopenharmony_ci    echo "General options:"
29617a3babSopenharmony_ci    echo "   --help          prints this text"
30617a3babSopenharmony_ci    echo "   --no-color      disables output colorization"
31617a3babSopenharmony_ci    echo "   --dump-asm      dumps all successfully compiled shader assemblies"
32617a3babSopenharmony_ci    echo "   --dump-val      dumps all validation results"
33617a3babSopenharmony_ci    echo "   --dump-comp     dumps all compilation logs"
34617a3babSopenharmony_ci    echo "Spam reduction options:"
35617a3babSopenharmony_ci    echo "   --no-summary    disables result summaries"
36617a3babSopenharmony_ci    echo "   --skip-ok       do not print successful validations"
37617a3babSopenharmony_ci    echo "   --skip-comperr  do not print compilation errors"
38617a3babSopenharmony_ci    echo "   --skip-valerr   do not print validation errors"
39617a3babSopenharmony_ci    echo "   --quiet         synonym for --skip-ok --skip-comperr --skip-valerr --no-summary"
40617a3babSopenharmony_ci    echo "   --terse         print terse single line progress summary"
41617a3babSopenharmony_ci    echo "Disassembly options:"
42617a3babSopenharmony_ci    echo "   --raw-id        uses raw ids for disassembly"
43617a3babSopenharmony_ci    echo
44617a3babSopenharmony_ci    echo "Usage examples.  Note most non-hlsl tests fail to compile for expected reasons."
45617a3babSopenharmony_ci    echo "   Exercise all hlsl.* files:"
46617a3babSopenharmony_ci    echo "       $(basename $0) hlsl.*"
47617a3babSopenharmony_ci    echo "   Exercise all hlsl.* files, tersely:"
48617a3babSopenharmony_ci    echo "       $(basename $0) --terse hlsl.*"
49617a3babSopenharmony_ci    echo "   Print validator output for myfile.frag:"
50617a3babSopenharmony_ci    echo "       $(basename $0) --quiet --dump-val myfile.frag"
51617a3babSopenharmony_ci    echo "   Exercise hlsl.* files, only printing validation errors:"
52617a3babSopenharmony_ci    echo "       $(basename $0) --skip-ok --skip-comperr hlsl.*"
53617a3babSopenharmony_ci
54617a3babSopenharmony_ci    exit 5
55617a3babSopenharmony_ci}
56617a3babSopenharmony_ci
57617a3babSopenharmony_cifunction status()
58617a3babSopenharmony_ci{
59617a3babSopenharmony_ci    printf "%-40s: %b\n" "$1" "$2"
60617a3babSopenharmony_ci}
61617a3babSopenharmony_ci
62617a3babSopenharmony_ci# make sure we can find glslang
63617a3babSopenharmony_ci[[ -x "$EXE" ]] || fatal "Unable to locate $(basename "$EXE") executable"
64617a3babSopenharmony_ci[[ -x "$VAL" ]] || fatal "Unable to locate spirv-val executable"
65617a3babSopenharmony_ci[[ -x "$DIS" ]] || fatal "Unable to locate spirv-dis executable"
66617a3babSopenharmony_ci
67617a3babSopenharmony_cifor gtest in $gtests; do
68617a3babSopenharmony_ci    [[ -r "$gtest" ]] || fatal "Unable to locate source file: $(basename $gtest)"
69617a3babSopenharmony_cidone
70617a3babSopenharmony_ci
71617a3babSopenharmony_ci# temp files
72617a3babSopenharmony_cideclare -r spvfile='out.spv' \
73617a3babSopenharmony_ci        complog='comp.out' \
74617a3babSopenharmony_ci        vallog='val.out' \
75617a3babSopenharmony_ci        dislog='dis.out' \
76617a3babSopenharmony_ci
77617a3babSopenharmony_ci# options
78617a3babSopenharmony_cideclare opt_vallog=false \
79617a3babSopenharmony_ci        opt_complog=false \
80617a3babSopenharmony_ci        opt_dislog=false \
81617a3babSopenharmony_ci        opt_summary=true \
82617a3babSopenharmony_ci        opt_stat_comperr=true \
83617a3babSopenharmony_ci        opt_stat_ok=true \
84617a3babSopenharmony_ci        opt_stat_valerr=true \
85617a3babSopenharmony_ci        opt_color=true \
86617a3babSopenharmony_ci        opt_raw_id=false \
87617a3babSopenharmony_ci        opt_quiet=false \
88617a3babSopenharmony_ci        opt_terse=false
89617a3babSopenharmony_ci
90617a3babSopenharmony_ci# clean up on exit
91617a3babSopenharmony_citrap "rm -f ${spvfile} ${complog} ${vallog} ${dislog}" EXIT
92617a3babSopenharmony_ci
93617a3babSopenharmony_ci# Language guesser: there is no fixed mapping from filenames to language,
94617a3babSopenharmony_ci# so this examines the file and return one of:
95617a3babSopenharmony_ci#     hlsl
96617a3babSopenharmony_ci#     glsl
97617a3babSopenharmony_ci#     bin
98617a3babSopenharmony_ci#     unknown
99617a3babSopenharmony_ci# This is easier WRT future expansion than a big explicit list.
100617a3babSopenharmony_cifunction FindLanguage()
101617a3babSopenharmony_ci{
102617a3babSopenharmony_ci    local test="$1"
103617a3babSopenharmony_ci
104617a3babSopenharmony_ci    # If it starts with hlsl, assume it's hlsl.
105617a3babSopenharmony_ci    if [[ "$test" == *hlsl.* ]]; then
106617a3babSopenharmony_ci        echo hlsl
107617a3babSopenharmony_ci        return
108617a3babSopenharmony_ci    fi
109617a3babSopenharmony_ci
110617a3babSopenharmony_ci    if [[ "$test" == *.spv ]]; then
111617a3babSopenharmony_ci        echo bin
112617a3babSopenharmony_ci        return;
113617a3babSopenharmony_ci    fi
114617a3babSopenharmony_ci
115617a3babSopenharmony_ci    # If it doesn't start with spv., assume it's GLSL.
116617a3babSopenharmony_ci    if [[ ! "$test" == spv.* && ! "$test" == remap.* ]]; then
117617a3babSopenharmony_ci        echo glsl
118617a3babSopenharmony_ci        return
119617a3babSopenharmony_ci    fi
120617a3babSopenharmony_ci
121617a3babSopenharmony_ci    # Otherwise, attempt to guess from shader contents, since there's no
122617a3babSopenharmony_ci    # fixed mapping of filenames to languages.
123617a3babSopenharmony_ci    local contents="$(cat "$test")"
124617a3babSopenharmony_ci
125617a3babSopenharmony_ci    if [[ "$contents" == *#version* ]]; then
126617a3babSopenharmony_ci        echo glsl
127617a3babSopenharmony_ci        return
128617a3babSopenharmony_ci    fi
129617a3babSopenharmony_ci
130617a3babSopenharmony_ci    if [[ "$contents" == *SamplerState* ||
131617a3babSopenharmony_ci          "$contents" == *cbuffer* ||
132617a3babSopenharmony_ci          "$contents" == *SV_* ]]; then
133617a3babSopenharmony_ci        echo hlsl
134617a3babSopenharmony_ci        return
135617a3babSopenharmony_ci    fi
136617a3babSopenharmony_ci
137617a3babSopenharmony_ci    echo unknown
138617a3babSopenharmony_ci}
139617a3babSopenharmony_ci
140617a3babSopenharmony_ci# Attempt to discover entry point
141617a3babSopenharmony_cifunction FindEntryPoint()
142617a3babSopenharmony_ci{
143617a3babSopenharmony_ci    local test="$1"
144617a3babSopenharmony_ci
145617a3babSopenharmony_ci    # if it's not hlsl, always use main
146617a3babSopenharmony_ci    if [[ "$language" != 'hlsl' ]]; then
147617a3babSopenharmony_ci        echo 'main'
148617a3babSopenharmony_ci        return
149617a3babSopenharmony_ci    fi
150617a3babSopenharmony_ci
151617a3babSopenharmony_ci    # Try to find it in test sources
152617a3babSopenharmony_ci    awk -F '[ (){",]+' -e "\$2 == \"${test}\" { print \$3; found=1; } END { if (found==0) print \"main\"; } " $gtests
153617a3babSopenharmony_ci}
154617a3babSopenharmony_ci
155617a3babSopenharmony_ci# command line options
156617a3babSopenharmony_ciwhile [ $# -gt 0 ]
157617a3babSopenharmony_cido
158617a3babSopenharmony_ci    case "$1" in
159617a3babSopenharmony_ci        # -c) glslang="$2"; shift 2;;
160617a3babSopenharmony_ci        --help|-?)      usage;;
161617a3babSopenharmony_ci        --no-color)     opt_color=false;        shift;;
162617a3babSopenharmony_ci        --no-summary)   opt_summary=false;      shift;;
163617a3babSopenharmony_ci        --skip-ok)      opt_stat_ok=false;      shift;;
164617a3babSopenharmony_ci        --skip-comperr) opt_stat_comperr=false; shift;;
165617a3babSopenharmony_ci        --skip-valerr)  opt_stat_valerr=false;  shift;;
166617a3babSopenharmony_ci        --dump-asm)     opt_dislog=true;        shift;;
167617a3babSopenharmony_ci        --dump-val)     opt_vallog=true;        shift;;
168617a3babSopenharmony_ci        --dump-comp)    opt_complog=true;       shift;;
169617a3babSopenharmony_ci        --raw-id)       opt_raw_id=true;        shift;;
170617a3babSopenharmony_ci        --quiet)        opt_quiet=true;         shift;;
171617a3babSopenharmony_ci        --terse)        opt_quiet=true
172617a3babSopenharmony_ci                        opt_terse=true
173617a3babSopenharmony_ci                        shift;;
174617a3babSopenharmony_ci        --*)            fatal "Unknown command line option: $1";;
175617a3babSopenharmony_ci        *) break;;
176617a3babSopenharmony_ci    esac
177617a3babSopenharmony_cidone
178617a3babSopenharmony_ci
179617a3babSopenharmony_ci# this is what quiet means
180617a3babSopenharmony_ciif $opt_quiet; then
181617a3babSopenharmony_ci    opt_stat_ok=false
182617a3babSopenharmony_ci    opt_stat_comperr=false
183617a3babSopenharmony_ci    opt_stat_valerr=false
184617a3babSopenharmony_ci    $opt_terse || opt_summary=false
185617a3babSopenharmony_cifi
186617a3babSopenharmony_ci
187617a3babSopenharmony_ciif $opt_color; then
188617a3babSopenharmony_ci    declare -r white="\e[1;37m" cyan="\e[1;36m" red="\e[0;31m" no_color="\e[0m"
189617a3babSopenharmony_cielse
190617a3babSopenharmony_ci    declare -r white="" cyan="" red="" no_color=""
191617a3babSopenharmony_cifi
192617a3babSopenharmony_ci
193617a3babSopenharmony_ci# stats
194617a3babSopenharmony_cideclare -i count_ok=0 count_err=0 count_nocomp=0 count_total=0
195617a3babSopenharmony_ci
196617a3babSopenharmony_cideclare -r dashsep='------------------------------------------------------------------------'
197617a3babSopenharmony_ci
198617a3babSopenharmony_citestfiles=(${@})
199617a3babSopenharmony_ci# if no shaders given, look for everything in current directory
200617a3babSopenharmony_ci[[ ${#testfiles[*]} == 0 ]] && testfiles=(*.frag *.vert *.tesc *.tese *.geom *.comp)
201617a3babSopenharmony_ci
202617a3babSopenharmony_ci$opt_summary && printf "\nValidating: ${#testfiles[*]} shaders\n\n"
203617a3babSopenharmony_ci
204617a3babSopenharmony_ci# Loop through the shaders we were given, compiling them if we can.
205617a3babSopenharmony_cifor test in ${testfiles[*]}
206617a3babSopenharmony_cido
207617a3babSopenharmony_ci    if [[ ! -r "$test" ]]; then
208617a3babSopenharmony_ci        $opt_quiet || status "$test" "${red}FILE NOT FOUND${no_color}"
209617a3babSopenharmony_ci        continue
210617a3babSopenharmony_ci    fi
211617a3babSopenharmony_ci
212617a3babSopenharmony_ci    ((++count_total))
213617a3babSopenharmony_ci
214617a3babSopenharmony_ci    $opt_terse && printf "\r[%-3d/%-3d : ${white}comperr=%-3d ${red}valerr=%-3d ${cyan}ok=%-3d${no_color}]" \
215617a3babSopenharmony_ci                         ${count_total} ${#testfiles[*]} ${count_nocomp} ${count_err} ${count_ok}
216617a3babSopenharmony_ci
217617a3babSopenharmony_ci    language="$(FindLanguage $test)"
218617a3babSopenharmony_ci    entry="$(FindEntryPoint $test)"
219617a3babSopenharmony_ci    langops=''
220617a3babSopenharmony_ci
221617a3babSopenharmony_ci    case "$language" in
222617a3babSopenharmony_ci        hlsl) langops='-D --hlsl-iomap --hlsl-offsets';;
223617a3babSopenharmony_ci        glsl) ;;
224617a3babSopenharmony_ci        bin) continue;;   # skip binaries
225617a3babSopenharmony_ci        *) $opt_quiet || status "$test" "${red}UNKNOWN LANGUAGE${no_color}"; continue;;
226617a3babSopenharmony_ci    esac
227617a3babSopenharmony_ci
228617a3babSopenharmony_ci    # compile the test file
229617a3babSopenharmony_ci    if compout=$("$EXE" -e "$entry" $langops -V -o "$spvfile" "$test" 2>&1)
230617a3babSopenharmony_ci    then
231617a3babSopenharmony_ci        # successful compilation: validate
232617a3babSopenharmony_ci        if valout=$("$VAL" --target-env ${targetenv} "$spvfile" 2>&1)
233617a3babSopenharmony_ci        then
234617a3babSopenharmony_ci            # validated OK
235617a3babSopenharmony_ci            $opt_stat_ok && status "$test" "${cyan}OK${no_color}"
236617a3babSopenharmony_ci            ((++count_ok))
237617a3babSopenharmony_ci        else
238617a3babSopenharmony_ci            # validation failure
239617a3babSopenharmony_ci            $opt_stat_valerr && status "$test" "${red}VAL ERROR${no_color}"
240617a3babSopenharmony_ci            printf "%s\n%s:\n%s\n" "$dashsep" "$test" "$valout" >> "$vallog"
241617a3babSopenharmony_ci            ((++count_err))
242617a3babSopenharmony_ci        fi
243617a3babSopenharmony_ci
244617a3babSopenharmony_ci        if $opt_dislog; then
245617a3babSopenharmony_ci            printf "%s\n%s:\n" "$dashsep" "$test" >> "$dislog"
246617a3babSopenharmony_ci            $opt_raw_id && id_opt=--raw-id
247617a3babSopenharmony_ci            "$DIS" ${id_opt} "$spvfile" >> "$dislog"
248617a3babSopenharmony_ci        fi
249617a3babSopenharmony_ci    else
250617a3babSopenharmony_ci        # compile failure
251617a3babSopenharmony_ci        $opt_stat_comperr && status "$test" "${white}COMP ERROR${no_color}"
252617a3babSopenharmony_ci        printf "%s\n%s\n" "$dashsep" "$compout" >> "$complog"
253617a3babSopenharmony_ci        ((++count_nocomp))
254617a3babSopenharmony_ci    fi
255617a3babSopenharmony_cidone
256617a3babSopenharmony_ci
257617a3babSopenharmony_ci$opt_terse && echo
258617a3babSopenharmony_ci
259617a3babSopenharmony_ci# summarize
260617a3babSopenharmony_ci$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"
261617a3babSopenharmony_ci
262617a3babSopenharmony_ci# dump logs
263617a3babSopenharmony_ci$opt_vallog  && [[ -r $vallog ]]  && cat "$vallog"
264617a3babSopenharmony_ci$opt_complog && [[ -r $complog ]] && cat "$complog"
265617a3babSopenharmony_ci$opt_dislog  && [[ -r $dislog ]]  && cat "$dislog"
266617a3babSopenharmony_ci
267617a3babSopenharmony_ci# exit code
268617a3babSopenharmony_ci[[ ${count_err} -gt 0 ]] && exit 1
269617a3babSopenharmony_ciexit 0
270