Hi! I’ve a multi-threaded code with runs perfectly with opengl but blocks the vulkan driver.
I use one thread to do frusturm culling and load entities to the renderer. My renderer looks like this :
void PerPixelLinkedListRenderComponent::drawNextFrame() {
{
std::lock_guard<std::recursive_mutex> lock(rec_mutex);
if (datasReady) {
datasReady = false;
m_instances = batcher.getInstances();
m_normals = normalBatcher.getInstances();
m_instancesIndexed = batcherIndexed.getInstances();
m_normalsIndexed = normalBatcherIndexed.getInstances();
m_selected = selectedBatcher.getInstances();
m_selectedScale = selectedScaleBatcher.getInstances();
m_selectedIndexed = selectedIndexBatcher.getInstances();
m_selectedScaleIndexed = selectedIndexScaleBatcher.getInstances();
m_selectedInstance = selectedInstanceBatcher.getInstances();
m_selectedScaleInstance = selectedInstanceScaleBatcher.getInstances();
m_selectedInstanceIndexed = selectedInstanceIndexBatcher.getInstances();
m_selectedScaleInstanceIndexed = selectedInstanceIndexScaleBatcher.getInstances();
m_skyboxInstance = skyboxBatcher.getInstances();
}
}
/*math::Matrix4f viewMatrix = view.getViewMatrix().getMatrix().transpose();
math::Matrix4f projMatrix = view.getProjMatrix().getMatrix().transpose();
viewMatrix = math::Matrix4f(math::Matrix3f(viewMatrix));
vb.clear();
//vb.name = "SKYBOXVB";
for (unsigned int i = 0; i < m_skyboxInstance.size(); i++) {
if (m_skyboxInstance[i].getAllVertices().getVertexCount() > 0) {
vb.setPrimitiveType(m_skyboxInstance[i].getAllVertices().getPrimitiveType());
for (unsigned int j = 0; j < m_skyboxInstance[i].getAllVertices().getVertexCount(); j++) {
//if (m_skyboxInstance[i].getAllVertices()[j].position.x != 0 && m_skyboxInstance[i].getAllVertices()[j].position.y != 0 && m_skyboxInstance[i].getAllVertices()[j].position.z != 0);
vb.append(m_skyboxInstance[i].getAllVertices()[j]);
}
}
}
currentStates.blendMode = sf::BlendAlpha;
currentStates.shader = &skyboxShader;
currentStates.texture = (skybox == nullptr ) ? nullptr : &static_cast<g3d::Skybox*>(skybox)->getTexture();
vb.update();
frameBuffer.drawVertexBuffer(vb, currentStates);
vb.clear();*/
math::Matrix4f projMatrix = view.getProjMatrix().getMatrix()/*.transpose()*/;
math::Matrix4f viewMatrix = view.getViewMatrix().getMatrix()/*.transpose()*/;
indirectDrawPushConsts.projMatrix = projMatrix;
indirectDrawPushConsts.viewMatrix = viewMatrix;
//indirectDrawPushConsts.projMatrix.m22 *= -1;
drawInstances();
drawInstancesIndexed();
drawSelectedInstances();
drawSelectedInstancesIndexed();
vb.clear();
vb.setPrimitiveType(sf::Triangles);
Vertex v1 (sf::Vector3f(0, 0, quad.getSize().z));
Vertex v2 (sf::Vector3f(quad.getSize().x,0, quad.getSize().z));
Vertex v3 (sf::Vector3f(quad.getSize().x, quad.getSize().y, quad.getSize().z));
Vertex v4 (sf::Vector3f(0, quad.getSize().y, quad.getSize().z));
vb.append(v1);
vb.append(v2);
vb.append(v3);
vb.append(v1);
vb.append(v3);
vb.append(v4);
vb.update();
math::Matrix4f matrix = quad.getTransform().getMatrix()/*.transpose()*/;
ppll2PushConsts.worldMat = matrix;
RenderStates currentStates;
currentStates.shader = &perPixelLinkedListP2;
currentStates.blendMode = sf::BlendNone;
frameBuffer.enableStencilTest(false);
//createDescriptorSets2(currentStates);
createCommandBufferVertexBuffer(currentStates);
}
void PerPixelLinkedListRenderComponent::allocateCommandBuffers() {
commandBuffers.resize(frameBuffer.getSwapchainImages().size());
VkCommandBufferAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.commandPool = commandPool;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
allocInfo.commandBufferCount = (uint32_t) commandBuffers.size();
if (vkAllocateCommandBuffers(vkDevice.getDevice(), &allocInfo, commandBuffers.data()) != VK_SUCCESS) {
throw core::Erreur(0, "failed to allocate command buffers!", 1);
}
}
void PerPixelLinkedListRenderComponent::createCommandBuffersIndirect(unsigned int p, unsigned int nbIndirectCommands, unsigned int stride, DepthStencilID depthStencilID, RenderStates currentStates) {
if (needToUpdateDS) {
createDescriptorSets(p, currentStates);
needToUpdateDS = false;
}
unsigned int currentFrame = frameBuffer.getCurrentFrame();
frameBuffer.beginRecordCommandBuffers();
frameBuffer.beginRenderPass();
/*VkCommandBufferInheritanceInfo inheritanceInfo;
inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
inheritanceInfo.pNext = nullptr;
inheritanceInfo.renderPass = frameBuffer.getRenderPass(1);
inheritanceInfo.subpass = 0;
inheritanceInfo.framebuffer = frameBuffer.getSwapchainFrameBuffers(1)[currentFrame];
inheritanceInfo.occlusionQueryEnable = VK_FALSE;
inheritanceInfo.queryFlags = 0;
inheritanceInfo.pipelineStatistics = 0;
VkCommandBufferBeginInfo commandBufferBeginInfo;
commandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
commandBufferBeginInfo.pNext = nullptr;
commandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
commandBufferBeginInfo.pInheritanceInfo = &inheritanceInfo;
if (vkBeginCommandBuffer(commandBuffers[currentFrame], &commandBufferBeginInfo) != VK_SUCCESS) {
std::runtime_error("Failed to begin recording command buffers");
}*/
Shader* shader = const_cast<Shader*>(currentStates.shader);
std::vector<Texture*> allTextures = Texture::getAllTextures();
vkCmdPushConstants(frameBuffer.getCommandBuffers()[currentFrame], frameBuffer.getPipelineLayout()[shader->getId() * (Batcher::nbPrimitiveTypes - 1) + p][frameBuffer.getId()][depthStencilID], VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(IndirectDrawPushConsts), &indirectDrawPushConsts);
frameBuffer.drawIndirect(frameBuffer.getCommandBuffers()[currentFrame], currentFrame, nbIndirectCommands, stride, vbBindlessTex[p], vboIndirect, depthStencilID,currentStates);
/*vkCmdResetEvent(frameBuffer.getCommandBuffers()[currentFrame], events[currentFrame], VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
vkCmdSetEvent(frameBuffer.getCommandBuffers()[currentFrame], events[currentFrame], VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);*/
/*frameBuffer.beginRecordCommandBuffers();
frameBuffer.beginRenderPass();
vkCmdExecuteCommands(frameBuffer.getCommandBuffers()[currentFrame], static_cast<uint32_t>(commandBuffers.size()), commandBuffers.data());*/
frameBuffer.display();
}
void PerPixelLinkedListRenderComponent::createCommandBufferVertexBuffer(RenderStates currentStates) {
frameBuffer.beginRecordCommandBuffers();
unsigned int currentFrame = frameBuffer.getCurrentFrame();
/*VkCommandBufferInheritanceInfo inheritanceInfo;
inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
inheritanceInfo.pNext = nullptr;
inheritanceInfo.renderPass = frameBuffer.getRenderPass(1);
inheritanceInfo.subpass = 0;
inheritanceInfo.framebuffer = frameBuffer.getSwapchainFrameBuffers(1)[currentFrame];
inheritanceInfo.occlusionQueryEnable = VK_FALSE;
inheritanceInfo.queryFlags = 0;
inheritanceInfo.pipelineStatistics = 0;
VkCommandBufferBeginInfo commandBufferBeginInfo;
commandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
commandBufferBeginInfo.pNext = nullptr;
commandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
commandBufferBeginInfo.pInheritanceInfo = &inheritanceInfo;
if (vkBeginCommandBuffer(commandBuffers[currentFrame], &commandBufferBeginInfo) != VK_SUCCESS) {
std::runtime_error("Failed to begin recording command buffers");
}*/
Shader* shader = const_cast<Shader*>(currentStates.shader);
//for (size_t i = 0; i < commandBuffers.size(); i++) {
/*vkResetCommandBuffer(commandBuffers[currentFrame], VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);
VkCommandBufferBeginInfo beginInfo{};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
if (vkBeginCommandBuffer(commandBuffers[i], &beginInfo) != VK_SUCCESS) {
throw core::Erreur(0, "failed to begin recording command buffer!", 1);
}*/
/*std::array<VkWriteDescriptorSet, 2> descriptorWrites{};
VkDescriptorImageInfo headPtrDescriptorImageInfo;
headPtrDescriptorImageInfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
headPtrDescriptorImageInfo.imageView = headPtrTextureImageView;
headPtrDescriptorImageInfo.sampler = headPtrTextureSampler;
descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrites[0].dstSet = 0;
descriptorWrites[0].dstBinding = 0;
descriptorWrites[0].dstArrayElement = 0;
descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
descriptorWrites[0].descriptorCount = 1;
descriptorWrites[0].pImageInfo = &headPtrDescriptorImageInfo;
VkDescriptorBufferInfo linkedListStorageBufferInfoLastFrame{};
linkedListStorageBufferInfoLastFrame.buffer = linkedListShaderStorageBuffers[currentFrame];
linkedListStorageBufferInfoLastFrame.offset = 0;
unsigned int nodeSize = 5 * sizeof(float) + sizeof(unsigned int);
linkedListStorageBufferInfoLastFrame.range = maxNodes * nodeSize;
descriptorWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrites[1].dstSet = 0;
descriptorWrites[1].dstBinding = 1;
descriptorWrites[1].dstArrayElement = 0;
descriptorWrites[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
descriptorWrites[1].descriptorCount = 1;
descriptorWrites[1].pBufferInfo = &linkedListStorageBufferInfoLastFrame;*/
vkCmdPipelineBarrier(frameBuffer.getCommandBuffers()[currentFrame], VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 0, nullptr);
VkMemoryBarrier memoryBarrier;
memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
memoryBarrier.pNext = VK_NULL_HANDLE;
memoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
vkCmdPipelineBarrier(frameBuffer.getCommandBuffers()[currentFrame], VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 1, &memoryBarrier, 0, nullptr, 0, nullptr);
//vkCmdPushDescriptorSetKHR(commandBuffers[currentFrame], VK_PIPELINE_BIND_POINT_GRAPHICS, frameBuffer.getPipelineLayout()[shader->getId() * (Batcher::nbPrimitiveTypes - 1) + vb.getPrimitiveType()][frameBuffer.getId()][NODEPTHNOSTENCIL], 0, 2, descriptorWrites.data());
frameBuffer.beginRenderPass();
vkCmdPushConstants(frameBuffer.getCommandBuffers()[currentFrame], frameBuffer.getPipelineLayout()[shader->getId() * (Batcher::nbPrimitiveTypes - 1) + vb.getPrimitiveType()][frameBuffer.getId()][NODEPTHNOSTENCIL], VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(Ppll2PushConsts), &ppll2PushConsts);
//vkCmdWaitEvents(frameBuffer.getCommandBuffers()[currentFrame], 1, &events[currentFrame], VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 1, &memoryBarrier, 0, nullptr, 0, nullptr);
frameBuffer.drawVertexBuffer(frameBuffer.getCommandBuffers()[currentFrame], currentFrame, vb, NODEPTHNOSTENCIL, currentStates);
/*if (vkEndCommandBuffer(commandBuffers[currentFrame]) != VK_SUCCESS) {
throw core::Erreur(0, "failed to record command buffer!", 1);
}*/
//}
/*if(vkEndCommandBuffer(commandBuffers[currentFrame]) != VK_SUCCESS) {
std::runtime_error("Failed to record command buffers");
}*/
/*frameBuffer.beginRecordCommandBuffers();
frameBuffer.beginRenderPass();
vkCmdExecuteCommands(frameBuffer.getCommandBuffers()[currentFrame], static_cast<uint32_t>(commandBuffers.size()), commandBuffers.data());*/
frameBuffer.display();
}
bool PerPixelLinkedListRenderComponent::loadEntitiesOnComponent(std::vector<Entity*> vEntities) {
{
std::lock_guard<std::recursive_mutex> lock(rec_mutex);
datasReady = false;
batcher.clear();
normalBatcher.clear();
batcherIndexed.clear();
normalBatcherIndexed.clear();
selectedBatcher.clear();
selectedScaleBatcher.clear();
selectedIndexBatcher.clear();
selectedIndexScaleBatcher.clear();
selectedInstanceBatcher.clear();
selectedInstanceScaleBatcher.clear();
selectedInstanceIndexBatcher.clear();
selectedInstanceIndexScaleBatcher.clear();
skyboxBatcher.clear();
visibleSelectedScaleEntities.clear();
}
if (skybox != nullptr) {
for (unsigned int i = 0; i < skybox->getNbFaces(); i++) {
skyboxBatcher.addFace(skybox->getFace(i));
}
}
for (unsigned int i = 0; i < vEntities.size(); i++) {
if ( vEntities[i] != nullptr && vEntities[i]->isLeaf()) {
Entity* border;
if (vEntities[i]->isSelected()) {
border = vEntities[i]->clone();
border->decreaseNbEntities();
}
for (unsigned int j = 0; j < vEntities[i]->getNbFaces(); j++) {
std::lock_guard<std::recursive_mutex> lock(rec_mutex);
if (vEntities[i]->getDrawMode() == Entity::INSTANCED && !vEntities[i]->isSelected()) {
if (vEntities[i]->getFace(j)->getVertexArray().getIndexes().size() == 0)
batcher.addFace( vEntities[i]->getFace(j));
else
batcherIndexed.addFace(vEntities[i]->getFace(j));
} else if (vEntities[i]->getDrawMode() == Entity::NORMAL && !vEntities[i]->isSelected()) {
if (vEntities[i]->getFace(j)->getVertexArray().getIndexes().size() == 0) {
normalBatcher.addFace( vEntities[i]->getFace(j));
} else
normalBatcherIndexed.addFace( vEntities[i]->getFace(j));
} else if (vEntities[i]->getDrawMode() == Entity::INSTANCED && vEntities[i]->isSelected()) {
if (vEntities[i]->getFace(j)->getVertexArray().getIndexes().size() == 0) {
selectedInstanceBatcher.addFace(vEntities[i]->getFace(j));
// std::cout<<"remove texture"<<std::endl;
//std::cout<<"get va"<<std::endl;
VertexArray& va = border->getFace(j)->getVertexArray();
//std::cout<<"change color"<<std::endl;
for (unsigned int j = 0; j < va.getVertexCount(); j++) {
va[j].color = sf::Color::Cyan;
}
Entity* root = (vEntities[i]->getRootEntity()->isAnimated()) ? vEntities[i]->getRootEntity() : vEntities[i];
math::Vec3f oldSize = root->getSize();
border->setOrigin(border->getSize() * 0.5f);
border->setScale(math::Vec3f(1.1f, 1.1f, 1.1f));
math::Vec3f offset = root->getSize() - oldSize;
border->setPosition(root->getPosition() - offset * 0.5f);
// std::cout<<"add to batcher"<<std::endl;
selectedInstanceScaleBatcher.addFace(border->getFace(j));
// std::cout<<"face added"<<std::endl;
} else {
selectedInstanceIndexBatcher.addFace(vEntities[i]->getFace(j));
// std::cout<<"remove texture"<<std::endl;
//std::cout<<"get va"<<std::endl;
VertexArray& va = border->getFace(j)->getVertexArray();
//std::cout<<"change color"<<std::endl;
for (unsigned int j = 0; j < va.getVertexCount(); j++) {
va[j].color = sf::Color::Cyan;
}
Entity* root = (vEntities[i]->getRootEntity()->isAnimated()) ? vEntities[i]->getRootEntity() : vEntities[i];
math::Vec3f oldSize = root->getSize();
border->setOrigin(root->getSize() * 0.5f);
border->setSize(root->getSize() * 1.1f);
math::Vec3f offset = root->getSize() - oldSize;
border->setPosition(root->getPosition() - offset * 0.5f);
// std::cout<<"add to batcher"<<std::endl;
selectedInstanceIndexScaleBatcher.addFace(border->getFace(j));
}
} else {
if (vEntities[i]->getFace(j)->getVertexArray().getIndexes().size() == 0) {
selectedBatcher.addFace(vEntities[i]->getFace(j));
// std::cout<<"remove texture"<<std::endl;
//std::cout<<"get va"<<std::endl;
VertexArray& va = border->getFace(j)->getVertexArray();
//std::cout<<"change color"<<std::endl;
for (unsigned int j = 0; j < va.getVertexCount(); j++) {
va[j].color = sf::Color::Cyan;
}
Entity* root = (vEntities[i]->getRootEntity()->isAnimated()) ? vEntities[i]->getRootEntity() : vEntities[i];
math::Vec3f oldSize = root->getSize();
border->setOrigin(root->getSize() * 0.5f);
border->setSize(root->getSize() * 1.1f);
math::Vec3f offset = root->getSize() - oldSize;
border->setPosition(root->getPosition() - offset * 0.5f);
selectedScaleBatcher.addFace(border->getFace(j));
// std::cout<<"face added"<<std::endl;
} else {
selectedIndexBatcher.addFace(vEntities[i]->getFace(j));
// std::cout<<"remove texture"<<std::endl;
//std::cout<<"get va"<<std::endl;
VertexArray& va = border->getFace(j)->getVertexArray();
//std::cout<<"change color"<<std::endl;
for (unsigned int j = 0; j < va.getVertexCount(); j++) {
va[j].color = sf::Color::Cyan;
}
border->setOrigin(border->getSize() * 0.5f);
border->setScale(math::Vec3f(1.1f, 1.1f, 1.1f));
// std::cout<<"add to batcher"<<std::endl;
selectedIndexScaleBatcher.addFace(border->getFace(j));
}
}
}
if (vEntities[i]->isSelected()) {
std::unique_ptr<Entity> ptr;
ptr.reset(border);
visibleSelectedScaleEntities.push_back(std::move(ptr));
}
}
}
I update the instances only when the entities are entirely loaded on the component so I use a boolean and an if.
Works perfectly with opengl but blocks the vulkan driver.
Thanks.