Skip to content

Result buffer getting destroyed while required to be alive by the command buffer in long running compute shader #5000

@BLaZeKiLL

Description

@BLaZeKiLL

Description
Hi, I implemented a raytracer using wgpu and compute shaders. It works fine, but when I try to render a larger scene or anything that takes more than 8 secs, I get an empty buffer as output. without any errors logged or panics.

If I run with METAL_DEVICE_WRAPPER_TYPE=1 I get the following error

-[MTLDebugDevice notifyExternalReferencesNonZeroOnDealloc:]:3190: failed assertion `The following Metal object is being destroyed while still required to be alive by the command buffer 0x142835a00 (label: (wgpu internal) Signal):
<MTLToolsObject: 0x142712e80> -> <AGXG13XFamilyBuffer: 0x142712c90>
    label = Result buffer 
    length = 8294400 
    cpuCacheMode = MTLCPUCacheModeDefaultCache 
    storageMode = MTLStorageModeShared 
    hazardTrackingMode = MTLHazardTrackingModeTracked 
    resourceOptions = MTLResourceCPUCacheModeDefaultCache MTLResourceStorageModeShared MTLResourceHazardTrackingModeTracked  
    purgeableState = MTLPurgeableStateNonVolatile'
zsh: abort      cargo run --bin vexray

I am assuming this has something to do with how I am waiting for the shader to finish execution

pub async fn finish(
    &self,
    gpu: &Gpu,
    config: &KernelConfig,
    buffers: &KernelBuffers,
    submission_index: wgpu::SubmissionIndex
) -> Result<Vec<u8>, ()> {
    let mut output = vec![0u8; (config.result_size()) as usize];

    let result_slice = buffers.result.slice(..);

    let (sender, receiver) = flume::bounded(1);

    result_slice.map_async(wgpu::MapMode::Read, move |v| sender.send(v).unwrap());

    // Wait for result
    gpu.device.poll(wgpu::Maintain::WaitForSubmissionIndex(submission_index));

    if let Ok(Ok(_)) = receiver.recv_async().await {
        let result_view = result_slice.get_mapped_range();

        output.copy_from_slice(&result_view[..]);
    } else {
        return Err(());
    }

    // Cleanup
    // result view would be dropped by here
    buffers.result.unmap();

    return Ok(output);
}

I read in the examples that we should use device.poll on a separate thread, being new to rust I am not sure how to go about doing that, an example of the same would be helpful.

My main issue is no errors or panics are reported unless I set the env variable METAL_DEVICE_WRAPPER_TYPE=1, I tried adding a simple divide by zero error in my compute shaders and still no errors were reported.

Repro steps
Source code - https://github.com/BLaZeKiLL/wgpu-app

  • run the binary with cargo run --bin vexray
  • should output render.png

Expected vs observed behavior
result buffer shouldn't be dropped before copy is complete

Platform
OS: MacOS 14.2
Backend: Metal
Wgpu: 0.18
Rust: 1.74.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions