Я провел некоторое профилирование и обнаружил, что vkEndCommandBuffer выполняет большую работу на Android (25% времени потока рендеринга в моем приложении). Самым странным для меня является то, что он делает огромные memcpy (20% времени потока рендеринга).
Я пробовал разные флаги в буфере команд и пуле командных буферов, а также пытался сбросить буфер команд неявно и явно, но ничего не помогло. Я обнаружил, что vkEndCommandBuffer работает быстрее, если я отключаю MSAA. Но это не имеет смысла для меня.
Стек:
- qglinternal :: vkEndCommandBuffer
- QglCommandBuffer :: End
- A5xCommandBuffer :: HwProcessWorkload
- memcpy
Почему это так медленно? И что это делает? Есть идеи?
UPD: я тестировал свое приложение на 5 устройствах. Приложение выполняет 200-400 вызовов на каждый кадр:
- Xiaomi MiA1. Android 7.1. Adreno 506. Версия драйвера: 55.277.3829 (по данным Vulkan Caps Viewer). 30 кадров в секунду. В vkEndCommandBuffer нет memcpy, но он по-прежнему занимает 5% времени рендеринга.
- Xiaomi MiA2 Lite. Android 9,0. Adreno 506. Версия драйвера: 512.331.0. 20-25 кадров в секунду. Огромный memcpy, vkEndCommandBuffer занимает 25,6% времени рендеринга потока.
- Яндекс YNDX-000SB. Android 8.1. Adreno 508. Версия драйвера: 14.307.2170. 30 кадров в секунду. Огромный memcpy, vkEndCommandBuffer занимает 22,7% времени рендеринга потока.
- Google Pixel 2 XL. Android 10.0. Adreno 540. Версия драйвера: 512.385.0. 60 кадров в секунду (но это дорогое устройство). Огромный memcpy, но vkEndCommandBuffer занимает всего 5,8% времени рендеринга потока.
- Samsung Galaxy J7. Android 8.1. Mali-T830. 45-50 кадров в секунду. vkEndCommandBuffer занимает только 0,2% времени рендеринга.
Также я заметил следующее:
- все устройства с Adreno выполняют большую работу в DrawIndexed. Они вызывают огромный memset (wtf?);
- все устройства с Adreno не используют командные буферы. Они всегда освобождают все ресурсы буфера команд (даже если я использую неявный сброс). Это занимает около 2-5% времени рендеринга в зависимости от устройства.