예제 #1
0
def ensure_amber_installed(
    device_serial: Optional[str], binary_manager: binaries_util.BinaryManager
) -> None:
    amber_apk_binary = binary_manager.get_binary_path_by_name("amber_apk")
    amber_apk_test_binary = binary_manager.get_binary_path_by_name("amber_apk_test")

    adb_can_fail(device_serial, ["uninstall", "com.google.amber"])
    adb_can_fail(device_serial, ["uninstall", "com.google.amber.test"])
    adb_check(device_serial, ["install", "-r", str(amber_apk_binary.path)])
    adb_check(device_serial, ["install", "-r", str(amber_apk_test_binary.path)])
예제 #2
0
def add_spirv_shader_test_binaries(
    test: Test,
    spirv_opt_args: Optional[List[str]],
    binary_manager: binaries_util.BinaryManager,
) -> Test:
    test.binaries.extend([binary_manager.get_binary_by_name(name="spirv-dis")])
    test.binaries.extend([binary_manager.get_binary_by_name(name="spirv-val")])
    if spirv_opt_args:
        test.binaries.extend([binary_manager.get_binary_by_name(name="spirv-opt")])
    test.binaries.extend([binary_manager.get_binary_by_name(name="amber")])
    test.binaries.extend([binary_manager.get_binary_by_name(name="amber_apk")])
    test.binaries.extend([binary_manager.get_binary_by_name(name="amber_apk_test")])
    return test
def run_shader_job(
    shader_compiler_device: DeviceShaderCompiler,
    spirv_shader_job_path: Path,
    output_dir: Path,
    binary_manager: binaries_util.BinaryManager,
) -> List[Path]:
    compiler_path = binary_manager.get_binary_path_by_name(
        shader_compiler_device.binary).path

    log(f"Running {str(compiler_path)} on shader job {str(spirv_shader_job_path)}"
        )

    shader_paths = shader_job_util.get_related_files(
        spirv_shader_job_path, language_suffix=[shader_job_util.SUFFIX_SPIRV])

    log(f"Running {str(compiler_path)} on shaders: {shader_paths}")

    result = []

    for shader_path in shader_paths:
        result.append(
            run_shader(
                shader_compiler_device,
                compiler_path=compiler_path,
                shader_path=shader_path,
                output_dir=output_dir,
            ))

    return result
예제 #4
0
def ensure_amber_installed(
        device_serial: Optional[str],
        binary_manager: binaries_util.BinaryManager) -> None:
    amber_apk_binary = binary_manager.get_binary_path_by_name("amber_apk")
    amber_apk_test_binary = binary_manager.get_binary_path_by_name(
        "amber_apk_test")

    adb_can_fail(device_serial, ["uninstall", "com.google.amber"])
    adb_can_fail(device_serial, ["uninstall", "com.google.amber.test"])
    adb_check(device_serial, ["install", "-r", str(amber_apk_binary.path)])
    adb_check(
        device_serial,
        ["install", "-r", str(amber_apk_test_binary.path)])

    # Run Amber once to ensure the external cache directory (on /sdcard) gets created by the application.
    adb_check(device_serial,
              ["shell", get_amber_adb_shell_cmd(["-d"])],
              verbose=True)
예제 #5
0
def device_host(binary_manager: binaries_util.BinaryManager) -> Device:
    amber_path = binary_manager.get_binary_path_by_name(binaries_util.AMBER_NAME).path

    driver_details = ""
    try:
        driver_details = host_device_util.get_driver_details(amber_path)
    except GetDeviceDetailsError as ex:
        log(f"WARNING: Failed to get device driver details: {ex}")

    return Device(name="host", host=DeviceHost(), device_properties=driver_details)
예제 #6
0
def make_test(
    base_source_dir: Path,
    subtest_dir: Path,
    spirv_opt_args: Optional[List[str]],
    binary_manager: binaries_util.BinaryManager,
) -> Path:
    # Create the subtest by copying the base source.
    util.copy_dir(base_source_dir, test_util.get_source_dir(subtest_dir))

    test = Test(spirv_fuzz=TestSpirvFuzz(spirv_opt_args=spirv_opt_args))

    test.binaries.extend([binary_manager.get_binary_by_name(name="spirv-dis")])
    test.binaries.extend([binary_manager.get_binary_by_name(name="spirv-val")])
    if spirv_opt_args:
        test.binaries.extend(
            [binary_manager.get_binary_by_name(name="spirv-opt")])

    # Write the test metadata.
    test_util.metadata_write(test, subtest_dir)

    return subtest_dir
예제 #7
0
def run_glsl_reduce(
    source_dir: Path,
    name_of_shader_to_reduce: str,
    output_dir: Path,
    binary_manager: binaries_util.BinaryManager,
    preserve_semantics: bool = False,
    extra_args: Optional[List[str]] = None,
) -> Path:

    input_shader_job = source_dir / name_of_shader_to_reduce / test_util.SHADER_JOB

    glsl_reduce_path = util.tool_on_path(
        "glsl-reduce",
        str(
            binary_manager.get_binary_path_by_name(
                "graphicsfuzz-tool").path.parent),
    )

    cmd = [
        str(glsl_reduce_path),
        str(input_shader_job),
        "--output",
        str(output_dir),
    ]

    if preserve_semantics:
        cmd.append("--preserve-semantics")

    if extra_args:
        cmd.extend(extra_args)

    cmd.extend([
        # This ensures the arguments that follow are all positional arguments.
        "--",
        "gfauto_interestingness_test",
        str(source_dir),
        # --override_shader_job requires two parameters to follow; the second will be added by glsl-reduce (the shader.json file).
        "--override_shader_job",
        str(name_of_shader_to_reduce),
    ])

    # Log the reduction.
    with util.file_open_text(output_dir / "command.log", "w") as f:
        gflogging.push_stream_for_logging(f)
        try:
            # The reducer can fail, but it will typically output an exception file, so we can ignore the exit code.
            subprocess_util.run(cmd, verbose=True, check_exit_code=False)
        finally:
            gflogging.pop_stream_for_logging()

    return output_dir
