Flutter Engine
The Flutter Engine
Classes | Namespaces | Typedefs | Functions | Variables
gm_bindings.cpp File Reference
#include <set>
#include <string>
#include <emscripten.h>
#include <emscripten/bind.h>
#include <emscripten/html5.h>
#include "gm/gm.h"
#include "include/core/SkBitmap.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkData.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkStream.h"
#include "include/core/SkSurface.h"
#include "include/gpu/GrContextOptions.h"
#include "include/gpu/GrDirectContext.h"
#include "include/gpu/ganesh/SkSurfaceGanesh.h"
#include "include/gpu/ganesh/gl/GrGLDirectContext.h"
#include "include/gpu/gl/GrGLInterface.h"
#include "include/gpu/gl/GrGLTypes.h"
#include "modules/canvaskit/WasmCommon.h"
#include "src/core/SkMD5.h"
#include "tests/Test.h"
#include "tests/TestHarness.h"
#include "tools/HashAndEncode.h"
#include "tools/ResourceFactory.h"
#include "tools/flags/CommandLineFlags.h"
#include "tools/fonts/FontToolUtils.h"
#include "tools/gpu/ContextType.h"

Go to the source code of this file.

Classes

struct  WasmReporter
 

Namespaces

namespace  skiatest
 
namespace  sk_gpu_test
 

Typedefs

using skiatest::ContextType = skgpu::ContextType
 

Functions

static JSArray ListGMs ()
 
static std::unique_ptr< skiagm::GMgetGMWithName (std::string name)
 
static sk_sp< GrDirectContextMakeGrContext (EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context)
 
static void LoadKnownDigest (std::string md5)
 
static sk_sp< SkDatagetResource (const char *name)
 
static void LoadResource (std::string name, WASMPointerU8 bPtr, size_t len)
 
static JSObject RunGM (sk_sp< GrDirectContext > ctx, std::string name)
 
static JSArray ListTests ()
 
static skiatest::Test getTestWithName (std::string name, bool *ok)
 
static JSObject RunTest (std::string name)
 
bool skiatest::IsGLContextType (skgpu::ContextType type)
 
bool skiatest::IsMockContextType (skgpu::ContextType type)
 
bool skiatest::IsVulkanContextType (skgpu::ContextType type)
 
bool skiatest::IsMetalContextType (skgpu::ContextType type)
 
bool skiatest::IsDirect3DContextType (skgpu::ContextType type)
 
bool skiatest::IsDawnContextType (skgpu::ContextType type)
 
void skiatest::RunWithGaneshTestContexts (GrContextTestFn *testFn, ContextTypeFilterFn *filter, Reporter *reporter, const GrContextOptions &options)
 
GLTestContext * sk_gpu_test::CreatePlatformGLTestContext (GrGLStandard forcedGpuAPI, GLTestContext *shareContext)
 
void Init ()
 
TestHarness CurrentTestHarness ()
 
 EMSCRIPTEN_BINDINGS (GMs)
 

Variables

static std::set< std::string > gKnownDigests
 
static std::map< std::string, sk_sp< SkData > > gResources
 

Function Documentation

◆ CurrentTestHarness()

TestHarness CurrentTestHarness ( )

Definition at line 348 of file gm_bindings.cpp.

348 {
350}

◆ EMSCRIPTEN_BINDINGS()

EMSCRIPTEN_BINDINGS ( GMs  )

Definition at line 352 of file gm_bindings.cpp.

352 {
353 function("Init", &Init);
354 function("ListGMs", &ListGMs);
355 function("ListTests", &ListTests);
356 function("LoadKnownDigest", &LoadKnownDigest);
357 function("_LoadResource", &LoadResource);
358 function("MakeGrContext", &MakeGrContext);
359 function("RunGM", &RunGM);
360 function("RunTest", &RunTest);
361
362 class_<GrDirectContext>("GrDirectContext")
363 .smart_ptr<sk_sp<GrDirectContext>>("sk_sp<GrDirectContext>");
364}
Dart_NativeFunction function
Definition: fuchsia.cc:51
void Init()
static void LoadKnownDigest(std::string md5)
Definition: gm_bindings.cpp:85
static JSArray ListTests()
static sk_sp< GrDirectContext > MakeGrContext(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context)
Definition: gm_bindings.cpp:69
static JSArray ListGMs()
Definition: gm_bindings.cpp:44
static JSObject RunGM(sk_sp< GrDirectContext > ctx, std::string name)
static JSObject RunTest(std::string name)
static void LoadResource(std::string name, WASMPointerU8 bPtr, size_t len)

