見出し画像

Tips:ハードウェア アクセラレータによるGPUスケジューリングとは?青い[HAGS]スイッチの向こう側

前記事になります↓


Windows 11の「グラフィックスの詳細設定」
そこにある「ハードウェア アクセラレータによるGPUスケジューリング」はオンになっている。つまみは右側。トグル背景色は青く見える。説明は短い。

Kは画面を見つめた。

「オンなら速い。オフなら遅い――そういう話なのか?」

そこにはFPSも、遅延も、相性も書かれていない。
だが、その二択の下には、二択では済まない世界が沈んでいると思った。

Kがスイッチへ指を伸ばした瞬間、画面の奥から声がした。

「押す前に、そのオンが何を意味するか知りたくないか」

振り返ると、黒いコートを着た案内役が立っている、顔は霧ががっていて、胸元には小さく、dxgkrnlと記されている。

「WindowsのGPU管制室まで案内する。そこで見れば、HAGSが速さの魔法ではないことも、ただの飾りではないことも分かる」

案内役が青いトグルスイッチへ触れると、設定画面が扉のように開いた。


仕事を速くする者、仕事を迷わせない者

扉の先には巨大な管制室があった。
無数の札がベルトコンベアを流れている。札にはゲーム、ブラウザ、動画再生、デスクトップ、録画ソフトの名前が書かれている。

ガタンガタン。

部屋の中央では、一人の管制官が目にも止まらぬ速さで札を仕分けしている。

「彼が旧来のWDDM GPUスケジューラ君だ」と案内役が親指を向けながらほくそ笑んだ。

管制官はCPU上の高優先度スレッドだった。仕事の順番、実行時間、コンテキスト切替を調整している。

「GPUは並列処理が得意なんだろう? 仕事を全部渡せばいい」
Kの言葉は妥当だ。せっかちとも取れる端的さで口が動いた。

「んなぁ単純でもない。列には順番がいる。英語ではQueueだ、こいつが大事だ。だからといって列をなくせば速くなるのではない。列をなくせば、仕事が衝突する、ドカンッ」
案内役が向けたピンと伸ばした人差し指が上に跳ねる。

Queue――は列。Kはその言葉を覚えた。

ゲームは普通、フレームNのGPU処理中に、CPUでフレームN+1のコマンドを準備する。命令をまとめればスケジューリング回数を減らし、CPUとGPUを並行して働かせられる。

「だったら旧方式で十分じゃないか」

「コストは多くの場合隠れていたんだよ。Microsoftも、移行は大半の利用者にとって透明だと説明している」

案内役は一枚の資料を差し出した。

Microsoftの説明では、HAGSは高頻度の量子管理とGPUエンジンのコンテキスト切替を、GPU上の専用スケジューリングプロセッサへ移す。

「量子?なんだ宇宙の話か?」

「こんな箱の中で宇宙の話なんか出すか、一つの仕事へ与える実行時間の単位だ。独占させすぎれば他が待つし、短すぎれば舞台転換ばかり増える」
案内役はあきれたよう脳みそをトントンさせた。

「Context Switchは舞台転換か」

「そうだ馬鹿頭。役者が変わるたび、舞台の状態も切り替える。転換がゼロなら一人芝居しかできない。多すぎれば芝居が進まないしな」

HAGSは演算器もVRAMも増やさず、シェーダーやレイトレーシングの計算量も減らさない。

変わるのは、舞台監督の居場所だった。

CPU側で高頻度に行っていた量子管理と舞台転換を、GPU側の専用プロセッサへ大きく移す。

Kは言った。てか思ったことが口に出ていた。

「つまりHAGSは、仕事を速くするんじゃない」

案内役がガタンガタンと作業が行われる背景をバックにやれやれ顔でそれでいて納得したかのような声音を飛ばす。

仕事を迷わせないための仕組みを、仕事場の近くへ移す。

それが最初の答えだった。

