Add basic setup for regression testing Metal output.

This commit is contained in:
Hans-Kristian Arntzen 2017-01-18 19:05:57 +01:00
parent 3535f88bc1
commit 1c28ec6885
6 changed files with 89 additions and 6 deletions

View File

@ -24,3 +24,4 @@ script:
- make -j2
- PATH=./glslang/StandAlone:./SPIRV-Tools/tools:$PATH
- ./test_shaders.py shaders
- ./test_shaders.py --metal shaders-msl

View File

@ -93,6 +93,9 @@ if (${PYTHONINTERP_FOUND})
add_test(NAME spirv-cross-test
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py
${CMAKE_CURRENT_SOURCE_DIR}/shaders)
add_test(NAME spirv-cross-test-metal
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --metal
${CMAKE_CURRENT_SOURCE_DIR}/shaders-msl)
endif()
else()
message(WARNING "Testing disabled. Could not find python3. If you have python3 installed try running "

View File

@ -171,6 +171,8 @@ In these cases, run `./test_shaders.py shaders --update` to update the reference
Always make sure you are running up to date glslangValidator as well as SPIRV-Tools when updating reference files.
In short, the master branch should always be able to run `./test_shaders.py shaders` without failure.
SPIRV-Cross uses Travis CI to test all pull requests, so it is not strictly needed to perform testing yourself if you have problems running it locally.
A pull request which does not pass testing on Travis will not be accepted however.
When adding support for new features to SPIRV-Cross, a new shader and reference file should be added which covers usage of the new shader features in question.
@ -205,6 +207,10 @@ The current reference output is contained in reference/.
See `./test_shaders.py --help` for more.
### Metal backend
To test the roundtrip path GLSL -> SPIR-V -> MSL, `--metal` can be added, e.g. `./test_shaders.py --metal shaders-msl`.
### Updating regression tests
When legitimate changes are found, use `--update` flag to update regression files.

View File

@ -0,0 +1,32 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct UBO
{
float4x4 uMVP;
};
struct main0_in
{
float4 aVertex [[attribute(0)]];
float3 aNormal [[attribute(0)]];
};
struct main0_out
{
float3 vNormal [[user(locn0)]];
float4 gl_Position [[position]];
float gl_PointSize;
};
vertex main0_out main0(main0_in in [[stage_in]], constant UBO& _16 [[buffer(0)]])
{
main0_out out = {};
out.gl_Position = _16.uMVP * in.aVertex;
out.vNormal = in.aNormal;
out.gl_Position.y = -(out.gl_Position.y); // Invert Y-axis for Metal
return out;
}

View File

@ -0,0 +1,15 @@
#version 310 es
layout(std140) uniform UBO
{
uniform mat4 uMVP;
};
in vec4 aVertex;
in vec3 aNormal;
out vec3 vNormal;
void main()
{
gl_Position = uMVP * aVertex;
vNormal = aNormal;
}

View File

@ -66,6 +66,19 @@ def validate_shader(shader, vulkan):
else:
subprocess.check_call(['glslangValidator', shader])
def cross_compile_msl(shader):
spirv_f, spirv_path = tempfile.mkstemp()
msl_f, msl_path = tempfile.mkstemp(suffix = os.path.basename(shader))
os.close(spirv_f)
os.close(msl_f)
subprocess.check_call(['glslangValidator', '-V', '-o', spirv_path, shader])
spirv_cross_path = './spirv-cross'
subprocess.check_call([spirv_cross_path, '--entry', 'main', '--output', msl_path, spirv_path, '--metal'])
subprocess.check_call(['spirv-val', spirv_path])
# TODO: Add optional validation of the MSL output.
return (spirv_path, msl_path)
def cross_compile(shader, vulkan, spirv, invalid_spirv, eliminate, is_legacy, flatten_ubo):
spirv_f, spirv_path = tempfile.mkstemp()
glsl_f, glsl_path = tempfile.mkstemp(suffix = os.path.basename(shader))
@ -212,20 +225,30 @@ def test_shader(stats, shader, update, keep):
a.append(str(i))
print(','.join(a), file = stats)
def test_shaders_helper(stats, shader_dir, update, malisc, keep):
def test_shader_msl(stats, shader, update, keep):
joined_path = os.path.join(shader[0], shader[1])
print('Testing MSL shader:', joined_path)
spirv, msl = cross_compile_msl(joined_path)
regression_check(shader, msl, update, keep)
os.remove(spirv)
def test_shaders_helper(stats, shader_dir, update, malisc, keep, backend):
for root, dirs, files in os.walk(os.path.join(shader_dir)):
for i in files:
path = os.path.join(root, i)
relpath = os.path.relpath(path, shader_dir)
test_shader(stats, (shader_dir, relpath), update, keep)
if backend == 'metal':
test_shader_msl(stats, (shader_dir, relpath), update, keep)
else:
test_shader(stats, (shader_dir, relpath), update, keep)
def test_shaders(shader_dir, update, malisc, keep):
def test_shaders(shader_dir, update, malisc, keep, backend):
if malisc:
with open('stats.csv', 'w') as stats:
print('Shader,OrigRegs,OrigUniRegs,OrigALUShort,OrigLSShort,OrigTEXShort,OrigALULong,OrigLSLong,OrigTEXLong,CrossRegs,CrossUniRegs,CrossALUShort,CrossLSShort,CrossTEXShort,CrossALULong,CrossLSLong,CrossTEXLong', file = stats)
test_shaders_helper(stats, shader_dir, update, malisc, keep)
test_shaders_helper(stats, shader_dir, update, malisc, keep, backend)
else:
test_shaders_helper(None, shader_dir, update, malisc, keep)
test_shaders_helper(None, shader_dir, update, malisc, keep, backend)
def main():
parser = argparse.ArgumentParser(description = 'Script for regression testing.')
@ -240,13 +263,16 @@ def main():
parser.add_argument('--malisc',
action = 'store_true',
help = 'Use malisc offline compiler to determine static cycle counts before and after spirv-cross.')
parser.add_argument('--metal',
action = 'store_true',
help = 'Test Metal backend.')
args = parser.parse_args()
if not args.folder:
sys.stderr.write('Need shader folder.\n')
sys.exit(1)
test_shaders(args.folder, args.update, args.malisc, args.keep)
test_shaders(args.folder, args.update, args.malisc, args.keep, 'metal' if args.metal else 'glsl')
if args.malisc:
print('Stats in stats.csv!')
print('Tests completed!')