Repository navigation
[RenderStateCache] RSC loses non-main entry points when reserializing shaders for WebGPU PSO archives #813
Description
Problem
On WebGPU, RenderStateCacheImpl::SerializedPsoCIWrapperBase::SerializeShader() does not restore the actual WGSL entry point when reserializing an existing device shader for a PSO archive. The newly constructed ShaderCreateInfo therefore retains its default EntryPoint = "main", causing reflection to fail for valid shaders with other entry point names, such as vertexMain and fragmentMain.
Observed reproduction sequence
- Start the WebGPU backend and load the
DrawTexturedRectvertex and pixel shaders from a previously saved archive. - The log first reports
Found ... in the archivefor both shaders. - During graphics PSO creation, the cache enters the branch in
SerializeShader()where the shader's reference-counter owner does not exposeIID_SerializedShader. It reconstructs aShaderCreateInfofrom the device shader's WGSL. - The WGSL entry point is
vertexMain, but the reconstructed descriptor requests the defaultmain. Reflection fails, followed by failure to serialize the shader required by the PSO archive.
Log excerpt, with content hashes omitted:
Render state cache: Found shader 'DrawTexturedRect_vertexMain_... [...]' in the archive.
Render state cache: Found shader 'DrawTexturedRect_fragmentMain_... [...]' in the archive.
ERROR ... WGSLShaderResources.cpp, 818:
Entry point 'main' is not found in shader 'DrawTexturedRect_vertexMain_...'
ERROR ... RenderDeviceBase.hpp, 467:
Failed to create Shader 'DrawTexturedRect_vertexMain_...'
ERROR ... RenderStateCacheImpl.cpp, 604:
Failed to serialize shader 'DrawTexturedRect_vertexMain_...'.
Root cause and source locations
In RenderStateCacheImpl.cpp:566–605:
- Line 576 constructs a default
ShaderCreateInfo, then copies onlyDescfrom the original shader. - The WebGPU branch restores
Source,SourceLanguage = WGSL, and the emulated-array suffix, but does not restoreEntryPoint. - ShaderCreateInfo::EntryPoint defaults to
"main". - ShaderWebGPUImpl.cpp:241–254 passes the explicit WGSL entry point to reflection.
- WGSLShaderResources.cpp:802–818 searches by name and throws when
mainis not found.
The entry point names were not lost during HLSL → SPIR-V → WGSL conversion. Inspection of the local DrawTexturedRect Vulkan SPIR-V cache shows OpEntryPoint names of vertexMain and fragmentMain. The final WebGPU WGSL artifacts also explicitly declare @vertex fn vertexMain(...) and @fragment fn fragmentMain(...). The missing information is the entry point selection in the subsequently reconstructed descriptor.
Expected and actual behavior
Expected: A valid WebGPU shader whose entry point is not named main can be added to a PSO archive while preserving its entry point selection.
Actual: Reserialization requests the default main, reports that the entry point does not exist, and then fails to serialize the shader.
The confirmed impact is failure in the shader / PSO archive serialization path. Since the implementation is shared, other WebGPU shaders with non-main entry points may also be affected; DrawTexturedRect is the observed case.
Suggested fix and regression coverage
- Restore the actual entry point selection when reconstructing the WebGPU
ShaderCreateInfo. - For WGSL known to contain exactly one entry point, consider setting
EntryPoint = nullptrso the existing reflection logic can infer that entry point. Supporting multi-entry-point WGSL requires preserving the original selected entry point rather than unconditionally choosing the first one. - Add an actual WebGPU regression covering non-
mainVS/PS entry points → save RenderStateCache → destroy and recreate the device/cache → load the archive → create a PSO using the restored shaders, checking both PSO status and archive results. - Also cover device-created shaders entering the same serialization branch and compute shaders with non-
mainentry points.
Successful direct shader / pipeline creation alone does not exercise the reproduced archive-reload-and-reserialize path.
Activity
TheMostDiligent commentedon Oct 28, 2026
Fixed in #814