Получение количества фрагментов, прошедших тест глубины

8

В «современных» средах расширение «NV Occlusion Query» предоставляет метод для получения количества фрагментов, прошедших тест глубины. Однако на iPad / iPhone, использующем OpenGL ES, расширение недоступно.

Каков наиболее эффективный подход для реализации аналогичного поведения во фрагментном шейдере?

Некоторые из моих идей:

  • Визуализируйте объект полностью белым, затем подсчитайте все цвета вместе, используя двухпроходный шейдер, где сначала отображается вертикальная линия, и для каждого фрагмента шейдер вычисляет сумму по всей строке. Затем отображается одна вершина, фрагмент которой суммирует все частичные суммы первого прохода. Кажется, не очень эффективно.

  • Сделать объект полностью белым на черном фоне. Рекурсивно уменьшать выборку, используя аппаратную линейную интерполяцию между текстурами, пока разрешение не будет достаточно маленьким. Это приводит к фрагментам, которые имеют уровень оттенков серого в зависимости от количества белых пикселей в соответствующей области. Это даже достаточно точно?

  • Используйте mipmaps и просто читайте пиксель на уровне 1x1. Опять же вопрос точности и возможно ли это даже при использовании текстур не-степени двух.

Проблема этих подходов заключается в том, что конвейер останавливается, что приводит к серьезным проблемам с производительностью. Поэтому я ищу более эффективный способ достичь своей цели.

Использование расширения EXT_OCCLUSION_QUERY_BOOLEAN

Apple представила EXT_OCCLUSION_QUERY_BOOLEAN в iOS 5.0 для iPad 2.

"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 для доступа к количеству пикселей?

Другими расширениями, которые могли бы быть использованы, были бы функции отладки, например, количество вызовов фрагмента шейдера (PSInvocations в DirectX - не уверен, что что-то похожее доступно в OpenGL ES). Однако это также приведет к остановке трубопровода.

Этан
источник
Какого конечного эффекта вы пытаетесь достичь?
Тетрад
Мне нужно количество пикселей не для эффекта рендеринга, а для вычислений. Я хочу использовать его для расчета веса частиц в фильтре частиц.
Этан
Apple поддерживает AMD_performance_monitor? Если да, вы можете найти счетчик, который показывает пройденные пиксели. Обратите внимание, что это очень, очень зависит от устройства, даже если вы заставите его работать.
Яри ​​Комппа
Проблема с AMD_performance_monitor заключается в том, что он не асинхронный, поэтому потеря производительности также будет иметь место, поскольку мне приходится ждать между кадрами, чтобы понять, что вызовы из следующего кадра уже не будут влиять на счетчики производительности.
Этан
Также AMD_performance_monitor недоступен.
Этан

Ответы:

1

Можно ли использовать это расширение, чтобы получить количество пикселей? Поддерживает ли это аппаратное обеспечение, так что может быть скрытый API для доступа к количеству пикселей?

Нет и нет Ну, я предположил, что если вы рисуете серию треугольника размером в один пиксель в пространстве окна, вы можете посчитать, сколько булевых значений вы получите. Но для этого потребуется отдельный запрос для каждого пикселя. Наверное, не самая быстрая вещь в мире.

Если есть «скрытый API», у вас не будет доступа к нему (поскольку он скрыт), поэтому это не имеет значения. Кроме того, характер расширения уже предполагает, что нет. В конце концов, если у оборудования было фактическое количество фрагментов, почему бы просто не предоставить его напрямую, как это делает настольный OpenGL? Если бы оборудование поддерживало это, они могли бы просто взять ARB_occlusion_query и использовать это.

Но они этого не сделали. Что сильно говорит о том, что они не могли.

Николь Болас
источник
Спасибо за ответ! Подход с использованием треугольников размером в один пиксель может быть улучшен простым рендерингом точек или маленьких линий, и его можно даже улучшить с помощью логарифмического масштабирования, где линия, которая возвращает «true», просто разбивается по центру, а затем обе части проверяются снова. Пока не уверен в производительности, так как у моделей не будет более 100-200 вершин. Обоснование отсутствия «скрытого API» также справедливо. Существуют ли другие способы передачи данных из графического процессора обратно в центральный процессор асинхронным способом без остановки конвейера (также, пожалуйста, хакерскими способами)?
Этан
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;
honjj
источник
Просто потому, что тип говорит GLint, не означает, что это целое число числа проходящих фрагментов. Спецификация довольно ясно, что QUERY_RESULT_EXTсостояние является логическим значением; вы просто запрашиваете его как целое число. Это GL_FALSEесли это не удалось, а GL_FALSEесли не прошло.
Никол Болас
Я только что реализовал код и обнаружил, что это просто правда или ложь, и изменил свой ответ, прежде чем я увидел твой комментарий ... так как это предупреждение, возможно, они добавят состояния в будущем, надеюсь.
хондж
кстати, в GKKit, похоже, есть ошибка, когда вы используете self.effect2 = [[GLKBaseEffect alloc] init]; тип кода GLKit, тип кода для визуализации объекта, а не обычный конвейер GLES2.0, запросы не смогут дать вам правильный ответ ... (никогда не скрывается), хотя я тестировал объект конвейера, скрывающий объект GLKBaseEffect, поэтому может быть, есть ошибка, просто смешивая два, я еще не тестировал ...
honjj
Расширения поясняются примерами в видеороликах WWDC, которые можно найти на сайте Apple с активной учетной записью разработчика.
Этан