예제 #1
0
def get_function_signature_from_address(
    module: Path,
    address: str,
    addr2line_mock: Optional[Callable[[Path, str], str]] = None,
) -> Optional[str]:
    # stdout result can be mocked for testing.
    stdout: str
    if addr2line_mock:
        stdout = addr2line_mock(module, address)
    else:
        try:
            address_tool = util.tool_on_path("addr2line")
        except util.ToolNotOnPathError:
            return None
        result = subprocess_util.run(
            [str(address_tool), "-e",
             str(module), address, "-f", "-C"],
            check_exit_code=False,
            verbose=True,
        )
        if result.returncode != 0:
            return None
        stdout = result.stdout

    lines = stdout.splitlines()
    if not lines:
        return None
    if lines[0].startswith("??"):
        return None
    return lines[0]
예제 #2
0
def run_glslang_glsl_shader_to_spirv_shader(
    glsl_shader_path: pathlib.Path,
    output_dir_path: pathlib.Path,
    glslang_validator_file_path: Optional[pathlib.Path] = None,
    time_limit: int = GLSLANG_DEFAULT_TIME_LIMIT,
) -> pathlib.Path:

    if not glslang_validator_file_path:
        glslang_validator_file_path = util.tool_on_path(
            binaries_util.GLSLANG_VALIDATOR_NAME
        )

    output_spirv_file_path = output_dir_path / (glsl_shader_path.name + ".spv")

    util.file_mkdirs_parent(output_spirv_file_path)

    subprocess_util.run(
        util.prepend_catchsegv_if_available(
            [
                str(glslang_validator_file_path),
                "-V",
                "-o",
                str(output_spirv_file_path),
                str(glsl_shader_path),
            ]
        ),
        timeout=time_limit,
    )

    return output_spirv_file_path
예제 #3
0
def adb_path() -> Path:
    if "ANDROID_HOME" in os.environ:
        platform_tools_path = Path(os.environ["ANDROID_HOME"]) / "platform-tools"
        adb = shutil.which("adb", path=str(platform_tools_path))
        if adb:
            return Path(adb)
    return util.tool_on_path("adb")
예제 #4
0
def run_glslang_glsl_to_spirv_job(
    glsl_shader_job_json_file_path: pathlib.Path,
    spirv_shader_job_json_file_path: pathlib.Path,
    glslang_validator_file_path: Optional[pathlib.Path] = None,
) -> pathlib.Path:

    if not glslang_validator_file_path:
        glslang_validator_file_path = util.tool_on_path(
            binaries_util.GLSLANG_VALIDATOR_NAME
        )

    glsl_shader_files = shader_job_util.get_related_files(
        glsl_shader_job_json_file_path
    )

    util.copy_file(glsl_shader_job_json_file_path, spirv_shader_job_json_file_path)

    for glsl_shader_file in glsl_shader_files:
        run_glslang_glsl_shader_to_spirv_shader(
            glsl_shader_file,
            spirv_shader_job_json_file_path.parent,
            glslang_validator_file_path,
        )

    return spirv_shader_job_json_file_path
예제 #5
0
def run_spirv_opt_on_spirv_shader_job(
    input_spirv_shader_job_json_file_path: pathlib.Path,
    output_spirv_shader_job_json_file_path: pathlib.Path,
    spirv_opt_args: List[str],
    spirv_opt_file_path: Optional[pathlib.Path] = None,
    spirv_opt_no_validate_after_all: bool = False,
    preprocessor_cache: Optional[util.CommandCache] = None,
) -> pathlib.Path:

    if not spirv_opt_file_path:
        spirv_opt_file_path = util.tool_on_path(binaries_util.SPIRV_OPT_NAME)

    shader_files = shader_job_util.get_related_files(
        input_spirv_shader_job_json_file_path,
        language_suffix=[shader_job_util.SUFFIX_SPIRV],
    )

    util.copy_file(input_spirv_shader_job_json_file_path,
                   output_spirv_shader_job_json_file_path)

    for shader_file in shader_files:
        run_spirv_opt_on_spirv_shader(
            shader_file,
            output_spirv_shader_job_json_file_path.parent,
            spirv_opt_args,
            spirv_opt_file_path,
            spirv_opt_no_validate_after_all,
            preprocessor_cache=preprocessor_cache,
        )

    return output_spirv_shader_job_json_file_path
