Multiple objects each having it's own 3 uniform/vertex/index buffers render fail

I’m learning Vulkan so i expect sophisticated help in this matter, and please forgive me for my English.

I wrote a simple program that doesn’t render anything on the screen, the issue appeared after i introduced multiple objects rendering per frame into my code, so that’s where the bug should probably be lying.

It creates 3 buffers for each mesh/object in my scene, one uniform buffer for storing model and rotation matrices, one vertex buffer and one index buffer and also allocates their corresponding memories in host-visible space:

void VulkanEngine::createBuffers() {
    for (uint16_t uniformBufferIndex = 0; uniformBufferIndex < scene->mNumMeshes * 3; uniformBufferIndex += 3) {
        bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;                                                                             /////////////////////////////////////
        bufferCreateInfo.pNext = nullptr;                                                                                                          ///////////                //////////
        bufferCreateInfo.flags = 0;                                                                                                                ///////////                //////////
        bufferCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;                                                                               /////////// UNIFORM BUFFER //////////
        bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;                                                                                  ///////////                //////////
        bufferCreateInfo.size = totalUniformBufferSize;                                                                                            ///////////                //////////
                                                                                                                                                   /////////////////////////////////////
        assert(vkCreateBuffer(logicalDevices[0], &bufferCreateInfo, &bufferCreationCallbacks, buffers + uniformBufferIndex + 0) == VK_SUCCESS);    /////////////////////////////////////


        bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;                                                                             ////////////////////////////////
        bufferCreateInfo.pNext = nullptr;                                                                                                          ////////               /////////
        bufferCreateInfo.flags = 0;                                                                                                                ////////               /////////
        bufferCreateInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;                                                                                //////// VERTEX BUFFER /////////
        bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;                                                                                  ////////               /////////
        bufferCreateInfo.size = vertexBufferSizes[uniformBufferIndex / 3];                                                                         ////////               /////////
                                                                                                                                                   ////////////////////////////////
        assert(vkCreateBuffer(logicalDevices[0], &bufferCreateInfo, &bufferCreationCallbacks, buffers + uniformBufferIndex + 1) == VK_SUCCESS);    ////////////////////////////////
                                                                                                                                                   ////////////////////////////////
        bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;                                                                             ////////////////////////////////
        bufferCreateInfo.pNext = nullptr;                                                                                                          ////////               /////////
        bufferCreateInfo.flags = 0;                                                                                                                ////////               /////////
        bufferCreateInfo.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT;                                                                                 //////// INDEX BUFFER  /////////
        bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;                                                                                  ////////               /////////
        bufferCreateInfo.size = indexBufferSizes[uniformBufferIndex / 3];                                                                          ////////               /////////
                                                                                                                                                   ////////////////////////////////
        assert(vkCreateBuffer(logicalDevices[0], &bufferCreateInfo, &bufferCreationCallbacks, buffers + uniformBufferIndex + 2) == VK_SUCCESS);    ////////////////////////////////
    }
}
void VulkanEngine::allocateDeviceMemories() {
    VkMemoryAllocateInfo deviceMemoryAllocateInfo;

    for (uint16_t uniformBufferIndex = 0; uniformBufferIndex < scene->mNumMeshes * 3; uniformBufferIndex += 3) {
        deviceMemoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
        deviceMemoryAllocateInfo.pNext = nullptr;
        deviceMemoryAllocateInfo.allocationSize = totalUniformBufferSize;
        deviceMemoryAllocateInfo.memoryTypeIndex = hostVisibleMemoryTypeIndex;

        assert(vkAllocateMemory(logicalDevices[0], &deviceMemoryAllocateInfo, &memoryAllocationCallbacks, bufferMemories + uniformBufferIndex + 0) == VK_SUCCESS);


        deviceMemoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
        deviceMemoryAllocateInfo.pNext = nullptr;
        deviceMemoryAllocateInfo.allocationSize = vertexBufferSizes[uniformBufferIndex / 3];
        deviceMemoryAllocateInfo.memoryTypeIndex = hostVisibleMemoryTypeIndex;

        assert(vkAllocateMemory(logicalDevices[0], &deviceMemoryAllocateInfo, &memoryAllocationCallbacks, bufferMemories + uniformBufferIndex + 1) == VK_SUCCESS);

        deviceMemoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
        deviceMemoryAllocateInfo.pNext = nullptr;
        deviceMemoryAllocateInfo.allocationSize = indexBufferSizes[uniformBufferIndex / 3];
        deviceMemoryAllocateInfo.memoryTypeIndex = hostVisibleMemoryTypeIndex;

        assert(vkAllocateMemory(logicalDevices[0], &deviceMemoryAllocateInfo, &memoryAllocationCallbacks, bufferMemories + uniformBufferIndex + 2) == VK_SUCCESS);
    }
}

