mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-09 04:49:39 -10:00
- 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.
289 lines
8.0 KiB
C++
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
|
|
|