PrismDesk
Android タブレットを Windows 11 のワイヤレスなサブモニタにする。HDR やペンの筆圧にも対応。

- 公式サイト (prismdesk.app)
2026 年 10 月 14 日公開。無料版あり。公開時のお知らせをメールで受け取れる
PrismDesk は、Android タブレットを Windows PC のワイヤレスなサブモニタにするツール。製品としての紹介は公式サイトの prismdesk.app にまとめてある。製品の説明をしても面白味がないので、このページは作った側の視点で中で何をしていて、なぜそうしたのかを書く。
PrismDesk — Android タブレットを Windows のワイヤレスなサブモニタに手元の Android タブレットを、Windows 11 のワイヤレスなサブモニタに。設定作業なし、切れても自動で復帰、HDR とペン入力に対応。性能は実測値で公開しています。無料版あり・アカウント不要。
全体の流れ
ホストは C++ (Win32 / D3D11)、クライアントは Kotlin (Android) で書いている。1 フレームが端末に届くまでの経路は以下のようになる。
仮想ディスプレイ (IddCx ドライバ)
→ Windows.Graphics.Capture でキャプチャ (D3D11 テクスチャのまま)
→ GPU で色変換 (NV12 / P010)
→ NVENC か Media Foundation で H.264 / H.265
→ UDP で送信 (AES-256-GCM) ───> MediaCodec でデコード → SurfaceView
← SendInput / ペン入力として注入 <─── タッチ・ペン (TLS 1.3)
← 仮想カメラ "PrismDesk Camera" <─── 端末カメラ (H.264)キャプチャからエンコードまで CPU を介さない。「毎フレームの経路に CPU↔GPU のコピーを増やさない」は不変条件として持っていて、GPU エンジンのカウンタとコードレビューの両方で確かめている。
本物のモニタを作る
画面の中に窓を 1 枚映すだけのアプリだと、ウィンドウをそこへ「置く」ことができない。PrismDesk は仮想ディスプレイドライバ (IddCx。上流は MttVDD で、そこからフォークした PrismDeskVdd)で Windows から見て解像度を持った増設モニタ を作り、その中身をキャプチャしている。
デバイスノードは SwDeviceCreate で作るが、このノードは 作ったプロセスが生きている間しか存在しない。なのでホストは起動のたびにノードを作り直していて、そこに管理者権限が要るので、ホストのアプリ自体が昇格を前提にしている。ドライバの導入・ファイアウォールの許可・ログオン時の自動起動は全部インストーラの仕事で、再起動したあとに利用者が触るものは何も無い。
止まった画面に 27 秒かかっていた
サブモニタは一日の大半、何も動いていない。そこで何も送らなければ帯域は限りなく 0 に近づく。実測で、静止画面は 8.9 kbps (0.24 fps) だった。
ところがこれには裏があって、静止画面から端末側のアプリを開き直すと、映像が戻るまで 27,427 ms かかっていた。エンコーダは「次に投入されたフレーム」に IDR を付ける。画面が止まっていると、その「次」がいつまでも来ない。以前は定期的に IDR を撒いていたので、偶然それが穴を埋めていた。
ここで定期 IDR を戻すと、アイドル帯域の不変条件 (10 kbps 以下) が壊れる。選んだ直し方は キーフレームを要求されてから 100 ms 新しいフレームが来なければ、直近のフレームを 1 枚だけ再投入する という手法。再配布は要求されたときだけなので、待機中の帯域は増えない。
| 直す前 | 直した後 | |
|---|---|---|
| アプリ再開 → 映像が戻るまで | 27,427 ms | 529〜1,260 ms (4 回) |
| 要求 → IDR が出るまで | — | 23 ms |
| 静止画面の帯域 | 8.9 kbps | 1 kbps |
HDR を最後まで HDR のまま運ぶ
HDR は「途中のどこかで SDR に落ちる」のが一番起きやすい壊れ方であり、落ちる場所はホスト側にもクライアント側にもあった。
ホスト側。 RGB→YUV の変換は GPU の VideoProcessor に任せているが、従来の D3D11_VIDEO_PROCESSOR_COLOR_SPACE には 伝達関数 (ガンマ) を指定する欄が無い。PQ も scRGB の線形も表せないので、DXGI_COLOR_SPACE_TYPE を取るVideoProcessorSetStreamColorSpace1 / VideoProcessorSetOutputColorSpace1 を使っている。
| キャプチャした形式 | 入力の色空間 | 出力の色空間 |
|---|---|---|
| scRGB FP16 | RGB_FULL_G10_NONE_P709 |
YCBCR_STUDIO_G2084_LEFT_P2020 |
| RGB10A2 (すでに PQ) | RGB_FULL_G2084_NONE_P2020 |
YCBCR_STUDIO_G2084_LEFT_P2020 |
| SDR BGRA8 | RGB_FULL_G22_NONE_P709 |
YCBCR_STUDIO_G22_LEFT_P709 |
「HDR かどうか」を bool 1 つで持っていると、PQ と scRGB を区別できない (どちらも true になる)。キャプチャしたフレームには色空間そのものを持たせている。
クライアント側。 Window.setColorMode(COLOR_MODE_HDR) は Compose の UI 層にしか効かず、映像には効かない。映像のレイヤに要るのは SurfaceView.setDesiredHdrHeadroom() (API 35 以降) であることが分かった。効いているかどうかは目で見ず、統計の HDR/SDR 比で確かめる。Pixel 9 で 7.999703。1.0 のままなら、どこかで SDR に落ちている。
fps はうたわない
キャプチャは Windows が画面を合成したときにだけフレームを受け取る。なので出せるフレームレートは主画面のリフレッシュレートの約数になる可能性がある。75 Hz の主画面なら 75 / 37.5 / 25 で、60 はこの並びに無い。
「60 fps」と書くことはできるが、それは開発機のモニタの話で、使う人のモニタの話ではない。公式サイトでもフレームレートの数字は出していない。
暗号化: UDP に DTLS を使わない
| 経路 | 中身 | 保護 |
|---|---|---|
| 制御 (TCP) | 能力交渉・セッション制御 | TLS 1.3 |
| 入力 (TCP) | タッチ・ペン・キーボード・マウス | TLS 1.3 |
| 映像・音声・カメラ (UDP) | 画面そのもの | AES-256-GCM |
| 探索 (UDP) | ホスト名・ポート・証明書の指紋 | 平文 |
映像の経路は 落ちたら落ちたままでよい という前提で組んである。DTLS はデータグラムごとにレコード層と再送・順序制御を持ち込むので、この前提とぶつかる。要るのは秘匿と改竄検知だけなので、鍵は TLS の制御チャネルで配り、データグラムには AEAD を 1 枚だけ被せている (SRTP と同じ考え方)。タブレット側は PC の証明書の指紋をピン留めする。後から測り直した範囲では、暗号化による帯域の増加は 2% ほどだった。
数字は製品の外から測る
サブモニタのアプリは、デモでは良く見えても毎日使うと粗が出る。だから性能の数字は形容詞にせず、アプリ自身が報告する値を使わずに 測っている。NIC のバイト数、GPU エンジンの使用率、タブレット側は SurfaceFlinger のフレーム時刻を使っている。
| 項目 | 実測 |
|---|---|
| 2944×1840 で動画を映したときの帯域 | 5.0 Mbps (同じ試験・同じ映像で spacedesk は 24.7 Mbps) |
| Wi-Fi を 2・5・10 秒切って戻した | 12/12 回、同じ仮想ディスプレイに自動で復帰 |
| 戻ってこない端末を片付けるまで | 20.5 秒 |
| 同時接続 (キャプチャとエンコーダは共有) | 4 台で確認 |
ホスト Core i7-11700 / RTX 3060 + UHD 750 / Windows 11 (build 26200) / 有線ギガビット
タブレット Lenovo Idea Tab Pro (Android 16) / 1840×2944 / Wi-Fi 6・RSSI −46 dBm / 同じ L2実機での受け入れ確認も、人の手から外しつつある。開発機ではホストを UAC 無しで昇格起動し、同じ利用者に閉じた制御パイプから GUI と同じコマンドを流して、端末側は debug ビルドだけにある口を adb から叩く。画面を目で読まずに 1 本の確認を通せるようにした(この機能はインストーラには入れていない)。
prismdesk.app も自分で作っている
公式サイトの prismdesk.app も、製品と同じリポジトリから出している。フレームワークは使っておらず、markdown 以外に依存の無い Python のスクリプト 1 本で静的な HTML を組み、Cloudflare Pages に置いている。日本語と英語の両方がある。
作るときに決めたことがいくつかある。
- 法務の文面はサイトに 1 文字も書かない。 利用規約やプライバシーポリシーは別のディレクトリにある文書を読んで HTML にするだけにして、情報源を 1 箇所にした
- 法務の文書が、存在しないページへのリンクを含んでいたらビルドを止める。 法務文書はアプリにも同梱する配布物で、出荷した後は URL を直せないため
- 送信先が埋まっていない登録フォームでは本番ビルドが通らない。
actionのないフォームは、押した人の登録を黙って失う。気づく手段が無い種類の失敗なので、ビルドで止めている - Pages は git 連携ではなく直接アップロードで出している。 git 連携は Cloudflare にリポジトリ全体の読み取り権を渡す。製品のソースや署名の手順が入ったリポジトリを、サイトのためだけに渡す理由は無い
トップには、アプリの設定画面にある「選んだ設定で端末にどう映るか」のプレビューを、ブラウザで動くようにしたデモを置いた。向きや解像度を変えて、PC 側のウィンドウを端末側へドラッグできる。「まだできないこと」の節 も、購入の判断に要る情報としてあえてページの中ほどに置いている。
公開リポジトリ
製品のソースは非公開だが、ドキュメント・Issue・Discussions・リリースは GitHub で公開している。不具合の報告や要望はこちらで受け付ける。
GitHub - Asynchronous-0x4C/prismdesk-app: Documentation, issue tracker and releases for PrismDesk - a wireless second monitor for Windows, using an Android tablet.Documentation, issue tracker and releases for PrismDesk - a wireless second monitor for Windows, using an Android tablet. - Asynchronous-0x4C/prismdesk-app無料版と Pro
| 無料版 | Pro (US$22・買い切り) | |
|---|---|---|
| 同時に接続できる端末 | 1 台 | 最大 4 台 |
| 表示 | SDR | HDR |
| ペン・タッチ入力 | ○ | ○ |
| 音声 | ○ | ○ |
| 端末のカメラを Web カメラにする | — | ○ |
Pro は 1 つのキーで自分の Windows PC 3 台まで使える。サブスクリプションもアカウントも無い。アカウント・テレメトリ・自動の更新確認も無く、ネットワークの外へ出るのは「有効化」と「更新を確認」を押したときだけになっている。
動作環境
- Windows 11 64 ビット (ビルド 22000 以降)、管理者権限。Windows 10 は試していないので対応とは書かない
- H.264 のハードウェアエンコードができる GPU (NVIDIA NVENC、または Intel / AMD の Media Foundation エンコーダ)
- Android 8.0 (API 26) 以降で、H.264 のハードウェアデコーダを積んだ端末
- PC と端末が同じ LAN にあること (有線でも Wi-Fi でもよい)