世界を動かす技術を、日本語で。

古代X11スケーリング技術

概要

  • X11 での DPIスケーリングマルチモニター対応 の不可能説への挑戦
  • OpenGL を用いた ピクセル単位のスケーリング制御 の実験
  • 複数ディスプレイ 間での物理サイズ維持の実証
  • Xサーバ から取得した情報を用いた 動的サイズ調整
  • 結論: 「できない」と言われても実際には可能 であるという実体験

X11のDPIスケーリングとマルチモニター対応の実態

  • 世間ではX11はDPIスケーリングや複数モニター対応ができない という意見が多い
  • 実際に検証するために、複数の異なるサイズ・解像度のディスプレイを用意
  • xrandrコマンド で各ディスプレイの物理サイズと解像度を取得
    • eDP (ラップトップ)、DisplayPort-0 (モニター)、DisplayPort-1 (TV)の構成
  • OpenGLとGLX でウィンドウとシェーダーを用意し、 常に2インチの円 を描画することを目標
  • シェーダー内のradius変数 が円の半径(ピクセル数)を制御

実装アプローチ

  • XサーバのConfigureNotifyイベント でウィンドウ位置やサイズの変化を検知
  • 各モニターの物理幅(mm)と仮想幅(ピクセル) をXRRScreenResourcesから取得
    • XRROutputInfo で物理幅を、 XRRCrtcInfo でピクセル幅・位置を取得
  • ピクセル幅/物理幅からDPIを計算し、目的の物理サイズに合わせてradiusを調整
  • モニター間でウィンドウを移動すると、常に同じ物理サイズの円が描画される ことを確認

実験結果と考察

  • 各ディスプレイで2インチの円が表示されることを実証
    • TVでは4K解像度にも関わらず、物理サイズは維持
  • 計測誤差(TVの実測サイズとスペック表記の違い) による微小なズレも経験
  • プログラムはリモートのルーターで実行しても問題なく動作
  • X11+OpenGL+MIT-MAGIC-COOKIE-1でのリモート描画の有効性 も確認

「できない」と言われる理由と反論

  • 「X11ではDPIスケーリングやマルチモニターはできない」という通説 は必ずしも正しくない
  • 必要な情報はXサーバから取得可能 で、プログラム側で適切に処理すれば実現可能
  • 「できない」と言われても、自分で試してみることの重要性
  • 実際に動作する例を示すことで、誤解を払拭

応用例とまとめ

  • Shape Extensionを使ったオンスクリーン定規 も作成
  • 端末の行高さ(1/8インチ)も正確に測定可能
  • 「できない」と言われていることも、実際には技術的に可能
  • 実験と検証による知見の重要性

Hackerたちの意見

この投稿大好き!前の同僚のGを思い出すな。彼はまさにこの態度で、やりたいことをほとんど成果に結びつけてたんだよね。

実際、これはちょっと悪質で無知な投稿だね。もしくは、無知な人たちの主張を否定するための間違い(知っててやったのかどうかは不明)かもしれない。空間をしっかり理解してる人は、X11で物理ディスプレイサイズを取得して、それをレンダリングするピクセル数にマッピングするのが不可能だなんて言わないよ。これは数十年前から可能だったし、完全に簡単ではないけど、良いUIスケーリングをする上での難しい部分ではない。良いUIスケーリングには、動的なスケーリング変更のためのインフラ、同じシーン内でのディスプレイごとの異なるスケールファクター、どんなスケールファクターでもシャープなラインを保証するための仕組みが必要なんだ。これらの問題は、X11でも追加の努力で解決できたはずで、一部は部分的な解決策として実現されてた。コミュニティは、Waylandスタックにエネルギーを注ぐことを選んだんだよ。

今日はWaylandでのスケーリングよりもずっと良さそうだね。ターゲット解像度で直接レンダリングするから、OSXが広めた「2倍スケールで描いてから縮小」っていうやり方をしなくて済むし。あの方法だと、パフォーマンスが落ちるし、出力がぼやけちゃうからね。コンポジタがカバーすべき特別なケースは、クライアントが2つの出力にまたがっているときだけ。それでも、高いサイズでレンダリングして、1つの出力では完璧な出力が得られるし、もう1つではぼやけるという同じ欠点があるから、やっぱりこっちの方がいいよね。Waylandが最初からこうしなかったのは不思議だな。クライアントにほとんどのことを任せる哲学なのに。任意のスケーリングをするためには、アプリに「M×Nピクセルのバッファにレンダリングしてて、合成される出力のスケーリングファクターはX.Yだよ」って伝えるだけでいいんだよね。その後は、クライアントが実際の座標でイベントを処理して、特定のコンテキストに最適な方法でスケールできる。ブラウザやPDFビューア、画像処理アプリなんかで、任意の解像度でレンダリングできないのは、品質とパフォーマンスを求めるときにすごくイライラするよね。Waylandでもやっとそれが実現できるといいな。

ツールキット(Motif、Tk、Gtk、Qtなど)は fractional scaling に対応できなかったから、Waylandが簡単な道を選んでたら、すべてのアプリが壊れちゃうところだったよ。

