我的代码在我绘制单个对象时起作用,但是当我想在vulkan中绘制多个对象时却得到Unhandled exception at 0x69FD41DC (nvoglv32.dll) in program.exe: Fatal program exit requested.
,我有一个函数可以创建所有必需的二进制顶点数据并将其存储到vertexBuffer对象的向量中,然后在命令缓冲区中,我绑定该矢量的每个顶点缓冲区成员并绘制我的对象。
主要功能如下:-
int main(int argc, char* argv[])
{
windowClass window;
enigma vulkanObject(window.windowHandler);
vulkanObject.loadModel("model/Pig.gltf"); // load first object
vulkanObject.loadModel("model/Duck.gltf"); // load second object
vulkanObject.createDepthResources();
vulkanObject.createRenderPass();
vulkanObject.createGraphicsPipeline();
vulkanObject.createFrameBuffer();
vulkanObject.createCommandBuffers();
vulkanObject.createSemaphores();
auto previousTime = std::chrono::high_resolution_clock::now();
float lag = 0.0f;
while (vulkanObject.running == true)
{
auto currentTime = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(currentTime - previousTime).count() / 1000.0f;
previousTime = currentTime;
lag += elapsed;
vulkanObject.handleEvents();
while (lag >= MS_PER_FRAME)
{
vulkanObject.updateUniformBuffer(vulkanObject.view);
lag -= MS_PER_FRAME;
}
vulkanObject.drawFrame();
}
return 0;
}
我的属性Buffer类:
class attributeBuffer
{
public:
attributeBuffer();
~attributeBuffer();
VkBuffer vertex;
VkBuffer normals;
VkBuffer texCoord;
VkBuffer index;
VkDeviceMemory vertexMem;
VkDeviceMemory normalMem;
VkDeviceMemory texCoordMem;
VkDeviceMemory indexMem;
};
在父类中,我为缓冲区类创建了一个向量,如下所示:
std::vector<attributeBuffer> vertexBuffer;
我将所有数据存储到缓冲区的函数:
void enigma::loadModel(std::string file)
{
gltf stagingModel;
stagingModel.loadAsset(file); // Reads and parses gltf files
model.push_back(std::move(stagingModel));
matrix = matrix * stagingModel.scale;
for (int j = 0; j < stagingModel.mesh.size(); j++)
{
vertexBuffer.push_back(attributeBuffer()); // appends a buffer object to the buffer vector
// the following code creates the required vertex attribute and buffers as well as the binding points
for (int i = 0; i < 2; i++)
{
VkVertexInputAttributeDescription stagingAttrib = {};
stagingAttrib.binding = i;
stagingAttrib.location = i;
stagingAttrib.format = VK_FORMAT_R32G32B32_SFLOAT;
stagingAttrib.offset = 0;
vertexAttributes.push_back(stagingAttrib);
VkVertexInputBindingDescription bindingDescription = {};
bindingDescription.binding = i;
bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
if (i == 0)
{
bindingDescription.stride = stagingModel.mesh[j].position.accessor.componentType * stagingModel.mesh[j].position.accessor.type;
}
else
{
bindingDescription.stride = stagingModel.mesh[j].normal.accessor.componentType * stagingModel.mesh[j].normal.accessor.type;
}
vertexBinding.push_back(bindingDescription);
}
VkDeviceSize bufferSize = 0;
VkDeviceSize bufferStart = 0;
for (int i = 0; i < 2; i++)
{
if (i == 0)
{
bufferSize = stagingModel.mesh[j].position.accessor.count * stagingModel.mesh[j].position.accessor.componentType * stagingModel.mesh[j].position.accessor.type;
bufferStart = stagingModel.mesh[j].position.accessor.accessorByteOffset + stagingModel.mesh[j].position.bufferView.byteOffset;
VkBuffer stagingBuffer;
VkDeviceMemory stagingBufferMemory;
createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory);
void * data;
std::vector<glm::vec3> stagingBin;
stagingBin.resize(stagingModel.mesh[j].position.getVec3Bin(stagingModel.bin).size());
stagingBin = stagingModel.mesh[j].position.getVec3Bin(stagingModel.bin);
vkMapMemory(device, stagingBufferMemory, 0, bufferSize, 0, &data);
memcpy(data, &stagingBin[0], (size_t)bufferSize);
vkUnmapMemory(device, stagingBufferMemory);
createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertexBuffer[j].vertex, vertexBuffer[j].vertexMem);
copyBuffer(stagingBuffer, vertexBuffer[j].vertex, bufferSize);
}
else if (i == 1)
{
bufferSize = stagingModel.mesh[j].normal.accessor.count * stagingModel.mesh[j].normal.accessor.componentType * stagingModel.mesh[j].normal.accessor.type;
bufferStart = stagingModel.mesh[j].normal.accessor.accessorByteOffset + stagingModel.mesh[j].normal.bufferView.byteOffset;
VkBuffer stagingBuffer;
VkDeviceMemory stagingBufferMemory;
createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory);
void * data;
std::vector<glm::vec3> stagingBin;
stagingBin.resize(stagingModel.mesh[j].normal.getVec3Bin(stagingModel.bin).size());
stagingBin = stagingModel.mesh[j].normal.getVec3Bin(stagingModel.bin);
vkMapMemory(device, stagingBufferMemory, 0, bufferSize, 0, &data);
memcpy(data, &stagingBin[0], (size_t)bufferSize);
vkUnmapMemory(device, stagingBufferMemory);
createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertexBuffer[j].normals, vertexBuffer[j].normalMem);
copyBuffer(stagingBuffer, vertexBuffer[j].normals, bufferSize);
}
}
if (stagingModel.mesh[j].indice.accessor.bufferViewIndex != -1)
{
VkBuffer stagingBuffer;
VkDeviceMemory stagingBufferMemory;
VkDeviceSize indexBufferSize = stagingModel.mesh[j].indice.accessor.count * stagingModel.mesh[j].indice.accessor.componentType;
VkDeviceSize indexBufferByteOffset = stagingModel.mesh[j].indice.accessor.accessorByteOffset + stagingModel.mesh[j].indice.bufferView.byteOffset;
createBuffer(indexBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory);
void* data;
vkMapMemory(device, stagingBufferMemory, 0, indexBufferSize, 0, &data);
memcpy(data, &stagingModel.bin[indexBufferByteOffset], (size_t)indexBufferSize);
vkUnmapMemory(device, stagingBufferMemory);
createBuffer(indexBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertexBuffer[j].index, vertexBuffer[j].indexMem);
copyBuffer(stagingBuffer, vertexBuffer[j].index, indexBufferSize);
vkDestroyBuffer(device, stagingBuffer, nullptr);
vkFreeMemory(device, stagingBufferMemory, nullptr);
}
}
}
我的命令缓冲区功能如下:
void enigma::createCommandBuffers()
{
commandBuffers.resize(swapChainFramebuffers.size());
VkCommandBufferAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.commandPool = commandPool;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandBufferCount = (uint32_t)commandBuffers.size();
if (vkAllocateCommandBuffers(device, &allocInfo, commandBuffers.data()) != VK_SUCCESS)
{
throw std::runtime_error("failed to allocate command buffers!");
}
for (size_t i = 0; i < commandBuffers.size(); i++)
{
uint64_t vertexCount = 0;
VkCommandBufferBeginInfo beginInfo = {};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
beginInfo.pInheritanceInfo = nullptr;
vkBeginCommandBuffer(commandBuffers[i], &beginInfo);
VkRenderPassBeginInfo renderPassInfo = {};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassInfo.renderPass = renderPass;
renderPassInfo.framebuffer = swapChainFramebuffers[i];
renderPassInfo.renderArea.offset = { 0, 0 };
renderPassInfo.renderArea.extent = swapChainExtend;
std::vector<VkClearValue> clearValues;
clearValues.resize(2);
clearValues[0].color = { 1.0f, 1.0f, 1.0f , 1.0f };
clearValues[1].depthStencil = { 1.0f, 0 };
renderPassInfo.clearValueCount = clearValues.size();
renderPassInfo.pClearValues = clearValues.data();
vkCmdBeginRenderPass(commandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
VkDeviceSize offsets[] = { 0 };
// the following loop iterates through all objects and records their drawing commands//
for (int x = 0; x < model.size(); x++)
{
for (int count = 0; count < model[x].mesh.size(); count++)
{
if (model[x].isInterleaved)
{
std::cout << "interleaved" << std::endl;
}
else
{
vkCmdBindVertexBuffers(commandBuffers[i], 0, 1, &vertexBuffer[count].vertex, offsets);
vkCmdBindVertexBuffers(commandBuffers[i], 1, 1, &vertexBuffer[count].normals, offsets);
if (model[x].mesh[count].indice.accessor.componentType == 2)
{
vkCmdBindIndexBuffer(commandBuffers[i], vertexBuffer[count].index, 0, VK_INDEX_TYPE_UINT16);
}
else if (model[x].mesh[count].indice.accessor.componentType == 4)
{
vkCmdBindIndexBuffer(commandBuffers[i], vertexBuffer[count].index, 0, VK_INDEX_TYPE_UINT32);
}
}
VkDescriptorSet finalSet = descriptorSet[0];
vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &finalSet, 0, nullptr);
vkCmdDrawIndexed(commandBuffers[i], static_cast<uint32_t>(model[x].mesh[count].indice.accessor.count), 1, 0, 0, 0);
}
}
vkCmdEndRenderPass(commandBuffers[i]);
if (vkEndCommandBuffer(commandBuffers[i]) != VK_SUCCESS)
{
throw std::runtime_error("failed to record command buffer!");
}
}
}
在我的draw函数上抛出了异常,该函数看起来像这样:
void enigma::drawFrame()
{
uint32_t imageIndex;
vkAcquireNextImageKHR(device, swapChain, std::numeric_limits<uint64_t>::max(), imageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
VkSemaphore waitSemaphores[] = { imageAvailableSemaphore };
VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = waitSemaphores;
submitInfo.pWaitDstStageMask = waitStages;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffers[imageIndex];
VkSemaphore signalSemaphores[] = { renderFinishedSemaphore };
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = signalSemaphores;
if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE) != VK_SUCCESS)
{
throw std::runtime_error("failed to submit draw command buffers!");
}
VkPresentInfoKHR presentInfo = {};
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
presentInfo.waitSemaphoreCount = 1;
presentInfo.pWaitSemaphores = signalSemaphores;
VkSwapchainKHR swapChains[] = { swapChain };
presentInfo.swapchainCount = 1;
presentInfo.pSwapchains = swapChains;
presentInfo.pImageIndices = &imageIndex;
presentInfo.pResults = nullptr;
vkQueuePresentKHR(presentQueue, &presentInfo); //the exception is thrown here
}
验证层输出:
validation Layer: Object: VK_NULL_HANDLE (Type = 0) | Duplicate vertex input binding descriptions for binding 0
validation Layer: Object: VK_NULL_HANDLE (Type = 0) | Duplicate vertex input binding descriptions for binding 1
validation Layer: Object: VK_NULL_HANDLE (Type = 0) | Duplicate vertex input binding descriptions for binding 0
validation Layer: Object: VK_NULL_HANDLE (Type = 0) | Duplicate vertex input binding descriptions for binding 1
validation Layer: Object: VK_NULL_HANDLE (Type = 0) | Duplicate vertex input binding descriptions for binding 0
validation Layer: Object: VK_NULL_HANDLE (Type = 0) | Duplicate vertex input binding descriptions for binding 1
validation Layer: Object: VK_NULL_HANDLE (Type = 0) | Duplicate vertex input binding descriptions for binding 0
validation Layer: Object: VK_NULL_HANDLE (Type = 0) | Duplicate vertex input binding descriptions for binding 1
validation Layer: Object: VK_NULL_HANDLE (Type = 0) | fragment shader writes to output location 1 with no matching attachment
validation Layer: Object: 0x58 (Type = 19) | OBJ[0x6f] : CREATE Pipeline object 0x58
validation Layer: Object: 0x59 (Type = 24) | OBJ[0x70] : CREATE Framebuffer object 0x59
validation Layer: Object: 0x5a (Type = 24) | OBJ[0x71] : CREATE Framebuffer object 0x5a
validation Layer: Object: 0x5b (Type = 24) | OBJ[0x72] : CREATE Framebuffer object 0x5b
validation Layer: Object: 0x9b997b8 (Type = 6) | OBJ[0x73] : CREATE VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT object 0x9b997b8
validation Layer: Object: 0x9b3b948 (Type = 6) | OBJ[0x74] : CREATE VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT object 0x9b3b948
validation Layer: Object: 0x9bb1d78 (Type = 6) | OBJ[0x75] : CREATE VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT object 0x9bb1d78
validation Layer: Object: 0x9b997b8 (Type = 6) | The Pipeline State Object (0x58) expects that this Command Buffer's vertex binding Index 2 should be set via vkCmdBindVertexBuffers. This is because VkVertexInputBindingDescription struct at index 10 of pVertexBindingDescriptions has a binding value of 2.
validation Layer: Object: 0x9b997b8 (Type = 6) | The Pipeline State Object (0x58) expects that this Command Buffer's vertex binding Index 2 should be set via vkCmdBindVertexBuffers. This is because VkVertexInputBindingDescription struct at index 10 of pVertexBindingDescriptions has a binding value of 2.
validation Layer: Object: 0x9b997b8 (Type = 6) | The Pipeline State Object (0x58) expects that this Command Buffer's vertex binding Index 2 should be set via vkCmdBindVertexBuffers. This is because VkVertexInputBindingDescription struct at index 10 of pVertexBindingDescriptions has a binding value of 2.
validation Layer: Object: 0x9b997b8 (Type = 6) | The Pipeline State Object (0x58) expects that this Command Buffer's vertex binding Index 2 should be set via vkCmdBindVertexBuffers. This is because VkVertexInputBindingDescription struct at index 10 of pVertexBindingDescriptions has a binding value of 2.
validation Layer: Object: 0x9b997b8 (Type = 6) | The Pipeline State Object (0x58) expects that this Command Buffer's vertex binding Index 2 should be set via vkCmdBindVertexBuffers. This is because VkVertexInputBindingDescription struct at index 10 of pVertexBindingDescriptions has a binding value of 2.
validation Layer: Object: 0x9b3b948 (Type = 6) | The Pipeline State Object (0x58) expects that this Command Buffer's vertex binding Index 2 should be set via vkCmdBindVertexBuffers. This is because VkVertexInputBindingDescription struct at index 10 of pVertexBindingDescriptions has a binding value of 2.
validation Layer: Object: 0x9b3b948 (Type = 6) | The Pipeline State Object (0x58) expects that this Command Buffer's vertex binding Index 2 should be set via vkCmdBindVertexBuffers. This is because VkVertexInputBindingDescription struct at index 10 of pVertexBindingDescriptions has a binding value of 2.
validation Layer: Object: 0x9b3b948 (Type = 6) | The Pipeline State Object (0x58) expects that this Command Buffer's vertex binding Index 2 should be set via vkCmdBindVertexBuffers. This is because VkVertexInputBindingDescription struct at index 10 of pVertexBindingDescriptions has a binding value of 2.
validation Layer: Object: 0x9b3b948 (Type = 6) | The Pipeline State Object (0x58) expects that this Command Buffer's vertex binding Index 2 should be set via vkCmdBindVertexBuffers. This is because VkVertexInputBindingDescription struct at index 10 of pVertexBindingDescriptions has a binding value of 2.
validation Layer: Object: 0x9b3b948 (Type = 6) | The Pipeline State Object (0x58) expects that this Command Buffer's vertex binding Index 2 should be set via vkCmdBindVertexBuffers. This is because VkVertexInputBindingDescription struct at index 10 of pVertexBindingDescriptions has a binding value of 2.
validation Layer: Object: 0x9bb1d78 (Type = 6) | The Pipeline State Object (0x58) expects that this Command Buffer's vertex binding Index 2 should be set via vkCmdBindVertexBuffers. This is because VkVertexInputBindingDescription struct at index 10 of pVertexBindingDescriptions has a binding value of 2.
validation Layer: Object: 0x9bb1d78 (Type = 6) | The Pipeline State Object (0x58) expects that this Command Buffer's vertex binding Index 2 should be set via vkCmdBindVertexBuffers. This is because VkVertexInputBindingDescription struct at index 10 of pVertexBindingDescriptions has a binding value of 2.
validation Layer: Object: 0x9bb1d78 (Type = 6) | The Pipeline State Object (0x58) expects that this Command Buffer's vertex binding Index 2 should be set via vkCmdBindVertexBuffers. This is because VkVertexInputBindingDescription struct at index 10 of pVertexBindingDescriptions has a binding value of 2.
validation Layer: Object: 0x9bb1d78 (Type = 6) | The Pipeline State Object (0x58) expects that this Command Buffer's vertex binding Index 2 should be set via vkCmdBindVertexBuffers. This is because VkVertexInputBindingDescription struct at index 10 of pVertexBindingDescriptions has a binding value of 2.
validation Layer: Object: 0x9bb1d78 (Type = 6) | The Pipeline State Object (0x58) expects that this Command Buffer's vertex binding Index 2 should be set via vkCmdBindVertexBuffers. This is because VkVertexInputBindingDescription struct at index 10 of pVertexBindingDescriptions has a binding value of 2.
validation Layer: Object: 0x5c (Type = 5) | OBJ[0x76] : CREATE Semaphore object 0x5c
validation Layer: Object: 0x5d (Type = 5) | OBJ[0x77] : CREATE Semaphore object 0x5d