예제 #8
0
def swift_shader_device(binary_manager: binaries_util.BinaryManager) -> Device:

    amber_path = binary_manager.get_binary_path_by_name(binaries_util.AMBER_NAME).path
    swift_shader_binary_and_path = binary_manager.get_binary_path_by_name(
        binaries_util.SWIFT_SHADER_NAME
    )

    driver_details = ""
    try:
        driver_details = host_device_util.get_driver_details(
            amber_path, swift_shader_binary_and_path.path
        )
    except GetDeviceDetailsError as ex:
        log(f"WARNING: Failed to get device driver details: {ex}")

    device = Device(
        name="swift_shader",
        swift_shader=DeviceSwiftShader(),
        binaries=[swift_shader_binary_and_path.binary],
        device_properties=driver_details,
    )

    return device
예제 #9
0
def get_device_list(
    binary_manager: binaries_util.BinaryManager,
    device_list: Optional[DeviceList] = None,
) -> DeviceList:

    if not device_list:
        device_list = DeviceList()

    # We use |extend| below (instead of |append|) because you cannot append to a list of non-scalars in protobuf.
    # |extend| copies the elements from the list and appends them.

    # Host preprocessor.
    device = device_preprocessor()
    device_list.devices.extend([device])
    device_list.active_device_names.append(device.name)

    # SwiftShader.
    device = swift_shader_device(binary_manager)
    device_list.devices.extend([device])
    device_list.active_device_names.append(device.name)

    # Host device.
    device = device_host(binary_manager)
    device_list.devices.extend([device])
    device_list.active_device_names.append(device.name)

    try:
        # Android devices.
        android_devices = android_device.get_all_android_devices(binary_manager)
        device_list.devices.extend(android_devices)
        device_list.active_device_names.extend([d.name for d in android_devices])
    except ToolNotOnPathError:
        log(
            "WARNING: adb was not found on PATH nor was ANDROID_HOME set; "
            "Android devices will not be added to settings.json"
        )

    # Offline compiler.
    device = Device(
        name="amdllpc",
        shader_compiler=DeviceShaderCompiler(
            binary="amdllpc", args=["-gfxip=9.0.0", "-verify-ir", "-auto-layout-desc"]
        ),
        binaries=[binary_manager.get_binary_path_by_name("amdllpc").binary],
    )
    device_list.devices.extend([device])
    # Don't add to active devices, since this is mostly just an example.

    return device_list
예제 #10
0
def _update_device_swiftshader(binary_manager: binaries_util.BinaryManager,
                               device: Device) -> None:

    check(
        device.HasField("swift_shader"),
        AssertionError(f"Expected SwiftShader device: {device}"),
    )

    amber_path = binary_manager.get_binary_path_by_name(
        binaries_util.AMBER_NAME).path

    swift_shader_binary_and_path = binary_manager.get_binary_path_by_name(
        binaries_util.SWIFT_SHADER_NAME)
    driver_details = ""
    try:
        driver_details = host_device_util.get_driver_details(
            amber_path, swift_shader_binary_and_path.path)
    except GetDeviceDetailsError as ex:
        log(f"WARNING: Failed to get device driver details: {ex}")

    device.device_properties = driver_details

    del device.binaries[:]
    device.binaries.extend([swift_shader_binary_and_path.binary])
예제 #11
0
def _update_device_host(binary_manager: binaries_util.BinaryManager,
                        device: Device) -> None:
    check(
        device.HasField("host"),
        AssertionError(f"Expected host device: {device}"),
    )

    amber_path = binary_manager.get_binary_path_by_name(
        binaries_util.AMBER_NAME).path

    driver_details = ""
    try:
        driver_details = host_device_util.get_driver_details(
            amber_path, custom_launcher=list(device.host.custom_launcher))
    except GetDeviceDetailsError as ex:
        log(f"WARNING: Failed to get device driver details: {ex}")

    device.device_properties = driver_details
예제 #12
0
def make_test(
    base_source_dir: Path,
    subtest_dir: Path,
    spirv_opt_args: Optional[List[str]],
    binary_manager: binaries_util.BinaryManager,
) -> Path:
    # Create the subtest by copying the base source.
    util.copy_dir(base_source_dir, test_util.get_source_dir(subtest_dir))

    test = Test(glsl=TestGlsl(spirv_opt_args=spirv_opt_args))

    test.binaries.extend(
        [binary_manager.get_binary_by_name(name="glslangValidator")])
    add_spirv_shader_test_binaries(test, spirv_opt_args, binary_manager)

    # Write the test metadata.
    test_util.metadata_write(test, subtest_dir)

    return subtest_dir
예제 #13
0
def make_test(
    base_source_dir: Path,
    subtest_dir: Path,
    spirv_opt_args: Optional[List[str]],
    binary_manager: binaries_util.BinaryManager,
    derived_from: Optional[str],
    stable_shader: bool,
    common_spirv_args: Optional[List[str]],
) -> Path:

    source_dir = test_util.get_source_dir(subtest_dir)

    # Create the subtest by copying the base source.
    util.copy_dir(base_source_dir, source_dir)

    test = Test(
        glsl=TestGlsl(spirv_opt_args=spirv_opt_args),
        derived_from=derived_from,
        common_spirv_args=common_spirv_args,
    )

    test.binaries.extend(
        [binary_manager.get_binary_by_name(name="glslangValidator")])
    fuzz_test_util.add_spirv_shader_test_binaries(test, spirv_opt_args,
                                                  binary_manager)

    # Write the test metadata.
    test_util.metadata_write(test, subtest_dir)

    # If the reference shader is "stable" (with respect to floating-point sensitivity)
    # then this can be a wrong image test; i.e. we will render the reference and variant shaders
    # and compare the output images.
    # Otherwise, we should just render the variant shader and check for crashes; to do this,
    # we just rename the `reference/` directory to `_reference/` so that the test has no reference shader.
    if not stable_shader and (source_dir / test_util.REFERENCE_DIR).is_dir():
        util.move_dir(
            source_dir / test_util.REFERENCE_DIR,
            source_dir / f"_{test_util.REFERENCE_DIR}",
        )

    return subtest_dir