The loading of mesh file is done through Assimp library and is expected to be stable:

void VulkanEngine::loadMesh() {
    std::string err;
    Assimp::Importer objImporter;

    scene = objImporter.ReadFile("C:\\1.obj", aiProcess_ConvertToLeftHanded | aiProcess_GenNormals | aiProcess_Triangulate | aiProcess_JoinIdenticalVertices | aiProcess_SortByPType);

    if (scene == NULL || !scene->HasMeshes()) {
        throw VulkanException("Couldn't load obj file: ");
    }
    else {
        std::cout << "OBj File Loaded successfully." << std::endl;
    }

    for (uint16_t meshIndex = 0; meshIndex < scene->mNumMeshes; meshIndex++) {

        uint32_t numVertices = scene->mMeshes[meshIndex]->mNumVertices;
        uint32_t numFaces = scene->mMeshes[meshIndex]->mNumFaces;
        uint32_t numIndices = numFaces * 3; // Triangulated

        for (int i = 0; i < numVertices; i++) {

            attribute tmpAttribute = {};
            memcpy_s(((byte*)&tmpAttribute) + offsetof(attribute, position), 3 * sizeof(float), &((aiVector3D*)(scene->mMeshes[meshIndex]->mVertices))[i].x, 3 * sizeof(float));
            memcpy_s(((byte*)&tmpAttribute) + offsetof(attribute, normal), 3 * sizeof(float), &((aiVector3D*)(scene->mMeshes[meshIndex]->mNormals))[i].x, 3 * sizeof(float));
            memcpy_s(((byte*)&tmpAttribute) + offsetof(attribute, uv), 2 * sizeof(float), &((aiVector3D*)(scene->mMeshes[meshIndex]->mTextureCoords[0]))[i].x, 2 * sizeof(float));

            sortedAttributes[meshIndex].push_back(tmpAttribute);
        }

        for (int i = 0; i < numFaces; i++) {
            for (int j = 0; j < ((aiFace*)(scene->mMeshes[meshIndex]->mFaces))[i].mNumIndices; j++) {
                uint32_t index = ((unsigned int*)(((aiFace*)(scene->mMeshes[meshIndex]->mFaces))[i].mIndices))[j];
                sortedIndices[meshIndex].push_back(index);
            }
        }

        vertexBufferSizes[meshIndex] = sortedAttributes[meshIndex].size() * sizeof(attribute);
        indexBufferSizes[meshIndex] = sortedIndices[meshIndex].size() * 4;
    }
}

Writing to buffers are rather straightforward (aside from the matrix calculations!):

