我的问题有两部分:
我正在学习本教程中的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 :(得分:0)
如果登台缓冲区内存不是主机一致的,那么在memcpy之后你还需要vkFlushMappedMemoryRanges
(内存可以保持映射)。如果您不这样做,则无法保证数据实际上对gpu可见。
实际上并不需要第一道屏障(主机转移);提交时存在隐含的障碍。
我看到的另一个问题是你有一个临时缓冲区,这意味着你需要等到上一帧完成才能上传新数据。
如果提到&#34;摧毁&#34;意味着你每帧分配...首先你必须等待销毁,直到所有提交的命令缓冲区都完成,第二次不要这样做。 GPU端分配很昂贵,而是更喜欢分配一次并使用环形缓冲区。
答案 1 :(得分:0)
ad 1。
可用和可见是内存依赖的两半。几乎必须要发生它才能成为有效的内存依赖。
您可以将其视为状态序列:
资源由src
编写→由src
提供→dst
可见→dst
使用。
它的目的是缓存的一致性。规范试图避免这个词&#34; cache&#34;更加抽象。
您负责制作并且可见。可以执行其中一些操作的操作是障碍,事件,相干映射内存或flush
和invalidate
以及其他一些......
AFAIK计划进行同步规范重写,命名法可能会改变。