注釈―
この説明はMicrosoft DirectX開発者ブログのHAGS解説を参照。
WindowsはHAGS ONでもアプリケーション間の優先順位を引き続き決定する。HAGSが移すのは「ほとんどのスケジューリング」とされるが、OSの統治そのものではないが大事。

出典: Microsoft: Hardware Accelerated GPU Scheduling


オンへ至る三つの数字

次の部屋には三つの数字が刻まれた扉があった。

0、1、2

扉の上にはHwSchModeと書かれている。

「設定画面のオンとオフなら、数字は二つで足りるはずだろ?」

「画面は結果を見せる。内部は交渉をする」
と理解しがたい言葉が返ってきた。

dxgkrnl!DpiInitializeGlobalStateは、GraphicsDriversから三つの値を読む。

  • HwSchMode

  • HwSchOverrideBlockList

  • HwSchTreatExperimentalAsStable

HwSchModeの既定値は0。
受理範囲は0~2で、問合せ失敗や3以上は0へ戻る。
PCに明示値がなかった時は内部値は0になる。

「値がないならオフでは?」

「そこが最初の罠だ。0はオフではなく、ドライバーとOSの交渉結果に従う既定動作だ」

GPUドライバーはHAGSへの対応状態を二ビットで報告する。
公開名称は四つ。

  1. Always Off――対応しない

  2. Experimental――実験段階

  3. Stable――安定対応

  4. Always On――この機能なしではドライバーが動作しない

対象ビルドのdxgkrnl!DpQueryFeatureSupportでは、HAGSについて次の中間判定を行う。

Always Off → modeに関係なく無効候補
Experimental → 通常は無効候補
Stable → mode 0または2なら有効候補、mode 1なら無効候補
Always On → modeに関係なく有効候補

HwSchTreatExperimentalAsStable=1なら、ExperimentalをStableとして扱う試験経路もある。

Kは扉を見比べた。

「0は任せる。1はStableを止める。2はStableを有効にする・・・か」

「この関数の段階では、そう読める」
案内役の霧がかっている顔がニヤリと笑った気がした。

「はぁ?この段階では?」

「ここで立つのは最終判決ではなく、有効候補の札にすぎないのさ。その後もDpiIsFeatureEnabled、機能構成、依存関係、アダプター能力などの確認が続く。地図にはなるが入国許可証ではないのが肝だ」

三つの扉の先に、さらに門が並んでいた。

最初の門はGPU Virtual Address。ContextSchedulingを報告してもGPU仮想アドレス能力がなければ拒否される。次はOS Allowed。ハードウェアとドライバーが対応してもOSが許可しなければ進めない。

その次はNode Capability。3D、Compute、Copy、Videoなど、GPUの各ノード/エンジンが同じ能力を持つとは限らない。ADAPTER_RENDER::NodeSupportsContextSchedulingは、指定ノードのメタデータにある対応ビットを検査する。

最後の壁には、黒い文字でDISABLE_HWSCHと書かれていた。

CheckKernelBlockListは、この文字列が適用された場合、アダプター状態へ0x800ビットを立てる。

「これがブロックリストか。なら、このビットがHAGSを止める」

「待て。それはまだお前の推論にすぎん」

「名前がDISABLE_HWSCHだろ?」

「名称とフラグ設定は確認できた。しかし、その0x800が最終的に消費されて、実効HAGSを無効にする全経路までは追跡できていないだろ。事実はフラグを立てる。その先は未確定だ」

証拠が一歩なら、結論も一歩まで。


柵を越えず、列を止めず

門を抜けると、無数のHW Queueが走る場所へ出た。

Queueには通常コマンド、Present、ページング、プリエンプションなどが並ぶ。動く列も、Fenceの前で止まる列もある。

「Fenceは柵か」

「そのままだよ。先行する処理が終わるまで越えてはいけない境界だ。ただし柵は邪魔者ではない。順序を守るから、後続の処理が壊れない」

VidSchiPacketBlockedOnWaitConditionは、パケット種別、同期条件、Primary allocationの参照状態、デバイス状態、HW Queueが満杯かどうかを調べる。HAGS ONでも、列が満杯なら仕事は待つ。Fenceが閉じていれば越えない。

