Per-Monitor DPI

  1. いつもお世話になっております。
    連休中にスミマセン。。。
    いくつかPer-Monitor DPIがらみの問題の報告です。

    OS: Win10
    メインモニタ:1920×1080 表示倍率150%
    サブモニタ:1600×1400 表示倍率100%

    1) Ver 2.6.7で修正いただいた「Per-Monitor DPI でモニタ間を移動時にコンボボックスの補完が動作することがある問題」が、いつの間にか(Ver2.6.12~VerVer2.6.14くらい?)復活しているようです。

    2) 保存しますか?等のメッセージボックスが、ぼやけて表示されるようになりました。

    3) Per-Monitor DPI がらみの問題かどうかはわかりませんが、以下の条件
     ・カスタムフォントを使用
     ・DirectWrite有効
     にて、Meryのウィンドウをモニタ間を移動させると、高頻度でキャレットの移動速度が遅くなってしまいます。矢印キーを押しっぱで、体感で1秒間に3行 or 3文字程度の移動速度です。
     上記条件のどちらかが不成立の場合は、現象が発生しないっぽいです。

     |  Dainty  |  返信
  2. ご報告ありがとうございます。

    > 1) Ver 2.6.7で修正いただいた「Per-Monitor DPI でモニタ間を移動時にコンボボックスの補完が動作することがある問題」が、いつの間にか(Ver2.6.12~VerVer2.6.14くらい?)復活しているようです。
    確認してみましたところ、現象を再現することができました。

    Per-Monitor DPI における Windows のコンボボックスの仕様ということで、以前は無理やり対策を施していたのですが、Ver 2.6.12 にて Windows 10 の PerMonitorV2 に対応したため、PerMonitorV2 では従来の対策だけでは効果がなくなってしまっているようです。

    現在のところ関連する情報が見つからないため、対応が可能かどうかわかりませんが、引き続き調査してみたいと思います。

    > 2) 保存しますか?等のメッセージボックスが、ぼやけて表示されるようになりました。
    これは Windows 10 の仕様ですが、従来の Per-Monitor DPI ではメッセージボックスは拡大・縮小されずそのまま表示されていました。

    PerMonitorV2 では、メッセージボックスがぼやけながらも拡大・縮小されるようになった模様ですので進化といえば進化ですが、こればっかりはマイクロソフトの対応を待つしかなさそうです。

    一応、アプリケーション側で MessageBox ではなく Vista 以降で使用できる新しいダイアログ (TaskDialog) の仕組みを採用することで綺麗な拡大・縮小に対応できるのですが、XP のサポートを終了することになりますので、ちょっとまだ決断できないところです。

    > 3) Per-Monitor DPI がらみの問題かどうかはわかりませんが、以下の条件
    >  ・カスタムフォントを使用
    >  ・DirectWrite有効
    >  にて、Meryのウィンドウをモニタ間を移動させると、高頻度でキャレットの移動速度が遅くなってしまいます。矢印キーを押しっぱで、体感で1秒間に3行 or 3文字程度の移動速度です。

    カスタムフォントを使用した DirectWrite はそもそも動作速度が遅いです。また、グラフィックカードの性能や種類、同時に起動している DirectWrite を使用するアプリなど、環境によっては極端に動作が遅くなるケースもございます。

    上記の条件で試してみましたところ、確かに、色分けの多いテキストなどではもっさりした動作になりますが、技術的にこれ以上の高速化は厳しいと思いますので、今後の課題とさせてください。

     |  Kuro  |  返信
  3. ご確認ありがとうございます。

    1), 2)については了解しました。

    3) について、念のため補足です。
    ・モニタ間を移動した時に、キャレットの移動速度が遅くなるときとならないときがある。
    ・同じファイルの同じ範囲を表示させている状態でも同上。
    ・カスタムフォント機能が搭載されてからカスタムフォント+DirectWrireで使用していますが、この現象が発生しはじめたのは、Ver2.6.12かVer2.7.0からかも?
    ・現象発生時、他のタブを一旦アクティブにすると復活する場合がある。

    Kuroさんの仰る「もっさり」とはちょっと違うような気がしたので補足してみました。

     |  Dainty  |  返信
  4. ご返信ありがとうございます。

    3) については、モニタ間を移動したことでフォントサイズが変更されるので、1 ページに描画する文字数が増えることで速度に影響が出るのかと思いましたが、同じ範囲を表示させていても遅くなるということは、別の問題かもしれないですね。

    フォントサイズの違いで速度に差がでることも考えられますが。

    私の環境では現象を再現できないようなので、よろしければもう少し詳細な環境を教えていただけますでしょうか。

    こちらでもできるだけ近い環境を用意して検証してみたいと思いますので、ちょっと項目が多いですが、わかる部分だけでも結構ですのでご協力いただけると助かります。

    ■お使いのパソコンのスペック
    CPU、メモリ。ノート PC の場合は型番でも良いです。

    ■お使いの OS とそのバージョン、ビット数
    検証したのは Windows 10 1809 64bit

    ■Mery のバージョンとビット数
    検証したのは Mery 2.7.4 64bit

    ■グラフィックボード
    検証したのは NVIDIA GeForce GTX 750 Ti

    ■カスタムフォントとして Mery の Fonts フォルダに入れているフォント (の数)
    フォント名の一覧までは必要ないですが、大量に導入されている場合は動作速度に影響があるかもしれません。

    ■Mery で設定しているフォント名
    ■Mery の DirectWrite の設定の [レンダリングモード]
    ■Mery の DirectWrite の設定の [カラーフォントを有効にする] のオン・オフ状態
    ■縦書きを使用しているかどうか

    ↑ この辺りは DirectWrite の動作速度に直接関係します。

    ■導入しているプラグイン
    ■導入しているマクロ
    ■現象が発生したときの [編集モード]

    ↑ それほど関係はありませんが、できればプラグイン、マクロを除いて、[編集モード] が [Text] で発生するかどうかご確認いただけると参考になります。

    ■ウイルスチェックソフト
    ■常駐しているアプリケーション

    ↑ 意外とこのあたりはあり得ます。MacType が導入されていたり、ウイルスチェックソフトで動作を制限されていたり。

    あとは、秀〇エディタさんの DirectWrite が遅くなるという記事がありまして、そちらでは OS の「フォールトトレラントヒープ」という機能が働くことで動作速度が低下するということが書かれていました。(が、詳細は長くなるので割愛)

    お手数をおかけしますが、よろしくお願いいたします。

     |  Kuro  |  返信
  5. せっかくのGWにお手数をおかけします。

    > 私の環境では現象を再現できないようなので、よろしければもう少し詳細な環境を教えていただけますでしょうか。

    実は会社のパソコンでして。。。
    わかる範囲で部分的にお答えしようかと思いましたが、いい加減な返答をしてKuroさんのGWを台無しにしてしまうとまずいので、GW明けに回答します。

    よいGWを!そして、よい令和を!

     |  Dainty  |  返信
  6. ご返信ありがとうございます。

    > せっかくのGWにお手数をおかけします。
    いいえー、こちらは雨なので特に楽しいこともなく…。Mery 関連で DirectWrite の研究をしながら過ごしております。

    > 実は会社のパソコンでして。。。
    > わかる範囲で部分的にお答えしようかと思いましたが、いい加減な返答をしてKuroさんのGWを台無しにしてしまうとまずいので、GW明けに回答します。
    そうでしたか、お手数をおかけして恐縮です。
    気がかりなのは、こちらでは動作検証できる環境が GeForce 系のグラボしかないので、もし Radeon だったらどうしようかと…。

    > よいGWを!そして、よい令和を!
    はい!よい令和を!
    平成最後の日に Mery を開発しています。

     |  Kuro  |  返信
  7. ご無沙汰しております。
    休み明けで仕事をする気にならないので、調べてみました。

    > ■パソコンのスペック
    Core i5 7300U / 8GB RAM / 256GB SSD

    > ■OS とそのバージョン、ビット数
    Windows 10 Pro / 1803 / 64bit

    > ■Mery のバージョンとビット数
    Mery 2.7.2 64bit

    > ■グラフィックボード
    Intel HD Graphics 620

    > ■カスタムフォントとして Mery の Fonts フォルダ
    Cica-Regular
    Ricty Diminished-Regular

    > ■Mery で設定しているフォント名
    Ricty Diminished-Regular

    > ■Mery の DirectWrite の設定の [レンダリングモード]
    Natural Symmetric

    > ■Mery の DirectWrite の設定の [カラーフォントを有効にする] のオン・オフ状態
    オン

    > ■縦書きを使用しているかどうか
    不使用

    > ■導入しているプラグイン
    クラスビュー

    > ■導入しているマクロ
    MeryWikiにあるkazyさん作のctagsジャンプマクロや、自作のマクロをいくつか使用していますが、イベント駆動のマクロはありません。

    > ■現象が発生したときの [編集モード]
    C#, C++

    > ↑ それほど関係はありませんが、できればプラグイン、マクロを除いて、[編集モード] が [Text] で発生するかどうかご確認いただけると参考になります。

    プラグイン無効でtextの場合は、発生しているような発生していないような微妙なところです。

    で、色々設定を弄ってみたのですが、自動マーカーを有効にすると現象が発生するようです。
    (大文字と小文字を区別のみチェック)

    お手数をおかけしますが、よろしくお願いいたします。

     |  Dainty  |  返信
  8. ご無沙汰しております、ご確認いただきありがとうございます。
    ハイスペックマシンですね。これじゃスペックのせいにできません… (w

    いただいた情報をもとに検証してみましたところ、自動マーカーがオンのときに何らかのタイミングで描画が非常に遅くなる場合があることが確認できました。

    調査してみましたところ、以下のことがわかりました。

    まず、1 つめ。
    ----
    カスタムフォントを使用していると、DirectWrite の描画速度は通常より遅いです。
    ----

    そして 2 つめ。
    ----
    自動マーカー機能がオンになっている場合、キャレットが移動するたびに画面に表示されている全行が再描画されてしまうため描画速度が遅いです。それにカスタムフォントの遅さが加わるのでさらに遅くなります。

    自動マーカーの [カーソル位置の単語を取得する] オプションがオンの場合は全行を再描画してマーカーを表示する必要がありますが、これがオフの場合でも全行の再描画が発動していました。

    この部分につきましては [カーソル位置の単語を取得する] オプションがオフの場合は、通常のキャレット移動のたびに全行を再描画する必要はないと思いますので若干速度改善の余地はありそうです。
    ----

    状況によっては非常に遅くなることがあるという現象についてですが、これは DirectWrite の仕様によるものなので内部までは知りようがありませんが、下記のような場合に発生することがあるようです。

    Windows では通常、 Windows Font Cache というサービスが動作しており、これはシステムキャッシュとユーザーごとのキャッシュを管理しています。

    アプリケーションが DirectWrite の API を呼び出すときに Font Cache サービスはユーザごとのキャッシュを読み込むのですが、この時に 0.5 秒間待機 (以下、この時間切れを "タイムアウト" と呼びます) しますが、タイムアウトした場合はキャッシュを使うのを諦めて、直接フォントを読みに行くため動作速度が遅くなるそうです。

    [KB2505438 より]
    https://support.microsoft.com/ja-jp/help/2505438/slow-performance-in-applications-that-use-the-directwrite-api-on-a-com

    ここからは推測ですが…

    通常、DirectWrite でテキストを描画するにあたって、フォントを読み込む際、最初にフォントの一覧 (フォントコレクション) を使って書式の情報を作成しますが、普通はここでシステムフォントコレクションを使用するので短時間で済みます。

    カスタムフォントを使用した場合、ここの処理でカスタムフォントコレクションを使用するため、処理に時間がかかり 0.5 秒のタイムアウト時間を超えてしまい、キャッシュが使用されない状態になっているように思います。

    バックグラウンドで動作しているプロセスの影響も受けますので、CPU の負荷状況によってタイムアウトが発生している可能性もあります。

    アプリケーション側からこのタイムアウト時間を制御する方法や、Font Cache サービスを制御する方法などはないようです。

    そういうわけでアプリケーション側でできる対応としては…。

    (1) Font Cache サービスに頼らず、自前でキャッシュする仕組みを設ける

    正確なことはわかりませんが Chrome ではそんなことしているような情報が…
    https://www.chromium.org/developers/design-documents/directwrite-font-cache

    (2) フォントキャッシュが使われない場合でも高速に動作するように、そもそも根本的な動作速度を改善する

    現在の Mery は GDI (DirectWrite オフ) が標準となっており、GDI と DirectWrite を共存 (適宜、切り替えて描画) させていますが、この GDI ←→ DirectWrite の切り替えが動作速度のボトルネックになっています。

    根本的な動作速度を改善する場合、GDI を捨てて完全に DirectWrite に移行することで大幅な速度の改善が見込めます。

    が、XP ~ 10 まで対応、国産の昔ながらの機能を継承したテキストエディタという性質上、ビットマップフォントを切り捨てることもできず、DirectWrite だとバグのあるフォントもあったりして、完全に DirectWrite に移行するのは現状では困難です。

    技術的に興味深いのは (1) の作戦ですが、世界の Google 先生の技術を私が再現できる自信はありません…。

    GDI と DirectWrite のプログラムを完全に分離して、DirectWrite 専用で動作する仕組みを構築できれば高速化できるはずなので、やるとしたら (2) の方法になると思いますが、描画ロジックの全体的な作り直しとなりますので対応には非常に時間がかかります。

    ご不便をおかけして申し訳ございませんが、将来的に改善したい事項ということで課題とさせていただければと思います。

     |  Kuro  |  返信
  9. 丁寧な解説、ありがとうございます。

    レアケース(?)の検証に時間を割いていただき申し訳ないです。

    いつの日かKuroさんが(1)の方法を実装してくれるのを楽しみにしておきますヾ(・д・`;)

     |  Dainty  |  返信
  10. 2.7.5 の記事にコメントした 2.7.4 に比べてカーソルの動き(エディタの描画)が著しく鈍くなるケースの報告の詳細です。

    ■ 検証環境

    OS: Windows 10 1809 64bit (OSビルド 17763.529)

    CPU: Intel Core i5-6200U

    メモリ: 8GB

    グラフィック: Intel HD Graphics 520

    モニタ: 1600 × 900 表示倍率100% のみ

    カスタムフォントは使用していません。

    64 ビット版 Mery 2.6.7、2.7.4、2.7.5 で検証して症状が出たのは 2.7.5 だけでした。

    いずれのバージョンも設定を退避して起動、初期状態からオプションで
    DirectWriteを有効にする
    タブ表示
    半角空白表示
    全角空白表示
    にチェックを入れただけで検証しました。

    ■ 検証手順

    %APPDATA%\Mery を移動または削除。

    Mery を起動しオプションを開き、DirectWriteを有効にする・タブ表示・半角空白表示・全角空白表示にチェックを入れ閉じる。

    ウィンドウを最大化する。(当環境ではこれで40行くらいです)

    Mery に同梱されてる en_US.aff を開く。(en_US.dic だと空白やタブがないためか症状が出ません)

    メニューバーの「ウィンドウ」から「左右に分割」を選択。

    左側のエディタで方向キーの下を押しっぱなしにする。

    ■ 検証結果

    2.6.7 と 2.7.4 ではスムーズにカーソルが移動します。

    2.7.5 だとカーソル移動がカクつき、一画面に表示されてる40行を超えたくらいから描画が止まり、数十行から数百行ごとに描画されるようになります。
    その間、スクロールバーはスムーズに動いています。

    ■ 備考

    検証時のメモリ使用率は 30% 程度です。

    2.7.5 でも右側のエディタだとスムーズに描画されます。

    2.7.5 で方向キーの下を押しっぱなしにしてる時、CPU 使用率は左側・右側ともに 30% 程度でしたが、GPU 使用率は症状の出る左側が 10% 程度、症状の出ない右側が 20% 程度と違いが出ました。

     |  ucky  |  返信
  11. ご連絡ありがとうございます。
    頂いた情報をもとに調査してみたいと思います。

     |  Kuro  |  返信
  12. 頂いた情報をもとに検証してみましたところ現象を再現することができました。

    本トピックで触れている "DirectWrite のキャッシュが効かなくなる現象" が影響しているのかと思いましたがそうでもないようで、これも本トピックで少し触れていますが "全行の再描画が発生していること" のほうが原因でした。

    全行の再描画は非常に遅いので、なるべく抑えたつもりだったのですが、ウィンドウ分割時はキャレット移動のたびにメインエディタもサブエディタも全行が再描画されていました。

    これは、メモリを節約するために 1 枚の裏画面をメインエディタとサブエディタで共有しているので、キャレットが移動するたびにメインエディタを全行再描画、サブエディタを全行再描画というエディタエンジンの仕様のためですが、DirectWrite オンだと無理しすぎですね。

    2.7.4 でも仕様は同じだったのですが、2.7.4 はキャレット移動のたびに強制的に画面が再描画されていたので、遅いながらもスクロールが見えていました。

    2.7.5 でなるべく画面の再描画を抑えることでスクロールの高速化を図ったことが災いして、全行を再描画してるけど再描画のタイミングを抑えすぎて見えていない状態となっているようです。

    ともあれ、全行の再描画が根本的な原因なので、ウィンドウ分割時に全行を再描画させないことと、メモリ使用量は増えてしまいますがウィンドウ分割時に 1 枚の裏画面を共有しない設計に変更することで大幅に速度を改善できそうです。

     |  Kuro  |  返信
  13. コンボボックスの補完が動作しちゃう件、Ver2.7.5で改修されていることを確認しました。

    キャレットの移動速度が遅くなっちゃう件も、十分許せる速度になりました。

    ご対応いただきありがとうございました。

     |  Dainty  |  返信
  14. 調査・検証お疲れ様です。

    現象が再現し原因が判明したとのことで、よかったです。
    改善作業、大変かと思いますがよろしくお願いします。

     |  ucky  |  返信
  15. >> Dainty さん
    動作確認のご協力ありがとうございます。

    コンボボックスの件、直っていて良かったです。私の環境だけでは直ってるかどうか不安だったので安心しました。

    キャレットが遅くなる件は根本的な解決には至っていませんので申し訳ない限りです。

    一応、自動マーカーで [カーソル位置の単語を取得する] がオフの場合は全行の再描画を抑えましたので若干改善されていると思いますが、[カーソル位置の単語を取得する] が必要な場合はほぼ従来と同じ速度だと思います。

    しかし、モニタ間移動時になぜか遅くなる現象は再現性が 100% ではないので、もっと別の原因があるのかもしれません。

    >> ucky さん
    ご返信ありがとうございます。
    改善はちょっと久しぶりの大改造が発生しそうなのでドキドキです。

    DirectWrite は本当、再現が難しくて。詳細な再現手順を頂けたので助かりました。ありがとうございました。

     |  Kuro  |  返信
スポンサーリンク