diff options
Diffstat (limited to 'dom/webgpu/tests/cts/checkout/src/webgpu/web_platform/util.ts')
-rw-r--r-- | dom/webgpu/tests/cts/checkout/src/webgpu/web_platform/util.ts | 430 |
1 files changed, 336 insertions, 94 deletions
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/web_platform/util.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/web_platform/util.ts index 84ac6b31d1..56514b2203 100644 --- a/dom/webgpu/tests/cts/checkout/src/webgpu/web_platform/util.ts +++ b/dom/webgpu/tests/cts/checkout/src/webgpu/web_platform/util.ts @@ -1,9 +1,10 @@ import { Fixture, SkipTestCase } from '../../common/framework/fixture.js'; import { getResourcePath } from '../../common/framework/resources.js'; -import { makeTable } from '../../common/util/data_tables.js'; +import { keysOf } from '../../common/util/data_tables.js'; import { timeout } from '../../common/util/timeout.js'; import { ErrorWithExtra, raceWithRejectOnTimeout } from '../../common/util/util.js'; import { GPUTest } from '../gpu_test.js'; +import { RGBA, srgbToDisplayP3 } from '../util/color_space_conversion.js'; declare global { interface HTMLMediaElement { @@ -13,113 +14,342 @@ declare global { } } -export const kVideoInfo = - /* prettier-ignore */ makeTable( - ['mimeType' ] as const, - [undefined ] as const, { - // All video names - 'four-colors-vp8-bt601.webm': ['video/webm; codecs=vp8' ], - 'four-colors-theora-bt601.ogv': ['video/ogg; codecs=theora' ], - 'four-colors-h264-bt601.mp4': ['video/mp4; codecs=avc1.4d400c'], - 'four-colors-vp9-bt601.webm': ['video/webm; codecs=vp9' ], - 'four-colors-vp9-bt709.webm': ['video/webm; codecs=vp9' ], - 'four-colors-vp9-bt2020.webm': ['video/webm; codecs=vp9' ], - 'four-colors-h264-bt601-rotate-90.mp4': ['video/mp4; codecs=avc1.4d400c'], - 'four-colors-h264-bt601-rotate-180.mp4': ['video/mp4; codecs=avc1.4d400c'], - 'four-colors-h264-bt601-rotate-270.mp4': ['video/mp4; codecs=avc1.4d400c'], - } as const); -export type VideoName = keyof typeof kVideoInfo; +// MAINTENANCE_TODO: Uses raw floats as expectation in external_texture related cases has some diffs. +// Remove this conversion utils and uses raw float data as expectation in external_textrue +// related cases when resolve this. +export function convertToUnorm8(expectation: Readonly<RGBA>): Uint8Array { + const rgba8Unorm = new Uint8ClampedArray(4); + rgba8Unorm[0] = Math.round(expectation.R * 255.0); + rgba8Unorm[1] = Math.round(expectation.G * 255.0); + rgba8Unorm[2] = Math.round(expectation.B * 255.0); + rgba8Unorm[3] = Math.round(expectation.A * 255.0); + return new Uint8Array(rgba8Unorm.buffer); +} + +// MAINTENANCE_TODO: Add helper function for BT.601 and BT.709 to remove all magic numbers. // Expectation values about converting video contents to sRGB color space. // Source video color space affects expected values. // The process to calculate these expected pixel values can be found: // https://github.com/gpuweb/cts/pull/2242#issuecomment-1430382811 // and https://github.com/gpuweb/cts/pull/2242#issuecomment-1463273434 const kBt601PixelValue = { - red: new Float32Array([0.972945567233341, 0.141794376683341, -0.0209589916711088, 1.0]), - green: new Float32Array([0.248234279433399, 0.984810378661784, -0.0564701319494314, 1.0]), - blue: new Float32Array([0.10159735826538, 0.135451122863674, 1.00262982899724, 1.0]), - yellow: new Float32Array([0.995470750775951, 0.992742114518355, -0.0774291236205402, 1.0]), -}; - -function convertToUnorm8(expectation: Float32Array): Uint8Array { - const unorm8 = new Uint8ClampedArray(expectation.length); + srgb: { + red: { R: 0.972945567233341, G: 0.141794376683341, B: -0.0209589916711088, A: 1.0 }, + green: { R: 0.248234279433399, G: 0.984810378661784, B: -0.0564701319494314, A: 1.0 }, + blue: { R: 0.10159735826538, G: 0.135451122863674, B: 1.00262982899724, A: 1.0 }, + yellow: { R: 0.995470750775951, G: 0.992742114518355, B: -0.0701036235167653, A: 1.0 }, + }, +} as const; - for (let i = 0; i < expectation.length; ++i) { - unorm8[i] = Math.round(expectation[i] * 255.0); - } +const kBt709PixelValue = { + srgb: { + red: { R: 1.0, G: 0.0, B: 0.0, A: 1.0 }, + green: { R: 0.0, G: 1.0, B: 0.0, A: 1.0 }, + blue: { R: 0.0, G: 0.0, B: 1.0, A: 1.0 }, + yellow: { R: 1.0, G: 1.0, B: 0.0, A: 1.0 }, + }, +} as const; - return new Uint8Array(unorm8.buffer); +function makeTable<Table extends { readonly [K: string]: {} }>({ + table, +}: { + table: Table; +}): { + readonly [F in keyof Table]: { + readonly [K in keyof Table[F]]: Table[F][K]; + }; +} { + return Object.fromEntries( + Object.entries(table).map(([k, row]) => [k, { ...row }]) + /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ + ) as any; } -// kVideoExpectations uses unorm8 results -const kBt601Red = convertToUnorm8(kBt601PixelValue.red); -const kBt601Green = convertToUnorm8(kBt601PixelValue.green); -const kBt601Blue = convertToUnorm8(kBt601PixelValue.blue); -const kBt601Yellow = convertToUnorm8(kBt601PixelValue.yellow); - -export const kVideoExpectations = [ - { - videoName: 'four-colors-vp8-bt601.webm', - _redExpectation: kBt601Red, - _greenExpectation: kBt601Green, - _blueExpectation: kBt601Blue, - _yellowExpectation: kBt601Yellow, - }, - { - videoName: 'four-colors-theora-bt601.ogv', - _redExpectation: kBt601Red, - _greenExpectation: kBt601Green, - _blueExpectation: kBt601Blue, - _yellowExpectation: kBt601Yellow, - }, - { - videoName: 'four-colors-h264-bt601.mp4', - _redExpectation: kBt601Red, - _greenExpectation: kBt601Green, - _blueExpectation: kBt601Blue, - _yellowExpectation: kBt601Yellow, +// Video expected pixel value table. Finding expected pixel value +// with video color space and dst color space. +export const kVideoExpectedColors = makeTable({ + table: { + bt601: { + 'display-p3': { + yellow: srgbToDisplayP3(kBt601PixelValue.srgb.yellow), + red: srgbToDisplayP3(kBt601PixelValue.srgb.red), + blue: srgbToDisplayP3(kBt601PixelValue.srgb.blue), + green: srgbToDisplayP3(kBt601PixelValue.srgb.green), + }, + srgb: { + yellow: kBt601PixelValue.srgb.yellow, + red: kBt601PixelValue.srgb.red, + blue: kBt601PixelValue.srgb.blue, + green: kBt601PixelValue.srgb.green, + }, + }, + bt709: { + 'display-p3': { + yellow: srgbToDisplayP3(kBt709PixelValue.srgb.yellow), + red: srgbToDisplayP3(kBt709PixelValue.srgb.red), + blue: srgbToDisplayP3(kBt709PixelValue.srgb.blue), + green: srgbToDisplayP3(kBt709PixelValue.srgb.green), + }, + srgb: { + yellow: kBt709PixelValue.srgb.yellow, + red: kBt709PixelValue.srgb.red, + blue: kBt709PixelValue.srgb.blue, + green: kBt709PixelValue.srgb.green, + }, + }, }, - { - videoName: 'four-colors-vp9-bt601.webm', - _redExpectation: kBt601Red, - _greenExpectation: kBt601Green, - _blueExpectation: kBt601Blue, - _yellowExpectation: kBt601Yellow, - }, - { - videoName: 'four-colors-vp9-bt709.webm', - _redExpectation: new Uint8Array([255, 0, 0, 255]), - _greenExpectation: new Uint8Array([0, 255, 0, 255]), - _blueExpectation: new Uint8Array([0, 0, 255, 255]), - _yellowExpectation: new Uint8Array([255, 255, 0, 255]), - }, -] as const; +} as const); -export const kVideoRotationExpectations = [ - { - videoName: 'four-colors-h264-bt601-rotate-90.mp4', - _topLeftExpectation: kBt601Red, - _topRightExpectation: kBt601Green, - _bottomLeftExpectation: kBt601Yellow, - _bottomRightExpectation: kBt601Blue, - }, - { - videoName: 'four-colors-h264-bt601-rotate-180.mp4', - _topLeftExpectation: kBt601Green, - _topRightExpectation: kBt601Blue, - _bottomLeftExpectation: kBt601Red, - _bottomRightExpectation: kBt601Yellow, - }, - { - videoName: 'four-colors-h264-bt601-rotate-270.mp4', - _topLeftExpectation: kBt601Blue, - _topRightExpectation: kBt601Yellow, - _bottomLeftExpectation: kBt601Green, - _bottomRightExpectation: kBt601Red, +// MAINTENANCE_TODO: Add BT.2020 video in table. +// Video container and codec defines several transform ops to apply to raw decoded frame to display. +// Our test cases covers 'visible rect' and 'rotation'. +// 'visible rect' is associated with the +// video bitstream and should apply to the raw decoded frames before any transformation. +// 'rotation' is associated with the track or presentation and should transform +// the whole visible rect (e.g. 90-degree rotate makes visible rect of vertical video to horizontal) +// The order to apply these transformations is below: + +// [raw decoded frame] ----visible rect clipping ---->[visible frame] ---rotation ---> present +// ^ ^ +// | | +// coded size display size +// The table holds test videos meta infos, including mimeType to check browser compatibility +// video color space, raw frame content layout and the frame displayed layout. +export const kVideoInfo = makeTable({ + table: { + 'four-colors-vp8-bt601.webm': { + mimeType: 'video/webm; codecs=vp8', + colorSpace: 'bt601', + coded: { + topLeftColor: 'yellow', + topRightColor: 'red', + bottomLeftColor: 'blue', + bottomRightColor: 'green', + }, + display: { + topLeftColor: 'yellow', + topRightColor: 'red', + bottomLeftColor: 'blue', + bottomRightColor: 'green', + }, + }, + 'four-colors-h264-bt601.mp4': { + mimeType: 'video/mp4; codecs=avc1.4d400c', + colorSpace: 'bt601', + coded: { + topLeftColor: 'yellow', + topRightColor: 'red', + bottomLeftColor: 'blue', + bottomRightColor: 'green', + }, + display: { + topLeftColor: 'yellow', + topRightColor: 'red', + bottomLeftColor: 'blue', + bottomRightColor: 'green', + }, + }, + 'four-colors-vp9-bt601.webm': { + mimeType: 'video/webm; codecs=vp9', + colorSpace: 'bt601', + coded: { + topLeftColor: 'yellow', + topRightColor: 'red', + bottomLeftColor: 'blue', + bottomRightColor: 'green', + }, + display: { + topLeftColor: 'yellow', + topRightColor: 'red', + bottomLeftColor: 'blue', + bottomRightColor: 'green', + }, + }, + 'four-colors-vp9-bt709.webm': { + mimeType: 'video/webm; codecs=vp9', + colorSpace: 'bt709', + coded: { + topLeftColor: 'yellow', + topRightColor: 'red', + bottomLeftColor: 'blue', + bottomRightColor: 'green', + }, + display: { + topLeftColor: 'yellow', + topRightColor: 'red', + bottomLeftColor: 'blue', + bottomRightColor: 'green', + }, + }, + // video coded content has been rotate + 'four-colors-h264-bt601-rotate-90.mp4': { + mimeType: 'video/mp4; codecs=avc1.4d400c', + colorSpace: 'bt601', + coded: { + topLeftColor: 'red', + topRightColor: 'green', + bottomLeftColor: 'yellow', + bottomRightColor: 'blue', + }, + display: { + topLeftColor: 'yellow', + topRightColor: 'red', + bottomLeftColor: 'blue', + bottomRightColor: 'green', + }, + }, + 'four-colors-h264-bt601-rotate-180.mp4': { + mimeType: 'video/mp4; codecs=avc1.4d400c', + colorSpace: 'bt601', + coded: { + topLeftColor: 'green', + topRightColor: 'blue', + bottomLeftColor: 'red', + bottomRightColor: 'yellow', + }, + display: { + topLeftColor: 'yellow', + topRightColor: 'red', + bottomLeftColor: 'blue', + bottomRightColor: 'green', + }, + }, + 'four-colors-h264-bt601-rotate-270.mp4': { + mimeType: 'video/mp4; codecs=avc1.4d400c', + colorSpace: 'bt601', + coded: { + topLeftColor: 'blue', + topRightColor: 'yellow', + bottomLeftColor: 'green', + bottomRightColor: 'red', + }, + display: { + topLeftColor: 'yellow', + topRightColor: 'red', + bottomLeftColor: 'blue', + bottomRightColor: 'green', + }, + }, + 'four-colors-vp9-bt601-rotate-90.mp4': { + mimeType: 'video/mp4; codecs=vp09.00.10.08', + colorSpace: 'bt601', + coded: { + topLeftColor: 'red', + topRightColor: 'green', + bottomLeftColor: 'yellow', + bottomRightColor: 'blue', + }, + display: { + topLeftColor: 'yellow', + topRightColor: 'red', + bottomLeftColor: 'blue', + bottomRightColor: 'green', + }, + }, + 'four-colors-vp9-bt601-rotate-180.mp4': { + mimeType: 'video/mp4; codecs=vp09.00.10.08', + colorSpace: 'bt601', + coded: { + topLeftColor: 'green', + topRightColor: 'blue', + bottomLeftColor: 'red', + bottomRightColor: 'yellow', + }, + display: { + topLeftColor: 'yellow', + topRightColor: 'red', + bottomLeftColor: 'blue', + bottomRightColor: 'green', + }, + }, + 'four-colors-vp9-bt601-rotate-270.mp4': { + mimeType: 'video/mp4; codecs=vp09.00.10.08', + colorSpace: 'bt601', + coded: { + topLeftColor: 'blue', + topRightColor: 'yellow', + bottomLeftColor: 'green', + bottomRightColor: 'red', + }, + display: { + topLeftColor: 'yellow', + topRightColor: 'red', + bottomLeftColor: 'blue', + bottomRightColor: 'green', + }, + }, + 'four-colors-h264-bt601-hflip.mp4': { + mimeType: 'video/mp4; codecs=avc1.4d400c', + colorSpace: 'bt601', + coded: { + topLeftColor: 'yellow', + topRightColor: 'red', + bottomLeftColor: 'blue', + bottomRightColor: 'green', + }, + display: { + topLeftColor: 'red', + topRightColor: 'yellow', + bottomLeftColor: 'green', + bottomRightColor: 'blue', + }, + }, + 'four-colors-h264-bt601-vflip.mp4': { + mimeType: 'video/mp4; codecs=avc1.4d400c', + colorSpace: 'bt601', + coded: { + topLeftColor: 'yellow', + topRightColor: 'red', + bottomLeftColor: 'blue', + bottomRightColor: 'green', + }, + display: { + topLeftColor: 'blue', + topRightColor: 'green', + bottomLeftColor: 'yellow', + bottomRightColor: 'red', + }, + }, + 'four-colors-vp9-bt601-hflip.mp4': { + mimeType: 'video/mp4; codecs=vp09.00.10.08', + colorSpace: 'bt601', + coded: { + topLeftColor: 'yellow', + topRightColor: 'red', + bottomLeftColor: 'blue', + bottomRightColor: 'green', + }, + display: { + topLeftColor: 'red', + topRightColor: 'yellow', + bottomLeftColor: 'green', + bottomRightColor: 'blue', + }, + }, + 'four-colors-vp9-bt601-vflip.mp4': { + mimeType: 'video/mp4; codecs=vp09.00.10.08', + colorSpace: 'bt601', + coded: { + topLeftColor: 'yellow', + topRightColor: 'red', + bottomLeftColor: 'blue', + bottomRightColor: 'green', + }, + display: { + topLeftColor: 'blue', + topRightColor: 'green', + bottomLeftColor: 'yellow', + bottomRightColor: 'red', + }, + }, }, -] as const; +} as const); +type VideoName = keyof typeof kVideoInfo; +export const kVideoNames: readonly VideoName[] = keysOf(kVideoInfo); + +export const kPredefinedColorSpace = ['display-p3', 'srgb'] as const; /** * Starts playing a video and waits for it to be consumable. * Returns a promise which resolves after `callback` (which may be async) completes. @@ -153,7 +383,12 @@ export function startPlayingAndWaitForVideo( video.addEventListener( 'error', - event => reject(new ErrorWithExtra('Video received "error" event', () => ({ event }))), + event => + reject( + new ErrorWithExtra('Video received "error" event, message: ' + event.message, () => ({ + event, + })) + ), true ); @@ -238,6 +473,7 @@ export async function getVideoFrameFromVideoElement( const transformer: TransformStream = new TransformStream({ transform(videoFrame, _controller) { videoTrack.stop(); + test.trackForCleanup(videoFrame); resolve(videoFrame); }, flush(controller) { @@ -267,6 +503,10 @@ export async function getVideoFrameFromVideoElement( * */ export function getVideoElement(t: GPUTest, videoName: VideoName): HTMLVideoElement { + if (typeof HTMLVideoElement === 'undefined') { + t.skip('HTMLVideoElement not available'); + } + const videoElement = document.createElement('video'); const videoInfo = kVideoInfo[videoName]; @@ -277,6 +517,8 @@ export function getVideoElement(t: GPUTest, videoName: VideoName): HTMLVideoElem const videoUrl = getResourcePath(videoName); videoElement.src = videoUrl; + t.trackForCleanup(videoElement); + return videoElement; } |