Why is webgpu on mac "max binding size" much smaller than reported "max buffer size"?

98 Views Asked by At

I'm developing a library based in WebGPU on a high end mac laptop using Chrome. The library is primarily designed to implement compute shader pipelines for manipulating microscopy and other 3d volume data (https://github.com/AaronWatters/webgpu_volume).

According to https://webgpureport.org/ I should be able to allocate a 4GB buffer based on the reported maxBufferSize and maxStorageBufferBindingSize.

However when I try to allocate a largish buffer I get this error message:

   Binding size (138331344) of [Buffer] is larger than the maximum binding size (134217728).

Why is the reported max buffer size 4GB and the actual limit when executing 134M?

Is there any way to request higher limits? What's up with this?

Note that the following question is similar but has no helpful responses: Binding size '...' is larger than the maximum binding size (134217728)

(edit) I tried this:

const twoGig = 2147483648;
const required_limits = {};
// https://developer.mozilla.org/en-US/docs/Web/API/GPUDevice/limits
required_limits.maxStorageBufferBindingSize = twoGig;
required_limits.maxBufferSize = twoGig;
this.device = await this.adapter.requestDevice(required_limits);

but so far it seems like the required_limits are ignored.

2

There are 2 best solutions below

0
Permille On BEST ANSWER

Your issue is caused by an incorrect layout of the object in your requestDevice call. The correct object format is the following:

const twoGig = 2147483648;
const required_limits = {};
// https://developer.mozilla.org/en-US/docs/Web/API/GPUDevice/limits
required_limits.maxStorageBufferBindingSize = twoGig;
required_limits.maxBufferSize = twoGig;
this.device = await this.adapter.requestDevice({
  "requiredLimits": required_limits
});

Notice how your required limits actually need to be a property inside of the object you pass in as a parameter. These are the relevant parts of the standard: for the requestDevice function, and its parameter object.

On another note, in production apps, I would recommend verifying that your limits do not exceed the amount actually supported by the adapter -- if they did, then your requestDevice call would throw a TypeError, as defined by the standard. As most surveyed devices only support a maxStorageBufferBindingSize of 2147483644 (just short of 2GiB), your code would probably not work on most devices. You can easily query the adapter's limits by checking its limits property, e.g. adapter.limits.maxStorageBufferBindingSize, and use that value when calling requestDevice.

0
gman On

To add to @Permille's answer

This gets simpler like this

const twoGig = 2147483648;
const requiredLimits = {};
requiredLimits.maxStorageBufferBindingSize = twoGig;
requiredLimits.maxBufferSize = twoGig;
this.device = await this.adapter.requestDevice({
  requiredLimits
});

or this

const twoGig = 2147483648;
const requiredLimits = {
   maxStorageBufferBindingSize: twoGig,
   maxBufferSize: twoGig,
};
this.device = await this.adapter.requestDevice({
  requiredLimits
});

or this

const twoGig = 2147483648;
this.device = await this.adapter.requestDevice({
  requiredLimits: {
    maxStorageBufferBindingSize: twoGig,
    maxBufferSize: twoGig,
  },
});

Also as @Permille answered, you probably want to to check the adapter supports the size you want/need

const twoGig = 2147483648;

const { maxBufferSize, maxStorageBufferBindingSize } = this.adapter.limits;

if (maxBufferSize < twoGig ||
    maxStorageBufferBindingSize < twoGig) {
  // tell the user they're out of luck or refactor your code
  // to work with smaller sizes. (like maybe multiple buffers?)
}

// request the adapter's maximum sizes
this.device = await this.adapter.requestDevice({
  requiredLimits: {
    maxStorageBufferBindingSize,
    maxBufferSize,
  },
});

note: You're free to use any style you want but in general, most JS code uses camelCase (including all browser APIs) and not snake_case