void VulkanEngine::writeBuffers() {
    void *mappedMemory;


    for (uint16_t uniformBufferIndex = 0; uniformBufferIndex < scene->mNumMeshes * 3; uniformBufferIndex += 3) {
        assert(vkMapMemory(logicalDevices[0], bufferMemories[uniformBufferIndex], 0, totalUniformBufferSize, 0, &mappedMemory) == VK_SUCCESS);

        float xRotation = (3.1415926536f / 180.0f) * 180;
        float yRotation = (3.1415926536f / 180.0f) * 90;

        ModelNormalRotation mnr;
        float rotationMatrices[2][16];
        float translationMatrices[2][16];

        rotationMatrices[0][0] = 1.0f;      rotationMatrices[0][4] = 0.0f;          rotationMatrices[0][8] = 0.0f;          rotationMatrices[0][12] = 0.0f;
        rotationMatrices[0][1] = 0.0f;      rotationMatrices[0][5] = cosf(xRotation);   rotationMatrices[0][9] = -sinf(xRotation);  rotationMatrices[0][13] = 0.0f;
        rotationMatrices[0][2] = 0.0f;      rotationMatrices[0][6] = sinf(xRotation);   rotationMatrices[0][10] = cosf(xRotation);  rotationMatrices[0][14] = 0.0f;
        rotationMatrices[0][3] = 0.0f;      rotationMatrices[0][7] = 0.0f;          rotationMatrices[0][11] = 0.0f;         rotationMatrices[0][15] = 1.0f;

        rotationMatrices[1][0] = cosf(yRotation);   rotationMatrices[1][4] = 0.0f;  rotationMatrices[1][8] = sinf(yRotation);   rotationMatrices[1][12] = 0.0f;
        rotationMatrices[1][1] = 0.0f;              rotationMatrices[1][5] = 1.0f;  rotationMatrices[1][9] = 0.0f;              rotationMatrices[1][13] = 0.0f;
        rotationMatrices[1][2] = -sinf(yRotation);  rotationMatrices[1][6] = 0.0f;  rotationMatrices[1][10] = cosf(yRotation);  rotationMatrices[1][14] = 0.0f;
        rotationMatrices[1][3] = 0.0f;              rotationMatrices[1][7] = 0.0f;  rotationMatrices[1][11] = 0.0f;             rotationMatrices[1][15] = 1.0f;

        multiplyMatrix<float>(mnr.model, rotationMatrices[0], rotationMatrices[1]);

        memcpy(mnr.rotation, mnr.model, 16 * sizeof(float));

        memcpy(mappedMemory, &mnr, totalUniformBufferSize);

        memoryFlushRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
        memoryFlushRange.pNext = nullptr;
        memoryFlushRange.size = VK_WHOLE_SIZE;
        memoryFlushRange.offset = 0;
        memoryFlushRange.memory = bufferMemories[uniformBufferIndex];

        assert(vkFlushMappedMemoryRanges(logicalDevices[0], 1, &memoryFlushRange) == VK_SUCCESS);

        vkUnmapMemory(logicalDevices[0], bufferMemories[uniformBufferIndex]);




        assert(vkMapMemory(logicalDevices[0], bufferMemories[uniformBufferIndex + 1], 0, vertexBufferSizes[uniformBufferIndex / 3], 0, &mappedMemory) == VK_SUCCESS);

        memcpy(mappedMemory, sortedAttributes[uniformBufferIndex / 3].data(), vertexBufferSizes[uniformBufferIndex / 3]);

        memoryFlushRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
        memoryFlushRange.pNext = nullptr;
        memoryFlushRange.size = VK_WHOLE_SIZE;
        memoryFlushRange.offset = 0;
        memoryFlushRange.memory = bufferMemories[uniformBufferIndex + 1];

        assert(vkFlushMappedMemoryRanges(logicalDevices[0], 1, &memoryFlushRange) == VK_SUCCESS);

        vkUnmapMemory(logicalDevices[0], bufferMemories[uniformBufferIndex + 1]);




        assert(vkMapMemory(logicalDevices[0], bufferMemories[uniformBufferIndex + 2], 0, indexBufferSizes[uniformBufferIndex / 3], 0, &mappedMemory) == VK_SUCCESS);

        memcpy(mappedMemory, sortedIndices[uniformBufferIndex / 3].data(), indexBufferSizes[uniformBufferIndex / 3]);

        memoryFlushRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
        memoryFlushRange.pNext = nullptr;
        memoryFlushRange.size = VK_WHOLE_SIZE;
        memoryFlushRange.offset = 0;
        memoryFlushRange.memory = bufferMemories[uniformBufferIndex + 2];

        assert(vkFlushMappedMemoryRanges(logicalDevices[0], 1, &memoryFlushRange) == VK_SUCCESS);

        vkUnmapMemory(logicalDevices[0], bufferMemories[uniformBufferIndex + 2]);


    }
}

