2015-01-15 5 views
3

Я стараюсь как можно быстрее отобразить большое количество очень маленьких 2D-квадов на графическом процессоре Apple A7 с использованием Metal API. Исследуя, что количество пропускных чисел треугольника GPU, например. here, и из Apple, цитируя> 1M треугольники на экране во время их основной записи, я ожидал, что смогу отобразить примерно 500 000 таких квадратов на кадр со скоростью 60 кадров в секунду. Возможно, немного меньше, учитывая, что все они видны (на экране, а не скрыты z-буфером) и крошечными (сложными для растеризатора), поэтому это, вероятно, не является прецедентом, для которого GPU отлично оптимизирован. И, возможно, что демонстрация Apple работает со скоростью 30 кадров в секунду, так что скажем, ~ 200 000 должны быть выполнимы. Конечно, 100 000 ... верно?Rendering Quads Performance с металлом

Однако в моем тестовом приложении максимальная скорость составляет всего ~ 20 000 - это больше, а частота кадров падает ниже 60 на iPad Air. С 100 000 квадрациклов он работает со скоростью 14 кадров в секунду, т. Е. При пропускной способности 2,8 М треугольников/сек (сравните это с 68.1M на экране треугольников, цитируемых в статье AnandTech!).

Даже если я сделаю квадрациклы маленькими пикселями с тривиальным шейдером фрагмента, производительность не улучшится. Таким образом, мы можем предположить, что это привязка вершины, и отчет графического процессора в Xcode согласен («Tiler» равен 100%). Вершинный шейдер также тривиальный, ничего не делая, кроме небольшого масштабирования и математики перевода, поэтому я предполагаю, что узким местом является некоторый этап фиксированной функции ...?

Просто для получения дополнительной информации о фон, я обрабатываю всю геометрию с помощью одного вызова с инкриминируемым обратным вызовом с одним квадратом на один экземпляр, т. Е. 4 вершины на экземпляр. Позиции квада применяются из отдельного буфера, который индексируется идентификатором экземпляра в вершинном шейдере. Я также пробовал несколько других методов (без инстансов со всеми предварительно преобразованными вершинами, instanced + indexed и т. Д.), Но это не помогло. Не существует сложных атрибутов вершин, форматов буфера/поверхности или чего-либо еще, о чем я могу думать, что, вероятно, попадет в медленный путь в драйвере/графическом процессоре (хотя я не уверен, конечно). Смешение выключено. Практически все остальное находится в состоянии по умолчанию (такие, как viewport, scissor, ztest, culling и т. Д.).

Приложение написано в Swift, хотя, надеюсь, что не имеет значения)

То, что я пытаюсь понять, является ли производительность, что я вижу, как ожидается, при оказании каре, как это (в отличие от «правильная» трехмерная сцена), или нужны ли какие-то более сложные методы для того, чтобы приблизить ту или иную рекламируемую пропускную способность треугольника. Что думают люди, вероятно, является ограничивающим узким местом здесь?

Кроме того, если кто-нибудь знает, почему это может быть быстрее в OpenGL, чем в Metal (я не пробовал и не могу думать о какой-либо причине), то я бы тоже хотел его услышать.

Thanks

Редактировать: добавление шейдерного кода.

vertex float4 vertex_shader(
     const constant float2* vertex_array [[ buffer(0) ]], 
     const device QuadState* quads [[ buffer(1) ]], 
     constant const Parms& parms [[ buffer(2) ]], 
     unsigned int vid [[ vertex_id ]], 
     unsigned int iid [[ instance_id ]]) 
{ 
    float2 v = vertex_array[vid]*0.5f; 

    v += quads[iid].position; 

    // ortho cam and projection transform 
    v += parms.cam.position; 
    v *= parms.cam.zoom * parms.proj.scaling; 

    return float4(v, 0, 1.0); 
} 


fragment half4 fragment_shader() 
{ 
    return half4(0.773,0.439,0.278,0.4); 
} 
+0

Можете ли вы показать нам макет/дескриптор вершин и ваш шейдерный код? В примере приложения, которое у меня есть, я могу нанести 150 кадров за кадр на iPad mini 2 и> 300ktris/frame на iPhone 6. Мои треугольники имеют средний охват в 2 пикселя. – warrenm

+0

Несомненно, я добавил код шейдера выше. Я явно не устанавливаю вершинную компоновку.Я также заметил, что это очень важно для Tiler, сколько экрана покрыто квадроциклами (я ожидал, что это будет иметь значение для этапа фрагмента, но было удивлено, что это так сильно влияет на этап вершины. эффект кеширования плитки). То есть, концентрируя все квадрациклы в небольшой области экрана, а не равномерно распределяя их по всему месту, улучшается много, а затем я могу ударить> 100k треугольников. Возможно, именно так они достигают> 1M: небольшие объекты с очень высоким количеством три. – lespalt

+0

Да, у tiler это много. Большинство этих крошечных треугольников будут касаться только одной плитки, и чем меньше фрагментов, которые нужно перенести на графический процессор, тем меньше будет накладных расходов на черепицу. FWIW, я не вижу ничего грубейшего в вашем шейдере. – warrenm

ответ

0

Не видя ваш Swift код/​​Objective-C Я не могу быть уверен, но я думаю, вы тратите слишком много времени, призывающую код инстансов. Instancing полезен, когда у вас есть модель с сотнями треугольников, а не для двух.

Попробуйте создать буфер вершин с 1000 квадрациклов в нем и посмотреть, увеличивается ли производительность.

Смежные вопросы