◆ getGMWithName()

static std::unique_ptr< skiagm::GM > getGMWithName ( std::string  name)
static

Definition at line 55 of file gm_bindings.cpp.

55 {
56 for (const skiagm::GMFactory& fact : skiagm::GMRegistry::Range()) {
57 std::unique_ptr<skiagm::GM> gm(fact());
58 if (gm->getName().c_str() == name) {
59 return gm;
60 }
61 }
62 return nullptr;
63}
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
std::function< std::unique_ptr< skiagm::GM >()> GMFactory
Definition: gm.h:239

◆ getResource()

static sk_sp< SkData > getResource ( const char *  name)
static

Definition at line 91 of file gm_bindings.cpp.

91 {
92 auto it = gResources.find(name);
93 if (it == gResources.end()) {
94 SkDebugf("Resource %s not found\n", name);
95 return nullptr;
96 }
97 return it->second;
98}
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
static std::map< std::string, sk_sp< SkData > > gResources
Definition: gm_bindings.cpp:89

◆ getTestWithName()

static skiatest::Test getTestWithName ( std::string  name,
bool *  ok 
)
static

Definition at line 213 of file gm_bindings.cpp.

213 {
214 for (auto test : skiatest::TestRegistry::Range()) {
215 if (name == test.fName) {
216 *ok = true;
217 return test;
218 }
219 }
220 *ok = false;
221 return skiatest::Test::MakeCPU(nullptr, nullptr);
222}
#define test(name)
static bool ok(int result)
static Test MakeCPU(const char *name, CPUTestProc proc)
Definition: Test.h:120

◆ Init()

void Init ( )

Definition at line 346 of file gm_bindings.cpp.

◆ ListGMs()

static JSArray ListGMs ( )
static

Returns a JS array of strings containing the names of the registered GMs. GMs are only registered when their source is included in the "link" step, not if they are in something like libgm.a. The names are also logged to the console.

Definition at line 44 of file gm_bindings.cpp.

44 {
45 SkDebugf("Listing GMs\n");
46 JSArray gms = emscripten::val::array();
47 for (const skiagm::GMFactory& fact : skiagm::GMRegistry::Range()) {
48 std::unique_ptr<skiagm::GM> gm(fact());
49 SkDebugf("gm %s\n", gm->getName().c_str());
50 gms.call<void>("push", std::string(gm->getName().c_str()));
51 }
52 return gms;
53}
emscripten::val JSArray
Definition: WasmCommon.h:27

◆ ListTests()

static JSArray ListTests ( )
static

Definition at line 203 of file gm_bindings.cpp.

203 {
204 SkDebugf("Listing Tests\n");
205 JSArray tests = emscripten::val::array();
206 for (auto test : skiatest::TestRegistry::Range()) {
207 SkDebugf("test %s\n", test.fName);
208 tests.call<void>("push", std::string(test.fName));
209 }
210 return tests;
211}
static BlurTest tests[]
Definition: BlurTest.cpp:84

◆ LoadKnownDigest()

static void LoadKnownDigest ( std::string  md5)
static

Definition at line 85 of file gm_bindings.cpp.

85 {
86 gKnownDigests.insert(md5);
87}
static SkMD5::Digest md5(const SkBitmap &bm)
Definition: CodecTest.cpp:77
static std::set< std::string > gKnownDigests
Definition: gm_bindings.cpp:83

◆ LoadResource()

static void LoadResource ( std::string  name,
WASMPointerU8  bPtr,
size_t  len 
)
static

Definition at line 100 of file gm_bindings.cpp.

