11

私の頂点シェーダーをATIドライバーのOpenGL3.3コアで実行するのに非常に問題がありました。

#version 150

uniform mat4 graph_matrix, view_matrix, proj_matrix;
uniform bool align_origin;

attribute vec2 graph_position;
attribute vec2 screen_position;
attribute vec2 texcoord0;
attribute vec4 color;
varying vec2 texcoord0_px;
varying vec4 color_px;

void main() {
    // Pick the position or the annotation position
    vec2 pos = graph_position;

    // Transform the coordinates
    pos = vec2(graph_matrix * vec4(pos, 0.0, 1.0));

    if( align_origin )
        pos = floor(pos + vec2(0.5, 0.5)) + vec2(0.5, 0.5);

    gl_Position = proj_matrix * view_matrix * vec4(pos + screen_position, 0.0, 1.0);
    texcoord0_px = texcoord0;
    color_px = color;
}

glVertexAttrib4fを使用して色属性を指定し、属性配列をオフにしました。3.3コア仕様の33ページによると、これは機能するはずです。

頂点シェーダーに必要なジェネリック属性に対応する配列が有効になっていない場合、対応する要素は現在のジェネリック属性の状態から取得されます(セクション2.7を参照)。

しかし(ほとんどの場合、プロファイルとドライバーによっては)シェーダーがまったく実行されなかったか、無効な色属性にアクセスした場合は黒を使用していました。定数に置き換えると実行されます。

多くの検索により、WebGLに関するヒントのこのページが得られました。

常に頂点属性0配列を有効にします。頂点属性0配列を無効にして描画する場合、デスクトップOpenGL(Mac OSXなど)で実行しているときに、ブラウザーに複雑なエミュレーションを強制します。これは、デスクトップOpenGLでは、頂点属性0が配列対応でない場合、何も描画されないためです。bindAttribLocation()を使用して頂点属性にロケーション0を使用させ、enableVertexAttribArray()を使用して配列を有効にすることができます。

案の定、色属性がインデックスゼロに割り当てられただけでなく、別の配列対応属性を強制的にゼロにバインドすると、コードが実行され、正しい色が生成されました。

このルールに関する他の言及はどこにも見つかりません。確かにATIハードウェアでは見つかりません。このルールがどこから来ているのか誰か知っていますか?それとも、これはMozillaの人々が気づき、警告した実装のバグですか?

4

1 に答える 1

30

tl; dr:これはドライバーのバグです。Core OpenGL 3.3では、属性0を使用できないようにする必要がありますが、互換性プロファイルでは使用できず、一部のドライバーはそのスイッチを正しく実装していません。問題を回避するために、必ず属性0を使用してください。

実際の内容:

OpenGL仕様がどのようになってきたかについて少し歴史を学びましょう。

OpenGLの最も古い時代には、レンダリングする方法は1つだけでした。それは、即時モード(つまり、:)ですglBegin/glVertex/glColor/glEtc/glEnd。ディスプレイリストは存在しましたが、それらは常に、キャプチャされたコマンドを単に再送信することとして定義されていました。したがって、実装は実際にはこれらの関数呼び出しのすべてを実行しませんでしたが、実装は実行したかのように動作します。

OpenGL 1.1では、クライアント側の頂点配列が仕様に追加されました。ここで覚えておいてください。仕様は、実装ではなく、動作を指定するドキュメントです。したがって、ARBは、クライアント側の配列が、現在の配列ポインターへの適切なアクセスを使用して、即時モード呼び出しを行うのとまったく同じように機能することを単純に定義しました。明らかに、実装は実際にはそれを行いませんが、あたかもそうするかのように動作しました。

バッファオブジェクトベースの頂点配列も同じ方法で定義されましたが、言語はクライアントストレージではなくサーバーストレージから取得することで少し複雑になりました。

次に、何かが起こりました:ARB_vertex_program(ARB_vertex_shaderではありません。アセンブリプログラムについて話しています)。

シェーダーを作成したら、組み込みの属性を使用する代わりに、独自の属性を定義できるようになりたいと考えています。そして、それはすべて理にかなっています。しかし、1つの問題がありました。

イミディエイトモードは次のように機能します。

glBegin(...);
glTexCoord(...);
glColor(...);
glVertex(...);
glTexCoord(...);
glColor(...);
glVertex(...);
glTexCoord(...);
glColor(...);
glVertex(...);
glEnd();

を呼び出すたびglVertexに、これにより、現在のすべての属性状態が単一の頂点に使用されます。他のすべてのイミディエイトモード関数は、コンテキストに値を設定するだけです。この関数は実際に頂点をOpenGLに送信して処理します。これは、即時モードでは非常に重要です。また、すべての頂点は固定関数の土地に位置する必要があるため、この関数を使用して頂点を処理するタイミングを決定することは理にかなっています。

OpenGLの固定関数頂点セマンティクスを使用しなくなると、即時モードで問題が発生します。つまり、実際に頂点を送信するタイミングをどのように決定しますか?

慣例により、これを属性0に固定しました。したがって、すべてのイミディエイトモードレンダリングでは、属性0またはglVertexのいずれかを使用して頂点を送信する必要があります。

ただし、他のすべてのレンダリングは即時モードレンダリングの言語に基づいているため、他のすべてのレンダリングには、即時モードレンダリングと同じ制限があります。イミディエイトモードには属性0またはglVertexが必要であるため、クライアント側の配列なども必要です。彼らにとっては意味がありませんが、仕様が彼らの行動をどのように定義しているかのために彼らはそれを必要としています。

その後、OpenGL3.0が登場しました。彼らは即時モードを廃止しました。非推奨とは、削除されることを意味するものではありません。仕様にはまだそれらの関数が含まれており、すべての頂点配列のレンダリングはそれらに関して定義されていました。

OpenGL3.1は実際に古いものを取り除いた。そして、それは言語の問題を少し引き起こしました。結局のところ、すべての配列描画コマンドは常に即時モードで定義されていました。しかし、イミディエイトモードが存在しなくなったら...どのように定義しますか?

そのため、彼らはコアOpenGL3.1以降の新しい言語を考え出す必要がありました。そうしている間、彼らは属性0を使用する必要があるという無意味な制限を取り除きました。

しかし、互換性プロファイルはそうではありませんでした。

したがって、OpenGL3.2以降のルールはこれです。コアOpenGLプロファイルがある場合は、属性0を使用する必要はありません。互換性のあるOpenGLプロファイルがある場合は、属性0(またはglVertex)を使用する必要があります。それが仕様書に書かれていることです。

しかし、それは実装が実装するものではありません。

一般に、NVIDIAは「属性0を使用する必要がある」というルールをあまり気にせず、互換性プロファイルであっても、期待どおりに実行します。したがって、仕様書に違反しています。AMDは一般的に仕様に固執する可能性が高いです。ただし、コアの動作を正しく実装するのを忘れていました。そのため、NVIDIAは互換性に対して寛容すぎ、AMDはコアに対して制限が強すぎます。

これらのドライバーのバグを回避するには、常に属性0を使用します。

ところで、あなたが疑問に思っているなら、NVIDIAが勝ちました。OpenGL 4.3では、互換性プロファイルは、その配列レンダリングコマンドにコアと同じ表現を使用します。したがって、コアと互換性の両方で属性0を使用することはできません。

于 2012-11-12T18:24:05.223 に答える