Я профилировал программу и обнаружил, что 99% времени тратится на glutSwapBuffers
. Это, конечно, частично из-за ожидания вертикальной синхронизации, но это происходит, когда я использую очень требовательный фрагментный шейдер, который значительно снижает частоту кадров. Это говорит о том, что фрагмент шейдера активируется только где-то в glutSwapBuffers
. Является
это правильно?
Нет. Эта логика совершенно ошибочна. Суть в том, что фрагментный шейдер работает на графическом процессоре , который работает полностью асинхронно с процессором. Вы не измеряете фрагментный шейдер, вы измеряете некоторую неявную синхронизацию CPU-GPU - похоже, ваша реализация синхронизируется при замене буфера (если слишком много кадров поставлено в очередь, вероятно), поэтому все, что вы измеряете, - это время CPU должен ждать GPU. И если вы увеличите рабочую нагрузку на графический процессор без значительного увеличения рабочей нагрузки на процессор, ваш процессор будет просто тратить больше времени на ожидание.
Сам OpenGL не определяет ничего из этого, поэтому все детали в конечном итоге полностью зависят от реализации. Спецификация просто гарантирует, что реализация будет вести себя так, как если бы фрагменты были сгенерированы в том порядке, в котором вы рисуете примитивы (например, при включенном смешивании, действительный порядок становится релевантным сценариям перерасчета еван-ионов). Но в какой момент фрагменты будут сгенерированы, и какие оптимизации могут произойти в промежутке между обработкой вершин и вызовом вашего фрагментного шейдера, полностью вне вашего контроля. Графические процессоры могут использовать схемы растеризации на основе тайлов, где фактическое затенение фрагмента немного задерживается (если это возможно), чтобы повысить эффективность и избежать чрезмерного затенения.
Обратите внимание, что большинство драйверов графического процессора работают полностью асинхронно. Когда вы вызываете команду gl*()
, она возвращается до того, как будет обработана. Он может быть поставлен в очередь только для последующей обработки (например, в другом потоке драйвера) и в конечном итоге будет преобразован в некоторые специфичные для GPU буферы команд, которые передаются в GPU. Вы можете получить неявную синхронизацию CPU-GPU (или CPU-CPU с потоком драйвера), например, когда вы читаете данные кадрового буфера после вызова отрисовки, это будет означать, что все предыдущие команды GL будут сброшены для обработки, и ЦП будет ожидать обработки, прежде чем извлекать данные изображения - и это также делает такие обратные передачи такими медленными.
Как следствие, любые меры на стороне процессора в коде OpenGL совершенно бессмысленны. Вам нужно измерить время на графическом процессоре , и для этого Запросы таймера .