100 {
101 const uint8_t* bytes = reinterpret_cast<const uint8_t*>(bPtr);
102 auto data = SkData::MakeFromMalloc(bytes, len);
103 gResources[name] = std::move(data);
104
105 if (!gResourceFactory) {
107 }
108}
sk_sp< SkData >(* gResourceFactory)(const char *)
Definition: Resources.cpp:21
static sk_sp< SkData > MakeFromMalloc(const void *data, size_t length)
Definition: SkData.cpp:107
static sk_sp< SkData > getResource(const char *name)
Definition: gm_bindings.cpp:91
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63

◆ MakeGrContext()

static sk_sp< GrDirectContext > MakeGrContext ( EMSCRIPTEN_WEBGL_CONTEXT_HANDLE  context)
static

Sets the given WebGL context to be "current" and then creates a GrDirectContext from that context.

Definition at line 69 of file gm_bindings.cpp.

70{
71 EMSCRIPTEN_RESULT r = emscripten_webgl_make_context_current(context);
72 if (r < 0) {
73 printf("failed to make webgl context current %d\n", r);
74 return nullptr;
75 }
76 // setup GrDirectContext
77 auto interface = GrGLMakeNativeInterface();
78 // setup contexts
80 return dContext;
81}
SK_API sk_sp< const GrGLInterface > GrGLMakeNativeInterface()
SK_API sk_sp< GrDirectContext > MakeGL(sk_sp< const GrGLInterface >, const GrContextOptions &)
std::string printf(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: SkSLString.cpp:83

◆ RunGM()

static JSObject RunGM ( sk_sp< GrDirectContext ctx,
std::string  name 
)
static

Runs the given GM and returns a JS object. If the GM was successful, the object will have the following properties: "png" - a Uint8Array of the PNG data extracted from the surface. "hash" - a string which is the md5 hash of the pixel contents and the metadata.

Definition at line 116 of file gm_bindings.cpp.

116 {
117 JSObject result = emscripten::val::object();
118 auto gm = getGMWithName(name);
119 if (!gm) {
120 SkDebugf("Could not find gm with name %s\n", name.c_str());
121 return result;
122 }
123 // TODO(kjlubick) make these configurable somehow. This probably makes sense to do as function
124 // parameters.
125 auto alphaType = SkAlphaType::kPremul_SkAlphaType;
126 auto colorType = SkColorType::kN32_SkColorType;
127 SkISize size = gm->getISize();
130 ctx.get(), skgpu::Budgeted::kYes, info, 0, kBottomLeft_GrSurfaceOrigin, nullptr, true));
131 if (!surface) {
132 SkDebugf("Could not make surface\n");
133 return result;
134 }
135 auto canvas = surface->getCanvas();
136
137 gm->onceBeforeDraw();
138 SkString msg;
139 // Based on GMSrc::draw from DM.
140 auto gpuSetupResult = gm->gpuSetup(canvas, &msg);
141 if (gpuSetupResult == skiagm::DrawResult::kFail) {
142 SkDebugf("Error with gpu setup for gm %s: %s\n", name.c_str(), msg.c_str());
143 return result;
144 } else if (gpuSetupResult == skiagm::DrawResult::kSkip) {
145 return result;
146 }
147
148 auto drawResult = gm->draw(canvas, &msg);
149 if (drawResult == skiagm::DrawResult::kFail) {
150 SkDebugf("Error with gm %s: %s\n", name.c_str(), msg.c_str());
151 return result;
152 } else if (drawResult == skiagm::DrawResult::kSkip) {
153 return result;
154 }
156
157 // Based on GPUSink::readBack
159 bitmap.allocPixels(info);
160 if (!canvas->readPixels(bitmap, 0, 0)) {
161 SkDebugf("Could not read pixels back\n");
162 return result;
163 }
164
165 // Now we need to encode to PNG and get the md5 hash of the pixels (and colorspace and stuff).
166 // This is based on Task::Run from DM.cpp
167 std::unique_ptr<HashAndEncode> hashAndEncode = std::make_unique<HashAndEncode>(bitmap);
169 SkMD5 hash;
170 hashAndEncode->feedHash(&hash);
171 SkMD5::Digest digest = hash.finish();
172 for (int i = 0; i < 16; i++) {
173 md5.appendf("%02x", digest.data[i]);
174 }
175
176 auto ok = gKnownDigests.find(md5.c_str());
177 if (ok == gKnownDigests.end()) {
178 // We only need to decode the image if it is "interesting", that is, we have not written it
179 // before to disk and uploaded it to gold.
181 // We do not need to include the keys because they are optional - they are not read by Gold.
183 hashAndEncode->encodePNG(&stream, md5.c_str(), empty, empty);
184
185 auto data = stream.detachAsData();
186
187 // This is the cleanest way to create a new Uint8Array with a copy of the data that is not
188 // in the WASM heap. kjlubick tried returning a pointer inside an SkData, but that lead to
189 // some use after free issues. By making the copy using the JS transliteration, we don't
190 // risk the SkData object being cleaned up before we make the copy.
191 Uint8Array pngData = emscripten::val(
192 // https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html#memory-views
193 typed_memory_view(data->size(), data->bytes())
194 ).call<Uint8Array>("slice"); // slice with no args makes a copy of the memory view.
195
196 result.set("png", pngData);
197 gKnownDigests.emplace(md5.c_str());
198 }
199 result.set("hash", md5.c_str());
200 return result;
201}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
@ kBottomLeft_GrSurfaceOrigin
Definition: GrTypes.h:149
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
static SkColorType colorType(AImageDecoder *decoder, const AImageDecoderHeaderInfo *headerInfo)
static uint32_t hash(const SkShaderBase::GradientInfo &v)
emscripten::val JSObject
Definition: WasmCommon.h:28
emscripten::val Uint8Array
Definition: WasmCommon.h:32
void flushAndSubmit(GrSyncCpu sync=GrSyncCpu::kNo)
Definition: SkMD5.h:19
const char * c_str() const
Definition: SkString.h:133
T * get() const
Definition: SkRefCnt.h:303
VkSurfaceKHR surface
Definition: main.cc:49
EMSCRIPTEN_KEEPALIVE void empty()
GAsyncResult * result
static std::unique_ptr< skiagm::GM > getGMWithName(std::string name)
Definition: gm_bindings.cpp:55
SK_API sk_sp< SkSurface > RenderTarget(GrRecordingContext *context, skgpu::Budgeted budgeted, const SkImageInfo &imageInfo, int sampleCount, GrSurfaceOrigin surfaceOrigin, const SkSurfaceProps *surfaceProps, bool shouldCreateWithMips=false, bool isProtected=false)
Definition: bitmap.py:1
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
Definition: SkSize.h:16
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
uint8_t data[16]
Definition: SkMD5.h:39