예제 #6
0
def main() -> None:
    parser = argparse.ArgumentParser(
        description=
        "Downloads the latest GraphicsFuzz AmberScript tests from vk-gl-cts, "
        "including those in pending CLs. "
        "Requires Git. Requires Khronos membership.")

    parser.add_argument(
        "gerrit_cookie",
        help=
        "The Gerrit cookie used for authentication. Requires Khronos membership. Obtain this as follows. "
        + GERRIT_COOKIE_INSTRUCTIONS,
    )

    parser.add_argument(
        "--settings",
        help="Path to the settings JSON file for this instance.",
        default=str(settings_util.DEFAULT_SETTINGS_FILE_PATH),
    )

    parsed_args = parser.parse_args(sys.argv[1:])

    cookie: str = parsed_args.gerrit_cookie
    settings_path: Path = Path(parsed_args.settings)

    # Need git.
    git_tool = util.tool_on_path("git")

    settings = settings_util.read_or_create(settings_path)

    binaries = binaries_util.get_default_binary_manager(settings=settings)

    tests_dir = Path() / "graphicsfuzz"
    download_cts_graphicsfuzz_tests(git_tool, cookie, tests_dir)
    extract_shaders(tests_dir, binaries)
예제 #7
0
def main() -> None:
    parser = argparse.ArgumentParser(
        description=
        "Downloads the latest GraphicsFuzz AmberScript tests from vk-gl-cts, "
        "including those in pending CLs. "
        "Requires Git.")

    parser.add_argument("gerrit_cookie",
                        help=GERRIT_COOKIE_ARGUMENT_DESCRIPTION)

    parser.add_argument(
        "--settings",
        help="Path to the settings JSON file for this instance.",
        default=str(settings_util.DEFAULT_SETTINGS_FILE_PATH),
    )

    parsed_args = parser.parse_args(sys.argv[1:])

    cookie: str = parsed_args.gerrit_cookie
    settings_path: Path = Path(parsed_args.settings)

    # Need git.
    git_tool = util.tool_on_path("git")

    settings = settings_util.read_or_create(settings_path)

    binaries = binaries_util.get_default_binary_manager(settings=settings)

    download_cts_graphicsfuzz_tests(git_tool, cookie, binaries)
예제 #8
0
def run_spirv_opt_on_spirv_shader(
    input_spirv_file_path: pathlib.Path,
    output_dir_path: pathlib.Path,
    spirv_opt_args: List[str],
    spirv_opt_file_path: Optional[pathlib.Path] = None,
    spirv_opt_no_validate_after_all: bool = False,
    time_limit: int = SPIRV_OPT_DEFAULT_TIME_LIMIT,
) -> pathlib.Path:

    if not spirv_opt_file_path:
        spirv_opt_file_path = util.tool_on_path(binaries_util.SPIRV_OPT_NAME)

    output_spirv_file_path = output_dir_path / input_spirv_file_path.name

    util.file_mkdirs_parent(output_spirv_file_path)

    cmd = [
        str(spirv_opt_file_path),
        str(input_spirv_file_path),
        "-o",
        str(output_spirv_file_path),
    ]

    if not spirv_opt_no_validate_after_all:
        cmd.append("--validate-after-all")

    cmd += spirv_opt_args

    cmd = util.prepend_catchsegv_if_available(cmd)

    subprocess_util.run(cmd, timeout=time_limit)

    return output_spirv_file_path
