diff --git a/src/backend/CMakeLists.txt b/src/backend/CMakeLists.txt index dcbbbdeb68..9a5fee24a9 100644 --- a/src/backend/CMakeLists.txt +++ b/src/backend/CMakeLists.txt @@ -288,6 +288,8 @@ if (NXT_ENABLE_VULKAN) target_include_directories(vulkan_autogen PUBLIC ${SRC_DIR}) list(APPEND BACKEND_SOURCES + ${VULKAN_DIR}/BlendStateVk.cpp + ${VULKAN_DIR}/BlendStateVk.h ${VULKAN_DIR}/BufferUploader.cpp ${VULKAN_DIR}/BufferUploader.h ${VULKAN_DIR}/BufferVk.cpp diff --git a/src/backend/vulkan/BlendStateVk.cpp b/src/backend/vulkan/BlendStateVk.cpp new file mode 100644 index 0000000000..33fbb66945 --- /dev/null +++ b/src/backend/vulkan/BlendStateVk.cpp @@ -0,0 +1,110 @@ +// 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/BlendStateVk.h" + +#include "common/Assert.h" + +namespace backend { namespace vulkan { + + namespace { + VkBlendFactor VulkanBlendFactor(nxt::BlendFactor factor) { + switch (factor) { + case nxt::BlendFactor::Zero: + return VK_BLEND_FACTOR_ZERO; + case nxt::BlendFactor::One: + return VK_BLEND_FACTOR_ONE; + case nxt::BlendFactor::SrcColor: + return VK_BLEND_FACTOR_SRC_COLOR; + case nxt::BlendFactor::OneMinusSrcColor: + return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR; + case nxt::BlendFactor::SrcAlpha: + return VK_BLEND_FACTOR_SRC_ALPHA; + case nxt::BlendFactor::OneMinusSrcAlpha: + return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + case nxt::BlendFactor::DstColor: + return VK_BLEND_FACTOR_DST_COLOR; + case nxt::BlendFactor::OneMinusDstColor: + return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR; + case nxt::BlendFactor::DstAlpha: + return VK_BLEND_FACTOR_DST_ALPHA; + case nxt::BlendFactor::OneMinusDstAlpha: + return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA; + case nxt::BlendFactor::SrcAlphaSaturated: + return VK_BLEND_FACTOR_SRC_ALPHA_SATURATE; + case nxt::BlendFactor::BlendColor: + return VK_BLEND_FACTOR_CONSTANT_COLOR; + case nxt::BlendFactor::OneMinusBlendColor: + return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR; + default: + UNREACHABLE(); + } + } + + VkBlendOp VulkanBlendOperation(nxt::BlendOperation operation) { + switch (operation) { + case nxt::BlendOperation::Add: + return VK_BLEND_OP_ADD; + case nxt::BlendOperation::Subtract: + return VK_BLEND_OP_SUBTRACT; + case nxt::BlendOperation::ReverseSubtract: + return VK_BLEND_OP_REVERSE_SUBTRACT; + case nxt::BlendOperation::Min: + return VK_BLEND_OP_MIN; + case nxt::BlendOperation::Max: + return VK_BLEND_OP_MAX; + default: + UNREACHABLE(); + } + } + + VkColorComponentFlagBits VulkanColorWriteMask(nxt::ColorWriteMask mask) { + // Vulkan and NXT color write masks match, static assert it and return the mask + static_assert(static_cast(nxt::ColorWriteMask::Red) == + VK_COLOR_COMPONENT_R_BIT, + ""); + static_assert(static_cast(nxt::ColorWriteMask::Green) == + VK_COLOR_COMPONENT_G_BIT, + ""); + static_assert(static_cast(nxt::ColorWriteMask::Blue) == + VK_COLOR_COMPONENT_B_BIT, + ""); + static_assert(static_cast(nxt::ColorWriteMask::Alpha) == + VK_COLOR_COMPONENT_A_BIT, + ""); + + return static_cast(mask); + } + } // anonymous namespace + + BlendState::BlendState(BlendStateBuilder* builder) : BlendStateBase(builder) { + // Fill the "color blend attachment info" that will be copied in an array and chained in + // the pipeline create info. + const auto& info = GetBlendInfo(); + + mState.blendEnable = info.blendEnabled ? VK_TRUE : VK_FALSE; + mState.srcColorBlendFactor = VulkanBlendFactor(info.colorBlend.srcFactor); + mState.dstColorBlendFactor = VulkanBlendFactor(info.colorBlend.dstFactor); + mState.colorBlendOp = VulkanBlendOperation(info.colorBlend.operation); + mState.srcAlphaBlendFactor = VulkanBlendFactor(info.alphaBlend.srcFactor); + mState.dstAlphaBlendFactor = VulkanBlendFactor(info.alphaBlend.dstFactor); + mState.alphaBlendOp = VulkanBlendOperation(info.alphaBlend.operation); + mState.colorWriteMask = VulkanColorWriteMask(info.colorWriteMask); + } + + const VkPipelineColorBlendAttachmentState& BlendState::GetState() const { + return mState; + } + +}} // namespace backend::vulkan diff --git a/src/backend/vulkan/BlendStateVk.h b/src/backend/vulkan/BlendStateVk.h new file mode 100644 index 0000000000..943e366880 --- /dev/null +++ b/src/backend/vulkan/BlendStateVk.h @@ -0,0 +1,39 @@ +// 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_BLENDSTATEVK_H_ +#define BACKEND_VULKAN_BLENDSTATEVK_H_ + +#include "backend/BlendState.h" + +#include "common/vulkan_platform.h" + +namespace backend { namespace vulkan { + + class Device; + + // Pre-computes the blend state configuration to give to a graphics pipeline create info. + class BlendState : public BlendStateBase { + public: + BlendState(BlendStateBuilder* builder); + + const VkPipelineColorBlendAttachmentState& GetState() const; + + private: + VkPipelineColorBlendAttachmentState mState; + }; + +}} // namespace backend::vulkan + +#endif // BACKEND_VULKAN_BLENDSTATEVK_H_ diff --git a/src/backend/vulkan/GeneratedCodeIncludes.h b/src/backend/vulkan/GeneratedCodeIncludes.h index 7b20269ccf..a4d8db552c 100644 --- a/src/backend/vulkan/GeneratedCodeIncludes.h +++ b/src/backend/vulkan/GeneratedCodeIncludes.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "backend/vulkan/BlendStateVk.h" #include "backend/vulkan/BufferVk.h" #include "backend/vulkan/CommandBufferVk.h" #include "backend/vulkan/FramebufferVk.h" diff --git a/src/backend/vulkan/RenderPipelineVk.cpp b/src/backend/vulkan/RenderPipelineVk.cpp index fd37ba3ce9..adea5363fc 100644 --- a/src/backend/vulkan/RenderPipelineVk.cpp +++ b/src/backend/vulkan/RenderPipelineVk.cpp @@ -14,6 +14,7 @@ #include "backend/vulkan/RenderPipelineVk.h" +#include "backend/vulkan/BlendStateVk.h" #include "backend/vulkan/FencedDeleter.h" #include "backend/vulkan/InputStateVk.h" #include "backend/vulkan/PipelineLayoutVk.h" @@ -155,28 +156,25 @@ namespace backend { namespace vulkan { depthStencil.minDepthBounds = 0.0f; depthStencil.maxDepthBounds = 0.0f; - // Even when not using independent blend, we need to provide blend information for every - // single attachment. + // Initialize the "blend state info" that will be chained in the "create info" from the data + // pre-computed in the BlendState + const auto& subpassInfo = GetRenderPass()->GetSubpassInfo(GetSubPass()); + 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; + for (uint32_t i : IterateBitSet(subpassInfo.colorAttachmentsSet)) { + colorBlendAttachments[i] = ToBackend(GetBlendState(i))->GetState(); } VkPipelineColorBlendStateCreateInfo colorBlend; colorBlend.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; colorBlend.pNext = nullptr; colorBlend.flags = 0; + // LogicOp isn't supported so we disable it. colorBlend.logicOpEnable = VK_FALSE; colorBlend.logicOp = VK_LOGIC_OP_CLEAR; - colorBlend.attachmentCount = kMaxColorAttachments; + // TODO(cwallez@chromium.org): Do we allow holes in the color attachments? + colorBlend.attachmentCount = static_cast(subpassInfo.colorAttachmentsSet.count()); colorBlend.pAttachments = colorBlendAttachments.data(); + // The blend constant is always dynamic so we fill in a dummy value colorBlend.blendConstants[0] = 0.0f; colorBlend.blendConstants[1] = 0.0f; colorBlend.blendConstants[2] = 0.0f; diff --git a/src/backend/vulkan/VulkanBackend.cpp b/src/backend/vulkan/VulkanBackend.cpp index ebd4feb47d..a9600b6baa 100644 --- a/src/backend/vulkan/VulkanBackend.cpp +++ b/src/backend/vulkan/VulkanBackend.cpp @@ -15,6 +15,7 @@ #include "backend/vulkan/VulkanBackend.h" #include "backend/Commands.h" +#include "backend/vulkan/BlendStateVk.h" #include "backend/vulkan/BufferUploader.h" #include "backend/vulkan/BufferVk.h" #include "backend/vulkan/CommandBufferVk.h" diff --git a/src/backend/vulkan/VulkanBackend.h b/src/backend/vulkan/VulkanBackend.h index 5705456af8..489fcea6bb 100644 --- a/src/backend/vulkan/VulkanBackend.h +++ b/src/backend/vulkan/VulkanBackend.h @@ -19,7 +19,6 @@ #include "backend/BindGroup.h" #include "backend/BindGroupLayout.h" -#include "backend/BlendState.h" #include "backend/ComputePipeline.h" #include "backend/DepthStencilState.h" #include "backend/Device.h" @@ -38,7 +37,7 @@ namespace backend { namespace vulkan { using BindGroup = BindGroupBase; using BindGroupLayout = BindGroupLayoutBase; - using BlendState = BlendStateBase; + class BlendState; class Buffer; using BufferView = BufferViewBase; class CommandBuffer;