My render function:

void VulkanEngine::render(uint32_t drawableImageIndex) {
    VkCommandBufferAllocateInfo commandBufferAllocateInfo = {};
    commandBufferAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
    commandBufferAllocateInfo.pNext = nullptr;
    commandBufferAllocateInfo.commandBufferCount = 1;
    commandBufferAllocateInfo.commandPool = renderCommandPool;
    commandBufferAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;


        assert(vkAllocateCommandBuffers(logicalDevices[0], &commandBufferAllocateInfo, &renderCommandBuffer) == VK_SUCCESS);

    VkCommandBufferBeginInfo commandBufferBeginInfo = {};
    commandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
    commandBufferBeginInfo.pInheritanceInfo = nullptr;
    commandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;

    assert(vkBeginCommandBuffer(renderCommandBuffer, &commandBufferBeginInfo) == VK_SUCCESS);


    VkRenderPassBeginInfo renderPassBeginInfo = {};

    VkClearValue clearValues[2];
    clearValues[0].color.float32[0] = 0.1f; //gray clear color
    clearValues[0].color.float32[1] = 0.1f;
    clearValues[0].color.float32[2] = 0.1f;
    clearValues[0].color.float32[3] = 1.0f;

    clearValues[1].depthStencil = { 1.0f, 0 };

    renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
    renderPassBeginInfo.pNext = nullptr;
    renderPassBeginInfo.clearValueCount = 2;
    renderPassBeginInfo.pClearValues = clearValues;
    renderPassBeginInfo.renderArea.extent.width = swapchainCreateInfo.imageExtent.width;
    renderPassBeginInfo.renderArea.extent.height = swapchainCreateInfo.imageExtent.height;
    renderPassBeginInfo.renderArea.offset.x = 0;
    renderPassBeginInfo.renderArea.offset.y = 0;
    renderPassBeginInfo.renderPass = renderPass;
    renderPassBeginInfo.framebuffer = framebuffers[drawableImageIndex];


    vkCmdBeginRenderPass(renderCommandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);

    vkCmdBindPipeline(renderCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);


    for (uint16_t meshIndex = 0; meshIndex < scene->mNumMeshes; meshIndex++) {
        unsigned long milliseconds_since_epoch =
            std::chrono::system_clock::now().time_since_epoch() /
            std::chrono::nanoseconds(1);


        float xRotation = (3.1415926536f / 180.0f) * 180.0f;
        auto yRotation = (3.1415926536 / 180) * (double)milliseconds_since_epoch / 10000000;

        float viewMatrices[2][16];


        viewMatrices[0][0] = 1.0f;  viewMatrices[0][4] = 0.0f;  viewMatrices[0][8] = 0.0f;  viewMatrices[0][12] = 0.00f;    // x translate
        viewMatrices[0][1] = 0.0f;  viewMatrices[0][5] = 1.0f;  viewMatrices[0][9] = 0.0f;  viewMatrices[0][13] = 0.00f;    // y translate
        viewMatrices[0][2] = 0.0f;  viewMatrices[0][6] = 0.0f;  viewMatrices[0][10] = 1.0f; viewMatrices[0][14] = -50.0f;   // z translate
        viewMatrices[0][3] = 0.0f;  viewMatrices[0][7] = 0.0f;  viewMatrices[0][11] = 0.0f; viewMatrices[0][15] = 1.0f;

        viewMatrices[1][0] = cos(yRotation);    viewMatrices[1][4] = 0.0f;  viewMatrices[1][8] = sin(yRotation);    viewMatrices[1][12] = 0.0f;
        viewMatrices[1][1] = 0.0f;              viewMatrices[1][5] = 1.0f;  viewMatrices[1][9] = 0.0f;              viewMatrices[1][13] = 0.0f;
        viewMatrices[1][2] = -sin(yRotation);   viewMatrices[1][6] = 0.0f;  viewMatrices[1][10] = cos(yRotation);   viewMatrices[1][14] = 30.0f;
        viewMatrices[1][3] = 0.0f;              viewMatrices[1][7] = 0.0f;  viewMatrices[1][11] = 0.0f;             viewMatrices[1][15] = 1.0f;

        multiplyMatrix<float>(viewProjection.view, viewMatrices[0], viewMatrices[1]);

        float frameBufferAspectRatio = ((float)swapchainCreateInfo.imageExtent.width) / ((float)swapchainCreateInfo.imageExtent.height);

        calculateProjectionMatrix<float>((float*)viewProjection.projection, (3.1415956536f / 180.0f) * 60.0f, frameBufferAspectRatio, 0.1f, 500.0f); // calculate perspective matrix

        vkCmdPushConstants(renderCommandBuffer, graphicsPipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ViewProjection), &viewProjection);


        VkDescriptorSet graphicsDescriptorSet = createDescriptorSet(meshIndex * 3 + 0);

        vkCmdBindDescriptorSets(renderCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipelineLayout, 0, 1, &graphicsDescriptorSet, 0, nullptr);



        VkDeviceSize offset = 0;

        vkCmdBindVertexBuffers(renderCommandBuffer, 0, 1, buffers + (meshIndex * 3) + 1, &offset);

        vkCmdBindIndexBuffer(renderCommandBuffer, buffers[(meshIndex * 3) + 2], 0, VK_INDEX_TYPE_UINT32);


        vkCmdDrawIndexed(renderCommandBuffer, sortedIndices[meshIndex].size(), 1, 0, 0, 0);
    }

    vkCmdEndRenderPass(renderCommandBuffer);

    assert(vkEndCommandBuffer(renderCommandBuffer) == VK_SUCCESS);

    VkSubmitInfo queueSubmit = {};
    queueSubmit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
    queueSubmit.pNext = nullptr;
    queueSubmit.waitSemaphoreCount = 0;
    queueSubmit.pWaitSemaphores = &waitToDrawSemaphore;
    queueSubmit.pWaitDstStageMask = nullptr;
    queueSubmit.commandBufferCount = 1;
    queueSubmit.pCommandBuffers = &renderCommandBuffer;
    queueSubmit.signalSemaphoreCount = 1;
    queueSubmit.pSignalSemaphores = &drawnSemaphore;

    assert(vkQueueSubmit(queue, 1, &queueSubmit, renderDoneFence) == VK_SUCCESS);

    vkWaitForFences(logicalDevices[0], 1, &renderDoneFence, VK_TRUE, 1000 * 1000000000); // Wait 1000 seconds for fence

    vkResetFences(logicalDevices[0], 1, &renderDoneFence);

    vkResetCommandPool(logicalDevices[0], renderCommandPool, VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT);

    vkResetDescriptorPool(logicalDevices[0], descriptorPool, 0);

    vkDestroySemaphore(logicalDevices[0], waitToDrawSemaphore, nullptr);
    waitToDrawSemaphoreValid = false;
}

