Vulkan: vkCmdPipelineBarrier для согласованности данных

Мой вопрос состоит из 2 частей:

  1. В чем разница между доступной / видимой памятью?
  2. Я учу Vulkan из этого урока (https://vulkan-tutorial.com) и в настоящее время ищет другой подход для загрузки единообразных данных (простые матрицы модели / вида / проекции) в локальную память устройства. Матрицы используются в вершинном шейдере.

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

    В то время как метод обучения приводит к быстрой анимации, в моем эксперименте эта функция отсутствует. Я попытался установить 2 bufferBarriers, чтобы убедиться, что копии сделаны (что, кажется, проблема), но это не помогло. Ресурсы правильно созданы и связаны — это работает нормально.

    //update uniform buffer and copy it to the staging buffer
    //(called every frame)
    Tools::UniformBufferObject ubo;
    //set the matrices
    void* data;
    data = device.mapMemory( uniformStagingMemory, 0, sizeof( ubo ), (vk::MemoryMapFlagBits) 0 );
    memcpy( data, &ubo, sizeof( ubo ));
    device.unmapMemory( uniformStagingMemory );//once: create a command buffer for each framebuffer of the swapchain
    //queueFamily struct members set properly
    //1st barrier: make transfer from host memory to staging buffer available / visible
    vk::BufferMemoryBarrier bufMemBarrierStaging;
    bufMemBarrierStaging.srcAccessMask = vk::AccessFlagBits::eHostWrite;
    bufMemBarrierStaging.dstAccessMask = vk::AccessFlagBits::eTransferRead;
    bufMemBarrierStaging.buffer = uniformStagingBuffer;
    bufMemBarrierStaging.offset = 0;
    bufMemBarrierStaging.size = sizeof( Tools::UniformBufferObject );
    
    //2nd barrier: make transfer from staging buffer to device local buffer available / visible
    vk::BufferMemoryBarrier bufMemBarrier;
    bufMemBarrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite;
    bufMemBarrier.dstAccessMask = vk::AccessFlagBits::eUniformRead | vk::AccessFlagBits::eShaderRead;
    bufMemBarrier.buffer = dataBuffer;
    bufMemBarrier.offset = dataBufferOffsets[2];
    bufMemBarrier.size = sizeof( Tools::UniformBufferObject );
    
    for( size_t i = 0; i < cmdBuffers.size(); i++ ) {
    //begin command buffer
    
    cmdBuffers[i].pipelineBarrier(
    vk::PipelineStageFlagBits::eHost, //srcPipelineStage
    vk::PipelineStageFlagBits::eTransfer, //dstPipelineStage
    (vk::DependencyFlagBits) 0,
    nullptr, //memBarrier
    bufMemBarrierStaging,
    nullptr //imgBarrier
    );
    vk::BufferCopy copyRegion; //filled appropriate
    cmdBuffers[i].copyBuffer( uniformStagingBuffer, dataBuffer, copyRegion );
    
    cmdBuffers[i].pipelineBarrier(
    vk::PipelineStageFlagBits::eTransfer, //srcPipelineStage
    vk::PipelineStageFlagBits::eVertexShader, //dstPipelineStage
    (vk::DependencyFlagBits) 0,
    nullptr, //memBarrier
    bufMemBarrier,
    nullptr //imgBarrier
    );
    //renderpass stuff and drawing etc.
    }
    

    с

    namespace Tools {
    struct UniformBufferObject {
    glm::mat4 model;
    glm::mat4 view;
    glm::mat4 proj;
    };
    };
    vk::Buffer uniformStagingBuffer;
    vk::DeviceMemory uniformStagingMemory;
    //dataBuffer also contains the vertex and index data, is device local
    vk::Buffer dataBuffer;
    vk::DeviceMemory dataBufferMemory;
    vk::vector<vk::DeviceSize> dataBufferOffsets;
    
    std::vector<vk::CommandBuffer> cmdBuffers;
    

    Я использую vkcpp (https://github.com/KhronosGroup/Vulkan-Hpp).

    Является ли причиной отсутствия анимации отсутствие согласованности данных — и я ошибся, пытаясь добиться этого?

Заранее спасибо!

Редактировать: Проблема части 2 была отсутствующей синхронизацией; промежуточный буфер был (частично) обновлен до того, как был прочитан во время рендеринга кадра. (Спасибо за разъяснение разницы между доступной / видимой памятью).

0

Решение

Если промежуточная буферная память не является хост-когерентной, вам необходимо vkFlushMappedMemoryRanges после memcpy (память может оставаться отображенной). Если вы этого не сделаете, то нет никакой гарантии, что данные действительно видны для GPU.

Первый барьер (хост для передачи) на самом деле не нужен; Существует неявный барьер при отправке.

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

Если упоминание «уничтожения» означает, что вы выделяете для каждого кадра … Сначала вы должны дождаться уничтожения, пока не будут выполнены все использованные буферы команд, во-вторых, не делайте этого. Распределение на стороне GPU стоит дорого, вместо этого предпочтительнее выделить один раз и использовать кольцевой буфер.

0

Другие решения

Объявление 1

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

Вы можете рассматривать это как последовательность состояний:

Ресурс написан src → сделано доступным src → сделано видимым для dst → используется dst,

Целью этого является согласованность кэшей. Спецификация пытается избежать того, чтобы слово «кеш» было более абстрактным.

Вы отвечаете за то, чтобы сделать доступным и видимым. Операции, которые могут сделать что-то из этого, являются барьерами, событиями, согласованной отображаемой памятью или flush а также invalidate и некоторые другие …

AFAIK запланировано переписывание спецификации синхронизации, и номенклатура может измениться.

0

По вопросам рекламы [email protected]