Compare commits

...

2 Commits

Author SHA1 Message Date
Konrad Piascik
22ba8875c5 Merge branch 'main' into kpiascik/shadowtestassert 2025-07-04 10:12:24 -04:00
Konrad Piascik
843e1a43c4 Fix shadowtest assert
A zero color target fragment stage implies a depth pass by Filament.
We can create a pipeline without a fragment stage to make it valid.

BUGS=[421933134]
2025-07-04 09:55:02 -04:00
2 changed files with 25 additions and 26 deletions

View File

@@ -1215,12 +1215,6 @@ void WebGPUDriver::bindPipeline(PipelineState const& pipelineState) {
} }
} }
// TODO: We expected this to be a sane check, however it complains when running shadowtest.
//if (program->fragmentShaderModule != nullptr) {
// FILAMENT_CHECK_POSTCONDITION(!pipelineColorFormats.empty())
// << "Render pipeline with fragment shader must have at least one color target "
// "format.";
//}
wgpu::RenderPipeline pipeline = createWebGPURenderPipeline(mDevice, *program, *vertexBufferInfo, wgpu::RenderPipeline pipeline = createWebGPURenderPipeline(mDevice, *program, *vertexBufferInfo,
layout, pipelineState.rasterState, pipelineState.stencilState, layout, pipelineState.rasterState, pipelineState.stencilState,
pipelineState.polygonOffset, pipelineState.primitiveType, pipelineColorFormats, pipelineState.polygonOffset, pipelineState.primitiveType, pipelineColorFormats,

View File

@@ -281,6 +281,14 @@ wgpu::RenderPipeline createWebGPURenderPipeline(wgpu::Device const& device,
} }
}; };
if (program.fragmentShaderModule != nullptr) { if (program.fragmentShaderModule != nullptr) {
// According to the WebGPU spec, a pipeline cannot have a fragment stage with zero color
// targets. This situation can arise in Filament during depth-only passes (like shadow map
// generation) if the material variant still includes a fragment shader.
//
// To handle this, we check if any color targets are configured for this pipeline. If not, we
// create a pipeline *without* a fragment stage. This makes the pipeline valid for a
// depth-only pass, allowing depth writes to proceed correctly.
if (!colorFormats.empty()) {
fragmentState.module = program.fragmentShaderModule; fragmentState.module = program.fragmentShaderModule;
fragmentState.entryPoint = "main"; fragmentState.entryPoint = "main";
// see the comment about constants for the vertex state, as the same reasoning applies // see the comment about constants for the vertex state, as the same reasoning applies
@@ -290,10 +298,6 @@ wgpu::RenderPipeline createWebGPURenderPipeline(wgpu::Device const& device,
fragmentState.targetCount = colorFormats.size(); fragmentState.targetCount = colorFormats.size();
fragmentState.targets = colorTargets.data(); fragmentState.targets = colorTargets.data();
assert_invariant(fragmentState.targetCount <= MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT); assert_invariant(fragmentState.targetCount <= MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT);
// We expect a fragment shader implies at least one color target if it outputs color.
// This should be guaranteed by the caller ensuring colorFormats is not empty.
// However, this fails on shadowtest.cpp, TODO investigate why
// assert_invariant(fragmentState.targetCount > 0);
for (size_t targetIndex = 0; targetIndex < fragmentState.targetCount; targetIndex++) { for (size_t targetIndex = 0; targetIndex < fragmentState.targetCount; targetIndex++) {
auto& colorTarget = colorTargets[targetIndex]; auto& colorTarget = colorTargets[targetIndex];
colorTarget.format = colorFormats[targetIndex]; colorTarget.format = colorFormats[targetIndex];
@@ -303,6 +307,7 @@ wgpu::RenderPipeline createWebGPURenderPipeline(wgpu::Device const& device,
} }
pipelineDescriptor.fragment = &fragmentState; pipelineDescriptor.fragment = &fragmentState;
} }
}
const wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDescriptor); const wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDescriptor);
FILAMENT_CHECK_POSTCONDITION(pipeline) FILAMENT_CHECK_POSTCONDITION(pipeline)
<< "Failed to create render pipeline for " << pipelineDescriptor.label; << "Failed to create render pipeline for " << pipelineDescriptor.label;