Limits

Querying supportedLimits and Requesting Higher Ones

adapter.limits is the best this adapter can do. To go beyond the defaults, for a 1 GiB storage buffer or 1024-thread workgroups, use requiredLimits, but never ask for more than the adapter reports: an unclamped request for 16 color attachments rejected the whole call with OperationError: Required limit (16) is greater than the supported limit (8). So clamp each wish:

Requesting higher limits, clamped to what the adapter supportsHTMLLive
<script type="module">
  const want = { maxBufferSize: 1024 ** 3, maxStorageBufferBindingSize: 1024 ** 3,
                 maxComputeInvocationsPerWorkgroup: 1024, maxColorAttachments: 16 };
  const adapter = await navigator.gpu.requestAdapter();
  const requiredLimits = {};
  for (const [name, value] of Object.entries(want)) {
    requiredLimits[name] = Math.min(value, adapter.limits[name]);   // never ask for more
  }
  const device = await adapter.requestDevice({ requiredLimits });
  for (const n in want) console.log(`${n}: wanted ${want[n]}, got ${device.limits[n]}`);
</script>

Then read device.limits and adapt, for example by splitting work into more dispatches. The two alignment limits (minUniformBufferOffsetAlignment, minStorageBufferOffsetAlignment) work the other way round (smaller is better), so clamp those with Math.max, as the helper in Feature Detection does.