예제 #14
0
def _update_device_shader_compiler(binary_manager: binaries_util.BinaryManager,
                                   device: Device) -> None:
    check(
        device.HasField("shader_compiler"),
        AssertionError(f"Expected shader_compiler device: {device}"),
    )

    # The only thing we can do is update the shader compiler binary if it is a built-in binary.

    if binaries_util.is_built_in_binary_name(device.shader_compiler.binary):
        # Remove existing binaries with this name from the device's binaries list.
        binaries = list(device.binaries)
        binaries = [
            b for b in binaries if b.name != device.shader_compiler.binary
        ]
        del device.binaries[:]
        device.binaries.extend(binaries)

        # Add our latest version of the binary.
        device.binaries.extend(
            [binary_manager.get_binary_by_name(device.shader_compiler.binary)])
예제 #15
0
def create_spirv_fuzz_variant_2(
    source_dir: Path, binary_manager: binaries_util.BinaryManager, settings: Settings,
) -> Optional[Path]:
    """
    Replays all transformations except the last to get variant_2.

    Replays all transformations except the last to get a variant_2 shader job, such that variant <-> variant_2 are
    likely even more similar than reference <-> variant.

    |source_dir| must be a spirv_fuzz test.
    """
    test_metadata: Test = test_util.metadata_read_from_source_dir(source_dir)
    check(test_metadata.HasField("spirv_fuzz"), AssertionError("Not a spirv_fuzz test"))

    variant_shader_job = source_dir / test_util.VARIANT_DIR / test_util.SHADER_JOB
    variant_2_shader_job = (
        source_dir / f"{test_util.VARIANT_DIR}_2" / test_util.SHADER_JOB
    )
    if not variant_shader_job.is_file():
        log(
            f"Skip generating variant_2 for {str(source_dir)} because the variant shader job was not found."
        )
        return None

    if variant_2_shader_job.is_file():
        log(
            f"Skip generating variant_2 for {str(source_dir)} because variant_2 shader job already exists."
        )
        return None

    return spirv_fuzz_util.run_replay_on_shader_job(
        spirv_fuzz_path=binary_manager.get_binary_path_by_name(
            binaries_util.SPIRV_FUZZ_NAME
        ).path,
        variant_shader_job_json=variant_shader_job,
        output_shader_job_json=variant_2_shader_job,
        other_args=list(settings.common_spirv_args),
    )
