Buffer Map Write Extended Usages

Background

By default WebGPU only allows wgpu::BufferUsage::MapWrite to be combined with wgpu::BufferUsage::CopySrc. Uploading data that the GPU consumes as a uniform, vertex, index, storage or indirect buffer therefore requires a separate staging buffer and an explicit copy on every update.

The wgpu::FeatureName::BufferMapWriteExtendedUsages feature removes this restriction: it allows creating a buffer with wgpu::BufferUsage::MapWrite combined with any other wgpu::BufferUsage, except wgpu::BufferUsage::MapRead. This makes it possible to write directly into a mappable buffer that is also GPU-usable, eliminating the staging buffer and the extra copy.

The feature works on the GPUs with either cache-coherent or non-cache-coherent Unified Memory Architecture (UMA), where we can effectively upload data from CPU to GPU through mapped pointer, and directly access the data on GPU without any extra copies.

This is a subset of the more permissive BufferMapExtendedUsages feature, which additionally allows wgpu::BufferUsage::MapRead to be combined with arbitrary usages but is only available on a narrower set of hardware (cache-coherent UMA). Because it is a superset, enabling BufferMapExtendedUsages on a device implicitly enables BufferMapWriteExtendedUsages as well.

Target API support

The table below summarizes the requirement to enable this feature on D3D12, Metal and Vulkan:

BackendRequirement to enableBacking memory for write-only mapping
Direct3D 12D3D12_FEATURE_DATA_ARCHITECTURE.UMA == TRUECustom heap (D3D12_HEAP_TYPE_CUSTOM) in the L0 system memory pool (D3D12_MEMORY_POOL_L0), with CPU page property D3D12_CPU_PAGE_PROPERTY_WRITE_BACK on cache-coherent UMA or D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE on non-cache-coherent UMA.
Metal[MTLDevice hasUnifiedMemory] == YESMTLResourceStorageModeShared allocation with MTLResourceCPUCacheModeWriteCombined; no didModifyRange: / synchronization needed.
VulkanA memory type exposing VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT.A HOST_COHERENT (write-combined) memory type; VK_MEMORY_PROPERTY_HOST_CACHED_BIT is not required, so non-cache-coherent UMA GPUs are supported.

Proposal

API

New feature name wgpu::FeatureName::BufferMapWriteExtendedUsages. It is currently experimental (see crbug.com/386255678).

Once enabled, wgpu::BufferUsage::MapWrite can be combined with any other wgpu::BufferUsage except wgpu::BufferUsage::MapRead.

Example Usage

wgpu::BufferDescriptor descriptor;
descriptor.size = size;
// MapWrite can now be combined with any usage other than MapRead.
descriptor.usage = wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::Uniform;
wgpu::Buffer uniformBuffer = device.CreateBuffer(&descriptor);

uniformBuffer.MapAsync(wgpu::MapMode::Write, 0, size,
    wgpu::CallbackMode::AllowSpontaneous,
    [uniformBuffer, size](wgpu::MapAsyncStatus status, wgpu::StringView) {
        if (status == wgpu::MapAsyncStatus::Success) {
            memcpy(uniformBuffer.GetMappedRange(), data, size);
            uniformBuffer.Unmap();
        }
    });

Validation

  • The feature must be enabled on the device before creating a buffer that combines wgpu::BufferUsage::MapWrite with non-wgpu::BufferUsage::CopySrc usages.
  • wgpu::BufferUsage::MapRead cannot be combined with other GPU usages under this feature.

Notes and Limitations

  • Reading back from a buffer created with this feature on CPU (for example via memcpy out of the mapped range) may be extremely slow because the underlying memory is typically uncached on CPU.