Skip to content

Stop the Shader constructor modifying the supplied definition - #9281

Merged
mvaligursky merged 1 commit into
mainfrom
fix-shader-definition-mutation
Sep 2, 2026
Merged

Stop the Shader constructor modifying the supplied definition#9281
mvaligursky merged 1 commit into
mainfrom
fix-shader-definition-mutation

Conversation

@willeastcott

Copy link
Copy Markdown
Contributor

Description

The Shader constructor modified the definition object supplied by the caller.
It replaced definition.vshader, definition.fshader and definition.cshader
with their pre-processed versions, and assigned definition.attributes when
extracting attribute names:

definition.vshader = Preprocessor.run(definition.vshader, definition.vincludes, { ... });
definition.attributes ??= ShaderDefinitionUtils.collectAttributes(definition.vshader);

Reusing a definition object to create a second shader therefore pre-processed
already pre-processed sources.

This PR shallow copies the definition at the top of the constructor, so these
writes land on an engine-owned object instead. The compute path had the same
problem with definition.cincludes — the caller's map was mutated to add the
built-in halfTypesCS include — so that is now copied as well. Both copies
happen once per shader creation, which is not a hot path.

Nothing in the engine reads back from the original object, and
ProgramLibrary.getProgram already built a fresh object literal before
constructing a Shader, so its cached definitions were never affected.

Note this does not change what shader.definition contains — it still holds
the pre-processed sources, just on a copy rather than on the caller's object.

Also adds test/platform/graphics/shader.test.mjs. Three of its cases fail
without this fix.

Checklist

  • I have read the contributing guidelines
  • My code follows the project's coding standards
  • This PR focuses on a single change

🤖 Generated with Claude Code

The constructor replaced `definition.vshader`, `definition.fshader` and
`definition.cshader` with their pre-processed versions and assigned
`definition.attributes`, all on the object supplied by the caller. Reusing a
definition object for a second shader therefore pre-processed already
pre-processed sources.

Shallow copy the definition up front so these writes land on an engine-owned
object. The compute path had the same problem with `definition.cincludes`, whose
map was mutated to add the built-in `halfTypesCS` include, so copy that too.

Note this does not change what `shader.definition` contains - it still holds the
pre-processed sources, just on a copy.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown

Build size report

This PR changes the size of the minified bundles.

Bundle Minified Gzip Brotli
playcanvas.min.js 2391.2 KB (+0.0 KB, +0.00%) 615.0 KB (+0.0 KB, +0.00%) 477.4 KB (−0.0 KB, −0.00%)
playcanvas.min.mjs 2388.6 KB (+0.0 KB, +0.00%) 613.6 KB (+0.0 KB, +0.00%) 477.1 KB (+0.5 KB, +0.12%)

@willeastcott willeastcott added area: graphics Graphics related issue bugfix labels Sep 2, 2026
@mvaligursky
mvaligursky merged commit 0a548b9 into main Sep 2, 2026
10 checks passed
@mvaligursky
mvaligursky deleted the fix-shader-definition-mutation branch September 2, 2026 13:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: graphics Graphics related issue bugfix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants