Files
fs2open.github.com/code/graphics/vulkan/VulkanConvert.cpp
the-e 817f641478 Enable primitive restart for supported topologies in Vulkan pipeline
- Added `topologySupportsPrimitiveRestart` to determine restart eligibility for each topology.
- Updated `primitiveRestartEnable` to be conditionally set based on topology, addressing compatibility issues with Metal/MoltenVK.
- Prevented crash scenarios on macOS by ensuring pipelines are valid for strip/fan topologies requiring primitive restart.
2026-11-07 19:36:13 +01:00

289 lines
8.0 KiB
C++

#include "VulkanConvert.h"
namespace graphics::vulkan {
void convertBlendMode(gr_alpha_blend mode, vk::BlendFactor& srcFactor, vk::BlendFactor& dstFactor)
{
// Based on SetAlphaBlendMode in gropenglstate.cpp
switch (mode) {
case ALPHA_BLEND_NONE:
srcFactor = vk::BlendFactor::eOne;
dstFactor = vk::BlendFactor::eZero;
break;
case ALPHA_BLEND_ALPHA_ADDITIVE:
srcFactor = vk::BlendFactor::eSrcAlpha;
dstFactor = vk::BlendFactor::eOne;
break;
case ALPHA_BLEND_ALPHA_BLEND_ALPHA:
srcFactor = vk::BlendFactor::eSrcAlpha;
dstFactor = vk::BlendFactor::eOneMinusSrcAlpha;
break;
case ALPHA_BLEND_ALPHA_BLEND_SRC_COLOR:
srcFactor = vk::BlendFactor::eSrcColor;
dstFactor = vk::BlendFactor::eOneMinusSrcColor;
break;
case ALPHA_BLEND_ADDITIVE:
srcFactor = vk::BlendFactor::eOne;
dstFactor = vk::BlendFactor::eOne;
break;
case ALPHA_BLEND_PREMULTIPLIED:
srcFactor = vk::BlendFactor::eOne;
dstFactor = vk::BlendFactor::eOneMinusSrcAlpha;
break;
default:
srcFactor = vk::BlendFactor::eOne;
dstFactor = vk::BlendFactor::eZero;
break;
}
}
void convertDepthMode(gr_zbuffer_type type, vk::CompareOp& compareOp, bool& writeEnable)
{
// Based on SetZbufferType in gropenglstate.cpp
switch (type) {
case ZBUFFER_TYPE_NONE:
compareOp = vk::CompareOp::eAlways;
writeEnable = false;
break;
case ZBUFFER_TYPE_READ:
compareOp = vk::CompareOp::eLess;
writeEnable = false;
break;
case ZBUFFER_TYPE_WRITE:
compareOp = vk::CompareOp::eAlways;
writeEnable = true;
break;
case ZBUFFER_TYPE_FULL:
compareOp = vk::CompareOp::eLess;
writeEnable = true;
break;
default:
compareOp = vk::CompareOp::eAlways;
writeEnable = false;
break;
}
}
vk::CompareOp convertStencilCompare(ComparisionFunction func)
{
switch (func) {
case ComparisionFunction::Never:
return vk::CompareOp::eNever;
case ComparisionFunction::Less:
return vk::CompareOp::eLess;
case ComparisionFunction::Equal:
return vk::CompareOp::eEqual;
case ComparisionFunction::LessOrEqual:
return vk::CompareOp::eLessOrEqual;
case ComparisionFunction::Greater:
return vk::CompareOp::eGreater;
case ComparisionFunction::NotEqual:
return vk::CompareOp::eNotEqual;
case ComparisionFunction::GreaterOrEqual:
return vk::CompareOp::eGreaterOrEqual;
case ComparisionFunction::Always:
default:
return vk::CompareOp::eAlways;
}
}
vk::StencilOp convertStencilOp(StencilOperation op)
{
switch (op) {
case StencilOperation::Keep:
return vk::StencilOp::eKeep;
case StencilOperation::Zero:
return vk::StencilOp::eZero;
case StencilOperation::Replace:
return vk::StencilOp::eReplace;
case StencilOperation::Increment:
return vk::StencilOp::eIncrementAndClamp;
case StencilOperation::Decrement:
return vk::StencilOp::eDecrementAndClamp;
case StencilOperation::Invert:
return vk::StencilOp::eInvert;
case StencilOperation::IncrementWrap:
return vk::StencilOp::eIncrementAndWrap;
case StencilOperation::DecrementWrap:
return vk::StencilOp::eDecrementAndWrap;
default:
return vk::StencilOp::eKeep;
}
}
vk::PrimitiveTopology convertPrimitiveType(primitive_type type)
{
switch (type) {
case PRIM_TYPE_POINTS:
return vk::PrimitiveTopology::ePointList;
case PRIM_TYPE_LINES:
return vk::PrimitiveTopology::eLineList;
case PRIM_TYPE_LINESTRIP:
return vk::PrimitiveTopology::eLineStrip;
case PRIM_TYPE_TRIS:
return vk::PrimitiveTopology::eTriangleList;
case PRIM_TYPE_TRISTRIP:
return vk::PrimitiveTopology::eTriangleStrip;
case PRIM_TYPE_TRIFAN:
return vk::PrimitiveTopology::eTriangleFan;
default:
return vk::PrimitiveTopology::eTriangleList;
}
}
bool topologySupportsPrimitiveRestart(vk::PrimitiveTopology topology)
{
switch (topology) {
case vk::PrimitiveTopology::eLineStrip:
case vk::PrimitiveTopology::eTriangleStrip:
case vk::PrimitiveTopology::eTriangleFan:
case vk::PrimitiveTopology::eLineStripWithAdjacency:
case vk::PrimitiveTopology::eTriangleStripWithAdjacency:
return true;
default:
return false;
}
}
vk::CullModeFlags convertCullMode(bool cullEnabled)
{
return cullEnabled ? vk::CullModeFlagBits::eBack : vk::CullModeFlagBits::eNone;
}
bool isBlendingEnabled(gr_alpha_blend mode)
{
return mode != ALPHA_BLEND_NONE;
}
vk::PipelineColorBlendAttachmentState createColorBlendAttachment(gr_alpha_blend mode, const bvec4& colorWriteMask)
{
vk::PipelineColorBlendAttachmentState attachment;
attachment.blendEnable = isBlendingEnabled(mode) ? VK_TRUE : VK_FALSE;
vk::BlendFactor srcFactor, dstFactor;
convertBlendMode(mode, srcFactor, dstFactor);
attachment.srcColorBlendFactor = srcFactor;
attachment.dstColorBlendFactor = dstFactor;
attachment.colorBlendOp = vk::BlendOp::eAdd;
// Alpha blend - same as color for most modes
attachment.srcAlphaBlendFactor = srcFactor;
attachment.dstAlphaBlendFactor = dstFactor;
attachment.alphaBlendOp = vk::BlendOp::eAdd;
// Color write mask from material
vk::ColorComponentFlags writeMask;
if (colorWriteMask.x) writeMask |= vk::ColorComponentFlagBits::eR;
if (colorWriteMask.y) writeMask |= vk::ColorComponentFlagBits::eG;
if (colorWriteMask.z) writeMask |= vk::ColorComponentFlagBits::eB;
if (colorWriteMask.w) writeMask |= vk::ColorComponentFlagBits::eA;
attachment.colorWriteMask = writeMask;
return attachment;
}
vk::PipelineDepthStencilStateCreateInfo createDepthStencilState(
gr_zbuffer_type depthMode,
bool stencilEnabled,
ComparisionFunction stencilFunc,
const material::StencilOp* frontOp,
const material::StencilOp* backOp,
uint32_t stencilMask)
{
vk::PipelineDepthStencilStateCreateInfo info;
// Depth settings
vk::CompareOp depthCompare;
bool depthWrite;
convertDepthMode(depthMode, depthCompare, depthWrite);
info.depthTestEnable = (depthMode != ZBUFFER_TYPE_NONE) ? VK_TRUE : VK_FALSE;
info.depthWriteEnable = depthWrite ? VK_TRUE : VK_FALSE;
info.depthCompareOp = depthCompare;
info.depthBoundsTestEnable = VK_FALSE;
info.minDepthBounds = 0.0f;
info.maxDepthBounds = 1.0f;
// Stencil settings
info.stencilTestEnable = stencilEnabled ? VK_TRUE : VK_FALSE;
if (stencilEnabled) {
// Front face stencil
info.front.compareOp = convertStencilCompare(stencilFunc);
info.front.compareMask = 0xFF;
info.front.writeMask = stencilMask;
info.front.reference = 0; // Set dynamically
if (frontOp) {
info.front.failOp = convertStencilOp(frontOp->stencilFailOperation);
info.front.depthFailOp = convertStencilOp(frontOp->depthFailOperation);
info.front.passOp = convertStencilOp(frontOp->successOperation);
} else {
info.front.failOp = vk::StencilOp::eKeep;
info.front.depthFailOp = vk::StencilOp::eKeep;
info.front.passOp = vk::StencilOp::eKeep;
}
// Back face stencil
info.back.compareOp = convertStencilCompare(stencilFunc);
info.back.compareMask = 0xFF;
info.back.writeMask = stencilMask;
info.back.reference = 0;
if (backOp) {
info.back.failOp = convertStencilOp(backOp->stencilFailOperation);
info.back.depthFailOp = convertStencilOp(backOp->depthFailOperation);
info.back.passOp = convertStencilOp(backOp->successOperation);
} else {
info.back.failOp = vk::StencilOp::eKeep;
info.back.depthFailOp = vk::StencilOp::eKeep;
info.back.passOp = vk::StencilOp::eKeep;
}
}
return info;
}
vk::PipelineRasterizationStateCreateInfo createRasterizationState(
bool cullEnabled,
int fillMode,
bool frontFaceCW,
bool depthBiasEnabled,
bool depthClampEnabled)
{
vk::PipelineRasterizationStateCreateInfo info;
info.depthClampEnable = depthClampEnabled ? VK_TRUE : VK_FALSE;
info.rasterizerDiscardEnable = VK_FALSE;
// Fill mode
switch (fillMode) {
case GR_FILL_MODE_WIRE:
info.polygonMode = vk::PolygonMode::eLine;
break;
case GR_FILL_MODE_SOLID:
default:
info.polygonMode = vk::PolygonMode::eFill;
break;
}
info.cullMode = convertCullMode(cullEnabled);
info.frontFace = frontFaceCW ? vk::FrontFace::eClockwise : vk::FrontFace::eCounterClockwise;
// Depth bias - actual values set dynamically via vkCmdSetDepthBias
info.depthBiasEnable = depthBiasEnabled ? VK_TRUE : VK_FALSE;
info.depthBiasConstantFactor = 0.0f;
info.depthBiasClamp = 0.0f;
info.depthBiasSlopeFactor = 0.0f;
info.lineWidth = 1.0f;
return info;
}
} // namespace graphics::vulkan