Repository: google/filament
File: filament/backend/src/webgpu/WebGPUPipelineCreation.cpp (C++)

Code before:
            //    where certain constants may be optimized out of the shader based
            //    on build configuration, etc.
            //
            // to bypass these problems, we do not use override constants in the
            // WebGPU backend, instead replacing placeholder constants in the shader
            // text before creating the shader module (essentially implementing
            // override constants ourselves)
            .constantCount = 0,
            .constants = nullptr,
            .bufferCount = vertexBufferInfo.getVertexBufferLayoutCount(),
            .buffers = vertexBufferInfo.getVertexBufferLayouts()
        },
        .primitive = {
            .topology = toWebGPU(primitiveType),
            // TODO should we assume some constant format here or is there a way to get
            //      this from PipelineState somehow or elsewhere?
            //      Perhaps, cache/assert format from index buffers as they are requested?
            .stripIndexFormat = wgpu::IndexFormat::Undefined,
            .frontFace = rasterState.inverseFrontFaces ? wgpu::FrontFace::CW : wgpu::FrontFace::CCW,
            .cullMode = toWebGPU(rasterState.culling),
            // TODO no depth clamp in WebGPU supported directly. unclippedDepth is close, so we are
            //      starting there
            .unclippedDepth = !rasterState.depthClamp &&
                              device.HasFeature(wgpu::FeatureName::DepthClipControl)
        },
        .depthStencil = depthStencilFormat != wgpu::TextureFormat::Undefined ? &depthStencilState: nullptr,
        .multisample = {
            .count = samplesCount,
            .mask = 0xFFFFFFFF,
            .alphaToCoverageEnabled = rasterState.alphaToCoverage
        },
        .fragment = nullptr // will add below if fragment module is included
    };
    wgpu::FragmentState fragmentState = {};
    std::array<wgpu::ColorTargetState, MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT> colorTargets {};
    const wgpu::BlendState blendState {
        .color = {
            .operation = toWebGPU(rasterState.blendEquationRGB),
            .srcFactor = toWebGPU(rasterState.blendFunctionSrcRGB),
            .dstFactor = toWebGPU(rasterState.blendFunctionDstRGB)
        },
        .alpha = {
            .operation = toWebGPU(rasterState.blendEquationAlpha),
            .srcFactor = toWebGPU(rasterState.blendFunctionSrcAlpha),
            .dstFactor = toWebGPU(rasterState.blendFunctionDstAlpha)
        }
    };
    if (program.fragmentShaderModule != nullptr) {
        fragmentState.module = program.fragmentShaderModule;
        fragmentState.entryPoint = "main";
        // see the comment about constants for the vertex state, as the same reasoning applies

Review comment (bug):
I think the condition should be based on the 2 flags, something like `= (requestedDepth || requestedStencil) ? &depthStencilState : nullptr;`?

The primary objective of this change is to use Filament's flags, not inferencing based on formats or provided textures, etc.

Code after:
            // (at least at the time of write this):
            // 1. they cannot be used for the size of an array, which is needed
            // 2. if we pass the WebGPU API (CPU-side) constants not referenced in the
            //    shader WebGPU fails. This is a problem with how Filament is designed,
            //    where certain constants may be optimized out of the shader based
            //    on build configuration, etc.
            //
            // to bypass these problems, we do not use override constants in the
            // WebGPU backend, instead replacing placeholder constants in the shader
            // text before creating the shader module (essentially implementing
            // override constants ourselves)
            .constantCount = 0,
            .constants = nullptr,
            .bufferCount = vertexBufferInfo.getVertexBufferLayoutCount(),
            .buffers = vertexBufferInfo.getVertexBufferLayouts()
        },
        .primitive = {
            .topology = toWebGPU(primitiveType),
            // TODO should we assume some constant format here or is there a way to get
            //      this from PipelineState somehow or elsewhere?
            //      Perhaps, cache/assert format from index buffers as they are requested?
            .stripIndexFormat = wgpu::IndexFormat::Undefined,
            .frontFace = rasterState.inverseFrontFaces ? wgpu::FrontFace::CW : wgpu::FrontFace::CCW,
            .cullMode = toWebGPU(rasterState.culling),
            // TODO no depth clamp in WebGPU supported directly. unclippedDepth is close, so we are
            //      starting there
            .unclippedDepth = !rasterState.depthClamp &&
                              device.HasFeature(wgpu::FeatureName::DepthClipControl)
        },
        .depthStencil = depthOrStencilRequested ? &depthStencilState: nullptr,
        .multisample = {
            .count = samplesCount,
            .mask = 0xFFFFFFFF,
            .alphaToCoverageEnabled = (samplesCount > 1) && rasterState.alphaToCoverage
        },
        .fragment = nullptr // will add below if fragment module is included
    };
    wgpu::FragmentState fragmentState = {};
    std::array<wgpu::ColorTargetState, MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT> colorTargets {};
    const wgpu::BlendState blendState {
        .color = {
            .operation = toWebGPU(rasterState.blendEquationRGB),
            .srcFactor = toWebGPU(rasterState.blendFunctionSrcRGB),
            .dstFactor = toWebGPU(rasterState.blendFunctionDstRGB)
        },
        .alpha = {
            .operation = toWebGPU(rasterState.blendEquationAlpha),
            .srcFactor = toWebGPU(rasterState.blendFunctionSrcAlpha),
            .dstFactor = toWebGPU(rasterState.blendFunctionDstAlpha)
        }
    };