|
| 1 | +#!/usr/bin/env python3 |
| 2 | +"""Setup Agility SDK binaries for DXC execution tests. |
| 3 | +
|
| 4 | +Automates downloading and installing the latest D3D12 Agility SDK binaries |
| 5 | +into the TAEF directory of an hlsl.bin build tree, so exec tests can run |
| 6 | +with the latest D3D12 runtime. |
| 7 | +
|
| 8 | +Usage: |
| 9 | + python setup_agility_sdk.py [hlsl_bin_dir] [options] |
| 10 | +
|
| 11 | +Examples: |
| 12 | + python setup_agility_sdk.py F:\\hlsl.bin |
| 13 | + python setup_agility_sdk.py F:\\hlsl.bin --sdk-type preview |
| 14 | + python setup_agility_sdk.py --overwrite |
| 15 | +""" |
| 16 | + |
| 17 | +import argparse |
| 18 | +import glob |
| 19 | +import logging |
| 20 | +import os |
| 21 | +import shutil |
| 22 | +import sys |
| 23 | +import tempfile |
| 24 | +import zipfile |
| 25 | + |
| 26 | +DEFAULT_HLSL_BIN = r"F:\hlsl.bin" |
| 27 | +NETWORK_SHARE = r"\\GRFXSHARE\Sigma-GRFX\Users\amarp\IHVDrops" |
| 28 | +ZIP_PATTERN = "D3D12_AgilitySDK_preview_*" |
| 29 | +AGILITY_DLLS = ["D3D12Core.dll", "D3D12SDKLayers.dll"] |
| 30 | + |
| 31 | +log = logging.getLogger("setup_agility_sdk") |
| 32 | + |
| 33 | + |
| 34 | +def parse_args(): |
| 35 | + parser = argparse.ArgumentParser( |
| 36 | + description="Setup Agility SDK binaries for DXC execution tests.", |
| 37 | + formatter_class=argparse.RawDescriptionHelpFormatter, |
| 38 | + epilog=( |
| 39 | + "examples:\n" |
| 40 | + " %(prog)s F:\\hlsl.bin\n" |
| 41 | + " %(prog)s F:\\hlsl.bin --sdk-type preview\n" |
| 42 | + " %(prog)s --overwrite\n" |
| 43 | + ), |
| 44 | + ) |
| 45 | + parser.add_argument( |
| 46 | + "hlsl_bin_dir", |
| 47 | + nargs="?", |
| 48 | + default=None, |
| 49 | + help="Path to the hlsl.bin build directory (default: %(default)s).", |
| 50 | + ) |
| 51 | + parser.add_argument( |
| 52 | + "--sdk-type", |
| 53 | + choices=["experimental", "preview"], |
| 54 | + default="experimental", |
| 55 | + help="Agility SDK flavor to install (default: experimental).", |
| 56 | + ) |
| 57 | + parser.add_argument( |
| 58 | + "--arch", |
| 59 | + choices=["x64", "x86", "ARM64"], |
| 60 | + default="x64", |
| 61 | + help="Target architecture (default: x64).", |
| 62 | + ) |
| 63 | + parser.add_argument( |
| 64 | + "--overwrite", |
| 65 | + action="store_true", |
| 66 | + help="Overwrite existing Agility SDK binaries even if already present.", |
| 67 | + ) |
| 68 | + return parser.parse_args() |
| 69 | + |
| 70 | + |
| 71 | +def validate_hlsl_bin(hlsl_bin_dir): |
| 72 | + """Validate that the hlsl.bin directory exists.""" |
| 73 | + if not os.path.isdir(hlsl_bin_dir): |
| 74 | + log.error("hlsl.bin directory does not exist: %s", hlsl_bin_dir) |
| 75 | + sys.exit(1) |
| 76 | + log.info("Using hlsl.bin directory: %s", hlsl_bin_dir) |
| 77 | + |
| 78 | + |
| 79 | +def validate_taef_dir(hlsl_bin_dir, arch): |
| 80 | + """Validate that the TAEF/<arch> directory exists under hlsl.bin.""" |
| 81 | + taef_dir = os.path.join(hlsl_bin_dir, "TAEF", arch) |
| 82 | + if not os.path.isdir(taef_dir): |
| 83 | + log.error( |
| 84 | + "TAEF directory not found: %s\n" |
| 85 | + " Make sure you have run hctstart.cmd to initialize the build environment.", |
| 86 | + taef_dir, |
| 87 | + ) |
| 88 | + sys.exit(1) |
| 89 | + log.info("Found TAEF directory: %s", taef_dir) |
| 90 | + return taef_dir |
| 91 | + |
| 92 | + |
| 93 | +def check_existing_sdk(taef_dir): |
| 94 | + """Check if D3D12 Agility SDK DLLs already exist. Returns the D3D12 dir path.""" |
| 95 | + d3d12_dir = os.path.join(taef_dir, "D3D12") |
| 96 | + if not os.path.isdir(d3d12_dir): |
| 97 | + log.info("D3D12 directory does not exist yet: %s", d3d12_dir) |
| 98 | + return d3d12_dir, False |
| 99 | + |
| 100 | + missing = [f for f in AGILITY_DLLS if not os.path.isfile(os.path.join(d3d12_dir, f))] |
| 101 | + if missing: |
| 102 | + log.info("Agility SDK incomplete, missing: %s", ", ".join(missing)) |
| 103 | + return d3d12_dir, False |
| 104 | + |
| 105 | + log.info("Agility SDK binaries already present in: %s", d3d12_dir) |
| 106 | + return d3d12_dir, True |
| 107 | + |
| 108 | + |
| 109 | +def access_network_share(): |
| 110 | + """Verify network share is accessible.""" |
| 111 | + log.info("Checking network share access: %s", NETWORK_SHARE) |
| 112 | + if not os.path.isdir(NETWORK_SHARE): |
| 113 | + log.error( |
| 114 | + "Cannot access network share: %s\n" |
| 115 | + " Must have corpnet or VPN access.", |
| 116 | + NETWORK_SHARE, |
| 117 | + ) |
| 118 | + sys.exit(1) |
| 119 | + log.info("Network share is accessible.") |
| 120 | + |
| 121 | + |
| 122 | +def find_newest_zip(): |
| 123 | + """Find the newest Agility SDK zip on the network share.""" |
| 124 | + pattern = os.path.join(NETWORK_SHARE, ZIP_PATTERN + ".zip") |
| 125 | + zips = sorted(glob.glob(pattern)) |
| 126 | + if not zips: |
| 127 | + log.error("No Agility SDK zips found matching: %s", pattern) |
| 128 | + sys.exit(1) |
| 129 | + newest = zips[-1] |
| 130 | + log.info("Found %d SDK zip(s). Using newest: %s", len(zips), os.path.basename(newest)) |
| 131 | + return newest |
| 132 | + |
| 133 | + |
| 134 | +def extract_and_copy(zip_path, sdk_type, arch, d3d12_dir): |
| 135 | + """Extract the SDK zip to a temp directory and copy binaries.""" |
| 136 | + tmp_dir = tempfile.mkdtemp(prefix="agility_sdk_") |
| 137 | + try: |
| 138 | + log.info("Extracting %s to temp directory...", os.path.basename(zip_path)) |
| 139 | + with zipfile.ZipFile(zip_path, "r") as zf: |
| 140 | + zf.extractall(tmp_dir) |
| 141 | + |
| 142 | + # The zip extracts into a top-level directory named like the zip (without .zip). |
| 143 | + # Find the actual extraction root. |
| 144 | + top_dirs = [ |
| 145 | + d for d in os.listdir(tmp_dir) if os.path.isdir(os.path.join(tmp_dir, d)) |
| 146 | + ] |
| 147 | + |
| 148 | + # Source path: <extract_root>/<sdk_type>/<arch>/sdkbin/ |
| 149 | + # Try with and without a top-level wrapper directory. |
| 150 | + candidates = [os.path.join(tmp_dir, sdk_type, arch, "sdkbin")] |
| 151 | + for td in top_dirs: |
| 152 | + candidates.insert(0, os.path.join(tmp_dir, td, sdk_type, arch, "sdkbin")) |
| 153 | + |
| 154 | + src_dir = None |
| 155 | + for c in candidates: |
| 156 | + if os.path.isdir(c): |
| 157 | + src_dir = c |
| 158 | + break |
| 159 | + |
| 160 | + if src_dir is None: |
| 161 | + log.error( |
| 162 | + "Could not find SDK binaries in extracted zip.\n" |
| 163 | + " Expected path: <zip_root>/%s/%s/sdkbin/\n" |
| 164 | + " Searched:\n %s", |
| 165 | + sdk_type, |
| 166 | + arch, |
| 167 | + "\n ".join(candidates), |
| 168 | + ) |
| 169 | + sys.exit(1) |
| 170 | + |
| 171 | + log.info("Found SDK binaries at: %s", src_dir) |
| 172 | + |
| 173 | + # Create destination D3D12 directory if needed. |
| 174 | + os.makedirs(d3d12_dir, exist_ok=True) |
| 175 | + |
| 176 | + # Copy only the Agility SDK DLLs and their PDBs. |
| 177 | + target_stems = {os.path.splitext(f)[0].lower() for f in AGILITY_DLLS} |
| 178 | + copied = [] |
| 179 | + for fname in os.listdir(src_dir): |
| 180 | + stem = os.path.splitext(fname)[0].lower() |
| 181 | + ext = os.path.splitext(fname)[1].lower() |
| 182 | + if stem in target_stems and ext in (".dll", ".pdb"): |
| 183 | + src = os.path.join(src_dir, fname) |
| 184 | + dst = os.path.join(d3d12_dir, fname) |
| 185 | + shutil.copy2(src, dst) |
| 186 | + copied.append(fname) |
| 187 | + log.info(" Copied: %s", fname) |
| 188 | + |
| 189 | + if not copied: |
| 190 | + log.warning("No DLL/PDB files found in %s", src_dir) |
| 191 | + else: |
| 192 | + log.info("Copied %d file(s) to %s", len(copied), d3d12_dir) |
| 193 | + |
| 194 | + finally: |
| 195 | + log.info("Cleaning up temp directory: %s", tmp_dir) |
| 196 | + shutil.rmtree(tmp_dir, ignore_errors=True) |
| 197 | + |
| 198 | + |
| 199 | +def main(): |
| 200 | + logging.basicConfig( |
| 201 | + level=logging.INFO, |
| 202 | + format="%(levelname)-7s %(message)s", |
| 203 | + ) |
| 204 | + |
| 205 | + args = parse_args() |
| 206 | + |
| 207 | + # Resolve hlsl.bin directory. |
| 208 | + if args.hlsl_bin_dir is None: |
| 209 | + log.warning( |
| 210 | + "No hlsl.bin path provided, defaulting to %s", DEFAULT_HLSL_BIN |
| 211 | + ) |
| 212 | + hlsl_bin_dir = DEFAULT_HLSL_BIN |
| 213 | + else: |
| 214 | + hlsl_bin_dir = args.hlsl_bin_dir |
| 215 | + |
| 216 | + hlsl_bin_dir = os.path.abspath(hlsl_bin_dir) |
| 217 | + |
| 218 | + # Step 1: Validate hlsl.bin. |
| 219 | + validate_hlsl_bin(hlsl_bin_dir) |
| 220 | + |
| 221 | + # Step 2: Validate TAEF directory. |
| 222 | + taef_dir = validate_taef_dir(hlsl_bin_dir, args.arch) |
| 223 | + |
| 224 | + # Step 3: Check for existing Agility SDK. |
| 225 | + d3d12_dir, already_present = check_existing_sdk(taef_dir) |
| 226 | + if already_present and not args.overwrite: |
| 227 | + log.info("Nothing to do. Use --overwrite to force update.") |
| 228 | + return |
| 229 | + if already_present and args.overwrite: |
| 230 | + log.info("--overwrite specified, will replace existing binaries.") |
| 231 | + |
| 232 | + # Step 4: Access network share. |
| 233 | + access_network_share() |
| 234 | + |
| 235 | + # Step 5: Find newest SDK zip. |
| 236 | + zip_path = find_newest_zip() |
| 237 | + |
| 238 | + # Step 6-7: Extract and copy. |
| 239 | + extract_and_copy(zip_path, args.sdk_type, args.arch, d3d12_dir) |
| 240 | + |
| 241 | + log.info("Agility SDK setup complete.") |
| 242 | + |
| 243 | + |
| 244 | +if __name__ == "__main__": |
| 245 | + main() |
0 commit comments