From 2b391dac74b0407173f80d0079748d0c1ee7e23f Mon Sep 17 00:00:00 2001 From: Corentin Wallez Date: Tue, 9 Jan 2018 10:50:07 -0800 Subject: [PATCH] Vulkan: Implement RenderPipeline --- src/backend/CMakeLists.txt | 4 + src/backend/RenderPipeline.h | 4 + src/backend/vulkan/CommandBufferVk.cpp | 44 +++- src/backend/vulkan/FencedDeleter.cpp | 19 ++ src/backend/vulkan/FencedDeleter.h | 4 + src/backend/vulkan/GeneratedCodeIncludes.h | 2 + src/backend/vulkan/RenderPipelineVk.cpp | 244 +++++++++++++++++++++ src/backend/vulkan/RenderPipelineVk.h | 40 ++++ src/backend/vulkan/ShaderModuleVk.cpp | 60 +++++ src/backend/vulkan/ShaderModuleVk.h | 37 ++++ src/backend/vulkan/VulkanBackend.cpp | 9 +- src/backend/vulkan/VulkanBackend.h | 6 +- 12 files changed, 461 insertions(+), 12 deletions(-) create mode 100644 src/backend/vulkan/RenderPipelineVk.cpp create mode 100644 src/backend/vulkan/RenderPipelineVk.h create mode 100644 src/backend/vulkan/ShaderModuleVk.cpp create mode 100644 src/backend/vulkan/ShaderModuleVk.h diff --git a/src/backend/CMakeLists.txt b/src/backend/CMakeLists.txt index 01bdf93dc2..5e5caab184 100644 --- a/src/backend/CMakeLists.txt +++ b/src/backend/CMakeLists.txt @@ -307,6 +307,10 @@ if (NXT_ENABLE_VULKAN) ${VULKAN_DIR}/PipelineLayoutVk.h ${VULKAN_DIR}/RenderPassVk.cpp ${VULKAN_DIR}/RenderPassVk.h + ${VULKAN_DIR}/RenderPipelineVk.cpp + ${VULKAN_DIR}/RenderPipelineVk.h + ${VULKAN_DIR}/ShaderModuleVk.cpp + ${VULKAN_DIR}/ShaderModuleVk.h ${VULKAN_DIR}/TextureVk.cpp ${VULKAN_DIR}/TextureVk.h ${VULKAN_DIR}/VulkanBackend.cpp diff --git a/src/backend/RenderPipeline.h b/src/backend/RenderPipeline.h index 6d4ac64526..9e34e7a348 100644 --- a/src/backend/RenderPipeline.h +++ b/src/backend/RenderPipeline.h @@ -15,7 +15,11 @@ #ifndef BACKEND_RENDERPIPELINE_H_ #define BACKEND_RENDERPIPELINE_H_ +#include "backend/BlendState.h" +#include "backend/DepthStencilState.h" +#include "backend/InputState.h" #include "backend/Pipeline.h" +#include "backend/RenderPass.h" #include "nxt/nxtcpp.h" diff --git a/src/backend/vulkan/CommandBufferVk.cpp b/src/backend/vulkan/CommandBufferVk.cpp index 1b524c74f9..65b2c105e8 100644 --- a/src/backend/vulkan/CommandBufferVk.cpp +++ b/src/backend/vulkan/CommandBufferVk.cpp @@ -18,6 +18,7 @@ #include "backend/vulkan/BufferVk.h" #include "backend/vulkan/FramebufferVk.h" #include "backend/vulkan/RenderPassVk.h" +#include "backend/vulkan/RenderPipelineVk.h" #include "backend/vulkan/TextureVk.h" #include "backend/vulkan/VulkanBackend.h" @@ -69,7 +70,6 @@ namespace backend { namespace vulkan { Command type; while (mCommands.NextCommandId(&type)) { switch (type) { - case Command::CopyBufferToBuffer: { CopyBufferToBufferCmd* copy = mCommands.NextCommand(); auto& src = copy->source; @@ -140,8 +140,40 @@ namespace backend { namespace vulkan { beginInfo.clearValueCount = renderPass->GetAttachmentCount(); beginInfo.pClearValues = clearValues.data(); - device->fn.CmdBeginRenderPass(commands, &beginInfo, VK_SUBPASS_CONTENTS_INLINE); + + // Set all the dynamic state just in case. + device->fn.CmdSetLineWidth(commands, 1.0f); + device->fn.CmdSetDepthBounds(commands, 0.0f, 1.0f); + + float blendConstants[4] = { + 1.0f, + 1.0f, + 1.0f, + 1.0f, + }; + device->fn.CmdSetBlendConstants(commands, blendConstants); + + device->fn.CmdSetStencilCompareMask(commands, VK_STENCIL_FRONT_AND_BACK, 0); + device->fn.CmdSetStencilWriteMask(commands, VK_STENCIL_FRONT_AND_BACK, 0); + device->fn.CmdSetStencilReference(commands, VK_STENCIL_FRONT_AND_BACK, 0); + + // The viewport and scissor default to cover all of the attachments + VkViewport viewport; + viewport.x = 0.0f; + viewport.y = 0.0f; + viewport.width = static_cast(framebuffer->GetWidth()); + viewport.height = static_cast(framebuffer->GetHeight()); + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + device->fn.CmdSetViewport(commands, 0, 1, &viewport); + + VkRect2D scissorRect; + scissorRect.offset.x = 0; + scissorRect.offset.y = 0; + scissorRect.extent.width = framebuffer->GetWidth(); + scissorRect.extent.height = framebuffer->GetHeight(); + device->fn.CmdSetScissor(commands, 0, 1, &scissorRect); } break; case Command::BeginRenderSubpass: { @@ -185,6 +217,14 @@ namespace backend { namespace vulkan { VK_INDEX_TYPE_UINT16); } break; + case Command::SetRenderPipeline: { + SetRenderPipelineCmd* cmd = mCommands.NextCommand(); + RenderPipeline* pipeline = ToBackend(cmd->pipeline).Get(); + + device->fn.CmdBindPipeline(commands, VK_PIPELINE_BIND_POINT_GRAPHICS, + pipeline->GetHandle()); + } break; + case Command::SetVertexBuffers: { SetVertexBuffersCmd* cmd = mCommands.NextCommand(); auto buffers = mCommands.NextData>(cmd->count); diff --git a/src/backend/vulkan/FencedDeleter.cpp b/src/backend/vulkan/FencedDeleter.cpp index 778c3fabfe..0f6ebe32f8 100644 --- a/src/backend/vulkan/FencedDeleter.cpp +++ b/src/backend/vulkan/FencedDeleter.cpp @@ -27,8 +27,10 @@ namespace backend { namespace vulkan { ASSERT(mImagesToDelete.Empty()); ASSERT(mImageViewsToDelete.Empty()); ASSERT(mMemoriesToDelete.Empty()); + ASSERT(mPipelinesToDelete.Empty()); ASSERT(mPipelineLayoutsToDelete.Empty()); ASSERT(mRenderPassesToDelete.Empty()); + ASSERT(mShaderModulesToDelete.Empty()); } void FencedDeleter::DeleteWhenUnused(VkBuffer buffer) { @@ -51,6 +53,10 @@ namespace backend { namespace vulkan { mImageViewsToDelete.Enqueue(view, mDevice->GetSerial()); } + void FencedDeleter::DeleteWhenUnused(VkPipeline pipeline) { + mPipelinesToDelete.Enqueue(pipeline, mDevice->GetSerial()); + } + void FencedDeleter::DeleteWhenUnused(VkPipelineLayout layout) { mPipelineLayoutsToDelete.Enqueue(layout, mDevice->GetSerial()); } @@ -59,6 +65,10 @@ namespace backend { namespace vulkan { mRenderPassesToDelete.Enqueue(renderPass, mDevice->GetSerial()); } + void FencedDeleter::DeleteWhenUnused(VkShaderModule module) { + mShaderModulesToDelete.Enqueue(module, mDevice->GetSerial()); + } + void FencedDeleter::Tick(Serial completedSerial) { VkDevice vkDevice = mDevice->GetVkDevice(); @@ -98,6 +108,15 @@ namespace backend { namespace vulkan { } mImageViewsToDelete.ClearUpTo(completedSerial); + for (VkShaderModule module : mShaderModulesToDelete.IterateUpTo(completedSerial)) { + mDevice->fn.DestroyShaderModule(vkDevice, module, nullptr); + } + mShaderModulesToDelete.ClearUpTo(completedSerial); + + for (VkPipeline pipeline : mPipelinesToDelete.IterateUpTo(completedSerial)) { + mDevice->fn.DestroyPipeline(vkDevice, pipeline, nullptr); + } + mPipelinesToDelete.ClearUpTo(completedSerial); } }} // namespace backend::vulkan diff --git a/src/backend/vulkan/FencedDeleter.h b/src/backend/vulkan/FencedDeleter.h index 6b8e2a1099..d18e0a38eb 100644 --- a/src/backend/vulkan/FencedDeleter.h +++ b/src/backend/vulkan/FencedDeleter.h @@ -34,6 +34,8 @@ namespace backend { namespace vulkan { void DeleteWhenUnused(VkImageView view); void DeleteWhenUnused(VkPipelineLayout layout); void DeleteWhenUnused(VkRenderPass renderPass); + void DeleteWhenUnused(VkPipeline pipeline); + void DeleteWhenUnused(VkShaderModule module); void Tick(Serial completedSerial); @@ -44,8 +46,10 @@ namespace backend { namespace vulkan { SerialQueue mMemoriesToDelete; SerialQueue mImagesToDelete; SerialQueue mImageViewsToDelete; + SerialQueue mPipelinesToDelete; SerialQueue mPipelineLayoutsToDelete; SerialQueue mRenderPassesToDelete; + SerialQueue mShaderModulesToDelete; }; }} // namespace backend::vulkan diff --git a/src/backend/vulkan/GeneratedCodeIncludes.h b/src/backend/vulkan/GeneratedCodeIncludes.h index a0fbdbeeac..c7104fcce8 100644 --- a/src/backend/vulkan/GeneratedCodeIncludes.h +++ b/src/backend/vulkan/GeneratedCodeIncludes.h @@ -18,5 +18,7 @@ #include "backend/vulkan/InputStateVk.h" #include "backend/vulkan/PipelineLayoutVk.h" #include "backend/vulkan/RenderPassVk.h" +#include "backend/vulkan/RenderPipelineVk.h" +#include "backend/vulkan/ShaderModuleVk.h" #include "backend/vulkan/TextureVk.h" #include "backend/vulkan/VulkanBackend.h" diff --git a/src/backend/vulkan/RenderPipelineVk.cpp b/src/backend/vulkan/RenderPipelineVk.cpp new file mode 100644 index 0000000000..fd37ba3ce9 --- /dev/null +++ b/src/backend/vulkan/RenderPipelineVk.cpp @@ -0,0 +1,244 @@ +// Copyright 2018 The NXT Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "backend/vulkan/RenderPipelineVk.h" + +#include "backend/vulkan/FencedDeleter.h" +#include "backend/vulkan/InputStateVk.h" +#include "backend/vulkan/PipelineLayoutVk.h" +#include "backend/vulkan/RenderPassVk.h" +#include "backend/vulkan/ShaderModuleVk.h" +#include "backend/vulkan/VulkanBackend.h" + +namespace backend { namespace vulkan { + + namespace { + + VkPrimitiveTopology VulkanPrimitiveTopology(nxt::PrimitiveTopology topology) { + switch (topology) { + case nxt::PrimitiveTopology::PointList: + return VK_PRIMITIVE_TOPOLOGY_POINT_LIST; + case nxt::PrimitiveTopology::LineList: + return VK_PRIMITIVE_TOPOLOGY_LINE_LIST; + case nxt::PrimitiveTopology::LineStrip: + return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP; + case nxt::PrimitiveTopology::TriangleList: + return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + case nxt::PrimitiveTopology::TriangleStrip: + return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; + default: + UNREACHABLE(); + } + } + + } // anonymous namespace + + RenderPipeline::RenderPipeline(RenderPipelineBuilder* builder) + : RenderPipelineBase(builder), mDevice(ToBackend(builder->GetDevice())) { + // Eventually a bunch of the structures that need to be chained in the create info will be + // held by objects such as the BlendState. They aren't implemented yet so we initialize + // everything here. + + VkPipelineShaderStageCreateInfo shaderStages[2]; + { + const auto& vertexStageInfo = builder->GetStageInfo(nxt::ShaderStage::Vertex); + const auto& fragmentStageInfo = builder->GetStageInfo(nxt::ShaderStage::Fragment); + + shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shaderStages[0].pNext = nullptr; + shaderStages[0].flags = 0; + shaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; + shaderStages[0].module = ToBackend(vertexStageInfo.module)->GetHandle(); + shaderStages[0].pName = vertexStageInfo.entryPoint.c_str(); + shaderStages[0].pSpecializationInfo = nullptr; + + shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shaderStages[1].pNext = nullptr; + shaderStages[1].flags = 0; + shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; + shaderStages[1].module = ToBackend(fragmentStageInfo.module)->GetHandle(); + shaderStages[1].pName = fragmentStageInfo.entryPoint.c_str(); + shaderStages[1].pSpecializationInfo = nullptr; + } + + VkPipelineInputAssemblyStateCreateInfo inputAssembly; + inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + inputAssembly.pNext = nullptr; + inputAssembly.flags = 0; + inputAssembly.topology = VulkanPrimitiveTopology(GetPrimitiveTopology()); + // Primitive restart is always enabled in NXT (because of Metal) + inputAssembly.primitiveRestartEnable = VK_TRUE; + + // A dummy viewport/scissor info. The validation layers force use to provide at least one + // scissor and one viewport here, even if we choose to make them dynamic. + VkViewport viewportDesc; + viewportDesc.x = 0.0f; + viewportDesc.y = 0.0f; + viewportDesc.width = 1.0f; + viewportDesc.height = 1.0f; + viewportDesc.minDepth = 0.0f; + viewportDesc.maxDepth = 1.0f; + VkRect2D scissorRect; + scissorRect.offset.x = 0; + scissorRect.offset.y = 0; + scissorRect.extent.width = 1; + scissorRect.extent.height = 1; + VkPipelineViewportStateCreateInfo viewport; + viewport.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewport.pNext = nullptr; + viewport.flags = 0; + viewport.viewportCount = 1; + viewport.pViewports = &viewportDesc; + viewport.scissorCount = 1; + viewport.pScissors = &scissorRect; + + VkPipelineRasterizationStateCreateInfo rasterization; + rasterization.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterization.pNext = nullptr; + rasterization.flags = 0; + rasterization.depthClampEnable = VK_FALSE; + rasterization.rasterizerDiscardEnable = VK_FALSE; + rasterization.polygonMode = VK_POLYGON_MODE_FILL; + rasterization.cullMode = VK_CULL_MODE_NONE; + rasterization.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rasterization.depthBiasEnable = VK_FALSE; + rasterization.depthBiasConstantFactor = 0.0f; + rasterization.depthBiasClamp = 0.0f; + rasterization.depthBiasSlopeFactor = 0.0f; + rasterization.lineWidth = 1.0f; + + VkPipelineMultisampleStateCreateInfo multisample; + multisample.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisample.pNext = nullptr; + multisample.flags = 0; + multisample.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + multisample.sampleShadingEnable = VK_FALSE; + multisample.minSampleShading = 0.0f; + multisample.pSampleMask = nullptr; + multisample.alphaToCoverageEnable = VK_FALSE; + multisample.alphaToOneEnable = VK_FALSE; + + VkPipelineDepthStencilStateCreateInfo depthStencil; + depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + depthStencil.pNext = nullptr; + depthStencil.flags = 0; + depthStencil.depthTestEnable = VK_TRUE; + depthStencil.depthWriteEnable = VK_TRUE; + depthStencil.depthCompareOp = VK_COMPARE_OP_LESS; + depthStencil.depthBoundsTestEnable = VK_FALSE; + depthStencil.stencilTestEnable = VK_FALSE; + depthStencil.front.failOp = VK_STENCIL_OP_KEEP; + depthStencil.front.passOp = VK_STENCIL_OP_KEEP; + depthStencil.front.depthFailOp = VK_STENCIL_OP_KEEP; + depthStencil.front.compareOp = VK_COMPARE_OP_NEVER; + depthStencil.front.compareMask = 0; + depthStencil.front.writeMask = 0; + depthStencil.front.reference = 0; + depthStencil.back.failOp = VK_STENCIL_OP_KEEP; + depthStencil.back.passOp = VK_STENCIL_OP_KEEP; + depthStencil.back.depthFailOp = VK_STENCIL_OP_KEEP; + depthStencil.back.compareOp = VK_COMPARE_OP_NEVER; + depthStencil.back.compareMask = 0; + depthStencil.back.writeMask = 0; + depthStencil.back.reference = 0; + depthStencil.minDepthBounds = 0.0f; + depthStencil.maxDepthBounds = 0.0f; + + // Even when not using independent blend, we need to provide blend information for every + // single attachment. + std::array colorBlendAttachments; + for (auto& attachment : colorBlendAttachments) { + attachment.blendEnable = VK_FALSE; + attachment.srcColorBlendFactor = VK_BLEND_FACTOR_ZERO; + attachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; + attachment.colorBlendOp = VK_BLEND_OP_ADD; + attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + attachment.alphaBlendOp = VK_BLEND_OP_ADD; + attachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + } + VkPipelineColorBlendStateCreateInfo colorBlend; + colorBlend.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + colorBlend.pNext = nullptr; + colorBlend.flags = 0; + colorBlend.logicOpEnable = VK_FALSE; + colorBlend.logicOp = VK_LOGIC_OP_CLEAR; + colorBlend.attachmentCount = kMaxColorAttachments; + colorBlend.pAttachments = colorBlendAttachments.data(); + colorBlend.blendConstants[0] = 0.0f; + colorBlend.blendConstants[1] = 0.0f; + colorBlend.blendConstants[2] = 0.0f; + colorBlend.blendConstants[3] = 0.0f; + + // Tag all state as dynamic. + VkDynamicState dynamicStates[] = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, + VK_DYNAMIC_STATE_LINE_WIDTH, + VK_DYNAMIC_STATE_DEPTH_BIAS, + VK_DYNAMIC_STATE_BLEND_CONSTANTS, + VK_DYNAMIC_STATE_DEPTH_BOUNDS, + VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK, + VK_DYNAMIC_STATE_STENCIL_WRITE_MASK, + VK_DYNAMIC_STATE_STENCIL_REFERENCE, + }; + VkPipelineDynamicStateCreateInfo dynamic; + dynamic.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamic.pNext = nullptr; + dynamic.flags = 0; + dynamic.dynamicStateCount = sizeof(dynamicStates) / sizeof(dynamicStates[0]); + dynamic.pDynamicStates = dynamicStates; + + // The create info chains in a bunch of things created on the stack here or inside state + // objects. + VkGraphicsPipelineCreateInfo createInfo; + createInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + createInfo.pNext = nullptr; + createInfo.flags = 0; + createInfo.stageCount = 2; + createInfo.pStages = shaderStages; + createInfo.pVertexInputState = ToBackend(GetInputState())->GetCreateInfo(); + createInfo.pInputAssemblyState = &inputAssembly; + createInfo.pTessellationState = nullptr; + createInfo.pViewportState = &viewport; + createInfo.pRasterizationState = &rasterization; + createInfo.pMultisampleState = &multisample; + createInfo.pDepthStencilState = &depthStencil; + createInfo.pColorBlendState = &colorBlend; + createInfo.pDynamicState = &dynamic; + createInfo.layout = ToBackend(GetLayout())->GetHandle(); + createInfo.renderPass = ToBackend(GetRenderPass())->GetHandle(); + createInfo.subpass = GetSubPass(); + createInfo.basePipelineHandle = VK_NULL_HANDLE; + createInfo.basePipelineIndex = -1; + + if (mDevice->fn.CreateGraphicsPipelines(mDevice->GetVkDevice(), VK_NULL_HANDLE, 1, + &createInfo, nullptr, &mHandle) != VK_SUCCESS) { + ASSERT(false); + } + } + + RenderPipeline::~RenderPipeline() { + if (mHandle != VK_NULL_HANDLE) { + mDevice->GetFencedDeleter()->DeleteWhenUnused(mHandle); + mHandle = VK_NULL_HANDLE; + } + } + + VkPipeline RenderPipeline::GetHandle() const { + return mHandle; + } + +}} // namespace backend::vulkan diff --git a/src/backend/vulkan/RenderPipelineVk.h b/src/backend/vulkan/RenderPipelineVk.h new file mode 100644 index 0000000000..5d7a5c69f6 --- /dev/null +++ b/src/backend/vulkan/RenderPipelineVk.h @@ -0,0 +1,40 @@ +// Copyright 2018 The NXT Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef BACKEND_VULKAN_RENDERPIPELINEVK_H_ +#define BACKEND_VULKAN_RENDERPIPELINEVK_H_ + +#include "backend/RenderPipeline.h" + +#include "backend/vulkan/vulkan_platform.h" + +namespace backend { namespace vulkan { + + class Device; + + class RenderPipeline : public RenderPipelineBase { + public: + RenderPipeline(RenderPipelineBuilder* builder); + ~RenderPipeline(); + + VkPipeline GetHandle() const; + + private: + VkPipeline mHandle = VK_NULL_HANDLE; + Device* mDevice = nullptr; + }; + +}} // namespace backend::vulkan + +#endif // BACKEND_VULKAN_RENDERPIPELINEVK_H_ diff --git a/src/backend/vulkan/ShaderModuleVk.cpp b/src/backend/vulkan/ShaderModuleVk.cpp new file mode 100644 index 0000000000..8df4ea3145 --- /dev/null +++ b/src/backend/vulkan/ShaderModuleVk.cpp @@ -0,0 +1,60 @@ +// Copyright 2018 The NXT Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "backend/vulkan/ShaderModuleVk.h" + +#include "backend/vulkan/FencedDeleter.h" +#include "backend/vulkan/VulkanBackend.h" + +#include + +namespace backend { namespace vulkan { + + ShaderModule::ShaderModule(ShaderModuleBuilder* builder) : ShaderModuleBase(builder) { + std::vector spirv = builder->AcquireSpirv(); + + // Use SPIRV-Cross to extract info from the SPIRV even if Vulkan consumes SPIRV. We want to + // have a translation step eventually anyway. + spirv_cross::Compiler compiler(spirv); + ExtractSpirvInfo(compiler); + + VkShaderModuleCreateInfo createInfo; + createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + createInfo.pNext = nullptr; + createInfo.flags = 0; + createInfo.codeSize = spirv.size() * sizeof(uint32_t); + createInfo.pCode = spirv.data(); + + Device* device = ToBackend(GetDevice()); + + if (device->fn.CreateShaderModule(device->GetVkDevice(), &createInfo, nullptr, &mHandle) != + VK_SUCCESS) { + ASSERT(false); + } + } + + ShaderModule::~ShaderModule() { + Device* device = ToBackend(GetDevice()); + + if (mHandle != VK_NULL_HANDLE) { + device->GetFencedDeleter()->DeleteWhenUnused(mHandle); + mHandle = VK_NULL_HANDLE; + } + } + + VkShaderModule ShaderModule::GetHandle() const { + return mHandle; + } + +}} // namespace backend::vulkan diff --git a/src/backend/vulkan/ShaderModuleVk.h b/src/backend/vulkan/ShaderModuleVk.h new file mode 100644 index 0000000000..f7108bed32 --- /dev/null +++ b/src/backend/vulkan/ShaderModuleVk.h @@ -0,0 +1,37 @@ +// Copyright 2018 The NXT Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef BACKEND_VULKAN_SHADERMODULEVK_H_ +#define BACKEND_VULKAN_SHADERMODULEVK_H_ + +#include "backend/ShaderModule.h" + +#include "backend/vulkan/vulkan_platform.h" + +namespace backend { namespace vulkan { + + class ShaderModule : public ShaderModuleBase { + public: + ShaderModule(ShaderModuleBuilder* builder); + ~ShaderModule(); + + VkShaderModule GetHandle() const; + + private: + VkShaderModule mHandle = VK_NULL_HANDLE; + }; + +}} // namespace backend::vulkan + +#endif // BACKEND_VULKAN_SHADERMODULEVK_H_ diff --git a/src/backend/vulkan/VulkanBackend.cpp b/src/backend/vulkan/VulkanBackend.cpp index 5036afaed0..5a778f2abb 100644 --- a/src/backend/vulkan/VulkanBackend.cpp +++ b/src/backend/vulkan/VulkanBackend.cpp @@ -23,6 +23,8 @@ #include "backend/vulkan/InputStateVk.h" #include "backend/vulkan/PipelineLayoutVk.h" #include "backend/vulkan/RenderPassVk.h" +#include "backend/vulkan/RenderPipelineVk.h" +#include "backend/vulkan/ShaderModuleVk.h" #include "backend/vulkan/TextureVk.h" #include "common/Platform.h" @@ -223,12 +225,7 @@ namespace backend { namespace vulkan { return new Sampler(builder); } ShaderModuleBase* Device::CreateShaderModule(ShaderModuleBuilder* builder) { - auto module = new ShaderModule(builder); - - spirv_cross::Compiler compiler(builder->AcquireSpirv()); - module->ExtractSpirvInfo(compiler); - - return module; + return new ShaderModule(builder); } SwapChainBase* Device::CreateSwapChain(SwapChainBuilder* builder) { return new SwapChain(builder); diff --git a/src/backend/vulkan/VulkanBackend.h b/src/backend/vulkan/VulkanBackend.h index 80cd3c9fac..9050748dfd 100644 --- a/src/backend/vulkan/VulkanBackend.h +++ b/src/backend/vulkan/VulkanBackend.h @@ -24,9 +24,7 @@ #include "backend/DepthStencilState.h" #include "backend/Device.h" #include "backend/Queue.h" -#include "backend/RenderPipeline.h" #include "backend/Sampler.h" -#include "backend/ShaderModule.h" #include "backend/SwapChain.h" #include "backend/ToBackend.h" #include "backend/vulkan/VulkanFunctions.h" @@ -53,9 +51,9 @@ namespace backend { namespace vulkan { class PipelineLayout; class Queue; class RenderPass; - using RenderPipeline = RenderPipelineBase; + class RenderPipeline; using Sampler = SamplerBase; - using ShaderModule = ShaderModuleBase; + class ShaderModule; class SwapChain; class Texture; class TextureView;