「HAGSをONにすれば、仕事が無制限にGPUへ流れるわけじゃない」

「無制限は高速の別名ではない。しばしば渋滞の別名だ」

少し先では時計係が働いていた。
VidSchiUpdateHwSchRunningTime。Monitored Fence、Suspend完了、Native FenceのDPCなどから呼ばれ、KeQueryPerformanceCounterを使い、ハードウェア時計を較正しながらコンテキスト実行時間を更新している。

「GPU側へ任せたのに、Windowsは見張っているのか」

「任せることと、目を離すことは違うだろ?」

さらに奥で、舞台転換の合図が鳴った。チリンチリン・・・

VidSchiCheckPreemptionPolicy。
VidSchiSubmitPreemptionCommand。
VidSchiNeedToForcePreemptNode。
ShouldPreemptTask。

プリエンプションは、実行中の仕事を必要に応じて切り替える。
高優先度の仕事を通すため、独占を防ぐため、タイムアウトへ近づいた仕事へ対処するために使われる。HAGSはこれを消さない。

目まぐるしく動く世界で、突然、警告灯が点滅した。

「目が痛ぇ・・・TDR・・?」

「Timeout Detection and Recovery。GPUが進んでいるかを監視し、停止と判断すれば回復を試みる奴さ」

VidSchiCheckHwSchNodeProgress、VidSchiCheckNodeTimeout、VidSchiCheckHwProgress。HAGS用ノードにも進捗確認とタイムアウト経路が存在する。

Kは、新旧経路が異なるなら、特定ドライバーの不具合を調べるON/OFF比較には意味があると考えた。

「診断仮説としては妥当だ。ただし、OFFで直った一件だけをHAGS一般の評価にしてはいけない」

Kは警告灯が消えるのを見届けた。

列は速ければよいのではない。順序を守り、独占を防ぎ、止まれば検出する。どれか一つを無くせば、速度以前に運行が成立しない。


存在しなかった性能ダイヤル

次の部屋でKは、大きなダイヤルを探した。あるはずだろそろそろ。

「何を探している?」

「HAGSの強度だ。省電力なら25%、バランスなら50%、高パフォーマンスなら100%。そういう段階があるはずだろ」

「見つかったか」

「ない」
馬鹿を見る目で見つめる案内人を直視できない。もちろん霧がかる顔なので想像の余地でしかないが。

HAGS有効判定には、電源プラン名、CPU最小状態、GPUクロック、バッテリー状態を見てHAGSを段階的に弱める分岐は確認されなかった。
Stable HAGSには有効候補と無効候補があるが、「弱いHAGS」「中くらいのHAGS」という倍率はない。

代わりに、別々の調整器が並んでいた。

QuantumUnit。
PreemptionQuantumUnit。
EnablePreemption。
HwQueuedRenderPacketGroupLimit。
QueuedPresentLimit。
MaximumAllowedPreemptionDelay。
BackgroundProcessMaximumAllowedPreemptionDelay。
ForegroundPriorityBoost。
VSyncIdleTimeout。
HwQueuePacketCap。
HwSchThreadOffloadMode。

こいつらはdxgmms2VidSchiReadGlobalConfigurationが読み取るスケジューラ内部設定名である。量子値については、優先度クラス別の乗数表へ掛けるコードも復元できた。

「やっぱり段階があるじゃないか」

「そりゃ最低限スケジューラの政策にはある。だが、それをHAGSの効果率と呼んではいけないよ愚か者。前景と背景、優先度、キュー深度、プリエンプション、表示同期は別々の問題だ。」バイアスが働いてると声にならないため息も聞こえたような気がした。

Kが探していたのは結局一つのダイヤルでしかなかった。実際にあったのは、多くのチャンネルを破綻しないよう調整するミキサーだったのだ。


眠るGPUと、目を覚ます列

部屋の照明が落ち、HW Queueの動きがゆっくりになった。

