diff --git a/src/common/rendering/vulkan/vk_renderdevice.cpp b/src/common/rendering/vulkan/vk_renderdevice.cpp index dcc4fa8b5..c5ac4fbbd 100644 --- a/src/common/rendering/vulkan/vk_renderdevice.cpp +++ b/src/common/rendering/vulkan/vk_renderdevice.cpp @@ -789,76 +789,130 @@ void VulkanRenderDevice::DrawLevelMesh(const HWViewpointUniforms& viewpoint) matrices.TextureMatrix.loadIdentity(); rsbuffers->MatrixBuffer->Write(matrices); - PushConstants pushConstants = {}; - pushConstants.uDataIndex = 0; - pushConstants.uLightIndex = -1; - pushConstants.uBoneIndexBase = -1; - auto submesh = GetRaytrace()->GetMesh()->StaticMesh.get(); // Draw opaque scene into the depth buffer for (LevelSubmeshDrawRange& range : submesh->DrawList) { VkPipelineKey pipelineKey = levelMeshPipelineKeys[range.PipelineID]; - if (pipelineKey.ShaderKey.AlphaTest) - continue; - + if (pipelineKey.ShaderKey.AlphaTest) continue; pipelineKey.ShaderKey.NoFragmentShader = true; - - VulkanPipelineLayout* layout = GetRenderPassManager()->GetPipelineLayout(pipelineKey.NumTextureLayers, pipelineKey.ShaderKey.UseLevelMesh); - uint32_t viewpointOffset = viewpointIndex * rsbuffers->Viewpoint.BlockAlign; - uint32_t matrixOffset = rsbuffers->MatrixBuffer->Offset(); - uint32_t lightsOffset = 0; - uint32_t offsets[] = { viewpointOffset, matrixOffset, lightsOffset }; - cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, passSetup->GetPipeline(pipelineKey)); - cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptors->GetFixedSet()); - cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 1, descriptors->GetLevelMeshSet(), 3, offsets); - cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 2, descriptors->GetBindlessSet()); - cmdbuffer->pushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, (uint32_t)sizeof(PushConstants), &pushConstants); - - cmdbuffer->drawIndexed(range.Count, 1, range.Start, 0, 0); + DrawLevelMeshRange(cmdbuffer, passSetup, pipelineKey, viewpointIndex, range.Start, range.Count, 0); } - - // Draw portal surface occlusion queries - for (LevelSubmeshDrawRange& range : submesh->PortalList) { VkPipelineKey pipelineKey = levelMeshPipelineKeys[range.PipelineID]; pipelineKey.ShaderKey.NoFragmentShader = true; - - VulkanPipelineLayout* layout = GetRenderPassManager()->GetPipelineLayout(pipelineKey.NumTextureLayers, pipelineKey.ShaderKey.UseLevelMesh); - uint32_t viewpointOffset = viewpointIndex * rsbuffers->Viewpoint.BlockAlign; - uint32_t matrixOffset = rsbuffers->MatrixBuffer->Offset(); - uint32_t lightsOffset = 0; - uint32_t offsets[] = { viewpointOffset, matrixOffset, lightsOffset }; - cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, passSetup->GetPipeline(pipelineKey)); - cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptors->GetFixedSet()); - cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 1, descriptors->GetLevelMeshSet(), 3, offsets); - cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 2, descriptors->GetBindlessSet()); - cmdbuffer->pushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, (uint32_t)sizeof(PushConstants), &pushConstants); - - // To do: add occlusion query - - cmdbuffer->drawIndexed(range.Count, 1, range.Start, 0, 0); + DrawLevelMeshRange(cmdbuffer, passSetup, pipelineKey, viewpointIndex, range.Start, range.Count, 0); } + // Draw portal surface occlusion queries + + //int portalIndex = 0; + //cmdbuffer->beginQuery(queryPool, portalIndex, 0); + for (LevelSubmeshDrawRange& range : submesh->PortalList) + { + VkPipelineKey pipelineKey = levelMeshPipelineKeys[range.PipelineID]; + pipelineKey.ShaderKey.NoFragmentShader = true; + DrawLevelMeshRange(cmdbuffer, passSetup, pipelineKey, viewpointIndex, range.Start, range.Count, 0); + } + //cmdbuffer->endQuery(queryPool, portalIndex); + //portalIndex++; + // Draw opaque scene for (LevelSubmeshDrawRange& range : submesh->DrawList) { - auto& pipelineKey = levelMeshPipelineKeys[range.PipelineID]; - VulkanPipelineLayout* layout = GetRenderPassManager()->GetPipelineLayout(pipelineKey.NumTextureLayers, pipelineKey.ShaderKey.UseLevelMesh); - uint32_t viewpointOffset = viewpointIndex * rsbuffers->Viewpoint.BlockAlign; - uint32_t matrixOffset = rsbuffers->MatrixBuffer->Offset(); - uint32_t lightsOffset = 0; - uint32_t offsets[] = { viewpointOffset, matrixOffset, lightsOffset }; - cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, passSetup->GetPipeline(pipelineKey)); - cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptors->GetFixedSet()); - cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 1, descriptors->GetLevelMeshSet(), 3, offsets); - cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 2, descriptors->GetBindlessSet()); - cmdbuffer->pushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, (uint32_t)sizeof(PushConstants), &pushConstants); - - cmdbuffer->drawIndexed(range.Count, 1, range.Start, 0, 0); + DrawLevelMeshRange(cmdbuffer, passSetup, levelMeshPipelineKeys[range.PipelineID], viewpointIndex, range.Start, range.Count, 0); } cmdbuffer->endRenderPass(); + + GetCommands()->FlushCommands(false); + //VkResult result = vkGetQueryPoolResults(GetDevice()->device, queryPool->pool, 0, portalIndex, ...); + cmdbuffer = GetCommands()->GetDrawCommands(); + + // Create stencil + for (LevelSubmeshDrawRange& range : submesh->PortalList) + { + VkPipelineKey pipelineKey = levelMeshPipelineKeys[range.PipelineID]; + pipelineKey.ShaderKey.NoFragmentShader = true; + pipelineKey.StencilTest = true; + pipelineKey.StencilPassOp = SOP_Increment; + DrawLevelMeshRange(cmdbuffer, passSetup, pipelineKey, viewpointIndex, range.Start, range.Count, 0); + } + + // Clear zbuffer + viewport.minDepth = 1.0f; + viewport.maxDepth = 1.0f; + cmdbuffer->setViewport(0, 1, &viewport); + for (LevelSubmeshDrawRange& range : submesh->PortalList) + { + VkPipelineKey pipelineKey = levelMeshPipelineKeys[range.PipelineID]; + pipelineKey.ShaderKey.NoFragmentShader = true; + pipelineKey.StencilTest = true; + pipelineKey.StencilPassOp = SOP_Keep; + pipelineKey.DepthFunc = DF_Always; + DrawLevelMeshRange(cmdbuffer, passSetup, pipelineKey, viewpointIndex, range.Start, range.Count, 1); + } + + // Portal scene + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + cmdbuffer->setViewport(0, 1, &viewport); + + /* + auto& state = *mRenderState.get(); + state.SetTextureMode(TM_OPAQUE); + mSkyData->RenderDome(state, origin->texture[0], origin->x_offset[0], origin->y_offset, origin->mirrored, FSkyVertexBuffer::SKYMODE_MAINLAYER, !!(di->Level->flags & LEVEL_FORCETILEDSKY)); + state.SetTextureMode(TM_NORMAL); + */ + + // Clear zbuffer + viewport.minDepth = 1.0f; + viewport.maxDepth = 1.0f; + cmdbuffer->setViewport(0, 1, &viewport); + for (LevelSubmeshDrawRange& range : submesh->PortalList) + { + VkPipelineKey pipelineKey = levelMeshPipelineKeys[range.PipelineID]; + pipelineKey.ShaderKey.NoFragmentShader = true; + pipelineKey.StencilTest = true; + pipelineKey.StencilPassOp = SOP_Keep; + pipelineKey.DepthFunc = DF_Always; + DrawLevelMeshRange(cmdbuffer, passSetup, pipelineKey, viewpointIndex, range.Start, range.Count, 1); + } + + // Restore zbuffer + for (LevelSubmeshDrawRange& range : submesh->PortalList) + { + VkPipelineKey pipelineKey = levelMeshPipelineKeys[range.PipelineID]; + pipelineKey.ShaderKey.NoFragmentShader = true; + pipelineKey.StencilTest = true; + pipelineKey.StencilPassOp = SOP_Decrement; + DrawLevelMeshRange(cmdbuffer, passSetup, pipelineKey, viewpointIndex, range.Start, range.Count, 1); + } +} + +void VulkanRenderDevice::DrawLevelMeshRange(VulkanCommandBuffer* cmdbuffer, VkRenderPassSetup* passSetup, const VkPipelineKey& pipelineKey, int viewpointIndex, int start, int count, int stencilRef) +{ + auto rsbuffers = GetBufferManager()->GetRSBuffers(); + auto descriptors = GetDescriptorSetManager(); + + PushConstants pushConstants = {}; + pushConstants.uDataIndex = 0; + pushConstants.uLightIndex = -1; + pushConstants.uBoneIndexBase = -1; + + VulkanPipelineLayout* layout = GetRenderPassManager()->GetPipelineLayout(pipelineKey.NumTextureLayers, pipelineKey.ShaderKey.UseLevelMesh); + uint32_t viewpointOffset = viewpointIndex * rsbuffers->Viewpoint.BlockAlign; + uint32_t matrixOffset = rsbuffers->MatrixBuffer->Offset(); + uint32_t lightsOffset = 0; + uint32_t offsets[] = { viewpointOffset, matrixOffset, lightsOffset }; + + cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, passSetup->GetPipeline(pipelineKey)); + cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptors->GetFixedSet()); + cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 1, descriptors->GetLevelMeshSet(), 3, offsets); + cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 2, descriptors->GetBindlessSet()); + cmdbuffer->pushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, (uint32_t)sizeof(PushConstants), &pushConstants); + cmdbuffer->setStencilReference(VK_STENCIL_FACE_FRONT_AND_BACK, stencilRef); + cmdbuffer->drawIndexed(count, 1, start, 0, 0); } diff --git a/src/common/rendering/vulkan/vk_renderdevice.h b/src/common/rendering/vulkan/vk_renderdevice.h index 67414ec5c..9c4ae0fb0 100644 --- a/src/common/rendering/vulkan/vk_renderdevice.h +++ b/src/common/rendering/vulkan/vk_renderdevice.h @@ -23,6 +23,7 @@ class VkHardwareTexture; class VkRenderBuffers; class VkPostprocess; class VkPipelineKey; +class VkRenderPassSetup; class VulkanRenderDevice : public SystemBaseFrameBuffer { @@ -97,6 +98,7 @@ private: void RenderTextureView(FCanvasTexture* tex, std::function renderFunc) override; void PrintStartupLog(); void CopyScreenToBuffer(int w, int h, uint8_t *data) override; + void DrawLevelMeshRange(VulkanCommandBuffer* cmdbuffer, VkRenderPassSetup* passSetup, const VkPipelineKey& pipelineKey, int viewpointIndex, int start, int count, int stencilRef); std::shared_ptr mDevice; std::unique_ptr mCommands;