深度テストに合格したフラグメントの数を取得する


8

「モダン」環境では、「NVオクルージョンクエリ」拡張機能により、深度テストに合格したフラグメントの数を取得する方法が提供されます。ただし、OpenGL ESを使用するiPad / iPhoneでは、拡張機能は利用できません。

フラグメントシェーダーで同様の動作を実装するための最もパフォーマンスの高いアプローチは何ですか?

私のアイデアのいくつか:

  • オブジェクトを完全に白でレンダリングし、次に2パスシェーダーを使用してすべての色を一緒にカウントします。最初に垂直線がレンダリングされ、各フラグメントについて、シェーダーは行全体の合計を計算します。次に、フラグメントが最初のパスのすべての部分和を合計した単一の頂点がレンダリングされます。非常に効率的ではないようです。

  • オブジェクトを黒の背景の上に完全に白でレンダリングします。合理的に小さい解像度になるまで、テクスチャ間のハードウェア線形補間を悪用して、再帰的にダウンサンプリングします。これは、対応する領域内の白いピクセルの数に応じてグレースケールレベルを持つフラグメントにつながります。これでも十分正確ですか?

  • ミップマップを使用して、単純に1x1レベルのピクセルを読み取ります。繰り返しになりますが、精度の問題と、2のべき乗ではないテクスチャを使用しても可能かどうかという問題です。

これらのアプローチの問題は、パイプラインが停止し、パフォーマンスに大きな問題が発生することです。したがって、私の目標を達成するためのよりパフォーマンスの高い方法を探しています。

EXT_OCCLUSION_QUERY_BOOLEAN拡張の使用

Apple はiOS 5.0 for iPad 2でEXT_OCCLUSION_QUERY_BOOLEANを導入しました。

"4.1.6  Occlusion Queries

Occlusion queries use query objects to track the number of fragments or 
samples that pass the depth test. An occlusion query can be started and 
finished by calling BeginQueryEXT and EndQueryEXT, respectively, with a 
target of ANY_SAMPLES_PASSED_EXT or ANY_SAMPLES_PASSED_CONSERVATIVE_EXT.

When an occlusion query is started with the target 
ANY_SAMPLES_PASSED_EXT, the samples-boolean state maintained by the GL is
set to FALSE. While that occlusion query is active, the samples-boolean 
state is set to TRUE if any fragment or sample passes the depth test. When 
the occlusion query finishes, the samples-boolean state of FALSE or TRUE is
written to the corresponding query object as the query result value, and 
the query result for that object is marked as available. If the target of 
the query is ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, an implementation may 
choose to use a less precise version of the test which can additionally set
the samples-boolean state to TRUE in some other implementation dependent 
cases."

最初の文は、まさに私が探している振る舞いのヒントです:パフォーマンスを大幅に低下させることなく、深度テストに非同期で合格したピクセル数を取得します。ただし、ドキュメントの残りの部分では、ブール結果を取得する方法についてのみ説明します。

この拡張機能を利用してピクセル数を取得することは可能ですか?ピクセル数にアクセスするための隠しAPIがあるように、ハードウェアはそれをサポートしていますか?

悪用される可能性のあるその他の拡張機能は、フラグメントシェーダーが呼び出された回数などのデバッグ機能です(DirectXのPSInvocations-OpenGL ESで類似のものが利用可能かどうか不明)。ただし、これによりパイプラインがストールすることもあります。


あなたが達成しようとしている最終的な効果は何ですか?
Tetrad

レンダリング効果ではなく計算のためにピクセル数が必要です。パーティクルフィルターでパーティクルのウェイトを計算するために使用したいと思います。
Etan、

アップルはAMD_performance_monitorをサポートしていますか?はいの場合、通過したピクセルを示すカウンターを見つけることができる場合があります。これが機能するようになったとしても、これはデバイス固有のものであることに注意してください。
Jari Komppa、2011年

