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