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