예제 #16
0
def run_shader_job(  # pylint: disable=too-many-return-statements,too-many-branches, too-many-locals, too-many-statements;
    source_dir: Path,
    output_dir: Path,
    binary_manager: binaries_util.BinaryManager,
    test: Optional[Test] = None,
    device: Optional[Device] = None,
    ignore_test_and_device_binaries: bool = False,
    shader_job_overrides: Iterable[tool.NameAndShaderJob] = (),
    shader_job_shader_overrides: Optional[
        tool.ShaderJobNameToShaderOverridesMap] = None,
) -> Path:

    if not shader_job_shader_overrides:
        shader_job_shader_overrides = {}

    with util.file_open_text(output_dir / "log.txt", "w") as log_file:
        try:
            gflogging.push_stream_for_logging(log_file)

            # TODO: Find amber path. NDK or host.

            # TODO: If Amber is going to be used, check if Amber can use Vulkan debug layers now, and if not, pass that
            #  info down via a bool.

            if not test:
                test = test_util.metadata_read_from_path(
                    source_dir / test_util.TEST_METADATA)

            if not device:
                device = test.device

            log(f"Running test on device:\n{device.name}")

            # We will create a binary_manager child with a restricted set of binaries so that we only use the binaries
            # specified in the test and by the device; if some required binaries are not specified by the test nor the
            # device, there will be an error instead of falling back to our default binaries. But we keep a reference to
            # the parent so we can still access certain "test-independent" binaries like Amber.

            binary_manager_parent = binary_manager

            if not ignore_test_and_device_binaries:
                binary_manager = binary_manager.get_child_binary_manager(
                    list(device.binaries) + list(test.binaries))

            spirv_opt_hash: Optional[str] = None
            spirv_opt_args: Optional[List[str]] = None
            if test.glsl.spirv_opt_args or test.spirv_fuzz.spirv_opt_args:
                spirv_opt_hash = binary_manager.get_binary_by_name(
                    binaries_util.SPIRV_OPT_NAME).version
                spirv_opt_args = (list(test.glsl.spirv_opt_args)
                                  if test.glsl.spirv_opt_args else list(
                                      test.spirv_fuzz.spirv_opt_args))

            shader_jobs = tool.get_shader_jobs(source_dir,
                                               overrides=shader_job_overrides)

            combined_spirv_shader_jobs: List[tool.SpirvCombinedShaderJob] = []

            for shader_job in shader_jobs:
                try:
                    shader_overrides = shader_job_shader_overrides.get(
                        shader_job.name, None)
                    combined_spirv_shader_jobs.append(
                        tool.compile_shader_job(
                            name=shader_job.name,
                            input_json=shader_job.shader_job,
                            work_dir=output_dir / shader_job.name,
                            binary_paths=binary_manager,
                            spirv_opt_args=spirv_opt_args,
                            shader_overrides=shader_overrides,
                        ))
                except subprocess.CalledProcessError:
                    result_util.write_status(output_dir,
                                             fuzz.STATUS_TOOL_CRASH,
                                             shader_job.name)
                    return output_dir
                except subprocess.TimeoutExpired:
                    result_util.write_status(output_dir,
                                             fuzz.STATUS_TOOL_TIMEOUT,
                                             shader_job.name)
                    return output_dir

            # Device types: |preprocess| and |shader_compiler| don't need an AmberScript file.

            # noinspection PyTypeChecker
            if device.HasField("preprocess"):
                # The "preprocess" device type just needs to get this far, so this is a success.
                result_util.write_status(output_dir, fuzz.STATUS_SUCCESS)
                return output_dir

            # noinspection PyTypeChecker
            if device.HasField("shader_compiler"):
                for combined_spirv_shader_job in combined_spirv_shader_jobs:
                    try:
                        shader_compiler_util.run_shader_job(
                            device.shader_compiler,
                            combined_spirv_shader_job.spirv_shader_job,
                            output_dir,
                            binary_manager=binary_manager,
                        )
                    except subprocess.CalledProcessError:
                        result_util.write_status(
                            output_dir,
                            fuzz.STATUS_CRASH,
                            combined_spirv_shader_job.name,
                        )
                        return output_dir
                    except subprocess.TimeoutExpired:
                        result_util.write_status(
                            output_dir,
                            fuzz.STATUS_TIMEOUT,
                            combined_spirv_shader_job.name,
                        )
                        return output_dir

                # The shader compiler succeeded on all files; this is a success.
                result_util.write_status(output_dir, fuzz.STATUS_SUCCESS)
                return output_dir

            # Other device types need an AmberScript file.

            amber_converter_shader_job_files = [
                amber_converter.ShaderJobFile(
                    name_prefix=combined_spirv_shader_job.name,
                    asm_spirv_shader_job_json=combined_spirv_shader_job.
                    spirv_asm_shader_job,
                    glsl_source_json=combined_spirv_shader_job.
                    glsl_source_shader_job,
                    processing_info="",
                ) for combined_spirv_shader_job in combined_spirv_shader_jobs
            ]

            # Check if the first is the reference shader; if so, pull it out into its own variable.

            reference: Optional[amber_converter.ShaderJobFile] = None
            variants = amber_converter_shader_job_files

            if (amber_converter_shader_job_files[0].name_prefix ==
                    test_util.REFERENCE_DIR):
                reference = amber_converter_shader_job_files[0]
                variants = variants[1:]
            elif len(variants) > 1:
                raise AssertionError(
                    "More than one variant, but no reference. This is unexpected."
                )

            amber_script_file = amber_converter.spirv_asm_shader_job_to_amber_script(
                shader_job_file_amber_test=amber_converter.
                ShaderJobFileBasedAmberTest(reference_asm_spirv_job=reference,
                                            variants_asm_spirv_job=variants),
                output_amber_script_file_path=output_dir / "test.amber",
                amberfy_settings=amber_converter.AmberfySettings(
                    spirv_opt_args=spirv_opt_args,
                    spirv_opt_hash=spirv_opt_hash),
            )

            is_compute = bool(
                shader_job_util.get_related_files(
                    combined_spirv_shader_jobs[0].spirv_shader_job,
                    [shader_job_util.EXT_COMP],
                ))

            # noinspection PyTypeChecker
            if device.HasField("host") or device.HasField("swift_shader"):
                icd: Optional[Path] = None

                # noinspection PyTypeChecker
                if device.HasField("swift_shader"):
                    icd = binary_manager.get_binary_path_by_name(
                        binaries_util.SWIFT_SHADER_NAME).path

                # Run the test on the host using Amber.
                host_device_util.run_amber(
                    amber_script_file,
                    output_dir,
                    amber_path=binary_manager_parent.get_binary_path_by_name(
                        binaries_util.AMBER_NAME).path,
                    dump_image=(not is_compute),
                    dump_buffer=is_compute,
                    icd=icd,
                )
                return output_dir

            # noinspection PyTypeChecker
            if device.HasField("android"):

                android_device.run_amber_on_device(
                    amber_script_file,
                    output_dir,
                    dump_image=(not is_compute),
                    dump_buffer=is_compute,
                    serial=device.android.serial,
                )
                return output_dir

            # TODO: For a remote device (which we will probably need to support), use log_a_file to output the
            #  "amber_log.txt" file.

            raise AssertionError(f"Unhandled device type:\n{str(device)}")

        finally:
            gflogging.pop_stream_for_logging()
