トップページ > 記事閲覧
Windows ディスプレイ拡大率について
名前:tripper 日時: 2022/10/12 00:42

いつも大変お世話になっております。 アプリ内で各種ディスプレイ関連の設定を一通りできるようにしようと考え GetDisplayInfo(), SetGraphMode(), SetWindowPosition() などを用いて実装したのですが、 Windows のコントロールパネル(設定>システム>ディスプレイ>拡大縮小とレイアウト>テキスト、アプリ、その他の項目のサイズを変更する)から拡大率を変更すると思うように動かなくなってしまいます。 以下、調査に使用したプログラムになります。 ttps://trippin.info/files/dxlib-reports/221010/dxlib-test-221010.cpp ※読みづらくてすみません 当方デュアルディスプレイ環境で、両方とも 1920x1080 までの解像度に対応しているという環境です。両方のモニタで拡大率が 100% の場合は上記のプログラムは期待した通りの動作になります。 が、プライマリモニタの拡大率を 125% にすると、GetWindowSize() や GetDisplayInfo() などで得られる値が以下のように変化します。 - SetGraphMode() でウィンドウサイズを変更した際に 1.25 が乗算されたサイズに変更される(例: SetGraphMode(960, 540) とするとウィンドウサイズが 1200x675 になる) - 拡大しなかった方も含め、ディスプレイのサイズがその拡大率分だけ大きくなっている扱いになる(もう片方のモニタが 1920x1080 の解像度の場合 2400x1350 として扱われる) - 結果として、GetDisplayInfo() から得られた情報をもとに SetGraphMode() を用いて画面サイズをディスプレイに合わせようとするとウィンドウがディスプレイからはみ出てしまう また、以下のような現象も確認できました。 - プライマリモニタの拡大率を変更した状態で SetFullScreenResolutionMode(DX_FSRESOLUTIONMODE_NATIVE) と ChangeWindowMode(FALSE) を実行すると画面右下に隙間ができる - 拡大率が変更されている状態で SetGraphMode() を呼び出すと稀にウィンドウサイズの変更に失敗する(上記のプログラムでは [3]キー→[2]キーと入力すると発生しました) 当方ではこの問題は GetWindowSizeExtendRate() で拡大率を取得できることを利用して解決しコンフィグを実装できたのですが、現状はあまり直感的な挙動ではないように思っております。 どのように対応していただくのが適切なのか私の方でもまだハッキリしていないのが現状ですが、例えば以下のいずれかのように対応して頂けると直感的で取り扱いがしやすくなるのではないかと考えております。 - 拡大率が100%より大きくなっているディスプレイがある場合、そのディスプレイに関しては解像度が下げられているものとして扱い、各関数の引数や返り値などが 自動で調整されるモードを用意し、関数呼び出しで変更できるようにする - 各種ディスプレイ等の関数について、拡大率の影響を受けない値を引数に取る/値を返すバージョンの別関数を用意する 本現象や過去ログ等について、調査不足などがありましたら大変失礼いたします。 何卒よろしくお願いいたします。
メンテ

Page: 1 |

Re: Windows ディスプレイ拡大率について ( No.1 )
名前:管理人 日時:2022/10/13 09:38