예제 #9
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
예제 #10
0
def get_function_signature_from_address(module: Path, address: str) -> Optional[str]:
    try:
        address_tool = util.tool_on_path("addr2line")
        result = subprocess_util.run(
            [str(address_tool), "-e", str(module), address, "-f", "-C"],
            check_exit_code=False,
        )
        if result.returncode != 0:
            return None
        stdout: str = result.stdout
        lines = stdout.splitlines()
        if not lines:
            return None
        return lines[0]
    except util.ToolNotOnPathError:
        return None
예제 #11
0
def run_spirv_shader_job_to_spirv_asm_shader_job(
    input_spirv_job_json_file_path: pathlib.Path,
    output_spirv_job_json_file_path: pathlib.Path,
    spirv_dis_file_path: Optional[pathlib.Path] = None,
) -> pathlib.Path:

    if not spirv_dis_file_path:
        spirv_dis_file_path = util.tool_on_path(binaries_util.SPIRV_DIS_NAME)

    shader_files = shader_job_util.get_related_files(
        input_spirv_job_json_file_path,
        language_suffix=[shader_job_util.SUFFIX_SPIRV])

    util.copy_file(input_spirv_job_json_file_path,
                   output_spirv_job_json_file_path)

    for shader_file in shader_files:
        run_spirv_dis_on_spirv_shader(shader_file,
                                      output_spirv_job_json_file_path.parent,
                                      spirv_dis_file_path)

    return output_spirv_job_json_file_path
예제 #12
0
def run_spirv_dis_on_spirv_shader(
    input_spirv_file_path: pathlib.Path,
    output_dir_path: pathlib.Path,
    spirv_dis_file_path: Optional[pathlib.Path] = None,
) -> pathlib.Path:
    if not spirv_dis_file_path:
        spirv_dis_file_path = util.tool_on_path(binaries_util.SPIRV_DIS_NAME)

    output_spirv_file_path = output_dir_path / (
        util.remove_end(input_spirv_file_path.name, ".spv") + ".asm")

    util.file_mkdirs_parent(output_spirv_file_path)

    subprocess_util.run(
        util.prepend_catchsegv_if_available([
            str(spirv_dis_file_path),
            str(input_spirv_file_path),
            "-o",
            str(output_spirv_file_path),
            "--raw-id",
        ]))

    return output_spirv_file_path
예제 #13
0
def run_spirv_opt_on_spirv_shader(
    input_spirv_file_path: pathlib.Path,
    output_dir_path: pathlib.Path,
    spirv_opt_args: List[str],
    spirv_opt_file_path: Optional[pathlib.Path] = None,
    spirv_opt_no_validate_after_all: bool = False,
    time_limit: int = SPIRV_OPT_DEFAULT_TIME_LIMIT,
    preprocessor_cache: Optional[util.CommandCache] = None,
) -> pathlib.Path:

    if not spirv_opt_file_path:
        spirv_opt_file_path = util.tool_on_path(binaries_util.SPIRV_OPT_NAME)

    output_spirv_file_path = output_dir_path / input_spirv_file_path.name

    util.file_mkdirs_parent(output_spirv_file_path)

    cmd = util.HashedCommand()
    cmd.append_program_path(spirv_opt_file_path)
    cmd.append_input_file(input_spirv_file_path)
    cmd.append_str("-o")
    cmd.append_output_file(output_spirv_file_path)
    if not spirv_opt_no_validate_after_all:
        cmd.append_str("--validate-after-all")
    cmd.extend_str(spirv_opt_args)

    if preprocessor_cache and preprocessor_cache.write_cached_output_file(
            cmd, output_spirv_file_path):
        return output_spirv_file_path

    cmd_str = util.prepend_catchsegv_if_available(cmd.cmd)
    subprocess_util.run(cmd_str, timeout=time_limit)

    if preprocessor_cache:
        preprocessor_cache.add_output_to_cache(cmd, output_spirv_file_path)

    return output_spirv_file_path