예제 #17
0
def main_helper(  # pylint: disable=too-many-locals,too-many-branches,too-many-statements;
    tests_dir: Path,
    work_dir: Path,
    binaries: binaries_util.BinaryManager,
    settings: Settings,
    active_devices: List[Device],
    results_out_handle: Optional[TextIO],
    updated_settings_output_path: Optional[Path],
) -> None:

    util.mkdirs_p(work_dir)

    def write_entry(entry: str) -> None:
        if not results_out_handle:
            return
        results_out_handle.write(entry)
        results_out_handle.write(", ")
        results_out_handle.flush()

    def write_newline() -> None:
        if not results_out_handle:
            return
        results_out_handle.write("\n")
        results_out_handle.flush()

    spirv_opt_path: Optional[Path] = None
    swift_shader_path: Optional[Path] = None
    amber_path: Optional[Path] = None

    # Small hack to ensure we have three devices for spirv-opt, each with a different name.
    main_spirv_opt_device: Optional[Device] = None

    if active_devices and active_devices[0].name == "host_preprocessor":
        main_spirv_opt_device = active_devices[0]
        main_spirv_opt_device.name = SPIRV_OPT_O

        spirv_opt_custom = Device()
        spirv_opt_custom.CopyFrom(main_spirv_opt_device)
        spirv_opt_custom.name = SPIRV_OPT_CUSTOM
        active_devices.insert(1, spirv_opt_custom)

        spirv_opt_os = Device()
        spirv_opt_os.CopyFrom(main_spirv_opt_device)
        spirv_opt_os.name = SPIRV_OPT_OS
        active_devices.insert(1, spirv_opt_os)

    # Enumerate active devices, writing their name and storing binary paths if needed.
    write_entry("test")
    for device in active_devices:
        write_entry(device.name)

        if device.HasField("preprocess"):
            spirv_opt_path = binaries.get_binary_path_by_name(
                binaries_util.SPIRV_OPT_NAME).path

        if device.HasField("swift_shader"):
            swift_shader_path = binaries.get_binary_path_by_name(
                binaries_util.SWIFT_SHADER_NAME).path

        if device.HasField("swift_shader") or device.HasField("host"):
            amber_path = binaries.get_binary_path_by_name(
                binaries_util.AMBER_NAME).path

    write_newline()

    # Enumerate tests and devices, writing the results.

    for test in sorted(tests_dir.glob("*.amber")):
        test_name = util.remove_end(test.name, ".amber")
        write_entry(test_name)
        spirv_shaders = sorted(
            tests_dir.glob(util.remove_end(test.name, "amber") + "*.spv"))
        for device in active_devices:
            test_run_dir = work_dir / f"{test_name}_{device.name}"
            util.mkdirs_p(test_run_dir)
            ignored_signatures_set: Set[str] = set(
                device.ignored_crash_signatures)

            with util.file_open_text(test_run_dir / "log.txt",
                                     "w") as log_stream:
                try:
                    gflogging.push_stream_for_logging(log_stream)
                    if device.HasField("preprocess"):
                        # This just means spirv-opt for now.

                        assert spirv_opt_path  # noqa
                        assert main_spirv_opt_device  # noqa

                        # Pick spirv-opt arguments based on device name.
                        if device.name == SPIRV_OPT_O:
                            spirv_opt_args = ["-O"]
                        elif device.name == SPIRV_OPT_OS:
                            spirv_opt_args = ["-Os"]
                        elif device.name == SPIRV_OPT_CUSTOM:
                            spirv_opt_args = (spirv_opt_util.
                                              OPT_INTERESTING_SUBSET_OF_PASSES)
                        else:
                            raise AssertionError(
                                f"Can't tell how to run device {device.name}; "
                                f"must be named host_preprocessor and be the first active device."
                            )

                        # Reset device and ignored_crash_signatures.
                        device = main_spirv_opt_device
                        ignored_signatures_set = set(
                            device.ignored_crash_signatures)

                        try:
                            for spirv_shader in spirv_shaders:
                                spirv_opt_util.run_spirv_opt_on_spirv_shader(
                                    spirv_shader,
                                    test_run_dir,
                                    spirv_opt_args,
                                    spirv_opt_path,
                                )
                            result_util.write_status(
                                test_run_dir,
                                fuzz.STATUS_SUCCESS,
                            )
                        except subprocess.CalledProcessError:
                            result_util.write_status(
                                test_run_dir,
                                fuzz.STATUS_TOOL_CRASH,
                            )
                        except subprocess.TimeoutExpired:
                            result_util.write_status(
                                test_run_dir,
                                fuzz.STATUS_TOOL_TIMEOUT,
                            )
                    elif device.HasField("shader_compiler"):
                        try:
                            for spirv_shader in spirv_shaders:
                                shader_compiler_util.run_shader(
                                    shader_compiler_device=device.
                                    shader_compiler,
                                    shader_path=spirv_shader,
                                    output_dir=test_run_dir,
                                    compiler_path=binaries.
                                    get_binary_path_by_name(
                                        device.shader_compiler.binary).path,
                                    timeout=DEFAULT_TIMEOUT,
                                )
                            result_util.write_status(
                                test_run_dir,
                                fuzz.STATUS_SUCCESS,
                            )
                        except subprocess.CalledProcessError:
                            result_util.write_status(
                                test_run_dir,
                                fuzz.STATUS_CRASH,
                            )
                        except subprocess.TimeoutExpired:
                            result_util.write_status(
                                test_run_dir,
                                fuzz.STATUS_TIMEOUT,
                            )
                    elif device.HasField("swift_shader"):
                        assert swift_shader_path  # noqa
                        assert amber_path  # noqa
                        host_device_util.run_amber(
                            test,
                            test_run_dir,
                            amber_path=amber_path,
                            dump_image=False,
                            dump_buffer=False,
                            icd=swift_shader_path,
                        )
                    elif device.HasField("host"):
                        assert amber_path  # noqa
                        host_device_util.run_amber(
                            test,
                            test_run_dir,
                            amber_path=amber_path,
                            dump_image=False,
                            dump_buffer=False,
                            custom_launcher=list(device.host.custom_launcher),
                        )
                    elif device.HasField("android"):
                        android_device.run_amber_on_device(
                            test,
                            test_run_dir,
                            dump_image=False,
                            dump_buffer=False,
                            serial=device.android.serial,
                        )
                    else:
                        raise AssertionError(
                            f"Unsupported device {device.name}")

                finally:
                    gflogging.pop_stream_for_logging()

            status = result_util.get_status(test_run_dir)

            if status == fuzz.STATUS_SUCCESS:
                write_entry("P")
            elif status in (fuzz.STATUS_TIMEOUT, fuzz.STATUS_TOOL_TIMEOUT):
                write_entry("T")
            else:
                write_entry("F")

            # Update ignored signatures.
            if (status in (
                    fuzz.STATUS_TOOL_CRASH,
                    fuzz.STATUS_CRASH,
                    fuzz.STATUS_UNRESPONSIVE,
            ) and updated_settings_output_path):
                log_contents = util.file_read_text(
                    result_util.get_log_path(test_run_dir))
                signature = signature_util.get_signature_from_log_contents(
                    log_contents)
                if signature == signature_util.NO_SIGNATURE:
                    log(f"NOT updating ignored signatures to include {signature}"
                        )
                elif signature in ignored_signatures_set:
                    log(f"Signature is already ignored: {signature}")
                else:
                    log(f"Adding ignored signature: {signature}")
                    device.ignored_crash_signatures.append(signature)

        write_newline()

    if updated_settings_output_path:
        # Reset main_spirv_opt_device name before writing it back out.
        if main_spirv_opt_device:
            main_spirv_opt_device.name = "host_preprocessor"
        settings_util.write(settings, updated_settings_output_path)