すみません、DXライブラリではディスプレイモニタの拡大率の設定に合わせて内部でウィンドウの 拡大率を変更しています( 内部で SetWindowSizeExtendRate を呼んでいます )ので、GetWindowSize や GetDisplayInfo を使用して自前で画面の解像度に合わせたウィンドウサイズの管理をされる場合は DxLib_Init の呼び出し前に SetWindowSizeExtendRate( 1.0 ); ↑を実行して、ディスプレイモニタの拡大率に関わらず SetGraphMode で指定したサイズ通りの ウィンドウが表示されるようにしていただければと思います m(_ _;m > - プライマリモニタの拡大率を変更した状態で SetFullScreenResolutionMode(DX_FSRESOLUTIONMODE_NATIVE) と ChangeWindowMode(FALSE) を実行すると画面右下に隙間ができる 私の環境では隙間ができるという現象は発生しませんでしたが、代わりに Visual Studio からデバッグ実行した場合に限り 画面モードが変更された直後に元の画面モードに戻ってしまい、DXライブラリの画面表示がされないという現象が発生しました ( 作成された exe ファイルを直接実行した場合や、SetGraphMode で指定した解像度がデスクトップ画面と同じ場合はこの現象は発生せず ) プログラムの問題というよりOS( 若しくは使用している NVidia のドライバ )の問題という印象なので、 純粋なフルスクリーンモードは現在ではあまり使用しないほうが良いのかもしれません… > - 拡大率が変更されている状態で SetGraphMode() を呼び出すと稀にウィンドウサイズの変更に失敗する(上記のプログラムでは [3]キー→[2]キーと入力すると発生しました) アップしていただいたテストプログラムを手元の環境で実行し、100回ほど [3]キー→[2]キー→[3]キーを繰り返し入力してみましたが こちらの現象は発生しませんでした ただ、最新版の Ver3.23f の後にも画面モード切り替え系の処理に変更を加えていますので、もしかしたら 手元の最新版だから正常に動作しているのかもしれません よろしければこちらの暫定最新バージョンでも同様の問題が発生してしまうかをお試しください m(_ _;m https://dxlib.xsrv.jp/temp/DxLibVCTest.zip // Windows版 VisualC++ 用 https://dxlib.xsrv.jp/temp/DxLibBCCTest.zip // Windows版 BorlandC++ 用 https://dxlib.xsrv.jp/temp/DxLibBCC2Test.zip // Windows版 C++ Builder 10.3 用 https://dxlib.xsrv.jp/temp/DxLibGCC_MinGWTest.zip // Windows版 MinGW 用 https://dxlib.xsrv.jp/temp/DxLibDotNet.zip // Windows版 .NET用 https://dxlib.xsrv.jp/temp/DxLibMakeTest.zip // ソース (中身を既存のライブラリのファイルに上書きして『リビルド』をして下さい) ( 因みに暫定最新版では DxLib_Init 呼び出し後でも SetFullScreenResolutionMode 呼び出しが可能になっています ) > - 拡大率が100%より大きくなっているディスプレイがある場合、そのディスプレイに関しては解像度が下げられているものとして扱い、各関数の引数や返り値などが > 自動で調整されるモードを用意し、関数呼び出しで変更できるようにする > - 各種ディスプレイ等の関数について、拡大率の影響を受けない値を引数に取る/値を返すバージョンの別関数を用意する DxLib_Init の呼び出し前に SetWindowSizeExtendRate( 1.0 ); を実行することでディスプレイの拡大率の影響は 無効化できますので、拡大率に関わる関数の追加はしなくても良いかなと思っています
メンテ
Re: Windows ディスプレイ拡大率について ( No.2 )
名前:tripper (解決) 日時:2022/10/13 22:09

> SetWindowSizeExtendRate( 1.0 ); DxLib の関数のテスト・調査不足でした、大変失礼いたしました…。 こちらを利用することでほぼ理想通りの動きになることを確認できました。ありがとうございます。 仰る通り拡大率関連の関数追加や仕様変更などは不要かと思います。 > 純粋なフルスクリーンモードは現在ではあまり使用しないほうが良いのかもしれません 当初私も(コンフィグ実装がややこしくなるためという理由もあって)サポートしないというのもありかと考えていたのですが、 144Hz などの高いリフレッシュレートのディスプレイを使用して 60fps の固定フレームレートで動くゲームをプレイしようとする場合、 ソフトウェア側で擬似的にウェイトを入れて 60fps に合わせようとするよりも、ディスプレイの解像度/リフレッシュレートの設定を 直接ゲームに合わせる形で変更したほうがより自然な表示結果を得られるというケースがあったためサポートすることにしています。 (いまどきのゲーム開発なら可変リフレッシュレートに対応できるようにゲームを設計していくべきというのはそうなのですが…) ただ、環境によってはフルスクリーンにすることで問題が発生することがあるというのも事実かと思いますので、 他の選択肢をサポートしつつ注釈などを入れておきプレイヤーに選ばせるのが良いのかなと考えています。 参考程度にお伺いしたいのですが、フルスクリーン化せずにソフトウェアを終了するまでの間だけ 特定のディスプレイのリフレッシュレートのみを変更する手段などは何かあるでしょうか…? > よろしければこちらの暫定最新バージョンでも同様の問題が発生してしまうかをお試しください m(_ _;m 残念ながら問題が再現してしまいました… こちらに関しては環境依存の問題と考えておりますので細かく調査・解決しておく必要はないかと思っております。 より詳しい再現条件などがはっきりしましたらまた報告させていただきます。 本件に関してはこちらでほぼ解決状態ですので、名前欄にはいったん(解決)をつけさせていただきます。
メンテ
Re: Windows ディスプレイ拡大率について ( No.3 )
名前:管理人(解決) 日時:2022/10/15 00:59

> こちらを利用することでほぼ理想通りの動きになることを確認できました。ありがとうございます。 > 仰る通り拡大率関連の関数追加や仕様変更などは不要かと思います。 了解です > 参考程度にお伺いしたいのですが、フルスクリーン化せずにソフトウェアを終了するまでの間だけ > 特定のディスプレイのリフレッシュレートのみを変更する手段などは何かあるでしょうか…? DXライブラリにはソフトウェアレンダリングモードがあり、ソフトウェアレンダリングモードでは DirectX を使用しないので、フルスクリーンモードを実現するために Windows標準の解像度変更機能を 使用しているのですが、それがこちらの API になります <ChangeDisplaySettings> https://learn.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-changedisplaysettingsa 例えば 640x480 60Hz の画面に変更する場合は以下のように記述します DEVMODEA DevMode ; memset( &DevMode, 0, sizeof( DevMode ) ) ; DevMode.dmSize = sizeof( DevMode ) ; DevMode.dmPelsWidth = 640 ; DevMode.dmPelsHeight = 480 ; DevMode.dmBitsPerPel = 32 ; DevMode.dmDisplayFrequency = 60 ; DevMode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY ; ChangeDisplaySettingsA( &DevMode, CDS_FULLSCREEN ) ; 上記では解像度とカラービット深度も指定していますが、以下のようにリフレッシュレートのみを変更する 指定をすればリフレッシュレートのみ変更できます DEVMODEA DevMode ; memset( &DevMode, 0, sizeof( DevMode ) ) ; DevMode.dmSize = sizeof( DevMode ) ; DevMode.dmDisplayFrequency = 120 ; DevMode.dmFields = DM_DISPLAYFREQUENCY ; ChangeDisplaySettingsA( &DevMode, CDS_FULLSCREEN ) ; > 残念ながら問題が再現してしまいました… お試しいただきありがとうございます、駄目でしたか… orz > こちらに関しては環境依存の問題と考えておりますので細かく調査・解決しておく必要はないかと思っております。 > より詳しい再現条件などがはっきりしましたらまた報告させていただきます。 すみません、よろしくお願いいたします
メンテ

Page: 1 |

題名
名前
コメント
パスワード (記事メンテ時に使用)

   クッキー保存