AMD_performance_monitorの問題は非同期ではないため、次のフレームからの呼び出しがパフォーマンスカウンターに影響を与えないことを確認するためにフレーム間で待機する必要があるため、パフォーマンスの低下も見られます。
Etan、2011年

また、AMD_performance_monitorは使用できません。
Etan、

回答:


1

この拡張機能を利用してピクセル数を取得することは可能ですか?ピクセル数にアクセスするための隠しAPIがあるように、ハードウェアはそれをサポートしていますか?

いいえ、ありません。ええと、ウィンドウスペースに一連の1ピクセルサイズの三角形を描画すると、取得したブール値の数を数えることができると思います。ただし、その場合は1ピクセルごとに個別のクエリが必要になります。おそらく世界で最速のものではありません。

「非表示のAPI」がある場合、(非表示になっているため)アクセスできず、問題ありません。さらに、拡張機能の性質上、存在しないことがすでに示唆されています。結局のところ、ハードウェアに実際のフラグメント数がある場合、デスクトップOpenGLのように直接ハードウェアを公開しないのはなぜですか?ハードウェアがそれをサポートしていれば、ARB_occlusion_queryを取得して使用しただけかもしれません。

しかし、そうではありませんでした。それは彼らができなかったことを強く示唆しています。


答えてくれてありがとう!1ピクセルサイズの三角形を使用したアプローチは、点または小さな線を単にレンダリングすることで改善できます。また、「true」を返す線を単に中央で分割し、両方の部分を再度チェックする対数スケーリングによって改善することもできます。モデルの頂点は100〜200を超えないため、パフォーマンスについてはまだわかりません。「隠されたAPI」が存在しない理由も有効です。パイプラインのストールなしに非同期でGPUからCPUにデータを戻す他の手段はありますか(これもハッキーな方法でお願いします)。
Etan、

0

結果はGLuintで返されます(別の呼び出しではGLintになることもあります)。残念ながら、結果は常に0または1であり、将来的にフラグを登録するように変更する可能性があります。

また、インターネット全体でこれらの新しい拡張機能について投稿した人が一人もいないようです...したがって、ここでは適切に設定されています...私が知る限りどこにも文書化されていません...あなたはそれらがどのように想像することができますここにこの小さなsudoコードからあなたのコードに入ります:

import UIKit/UIKit.h

import GLKit/GLKit.h

import "GLProgram.h"

GLuint testBox,hasBeenTested,theParams;

//...

glGenQueriesEXT(1, &testBox);

glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, testBox);


//... draw an object .......

glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);

glGetQueryObjectuivEXT(testBox, GL_QUERY_RESULT_AVAILABLE_EXT, &hasBeenTested);

if (hasBeenTested) glGetQueryObjectuivEXT(testBox, GL_QUERY_RESULT_EXT, &theParams);

glDeleteQueriesEXT(1, &testBox);

if (!theParams)  object is hidden;  don't draw next time;

型が言うからといっGLintて、それが通過するフラグメントの数の整数カウントであるとは限りません。仕様はQUERY_RESULT_EXT状態がブール値であることを非常に明確にしています。整数としてクエリするだけです。それはGL_FALSE、それが失敗したとされていない場合GL_FALSE、それが渡された場合。
Nicol Bolas

私はコードを実装したばかりで、それが真か偽であることに気づき、あなたのコメントを見る前に私の答えを変更しました。
honjj

ちなみに、GKKitにはバグがあるようです。self.effect2= [[GLKBaseEffect alloc] init];を使用すると、通常のGLES2.0パイプラインではなく、オブジェクトをレンダリングするためのGLKitタイプのコードでは、クエリは正しい答えを提供しません... 2つを混合するだけのバグがある可能性があります。これ以上テストしていません...
honjj

拡張機能は、アクティブな開発者アカウントを持つApplesサイトにあるWWDCビデオの例で説明されています。
Etan、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.