0

OpenGLフレームバッファ処理を単純な「このテクスチャを「レンダリングターゲット」として設定する」呼び出しに抽象化するC#(SharpGL風)コードがあります。テクスチャが最初にレンダー ターゲットとして設定されるとき、そのサイズのテクスチャに一致する深度バッファを持つ FBO を作成します。その FBO/深度バッファ コンボは、同じサイズのすべてのテクスチャに再利用されます。

次のような奇妙なエラーがあります。

最初はアプリが実行され、正常にレンダリングされます。しかし、ウィンドウ サイズを大きくすると、一部のコードで「レンダー ターゲット」テクスチャのサイズを変更する必要が生じる可能性があります。これは、glDeleteTextures() および glGenTextures() を介して行われます (バインド、glTexImage2D、および texparams により、MIN_FILTER と MAG_FILTER は両方とも GL_NEAREST になります)。 )。そうするときに同じ名前 (ID) を取得する傾向があることに気付きました (GL は解放されたばかりの名前を再利用するため)。

次に、次のコードを実行します (わずかに粗悪な GL ライクな構文をお詫びします)。

    void SetRenderTarget(Texture texture)
    {
        if (texture != null)
        {
            var size = (texture.Width << 16) | texture.Height;
            FrameBufferInfo info;
            if (!_mapSizeToFrameBufferInfo.TryGetValue(size, out info))
            {
                info = new FrameBufferInfo();
                info.Width = texture.Width;
                info.Height = texture.Height;

                GL.GenFramebuffersEXT(1, _buffer);
                info.FrameBuffer = _buffer[0];

                GL.BindFramebufferEXT(GL.FRAMEBUFFER_EXT, info.FrameBuffer);
                GL.FramebufferTexture2DEXT(GL.FRAMEBUFFER_EXT, GL.COLOR_ATTACHMENT0_EXT, GL.TEXTURE_2D, texture.InternalID, 0);

                GL.GenRenderbuffersEXT(1, _buffer);
                info.DepthBuffer = _buffer[0];
                GL.BindRenderBufferEXT(GL.RENDERBUFFER_EXT, info.DepthBuffer);
                GL.RenderbufferStorageEXT(GL.RENDERBUFFER_EXT, GL.DEPTH_COMPONENT16, texture.Width, texture.Height);
                GL.BindRenderBufferEXT(GL.RENDERBUFFER_EXT, 0);
                GL.FramebufferRenderbufferEXT(GL.FRAMEBUFFER_EXT, GL.DEPTH_ATTACHMENT_EXT, GL.RENDERBUFFER_EXT, info.DepthBuffer);
                _mapSizeToFrameBufferInfo.Add(size, info);
            }
            else
            {
                GL.BindFramebufferEXT(GL.FRAMEBUFFER_EXT, info.FrameBuffer);
                GL.FramebufferTexture2DEXT(GL.FRAMEBUFFER_EXT, GL.COLOR_ATTACHMENT0_EXT, GL.TEXTURE_2D, texture.InternalID, 0);
            }
            GL.CheckFrameBufferStatus(GL.FRAMEBUFFER_EXT);
        }
        else
        {
            GL.FramebufferTexture2DEXT(GL.FRAMEBUFFER_EXT, GL.COLOR_ATTACHMENT0_EXT, GL.TEXTURE_2D, 0, 0);
            GL.BindFramebufferEXT(GL.FRAMEBUFFER_EXT, 0);
        }

        ProjectStandardOrthographic();
    }

上記のウィンドウのサイズ変更後、GL は glFramebufferTexture2DEXT() 呼び出しから GL_INVALID_VALUE エラーを返します (glGetError() および gDEBugger で識別されます)。これを無視すると、glCheckFrameBufferStatus() は後で GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT で失敗します。これも無視すると、「framebuffer to dobious to do anything」エラーを確認すると、予想されるエラーが表示され、確認しないと黒い画面が表示されます。

NVidia GeForce GTX 550 Ti、Vista 64 (32 ビット アプリ)、306.97 ドライバーで実行しています。Core プロファイルで GL 3.3 を使用しています。

回避策と好奇心:テクスチャを再配置するときに、glDeleteTextures() の前に glGenTextures() を実行すると、同じ ID が返されないようにするために、問題が解決します。これは愚かなクルーゲであり、メモリ不足エラーの可能性を高めるため、これを行いたくありません。GLが最近のFBOでテクスチャを使用していた/使用していて、テクスチャIDが使用されているか、何らかの形で無効になっているため、受け入れられないと判断したためだと理論付けていますか? 多分?

問題の後、gDEBugger は、両方の FBO (深度バッファーと以前のテクスチャが小さい元のものと、組み合わせが大きい新しいもの) に同じテクスチャ ID が添付されていることを示しています。

割り当てを解除する前に、(再び glFramebufferTexture2DEXT を介して) フレーム バッファからテクスチャを切り離そうとしましたが、役に立ちませんでした (gDEBuffer は変更を反映しますが、問題は引き続き発生します)。深度バッファを完全に取り出してみました。使用する前に glGetTexLevelParameter() でテクスチャ サイズを確認してみました。それは確かに存在します。

4

1 に答える 1

1

これは、NVIDIA の OpenGL 実装のバグのようです。オブジェクト名を削除すると、そのオブジェクト名は無効になるためglGen*、返される正当な候補となるはずです。

問題を再現する最小限のケースで、バグ レポートを提出する必要があります。

これは愚かなクルーゲであり、メモリ不足エラーの可能性を高めるため、これを行いたくありません。

いいえ、そうではありません。テクスチャ用のストレージglGenTexturesを割り当てません(実際の OOM エラーはここから発生する可能性があります)。テクスチャ名のみを作成します。回避策を使用しなければならないのは残念ですが、それは本当の問題ではありません。

于 2012-11-29T20:06:30.563 に答える