Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
bindings.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2021 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
13#include "include/core/SkRect.h"
21
22#include <emscripten/bind.h>
23#include <emscripten/emscripten.h>
24#include <emscripten/html5.h>
25// https://github.com/emscripten-core/emscripten/blob/main/system/include/emscripten/html5_webgpu.h
26// The import/export functions defined here should allow us to fetch a handle to a given JS
27// Texture/Sampler/Device etc if needed.
28#include <emscripten/html5_webgpu.h>
29// https://github.com/emscripten-core/emscripten/blob/main/system/include/webgpu/webgpu.h
30// This defines WebGPU constants and such. It also includes a lot of typedefs that make something
31// like WGPUDevice defined as a pointer to something external. These "pointers" are actually just
32// a small integer that refers to an array index of JS objects being held by a "manager"
33// https://github.com/emscripten-core/emscripten/blob/f47bef371f3464471c6d30b631cffcdd06ced004/src/library_webgpu.js#L192
34#include <webgpu/webgpu.h>
35// https://github.com/emscripten-core/emscripten/blob/main/system/include/webgpu/webgpu_cpp.h
36// This defines the C++ equivalents to the JS WebGPU API.
37#include <webgpu/webgpu_cpp.h>
38
39static wgpu::SwapChain getSwapChainForCanvas(wgpu::Device device,
40 std::string canvasSelector,
41 int width,
42 int height) {
43 wgpu::SurfaceDescriptorFromCanvasHTMLSelector surfaceSelector;
44 surfaceSelector.selector = canvasSelector.c_str();
45
46 wgpu::SurfaceDescriptor surface_desc;
47 surface_desc.nextInChain = &surfaceSelector;
48 wgpu::Instance instance;
49 wgpu::Surface surface = instance.CreateSurface(&surface_desc);
50
51 wgpu::SwapChainDescriptor swap_chain_desc;
52 swap_chain_desc.format = wgpu::TextureFormat::BGRA8Unorm;
53 swap_chain_desc.usage = wgpu::TextureUsage::RenderAttachment;
54 swap_chain_desc.presentMode = wgpu::PresentMode::Fifo;
55 swap_chain_desc.width = width;
56 swap_chain_desc.height = height;
57 return device.CreateSwapChain(surface, &swap_chain_desc);
58}
59
60enum class DemoKind {
64};
65
67 float width;
68 float height;
69 float time;
70};
71
72class Demo final {
73public:
74 bool init(std::string canvasSelector, int width, int height) {
75 GrContextOptions ctxOpts;
76
77 wgpu::Device device = wgpu::Device::Acquire(emscripten_webgpu_get_device());
78 sk_sp<GrDirectContext> context = GrDirectContext::MakeDawn(device, ctxOpts);
79 if (!context) {
80 SkDebugf("Could not create GrDirectContext\n");
81 return false;
82 }
83
84 const char* sksl =
85 "uniform float2 iResolution;"
86 "uniform float iTime;"
87 "vec2 d;"
88 "float b(float a) {"
89 " return step(max(d.x, d.y), a);"
90 "}"
91 "half4 main(float2 C) {"
92 " vec4 O = vec4(0);"
93 " C.y = iResolution.y - C.y;"
94 " for (float i = 0; i < 3; ++i) {"
95 " vec2 U = C.yx / iResolution.yx;"
96 " U.y -= .5;"
97 " U.x = U.x * .4 + U.y * U.y;"
98 " U.y += U.x * sin(-iTime * 9. + i * 2. + U.x * 25.) * .2;"
99 " U.x -= asin(sin(U.y * 34.))/20.;"
100 " d = abs(U);"
101 " O += .3 * vec4(.8 * b(.3) + b(.2), b(.2), b(.1), -1.);"
102 " }"
103 " return O.xyz1;"
104 "}";
105
106 auto [effect, err] = SkRuntimeEffect::MakeForShader(SkString(sksl));
107 if (!effect) {
108 SkDebugf("Failed to compile SkSL: %s\n", err.c_str());
109 return false;
110 }
111
112 fWidth = width;
113 fHeight = height;
114 fCanvasSwapChain = getSwapChainForCanvas(device, canvasSelector, width, height);
115 fContext = context;
116 fEffect = effect;
117
118 return true;
119 }
120
121 void setKind(DemoKind kind) { fDemoKind = kind; }
122
123 void draw(int timestamp) {
124 GrDawnRenderTargetInfo rtInfo;
125 rtInfo.fTextureView = fCanvasSwapChain.GetCurrentTextureView();
126 rtInfo.fFormat = wgpu::TextureFormat::BGRA8Unorm;
127 rtInfo.fLevelCount = 1;
128 GrBackendRenderTarget backendRenderTarget(fWidth, fHeight, 1, 8, rtInfo);
129 SkSurfaceProps surfaceProps(0, kRGB_H_SkPixelGeometry);
130
132 backendRenderTarget,
134 kN32_SkColorType,
135 nullptr,
136 &surfaceProps);
137
139 if (fDemoKind == DemoKind::SOLID_COLOR) {
141 } else if (fDemoKind == DemoKind::GRADIENT) {
143 } else if (fDemoKind == DemoKind::RUNTIME_EFFECT) {
144 drawRuntimeEffect(&paint, timestamp);
145 }
146
147 // Schedule the recorded commands and wait until the GPU has executed them.
148 surface->getCanvas()->drawPaint(paint);
149 fContext->flushAndSubmit(surface, true);
150 fFrameCount++;
151 }
152
154 bool flipColor = fFrameCount % 2 == 0;
155 paint->setColor(flipColor ? SK_ColorCYAN : SK_ColorMAGENTA);
156 }
157
159 bool flipColor = fFrameCount % 2 == 0;
160 SkColor colors1[2] = {SK_ColorMAGENTA, SK_ColorCYAN};
161 SkColor colors2[2] = {SK_ColorCYAN, SK_ColorMAGENTA};
162
163 float x = (float)fWidth / 2.f;
164 float y = (float)fHeight / 2.f;
166 std::min(x, y),
167 flipColor ? colors1 : colors2,
168 nullptr,
169 2,
171 }
172
173 void drawRuntimeEffect(SkPaint* paint, int timestamp) {
174 DemoUniforms uniforms;
175 uniforms.width = fWidth;
176 uniforms.height = fHeight;
177 uniforms.time = static_cast<float>(timestamp) / 1000.f;
178
179 sk_sp<SkData> uniformData = SkData::MakeWithCopy(&uniforms, sizeof(uniforms));
180 sk_sp<SkShader> shader = fEffect->makeShader(std::move(uniformData), /*children=*/{});
181 paint->setShader(shader);
182 }
183
184private:
185 int fFrameCount = 0;
186 int fWidth;
187 int fHeight;
188 wgpu::SwapChain fCanvasSwapChain;
189 sk_sp<GrDirectContext> fContext;
192};
193
195 emscripten::enum_<DemoKind>("DemoKind")
196 .value("SOLID_COLOR", DemoKind::SOLID_COLOR)
197 .value("GRADIENT", DemoKind::GRADIENT)
198 .value("RUNTIME_EFFECT", DemoKind::RUNTIME_EFFECT);
199 emscripten::class_<Demo>("Demo")
200 .constructor()
201 .function("init", &Demo::init)
202 .function("setKind", &Demo::setKind)
203 .function("draw", &Demo::draw);
204}
@ kTopLeft_GrSurfaceOrigin
Definition GrTypes.h:148
constexpr SkColor SK_ColorMAGENTA
Definition SkColor.h:147
uint32_t SkColor
Definition SkColor.h:37
constexpr SkColor SK_ColorCYAN
Definition SkColor.h:143
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
@ kRGB_H_SkPixelGeometry
static wgpu::SwapChain getSwapChainForCanvas(wgpu::Device device, std::string canvasSelector, int width, int height)
Definition bindings.cpp:39
DemoKind
Definition bindings.cpp:60
@ RUNTIME_EFFECT
EMSCRIPTEN_BINDINGS(Skia)
Definition bindings.cpp:194
void drawGradient(SkPaint *paint)
Definition bindings.cpp:158
void draw(int timestamp)
Definition bindings.cpp:123
void drawSolidColor(SkPaint *paint)
Definition bindings.cpp:153
bool init(std::string canvasSelector, int width, int height)
Definition bindings.cpp:74
void setKind(DemoKind kind)
Definition bindings.cpp:121
void drawRuntimeEffect(SkPaint *paint, int timestamp)
Definition bindings.cpp:173
void flushAndSubmit(GrSyncCpu sync=GrSyncCpu::kNo)
static sk_sp< SkData > MakeWithCopy(const void *data, size_t length)
Definition SkData.cpp:111
static sk_sp< SkShader > MakeRadial(const SkPoint &center, SkScalar radius, const SkColor colors[], const SkScalar pos[], int count, SkTileMode mode, uint32_t flags=0, const SkMatrix *localMatrix=nullptr)
sk_sp< SkShader > makeShader(sk_sp< const SkData > uniforms, sk_sp< SkShader > children[], size_t childCount, const SkMatrix *localMatrix=nullptr) const
static Result MakeForShader(SkString sksl, const Options &)
T * get() const
Definition SkRefCnt.h:303
const Paint & paint
VkDevice device
Definition main.cc:53
VkInstance instance
Definition main.cc:48
VkSurfaceKHR surface
Definition main.cc:49
double y
double x
SK_API sk_sp< SkSurface > WrapBackendRenderTarget(GrRecordingContext *context, const GrBackendRenderTarget &backendRenderTarget, GrSurfaceOrigin origin, SkColorType colorType, sk_sp< SkColorSpace > colorSpace, const SkSurfaceProps *surfaceProps, RenderTargetReleaseProc releaseProc=nullptr, ReleaseContext releaseContext=nullptr)
int32_t height
int32_t width
static constexpr SkPoint Make(float x, float y)