トップページ > 記事閲覧
DrawStringで大量の文字列を描画すると処理が重くなる
名前:sereparu 日時: 2018/10/19 11:13

いつもお世話になっております。 DrawStringの仕様について確認させてください。 現在、VisualStudio 2017 CommunityでUnicode文字セットを使用する環境でDXライブラリ(ver 3.19d)を使用しています。 DrawStringで色々な特殊文字や記号を描画できるかテストしていたところ 大量の文字列を描画すると急に処理が重くなることを確認しました。 処理が重くなったのは、下記ページの最後の方にある「全角記号」をすべて一度にDrawStringで描画させた場合です。 (URLの先頭に「h」を付けてください) ttps://qiita.com/sta/items/848e7a8c4699a59c604f 通常DrawStringで文字を描画するだけの処理であれば、CPU使用率は5〜10%ほどですが 処理が重くなったときは、CPU使用率が20〜30%に上がります。 上記ページの「全角記号」すべてを合わせると、文字数は435文字になりますが 例えば、「あ」の文字を435文字描画させる場合は、処理は重くなりませんでした。 このことから考えると、DrawStringは文字列ではなく、文字の種類が多くなると 負荷が高くなると考えられますが、そのような認識でよろしいでしょうか? 文字の種類が多くなると負荷が高くなる場合、何か回避策はあるでしょうか? よろしくお願いいたします。
メンテ

Page: 1 |

Re: DrawStringで大量の文字列を描画すると処理が重くなる ( No.1 )
名前:PSPv1.5 日時:2018/10/19 21:18

↓のようなのを書いてみました。CPU負荷ではなくノーウェイトFPSでの比較ですが、「あだけ」と「全角(半角も 混じっていますが)だけ」とでほとんど同じでした。140くらい。 フォントって最初の描画は重いがそこでデータを作って2ループ目からはそれを使うのでそこそこ早い、という 認識なので、メインループに入る前にこっそりごっそり描画しておけばいいのかなとか思っています。 (そこまでやったことはありませんが) #include "DxLib.h" int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { ChangeWindowMode(TRUE); SetGraphMode(1280, 720, 32); SetWaitVSyncFlag(FALSE); if (DxLib_Init() < 0) return -1; SetDrawScreen(DX_SCREEN_BACK); TCHAR str1[] = TEXT("、。,.・:;?!゛゜´`¨^ ̄_ヽヾゝゞ〃仝々〆〇ー―‐/\〜‖|…‥\n" \ "‘’“”()〔〕[]{}〈〉《》「」『』【】+−±×÷=≠<>≦≧∞∴\n" \ "♂♀°′″℃¥$¢£%#&*@§☆★○●◎◇◆□■△▲▽▼※〒→←↑↓〓\n" \ "∈∋⊆⊇⊂⊃∪∩∧∨¬⇒⇔∀∃∠⊥⌒∂∇≡≒≪≫√∽∝∵∫∬ʼn♯♭♪\n" \ "ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθ\n" \ "ικλμνξοπρστυφχψωАБВГДЕЁЖЗИЙКЛМНО\n" \ "ПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмн\n" \ "опрстуфхцчшщъыьэюя\n" \ "─│┌┐┘└├┬┤┴┼━┃┏┓┛┗┣┳┫┻╋┠┯┨┷┿┝┰┥┸╂\n" \ "。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚\n" \ "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]_`\n" \ "abcdefghijklmnopqrstu ~∞gョх\n" \ "援括窮欠合紫潤焉゚∫島煤縺ロ∠凵諱ソ∪"); int l = strlenDx(str1); TCHAR str2[500], buf[64]; for (int i = 0; i < l; i++) str2[i] = (str1[i] == _T('\n')) ? _T('\n') : _T('あ'); str2[l] = _T('\0'); unsigned int c = 0; char KeyBuf[256]; while (ProcessMessage() == 0) { GetHitKeyStateAll(KeyBuf); ClearDrawScreen(); for (int i = 0; i < 192; i++) { if (KeyBuf[KEY_INPUT_LSHIFT]) // Lシフトキーで全角+半角 DrawString(0, 20 + i * 2, str1, GetColor((c & 2) ? 255 : 0, (c & 4) ? 255 : 0, (c & 1) ? 255 : 0)); if (KeyBuf[KEY_INPUT_LCONTROL]) // Lコントロールキーで あ のみ DrawString(0, 20 + i * 2, str2, GetColor((c & 2) ? 255 : 0, (c & 4) ? 255 : 0, (c & 1) ? 255 : 0)); c++; } float fFPS = GetFPS(); sprintfDx(buf, TEXT("L-Shift:全角文字(+半角カナ) L-Control:「あ」のみ  %d fps"), (int)fFPS); DrawString(0, 0, buf, GetColor(255, 255, 255)); ScreenFlip(); } return DxLib_End(); }
メンテ
Re: DrawStringで大量の文字列を描画すると処理が重くなる ( No.2 )
名前:sereparu 日時:2018/10/20 10:34