◆ RunTest()

static JSObject RunTest ( std::string  name)
static

Runs the given Test and returns a JS object. If the Test was located, the object will have the following properties: "result" : One of "passed", "failed", "skipped". "msg": May be non-empty on failure

Definition at line 243 of file gm_bindings.cpp.

243 {
244 JSObject result = emscripten::val::object();
245 bool ok = false;
246 auto test = getTestWithName(name, &ok);
247 if (!ok) {
248 SkDebugf("Could not find test with name %s\n", name.c_str());
249 return result;
250 }
251 GrContextOptions grOpts;
252 if (test.fTestType == skiatest::TestType::kGanesh) {
253 result.set("result", "passed"); // default to passing - the reporter will mark failed.
255 test.modifyGrContextOptions(&grOpts);
256 test.ganesh(&reporter, grOpts);
257 return result;
258 } else if (test.fTestType == skiatest::TestType::kGraphite) {
259 SkDebugf("Graphite test %s not yet supported\n", name.c_str());
260 return result;
261 }
262
263 result.set("result", "passed"); // default to passing - the reporter will mark failed.
265 test.cpu(&reporter);
266 return result;
267}
reporter
Definition: FontMgrTest.cpp:39
static skiatest::Test getTestWithName(std::string name, bool *ok)

Variable Documentation

◆ gKnownDigests

std::set<std::string> gKnownDigests
static

Definition at line 83 of file gm_bindings.cpp.

◆ gResources

std::map<std::string, sk_sp<SkData> > gResources
static

Definition at line 89 of file gm_bindings.cpp.