def run_glslang_glsl_shader_to_spirv_shader(
    glsl_shader_path: pathlib.Path,
    output_dir_path: pathlib.Path,
    glslang_validator_file_path: Optional[pathlib.Path] = None,
    time_limit: int = GLSLANG_DEFAULT_TIME_LIMIT,
    preprocessor_cache: Optional[util.CommandCache] = None,
) -> pathlib.Path:

    if not glslang_validator_file_path:
        glslang_validator_file_path = util.tool_on_path(
            binaries_util.GLSLANG_VALIDATOR_NAME)

    output_spirv_file_path = output_dir_path / (glsl_shader_path.name + ".spv")

    util.file_mkdirs_parent(output_spirv_file_path)

    cmd = util.HashedCommand()
    cmd.append_program_path(glslang_validator_file_path)
    cmd.append_str("-V")
    cmd.append_str("-o")
    cmd.append_output_file(output_spirv_file_path)
    cmd.append_input_file(glsl_shader_path)

    if preprocessor_cache and preprocessor_cache.write_cached_output_file(
            cmd, output_spirv_file_path):
        return output_spirv_file_path

    cmd_str = util.prepend_catchsegv_if_available(cmd.cmd)
    subprocess_util.run(
        cmd_str,
        timeout=time_limit,
    )

    if preprocessor_cache:
        preprocessor_cache.add_output_to_cache(cmd, output_spirv_file_path)

    return output_spirv_file_path
