0

my code works when i draw a single object however I get Unhandled exception at 0x69FD41DC (nvoglv32.dll) in program.exe: Fatal program exit requested. while i want to draw multiple objects in vulkan, i have a function that creates and stores all necessary binary vertex data into a vector of vertexBuffer objects, then in the command buffer i bind each vertex buffer member of that vector and draw my object.

main function is as follows:-

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;
}

my attribute Buffer class:

class attributeBuffer
{
public:
    attributeBuffer();
    ~attributeBuffer();

    VkBuffer vertex;
    VkBuffer normals;
    VkBuffer texCoord;
    VkBuffer index;

    VkDeviceMemory vertexMem;
    VkDeviceMemory normalMem;
    VkDeviceMemory texCoordMem;
    VkDeviceMemory indexMem;
};

inside my parent class i created a vector for the buffer class as follows:

    std::vector<attributeBuffer> vertexBuffer;

my function that stores all the data to the buffer:

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);

            }

      }
}

my command buffer function is as follows:

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!");
    }

    }
}

the exception is thrown at my draw function, the function looks like this:

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 output:

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
BulBul
  • 1,159
  • 3
  • 24
  • 37
  • 3
    If you get a crash in the driver then the very first step would be to enable the validation layers. Those will most likely tell you what's leading to the actual driver crashes. So enable validation layers first and if their output doesn't help you locate the problem you may post that here so we can check. – Sascha Willems Aug 04 '18 at 13:57
  • @SaschaWillems i included the last portion of the validation layer messages, i also double checked the line in which the exception thrown it happens right after the `vkQueuePresentKHR` is executed – BulBul Aug 04 '18 at 14:54
  • 4
    There are obvious errors reported by the layers that may cause the driver to bail out after submitting or presenting. So first step would be fixing those. If that doesn't work, then make sure all structs are properly initialized (e.g. no pNext != ullptr where not requested). – Sascha Willems Aug 04 '18 at 17:51
  • 1
    Can you also post the code where you get the address of the vkQueuePresentKHR procedure? – Sascha Willems Aug 04 '18 at 20:37
  • @SaschaWillems I don't have a procedure where i get the address of vkQueuePresentKHR , i only use the addressing procedure during validation layer initialization, i fixed most of the errors reported by the validation layer messages and i also realized that when i load the same model twice i don't get the exception thrown, the difference between the two models is one has textures and the other does not, do you think if i bind a vertex attribute but don't use it will cause the exception to be thrown? – BulBul Aug 05 '18 at 05:22
  • 3
    Binding and not using a vertex attribute in a shader is fine and shouldn't cause the crash, but if one mesh works fine and the other does crash then you may have some uninitlaized struct or member that causes the driver to bail out. Also make sure that everything stays within limits. E.g. number of indices to render. Not initializing something like that may result in values out of bounds. If that doesn't help, try RenderDoc and check all buffers, bindings, etc. – Sascha Willems Aug 05 '18 at 13:35

0 Answers0