Skip to content

Commit

Permalink
Base defaults off of device with no limits requested
Browse files Browse the repository at this point in the history
rather than a table.

Add link to features and limits that they must be requested
  • Loading branch information
greggman committed Jul 23, 2024
1 parent 2813ec1 commit 48544da
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 62 deletions.
7 changes: 7 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,13 @@
padding-left: 2em;
}

.bracketed-link {
font-size: x-small;
}
.bracketed-link a {
text-decoration: none;
}

#download {
padding-left: 1em;
cursor: pointer;
Expand Down
143 changes: 81 additions & 62 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,46 +14,46 @@ export const kMaxUnsignedLongValue = 4294967295;
export const kMaxUnsignedLongLongValue = Number.MAX_SAFE_INTEGER;

/** Info for each entry of GPUSupportedLimits */
const kLimitInfo = /* prettier-ignore */ makeTable(
[ 'class','type' , 'default', 'compat' , 'maximumValue'],
[ 'maximum', , , , kMaxUnsignedLongValue], {
'maxTextureDimension1D': [ , 'size' , 8192, 4096, ],
'maxTextureDimension2D': [ , 'size' , 8192, 4096, ],
'maxTextureDimension3D': [ , 'size' , 2048, 1024, ],
'maxTextureArrayLayers': [ , 'size' , 256, 256, ],

'maxBindGroups': [ , 'count' , 4, 4, ],
'maxBindGroupsPlusVertexBuffers': [ , 'count' , 24, 24, ],
'maxBindingsPerBindGroup': [ , 'count' , 1000, 1000, ],
'maxDynamicUniformBuffersPerPipelineLayout': [ , 'count' , 8, 8, ],
'maxDynamicStorageBuffersPerPipelineLayout': [ , 'count' , 4, 4, ],
'maxSampledTexturesPerShaderStage': [ , 'count' , 16, 16, ],
'maxSamplersPerShaderStage': [ , 'count' , 16, 16, ],
'maxStorageBuffersPerShaderStage': [ , 'count' , 8, 4, ],
'maxStorageTexturesPerShaderStage': [ , 'count' , 4, 4, ],
'maxUniformBuffersPerShaderStage': [ , 'count' , 12, 12, ],

'maxUniformBufferBindingSize': [ , 'mem' , 65536, 16384, kMaxUnsignedLongLongValue],
'maxStorageBufferBindingSize': [ , 'mem' , 134217728, 134217728, kMaxUnsignedLongLongValue],
'minUniformBufferOffsetAlignment': ['alignment', 'mem' , 256, 256, ],
'minStorageBufferOffsetAlignment': ['alignment', 'mem' , 256, 256, ],

'maxVertexBuffers': [ , 'count' , 8, 8, ],
'maxBufferSize': [ , 'mem' , 268435456, 268435456, kMaxUnsignedLongLongValue],
'maxVertexAttributes': [ , 'count' , 16, 16, ],
'maxVertexBufferArrayStride': [ , 'mem' , 2048, 2048, ],
'maxInterStageShaderComponents': [ , 'count' , 60, 60, ],
'maxInterStageShaderVariables': [ , 'count' , 16, 16, ],

'maxColorAttachments': [ , 'count' , 8, 4, ],
'maxColorAttachmentBytesPerSample': [ , 'mem' , 32, 32, ],

'maxComputeWorkgroupStorageSize': [ , 'mem' , 16384, 16384, ],
'maxComputeInvocationsPerWorkgroup': [ , 'count' , 256, 128, ],
'maxComputeWorkgroupSizeX': [ , 'size' , 256, 128, ],
'maxComputeWorkgroupSizeY': [ , 'size' , 256, 128, ],
'maxComputeWorkgroupSizeZ': [ , 'size' , 64, 64, ],
'maxComputeWorkgroupsPerDimension': [ , 'mem' , 65535, 65535, ],
const kLimitInfo = makeTable(
[ 'class','type' , 'maximumValue'],
[ 'maximum', , kMaxUnsignedLongValue], {
'maxTextureDimension1D': [ , 'size' , ],
'maxTextureDimension2D': [ , 'size' , ],
'maxTextureDimension3D': [ , 'size' , ],
'maxTextureArrayLayers': [ , 'count' , ],

'maxBindGroups': [ , 'count' , ],
'maxBindGroupsPlusVertexBuffers': [ , 'count' , ],
'maxBindingsPerBindGroup': [ , 'count' , ],
'maxDynamicUniformBuffersPerPipelineLayout': [ , 'count' , ],
'maxDynamicStorageBuffersPerPipelineLayout': [ , 'count' , ],
'maxSampledTexturesPerShaderStage': [ , 'count' , ],
'maxSamplersPerShaderStage': [ , 'count' , ],
'maxStorageBuffersPerShaderStage': [ , 'count' , ],
'maxStorageTexturesPerShaderStage': [ , 'count' , ],
'maxUniformBuffersPerShaderStage': [ , 'count' , ],

'maxUniformBufferBindingSize': [ , 'mem' , kMaxUnsignedLongLongValue],
'maxStorageBufferBindingSize': [ , 'mem' , kMaxUnsignedLongLongValue],
'minUniformBufferOffsetAlignment': ['alignment', 'mem' , ],
'minStorageBufferOffsetAlignment': ['alignment', 'mem' , ],

'maxVertexBuffers': [ , 'count' , ],
'maxBufferSize': [ , 'mem' , kMaxUnsignedLongLongValue],
'maxVertexAttributes': [ , 'count' , ],
'maxVertexBufferArrayStride': [ , 'mem' , ],
'maxInterStageShaderComponents': [ , 'count' , ],
'maxInterStageShaderVariables': [ , 'count' , ],

'maxColorAttachments': [ , 'count' , ],
'maxColorAttachmentBytesPerSample': [ , 'mem' , ],

'maxComputeWorkgroupStorageSize': [ , 'mem' , ],
'maxComputeInvocationsPerWorkgroup': [ , 'count' , ],
'maxComputeWorkgroupSizeX': [ , 'size' , ],
'maxComputeWorkgroupSizeY': [ , 'size' , ],
'maxComputeWorkgroupSizeZ': [ , 'size' , ],
'maxComputeWorkgroupsPerDimension': [ , 'size' , ],
});

function createElem(tag, attrs = {}, children = []) {
Expand Down Expand Up @@ -221,43 +221,52 @@ function mapLikeToTableRows(values, sort = true) {
: [el('tr', {}, [el('td', {colSpan: 2, textContent: 'not yet implemented by this browser'})])];
}

function makeBracketedLink(href, textContent, brackets = '()') {
return [
createElem('span', {className: 'bracketed-link'}, [
createElem('span', `${brackets[0]} `),
createElem('a', { target: '_blank', href, textContent }),
createElem('span', ` ${brackets[1]}`),
]),
];
}

function log(...args) {
const elem = document.createElement('pre');
elem.textContent = args.join(' ');
addElemToDocument(elem);
}

function differenceWorse(info, v) {
switch (info.class) {
case 'alignment':
return v > info.default;
case 'maximum':
return v < info.default;
default:
throw new Error(`unknown className: ${info.class}`)
function differenceWorse(name, defaultLimit, v) {
if (name.startsWith('min')) {
return v > defaultLimit;
} else if (name.startsWith('max')) {
return v < defaultLimit;
} else {
throw new Error(`unknown limit type: ${name}`)
}
}

function markDifferencesInLimits(adapter) {
function markDifferencesInLimits(adapter, device) {
const defaultLimits = device?.limits ?? {};
return Object.fromEntries(
mapLikeToKeyValueArray(adapter.limits)
.map(([k, v]) => {
const defaultLimit = defaultLimits[k];
const info = kLimitInfo[k];
const isDiff = info && info.default !== v;
const diffClass = info
const isDiff = defaultLimit !== undefined && defaultLimit !== v;
const diffClass = defaultLimit !== undefined
? (isDiff
? differenceWorse(info, v) ? 'different-worse' : 'different-better'
? differenceWorse(k, defaultLimit, v) ? 'different-worse' : 'different-better'
: '')
: 'unknown';
const value = v > 1024 && info ? `${v} (${shortSizeByType(v, info.type)})` : v;
const shortSize = shortSizeByType(v, info?.type ?? 'count');
const value = v > 1024 ? `${v} (${shortSize})` : shortSize;
return [
k,
isDiff
? [value, {className: `${diffClass} nowrap`, title: `default${adapter.isCompatibilityMode ? ' in compat' : ''}: ${shortSizeByType(adapter.isCompatibilityMode ? info.compat : info.default, info.type)}`}]
: info
? [value, {className: 'nowrap', title: 'same as default'}]
: [value, {className: 'unknown nowrap', title: 'unknown limit (new?)'}]

? [value, {className: `${diffClass} nowrap`, title: `default: ${shortSize}`}]
: [value, {className: 'nowrap', title: 'same as default'}]
];
})
);
Expand Down Expand Up @@ -299,9 +308,15 @@ async function adapterToElements(adapter) {
}
// UGH!
const adapterInfo = adapter.info || await (adapter.requestAdapterInfo ? adapter.requestAdapterInfo() : undefined);
const device = await adapter.requestDevice() || {}

const limitsSectionElem = el('tr', {className: 'section'}, [
el('td', {colSpan: 2}, [createHeading('div', '-', 'limits:')]),
el('td', {colSpan: 2}, [
createHeading('div', '-', {}, [
createElem('span', {textContent: 'limits: '}),
...makeBracketedLink('https://webgpufundamentals.org/webgpu/lessons/webgpu-limits-and-features.html', 'must be requested'),
]),
]),
]);

return el('table', {}, [
Expand All @@ -315,9 +330,14 @@ async function adapterToElements(adapter) {
]),
...mapLikeToTableRows(parseAdapterFlags(adapter)),
limitsSectionElem,
...mapLikeToTableRows(markDifferencesInLimits(adapter)),
...mapLikeToTableRows(markDifferencesInLimits(adapter, device), true),
el('tr', {className: 'section'}, [
el('td', {colSpan: 2}, [createHeading('div', '-', 'features:')]),
el('td', {colSpan: 2}, [
createHeading('div', '-', {}, [
createElem('span', {textContent: 'features: '}),
...makeBracketedLink('https://webgpufundamentals.org/webgpu/lessons/webgpu-limits-and-features.html', 'must be requested'),
]),
]),
]),
...setLikeToTableRows(adapter.features),
]),
Expand Down Expand Up @@ -605,7 +625,6 @@ async function main() {
}

const haveFallback = [...adapterIds].findIndex(([, desc]) => desc.fallback) >= 0;
const numUniqueGPUs = adapterIds.size - (haveFallback ? 1 : 0)

const actualAdaptersIds = [...adapterIds].filter(([, {elem}]) => !!elem);
if (actualAdaptersIds.length === 0) {
Expand Down

0 comments on commit 48544da

Please sign in to comment.