From 791f62866b3496ae7e3a66918c3355dceec6772f Mon Sep 17 00:00:00 2001 From: Kai Ninomiya Date: Thu, 20 Feb 2020 04:29:37 -0800 Subject: [PATCH] Revert "Roll CTS and fix extract_expectation_names.py" This reverts commit 51f4efc99436a226e20ece367e1027dbb8577f82. Reason for revert: rmtree fix was reverted Original change's description: > Roll CTS and fix extract_expectation_names.py > > https://chromium.googlesource.com/external/github.com/gpuweb/cts/+log/ec18cc3262922e7dcdbe70243c6f40606f979144..02b62c256590b040d514ec15c0f12041be8d1575 > > Change-Id: I6db0043cf844a81d1ccdecb4e7c0a51de5430fb4 > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2050036 > Reviewed-by: Robert Ma > Reviewed-by: Rakib Hasan > Reviewed-by: Austin Eng > Commit-Queue: Kai Ninomiya > Cr-Commit-Position: refs/heads/master@{#743007} TBR=kainino@chromium.org,robertma@chromium.org,enga@chromium.org,rmhasan@google.com Change-Id: I2fee3ed2df610c3fc0e385725e3ae0e86718f745 No-Presubmit: true No-Tree-Checks: true No-Try: true Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2066464 Reviewed-by: Kai Ninomiya Commit-Queue: Kai Ninomiya Cr-Commit-Position: refs/heads/master@{#743062} --- webgpu/framework/version.js | 2 +- .../cts/copyImageBitmapToTexture.spec.js | 16 +- .../{capability_info.js => format_info.js} | 41 +---- .../cts/validation/createBindGroup.spec.js | 11 +- .../validation/createBindGroupLayout.spec.js | 151 +++--------------- .../validation/createPipelineLayout.spec.js | 48 +++--- .../validation/createRenderPipeline.spec.js | 6 +- .../cts/validation/createTexture.spec.js | 6 +- 8 files changed, 86 insertions(+), 195 deletions(-) rename webgpu/suites/cts/{capability_info.js => format_info.js} (71%) diff --git a/webgpu/framework/version.js b/webgpu/framework/version.js index a69fa66b29d965..f8067d48eeb9a9 100644 --- a/webgpu/framework/version.js +++ b/webgpu/framework/version.js @@ -1,3 +1,3 @@ // AUTO-GENERATED - DO NOT EDIT. See tools/gen_version. -export const version = '02b62c256590b040d514ec15c0f12041be8d1575'; +export const version = 'ec18cc3262922e7dcdbe70243c6f40606f979144'; diff --git a/webgpu/suites/cts/copyImageBitmapToTexture.spec.js b/webgpu/suites/cts/copyImageBitmapToTexture.spec.js index 046a96f31782a9..b201bb49750c4f 100644 --- a/webgpu/suites/cts/copyImageBitmapToTexture.spec.js +++ b/webgpu/suites/cts/copyImageBitmapToTexture.spec.js @@ -5,7 +5,7 @@ export const description = ` copy imageBitmap To texture tests. `; -import { TestGroup, pcombine, poptions } from '../../framework/index.js'; +import { TestGroup, assert, pcombine, poptions } from '../../framework/index.js'; import { GPUTest } from './gpu_test.js'; function calculateRowPitch(width, bytesPerPixel) { @@ -60,6 +60,17 @@ class F extends GPUTest { } return failedPixels > 0 ? lines.join('\n') : undefined; + } // Using drawImage to extract imageBitmap content. + + + imageBitmapToData(imageBitmap) { + const imageCanvas = document.createElement('canvas'); + imageCanvas.width = imageBitmap.width; + imageCanvas.height = imageBitmap.height; + const imageCanvasContext = imageCanvas.getContext('2d'); + assert(imageCanvasContext !== null, 'Cannot create canvas context for reading back contents from imageBitmap.'); + imageCanvasContext.drawImage(imageBitmap, 0, 0, imageBitmap.width, imageBitmap.height); + return imageCanvasContext.getImageData(0, 0, imageBitmap.width, imageBitmap.height).data; } } @@ -102,6 +113,7 @@ g.test('from ImageData', async t => { height: imageBitmap.height, depth: 1 }); + const data = t.imageBitmapToData(imageBitmap); const rowPitchValue = calculateRowPitch(imageBitmap.width, bytesPerPixel); const testBuffer = t.device.createBuffer({ size: rowPitchValue * imageBitmap.height, @@ -126,7 +138,7 @@ g.test('from ImageData', async t => { depth: 1 }); t.device.defaultQueue.submit([encoder.finish()]); - t.checkCopyImageBitmapResult(testBuffer, imagePixels, imageBitmap.width, imageBitmap.height, bytesPerPixel); + t.checkCopyImageBitmapResult(testBuffer, data, imageBitmap.width, imageBitmap.height, bytesPerPixel); }).params(pcombine(poptions('width', [1, 2, 4, 15, 255, 256]), // poptions('height', [1, 2, 4, 15, 255, 256]))); //# sourceMappingURL=copyImageBitmapToTexture.spec.js.map \ No newline at end of file diff --git a/webgpu/suites/cts/capability_info.js b/webgpu/suites/cts/format_info.js similarity index 71% rename from webgpu/suites/cts/capability_info.js rename to webgpu/suites/cts/format_info.js index 10947ee1367e1d..5d54bbb8c51ecd 100644 --- a/webgpu/suites/cts/capability_info.js +++ b/webgpu/suites/cts/format_info.js @@ -2,9 +2,7 @@ * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts **/ -import { C } from '../../framework/index.js'; // Textures - -export const kTextureFormatInfo = +export const textureFormatInfo = /* prettier-ignore */ { // Try to keep these manually-formatted in a readable grid. @@ -169,61 +167,36 @@ export const kTextureFormatInfo = color: false } }; -export const kTextureFormats = Object.keys(kTextureFormatInfo); // Bindings - -export const kMaxBindingsPerBindGroup = 16; -export const kPerStageBindingLimits = -/* prettier-ignore */ -{ - 'uniform-buffer': 12, - 'storage-buffer': 4, - 'sampler': 16, - 'sampled-texture': 16, - 'storage-texture': 4 -}; -const kStagesAll = C.ShaderStage.Vertex | C.ShaderStage.Fragment | C.ShaderStage.Compute; -const kStagesNonVertex = C.ShaderStage.Fragment | C.ShaderStage.Compute; -export const kBindingTypeInfo = +export const textureFormats = Object.keys(textureFormatInfo); +export const bindingTypeInfo = /* prettier-ignore */ { 'uniform-buffer': { type: 'buffer', - validStages: kStagesAll, - perStageLimitType: 'uniform-buffer', maxDynamicCount: 8 }, 'storage-buffer': { type: 'buffer', - validStages: kStagesNonVertex, - perStageLimitType: 'storage-buffer', maxDynamicCount: 4 }, 'readonly-storage-buffer': { type: 'buffer', - validStages: kStagesAll, - perStageLimitType: 'storage-buffer', maxDynamicCount: 4 }, 'sampler': { type: 'sampler', - validStages: kStagesAll, - perStageLimitType: 'sampler', maxDynamicCount: 0 }, 'sampled-texture': { type: 'texture', - validStages: kStagesAll, - perStageLimitType: 'sampled-texture', maxDynamicCount: 0 }, 'storage-texture': { type: 'texture', - validStages: kStagesAll, - perStageLimitType: 'storage-texture', maxDynamicCount: 0 } }; -export const kBindingTypes = Object.keys(kBindingTypeInfo); -export const kShaderStages = [C.ShaderStage.Vertex, C.ShaderStage.Fragment, C.ShaderStage.Compute]; -export const kShaderStageCombinations = [0, 1, 2, 3, 4, 5, 6, 7]; -//# sourceMappingURL=capability_info.js.map \ No newline at end of file +export const bindingTypes = Object.keys(bindingTypeInfo); +export const shaderStages = [1, 2, 4]; +export const shaderStageCombinations = [0, 1, 2, 3, 4, 5, 6, 7]; +//# sourceMappingURL=format_info.js.map \ No newline at end of file diff --git a/webgpu/suites/cts/validation/createBindGroup.spec.js b/webgpu/suites/cts/validation/createBindGroup.spec.js index 2f42a8b643d490..22472f8dff2cf6 100644 --- a/webgpu/suites/cts/validation/createBindGroup.spec.js +++ b/webgpu/suites/cts/validation/createBindGroup.spec.js @@ -6,7 +6,7 @@ export const description = ` createBindGroup validation tests. `; import { C, TestGroup, pcombine, poptions, unreachable } from '../../../framework/index.js'; -import { kBindingTypes } from '../capability_info.js'; +import { bindingTypes } from '../format_info.js'; import { BindingResourceType, ValidationTest, resourceBindingMatches } from './validation_test.js'; function clone(descriptor) { @@ -107,7 +107,7 @@ g.test('buffer binding must contain exactly one buffer of its type', t => { }] }); }, shouldError); -}).params(pcombine(poptions('bindingType', kBindingTypes), poptions('resourceType', Object.keys(BindingResourceType)))); +}).params(pcombine(poptions('bindingType', bindingTypes), poptions('resourceType', Object.keys(BindingResourceType)))); g.test('texture binding must have correct usage', async t => { const type = t.params.type; const usage = t.params._usage; @@ -389,6 +389,11 @@ g.test('buffer offset and size for bind groups match', async t => { offset: 1024, size: 1, _success: false -} // offset+size is OOB +}, // offset+size is OOB +{ + offset: 256, + size: -256, + _success: false +} // offset+size overflows to be 0 ]); //# sourceMappingURL=createBindGroup.spec.js.map \ No newline at end of file diff --git a/webgpu/suites/cts/validation/createBindGroupLayout.spec.js b/webgpu/suites/cts/validation/createBindGroupLayout.spec.js index b48db9598dd62f..22fa8f5d606e01 100644 --- a/webgpu/suites/cts/validation/createBindGroupLayout.spec.js +++ b/webgpu/suites/cts/validation/createBindGroupLayout.spec.js @@ -6,7 +6,7 @@ export const description = ` createBindGroupLayout validation tests. `; import { C, TestGroup, poptions } from '../../../framework/index.js'; -import { kBindingTypeInfo, kBindingTypes, kMaxBindingsPerBindGroup, kPerStageBindingLimits, kShaderStages } from '../capability_info.js'; +import { bindingTypeInfo, bindingTypes } from '../format_info.js'; import { ValidationTest } from './validation_test.js'; function clone(descriptor) { @@ -35,6 +35,23 @@ g.test('some binding index was specified more than once', async t => { t.device.createBindGroupLayout(badDescriptor); }); }); +g.test('negative binding index', async t => { + const goodDescriptor = { + bindings: [{ + binding: 0, + visibility: GPUShaderStage.COMPUTE, + type: C.BindingType.StorageBuffer + }] + }; // Control case + + t.device.createBindGroupLayout(goodDescriptor); // Negative binding index can't be specified. + + const badDescriptor = clone(goodDescriptor); + badDescriptor.bindings[0].binding = -1; + t.expectValidationError(() => { + t.device.createBindGroupLayout(badDescriptor); + }); +}); g.test('Visibility of bindings can be 0', async t => { t.device.createBindGroupLayout({ bindings: [{ @@ -85,7 +102,7 @@ g.test('number of dynamic buffers exceeds the maximum value', async t => { }]); g.test('dynamic set to true is allowed only for buffers', async t => { const type = t.params.type; - const success = kBindingTypeInfo[type].type === 'buffer'; + const success = bindingTypeInfo[type].type === 'buffer'; const descriptor = { bindings: [{ binding: 0, @@ -97,133 +114,5 @@ g.test('dynamic set to true is allowed only for buffers', async t => { t.expectValidationError(() => { t.device.createBindGroupLayout(descriptor); }, !success); -}).params(poptions('type', kBindingTypes)); -let kCasesForMaxResourcesPerStageTests; -{ - // One bind group layout will be filled with kPerStageBindingLimit[...] of the type |type|. - // For each item in the array returned here, a case will be generated which tests a pipeline - // layout with one extra bind group layout with one extra binding. That extra binding will have: - // - // - If extraTypeSame, any of the binding types which counts toward the same limit as |type|. - // (i.e. 'storage-buffer' <-> 'readonly-storage-buffer'). - // - Otherwise, an arbitrary other type. - function pickExtraBindingTypes(type, extraTypeSame) { - if (extraTypeSame) { - switch (type) { - case 'storage-buffer': - case 'readonly-storage-buffer': - return ['storage-buffer', 'readonly-storage-buffer']; - - default: - return [type]; - } - } else { - return type === 'sampler' ? ['sampled-texture'] : ['sampler']; - } - } - - kCasesForMaxResourcesPerStageTests = []; - - for (const maxedType of kBindingTypes) { - for (const maxedVisibility of kShaderStages) { - // Don't generate a case where maxedType isn't valid in maxedVisibility. - if (!(kBindingTypeInfo[maxedType].validStages & maxedVisibility)) continue; - - for (const extraTypeSame of [true, false]) { - for (const extraType of pickExtraBindingTypes(maxedType, extraTypeSame)) { - for (const extraVisibility of kShaderStages) { - // Don't generate a case where extraType isn't valid in extraVisibility. - if (!(kBindingTypeInfo[extraType].validStages & extraVisibility)) continue; - kCasesForMaxResourcesPerStageTests.push({ - maxedType, - maxedVisibility, - extraType, - extraVisibility - }); - } - } - } - } - } -} // Should never fail unless kMaxBindingsPerBindGroup is exceeded, because the validation for -// resources-of-type-per-stage is in pipeline layout creation. - -g.test('max resources per stage/in bind group layout', async t => { - const maxedType = t.params.maxedType; - const extraType = t.params.extraType; - const { - maxedVisibility, - extraVisibility - } = t.params; - const maxedCount = kPerStageBindingLimits[kBindingTypeInfo[maxedType].perStageLimitType]; - const maxResourceBindings = []; - - for (let i = 0; i < maxedCount; i++) { - maxResourceBindings.push({ - binding: i, - visibility: maxedVisibility, - type: maxedType - }); - } - - const goodDescriptor = { - bindings: maxResourceBindings - }; // Control - - t.device.createBindGroupLayout(goodDescriptor); - const newDescriptor = clone(goodDescriptor); - newDescriptor.bindings.push({ - binding: maxedCount, - visibility: extraVisibility, - type: extraType - }); - const shouldError = maxedCount >= kMaxBindingsPerBindGroup; - t.expectValidationError(() => { - t.device.createBindGroupLayout(newDescriptor); - }, shouldError); -}).params(kCasesForMaxResourcesPerStageTests); // One pipeline layout can have a maximum number of each type of binding *per stage* (which is -// different for each type). Test that the max works, then add one more binding of same-or-different -// type and same-or-different visibility. - -g.test('max resources per stage/in pipeline layout', async t => { - const maxedType = t.params.maxedType; - const extraType = t.params.extraType; - const { - maxedVisibility, - extraVisibility - } = t.params; - const maxedCount = kPerStageBindingLimits[kBindingTypeInfo[maxedType].perStageLimitType]; - const maxResourceBindings = []; - - for (let i = 0; i < maxedCount; i++) { - maxResourceBindings.push({ - binding: i, - visibility: maxedVisibility, - type: maxedType - }); - } - - const goodLayout = t.device.createBindGroupLayout({ - bindings: maxResourceBindings - }); // Control - - t.device.createPipelineLayout({ - bindGroupLayouts: [goodLayout] - }); - const extraLayout = t.device.createBindGroupLayout({ - bindings: [{ - binding: 0, - visibility: extraVisibility, - type: extraType - }] - }); // Some binding types use the same limit, e.g. 'storage-buffer' and 'readonly-storage-buffer'. - - const newBindingCountsTowardSamePerStageLimit = (maxedVisibility & extraVisibility) !== 0 && kBindingTypeInfo[maxedType].perStageLimitType === kBindingTypeInfo[extraType].perStageLimitType; - const layoutExceedsPerStageLimit = newBindingCountsTowardSamePerStageLimit; - t.expectValidationError(() => { - t.device.createPipelineLayout({ - bindGroupLayouts: [goodLayout, extraLayout] - }); - }, layoutExceedsPerStageLimit); -}).params(kCasesForMaxResourcesPerStageTests); +}).params(poptions('type', bindingTypes)); //# sourceMappingURL=createBindGroupLayout.spec.js.map \ No newline at end of file diff --git a/webgpu/suites/cts/validation/createPipelineLayout.spec.js b/webgpu/suites/cts/validation/createPipelineLayout.spec.js index 0018c24e54075c..9d5394f925b6be 100644 --- a/webgpu/suites/cts/validation/createPipelineLayout.spec.js +++ b/webgpu/suites/cts/validation/createPipelineLayout.spec.js @@ -5,8 +5,8 @@ export const description = ` createPipelineLayout validation tests. `; -import { TestGroup, pbool, pcombine, poptions } from '../../../framework/index.js'; -import { kBindingTypeInfo, kBindingTypes, kShaderStageCombinations } from '../capability_info.js'; +import { TestGroup, pcombine, poptions } from '../../../framework/index.js'; +import { bindingTypeInfo, bindingTypes, shaderStageCombinations } from '../format_info.js'; import { ValidationTest } from './validation_test.js'; function clone(descriptor) { @@ -19,7 +19,7 @@ g.test('number of dynamic buffers exceeds the maximum value', async t => { type, visibility } = t.params; - const maxDynamicCount = kBindingTypeInfo[type].maxDynamicCount; + const maxDynamicCount = bindingTypeInfo[type].maxDynamicCount; const maxDynamicBufferBindings = []; for (let binding = 0; binding < maxDynamicCount; binding++) { @@ -58,32 +58,44 @@ g.test('number of dynamic buffers exceeds the maximum value', async t => { }); }).params(pcombine(poptions('visibility', [0, 2, 4, 6]), // poptions('type', ['uniform-buffer', 'storage-buffer', 'readonly-storage-buffer']))); -g.test('visibility and dynamic offsets', t => { - const hasDynamicOffset = t.params.hasDynamicOffset; - const type = t.params.type; - const visibility = t.params.visibility; - const info = kBindingTypeInfo[type]; - const descriptor = { +g.test('dynamic offsets are only allowed on buffers', t => { + const { + type, + visibility + } = t.params; + const info = bindingTypeInfo[type]; + const goodDescriptor = { bindings: [{ binding: 0, visibility, type, - hasDynamicOffset + hasDynamicOffset: false }] }; - let success = true; - if (info.type !== 'buffer' && hasDynamicOffset) success = false; - if ((visibility & ~info.validStages) !== 0) success = false; + t.device.createPipelineLayout({ + bindGroupLayouts: [t.device.createBindGroupLayout(goodDescriptor)] + }); + const badDescriptor = clone(goodDescriptor); + badDescriptor.bindings[0].hasDynamicOffset = true; + const success = info.type === 'buffer'; t.expectValidationError(() => { t.device.createPipelineLayout({ - bindGroupLayouts: [t.device.createBindGroupLayout(descriptor)] + bindGroupLayouts: [t.device.createBindGroupLayout(badDescriptor)] }); }, !success); -}).params(pcombine(poptions('type', kBindingTypes), // -pbool('hasDynamicOffset'), poptions('visibility', kShaderStageCombinations))); +}).params(pcombine(poptions('visibility', shaderStageCombinations), // +poptions('type', bindingTypes))); g.test('number of bind group layouts exceeds the maximum value', async t => { + const { + visibility, + type + } = t.params; const bindGroupLayoutDescriptor = { - bindings: [] + bindings: [{ + binding: 0, + visibility, + type + }] }; // 4 is the maximum number of bind group layouts. const maxBindGroupLayouts = [1, 2, 3, 4].map(() => t.device.createBindGroupLayout(bindGroupLayoutDescriptor)); @@ -99,5 +111,5 @@ g.test('number of bind group layouts exceeds the maximum value', async t => { t.expectValidationError(() => { t.device.createPipelineLayout(badPipelineLayoutDescriptor); }); -}); +}).params(pcombine(poptions('visibility', shaderStageCombinations), poptions('type', bindingTypes))); //# sourceMappingURL=createPipelineLayout.spec.js.map \ No newline at end of file diff --git a/webgpu/suites/cts/validation/createRenderPipeline.spec.js b/webgpu/suites/cts/validation/createRenderPipeline.spec.js index d56f6f7be57385..f6a55552655996 100644 --- a/webgpu/suites/cts/validation/createRenderPipeline.spec.js +++ b/webgpu/suites/cts/validation/createRenderPipeline.spec.js @@ -6,7 +6,7 @@ export const description = ` createRenderPipeline validation tests. `; import { TestGroup, poptions } from '../../../framework/index.js'; -import { kTextureFormatInfo, kTextureFormats } from '../capability_info.js'; +import { textureFormatInfo, textureFormats } from '../format_info.js'; import { ValidationTest } from './validation_test.js'; class F extends ValidationTest { @@ -127,7 +127,7 @@ g.test('at least one color state is required', async t => { }); g.test('color formats must be renderable', async t => { const format = t.params.format; - const info = kTextureFormatInfo[format]; + const info = textureFormatInfo[format]; const descriptor = t.getDescriptor({ colorStates: [{ format @@ -143,7 +143,7 @@ g.test('color formats must be renderable', async t => { t.device.createRenderPipeline(descriptor); }); } -}).params(poptions('format', kTextureFormats)); +}).params(poptions('format', textureFormats)); g.test('sample count must be valid', async t => { const { sampleCount, diff --git a/webgpu/suites/cts/validation/createTexture.spec.js b/webgpu/suites/cts/validation/createTexture.spec.js index a7317a88f5badd..08c6d1b50b596e 100644 --- a/webgpu/suites/cts/validation/createTexture.spec.js +++ b/webgpu/suites/cts/validation/createTexture.spec.js @@ -6,7 +6,7 @@ export const description = ` createTexture validation tests. `; import { TestGroup, poptions } from '../../../framework/index.js'; -import { kTextureFormatInfo, kTextureFormats } from '../capability_info.js'; +import { textureFormatInfo, textureFormats } from '../format_info.js'; import { ValidationTest } from './validation_test.js'; class F extends ValidationTest { @@ -223,7 +223,7 @@ g.test('it is invalid to submit a destroyed texture before and after encode', as }]); g.test('it is invalid to have an output attachment texture with non renderable format', async t => { const format = t.params.format; - const info = kTextureFormatInfo[format]; + const info = textureFormatInfo[format]; const descriptor = t.getDescriptor({ width: 1, height: 1, @@ -232,5 +232,5 @@ g.test('it is invalid to have an output attachment texture with non renderable f t.expectValidationError(() => { t.device.createTexture(descriptor); }, !info.renderable); -}).params(poptions('format', kTextureFormats)); // TODO: Add tests for compressed texture formats +}).params(poptions('format', textureFormats)); // TODO: Add tests for compressed texture formats //# sourceMappingURL=createTexture.spec.js.map \ No newline at end of file