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

Code before:
 * @param samples How many samples to use for MSAA
 * @param supportsMultipleMipLevels if we support and (potentially) need multiple
 *                                  mip levels for the texture
 * @return The appropriate texture usage flags for the underlying texture
 */
[[nodiscard]] wgpu::TextureUsage fToWGPUTextureUsage(TextureUsage const& fUsage,
        const uint8_t samples, const bool supportsMultipleMipLevels) {
    wgpu::TextureUsage retUsage = wgpu::TextureUsage::None;

    // if supportsMultipleMipLevels we need to read and write to the texture in a shader to actually
    // generate the different levels
    // (until WebGPU natively supports mipmap generation,
    //  which it unfortunately does not at the time of writing this, ->
    //  https://github.com/gpuweb/gpuweb/issues/386)
    // Thus we need the usage of the texture to include
    // CopySrc, CopyDst, TextureBinding, & StorageBinding

    // Basing this mapping off of VulkanTexture.cpp's getUsage func and suggestions from Gemini
    // TODO Validate assumptions, revisit if issues.
    if (supportsMultipleMipLevels || any(TextureUsage::BLIT_SRC & fUsage)) {
        retUsage |= wgpu::TextureUsage::CopySrc;
    }
    if (supportsMultipleMipLevels ||
            any((TextureUsage::BLIT_DST | TextureUsage::UPLOADABLE) & fUsage)) {
        retUsage |= wgpu::TextureUsage::CopyDst;
    }
    if (supportsMultipleMipLevels || any(TextureUsage::SAMPLEABLE & fUsage)) {
        retUsage |= wgpu::TextureUsage::TextureBinding;
    }
    if (supportsMultipleMipLevels) {
        retUsage |= wgpu::TextureUsage::StorageBinding;
    }
    // WGPU Render attachment covers either color or stencil situation dependant
    // NOTE: Depth attachment isn't used this way in Vulkan but logically maps to WGPU docs. If
    // issues, investigate here.
    if (any((TextureUsage::COLOR_ATTACHMENT | TextureUsage::STENCIL_ATTACHMENT |
                    TextureUsage::DEPTH_ATTACHMENT) &
                fUsage)) {
        retUsage |= wgpu::TextureUsage::RenderAttachment;
    }

    // This is from Vulkan logic- if there are any issues try disabling this first, allows perf
    // benefit though
    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.

Review comment (performance):
Personally, I'd take a tactic of "If the format supports compute, just put the bit to true for the texture". If I understand right, having the bit set aggressively shouldn't be expensive.

Then, for any default texture views we should take the bit off every time. We don't have any intention of using any views we make here in a compute shader (We pass the whole texture to the mipmap generator and it makes it's own views as appropriate)

Code after:
 * @param samples How many samples to use for MSAA
 * @param needsComputeStorageSupport if we need to use this texture as storage binding in something
 *                                   like a compute shader
 * @return The appropriate texture usage flags for the underlying texture
 */
[[nodiscard]] wgpu::TextureUsage fToWGPUTextureUsage(TextureUsage const& fUsage,
        const uint8_t samples, const bool needsComputeStorageSupport) {
    wgpu::TextureUsage retUsage = wgpu::TextureUsage::None;

    // if needsComputeStorageSupport we need to read and write to the texture in a shader and thus
    // require CopySrc, CopyDst, TextureBinding, & StorageBinding

    // Basing this mapping off of VulkanTexture.cpp's getUsage func and suggestions from Gemini
    // TODO Validate assumptions, revisit if issues.
    if (needsComputeStorageSupport || any(TextureUsage::BLIT_SRC & fUsage)) {
        retUsage |= wgpu::TextureUsage::CopySrc;
    }
    if (needsComputeStorageSupport ||
            any((TextureUsage::BLIT_DST | TextureUsage::UPLOADABLE) & fUsage)) {
        retUsage |= wgpu::TextureUsage::CopyDst;
    }
    if (needsComputeStorageSupport || any(TextureUsage::SAMPLEABLE & fUsage)) {
        retUsage |= wgpu::TextureUsage::TextureBinding;
    }
    if (needsComputeStorageSupport) {
        retUsage |= wgpu::TextureUsage::StorageBinding;
    }
    // WGPU Render attachment covers either color or stencil situation dependant
    // NOTE: Depth attachment isn't used this way in Vulkan but logically maps to WGPU docs. If
    // issues, investigate here.
    if (any((TextureUsage::COLOR_ATTACHMENT | TextureUsage::STENCIL_ATTACHMENT |
                    TextureUsage::DEPTH_ATTACHMENT) &
                fUsage)) {
        retUsage |= wgpu::TextureUsage::RenderAttachment;
    }

    // This is from Vulkan logic- if there are any issues try disabling this first, allows perf
    // benefit though
    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) {
        retUsage |= wgpu::TextureUsage::TransientAttachment;