トップページ > 記事閲覧
CPUで扱える形式を介して画像を読み込んだ際のメモリ使用量に関して
名前:Ingaan 日時: 2026/08/27 18:17

実行時に画像を乗算済みアルファにするのに加えて、他にも色々画素操作を行えるようにしたいと考えています。 そこで、乗算済みアルファにする方法として今までSetUsePremulAlphaConvertLoad()を用いていた処理を、 一旦CPUで扱える形式で読み込んでからGPUに転送するよう変えることにしました。 ところが、 (1)読み込みフラグを利用して SetUsePremulAlphaConvertLoad(TRUE); LoadGraph() とした場合と、 (2)ソフトウェアイメージを使って、 LoadARGB8ColorSoftImage() ConvertPremulAlphaSoftImage() CreateGraphFromSoftImage() DeleteSoftImage(); とした場合とでは、後者の方がメモリ使用量が多くなってしまいます。 後者のやり方でも前者と同程度のメモリ使用量に抑えるにはどうしたらよいのでしょうか? [大きさ4096x4096のPNGを4枚読み込んだ際のメモリ使用量] imgur.com/a/PO0MNvN 挙動として、 (3)BASEIMAGEを使った場合でも、ソフトウェアイメージを使った場合と同程度の消費量でした。 CreateBaseImageToFile() ConvertPremulAlphaBaseImage() CreateGraphFromGraphImage() ReleaseBaseImage() また、何度か再読み込みを行っても時間が経てば大体同じ使用量に落ち着きます。 試したコードを抜粋したものが以下になります。 ======================================== #if defined(_WIN32) && defined(_UNICODE) static constexpr size_t kMaxPathLength = 1024; /// @brief 現在DxLibに設定されているコードページを元に、固定長バッファ上でchar文字列をwchar_t文字列に変換 /// @param dstSize 変換先の大きさ。既定引数の場合、変換前の大きさ超過確認を行わない。 /// @return 実際に書き込まれた長さ static int WidenInBuffer(const char* str, wchar_t* dst, int dstSize = -1) { int iCharCode = DxLib::GetUseCharCodeFormat(); int iWcharCode = DxLib::Get_wchar_t_CharCodeFormat(); if (dstSize != -1) { int iRet = DxLib::ConvertStringCharCodeFormat(iCharCode, str, iWcharCode, nullptr); if (iRet < sizeof(wchar_t))return 0; if (iRet >= dstSize * sizeof(wchar_t))return 0; } int iLength = DxLib::ConvertStringCharCodeFormat(iCharCode, str, iWcharCode, dst); iLength = iLength / sizeof(wchar_t) - 1; return iLength; } #endif /* defined(_WIN32) && defined(_UNICODE) */ void CDxLibTextureLoader::load(const char* textureFilePath) { #if defined(_WIN32) && defined(_UNICODE) wchar_t wcharPathBuffer[kMaxPathLength]{}; int nWritten = WidenInBuffer(textureFilePath, wcharPathBuffer); #endif #if 0 /* BASEIMAGEを使った処理 */ DxLib::BASEIMAGE baseImage{}; #if defined(_WIN32) && defined(_UNICODE) DxLib::CreateBaseImageToFile(wcharPathBuffer, &baseImage); #else DxLib::CreateBaseImageToFile(textureFilePath, &baseImage); #endif if (baseImage.GraphData == nullptr)return; if (m_toConvertToPma) { DxLib::ConvertPremulAlphaBaseImage(&baseImage); } int iDxLibTexture = DxLib::CreateGraphFromGraphImage(&baseImage); DxLib::ReleaseBaseImage(&baseImage); if (iDxLibTexture == -1)return; #elif 0 /* ソフトウェアイメージを使った処理 */ int softwareImageHandle = -1; #if defined(_WIN32) && defined(_UNICODE) softwareImageHandle = DxLib::LoadARGB8ColorSoftImage(wcharPathBuffer); #else softwareImageHandle = DxLib::LoadARGB8ColorSoftImage(textureFilePath); #endif if (softwareImageHandle == -1)return; if (m_toConvertToPma) { DxLib::ConvertPremulAlphaSoftImage(softwareImageHandle); } int iDxLibTexture = DxLib::CreateGraphFromSoftImage(softwareImageHandle); DxLib::DeleteSoftImage(softwareImageHandle); if (iDxLibTexture == -1)return; #else /* 読み込みフラグを用いた場合 */ DxLib::SetUsePremulAlphaConvertLoad(m_toConvertToPma ? TRUE : FALSE); #if defined(_WIN32) && defined(_UNICODE) int iDxLibTexture = DxLib::LoadGraph(wcharPathBuffer); #else int iDxLibTexture = DxLib::LoadGraph(textureFilePath); #endif if (iDxLibTexture == -1)return; #endif /* 以下略 */ } ========================================
メンテ

