Как использовать std :: vector <char>вместо void ** при отображении памяти с помощью Vulkan? - PullRequest
1 голос
/ 12 января 2020

Я пытался максимально удалить любой raw и unique_ptr из пользовательского игрового движка. Используемый API - Vulkan. И на данный момент одним из самых простых решений для всех данных Vulkan является использование простого std::vector<char>.

Но это одна точка, которую я не могу понять, это когда я сопоставляю свою память с LogicalDevice.

Чтобы отобразить свою память, я использую эту функцию:

void Buffer::MapMemory(char** data) const {
    CheckVk(vkMapMemory(kLogicalDevice_, GetBufferMemory(), 0, size_, 0, reinterpret_cast<void**>(data)));
}
  • CheckVk - это функция * stati c, которая обрабатывает все мои VkResults
  • В этом примере я пытался скрыть void** и использовал char** вместо

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

void UniformBuffer::Update(const std::vector<char>& newData) const {
    char* data;
    MapMemory(&data);
    std::memcpy(data, newData.data(), static_cast<std::size_t>(size_));
    UnmapMemory();
}

Простая функция, когда я отображаю данные в графический процессор , напишите на нем, затем распакуйте его.

I wi sh, чтобы удалить символ * и заменить его на std::vector<char>.


Что До сих пор я тестировал:

void UniformBuffer::Update(const std::vector<char>& newData) const {
    std::vector<char> data;
    MapMemory(reinterpret_cast<char**>(data.data()));
    std::memcpy(data.data(), newData.data(), static_cast<std::size_t>(size_));
    UnmapMemory();
}

Программа компилируется, но данные, похоже, не отображаются, потому что на GPU ничего не написано. (Я даже посмотрел с RenderDo c и, похоже, ничего не отправлено в GPU).

1 Ответ

1 голос
/ 12 января 2020

I sh, чтобы удалить char* и заменить его на std::vector<char>.

Это хорошо. Но этого не произойдет.

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

Также сопоставьте весь блок памяти, поскольку любое выделение памяти может только быть нанесенным на карту один раз. И вы, несомненно, уже знаете, не вызывать vkAllocateMemory для каждого отдельного отдельного буфера, который вы хотите создать.

Во-вторых, отображение памяти означает, что устройство Vulkan делает память доступной для ЦП для чтение / запись (на основе операции отображения). Вы не владеете этой памятью; устройство Vulkan владеет им. Он просто делится этим указателем с вами.

vector владеет памятью, которую он выделяет. Он выделяет его и удаляет его через указанный пользователем тип распределителя.

Теперь вы можете подумать, что вы можете просто создать vector<char, MappedAllocator<char>>, где MappedAllocator - это некоторый объект распределителя, который «выделяет» его память из сопоставленного указателя. Но это не сработает. Видите ли, распределитель выделяет память, но vector - это тот, кто решает , сколько памяти выделять и когда выделять.

Не имея возможности контролировать, сколько памяти vector может попытаться выделить, на самом деле не существует эффективного способа записать распределитель в статический c буфер памяти.

Если вы просто хотите отслеживать размер отображаемого хранилища, он было бы лучше использовать что-то вроде gsl::span<char>. Но в противном случае, просто указатель и делать указатель-у вещи. Не стоит пытаться написать собственную версию vector только для этого.

...