예제 #15
0
def main_helper(  # pylint: disable=too-many-locals, too-many-branches, too-many-statements;
    settings_path: Path,
    iteration_seed_override: Optional[int] = None,
    fuzzing_tool_pattern: Optional[List[FuzzingTool]] = None,
    allow_no_stack_traces: bool = False,
    override_sigint: bool = True,
    use_amber_vulkan_loader: bool = False,
    active_device_names: Optional[List[str]] = None,
    update_ignored_crash_signatures_gerrit_cookie: Optional[str] = None,
) -> None:

    if not fuzzing_tool_pattern:
        fuzzing_tool_pattern = [FuzzingTool.GLSL_FUZZ]

    util.update_gcov_environment_variable_if_needed()

    if override_sigint:
        interrupt_util.override_sigint()

    try_get_root_file()

    settings = settings_util.read_or_create(settings_path)

    binary_manager = binaries_util.get_default_binary_manager(
        settings=settings)

    temp_dir = Path() / "temp"

    # Note: we use "is not None" so that if the user passes an empty Gerrit cookie, we still try to execute this code.
    if update_ignored_crash_signatures_gerrit_cookie is not None:
        git_tool = util.tool_on_path("git")
        downloaded_graphicsfuzz_tests_dir = (
            temp_dir / f"graphicsfuzz_cts_tests_{get_random_name()[:8]}")
        work_dir = temp_dir / f"graphicsfuzz_cts_run_{get_random_name()[:8]}"
        download_cts_gf_tests.download_cts_graphicsfuzz_tests(
            git_tool=git_tool,
            cookie=update_ignored_crash_signatures_gerrit_cookie,
            output_tests_dir=downloaded_graphicsfuzz_tests_dir,
        )
        download_cts_gf_tests.extract_shaders(
            tests_dir=downloaded_graphicsfuzz_tests_dir,
            binaries=binary_manager)
        with util.file_open_text(work_dir / "results.csv",
                                 "w") as results_out_handle:
            run_cts_gf_tests.main_helper(
                tests_dir=downloaded_graphicsfuzz_tests_dir,
                work_dir=work_dir,
                binaries=binary_manager,
                settings=settings,
                active_devices=devices_util.get_active_devices(
                    settings.device_list),
                results_out_handle=results_out_handle,
                updated_settings_output_path=settings_path,
            )
        return

    active_devices = devices_util.get_active_devices(
        settings.device_list, active_device_names=active_device_names)

    # Add host_preprocessor device from device list if it is missing.
    if not active_devices[0].HasField("preprocess"):
        for device in settings.device_list.devices:
            if device.HasField("preprocess"):
                active_devices.insert(0, device)
                break

    # Add host_preprocessor device (from scratch) if it is still missing.
    if not active_devices[0].HasField("preprocess"):
        active_devices.insert(
            0, Device(name="host_preprocessor", preprocess=DevicePreprocess()))

    reports_dir = Path() / "reports"
    fuzz_failures_dir = reports_dir / FUZZ_FAILURES_DIR_NAME
    references_dir = Path() / REFERENCES_DIR
    donors_dir = Path() / DONORS_DIR
    spirv_fuzz_shaders_dir = Path() / "spirv_fuzz_shaders"

    # Log a warning if there is no tool on the PATH for printing stack traces.
    prepended = util.prepend_catchsegv_if_available([], log_warning=True)
    if not allow_no_stack_traces and not prepended:
        raise AssertionError("Stopping because we cannot get stack traces.")

    spirv_fuzz_shaders: List[Path] = []
    references: List[Path] = []

    if FuzzingTool.SPIRV_FUZZ in fuzzing_tool_pattern:
        check_dir_exists(spirv_fuzz_shaders_dir)
        spirv_fuzz_shaders = sorted(spirv_fuzz_shaders_dir.rglob("*.json"))

    if FuzzingTool.GLSL_FUZZ in fuzzing_tool_pattern:
        check_dir_exists(references_dir)
        check_dir_exists(donors_dir)
        # TODO: make GraphicsFuzz find donors recursively.
        references = sorted(references_dir.rglob("*.json"))
        # Filter to only include .json files that have at least one shader (.frag, .vert, .comp) file.
        references = [
            ref for ref in references if shader_job_util.get_related_files(ref)
        ]

    if use_amber_vulkan_loader:
        library_path = binary_manager.get_binary_path_by_name(
            binaries_util.AMBER_VULKAN_LOADER_NAME).path.parent
        util.add_library_paths_to_environ([library_path], os.environ)

    fuzzing_tool_index = 0

    while True:

        interrupt_util.interrupt_if_needed()

        # We have to use "is not None" because the seed could be 0.
        if iteration_seed_override is not None:
            iteration_seed = iteration_seed_override
        else:
            iteration_seed = secrets.randbits(ITERATION_SEED_BITS)

        log(f"Iteration seed: {iteration_seed}")
        random.seed(iteration_seed)

        staging_name = get_random_name()[:8]
        staging_dir = temp_dir / staging_name

        try:
            util.mkdir_p_new(staging_dir)
        except FileExistsError:
            if iteration_seed_override is not None:
                raise
            log(f"Staging directory already exists: {str(staging_dir)}")
            log("Starting new iteration.")
            continue

        # Pseudocode:
        #  - Create test_dir(s) in staging directory.
        #  - Run test_dir(s) on all active devices (stop early if appropriate).
        #  - For each test failure on each device, copy the test to reports_dir, adding the device and crash signature.
        #  - Reduce each report (on the given device).
        #  - Produce a summary for each report.

        fuzzing_tool = fuzzing_tool_pattern[fuzzing_tool_index]
        fuzzing_tool_index = (fuzzing_tool_index +
                              1) % len(fuzzing_tool_pattern)

        if fuzzing_tool == FuzzingTool.SPIRV_FUZZ:
            fuzz_spirv_test.fuzz_spirv(
                staging_dir,
                reports_dir,
                fuzz_failures_dir,
                active_devices,
                spirv_fuzz_shaders,
                settings,
                binary_manager,
            )
        elif fuzzing_tool == FuzzingTool.GLSL_FUZZ:
            fuzz_glsl_test.fuzz_glsl(
                staging_dir,
                reports_dir,
                fuzz_failures_dir,
                active_devices,
                references,
                donors_dir,
                settings,
                binary_manager,
            )
        else:
            raise AssertionError(f"Unknown fuzzing tool: {fuzzing_tool}")

        if iteration_seed_override is not None:
            log("Stopping due to iteration_seed")
            break
        shutil.rmtree(staging_dir)
