Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
surface.cc
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
6
7#include <algorithm>
8
9#include <emscripten/wasm_worker.h>
10
15#include "third_party/skia/include/core/SkColorSpace.h"
16
20 } else {
21 assert(emscripten_is_main_browser_thread());
22
23 thread_ = emscripten_malloc_wasm_worker(65536);
24 emscripten_wasm_worker_post_function_v(thread_, []() {
25 // Listen to the main thread from the worker
27 });
28
29 // Listen to messages from the worker
30 skwasm_connectThread(thread_);
31 }
32}
33
34// Worker thread only
36 delete this;
37}
38
39// Main thread only
41 render_context_->SetResourceCacheLimit(bytes);
42}
43
44// Main thread only
46 int width,
47 int height,
48 int count) {
49 assert(emscripten_is_main_browser_thread());
50 uint32_t callback_id = ++current_callback_id_;
51 std::unique_ptr<sk_sp<flutter::DisplayList>[]> picture_pointers =
52 std::make_unique<sk_sp<flutter::DisplayList>[]>(count);
53 for (int i = 0; i < count; i++) {
54 picture_pointers[i] = sk_ref_sp(pictures[i]);
55 }
56
57 // Releasing picturePointers here and will recreate the unique_ptr on the
58 // other thread See surface_renderPicturesOnWorker
59 skwasm_dispatchRenderPictures(thread_, this, picture_pointers.release(),
60 width, height, count, callback_id);
61 return callback_id;
62}
63
64// Main thread only
67 assert(emscripten_is_main_browser_thread());
68 uint32_t callback_id = ++current_callback_id_;
69 image->ref();
70
71 skwasm_dispatchRasterizeImage(thread_, this, image, format, callback_id);
72 return callback_id;
73}
74
75std::unique_ptr<Skwasm::TextureSourceWrapper>
77 Skwasm::SkwasmObject texture_source) {
78 return std::unique_ptr<Skwasm::TextureSourceWrapper>(
79 new Skwasm::TextureSourceWrapper(thread_, texture_source));
80}
81
82// Main thread only
85 assert(emscripten_is_main_browser_thread());
86 callback_handler_ = callback_handler;
87}
88
89// Worker thread only
90void Skwasm::Surface::Init() {
91 // 256x256 is just an arbitrary size for the initial canvas, so that we can
92 // get a gl context off of it.
93 gl_context_ = skwasm_createOffscreenCanvas(256, 256);
94 if (!gl_context_) {
95 printf("Failed to create context!\n");
96 return;
97 }
98
99 Skwasm::makeCurrent(gl_context_);
100 emscripten_webgl_enable_extension(gl_context_, "WEBGL_debug_renderer_info");
101
102 // WebGL should already be clearing the color and stencil buffers, but do it
103 // again here to ensure Skia receives them in the expected state.
104 emscripten_glBindFramebuffer(GL_FRAMEBUFFER, 0);
105 emscripten_glClearColor(0, 0, 0, 0);
106 emscripten_glClearStencil(0);
107 emscripten_glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
108
109 int sample_count;
110 int stencil;
111 emscripten_glGetIntegerv(GL_SAMPLES, &sample_count);
112 emscripten_glGetIntegerv(GL_STENCIL_BITS, &stencil);
113
114 render_context_ = Skwasm::RenderContext::Make(sample_count, stencil);
115 render_context_->Resize(256, 256);
116
117 is_initialized_ = true;
118}
119
120// Worker thread only
121void Skwasm::Surface::ResizeSurface(int width, int height) {
122 if (width != canvas_width_ || height != canvas_height_) {
123 canvas_width_ = width;
124 canvas_height_ = height;
125 RecreateSurface();
126 }
127}
128
129// Worker thread only
130void Skwasm::Surface::RecreateSurface() {
131 Skwasm::makeCurrent(gl_context_);
132 skwasm_resizeCanvas(gl_context_, canvas_width_, canvas_height_);
133 render_context_->Resize(canvas_width_, canvas_height_);
134}
135
136// Worker thread only
138 sk_sp<flutter::DisplayList>* pictures,
139 int width,
140 int height,
141 int picture_count,
142 uint32_t callback_id,
143 double raster_start) {
144 if (!is_initialized_) {
145 Init();
146 }
147
148 // This is initialized on the first call to `skwasm_captureImageBitmap` and
149 // then populated with more bitmaps on subsequent calls.
150 Skwasm::SkwasmObject image_bitmap_array = __builtin_wasm_ref_null_extern();
151 for (int i = 0; i < picture_count; i++) {
152 sk_sp<flutter::DisplayList> picture = pictures[i];
153 ResizeSurface(width, height);
154 Skwasm::makeCurrent(gl_context_);
155
156 render_context_->RenderPicture(picture);
157
158 image_bitmap_array =
159 skwasm_captureImageBitmap(gl_context_, image_bitmap_array);
160 }
161 skwasm_resolveAndPostImages(this, image_bitmap_array, raster_start,
162 callback_id);
163}
164
165// Worker thread only
168 uint32_t callback_id) {
169 if (!is_initialized_) {
170 Init();
171 }
172
173 // We handle PNG encoding with browser APIs so that we can omit libpng from
174 // skia to save binary size.
177 ? SkAlphaType::kUnpremul_SkAlphaType
178 : SkAlphaType::kPremul_SkAlphaType;
179 SkImageInfo info = SkImageInfo::Make(image->width(), image->height(),
180 SkColorType::kRGBA_8888_SkColorType,
181 alpha_type, SkColorSpace::MakeSRGB());
182 sk_sp<SkData> data;
183 size_t bytes_per_row = 4 * image->width();
184 size_t byte_size = info.computeByteSize(bytes_per_row);
185 data = SkData::MakeUninitialized(byte_size);
186 uint8_t* pixels = reinterpret_cast<uint8_t*>(data->writable_data());
187
188 // TODO(jacksongardner):
189 // Normally we'd just call `readPixels` on the image. However, this doesn't
190 // actually work in some cases due to a skia bug. Instead, we just draw the
191 // image to our scratch canvas and grab the pixels out directly with
192 // `glReadPixels`. Once the skia bug is fixed, we should switch back to using
193 // `SkImage::readPixels` instead.
194 // See https://g-issues.skia.org/issues/349201915
195 ResizeSurface(image->width(), image->height());
196
197 render_context_->RenderImage(image, format);
198
199 emscripten_glReadPixels(0, 0, image->width(), image->height(), GL_RGBA,
200 GL_UNSIGNED_BYTE, reinterpret_cast<void*>(pixels));
201
202 image->unref();
203 skwasm_postRasterizeResult(this, data.release(), callback_id);
204}
205
206void Skwasm::Surface::OnRasterizeComplete(uint32_t callback_id, SkData* data) {
207 callback_handler_(callback_id, data, __builtin_wasm_ref_null_extern());
208}
209
210// Main thread only
211void Skwasm::Surface::OnRenderComplete(uint32_t callback_id,
212 Skwasm::SkwasmObject image_bitmap) {
213 assert(emscripten_is_main_browser_thread());
214 callback_handler_(callback_id, nullptr, image_bitmap);
215}
216
218 unsigned long thread_id,
219 Skwasm::SkwasmObject texture_source)
220 : raster_thread_id_(thread_id) {
221 skwasm_setAssociatedObjectOnThread(raster_thread_id_, this, texture_source);
222}
223
227
231
236
238 return surface->GetThreadId();
239}
240
246
249 // Dispatch to the worker
251}
252
254 // This should be called directly only on the worker
255 surface->Dispose();
256}
257
259 int bytes) {
260 surface->SetResourceCacheLimit(bytes);
261}
262
264 flutter::DisplayList** pictures,
265 int width,
266 int height,
267 int count) {
268 return surface->RenderPictures(pictures, width, height, count);
269}
270
272 Skwasm::Surface* surface,
273 sk_sp<flutter::DisplayList>* pictures,
274 int width,
275 int height,
276 int picture_count,
277 uint32_t callback_id,
278 double raster_start) {
279 // This will release the pictures when they leave scope.
280 std::unique_ptr<sk_sp<flutter::DisplayList>[]> pictures_pointer =
281 std::unique_ptr<sk_sp<flutter::DisplayList>[]>(pictures);
282 surface->RenderPicturesOnWorker(pictures, width, height, picture_count,
283 callback_id, raster_start);
284}
285
289 return surface->RasterizeImage(image, format);
290}
291
293 Skwasm::Surface* surface,
296 uint32_t callback_id) {
297 surface->RasterizeImageOnWorker(image, format, callback_id);
298}
299
300// This is used by the skwasm JS support code to call back into C++ when the
301// we finish creating the image bitmap, which is an asynchronous operation.
303 uint32_t callback_id,
304 Skwasm::SkwasmObject image_bitmap) {
305 surface->OnRenderComplete(callback_id, image_bitmap);
306}
307
309 SkData* data,
310 uint32_t callback_id) {
311 surface->OnRasterizeComplete(callback_id, data);
312}
313
static std::unique_ptr< RenderContext > Make(int sample_count, int stencil)
uint32_t RenderPictures(flutter::DisplayList **pictures, int width, int height, int count)
Definition surface.cc:45
std::unique_ptr< TextureSourceWrapper > CreateTextureSourceWrapper(SkwasmObject texture_source)
Definition surface.cc:76
void RenderPicturesOnWorker(sk_sp< flutter::DisplayList > *pictures, int width, int height, int picture_count, uint32_t callback_id, double raster_start)
Definition surface.cc:137
void RasterizeImageOnWorker(flutter::DlImage *image, ImageByteFormat format, uint32_t callback_id)
Definition surface.cc:166
void(uint32_t, void *, SkwasmObject) CallbackHandler
Definition surface.h:43
uint32_t RasterizeImage(flutter::DlImage *image, ImageByteFormat format)
Definition surface.cc:65
void OnRenderComplete(uint32_t callback_id, SkwasmObject image_bitmap)
Definition surface.cc:211
void OnRasterizeComplete(uint32_t callback_id, SkData *data)
Definition surface.cc:206
void Dispose()
Definition surface.cc:35
void SetCallbackHandler(CallbackHandler *callback_handler)
Definition surface.cc:83
void SetResourceCacheLimit(int bytes)
Definition surface.cc:40
SkwasmObject GetTextureSource()
Definition surface.cc:228
TextureSourceWrapper(unsigned long thread_id, SkwasmObject texture_source)
Definition surface.cc:217
Represents an image whose allocation is (usually) resident on device memory.
Definition dl_image.h:32
FlutterVulkanImage * image
VkSurfaceKHR surface
Definition main.cc:65
uint32_t uint32_t * format
CallbackHandler callback_handler
__externref_t SkwasmObject
Definition wrappers.h:18
void makeCurrent(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE handle)
Definition wrappers.h:26
uint32_t live_surface_count
ImageByteFormat
Definition helpers.h:75
int32_t height
int32_t width
uint32_t alpha_type
#define SKWASM_EXPORT
Definition export.h:10
SKWASM_EXPORT void surface_rasterizeImageOnWorker(Skwasm::Surface *surface, flutter::DlImage *image, Skwasm::ImageByteFormat format, uint32_t callback_id)
Definition surface.cc:292
SKWASM_EXPORT Skwasm::Surface * surface_create()
Definition surface.cc:232
SKWASM_EXPORT unsigned long surface_getThreadId(Skwasm::Surface *surface)
Definition surface.cc:237
SKWASM_EXPORT uint32_t surface_renderPictures(Skwasm::Surface *surface, flutter::DisplayList **pictures, int width, int height, int count)
Definition surface.cc:263
SKWASM_EXPORT void surface_destroy(Skwasm::Surface *surface)
Definition surface.cc:247
SKWASM_EXPORT void surface_onRasterizeComplete(Skwasm::Surface *surface, SkData *data, uint32_t callback_id)
Definition surface.cc:308
SKWASM_EXPORT void surface_setCallbackHandler(Skwasm::Surface *surface, Skwasm::Surface::CallbackHandler *callback_handler)
Definition surface.cc:241
SKWASM_EXPORT bool skwasm_isMultiThreaded()
Definition surface.cc:314
SKWASM_EXPORT void surface_onRenderComplete(Skwasm::Surface *surface, uint32_t callback_id, Skwasm::SkwasmObject image_bitmap)
Definition surface.cc:302
SKWASM_EXPORT uint32_t surface_rasterizeImage(Skwasm::Surface *surface, flutter::DlImage *image, Skwasm::ImageByteFormat format)
Definition surface.cc:286
SKWASM_EXPORT void surface_dispose(Skwasm::Surface *surface)
Definition surface.cc:253
SKWASM_EXPORT void surface_renderPicturesOnWorker(Skwasm::Surface *surface, sk_sp< flutter::DisplayList > *pictures, int width, int height, int picture_count, uint32_t callback_id, double raster_start)
Definition surface.cc:271
SKWASM_EXPORT void surface_setResourceCacheLimitBytes(Skwasm::Surface *surface, int bytes)
Definition surface.cc:258
void skwasm_resolveAndPostImages(Skwasm::Surface *surface, SkwasmObject image_bitmaps, double raster_start, uint32_t callback_id)
void skwasm_resizeCanvas(uint32_t context_handle, int width, int height)
SkwasmObject skwasm_getAssociatedObject(void *pointer)
uint32_t skwasm_createOffscreenCanvas(int width, int height)
SkwasmObject skwasm_captureImageBitmap(uint32_t context_handle, SkwasmObject image_bitmaps)
void skwasm_connectThread(pthread_t thread_id)
void skwasm_dispatchDisposeSurface(unsigned long thread_id, Skwasm::Surface *surface)
void skwasm_postRasterizeResult(Skwasm::Surface *surface, SkData *data, uint32_t callback_id)
void skwasm_dispatchRasterizeImage(unsigned long thread_id, Skwasm::Surface *surface, flutter::DlImage *image, Skwasm::ImageByteFormat format, uint32_t callback_id)
bool skwasm_isSingleThreaded()
void skwasm_disposeAssociatedObjectOnThread(unsigned long thread_id, void *pointer)
void skwasm_setAssociatedObjectOnThread(unsigned long thread_id, void *pointer, SkwasmObject object)
void skwasm_dispatchRenderPictures(unsigned long thread_id, Skwasm::Surface *surface, sk_sp< flutter::DisplayList > *pictures, int width, int height, int count, uint32_t callback_id)
std::shared_ptr< const fml::Mapping > data