예제 #18
0
def write_shader(
    shader_asm: str,
    amber_file: Path,
    output_dir: Path,
    shader_type: str,
    shader_name: str,
    binaries: binaries_util.BinaryManager,
) -> List[Path]:

    files_written: List[Path] = []

    shader_type_to_suffix = {
        "fragment": shader_job_util.EXT_FRAG,
        "vertex": shader_job_util.EXT_VERT,
        "compute": shader_job_util.EXT_COMP,
    }

    shader_type_suffix = shader_type_to_suffix[shader_type]

    # E.g. ifs-and-whiles.variant_fragment_shader.frag.asm
    shader_asm_file_path = output_dir / (
        f"{amber_file.stem}.{shader_name}{shader_type_suffix}{shader_job_util.SUFFIX_ASM_SPIRV}"
    )

    # E.g. ifs-and-whiles.variant_fragment_shader.frag.spv
    shader_spirv_file_path = output_dir / (
        f"{amber_file.stem}.{shader_name}{shader_type_suffix}{shader_job_util.SUFFIX_SPIRV}"
    )

    # E.g. dEQP-VK.graphicsfuzz.ifs-and-whiles.variant_fragment_shader.spvas
    # These files can be added to the llpc repo as a shader test.
    shader_llpc_asm_test_file_path = output_dir / (
        f"dEQP-VK.graphicsfuzz.{amber_file.stem}.{shader_name}.spvas")

    util.file_write_text(shader_asm_file_path, shader_asm)
    files_written.append(shader_asm_file_path)

    spirv_as_path = binaries.get_binary_path_by_name("spirv-as").path

    subprocess_util.run(
        [
            str(spirv_as_path),
            "-o",
            str(shader_spirv_file_path),
            str(shader_asm_file_path),
            "--target-env",
            "spv1.0",
        ],
        verbose=True,
    )

    files_written.append(shader_spirv_file_path)

    util.file_write_text(
        shader_llpc_asm_test_file_path,
        """; BEGIN_SHADERTEST
; RUN: amdllpc -verify-ir -spvgen-dir=%spvgendir% -v %gfxip %s | FileCheck -check-prefix=SHADERTEST %s
; SHADERTEST-LABEL: {{^// LLPC.*}} SPIRV-to-LLVM translation results
; SHADERTEST: AMDLLPC SUCCESS
; END_SHADERTEST
;
""" + f"; Based on dEQP-VK.graphicsfuzz.{amber_file.stem}\n\n" + shader_asm,
    )
    files_written.append(shader_llpc_asm_test_file_path)

    return files_written
예제 #19
0
def fuzz_glsl(  # pylint: disable=too-many-locals;
    staging_dir: Path,
    reports_dir: Path,
    fuzz_failures_dir: Path,
    active_devices: List[Device],
    references: List[Path],
    donors_dir: Path,
    settings: Settings,
    binary_manager: binaries_util.BinaryManager,
) -> None:
    staging_name = staging_dir.name
    template_source_dir = staging_dir / "source_template"

    # Pick a randomly chosen reference.
    unprepared_reference_shader_job: Path = random.choice(references)

    # The "graphicsfuzz-tool" tool is designed to be on your PATH so that e.g. ".bat" will be appended on Windows.
    # So we use tool_on_path with a custom PATH to get the actual file we want to execute.
    graphicsfuzz_tool_path = util.tool_on_path(
        "graphicsfuzz-tool",
        str(
            binary_manager.get_binary_path_by_name(
                "graphicsfuzz-tool").path.parent),
    )

    try:
        with util.file_open_text(staging_dir / "log.txt", "w") as log_file:
            try:
                gflogging.push_stream_for_logging(log_file)

                # Create the prepared (for Vulkan GLSL) reference.
                glsl_generate_util.run_prepare_reference(
                    graphicsfuzz_tool_path,
                    unprepared_reference_shader_job,
                    template_source_dir / test_util.REFERENCE_DIR /
                    test_util.SHADER_JOB,
                    legacy_graphics_fuzz_vulkan_arg=settings.
                    legacy_graphics_fuzz_vulkan_arg,
                )

                # Generate the variant (GraphicsFuzz requires the unprepared reference as input).
                glsl_generate_util.run_generate(
                    graphicsfuzz_tool_path,
                    unprepared_reference_shader_job,
                    donors_dir,
                    template_source_dir / test_util.VARIANT_DIR /
                    test_util.SHADER_JOB,
                    seed=str(
                        random.getrandbits(
                            glsl_generate_util.GENERATE_SEED_BITS)),
                    other_args=list(settings.extra_graphics_fuzz_generate_args)
                    if settings.extra_graphics_fuzz_generate_args else None,
                    legacy_graphics_fuzz_vulkan_arg=settings.
                    legacy_graphics_fuzz_vulkan_arg,
                )
            finally:
                gflogging.pop_stream_for_logging()
    except subprocess.CalledProcessError:
        util.mkdirs_p(fuzz_failures_dir)
        if len(list(
                fuzz_failures_dir.iterdir())) < settings.maximum_fuzz_failures:
            util.copy_dir(staging_dir, fuzz_failures_dir / staging_dir.name)
        return

    reference_name = unprepared_reference_shader_job.stem

    stable_shader = reference_name.startswith("stable_")

    common_spirv_args = list(settings.common_spirv_args)

    test_dirs = [
        make_test(
            template_source_dir,
            staging_dir / f"{staging_name}_no_opt_test",
            spirv_opt_args=None,
            binary_manager=binary_manager,
            derived_from=reference_name,
            stable_shader=stable_shader,
            common_spirv_args=common_spirv_args,
        ),
        make_test(
            template_source_dir,
            staging_dir / f"{staging_name}_opt_O_test",
            spirv_opt_args=["-O"],
            binary_manager=binary_manager,
            derived_from=reference_name,
            stable_shader=stable_shader,
            common_spirv_args=common_spirv_args,
        ),
    ]

    if not settings.spirv_opt_just_o:
        test_dirs += [
            make_test(
                template_source_dir,
                staging_dir / f"{staging_name}_opt_Os_test",
                spirv_opt_args=["-Os"],
                binary_manager=binary_manager,
                derived_from=reference_name,
                stable_shader=stable_shader,
                common_spirv_args=common_spirv_args,
            ),
            make_test(
                template_source_dir,
                staging_dir / f"{staging_name}_opt_rand1_test",
                spirv_opt_args=spirv_opt_util.random_spirv_opt_args(),
                binary_manager=binary_manager,
                derived_from=reference_name,
                stable_shader=stable_shader,
                common_spirv_args=common_spirv_args,
            ),
            make_test(
                template_source_dir,
                staging_dir / f"{staging_name}_opt_rand2_test",
                spirv_opt_args=spirv_opt_util.random_spirv_opt_args(),
                binary_manager=binary_manager,
                derived_from=reference_name,
                stable_shader=stable_shader,
                common_spirv_args=common_spirv_args,
            ),
            make_test(
                template_source_dir,
                staging_dir / f"{staging_name}_opt_rand3_test",
                spirv_opt_args=spirv_opt_util.random_spirv_opt_args(),
                binary_manager=binary_manager,
                derived_from=reference_name,
                stable_shader=stable_shader,
                common_spirv_args=common_spirv_args,
            ),
        ]

    for test_dir in test_dirs:
        interrupt_util.interrupt_if_needed()
        if handle_test(test_dir, reports_dir, active_devices, binary_manager,
                       settings):
            # If we generated a report, don't bother trying other optimization combinations.
            break