예제 #16
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
예제 #17
0
def main() -> None:  # pylint: disable=too-many-locals;
    parser = argparse.ArgumentParser(
        description="Generates an AmberScript test from a shader job.")

    parser.add_argument(
        "shader_job",
        help="The input .json shader job file.",
    )

    parser.add_argument(
        "--output",
        help="Output directory.",
        default="output",
    )

    parser.add_argument(
        "--spirv_opt_args",
        help=
        "Arguments for spirv-opt as a space-separated string, or an empty string to skip running spirv-opt.",
        default="",
    )

    parser.add_argument(
        "--settings",
        help=
        "Path to a settings JSON file for this instance. The file will be generated if needed. ",
        default="settings.json",
    )

    parsed_args = parser.parse_args(sys.argv[1:])

    shader_job: Path = Path(parsed_args.shader_job)
    out_dir: Path = Path(parsed_args.output)
    spirv_opt_args_str: str = parsed_args.spirv_opt_args
    settings_path: Path = Path(parsed_args.settings)

    spirv_opt_args: List[str] = []
    if spirv_opt_args_str:
        spirv_opt_args = spirv_opt_args_str.split(" ")

    settings = settings_util.read_or_create(settings_path)

    binary_manager = binaries_util.get_default_binary_manager(settings)

    staging_dir = out_dir / "staging"

    template_source_dir = staging_dir / "source_template"
    test_dir = staging_dir / "test"

    run_output_dir: Path = out_dir / "run"

    # Remove stale directories.
    if staging_dir.is_dir():
        shutil.rmtree(staging_dir)
    if run_output_dir.is_dir():
        shutil.rmtree(run_output_dir)

    # Create source template and call |make_test|.

    if shader_job_util.get_related_suffixes_that_exist(
            shader_job, language_suffix=[shader_job_util.SUFFIX_SPIRV]):
        # This is a SPIR-V shader job.

        shader_job_util.copy(
            shader_job,
            template_source_dir / test_util.VARIANT_DIR / test_util.SHADER_JOB,
            language_suffix=shader_job_util.SUFFIXES_SPIRV_FUZZ_INPUT,
        )

        fuzz_spirv_amber_test.make_test(
            template_source_dir,
            test_dir,
            spirv_opt_args=spirv_opt_args,
            binary_manager=binary_manager,
            derived_from=shader_job.stem,
            stable_shader=False,
            common_spirv_args=list(settings.common_spirv_args),
        )

    elif shader_job_util.get_related_suffixes_that_exist(
            shader_job, language_suffix=[shader_job_util.SUFFIX_GLSL]):
        # This is a GLSL shader job.

        # 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),
        )

        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,
                    shader_job,
                    template_source_dir / test_util.VARIANT_DIR /
                    test_util.SHADER_JOB,
                    legacy_graphics_fuzz_vulkan_arg=settings.
                    legacy_graphics_fuzz_vulkan_arg,
                )
            finally:
                gflogging.pop_stream_for_logging()

        fuzz_glsl_amber_test.make_test(
            template_source_dir,
            test_dir,
            spirv_opt_args=spirv_opt_args,
            binary_manager=binary_manager,
            derived_from=shader_job.stem,
            stable_shader=False,
            common_spirv_args=list(settings.common_spirv_args),
        )

    else:
        raise AssertionError(
            "Unexpected shader job type; expected GLSL or SPIR-V shaders.")

    preprocessor_cache = util.CommandCache()

    fuzz_test_util.run_shader_job(
        source_dir=test_util.get_source_dir(test_dir),
        output_dir=run_output_dir,
        binary_manager=binary_manager,
        device=Device(host=DeviceHost()),
        preprocessor_cache=preprocessor_cache,
        stop_after_amber=True,
    )