質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
OpenGL

OpenGLは、プラットフォームから独立した、デスクトップやワークステーション、モバイルサービスで使用可能な映像処理用のAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

1465閲覧

OpenGLとマルチスレッドを組み合わせた際の遅延問題

HexagramNM

総合スコア13

OpenGL

OpenGLは、プラットフォームから独立した、デスクトップやワークステーション、モバイルサービスで使用可能な映像処理用のAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2018/11/02 12:52

編集2018/11/02 12:54

発生している問題・エラーメッセージ

以下のコードのように,スレッドを生成する処理をした後に,OpenGLのSwapBufferをした後に,glFinishでopenGLの命令の同期待ちをするとglFinishの部分で1フレームにつき100~200msecの大きな遅延が発生してしまいます(実際の開発しているコードではCUDAとOpenGLを連携させるためのマッピングをしており,その際にOpenGLの同期待ちをしてしまうようなので今回は代わりにglFinishを使用しています).スレッドを生成する処理をコメントアウトすると,そのような遅延がなくなります.マルチスレッドの処理を残しつつ,遅延を抑える方法や,このようなことが起きている原因の手がかりなどご教授いただければと思います..

該当のソースコード

C++のコードです.

C++

1/** VisualStudioの環境でsscanfを使用する際にエラー回避のために必要.*/ 2#define _CRT_SECURE_NO_WARNINGS 3#include <GL/glew.h> 4#include <GL/glut.h> 5 6#include <fstream> 7#include <iostream> 8 9#include <GL/freeglut_std.h> 10#include <GL/freeglut_ext.h> 11#include <chrono> 12 13#include <process.h> 14#include <thread> 15 16using namespace std; 17 18/** 60fps制御を行う. */ 19void idle() 20{ 21 auto start = std::chrono::system_clock::now(); 22 glutPostRedisplay(); 23 24 auto end = std::chrono::system_clock::now(); 25 auto msec = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); 26 while (msec < 50.0 / 3.0) { 27 end = std::chrono::system_clock::now(); 28 msec = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); 29 } 30} 31 32/** std::thread用 */ 33unsigned int threadTest() { 34 cout << "test" << endl; 35 return 0; 36} 37 38/** process.h用 */ 39/*unsigned _stdcall threadTest(void *arg) { 40 cout << "test" << endl; 41 return 0; 42}*/ 43 44void oneFrameProcessAll() { 45 /*HANDLE test; 46 test = (HANDLE)_beginthreadex(NULL, 0, threadTest, NULL, 0, NULL); 47 WaitForSingleObject(test, INFINITE); 48 CloseHandle(test);*/ 49 thread test(threadTest); 50 test.join(); 51 52} 53 54void display(void) { 55 56 oneFrameProcessAll(); 57 58 glutSwapBuffers(); 59 60 std::chrono::time_point<std::chrono::system_clock> tmpStart; 61 std::chrono::time_point<std::chrono::system_clock> tmpEnd; 62 long long tmpMsec = 0; 63 tmpStart = std::chrono::system_clock::now(); 64 65 //ここの同期待ちで遅延が発生 66 glFinish(); 67 GLenum glerr = glGetError(); 68 if (glerr != GL_NO_ERROR) { 69 cout << glerr << endl; 70 } 71 72 tmpEnd = std::chrono::system_clock::now(); 73 tmpMsec = std::chrono::duration_cast<std::chrono::milliseconds>(tmpEnd - tmpStart).count(); 74 cout << "Temp: " << tmpMsec << "msec" << endl; 75 76} 77 78/** 画面のサイズが変更された際の処理. */ 79void resize(int w, int h) { 80 glViewport(0, 0, w, h); 81 glMatrixMode(GL_PROJECTION); 82 glLoadIdentity(); 83 gluPerspective(45.0, w/h, 10.0, 1000.0); 84 glMatrixMode(GL_MODELVIEW); 85 glLoadIdentity(); 86} 87 88/** qキーかESCキーが押されると終了処理. */ 89void hitkey(unsigned char key, int x, int y) { 90 switch (key) { 91 case 'q': 92 case 'Q': 93 case 27: // esc 94 glutLeaveMainLoop(); 95 break; 96 default: 97 break; 98 } 99} 100 101/** OpenGL描画関係の初期化. */ 102void dispinit(void) 103{ 104 glClearColor(0.0, 0.0, 0.0, 1.0); 105} 106 107int main(int argc, char *argv[]) 108{ 109 110 glutInit(&argc, argv); 111 glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS); 112 glutInitWindowSize(960, 720); 113 glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); 114 glutCreateWindow(argv[0]); 115 glutDisplayFunc(display); 116 glutKeyboardFunc(hitkey); 117 glutIdleFunc(idle); 118 glutReshapeFunc(resize);; 119 dispinit(); 120 121 glutMainLoop(); 122 123 system("PAUSE"); 124 125 return 0; 126}

試したこと

・スレッドの生成についてpthread.hによる方法とstd::threadクラスを用いた方法を試しましたが,同じ現象が発生しました.
・上のコードではfreeglutを用いていますが,glfwで同じようなコードを書いても,同じ現象が発生しました.
・GPUのドライバの更新もしてみましたが,効果がありませんでした.

補足情報(FW/ツールのバージョンなど)

開発にはVisual Studio 2015を使用しております.
PCのCPUはIntel Core i7-3770を,GPUはNVIDIA GTX 1070Tiを使用しております.RAMは8GBです.OSはWindows 10 Homeです.

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yohhoy