예제 #20
0
def create_summary_and_reproduce(  # pylint: disable=too-many-locals;
        test_dir: Path, binary_manager: binaries_util.BinaryManager,
        settings: Settings) -> None:
    test_metadata = test_util.metadata_read(test_dir)

    summary_dir = test_dir / "summary"

    summary_source_dirs: List[Path] = []

    unreduced = util.copy_dir(test_util.get_source_dir(test_dir),
                              summary_dir / "unreduced")
    summary_source_dirs.append(unreduced)

    # For the `summary/reduced_1/` directory.
    reduction_output_dir_1 = test_util.get_reduced_test_dir(
        test_dir, test_metadata.device.name, "1")
    reduced_1: Optional[Path] = None
    if reduction_output_dir_1.is_dir():
        reduction_output_source_dir_1 = test_util.get_source_dir(
            reduction_output_dir_1)
        if reduction_output_source_dir_1.is_dir():
            reduced_1 = util.copy_dir(reduction_output_source_dir_1,
                                      summary_dir / "reduced_1")
            summary_source_dirs.append(reduced_1)

    # For the `summary/reduced_2/` directory.
    reduction_output_dir_2 = test_util.get_reduced_test_dir(
        test_dir, test_metadata.device.name, "2")
    if reduction_output_dir_2.is_dir():
        reduction_output_source_dir_2 = test_util.get_source_dir(
            reduction_output_dir_2)
        if reduction_output_source_dir_2.is_dir():
            reduced_2 = util.copy_dir(reduction_output_source_dir_2,
                                      summary_dir / "reduced_2")
            summary_source_dirs.append(reduced_2)

    # If this test was generated from a stable shader...
    if test_metadata.derived_from.startswith("stable_") and reduced_1:
        # Before running the reduced_1 source dir, find any renamed shader jobs (e.g. reference/ -> _reference/)
        # and rename them back. Thus, the modified test becomes a wrong image test once again, even though
        # the actual bug was probably a crash bug.
        renamed_shader_jobs = list(reduced_1.glob("_*"))
        renamed_shader_jobs = [
            r for r in renamed_shader_jobs
            if (r / test_util.SHADER_JOB).is_file()
        ]
        if renamed_shader_jobs:
            for renamed_shader_job in renamed_shader_jobs:
                util.move_dir(
                    renamed_shader_job,
                    renamed_shader_job.with_name(renamed_shader_job.name[1:]),
                )

        # Also, if this is a spirv_fuzz test then try to create a variant_2 shader job that is even more similar to the
        # variant than the reference shader job.
        if test_metadata.HasField("spirv_fuzz"):
            spirv_fuzz_util.create_spirv_fuzz_variant_2(
                spirv_fuzz_path=binary_manager.get_binary_path_by_name(
                    binaries_util.SPIRV_FUZZ_NAME).path,
                source_dir=reduced_1,
                settings=settings,
            )

    # Run every source dir that we added to the summary dir.
    for summary_source_dir in summary_source_dirs:
        run_shader_job(
            source_dir=summary_source_dir,
            output_dir=(summary_dir / f"{summary_source_dir.name}_result"),
            binary_manager=binary_manager,
        )
