Skip to content

Commit 03803c9

Browse files
authored
Script for testing shaders via GAPID traces (#96)
1 parent 045e96f commit 03803c9

File tree

3 files changed

+207
-0
lines changed

3 files changed

+207
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/usr/bin/env bash
2+
${BASH_SOURCE}.py "$@"
3+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
@echo off
2+
3+
@REM
4+
@REM Copyright 2018 The GraphicsFuzz Project Authors
5+
@REM
6+
@REM Licensed under the Apache License, Version 2.0 (the "License");
7+
@REM you may not use this file except in compliance with the License.
8+
@REM You may obtain a copy of the License at
9+
@REM
10+
@REM https://www.apache.org/licenses/LICENSE-2.0
11+
@REM
12+
@REM Unless required by applicable law or agreed to in writing, software
13+
@REM distributed under the License is distributed on an "AS IS" BASIS,
14+
@REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
@REM See the License for the specific language governing permissions and
16+
@REM limitations under the License.
17+
@REM
18+
19+
python "%~dpn0.py" %*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
#!/usr/bin/env python3
2+
3+
# Copyright 2018 The GraphicsFuzz Project Authors
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# https://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
import sys
18+
import argparse
19+
from pathlib import Path
20+
from typing import List
21+
import subprocess
22+
import re
23+
import typing
24+
25+
# Types:
26+
27+
RunInfo = typing.NamedTuple(
28+
'RunInfo', [
29+
('gapis_port', str),
30+
('shader_source_file', str),
31+
('shader_handle', str),
32+
('orig_capture_id', str),
33+
('output_png', str),
34+
('out_dir', str),
35+
('orig_capture_file', str),
36+
('gapis_log', str),
37+
('frag_files_dir', str)
38+
])
39+
40+
41+
# Regex:
42+
43+
replaced_capture_id_regex = re.compile('New capture id: ([a-z0-9]*)\n')
44+
45+
# When using gapit screenshot filename, the capture ID is output which can be a nice way to
46+
# load a capture into gapis and get its ID.
47+
screenshot_capture_id_regex = re.compile('Getting screenshot from capture id: ([a-z0-9])*\n')
48+
49+
# Commands:
50+
51+
gapit = ['gapit']
52+
gapis = ['gapis']
53+
54+
55+
# Functions:
56+
57+
58+
def call(args: List[str]):
59+
print(" ".join(args))
60+
res = subprocess.run(
61+
args,
62+
stdout=subprocess.PIPE,
63+
stderr=subprocess.PIPE,
64+
check=True,
65+
universal_newlines=True)
66+
print("\nstdout:\n")
67+
print(res.stdout)
68+
print("\nstderr:\n")
69+
print(res.stderr)
70+
print("\nend.\n")
71+
return res
72+
73+
74+
def run_gapit_screenshot_file(info: RunInfo) -> str:
75+
"""
76+
Not used when executed. Could be used if imported into Python shell.
77+
:param info:
78+
:returns capture ID
79+
"""
80+
res = call(gapit + [
81+
'screenshot',
82+
'-gapis-port='+info.gapis_port,
83+
'-out='+info.output_png,
84+
info.orig_capture_file
85+
])
86+
87+
stdout = res.stdout # type: str
88+
new_capture_id = screenshot_capture_id_regex.search(stdout).group(1)
89+
90+
return new_capture_id
91+
92+
93+
def run_gapis(port: str):
94+
"""
95+
Not used when executed. Could be used if imported into Python shell.
96+
97+
:param port:
98+
"""
99+
call(gapis + [
100+
'-persist',
101+
'-rpc', 'localhost:'+port,
102+
])
103+
104+
105+
def run_shader(info: RunInfo):
106+
# Call gapit replace_resource to create a new capture in gapis with the replaced shader source.
107+
# The new capture id is output to stdout.
108+
res = call(gapit + [
109+
'replace_resource',
110+
'-skipoutput=true',
111+
'-resourcepath='+info.shader_source_file,
112+
'-handle='+info.shader_handle,
113+
'-gapis-port='+info.gapis_port,
114+
'-captureid', # This is a bool flag, not an arg that takes a string.
115+
info.orig_capture_id])
116+
117+
stdout = res.stdout # type: str
118+
new_capture_id = replaced_capture_id_regex.search(stdout).group(1)
119+
120+
info = info._replace(
121+
output_png=str(Path(info.out_dir) / (Path(info.shader_source_file).stem + ".png"))
122+
)
123+
124+
# Now call gapit screenshot to capture and write out the screenshot.
125+
res = call(gapit + [
126+
'screenshot',
127+
'-gapis-port='+info.gapis_port,
128+
'-out='+info.output_png,
129+
'-captureid', # This is a bool flag, not an arg that takes a string.
130+
new_capture_id
131+
])
132+
133+
134+
def run_shader_family(info: RunInfo):
135+
frag_dir = Path(info.frag_files_dir)
136+
for f in frag_dir.iterdir():
137+
if f.is_file() and f.name.endswith('.frag'):
138+
info = info._replace(
139+
shader_source_file=str(frag_dir / f)
140+
)
141+
run_shader(info)
142+
143+
144+
def go(argv):
145+
146+
parser = argparse.ArgumentParser(
147+
formatter_class=argparse.RawDescriptionHelpFormatter,
148+
description="Run shaders via gapid. First:\n"
149+
"$ gapis -enable-local-files -persist -rpc 'localhost:40000'\n"
150+
"$ gapit screenshot -gapis-port 40000 capture.linear.gfxtrace (and make a note "
151+
"of the capture id)")
152+
153+
parser.add_argument("frag_files_dir", type=str, action="store",
154+
help="directory containing .frag files")
155+
parser.add_argument("gapis_port", type=str, action="store",
156+
help="port on which gapis is listening")
157+
parser.add_argument("shader_handle", type=str, action="store",
158+
help="the shader handle within the capture in gapis that should be "
159+
"replaced")
160+
parser.add_argument("orig_capture_id", type=str, action="store",
161+
help="the capture id that is already loaded in gapis "
162+
"(e.g. via gapit screenshot)")
163+
parser.add_argument("out_dir", type=str, action="store",
164+
help="the output directory that will receive .png files")
165+
166+
args = parser.parse_args(argv)
167+
168+
info = RunInfo(
169+
args.gapis_port,
170+
'',
171+
args.shader_handle,
172+
args.orig_capture_id,
173+
'',
174+
args.out_dir,
175+
'',
176+
'',
177+
args.frag_files_dir
178+
)
179+
180+
run_shader_family(info)
181+
182+
183+
if __name__ == "__main__":
184+
go(sys.argv[1:])
185+

0 commit comments

Comments
 (0)