"2倍スケールで描いてから縮小"っていうやり方を広めたのはOSXだよね。元々OS Xは、2倍スケールで描いてから縮小することなく描画するのがデフォルトだったんだ。ハードウェアが2倍スケールに必要なピクセル数を持つように設計されてたからね。例えば、2012年の初代Retina MacBook Proは、前の非Retina MacBook Proの幅と高さがどちらも2倍だった。結局、ハードウェアのコストが高くなりすぎて、これが難しくなったんだと思う。例えば、27インチの5K LCDパネルと27インチの4KパネルのSKUはどれだけ違うのか?でもAppleが整数スケーリングファクターを採用して縮小することを決める前に、もっと伝統的なアプローチを試してたんだ。TigerやLeopardなどの初期のOS Xリリースでそれが見られるよ。問題は、Apple自身が自社アプリに実装するのにかなりの労力がかかって、サードパーティアプリの採用が低くなるのを知ってたことだね。このLeopardのHiDPIレンダリングの例を見てみて:https://cdn.arstechnica.net/wp-content/uploads/archive/revie... これはAppleのTextEditアプリで、バグがあったんだ。スケーリングファクターを非整数に変更するためのいいUIもあったよ:https://superuser.com/a/13675

OS Xのグラフィックスって、ずっとDisplay Postscript/PDF技術に基づいてるんじゃなかったっけ?なんで2倍でレンダリングしてダウンサンプリングしなきゃいけないの?ベクターベースのプリミティブをネイティブ解像度でそのままレンダリングすればいいのに。

OSXで流行った「2倍スケールで描いてから縮小する」ダンスをやってるけど、Linuxはそれをやってない。 > Waylandが最初からこうしなかったのは変だね。最初は整数スケールファクター用にやってたし、後からは分数スケールファクターにも対応したけど、一部のWaylandベースの環境は早くからそれを実装してたよ。

Waylandは2022年からX11スタイルの分数スケーリングをサポートしてるよ: https://wayland.app/protocols/fractional-scale-v1 。QtとGTKの両方がWaylandでの分数スケーリングをサポートしてる。

最初の画像が十分大きければ、ダウンスケーリングによるぼやけはそれほど悪くないよ。例えば、1.3ピクセル対10.1ピクセルみたいな感じ。

Windowsはずっとこれを試してたけど、実際にちゃんと動くアプリはなかったよ。Excelがデバイスに依存しないピクセルでまともに表示できるようにするのに、何年もかけたけど、やっぱり人は生のピクセルで考えちゃうのが難しいんだよね。

だから、ぼやけたスーパーレゾリューションに基づくダウンサンプリングのミームがどこから来たのか理解できない。もしそうなら、スーパーレゾリューションアンチエイリアシング[1]は何なの?ダウンサンプリングされた解像度よりも高い解像度でレンダリングされた画像は、通常、ダウンサンプリングされた解像度でレンダリングされた画像よりもシャープだよ。これは、高周波成分をよりよく保持するから。ダウンサンプリングに基づく他のアンチエイリアシング技術もいくつかあって、すべて信号対雑音比を向上させる。これってUIにも効くんじゃないの?ほとんどがベクターグラフィックスだし。ビットマップアイコンは更新が必要だけど、他のUI(テキスト)はシャープであるべきだよね。1ピクセルの線(完全に水平または垂直)について言及する人がいるのは知ってる。その後、1.25倍とかに掛け算して、「ああ、見て、0.25ピクセルは嘘だ、だから分数スケーリングはフェイクだ」って言う(スウェイのドキュメントは今でもこれを言及してる)。これは、非常にニッチなメンタルエクササイズ以外では実際には成立しないように思える。十分に高い解像度では、私たちが話しているディスプレイのケースでは、1ピクセルの線が本当に欲しいの?ほとんど見えないよ。今、Linuxでこの問題に直面してる。さらに、線がドラッグ可能な場合、クリックゾーンも小さくなりすぎる。物理的な寸法を持つ何かが欲しいだろうし、それはおそらく複数のピクセルを必要とするだろう。その時点で、見えないアンチエイリアスが必要になるだろう。さらに、1ピクセルの線は、プログラムが指定した色である必要はない。私の画面上の完全に水平で垂直な線のほとんどは灰色がかってる。AAのアーティファクトがあれば、色が少し変わるけど、実質的な影響はないと思う。そうだとしたら、スーパーレゾリューションはかなりうまく機能するはずだ。じゃあ、本当に欲しいのは次のようなものだね:1. ほとんどの「デスクトップ」アプリケーションに対するスーパーレゾリューションスケーリング。2. 一部のフルスクリーンアプリケーション(ゲーム、動画再生)にはネイティブ解像度を与え、動画再生のようなアプリには画面上の矩形のネイティブ解像度を与える。これにより、これらのアプリケーションで情報損失を引き起こす可能性のある高解像度でレンダリングしてからダウンサンプリングするのを避けられる。3. これをセッション単位ではなく、アプリケーション単位で行う。LinuxのDEはこれを実装していない。KDEはセッション単位を実装しているけど、柔軟性が足りない。起動時に各アプリケーションごとに設定する必要がある。 [1]: https://en.wikipedia.org/wiki/Supersampling

Linuxを使ってるけど、コンポジタのコードを書いたり、仕組みを詳しく知らない自分からすると、WaylandはX11よりも fractional scaling(小数スケーリング)に対応してるのが全然良いね。少なくとも、X11で1.5倍のスケールを設定するのは全くできなかった。いつもアドバイスは「使ってるアプリごとにフォントサイズを大きくすればいい」だったし。Waylandで fractional scalingを使うと、XWaylandのアプリはいつもすごくぼやけて見えるけど、Waylandネイティブのアプリはめっちゃ綺麗に見えるよ。

Hacker Newsで議論の続きを見る