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

Code before:
    if (any(TextureUsage::GEN_MIPMAPPABLE & fUsage)) {
        retUsage |= (wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TextureBinding);
    }
    if (any(TextureUsage::SAMPLEABLE & fUsage)) {
        retUsage |= wgpu::TextureUsage::TextureBinding;
    }
    // if needsComputeStorageSupport we need to read and write to the texture in a shader and thus
    // require CopySrc, CopyDst, TextureBinding, & StorageBinding
    if (needsComputeStorageSupport) {
        retUsage |= (wgpu::TextureUsage::StorageBinding | wgpu::TextureUsage::CopySrc |
                     wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::TextureBinding);
    }

    wgpu::TextureUsage transientAttachmentNeeded{ wgpu::TextureUsage::None };
    const bool useTransientAttachment {
            // Usage consists of attachment flags only.
            none(fUsage & ~TextureUsage::ALL_ATTACHMENTS) &&
            // Usage contains at least one attachment flag.
            any(fUsage & TextureUsage::ALL_ATTACHMENTS) &&
            // Depth resolve cannot use transient attachment because it uses a custom shader.
            // TODO: see VulkanDriver::isDepthStencilResolveSupported() to know when to remove this
            // restriction.
            // Note that the custom shader does not resolve stencil. We do need to move to vk 1.2
            // and above to be able to support stencil resolve (along with depth).
            !(any(fUsage & TextureUsage::DEPTH_ATTACHMENT) && samples > 1)};
    if (useTransientAttachment && deviceSupportsTransientAttachments) {
        transientAttachmentNeeded |= wgpu::TextureUsage::TransientAttachment;
    }

    // A texture that is a blit destination or render attachment will often need to be
    // a copy source for subsequent operations (e.g., mipmap generation, readbacks).
    // However, we dont need to add the CopySrc IF its a transientAttachment
    if (any((TextureUsage::BLIT_DST | TextureUsage::COLOR_ATTACHMENT |
                    TextureUsage::DEPTH_ATTACHMENT) &
                fUsage)) {
        if (!useTransientAttachment) {
            retUsage |= wgpu::TextureUsage::CopySrc;
        }
    }

    if (needsRenderAttachmentSupport) {
        retUsage |= wgpu::TextureUsage::RenderAttachment;
    }
    // WGPU Render attachment covers either color or stencil situation dependant
    if (any((TextureUsage::COLOR_ATTACHMENT | TextureUsage::STENCIL_ATTACHMENT |
                    TextureUsage::DEPTH_ATTACHMENT) &
                fUsage)) {
        retUsage |= wgpu::TextureUsage::RenderAttachment;
        retUsage |= transientAttachmentNeeded;
    }


Review comment (suggestion):
I think `deviceSupportsTransientAttachments` needs to be part of how we set/compute the bool `useTransientAttachment`itself. Otherwise, we are making decisions about other things w.r.t. having a transient attachment when we don't... logical inconsistencies that can get very confusing and error prone.

Code after:
    }

    if (fFormat == filament::backend::TextureFormat::DEPTH24_STENCIL8 ||
            fFormat == filament::backend::TextureFormat::DEPTH32F_STENCIL8) {
        if (isSample) {
            return wgpu::TextureAspect::DepthOnly;
        }
    }

    return wgpu::TextureAspect::All;
}

[[nodiscard]] WebGPUTexture::MipmapGenerationStrategy determineMipmapGenerationStrategy(
        const wgpu::TextureFormat format, const SamplerType samplerType, const uint8_t sampleCount,
        const uint8_t mipmapLevels) {
    if (mipmapLevels <= 1) {
        return WebGPUTexture::MipmapGenerationStrategy::NONE; // no mipmap generation needed
    }
    const WebGPURenderPassMipmapGenerator::FormatCompatibility renderPassCompatibility{
        WebGPURenderPassMipmapGenerator::getCompatibilityFor(format,
                toWebGPUTextureDimension(samplerType), sampleCount)
    };
    if (renderPassCompatibility.compatible) {
        return WebGPUTexture::MipmapGenerationStrategy::RENDER_PASS;
    }
    if (WebGPUTexture::supportsMultipleMipLevelsViaStorageBinding(format)) {
        return WebGPUTexture::MipmapGenerationStrategy::SPD_COMPUTE_PASS;
    }
    // we don't have a way to generate mipmaps for this texture, at least at this time
    return WebGPUTexture::MipmapGenerationStrategy::NONE;
}

[[nodiscard]] constexpr wgpu::Extent3D toTextureSize(const SamplerType samplerType,
        const uint32_t width, const uint32_t height, const uint32_t depth) {
    switch (samplerType) {
        case SamplerType::SAMPLER_2D:
        case SamplerType::SAMPLER_2D_ARRAY:
        case SamplerType::SAMPLER_EXTERNAL:
        case SamplerType::SAMPLER_3D:
            return { .width = width, .height = height, .depthOrArrayLayers = depth };
        case SamplerType::SAMPLER_CUBEMAP:
            return { .width = width, .height = height, .depthOrArrayLayers = 6 };
        case SamplerType::SAMPLER_CUBEMAP_ARRAY:
            return { .width = width, .height = height, .depthOrArrayLayers = depth * 6 };
    }
}

[[nodiscard]] constexpr uint32_t toArrayLayerCount(const SamplerType samplerType,
        const uint32_t depthOrArrayLayers) {
    switch (samplerType) {
        case SamplerType::SAMPLER_2D: