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)