PSPv1.5さん 検証用のソースまでご用意いただき、誠にありがとうございます。 PSPv1.5さんのソースを実行してみたところ、PSPv1.5さんのおっしゃる通り 「あ」だけの場合も、全角記号の場合も、処理が重くなることなく、FPSも140くらいで安定していました。 自分のソースもほぼ同じものだったので、何が違うか一つずつ比較してみたところ SetGraphModeの画面の解像度の引数を変えると、全角記号の表示で処理が重くなる(FPSが0になる)ことが分かりました。 PSPv1.5さんのソースでは「SetGraphMode(1280, 720, 32);」となっていますが 自分のソースでは「SetGraphMode(960, 540, 32);」と設定していました。 PSPv1.5さんのソースの「SetGraphMode(1280, 720, 32);」の画面の解像度の部分を 色々変更してみたところ、以下のような結果になりました。 (○…全角記号の表示で処理が重くならなかった、×…全角記号の表示で処理が重くなった) SetGraphMode(640, 480, 32); → × SetGraphMode(800, 600, 32); → × SetGraphMode(1024, 768, 32); → ○ SetGraphMode(1280, 1024, 32); → ○ SetGraphMode(1280, 720, 32); → ○ SetGraphMode(1920, 1080, 32); → ○ 現在、解像度が最大1920×1080のデスクトップPC用のモニターを使っていますが 試しに解像度が最大1280×800のノートPCで同じソースを実行してみたところ ノートPCの方では、どの解像度にしても「あ」だけの場合も、全角記号の場合もFPSは20くらいでした。 そのため、使用しているモニターの性能に依存する問題なのではないかと思います。 そうなると、プログラム側で修正するのが難しいかもしれません。 もう少し何か方法がないか調べてみます。
メンテ
Re: DrawStringで大量の文字列を描画すると処理が重くなる ( No.3 )
名前:PSPv1.5 日時:2018/10/20 12:45

No.1に書いたソースのSetGraphMode(w, h, bpp)のwとhを変えて試してみました。 すると ■NG (FPS=0 ... 1コマ描くのに5秒以上かかる) 1600 x 384 ドット数:614400 640 x 962 ドット数:615680 1280 x 481 ドット数:615680 1600 x 385 ドット数:616000 800 x 770 ドット数:616000 960 x 642 ドット数:616320 640 x 963 ドット数:616320 800 x 771 ドット数:616800 1028 x 600 ドット数:616800 ■OK (FPS = 140程度) 1280 x 482 ドット数:616960 640 x 964 ドット数:616960 960 x 643 ドット数:617280 1600 x 386 ドット数:617600 1920 x 322 ドット数:618240 1600 x 390 ドット数:624000 という結果でした。つまり、バックバッファの縦と横のドット数をかけた数値が 616800まではNG、616960から普通の速度、という感じです。 また、str1[]の中身を半分くらいまでにすると、上記NGだった組み合わせのうち、 FPS=140程度になるものもあります。 ちょっと調べてみましたが、  SetFontCacheCharNum(int n);  int GetFontCacheCharNum(); // デフォルトは0が返ってくるので最初どれだけ確保されているのかは取得できない という関数が存在します。 今回は 435文字+あ+英数字+αで500もないので、SetFontCacheCharNum(2048); のようにすると (VRAMが十分確保できるPCなら)640x480でもOKでした。 推測ですが、バックバッファサイズに応じたキャッシュサイズを最初に作る仕様なのかもしれませんね。 (GetFontCacheCharNum() はそれを返してほしいところですが…)
メンテ
Re: DrawStringで大量の文字列を描画すると処理が重くなる ( No.4 )
名前:yumetodo 日時:2018/10/20 13:47

