1

Windows 上の C++ でサードパーティ プログラム内にプラグインを実装しています。

サードパーティ プログラムには、OpenGL を使用して 3D グラフィックを表示するウィンドウがあります。ただし、OpenGL を使用して 3D グラフィックスも表示する別のウィンドウを作成するには、プラグインが必要です。

自分のウィンドウ用に新しい OpenGL レンダリング コンテキストを作成する必要がありますか、またはサード パーティ プログラムで使用される OpenGL レンダリング コンテキストを「再利用」する方法はありますか?

新しい OpenGL レンダリング コンテキストを作成する必要があると想定し、次のことを試しました。

// create a rendering context  
hglrc = wglCreateContext (hdc); 

// make it the calling thread's current rendering context 
wglMakeCurrent (hdc, hglrc);

ただし、最後の関数は失敗しました。wglMakeCurrent のドキュメントを読むと、

スレッドは、現在のレンダリング コンテキストを 1 つ持つことができます。プロセスは、マルチスレッドによって複数のレンダリング コンテキストを持つことができます。

これは、ウィンドウをサードパーティ プログラムとは別のスレッドで実行する必要があるということですか?

4

2 に答える 2

1

wglMakeCurrent() によって生成されたエラー コードを投稿していないので、その理由は推測できません。ただし、バインディング自体ではありません。「スレッドは現在のレンダリング コンテキストを 1 つ持つことができる」という文は、新しいコンテキストが古いコンテキストを「置き換え」、現在のコンテキストになることを意味します。2 つのコンテキストを現在のコンテキストとして設定しようとしている (または別のスレッドを実行しようとしている) 理由はわかりませんが、それは方法ではありません。どうしても必要な場合を除き、レンダリングでのマルチスレッド化は避けてください。だから、あなたの質問に答える:

はい、OpenGL レンダリング コンテキストを再利用」できます。

なぜ、あなたは尋ねるかもしれませんか?レンダリング コンテキストは、各ウィンドウ (HWND) の排他的プロパティである特定のデバイス コンテキスト (HDC) に対して作成されます。では、どうしてこれが可能になるのでしょうか?!

関数プロトタイプのせいで、なんとなく不可能に思えます。

    HWND my_window = CreateWindow(...);
    HDC my_dc = GetDC(my_new_window);

    //「my_dc」のピクセル形式を設定...

    HGLRC my_rc = wglCreateContext(my_dc);
    wglMakeCurrent(my_dc, my_rc);

これにより、レンダリング コンテキストがこの特定のデバイス コンテキストにバインドされ、そのコンテキストに対してのみ有効であると考えることができます。しかし、そうではありません。重要な部分はコメント (設定ピクセル形式) です。レンダリング コンテキストは、DC の特定の CLASS 、より正確には、同じピクセル形式の DC に対して作成されます。したがって、以下のコードは完全に有効です。

    //window_1 = メイン ウィンドウ、window_2 = 自分のウィンドウ

    HDC dc_1 = GetDC(window_1);
    Set_pixel_format_for_dc_1(); // いつものこと
    HGLRC rc = wglCreateContext(dc_1);

    wglMakeCurrent(dc_1, rc);
    ultra_super_draw();

    //.....

    HDC dc_2 = GetDC(window_2);

    // dc_1 の PF を取得して、rc と互換性があることを確認します。
    int pf_index = GetPixelFormat(dc_1);
    PIXELFORMATDESCRIPTOR pfd;
    ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR));
    DescribePixelFormat(dc_1, pf_index, sizeof(PIXELFORMATDESCRIPTOR), &pfd);

    SetPixelFormat(dc_2, pf_index, &pfd);

    wglMakeCurrent(dc_2, rc);
    another_awesome_render();

    wglMakeCurrent(NULL, NULL);

それでも納得できない場合は、MSDN :

wglMakeCurrent(hdc, hglrc): hdc パラメーターは、OpenGL でサポートされている描画面を参照する必要があります。hglrc が作成されたときに wglCreateContext に渡されたものと同じ hdc である必要はありませんが、同じデバイス上にあり、同じピクセル形式である必要があります。

あなたはすでにこれらの呼び出しに精通していると思います。さて、レンダリングが満たさなければならない条件が何であるかはわかりませんが、追加の要件がなければ、この時点から問題はないと思います。

    HDC my_dc = Create_my_DC();

    //...

    void my_new_render
    {
        //おそらく、現在のバインディングを保存したいでしょう:
        HDC current_dc = wglGetCurrentDC();
        HGLRC current_context = wglGetCurrentContext();

        wglMakeCurrent(my_dc, current_context);

        MyUltraSuperRender(...);

        wglMakeCurrent(current_dc, current_context);
    }

お役に立てれば :)

于 2013-09-24T22:12:13.360 に答える
1

まず最初に、実際にはプラグイン用に別の OpenGL コンテキストを作成する必要があります。これは、メイン プログラムの OpenGL コンテキストに干渉しない別の状態空間を提供するという単純な理由からです。

ただし、複数のレンダリング コンテキストに関する部分を誤解していました。プロセスに任意の数の OpenGL コンテキストを設定することは完全に可能です。ただし、プロセスの各スレッドは、一度に 1 つのコンテキストしかバインドできません。その 1 つのバインドには、コンテキストがバインドされているウィンドウ DC も含まれます。ただし、いつでもコンテキストバインディングを完全に合法的に変更できます。特定のコンテキストがバインドされているウィンドウを変更するか、コンテキストを切り替えるか、または両方を同時に行います。

したがって、あなたの状況では、プラグインが作成するすべてのウィンドウに使用する、プラグイン用のカスタム コンテキストを作成することをお勧めします。

単純なコンテキストの「作成」コードが失敗するのには、1 つの単純な理由があります。ウィンドウにピクセル フォーマット記述子が設定されていない可能性が高いからです。

新しいウィンドウとコンテキストを作成するには、次の方法を使用することをお勧めします。

/* first get hold of the HDC/HRC of the parent */
HDC parentDC = wglGetCurrentDC();
HRC parentRC = wglGetCurrentContext();
int pixelformatID = GetPixelFormat(parentDC);

/* we use the same PFD as the parent */
PIXELFORMATDESCRIPTOR pixelformat;
memset(pixelformat, 0, sizeof(pixelformat);
DescribePixelFormat(parentDC, pixelformatID, sizeof(pixelformat), &pixelformat);

/* create a window and set it's pixelformat to the parent one's */
HWND myWND = create_my_window();
HDC  myDC = GetDC(myWND);
SetPixelFormat(myDC, pixelformatID, &pixelformat);

/* finally we can create a rendering context
 * it doesn't matter if we create it against
 * the parent or our own DC.
 */
HRC myRC = wglCreateContext(myDC);

/* we're done here... */

プラグインが何かをレンダリングしたいときはいつでも、独自のコンテキストをバインドし、そのことを行い、以前にバインドされたコンテキストをバインドする必要があります。

HDC prevDC = wglGetCurrentDC();
HRC prevRC = wglGetCurrentContext();

wglMakeCurrent(myDC, myRC);

/* do OpenGL stuff */

wglMakeCurrent(prevDC, prevRC);
于 2013-09-24T22:15:20.470 に答える