I am close to implementing runtime model loading on my own, however I am stuck with the issue of vertex and index buffers being consumed by the command buffer as they are bound to it by vkBindVertexBuffers() and vkBindIndexBuffer(), is there a way to update the vertex and index buffer without recreating it, or am I going towards the wrong path in reloading a scene?
#How would you reload a scene?
80 messages · Page 1 of 1 (latest)
For reloading a scene, you can wait for the GPU to finish using the vertex buffers before updating them. Obviously that'll make you wait for stuff, but it probably won't matter since reloading a scene doesn't happen often.
If you're trying to stream in models dynamically without frame hitches, I think you can still access areas of vertex buffers that aren't currently in use, which works great if you have the "one big vertex buffer" approach. If you're creating vertex buffers per model, you can make a new vertex buffer for the new model, upload stuff to it, and replace it in the next frame when it's ready. The old model can then go on a deletion queue to get deleted and freed when the GPU is done with it.
If you're updating this stuff each frame, then you should just double buffer it.
I got vkDeviceIdle on my reload
is that software or gpu based
nvm it uses the logical device
vkDeviceWaitIdle will wait for the GPU to finish everything.
but i still don't get why i get a validation error from it
You're getting a validation error from the wait idle?
i got this ```cpp
Validation Error: [ VUID-vkDestroyBuffer-buffer-00922 ] Object 0: handle = 0x25b2cf8c990, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0xe4549c11 | Cannot call vkDestroyBuffer on VkBuffer 0xf6d9250000000139[] that is currently in use by a command buffer. The Vulkan spec states: All submitted commands that refer to buffer, either directly or via a VkBufferView, must have completed execution (https://vulkan.lunarg.com/doc/view/1.3.224.1/windows/1.3-extensions/vkspec.html#VUID-vkDestroyBuffer-buffer-00922)
then this ```cpp
Validation Error: [ VUID-vkCmdBindDescriptorSets-pDescriptorSets-01979 ] Object 0: handle = 0x25b2ce96b00, name = FRAME COMMAND BUFFER, type = VK_OBJECT_TYPE_COMMAND_BUFFER; Object 1: handle = 0xb9b24e0000000113, type = VK_OBJECT_TYPE_DESCRIPTOR_SET; Object 2: handle = 0x35643f0000000111, name = DYNAMIC UNIFORM, type = VK_OBJECT_TYPE_BUFFER; | MessageID = 0xa159a763 | vkCmdBindDescriptorSets(): pDynamicOffsets[0] is 0x40 which when added to the buffer descriptor's range (0x40) is greater than the size of the buffer (0x40) in descriptorSet #0 binding #1 descriptor[0]. The Vulkan spec states: For each dynamic uniform or storage buffer binding in pDescriptorSets, the sum of the effective offset and the range of the binding must be less than or equal to the size of the buffer (https://vulkan.lunarg.com/doc/view/1.3.224.1/windows/1.3-extensions/vkspec.html#VUID-vkCmdBindDescriptorSets-pDescriptorSets-01979)
Validation Error: [ VUID-vkCmdDrawIndexed-firstIndex-04932 ] Object 0: handle = 0x2c9fc9000000010f, name = INDEX BUFFER, type = VK_OBJECT_TYPE_BUFFER; | MessageID = 0x20509750 | vkCmdDrawIndexed(): index size (4) * (firstIndex (786801) + indexCount (19188)) + binding offset (0) = an ending offset of 3223956 bytes, which is greater than the index buffer size (3147204). The Vulkan spec states: (indexSize {times} (firstIndex + indexCount) + offset) must be less than or equal to the size of the bound index buffer, with indexSize being based on the type specified by indexType, where the index buffer, indexType, and offset are specified via vkCmdBindIndexBuffer (https://vulkan.lunarg.com/doc/view/1.3.224.1/windows/1.3-extensions/vkspec.html#VUID-vkCmdDrawIndexed-firstIndex-04932)
For the first one, how are you destroying the buffer? What's your code for the scene reload?
that one is related to my viewport resizing which i have not found the root of yet, but the second one is related to my reload scene
which looks like this
void Adren::Renderer::reloadScene(std::vector<Model>& models, Camera* camera) {
/*
This function would be the basis of model loading, as buffers and descriptors get updated
when there is a new model. This is experimental and may be causing lots of performance issues
What this does is re-render the entire screen when new elements are in.
*/
vkDeviceWaitIdle(devices.device);
vmaDestroyBuffer(devices.allocator, buffers.index.buffer, buffers.index.memory);
vmaDestroyBuffer(devices.allocator, buffers.vertex.buffer, buffers.vertex.memory);
vmaUnmapMemory(devices.allocator, buffers.dynamicUniform.memory);
for (const Model::Texture& texture : textures) {
vmaDestroyImage(devices.allocator, texture.image, texture.memory);
vkDestroyImageView(devices.device, texture.view, nullptr);
}
textures.clear();
images.loadTextures(instance, models, textures, processing.commandPool);
buffers.createModelBuffers(models, processing.commandPool);
buffers.createUniformBuffers(swapchain.images, models);
descriptor.createSets(textures, swapchain.images, camera->cam);
}
basically i am destroying the vertex, index and dynamic uniform buffer, destroying the textures and then reloading the textures, recreating the vertex, index, and dynamic uniform buffer while also updating the descriptor sets.
Ok. What does createModelBuffers look like?
void Adren::Buffers::createModelBuffers(std::vector<Model>& models, VkCommandPool& commandPool) {
std::vector<Vertex> vertices;
std::vector<uint32_t> indices;
for (auto& model : models) {
indices.insert(indices.end(), model.indices.begin(), model.indices.end());
vertices.insert(vertices.end(), model.vertices.begin(), model.vertices.end());
}
vertex.size = sizeof(vertices[0]) * vertices.size();
Buffer vStaging;
createBuffer(allocator, vertex.size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, vStaging, VMA_MEMORY_USAGE_AUTO);
vmaMapMemory(allocator, vStaging.memory, &vStaging.mapped);
memcpy(vStaging.mapped, vertices.data(), (size_t)vertex.size);
vmaUnmapMemory(allocator, vStaging.memory);
createBuffer(allocator, vertex.size, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertex, VMA_MEMORY_USAGE_AUTO);
copyBuffer(vStaging.buffer, vertex.buffer, vertex.size, commandPool);
vmaDestroyBuffer(allocator, vStaging.buffer, vStaging.memory);
index.size = sizeof(indices[0]) * indices.size();
Buffer iStaging;
createBuffer(allocator, index.size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, iStaging, VMA_MEMORY_USAGE_AUTO);
vmaMapMemory(allocator, iStaging.memory, &iStaging.mapped);
memcpy(iStaging.mapped, indices.data(), (size_t)index.size);
vmaUnmapMemory(allocator, iStaging.memory);
createBuffer(allocator, index.size, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, index, VMA_MEMORY_USAGE_AUTO);
copyBuffer(iStaging.buffer, index.buffer, index.size, commandPool);
vmaDestroyBuffer(allocator, iStaging.buffer, iStaging.memory);
#ifdef DEBUG
Adren::Tools::label(instance, device, VK_OBJECT_TYPE_BUFFER, (uint64_t)vertex.buffer, "VERTEX BUFFER");
Adren::Tools::label(instance, device, VK_OBJECT_TYPE_BUFFER, (uint64_t)index.buffer, "INDEX BUFFER");
#endif
}
Ok, what's createBuffer and copyBuffer? Trying to get down to the Vulkan calls here.
void Adren::Buffers::copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size, VkCommandPool& commandPool) {
VkCommandBuffer commandBuffer = Adren::Tools::beginSingleTimeCommands(device, commandPool);
VkBufferCopy copyRegion{};
copyRegion.size = size;
vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, 1, ©Region);
Adren::Tools::endSingleTimeCommands(commandBuffer, device, graphicsQueue, commandPool);
}
void Adren::Buffers::createBuffer(VmaAllocator& allocator, VkDeviceSize& size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, Buffer& buffer, VmaMemoryUsage vmaUsage) {
VkBufferCreateInfo bufferInfo{};
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferInfo.size = size;
bufferInfo.usage = usage;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VmaAllocationCreateInfo vmaAllocInfo{};
vmaAllocInfo.usage = vmaUsage;
vmaAllocInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
vmaAllocInfo.preferredFlags = properties;
vmaCreateBuffer(allocator, &bufferInfo, &vmaAllocInfo, &buffer.buffer, &buffer.memory, nullptr);
}
What's the code where the vkCmdDrawIndexed fails?
It seems that for that one you're passing the size of the index buffer as first index.
oh
it appears i may have to update firstindex
cause what i am doing is trying to load this model
with sponza
I already have sponza loaded at start up, i just want to load this one while it is running
Oh, were you still having issues with this?
What are the errors after you fixed the first index thing?
What validation errors are you getting now then?
sorry for the very late response, but I am a bit busy with university, and I kinda messed up my engine again by rewriting a bunch of code. I am currently decoupling a class and putting the function of it in the main renderer class but I am a bit busy to continue working on it.
@hollow kestrel sorry for the delay, but I finally was able to continue working on it and get it running again. However here is the validation errors I get.
Reloading the scene..
Validation Error: [ VUID-vkDestroyBuffer-buffer-00922 ] Object 0: handle = 0x2b10d969de0, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0xe4549c11 | Cannot call vkDestroyBuffer on VkBuffer 0x2c9fc9000000010f[INDEX BUFFER] that is currently in use by a command buffer. The Vulkan spec states: All submitted commands that refer to buffer, either directly or via a VkBufferView, must have completed execution (https://vulkan.lunarg.com/doc/view/1.3.224.1/windows/1.3-extensions/vkspec.html#VUID-vkDestroyBuffer-buffer-00922)
Index buffer destroyed..
Validation Error: [ VUID-vkDestroyBuffer-buffer-00922 ] Object 0: handle = 0x2b10d969de0, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0xe4549c11 | Cannot call vkDestroyBuffer on VkBuffer 0x4d6d9a000000010c[VERTEX BUFFER] that is currently in use by a command buffer. The Vulkan spec states: All submitted commands that refer to buffer, either directly or via a VkBufferView, must have completed execution (https://vulkan.lunarg.com/doc/view/1.3.224.1/windows/1.3-extensions/vkspec.html#VUID-vkDestroyBuffer-buffer-00922)
Vertex buffer destroyed..
Dynamic uniform buffer destroyed..
Validation Error: [ VUID-vkDestroyImage-image-01000 ] Object 0: handle = 0x2b10d969de0, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0xf2d29b5a | Cannot call vkDestroyImage on VkImage 0x301e6c0000000022[TEXTURE IMAGE] that is currently in use by a command buffer. The Vulkan spec states: All submitted commands that refer to image, either directly or via a VkImageView, must have completed execution (https://vulkan.lunarg.com/doc/view/1.3.224.1/windows/1.3-extensions/vkspec.html#VUID-vkDestroyImage-image-01000)
Textures destroyed..
So somehow vkdevicewaitidle was no longer in the function so all these errors are gone
but i still have a memory issue
where it tries to map the textures but fails even though the previous textures are already deallocated
Ok, so you just needed the wait idle in there and it works now?
What do you mean fails? What's the error?
visual studio just stops it during the part where i am copying the image data to a memory buffer
Stops it how? Does it hit a segfault, freeze, break?
What's the code around the image data copying?
it just crashes after i press import model then picked a file. Doing that adds it to my model vector and then I have a object counter that an if statement is checking if the model vector's size is greater than it, if so then the object counter gets updated and then reloadScene() is called, it manages to destroy everything but the error comes from re-creating it.
I'm still not really sure what sort of crash this is. Does it segfault or hit a debug assert or validation error or what? Would you post the code for recreating your images and show the part that actually crashes?
Alright
Ok, so it segfaults trying to read image data. Make sure that image actually exists before using it.
Have you got this code on github by any chance? It would be much easier to debug if I could see the code leading up to this.
I do have it on github but i have the bad habit of not committing so I am going to do that now
the textures are loaded in images
i was gonna decouple it but forgot to 🤦
anyways this is the model i was trying to load in
Ok, I've looked at the code for a while. While I haven't checked to make sure, I'd be worried about this code in Model::getTextures. If the model gets copied, I think the the GLTF vector might change while the pointer into it doesn't. I could be missing something though, like I said, I haven't actually tested.
hmm
The sponza one would have worked because that one stays in the class and still exists, but anything loaded with the model load method allocates a model on the stack first.
You could take the address from the image data vector every time you copy from it. You could also take it again in a copy constructor/assignment. You could also implement a move constructor/assignment and use that when putting the model in the vector (though I'm not sure if the vector data is guaranteed to be the same after a move).
Whatever you do, the pointer has to actually point to the texture memory when you copy it to the staging buffer.
I made it a pointer but still getting the same error.
What if I made the model itself a pointer?
alright that solved the image issue but now i have this
VULKAN ERROR FOR ALLOCATED DESCRIPTOR SETS: -1000069000
which is VK_ERROR_OUT_OF_POOL_MEMORY = -1000069000
how do i allocate more
so i made my descriptor pool have 100,000 size
and set the max sets to 200
now i get this kaleidoscope
At least I am not crashing
Yeah, I've had lots of those when screwing up my vertex data or vertex formats.
I rooted the problem to textures, according to render doc the vertices and indices have loaded properly
Why would textures cause the geometry to go crazy like that?