Перенос памяти из GPU в CPU с помощью синхронизации Vulkan и vkInvalidateMappedMemoryRanges? - PullRequest
1 голос
/ 14 июня 2019

В Vulkan, когда я хочу перенести часть памяти графического процессора обратно в ЦП, я думаю, что наиболее эффективный способ сделать это - записать данные в память с флагами VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT.

Вопрос № 1: это предположение верно?

(Полный список доступных флагов свойств памяти можно найти в документации Vulkan VkMemoryPropertyFlagBits )

Чтобы получить последние данные, я должен сделать недействительной память, используя vkInvalidateMappedMemoryRanges , верно?

Вопрос № 2: Что происходит под капотом во время vkInvalidateMappedMemoryRanges?Это просто memcpy из некоторого внутреннего кэша или это может быть более длительной процедурой?

Вопрос № 3: Если это может занять больше времени (т. Е. Это не просто memcpy), то у меня, вероятно, должна быть возможность синхронизироваться с завершением, верно?Однако vkInvalidateMappedMemoryRanges не предлагает никаких параметров синхронизации.На самом деле, мой вопрос: если я должен синхронизировать это, КАК синхронизировать это?

1 Ответ

3 голосов
/ 14 июня 2019

Вопрос № 1: Это предположение верно?

Возможно, нет, но это зависит от вашей платформы, поддерживаете ли вы альтернативу.Для передачи GPU-> CPU действительно есть три варианта:

1.HOST_VISIBLE

Этот тип видим для хоста и гарантированно является связным, но не кэшируется на хосте.Чтение ЦП будет очень медленным, но это может быть нормально, если вы читаете только небольшой объем данных (и может быть дешевле, чем выдача vkInvalidateMappedMemoryRanges(), и при этом мало места для потоковой передачи данных в кэш ЦПесли вы никогда не ожидаете снова прикоснуться к нему на процессоре).

2.HOST_VISIBLE |HOST_CACHED

Этот тип является видимым для хоста и кэшируется, но не гарантированно будет согласованным (CPU и GPU могут видеть разные вещи по одному и тому же адресу, если вы вручную не применяете согласованность).Для этого типа памяти вы должны использовать vkInvalidateMappedMemoryRanges() после записи в GPU и до чтения ЦП (или vkFlushMappedRange() для другого направления), чтобы один процессор мог видеть то, что написал другой, или вы могли читать устаревшие данные.

3.HOST_VISIBLE |HOST_CACHED |HOST_COHERENT

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

Стоит отметить, что нет «лучших» настроек памяти для всех выделений.Не используйте кэшированную или связную память хоста для вещей, которые вы никогда не собираетесь передавать обратно в ЦП (когерентность памяти не свободна с точки зрения мощности или производительности памяти).

Вопрос № 2: Чтопроисходит под капотом во время vkInvalidateMappedMemoryRanges?Это просто memcpy из некоторого внутреннего кэша или это может быть более длительная процедура?

В случае, когда у вас некогерентная память, она делает все необходимое, чтобы сделать их связными.Как правило, это означает аннулирование (удаление) строк кэша в кэше ЦП, которые могут содержать устаревшие копии данных, гарантируя, что последующие чтения ЦП увидят версию, которую фактически записал графический процессор.

Вопрос № 3:Если это может занять больше времени (т. Е. Это не просто memcpy), то у меня, вероятно, должна быть возможность синхронизироваться с завершением, верно?

Нет.Аннулирование - это операция на стороне ЦП, поэтому для ее завершения требуется время, а ЦП занята, когда операция завершается.В целом вы можете избежать необходимости делать это вообще, используя когерентную память.

...