mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-12 16:17:44 -10:00
* FSR4 libs * Motion Vectors * FSR AA * FSR upscaling * Cleanup * Clang Tidy * Address Feedback * Improve canonical_prev handling * Clang Tidy again * Clean up prev_ submodel motion handling * Address Feedback
191 lines
7.5 KiB
C++
191 lines
7.5 KiB
C++
#include "VulkanVertexFormat.h"
|
|
|
|
|
|
namespace graphics::vulkan {
|
|
|
|
// Vertex format mapping table
|
|
// Maps FSO vertex_format_data::vertex_format to Vulkan formats
|
|
// Based on GL_array_binding_data in gropengltnl.cpp
|
|
const VertexFormatMapping VERTEX_FORMAT_MAPPINGS[] = {
|
|
// Position formats
|
|
{ vertex_format_data::POSITION4, vk::Format::eR32G32B32A32Sfloat, VATTRIB_POSITION, 4, 16 },
|
|
{ vertex_format_data::POSITION3, vk::Format::eR32G32B32Sfloat, VATTRIB_POSITION, 3, 12 },
|
|
{ vertex_format_data::POSITION2, vk::Format::eR32G32Sfloat, VATTRIB_POSITION, 2, 8 },
|
|
|
|
// Color formats
|
|
{ vertex_format_data::COLOR3, vk::Format::eR8G8B8Unorm, VATTRIB_COLOR, 3, 3 },
|
|
{ vertex_format_data::COLOR4, vk::Format::eR8G8B8A8Unorm, VATTRIB_COLOR, 4, 4 },
|
|
{ vertex_format_data::COLOR4F, vk::Format::eR32G32B32A32Sfloat, VATTRIB_COLOR, 4, 16 },
|
|
|
|
// Texture coordinate formats
|
|
{ vertex_format_data::TEX_COORD2, vk::Format::eR32G32Sfloat, VATTRIB_TEXCOORD, 2, 8 },
|
|
{ vertex_format_data::TEX_COORD4, vk::Format::eR32G32B32A32Sfloat, VATTRIB_TEXCOORD, 4, 16 },
|
|
|
|
// Normal/tangent formats
|
|
{ vertex_format_data::NORMAL, vk::Format::eR32G32B32Sfloat, VATTRIB_NORMAL, 3, 12 },
|
|
{ vertex_format_data::TANGENT, vk::Format::eR32G32B32A32Sfloat, VATTRIB_TANGENT, 4, 16 },
|
|
|
|
// Instance/particle formats
|
|
{ vertex_format_data::MODEL_ID, vk::Format::eR32Sfloat, VATTRIB_MODELID, 1, 4 },
|
|
{ vertex_format_data::RADIUS, vk::Format::eR32Sfloat, VATTRIB_RADIUS, 1, 4 },
|
|
{ vertex_format_data::UVEC, vk::Format::eR32G32B32Sfloat, VATTRIB_UVEC, 3, 12 },
|
|
|
|
// Matrix format (mat4 = 4 vec4s, uses locations 8-11)
|
|
{ vertex_format_data::MATRIX4, vk::Format::eR32G32B32A32Sfloat, VATTRIB_MODEL_MATRIX, 16, 64 },
|
|
|
|
{ vertex_format_data::MOTION4, vk::Format::eR32G32B32A32Sfloat, VATTRIB_EFFECT_MOTION, 4, 16 },
|
|
};
|
|
|
|
const size_t VERTEX_FORMAT_MAPPINGS_COUNT = sizeof(VERTEX_FORMAT_MAPPINGS) / sizeof(VERTEX_FORMAT_MAPPINGS[0]);
|
|
|
|
const VertexFormatMapping* getVertexFormatMapping(vertex_format_data::vertex_format format)
|
|
{
|
|
for (const auto & i : VERTEX_FORMAT_MAPPINGS) {
|
|
if (i.format == format) {
|
|
return &i;
|
|
}
|
|
}
|
|
// A missing mapping means a new vertex_format was added without a matching
|
|
// entry in VERTEX_FORMAT_MAPPINGS above -- a coding error, not bad user data.
|
|
// Catch it in debug; release still returns nullptr so callers fall back safely.
|
|
Assertion(false, "No Vulkan vertex format mapping for vertex_format %d", static_cast<int>(format));
|
|
return nullptr;
|
|
}
|
|
|
|
void VertexInputConfig::updatePointers()
|
|
{
|
|
createInfo.vertexBindingDescriptionCount = static_cast<uint32_t>(bindings.size());
|
|
createInfo.pVertexBindingDescriptions = bindings.empty() ? nullptr : bindings.data();
|
|
createInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(attributes.size());
|
|
createInfo.pVertexAttributeDescriptions = attributes.empty() ? nullptr : attributes.data();
|
|
}
|
|
|
|
const VertexInputConfig& VulkanVertexFormatCache::getVertexInputConfig(const vertex_layout& layout)
|
|
{
|
|
size_t hash = layout.hash();
|
|
|
|
auto it = m_cache.find(hash);
|
|
if (it != m_cache.end()) {
|
|
return it->second;
|
|
}
|
|
|
|
// Create new configuration
|
|
auto result = m_cache.emplace(hash, createVertexInputConfig(layout));
|
|
return result.first->second;
|
|
}
|
|
|
|
void VulkanVertexFormatCache::clear()
|
|
{
|
|
m_cache.clear();
|
|
}
|
|
|
|
VertexInputConfig VulkanVertexFormatCache::createVertexInputConfig(const vertex_layout& layout)
|
|
{
|
|
VertexInputConfig config;
|
|
|
|
// Track which bindings we've already added
|
|
SCP_unordered_map<size_t, uint32_t> bufferBindings; // buffer_number -> binding index
|
|
|
|
size_t numComponents = layout.get_num_vertex_components();
|
|
|
|
for (size_t i = 0; i < numComponents; ++i) {
|
|
const vertex_format_data* component = layout.get_vertex_component(i);
|
|
const VertexFormatMapping* mapping = getVertexFormatMapping(component->format_type);
|
|
|
|
if (!mapping) {
|
|
nprintf(("vulkan", "VulkanVertexFormat: Unknown vertex format %d\n", static_cast<int>(component->format_type)));
|
|
continue;
|
|
}
|
|
|
|
// Track which locations the layout natively provides
|
|
auto loc = mapping->location;
|
|
config.providedInputMask |= (1u << loc);
|
|
|
|
// Get or create binding for this buffer
|
|
uint32_t bindingIndex;
|
|
auto bindingIt = bufferBindings.find(component->buffer_number);
|
|
if (bindingIt == bufferBindings.end()) {
|
|
bindingIndex = static_cast<uint32_t>(config.bindings.size());
|
|
bufferBindings[component->buffer_number] = bindingIndex;
|
|
|
|
vk::VertexInputBindingDescription binding;
|
|
binding.binding = bindingIndex;
|
|
binding.stride = static_cast<uint32_t>(component->stride);
|
|
binding.inputRate = (component->divisor > 0) ?
|
|
vk::VertexInputRate::eInstance : vk::VertexInputRate::eVertex;
|
|
config.bindings.push_back(binding);
|
|
} else {
|
|
bindingIndex = bindingIt->second;
|
|
}
|
|
|
|
// Handle MATRIX4 specially - it needs 4 attribute locations
|
|
if (component->format_type == vertex_format_data::MATRIX4) {
|
|
// mat4 requires 4 vec4 attributes at consecutive locations
|
|
for (uint32_t row = 0; row < 4; ++row) {
|
|
vk::VertexInputAttributeDescription attr;
|
|
attr.location = mapping->location + row;
|
|
attr.binding = bindingIndex;
|
|
attr.format = vk::Format::eR32G32B32A32Sfloat;
|
|
attr.offset = static_cast<uint32_t>(component->offset) + (row * 16);
|
|
config.attributes.push_back(attr);
|
|
}
|
|
// Mark all 4 matrix locations as provided
|
|
config.providedInputMask |= (1u << (loc + 1)) | (1u << (loc + 2)) | (1u << (loc + 3));
|
|
} else {
|
|
vk::VertexInputAttributeDescription attr;
|
|
attr.location = mapping->location;
|
|
attr.binding = bindingIndex;
|
|
attr.format = mapping->vkFormat;
|
|
attr.offset = static_cast<uint32_t>(component->offset);
|
|
config.attributes.push_back(attr);
|
|
}
|
|
}
|
|
|
|
// Only add fallback bindings when the layout has actual vertex components.
|
|
// Empty layouts (e.g. fullscreen triangles) generate vertices in the shader
|
|
// and don't need any vertex input bindings.
|
|
uint32_t colorBit = 1u << VATTRIB_COLOR;
|
|
if (!(config.providedInputMask & colorBit) && numComponents > 0) {
|
|
// Add binding for fallback color buffer (instanced so one value applies to all vertices)
|
|
vk::VertexInputBindingDescription colorBinding;
|
|
colorBinding.binding = FALLBACK_COLOR_BINDING;
|
|
colorBinding.stride = 16; // vec4 = 16 bytes
|
|
colorBinding.inputRate = vk::VertexInputRate::eInstance; // Same color for all vertices
|
|
config.bindings.push_back(colorBinding);
|
|
|
|
vk::VertexInputAttributeDescription colorAttr;
|
|
colorAttr.location = VATTRIB_COLOR;
|
|
colorAttr.binding = FALLBACK_COLOR_BINDING;
|
|
colorAttr.format = vk::Format::eR32G32B32A32Sfloat;
|
|
colorAttr.offset = 0;
|
|
config.attributes.push_back(colorAttr);
|
|
}
|
|
|
|
// If no texcoord attribute, add a fallback providing (0,0,0,0)
|
|
// In OpenGL, missing vertex attributes default to (0,0,0,1); Vulkan requires explicit input
|
|
uint32_t texCoordBit = 1u << VATTRIB_TEXCOORD;
|
|
if (!(config.providedInputMask & texCoordBit) && numComponents > 0) {
|
|
// Add binding for fallback texcoord buffer (instanced so one value applies to all vertices)
|
|
vk::VertexInputBindingDescription texCoordBinding;
|
|
texCoordBinding.binding = FALLBACK_TEXCOORD_BINDING;
|
|
texCoordBinding.stride = 16; // vec4 = 16 bytes
|
|
texCoordBinding.inputRate = vk::VertexInputRate::eInstance;
|
|
config.bindings.push_back(texCoordBinding);
|
|
|
|
vk::VertexInputAttributeDescription texCoordAttr;
|
|
texCoordAttr.location = VATTRIB_TEXCOORD;
|
|
texCoordAttr.binding = FALLBACK_TEXCOORD_BINDING;
|
|
texCoordAttr.format = vk::Format::eR32G32B32A32Sfloat;
|
|
texCoordAttr.offset = 0;
|
|
config.attributes.push_back(texCoordAttr);
|
|
}
|
|
|
|
// Update the createInfo pointers
|
|
config.updatePointers();
|
|
|
|
return config;
|
|
}
|
|
|
|
} // namespace graphics::vulkan
|
|
|