I have a problem with Vulkan. I want to render two copies of the same cube so I translate them to a different position as I show in the function VulkanRenderer::initUniformBuffer()
. But I can only see the first cube. I have no idea what I am doing wrong. I tried to change the offset in vkCmdBindDescriptorSets()
but it did not change anything. Maybe something is wrong with my descriptors? Or I missed to set something else.
I have two uniform buffers (one per mesh), one command buffer, one pipeline and one renderpass. Here is my render loop:
bool VulkanRenderer::Run() {
InitSemaphore(&_semaphoreA);
if(_window != nullptr) {
_window->UpdateWindow();
auto res = VK_SUCCESS;
InitRenderPass(_imageKHRindex);
vkCmdBindPipeline(_commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, GetPipeline());
const VkDeviceSize offsets [1] = { 0 };
VkMemoryRequirements memoryRequirements;
vkGetBufferMemoryRequirements(_deviceHandler, _uniformDataBuffer, &memoryRequirements);
VkMemoryAllocateInfo memoryAllocatorInfo {};
memoryAllocatorInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
memoryAllocatorInfo.allocationSize = memoryRequirements.size;
uint32_t memoryTypeCount = _memoryProperties.memoryTypeCount;
for(uint32_t i = 0; i < memoryTypeCount; ++i) {
if((memoryRequirements.memoryTypeBits & 1) == 1) {
if((_memoryProperties.memoryTypes [i].propertyFlags &
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) {
memoryAllocatorInfo.memoryTypeIndex = i;
}
}
memoryRequirements.memoryTypeBits >>= 1;
}
vkCmdBindVertexBuffers(_commandBuffer, 0, 1, &_vertexBuffer, offsets);
vkCmdSetViewport(_commandBuffer, 0, 1, &_viewport);
VkRect2D rect2d;
rect2d.extent.width = _winWidth;
rect2d.extent.height = _winHeight;
rect2d.offset.x = 0;
rect2d.offset.y = 0;
vkCmdSetScissor(_commandBuffer, 0, 1, &rect2d);
for(int i = 0; i < 2; i++) {
const uint32_t offset = i * sizeof(_mvp);
vkCmdBindDescriptorSets(_commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, GetPipelineLayout(),
0, 1, _descriptorSets.data(), 0, 0);
vkCmdDraw(_commandBuffer, vertices.size(), 2, 0, 0);
}
vkCmdEndRenderPass(_commandBuffer);
prePresentBarrier.image = GetSwapchainImage() [_imageKHRindex];
vkCmdPipelineBarrier(_commandBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1, &prePresentBarrier);
const VkCommandBuffer cmdBufs [] = { _commandBuffer };
VkPipelineStageFlags pipelineStageFlags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
vkResetFences(_deviceHandler, 1, &_drawFence);
VkSubmitInfo submitInfo [1] = {};
submitInfo [0].pNext = NULL;
submitInfo [0].sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo [0].waitSemaphoreCount = 1;
submitInfo [0].pWaitSemaphores = &_semaphoreA;
submitInfo [0].pWaitDstStageMask = &pipelineStageFlags;
submitInfo [0].commandBufferCount = 1;
submitInfo [0].pCommandBuffers = cmdBufs;
submitInfo [0].signalSemaphoreCount = 0;
submitInfo [0].pSignalSemaphores = NULL;
ErrorCheck(vkEndCommandBuffer(_commandBuffer));
ErrorCheck(vkQueueSubmit(_queue, 1, submitInfo, _drawFence));
VkPresentInfoKHR present {};
present.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
present.swapchainCount = 1;
present.pSwapchains = pGetVulcanSwapchainKHR();
present.pImageIndices = &_imageKHRindex;
do {
res = vkWaitForFences(_deviceHandler, 1, &_drawFence, VK_TRUE, UINT64_MAX);
} while(res == VK_TIMEOUT);
assert(res == VK_SUCCESS);
ErrorCheck(vkQueuePresentKHR(_queue, &present));
ExecuteBeginCommandBuffer();
return _window->isOpened();
}
ExecuteBeginCommandBuffer();
return true;
}
and the initUniformBuffer()
function:
void VulkanRenderer::initUniformBuffer() {
float fov = glm::radians(45.0f);
if(_winWidth > _winHeight) {
fov *= static_cast<float>(_winHeight) / static_cast<float>(_winWidth);
}
_projection = glm::perspective(fov, static_cast<float>(_winWidth) / static_cast<float>(_winHeight), 0.1f, 100.0f);
vulkanCamera.cameraPosition = glm::vec3(5, 3, 10);
_view = glm::lookAt(vulkanCamera.cameraPosition,//Camera Position,
glm::vec3(0, 0, 0), // look at
glm::vec3(0, -1, 0) /*head up */);
_model = glm::mat4(1.0f);
// Vulkan clip space has inverted Y and half Z.
_clip = glm::mat4(1.0f, 0.0f, 0.0f, 0.0f,
0.0f, -1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.5f, 0.0f,
0.0f, 0.0f, 0.5f, 1.0f);
_mvp = _clip * _projection * _view * _model;
_model = glm::translate(_model, glm::vec3(4, 4, 4));
glm::mat4 mvp2 = _clip * _projection * _view * _model;
//Create uniform buffer
VkBufferCreateInfo uniformBufferCreateInfo {};
uniformBufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
uniformBufferCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
uniformBufferCreateInfo.size = sizeof(_mvp) * 2;
uniformBufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
uniformBufferCreateInfo.flags = 0;
ErrorCheck(vkCreateBuffer(_deviceHandler, &uniformBufferCreateInfo, NULL, &_uniformDataBuffer));
VkMemoryAllocateInfo memoryAllocatorInfo {};
memoryAllocatorInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
VkMemoryRequirements memoryRequirements;
vkGetBufferMemoryRequirements(_deviceHandler, _uniformDataBuffer, &memoryRequirements);
memoryAllocatorInfo.allocationSize = memoryRequirements.size;
uint32_t memoryTypeCount = _memoryProperties.memoryTypeCount;
for(uint32_t i = 0; i < memoryTypeCount; ++i) {
if((memoryRequirements.memoryTypeBits & 1) == 1) {
if((_memoryProperties.memoryTypes [i].propertyFlags &
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) {
memoryAllocatorInfo.memoryTypeIndex = i;
}
}
memoryRequirements.memoryTypeBits >>= 1;
}
ErrorCheck(vkAllocateMemory(_deviceHandler, &memoryAllocatorInfo, nullptr, &_uniformBufferMemory));
uint8_t *pData;
ErrorCheck(vkMapMemory(_deviceHandler, _uniformBufferMemory, 0, memoryRequirements.size, 0, (void **) &pData));
memcpy(pData, &mvp2, sizeof(_mvp));
memcpy(pData + sizeof(_mvp), &_mvp, sizeof(_mvp));
vkUnmapMemory(_deviceHandler, _uniformBufferMemory);
ErrorCheck(vkBindBufferMemory(_deviceHandler, _uniformDataBuffer, _uniformBufferMemory, 0));
_uniformDescriptorInfo.buffer = _uniformDataBuffer;
_uniformDescriptorInfo.offset = 0;
_uniformDescriptorInfo.range = VK_WHOLE_SIZE;
}
initDescritorSet()
function:
void VulkanRenderer::initDescriptorSet() {
VkDescriptorSetAllocateInfo descriptorSetAllocateInfo [1];
descriptorSetAllocateInfo [0].sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
descriptorSetAllocateInfo [0].pNext = NULL;
descriptorSetAllocateInfo [0].descriptorPool = _descriptorPool;
descriptorSetAllocateInfo [0].descriptorSetCount = 1;
descriptorSetAllocateInfo [0].pSetLayouts = _descriptorSetLayout.data();
_descriptorSets.resize(1);
ErrorCheck(vkAllocateDescriptorSets(_deviceHandler, descriptorSetAllocateInfo, _descriptorSets.data()));
VkWriteDescriptorSet writes [2];
writes [0] = {};
writes [0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writes [0].pNext = NULL;
writes [0].dstSet = _descriptorSets [0];
writes [0].descriptorCount = 1;
writes [0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
writes [0].pBufferInfo = &_uniformDescriptorInfo;
writes [0].dstArrayElement = 0;
writes [0].dstBinding = 0;
vkUpdateDescriptorSets(_deviceHandler, 1, writes, 0, nullptr);
}