1cb93a386Sopenharmony_ci<!-- This runs the GMs and unit tests which have been compiled to WASM. When this completes, 2cb93a386Sopenharmony_cieither window._error will be set or window._testsDone will be true and window._results will be an 3cb93a386Sopenharmony_ciarray of the test names and what they drew. 4cb93a386Sopenharmony_ci--> 5cb93a386Sopenharmony_ci<!DOCTYPE html> 6cb93a386Sopenharmony_ci<html> 7cb93a386Sopenharmony_ci<head> 8cb93a386Sopenharmony_ci <title>WASM Runner of GMs and Unit Tests</title> 9cb93a386Sopenharmony_ci <meta charset="utf-8" /> 10cb93a386Sopenharmony_ci <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> 11cb93a386Sopenharmony_ci <meta name="viewport" content="width=device-width, initial-scale=1.0"> 12cb93a386Sopenharmony_ci <script src="/static/wasm_gm_tests.js" type="text/javascript" charset="utf-8"></script> 13cb93a386Sopenharmony_ci <style type="text/css" media="screen"> 14cb93a386Sopenharmony_ci #status_text { 15cb93a386Sopenharmony_ci min-width: 900px; 16cb93a386Sopenharmony_ci min-height: 500px; 17cb93a386Sopenharmony_ci } 18cb93a386Sopenharmony_ci </style> 19cb93a386Sopenharmony_ci</head> 20cb93a386Sopenharmony_ci<body> 21cb93a386Sopenharmony_ci<main> 22cb93a386Sopenharmony_ci <button id=start_tests>Start Tests</button> 23cb93a386Sopenharmony_ci <br> 24cb93a386Sopenharmony_ci <pre id=status_text></pre> 25cb93a386Sopenharmony_ci 26cb93a386Sopenharmony_ci <canvas id=gm_canvas></canvas> 27cb93a386Sopenharmony_ci</main> 28cb93a386Sopenharmony_ci<script type="text/javascript" charset="utf-8"> 29cb93a386Sopenharmony_ci const loadTestsPromise = InitWasmGMTests({ 30cb93a386Sopenharmony_ci locateFile: (file) => '/static/'+file, 31cb93a386Sopenharmony_ci }); 32cb93a386Sopenharmony_ci 33cb93a386Sopenharmony_ci const loadKnownHashesPromise = fetch('/static/hashes.txt').then((resp) => resp.text()); 34cb93a386Sopenharmony_ci 35cb93a386Sopenharmony_ci const resourceNames = []; 36cb93a386Sopenharmony_ci const loadResourceListing = fetch('/static/resource_listing.json').then((resp) => resp.json()) 37cb93a386Sopenharmony_ci .then((json) => { 38cb93a386Sopenharmony_ci console.debug('should fetch resources', json); 39cb93a386Sopenharmony_ci const loadingPromises = []; 40cb93a386Sopenharmony_ci for (const resource of json) { 41cb93a386Sopenharmony_ci resourceNames.push(resource); 42cb93a386Sopenharmony_ci const url = `/static/resources/${resource}`; 43cb93a386Sopenharmony_ci loadingPromises.push(fetch(url).then((resp) => resp.arrayBuffer())); 44cb93a386Sopenharmony_ci } 45cb93a386Sopenharmony_ci return Promise.all(loadingPromises).catch((e) => { 46cb93a386Sopenharmony_ci console.error(e); 47cb93a386Sopenharmony_ci window._error = `Failed getting resources: ${JSON.stringify(e)}`; 48cb93a386Sopenharmony_ci }); 49cb93a386Sopenharmony_ci }); 50cb93a386Sopenharmony_ci 51cb93a386Sopenharmony_ci let attemptedPOSTs = 0; 52cb93a386Sopenharmony_ci let successfulPOSTs = 0; 53cb93a386Sopenharmony_ci Promise.all([loadTestsPromise, loadKnownHashesPromise, loadResourceListing]).then(([GM, hashes, resourceBuffers]) => { 54cb93a386Sopenharmony_ci GM.Init(); 55cb93a386Sopenharmony_ci LoadResources(GM, resourceNames, resourceBuffers); 56cb93a386Sopenharmony_ci LoadKnownHashes(GM, hashes); 57cb93a386Sopenharmony_ci document.getElementById('start_tests').addEventListener('click', async () => { 58cb93a386Sopenharmony_ci window._testsProgress = 0; 59cb93a386Sopenharmony_ci window._log = 'Starting\n'; 60cb93a386Sopenharmony_ci window._failed = []; 61cb93a386Sopenharmony_ci await RunTests(GM); 62cb93a386Sopenharmony_ci if (window._error) { 63cb93a386Sopenharmony_ci console.log(window._error); 64cb93a386Sopenharmony_ci return; 65cb93a386Sopenharmony_ci } 66cb93a386Sopenharmony_ci await RunGMs(GM); 67cb93a386Sopenharmony_ci if (attemptedPOSTs !== successfulPOSTs) { 68cb93a386Sopenharmony_ci window._error = `Failed to POST all the PNG files (expected ${attemptedPOSTs}, finished ${successfulPOSTs})`; 69cb93a386Sopenharmony_ci } else { 70cb93a386Sopenharmony_ci window._testsDone = true; 71cb93a386Sopenharmony_ci } 72cb93a386Sopenharmony_ci }); 73cb93a386Sopenharmony_ci window._testsReady = true; 74cb93a386Sopenharmony_ci }); 75cb93a386Sopenharmony_ci 76cb93a386Sopenharmony_ci const statusElement = document.getElementById('status_text'); 77cb93a386Sopenharmony_ci function log(line) { 78cb93a386Sopenharmony_ci console.log(line); 79cb93a386Sopenharmony_ci line += '\n'; 80cb93a386Sopenharmony_ci statusElement.innerText += line; 81cb93a386Sopenharmony_ci window._log += line; 82cb93a386Sopenharmony_ci } 83cb93a386Sopenharmony_ci 84cb93a386Sopenharmony_ci function LoadResources(GM, resourceNames, resourceBuffers) { 85cb93a386Sopenharmony_ci for (let i = 0; i < resourceNames.length; i++) { 86cb93a386Sopenharmony_ci const name = resourceNames[i]; 87cb93a386Sopenharmony_ci const buffer = resourceBuffers[i]; 88cb93a386Sopenharmony_ci if (name.includes('mandril')) { 89cb93a386Sopenharmony_ci console.log(name, new Uint8Array(buffer).slice(0, 20)); 90cb93a386Sopenharmony_ci } 91cb93a386Sopenharmony_ci GM.LoadResource(name, buffer); 92cb93a386Sopenharmony_ci } 93cb93a386Sopenharmony_ci } 94cb93a386Sopenharmony_ci 95cb93a386Sopenharmony_ci // There's a global set of known hashes that we preload with the md5 hashes that are already 96cb93a386Sopenharmony_ci // uploaded to Gold. This saves us some time to encode them and write them to disk. 97cb93a386Sopenharmony_ci function LoadKnownHashes(GM, hashes) { 98cb93a386Sopenharmony_ci log(`Loading ${hashes.length} hashes`); 99cb93a386Sopenharmony_ci console.time('load_hashes'); 100cb93a386Sopenharmony_ci for (const hash of hashes.split('\n')) { 101cb93a386Sopenharmony_ci if (hash.length < 5) { // be sure not to add empty lines 102cb93a386Sopenharmony_ci continue; 103cb93a386Sopenharmony_ci } 104cb93a386Sopenharmony_ci GM.LoadKnownDigest(hash); 105cb93a386Sopenharmony_ci } 106cb93a386Sopenharmony_ci console.timeEnd('load_hashes'); 107cb93a386Sopenharmony_ci log('hashes loaded'); 108cb93a386Sopenharmony_ci } 109cb93a386Sopenharmony_ci 110cb93a386Sopenharmony_ci const gmSkipList = new Set([ 111cb93a386Sopenharmony_ci // gm names can be added here to skip, if failing. 112cb93a386Sopenharmony_ci ]); 113cb93a386Sopenharmony_ci 114cb93a386Sopenharmony_ci async function RunGMs(GM) { 115cb93a386Sopenharmony_ci const canvas = document.getElementById('gm_canvas'); 116cb93a386Sopenharmony_ci const ctx = GM.GetWebGLContext(canvas, 2); 117cb93a386Sopenharmony_ci const grcontext = GM.MakeGrContext(ctx); 118cb93a386Sopenharmony_ci window._results = []; 119cb93a386Sopenharmony_ci 120cb93a386Sopenharmony_ci const names = GM.ListGMs(); 121cb93a386Sopenharmony_ci names.sort(); 122cb93a386Sopenharmony_ci for (const name of names) { 123cb93a386Sopenharmony_ci if (gmSkipList.has(name)) { 124cb93a386Sopenharmony_ci continue; 125cb93a386Sopenharmony_ci } 126cb93a386Sopenharmony_ci log(`Starting GM ${name}`); 127cb93a386Sopenharmony_ci const pngAndMetadata = GM.RunGM(grcontext, name); 128cb93a386Sopenharmony_ci if (!pngAndMetadata || !pngAndMetadata.hash) { 129cb93a386Sopenharmony_ci console.debug('No output for ', name); 130cb93a386Sopenharmony_ci continue; // Was skipped 131cb93a386Sopenharmony_ci } 132cb93a386Sopenharmony_ci log(` drew ${pngAndMetadata.hash}`); 133cb93a386Sopenharmony_ci window._results.push({ 134cb93a386Sopenharmony_ci name: name, 135cb93a386Sopenharmony_ci digest: pngAndMetadata.hash, 136cb93a386Sopenharmony_ci }); 137cb93a386Sopenharmony_ci if (pngAndMetadata.png) { 138cb93a386Sopenharmony_ci await postPNG(pngAndMetadata.hash, pngAndMetadata.png); 139cb93a386Sopenharmony_ci } 140cb93a386Sopenharmony_ci window._testsProgress++; 141cb93a386Sopenharmony_ci } 142cb93a386Sopenharmony_ci grcontext.delete(); 143cb93a386Sopenharmony_ci } 144cb93a386Sopenharmony_ci 145cb93a386Sopenharmony_ci async function postPNG(hash, data) { 146cb93a386Sopenharmony_ci attemptedPOSTs += 1; 147cb93a386Sopenharmony_ci await fetch('/write_png', { 148cb93a386Sopenharmony_ci method: 'POST', 149cb93a386Sopenharmony_ci body: data, 150cb93a386Sopenharmony_ci headers: { 151cb93a386Sopenharmony_ci 'Content-type': 'image/png', 152cb93a386Sopenharmony_ci 'X-MD5-Hash': hash, // this will be used server side to create the name of the png. 153cb93a386Sopenharmony_ci } 154cb93a386Sopenharmony_ci }).then((resp) => { 155cb93a386Sopenharmony_ci if (resp.ok) { 156cb93a386Sopenharmony_ci successfulPOSTs += 1; 157cb93a386Sopenharmony_ci } else { 158cb93a386Sopenharmony_ci console.error('not ok response', resp); 159cb93a386Sopenharmony_ci } 160cb93a386Sopenharmony_ci }).catch((e) => { 161cb93a386Sopenharmony_ci console.error('Could not post PNG', e); 162cb93a386Sopenharmony_ci }); 163cb93a386Sopenharmony_ci } 164cb93a386Sopenharmony_ci 165cb93a386Sopenharmony_ci const testSkipList = new Set([ 166cb93a386Sopenharmony_ci // These tests all crash https://bugs.chromium.org/p/skia/issues/detail?id=10869 167cb93a386Sopenharmony_ci 168cb93a386Sopenharmony_ci 169cb93a386Sopenharmony_ci // note, to catch these crashes, you must compile a debug build, 170cb93a386Sopenharmony_ci // run with --manual_mode and open the developer console, 171cb93a386Sopenharmony_ci // and enable pause on exceptions in the sources tab, or the browser will just close 172cb93a386Sopenharmony_ci // the instant this test crashes. 173cb93a386Sopenharmony_ci 174cb93a386Sopenharmony_ci // These tests fail when doing a dlopen call 175cb93a386Sopenharmony_ci // "To use dlopen, you need to use Emscripten's linking support" 176cb93a386Sopenharmony_ci // Some of these appear to hit the default case instead of the GLES case in GrContextFactory.cpp 177cb93a386Sopenharmony_ci // which isn't expected to work. If they had a GLES context, they'd probably pass. 178cb93a386Sopenharmony_ci 'AsyncReadPixelsContextShutdown', 179cb93a386Sopenharmony_ci 'GrContextFactory_abandon', 180cb93a386Sopenharmony_ci 'GrContext_abandonContext', 181cb93a386Sopenharmony_ci 'GrContext_oomed', 182cb93a386Sopenharmony_ci 'GrDDLImage_MakeSubset', 183cb93a386Sopenharmony_ci 'InitialTextureClear', 184cb93a386Sopenharmony_ci 'PinnedImageTest', 185cb93a386Sopenharmony_ci 'PromiseImageTextureShutdown', 186cb93a386Sopenharmony_ci 187cb93a386Sopenharmony_ci // These tests time out 188cb93a386Sopenharmony_ci 'SkTraceMemoryDump_ownedGLRenderTarget', 189cb93a386Sopenharmony_ci 190cb93a386Sopenharmony_ci // wasm doesn't have threading 191cb93a386Sopenharmony_ci 'GrContextFactory_executorAndTaskGroup', 192cb93a386Sopenharmony_ci 'GrContextFactory_sharedContexts', 193cb93a386Sopenharmony_ci 'RefCnt', 194cb93a386Sopenharmony_ci 'SkRuntimeEffectThreaded', 195cb93a386Sopenharmony_ci 'SkScalerCacheMultiThread', 196cb93a386Sopenharmony_ci 'String_Threaded', 197cb93a386Sopenharmony_ci 198cb93a386Sopenharmony_ci // These tests are crashing for unknown reasons 199cb93a386Sopenharmony_ci 'AdvancedBlendTest', 200cb93a386Sopenharmony_ci 'FILEStreamWithOffset', 201cb93a386Sopenharmony_ci 'Data', 202cb93a386Sopenharmony_ci 'ES2BlendWithNoTexture', 203cb93a386Sopenharmony_ci 204cb93a386Sopenharmony_ci // keys invalid 205cb93a386Sopenharmony_ci 'GrPathKeys', 206cb93a386Sopenharmony_ci 207cb93a386Sopenharmony_ci // Creates only 35 of 36 expected fragment processor factories 208cb93a386Sopenharmony_ci 'ProcessorCloneTest', 209cb93a386Sopenharmony_ci 'ProcessorOptimizationValidationTest', 210cb93a386Sopenharmony_ci 'ProcessorRefTest', 211cb93a386Sopenharmony_ci 'Programs', 212cb93a386Sopenharmony_ci 213cb93a386Sopenharmony_ci // Apparently fail only on release builds / bots 214cb93a386Sopenharmony_ci 'FlushFinishedProcTest', 215cb93a386Sopenharmony_ci 'WritePixelsNonTextureMSAA_Gpu', 216cb93a386Sopenharmony_ci ]); 217cb93a386Sopenharmony_ci 218cb93a386Sopenharmony_ci async function RunTests(GM) { 219cb93a386Sopenharmony_ci const canvas = document.getElementById('gm_canvas'); 220cb93a386Sopenharmony_ci const ctx = GM.GetWebGLContext(canvas, 2); 221cb93a386Sopenharmony_ci // This sets up the GL context for all tests. 222cb93a386Sopenharmony_ci const grcontext = GM.MakeGrContext(ctx); 223cb93a386Sopenharmony_ci if (!grcontext) { 224cb93a386Sopenharmony_ci window._error = 'Could not make GrContext for tests'; 225cb93a386Sopenharmony_ci return; 226cb93a386Sopenharmony_ci } 227cb93a386Sopenharmony_ci // We run these tests in batchs so as not to lock up the main thread, which makes it easier 228cb93a386Sopenharmony_ci // to read the progress as well as making the page more responsive when debugging. 229cb93a386Sopenharmony_ci await new Promise((resolve, reject) => { 230cb93a386Sopenharmony_ci const names = GM.ListTests(); 231cb93a386Sopenharmony_ci names.sort(); 232cb93a386Sopenharmony_ci console.log(names); 233cb93a386Sopenharmony_ci let testIdx = -1; 234cb93a386Sopenharmony_ci const nextBatch = () => { 235cb93a386Sopenharmony_ci for (let i = 0; i < 10 && testIdx < names.length; i++) { 236cb93a386Sopenharmony_ci testIdx++; 237cb93a386Sopenharmony_ci const name = names[testIdx]; 238cb93a386Sopenharmony_ci if (!name) { 239cb93a386Sopenharmony_ci testIdx = names.length; 240cb93a386Sopenharmony_ci break; 241cb93a386Sopenharmony_ci } 242cb93a386Sopenharmony_ci if (testSkipList.has(name)) { 243cb93a386Sopenharmony_ci continue; 244cb93a386Sopenharmony_ci } 245cb93a386Sopenharmony_ci log(`Running test ${name}`); 246cb93a386Sopenharmony_ci try { 247cb93a386Sopenharmony_ci const result = GM.RunTest(name); 248cb93a386Sopenharmony_ci log(' ' + result.result, result.msg || ''); 249cb93a386Sopenharmony_ci if (result.result !== 'passed' && result.result !== 'skipped') { 250cb93a386Sopenharmony_ci window._failed.push(name); 251cb93a386Sopenharmony_ci } 252cb93a386Sopenharmony_ci } catch (e) { 253cb93a386Sopenharmony_ci log(`${name} crashed with ${e.toString()} ${e.stack}`); 254cb93a386Sopenharmony_ci window._error = e.toString(); 255cb93a386Sopenharmony_ci reject(); 256cb93a386Sopenharmony_ci return; 257cb93a386Sopenharmony_ci } 258cb93a386Sopenharmony_ci window._testsProgress++; 259cb93a386Sopenharmony_ci } 260cb93a386Sopenharmony_ci if (testIdx >= names.length) { 261cb93a386Sopenharmony_ci resolve(); 262cb93a386Sopenharmony_ci return; 263cb93a386Sopenharmony_ci } 264cb93a386Sopenharmony_ci setTimeout(nextBatch); 265cb93a386Sopenharmony_ci }; 266cb93a386Sopenharmony_ci setTimeout(nextBatch); 267cb93a386Sopenharmony_ci }); 268cb93a386Sopenharmony_ci 269cb93a386Sopenharmony_ci grcontext.delete(); 270cb93a386Sopenharmony_ci } 271cb93a386Sopenharmony_ci</script> 272cb93a386Sopenharmony_ci</body> 273cb93a386Sopenharmony_ci</html> 274