我是Vulkan的新手,所以请不要让我忘记。我一直在构建一个可以加载fbx格式的3D模型的程序。我一次渲染多个纹理对象时遇到了问题。我一直在根据一本名为Learning Vulkan的书来构建这个程序,并在这里和那里做了一些小改动。
编辑: 我现在已经从VulkanDrawable将渲染函数移动到VulkanRenderer。我将每个VulkanDrawable的绘图命令缓冲区收集到一个向量中,并尝试将其提交到队列但是收到错误,程序在将其中一个对象绘制到屏幕上几分之一秒后崩溃。程序失败,出现以下错误,我似乎无法修复:[VK_DEBUG_REPORT]错误:[ObjectTracker] Code149:无效的命令缓冲区对象0x21。 以下是请求的代码段。
这是VulkanRenderer中的函数(也可能是bug):
bool VulkanRenderer::render(){
while(!glfwWindowShouldClose(window))
{
glfwPollEvents();
uint32_t& currentColorImage = swapChainObject->scPublicVariables.currentColorBuffer;
VkSwapchainKHR& swapchain = swapChainObject->scPublicVariables.swapchain;
//Get the index of the next available swapchain image
VkResult result = swapChainObject->fpAcquireNextImageKHR(deviceObject->device,
swapchain,
UINT64_MAX,
presentCompleteSemaphore,
VK_NULL_HANDLE,
¤tColorImage);
//getDrawBuffer function inside VulkanDrawable looks like this (all in header file):
//inline VkCommandBuffer* getDrawBuffer(int index){return &vecCmdDraw[index];}
//This is a temporary solution and probably wrong as well. I am gathering pointers to
//the drawing buffers that I want to execute.
std::vector<VkCommandBuffer*> buffers{drawableObjects[0]->getDrawBuffer(currentColorImage),
drawableObjects[1]->getDrawBuffer(currentColorImage)};
//Create submit information
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.pNext = nullptr;
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = &presentCompleteSemaphore;
submitInfo.pWaitDstStageMask = &submitPipelineStages;
submitInfo.commandBufferCount = (uint32_t)sizeof(buffers) / sizeof(VkCommandBuffer);
//This *buffers.data looks dodgy but it won't compile otherwise
submitInfo.pCommandBuffers = *buffers.data();
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = &drawingCompleteSemaphore;
CommandBufferManager::submitCommandBuffer(deviceObject->queue, *buffers.data(), &submitInfo);
//Present image in the window
VkPresentInfoKHR present = {};
present.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
present.pNext = nullptr;
present.swapchainCount = 1;
present.pSwapchains = &swapchain;
present.pImageIndices = ¤tColorImage;
present.pWaitSemaphores = &drawingCompleteSemaphore;
present.waitSemaphoreCount = 1;
present.pResults = nullptr;
//queue the image for presentation
result = swapChainObject->fpQueuePresentKHR(deviceObject->queue, &present);
}
}
这是submitCommandBuffer函数(fence是默认的VK_NULL_HANDLE):
//Submits given command buffer to given queue with provided submit info and fence.
void CommandBufferManager::submitCommandBuffer(const VkQueue &queue,
const VkCommandBuffer *cmdBuffer,
const VkSubmitInfo *submitInfo,
const VkFence &fence){
VkResult result;
//If submit information is provided, use it.
if(submitInfo)
{
result = vkQueueSubmit(queue, 1, submitInfo, fence);
assert(!result);
result = vkQueueWaitIdle(queue);
assert(!result);
return;
}
//If not, create default submit info
VkSubmitInfo defaultSubmitInfo = {};
defaultSubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
defaultSubmitInfo.pNext = nullptr;
defaultSubmitInfo.waitSemaphoreCount = 0;
defaultSubmitInfo.pWaitSemaphores = nullptr;
defaultSubmitInfo.signalSemaphoreCount = 0;
defaultSubmitInfo.pSignalSemaphores = nullptr;
defaultSubmitInfo.pWaitDstStageMask = nullptr;
defaultSubmitInfo.commandBufferCount = (uint32_t) sizeof(cmdBuffer) / sizeof(VkCommandBuffer);
defaultSubmitInfo.pCommandBuffers = cmdBuffer;
result = vkQueueSubmit(queue, 1, &defaultSubmitInfo, fence);
assert(!result);
result = vkQueueWaitIdle(queue);
assert(!result);
}
Renderpass:
void VulkanRenderer::createRenderPass(bool includeDepth, bool clear)
{
//This function depends on the VulkanSwapchain to get the
//color image and VulkanRenderer to get the depth image
VkResult result;
//Attach color and depth buffers as an attachment to render pass instance.
VkAttachmentDescription attachments[2];
attachments[0].format = swapChainObject->scPublicVariables.format;
attachments[0].samples = NUM_SAMPLES;
//If clear is required, use it, else don't care.
attachments[0].loadOp = clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachments[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
attachments[0].flags = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT;
//If depth buffer is presented, define the properties for depth buffer attachment
if(includeDepth)
{
attachments[1].format = Depth.format;
attachments[1].samples = NUM_SAMPLES;
attachments[1].loadOp = clear ? VK_ATTACHMENT_LOAD_OP_CLEAR :
VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
attachments[1].flags = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT;
}
//Define color buffer attachment binding points and layout information
VkAttachmentReference colorReference = {};
colorReference.attachment = 0;
colorReference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
//Define depth buffer attachment binding points and layout information
VkAttachmentReference depthReference = {};
depthReference.attachment = 1;
depthReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
//Specify attachments - color, depth, resolve, preserve etc.
VkSubpassDescription subpass = {};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.flags = 0;
subpass.inputAttachmentCount = 0;
subpass.pInputAttachments = nullptr;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorReference;
subpass.pResolveAttachments = nullptr;
subpass.pDepthStencilAttachment = includeDepth ? &depthReference : nullptr;
subpass.preserveAttachmentCount = 0;
subpass.pPreserveAttachments = nullptr;
//Specify the attachment and subpass associated with render pass
VkRenderPassCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.attachmentCount = includeDepth ? 2 : 1;
createInfo.pAttachments = attachments;
createInfo.subpassCount = 1;
createInfo.pSubpasses = &subpass;
createInfo.dependencyCount = 0;
createInfo.pDependencies = nullptr;
//Create the render pass
result = vkCreateRenderPass(deviceObject->device, &createInfo, nullptr, &renderPass);
assert(result == VK_SUCCESS);
}
编辑:忘了添加命令缓冲区记录和api转储的部分内容:
Thread 0, Frame 0:
vkBeginCommandBuffer(commandBuffer, pBeginInfo) returns VkResult VK_SUCCESS (0):
commandBuffer: VkCommandBuffer = 0x1fc0bf0
pBeginInfo: const VkCommandBufferBeginInfo* = 0x1f9c070:
sType: VkStructureType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO (42)
pNext: const void* = NULL
flags: VkCommandBufferUsageFlags = 0
pInheritanceInfo: const VkCommandBufferInheritanceInfo* = UNUSED
Thread 0, Frame 0:
vkCmdBeginRenderPass(commandBuffer, pRenderPassBegin, contents) returns void:
commandBuffer: VkCommandBuffer = 0x1fc0bf0
pRenderPassBegin: const VkRenderPassBeginInfo* = 0x1fc2810:
sType: VkStructureType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO (43)
pNext: const void* = NULL
renderPass: VkRenderPass = 0x1f76d00
framebuffer: VkFramebuffer = 0x1f77b00
renderArea: VkRect2D = 0x1fc2830:
offset: VkOffset2D = 0x1fc2830:
x: int32_t = 0
y: int32_t = 0
extent: VkExtent2D = 0x1fc2838:
width: uint32_t = 800
height: uint32_t = 800
clearValueCount: uint32_t = 2
pClearValues: const VkClearValue* = 0x1fc2860
pClearValues[0]: const VkClearValue = 0x1fc2860 (Union):
color: VkClearColorValue = 0x1fc2860 (Union):
float32: float[4] = 0x1fc2860
float32[0]: float = 1
float32[1]: float = 1
float32[2]: float = 1
float32[3]: float = 1
int32: int32_t[4] = 0x1fc2860
int32[0]: int32_t = 1065353216
int32[1]: int32_t = 1065353216
int32[2]: int32_t = 1065353216
int32[3]: int32_t = 1065353216
uint32: uint32_t[4] = 0x1fc2860
uint32[0]: uint32_t = 1065353216
uint32[1]: uint32_t = 1065353216
uint32[2]: uint32_t = 1065353216
uint32[3]: uint32_t = 1065353216
depthStencil: VkClearDepthStencilValue = 0x1fc2860:
depth: float = 1
stencil: uint32_t = 1065353216
pClearValues[1]: const VkClearValue = 0x1fc2870 (Union):
color: VkClearColorValue = 0x1fc2870 (Union):
float32: float[4] = 0x1fc2870
float32[0]: float = 1
float32[1]: float = 0
float32[2]: float = 0
float32[3]: float = 0
int32: int32_t[4] = 0x1fc2870
int32[0]: int32_t = 1065353216
int32[1]: int32_t = 0
int32[2]: int32_t = 0
int32[3]: int32_t = 0
uint32: uint32_t[4] = 0x1fc2870
uint32[0]: uint32_t = 1065353216
uint32[1]: uint32_t = 0
uint32[2]: uint32_t = 0
uint32[3]: uint32_t = 0
depthStencil: VkClearDepthStencilValue = 0x1fc2870:
depth: float = 1
stencil: uint32_t = 0
contents: VkSubpassContents = VK_SUBPASS_CONTENTS_INLINE (0)
Thread 0, Frame 0:
vkCmdBindPipeline(commandBuffer, pipelineBindPoint, pipeline) returns void:
commandBuffer: VkCommandBuffer = 0x1fc0bf0
pipelineBindPoint: VkPipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS (0)
pipeline: VkPipeline = 0x1fa4ae0
Thread 0, Frame 0:
vkCmdBindDescriptorSets(commandBuffer, pipelineBindPoint, layout, firstSet, descriptorSetCount, pDescriptorSets, dynamicOffsetCount, pDynamicOffsets) returns void:
commandBuffer: VkCommandBuffer = 0x1fc0bf0
pipelineBindPoint: VkPipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS (0)
layout: VkPipelineLayout = 0x1fa2fe0
firstSet: uint32_t = 0
descriptorSetCount: uint32_t = 1
pDescriptorSets: const VkDescriptorSet* = 0x1fc2970
pDescriptorSets[0]: const VkDescriptorSet = 0x1fa1f70
dynamicOffsetCount: uint32_t = 0
pDynamicOffsets: const uint32_t* = NULL
Thread 0, Frame 0:
vkCmdBindVertexBuffers(commandBuffer, firstBinding, bindingCount, pBuffers, pOffsets) returns void:
commandBuffer: VkCommandBuffer = 0x1fc0bf0
firstBinding: uint32_t = 0
bindingCount: uint32_t = 1
pBuffers: const VkBuffer* = 0x1fc2a40
pBuffers[0]: const VkBuffer = 0x1f98020
pOffsets: const VkDeviceSize* = 0x7ffc731014c0
pOffsets[0]: const VkDeviceSize = 0
Thread 0, Frame 0:
vkCmdSetViewport(commandBuffer, firstViewport, viewportCount, pViewports) returns void:
commandBuffer: VkCommandBuffer = 0x1fc0bf0
firstViewport: uint32_t = 0
viewportCount: uint32_t = 1
pViewports: const VkViewport* = 0x1f95c58
pViewports[0]: const VkViewport = 0x1f95c58:
x: float = 0
y: float = 0
width: float = 800
height: float = 800
minDepth: float = 0
maxDepth: float = 1
Thread 0, Frame 0:
vkCmdSetScissor(commandBuffer, firstScissor, scissorCount, pScissors) returns void:
commandBuffer: VkCommandBuffer = 0x1fc0bf0
firstScissor: uint32_t = 0
scissorCount: uint32_t = 1
pScissors: const VkRect2D* = 0x1f95c70
pScissors[0]: const VkRect2D = 0x1f95c70:
offset: VkOffset2D = 0x1f95c70:
x: int32_t = 0
y: int32_t = 0
extent: VkExtent2D = 0x1f95c78:
width: uint32_t = 800
height: uint32_t = 800
Thread 0, Frame 0:
vkCmdDraw(commandBuffer, vertexCount, instanceCount, firstVertex, firstInstance) returns void:
commandBuffer: VkCommandBuffer = 0x1fc0bf0
vertexCount: uint32_t = 36
instanceCount: uint32_t = 1
firstVertex: uint32_t = 0
firstInstance: uint32_t = 0
Thread 0, Frame 0:
vkCmdEndRenderPass(commandBuffer) returns void:
commandBuffer: VkCommandBuffer = 0x1fc0bf0
Thread 0, Frame 0:
vkEndCommandBuffer(commandBuffer) returns VkResult VK_SUCCESS (0):
commandBuffer: VkCommandBuffer = 0x1fc0bf0
Thread 0, Frame 0:
vkAcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex) returns VkResult VK_SUCCESS (0):
device: VkDevice = 0x1d86dd0
swapchain: VkSwapchainKHR = 0x1f23c60
timeout: uint64_t = 18446744073709551615
semaphore: VkSemaphore = 0x1d8a560
fence: VkFence = 0
pImageIndex: uint32_t* = 0
Thread 0, Frame 0:
vkQueueSubmit(queue, submitCount, pSubmits, fence) returns VkResult VK_SUCCESS (0):
queue: VkQueue = 0x1eba560
submitCount: uint32_t = 1
pSubmits: const VkSubmitInfo* = 0x1efeaa8
pSubmits[0]: const VkSubmitInfo = 0x1efeaa8:
sType: VkStructureType = VK_STRUCTURE_TYPE_SUBMIT_INFO (4)
pNext: const void* = NULL
waitSemaphoreCount: uint32_t = 1
pWaitSemaphores: const VkSemaphore* = 0x1fc3820
pWaitSemaphores[0]: const VkSemaphore = 0x1d8a560
pWaitDstStageMask: const VkPipelineStageFlags* = 0x1fc3780
pWaitDstStageMask[0]: const VkPipelineStageFlags = 1024 (VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)
commandBufferCount: uint32_t = 3
pCommandBuffers: const VkCommandBuffer* = 0x1fc3730
pCommandBuffers[0]: const VkCommandBuffer = 0x1fa98a0
pCommandBuffers[1]: const VkCommandBuffer = 0x1fb01c0
pCommandBuffers[2]: const VkCommandBuffer = 0x1fb7d70
signalSemaphoreCount: uint32_t = 1
pSignalSemaphores: const VkSemaphore* = 0x1fc36e0
pSignalSemaphores[0]: const VkSemaphore = 0x1d8a710
fence: VkFence = 0
Thread 0, Frame 0:
vkQueuePresentKHR(queue, pPresentInfo) returns VkResult VK_SUCCESS (0):
queue: VkQueue = 0x1eba560
pPresentInfo: const VkPresentInfoKHR* = 0x1fc2810:
sType: VkStructureType = UNKNOWN (1000001001)
pNext: const void* = NULL
waitSemaphoreCount: uint32_t = 1
pWaitSemaphores: const VkSemaphore* = 0x1fc36e0
pWaitSemaphores[0]: const VkSemaphore = 0x1d8a710
swapchainCount: uint32_t = 1
pSwapchains: const VkSwapchainKHR* = 0x1fc3730
pSwapchains[0]: const VkSwapchainKHR = 0x1f23c60
pImageIndices: const uint32_t* = 0x1d8a418
pImageIndices[0]: const uint32_t = 0
pResults: VkResult* = NULL
Thread 0, Frame 1:
vkAcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex) returns VkResult VK_SUCCESS (0):
device: VkDevice = 0x1d86dd0
swapchain: VkSwapchainKHR = 0x1f23c60
timeout: uint64_t = 18446744073709551615
semaphore: VkSemaphore = 0x1d8a560
fence: VkFence = 0
pImageIndex: uint32_t* = 1
[VK_DEBUG_REPORT] ERROR: [ObjectTracker] Code149:Invalid Command Buffer Object 0x21. For more information refer to Vulkan Spec Section '5.4. Command Buffer Submission' which states 'If commandBufferCount is not 0, pCommandBuffers must be a pointer to an array of commandBufferCount valid VkCommandBuffer handles' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#VkSubmitInfo)
命令缓冲区记录:
void VulkanDrawable::recordCommandBuffer(int currentImage, VkCommandBuffer *cmdDraw){
//VulkanDevice* deviceObject = rendererObject->getDevice();
//Specify clear color values
VkClearValue clearValues[2];
clearValues[0].color.float32[0] = 1.0f;
clearValues[0].color.float32[1] = 1.0f;
clearValues[0].color.float32[2] = 1.0f;
clearValues[0].color.float32[3] = 1.0f;
//Specify depth/stencil clear value
clearValues[1].depthStencil.depth = 1.0f;
clearValues[1].depthStencil.stencil = 0;
VkRenderPassBeginInfo renderPassBegin = {};
renderPassBegin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBegin.pNext = nullptr;
renderPassBegin.renderPass = rendererObject->renderPass;
renderPassBegin.framebuffer = rendererObject->framebuffers[currentImage];
renderPassBegin.renderArea.offset.x = 0;
renderPassBegin.renderArea.offset.y = 0;
renderPassBegin.renderArea.extent.width = rendererObject->width;
renderPassBegin.renderArea.extent.height = rendererObject->height;
renderPassBegin.clearValueCount = 2;
renderPassBegin.pClearValues = clearValues;
//Start recording the render pass instance
vkCmdBeginRenderPass(*cmdDraw, &renderPassBegin, VK_SUBPASS_CONTENTS_INLINE);
//Bind the command buffer with the pipeline
vkCmdBindPipeline(*cmdDraw, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
//Bind descriptor sets
vkCmdBindDescriptorSets(*cmdDraw, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout,0, 1,
descriptorSets.data(),0,nullptr);
//Bind vertex data to the command buffer
const VkDeviceSize offsets[1] = {0};
vkCmdBindVertexBuffers(*cmdDraw, 0, 1, &VertexBuffer.buffer, offsets);
//Define the dynamic viewport
initViewports(cmdDraw);
//Define the scissoring also
initScissors(cmdDraw);
//Draw
vkCmdDraw(*cmdDraw, verticeAmount, 1,0,0);
//vkCmdDrawIndexed(*cmdDraw, indiceAmount, 1,0,0,0);
//End render pass instance recording
vkCmdEndRenderPass(*cmdDraw);
}
感谢您的帮助。如果您有任何其他信息,请告知我们。