Flutter Engine
The Flutter Engine
surface.cpp
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "surface.h"
6#include <algorithm>
7
13
14using namespace Skwasm;
15
16Surface::Surface() {
17 assert(emscripten_is_main_browser_thread());
18
19 pthread_attr_t attr;
20 pthread_attr_init(&attr);
21 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
22
23 pthread_create(
24 &_thread, &attr,
25 [](void* context) -> void* {
26 static_cast<Surface*>(context)->_runWorker();
27 return nullptr;
28 },
29 this);
30 // Listen to messages from the worker
32
33 // Synchronize the time origin for the worker thread
35}
36
37// Main thread only
39 assert(emscripten_is_main_browser_thread());
40 emscripten_dispatch_to_thread(_thread, EM_FUNC_SIG_VI,
41 reinterpret_cast<void*>(fDispose), nullptr,
42 this);
43}
44
45// Main thread only
46uint32_t Surface::renderPictures(SkPicture** pictures, int count) {
47 assert(emscripten_is_main_browser_thread());
48 uint32_t callbackId = ++_currentCallbackId;
49 std::unique_ptr<sk_sp<SkPicture>[]> picturePointers =
50 std::make_unique<sk_sp<SkPicture>[]>(count);
51 for (int i = 0; i < count; i++) {
52 picturePointers[i] = sk_ref_sp(pictures[i]);
53 }
54
55 // Releasing picturePointers here and will recreate the unique_ptr on the
56 // other thread See surface_renderPicturesOnWorker
57 skwasm_dispatchRenderPictures(_thread, this, picturePointers.release(), count,
58 callbackId);
59 return callbackId;
60}
61
62// Main thread only
64 assert(emscripten_is_main_browser_thread());
65 uint32_t callbackId = ++_currentCallbackId;
66 image->ref();
67
68 emscripten_dispatch_to_thread(_thread, EM_FUNC_SIG_VIIII,
69 reinterpret_cast<void*>(fRasterizeImage),
70 nullptr, this, image, format, callbackId);
71 return callbackId;
72}
73
74std::unique_ptr<TextureSourceWrapper> Surface::createTextureSourceWrapper(
75 SkwasmObject textureSource) {
76 return std::unique_ptr<TextureSourceWrapper>(
77 new TextureSourceWrapper(_thread, textureSource));
78}
79
80// Main thread only
82 assert(emscripten_is_main_browser_thread());
83 _callbackHandler = callbackHandler;
84}
85
86// Worker thread only
87void Surface::_runWorker() {
88 _init();
89 emscripten_exit_with_live_runtime();
90}
91
92// Worker thread only
93void Surface::_init() {
94 // Listen to messages from the main thread
96 _glContext = skwasm_createOffscreenCanvas(256, 256);
97 if (!_glContext) {
98 printf("Failed to create context!\n");
99 return;
100 }
101
102 makeCurrent(_glContext);
103 emscripten_webgl_enable_extension(_glContext, "WEBGL_debug_renderer_info");
104
106
107 // WebGL should already be clearing the color and stencil buffers, but do it
108 // again here to ensure Skia receives them in the expected state.
109 emscripten_glBindFramebuffer(GL_FRAMEBUFFER, 0);
110 emscripten_glClearColor(0, 0, 0, 0);
111 emscripten_glClearStencil(0);
112 emscripten_glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
115
116 // The on-screen canvas is FBO 0. Wrap it in a Skia render target so Skia
117 // can render to it.
118 _fbInfo.fFBOID = 0;
119 _fbInfo.fFormat = GL_RGBA8_OES;
120
121 emscripten_glGetIntegerv(GL_SAMPLES, &_sampleCount);
122 emscripten_glGetIntegerv(GL_STENCIL_BITS, &_stencil);
123}
124
125// Worker thread only
126void Surface::_dispose() {
127 delete this;
128}
129
130// Worker thread only
131void Surface::_resizeCanvasToFit(int width, int height) {
132 if (!_surface || width > _canvasWidth || height > _canvasHeight) {
133 _canvasWidth = std::max(width, _canvasWidth);
134 _canvasHeight = std::max(height, _canvasHeight);
135 _recreateSurface();
136 }
137}
138
139// Worker thread only
140void Surface::_recreateSurface() {
141 makeCurrent(_glContext);
142 skwasm_resizeCanvas(_glContext, _canvasWidth, _canvasHeight);
143 auto target = GrBackendRenderTargets::MakeGL(_canvasWidth, _canvasHeight,
144 _sampleCount, _stencil, _fbInfo);
148}
149
150// Worker thread only
152 int pictureCount,
153 uint32_t callbackId,
154 double rasterStart) {
155 // This is populated by the `captureImageBitmap` call the first time it is
156 // passed in.
157 SkwasmObject imagePromiseArray = __builtin_wasm_ref_null_extern();
158 for (int i = 0; i < pictureCount; i++) {
159 sk_sp<SkPicture> picture = pictures[i];
160 SkRect pictureRect = picture->cullRect();
161 SkIRect roundedOutRect;
162 pictureRect.roundOut(&roundedOutRect);
163 _resizeCanvasToFit(roundedOutRect.width(), roundedOutRect.height());
165 SkMatrix::Translate(-roundedOutRect.fLeft, -roundedOutRect.fTop);
166 makeCurrent(_glContext);
167 auto canvas = _surface->getCanvas();
169 canvas->drawPicture(picture, &matrix, nullptr);
170 _grContext->flush(_surface.get());
171 imagePromiseArray =
172 skwasm_captureImageBitmap(_glContext, roundedOutRect.width(),
173 roundedOutRect.height(), imagePromiseArray);
174 }
175 skwasm_resolveAndPostImages(this, imagePromiseArray, rasterStart, callbackId);
176}
177
178void Surface::_rasterizeImage(SkImage* image,
180 uint32_t callbackId) {
181 // We handle PNG encoding with browser APIs so that we can omit libpng from
182 // skia to save binary size.
183 assert(format != ImageByteFormat::png);
190 alphaType, SkColorSpace::MakeSRGB());
191 size_t bytesPerRow = 4 * image->width();
192 size_t byteSize = info.computeByteSize(bytesPerRow);
194 uint8_t* pixels = reinterpret_cast<uint8_t*>(data->writable_data());
195 bool success = image->readPixels(_grContext.get(), image->imageInfo(), pixels,
196 bytesPerRow, 0, 0);
197 if (!success) {
198 printf("Failed to read pixels from image!\n");
199 data = nullptr;
200 }
201 emscripten_async_run_in_main_runtime_thread(
202 EM_FUNC_SIG_VIII, fOnRasterizeComplete, this, data.release(), callbackId);
203}
204
205void Surface::_onRasterizeComplete(SkData* data, uint32_t callbackId) {
206 _callbackHandler(callbackId, data, __builtin_wasm_ref_null_extern());
207}
208
209// Main thread only
210void Surface::onRenderComplete(uint32_t callbackId, SkwasmObject imageBitmap) {
211 assert(emscripten_is_main_browser_thread());
212 _callbackHandler(callbackId, nullptr, imageBitmap);
213}
214
215void Surface::fDispose(Surface* surface) {
216 surface->_dispose();
217}
218
219void Surface::fOnRasterizeComplete(Surface* surface,
220 SkData* imageData,
221 uint32_t callbackId) {
222 surface->_onRasterizeComplete(imageData, callbackId);
223}
224
225void Surface::fRasterizeImage(Surface* surface,
226 SkImage* image,
228 uint32_t callbackId) {
229 surface->_rasterizeImage(image, format, callbackId);
230 image->unref();
231}
232
234 return new Surface();
235}
236
238 return surface->getThreadId();
239}
240
243 Surface::CallbackHandler* callbackHandler) {
244 surface->setCallbackHandler(callbackHandler);
245}
246
248 surface->dispose();
249}
250
252 SkPicture** pictures,
253 int count) {
254 return surface->renderPictures(pictures, count);
255}
256
258 sk_sp<SkPicture>* pictures,
259 int pictureCount,
260 uint32_t callbackId,
261 double rasterStart) {
262 // This will release the pictures when they leave scope.
263 std::unique_ptr<sk_sp<SkPicture>[]> picturesPointer =
264 std::unique_ptr<sk_sp<SkPicture>[]>(pictures);
265 surface->renderPicturesOnWorker(pictures, pictureCount, callbackId,
266 rasterStart);
267}
268
270 SkImage* image,
272 return surface->rasterizeImage(image, format);
273}
274
275// This is used by the skwasm JS support code to call back into C++ when the
276// we finish creating the image bitmap, which is an asynchronous operation.
278 uint32_t callbackId,
279 SkwasmObject imageBitmap) {
280 return surface->onRenderComplete(callbackId, imageBitmap);
281}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
int count
Definition: FontMgrTest.cpp:50
@ kBottomLeft_GrSurfaceOrigin
Definition: GrTypes.h:149
@ kMisc_GrGLBackendState
Definition: GrTypes.h:169
@ kRenderTarget_GrGLBackendState
Definition: GrTypes.h:157
kUnpremul_SkAlphaType
SkAlphaType
Definition: SkAlphaType.h:26
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition: SkColorType.h:24
constexpr SkColor SK_ColorTRANSPARENT
Definition: SkColor.h:99
sk_sp< T > sk_ref_sp(T *obj)
Definition: SkRefCnt.h:381
void resetContext(uint32_t state=kAll_GrBackendState)
GrSemaphoresSubmitted flush(const GrFlushInfo &info)
void drawColor(SkColor color, SkBlendMode mode=SkBlendMode::kSrcOver)
Definition: SkCanvas.h:1182
static sk_sp< SkColorSpace > MakeSRGB()
Definition: SkData.h:25
static sk_sp< SkData > MakeUninitialized(size_t length)
Definition: SkData.cpp:116
const SkImageInfo & imageInfo() const
Definition: SkImage.h:279
bool readPixels(GrDirectContext *context, const SkImageInfo &dstInfo, void *dstPixels, size_t dstRowBytes, int srcX, int srcY, CachingHint cachingHint=kAllow_CachingHint) const
Definition: SkImage.cpp:42
int width() const
Definition: SkImage.h:285
int height() const
Definition: SkImage.h:291
static SkMatrix Translate(SkScalar dx, SkScalar dy)
Definition: SkMatrix.h:91
virtual SkRect cullRect() const =0
void ref() const
Definition: SkRefCnt.h:62
void unref() const
Definition: SkRefCnt.h:72
SkCanvas * getCanvas()
Definition: SkSurface.cpp:82
void dispose()
Definition: surface.cpp:38
std::unique_ptr< TextureSourceWrapper > createTextureSourceWrapper(SkwasmObject textureSource)
Definition: surface.cpp:74
void setCallbackHandler(CallbackHandler *callbackHandler)
Definition: surface.cpp:81
void(uint32_t, void *, SkwasmObject) CallbackHandler
Definition: surface.h:56
void onRenderComplete(uint32_t callbackId, SkwasmObject imageBitmap)
Definition: surface.cpp:210
uint32_t rasterizeImage(SkImage *image, ImageByteFormat format)
Definition: surface.cpp:63
void renderPicturesOnWorker(sk_sp< SkPicture > *picture, int pictureCount, uint32_t callbackId, double rasterStart)
Definition: surface.cpp:151
uint32_t renderPictures(SkPicture **picture, int count)
Definition: surface.cpp:46
T * get() const
Definition: SkRefCnt.h:303
VkSurfaceKHR surface
Definition: main.cc:49
uint32_t uint32_t * format
uint32_t * target
static float max(float r, float g, float b)
Definition: hsl.cpp:49
SKWASM_EXPORT void surface_destroy(Surface *surface)
Definition: surface.cpp:247
SKWASM_EXPORT uint32_t surface_renderPictures(Surface *surface, SkPicture **pictures, int count)
Definition: surface.cpp:251
SKWASM_EXPORT void surface_renderPicturesOnWorker(Surface *surface, sk_sp< SkPicture > *pictures, int pictureCount, uint32_t callbackId, double rasterStart)
Definition: surface.cpp:257
SKWASM_EXPORT void surface_onRenderComplete(Surface *surface, uint32_t callbackId, SkwasmObject imageBitmap)
Definition: surface.cpp:277
SKWASM_EXPORT void surface_setCallbackHandler(Surface *surface, Surface::CallbackHandler *callbackHandler)
Definition: surface.cpp:241
SKWASM_EXPORT unsigned long surface_getThreadId(Surface *surface)
Definition: surface.cpp:237
SKWASM_EXPORT Surface * surface_create()
Definition: surface.cpp:233
SKWASM_EXPORT uint32_t surface_rasterizeImage(Surface *surface, SkImage *image, ImageByteFormat format)
Definition: surface.cpp:269
SK_API GrBackendRenderTarget MakeGL(int width, int height, int sampleCnt, int stencilBits, const GrGLFramebufferInfo &glInfo)
SK_API sk_sp< GrDirectContext > MakeGL(sk_sp< const GrGLInterface >, const GrContextOptions &)
SK_API sk_sp< const GrGLInterface > MakeWebGL()
unsigned useCenter Optional< SkMatrix > matrix
Definition: SkRecords.h:258
sk_sp< const SkImage > image
Definition: SkRecords.h:269
sk_sp< const SkPicture > picture
Definition: SkRecords.h:299
std::string printf(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: SkSLString.cpp:83
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)
Definition: helpers.h:12
void makeCurrent(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE handle)
Definition: wrappers.h:22
ImageByteFormat
Definition: surface.h:30
int32_t height
int32_t width
void skwasm_dispatchRenderPictures(unsigned long threadId, Skwasm::Surface *surface, sk_sp< SkPicture > *pictures, int count, uint32_t callbackId)
SkwasmObject skwasm_captureImageBitmap(uint32_t contextHandle, int width, int height, SkwasmObject imagePromises)
uint32_t skwasm_createOffscreenCanvas(int width, int height)
void skwasm_resizeCanvas(uint32_t contextHandle, int width, int height)
void skwasm_syncTimeOriginForThread(pthread_t threadId)
void skwasm_resolveAndPostImages(Skwasm::Surface *surface, SkwasmObject imagePromises, double rasterStart, uint32_t callbackId)
__externref_t SkwasmObject
void skwasm_registerMessageListener(pthread_t threadId)
Definition: SkRect.h:32
constexpr int32_t height() const
Definition: SkRect.h:165
int32_t fTop
smaller y-axis bounds
Definition: SkRect.h:34
constexpr int32_t width() const
Definition: SkRect.h:158
int32_t fLeft
smaller x-axis bounds
Definition: SkRect.h:33
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
void roundOut(SkIRect *dst) const
Definition: SkRect.h:1241
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63
#define SKWASM_EXPORT
Definition: export.h:10