Skip to content

Fix shaders that declare or name samplers through macros - #1072

Open
Coastrnaut wants to merge 2 commits into
projectM-visualizer:masterfrom
Coastrnaut:fix/macro-samplers
Open

Coastrnaut wants to merge 2 commits into
projectM-visualizer:masterfrom
Coastrnaut:fix/macro-samplers

Conversation

@Coastrnaut

@Coastrnaut Coastrnaut commented Nov 9, 2026 •

Copy link
Copy Markdown

Shaders that name samplers through macros failed to parse:

  • Preprocessor (Fed + Geiss - Color Pox Remix). hlslparser built macro values from the trimmed tokens, so #define smp sampler sampler_manyfish; got the value samplersampler_manyfish;, and it put every value in parentheses when substituting it, which is only valid for expressions. The expansion became (samplersampler_manyfish;). Values now keep the whitespace between their tokens (in all three places where they're built), and values containing a semicolon, i.e. statements and declarations, are inserted without parentheses. Expression macros are still wrapped as before.
  • Samplers named via macros ([dylan] cube in a room …, 2 presets). #define base01 main, sampler base01; and tex2D(base01, uv) turn into sampler_fw_main in the preprocessor, but projectM only searched the original code for sampler_ names, so it didn't declare it. GetReferencedSamplers() now searches the macro-expanded code as well.

Results

  • The 3 presets compile now. With all open shader PRs combined, the only presets in the four packs below whose shaders still fall back are the two shifter + flexi - liquid circuitry … ones: their composite shader has an extra } left over from a commented-out loop, so it doesn't compile in Milkdrop either.
  • For all other presets, including every preset that uses #define, shader compile/link results and rendered frames are identical to master.
  • New HLSLPreprocessorTest. All unit tests pass.

How I tested it

I loaded all 14,536 presets from cream-of-the-crop, en-d, milkdrop-original and projectm-classic one after another (Windows, RTX A6000, GL 3.3 core and GLES contexts), with and without the preset folders as texture search path, rendered frames with fixed audio and frame times, and recorded shader compile/link results, failed loads, logged shader fallbacks and frame hashes. For the pixel comparison both builds had their random seeds fixed (a local patch only, identical on both sides). The presets this PR fixes are excluded from the pixel comparison, since loading them changes shared state (e.g. the expression evaluator's random generator) for every preset after them.

Retested on current master (2026-11-12)

The HLSL preprocessor built macro values from the trimmed tokens, so
"#define smp sampler sampler_manyfish;" got the value
"samplersampler_manyfish;", and it put every value in parentheses when
substituting it, which is only valid for expressions. A macro expanding
to a declaration, as used in "Fed + Geiss - Color Pox Remix", became
"(samplersampler_manyfish;)", and the shader failed to parse.

Keep the whitespace between the tokens of a value, and insert values
containing a semicolon, i.e. statements and declarations, without
parentheses. Expression macros are still wrapped as before.
Presets can name a sampler through a macro, e.g. "#define base01 main",
"sampler base01;" and "tex2D(base01, uv)", which the HLSL preprocessor
turns into "sampler_fw_main". projectM only searched the original code
for "sampler_" names, so it didn't declare this sampler and the shader
failed to parse.

Search the macro-expanded code as well.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant