| // Copyright 2018 The SwiftShader Authors. All Rights Reserved. |
| // |
| // 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 <Pipeline/SpirvShader.hpp> |
| #include "VkPipeline.hpp" |
| #include "VkShaderModule.hpp" |
| |
| namespace |
| { |
| |
| sw::DrawType Convert(VkPrimitiveTopology topology) |
| { |
| switch(topology) |
| { |
| case VK_PRIMITIVE_TOPOLOGY_POINT_LIST: |
| return sw::DRAW_POINTLIST; |
| case VK_PRIMITIVE_TOPOLOGY_LINE_LIST: |
| return sw::DRAW_LINELIST; |
| case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP: |
| return sw::DRAW_LINESTRIP; |
| case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: |
| return sw::DRAW_TRIANGLELIST; |
| case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: |
| return sw::DRAW_TRIANGLESTRIP; |
| case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN: |
| return sw::DRAW_TRIANGLEFAN; |
| case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY: |
| case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY: |
| case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY: |
| case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY: |
| // geometry shader specific |
| ASSERT(false); |
| break; |
| case VK_PRIMITIVE_TOPOLOGY_PATCH_LIST: |
| // tesselation shader specific |
| ASSERT(false); |
| break; |
| default: |
| UNIMPLEMENTED(); |
| } |
| |
| return sw::DRAW_TRIANGLELIST; |
| } |
| |
| sw::Rect Convert(const VkRect2D& rect) |
| { |
| return sw::Rect(rect.offset.x, rect.offset.y, rect.offset.x + rect.extent.width, rect.offset.y + rect.extent.height); |
| } |
| |
| sw::StreamType getStreamType(VkFormat format) |
| { |
| switch(format) |
| { |
| case VK_FORMAT_R8_UNORM: |
| case VK_FORMAT_R8G8_UNORM: |
| case VK_FORMAT_R8G8B8A8_UNORM: |
| case VK_FORMAT_R8_UINT: |
| case VK_FORMAT_R8G8_UINT: |
| case VK_FORMAT_R8G8B8A8_UINT: |
| case VK_FORMAT_B8G8R8A8_UNORM: |
| case VK_FORMAT_A8B8G8R8_UNORM_PACK32: |
| case VK_FORMAT_A8B8G8R8_UINT_PACK32: |
| return sw::STREAMTYPE_BYTE; |
| case VK_FORMAT_R8_SNORM: |
| case VK_FORMAT_R8_SINT: |
| case VK_FORMAT_R8G8_SNORM: |
| case VK_FORMAT_R8G8_SINT: |
| case VK_FORMAT_R8G8B8A8_SNORM: |
| case VK_FORMAT_R8G8B8A8_SINT: |
| case VK_FORMAT_A8B8G8R8_SNORM_PACK32: |
| case VK_FORMAT_A8B8G8R8_SINT_PACK32: |
| return sw::STREAMTYPE_SBYTE; |
| case VK_FORMAT_A2B10G10R10_UNORM_PACK32: |
| return sw::STREAMTYPE_2_10_10_10_UINT; |
| case VK_FORMAT_R16_UNORM: |
| case VK_FORMAT_R16_UINT: |
| case VK_FORMAT_R16G16_UNORM: |
| case VK_FORMAT_R16G16_UINT: |
| case VK_FORMAT_R16G16B16A16_UNORM: |
| case VK_FORMAT_R16G16B16A16_UINT: |
| return sw::STREAMTYPE_USHORT; |
| case VK_FORMAT_R16_SNORM: |
| case VK_FORMAT_R16_SINT: |
| case VK_FORMAT_R16G16_SNORM: |
| case VK_FORMAT_R16G16_SINT: |
| case VK_FORMAT_R16G16B16A16_SNORM: |
| case VK_FORMAT_R16G16B16A16_SINT: |
| return sw::STREAMTYPE_SHORT; |
| case VK_FORMAT_R16_SFLOAT: |
| case VK_FORMAT_R16G16_SFLOAT: |
| case VK_FORMAT_R16G16B16A16_SFLOAT: |
| return sw::STREAMTYPE_HALF; |
| case VK_FORMAT_R32_UINT: |
| case VK_FORMAT_R32G32_UINT: |
| case VK_FORMAT_R32G32B32_UINT: |
| case VK_FORMAT_R32G32B32A32_UINT: |
| return sw::STREAMTYPE_UINT; |
| case VK_FORMAT_R32_SINT: |
| case VK_FORMAT_R32G32_SINT: |
| case VK_FORMAT_R32G32B32_SINT: |
| case VK_FORMAT_R32G32B32A32_SINT: |
| return sw::STREAMTYPE_INT; |
| case VK_FORMAT_R32_SFLOAT: |
| case VK_FORMAT_R32G32_SFLOAT: |
| case VK_FORMAT_R32G32B32_SFLOAT: |
| case VK_FORMAT_R32G32B32A32_SFLOAT: |
| return sw::STREAMTYPE_FLOAT; |
| default: |
| UNIMPLEMENTED(); |
| } |
| |
| return sw::STREAMTYPE_BYTE; |
| } |
| |
| uint32_t getNumberOfChannels(VkFormat format) |
| { |
| switch(format) |
| { |
| case VK_FORMAT_R8_UNORM: |
| case VK_FORMAT_R8_SNORM: |
| case VK_FORMAT_R8_UINT: |
| case VK_FORMAT_R8_SINT: |
| case VK_FORMAT_R16_UNORM: |
| case VK_FORMAT_R16_SNORM: |
| case VK_FORMAT_R16_UINT: |
| case VK_FORMAT_R16_SINT: |
| case VK_FORMAT_R16_SFLOAT: |
| case VK_FORMAT_R32_UINT: |
| case VK_FORMAT_R32_SINT: |
| case VK_FORMAT_R32_SFLOAT: |
| return 1; |
| case VK_FORMAT_R8G8_UNORM: |
| case VK_FORMAT_R8G8_SNORM: |
| case VK_FORMAT_R8G8_UINT: |
| case VK_FORMAT_R8G8_SINT: |
| case VK_FORMAT_R16G16_UNORM: |
| case VK_FORMAT_R16G16_SNORM: |
| case VK_FORMAT_R16G16_UINT: |
| case VK_FORMAT_R16G16_SINT: |
| case VK_FORMAT_R16G16_SFLOAT: |
| case VK_FORMAT_R32G32_UINT: |
| case VK_FORMAT_R32G32_SINT: |
| case VK_FORMAT_R32G32_SFLOAT: |
| return 2; |
| case VK_FORMAT_R32G32B32_UINT: |
| case VK_FORMAT_R32G32B32_SINT: |
| case VK_FORMAT_R32G32B32_SFLOAT: |
| return 3; |
| case VK_FORMAT_R8G8B8A8_UNORM: |
| case VK_FORMAT_R8G8B8A8_SNORM: |
| case VK_FORMAT_R8G8B8A8_UINT: |
| case VK_FORMAT_R8G8B8A8_SINT: |
| case VK_FORMAT_B8G8R8A8_UNORM: |
| case VK_FORMAT_A8B8G8R8_UNORM_PACK32: |
| case VK_FORMAT_A8B8G8R8_SNORM_PACK32: |
| case VK_FORMAT_A8B8G8R8_UINT_PACK32: |
| case VK_FORMAT_A8B8G8R8_SINT_PACK32: |
| case VK_FORMAT_A2B10G10R10_UNORM_PACK32: |
| case VK_FORMAT_R16G16B16A16_UNORM: |
| case VK_FORMAT_R16G16B16A16_SNORM: |
| case VK_FORMAT_R16G16B16A16_UINT: |
| case VK_FORMAT_R16G16B16A16_SINT: |
| case VK_FORMAT_R16G16B16A16_SFLOAT: |
| case VK_FORMAT_R32G32B32A32_UINT: |
| case VK_FORMAT_R32G32B32A32_SINT: |
| case VK_FORMAT_R32G32B32A32_SFLOAT: |
| return 4; |
| default: |
| UNIMPLEMENTED(); |
| } |
| |
| return 0; |
| } |
| |
| } |
| |
| namespace vk |
| { |
| |
| GraphicsPipeline::GraphicsPipeline(const VkGraphicsPipelineCreateInfo* pCreateInfo, void* mem) |
| { |
| if((pCreateInfo->flags != 0) || |
| (pCreateInfo->stageCount != 2) || |
| (pCreateInfo->pTessellationState != nullptr) || |
| (pCreateInfo->pDynamicState != nullptr) || |
| (pCreateInfo->subpass != 0) || |
| (pCreateInfo->basePipelineHandle != VK_NULL_HANDLE) || |
| (pCreateInfo->basePipelineIndex != 0)) |
| { |
| UNIMPLEMENTED(); |
| } |
| |
| const VkPipelineShaderStageCreateInfo& vertexStage = pCreateInfo->pStages[0]; |
| if((vertexStage.stage != VK_SHADER_STAGE_VERTEX_BIT) || |
| (vertexStage.flags != 0) || |
| !((vertexStage.pSpecializationInfo == nullptr) || |
| ((vertexStage.pSpecializationInfo->mapEntryCount == 0) && |
| (vertexStage.pSpecializationInfo->dataSize == 0)))) |
| { |
| UNIMPLEMENTED(); |
| } |
| |
| const VkPipelineShaderStageCreateInfo& fragmentStage = pCreateInfo->pStages[1]; |
| if((fragmentStage.stage != VK_SHADER_STAGE_FRAGMENT_BIT) || |
| (fragmentStage.flags != 0) || |
| !((fragmentStage.pSpecializationInfo == nullptr) || |
| ((fragmentStage.pSpecializationInfo->mapEntryCount == 0) && |
| (fragmentStage.pSpecializationInfo->dataSize == 0)))) |
| { |
| UNIMPLEMENTED(); |
| } |
| |
| const VkPipelineVertexInputStateCreateInfo* vertexInputState = pCreateInfo->pVertexInputState; |
| if(vertexInputState->flags != 0) |
| { |
| UNIMPLEMENTED(); |
| } |
| |
| for(uint32_t i = 0; i < vertexInputState->vertexBindingDescriptionCount; i++) |
| { |
| const VkVertexInputBindingDescription* vertexBindingDescription = vertexInputState->pVertexBindingDescriptions; |
| context.input[vertexBindingDescription->binding].stride = vertexBindingDescription->stride; |
| if(vertexBindingDescription->inputRate != VK_VERTEX_INPUT_RATE_VERTEX) |
| { |
| UNIMPLEMENTED(); |
| } |
| } |
| |
| for(uint32_t i = 0; i < vertexInputState->vertexAttributeDescriptionCount; i++) |
| { |
| const VkVertexInputAttributeDescription* vertexAttributeDescriptions = vertexInputState->pVertexAttributeDescriptions; |
| sw::Stream& input = context.input[vertexAttributeDescriptions->binding]; |
| input.count = getNumberOfChannels(vertexAttributeDescriptions->format); |
| input.type = getStreamType(vertexAttributeDescriptions->format); |
| input.normalized = !sw::Surface::isNonNormalizedInteger(vertexAttributeDescriptions->format); |
| |
| if(vertexAttributeDescriptions->location != vertexAttributeDescriptions->binding) |
| { |
| UNIMPLEMENTED(); |
| } |
| if(vertexAttributeDescriptions->offset != 0) |
| { |
| UNIMPLEMENTED(); |
| } |
| } |
| |
| const VkPipelineInputAssemblyStateCreateInfo* assemblyState = pCreateInfo->pInputAssemblyState; |
| if((assemblyState->flags != 0) || |
| (assemblyState->primitiveRestartEnable != 0)) |
| { |
| UNIMPLEMENTED(); |
| } |
| |
| context.drawType = Convert(assemblyState->topology); |
| |
| const VkPipelineViewportStateCreateInfo* viewportState = pCreateInfo->pViewportState; |
| if((viewportState->flags != 0) || |
| (viewportState->viewportCount != 1) || |
| (viewportState->scissorCount != 1)) |
| { |
| UNIMPLEMENTED(); |
| } |
| |
| scissor = Convert(viewportState->pScissors[0]); |
| viewport = viewportState->pViewports[0]; |
| |
| const VkPipelineRasterizationStateCreateInfo* rasterizationState = pCreateInfo->pRasterizationState; |
| if((rasterizationState->flags != 0) || |
| (rasterizationState->depthClampEnable != 0) || |
| (rasterizationState->polygonMode != VK_POLYGON_MODE_FILL)) |
| { |
| UNIMPLEMENTED(); |
| } |
| |
| context.rasterizerDiscard = rasterizationState->rasterizerDiscardEnable; |
| context.frontFacingCCW = rasterizationState->frontFace == VK_FRONT_FACE_COUNTER_CLOCKWISE; |
| context.depthBias = (rasterizationState->depthBiasEnable ? rasterizationState->depthBiasConstantFactor : 0.0f); |
| context.slopeDepthBias = (rasterizationState->depthBiasEnable ? rasterizationState->depthBiasSlopeFactor : 0.0f); |
| |
| const VkPipelineMultisampleStateCreateInfo* multisampleState = pCreateInfo->pMultisampleState; |
| if((multisampleState->flags != 0) || |
| (multisampleState->rasterizationSamples != VK_SAMPLE_COUNT_1_BIT) || |
| (multisampleState->sampleShadingEnable != 0) || |
| !((multisampleState->pSampleMask == nullptr) || |
| (*(multisampleState->pSampleMask) == 0xFFFFFFFFu)) || |
| (multisampleState->alphaToCoverageEnable != 0) || |
| (multisampleState->alphaToOneEnable != 0)) |
| { |
| UNIMPLEMENTED(); |
| } |
| |
| const VkPipelineDepthStencilStateCreateInfo* depthStencilState = pCreateInfo->pDepthStencilState; |
| if((depthStencilState->flags != 0) || |
| (depthStencilState->depthBoundsTestEnable != 0) || |
| (depthStencilState->minDepthBounds != 0.0f) || |
| (depthStencilState->maxDepthBounds != 1.0f)) |
| { |
| UNIMPLEMENTED(); |
| } |
| |
| context.depthBufferEnable = depthStencilState->depthTestEnable; |
| context.depthWriteEnable = depthStencilState->depthWriteEnable; |
| context.depthCompareMode = depthStencilState->depthCompareOp; |
| |
| context.stencilEnable = context.twoSidedStencil = depthStencilState->stencilTestEnable; |
| if(context.stencilEnable) |
| { |
| context.stencilMask = depthStencilState->front.compareMask; |
| context.stencilCompareMode = depthStencilState->front.compareOp; |
| context.stencilZFailOperation = depthStencilState->front.depthFailOp; |
| context.stencilFailOperation = depthStencilState->front.failOp; |
| context.stencilPassOperation = depthStencilState->front.passOp; |
| context.stencilReference = depthStencilState->front.reference; |
| context.stencilWriteMask = depthStencilState->front.writeMask; |
| |
| context.stencilMaskCCW = depthStencilState->back.compareMask; |
| context.stencilCompareModeCCW = depthStencilState->back.compareOp; |
| context.stencilZFailOperationCCW = depthStencilState->back.depthFailOp; |
| context.stencilFailOperationCCW = depthStencilState->back.failOp; |
| context.stencilPassOperationCCW = depthStencilState->back.passOp; |
| context.stencilReferenceCCW = depthStencilState->back.reference; |
| context.stencilWriteMaskCCW = depthStencilState->back.writeMask; |
| } |
| |
| const VkPipelineColorBlendStateCreateInfo* colorBlendState = pCreateInfo->pColorBlendState; |
| if((colorBlendState->flags != 0) || |
| ((colorBlendState->logicOpEnable != 0) && |
| (colorBlendState->attachmentCount > 1))) |
| { |
| UNIMPLEMENTED(); |
| } |
| |
| context.colorLogicOpEnabled = colorBlendState->logicOpEnable; |
| context.logicalOperation = colorBlendState->logicOp; |
| blendConstants.r = colorBlendState->blendConstants[0]; |
| blendConstants.g = colorBlendState->blendConstants[1]; |
| blendConstants.b = colorBlendState->blendConstants[2]; |
| blendConstants.a = colorBlendState->blendConstants[3]; |
| |
| if(colorBlendState->attachmentCount == 1) |
| { |
| const VkPipelineColorBlendAttachmentState& attachment = colorBlendState->pAttachments[0]; |
| if(attachment.colorWriteMask != (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT)) |
| { |
| UNIMPLEMENTED(); |
| } |
| |
| context.alphaBlendEnable = attachment.blendEnable; |
| context.separateAlphaBlendEnable = (attachment.alphaBlendOp != attachment.colorBlendOp) || |
| (attachment.dstAlphaBlendFactor != attachment.dstColorBlendFactor) || |
| (attachment.srcAlphaBlendFactor != attachment.srcColorBlendFactor); |
| context.blendOperationStateAlpha = attachment.alphaBlendOp; |
| context.blendOperationState = attachment.colorBlendOp; |
| context.destBlendFactorStateAlpha = attachment.dstAlphaBlendFactor; |
| context.destBlendFactorState = attachment.dstColorBlendFactor; |
| context.sourceBlendFactorStateAlpha = attachment.srcAlphaBlendFactor; |
| context.sourceBlendFactorState = attachment.srcColorBlendFactor; |
| } |
| } |
| |
| void GraphicsPipeline::destroyPipeline(const VkAllocationCallbacks* pAllocator) |
| { |
| delete vertexShader; |
| delete fragmentShader; |
| } |
| |
| size_t GraphicsPipeline::ComputeRequiredAllocationSize(const VkGraphicsPipelineCreateInfo* pCreateInfo) |
| { |
| return 0; |
| } |
| |
| void GraphicsPipeline::compileShaders(const VkAllocationCallbacks* pAllocator, const VkGraphicsPipelineCreateInfo* pCreateInfo) |
| { |
| for (auto pStage = pCreateInfo->pStages; pStage != pCreateInfo->pStages + pCreateInfo->stageCount; pStage++) { |
| auto module = Cast(pStage->module); |
| |
| // TODO: apply prep passes using SPIRV-Opt here. |
| // - Apply and freeze specializations, etc. |
| auto code = module->getCode(); |
| |
| // TODO: pass in additional information here: |
| // - any NOS from pCreateInfo which we'll actually need |
| auto spirvShader = new sw::SpirvShader{code}; |
| |
| switch (pStage->stage) { |
| case VK_SHADER_STAGE_VERTEX_BIT: |
| vertexShader = spirvShader; |
| break; |
| |
| case VK_SHADER_STAGE_FRAGMENT_BIT: |
| fragmentShader = spirvShader; |
| break; |
| |
| default: |
| UNIMPLEMENTED("Unsupported stage"); |
| } |
| } |
| } |
| |
| uint32_t GraphicsPipeline::computePrimitiveCount(uint32_t vertexCount) const |
| { |
| switch(context.drawType) |
| { |
| case sw::DRAW_POINTLIST: |
| return vertexCount; |
| case sw::DRAW_LINELIST: |
| return vertexCount / 2; |
| case sw::DRAW_LINESTRIP: |
| return vertexCount - 1; |
| case sw::DRAW_TRIANGLELIST: |
| return vertexCount / 3; |
| case sw::DRAW_TRIANGLESTRIP: |
| return vertexCount - 2; |
| case sw::DRAW_TRIANGLEFAN: |
| return vertexCount - 2; |
| default: |
| UNIMPLEMENTED(); |
| } |
| |
| return 0; |
| } |
| |
| const sw::Context& GraphicsPipeline::getContext() const |
| { |
| return context; |
| } |
| |
| const sw::Rect& GraphicsPipeline::getScissor() const |
| { |
| return scissor; |
| } |
| |
| const VkViewport& GraphicsPipeline::getViewport() const |
| { |
| return viewport; |
| } |
| |
| const sw::Color<float>& GraphicsPipeline::getBlendConstants() const |
| { |
| return blendConstants; |
| } |
| |
| ComputePipeline::ComputePipeline(const VkComputePipelineCreateInfo* pCreateInfo, void* mem) |
| { |
| } |
| |
| void ComputePipeline::destroyPipeline(const VkAllocationCallbacks* pAllocator) |
| { |
| } |
| |
| size_t ComputePipeline::ComputeRequiredAllocationSize(const VkComputePipelineCreateInfo* pCreateInfo) |
| { |
| return 0; |
| } |
| |
| } // namespace vk |