「省電力モードか。HAGSも止まった?」

「有効状態と、今この瞬間の電源状態を混同しているな馬鹿」

GPUにはエンジン単位のF状態や、デバイス単位のD状態がある。
公開されているWDDM 3.2 User-Mode Submission仕様では、エンジンがF1へ移る際、DxgkrnlはそのエンジンのDoorbellを切断し、F0へ戻す必要がある新しい投入時に再接続する。

D0からD3への電源遷移では、HW QueueをSuspendし、Doorbellを切断し、必要に応じてRing Buffer関連の割当てを退避する。新しい仕事が来ればD0へ戻し、必要なメモリを常駐化し、Doorbellとコンテキストを再開する。

VidSchSetNodePowerState、VidSchiSuspendResumeDevicesForPowerTransition、VidSchiWaitForEmptyHwQueueも、電源遷移時の処理・排出・停止・再開を示す。

Kは、省電力でクロックや復帰時間が変わればゲーム結果も変わり得ると考えた。

「その可能性はある。しかし、それは“HAGSが半分になった”のではないということ」

機能が有効か。今、装置が活動状態か。性能のボトルネックはどこか。三つは別の問いである。


フレームが画面へ届くまで

管制室の先に、巨大なスクリーンがあった。GPUが絵を描き終えても、画面へ表示されるまで旅は終わらない。

VidSchSetQueuedPresentLimitは、未完了Present数の上限を設定する。VidSchWaitForQueuedPresentLimitは、指定した表示ソースの未完了Presentが上限未満なら戻り、上限以上なら完了イベントを待つことができる。

「キューを深くすれば、GPUを遊ばせずFPSを上げられるな」

Kは、古い入力から作ったフレームが列に残れば、表示までの遅延が増えるのではないかと尋ねた。

「そうなり得る。スループットと遅延は同じ方向を向くとは限らないがな」

Kはまた、VidSchiSubmitIndependentFlipとVidSchiSubmitHwQueueMmIoFlipCommandを見つけた。
Independent Flip、DWM合成、VSync、VRR。表示方式によって旅程は変わる。

さらにHardware Flip Queueという別の設備があった。
複数の将来フレームを表示コントローラへキューできる。Microsoftの公開資料によれば、動画再生ではCPUとGPUの一部が複数VSync期間にわたって低電力状態へ入りやすくなる。Advanced Hardware Flip Queueでは、GPUの描画完了後にCPUへ戻ってからFlipを送る往復を避け、VSync直前に描画が終わったフレームが目標を逃す可能性を減らせる。

「これもHAGSか?」

「別機能だ。ただし正式リリースドライバーでBasic Hardware Flip Queueを有効にするには、現在のWindowsはGPU Hardware Schedulingを要求する。Advanced版にはBasic版とGPU hardware scheduling stage 2が必要だ」

同じ建物にあり、通路でつながっている。しかし同じ部屋ではないことが複雑さを加速させる。

2026-06-29、Windows公式のD3DKMTIsFeatureEnabledでこのRTX 5060を直接照会すると、HWSCHはVersion 1、Enabled、Known、SupportedByDriver、SupportedOnCurrentConfigがすべて真だった。Hardware Flip Queueも同じく有効だった。

「設定画面の青いスイッチだけでは見えなかった二つ目のオンだ」

注釈――
Hardware Flip Queueの要件と電力・表示上の目的はMicrosoft公開仕様に基づく。

出典: Microsoft: Hardware Flip Queue


ゲームという、同じ条件が二度とない実験場

Kはようやく、最初から聞きたかった質問を口にだした。

「結局、ゲームでは速くなるのか?」

案内役は答えず、二つのゲーム画面を見せた。

一方は低解像度で非常に高いFPSを狙い、CPUが短いGPU仕事を頻繁に投入している。もう一方は4K、重いレイトレーシングでGPU演算器がほぼ埋まっている。

Kは考えた・・・

