fix: IW3 ensure loadForRenderer is set for shaders (#907)

* fix: IW3 restore renderer loading for disk shaders

* fix: IW3 ensure `loadForRenderer` is set for shaders

* fix: use modtools linker logic for iw3 loadForRenderer shader values

---------

Co-authored-by: Jan Laupetin <[email protected]>
This commit is contained in:
mo
2026-07-17 21:55:49 +02:00
committed by GitHub
co-authored by Jan Laupetin
parent 0c1efa1667
commit a2fe2e88ab
2 changed files with 47 additions and 3 deletions
@@ -69,6 +69,28 @@ namespace
return static_cast<MaterialWorldVertexFormat>(0);
}
#if defined(FEATURE_IW3)
uint16_t GetLoadForRenderer(const std::string& techniqueSetName)
{
if (techniqueSetName.starts_with("sm2/"))
return 0;
return 1;
}
void ApplyLoadForRendererToTechnique(const MaterialTechnique& technique, const uint16_t loadForRenderer)
{
for (auto passIndex = 0u; passIndex < technique.passCount; passIndex++)
{
auto* vertexShader = technique.passArray[passIndex].vertexShader;
if (vertexShader)
vertexShader->prog.loadDef.loadForRenderer = std::max(vertexShader->prog.loadDef.loadForRenderer, loadForRenderer);
auto* pixelShader = technique.passArray[passIndex].pixelShader;
if (pixelShader)
pixelShader->prog.loadDef.loadForRenderer = std::max(pixelShader->prog.loadDef.loadForRenderer, loadForRenderer);
}
}
#endif
#if defined(FEATURE_T6)
MaterialType GetMaterialType(const std::string& name)
{
@@ -116,6 +138,9 @@ namespace
return failure ? AssetCreationResult::Failure() : AssetCreationResult::NoAction();
auto* techset = ConvertTechniqueSet(*commonTechset, m_memory);
#if defined(FEATURE_IW3)
const auto loadForRenderer = GetLoadForRenderer(assetName);
#endif
#if defined(FEATURE_T6)
const auto materialType = GetMaterialType(assetName);
#endif
@@ -132,6 +157,12 @@ namespace
techset->techniques[techniqueIndex] = technique->Asset();
#if defined(FEATURE_IW3)
// IW3 supports both sm2 and sm3.
// The shader's loadForRenderer property is set to 0 for sm2 and 1 for sm3.
// Which shader model a techset is for is entirely determined by its name according to modtools.
ApplyLoadForRendererToTechnique(*techset->techniques[techniqueIndex], loadForRenderer);
#endif
#if defined(FEATURE_T6)
// Another techset may override this for the technique
// but the game determines the material type by techset name.
@@ -19,6 +19,9 @@ namespace
{
auto* technique = memory.Alloc<MaterialTechnique>();
technique->name = memory.Dup(name.c_str());
technique->passCount = 1;
technique->passArray[0].vertexShader = memory.Alloc<MaterialVertexShader>();
technique->passArray[0].pixelShader = memory.Alloc<MaterialPixelShader>();
context.AddSubAsset<SubAssetTechnique>(name, technique);
@@ -79,7 +82,13 @@ TEST_CASE("TechsetCompilerIW3", "[techset][iw3][compiler]")
SECTION("Can parse simple techset")
{
searchPath.AddFileData(techset::GetFileNameForTechsetName("simple"), R"TECHSET(
const auto [techsetName, expectedLoadForRendererValue] = GENERATE(Catch::Generators::table<std::string, uint16_t>({
{"simple", 1},
{"sm2/simple", 0},
}));
CAPTURE(techsetName);
searchPath.AddFileData(techset::GetFileNameForTechsetName(techsetName), R"TECHSET(
"depth prepass":
example_zprepass;
@@ -90,11 +99,11 @@ TEST_CASE("TechsetCompilerIW3", "[techset][iw3][compiler]")
auto* exampleZPrepass = GivenTechnique("example_zprepass", context, memory);
auto* exampleLit = GivenTechnique("example_lit_spot", context, memory);
const auto result = sut->CreateAsset("simple", context);
const auto result = sut->CreateAsset(techsetName, context);
REQUIRE(result.HasBeenSuccessful());
const auto* techset = static_cast<MaterialTechniqueSet*>(result.GetAssetInfo()->m_ptr);
CHECK(techset->name == "simple"s);
CHECK(techset->name == techsetName);
CHECK(techset->worldVertFormat == MTL_WORLDVERT_TEX_1_NRM_1);
size_t techniqueCount = 0;
@@ -107,6 +116,10 @@ TEST_CASE("TechsetCompilerIW3", "[techset][iw3][compiler]")
CHECK(techniqueCount == 2);
CHECK(techset->techniques[TECHNIQUE_DEPTH_PREPASS] == exampleZPrepass);
CHECK(techset->techniques[TECHNIQUE_LIT_SPOT] == exampleLit);
// Make sure IW3 techset postprocessing sets correct values for loadForRenderer
CHECK(exampleZPrepass->passArray[0].vertexShader->prog.loadDef.loadForRenderer == expectedLoadForRendererValue);
CHECK(exampleZPrepass->passArray[0].pixelShader->prog.loadDef.loadForRenderer == expectedLoadForRendererValue);
}
SECTION("Can parse techset with same technique used multiple times")