Эффективное объединение нескольких пиксельных шейдеров

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

На данный момент я рисую всю сцену в RenderTarget2D, к которому затем применяю все эффекты. Я храню SortedDictionary, содержащий эффекты и их идентификаторы (идентификаторы используются для изменения параметров во время выполнения), и я перебираю его и применяю каждый эффект один за другим:

foreach(KeyValuePair<Ref<int>,Effect> p in renderEffects)
{
    Effect r = p.Value;
    g.SetRenderTarget(0, MainGame.MainRenderTarget);
    //Change RenderTarget to allow code to grab existing texture in the same draw area.
    levelDraw = MainGame.LevelRenderTarget.GetTexture();
    //Change back to draw back to this texture, allowing render effects to be layered.
    g.SetRenderTarget(0, MainGame.LevelRenderTarget);

    MainGame.StartDraw(MainGame.GameBatch);
    //Starts the sprite batch and sets some parameters
    r.Begin();
    r.CurrentTechnique.Passes[0].Begin();
    MainGame.GameBatch.Draw(levelDraw, new Rectangle(0, 0, levelDraw.Width, levelDraw.Height), Color.White);
    r.CurrentTechnique.Passes[0].End();
    r.End();
    MainGame.GameBatch.End();
}

Теперь это дает заметные просадки кадров при наложении всего 3-х эффектов, а при наложении 10-ти падает с 60FPS до 16FPS, что конечно неприемлемо. Мне интересно, есть ли более эффективный способ сделать это. Учитывая, что у меня есть только одна текстура, я подумал, что смогу объединить эффекты в один файл и выполнить несколько проходов, не забирая текстуру обратно. Однако я не уверен, что это возможно.

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


person Hoeloe    schedule 11.12.2012    source источник
comment
Я отредактировал ваш заголовок. См. Должны ли вопросы включать «теги» в свои заголовки?, если нет единого мнения, не следует.   -  person John Saunders    schedule 11.12.2012
comment
Спасибо за это. Я обычно включаю их, чтобы люди сразу знали, могут они помочь или нет, вместо того, чтобы просматривать теги, но я вижу логику в том, чтобы не использовать их там.   -  person Hoeloe    schedule 11.12.2012
comment
Теги включают в себя механизм лучше, чем смотреть на искаженный заголовок. Вы можете установить избранные теги, которые будут выделять сообщения с этими тегами; и игнорируемые теги, что приведет к скрытию сообщений с этими тегами.   -  person John Saunders    schedule 11.12.2012
comment
О, я знаю, что это лучшая система. Это скорее привычка с разных сайтов, на которых такой системы нет.   -  person Hoeloe    schedule 11.12.2012
comment
Было бы здорово, если бы вы могли узнать, какие этапы самые медленные — применение каждого эффекта, переключение эффектов или что-то среднее между этими действиями. Или, может быть, вы просто используете разрешение Full HD, поэтому оно естественно медленное.   -  person user1306322    schedule 14.12.2012
comment
Я сделал несколько тестов. Применение самих шейдеров снижает скорость с 60 до примерно 50 или 40. Замена RenderTarget, захват текстуры из него, а затем замена ее обратно делает все остальное.   -  person Hoeloe    schedule 16.12.2012


Ответы (2)


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

Вы можете посмотреть статью Шона Харгривза о фрагментах шейдеров в HLSL и код Тима Джонса для выполнения этого в XNA< /а>

person theodox    schedule 30.12.2012
comment
Код Тима Джонса для меня бесполезен, так как он есть в XNA 4, а я использую 3.1. Тем не менее, спасибо за ссылку на эти статьи. - person Hoeloe; 30.12.2012
comment
Для вашего размера задачи вам, возможно, лучше выполнять комбинаторную работу вручную - вы, вероятно, обнаружите, что наложение эффектов затрудняет визуальное расшифровку, а это означает, что сложные версии с несколькими эффектами могут быть оптимизированы, чтобы сделать их дешевле, не отвлекая внимания. от взгляда. - person theodox; 31.12.2012
comment
Это заставило меня задуматься, и я рассматриваю возможность написания синтаксического анализатора и компилятора, чтобы взять список шейдеров HLSL, каждый с определенными параметрами, и поместить их все в один файл. Он будет читать код как строку, а затем преобразовывать код из строковой формы в массив байтов, который можно записать в новый файл эффекта. Я не уверен, сработает ли это, или будет ли это хорошо, но, возможно, стоит попробовать. Я просто не уверен, как получить исходный код в виде строки из файла... - person Hoeloe; 31.12.2012

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

Другими словами, визуализируйте все непрозрачные объекты, обновляя только буфер глубины при первом проходе.

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

РЕДАКТИРОВАТЬ: теперь я понимаю, что OP выполняет полноэкранные эффекты, а не рендеринг сцены.

person doug65536    schedule 22.12.2012
comment
Я применяю шейдеры только к одной текстуре, поэтому не должно быть проблем с буфером глубины, поскольку каждый пиксель отрисовывается только один раз для каждого прохода, и никакие пиксели никогда не будут перерисованы в буфере глубины. - person Hoeloe; 24.12.2012
comment
Я понимаю, что вы имеете в виду, вы просто рекламируете гигантский квадроцикл, чтобы применить серию полноэкранных эффектов, и это то, что является узким местом в производительности? - person doug65536; 24.12.2012
comment
Можно ли отсортировать цикл эффектов, чтобы свести к минимуму изменения состояния? В общем, по удешевлению: шейдерная программа, привязка текстур, привязка буфера, прочее. Возможно, вы сможете избежать изменений состояния, изменив порядок проходов, чтобы свести к минимуму изменения состояния. Буферы вершин и текстуры можно накладывать на более крупные текстуры/большие буферы вершин, чтобы исключить постоянное изменение некоторых состояний. - person doug65536; 24.12.2012
comment
Все мои эффекты представляют собой пиксельные шейдеры, и они должны применяться в определенном порядке для достижения нужного мне эффекта (например, эффект свечения, примененный перед эффектом ряби, даст другой результат, чем эффект ряби, примененный перед свечением). - person Hoeloe; 24.12.2012
comment
Я бы инструмент это. Используйте объект «Секундомер», чтобы измерить наносекунды каждой из линий начала/рисования/конца, и выйдите из системы, чтобы отладить время, чтобы увидеть, какой эффект и/или операция является вашим фактическим узким местом. - person doug65536; 26.12.2012
comment
Возможно, вам придется сбросить пакет или немного реорганизовать цикл (создать другую функцию для целей профилирования производительности), чтобы принудительно завершить работу, чтобы сделать тайминги значимыми. - person doug65536; 26.12.2012
comment
Это может быть очень сложно сказать, так как список, который я повторяю, полностью динамичен (т.е. я постоянно добавляю, удаляю и изменяю эффекты). Кроме того, я запускаю несколько почти идентичных эффектов (эффекты свечения с одинаковой интенсивностью и радиусом, но другим цветом и центральной точкой), так что это не какой-то конкретный эффект, а комбинация многих. В любом случае, когда я смогу (в данный момент я не дома), я проверю каждую команду по очереди и посмотрю, что произойдет. - person Hoeloe; 26.12.2012