1e5c31af7Sopenharmony_ci# Copyright 2021 Google LLC.
2e5c31af7Sopenharmony_ci# Copyright 2021 The Khronos Group Inc.
3e5c31af7Sopenharmony_ci#
4e5c31af7Sopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License");
5e5c31af7Sopenharmony_ci# you may not use this file except in compliance with the License.
6e5c31af7Sopenharmony_ci# You may obtain a copy of the License at
7e5c31af7Sopenharmony_ci#
8e5c31af7Sopenharmony_ci#     https://www.apache.org/licenses/LICENSE-2.0
9e5c31af7Sopenharmony_ci#
10e5c31af7Sopenharmony_ci# Unless required by applicable law or agreed to in writing, software
11e5c31af7Sopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS,
12e5c31af7Sopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e5c31af7Sopenharmony_ci# See the License for the specific language governing permissions and
14e5c31af7Sopenharmony_ci# limitations under the License.
15e5c31af7Sopenharmony_ci
16e5c31af7Sopenharmony_ci# Requirements to run the script:
17e5c31af7Sopenharmony_ci# - Python3 (apt-get install -y python3.x)
18e5c31af7Sopenharmony_ci# - GO      (apt-get install -y golang-go)
19e5c31af7Sopenharmony_ci# - cmake   (version 3.13 or later)
20e5c31af7Sopenharmony_ci# - ninja   (apt-get install -y ninja-build)
21e5c31af7Sopenharmony_ci# - git     (sudo apt-get install -y git)
22e5c31af7Sopenharmony_ci
23e5c31af7Sopenharmony_ci# GO dependencies needed:
24e5c31af7Sopenharmony_ci# - crypto/openpgp (go get -u golang.org/x/crypto/openpgp...)
25e5c31af7Sopenharmony_ci
26e5c31af7Sopenharmony_ciimport os
27e5c31af7Sopenharmony_ciimport json
28e5c31af7Sopenharmony_ciimport tempfile
29e5c31af7Sopenharmony_ciimport subprocess
30e5c31af7Sopenharmony_ciimport sys
31e5c31af7Sopenharmony_ci
32e5c31af7Sopenharmony_cifrom argparse import ArgumentParser
33e5c31af7Sopenharmony_cifrom shutil import which, copyfile
34e5c31af7Sopenharmony_cifrom pathlib import Path
35e5c31af7Sopenharmony_cifrom datetime import datetime
36e5c31af7Sopenharmony_ci
37e5c31af7Sopenharmony_ci# Check for correct python version (python3) before doing anything.
38e5c31af7Sopenharmony_ciif sys.version_info.major < 3:
39e5c31af7Sopenharmony_ci        raise RuntimeError("Python version needs to be 3 or greater.")
40e5c31af7Sopenharmony_ci
41e5c31af7Sopenharmony_ciAP = ArgumentParser()
42e5c31af7Sopenharmony_ciAP.add_argument(
43e5c31af7Sopenharmony_ci    "-d",
44e5c31af7Sopenharmony_ci    "--directory",
45e5c31af7Sopenharmony_ci    metavar="DIRECTORY",
46e5c31af7Sopenharmony_ci    type=str,
47e5c31af7Sopenharmony_ci    help="Path to directory that will be used as root for cloning and file saving.",
48e5c31af7Sopenharmony_ci    default=str(Path(tempfile.gettempdir()) / "deqp-swiftshader")
49e5c31af7Sopenharmony_ci)
50e5c31af7Sopenharmony_ciAP.add_argument(
51e5c31af7Sopenharmony_ci    "-u",
52e5c31af7Sopenharmony_ci    "--url",
53e5c31af7Sopenharmony_ci    metavar="URL",
54e5c31af7Sopenharmony_ci    type=str,
55e5c31af7Sopenharmony_ci    help="URL of SwiftShader Git repository.",
56e5c31af7Sopenharmony_ci    default="https://swiftshader.googlesource.com/SwiftShader",
57e5c31af7Sopenharmony_ci)
58e5c31af7Sopenharmony_ciAP.add_argument(
59e5c31af7Sopenharmony_ci    "-l",
60e5c31af7Sopenharmony_ci    "--vlayer_url",
61e5c31af7Sopenharmony_ci    metavar="VURL",
62e5c31af7Sopenharmony_ci    type=str,
63e5c31af7Sopenharmony_ci    help="URL of Validation Layers Git repository.",
64e5c31af7Sopenharmony_ci    default="https://github.com/KhronosGroup/Vulkan-ValidationLayers.git",
65e5c31af7Sopenharmony_ci)
66e5c31af7Sopenharmony_ciAP.add_argument(
67e5c31af7Sopenharmony_ci    "-b",
68e5c31af7Sopenharmony_ci    "--sws_build_type",
69e5c31af7Sopenharmony_ci    metavar="SWS_BUILD_TYPE",
70e5c31af7Sopenharmony_ci    type=str,
71e5c31af7Sopenharmony_ci    help="SwiftShader build type.",
72e5c31af7Sopenharmony_ci    choices=["debug", "release"],
73e5c31af7Sopenharmony_ci    default="debug",
74e5c31af7Sopenharmony_ci)
75e5c31af7Sopenharmony_ciAP.add_argument(
76e5c31af7Sopenharmony_ci    "-q",
77e5c31af7Sopenharmony_ci    "--deqp_vk",
78e5c31af7Sopenharmony_ci    metavar="DEQP_VK",
79e5c31af7Sopenharmony_ci    type=str,
80e5c31af7Sopenharmony_ci    help="Path to deqp-vk binary.",
81e5c31af7Sopenharmony_ci)
82e5c31af7Sopenharmony_ciAP.add_argument(
83e5c31af7Sopenharmony_ci    "-v",
84e5c31af7Sopenharmony_ci    "--vk_gl_cts",
85e5c31af7Sopenharmony_ci    metavar="VK_GL_CTS",
86e5c31af7Sopenharmony_ci    type=str,
87e5c31af7Sopenharmony_ci    help="Path to vk-gl-cts source directory.",
88e5c31af7Sopenharmony_ci)
89e5c31af7Sopenharmony_ciAP.add_argument(
90e5c31af7Sopenharmony_ci    "-w",
91e5c31af7Sopenharmony_ci    "--vk_gl_cts_build",
92e5c31af7Sopenharmony_ci    metavar="VK_GL_CTS_BUILD",
93e5c31af7Sopenharmony_ci    type=str,
94e5c31af7Sopenharmony_ci    help="Path to vk-gl-cts build directory.",
95e5c31af7Sopenharmony_ci    default=str(Path(tempfile.gettempdir()) / "deqp-swiftshader" / "vk-gl-cts-build"),
96e5c31af7Sopenharmony_ci)
97e5c31af7Sopenharmony_ciAP.add_argument(
98e5c31af7Sopenharmony_ci    "-t",
99e5c31af7Sopenharmony_ci    "--vk_gl_cts_build_type",
100e5c31af7Sopenharmony_ci    metavar="VK_GL_CTS_BUILD_TYPE",
101e5c31af7Sopenharmony_ci    type=str,
102e5c31af7Sopenharmony_ci    help="vk-gl-cts build type.",
103e5c31af7Sopenharmony_ci    choices=["debug", "release"],
104e5c31af7Sopenharmony_ci    default="debug",
105e5c31af7Sopenharmony_ci)
106e5c31af7Sopenharmony_ciAP.add_argument(
107e5c31af7Sopenharmony_ci    "-r",
108e5c31af7Sopenharmony_ci    "--recipe",
109e5c31af7Sopenharmony_ci    metavar="RECIPE",
110e5c31af7Sopenharmony_ci    type=str,
111e5c31af7Sopenharmony_ci    help="Recipes to only run parts of script.",
112e5c31af7Sopenharmony_ci    choices=["run-deqp", "check-comparison"],
113e5c31af7Sopenharmony_ci    default="run-deqp",
114e5c31af7Sopenharmony_ci)
115e5c31af7Sopenharmony_ciAP.add_argument(
116e5c31af7Sopenharmony_ci    "-f",
117e5c31af7Sopenharmony_ci    "--files",
118e5c31af7Sopenharmony_ci    nargs=2,
119e5c31af7Sopenharmony_ci    metavar=("NEWER_FILE_PATH", "OLDER_FILE_PATH"),
120e5c31af7Sopenharmony_ci    type=str,
121e5c31af7Sopenharmony_ci    help="Compare two different run results.",
122e5c31af7Sopenharmony_ci)
123e5c31af7Sopenharmony_ciAP.add_argument(
124e5c31af7Sopenharmony_ci    "-a",
125e5c31af7Sopenharmony_ci    "--validation",
126e5c31af7Sopenharmony_ci    metavar="VALIDATION",
127e5c31af7Sopenharmony_ci    type=str,
128e5c31af7Sopenharmony_ci    help="Enable vulkan validation layers.",
129e5c31af7Sopenharmony_ci    choices=["true", "false"],
130e5c31af7Sopenharmony_ci    default="false",
131e5c31af7Sopenharmony_ci)
132e5c31af7Sopenharmony_ciAP.add_argument(
133e5c31af7Sopenharmony_ci    "-o",
134e5c31af7Sopenharmony_ci    "--result_output",
135e5c31af7Sopenharmony_ci    metavar="OUTPUT",
136e5c31af7Sopenharmony_ci    type=str,
137e5c31af7Sopenharmony_ci    help="Filename of the regres results.",
138e5c31af7Sopenharmony_ci    default=str("result_" + str(datetime.now().strftime('%m_%d_%Y_%H_%M_%S')) + ".json"),
139e5c31af7Sopenharmony_ci)
140e5c31af7Sopenharmony_ci
141e5c31af7Sopenharmony_ciARGS = AP.parse_args()
142e5c31af7Sopenharmony_ci
143e5c31af7Sopenharmony_ci# Check that we have everything needed to run the script when using recipe run-deqp.
144e5c31af7Sopenharmony_ciif ARGS.recipe == "run-deqp":
145e5c31af7Sopenharmony_ci    if which("go") is None:
146e5c31af7Sopenharmony_ci        raise RuntimeError("go not found. (apt-get install -y golang-go)")
147e5c31af7Sopenharmony_ci    if which("cmake") is None:
148e5c31af7Sopenharmony_ci        raise RuntimeError("CMake not found. (version 3.13 or later needed)")
149e5c31af7Sopenharmony_ci    if which("ninja") is None:
150e5c31af7Sopenharmony_ci        raise RuntimeError("Ninja not found. (apt-get install -y ninja-build)")
151e5c31af7Sopenharmony_ci    if which("git") is None:
152e5c31af7Sopenharmony_ci        raise RuntimeError("Git not found. (apt-get install -y git)")
153e5c31af7Sopenharmony_ci    if ARGS.vk_gl_cts is None:
154e5c31af7Sopenharmony_ci        raise RuntimeError("vk-gl-cts source directory must be provided. Use --help for more info.")
155e5c31af7Sopenharmony_ci
156e5c31af7Sopenharmony_ciPARENT_DIR = Path(ARGS.directory).resolve()
157e5c31af7Sopenharmony_ci
158e5c31af7Sopenharmony_ciSWS_SRC_DIR = PARENT_DIR / "SwiftShader"
159e5c31af7Sopenharmony_ciSWS_BUILD_DIR = SWS_SRC_DIR / "build"
160e5c31af7Sopenharmony_ciSWIFTSHADER_URL = ARGS.url
161e5c31af7Sopenharmony_ci
162e5c31af7Sopenharmony_ciLAYERS_PARENT_DIR = Path(ARGS.directory).resolve()
163e5c31af7Sopenharmony_ciLAYERS_SRC_DIR = LAYERS_PARENT_DIR / "Vulkan_Validation_Layers"
164e5c31af7Sopenharmony_ciLAYERS_URL = ARGS.vlayer_url
165e5c31af7Sopenharmony_ciLAYERS_BUILD_DIR = LAYERS_SRC_DIR / "build"
166e5c31af7Sopenharmony_ci
167e5c31af7Sopenharmony_ciLINUX_SWS_ICD_DIR = SWS_BUILD_DIR / "Linux"
168e5c31af7Sopenharmony_ciREGRES_DIR = SWS_SRC_DIR / "tests" / "regres"
169e5c31af7Sopenharmony_ciRESULT_DIR = PARENT_DIR / "regres_results"
170e5c31af7Sopenharmony_ciCOMP_RESULTS_DIR = PARENT_DIR / "comparison_results"
171e5c31af7Sopenharmony_ci
172e5c31af7Sopenharmony_ciVK_GL_CTS_ROOT_DIR = Path(ARGS.vk_gl_cts)
173e5c31af7Sopenharmony_ciVK_GL_CTS_BUILD_DIR = Path(ARGS.vk_gl_cts_build)
174e5c31af7Sopenharmony_ciMUSTPASS_LIST = VK_GL_CTS_ROOT_DIR / "external" / "vulkancts" / "mustpass" / "master" / "vk-default.txt"
175e5c31af7Sopenharmony_ciif ARGS.deqp_vk is None:
176e5c31af7Sopenharmony_ci    DEQP_VK_BINARY = VK_GL_CTS_BUILD_DIR / "external" / "vulkancts" / "modules" / "vulkan" / "deqp-vk"
177e5c31af7Sopenharmony_cielse:
178e5c31af7Sopenharmony_ci    DEQP_VK_BINARY = str(ARGS.deqp_vk)
179e5c31af7Sopenharmony_ci
180e5c31af7Sopenharmony_cinew_pass = []
181e5c31af7Sopenharmony_cinew_fail = []
182e5c31af7Sopenharmony_cinew_crash = []
183e5c31af7Sopenharmony_cinew_notsupported = []
184e5c31af7Sopenharmony_cihas_been_removed = []
185e5c31af7Sopenharmony_cistatus_change = []
186e5c31af7Sopenharmony_cicompatibility_warning = []
187e5c31af7Sopenharmony_ciquality_warning = []
188e5c31af7Sopenharmony_ciinternal_errors = []
189e5c31af7Sopenharmony_ciwaivers = []
190e5c31af7Sopenharmony_ci
191e5c31af7Sopenharmony_ciclass Result:
192e5c31af7Sopenharmony_ci    def __init__(self, filename):
193e5c31af7Sopenharmony_ci        self.filename = filename
194e5c31af7Sopenharmony_ci        self.f = open(filename)
195e5c31af7Sopenharmony_ci        # Skip the first four lines and check that the file order has not been changed.
196e5c31af7Sopenharmony_ci        tmp = ""
197e5c31af7Sopenharmony_ci        for i in range(4):
198e5c31af7Sopenharmony_ci            tmp = tmp + self.f.readline()
199e5c31af7Sopenharmony_ci        if "Tests" not in tmp:
200e5c31af7Sopenharmony_ci            raise RuntimeError("Skipped four lines, no starting line found. Has the file order changed?")
201e5c31af7Sopenharmony_ci
202e5c31af7Sopenharmony_ci    # Reads one test item from the file.
203e5c31af7Sopenharmony_ci    def readResult(self):
204e5c31af7Sopenharmony_ci        while True:
205e5c31af7Sopenharmony_ci            tmp = ""
206e5c31af7Sopenharmony_ci            while "}" not in tmp:
207e5c31af7Sopenharmony_ci                tmp = tmp + self.f.readline()
208e5c31af7Sopenharmony_ci            if "Test" in tmp:
209e5c31af7Sopenharmony_ci                tmp = tmp[tmp.find("{") : tmp.find("}") + 1]
210e5c31af7Sopenharmony_ci                return json.loads(tmp)
211e5c31af7Sopenharmony_ci            else:
212e5c31af7Sopenharmony_ci                return None
213e5c31af7Sopenharmony_ci
214e5c31af7Sopenharmony_ci    # Search for a test name. Returns the test data if found and otherwise False.
215e5c31af7Sopenharmony_ci    def searchTest(self, test):
216e5c31af7Sopenharmony_ci        line = self.f.readline()
217e5c31af7Sopenharmony_ci        while line:
218e5c31af7Sopenharmony_ci            if line.find(test) != -1:
219e5c31af7Sopenharmony_ci                # Found the test.
220e5c31af7Sopenharmony_ci                while "}" not in line:
221e5c31af7Sopenharmony_ci                    line = line + self.f.readline()
222e5c31af7Sopenharmony_ci
223e5c31af7Sopenharmony_ci                line = line[line.find("{") : line.find("}") + 1]
224e5c31af7Sopenharmony_ci                return json.loads(line)
225e5c31af7Sopenharmony_ci            line = self.f.readline()
226e5c31af7Sopenharmony_ci
227e5c31af7Sopenharmony_ci# Run deqp-vk with regres.
228e5c31af7Sopenharmony_cidef runDeqp(deqp_path, testlist_path):
229e5c31af7Sopenharmony_ci    deqpVkParam = "--deqp-vk=" + deqp_path
230e5c31af7Sopenharmony_ci    validationLayerParam = "--validation=" + ARGS.validation
231e5c31af7Sopenharmony_ci    testListParam = "--test-list=" + testlist_path
232e5c31af7Sopenharmony_ci    run(["./run_testlist.sh", deqpVkParam, validationLayerParam, testListParam], working_dir=REGRES_DIR)
233e5c31af7Sopenharmony_ci
234e5c31af7Sopenharmony_ci# Run commands.
235e5c31af7Sopenharmony_cidef run(command: str, working_dir: str = Path.cwd()) -> None:
236e5c31af7Sopenharmony_ci    """Run command using subprocess.run()"""
237e5c31af7Sopenharmony_ci    subprocess.run(command, cwd=working_dir, check=True)
238e5c31af7Sopenharmony_ci
239e5c31af7Sopenharmony_ci# Set VK_ICD_FILENAMES
240e5c31af7Sopenharmony_cidef setVkIcdFilenames():
241e5c31af7Sopenharmony_ci    os.environ["VK_ICD_FILENAMES"] = str(LINUX_SWS_ICD_DIR / "vk_swiftshader_icd.json")
242e5c31af7Sopenharmony_ci    print(f"VK_ICD_FILENAMES = {os.getenv('VK_ICD_FILENAMES')}")
243e5c31af7Sopenharmony_ci
244e5c31af7Sopenharmony_ci# Choose the category/status to write results to.
245e5c31af7Sopenharmony_cidef writeToStatus(test):
246e5c31af7Sopenharmony_ci    if test['Status'] == "PASS":
247e5c31af7Sopenharmony_ci        new_pass.append(test['Test'])
248e5c31af7Sopenharmony_ci    elif test['Status'] == "FAIL":
249e5c31af7Sopenharmony_ci        new_fail.append(test['Test'])
250e5c31af7Sopenharmony_ci    elif test['Status'] == "NOT_SUPPORTED" or test['Status'] == "UNSUPPORTED":
251e5c31af7Sopenharmony_ci        new_notsupported.append(test['Test'])
252e5c31af7Sopenharmony_ci    elif test['Status'] == "CRASH":
253e5c31af7Sopenharmony_ci        new_crash.append(test['Test'])
254e5c31af7Sopenharmony_ci    elif test['Status'] == "COMPATIBILITY_WARNING":
255e5c31af7Sopenharmony_ci        compatibility_warning.append(test['Test'])
256e5c31af7Sopenharmony_ci    elif test['Status'] == "QUALITY_WARNING":
257e5c31af7Sopenharmony_ci        quality_warning.append(test['Test'])
258e5c31af7Sopenharmony_ci    elif test['Status'] == "INTERNAL_ERROR":
259e5c31af7Sopenharmony_ci        internal_errors.append(test['Test'])
260e5c31af7Sopenharmony_ci    elif test['Status'] == "WAIVER":
261e5c31af7Sopenharmony_ci        waivers.append(test['Test'])
262e5c31af7Sopenharmony_ci    else:
263e5c31af7Sopenharmony_ci        raise RuntimeError(f"Expected PASS, FAIL, NOT_SUPPORTED, UNSUPPORTED, CRASH, COMPATIBILITY_WARNING, " +
264e5c31af7Sopenharmony_ci                           f"QUALITY_WARNING, INTERNAL_ERROR or WAIVER as status, " +
265e5c31af7Sopenharmony_ci                           f"got {test['Status']}. Is there an unhandled status case?")
266e5c31af7Sopenharmony_ci
267e5c31af7Sopenharmony_ci# Compare two result.json files for regression.
268e5c31af7Sopenharmony_cidef compareRuns(new_result, old_result):
269e5c31af7Sopenharmony_ci    print(f"Comparing files: {old_result} and {new_result}")
270e5c31af7Sopenharmony_ci
271e5c31af7Sopenharmony_ci    r0 = Result(new_result)
272e5c31af7Sopenharmony_ci    r1 = Result(old_result)
273e5c31af7Sopenharmony_ci
274e5c31af7Sopenharmony_ci    t0 = r0.readResult()
275e5c31af7Sopenharmony_ci    t1 = r1.readResult()
276e5c31af7Sopenharmony_ci
277e5c31af7Sopenharmony_ci    done = False
278e5c31af7Sopenharmony_ci
279e5c31af7Sopenharmony_ci    while not done:
280e5c31af7Sopenharmony_ci        # Old result file has ended, continue with new.
281e5c31af7Sopenharmony_ci        if t1 == None and t0 != None:
282e5c31af7Sopenharmony_ci            advance1 = False
283e5c31af7Sopenharmony_ci            writeToStatus(t0)
284e5c31af7Sopenharmony_ci        # New result file has ended, continue with old.
285e5c31af7Sopenharmony_ci        elif t0 == None and t1 != None:
286e5c31af7Sopenharmony_ci            advance0 = False
287e5c31af7Sopenharmony_ci            has_been_removed.append(t1['Test'])
288e5c31af7Sopenharmony_ci        # Both files have ended, stop iteration.
289e5c31af7Sopenharmony_ci        elif t1 == None and t0 == None:
290e5c31af7Sopenharmony_ci            done = True
291e5c31af7Sopenharmony_ci        # By default advance both files.
292e5c31af7Sopenharmony_ci        else:
293e5c31af7Sopenharmony_ci            advance0 = True
294e5c31af7Sopenharmony_ci            advance1 = True
295e5c31af7Sopenharmony_ci
296e5c31af7Sopenharmony_ci            if t0['Test'] == t1['Test']:
297e5c31af7Sopenharmony_ci                # The normal case where both files are in sync. Just check if the status matches.
298e5c31af7Sopenharmony_ci                if t0['Status'] != t1['Status']:
299e5c31af7Sopenharmony_ci                    status_change.append(f"{t0['Test']}, new status: {t0['Status']}, old status: {t1['Status']}")
300e5c31af7Sopenharmony_ci                    print(f"Status changed: {t0['Test']} {t0['Status']} vs {t1['Status']}")
301e5c31af7Sopenharmony_ci            else:
302e5c31af7Sopenharmony_ci                # Create temporary objects for searching through the whole file.
303e5c31af7Sopenharmony_ci                tmp0 = Result(r0.filename)
304e5c31af7Sopenharmony_ci                tmp1 = Result(r1.filename)
305e5c31af7Sopenharmony_ci
306e5c31af7Sopenharmony_ci                # Search the mismatching test cases from the opposite file.
307e5c31af7Sopenharmony_ci                s0 = tmp0.searchTest(t1['Test'])
308e5c31af7Sopenharmony_ci                s1 = tmp1.searchTest(t0['Test'])
309e5c31af7Sopenharmony_ci
310e5c31af7Sopenharmony_ci                # Old test not in new results
311e5c31af7Sopenharmony_ci                if not s0:
312e5c31af7Sopenharmony_ci                    print(f"Missing old test {t1['Test']} from new file: {r0.filename}\n")
313e5c31af7Sopenharmony_ci                    has_been_removed.append(t1['Test'])
314e5c31af7Sopenharmony_ci                    # Don't advance this file since we already read a test case other than the missing one.
315e5c31af7Sopenharmony_ci                    advance0 = False
316e5c31af7Sopenharmony_ci
317e5c31af7Sopenharmony_ci                # New test not in old results
318e5c31af7Sopenharmony_ci                if not s1:
319e5c31af7Sopenharmony_ci                    print(f"Missing new test {t0['Test']} from old file: {r1.filename}\n")
320e5c31af7Sopenharmony_ci                    writeToStatus(t0)
321e5c31af7Sopenharmony_ci                    # Don't advance this file since we already read a test case other than the missing one.
322e5c31af7Sopenharmony_ci                    advance1 = False
323e5c31af7Sopenharmony_ci
324e5c31af7Sopenharmony_ci                if s0 and s1:
325e5c31af7Sopenharmony_ci                    # This should never happen because the test cases are in alphabetical order.
326e5c31af7Sopenharmony_ci                    # Print an error and bail out.
327e5c31af7Sopenharmony_ci                    raise RuntimeError(f"Tests in different locations: {t0['Test']}\n")
328e5c31af7Sopenharmony_ci
329e5c31af7Sopenharmony_ci            if not advance0 and not advance1:
330e5c31af7Sopenharmony_ci                # An exotic case where both tests are missing from the other file.
331e5c31af7Sopenharmony_ci                # Need to skip both.
332e5c31af7Sopenharmony_ci                advance0 = True
333e5c31af7Sopenharmony_ci                advance1 = True
334e5c31af7Sopenharmony_ci
335e5c31af7Sopenharmony_ci        if advance0:
336e5c31af7Sopenharmony_ci            t0 = r0.readResult()
337e5c31af7Sopenharmony_ci        if advance1:
338e5c31af7Sopenharmony_ci            t1 = r1.readResult()
339e5c31af7Sopenharmony_ci
340e5c31af7Sopenharmony_ci    result_file = str(COMP_RESULTS_DIR / "comparison_results_") + str(datetime.now().strftime('%m_%d_%Y_%H_%M_%S')) + ".txt"
341e5c31af7Sopenharmony_ci    print(f"Writing to file {result_file}")
342e5c31af7Sopenharmony_ci    COMP_RESULTS_DIR.mkdir(parents=True, exist_ok=True)
343e5c31af7Sopenharmony_ci
344e5c31af7Sopenharmony_ci    with open(result_file, "w") as log_file:
345e5c31af7Sopenharmony_ci        log_file.write("New passes:\n")
346e5c31af7Sopenharmony_ci        for line in new_pass:
347e5c31af7Sopenharmony_ci            log_file.write(line + "\n")
348e5c31af7Sopenharmony_ci        log_file.write("\n")
349e5c31af7Sopenharmony_ci
350e5c31af7Sopenharmony_ci        log_file.write("New fails:\n")
351e5c31af7Sopenharmony_ci        for line in new_fail:
352e5c31af7Sopenharmony_ci            log_file.write(line + "\n")
353e5c31af7Sopenharmony_ci        log_file.write("\n")
354e5c31af7Sopenharmony_ci
355e5c31af7Sopenharmony_ci        log_file.write("New crashes:\n")
356e5c31af7Sopenharmony_ci        for line in new_crash:
357e5c31af7Sopenharmony_ci            log_file.write(line + "\n")
358e5c31af7Sopenharmony_ci        log_file.write("\n")
359e5c31af7Sopenharmony_ci
360e5c31af7Sopenharmony_ci        log_file.write("New not_supported:\n")
361e5c31af7Sopenharmony_ci        for line in new_notsupported:
362e5c31af7Sopenharmony_ci            log_file.write(line + "\n")
363e5c31af7Sopenharmony_ci        log_file.write("\n")
364e5c31af7Sopenharmony_ci
365e5c31af7Sopenharmony_ci        log_file.write("Tests removed:\n")
366e5c31af7Sopenharmony_ci        for line in has_been_removed:
367e5c31af7Sopenharmony_ci            log_file.write(line + "\n")
368e5c31af7Sopenharmony_ci        log_file.write("\n")
369e5c31af7Sopenharmony_ci
370e5c31af7Sopenharmony_ci        log_file.write("Status changes:\n")
371e5c31af7Sopenharmony_ci        for line in status_change:
372e5c31af7Sopenharmony_ci            log_file.write(line + "\n")
373e5c31af7Sopenharmony_ci        log_file.write("\n")
374e5c31af7Sopenharmony_ci
375e5c31af7Sopenharmony_ci        log_file.write("Compatibility warnings:\n")
376e5c31af7Sopenharmony_ci        for line in compatibility_warning:
377e5c31af7Sopenharmony_ci            log_file.write(line + "\n")
378e5c31af7Sopenharmony_ci        log_file.write("\n")
379e5c31af7Sopenharmony_ci
380e5c31af7Sopenharmony_ci        log_file.write("Quality warnings:\n")
381e5c31af7Sopenharmony_ci        for line in quality_warning:
382e5c31af7Sopenharmony_ci            log_file.write(line + "\n")
383e5c31af7Sopenharmony_ci        log_file.write("\n")
384e5c31af7Sopenharmony_ci
385e5c31af7Sopenharmony_ci        log_file.write("Internal errors:\n")
386e5c31af7Sopenharmony_ci        for line in internal_errors:
387e5c31af7Sopenharmony_ci            log_file.write(line + "\n")
388e5c31af7Sopenharmony_ci        log_file.write("\n")
389e5c31af7Sopenharmony_ci
390e5c31af7Sopenharmony_ci        log_file.write("Waiver:\n")
391e5c31af7Sopenharmony_ci        for line in waivers:
392e5c31af7Sopenharmony_ci            log_file.write(line + "\n")
393e5c31af7Sopenharmony_ci
394e5c31af7Sopenharmony_ci    print(f"Comparison done. Results have been written to: {COMP_RESULTS_DIR}")
395e5c31af7Sopenharmony_ci
396e5c31af7Sopenharmony_ci# Build VK-GL-CTS
397e5c31af7Sopenharmony_cidef buildCts():
398e5c31af7Sopenharmony_ci    VK_GL_CTS_BUILD_DIR.mkdir(parents=True, exist_ok=True)
399e5c31af7Sopenharmony_ci
400e5c31af7Sopenharmony_ci    FETCH_SOURCES = str(VK_GL_CTS_ROOT_DIR / "external" / "fetch_sources.py")
401e5c31af7Sopenharmony_ci    run([which("python3"), FETCH_SOURCES], working_dir=VK_GL_CTS_ROOT_DIR)
402e5c31af7Sopenharmony_ci
403e5c31af7Sopenharmony_ci    # Build VK-GL-CTS
404e5c31af7Sopenharmony_ci    buildType = "-DCMAKE_BUILD_TYPE=" + ARGS.vk_gl_cts_build_type
405e5c31af7Sopenharmony_ci    run([which("cmake"), "-GNinja", str(VK_GL_CTS_ROOT_DIR), buildType], working_dir=VK_GL_CTS_BUILD_DIR)
406e5c31af7Sopenharmony_ci    run([which("ninja"), "deqp-vk"], working_dir=VK_GL_CTS_BUILD_DIR)
407e5c31af7Sopenharmony_ci    print(f"vk-gl-cts built to: {VK_GL_CTS_BUILD_DIR}")
408e5c31af7Sopenharmony_ci
409e5c31af7Sopenharmony_ci# Clone and build SwiftShader and Vulkan validation layers.
410e5c31af7Sopenharmony_cidef cloneSwsAndLayers():
411e5c31af7Sopenharmony_ci    # Clone SwiftShader or update if it already exists.
412e5c31af7Sopenharmony_ci    if not SWS_SRC_DIR.exists():
413e5c31af7Sopenharmony_ci        SWS_SRC_DIR.mkdir(parents=True, exist_ok=True)
414e5c31af7Sopenharmony_ci        run([which("git"), "clone", SWIFTSHADER_URL, SWS_SRC_DIR])
415e5c31af7Sopenharmony_ci    else:
416e5c31af7Sopenharmony_ci        run([which("git"), "pull", "origin"], working_dir=SWS_SRC_DIR)
417e5c31af7Sopenharmony_ci
418e5c31af7Sopenharmony_ci    # Build SwiftShader.
419e5c31af7Sopenharmony_ci    run([which("cmake"),
420e5c31af7Sopenharmony_ci            "-GNinja",
421e5c31af7Sopenharmony_ci            str(SWS_SRC_DIR),
422e5c31af7Sopenharmony_ci            "-DSWIFTSHADER_BUILD_EGL:BOOL=OFF",
423e5c31af7Sopenharmony_ci            "-DSWIFTSHADER_BUILD_GLESv2:BOOL=OFF",
424e5c31af7Sopenharmony_ci            "-DSWIFTSHADER_BUILD_TESTS:BOOL=OFF",
425e5c31af7Sopenharmony_ci            "-DINSTALL_GTEST=OFF",
426e5c31af7Sopenharmony_ci            "-DBUILD_TESTING:BOOL=OFF",
427e5c31af7Sopenharmony_ci            "-DENABLE_CTEST:BOOL=OFF",
428e5c31af7Sopenharmony_ci            "-DCMAKE_BUILD_TYPE=" + ARGS.sws_build_type],
429e5c31af7Sopenharmony_ci            working_dir=SWS_BUILD_DIR)
430e5c31af7Sopenharmony_ci    run([which("cmake"), "--build", ".", "--target", "vk_swiftshader"], working_dir=SWS_BUILD_DIR)
431e5c31af7Sopenharmony_ci
432e5c31af7Sopenharmony_ci    # Set Vulkan validation layers if flag is set.
433e5c31af7Sopenharmony_ci    if ARGS.validation == "true":
434e5c31af7Sopenharmony_ci        # Clone Vulkan validation layers or update if they already exist.
435e5c31af7Sopenharmony_ci        if not LAYERS_SRC_DIR.exists():
436e5c31af7Sopenharmony_ci            LAYERS_SRC_DIR.mkdir(parents=True, exist_ok=True)
437e5c31af7Sopenharmony_ci            run([which("git"), "clone", LAYERS_URL, LAYERS_SRC_DIR])
438e5c31af7Sopenharmony_ci        else:
439e5c31af7Sopenharmony_ci            run([which("git"), "pull", "origin"], working_dir=LAYERS_SRC_DIR)
440e5c31af7Sopenharmony_ci
441e5c31af7Sopenharmony_ci        # Build and set Vulkan validation layers.
442e5c31af7Sopenharmony_ci        LAYERS_BUILD_DIR.mkdir(parents=True, exist_ok=True)
443e5c31af7Sopenharmony_ci        UPDATE_DEPS = str(LAYERS_SRC_DIR / "scripts" / "update_deps.py")
444e5c31af7Sopenharmony_ci        run([which("python3"), UPDATE_DEPS], working_dir=LAYERS_BUILD_DIR)
445e5c31af7Sopenharmony_ci        run([which("cmake"),
446e5c31af7Sopenharmony_ci                "-GNinja",
447e5c31af7Sopenharmony_ci                "-C",
448e5c31af7Sopenharmony_ci                "helper.cmake",
449e5c31af7Sopenharmony_ci                LAYERS_SRC_DIR],
450e5c31af7Sopenharmony_ci                working_dir=LAYERS_BUILD_DIR)
451e5c31af7Sopenharmony_ci        run([which("cmake"), "--build", "."], working_dir=LAYERS_BUILD_DIR)
452e5c31af7Sopenharmony_ci        LAYERS_PATH = str(LAYERS_BUILD_DIR / "layers")
453e5c31af7Sopenharmony_ci        os.environ["VK_LAYER_PATH"] = LAYERS_PATH
454e5c31af7Sopenharmony_ci    print(f"Tools cloned and built in: {PARENT_DIR}")
455e5c31af7Sopenharmony_ci
456e5c31af7Sopenharmony_ci# Run cts with regres and move result files accordingly.
457e5c31af7Sopenharmony_cidef runCts():
458e5c31af7Sopenharmony_ci    setVkIcdFilenames()
459e5c31af7Sopenharmony_ci
460e5c31af7Sopenharmony_ci    # Run cts and copy the resulting file to RESULT_DIR.
461e5c31af7Sopenharmony_ci    print("Running cts...")
462e5c31af7Sopenharmony_ci    runDeqp(str(DEQP_VK_BINARY), str(MUSTPASS_LIST))
463e5c31af7Sopenharmony_ci    RESULT_DIR.mkdir(parents=True, exist_ok=True)
464e5c31af7Sopenharmony_ci    copyfile(str(REGRES_DIR / "results.json"), str(RESULT_DIR / ARGS.result_output))
465e5c31af7Sopenharmony_ci    print("Run completed.")
466e5c31af7Sopenharmony_ci    print(f"Result file copied to: {RESULT_DIR}")
467e5c31af7Sopenharmony_ci    exit(0)
468e5c31af7Sopenharmony_ci
469e5c31af7Sopenharmony_ci# Recipe for running cts.
470e5c31af7Sopenharmony_ciif ARGS.recipe == "run-deqp":
471e5c31af7Sopenharmony_ci    cloneSwsAndLayers()
472e5c31af7Sopenharmony_ci    if ARGS.deqp_vk is None:
473e5c31af7Sopenharmony_ci        buildCts()
474e5c31af7Sopenharmony_ci    runCts()
475e5c31af7Sopenharmony_ci
476e5c31af7Sopenharmony_ci# Recipe for only comparing the already existing result files.
477e5c31af7Sopenharmony_ciif ARGS.recipe == "check-comparison":
478e5c31af7Sopenharmony_ci    if ARGS.files is None:
479e5c31af7Sopenharmony_ci        raise RuntimeError("No comparable files provided. Please provide them with flag --files. Use --help for more info.")
480e5c31af7Sopenharmony_ci    newFile, oldFile = ARGS.files
481e5c31af7Sopenharmony_ci    compareRuns(str(newFile), str(oldFile))
482