そもそもDrawStringToHandleを使うようにするとどうなりますか?
メンテ
Re: DrawStringで大量の文字列を描画すると処理が重くなる ( No.5 )
名前:sereparu 日時:2018/10/20 15:31

PSPv1.5さん、yumetodoさん 迅速なご回答、誠にありがとうございます。 PSPv1.5さんのおっしゃる通り、「SetFontCacheCharNum(2048);」を指定したところ どの解像度でも全角記号を描画しても処理落ちが発生しなくなりました。 過去ログをよく調べたら同じような回答が既に存在しました。 過去ログの調査不足でした。申し訳ありません。 ttp://dxlib.o.oo7.jp/cgi/patiobbs/patio.cgi?mode=view&no=3307 ttp://dxlib.o.oo7.jp/cgi/patiobbs/patio.cgi?mode=view&no=3949 >yumetodoさん CreateFontToHandleでフォントサイズの小さいフォントハンドルを作成して DrawStringToHandleで全角記号を描画した場合は、処理落ちが発生しませんでした。 ただ、今回の場合、フォントサイズを15以上に設定すると処理落ちが発生しました。 「SetFontCacheCharNum(2048);」を指定しても、フォントサイズを巨大(150など)にした場合は コンソールに「テクスチャに画像を転送するためのメモリの確保に失敗しました」とエラーが出力され 描画自体できなくなります。 使用する文字の種類、解像度、フォントサイズなどに合わせて ちょうど良いキャッシュサイズを自動で設定できる機能があったら良いのに、と思いました。 何か良い方法がないか、もう少し考えてみます。
メンテ
Re: DrawStringで大量の文字列を描画すると処理が重くなる ( No.6 )
名前:管理人 日時:2018/10/23 01:37

SetFontCacheCharNum に大きな数値を設定して CreateFontToHandle で大きなサイズのフォントを作成しようとすると グラフィックスデバイスが対応していないサイズのテクスチャを作成しようとしてしまったり、仮に作成できても 1GBのVRAMを必要とするテクスチャ( 16384x16384 の 32bitカラーのテクスチャ )を作成しようとしてしまったり するような処理になっていたので、フォントのキャッシュ用のテクスチャサイズは最大でも 8192x8192 になるように処理を変更しました ただ、これでも最大で1フォントハンドルにつき256MBもメモリを消費するので SetFontCacheCharNum に渡す値の調節には気をつけてください 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.2 用 https://dxlib.xsrv.jp/temp/DxLibGCC_MinGWTest.zip // Windows版 MinGW 用 https://dxlib.xsrv.jp/temp/DxLibDotNet.zip // Windows版 .NET用 https://dxlib.xsrv.jp/temp/DxLibAndroidTest_ARM.zip // Android版 ARM用 https://dxlib.xsrv.jp/temp/DxLibAndroidTest_ARM64.zip // Android版 ARM64用 https://dxlib.xsrv.jp/temp/DxLibAndroidTest_x86.zip // Android版 x86用 https://dxlib.xsrv.jp/temp/DxLibAndroidTest_x64.zip // Android版 x64用 https://dxlib.xsrv.jp/temp/DxLibMakeTest.zip // ソース (中身を既存のライブラリのファイルに上書きして、BCCをお使いの 場合は『再構築』を、VCをお使いの場合は『リビルド』を、 Dev-C++をお使いの方は「Rebuild All(Ctrl+F11)」をして下さい)
メンテ
Re: DrawStringで大量の文字列を描画すると処理が重くなる ( No.7 )
名前:sereparu(解決) 日時:2018/10/27 00:13

管理人さん ライブラリの更新、誠にありがとうございます。 とりあえず、一度に大量の文字を表示しない、フォントサイズを大きくしすぎないよう 気を付けて使用することにします。 今回はテスト用に大量の文字を表示したため発生した現象であり 通常は問題ないと思いますので、解決とさせていただきます。 ありがとうございました。
メンテ

Page: 1 |

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

   クッキー保存