xref: /aosp_15_r20/external/skia/modules/canvaskit/gm_bindings.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2020 Google LLC
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include <set>
9*c8dee2aaSAndroid Build Coastguard Worker #include <string>
10*c8dee2aaSAndroid Build Coastguard Worker #include <emscripten.h>
11*c8dee2aaSAndroid Build Coastguard Worker #include <emscripten/bind.h>
12*c8dee2aaSAndroid Build Coastguard Worker #include <emscripten/html5.h>
13*c8dee2aaSAndroid Build Coastguard Worker 
14*c8dee2aaSAndroid Build Coastguard Worker #include "gm/gm.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBitmap.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkData.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkStream.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurface.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrContextOptions.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrDirectContext.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/SkSurfaceGanesh.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/gl/GrGLDirectContext.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/gl/GrGLInterface.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/gl/GrGLTypes.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "modules/canvaskit/WasmCommon.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkMD5.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "tests/Test.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "tests/TestHarness.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "tools/HashAndEncode.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "tools/ResourceFactory.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "tools/flags/CommandLineFlags.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "tools/fonts/FontToolUtils.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "tools/gpu/ContextType.h"
36*c8dee2aaSAndroid Build Coastguard Worker 
37*c8dee2aaSAndroid Build Coastguard Worker using namespace emscripten;
38*c8dee2aaSAndroid Build Coastguard Worker 
39*c8dee2aaSAndroid Build Coastguard Worker /**
40*c8dee2aaSAndroid Build Coastguard Worker  * Returns a JS array of strings containing the names of the registered GMs. GMs are only registered
41*c8dee2aaSAndroid Build Coastguard Worker  * when their source is included in the "link" step, not if they are in something like libgm.a.
42*c8dee2aaSAndroid Build Coastguard Worker  * The names are also logged to the console.
43*c8dee2aaSAndroid Build Coastguard Worker  */
ListGMs()44*c8dee2aaSAndroid Build Coastguard Worker static JSArray ListGMs() {
45*c8dee2aaSAndroid Build Coastguard Worker     SkDebugf("Listing GMs\n");
46*c8dee2aaSAndroid Build Coastguard Worker     JSArray gms = emscripten::val::array();
47*c8dee2aaSAndroid Build Coastguard Worker     for (const skiagm::GMFactory& fact : skiagm::GMRegistry::Range()) {
48*c8dee2aaSAndroid Build Coastguard Worker         std::unique_ptr<skiagm::GM> gm(fact());
49*c8dee2aaSAndroid Build Coastguard Worker         SkDebugf("gm %s\n", gm->getName().c_str());
50*c8dee2aaSAndroid Build Coastguard Worker         gms.call<void>("push", std::string(gm->getName().c_str()));
51*c8dee2aaSAndroid Build Coastguard Worker     }
52*c8dee2aaSAndroid Build Coastguard Worker     return gms;
53*c8dee2aaSAndroid Build Coastguard Worker }
54*c8dee2aaSAndroid Build Coastguard Worker 
getGMWithName(std::string name)55*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<skiagm::GM> getGMWithName(std::string name) {
56*c8dee2aaSAndroid Build Coastguard Worker     for (const skiagm::GMFactory& fact : skiagm::GMRegistry::Range()) {
57*c8dee2aaSAndroid Build Coastguard Worker         std::unique_ptr<skiagm::GM> gm(fact());
58*c8dee2aaSAndroid Build Coastguard Worker         if (gm->getName().c_str() == name) {
59*c8dee2aaSAndroid Build Coastguard Worker             return gm;
60*c8dee2aaSAndroid Build Coastguard Worker         }
61*c8dee2aaSAndroid Build Coastguard Worker     }
62*c8dee2aaSAndroid Build Coastguard Worker     return nullptr;
63*c8dee2aaSAndroid Build Coastguard Worker }
64*c8dee2aaSAndroid Build Coastguard Worker 
65*c8dee2aaSAndroid Build Coastguard Worker /**
66*c8dee2aaSAndroid Build Coastguard Worker  * Sets the given WebGL context to be "current" and then creates a GrDirectContext from that
67*c8dee2aaSAndroid Build Coastguard Worker  * context.
68*c8dee2aaSAndroid Build Coastguard Worker  */
MakeGrContext(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context)69*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<GrDirectContext> MakeGrContext(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context)
70*c8dee2aaSAndroid Build Coastguard Worker {
71*c8dee2aaSAndroid Build Coastguard Worker     EMSCRIPTEN_RESULT r = emscripten_webgl_make_context_current(context);
72*c8dee2aaSAndroid Build Coastguard Worker     if (r < 0) {
73*c8dee2aaSAndroid Build Coastguard Worker         printf("failed to make webgl context current %d\n", r);
74*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
75*c8dee2aaSAndroid Build Coastguard Worker     }
76*c8dee2aaSAndroid Build Coastguard Worker     // setup GrDirectContext
77*c8dee2aaSAndroid Build Coastguard Worker     auto interface = GrGLMakeNativeInterface();
78*c8dee2aaSAndroid Build Coastguard Worker     // setup contexts
79*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<GrDirectContext> dContext((GrDirectContexts::MakeGL(interface)));
80*c8dee2aaSAndroid Build Coastguard Worker     return dContext;
81*c8dee2aaSAndroid Build Coastguard Worker }
82*c8dee2aaSAndroid Build Coastguard Worker 
83*c8dee2aaSAndroid Build Coastguard Worker static std::set<std::string> gKnownDigests;
84*c8dee2aaSAndroid Build Coastguard Worker 
LoadKnownDigest(std::string md5)85*c8dee2aaSAndroid Build Coastguard Worker static void LoadKnownDigest(std::string md5) {
86*c8dee2aaSAndroid Build Coastguard Worker   gKnownDigests.insert(md5);
87*c8dee2aaSAndroid Build Coastguard Worker }
88*c8dee2aaSAndroid Build Coastguard Worker 
89*c8dee2aaSAndroid Build Coastguard Worker static std::map<std::string, sk_sp<SkData>> gResources;
90*c8dee2aaSAndroid Build Coastguard Worker 
getResource(const char * name)91*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkData> getResource(const char* name) {
92*c8dee2aaSAndroid Build Coastguard Worker   auto it = gResources.find(name);
93*c8dee2aaSAndroid Build Coastguard Worker   if (it == gResources.end()) {
94*c8dee2aaSAndroid Build Coastguard Worker     SkDebugf("Resource %s not found\n", name);
95*c8dee2aaSAndroid Build Coastguard Worker     return nullptr;
96*c8dee2aaSAndroid Build Coastguard Worker   }
97*c8dee2aaSAndroid Build Coastguard Worker   return it->second;
98*c8dee2aaSAndroid Build Coastguard Worker }
99*c8dee2aaSAndroid Build Coastguard Worker 
LoadResource(std::string name,WASMPointerU8 bPtr,size_t len)100*c8dee2aaSAndroid Build Coastguard Worker static void LoadResource(std::string name, WASMPointerU8 bPtr, size_t len) {
101*c8dee2aaSAndroid Build Coastguard Worker   const uint8_t* bytes = reinterpret_cast<const uint8_t*>(bPtr);
102*c8dee2aaSAndroid Build Coastguard Worker   auto data = SkData::MakeFromMalloc(bytes, len);
103*c8dee2aaSAndroid Build Coastguard Worker   gResources[name] = std::move(data);
104*c8dee2aaSAndroid Build Coastguard Worker 
105*c8dee2aaSAndroid Build Coastguard Worker   if (!gResourceFactory) {
106*c8dee2aaSAndroid Build Coastguard Worker     gResourceFactory = getResource;
107*c8dee2aaSAndroid Build Coastguard Worker   }
108*c8dee2aaSAndroid Build Coastguard Worker }
109*c8dee2aaSAndroid Build Coastguard Worker 
110*c8dee2aaSAndroid Build Coastguard Worker /**
111*c8dee2aaSAndroid Build Coastguard Worker  * Runs the given GM and returns a JS object. If the GM was successful, the object will have the
112*c8dee2aaSAndroid Build Coastguard Worker  * following properties:
113*c8dee2aaSAndroid Build Coastguard Worker  *   "png" - a Uint8Array of the PNG data extracted from the surface.
114*c8dee2aaSAndroid Build Coastguard Worker  *   "hash" - a string which is the md5 hash of the pixel contents and the metadata.
115*c8dee2aaSAndroid Build Coastguard Worker  */
RunGM(sk_sp<GrDirectContext> ctx,std::string name)116*c8dee2aaSAndroid Build Coastguard Worker static JSObject RunGM(sk_sp<GrDirectContext> ctx, std::string name) {
117*c8dee2aaSAndroid Build Coastguard Worker     JSObject result = emscripten::val::object();
118*c8dee2aaSAndroid Build Coastguard Worker     auto gm = getGMWithName(name);
119*c8dee2aaSAndroid Build Coastguard Worker     if (!gm) {
120*c8dee2aaSAndroid Build Coastguard Worker         SkDebugf("Could not find gm with name %s\n", name.c_str());
121*c8dee2aaSAndroid Build Coastguard Worker         return result;
122*c8dee2aaSAndroid Build Coastguard Worker     }
123*c8dee2aaSAndroid Build Coastguard Worker     // TODO(kjlubick) make these configurable somehow. This probably makes sense to do as function
124*c8dee2aaSAndroid Build Coastguard Worker     //   parameters.
125*c8dee2aaSAndroid Build Coastguard Worker     auto alphaType = SkAlphaType::kPremul_SkAlphaType;
126*c8dee2aaSAndroid Build Coastguard Worker     auto colorType = SkColorType::kN32_SkColorType;
127*c8dee2aaSAndroid Build Coastguard Worker     SkISize size = gm->getISize();
128*c8dee2aaSAndroid Build Coastguard Worker     SkImageInfo info = SkImageInfo::Make(size, colorType, alphaType);
129*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkSurface> surface(SkSurfaces::RenderTarget(
130*c8dee2aaSAndroid Build Coastguard Worker             ctx.get(), skgpu::Budgeted::kYes, info, 0, kBottomLeft_GrSurfaceOrigin, nullptr, true));
131*c8dee2aaSAndroid Build Coastguard Worker     if (!surface) {
132*c8dee2aaSAndroid Build Coastguard Worker         SkDebugf("Could not make surface\n");
133*c8dee2aaSAndroid Build Coastguard Worker         return result;
134*c8dee2aaSAndroid Build Coastguard Worker     }
135*c8dee2aaSAndroid Build Coastguard Worker     auto canvas = surface->getCanvas();
136*c8dee2aaSAndroid Build Coastguard Worker 
137*c8dee2aaSAndroid Build Coastguard Worker     gm->onceBeforeDraw();
138*c8dee2aaSAndroid Build Coastguard Worker     SkString msg;
139*c8dee2aaSAndroid Build Coastguard Worker     // Based on GMSrc::draw from DM.
140*c8dee2aaSAndroid Build Coastguard Worker     auto gpuSetupResult = gm->gpuSetup(canvas, &msg);
141*c8dee2aaSAndroid Build Coastguard Worker     if (gpuSetupResult == skiagm::DrawResult::kFail) {
142*c8dee2aaSAndroid Build Coastguard Worker         SkDebugf("Error with gpu setup for gm %s: %s\n", name.c_str(), msg.c_str());
143*c8dee2aaSAndroid Build Coastguard Worker         return result;
144*c8dee2aaSAndroid Build Coastguard Worker     } else if (gpuSetupResult == skiagm::DrawResult::kSkip) {
145*c8dee2aaSAndroid Build Coastguard Worker         return result;
146*c8dee2aaSAndroid Build Coastguard Worker     }
147*c8dee2aaSAndroid Build Coastguard Worker 
148*c8dee2aaSAndroid Build Coastguard Worker     auto drawResult = gm->draw(canvas, &msg);
149*c8dee2aaSAndroid Build Coastguard Worker     if (drawResult == skiagm::DrawResult::kFail) {
150*c8dee2aaSAndroid Build Coastguard Worker         SkDebugf("Error with gm %s: %s\n", name.c_str(), msg.c_str());
151*c8dee2aaSAndroid Build Coastguard Worker         return result;
152*c8dee2aaSAndroid Build Coastguard Worker     } else if (drawResult == skiagm::DrawResult::kSkip) {
153*c8dee2aaSAndroid Build Coastguard Worker         return result;
154*c8dee2aaSAndroid Build Coastguard Worker     }
155*c8dee2aaSAndroid Build Coastguard Worker     ctx->flushAndSubmit(surface.get(), GrSyncCpu::kYes);
156*c8dee2aaSAndroid Build Coastguard Worker 
157*c8dee2aaSAndroid Build Coastguard Worker     // Based on GPUSink::readBack
158*c8dee2aaSAndroid Build Coastguard Worker     SkBitmap bitmap;
159*c8dee2aaSAndroid Build Coastguard Worker     bitmap.allocPixels(info);
160*c8dee2aaSAndroid Build Coastguard Worker     if (!canvas->readPixels(bitmap, 0, 0)) {
161*c8dee2aaSAndroid Build Coastguard Worker         SkDebugf("Could not read pixels back\n");
162*c8dee2aaSAndroid Build Coastguard Worker         return result;
163*c8dee2aaSAndroid Build Coastguard Worker     }
164*c8dee2aaSAndroid Build Coastguard Worker 
165*c8dee2aaSAndroid Build Coastguard Worker     // Now we need to encode to PNG and get the md5 hash of the pixels (and colorspace and stuff).
166*c8dee2aaSAndroid Build Coastguard Worker     // This is based on Task::Run from DM.cpp
167*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<HashAndEncode> hashAndEncode = std::make_unique<HashAndEncode>(bitmap);
168*c8dee2aaSAndroid Build Coastguard Worker     SkString md5;
169*c8dee2aaSAndroid Build Coastguard Worker     SkMD5 hash;
170*c8dee2aaSAndroid Build Coastguard Worker     hashAndEncode->feedHash(&hash);
171*c8dee2aaSAndroid Build Coastguard Worker     SkMD5::Digest digest = hash.finish();
172*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < 16; i++) {
173*c8dee2aaSAndroid Build Coastguard Worker         md5.appendf("%02x", digest.data[i]);
174*c8dee2aaSAndroid Build Coastguard Worker     }
175*c8dee2aaSAndroid Build Coastguard Worker 
176*c8dee2aaSAndroid Build Coastguard Worker     auto ok = gKnownDigests.find(md5.c_str());
177*c8dee2aaSAndroid Build Coastguard Worker     if (ok == gKnownDigests.end()) {
178*c8dee2aaSAndroid Build Coastguard Worker         // We only need to decode the image if it is "interesting", that is, we have not written it
179*c8dee2aaSAndroid Build Coastguard Worker         // before to disk and uploaded it to gold.
180*c8dee2aaSAndroid Build Coastguard Worker         SkDynamicMemoryWStream stream;
181*c8dee2aaSAndroid Build Coastguard Worker         // We do not need to include the keys because they are optional - they are not read by Gold.
182*c8dee2aaSAndroid Build Coastguard Worker         CommandLineFlags::StringArray empty;
183*c8dee2aaSAndroid Build Coastguard Worker         hashAndEncode->encodePNG(&stream, md5.c_str(), empty, empty);
184*c8dee2aaSAndroid Build Coastguard Worker 
185*c8dee2aaSAndroid Build Coastguard Worker         auto data = stream.detachAsData();
186*c8dee2aaSAndroid Build Coastguard Worker 
187*c8dee2aaSAndroid Build Coastguard Worker         // This is the cleanest way to create a new Uint8Array with a copy of the data that is not
188*c8dee2aaSAndroid Build Coastguard Worker         // in the WASM heap. kjlubick tried returning a pointer inside an SkData, but that lead to
189*c8dee2aaSAndroid Build Coastguard Worker         // some use after free issues. By making the copy using the JS transliteration, we don't
190*c8dee2aaSAndroid Build Coastguard Worker         // risk the SkData object being cleaned up before we make the copy.
191*c8dee2aaSAndroid Build Coastguard Worker         Uint8Array pngData = emscripten::val(
192*c8dee2aaSAndroid Build Coastguard Worker             // https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html#memory-views
193*c8dee2aaSAndroid Build Coastguard Worker             typed_memory_view(data->size(), data->bytes())
194*c8dee2aaSAndroid Build Coastguard Worker         ).call<Uint8Array>("slice"); // slice with no args makes a copy of the memory view.
195*c8dee2aaSAndroid Build Coastguard Worker 
196*c8dee2aaSAndroid Build Coastguard Worker         result.set("png", pngData);
197*c8dee2aaSAndroid Build Coastguard Worker         gKnownDigests.emplace(md5.c_str());
198*c8dee2aaSAndroid Build Coastguard Worker     }
199*c8dee2aaSAndroid Build Coastguard Worker     result.set("hash", md5.c_str());
200*c8dee2aaSAndroid Build Coastguard Worker     return result;
201*c8dee2aaSAndroid Build Coastguard Worker }
202*c8dee2aaSAndroid Build Coastguard Worker 
ListTests()203*c8dee2aaSAndroid Build Coastguard Worker static JSArray ListTests() {
204*c8dee2aaSAndroid Build Coastguard Worker     SkDebugf("Listing Tests\n");
205*c8dee2aaSAndroid Build Coastguard Worker     JSArray tests = emscripten::val::array();
206*c8dee2aaSAndroid Build Coastguard Worker     for (auto test : skiatest::TestRegistry::Range()) {
207*c8dee2aaSAndroid Build Coastguard Worker         SkDebugf("test %s\n", test.fName);
208*c8dee2aaSAndroid Build Coastguard Worker         tests.call<void>("push", std::string(test.fName));
209*c8dee2aaSAndroid Build Coastguard Worker     }
210*c8dee2aaSAndroid Build Coastguard Worker     return tests;
211*c8dee2aaSAndroid Build Coastguard Worker }
212*c8dee2aaSAndroid Build Coastguard Worker 
getTestWithName(std::string name,bool * ok)213*c8dee2aaSAndroid Build Coastguard Worker static skiatest::Test getTestWithName(std::string name, bool* ok) {
214*c8dee2aaSAndroid Build Coastguard Worker     for (auto test : skiatest::TestRegistry::Range()) {
215*c8dee2aaSAndroid Build Coastguard Worker         if (name == test.fName) {
216*c8dee2aaSAndroid Build Coastguard Worker           *ok = true;
217*c8dee2aaSAndroid Build Coastguard Worker           return test;
218*c8dee2aaSAndroid Build Coastguard Worker         }
219*c8dee2aaSAndroid Build Coastguard Worker     }
220*c8dee2aaSAndroid Build Coastguard Worker     *ok = false;
221*c8dee2aaSAndroid Build Coastguard Worker     return skiatest::Test::MakeCPU(nullptr, nullptr);
222*c8dee2aaSAndroid Build Coastguard Worker }
223*c8dee2aaSAndroid Build Coastguard Worker 
224*c8dee2aaSAndroid Build Coastguard Worker // Based on DM.cpp:run_test
225*c8dee2aaSAndroid Build Coastguard Worker struct WasmReporter : public skiatest::Reporter {
WasmReporterWasmReporter226*c8dee2aaSAndroid Build Coastguard Worker     WasmReporter(std::string name, JSObject result): fName(name), fResult(result){}
227*c8dee2aaSAndroid Build Coastguard Worker 
reportFailedWasmReporter228*c8dee2aaSAndroid Build Coastguard Worker     void reportFailed(const skiatest::Failure& failure) override {
229*c8dee2aaSAndroid Build Coastguard Worker         SkDebugf("Test %s failed: %s\n", fName.c_str(), failure.toString().c_str());
230*c8dee2aaSAndroid Build Coastguard Worker         fResult.set("result", "failed");
231*c8dee2aaSAndroid Build Coastguard Worker         fResult.set("msg", failure.toString().c_str());
232*c8dee2aaSAndroid Build Coastguard Worker     }
233*c8dee2aaSAndroid Build Coastguard Worker     std::string fName;
234*c8dee2aaSAndroid Build Coastguard Worker     JSObject fResult;
235*c8dee2aaSAndroid Build Coastguard Worker };
236*c8dee2aaSAndroid Build Coastguard Worker 
237*c8dee2aaSAndroid Build Coastguard Worker /**
238*c8dee2aaSAndroid Build Coastguard Worker  * Runs the given Test and returns a JS object. If the Test was located, the object will have the
239*c8dee2aaSAndroid Build Coastguard Worker  * following properties:
240*c8dee2aaSAndroid Build Coastguard Worker  *   "result" : One of "passed", "failed", "skipped".
241*c8dee2aaSAndroid Build Coastguard Worker  *   "msg": May be non-empty on failure
242*c8dee2aaSAndroid Build Coastguard Worker  */
RunTest(std::string name)243*c8dee2aaSAndroid Build Coastguard Worker static JSObject RunTest(std::string name) {
244*c8dee2aaSAndroid Build Coastguard Worker     JSObject result = emscripten::val::object();
245*c8dee2aaSAndroid Build Coastguard Worker     bool ok = false;
246*c8dee2aaSAndroid Build Coastguard Worker     auto test = getTestWithName(name, &ok);
247*c8dee2aaSAndroid Build Coastguard Worker     if (!ok) {
248*c8dee2aaSAndroid Build Coastguard Worker         SkDebugf("Could not find test with name %s\n", name.c_str());
249*c8dee2aaSAndroid Build Coastguard Worker         return result;
250*c8dee2aaSAndroid Build Coastguard Worker     }
251*c8dee2aaSAndroid Build Coastguard Worker     GrContextOptions grOpts;
252*c8dee2aaSAndroid Build Coastguard Worker     if (test.fTestType == skiatest::TestType::kGanesh) {
253*c8dee2aaSAndroid Build Coastguard Worker         result.set("result", "passed"); // default to passing - the reporter will mark failed.
254*c8dee2aaSAndroid Build Coastguard Worker         WasmReporter reporter(name, result);
255*c8dee2aaSAndroid Build Coastguard Worker         test.modifyGrContextOptions(&grOpts);
256*c8dee2aaSAndroid Build Coastguard Worker         test.ganesh(&reporter, grOpts);
257*c8dee2aaSAndroid Build Coastguard Worker         return result;
258*c8dee2aaSAndroid Build Coastguard Worker     } else if (test.fTestType == skiatest::TestType::kGraphite) {
259*c8dee2aaSAndroid Build Coastguard Worker         SkDebugf("Graphite test %s not yet supported\n", name.c_str());
260*c8dee2aaSAndroid Build Coastguard Worker         return result;
261*c8dee2aaSAndroid Build Coastguard Worker     }
262*c8dee2aaSAndroid Build Coastguard Worker 
263*c8dee2aaSAndroid Build Coastguard Worker     result.set("result", "passed"); // default to passing - the reporter will mark failed.
264*c8dee2aaSAndroid Build Coastguard Worker     WasmReporter reporter(name, result);
265*c8dee2aaSAndroid Build Coastguard Worker     test.cpu(&reporter);
266*c8dee2aaSAndroid Build Coastguard Worker     return result;
267*c8dee2aaSAndroid Build Coastguard Worker }
268*c8dee2aaSAndroid Build Coastguard Worker 
269*c8dee2aaSAndroid Build Coastguard Worker namespace skiatest {
270*c8dee2aaSAndroid Build Coastguard Worker 
271*c8dee2aaSAndroid Build Coastguard Worker using ContextType = skgpu::ContextType;
272*c8dee2aaSAndroid Build Coastguard Worker 
273*c8dee2aaSAndroid Build Coastguard Worker // These are the supported ContextTypeFilterFn. They are defined in Test.h and implemented here.
IsGLContextType(skgpu::ContextType ct)274*c8dee2aaSAndroid Build Coastguard Worker bool IsGLContextType(skgpu::ContextType ct) {
275*c8dee2aaSAndroid Build Coastguard Worker     return skgpu::ganesh::ContextTypeBackend(ct) == GrBackendApi::kOpenGL;
276*c8dee2aaSAndroid Build Coastguard Worker }
IsMockContextType(skgpu::ContextType ct)277*c8dee2aaSAndroid Build Coastguard Worker bool IsMockContextType(skgpu::ContextType ct) {
278*c8dee2aaSAndroid Build Coastguard Worker     return ct == skgpu::ContextType::kMock;
279*c8dee2aaSAndroid Build Coastguard Worker }
280*c8dee2aaSAndroid Build Coastguard Worker // These are not supported
IsVulkanContextType(ContextType)281*c8dee2aaSAndroid Build Coastguard Worker bool IsVulkanContextType(ContextType) { return false; }
IsMetalContextType(ContextType)282*c8dee2aaSAndroid Build Coastguard Worker bool IsMetalContextType(ContextType) { return false; }
IsDirect3DContextType(ContextType)283*c8dee2aaSAndroid Build Coastguard Worker bool IsDirect3DContextType(ContextType) { return false; }
IsDawnContextType(ContextType)284*c8dee2aaSAndroid Build Coastguard Worker bool IsDawnContextType(ContextType) { return false; }
285*c8dee2aaSAndroid Build Coastguard Worker 
RunWithGaneshTestContexts(GrContextTestFn * testFn,ContextTypeFilterFn * filter,Reporter * reporter,const GrContextOptions & options)286*c8dee2aaSAndroid Build Coastguard Worker void RunWithGaneshTestContexts(GrContextTestFn* testFn, ContextTypeFilterFn* filter,
287*c8dee2aaSAndroid Build Coastguard Worker                                Reporter* reporter, const GrContextOptions& options) {
288*c8dee2aaSAndroid Build Coastguard Worker     for (auto contextType : {skgpu::ContextType::kGLES, skgpu::ContextType::kMock}) {
289*c8dee2aaSAndroid Build Coastguard Worker         if (filter && !(*filter)(contextType)) {
290*c8dee2aaSAndroid Build Coastguard Worker             continue;
291*c8dee2aaSAndroid Build Coastguard Worker         }
292*c8dee2aaSAndroid Build Coastguard Worker 
293*c8dee2aaSAndroid Build Coastguard Worker         sk_gpu_test::GrContextFactory factory(options);
294*c8dee2aaSAndroid Build Coastguard Worker         sk_gpu_test::ContextInfo ctxInfo = factory.getContextInfo(contextType);
295*c8dee2aaSAndroid Build Coastguard Worker 
296*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, ctxInfo.directContext() != nullptr);
297*c8dee2aaSAndroid Build Coastguard Worker         if (!ctxInfo.directContext()) {
298*c8dee2aaSAndroid Build Coastguard Worker             return;
299*c8dee2aaSAndroid Build Coastguard Worker         }
300*c8dee2aaSAndroid Build Coastguard Worker         ctxInfo.testContext()->makeCurrent();
301*c8dee2aaSAndroid Build Coastguard Worker         // From DMGpuTestProcs.cpp
302*c8dee2aaSAndroid Build Coastguard Worker         (*testFn)(reporter, ctxInfo);
303*c8dee2aaSAndroid Build Coastguard Worker         // Sync so any release/finished procs get called.
304*c8dee2aaSAndroid Build Coastguard Worker         ctxInfo.directContext()->flushAndSubmit(GrSyncCpu::kYes);
305*c8dee2aaSAndroid Build Coastguard Worker     }
306*c8dee2aaSAndroid Build Coastguard Worker }
307*c8dee2aaSAndroid Build Coastguard Worker } // namespace skiatest
308*c8dee2aaSAndroid Build Coastguard Worker 
309*c8dee2aaSAndroid Build Coastguard Worker namespace {
310*c8dee2aaSAndroid Build Coastguard Worker 
311*c8dee2aaSAndroid Build Coastguard Worker // A GLtestContext that we can return from CreatePlatformGLTestContext below.
312*c8dee2aaSAndroid Build Coastguard Worker // It doesn't have to do anything WebGL-specific that I know of but we can't return
313*c8dee2aaSAndroid Build Coastguard Worker // a GLTestContext because it has pure virtual methods that need to be implemented.
314*c8dee2aaSAndroid Build Coastguard Worker class WasmWebGlTestContext : public sk_gpu_test::GLTestContext {
315*c8dee2aaSAndroid Build Coastguard Worker public:
WasmWebGlTestContext()316*c8dee2aaSAndroid Build Coastguard Worker     WasmWebGlTestContext() {}
~WasmWebGlTestContext()317*c8dee2aaSAndroid Build Coastguard Worker     ~WasmWebGlTestContext() override {
318*c8dee2aaSAndroid Build Coastguard Worker         this->teardown();
319*c8dee2aaSAndroid Build Coastguard Worker     }
320*c8dee2aaSAndroid Build Coastguard Worker     // We assume WebGL only has one context and that it is always current.
321*c8dee2aaSAndroid Build Coastguard Worker     // Therefore these context related functions return null intentionally.
322*c8dee2aaSAndroid Build Coastguard Worker     // It's possible that more tests will pass if these were correctly implemented.
makeNew() const323*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<GLTestContext> makeNew() const override {
324*c8dee2aaSAndroid Build Coastguard Worker         // This is supposed to create a new GL context in a new GLTestContext.
325*c8dee2aaSAndroid Build Coastguard Worker         // Specifically for tests that do not want to re-use the existing one.
326*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
327*c8dee2aaSAndroid Build Coastguard Worker     }
onPlatformMakeNotCurrent() const328*c8dee2aaSAndroid Build Coastguard Worker     void onPlatformMakeNotCurrent() const override { }
onPlatformMakeCurrent() const329*c8dee2aaSAndroid Build Coastguard Worker     void onPlatformMakeCurrent() const override { }
onPlatformGetAutoContextRestore() const330*c8dee2aaSAndroid Build Coastguard Worker     std::function<void()> onPlatformGetAutoContextRestore() const override {
331*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
332*c8dee2aaSAndroid Build Coastguard Worker     }
onPlatformGetProcAddress(const char * procName) const333*c8dee2aaSAndroid Build Coastguard Worker     GrGLFuncPtr onPlatformGetProcAddress(const char* procName) const override {
334*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
335*c8dee2aaSAndroid Build Coastguard Worker     }
336*c8dee2aaSAndroid Build Coastguard Worker };
337*c8dee2aaSAndroid Build Coastguard Worker } // namespace
338*c8dee2aaSAndroid Build Coastguard Worker 
339*c8dee2aaSAndroid Build Coastguard Worker namespace sk_gpu_test {
CreatePlatformGLTestContext(GrGLStandard forcedGpuAPI,GLTestContext * shareContext)340*c8dee2aaSAndroid Build Coastguard Worker GLTestContext *CreatePlatformGLTestContext(GrGLStandard forcedGpuAPI,
341*c8dee2aaSAndroid Build Coastguard Worker                                            GLTestContext *shareContext) {
342*c8dee2aaSAndroid Build Coastguard Worker     return new WasmWebGlTestContext();
343*c8dee2aaSAndroid Build Coastguard Worker }
344*c8dee2aaSAndroid Build Coastguard Worker } // namespace sk_gpu_test
345*c8dee2aaSAndroid Build Coastguard Worker 
Init()346*c8dee2aaSAndroid Build Coastguard Worker void Init() { ToolUtils::UsePortableFontMgr(); }
347*c8dee2aaSAndroid Build Coastguard Worker 
CurrentTestHarness()348*c8dee2aaSAndroid Build Coastguard Worker TestHarness CurrentTestHarness() {
349*c8dee2aaSAndroid Build Coastguard Worker     return TestHarness::kWasmGMTests;
350*c8dee2aaSAndroid Build Coastguard Worker }
351*c8dee2aaSAndroid Build Coastguard Worker 
EMSCRIPTEN_BINDINGS(GMs)352*c8dee2aaSAndroid Build Coastguard Worker EMSCRIPTEN_BINDINGS(GMs) {
353*c8dee2aaSAndroid Build Coastguard Worker     function("Init", &Init);
354*c8dee2aaSAndroid Build Coastguard Worker     function("ListGMs", &ListGMs);
355*c8dee2aaSAndroid Build Coastguard Worker     function("ListTests", &ListTests);
356*c8dee2aaSAndroid Build Coastguard Worker     function("LoadKnownDigest", &LoadKnownDigest);
357*c8dee2aaSAndroid Build Coastguard Worker     function("_LoadResource", &LoadResource);
358*c8dee2aaSAndroid Build Coastguard Worker     function("MakeGrContext", &MakeGrContext);
359*c8dee2aaSAndroid Build Coastguard Worker     function("RunGM", &RunGM);
360*c8dee2aaSAndroid Build Coastguard Worker     function("RunTest", &RunTest);
361*c8dee2aaSAndroid Build Coastguard Worker 
362*c8dee2aaSAndroid Build Coastguard Worker     class_<GrDirectContext>("GrDirectContext")
363*c8dee2aaSAndroid Build Coastguard Worker         .smart_ptr<sk_sp<GrDirectContext>>("sk_sp<GrDirectContext>");
364*c8dee2aaSAndroid Build Coastguard Worker }
365