Kの推論
「HAGSが高頻度スケジューリングの場所を変えるなら、CPU側の投入や切替コストが相対的に大きい前者では差が出る余地がある。後者ではシェーダーやRTの実行時間そのものが支配的だから、平均FPS差は小さいかもしれない」

案内役がうなずいた。

「構造から導く仮説としては妥当だな。ポンコツとも思えん想像性だ。ただし、まだ測定結果ではない。CPUボトルネックなら必ず向上する、GPUボトルネックなら必ず差がないとは言えない」

Kは、DX11、DX12、VulkanのいずれもWindows上でWDDMとドライバーへ仕事を渡す以上、HAGSの影響範囲に入り得ると整理した。ただしエンジンのコマンド生成、UMD、キュー、同期、Present方式が違えば結果も変わる。

VSync ONではPresent待ちとキュー深度、OFFではtearingを許す経路、VRRでは可変更新が関わる。ボーダーレスにはDWMやFlip Model、録画には3D・Copy・Video Encode、マルチモニターには複数表示ソース、VRには期限超過と再投影が加わる。

「条件が多すぎるだろ」

「だからオンで何%速いという一つの数字が真理にならないんだよ」

HAGSはシェーダーコンパイルのスタッターを直接直さず、VRAM容量も増やさず、熱・電力上限によるクロック低下も解決しない。
Kは、平均FPS以外のフレームタイム分布、Present間隔、表示遅延、バックグラウンドGPU負荷との競合なら変化する可能性があると考えた。
ただし、それも可能性の範囲である。

事実にするには、OS、ドライバー、ゲーム版、場面、画質、VSync・VRR・上限、電源条件を固定し、ONとOFFを交互に複数回測る。平均FPSだけでなく、1% Low、frame time、Present間隔、missed present、クロック、電力、温度、TDRも見る。

「測るまで、推論は俺の考えに留める」

「それ性能解析の作法だ。測定値のない自信は、数字の服を着ていない意見にすぎないしな」
どこから取り出したかわからない棒付きキャンディーを投げ渡された。


フレームを増やす者と、ベルを鳴らす者

スクリーンに、実際に描画されたフレームの間を埋める新しいフレームが現れた。

「DLSS Frame Generation?」

NVIDIA Streamline 2.12.0のDLSS-G統合仕様は、Windows 10 2004 build 19041以上に加え、Windows設定でHAGSが有効であることを必須条件としている。満たさなければDLSS-Gは利用不可になる。

「なら、HAGSがフレームを生成している?」

「違うな。DLSS-Gは深度、モーションベクトル、カラー、UI情報などを使う別処理だ。HAGSはその動作基盤の必要条件であって、生成アルゴリズムではない」

RTXはNVIDIA公式上、DLSS 4 Multi Frame Generation対応GPUである。
したがって、その機能を使う場面ではHAGS OFFを選べない。これはONの方が数%速いという比較ではなく、OFFでは機能要件を満たさないという互換性の差だ。

注釈―
DLSS-GのHAGS要件はNVIDIAの統合仕様に明記されている。

出典: NVIDIA Streamline: Programming Guide DLSS-G

そのとき、遠くでベルが鳴った。

Kは振り返った。

「Doorbell。これがHAGSの核心か」

案内役は、今度こそはっきり首を振った。

「ベルは鳴っている。だが、HAGSの玄関ではなかった」

Doorbellは、User-Mode SubmissionでUMDがRing Bufferへ新しい仕事を追加したことをGPUへ知らせる通知機構だ。PCIe BARやシステムメモリに置かれた領域へ書き込み、GPUスケジューラへ「列に新しい仕事がある」と知らせる。

通常のカーネルモード投入では、Dxgkrnl/KMDがHW Queueへの投入を管理する。UMSでは、対応するキューについてUMDがより直接的にRing Bufferを更新し、Doorbellを鳴らす。

「HAGS ONならDoorbellもONでは?」

「別のFeature IDだ」

