"""v4.8.0 GPU capability-profile tests. Covers the combined generation dropdown entries: profile data integrity, the auto-match matrix (including Tesla/data-center and the crypto-era CMP oddballs), profile-driven encoder resolution, and the rebuild dep-tree extension. """ import os import pytest from conftest import load_program_module _m = load_program_module() VIDEO_CODECS = _m.VIDEO_CODECS resolve_gpu_encoder = _m.resolve_gpu_encoder GPU_PROFILES = _m.GPU_PROFILES encoder_filter_chain = _m.encoder_filter_chain encoder_quality_args = _m.encoder_quality_args encoder_pre_args = _m.encoder_pre_args gpu_profile_by_key = _m.gpu_profile_by_key match_gpu_profile = _m.match_gpu_profile class TestProfileData: def test_keys_unique(self): keys = [p.key for p in GPU_PROFILES] assert len(keys) == len(set(keys)) def test_labels_unique(self): labels = [p.label for p in GPU_PROFILES] assert len(labels) == len(set(labels)) def test_cpu_only_profile_claims_nothing(self): cpu = gpu_profile_by_key("cpu") assert cpu.encoders == {} assert cpu.api == "none" def test_compute_boards_claim_nothing(self): """V100/A100/H100-class boards and CMP 170HX have no NVENC — selecting them must land on the CPU path, not crash.""" compute = gpu_profile_by_key("nv-compute") assert compute.encoders == {} def test_ada_has_av1_older_nvidia_does_not(self): ada = gpu_profile_by_key("nv-ada") assert ada.encoders["av1"] == "av1_nvenc" for key in ("nv-pascal", "nv-turing", "nv-ampere"): assert "av1" not in gpu_profile_by_key(key).encoders def test_intel_arc_has_av1_qsv(self): arc = gpu_profile_by_key("intel-arc") assert arc.api == "qsv" assert arc.encoders["av1"] == "av1_qsv" def test_amd_rdna3_has_av1_vaapi_rdna12_does_not(self): assert gpu_profile_by_key("amd-rdna3").encoders["av1"] == "av1_vaapi" assert "av1" not in gpu_profile_by_key("amd-rdna12").encoders def test_vp9_only_via_vaapi(self): VIDEO_CODECS = load_program_module().VIDEO_CODECS vp9 = next(c for c in VIDEO_CODECS if "VP9" in c.label) assert vp9.gpu_encoders_by_api == {"vaapi": "vp9_vaapi"} class TestMatchMatrix: @pytest.mark.parametrize("name,expected_key", [ ("NVIDIA GeForce GTX 1070", "nv-pascal"), ("NVIDIA GeForce GTX 1080 Ti", "nv-pascal"), ("NVIDIA GeForce RTX 2060", "nv-turing"), ("NVIDIA GeForce GTX 1660 SUPER", "nv-turing"), ("NVIDIA GeForce RTX 3060", "nv-ampere"), ("NVIDIA GeForce RTX 4090", "nv-ada"), ("NVIDIA GeForce RTX 5080", "nv-ada"), ("Tesla P40", "nv-pascal"), ("Tesla T4", "nv-turing"), ("NVIDIA A10", "nv-ampere"), ("NVIDIA CMP 50HX", "nv-turing"), ("NVIDIA CMP 90HX", "nv-ampere"), ("NVIDIA CMP 170HX GA100", "nv-compute"), ("NVIDIA CMP 170HX", "nv-compute"), ("NVIDIA A100-SXM4-40GB", "nv-compute"), ("NVIDIA H100", "nv-compute"), ("Intel(R) Arc(TM) B580", "intel-arc"), ("Intel(R) UHD Graphics 770", "intel-xe"), ]) def test_match(self, name, expected_key): assert match_gpu_profile(name).key == expected_key def test_no_match_returns_none(self): assert match_gpu_profile("") is None assert match_gpu_profile("Unknown Widget Graphics") is None class TestProfileResolution: def _env(self, functional, flags=None, profile_key=""): class G: pass g = G() g.functional = functional g.profile_key = profile_key class E: pass e = E() e.gpu = g e.av1an_flags = flags or {} return e def test_hevc_via_pascal_profile(self): env = self._env({"hevc_nvenc": True}, {"gpu_profile": "nv-pascal"}) codec = next(c for c in VIDEO_CODECS if "x265" in c.label) assert resolve_gpu_encoder("auto", codec, env) == ("hevc_nvenc", "nvenc") def test_arc_qsv_hevc(self): env = self._env({"hevc_qsv": True}, {"gpu_profile": "intel-arc"}) codec = next(c for c in VIDEO_CODECS if "x265" in c.label) assert resolve_gpu_encoder("auto", codec, env) == ("hevc_qsv", "qsv") def test_vp9_on_amd_stays_cpu(self): # AMD VCN has no VP9 encode — even though ffmpeg has vp9_vaapi, # the RDNA 3 profile truthfully claims none. env = self._env({"vp9_vaapi": True}, {"gpu_profile": "amd-rdna3"}) codec = next(c for c in VIDEO_CODECS if "VP9" in c.label) assert resolve_gpu_encoder("auto", codec, env) == (None, None) def test_vaapi_encoder_args_shape(self): profile = gpu_profile_by_key("amd-rdna3") assert encoder_pre_args(profile)[0] == "-vaapi_device" assert "format=nv12,hwupload" in encoder_filter_chain(profile) args = encoder_quality_args("vaapi", "hevc_vaapi", 28, 9) assert args[:2] == ["-rc_mode", "CQP"] class TestRebuildGpuDeps: def test_nvenc_needs_codec_headers(self): gpu_dep_packages = load_program_module().gpu_dep_packages pkgs = gpu_dep_packages("nvenc", "arch") assert "nv-codec-headers" in pkgs def test_vaapi_qsv_driver_packages(self): gpu_dep_packages = load_program_module().gpu_dep_packages assert any("libva" in p for p in gpu_dep_packages("vaapi", "arch")) assert any("intel-media-driver" in p for p in gpu_dep_packages("qsv", "arch")) def test_unpackaged_family_returns_empty(self): gpu_dep_packages = load_program_module().gpu_dep_packages assert gpu_dep_packages("nvenc", "nixos") == [] def importlib_pyside_available(): import importlib.util return importlib.util.find_spec("PySide6") is not None class TestGpuComboEngineInteraction: @pytest.mark.skipif( not importlib_pyside_available(), reason="requires a real PySide6 (stub mode cannot instantiate Qt)", ) def test_cpu_engine_disables_gpu_menu(self): """v4.8.1: ENGINE = CPU greys out the GPU dropdown; the explicit 'None (CPU-only encode)' entry remains for opting out while a GPU-capable engine is selected.""" os.environ.setdefault("QT_QPA_PLATFORM", "offscreen") from PySide6.QtWidgets import QApplication OpenCodecMaster = load_program_module().OpenCodecMaster app = QApplication.instance() or QApplication([]) window = OpenCodecMaster() try: gpu_idx = next(i for i in range(window.gpu_combo.count()) if "None (CPU-only" in window.gpu_combo.itemText(i)) assert gpu_idx > 0, "None (CPU-only) must be an explicit option" window.engine_combo.setCurrentIndex(0) # Auto assert window.gpu_combo.isEnabled() window.engine_combo.setCurrentIndex(2) # CPU assert not window.gpu_combo.isEnabled(), ( "ENGINE = CPU must disable the GPU dropdown" ) window.engine_combo.setCurrentIndex(1) # GPU assert window.gpu_combo.isEnabled() finally: window.close() class TestLauncherParity: def test_launcher_has_gpu_profiles(self, opentranscode_module): assert hasattr(opentranscode_module, "GPU_PROFILES") assert hasattr(opentranscode_module, "match_gpu_profile")