5

私は SDL2 と C++11 を使用してゲーム エンジンを構築しています (個人的なプロジェクトとして、楽しみと練習のために)。私がやりたいことの 1 つは、サポートされている最新バージョンをグラフィックス ドライバーで使用することです。バージョンに基づいて、エンジンのグラフィックス部分のレンダリング方法が異なります。このようにして、関連性があり便利な OpenGL の最新機能を使用できるだけでなく、古いハードウェアもサポートできます。私が考えることができる2つの方法があります:

  1. サポートされている最新バージョンの OpenGL を検出して使用していますが、それを行う方法が思いつきません。はい、Google を試しました。

  2. 試行錯誤を使用して、最新バージョン (4.3、ただし、ドライバーを更新したにもかかわらず、私の GTX 460 は 4.2 までしかサポートしていません) から開始し、それが失敗した場合 (SDL をチェックして NULL コンテキストを返すことで検出します) )、バージョン番号を下げて再試行します。

私が使用する方法 (#2) は、4.3 コンテキストの作成直後に失敗します。現在、グラフィックス ドライバーが 4.2 しかサポートしていないことはわかっていますが、GLX はエラーをスローし、NULL コンテキストを与え、プログラムを続行させるように設計されていると思っていましたが、代わりにコンテキストの作成の失敗を乗り越えることはできません。 . GLX がどのように動作するかについての私の仮定は間違っていますか? コンテキストを作成せずに、サポートされている最新のバージョンを検出する方法はありますか?

一部の人々がエラーを示す完全で最小限のソースを見たいと思っていることを知っているので、ここに示します:

#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>
int main() {
    if( SDL_Init( SDL_INIT_EVERYTHING ) < 0 ) {
        return -1;
    }
    SDL_Window* window = SDL_CreateWindow( "SDL Window", 0, 0, 800, 600, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN );
    if( window == nullptr ) {
        return -1;
    }
    unsigned int major = 4;
    unsigned int minor = 3;
    SDL_GLContext context = nullptr;
    while( context == nullptr ) {
        SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, major );
        SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, minor );
        context = SDL_GL_CreateContext( window );
        if( context == nullptr ) {
            if( minor == 0 && major > 1 ) {
                --major;
                minor = 9;
            }
            else if( minor > 0 ) {
                --minor;
            }
            else {
                SDL_DestroyWindow( window );
                return -1;
            }
        }
    }
    SDL_Delay( 5000 );
    SDL_GL_DeleteContext( context );
    SDL_DestroyWindow( window );
    return 0;
}

また、そのコードを 4.3 ではなく 4.2 コンテキストで開始するように変更すると、問題なく動作します。したがって、具体的には 4.3 コンテキストを作成する際にエラーが発生します。

4

2 に答える 2

1

これは、SDL の X11_GL_CreateContext() のバグを示している可能性があります (Web では、SDL2 はまだ実験段階であると書かれています)。サポートされている OpenGL バージョンを見つける戦略は有効ですが、SDL が前方互換性のあるコンテキストを提供するには、まず一時的なコンテキストを作成する必要があり、glXGetProcAddress() を呼び出して glCreateContextAttribsARB を取得する必要があります (アクティブな OpenGL コンテキスト)、要求した OpenGL バージョンの初期化を試みます。失敗した場合、一時コンテキストを破棄して NULL を返します。

一時コンテキストの作成に失敗したのは 2 回目だと思います。デバッグ情報を使用して SDL をビルドし、X11_GL_CreateContext() で失敗した場所を正確に見つけようとすることをお勧めします (または少なくともいくつかの printf を挿入します)。

一方、SDL_GL_CONTEXT_MAJOR_VERSION と SDL_GL_CONTEXT_MINOR_VERSION をデフォルト値のままにしておくと、すでに最大の OpenGL バージョンを取得しています。前方互換性のあるコンテキストが得られないだけです。つまり、将来のバージョンで「エラー」と見なされる動作がすり抜けてしまう可能性があります。

また、一般に、可能な最大バージョンで前方互換性のあるコンテキストを作成することはお勧めできません。たとえば、OpenGL 3.2 では、前方互換性プロファイルによって頂点配列オブジェクトの使用が強制され、VAO を使用していない古いコードが壊れます。そのため、OpenGL 3.1 (またはその他のバージョン) 用に作成されたアプリケーションが可能な限り最新の前方互換性のあるプロファイルを取得しようとすると、実際には将来動作しなくなる可能性があります。これは良い考えではありません。

1 つのオプションは、1 つの前方互換性のあるプロファイルの使用を決定することです。これは、非推奨の機能に関するエラーを報告するため、非常に役立ちます。より多くのバージョンを本当に使用したい場合は、より多くのコード パス (= ゲーム エンジンのより多くのバージョン) が必要です。OpenGL のバージョンを検出するには、ダミーの SDL ウィンドウを作成し、単純な OpenGL プロファイルを初期化し、バージョンを取得してすべてをシャットダウンし、決定したバージョンで再度初期化することをお勧めします。それはうまくいくはずです。

もう 1 つのオプションは、開発にのみ前方互換性プロファイルを使用し、配布には単純なレガシー プロファイルを使用することです。これは最も互換性があり、最小限の労力で済みます (いずれにせよ、リリース バージョンの OpenGL エラーのほとんどを無視する必要があります。ドライバーによってエラー報告が無効になることさえあります)。

于 2012-11-09T11:58:52.313 に答える