예제 #21
0
def fuzz_spirv(  # pylint: disable=too-many-locals;
    staging_dir: Path,
    reports_dir: Path,
    fuzz_failures_dir: Path,
    active_devices: List[Device],
    spirv_fuzz_shaders: List[Path],
    settings: Settings,
    binary_manager: binaries_util.BinaryManager,
) -> None:

    staging_name = staging_dir.name
    template_source_dir = staging_dir / "source_template"

    reference_spirv_shader_job_orig_path: Path = random.choice(
        spirv_fuzz_shaders)

    # Copy in a randomly chosen reference.
    reference_spirv_shader_job = shader_job_util.copy(
        reference_spirv_shader_job_orig_path,
        template_source_dir / test_util.REFERENCE_DIR / test_util.SHADER_JOB,
        language_suffix=shader_job_util.SUFFIXES_SPIRV_FUZZ_INPUT,
    )

    try:
        with util.file_open_text(staging_dir / "log.txt", "w") as log_file:
            try:
                gflogging.push_stream_for_logging(log_file)
                spirv_fuzz_util.run_generate_on_shader_job(
                    binary_manager.get_binary_path_by_name("spirv-fuzz").path,
                    reference_spirv_shader_job,
                    template_source_dir / test_util.VARIANT_DIR /
                    test_util.SHADER_JOB,
                    donor_shader_job_paths=spirv_fuzz_shaders,
                    seed=str(
                        random.getrandbits(
                            spirv_fuzz_util.GENERATE_SEED_BITS)),
                    other_args=list(settings.extra_spirv_fuzz_generate_args) +
                    list(settings.common_spirv_args),
                )
            finally:
                gflogging.pop_stream_for_logging()
    except subprocess.CalledProcessError:
        util.mkdirs_p(fuzz_failures_dir)
        if len(list(
                fuzz_failures_dir.iterdir())) < settings.maximum_fuzz_failures:
            util.copy_dir(staging_dir, fuzz_failures_dir / staging_dir.name)
        return

    reference_name = reference_spirv_shader_job_orig_path.stem

    stable_shader = reference_name.startswith("stable_")

    common_spirv_args = list(settings.common_spirv_args)

    test_dirs = [
        make_test(
            template_source_dir,
            staging_dir / f"{staging_name}_no_opt_test",
            spirv_opt_args=None,
            binary_manager=binary_manager,
            derived_from=reference_name,
            stable_shader=stable_shader,
            common_spirv_args=common_spirv_args,
        ),
        make_test(
            template_source_dir,
            staging_dir / f"{staging_name}_opt_O_test",
            spirv_opt_args=["-O"],
            binary_manager=binary_manager,
            derived_from=reference_name,
            stable_shader=stable_shader,
            common_spirv_args=common_spirv_args,
        ),
        make_test(
            template_source_dir,
            staging_dir / f"{staging_name}_opt_Os_test",
            spirv_opt_args=["-Os"],
            binary_manager=binary_manager,
            derived_from=reference_name,
            stable_shader=stable_shader,
            common_spirv_args=common_spirv_args,
        ),
        make_test(
            template_source_dir,
            staging_dir / f"{staging_name}_opt_rand1_test",
            spirv_opt_args=spirv_opt_util.random_spirv_opt_args(),
            binary_manager=binary_manager,
            derived_from=reference_name,
            stable_shader=stable_shader,
            common_spirv_args=common_spirv_args,
        ),
        make_test(
            template_source_dir,
            staging_dir / f"{staging_name}_opt_rand2_test",
            spirv_opt_args=spirv_opt_util.random_spirv_opt_args(),
            binary_manager=binary_manager,
            derived_from=reference_name,
            stable_shader=stable_shader,
            common_spirv_args=common_spirv_args,
        ),
        make_test(
            template_source_dir,
            staging_dir / f"{staging_name}_opt_rand3_test",
            spirv_opt_args=spirv_opt_util.random_spirv_opt_args(),
            binary_manager=binary_manager,
            derived_from=reference_name,
            stable_shader=stable_shader,
            common_spirv_args=common_spirv_args,
        ),
    ]

    for test_dir in test_dirs:
        interrupt_util.interrupt_if_needed()
        if handle_test(test_dir, reports_dir, active_devices, binary_manager,
                       settings):
            # If we generated a report, don't bother trying other optimization combinations.
            break
예제 #22
0
def run_spirv_reduce_or_shrink(  # pylint: disable=too-many-locals;
    source_dir: Path,
    name_of_shader_job_to_reduce: str,
    extension_to_reduce: str,
    output_dir: Path,
    preserve_semantics: bool,
    binary_manager: binaries_util.BinaryManager,
    settings: Settings,
) -> Path:
    test = test_util.metadata_read_from_source_dir(source_dir)
    input_shader_job = source_dir / name_of_shader_job_to_reduce / test_util.SHADER_JOB

    original_spirv_file = input_shader_job.with_suffix(
        extension_to_reduce + shader_job_util.SUFFIX_SPIRV_ORIG)

    transformed_spirv_file = input_shader_job.with_suffix(
        extension_to_reduce + shader_job_util.SUFFIX_SPIRV)
    transformations_file = input_shader_job.with_suffix(
        extension_to_reduce + shader_job_util.SUFFIX_TRANSFORMATIONS)

    util.mkdirs_p(output_dir)

    final_shader = output_dir / "final.spv"

    # E.g. transformation_suffix_to_reduce == ".frag.transformations"

    # E.g. ".frag.??" -> ".frag.spv"
    shader_suffix_to_override = extension_to_reduce + shader_job_util.SUFFIX_SPIRV

    if preserve_semantics:
        cmd = [
            str(binary_manager.get_binary_path_by_name("spirv-fuzz").path),
            str(original_spirv_file),
            "-o",
            str(final_shader),
            f"--shrink={str(transformations_file)}",
            f"--shrinker-temp-file-prefix={str(output_dir / 'temp_')}",
        ]
        cmd += list(settings.extra_spirv_fuzz_shrink_args)
        cmd += list(test.common_spirv_args)
        cmd += [
            # This ensures the arguments that follow are all positional arguments.
            "--",
            "gfauto_interestingness_test",
            str(source_dir),
            # --override_shader requires three parameters to follow; the third will be added by spirv-fuzz (the shader.spv file).
            "--override_shader",
            name_of_shader_job_to_reduce,
            shader_suffix_to_override,
        ]
    else:
        cmd = [
            str(binary_manager.get_binary_path_by_name("spirv-reduce").path),
            str(transformed_spirv_file),
            "-o",
            str(final_shader),
            f"--temp-file-prefix={str(output_dir / 'temp_')}",
        ]
        cmd += list(settings.extra_spirv_reduce_args)
        cmd += list(test.common_spirv_args)
        cmd += [
            # This ensures the arguments that follow are all positional arguments.
            "--",
            "gfauto_interestingness_test",
            str(source_dir),
            # --override_shader requires three parameters to follow; the third will be added by spirv-reduce (the shader.spv file).
            "--override_shader",
            name_of_shader_job_to_reduce,
            shader_suffix_to_override,
        ]

    # Log the reduction.
    with util.file_open_text(output_dir / "command.log", "w") as f:
        gflogging.push_stream_for_logging(f)
        try:
            # The reducer can fail, but it will typically output an exception file, so we can ignore the exit code.
            subprocess_util.run(cmd, verbose=True, check_exit_code=False)
        finally:
            gflogging.pop_stream_for_logging()

    return final_shader