UMSには、ContextScheduling、OSの許可、ノード単位のUserModeSubmissionSupported、Native GPU Fence、Doorbell DDI一式など追加条件がある。対象バイナリにはDoorbellサイズを1~0x4000 bytesに制限する検査や、UMS用HW Queueで条件に応じてNoKmdAccessを要求する経路も存在する。

そして、このPCの答えはすでに公式APIが返していた。
表示された画面を見つめる。

HWSCH Enabled=True
HWFLIPQUEUE Enabled=True
USER_MODE_SUBMISSION Enabled=False
SupportedByDriver=False
SupportedOnCurrentConfig=False

「つまり、俺のHAGSはON。Hardware Flip QueueもON。でもWindowsのUMS Doorbellは使われていない」

「そのとおり。Doorbellだけを一般ユーザーがONにするコマンドもない。UMDが対応キューを作り、D3DKMTCreateDoorbell、ConnectDoorbell、DestroyDoorbellでライフサイクルを管理する。ドライバーがUMS非対応なら、レジストリで能力を作り出すことはできない」

「NVIDIA内部に別のベルがある可能性は?」

未確定だ。NVIDIAのこのバイナリに対応する公開PDBはMicrosoft Symbol Serverで404だった。Windowsが公開するUMS Doorbellが無効であることは確認できる。NVIDIA内部の非公開通知機構まで存在しないとは断定できない、うちはハッカーじゃないんでね」

Kはようやくベルの正体を理解した。

Doorbellは到着を知らせる。HAGSは舞台転換を担い、Windowsは公演全体の優先順位を決める。

注釈7―UMSは発展中の別機能
MicrosoftはUser-Mode Work SubmissionをWindows 11 24H2 / WDDM 3.2でなお開発中の機能として説明している。ローカルコードにWDDM 3.1以上という下限検査はあるが、WDDM 3.1で一般利用可能だったことを意味しない。

出典: Microsoft: User-Mode Work Submission


同じ青、違う意味

気がつくと、Kは最初の設定画面の前に戻っていた。狐に化かされたか?

青いスイッチは、何も語らなかった。

表示は旅の前と同じだった。「ハードウェア アクセラレータによるGPUスケジューリング」――オン・・・

だが、Kにはもう、同じものには見えなかった。

このオンは、演算能力を増やすボタンでも、FPSを一定割合で上げる契約書でも、電源状態で効き目が変わる性能ダイヤルでもない。

ドライバーの支持状態がStableであること。HwSchModeの中間判定を通ること。OSの機能構成、GPU VA、ContextScheduling、アダプターとノードの能力が整うこと。そうした複数の門の先で成立する、新しいスケジューリング経路だ。

ONでもWindowsは優先順位を手放さず、メモリ管理、Fence、プリエンプション、TDRも残る。PresentとHardware Flip Queueには別の役割がある。DLSS-GはHAGSを必要とするが、HAGSがフレームを生成するわけではない。DoorbellはHAGSのスイッチではなく、このPCでは無効なUMSの通知機構だった。

「では、オンにしておくべきか?」

Kは自問自答、自分に投げかけ、口に出した。

「俺のPCではStable、実効ON。RTX 5060でDLSS Frame GenerationやMulti Frame Generationを使うならONが必要だ。問題がない通常運用では、そのままにする理由がある。ただし通常ゲームの性能差は、測っていない。特定のスタッターやTDRが再現するなら、条件を固定してOFFと比較する。それまでは“速いはず”も“遅いはず”も、俺の推論に留める・・・か」

見えない案内役が笑った気がする。幻聴幻聴

「青いスイッチから、ずいぶん遠くまで来たな」

Kは首を振った。

「いや。最初からここにいた。ただ、スイッチの下にある列が見えていなかっただけだ」

Queueは列、Fenceは柵、Context Switchは舞台転換、Doorbellは別の玄関のベルだった。HAGSは、GPUを魔法のように速くする呪文ではなかった。

仕事を速くする者ではなく、仕事を迷わせない者だった。

Kは青いスイッチから手を離す。

オンのままにした。

青いスイッチは、やはり何も語らなかった。



いいなと思ったら応援しよう!