Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions code/graphics/shader_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,19 @@ static ShaderVariantInfo SHADER_VARIANTS[] = {
{SDR_TYPE_SHADOW_MAP_GEN, true, SDR_FLAG_SHADOW_FALLBACK, "GEOMETRY_FALLBACK", {}, "Use a geometry shader to select the cascade layer instead of writing gl_Layer from the vertex shader"}
};

static_assert(VATTRIB_MODEL_MATRIX + 4 <= 32, "vertex input mask is 32 bits wide");

uint32_t shader_vertex_input_mask(const ShaderTypeInfo& info)
{
uint32_t mask = 0;
for (auto attr : info.attributes) {
// The Vulkan pipeline drops every location the mask omits, so a mat4 needs all four of its bits.
const uint32_t locations = (attr == VATTRIB_MODEL_MATRIX) ? 4u : 1u;
mask |= ((1u << locations) - 1u) << attr;
}
return mask;
}

const ShaderTypeInfo* shader_get_type_info(shader_type type)
{
for (auto & i : SHADER_TYPES) {
Expand Down
8 changes: 8 additions & 0 deletions code/graphics/shader_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@ const ShaderTypeInfo* shader_get_type_info(shader_type type);
// Lookup helper: find variant info by (type, flag). Returns nullptr if not found.
const ShaderVariantInfo* shader_get_variant_info(shader_type type, int flag);

/**
* @brief Bitmask of the vertex attribute locations a shader type reads.
*
* One bit per location; VATTRIB_MODEL_MATRIX contributes bits 8-11 because a
* mat4 input occupies four consecutive locations.
*/
uint32_t shader_vertex_input_mask(const ShaderTypeInfo& info);

// Iterate all variants matching type whose flag bit is set in flags.
void shader_for_each_active_variant(shader_type type, unsigned int flags, const std::function<void(const ShaderVariantInfo&)>& fn);

Expand Down
1 change: 1 addition & 0 deletions code/graphics/vulkan/VulkanDeferred.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -959,6 +959,7 @@ void vulkan_render_decals(decal_material* material_info,
// Build pipeline config for decal rendering
PipelineConfig config;
config.shaderType = SDR_TYPE_DECAL;
config.shaderFlags = material_info->get_shader_flags();
config.primitiveType = prim_type;
config.depthMode = material_info->get_depth_mode();
config.depthWriteEnabled = false;
Expand Down
10 changes: 2 additions & 8 deletions code/graphics/vulkan/VulkanShader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,7 @@ void VulkanShaderManager::recompileAllShaders(const std::function<void(size_t, s
nprintf(("vulkan", "VulkanShaderManager: Failed to create vertex module: %s\n", e.what()));
}
}
shader.vertexInputMask = 0;
for (auto attr : typeInfo->attributes) {
shader.vertexInputMask |= (1u << attr);
}
shader.vertexInputMask = shader_vertex_input_mask(*typeInfo);

SCP_string fragFile = typeInfo->frag;
auto fragSpirv = m_compiler->compile(fragFile, vk::ShaderStageFlagBits::eFragment, type, flags, requiresRaytracing);
Expand Down Expand Up @@ -216,10 +213,7 @@ int VulkanShaderManager::loadShader(shader_type type, unsigned int flags)
vertFile.c_str(), e.what()));
}
}
shader.vertexInputMask = 0;
for (auto attr : typeInfo->attributes) {
shader.vertexInputMask |= (1u << attr);
}
shader.vertexInputMask = shader_vertex_input_mask(*typeInfo);

// Compile fragment shader
SCP_string fragFile = typeInfo->frag;
Expand Down
16 changes: 16 additions & 0 deletions test/src/graphics/test_material.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include <gtest/gtest.h>
#include <graphics/material.h>

// USE_NORMAL_MAP means "read the scene normal buffer": set when the decal brings no normal map of its own.
TEST(DecalMaterial, SceneNormalFlagSetOnlyWithoutDecalNormalMap)
{
decal_material without_normal;
without_normal.set_texture_map(TM_BASE_TYPE, 0);
without_normal.set_texture_map(TM_NORMAL_TYPE, -1);
EXPECT_EQ(without_normal.get_shader_flags(), static_cast<uint>(SDR_FLAG_DECAL_USE_NORMAL_MAP));

decal_material with_normal;
with_normal.set_texture_map(TM_BASE_TYPE, 0);
with_normal.set_texture_map(TM_NORMAL_TYPE, 1);
EXPECT_EQ(with_normal.get_shader_flags(), 0u);
}
37 changes: 37 additions & 0 deletions test/src/graphics/test_shader_types.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include <gtest/gtest.h>
#include <graphics/shader_types.h>

// A mat4 input spans locations 8-11; the Vulkan pipeline drops any location the mask omits.
TEST(ShaderTypes, ModelMatrixInputMaskCoversFourLocations)
{
const ShaderTypeInfo* decal = shader_get_type_info(SDR_TYPE_DECAL);
ASSERT_NE(decal, nullptr);

const uint32_t mask = shader_vertex_input_mask(*decal);
for (uint32_t loc = VATTRIB_MODEL_MATRIX; loc < VATTRIB_MODEL_MATRIX + 4; ++loc) {
EXPECT_TRUE(mask & (1u << loc)) << "location " << loc << " missing from mask " << mask;
}
EXPECT_TRUE(mask & (1u << VATTRIB_POSITION));
}

TEST(ShaderTypes, VertexInputMaskIsExactPerType)
{
struct Case {
shader_type type;
uint32_t expected;
};
const Case cases[] = {
{SDR_TYPE_DECAL, (1u << VATTRIB_POSITION) | (0xFu << VATTRIB_MODEL_MATRIX)},
{SDR_TYPE_NANOVG, (1u << VATTRIB_POSITION) | (1u << VATTRIB_TEXCOORD)},
{SDR_TYPE_MODEL,
(1u << VATTRIB_POSITION) | (1u << VATTRIB_TEXCOORD) | (1u << VATTRIB_NORMAL) | (1u << VATTRIB_TANGENT) |
(1u << VATTRIB_MODELID)},
{SDR_TYPE_EFFECT_PARTICLE,
(1u << VATTRIB_POSITION) | (1u << VATTRIB_TEXCOORD) | (1u << VATTRIB_RADIUS) | (1u << VATTRIB_COLOR)},
};
for (const auto& c : cases) {
const ShaderTypeInfo* info = shader_get_type_info(c.type);
ASSERT_NE(info, nullptr) << "type " << static_cast<int>(c.type);
EXPECT_EQ(shader_vertex_input_mask(*info), c.expected) << "type " << static_cast<int>(c.type);
}
}
2 changes: 2 additions & 0 deletions test/src/source_groups.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ add_file_folder("Globalincs"

add_file_folder("Graphics"
graphics/test_font.cpp
graphics/test_material.cpp
graphics/test_shader_types.cpp
)

if (FSO_BUILD_WITH_VULKAN)
Expand Down
Loading