2018/11/03 00:28 編集

1フレーム毎にスレッドを生成していますか?スレッド生成は非常に"重い"処理です。予め生成しておいたスレッドを使う構造はとれないのでしょうか?他スレッドで何をさせたいのでしょう?
HexagramNM

2018/11/03 09:54

ありがとうございます.スレッドを最初に生成する構造はこれから考えてみます.実際の自分の開発では他スレッドでモデルの更新などをさせたいと思っております.
HexagramNM

2018/11/03 17:19

昨日別のノートPCでコンパイルして試したところ,このような現象が生じなかったり,知り合いの環境でもこの現象が生じなかったりしたことから,環境によるものなのかと現在推測しています.
guest

回答1

0

自己解決

スレッド生成の処理が重く,問題になっていた環境だとボトルネックになっていたようです.以下のように最初からスレッドを作っておいて,ロックを用いて同期したところ遅延を回避できるようになりました(下のコードもひょっとすると不完全なところがあるかもしれませんが).yohhoyさん,アイデアをありがとうございました!

C++

1 2/** VisualStudioの環境でsscanfを使用する際にエラー回避のために必要.*/ 3#define _CRT_SECURE_NO_WARNINGS 4#include <GL/glew.h> 5#include <GL/glut.h> 6 7#include <fstream> 8#include <iostream> 9 10#include <GL/freeglut_std.h> 11#include <GL/freeglut_ext.h> 12#include <chrono> 13 14#include <process.h> 15#include <thread> 16#include <mutex> 17 18using namespace std; 19mutex mtx1; 20thread *test = NULL; 21int condVar[2] = { 0, 0 }; 22 23/** 60fps制御を行う. */ 24void idle() 25{ 26 auto start = std::chrono::system_clock::now(); 27 glutPostRedisplay(); 28 29 auto end = std::chrono::system_clock::now(); 30 auto msec = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); 31 while (msec < 50.0 / 3.0) { 32 end = std::chrono::system_clock::now(); 33 msec = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); 34 } 35} 36 37/** std::thread用 */ 38unsigned int threadTest() { 39 while(true){ 40 while (true) { 41 { 42 lock_guard<mutex> lock1(mtx1); 43 if (condVar[0] == condVar[1] + 1 ) { 44 break; 45 } 46 else if (condVar[0] == -1) { 47 return 0; 48 } 49 } 50 } 51 cout << "test" << endl; 52 { 53 lock_guard<mutex> lock1(mtx1); 54 condVar[1]++; 55 } 56 } 57 return 0; 58} 59 60void oneFrameProcessAll() { 61 { 62 lock_guard<mutex> lock1(mtx1); 63 condVar[0]++; 64 } 65 66 cout << "rendering" << endl; 67 68 while (true) { 69 { 70 lock_guard<mutex> lock1(mtx1); 71 if (condVar[1] == condVar[0]) { 72 break; 73 } 74 } 75 } 76} 77 78void display(void) { 79 glClearColor(0.0, 0.0, 0.0, 1.0); 80 81 oneFrameProcessAll(); 82 83 glutSwapBuffers(); 84 85 std::chrono::time_point<std::chrono::system_clock> tmpStart; 86 std::chrono::time_point<std::chrono::system_clock> tmpEnd; 87 long long tmpMsec = 0; 88 tmpStart = std::chrono::system_clock::now(); 89 90 //ここの同期待ちで遅延が発生 91 glFinish(); 92 GLenum glerr = glGetError(); 93 if (glerr != GL_NO_ERROR) { 94 cout << glerr << endl; 95 } 96 97 tmpEnd = std::chrono::system_clock::now(); 98 tmpMsec = std::chrono::duration_cast<std::chrono::milliseconds>(tmpEnd - tmpStart).count(); 99 cout << "Temp: " << tmpMsec << "msec" << endl; 100 101} 102 103/** 画面のサイズが変更された際の処理. */ 104void resize(int w, int h) { 105 glViewport(0, 0, w, h); 106 glMatrixMode(GL_PROJECTION); 107 glLoadIdentity(); 108 gluPerspective(45.0, w/h, 10.0, 1000.0); 109 glMatrixMode(GL_MODELVIEW); 110 glLoadIdentity(); 111} 112 113/** qキーかESCキーが押されると終了処理. */ 114void hitkey(unsigned char key, int x, int y) { 115 switch (key) { 116 case 'q': 117 case 'Q': 118 case 27: // esc 119 { 120 lock_guard<mutex> lock1(mtx1); 121 condVar[0] = -1; 122 } 123 glutLeaveMainLoop(); 124 test->join(); 125 delete test; 126 test = NULL; 127 break; 128 default: 129 break; 130 } 131} 132 133/** OpenGL描画関係の初期化. */ 134void dispinit(void) 135{ 136 glClearColor(0.0, 0.0, 0.0, 1.0); 137 test = new thread(threadTest); 138} 139 140int main(int argc, char *argv[]) 141{ 142 143 glutInit(&argc, argv); 144 glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS); 145 glutInitWindowSize(960, 720); 146 glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); 147 glutCreateWindow(argv[0]); 148 glutDisplayFunc(display); 149 glutKeyboardFunc(hitkey); 150 glutIdleFunc(idle); 151 glutReshapeFunc(resize);; 152 dispinit(); 153 154 glutMainLoop(); 155 156 system("PAUSE"); 157 158 return 0; 159}

投稿2018/11/04 12:13

HexagramNM

総合スコア13

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問