76d13bbdf8
Bug: skia:11369 Change-Id: I0d1a74cc64dd74486acbb69df529ccc0f8b63ef3 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/375202 Reviewed-by: Greg Daniel <egdaniel@google.com> Reviewed-by: Robert Phillips <robertphillips@google.com> Commit-Queue: Brian Salomon <bsalomon@google.com>
289 lines
8.8 KiB
HTML
289 lines
8.8 KiB
HTML
<!-- This runs the GMs and unit tests which have been compiled to WASM. When this completes,
|
|
either window._error will be set or window._testsDone will be true and window._results will be an
|
|
array of the test names and what they drew.
|
|
-->
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>WASM Runner of GMs and Unit Tests</title>
|
|
<meta charset="utf-8" />
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<script src="/static/wasm_gm_tests.js" type="text/javascript" charset="utf-8"></script>
|
|
<style type="text/css" media="screen">
|
|
#status_text {
|
|
min-width: 900px;
|
|
min-height: 500px;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<main>
|
|
<button id=start_tests>Start Tests</button>
|
|
<br>
|
|
<pre id=status_text></pre>
|
|
|
|
<canvas id=gm_canvas></canvas>
|
|
</main>
|
|
<script type="text/javascript" charset="utf-8">
|
|
const loadTestsPromise = InitWasmGMTests({
|
|
locateFile: (file) => '/static/'+file,
|
|
});
|
|
|
|
const loadKnownHashesPromise = fetch('/static/hashes.txt').then((resp) => resp.text());
|
|
|
|
const resourceNames = [];
|
|
const loadResourceListing = fetch('/static/resource_listing.json').then((resp) => resp.json())
|
|
.then((json) => {
|
|
console.debug('should fetch resources', json);
|
|
const loadingPromises = [];
|
|
for (const resource of json) {
|
|
resourceNames.push(resource);
|
|
const url = `/static/resources/${resource}`;
|
|
loadingPromises.push(fetch(url).then((resp) => resp.arrayBuffer()));
|
|
}
|
|
return Promise.all(loadingPromises).catch((e) => {
|
|
console.error(e);
|
|
window._error = `Failed getting resources: ${JSON.stringify(e)}`;
|
|
});
|
|
});
|
|
|
|
let attemptedPOSTs = 0;
|
|
let successfulPOSTs = 0;
|
|
Promise.all([loadTestsPromise, loadKnownHashesPromise, loadResourceListing]).then(([GM, hashes, resourceBuffers]) => {
|
|
GM.Init();
|
|
LoadResources(GM, resourceNames, resourceBuffers);
|
|
LoadKnownHashes(GM, hashes);
|
|
document.getElementById('start_tests').addEventListener('click', async () => {
|
|
window._testsProgress = 0;
|
|
window._log = 'Starting\n';
|
|
window._failed = [];
|
|
await RunTests(GM);
|
|
if (window._error) {
|
|
console.log(window._error);
|
|
return;
|
|
}
|
|
await RunGMs(GM);
|
|
if (attemptedPOSTs !== successfulPOSTs) {
|
|
window._error = `Failed to POST all the PNG files (expected ${attemptedPOSTs}, finished ${successfulPOSTs})`;
|
|
} else {
|
|
window._testsDone = true;
|
|
}
|
|
});
|
|
window._testsReady = true;
|
|
});
|
|
|
|
const statusElement = document.getElementById('status_text');
|
|
function log(line) {
|
|
console.log(line);
|
|
line += '\n';
|
|
statusElement.innerText += line;
|
|
window._log += line;
|
|
}
|
|
|
|
function LoadResources(GM, resourceNames, resourceBuffers) {
|
|
for (let i = 0; i < resourceNames.length; i++) {
|
|
const name = resourceNames[i];
|
|
const buffer = resourceBuffers[i];
|
|
if (name.includes('mandril')) {
|
|
console.log(name, new Uint8Array(buffer).slice(0, 20));
|
|
}
|
|
GM.LoadResource(name, buffer);
|
|
}
|
|
}
|
|
|
|
// There's a global set of known hashes that we preload with the md5 hashes that are already
|
|
// uploaded to Gold. This saves us some time to encode them and write them to disk.
|
|
function LoadKnownHashes(GM, hashes) {
|
|
log(`Loading ${hashes.length} hashes`);
|
|
console.time('load_hashes');
|
|
for (const hash of hashes.split('\n')) {
|
|
if (hash.length < 5) { // be sure not to add empty lines
|
|
continue;
|
|
}
|
|
GM.LoadKnownDigest(hash);
|
|
}
|
|
console.timeEnd('load_hashes');
|
|
log('hashes loaded');
|
|
}
|
|
|
|
const gmSkipList = new Set([
|
|
// gm names can be added here to skip, if failing.
|
|
]);
|
|
|
|
async function RunGMs(GM) {
|
|
const canvas = document.getElementById('gm_canvas');
|
|
const ctx = GM.GetWebGLContext(canvas, 2);
|
|
const grcontext = GM.MakeGrContext(ctx);
|
|
window._results = [];
|
|
|
|
const names = GM.ListGMs();
|
|
names.sort();
|
|
for (const name of names) {
|
|
if (gmSkipList.has(name)) {
|
|
continue;
|
|
}
|
|
log(`Starting GM ${name}`);
|
|
const pngAndMetadata = GM.RunGM(grcontext, name);
|
|
if (!pngAndMetadata || !pngAndMetadata.hash) {
|
|
console.debug('No output for ', name);
|
|
continue; // Was skipped
|
|
}
|
|
log(` drew ${pngAndMetadata.hash}`);
|
|
window._results.push({
|
|
name: name,
|
|
digest: pngAndMetadata.hash,
|
|
});
|
|
if (pngAndMetadata.png) {
|
|
await postPNG(pngAndMetadata.hash, pngAndMetadata.png);
|
|
}
|
|
window._testsProgress++;
|
|
}
|
|
grcontext.delete();
|
|
}
|
|
|
|
async function postPNG(hash, data) {
|
|
attemptedPOSTs += 1;
|
|
await fetch('/write_png', {
|
|
method: 'POST',
|
|
body: data,
|
|
headers: {
|
|
'Content-type': 'image/png',
|
|
'X-MD5-Hash': hash, // this will be used server side to create the name of the png.
|
|
}
|
|
}).then((resp) => {
|
|
if (resp.ok) {
|
|
successfulPOSTs += 1;
|
|
} else {
|
|
console.error('not ok response', resp);
|
|
}
|
|
}).catch((e) => {
|
|
console.error('Could not post PNG', e);
|
|
});
|
|
}
|
|
|
|
const testSkipList = new Set([
|
|
// These tests all crash https://bugs.chromium.org/p/skia/issues/detail?id=10869
|
|
|
|
|
|
// note, to catch these crashes, you must compile a debug build,
|
|
// run with --manual_mode and open the developer console,
|
|
// and enable pause on exceptions in the sources tab, or the browser will just close
|
|
// the instant this test crashes.
|
|
|
|
// These tests fail when doing a dlopen call
|
|
// "To use dlopen, you need to use Emscripten's linking support"
|
|
// Some of these appear to hit the default case instead of the GLES case in GrContextFactory.cpp
|
|
// which isn't expected to work. If they had a GLES context, they'd probably pass.
|
|
'AsyncReadPixelsContextShutdown',
|
|
'GrContextFactory_abandon',
|
|
'GrContext_abandonContext',
|
|
'GrContext_oomed',
|
|
'GrDDLImage_MakeSubset',
|
|
'InitialTextureClear',
|
|
'PinnedImageTest',
|
|
'PromiseImageTextureShutdown',
|
|
|
|
// These tests time out
|
|
'SkTraceMemoryDump_ownedGLRenderTarget',
|
|
|
|
// wasm doesn't have threading
|
|
'GrContextFactory_executorAndTaskGroup',
|
|
'GrContextFactory_sharedContexts',
|
|
'RefCnt',
|
|
'SkRuntimeEffectThreaded',
|
|
'SkScalerCacheMultiThread',
|
|
'String_Threaded',
|
|
|
|
// These tests are crashing for unknown reasons
|
|
'AdvancedBlendTest',
|
|
'FILEStreamWithOffset',
|
|
'Data',
|
|
'ES2BlendWithNoTexture',
|
|
|
|
// keys invalid
|
|
'GrPathKeys',
|
|
|
|
// flaky crash.
|
|
// crash seems more likely the faster you hit the "Start Tests" button.
|
|
'CCPR_cache_animationAtlasReuse',
|
|
'CCPR_cache_deferredCleanup',
|
|
'CCPR_cache_hashTable',
|
|
'CCPR_cache_mostlyVisible',
|
|
'CCPR_cache_multiFlush',
|
|
'CCPR_cache_multiTileCache',
|
|
'CCPR_cache_partialInvalidate',
|
|
'CCPR_cache_recycleEntries',
|
|
'CCPR_cleanup',
|
|
'CCPR_cleanupWithTexAllocFail',
|
|
'CCPR_busyPath',
|
|
'CCPR_evictCacheEntryForPendingDrawOp',
|
|
|
|
// Creates only 35 of 36 expected fragment processor factories
|
|
'ProcessorCloneTest',
|
|
'ProcessorOptimizationValidationTest',
|
|
'ProcessorRefTest',
|
|
'Programs',
|
|
|
|
// Apparently fail only on release builds / bots
|
|
'FlushFinishedProcTest',
|
|
'WritePixelsNonTextureMSAA_Gpu',
|
|
]);
|
|
|
|
async function RunTests(GM) {
|
|
const canvas = document.getElementById('gm_canvas');
|
|
const ctx = GM.GetWebGLContext(canvas, 2);
|
|
// This sets up the GL context for all tests.
|
|
const grcontext = GM.MakeGrContext(ctx);
|
|
if (!grcontext) {
|
|
window._error = 'Could not make GrContext for tests';
|
|
return;
|
|
}
|
|
// We run these tests in batchs so as not to lock up the main thread, which makes it easier
|
|
// to read the progress as well as making the page more responsive when debugging.
|
|
await new Promise((resolve, reject) => {
|
|
const names = GM.ListTests();
|
|
names.sort();
|
|
console.log(names);
|
|
let testIdx = -1;
|
|
const nextBatch = () => {
|
|
for (let i = 0; i < 10 && testIdx < names.length; i++) {
|
|
testIdx++;
|
|
const name = names[testIdx];
|
|
if (!name) {
|
|
testIdx = names.length;
|
|
break;
|
|
}
|
|
if (testSkipList.has(name)) {
|
|
continue;
|
|
}
|
|
log(`Running test ${name}`);
|
|
try {
|
|
const result = GM.RunTest(name);
|
|
log(' ' + result.result, result.msg || '');
|
|
if (result.result !== 'passed' && result.result !== 'skipped') {
|
|
window._failed.push(name);
|
|
}
|
|
} catch (e) {
|
|
log(`${name} crashed with ${e.toString()} ${e.stack}`);
|
|
window._error = e.toString();
|
|
reject();
|
|
return;
|
|
}
|
|
window._testsProgress++;
|
|
}
|
|
if (testIdx >= names.length) {
|
|
resolve();
|
|
return;
|
|
}
|
|
setTimeout(nextBatch);
|
|
};
|
|
setTimeout(nextBatch);
|
|
});
|
|
|
|
grcontext.delete();
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|