Finally, the graphics pipeline, which i create once with no dynamic states:

void VulkanEngine::createGraphicsPipeline() {
    VkPipelineShaderStageCreateInfo stageCreateInfos[2];

    stageCreateInfos[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
    stageCreateInfos[0].pNext = nullptr;
    stageCreateInfos[0].flags = 0;
    stageCreateInfos[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
    stageCreateInfos[0].module = graphicsVertexShaderModule;
    stageCreateInfos[0].pName = u8"main";
    stageCreateInfos[0].pSpecializationInfo = nullptr;

    stageCreateInfos[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
    stageCreateInfos[1].pNext = nullptr;
    stageCreateInfos[1].flags = 0;
    stageCreateInfos[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
    stageCreateInfos[1].module = graphicsFragmentShaderModule;
    stageCreateInfos[1].pName = u8"main";
    stageCreateInfos[1].pSpecializationInfo = nullptr;

    vertexBindingDescription.binding = 0;
    vertexBindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
    vertexBindingDescription.stride = sizeof(attribute);

    vertexAttributeDescriptions[0].binding = 0;
    vertexAttributeDescriptions[0].location = 0;
    vertexAttributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
    vertexAttributeDescriptions[0].offset = offsetof(attribute, position);

    vertexAttributeDescriptions[1].binding = 0;
    vertexAttributeDescriptions[1].location = 1;
    vertexAttributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
    vertexAttributeDescriptions[1].offset = offsetof(attribute, normal);

    vertexAttributeDescriptions[2].binding = 0;
    vertexAttributeDescriptions[2].location = 2;
    vertexAttributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
    vertexAttributeDescriptions[2].offset = offsetof(attribute, uv);

    vertexInputStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
    vertexInputStateCreateInfo.pNext = nullptr;
    vertexInputStateCreateInfo.flags = 0;
    vertexInputStateCreateInfo.vertexBindingDescriptionCount = 1;
    vertexInputStateCreateInfo.pVertexBindingDescriptions = &vertexBindingDescription;
    vertexInputStateCreateInfo.vertexAttributeDescriptionCount = 3;
    vertexInputStateCreateInfo.pVertexAttributeDescriptions = vertexAttributeDescriptions;

    inputAssemblyStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
    inputAssemblyStateCreateInfo.pNext = nullptr;
    inputAssemblyStateCreateInfo.flags = 0;
    inputAssemblyStateCreateInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
    inputAssemblyStateCreateInfo.primitiveRestartEnable = VK_FALSE;

    viewport.width = swapchainCreateInfo.imageExtent.width;
    viewport.height = swapchainCreateInfo.imageExtent.height;
    viewport.x = 0;
    viewport.y = 0;
    viewport.minDepth = 0.0f;
    viewport.maxDepth = 1.0f;

    scissor.offset.x = 0;
    scissor.offset.y = 0;
    scissor.extent.width = viewport.width;
    scissor.extent.height = viewport.height;

    viewportStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
    viewportStateCreateInfo.pNext = nullptr;
    viewportStateCreateInfo.flags = 0;
    viewportStateCreateInfo.viewportCount = 1;
    viewportStateCreateInfo.pViewports = &viewport;
    viewportStateCreateInfo.scissorCount = 1;
    viewportStateCreateInfo.pScissors = &scissor;

    rasterizationStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
    rasterizationStateCreateInfo.pNext = nullptr;
    rasterizationStateCreateInfo.flags = 0;
    rasterizationStateCreateInfo.depthClampEnable = VK_FALSE;
    rasterizationStateCreateInfo.rasterizerDiscardEnable = VK_FALSE;
    rasterizationStateCreateInfo.polygonMode = VK_POLYGON_MODE_FILL;
    rasterizationStateCreateInfo.cullMode = VK_CULL_MODE_NONE; // no back-face/front-face culling!
    rasterizationStateCreateInfo.frontFace = VK_FRONT_FACE_CLOCKWISE;
    rasterizationStateCreateInfo.depthBiasEnable = VK_FALSE;
    rasterizationStateCreateInfo.depthBiasConstantFactor = 0.0f;
    rasterizationStateCreateInfo.depthBiasSlopeFactor = 0.0f;
    rasterizationStateCreateInfo.depthBiasClamp = 0.0f;
    rasterizationStateCreateInfo.lineWidth = 1.0f;


    multisampleStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
    multisampleStateCreateInfo.pNext = nullptr;
    multisampleStateCreateInfo.flags = 0;
    multisampleStateCreateInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
    multisampleStateCreateInfo.sampleShadingEnable = VK_FALSE;
    multisampleStateCreateInfo.pSampleMask = nullptr;

    VkPipelineColorBlendAttachmentState colorBlendAttachmentState = {};
    colorBlendAttachmentState.blendEnable = VK_FALSE;
    colorBlendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
    colorBlendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
    colorBlendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD;
    colorBlendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
    colorBlendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
    colorBlendAttachmentState.alphaBlendOp = VK_BLEND_OP_MAX;
    colorBlendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;

    colorBlendStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
    colorBlendStateCreateInfo.pNext = nullptr;
    colorBlendStateCreateInfo.flags = 0;
    colorBlendStateCreateInfo.logicOpEnable = VK_FALSE;
    colorBlendStateCreateInfo.attachmentCount = 1;
    colorBlendStateCreateInfo.pAttachments = &colorBlendAttachmentState;

    VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo = { };
    depthStencilStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
    depthStencilStateCreateInfo.pNext = nullptr;
    depthStencilStateCreateInfo.flags = 0;
    depthStencilStateCreateInfo.depthTestEnable = VK_TRUE;
    depthStencilStateCreateInfo.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
    depthStencilStateCreateInfo.depthWriteEnable = VK_TRUE;
    depthStencilStateCreateInfo.stencilTestEnable = VK_FALSE;

    graphicsPipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
    graphicsPipelineCreateInfo.pNext = nullptr;
    graphicsPipelineCreateInfo.flags = 0;
    graphicsPipelineCreateInfo.stageCount = 2;
    graphicsPipelineCreateInfo.pStages = stageCreateInfos;
    graphicsPipelineCreateInfo.pVertexInputState = &vertexInputStateCreateInfo;
    graphicsPipelineCreateInfo.pInputAssemblyState = &inputAssemblyStateCreateInfo;
    graphicsPipelineCreateInfo.pTessellationState = nullptr;
    graphicsPipelineCreateInfo.pViewportState = &viewportStateCreateInfo;
    graphicsPipelineCreateInfo.pRasterizationState = &rasterizationStateCreateInfo;
    graphicsPipelineCreateInfo.pMultisampleState = &multisampleStateCreateInfo;
    graphicsPipelineCreateInfo.pDepthStencilState = &depthStencilStateCreateInfo;
    graphicsPipelineCreateInfo.pColorBlendState = &colorBlendStateCreateInfo;
    graphicsPipelineCreateInfo.pDynamicState = nullptr;
    graphicsPipelineCreateInfo.layout = graphicsPipelineLayout;
    graphicsPipelineCreateInfo.renderPass = renderPass;
    graphicsPipelineCreateInfo.subpass = 0;
    graphicsPipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE;
    graphicsPipelineCreateInfo.basePipelineIndex = -1;

    VkResult result = vkCreateGraphicsPipelines(logicalDevices[0], VK_NULL_HANDLE, 1, &graphicsPipelineCreateInfo, nullptr, &graphicsPipeline);

    if (result == VK_SUCCESS)
        std::cout << "Graphics Pipeline created successfully." << std::endl;
    else
        throw VulkanException("Couldn't create graphics pipeline.");
}

I didn’t include the shaders, because I’m almost sure they’re correct, since they were working before I changed my code (as explained before).

P.S.: I don’t get any complaints from validation layers.

Here’s the complete source:
https://github.com/chakmeshma/Vulkan-Test/tree/graphics

The last commit is the commit with this new bug (since its parent commit)

A relevant question is “Does the pipeline need to get updated (either through creating a new pipeline and binding it to the command buffer or updating it’s vertex input dynamic state (if there’s such a thing!)) after updating the current vertex/index bindings between each vkCmdDraw* ?”.