Page: 1 |

Re: CPUで扱える形式を介して画像を読み込んだ際のメモリ使用量に関して ( No.1 )
名前:管理人 日時:2026/08/29 03:03

DXライブラリは Direct3D を使用して画像を表示しているのですが、 Direct3D では稀にデバイスロストという現象が発生して Direct3D で使用するテクスチャとして VRAM に転送していた画像データが消失することがあります なので、LoadGraph や CreateGraphFromGraphImage 等で読み込まれた画像は Direct3D のデバイスロストが発生しても Direct3D のテクスチャを元通りに復旧できるように LoadGraph や CreateGraphFromGraphImage で渡された画像情報をシステムメモリ上に 保存しておき、いつデバイスロストが発生しても問題が無いようにしています そして、この『システムメモリ上に保存しておく画像情報』の差がメモリ使用量の差となっています LoadGraph で読み込まれた場合はシステムメモリに保存される画像情報は PNG画像です、 PNGは圧縮形式なので、4096x4096の画像でも数MBの容量であったりします、これが復旧用情報として システムメモリに保存されるので使用メモリ量も抑えられます ところが、CreateGraphFromGraphImage でシステムメモリ上に保存される復旧用情報は 無圧縮の 4096x4096 の画像情報です、無圧縮の 4096x4096 の画像は単純計算で 64MB の 容量があり、それがシステムメモリに保存されるために、メモリ使用量が LoadGraph の場合より 多くなってしまうのです CreateGraphFromGraphImage を呼ぶ前に PNG画像として圧縮するなどすれば LoadGraph と 同じメモリ使用量にすることができますが、4096x4096 の画像の PNG圧縮は非常に時間が掛かるので 現実的ではありません なのでこの件に関してはメモリ使用量が多くなるのは基本的には諦めるしかありません かなり手間の掛かるその他の対策としては『DXライブラリのデバイスロストからの画像復旧処理を 頼らず、自分で復旧処理を行う』というものがあります まず DxLib_Init の後に SetUseGraphBaseDataBackup( FALSE ); を実行して、LoadGraph や CreateGraphFromGraphImage などが呼ばれた時にデフォルトでは行われる『デバイスロストが発生したときの 復旧用に画像情報を保存する』処理を無効化します、これで CreateGraphFromGraphImage を使用しても 大量のメモリ消費が発生しなくなります // グラフィックハンドルを作成する際に使用した画像データのバックアップをして Direct3DDevice のデバイスロスト時に使用するかどうかを設定する( TRUE:バックアップをする( デフォルト ) FALSE:バックアップをしない ) // ( バックアップをしないとメモリの節約になりますが、復帰に掛かる時間が長くなり、メモリ上のファイルイメージからグラフィックハンドルを作成した場合は自動復帰ができないなどの弊害があります ) int SetUseGraphBaseDataBackup( int Flag ) ; そして次に SetRestoreGraphCallback という関数で、デバイスロストが発生したときに呼ばれる 画像データ復旧用の自前のコールバック関数を登録します // グラフィックハンドル復元関数を登録する int SetRestoreGraphCallback( void (* Callback )( void ) ) ; デバイスロストが発生するとこの関数が呼ばれますので、各グラフィックハンドルに対して ReloadGraph や ReCreateGraphFromSoftImage でグラフィックハンドルの画像情報を自前で復旧します この方法を使用することでメモリ使用量を抑えることができますが、対応には少し大きめの作業が必要になります…
メンテ

Page: 1 |

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

   クッキー保存