dawn-cmake/src/dawn_native/vulkan/RenderPipelineVk.cpp

564 lines
26 KiB
C++
Raw Normal View History

// Copyright 2018 The Dawn Authors
2018-01-09 18:50:07 +00:00
//
// 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.
2018-07-24 11:53:51 +00:00
#include "dawn_native/vulkan/RenderPipelineVk.h"
#include "dawn_native/vulkan/DeviceVk.h"
#include "dawn_native/vulkan/FencedDeleter.h"
#include "dawn_native/vulkan/PipelineLayoutVk.h"
#include "dawn_native/vulkan/RenderPassCache.h"
#include "dawn_native/vulkan/ShaderModuleVk.h"
#include "dawn_native/vulkan/TextureVk.h"
#include "dawn_native/vulkan/UtilsVulkan.h"
#include "dawn_native/vulkan/VulkanError.h"
2018-01-09 18:50:07 +00:00
namespace dawn_native { namespace vulkan {
2018-01-09 18:50:07 +00:00
namespace {
VkVertexInputRate VulkanInputRate(dawn::InputStepMode stepMode) {
switch (stepMode) {
case dawn::InputStepMode::Vertex:
return VK_VERTEX_INPUT_RATE_VERTEX;
case dawn::InputStepMode::Instance:
return VK_VERTEX_INPUT_RATE_INSTANCE;
default:
UNREACHABLE();
}
}
VkFormat VulkanVertexFormat(dawn::VertexFormat format) {
switch (format) {
case dawn::VertexFormat::UChar2:
return VK_FORMAT_R8G8_UINT;
case dawn::VertexFormat::UChar4:
return VK_FORMAT_R8G8B8A8_UINT;
case dawn::VertexFormat::Char2:
return VK_FORMAT_R8G8_SINT;
case dawn::VertexFormat::Char4:
return VK_FORMAT_R8G8B8A8_SINT;
case dawn::VertexFormat::UChar2Norm:
return VK_FORMAT_R8G8_UNORM;
case dawn::VertexFormat::UChar4Norm:
return VK_FORMAT_R8G8B8A8_UNORM;
case dawn::VertexFormat::Char2Norm:
return VK_FORMAT_R8G8_SNORM;
case dawn::VertexFormat::Char4Norm:
return VK_FORMAT_R8G8B8A8_SNORM;
case dawn::VertexFormat::UShort2:
return VK_FORMAT_R16G16_UINT;
case dawn::VertexFormat::UShort4:
return VK_FORMAT_R16G16B16A16_UINT;
case dawn::VertexFormat::Short2:
return VK_FORMAT_R16G16_SINT;
case dawn::VertexFormat::Short4:
return VK_FORMAT_R16G16B16A16_SINT;
case dawn::VertexFormat::UShort2Norm:
return VK_FORMAT_R16G16_UNORM;
case dawn::VertexFormat::UShort4Norm:
return VK_FORMAT_R16G16B16A16_UNORM;
case dawn::VertexFormat::Short2Norm:
return VK_FORMAT_R16G16_SNORM;
case dawn::VertexFormat::Short4Norm:
return VK_FORMAT_R16G16B16A16_SNORM;
case dawn::VertexFormat::Half2:
return VK_FORMAT_R16G16_SFLOAT;
case dawn::VertexFormat::Half4:
return VK_FORMAT_R16G16B16A16_SFLOAT;
case dawn::VertexFormat::Float:
return VK_FORMAT_R32_SFLOAT;
case dawn::VertexFormat::Float2:
return VK_FORMAT_R32G32_SFLOAT;
case dawn::VertexFormat::Float3:
return VK_FORMAT_R32G32B32_SFLOAT;
case dawn::VertexFormat::Float4:
return VK_FORMAT_R32G32B32A32_SFLOAT;
case dawn::VertexFormat::UInt:
return VK_FORMAT_R32_UINT;
case dawn::VertexFormat::UInt2:
return VK_FORMAT_R32G32_UINT;
case dawn::VertexFormat::UInt3:
return VK_FORMAT_R32G32B32_UINT;
case dawn::VertexFormat::UInt4:
return VK_FORMAT_R32G32B32A32_UINT;
case dawn::VertexFormat::Int:
return VK_FORMAT_R32_SINT;
case dawn::VertexFormat::Int2:
return VK_FORMAT_R32G32_SINT;
case dawn::VertexFormat::Int3:
return VK_FORMAT_R32G32B32_SINT;
case dawn::VertexFormat::Int4:
return VK_FORMAT_R32G32B32A32_SINT;
default:
UNREACHABLE();
}
}
2018-07-18 09:38:11 +00:00
VkPrimitiveTopology VulkanPrimitiveTopology(dawn::PrimitiveTopology topology) {
2018-01-09 18:50:07 +00:00
switch (topology) {
2018-07-18 09:38:11 +00:00
case dawn::PrimitiveTopology::PointList:
2018-01-09 18:50:07 +00:00
return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
2018-07-18 09:38:11 +00:00
case dawn::PrimitiveTopology::LineList:
2018-01-09 18:50:07 +00:00
return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
2018-07-18 09:38:11 +00:00
case dawn::PrimitiveTopology::LineStrip:
2018-01-09 18:50:07 +00:00
return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
2018-07-18 09:38:11 +00:00
case dawn::PrimitiveTopology::TriangleList:
2018-01-09 18:50:07 +00:00
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
2018-07-18 09:38:11 +00:00
case dawn::PrimitiveTopology::TriangleStrip:
2018-01-09 18:50:07 +00:00
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
default:
UNREACHABLE();
}
}
bool ShouldEnablePrimitiveRestart(dawn::PrimitiveTopology topology) {
// Primitive restart is always enabled in WebGPU but Vulkan validation rules ask that
// primitive restart be only enabled on primitive topologies that support restarting.
switch (topology) {
case dawn::PrimitiveTopology::PointList:
case dawn::PrimitiveTopology::LineList:
case dawn::PrimitiveTopology::TriangleList:
return false;
case dawn::PrimitiveTopology::LineStrip:
case dawn::PrimitiveTopology::TriangleStrip:
return true;
default:
UNREACHABLE();
}
}
VkFrontFace VulkanFrontFace(dawn::FrontFace face) {
switch (face) {
case dawn::FrontFace::CCW:
return VK_FRONT_FACE_COUNTER_CLOCKWISE;
case dawn::FrontFace::CW:
return VK_FRONT_FACE_CLOCKWISE;
}
}
VkCullModeFlagBits VulkanCullMode(dawn::CullMode mode) {
switch (mode) {
case dawn::CullMode::None:
return VK_CULL_MODE_NONE;
case dawn::CullMode::Front:
return VK_CULL_MODE_FRONT_BIT;
case dawn::CullMode::Back:
return VK_CULL_MODE_BACK_BIT;
}
}
VkBlendFactor VulkanBlendFactor(dawn::BlendFactor factor) {
switch (factor) {
case dawn::BlendFactor::Zero:
return VK_BLEND_FACTOR_ZERO;
case dawn::BlendFactor::One:
return VK_BLEND_FACTOR_ONE;
case dawn::BlendFactor::SrcColor:
return VK_BLEND_FACTOR_SRC_COLOR;
case dawn::BlendFactor::OneMinusSrcColor:
return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
case dawn::BlendFactor::SrcAlpha:
return VK_BLEND_FACTOR_SRC_ALPHA;
case dawn::BlendFactor::OneMinusSrcAlpha:
return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
case dawn::BlendFactor::DstColor:
return VK_BLEND_FACTOR_DST_COLOR;
case dawn::BlendFactor::OneMinusDstColor:
return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR;
case dawn::BlendFactor::DstAlpha:
return VK_BLEND_FACTOR_DST_ALPHA;
case dawn::BlendFactor::OneMinusDstAlpha:
return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
case dawn::BlendFactor::SrcAlphaSaturated:
return VK_BLEND_FACTOR_SRC_ALPHA_SATURATE;
case dawn::BlendFactor::BlendColor:
return VK_BLEND_FACTOR_CONSTANT_COLOR;
case dawn::BlendFactor::OneMinusBlendColor:
return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR;
default:
UNREACHABLE();
}
}
VkBlendOp VulkanBlendOperation(dawn::BlendOperation operation) {
switch (operation) {
case dawn::BlendOperation::Add:
return VK_BLEND_OP_ADD;
case dawn::BlendOperation::Subtract:
return VK_BLEND_OP_SUBTRACT;
case dawn::BlendOperation::ReverseSubtract:
return VK_BLEND_OP_REVERSE_SUBTRACT;
case dawn::BlendOperation::Min:
return VK_BLEND_OP_MIN;
case dawn::BlendOperation::Max:
return VK_BLEND_OP_MAX;
default:
UNREACHABLE();
}
}
Set writemask to 0 when no fs output matches color state on Metal and Vulkan This patch fixes an undefined behaviour on Metal and Vulkan when there is a color state whose corresponding fragment output is not declared in the fragment shader. According to Vulkan SPEC (Chapter 14.3), the input values to blending or color attachment writes are undefined for components which do not correspond to a fragment shader output. Vulkan validation layer follows the SPEC that it only allows the shader to not produce a matching output if the writemask is 0, or it will report a warning when the application is against this rule. When no fragment output matches the color state in a render pipeline, the output differs on different Metal devices. On some Metal devices the fragment output will be (0, 0, 0, 0) even if it is not declared in the shader, while on others there will be no fragment outputs and the content in the color attachments is not changed. This patch fixes this issue by setting the color write mask to 0 to prevent the undefined values being written into the color attachments. With this patch, the following end2end tests will not report warnings any more when we enable the Vulkan validation layer: ObjectCachingTest.RenderPipelineDeduplicationOnLayout/Vulkan ObjectCachingTest.RenderPipelineDeduplicationOnVertexModule/Vulkan ObjectCachingTest.RenderPipelineDeduplicationOnFragmentModule/Vulkan BUG=dawn:209 TEST=dawn_end2end_tests Change-Id: I5613daa1b9a45349ea1459fbdfe4a12d6149f0f7 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/11581 Reviewed-by: Austin Eng <enga@chromium.org> Reviewed-by: Corentin Wallez <cwallez@chromium.org> Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
2019-09-30 07:27:57 +00:00
VkColorComponentFlags VulkanColorWriteMask(dawn::ColorWriteMask mask,
bool isDeclaredInFragmentShader) {
// Vulkan and Dawn color write masks match, static assert it and return the mask
static_assert(static_cast<VkColorComponentFlagBits>(dawn::ColorWriteMask::Red) ==
VK_COLOR_COMPONENT_R_BIT,
"");
static_assert(static_cast<VkColorComponentFlagBits>(dawn::ColorWriteMask::Green) ==
VK_COLOR_COMPONENT_G_BIT,
"");
static_assert(static_cast<VkColorComponentFlagBits>(dawn::ColorWriteMask::Blue) ==
VK_COLOR_COMPONENT_B_BIT,
"");
static_assert(static_cast<VkColorComponentFlagBits>(dawn::ColorWriteMask::Alpha) ==
VK_COLOR_COMPONENT_A_BIT,
"");
Set writemask to 0 when no fs output matches color state on Metal and Vulkan This patch fixes an undefined behaviour on Metal and Vulkan when there is a color state whose corresponding fragment output is not declared in the fragment shader. According to Vulkan SPEC (Chapter 14.3), the input values to blending or color attachment writes are undefined for components which do not correspond to a fragment shader output. Vulkan validation layer follows the SPEC that it only allows the shader to not produce a matching output if the writemask is 0, or it will report a warning when the application is against this rule. When no fragment output matches the color state in a render pipeline, the output differs on different Metal devices. On some Metal devices the fragment output will be (0, 0, 0, 0) even if it is not declared in the shader, while on others there will be no fragment outputs and the content in the color attachments is not changed. This patch fixes this issue by setting the color write mask to 0 to prevent the undefined values being written into the color attachments. With this patch, the following end2end tests will not report warnings any more when we enable the Vulkan validation layer: ObjectCachingTest.RenderPipelineDeduplicationOnLayout/Vulkan ObjectCachingTest.RenderPipelineDeduplicationOnVertexModule/Vulkan ObjectCachingTest.RenderPipelineDeduplicationOnFragmentModule/Vulkan BUG=dawn:209 TEST=dawn_end2end_tests Change-Id: I5613daa1b9a45349ea1459fbdfe4a12d6149f0f7 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/11581 Reviewed-by: Austin Eng <enga@chromium.org> Reviewed-by: Corentin Wallez <cwallez@chromium.org> Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
2019-09-30 07:27:57 +00:00
// According to Vulkan SPEC (Chapter 14.3): "The input values to blending or color
// attachment writes are undefined for components which do not correspond to a fragment
// shader outputs", we set the color write mask to 0 to prevent such undefined values
// being written into the color attachments.
return isDeclaredInFragmentShader ? static_cast<VkColorComponentFlags>(mask)
: static_cast<VkColorComponentFlags>(0);
}
Set writemask to 0 when no fs output matches color state on Metal and Vulkan This patch fixes an undefined behaviour on Metal and Vulkan when there is a color state whose corresponding fragment output is not declared in the fragment shader. According to Vulkan SPEC (Chapter 14.3), the input values to blending or color attachment writes are undefined for components which do not correspond to a fragment shader output. Vulkan validation layer follows the SPEC that it only allows the shader to not produce a matching output if the writemask is 0, or it will report a warning when the application is against this rule. When no fragment output matches the color state in a render pipeline, the output differs on different Metal devices. On some Metal devices the fragment output will be (0, 0, 0, 0) even if it is not declared in the shader, while on others there will be no fragment outputs and the content in the color attachments is not changed. This patch fixes this issue by setting the color write mask to 0 to prevent the undefined values being written into the color attachments. With this patch, the following end2end tests will not report warnings any more when we enable the Vulkan validation layer: ObjectCachingTest.RenderPipelineDeduplicationOnLayout/Vulkan ObjectCachingTest.RenderPipelineDeduplicationOnVertexModule/Vulkan ObjectCachingTest.RenderPipelineDeduplicationOnFragmentModule/Vulkan BUG=dawn:209 TEST=dawn_end2end_tests Change-Id: I5613daa1b9a45349ea1459fbdfe4a12d6149f0f7 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/11581 Reviewed-by: Austin Eng <enga@chromium.org> Reviewed-by: Corentin Wallez <cwallez@chromium.org> Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
2019-09-30 07:27:57 +00:00
VkPipelineColorBlendAttachmentState ComputeColorDesc(const ColorStateDescriptor* descriptor,
bool isDeclaredInFragmentShader) {
VkPipelineColorBlendAttachmentState attachment;
attachment.blendEnable = BlendEnabled(descriptor) ? VK_TRUE : VK_FALSE;
attachment.srcColorBlendFactor = VulkanBlendFactor(descriptor->colorBlend.srcFactor);
attachment.dstColorBlendFactor = VulkanBlendFactor(descriptor->colorBlend.dstFactor);
attachment.colorBlendOp = VulkanBlendOperation(descriptor->colorBlend.operation);
attachment.srcAlphaBlendFactor = VulkanBlendFactor(descriptor->alphaBlend.srcFactor);
attachment.dstAlphaBlendFactor = VulkanBlendFactor(descriptor->alphaBlend.dstFactor);
attachment.alphaBlendOp = VulkanBlendOperation(descriptor->alphaBlend.operation);
Set writemask to 0 when no fs output matches color state on Metal and Vulkan This patch fixes an undefined behaviour on Metal and Vulkan when there is a color state whose corresponding fragment output is not declared in the fragment shader. According to Vulkan SPEC (Chapter 14.3), the input values to blending or color attachment writes are undefined for components which do not correspond to a fragment shader output. Vulkan validation layer follows the SPEC that it only allows the shader to not produce a matching output if the writemask is 0, or it will report a warning when the application is against this rule. When no fragment output matches the color state in a render pipeline, the output differs on different Metal devices. On some Metal devices the fragment output will be (0, 0, 0, 0) even if it is not declared in the shader, while on others there will be no fragment outputs and the content in the color attachments is not changed. This patch fixes this issue by setting the color write mask to 0 to prevent the undefined values being written into the color attachments. With this patch, the following end2end tests will not report warnings any more when we enable the Vulkan validation layer: ObjectCachingTest.RenderPipelineDeduplicationOnLayout/Vulkan ObjectCachingTest.RenderPipelineDeduplicationOnVertexModule/Vulkan ObjectCachingTest.RenderPipelineDeduplicationOnFragmentModule/Vulkan BUG=dawn:209 TEST=dawn_end2end_tests Change-Id: I5613daa1b9a45349ea1459fbdfe4a12d6149f0f7 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/11581 Reviewed-by: Austin Eng <enga@chromium.org> Reviewed-by: Corentin Wallez <cwallez@chromium.org> Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
2019-09-30 07:27:57 +00:00
attachment.colorWriteMask =
VulkanColorWriteMask(descriptor->writeMask, isDeclaredInFragmentShader);
return attachment;
}
VkStencilOp VulkanStencilOp(dawn::StencilOperation op) {
switch (op) {
case dawn::StencilOperation::Keep:
return VK_STENCIL_OP_KEEP;
case dawn::StencilOperation::Zero:
return VK_STENCIL_OP_ZERO;
case dawn::StencilOperation::Replace:
return VK_STENCIL_OP_REPLACE;
case dawn::StencilOperation::IncrementClamp:
return VK_STENCIL_OP_INCREMENT_AND_CLAMP;
case dawn::StencilOperation::DecrementClamp:
return VK_STENCIL_OP_DECREMENT_AND_CLAMP;
case dawn::StencilOperation::Invert:
return VK_STENCIL_OP_INVERT;
case dawn::StencilOperation::IncrementWrap:
return VK_STENCIL_OP_INCREMENT_AND_WRAP;
case dawn::StencilOperation::DecrementWrap:
return VK_STENCIL_OP_DECREMENT_AND_WRAP;
default:
UNREACHABLE();
}
}
VkPipelineDepthStencilStateCreateInfo ComputeDepthStencilDesc(
const DepthStencilStateDescriptor* descriptor) {
VkPipelineDepthStencilStateCreateInfo depthStencilState;
depthStencilState.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
depthStencilState.pNext = nullptr;
depthStencilState.flags = 0;
// Depth writes only occur if depth is enabled
depthStencilState.depthTestEnable =
(descriptor->depthCompare == dawn::CompareFunction::Always &&
!descriptor->depthWriteEnabled)
? VK_FALSE
: VK_TRUE;
depthStencilState.depthWriteEnable = descriptor->depthWriteEnabled ? VK_TRUE : VK_FALSE;
depthStencilState.depthCompareOp = ToVulkanCompareOp(descriptor->depthCompare);
depthStencilState.depthBoundsTestEnable = false;
depthStencilState.minDepthBounds = 0.0f;
depthStencilState.maxDepthBounds = 1.0f;
depthStencilState.stencilTestEnable =
StencilTestEnabled(descriptor) ? VK_TRUE : VK_FALSE;
depthStencilState.front.failOp = VulkanStencilOp(descriptor->stencilFront.failOp);
depthStencilState.front.passOp = VulkanStencilOp(descriptor->stencilFront.passOp);
depthStencilState.front.depthFailOp =
VulkanStencilOp(descriptor->stencilFront.depthFailOp);
depthStencilState.front.compareOp = ToVulkanCompareOp(descriptor->stencilFront.compare);
depthStencilState.back.failOp = VulkanStencilOp(descriptor->stencilBack.failOp);
depthStencilState.back.passOp = VulkanStencilOp(descriptor->stencilBack.passOp);
depthStencilState.back.depthFailOp =
VulkanStencilOp(descriptor->stencilBack.depthFailOp);
depthStencilState.back.compareOp = ToVulkanCompareOp(descriptor->stencilBack.compare);
// Dawn doesn't have separate front and back stencil masks.
depthStencilState.front.compareMask = descriptor->stencilReadMask;
depthStencilState.back.compareMask = descriptor->stencilReadMask;
depthStencilState.front.writeMask = descriptor->stencilWriteMask;
depthStencilState.back.writeMask = descriptor->stencilWriteMask;
// The stencil reference is always dynamic
depthStencilState.front.reference = 0;
depthStencilState.back.reference = 0;
return depthStencilState;
}
2018-01-09 18:50:07 +00:00
} // anonymous namespace
// static
ResultOrError<RenderPipeline*> RenderPipeline::Create(
Device* device,
const RenderPipelineDescriptor* descriptor) {
std::unique_ptr<RenderPipeline> pipeline =
std::make_unique<RenderPipeline>(device, descriptor);
DAWN_TRY(pipeline->Initialize(descriptor));
return pipeline.release();
}
MaybeError RenderPipeline::Initialize(const RenderPipelineDescriptor* descriptor) {
Device* device = ToBackend(GetDevice());
2018-01-09 18:50:07 +00:00
VkPipelineShaderStageCreateInfo shaderStages[2];
{
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].pSpecializationInfo = nullptr;
shaderStages[0].module = ToBackend(descriptor->vertexStage.module)->GetHandle();
shaderStages[0].pName = descriptor->vertexStage.entryPoint;
2018-01-09 18:50:07 +00:00
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].pSpecializationInfo = nullptr;
shaderStages[1].module = ToBackend(descriptor->fragmentStage->module)->GetHandle();
shaderStages[1].pName = descriptor->fragmentStage->entryPoint;
2018-01-09 18:50:07 +00:00
}
std::array<VkVertexInputBindingDescription, kMaxVertexBuffers> mBindings;
std::array<VkVertexInputAttributeDescription, kMaxVertexAttributes> mAttributes;
const VertexInputDescriptor* vertexInput = GetVertexInputDescriptor();
VkPipelineVertexInputStateCreateInfo vertexInputCreateInfo =
ComputeVertexInputDesc(vertexInput, &mBindings, &mAttributes);
2018-01-09 18:50:07 +00:00
VkPipelineInputAssemblyStateCreateInfo inputAssembly;
inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
inputAssembly.pNext = nullptr;
inputAssembly.flags = 0;
inputAssembly.topology = VulkanPrimitiveTopology(GetPrimitiveTopology());
inputAssembly.primitiveRestartEnable = ShouldEnablePrimitiveRestart(GetPrimitiveTopology());
2018-01-09 18:50:07 +00:00
// 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 = VulkanCullMode(GetCullMode());
rasterization.frontFace = VulkanFrontFace(GetFrontFace());
2018-01-09 18:50:07 +00:00
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 = VulkanSampleCount(GetSampleCount());
2018-01-09 18:50:07 +00:00
multisample.sampleShadingEnable = VK_FALSE;
multisample.minSampleShading = 0.0f;
multisample.pSampleMask = nullptr;
multisample.alphaToCoverageEnable = VK_FALSE;
multisample.alphaToOneEnable = VK_FALSE;
VkPipelineDepthStencilStateCreateInfo depthStencilState =
ComputeDepthStencilDesc(GetDepthStencilStateDescriptor());
2018-02-02 16:26:51 +00:00
// Initialize the "blend state info" that will be chained in the "create info" from the data
// pre-computed in the ColorState
2018-01-09 18:50:07 +00:00
std::array<VkPipelineColorBlendAttachmentState, kMaxColorAttachments> colorBlendAttachments;
Set writemask to 0 when no fs output matches color state on Metal and Vulkan This patch fixes an undefined behaviour on Metal and Vulkan when there is a color state whose corresponding fragment output is not declared in the fragment shader. According to Vulkan SPEC (Chapter 14.3), the input values to blending or color attachment writes are undefined for components which do not correspond to a fragment shader output. Vulkan validation layer follows the SPEC that it only allows the shader to not produce a matching output if the writemask is 0, or it will report a warning when the application is against this rule. When no fragment output matches the color state in a render pipeline, the output differs on different Metal devices. On some Metal devices the fragment output will be (0, 0, 0, 0) even if it is not declared in the shader, while on others there will be no fragment outputs and the content in the color attachments is not changed. This patch fixes this issue by setting the color write mask to 0 to prevent the undefined values being written into the color attachments. With this patch, the following end2end tests will not report warnings any more when we enable the Vulkan validation layer: ObjectCachingTest.RenderPipelineDeduplicationOnLayout/Vulkan ObjectCachingTest.RenderPipelineDeduplicationOnVertexModule/Vulkan ObjectCachingTest.RenderPipelineDeduplicationOnFragmentModule/Vulkan BUG=dawn:209 TEST=dawn_end2end_tests Change-Id: I5613daa1b9a45349ea1459fbdfe4a12d6149f0f7 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/11581 Reviewed-by: Austin Eng <enga@chromium.org> Reviewed-by: Corentin Wallez <cwallez@chromium.org> Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
2019-09-30 07:27:57 +00:00
const ShaderModuleBase::FragmentOutputBaseTypes& fragmentOutputBaseTypes =
descriptor->fragmentStage->module->GetFragmentOutputBaseTypes();
for (uint32_t i : IterateBitSet(GetColorAttachmentsMask())) {
Set writemask to 0 when no fs output matches color state on Metal and Vulkan This patch fixes an undefined behaviour on Metal and Vulkan when there is a color state whose corresponding fragment output is not declared in the fragment shader. According to Vulkan SPEC (Chapter 14.3), the input values to blending or color attachment writes are undefined for components which do not correspond to a fragment shader output. Vulkan validation layer follows the SPEC that it only allows the shader to not produce a matching output if the writemask is 0, or it will report a warning when the application is against this rule. When no fragment output matches the color state in a render pipeline, the output differs on different Metal devices. On some Metal devices the fragment output will be (0, 0, 0, 0) even if it is not declared in the shader, while on others there will be no fragment outputs and the content in the color attachments is not changed. This patch fixes this issue by setting the color write mask to 0 to prevent the undefined values being written into the color attachments. With this patch, the following end2end tests will not report warnings any more when we enable the Vulkan validation layer: ObjectCachingTest.RenderPipelineDeduplicationOnLayout/Vulkan ObjectCachingTest.RenderPipelineDeduplicationOnVertexModule/Vulkan ObjectCachingTest.RenderPipelineDeduplicationOnFragmentModule/Vulkan BUG=dawn:209 TEST=dawn_end2end_tests Change-Id: I5613daa1b9a45349ea1459fbdfe4a12d6149f0f7 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/11581 Reviewed-by: Austin Eng <enga@chromium.org> Reviewed-by: Corentin Wallez <cwallez@chromium.org> Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
2019-09-30 07:27:57 +00:00
const ColorStateDescriptor* colorStateDescriptor = GetColorStateDescriptor(i);
bool isDeclaredInFragmentShader = fragmentOutputBaseTypes[i] != Format::Other;
colorBlendAttachments[i] =
ComputeColorDesc(colorStateDescriptor, isDeclaredInFragmentShader);
2018-01-09 18:50:07 +00:00
}
VkPipelineColorBlendStateCreateInfo colorBlend;
colorBlend.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
colorBlend.pNext = nullptr;
colorBlend.flags = 0;
2018-02-02 16:26:51 +00:00
// LogicOp isn't supported so we disable it.
2018-01-09 18:50:07 +00:00
colorBlend.logicOpEnable = VK_FALSE;
colorBlend.logicOp = VK_LOGIC_OP_CLEAR;
2018-02-02 16:26:51 +00:00
// TODO(cwallez@chromium.org): Do we allow holes in the color attachments?
colorBlend.attachmentCount = static_cast<uint32_t>(GetColorAttachmentsMask().count());
2018-01-09 18:50:07 +00:00
colorBlend.pAttachments = colorBlendAttachments.data();
2018-02-02 16:26:51 +00:00
// The blend constant is always dynamic so we fill in a dummy value
2018-01-09 18:50:07 +00:00
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 but stencil masks.
2018-01-09 18:50:07 +00:00
VkDynamicState dynamicStates[] = {
2018-07-24 11:53:51 +00:00
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,
2018-01-09 18:50:07 +00:00
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;
// Get a VkRenderPass that matches the attachment formats for this pipeline, load ops don't
// matter so set them all to LoadOp::Load
VkRenderPass renderPass = VK_NULL_HANDLE;
{
RenderPassCacheQuery query;
for (uint32_t i : IterateBitSet(GetColorAttachmentsMask())) {
query.SetColor(i, GetColorAttachmentFormat(i), dawn::LoadOp::Load, false);
}
if (HasDepthStencilAttachment()) {
2018-07-18 09:38:11 +00:00
query.SetDepthStencil(GetDepthStencilFormat(), dawn::LoadOp::Load,
dawn::LoadOp::Load);
}
query.SetSampleCount(GetSampleCount());
DAWN_TRY_ASSIGN(renderPass, device->GetRenderPassCache()->GetRenderPass(query));
}
2018-01-09 18:50:07 +00:00
// 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 = &vertexInputCreateInfo;
2018-01-09 18:50:07 +00:00
createInfo.pInputAssemblyState = &inputAssembly;
createInfo.pTessellationState = nullptr;
createInfo.pViewportState = &viewport;
createInfo.pRasterizationState = &rasterization;
createInfo.pMultisampleState = &multisample;
createInfo.pDepthStencilState = &depthStencilState;
2018-01-09 18:50:07 +00:00
createInfo.pColorBlendState = &colorBlend;
createInfo.pDynamicState = &dynamic;
createInfo.layout = ToBackend(GetLayout())->GetHandle();
createInfo.renderPass = renderPass;
createInfo.subpass = 0;
2018-01-09 18:50:07 +00:00
createInfo.basePipelineHandle = VK_NULL_HANDLE;
createInfo.basePipelineIndex = -1;
return CheckVkSuccess(
device->fn.CreateGraphicsPipelines(device->GetVkDevice(), VK_NULL_HANDLE, 1,
&createInfo, nullptr, &mHandle),
"CreateGraphicsPipeline");
2018-01-09 18:50:07 +00:00
}
VkPipelineVertexInputStateCreateInfo RenderPipeline::ComputeVertexInputDesc(
const VertexInputDescriptor* vertexInput,
std::array<VkVertexInputBindingDescription, kMaxVertexBuffers>* mBindings,
std::array<VkVertexInputAttributeDescription, kMaxVertexAttributes>* mAttributes) {
// Fill in the "binding info" that will be chained in the create info
uint32_t bindingCount = 0;
for (uint32_t i : IterateBitSet(GetInputsSetMask())) {
const auto& bindingInfo = GetInput(i);
auto& bindingDesc = (*mBindings)[bindingCount];
bindingDesc.binding = i;
bindingDesc.stride = bindingInfo.stride;
bindingDesc.inputRate = VulkanInputRate(bindingInfo.stepMode);
bindingCount++;
}
// Fill in the "attribute info" that will be chained in the create info
uint32_t attributeCount = 0;
for (uint32_t i : IterateBitSet(GetAttributesSetMask())) {
const auto& attributeInfo = GetAttribute(i);
auto& attributeDesc = (*mAttributes)[attributeCount];
attributeDesc.location = i;
attributeDesc.binding = attributeInfo.inputSlot;
attributeDesc.format = VulkanVertexFormat(attributeInfo.format);
attributeDesc.offset = attributeInfo.offset;
attributeCount++;
}
// Build the create info
VkPipelineVertexInputStateCreateInfo mCreateInfo;
mCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
mCreateInfo.pNext = nullptr;
mCreateInfo.flags = 0;
mCreateInfo.vertexBindingDescriptionCount = bindingCount;
mCreateInfo.pVertexBindingDescriptions = &(*mBindings)[0];
mCreateInfo.vertexAttributeDescriptionCount = attributeCount;
mCreateInfo.pVertexAttributeDescriptions = &(*mAttributes)[0];
return mCreateInfo;
}
2018-01-09 18:50:07 +00:00
RenderPipeline::~RenderPipeline() {
if (mHandle != VK_NULL_HANDLE) {
ToBackend(GetDevice())->GetFencedDeleter()->DeleteWhenUnused(mHandle);
2018-01-09 18:50:07 +00:00
mHandle = VK_NULL_HANDLE;
}
}
VkPipeline RenderPipeline::GetHandle() const {
return mHandle;
}
}} // namespace dawn_native::vulkan