Как обработать обобщение между семействами очередей в Vulkan для вычислительной работы - PullRequest
0 голосов
/ 11 июня 2019

Я изучаю Vulkan и был заинтересован в создании хорошей многопоточной вычислительной среды.Моя цель - увеличить занятость графического процессора, используя вычислительную очередь на поток.Тем не менее, я работаю над 32-поточным процессором (конечно, нет способа получить 32 очереди вычислений на большинстве графических процессоров).Я остановился на идее добавления этих VkQueues в ... потокобезопасную очередь (TSQ), когда мне требуется VkQueue для работы в одном из потоков, я просто выталкиваю одно из VkQueues из TSQ, выполняюпоместите в него буфер команд и вставьте VkQueue в заднюю часть TSQ.Таким образом, каждый раз, когда потоку требуется VkQueue для выполнения некоторой вычислительной работы, ему будет предоставлена ​​очередь, которая, скорее всего, будет выполнена с его работой.

Однако есть несколько проблем с этим.
Например:
На моем GPU есть 3 семейства очередей
Compute / Graphics (16)
Transfer (1)
Compute (8)
Одна из очередей Compute / Graphics используется для рендеринга, поэтому у меня остается 23 очереди вычислений.

В качестве краткого примечания: алгоритм, который я написал для выбора этих вариантов, выбирает «Вычислить выделенные» семейства до того, как он выбирает «Вычислять / графические семейства».(Если бы у меня было только 4 потока ЦП, он бы выбрал 4 очереди вычислений из третьего семейства очередей)

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

Выполнение этого:
queue = GetQueue ()
cb = GetCommandBuffer (queue.familyIndex)
...
Выполнить тонну работы
...
ExecuteCommandBuffer (очередь, cb)
ReturnQueue (очередь)

Гораздо хуже, чем возможность сделать это:
cb = GetCommandBuffer ()// Уже известно, какой буфер команд нужно получить
...
Выполнить тонну работы
...
queue = GetQueue () // Это означает, что я могу получить и вернуть очередь намного быстрее
ExecuteCommandBuffer (очередь, cb)
ReturnQueue (очередь)

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

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

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

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

Любая помощь приветствуется!:)

...