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

Code before:
WebGPUSwapChain::WebGPUSwapChain(wgpu::Extent2D const& extent,
        wgpu::Adapter const& adapter, wgpu::Device const& device, uint64_t flags)
    : mType(SwapChainType::HEADLESS),
      mHeadlessWidth(extent.width),
      mHeadlessHeight(extent.height){

    const wgpu::TextureDescriptor textureDescriptor = {
        .usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc,
        .dimension = wgpu::TextureDimension::e2D,
        .size = { mHeadlessWidth, mHeadlessHeight, 1 },
        .format = wgpu::TextureFormat::RGBA8Unorm,
        .mipLevelCount = 1,
        .sampleCount = 1,
    };

     mRenderTargetTextures.fill(nullptr);
     mRenderTargetViews.fill(nullptr);

    for (size_t i = 0; i < mHeadlessBufferCount; ++i) {
        mRenderTargetTextures[i] = device.CreateTexture(&textureDescriptor);
        wgpu::TextureViewDescriptor viewDesc{};
        viewDesc.format = textureDescriptor.format;
        viewDesc.dimension = wgpu::TextureViewDimension::e2D;
        viewDesc.baseMipLevel = 0;
        viewDesc.mipLevelCount = 1;
        viewDesc.baseArrayLayer = 0;
        viewDesc.arrayLayerCount = 1;
        viewDesc.aspect = wgpu::TextureAspect::All;
        mRenderTargetViews[i] = mRenderTargetTextures[i].CreateView(&viewDesc);
    }
}

WebGPUSwapChain::~WebGPUSwapChain() {
    if (isHeadless()) {
        for (auto& texture: mRenderTargetTextures) {
            if (texture) texture.Destroy();
        }
    } else {
        mSurface.Unconfigure();
    }
}


void WebGPUSwapChain::setExtent(wgpu::Extent2D const& currentSurfaceSize) {
    FILAMENT_CHECK_POSTCONDITION(currentSurfaceSize.width > 0 || currentSurfaceSize.height > 0)
            << "WebGPUSwapChain::setExtent: Invalid width " << currentSurfaceSize.width
            << " and/or height " << currentSurfaceSize.height << " requested.";
    if (mConfig.width != currentSurfaceSize.width || mConfig.height != currentSurfaceSize.height) {
        mConfig.width = currentSurfaceSize.width;
        mConfig.height = currentSurfaceSize.height;
        FWGPU_LOGD << "Resizing to width " << mConfig.width << " height " << mConfig.height

Review comment (bug):
we should check if the result of `CreateView` is `nullptr`, if the texture view failed to get created.

Code after:
    mConfig.alphaMode = wgpu::CompositeAlphaMode::Auto;

    mDepthFormat = selectDepthFormat(device.HasFeature(wgpu::FeatureName::Depth32FloatStencil8),
                mNeedStencil);
    const wgpu::TextureDescriptor textureDescriptor = {
        .usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc,
        .dimension = wgpu::TextureDimension::e2D,
        .size = { .width = mHeadlessWidth, .height = mHeadlessHeight, .depthOrArrayLayers = 1 },
        .format = wgpu::TextureFormat::RGBA8Unorm,
        .mipLevelCount = 1,
        .sampleCount = 1,
    };

    const wgpu::TextureViewDescriptor viewDesc = {
        .format = textureDescriptor.format,
        .dimension = wgpu::TextureViewDimension::e2D,
        .baseMipLevel = 0,
        .mipLevelCount = 1,
        .baseArrayLayer = 0,
        .arrayLayerCount = 1,
        .aspect = wgpu::TextureAspect::All,
    };

    for (size_t i = 0; i < mHeadlessBufferCount; ++i) {
        mRenderTargetTextures[i] = device.CreateTexture(&textureDescriptor);
        mRenderTargetViews[i] = mRenderTargetTextures[i].CreateView(&viewDesc);
        FILAMENT_CHECK_POSTCONDITION( mRenderTargetViews[i]) << "Failed to create headless texture with width "
                                               << extent.width << " and height " << extent.height;
    }
}

WebGPUSwapChain::~WebGPUSwapChain() {
    if (!isHeadless()) {
        mSurface.Unconfigure();
    }
}


void WebGPUSwapChain::setExtent(wgpu::Extent2D const& currentSurfaceSize) {
    FILAMENT_CHECK_POSTCONDITION(currentSurfaceSize.width > 0 || currentSurfaceSize.height > 0)
            << "WebGPUSwapChain::setExtent: Invalid width " << currentSurfaceSize.width
            << " and/or height " << currentSurfaceSize.height << " requested.";
    if (mConfig.width != currentSurfaceSize.width || mConfig.height != currentSurfaceSize.height) {
        mConfig.width = currentSurfaceSize.width;
        mConfig.height = currentSurfaceSize.height;
        FWGPU_LOGD << "Resizing to width " << mConfig.width << " height " << mConfig.height;
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
        printSurfaceConfiguration(mConfig, mDepthFormat);
#endif
        // TODO we may need to ensure no surface texture is in flight when we do this. some
        //      synchronization may be necessary