Kevin Gu
4 年前
当前提交
ab9d2afd
共有 100 个文件被更改,包括 7081 次插入 和 1206 次删除
-
16com.unity.uiwidgets/Runtime/ui2/compositing.cs
-
21com.unity.uiwidgets/Runtime/ui2/hooks.cs
-
2com.unity.uiwidgets/Runtime/ui2/native_bindings.cs
-
43com.unity.uiwidgets/Runtime/ui2/painting.cs
-
93engine/Build.bee.cs
-
7engine/src/common/settings.h
-
10engine/src/engine.cc
-
14engine/src/flow/skia_gpu_object.cc
-
2engine/src/flow/skia_gpu_object.h
-
2engine/src/lib/ui/compositing/scene.cc
-
35engine/src/lib/ui/compositing/scene_builder.cc
-
2engine/src/lib/ui/compositing/scene_builder.h
-
49engine/src/lib/ui/painting/gradient.cc
-
7engine/src/lib/ui/painting/image_decoder.cc
-
13engine/src/lib/ui/painting/image_decoder.h
-
10engine/src/lib/ui/window/window.cc
-
2engine/src/lib/ui/window/window.h
-
62engine/src/runtime/mono_api.cc
-
4engine/src/runtime/mono_api.h
-
108engine/src/runtime/runtime_controller.cc
-
30engine/src/runtime/runtime_controller.h
-
2engine/src/runtime/runtime_delegate.h
-
8engine/src/shell/common/animator.cc
-
229engine/src/shell/common/engine.cc
-
15engine/src/shell/common/engine.h
-
622engine/src/shell/common/shell.cc
-
335engine/src/shell/common/shell.h
-
2engine/src/shell/common/vsync_waiter.h
-
3com.unity.uiwidgets/Runtime/engine2.meta
-
7engine/src/runtime/start_up.cc
-
9engine/src/runtime/start_up.h
-
194engine/src/shell/common/canvas_spy.cc
-
165engine/src/shell/common/canvas_spy.h
-
64engine/src/shell/common/run_configuration.cc
-
42engine/src/shell/common/run_configuration.h
-
24engine/third_party/Unity/IUnityUIWidgets.h
-
154com.unity.uiwidgets/Runtime/engine2/UIWidgetsPanel.cs
-
3com.unity.uiwidgets/Runtime/engine2/UIWidgetsPanel.cs.meta
-
48engine/src/assets/asset_manager.cc
-
35engine/src/assets/asset_manager.h
-
26engine/src/assets/asset_resolver.h
-
41engine/src/assets/directory_asset_bundle.cc
-
30engine/src/assets/directory_asset_bundle.h
-
14engine/src/shell/gpu/gpu_surface_delegate.h
-
328engine/src/shell/gpu/gpu_surface_gl.cc
-
68engine/src/shell/gpu/gpu_surface_gl.h
-
100engine/src/shell/gpu/gpu_surface_gl_delegate.cc
-
65engine/src/shell/gpu/gpu_surface_gl_delegate.h
-
90engine/src/shell/gpu/gpu_surface_software.cc
-
44engine/src/shell/gpu/gpu_surface_software.h
-
11engine/src/shell/gpu/gpu_surface_software_delegate.cc
-
22engine/src/shell/gpu/gpu_surface_software_delegate.h
-
1001engine/src/shell/platform/embedder/embedder.cc
-
459engine/src/shell/platform/embedder/embedder.h
-
252engine/src/shell/platform/embedder/embedder_engine.cc
-
84engine/src/shell/platform/embedder/embedder_engine.h
-
47engine/src/shell/platform/embedder/embedder_external_texture_gl.cc
-
43engine/src/shell/platform/embedder/embedder_external_texture_gl.h
-
98engine/src/shell/platform/embedder/embedder_external_view.cc
-
118engine/src/shell/platform/embedder/embedder_external_view.h
-
265engine/src/shell/platform/embedder/embedder_external_view_embedder.cc
-
77engine/src/shell/platform/embedder/embedder_external_view_embedder.h
-
205engine/src/shell/platform/embedder/embedder_layers.cc
-
46engine/src/shell/platform/embedder/embedder_layers.h
-
32engine/src/shell/platform/embedder/embedder_platform_message_response.cc
-
31engine/src/shell/platform/embedder/embedder_platform_message_response.h
-
35engine/src/shell/platform/embedder/embedder_render_target.cc
-
30engine/src/shell/platform/embedder/embedder_render_target.h
-
69engine/src/shell/platform/embedder/embedder_render_target_cache.cc
-
49engine/src/shell/platform/embedder/embedder_render_target_cache.h
-
9engine/src/shell/platform/embedder/embedder_surface.cc
-
25engine/src/shell/platform/embedder/embedder_surface.h
-
107engine/src/shell/platform/embedder/embedder_surface_gl.cc
-
73engine/src/shell/platform/embedder/embedder_surface_gl.h
-
110engine/src/shell/platform/embedder/embedder_surface_software.cc
-
51engine/src/shell/platform/embedder/embedder_surface_software.h
-
82engine/src/shell/platform/embedder/embedder_task_runner.cc
-
51engine/src/shell/platform/embedder/embedder_task_runner.h
-
206engine/src/shell/platform/embedder/embedder_thread_host.cc
-
40engine/src/shell/platform/embedder/embedder_thread_host.h
-
74engine/src/shell/platform/embedder/platform_view_embedder.cc
-
62engine/src/shell/platform/embedder/platform_view_embedder.h
-
39engine/src/shell/platform/embedder/vsync_waiter_embedder.cc
-
28engine/src/shell/platform/embedder/vsync_waiter_embedder.h
-
43engine/src/shell/platform/unity/gfx_worker_task_runner.cc
-
43engine/src/shell/platform/unity/gfx_worker_task_runner.h
-
281engine/src/shell/platform/unity/uiwidgets_panel.cc
-
55engine/src/shell/platform/unity/uiwidgets_panel.h
-
95engine/src/shell/platform/unity/uiwidgets_system.cc
-
69engine/src/shell/platform/unity/uiwidgets_system.h
-
231engine/src/shell/platform/unity/unity_surface_manager.cc
-
51engine/src/shell/platform/unity/unity_surface_manager.h
-
116engine/src/shell/platform/unity/win32_task_runner.cc
-
73engine/src/shell/platform/unity/win32_task_runner.h
|
|||
#pragma once |
|||
|
|||
#include <flutter/fml/concurrent_message_loop.h> |
|||
#include <flutter/fml/memory/weak_ptr.h> |
|||
|
|||
#include "common/task_runners.h" |
|||
#include "lib/ui/io_manager.h" |
|||
|
|||
public: |
|||
ImageDecoder( |
|||
TaskRunners runners, |
|||
std::shared_ptr<fml::ConcurrentTaskRunner> concurrent_task_runner, |
|||
fml::WeakPtr<IOManager> io_manager); |
|||
|
|||
fml::WeakPtr<ImageDecoder> GetWeakPtr() const; |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
fileFormatVersion: 2 |
|||
guid: ffb851d47f1449fa9ea328aa58f27be7 |
|||
timeCreated: 1597215228 |
|
|||
#include "start_up.h"
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
int64_t engine_main_enter_ts = 0; |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include <stdint.h> |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
extern int64_t engine_main_enter_ts; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#include "canvas_spy.h"
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
CanvasSpy::CanvasSpy(SkCanvas* target_canvas) { |
|||
SkISize canvas_size = target_canvas->getBaseLayerSize(); |
|||
n_way_canvas_ = |
|||
std::make_unique<SkNWayCanvas>(canvas_size.width(), canvas_size.height()); |
|||
did_draw_canvas_ = std::make_unique<DidDrawCanvas>(canvas_size.width(), |
|||
canvas_size.height()); |
|||
n_way_canvas_->addCanvas(target_canvas); |
|||
n_way_canvas_->addCanvas(did_draw_canvas_.get()); |
|||
} |
|||
|
|||
SkCanvas* CanvasSpy::GetSpyingCanvas() { return n_way_canvas_.get(); } |
|||
|
|||
DidDrawCanvas::DidDrawCanvas(int width, int height) |
|||
: SkCanvasVirtualEnforcer<SkNoDrawCanvas>(width, height) {} |
|||
|
|||
DidDrawCanvas::~DidDrawCanvas() {} |
|||
|
|||
void DidDrawCanvas::MarkDrawIfNonTransparentPaint(const SkPaint& paint) { |
|||
bool isTransparent = paint.getAlpha() == 0; |
|||
did_draw_ |= !isTransparent; |
|||
} |
|||
|
|||
bool CanvasSpy::DidDrawIntoCanvas() { |
|||
return did_draw_canvas_->DidDrawIntoCanvas(); |
|||
} |
|||
|
|||
bool DidDrawCanvas::DidDrawIntoCanvas() { return did_draw_; } |
|||
|
|||
void DidDrawCanvas::willSave() {} |
|||
|
|||
SkCanvas::SaveLayerStrategy DidDrawCanvas::getSaveLayerStrategy( |
|||
const SaveLayerRec& rec) { |
|||
return kNoLayer_SaveLayerStrategy; |
|||
} |
|||
|
|||
bool DidDrawCanvas::onDoSaveBehind(const SkRect* bounds) { return false; } |
|||
|
|||
void DidDrawCanvas::willRestore() {} |
|||
|
|||
void DidDrawCanvas::didConcat(const SkMatrix& matrix) {} |
|||
|
|||
void DidDrawCanvas::didConcat44(const SkM44&) {} |
|||
|
|||
void DidDrawCanvas::didScale(SkScalar, SkScalar) {} |
|||
|
|||
void DidDrawCanvas::didTranslate(SkScalar, SkScalar) {} |
|||
|
|||
void DidDrawCanvas::didSetMatrix(const SkMatrix& matrix) {} |
|||
|
|||
void DidDrawCanvas::onClipRect(const SkRect& rect, SkClipOp op, |
|||
ClipEdgeStyle edgeStyle) {} |
|||
|
|||
void DidDrawCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, |
|||
ClipEdgeStyle edgeStyle) {} |
|||
|
|||
void DidDrawCanvas::onClipPath(const SkPath& path, SkClipOp op, |
|||
ClipEdgeStyle edgeStyle) {} |
|||
|
|||
void DidDrawCanvas::onClipRegion(const SkRegion& deviceRgn, SkClipOp op) {} |
|||
|
|||
void DidDrawCanvas::onDrawPaint(const SkPaint& paint) { |
|||
MarkDrawIfNonTransparentPaint(paint); |
|||
} |
|||
|
|||
void DidDrawCanvas::onDrawBehind(const SkPaint& paint) { |
|||
MarkDrawIfNonTransparentPaint(paint); |
|||
} |
|||
|
|||
void DidDrawCanvas::onDrawPoints(PointMode mode, size_t count, |
|||
const SkPoint pts[], const SkPaint& paint) { |
|||
MarkDrawIfNonTransparentPaint(paint); |
|||
} |
|||
|
|||
void DidDrawCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) { |
|||
MarkDrawIfNonTransparentPaint(paint); |
|||
} |
|||
|
|||
void DidDrawCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) { |
|||
MarkDrawIfNonTransparentPaint(paint); |
|||
} |
|||
|
|||
void DidDrawCanvas::onDrawOval(const SkRect& rect, const SkPaint& paint) { |
|||
MarkDrawIfNonTransparentPaint(paint); |
|||
} |
|||
|
|||
void DidDrawCanvas::onDrawArc(const SkRect& rect, SkScalar startAngle, |
|||
SkScalar sweepAngle, bool useCenter, |
|||
const SkPaint& paint) { |
|||
MarkDrawIfNonTransparentPaint(paint); |
|||
} |
|||
|
|||
void DidDrawCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) { |
|||
MarkDrawIfNonTransparentPaint(paint); |
|||
} |
|||
|
|||
void DidDrawCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, |
|||
const SkPaint& paint) { |
|||
MarkDrawIfNonTransparentPaint(paint); |
|||
} |
|||
|
|||
void DidDrawCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) { |
|||
MarkDrawIfNonTransparentPaint(paint); |
|||
} |
|||
|
|||
void DidDrawCanvas::onDrawImage(const SkImage* image, SkScalar left, |
|||
SkScalar top, const SkPaint* paint) { |
|||
did_draw_ = true; |
|||
} |
|||
|
|||
void DidDrawCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, |
|||
const SkRect& dst, const SkPaint* paint, |
|||
SrcRectConstraint constraint) { |
|||
did_draw_ = true; |
|||
} |
|||
|
|||
void DidDrawCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, |
|||
const SkRect& dst, const SkPaint* paint) { |
|||
did_draw_ = true; |
|||
} |
|||
|
|||
void DidDrawCanvas::onDrawImageLattice(const SkImage* image, |
|||
const Lattice& lattice, |
|||
const SkRect& dst, |
|||
const SkPaint* paint) { |
|||
did_draw_ = true; |
|||
} |
|||
|
|||
void DidDrawCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, |
|||
SkScalar y, const SkPaint& paint) { |
|||
MarkDrawIfNonTransparentPaint(paint); |
|||
} |
|||
|
|||
void DidDrawCanvas::onDrawPicture(const SkPicture* picture, |
|||
const SkMatrix* matrix, |
|||
const SkPaint* paint) { |
|||
did_draw_ = true; |
|||
} |
|||
|
|||
void DidDrawCanvas::onDrawDrawable(SkDrawable* drawable, |
|||
const SkMatrix* matrix) { |
|||
did_draw_ = true; |
|||
} |
|||
|
|||
void DidDrawCanvas::onDrawVerticesObject(const SkVertices* vertices, |
|||
SkBlendMode bmode, |
|||
const SkPaint& paint) { |
|||
MarkDrawIfNonTransparentPaint(paint); |
|||
} |
|||
|
|||
void DidDrawCanvas::onDrawPatch(const SkPoint cubics[12], |
|||
const SkColor colors[4], |
|||
const SkPoint texCoords[4], SkBlendMode bmode, |
|||
const SkPaint& paint) { |
|||
MarkDrawIfNonTransparentPaint(paint); |
|||
} |
|||
|
|||
void DidDrawCanvas::onDrawAtlas(const SkImage* image, const SkRSXform xform[], |
|||
const SkRect tex[], const SkColor colors[], |
|||
int count, SkBlendMode bmode, |
|||
const SkRect* cull, const SkPaint* paint) { |
|||
did_draw_ = true; |
|||
} |
|||
|
|||
void DidDrawCanvas::onDrawShadowRec(const SkPath& path, |
|||
const SkDrawShadowRec& rec) { |
|||
did_draw_ = true; |
|||
} |
|||
|
|||
void DidDrawCanvas::onDrawAnnotation(const SkRect& rect, const char key[], |
|||
SkData* data) { |
|||
did_draw_ = true; |
|||
} |
|||
|
|||
void DidDrawCanvas::onDrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4], |
|||
SkCanvas::QuadAAFlags aa, |
|||
const SkColor4f& color, SkBlendMode mode) { |
|||
did_draw_ = true; |
|||
} |
|||
|
|||
void DidDrawCanvas::onDrawEdgeAAImageSet(const ImageSetEntry set[], int count, |
|||
const SkPoint dstClips[], |
|||
const SkMatrix preViewMatrices[], |
|||
const SkPaint* paint, |
|||
SrcRectConstraint constraint) { |
|||
did_draw_ = true; |
|||
} |
|||
|
|||
void DidDrawCanvas::onFlush() {} |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include "flutter/fml/macros.h" |
|||
#include "include/core/SkCanvas.h" |
|||
#include "include/core/SkCanvasVirtualEnforcer.h" |
|||
#include "include/utils/SkNWayCanvas.h" |
|||
#include "include/utils/SkNoDrawCanvas.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class DidDrawCanvas; |
|||
|
|||
class CanvasSpy { |
|||
public: |
|||
CanvasSpy(SkCanvas* target_canvas); |
|||
|
|||
bool DidDrawIntoCanvas(); |
|||
|
|||
SkCanvas* GetSpyingCanvas(); |
|||
|
|||
private: |
|||
std::unique_ptr<SkNWayCanvas> n_way_canvas_; |
|||
std::unique_ptr<DidDrawCanvas> did_draw_canvas_; |
|||
|
|||
FML_DISALLOW_COPY_AND_ASSIGN(CanvasSpy); |
|||
}; |
|||
|
|||
class DidDrawCanvas final : public SkCanvasVirtualEnforcer<SkNoDrawCanvas> { |
|||
public: |
|||
DidDrawCanvas(int width, int height); |
|||
~DidDrawCanvas() override; |
|||
bool DidDrawIntoCanvas(); |
|||
|
|||
private: |
|||
bool did_draw_ = false; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
void willSave() override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
bool onDoSaveBehind(const SkRect*) override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
void willRestore() override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
void didConcat(const SkMatrix&) override; |
|||
void didConcat44(const SkM44&) override; |
|||
void didScale(SkScalar, SkScalar) override; |
|||
void didTranslate(SkScalar, SkScalar) override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
void didSetMatrix(const SkMatrix&) override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
virtual void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, |
|||
const SkPaint& paint) override; |
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], |
|||
const SkPoint texCoords[4], SkBlendMode, |
|||
const SkPaint& paint) override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
void onDrawPaint(const SkPaint&) override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
void onDrawBehind(const SkPaint&) override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
void onDrawPoints(PointMode, size_t count, const SkPoint pts[], |
|||
const SkPaint&) override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
void onDrawRect(const SkRect&, const SkPaint&) override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
void onDrawRegion(const SkRegion&, const SkPaint&) override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
void onDrawOval(const SkRect&, const SkPaint&) override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
void onDrawArc(const SkRect&, SkScalar, SkScalar, bool, |
|||
const SkPaint&) override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
void onDrawRRect(const SkRRect&, const SkPaint&) override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
void onDrawPath(const SkPath&, const SkPaint&) override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
void onDrawImage(const SkImage*, SkScalar left, SkScalar top, |
|||
const SkPaint*) override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst, |
|||
const SkPaint*, SrcRectConstraint) override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
void onDrawImageLattice(const SkImage*, const Lattice&, const SkRect&, |
|||
const SkPaint*) override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst, |
|||
const SkPaint*) override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
void onDrawVerticesObject(const SkVertices*, SkBlendMode, |
|||
const SkPaint&) override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], |
|||
const SkColor[], int, SkBlendMode, const SkRect*, |
|||
const SkPaint*) override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
void onClipPath(const SkPath&, SkClipOp, ClipEdgeStyle) override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
void onClipRegion(const SkRegion&, SkClipOp) override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
void onDrawPicture(const SkPicture*, const SkMatrix*, |
|||
const SkPaint*) override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
void onDrawDrawable(SkDrawable*, const SkMatrix*) override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
void onDrawAnnotation(const SkRect&, const char[], SkData*) override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
void onDrawEdgeAAQuad(const SkRect&, const SkPoint[4], SkCanvas::QuadAAFlags, |
|||
const SkColor4f&, SkBlendMode) override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
void onDrawEdgeAAImageSet(const ImageSetEntry[], int count, const SkPoint[], |
|||
const SkMatrix[], const SkPaint*, |
|||
SrcRectConstraint) override; |
|||
|
|||
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>| |
|||
void onFlush() override; |
|||
|
|||
void MarkDrawIfNonTransparentPaint(const SkPaint& paint); |
|||
|
|||
FML_DISALLOW_COPY_AND_ASSIGN(DidDrawCanvas); |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#include "run_configuration.h"
|
|||
|
|||
#include <sstream>
|
|||
#include <utility>
|
|||
|
|||
#include "assets/directory_asset_bundle.h"
|
|||
#include "flutter/fml/file.h"
|
|||
#include "flutter/fml/unique_fd.h"
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
RunConfiguration RunConfiguration::InferFromSettings(const Settings& settings) { |
|||
auto asset_manager = std::make_shared<AssetManager>(); |
|||
|
|||
if (fml::UniqueFD::traits_type::IsValid(settings.assets_dir)) { |
|||
asset_manager->PushBack(std::make_unique<DirectoryAssetBundle>( |
|||
fml::Duplicate(settings.assets_dir))); |
|||
} |
|||
|
|||
asset_manager->PushBack( |
|||
std::make_unique<DirectoryAssetBundle>(fml::OpenDirectory( |
|||
settings.assets_path.c_str(), false, fml::FilePermission::kRead))); |
|||
|
|||
return {asset_manager, settings.mono_entrypoint_callback}; |
|||
} |
|||
|
|||
RunConfiguration::RunConfiguration() |
|||
: RunConfiguration(std::make_shared<AssetManager>(), fml::closure()) {} |
|||
|
|||
RunConfiguration::RunConfiguration(std::shared_ptr<AssetManager> asset_manager, |
|||
fml::closure mono_entrypoint_callback) |
|||
: asset_manager_(std::move(asset_manager)), |
|||
mono_entrypoint_callback_(std::move(mono_entrypoint_callback)) {} |
|||
|
|||
RunConfiguration::RunConfiguration(RunConfiguration&&) = default; |
|||
|
|||
RunConfiguration::~RunConfiguration() = default; |
|||
|
|||
bool RunConfiguration::IsValid() const { |
|||
return static_cast<bool>(asset_manager_); |
|||
} |
|||
|
|||
bool RunConfiguration::AddAssetResolver( |
|||
std::unique_ptr<AssetResolver> resolver) { |
|||
if (!resolver || !resolver->IsValid()) { |
|||
return false; |
|||
} |
|||
|
|||
asset_manager_->PushBack(std::move(resolver)); |
|||
return true; |
|||
} |
|||
|
|||
std::shared_ptr<AssetManager> RunConfiguration::GetAssetManager() const { |
|||
return asset_manager_; |
|||
} |
|||
|
|||
void RunConfiguration::SetMonoEntrypointCallback(fml::closure mono_entrypoint_callback) { |
|||
mono_entrypoint_callback_ = std::move(mono_entrypoint_callback); |
|||
} |
|||
|
|||
fml::closure RunConfiguration::GetMonoEntrypointCallback() const { |
|||
return mono_entrypoint_callback_; |
|||
} |
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include <memory> |
|||
#include <string> |
|||
|
|||
#include "assets/asset_manager.h" |
|||
#include "assets/asset_resolver.h" |
|||
#include "common/settings.h" |
|||
#include "flutter/fml/macros.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class RunConfiguration { |
|||
public: |
|||
static RunConfiguration InferFromSettings(const Settings& settings); |
|||
|
|||
RunConfiguration(); |
|||
|
|||
RunConfiguration(std::shared_ptr<AssetManager> asset_manager, fml::closure mono_entrypoint_callback); |
|||
|
|||
RunConfiguration(RunConfiguration&& config); |
|||
|
|||
~RunConfiguration(); |
|||
|
|||
bool IsValid() const; |
|||
|
|||
bool AddAssetResolver(std::unique_ptr<AssetResolver> resolver); |
|||
|
|||
std::shared_ptr<AssetManager> GetAssetManager() const; |
|||
|
|||
void SetMonoEntrypointCallback(fml::closure mono_entrypoint_callback); |
|||
|
|||
fml::closure GetMonoEntrypointCallback() const; |
|||
|
|||
private: |
|||
std::shared_ptr<AssetManager> asset_manager_; |
|||
fml::closure mono_entrypoint_callback_; |
|||
|
|||
FML_DISALLOW_COPY_AND_ASSIGN(RunConfiguration); |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#pragma once |
|||
|
|||
#include "IUnityInterface.h" |
|||
#include "IUnityGraphics.h" |
|||
|
|||
namespace UnityUIWidgets { |
|||
typedef void (*VoidCallback)(); |
|||
typedef void (*VoidCallbackLong)(long); |
|||
|
|||
UNITY_DECLARE_INTERFACE(IUnityUIWidgets) { |
|||
virtual ~IUnityUIWidgets() {} |
|||
|
|||
virtual void SetUpdateCallback(VoidCallback callback) = 0; |
|||
virtual void SetVSyncCallback(VoidCallback callback) = 0; |
|||
virtual void SetWaitCallback(VoidCallbackLong callback) = 0; |
|||
virtual void SetWakeUpCallback(VoidCallback callback) = 0; |
|||
virtual void IssuePluginEventAndData(UnityRenderingEventAndData callback, |
|||
int eventId, void* data) = 0; |
|||
}; |
|||
} // namespace UnityUIWidgets |
|||
|
|||
UNITY_REGISTER_INTERFACE_GUID_IN_NAMESPACE(0x4C8BE8056B3C41D7ULL, |
|||
0xBC8BF5F2F0AC3532ULL, |
|||
IUnityUIWidgets, UnityUIWidgets) |
|
|||
using System; |
|||
using System.Runtime.InteropServices; |
|||
using AOT; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.ui2; |
|||
using UnityEngine; |
|||
using UnityEngine.UI; |
|||
using NativeBindings = Unity.UIWidgets.ui2.NativeBindings; |
|||
|
|||
namespace Unity.UIWidgets.engine2 { |
|||
public class UIWidgetsPanel : RawImage { |
|||
public IntPtr isolate { get; private set; } |
|||
|
|||
IntPtr _ptr; |
|||
GCHandle _handle; |
|||
|
|||
RenderTexture _renderTexture; |
|||
int _width; |
|||
int _height; |
|||
float _devicePixelRatio; |
|||
|
|||
int _currentWidth { |
|||
get { return Mathf.RoundToInt(rectTransform.rect.width * canvas.scaleFactor); } |
|||
} |
|||
|
|||
int _currentHeight { |
|||
get { return Mathf.RoundToInt(rectTransform.rect.height * canvas.scaleFactor); } |
|||
} |
|||
|
|||
float _currentDevicePixelRatio { |
|||
get { |
|||
float currentDpi = Screen.dpi; |
|||
if (currentDpi == 0) { |
|||
currentDpi = canvas.GetComponent<CanvasScaler>().fallbackScreenDPI; |
|||
} |
|||
|
|||
return currentDpi / 96; |
|||
} |
|||
} |
|||
|
|||
protected override void OnEnable() { |
|||
base.OnEnable(); |
|||
|
|||
_recreateRenderTexture(_currentWidth, _currentHeight, _currentDevicePixelRatio); |
|||
|
|||
_handle = GCHandle.Alloc(this); |
|||
|
|||
_ptr = UIWidgetsPanel_constructor((IntPtr) _handle, UIWidgetsPanel_entrypoint); |
|||
UIWidgetsPanel_onEnable(_ptr, _renderTexture.GetNativeTexturePtr(), |
|||
_width, _height, _devicePixelRatio); |
|||
} |
|||
|
|||
protected virtual void main() { |
|||
} |
|||
|
|||
public void entryPoint() { |
|||
try { |
|||
isolate = Isolate.current; |
|||
main(); |
|||
} |
|||
catch (Exception ex) { |
|||
Debug.LogException(new Exception("exception in main", ex)); |
|||
} |
|||
} |
|||
|
|||
protected override void OnRectTransformDimensionsChange() { |
|||
if (_ptr != IntPtr.Zero) { |
|||
if (_recreateRenderTexture(_currentWidth, _currentHeight, _currentDevicePixelRatio)) { |
|||
UIWidgetsPanel_onRenderTexture(_ptr, |
|||
_renderTexture.GetNativeTexturePtr(), |
|||
_width, _height, _devicePixelRatio); |
|||
} |
|||
} |
|||
} |
|||
|
|||
protected override void OnDisable() { |
|||
UIWidgetsPanel_onDisable(_ptr); |
|||
UIWidgetsPanel_dispose(_ptr); |
|||
_ptr = IntPtr.Zero; |
|||
|
|||
_handle.Free(); |
|||
_handle = default; |
|||
|
|||
base.OnDisable(); |
|||
} |
|||
|
|||
bool _recreateRenderTexture(int width, int height, float devicePixelRatio) { |
|||
if (_renderTexture != null && _width == width && _height == height && |
|||
_devicePixelRatio == devicePixelRatio) { |
|||
return false; |
|||
} |
|||
|
|||
if (_renderTexture) { |
|||
_destroyRenderTexture(); |
|||
} |
|||
|
|||
_createRenderTexture(width, height, devicePixelRatio); |
|||
return true; |
|||
} |
|||
|
|||
void _createRenderTexture(int width, int height, float devicePixelRatio) { |
|||
D.assert(_renderTexture == null); |
|||
|
|||
var desc = new RenderTextureDescriptor( |
|||
width, height, RenderTextureFormat.ARGB32, 0) { |
|||
useMipMap = false, |
|||
autoGenerateMips = false, |
|||
}; |
|||
|
|||
_renderTexture = new RenderTexture(desc) {hideFlags = HideFlags.HideAndDontSave}; |
|||
_renderTexture.Create(); |
|||
|
|||
_width = width; |
|||
_height = height; |
|||
_devicePixelRatio = devicePixelRatio; |
|||
|
|||
texture = _renderTexture; |
|||
} |
|||
|
|||
void _destroyRenderTexture() { |
|||
D.assert(_renderTexture != null); |
|||
texture = null; |
|||
ObjectUtils.SafeDestroy(_renderTexture); |
|||
_renderTexture = null; |
|||
} |
|||
|
|||
delegate void UIWidgetsPanel_EntrypointCallback(IntPtr handle); |
|||
|
|||
[MonoPInvokeCallback(typeof(UIWidgetsPanel_EntrypointCallback))] |
|||
static void UIWidgetsPanel_entrypoint(IntPtr handle) { |
|||
GCHandle gcHandle = (GCHandle) handle; |
|||
UIWidgetsPanel panel = (UIWidgetsPanel) gcHandle.Target; |
|||
panel.entryPoint(); |
|||
} |
|||
|
|||
[DllImport(NativeBindings.dllName)] |
|||
static extern IntPtr UIWidgetsPanel_constructor(IntPtr handle, |
|||
UIWidgetsPanel_EntrypointCallback entrypointCallback); |
|||
|
|||
[DllImport(NativeBindings.dllName)] |
|||
static extern void UIWidgetsPanel_dispose(IntPtr ptr); |
|||
|
|||
[DllImport(NativeBindings.dllName)] |
|||
static extern void UIWidgetsPanel_onEnable(IntPtr ptr, |
|||
IntPtr nativeTexturePtr, int width, int height, float dpi); |
|||
|
|||
[DllImport(NativeBindings.dllName)] |
|||
static extern void UIWidgetsPanel_onDisable(IntPtr ptr); |
|||
|
|||
[DllImport(NativeBindings.dllName)] |
|||
static extern void UIWidgetsPanel_onRenderTexture( |
|||
IntPtr ptr, IntPtr nativeTexturePtr, int width, int height, float dpi); |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 305c123a2a944eba8f2b397a962323ff |
|||
timeCreated: 1597215247 |
|
|||
#include "asset_manager.h"
|
|||
|
|||
#include "flutter/fml/trace_event.h"
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
AssetManager::AssetManager() = default; |
|||
|
|||
AssetManager::~AssetManager() = default; |
|||
|
|||
void AssetManager::PushFront(std::unique_ptr<AssetResolver> resolver) { |
|||
if (resolver == nullptr || !resolver->IsValid()) { |
|||
return; |
|||
} |
|||
|
|||
resolvers_.push_front(std::move(resolver)); |
|||
} |
|||
|
|||
void AssetManager::PushBack(std::unique_ptr<AssetResolver> resolver) { |
|||
if (resolver == nullptr || !resolver->IsValid()) { |
|||
return; |
|||
} |
|||
|
|||
resolvers_.push_back(std::move(resolver)); |
|||
} |
|||
|
|||
// |AssetResolver|
|
|||
std::unique_ptr<fml::Mapping> AssetManager::GetAsMapping( |
|||
const std::string& asset_name) const { |
|||
if (asset_name.empty()) { |
|||
return std::unique_ptr<fml::Mapping>(nullptr); |
|||
} |
|||
TRACE_EVENT1("uiwidgets", "AssetManager::GetAsMapping", "name", |
|||
asset_name.c_str()); |
|||
for (const auto& resolver : resolvers_) { |
|||
auto mapping = resolver->GetAsMapping(asset_name); |
|||
if (mapping != nullptr) { |
|||
return mapping; |
|||
} |
|||
} |
|||
FML_DLOG(WARNING) << "Could not find asset: " << asset_name; |
|||
return std::unique_ptr<fml::Mapping>(nullptr); |
|||
} |
|||
|
|||
// |AssetResolver|
|
|||
bool AssetManager::IsValid() const { return !resolvers_.empty(); } |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include <deque> |
|||
#include <memory> |
|||
#include <string> |
|||
|
|||
#include "asset_resolver.h" |
|||
#include "flutter/fml/macros.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class AssetManager final : public AssetResolver { |
|||
public: |
|||
AssetManager(); |
|||
|
|||
~AssetManager() override; |
|||
|
|||
void PushFront(std::unique_ptr<AssetResolver> resolver); |
|||
|
|||
void PushBack(std::unique_ptr<AssetResolver> resolver); |
|||
|
|||
// |AssetResolver| |
|||
bool IsValid() const override; |
|||
|
|||
// |AssetResolver| |
|||
std::unique_ptr<fml::Mapping> GetAsMapping( |
|||
const std::string& asset_name) const override; |
|||
|
|||
private: |
|||
std::deque<std::unique_ptr<AssetResolver>> resolvers_; |
|||
|
|||
FML_DISALLOW_COPY_AND_ASSIGN(AssetManager); |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#pragma once |
|||
|
|||
#include <string> |
|||
#include <vector> |
|||
|
|||
#include "flutter/fml/macros.h" |
|||
#include "flutter/fml/mapping.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class AssetResolver { |
|||
public: |
|||
AssetResolver() = default; |
|||
|
|||
virtual ~AssetResolver() = default; |
|||
|
|||
virtual bool IsValid() const = 0; |
|||
|
|||
[[nodiscard]] virtual std::unique_ptr<fml::Mapping> GetAsMapping( |
|||
const std::string& asset_name) const = 0; |
|||
|
|||
private: |
|||
FML_DISALLOW_COPY_AND_ASSIGN(AssetResolver); |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#include "directory_asset_bundle.h"
|
|||
|
|||
#include <utility>
|
|||
|
|||
#include "flutter/fml/file.h"
|
|||
#include "flutter/fml/mapping.h"
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
DirectoryAssetBundle::DirectoryAssetBundle(fml::UniqueFD descriptor) |
|||
: descriptor_(std::move(descriptor)) { |
|||
if (!fml::IsDirectory(descriptor_)) { |
|||
return; |
|||
} |
|||
is_valid_ = true; |
|||
} |
|||
|
|||
DirectoryAssetBundle::~DirectoryAssetBundle() = default; |
|||
|
|||
// |AssetResolver|
|
|||
bool DirectoryAssetBundle::IsValid() const { return is_valid_; } |
|||
|
|||
// |AssetResolver|
|
|||
std::unique_ptr<fml::Mapping> DirectoryAssetBundle::GetAsMapping( |
|||
const std::string& asset_name) const { |
|||
if (!is_valid_) { |
|||
FML_DLOG(WARNING) << "Asset bundle was not valid."; |
|||
return std::unique_ptr<fml::Mapping>(nullptr); |
|||
} |
|||
|
|||
auto mapping = std::make_unique<fml::FileMapping>(fml::OpenFile( |
|||
descriptor_, asset_name.c_str(), false, fml::FilePermission::kRead)); |
|||
|
|||
if (!mapping->IsValid()) { |
|||
return std::unique_ptr<fml::Mapping>(nullptr); |
|||
} |
|||
|
|||
return mapping; |
|||
} |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include "asset_resolver.h" |
|||
#include "flutter/fml/macros.h" |
|||
#include "flutter/fml/memory/ref_counted.h" |
|||
#include "flutter/fml/unique_fd.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class DirectoryAssetBundle : public AssetResolver { |
|||
public: |
|||
explicit DirectoryAssetBundle(fml::UniqueFD descriptor); |
|||
|
|||
~DirectoryAssetBundle() override; |
|||
|
|||
private: |
|||
const fml::UniqueFD descriptor_; |
|||
bool is_valid_ = false; |
|||
|
|||
// |AssetResolver| |
|||
bool IsValid() const override; |
|||
|
|||
// |AssetResolver| |
|||
std::unique_ptr<fml::Mapping> GetAsMapping( |
|||
const std::string& asset_name) const override; |
|||
|
|||
FML_DISALLOW_COPY_AND_ASSIGN(DirectoryAssetBundle); |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#pragma once |
|||
|
|||
#include "flow/embedded_views.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class GPUSurfaceDelegate { |
|||
public: |
|||
virtual ~GPUSurfaceDelegate() {} |
|||
|
|||
virtual ExternalViewEmbedder* GetExternalViewEmbedder() = 0; |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#include "gpu_surface_gl.h"
|
|||
|
|||
#include "flutter/fml/base32.h"
|
|||
#include "flutter/fml/logging.h"
|
|||
#include "flutter/fml/size.h"
|
|||
#include "flutter/fml/trace_event.h"
|
|||
#include "include/core/SkColorFilter.h"
|
|||
#include "include/core/SkSurface.h"
|
|||
#include "include/gpu/GrBackendSurface.h"
|
|||
#include "include/gpu/GrContextOptions.h"
|
|||
#include "shell/common/persistent_cache.h"
|
|||
|
|||
// These are common defines present on all OpenGL headers. However, we don't
|
|||
// want to perform GL header reasolution on each platform we support. So just
|
|||
// define these upfront. It is unlikely we will need more. But, if we do, we can
|
|||
// add the same here.
|
|||
#define GPU_GL_RGBA8 0x8058
|
|||
#define GPU_GL_RGBA4 0x8056
|
|||
#define GPU_GL_RGB565 0x8D62
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
// Default maximum number of budgeted resources in the cache.
|
|||
static const int kGrCacheMaxCount = 8192; |
|||
|
|||
// Default maximum number of bytes of GPU memory of budgeted resources in the
|
|||
// cache.
|
|||
// The shell will dynamically increase or decrease this cache based on the
|
|||
// viewport size, unless a user has specifically requested a size on the Skia
|
|||
// system channel.
|
|||
static const size_t kGrCacheMaxByteSize = 24 * (1 << 20); |
|||
|
|||
GPUSurfaceGL::GPUSurfaceGL(GPUSurfaceGLDelegate* delegate, |
|||
bool render_to_surface) |
|||
: delegate_(delegate), |
|||
render_to_surface_(render_to_surface), |
|||
weak_factory_(this) { |
|||
if (!delegate_->GLContextMakeCurrent()) { |
|||
FML_LOG(ERROR) |
|||
<< "Could not make the context current to setup the gr context."; |
|||
return; |
|||
} |
|||
|
|||
GrContextOptions options; |
|||
|
|||
if (PersistentCache::cache_sksl()) { |
|||
FML_LOG(INFO) << "Cache SkSL"; |
|||
options.fShaderCacheStrategy = GrContextOptions::ShaderCacheStrategy::kSkSL; |
|||
} |
|||
PersistentCache::MarkStrategySet(); |
|||
options.fPersistentCache = PersistentCache::GetCacheForProcess(); |
|||
|
|||
options.fAvoidStencilBuffers = true; |
|||
|
|||
// To get video playback on the widest range of devices, we limit Skia to
|
|||
// ES2 shading language when the ES3 external image extension is missing.
|
|||
options.fPreferExternalImagesOverES3 = true; |
|||
|
|||
// TODO(goderbauer): remove option when skbug.com/7523 is fixed.
|
|||
// A similar work-around is also used in shell/common/io_manager.cc.
|
|||
options.fDisableGpuYUVConversion = true; |
|||
|
|||
auto context = GrContext::MakeGL(delegate_->GetGLInterface(), options); |
|||
|
|||
if (context == nullptr) { |
|||
FML_LOG(ERROR) << "Failed to setup Skia Gr context."; |
|||
return; |
|||
} |
|||
|
|||
context_ = std::move(context); |
|||
|
|||
context_->setResourceCacheLimits(kGrCacheMaxCount, kGrCacheMaxByteSize); |
|||
|
|||
context_owner_ = true; |
|||
|
|||
valid_ = true; |
|||
|
|||
std::vector<PersistentCache::SkSLCache> caches = |
|||
PersistentCache::GetCacheForProcess()->LoadSkSLs(); |
|||
int compiled_count = 0; |
|||
for (const auto& cache : caches) { |
|||
compiled_count += context_->precompileShader(*cache.first, *cache.second); |
|||
} |
|||
FML_LOG(INFO) << "Found " << caches.size() << " SkSL shaders; precompiled " |
|||
<< compiled_count; |
|||
|
|||
delegate_->GLContextClearCurrent(); |
|||
} |
|||
|
|||
GPUSurfaceGL::GPUSurfaceGL(sk_sp<GrContext> gr_context, |
|||
GPUSurfaceGLDelegate* delegate, |
|||
bool render_to_surface) |
|||
: delegate_(delegate), |
|||
context_(gr_context), |
|||
render_to_surface_(render_to_surface), |
|||
weak_factory_(this) { |
|||
if (!delegate_->GLContextMakeCurrent()) { |
|||
FML_LOG(ERROR) |
|||
<< "Could not make the context current to setup the gr context."; |
|||
return; |
|||
} |
|||
|
|||
delegate_->GLContextClearCurrent(); |
|||
|
|||
valid_ = true; |
|||
context_owner_ = false; |
|||
} |
|||
|
|||
GPUSurfaceGL::~GPUSurfaceGL() { |
|||
if (!valid_) { |
|||
return; |
|||
} |
|||
|
|||
if (!delegate_->GLContextMakeCurrent()) { |
|||
FML_LOG(ERROR) << "Could not make the context current to destroy the " |
|||
"GrContext resources."; |
|||
return; |
|||
} |
|||
|
|||
onscreen_surface_ = nullptr; |
|||
if (context_owner_) { |
|||
context_->releaseResourcesAndAbandonContext(); |
|||
} |
|||
context_ = nullptr; |
|||
|
|||
delegate_->GLContextClearCurrent(); |
|||
} |
|||
|
|||
// |Surface|
|
|||
bool GPUSurfaceGL::IsValid() { return valid_; } |
|||
|
|||
static SkColorType FirstSupportedColorType(GrContext* context, |
|||
GrGLenum* format) { |
|||
#define RETURN_IF_RENDERABLE(x, y) \
|
|||
if (context->colorTypeSupportedAsSurface((x))) { \ |
|||
*format = (y); \ |
|||
return (x); \ |
|||
} |
|||
RETURN_IF_RENDERABLE(kRGBA_8888_SkColorType, GPU_GL_RGBA8); |
|||
RETURN_IF_RENDERABLE(kARGB_4444_SkColorType, GPU_GL_RGBA4); |
|||
RETURN_IF_RENDERABLE(kRGB_565_SkColorType, GPU_GL_RGB565); |
|||
return kUnknown_SkColorType; |
|||
} |
|||
|
|||
static sk_sp<SkSurface> WrapOnscreenSurface(GrContext* context, |
|||
const SkISize& size, intptr_t fbo) { |
|||
GrGLenum format; |
|||
const SkColorType color_type = FirstSupportedColorType(context, &format); |
|||
|
|||
GrGLFramebufferInfo framebuffer_info = {}; |
|||
framebuffer_info.fFBOID = static_cast<GrGLuint>(fbo); |
|||
framebuffer_info.fFormat = format; |
|||
|
|||
GrBackendRenderTarget render_target(size.width(), // width
|
|||
size.height(), // height
|
|||
0, // sample count
|
|||
0, // stencil bits (TODO)
|
|||
framebuffer_info // framebuffer info
|
|||
); |
|||
|
|||
sk_sp<SkColorSpace> colorspace = SkColorSpace::MakeSRGB(); |
|||
|
|||
SkSurfaceProps surface_props( |
|||
SkSurfaceProps::InitType::kLegacyFontHost_InitType); |
|||
|
|||
return SkSurface::MakeFromBackendRenderTarget( |
|||
context, // gr context
|
|||
render_target, // render target
|
|||
GrSurfaceOrigin::kBottomLeft_GrSurfaceOrigin, // origin
|
|||
color_type, // color type
|
|||
colorspace, // colorspace
|
|||
&surface_props // surface properties
|
|||
); |
|||
} |
|||
|
|||
bool GPUSurfaceGL::CreateOrUpdateSurfaces(const SkISize& size) { |
|||
if (onscreen_surface_ != nullptr && |
|||
size == SkISize::Make(onscreen_surface_->width(), |
|||
onscreen_surface_->height())) { |
|||
// Surface size appears unchanged. So bail.
|
|||
return true; |
|||
} |
|||
|
|||
// We need to do some updates.
|
|||
TRACE_EVENT0("uiwidgets", "UpdateSurfacesSize"); |
|||
|
|||
// Either way, we need to get rid of previous surface.
|
|||
onscreen_surface_ = nullptr; |
|||
|
|||
if (size.isEmpty()) { |
|||
FML_LOG(ERROR) << "Cannot create surfaces of empty size."; |
|||
return false; |
|||
} |
|||
|
|||
sk_sp<SkSurface> onscreen_surface; |
|||
|
|||
onscreen_surface = |
|||
WrapOnscreenSurface(context_.get(), // GL context
|
|||
size, // root surface size
|
|||
delegate_->GLContextFBO() // window FBO ID
|
|||
); |
|||
|
|||
if (onscreen_surface == nullptr) { |
|||
// If the onscreen surface could not be wrapped. There is absolutely no
|
|||
// point in moving forward.
|
|||
FML_LOG(ERROR) << "Could not wrap onscreen surface."; |
|||
return false; |
|||
} |
|||
|
|||
onscreen_surface_ = std::move(onscreen_surface); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
// |Surface|
|
|||
SkMatrix GPUSurfaceGL::GetRootTransformation() const { |
|||
return delegate_->GLContextSurfaceTransformation(); |
|||
} |
|||
|
|||
// |Surface|
|
|||
std::unique_ptr<SurfaceFrame> GPUSurfaceGL::AcquireFrame(const SkISize& size) { |
|||
if (delegate_ == nullptr) { |
|||
return nullptr; |
|||
} |
|||
|
|||
if (!delegate_->GLContextMakeCurrent()) { |
|||
FML_LOG(ERROR) |
|||
<< "Could not make the context current to acquire the frame."; |
|||
return nullptr; |
|||
} |
|||
|
|||
// TODO(38466): Refactor GPU surface APIs take into account the fact that an
|
|||
// external view embedder may want to render to the root surface.
|
|||
if (!render_to_surface_) { |
|||
return std::make_unique<SurfaceFrame>( |
|||
nullptr, true, [](const SurfaceFrame& surface_frame, SkCanvas* canvas) { |
|||
return true; |
|||
}); |
|||
} |
|||
|
|||
const auto root_surface_transformation = GetRootTransformation(); |
|||
|
|||
sk_sp<SkSurface> surface = |
|||
AcquireRenderSurface(size, root_surface_transformation); |
|||
|
|||
if (surface == nullptr) { |
|||
return nullptr; |
|||
} |
|||
|
|||
surface->getCanvas()->setMatrix(root_surface_transformation); |
|||
|
|||
SurfaceFrame::SubmitCallback submit_callback = |
|||
[weak = weak_factory_.GetWeakPtr()](const SurfaceFrame& surface_frame, |
|||
SkCanvas* canvas) { |
|||
return weak ? weak->PresentSurface(canvas) : false; |
|||
}; |
|||
|
|||
return std::make_unique<SurfaceFrame>( |
|||
surface, delegate_->SurfaceSupportsReadback(), submit_callback); |
|||
} |
|||
|
|||
bool GPUSurfaceGL::PresentSurface(SkCanvas* canvas) { |
|||
if (delegate_ == nullptr || canvas == nullptr || context_ == nullptr) { |
|||
return false; |
|||
} |
|||
|
|||
{ |
|||
TRACE_EVENT0("uiwidgets", "SkCanvas::Flush"); |
|||
onscreen_surface_->getCanvas()->flush(); |
|||
onscreen_surface_->getContext()->submit(true); |
|||
} |
|||
|
|||
if (!delegate_->GLContextPresent()) { |
|||
return false; |
|||
} |
|||
|
|||
if (delegate_->GLContextFBOResetAfterPresent()) { |
|||
auto current_size = |
|||
SkISize::Make(onscreen_surface_->width(), onscreen_surface_->height()); |
|||
|
|||
// The FBO has changed, ask the delegate for the new FBO and do a surface
|
|||
// re-wrap.
|
|||
auto new_onscreen_surface = |
|||
WrapOnscreenSurface(context_.get(), // GL context
|
|||
current_size, // root surface size
|
|||
delegate_->GLContextFBO() // window FBO ID
|
|||
); |
|||
|
|||
if (!new_onscreen_surface) { |
|||
return false; |
|||
} |
|||
|
|||
onscreen_surface_ = std::move(new_onscreen_surface); |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
sk_sp<SkSurface> GPUSurfaceGL::AcquireRenderSurface( |
|||
const SkISize& untransformed_size, |
|||
const SkMatrix& root_surface_transformation) { |
|||
const auto transformed_rect = root_surface_transformation.mapRect( |
|||
SkRect::MakeWH(untransformed_size.width(), untransformed_size.height())); |
|||
|
|||
const auto transformed_size = |
|||
SkISize::Make(transformed_rect.width(), transformed_rect.height()); |
|||
|
|||
if (!CreateOrUpdateSurfaces(transformed_size)) { |
|||
return nullptr; |
|||
} |
|||
|
|||
return onscreen_surface_; |
|||
} |
|||
|
|||
// |Surface|
|
|||
GrContext* GPUSurfaceGL::GetContext() { return context_.get(); } |
|||
|
|||
// |Surface|
|
|||
ExternalViewEmbedder* GPUSurfaceGL::GetExternalViewEmbedder() { |
|||
return delegate_->GetExternalViewEmbedder(); |
|||
} |
|||
|
|||
// |Surface|
|
|||
bool GPUSurfaceGL::MakeRenderContextCurrent() { |
|||
return delegate_->GLContextMakeCurrent(); |
|||
} |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include <functional> |
|||
#include <memory> |
|||
|
|||
#include "flow/embedded_views.h" |
|||
#include "flutter/fml/macros.h" |
|||
#include "flutter/fml/memory/weak_ptr.h" |
|||
#include "include/gpu/GrContext.h" |
|||
#include "shell/common/surface.h" |
|||
#include "shell/gpu/gpu_surface_gl_delegate.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class GPUSurfaceGL : public Surface { |
|||
public: |
|||
GPUSurfaceGL(GPUSurfaceGLDelegate* delegate, bool render_to_surface); |
|||
|
|||
// Creates a new GL surface reusing an existing GrContext. |
|||
GPUSurfaceGL(sk_sp<GrContext> gr_context, GPUSurfaceGLDelegate* delegate, |
|||
bool render_to_surface); |
|||
|
|||
// |Surface| |
|||
~GPUSurfaceGL() override; |
|||
|
|||
// |Surface| |
|||
bool IsValid() override; |
|||
|
|||
// |Surface| |
|||
std::unique_ptr<SurfaceFrame> AcquireFrame(const SkISize& size) override; |
|||
|
|||
// |Surface| |
|||
SkMatrix GetRootTransformation() const override; |
|||
|
|||
// |Surface| |
|||
GrContext* GetContext() override; |
|||
|
|||
// |Surface| |
|||
ExternalViewEmbedder* GetExternalViewEmbedder() override; |
|||
|
|||
// |Surface| |
|||
bool MakeRenderContextCurrent() override; |
|||
|
|||
private: |
|||
GPUSurfaceGLDelegate* delegate_; |
|||
sk_sp<GrContext> context_; |
|||
sk_sp<SkSurface> onscreen_surface_; |
|||
bool context_owner_; |
|||
// TODO(38466): Refactor GPU surface APIs take into account the fact that an |
|||
// external view embedder may want to render to the root surface. This is a |
|||
// hack to make avoid allocating resources for the root surface when an |
|||
// external view embedder is present. |
|||
const bool render_to_surface_; |
|||
bool valid_ = false; |
|||
fml::WeakPtrFactory<GPUSurfaceGL> weak_factory_; |
|||
|
|||
bool CreateOrUpdateSurfaces(const SkISize& size); |
|||
|
|||
sk_sp<SkSurface> AcquireRenderSurface( |
|||
const SkISize& untransformed_size, |
|||
const SkMatrix& root_surface_transformation); |
|||
|
|||
bool PresentSurface(SkCanvas* canvas); |
|||
|
|||
FML_DISALLOW_COPY_AND_ASSIGN(GPUSurfaceGL); |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#pragma once
|
|||
|
|||
#include "gpu_surface_gl_delegate.h"
|
|||
|
|||
#include "include/gpu/gl/GrGLAssembleInterface.h"
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
GPUSurfaceGLDelegate::~GPUSurfaceGLDelegate() = default; |
|||
|
|||
bool GPUSurfaceGLDelegate::GLContextFBOResetAfterPresent() const { |
|||
return false; |
|||
} |
|||
|
|||
bool GPUSurfaceGLDelegate::SurfaceSupportsReadback() const { return true; } |
|||
|
|||
SkMatrix GPUSurfaceGLDelegate::GLContextSurfaceTransformation() const { |
|||
SkMatrix matrix; |
|||
matrix.setIdentity(); |
|||
return matrix; |
|||
} |
|||
|
|||
GPUSurfaceGLDelegate::GLProcResolver GPUSurfaceGLDelegate::GetGLProcResolver() |
|||
const { |
|||
return nullptr; |
|||
} |
|||
|
|||
static bool IsProcResolverOpenGLES( |
|||
GPUSurfaceGLDelegate::GLProcResolver proc_resolver) { |
|||
// Version string prefix that identifies an OpenGL ES implementation.
|
|||
#define GPU_GL_VERSION 0x1F02
|
|||
constexpr char kGLESVersionPrefix[] = "OpenGL ES"; |
|||
|
|||
using GLGetStringProc = const char* (*)(uint32_t); |
|||
|
|||
GLGetStringProc gl_get_string = |
|||
reinterpret_cast<GLGetStringProc>(proc_resolver("glGetString")); |
|||
|
|||
FML_CHECK(gl_get_string) |
|||
<< "The GL proc resolver could not resolve glGetString"; |
|||
|
|||
const char* gl_version_string = gl_get_string(GPU_GL_VERSION); |
|||
|
|||
FML_CHECK(gl_version_string) |
|||
<< "The GL proc resolver's glGetString(GL_VERSION) failed"; |
|||
|
|||
return strncmp(gl_version_string, kGLESVersionPrefix, |
|||
strlen(kGLESVersionPrefix)) == 0; |
|||
} |
|||
|
|||
static sk_sp<const GrGLInterface> CreateGLInterface( |
|||
GPUSurfaceGLDelegate::GLProcResolver proc_resolver) { |
|||
if (proc_resolver == nullptr) { |
|||
// If there is no custom proc resolver, ask Skia to guess the native
|
|||
// interface. This often leads to interesting results on most platforms.
|
|||
return GrGLMakeNativeInterface(); |
|||
} |
|||
|
|||
struct ProcResolverContext { |
|||
GPUSurfaceGLDelegate::GLProcResolver resolver; |
|||
}; |
|||
|
|||
ProcResolverContext context = {proc_resolver}; |
|||
|
|||
GrGLGetProc gl_get_proc = [](void* context, |
|||
const char gl_proc_name[]) -> GrGLFuncPtr { |
|||
auto proc_resolver_context = |
|||
reinterpret_cast<ProcResolverContext*>(context); |
|||
return reinterpret_cast<GrGLFuncPtr>( |
|||
proc_resolver_context->resolver(gl_proc_name)); |
|||
}; |
|||
|
|||
// glGetString indicates an OpenGL ES interface.
|
|||
if (IsProcResolverOpenGLES(proc_resolver)) { |
|||
return GrGLMakeAssembledGLESInterface(&context, gl_get_proc); |
|||
} |
|||
|
|||
// Fallback to OpenGL.
|
|||
if (auto interface = GrGLMakeAssembledGLInterface(&context, gl_get_proc)) { |
|||
return interface; |
|||
} |
|||
|
|||
FML_LOG(ERROR) << "Could not create a valid GL interface."; |
|||
return nullptr; |
|||
} |
|||
|
|||
sk_sp<const GrGLInterface> GPUSurfaceGLDelegate::GetGLInterface() const { |
|||
return CreateGLInterface(GetGLProcResolver()); |
|||
} |
|||
|
|||
sk_sp<const GrGLInterface> |
|||
GPUSurfaceGLDelegate::GetDefaultPlatformGLInterface() { |
|||
return CreateGLInterface(nullptr); |
|||
} |
|||
|
|||
ExternalViewEmbedder* GPUSurfaceGLDelegate::GetExternalViewEmbedder() { |
|||
return nullptr; |
|||
} |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include "flow/embedded_views.h" |
|||
#include "flutter/fml/macros.h" |
|||
#include "include/core/SkMatrix.h" |
|||
#include "include/gpu/gl/GrGLInterface.h" |
|||
#include "shell/gpu/gpu_surface_delegate.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class GPUSurfaceGLDelegate : public GPUSurfaceDelegate { |
|||
public: |
|||
~GPUSurfaceGLDelegate() override; |
|||
|
|||
// |GPUSurfaceDelegate| |
|||
ExternalViewEmbedder* GetExternalViewEmbedder() override; |
|||
|
|||
// Called to make the main GL context current on the current thread. |
|||
virtual bool GLContextMakeCurrent() = 0; |
|||
|
|||
// Called to clear the current GL context on the thread. This may be called on |
|||
// either the GPU or IO threads. |
|||
virtual bool GLContextClearCurrent() = 0; |
|||
|
|||
// Called to present the main GL surface. This is only called for the main GL |
|||
// context and not any of the contexts dedicated for IO. |
|||
virtual bool GLContextPresent() = 0; |
|||
|
|||
// The ID of the main window bound framebuffer. Typically FBO0. |
|||
virtual intptr_t GLContextFBO() const = 0; |
|||
|
|||
// The rendering subsystem assumes that the ID of the main window bound |
|||
// framebuffer remains constant throughout. If this assumption in incorrect, |
|||
// embedders are required to return true from this method. In such cases, |
|||
// GLContextFBO() will be called again to acquire the new FBO ID for rendering |
|||
// subsequent frames. |
|||
virtual bool GLContextFBOResetAfterPresent() const; |
|||
|
|||
// Indicates whether or not the surface supports pixel readback as used in |
|||
// circumstances such as a BackdropFilter. |
|||
virtual bool SurfaceSupportsReadback() const; |
|||
|
|||
// A transformation applied to the onscreen surface before the canvas is |
|||
// flushed. |
|||
virtual SkMatrix GLContextSurfaceTransformation() const; |
|||
|
|||
sk_sp<const GrGLInterface> GetGLInterface() const; |
|||
|
|||
// TODO(chinmaygarde): The presence of this method is to work around the fact |
|||
// that not all platforms can accept a custom GL proc table. Migrate all |
|||
// platforms to move GL proc resolution to the embedder and remove this |
|||
// method. |
|||
static sk_sp<const GrGLInterface> GetDefaultPlatformGLInterface(); |
|||
|
|||
using GLProcResolver = |
|||
std::function<void* /* proc name */ (const char* /* proc address */)>; |
|||
// Provide a custom GL proc resolver. If no such resolver is present, Skia |
|||
// will attempt to do GL proc address resolution on its own. Embedders that |
|||
// have specific opinions on GL API selection or need to add their own |
|||
// instrumentation to specific GL calls can specify custom GL functions |
|||
// here. |
|||
virtual GLProcResolver GetGLProcResolver() const; |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#include "gpu_surface_software.h"
|
|||
|
|||
#include <memory>
|
|||
|
|||
#include "flutter/fml/logging.h"
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
GPUSurfaceSoftware::GPUSurfaceSoftware(GPUSurfaceSoftwareDelegate* delegate, |
|||
bool render_to_surface) |
|||
: delegate_(delegate), |
|||
render_to_surface_(render_to_surface), |
|||
weak_factory_(this) {} |
|||
|
|||
GPUSurfaceSoftware::~GPUSurfaceSoftware() = default; |
|||
|
|||
// |Surface|
|
|||
bool GPUSurfaceSoftware::IsValid() { return delegate_ != nullptr; } |
|||
|
|||
// |Surface|
|
|||
std::unique_ptr<SurfaceFrame> GPUSurfaceSoftware::AcquireFrame( |
|||
const SkISize& logical_size) { |
|||
// TODO(38466): Refactor GPU surface APIs take into account the fact that an
|
|||
// external view embedder may want to render to the root surface.
|
|||
if (!render_to_surface_) { |
|||
return std::make_unique<SurfaceFrame>( |
|||
nullptr, true, [](const SurfaceFrame& surface_frame, SkCanvas* canvas) { |
|||
return true; |
|||
}); |
|||
} |
|||
|
|||
if (!IsValid()) { |
|||
return nullptr; |
|||
} |
|||
|
|||
const auto size = SkISize::Make(logical_size.width(), logical_size.height()); |
|||
|
|||
sk_sp<SkSurface> backing_store = delegate_->AcquireBackingStore(size); |
|||
|
|||
if (backing_store == nullptr) { |
|||
return nullptr; |
|||
} |
|||
|
|||
if (size != SkISize::Make(backing_store->width(), backing_store->height())) { |
|||
return nullptr; |
|||
} |
|||
|
|||
// If the surface has been scaled, we need to apply the inverse scaling to the
|
|||
// underlying canvas so that coordinates are mapped to the same spot
|
|||
// irrespective of surface scaling.
|
|||
SkCanvas* canvas = backing_store->getCanvas(); |
|||
canvas->resetMatrix(); |
|||
|
|||
SurfaceFrame::SubmitCallback on_submit = |
|||
[self = weak_factory_.GetWeakPtr()](const SurfaceFrame& surface_frame, |
|||
SkCanvas* canvas) -> bool { |
|||
// If the surface itself went away, there is nothing more to do.
|
|||
if (!self || !self->IsValid() || canvas == nullptr) { |
|||
return false; |
|||
} |
|||
|
|||
canvas->flush(); |
|||
|
|||
return self->delegate_->PresentBackingStore(surface_frame.SkiaSurface()); |
|||
}; |
|||
|
|||
return std::make_unique<SurfaceFrame>(backing_store, true, on_submit); |
|||
} |
|||
|
|||
// |Surface|
|
|||
SkMatrix GPUSurfaceSoftware::GetRootTransformation() const { |
|||
// This backend does not currently support root surface transformations. Just
|
|||
// return identity.
|
|||
SkMatrix matrix; |
|||
matrix.reset(); |
|||
return matrix; |
|||
} |
|||
|
|||
// |Surface|
|
|||
GrContext* GPUSurfaceSoftware::GetContext() { |
|||
// There is no GrContext associated with a software surface.
|
|||
return nullptr; |
|||
} |
|||
|
|||
// |Surface|
|
|||
ExternalViewEmbedder* GPUSurfaceSoftware::GetExternalViewEmbedder() { |
|||
return delegate_->GetExternalViewEmbedder(); |
|||
} |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include "flutter/fml/macros.h" |
|||
#include "flutter/fml/memory/weak_ptr.h" |
|||
#include "shell/common/surface.h" |
|||
#include "shell/gpu/gpu_surface_software_delegate.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class GPUSurfaceSoftware : public Surface { |
|||
public: |
|||
GPUSurfaceSoftware(GPUSurfaceSoftwareDelegate* delegate, |
|||
bool render_to_surface); |
|||
|
|||
~GPUSurfaceSoftware() override; |
|||
|
|||
// |Surface| |
|||
bool IsValid() override; |
|||
|
|||
// |Surface| |
|||
std::unique_ptr<SurfaceFrame> AcquireFrame(const SkISize& size) override; |
|||
|
|||
// |Surface| |
|||
SkMatrix GetRootTransformation() const override; |
|||
|
|||
// |Surface| |
|||
GrContext* GetContext() override; |
|||
|
|||
// |Surface| |
|||
ExternalViewEmbedder* GetExternalViewEmbedder() override; |
|||
|
|||
private: |
|||
GPUSurfaceSoftwareDelegate* delegate_; |
|||
// TODO(38466): Refactor GPU surface APIs take into account the fact that an |
|||
// external view embedder may want to render to the root surface. This is a |
|||
// hack to make avoid allocating resources for the root surface when an |
|||
// external view embedder is present. |
|||
const bool render_to_surface_; |
|||
fml::WeakPtrFactory<GPUSurfaceSoftware> weak_factory_; |
|||
|
|||
FML_DISALLOW_COPY_AND_ASSIGN(GPUSurfaceSoftware); |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#include "gpu_surface_software_delegate.h"
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
GPUSurfaceSoftwareDelegate::~GPUSurfaceSoftwareDelegate() = default; |
|||
|
|||
ExternalViewEmbedder* GPUSurfaceSoftwareDelegate::GetExternalViewEmbedder() { |
|||
return nullptr; |
|||
} |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include "flow/embedded_views.h" |
|||
#include "flutter/fml/macros.h" |
|||
#include "include/core/SkSurface.h" |
|||
#include "shell/gpu/gpu_surface_delegate.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class GPUSurfaceSoftwareDelegate : public GPUSurfaceDelegate { |
|||
public: |
|||
~GPUSurfaceSoftwareDelegate() override; |
|||
|
|||
// |GPUSurfaceDelegate| |
|||
ExternalViewEmbedder* GetExternalViewEmbedder() override; |
|||
|
|||
virtual sk_sp<SkSurface> AcquireBackingStore(const SkISize& size) = 0; |
|||
|
|||
virtual bool PresentBackingStore(sk_sp<SkSurface> backing_store) = 0; |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
1001
engine/src/shell/platform/embedder/embedder.cc
文件差异内容过多而无法显示
查看文件
文件差异内容过多而无法显示
查看文件
|
|||
#pragma once |
|||
|
|||
#include <stdbool.h> |
|||
#include <stddef.h> |
|||
#include <stdint.h> |
|||
|
|||
#if defined(__cplusplus) |
|||
extern "C" { |
|||
#endif |
|||
|
|||
typedef enum { |
|||
kSuccess = 0, |
|||
kInvalidLibraryVersion, |
|||
kInvalidArguments, |
|||
kInternalInconsistency, |
|||
} UIWidgetsEngineResult; |
|||
|
|||
typedef enum { |
|||
kOpenGL, |
|||
kSoftware, |
|||
} UIWidgetsRendererType; |
|||
|
|||
typedef enum { |
|||
kUIWidgetsAccessibilityFeatureAccessibleNavigation = 1 << 0, |
|||
kUIWidgetsAccessibilityFeatureInvertColors = 1 << 1, |
|||
kUIWidgetsAccessibilityFeatureDisableAnimations = 1 << 2, |
|||
kUIWidgetsAccessibilityFeatureBoldText = 1 << 3, |
|||
kUIWidgetsAccessibilityFeatureReduceMotion = 1 << 4, |
|||
} UIWidgetsAccessibilityFeature; |
|||
|
|||
typedef enum { |
|||
kUIWidgetsTextDirectionUnknown = 0, |
|||
kUIWidgetsTextDirectionRTL = 1, |
|||
kUIWidgetsTextDirectionLTR = 2, |
|||
} UIWidgetsTextDirection; |
|||
|
|||
typedef struct _UIWidgetsEngine* UIWidgetsEngine; |
|||
|
|||
typedef struct { |
|||
float scaleX; |
|||
float skewX; |
|||
float transX; |
|||
float skewY; |
|||
float scaleY; |
|||
float transY; |
|||
float pers0; |
|||
float pers1; |
|||
float pers2; |
|||
} UIWidgetsTransformation; |
|||
|
|||
typedef void (*VoidCallback)(void* /* user data */); |
|||
|
|||
typedef enum { |
|||
kUIWidgetsOpenGLTargetTypeTexture, |
|||
kUIWidgetsOpenGLTargetTypeFramebuffer, |
|||
} UIWidgetsOpenGLTargetType; |
|||
|
|||
typedef struct { |
|||
uint32_t target; |
|||
uint32_t name; |
|||
uint32_t format; |
|||
void* user_data; |
|||
VoidCallback destruction_callback; |
|||
size_t width; |
|||
size_t height; |
|||
} UIWidgetsOpenGLTexture; |
|||
|
|||
typedef struct { |
|||
uint32_t target; |
|||
uint32_t name; |
|||
void* user_data; |
|||
VoidCallback destruction_callback; |
|||
} UIWidgetsOpenGLFramebuffer; |
|||
|
|||
typedef bool (*BoolCallback)(void* /* user data */); |
|||
typedef UIWidgetsTransformation (*TransformationCallback)( |
|||
void* /* user data */); |
|||
typedef uint32_t (*UIntCallback)(void* /* user data */); |
|||
typedef bool (*SoftwareSurfacePresentCallback)(void* /* user data */, |
|||
const void* /* allocation */, |
|||
size_t /* row bytes */, |
|||
size_t /* height */); |
|||
typedef void* (*ProcResolver)(void* /* user data */, const char* /* name */); |
|||
typedef bool (*TextureFrameCallback)(void* /* user data */, |
|||
int64_t /* texture identifier */, |
|||
size_t /* width */, size_t /* height */, |
|||
UIWidgetsOpenGLTexture* /* texture out */); |
|||
typedef void (*VsyncCallback)(void* /* user data */, intptr_t /* baton */); |
|||
|
|||
typedef struct { |
|||
size_t struct_size; |
|||
BoolCallback make_current; |
|||
BoolCallback clear_current; |
|||
BoolCallback present; |
|||
UIntCallback fbo_callback; |
|||
BoolCallback make_resource_current; |
|||
bool fbo_reset_after_present; |
|||
TransformationCallback surface_transformation; |
|||
ProcResolver gl_proc_resolver; |
|||
TextureFrameCallback gl_external_texture_frame_callback; |
|||
} UIWidgetsOpenGLRendererConfig; |
|||
|
|||
typedef struct { |
|||
size_t struct_size; |
|||
SoftwareSurfacePresentCallback surface_present_callback; |
|||
} UIWidgetsSoftwareRendererConfig; |
|||
|
|||
typedef struct { |
|||
UIWidgetsRendererType type; |
|||
union { |
|||
UIWidgetsOpenGLRendererConfig open_gl; |
|||
UIWidgetsSoftwareRendererConfig software; |
|||
}; |
|||
} UIWidgetsRendererConfig; |
|||
|
|||
typedef struct { |
|||
size_t struct_size; |
|||
size_t width; |
|||
size_t height; |
|||
float pixel_ratio; |
|||
} UIWidgetsWindowMetricsEvent; |
|||
|
|||
typedef enum { |
|||
kCancel, |
|||
kUp, |
|||
kDown, |
|||
kMove, |
|||
kAdd, |
|||
kRemove, |
|||
kHover, |
|||
} UIWidgetsPointerPhase; |
|||
|
|||
typedef enum { |
|||
kUIWidgetsPointerDeviceKindMouse = 1, |
|||
kUIWidgetsPointerDeviceKindTouch, |
|||
} UIWidgetsPointerDeviceKind; |
|||
|
|||
typedef enum { |
|||
kUIWidgetsPointerButtonMousePrimary = 1 << 0, |
|||
kUIWidgetsPointerButtonMouseSecondary = 1 << 1, |
|||
kUIWidgetsPointerButtonMouseMiddle = 1 << 2, |
|||
kUIWidgetsPointerButtonMouseBack = 1 << 3, |
|||
kUIWidgetsPointerButtonMouseForward = 1 << 4, |
|||
} UIWidgetsPointerMouseButtons; |
|||
|
|||
typedef enum { |
|||
kUIWidgetsPointerSignalKindNone, |
|||
kUIWidgetsPointerSignalKindScroll, |
|||
} UIWidgetsPointerSignalKind; |
|||
|
|||
typedef struct { |
|||
size_t struct_size; |
|||
UIWidgetsPointerPhase phase; |
|||
size_t timestamp; |
|||
float x; |
|||
float y; |
|||
int32_t device; |
|||
UIWidgetsPointerSignalKind signal_kind; |
|||
float scroll_delta_x; |
|||
float scroll_delta_y; |
|||
UIWidgetsPointerDeviceKind device_kind; |
|||
int64_t buttons; |
|||
} UIWidgetsPointerEvent; |
|||
|
|||
struct _UIWidgetsPlatformMessageResponseHandle; |
|||
typedef struct _UIWidgetsPlatformMessageResponseHandle |
|||
UIWidgetsPlatformMessageResponseHandle; |
|||
|
|||
typedef struct { |
|||
size_t struct_size; |
|||
const char* channel; |
|||
const uint8_t* message; |
|||
size_t message_size; |
|||
const UIWidgetsPlatformMessageResponseHandle* response_handle; |
|||
} UIWidgetsPlatformMessage; |
|||
|
|||
typedef void (*UIWidgetsPlatformMessageCallback)( |
|||
const UIWidgetsPlatformMessage* /* message*/, void* /* user data */); |
|||
|
|||
typedef void (*UIWidgetsDataCallback)(const uint8_t* /* data */, |
|||
size_t /* size */, void* /* user data */); |
|||
|
|||
typedef struct { |
|||
float left; |
|||
float top; |
|||
float right; |
|||
float bottom; |
|||
} UIWidgetsRect; |
|||
|
|||
typedef struct { |
|||
float x; |
|||
float y; |
|||
} UIWidgetsPoint; |
|||
|
|||
typedef struct { |
|||
float width; |
|||
float height; |
|||
} UIWidgetsSize; |
|||
|
|||
typedef struct { |
|||
UIWidgetsRect rect; |
|||
UIWidgetsSize upper_left_corner_radius; |
|||
UIWidgetsSize upper_right_corner_radius; |
|||
UIWidgetsSize lower_right_corner_radius; |
|||
UIWidgetsSize lower_left_corner_radius; |
|||
} UIWidgetsRoundedRect; |
|||
|
|||
typedef int64_t UIWidgetsPlatformViewIdentifier; |
|||
|
|||
typedef struct _UIWidgetsTaskRunner* UIWidgetsTaskRunner; |
|||
|
|||
typedef struct { |
|||
UIWidgetsTaskRunner runner; |
|||
uint64_t task; |
|||
} UIWidgetsTask; |
|||
|
|||
typedef void (*UIWidgetsTaskRunnerPostTaskCallback)( |
|||
UIWidgetsTask /* task */, uint64_t /* target time nanos */, |
|||
void* /* user data */); |
|||
|
|||
typedef struct { |
|||
size_t struct_size; |
|||
void* user_data; |
|||
BoolCallback runs_task_on_current_thread_callback; |
|||
UIWidgetsTaskRunnerPostTaskCallback post_task_callback; |
|||
size_t identifier; |
|||
} UIWidgetsTaskRunnerDescription; |
|||
|
|||
typedef struct { |
|||
size_t struct_size; |
|||
const UIWidgetsTaskRunnerDescription* platform_task_runner; |
|||
const UIWidgetsTaskRunnerDescription* ui_task_runner; |
|||
const UIWidgetsTaskRunnerDescription* render_task_runner; |
|||
} UIWidgetsCustomTaskRunners; |
|||
|
|||
typedef struct { |
|||
UIWidgetsOpenGLTargetType type; |
|||
union { |
|||
UIWidgetsOpenGLTexture texture; |
|||
UIWidgetsOpenGLFramebuffer framebuffer; |
|||
}; |
|||
} UIWidgetsOpenGLBackingStore; |
|||
|
|||
typedef struct { |
|||
const void* allocation; |
|||
size_t row_bytes; |
|||
size_t height; |
|||
void* user_data; |
|||
VoidCallback destruction_callback; |
|||
} UIWidgetsSoftwareBackingStore; |
|||
|
|||
typedef enum { |
|||
kUIWidgetsPlatformViewMutationTypeOpacity, |
|||
kUIWidgetsPlatformViewMutationTypeClipRect, |
|||
kUIWidgetsPlatformViewMutationTypeClipRoundedRect, |
|||
kUIWidgetsPlatformViewMutationTypeTransformation, |
|||
} UIWidgetsPlatformViewMutationType; |
|||
|
|||
typedef struct { |
|||
UIWidgetsPlatformViewMutationType type; |
|||
union { |
|||
double opacity; |
|||
UIWidgetsRect clip_rect; |
|||
UIWidgetsRoundedRect clip_rounded_rect; |
|||
UIWidgetsTransformation transformation; |
|||
}; |
|||
} UIWidgetsPlatformViewMutation; |
|||
|
|||
typedef struct { |
|||
size_t struct_size; |
|||
UIWidgetsPlatformViewIdentifier identifier; |
|||
size_t mutations_count; |
|||
const UIWidgetsPlatformViewMutation** mutations; |
|||
} UIWidgetsPlatformView; |
|||
|
|||
typedef enum { |
|||
kUIWidgetsBackingStoreTypeOpenGL, |
|||
kUIWidgetsBackingStoreTypeSoftware, |
|||
} UIWidgetsBackingStoreType; |
|||
|
|||
typedef struct { |
|||
size_t struct_size; |
|||
void* user_data; |
|||
UIWidgetsBackingStoreType type; |
|||
bool did_update; |
|||
union { |
|||
UIWidgetsOpenGLBackingStore open_gl; |
|||
UIWidgetsSoftwareBackingStore software; |
|||
}; |
|||
} UIWidgetsBackingStore; |
|||
|
|||
typedef struct { |
|||
size_t struct_size; |
|||
UIWidgetsSize size; |
|||
} UIWidgetsBackingStoreConfig; |
|||
|
|||
typedef enum { |
|||
kUIWidgetsLayerContentTypeBackingStore, |
|||
kUIWidgetsLayerContentTypePlatformView, |
|||
} UIWidgetsLayerContentType; |
|||
|
|||
typedef struct { |
|||
size_t struct_size; |
|||
UIWidgetsLayerContentType type; |
|||
union { |
|||
const UIWidgetsBackingStore* backing_store; |
|||
const UIWidgetsPlatformView* platform_view; |
|||
}; |
|||
UIWidgetsPoint offset; |
|||
UIWidgetsSize size; |
|||
} UIWidgetsLayer; |
|||
|
|||
typedef bool (*UIWidgetsBackingStoreCreateCallback)( |
|||
const UIWidgetsBackingStoreConfig* config, |
|||
UIWidgetsBackingStore* backing_store_out, void* user_data); |
|||
|
|||
typedef bool (*UIWidgetsBackingStoreCollectCallback)( |
|||
const UIWidgetsBackingStore* renderer, void* user_data); |
|||
|
|||
typedef bool (*UIWidgetsLayersPresentCallback)(const UIWidgetsLayer** layers, |
|||
size_t layers_count, |
|||
void* user_data); |
|||
|
|||
typedef struct { |
|||
size_t struct_size; |
|||
void* user_data; |
|||
UIWidgetsBackingStoreCreateCallback create_backing_store_callback; |
|||
UIWidgetsBackingStoreCollectCallback collect_backing_store_callback; |
|||
UIWidgetsLayersPresentCallback present_layers_callback; |
|||
} UIWidgetsCompositor; |
|||
|
|||
typedef struct { |
|||
size_t struct_size; |
|||
const char* language_code; |
|||
const char* country_code; |
|||
const char* script_code; |
|||
const char* variant_code; |
|||
} UIWidgetsLocale; |
|||
|
|||
typedef enum { |
|||
kUIWidgetsNativeThreadTypePlatform, |
|||
kUIWidgetsNativeThreadTypeRender, |
|||
kUIWidgetsNativeThreadTypeUI, |
|||
kUIWidgetsNativeThreadTypeWorker, |
|||
} UIWidgetsNativeThreadType; |
|||
|
|||
typedef void (*UIWidgetsNativeThreadCallback)(UIWidgetsNativeThreadType type, |
|||
void* user_data); |
|||
|
|||
typedef void (*UIWidgetsTaskObserverAdd)(intptr_t key, void* callback, |
|||
void* user_data); |
|||
typedef void (*UIWidgetsTaskObserverRemove)(intptr_t key, void* user_data); |
|||
|
|||
typedef void (*UIWidgetsMonoEntrypointCallback)(void* user_data); |
|||
|
|||
typedef struct { |
|||
size_t struct_size; |
|||
const char* assets_path; |
|||
const char* icu_data_path; |
|||
int command_line_argc; |
|||
const char* const* command_line_argv; |
|||
UIWidgetsPlatformMessageCallback platform_message_callback; |
|||
VoidCallback root_isolate_create_callback; |
|||
const char* persistent_cache_path; |
|||
bool is_persistent_cache_read_only; |
|||
VsyncCallback vsync_callback; |
|||
const UIWidgetsCustomTaskRunners* custom_task_runners; |
|||
const UIWidgetsCompositor* compositor; |
|||
UIWidgetsTaskObserverAdd task_observer_add; |
|||
UIWidgetsTaskObserverRemove task_observer_remove; |
|||
UIWidgetsMonoEntrypointCallback custom_mono_entrypoint; |
|||
UIWidgetsWindowMetricsEvent initial_window_metrics; |
|||
} UIWidgetsProjectArgs; |
|||
|
|||
UIWidgetsEngineResult UIWidgetsEngineRun(const UIWidgetsRendererConfig* config, |
|||
const UIWidgetsProjectArgs* args, |
|||
void* user_data, |
|||
UIWidgetsEngine* engine_out); |
|||
|
|||
UIWidgetsEngineResult UIWidgetsEngineShutdown(UIWidgetsEngine engine); |
|||
|
|||
UIWidgetsEngineResult UIWidgetsEngineInitialize( |
|||
const UIWidgetsRendererConfig* config, const UIWidgetsProjectArgs* args, |
|||
void* user_data, UIWidgetsEngine* engine_out); |
|||
|
|||
UIWidgetsEngineResult UIWidgetsEngineDeinitialize(UIWidgetsEngine engine); |
|||
|
|||
UIWidgetsEngineResult UIWidgetsEngineRunInitialized(UIWidgetsEngine engine); |
|||
|
|||
UIWidgetsEngineResult UIWidgetsEngineSendWindowMetricsEvent( |
|||
UIWidgetsEngine engine, const UIWidgetsWindowMetricsEvent* event); |
|||
|
|||
UIWidgetsEngineResult UIWidgetsEngineSendPointerEvent( |
|||
UIWidgetsEngine engine, const UIWidgetsPointerEvent* events, |
|||
size_t events_count); |
|||
|
|||
UIWidgetsEngineResult UIWidgetsEngineSendPlatformMessage( |
|||
UIWidgetsEngine engine, const UIWidgetsPlatformMessage* message); |
|||
|
|||
UIWidgetsEngineResult UIWidgetsPlatformMessageCreateResponseHandle( |
|||
UIWidgetsEngine engine, UIWidgetsDataCallback data_callback, |
|||
void* user_data, UIWidgetsPlatformMessageResponseHandle** response_out); |
|||
|
|||
UIWidgetsEngineResult UIWidgetsPlatformMessageReleaseResponseHandle( |
|||
UIWidgetsEngine engine, UIWidgetsPlatformMessageResponseHandle* response); |
|||
|
|||
UIWidgetsEngineResult UIWidgetsEngineSendPlatformMessageResponse( |
|||
UIWidgetsEngine engine, |
|||
const UIWidgetsPlatformMessageResponseHandle* handle, const uint8_t* data, |
|||
size_t data_length); |
|||
|
|||
UIWidgetsEngineResult __UIWidgetsEngineFlushPendingTasksNow(); |
|||
|
|||
UIWidgetsEngineResult UIWidgetsEngineRegisterExternalTexture( |
|||
UIWidgetsEngine engine, int64_t texture_identifier); |
|||
|
|||
UIWidgetsEngineResult UIWidgetsEngineUnregisterExternalTexture( |
|||
UIWidgetsEngine engine, int64_t texture_identifier); |
|||
|
|||
UIWidgetsEngineResult UIWidgetsEngineMarkExternalTextureFrameAvailable( |
|||
UIWidgetsEngine engine, int64_t texture_identifier); |
|||
|
|||
UIWidgetsEngineResult UIWidgetsEngineUpdateAccessibilityFeatures( |
|||
UIWidgetsEngine engine, UIWidgetsAccessibilityFeature features); |
|||
|
|||
UIWidgetsEngineResult UIWidgetsEngineOnVsync(UIWidgetsEngine engine, |
|||
intptr_t baton, |
|||
uint64_t frame_start_time_nanos, |
|||
uint64_t frame_target_time_nanos); |
|||
|
|||
UIWidgetsEngineResult UIWidgetsEngineReloadSystemFonts(UIWidgetsEngine engine); |
|||
|
|||
void UIWidgetsEngineTraceEventDurationBegin(const char* name); |
|||
|
|||
void UIWidgetsEngineTraceEventDurationEnd(const char* name); |
|||
|
|||
void UIWidgetsEngineTraceEventInstant(const char* name); |
|||
|
|||
UIWidgetsEngineResult UIWidgetsEnginePostRenderThreadTask( |
|||
UIWidgetsEngine engine, VoidCallback callback, void* callback_data); |
|||
|
|||
uint64_t UIWidgetsEngineGetCurrentTime(); |
|||
|
|||
UIWidgetsEngineResult UIWidgetsEngineRunTask(UIWidgetsEngine engine, |
|||
const UIWidgetsTask* task); |
|||
|
|||
UIWidgetsEngineResult UIWidgetsEngineUpdateLocales( |
|||
UIWidgetsEngine engine, const UIWidgetsLocale** locales, |
|||
size_t locales_count); |
|||
UIWidgetsEngineResult UIWidgetsEngineNotifyLowMemoryWarning( |
|||
UIWidgetsEngine engine); |
|||
|
|||
UIWidgetsEngineResult UIWidgetsEnginePostCallbackOnAllNativeThreads( |
|||
UIWidgetsEngine engine, UIWidgetsNativeThreadCallback callback, |
|||
void* user_data); |
|||
|
|||
#if defined(__cplusplus) |
|||
} // extern "C" |
|||
#endif |
|
|||
#include "embedder_engine.h"
|
|||
|
|||
#include <utility>
|
|||
|
|||
#include "flutter/fml/make_copyable.h"
|
|||
#include "shell/platform/embedder/vsync_waiter_embedder.h"
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
struct ShellArgs { |
|||
WindowData window_data; |
|||
Settings settings; |
|||
Shell::CreateCallback<PlatformView> on_create_platform_view; |
|||
Shell::CreateCallback<Rasterizer> on_create_rasterizer; |
|||
ShellArgs(const WindowData& p_window_data, const Settings& p_settings, |
|||
Shell::CreateCallback<PlatformView> p_on_create_platform_view, |
|||
Shell::CreateCallback<Rasterizer> p_on_create_rasterizer) |
|||
: window_data(p_window_data), |
|||
settings(p_settings), |
|||
on_create_platform_view(std::move(p_on_create_platform_view)), |
|||
on_create_rasterizer(std::move(p_on_create_rasterizer)) {} |
|||
}; |
|||
|
|||
EmbedderEngine::EmbedderEngine( |
|||
std::unique_ptr<EmbedderThreadHost> thread_host, |
|||
const TaskRunners& task_runners, const WindowData& window_data, |
|||
const Settings& settings, RunConfiguration run_configuration, |
|||
Shell::CreateCallback<PlatformView> on_create_platform_view, |
|||
Shell::CreateCallback<Rasterizer> on_create_rasterizer, |
|||
EmbedderExternalTextureGL::ExternalTextureCallback |
|||
external_texture_callback) |
|||
: thread_host_(std::move(thread_host)), |
|||
task_runners_(task_runners), |
|||
run_configuration_(std::move(run_configuration)), |
|||
shell_args_(std::make_unique<ShellArgs>( |
|||
window_data, settings, std::move(on_create_platform_view), |
|||
std::move(on_create_rasterizer))), |
|||
external_texture_callback_(std::move(external_texture_callback)) {} |
|||
|
|||
EmbedderEngine::~EmbedderEngine() = default; |
|||
|
|||
bool EmbedderEngine::LaunchShell() { |
|||
if (!shell_args_) { |
|||
FML_DLOG(ERROR) << "Invalid shell arguments."; |
|||
return false; |
|||
} |
|||
|
|||
if (shell_) { |
|||
FML_DLOG(ERROR) << "Shell already initialized"; |
|||
} |
|||
|
|||
shell_ = Shell::Create( |
|||
task_runners_, shell_args_->window_data, shell_args_->settings, |
|||
shell_args_->on_create_platform_view, shell_args_->on_create_rasterizer); |
|||
|
|||
// Reset the args no matter what. They will never be used to initialize a
|
|||
// shell again.
|
|||
shell_args_.reset(); |
|||
|
|||
return IsValid(); |
|||
} |
|||
|
|||
bool EmbedderEngine::CollectShell() { |
|||
shell_.reset(); |
|||
return IsValid(); |
|||
} |
|||
|
|||
bool EmbedderEngine::RunRootIsolate() { |
|||
if (!IsValid() || !run_configuration_.IsValid()) { |
|||
return false; |
|||
} |
|||
shell_->RunEngine(std::move(run_configuration_)); |
|||
return true; |
|||
} |
|||
|
|||
bool EmbedderEngine::IsValid() const { return static_cast<bool>(shell_); } |
|||
|
|||
const TaskRunners& EmbedderEngine::GetTaskRunners() const { |
|||
return task_runners_; |
|||
} |
|||
|
|||
bool EmbedderEngine::NotifyCreated() { |
|||
if (!IsValid()) { |
|||
return false; |
|||
} |
|||
|
|||
shell_->GetPlatformView()->NotifyCreated(); |
|||
return true; |
|||
} |
|||
|
|||
bool EmbedderEngine::NotifyDestroyed() { |
|||
if (!IsValid()) { |
|||
return false; |
|||
} |
|||
|
|||
shell_->GetPlatformView()->NotifyDestroyed(); |
|||
return true; |
|||
} |
|||
|
|||
bool EmbedderEngine::SetViewportMetrics(ViewportMetrics metrics) { |
|||
if (!IsValid()) { |
|||
return false; |
|||
} |
|||
|
|||
auto platform_view = shell_->GetPlatformView(); |
|||
if (!platform_view) { |
|||
return false; |
|||
} |
|||
platform_view->SetViewportMetrics(std::move(metrics)); |
|||
return true; |
|||
} |
|||
|
|||
bool EmbedderEngine::DispatchPointerDataPacket( |
|||
std::unique_ptr<PointerDataPacket> packet) { |
|||
if (!IsValid() || !packet) { |
|||
return false; |
|||
} |
|||
|
|||
auto platform_view = shell_->GetPlatformView(); |
|||
if (!platform_view) { |
|||
return false; |
|||
} |
|||
|
|||
platform_view->DispatchPointerDataPacket(std::move(packet)); |
|||
return true; |
|||
} |
|||
|
|||
bool EmbedderEngine::SendPlatformMessage(fml::RefPtr<PlatformMessage> message) { |
|||
if (!IsValid() || !message) { |
|||
return false; |
|||
} |
|||
|
|||
auto platform_view = shell_->GetPlatformView(); |
|||
if (!platform_view) { |
|||
return false; |
|||
} |
|||
|
|||
platform_view->DispatchPlatformMessage(message); |
|||
return true; |
|||
} |
|||
|
|||
bool EmbedderEngine::RegisterTexture(int64_t texture) { |
|||
if (!IsValid() || !external_texture_callback_) { |
|||
return false; |
|||
} |
|||
shell_->GetPlatformView()->RegisterTexture( |
|||
std::make_unique<EmbedderExternalTextureGL>(texture, |
|||
external_texture_callback_)); |
|||
return true; |
|||
} |
|||
|
|||
bool EmbedderEngine::UnregisterTexture(int64_t texture) { |
|||
if (!IsValid() || !external_texture_callback_) { |
|||
return false; |
|||
} |
|||
shell_->GetPlatformView()->UnregisterTexture(texture); |
|||
return true; |
|||
} |
|||
|
|||
bool EmbedderEngine::MarkTextureFrameAvailable(int64_t texture) { |
|||
if (!IsValid() || !external_texture_callback_) { |
|||
return false; |
|||
} |
|||
shell_->GetPlatformView()->MarkTextureFrameAvailable(texture); |
|||
return true; |
|||
} |
|||
|
|||
bool EmbedderEngine::SetAccessibilityFeatures(int32_t flags) { |
|||
if (!IsValid()) { |
|||
return false; |
|||
} |
|||
auto platform_view = shell_->GetPlatformView(); |
|||
if (!platform_view) { |
|||
return false; |
|||
} |
|||
platform_view->SetAccessibilityFeatures(flags); |
|||
return true; |
|||
} |
|||
|
|||
bool EmbedderEngine::OnVsyncEvent(intptr_t baton, |
|||
fml::TimePoint frame_start_time, |
|||
fml::TimePoint frame_target_time) { |
|||
if (!IsValid()) { |
|||
return false; |
|||
} |
|||
|
|||
return VsyncWaiterEmbedder::OnEmbedderVsync(baton, frame_start_time, |
|||
frame_target_time); |
|||
} |
|||
|
|||
bool EmbedderEngine::ReloadSystemFonts() { |
|||
if (!IsValid()) { |
|||
return false; |
|||
} |
|||
|
|||
return shell_->ReloadSystemFonts(); |
|||
} |
|||
|
|||
bool EmbedderEngine::PostRenderThreadTask(const fml::closure& task) { |
|||
if (!IsValid()) { |
|||
return false; |
|||
} |
|||
|
|||
shell_->GetTaskRunners().GetRasterTaskRunner()->PostTask(task); |
|||
return true; |
|||
} |
|||
|
|||
bool EmbedderEngine::RunTask(const UIWidgetsTask* task) { |
|||
// The shell doesn't need to be running or valid for access to the thread
|
|||
// host. This is why there is no `IsValid` check here. This allows embedders
|
|||
// to perform custom task runner interop before the shell is running.
|
|||
if (task == nullptr) { |
|||
return false; |
|||
} |
|||
return thread_host_->PostTask(reinterpret_cast<int64_t>(task->runner), |
|||
task->task); |
|||
} |
|||
|
|||
bool EmbedderEngine::PostTaskOnEngineManagedNativeThreads( |
|||
std::function<void(UIWidgetsNativeThreadType)> closure) const { |
|||
if (!IsValid() || closure == nullptr) { |
|||
return false; |
|||
} |
|||
|
|||
const auto trampoline = [closure](UIWidgetsNativeThreadType type, |
|||
fml::RefPtr<fml::TaskRunner> runner) { |
|||
runner->PostTask([closure, type] { closure(type); }); |
|||
}; |
|||
|
|||
// Post the task to all thread host threads.
|
|||
const auto& task_runners = shell_->GetTaskRunners(); |
|||
trampoline(kUIWidgetsNativeThreadTypeRender, |
|||
task_runners.GetRasterTaskRunner()); |
|||
trampoline(kUIWidgetsNativeThreadTypeWorker, task_runners.GetIOTaskRunner()); |
|||
trampoline(kUIWidgetsNativeThreadTypeUI, task_runners.GetUITaskRunner()); |
|||
trampoline(kUIWidgetsNativeThreadTypePlatform, |
|||
task_runners.GetPlatformTaskRunner()); |
|||
|
|||
// Post the task to all worker threads.
|
|||
auto engine = shell_->GetEngine(); |
|||
engine->GetConcurrentMessageLoop()->PostTaskToAllWorkers( |
|||
[closure]() { closure(kUIWidgetsNativeThreadTypeWorker); }); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
Shell& EmbedderEngine::GetShell() { |
|||
FML_DCHECK(shell_); |
|||
return *shell_.get(); |
|||
} |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include <memory> |
|||
#include <unordered_map> |
|||
|
|||
#include "flutter/fml/macros.h" |
|||
#include "shell/common/shell.h" |
|||
#include "shell/common/thread_host.h" |
|||
#include "shell/platform/embedder/embedder.h" |
|||
#include "shell/platform/embedder/embedder_engine.h" |
|||
#include "shell/platform/embedder/embedder_external_texture_gl.h" |
|||
#include "shell/platform/embedder/embedder_thread_host.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
struct ShellArgs; |
|||
|
|||
class EmbedderEngine { |
|||
public: |
|||
EmbedderEngine(std::unique_ptr<EmbedderThreadHost> thread_host, |
|||
const TaskRunners& task_runners, const WindowData& window_data, const Settings& settings, |
|||
RunConfiguration run_configuration, |
|||
Shell::CreateCallback<PlatformView> on_create_platform_view, |
|||
Shell::CreateCallback<Rasterizer> on_create_rasterizer, |
|||
EmbedderExternalTextureGL::ExternalTextureCallback |
|||
external_texture_callback); |
|||
|
|||
~EmbedderEngine(); |
|||
|
|||
bool LaunchShell(); |
|||
|
|||
bool CollectShell(); |
|||
|
|||
const TaskRunners& GetTaskRunners() const; |
|||
|
|||
bool NotifyCreated(); |
|||
|
|||
bool NotifyDestroyed(); |
|||
|
|||
bool RunRootIsolate(); |
|||
|
|||
bool IsValid() const; |
|||
|
|||
bool SetViewportMetrics(ViewportMetrics metrics); |
|||
|
|||
bool DispatchPointerDataPacket(std::unique_ptr<PointerDataPacket> packet); |
|||
|
|||
bool SendPlatformMessage(fml::RefPtr<PlatformMessage> message); |
|||
|
|||
bool RegisterTexture(int64_t texture); |
|||
|
|||
bool UnregisterTexture(int64_t texture); |
|||
|
|||
bool MarkTextureFrameAvailable(int64_t texture); |
|||
|
|||
bool SetAccessibilityFeatures(int32_t flags); |
|||
|
|||
bool OnVsyncEvent(intptr_t baton, fml::TimePoint frame_start_time, |
|||
fml::TimePoint frame_target_time); |
|||
|
|||
bool ReloadSystemFonts(); |
|||
|
|||
bool PostRenderThreadTask(const fml::closure& task); |
|||
|
|||
bool RunTask(const UIWidgetsTask* task); |
|||
|
|||
bool PostTaskOnEngineManagedNativeThreads( |
|||
std::function<void(UIWidgetsNativeThreadType)> closure) const; |
|||
|
|||
Shell& GetShell(); |
|||
|
|||
private: |
|||
const std::unique_ptr<EmbedderThreadHost> thread_host_; |
|||
TaskRunners task_runners_; |
|||
RunConfiguration run_configuration_; |
|||
std::unique_ptr<ShellArgs> shell_args_; |
|||
std::unique_ptr<Shell> shell_; |
|||
const EmbedderExternalTextureGL::ExternalTextureCallback |
|||
external_texture_callback_; |
|||
|
|||
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderEngine); |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#include "embedder_external_texture_gl.h"
|
|||
|
|||
#include "flutter/fml/logging.h"
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
EmbedderExternalTextureGL::EmbedderExternalTextureGL( |
|||
int64_t texture_identifier, const ExternalTextureCallback& callback) |
|||
: Texture(texture_identifier), external_texture_callback_(callback) { |
|||
FML_DCHECK(external_texture_callback_); |
|||
} |
|||
|
|||
EmbedderExternalTextureGL::~EmbedderExternalTextureGL() = default; |
|||
|
|||
// |flutter::Texture|
|
|||
void EmbedderExternalTextureGL::Paint(SkCanvas& canvas, const SkRect& bounds, |
|||
bool freeze, GrContext* context) { |
|||
if (auto image = external_texture_callback_( |
|||
Id(), //
|
|||
canvas.getGrContext(), //
|
|||
SkISize::Make(bounds.width(), bounds.height()) //
|
|||
)) { |
|||
last_image_ = image; |
|||
} |
|||
|
|||
if (last_image_) { |
|||
if (bounds != SkRect::Make(last_image_->bounds())) { |
|||
canvas.drawImageRect(last_image_, bounds, nullptr); |
|||
} else { |
|||
canvas.drawImage(last_image_, bounds.x(), bounds.y()); |
|||
} |
|||
} |
|||
} |
|||
|
|||
// |flutter::Texture|
|
|||
void EmbedderExternalTextureGL::OnGrContextCreated() {} |
|||
|
|||
// |flutter::Texture|
|
|||
void EmbedderExternalTextureGL::OnGrContextDestroyed() {} |
|||
|
|||
// |flutter::Texture|
|
|||
void EmbedderExternalTextureGL::MarkNewFrameAvailable() {} |
|||
|
|||
// |flutter::Texture|
|
|||
void EmbedderExternalTextureGL::OnTextureUnregistered() {} |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include "flow/texture.h" |
|||
#include "flutter/fml/macros.h" |
|||
#include "include/core/SkImage.h" |
|||
#include "include/core/SkSize.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class EmbedderExternalTextureGL : public Texture { |
|||
public: |
|||
using ExternalTextureCallback = std::function<sk_sp<SkImage>( |
|||
int64_t texture_identifier, GrContext*, const SkISize&)>; |
|||
|
|||
EmbedderExternalTextureGL(int64_t texture_identifier, |
|||
const ExternalTextureCallback& callback); |
|||
|
|||
~EmbedderExternalTextureGL(); |
|||
|
|||
private: |
|||
ExternalTextureCallback external_texture_callback_; |
|||
sk_sp<SkImage> last_image_; |
|||
|
|||
// |flutter::Texture| |
|||
void Paint(SkCanvas& canvas, const SkRect& bounds, bool freeze, |
|||
GrContext* context) override; |
|||
|
|||
// |flutter::Texture| |
|||
void OnGrContextCreated() override; |
|||
|
|||
// |flutter::Texture| |
|||
void OnGrContextDestroyed() override; |
|||
|
|||
// |flutter::Texture| |
|||
void MarkNewFrameAvailable() override; |
|||
|
|||
// |flutter::Texture| |
|||
void OnTextureUnregistered() override; |
|||
|
|||
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderExternalTextureGL); |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#include "embedder_external_view.h"
|
|||
|
|||
#include "flutter/fml/trace_event.h"
|
|||
#include "shell/common/canvas_spy.h"
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
static SkISize TransformedSurfaceSize(const SkISize& size, |
|||
const SkMatrix& transformation) { |
|||
const auto source_rect = SkRect::MakeWH(size.width(), size.height()); |
|||
const auto transformed_rect = transformation.mapRect(source_rect); |
|||
return SkISize::Make(transformed_rect.width(), transformed_rect.height()); |
|||
} |
|||
|
|||
EmbedderExternalView::EmbedderExternalView( |
|||
const SkISize& frame_size, const SkMatrix& surface_transformation) |
|||
: EmbedderExternalView(frame_size, surface_transformation, {}, nullptr) {} |
|||
|
|||
EmbedderExternalView::EmbedderExternalView( |
|||
const SkISize& frame_size, const SkMatrix& surface_transformation, |
|||
ViewIdentifier view_identifier, std::unique_ptr<EmbeddedViewParams> params) |
|||
: render_surface_size_( |
|||
TransformedSurfaceSize(frame_size, surface_transformation)), |
|||
surface_transformation_(surface_transformation), |
|||
view_identifier_(view_identifier), |
|||
embedded_view_params_(std::move(params)), |
|||
recorder_(std::make_unique<SkPictureRecorder>()), |
|||
canvas_spy_(std::make_unique<CanvasSpy>(recorder_->beginRecording( |
|||
frame_size.width(), frame_size.height()))) {} |
|||
|
|||
EmbedderExternalView::~EmbedderExternalView() = default; |
|||
|
|||
EmbedderExternalView::RenderTargetDescriptor |
|||
EmbedderExternalView::CreateRenderTargetDescriptor() const { |
|||
return {view_identifier_, render_surface_size_}; |
|||
} |
|||
|
|||
SkCanvas* EmbedderExternalView::GetCanvas() const { |
|||
return canvas_spy_->GetSpyingCanvas(); |
|||
} |
|||
|
|||
SkISize EmbedderExternalView::GetRenderSurfaceSize() const { |
|||
return render_surface_size_; |
|||
} |
|||
|
|||
bool EmbedderExternalView::IsRootView() const { return !HasPlatformView(); } |
|||
|
|||
bool EmbedderExternalView::HasPlatformView() const { |
|||
return view_identifier_.platform_view_id.has_value(); |
|||
} |
|||
|
|||
bool EmbedderExternalView::HasEngineRenderedContents() const { |
|||
return canvas_spy_->DidDrawIntoCanvas(); |
|||
} |
|||
|
|||
EmbedderExternalView::ViewIdentifier EmbedderExternalView::GetViewIdentifier() |
|||
const { |
|||
return view_identifier_; |
|||
} |
|||
|
|||
const EmbeddedViewParams* EmbedderExternalView::GetEmbeddedViewParams() const { |
|||
return embedded_view_params_.get(); |
|||
} |
|||
|
|||
bool EmbedderExternalView::Render(const EmbedderRenderTarget& render_target) { |
|||
TRACE_EVENT0("flutter", "EmbedderExternalView::Render"); |
|||
|
|||
FML_DCHECK(HasEngineRenderedContents()) |
|||
<< "Unnecessarily asked to render into a render target when there was " |
|||
"nothing to render."; |
|||
|
|||
auto picture = recorder_->finishRecordingAsPicture(); |
|||
if (!picture) { |
|||
return false; |
|||
} |
|||
|
|||
auto surface = render_target.GetRenderSurface(); |
|||
if (!surface) { |
|||
return false; |
|||
} |
|||
|
|||
FML_DCHECK(SkISize::Make(surface->width(), surface->height()) == |
|||
render_surface_size_); |
|||
|
|||
auto canvas = surface->getCanvas(); |
|||
if (!canvas) { |
|||
return false; |
|||
} |
|||
|
|||
canvas->setMatrix(surface_transformation_); |
|||
canvas->clear(SK_ColorTRANSPARENT); |
|||
canvas->drawPicture(picture); |
|||
canvas->flush(); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include <optional> |
|||
#include <unordered_map> |
|||
#include <unordered_set> |
|||
|
|||
#include "flow/embedded_views.h" |
|||
#include "flutter/fml/hash_combine.h" |
|||
#include "flutter/fml/macros.h" |
|||
#include "include/core/SkPictureRecorder.h" |
|||
#include "shell/common/canvas_spy.h" |
|||
#include "shell/platform/embedder/embedder_render_target.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class EmbedderExternalView { |
|||
public: |
|||
using PlatformViewID = int64_t; |
|||
struct ViewIdentifier { |
|||
std::optional<PlatformViewID> platform_view_id; |
|||
|
|||
ViewIdentifier() {} |
|||
|
|||
ViewIdentifier(PlatformViewID view_id) : platform_view_id(view_id) {} |
|||
|
|||
struct Hash { |
|||
constexpr std::size_t operator()(const ViewIdentifier& desc) const { |
|||
if (!desc.platform_view_id.has_value()) { |
|||
return fml::HashCombine(); |
|||
} |
|||
|
|||
return fml::HashCombine(desc.platform_view_id.value()); |
|||
} |
|||
}; |
|||
|
|||
struct Equal { |
|||
constexpr bool operator()(const ViewIdentifier& lhs, |
|||
const ViewIdentifier& rhs) const { |
|||
return lhs.platform_view_id == rhs.platform_view_id; |
|||
} |
|||
}; |
|||
}; |
|||
|
|||
struct RenderTargetDescriptor { |
|||
ViewIdentifier view_identifier; |
|||
SkISize surface_size; |
|||
|
|||
RenderTargetDescriptor(ViewIdentifier p_view_identifier, |
|||
SkISize p_surface_size) |
|||
: view_identifier(p_view_identifier), surface_size(p_surface_size) {} |
|||
|
|||
struct Hash { |
|||
constexpr std::size_t operator()( |
|||
const RenderTargetDescriptor& desc) const { |
|||
return fml::HashCombine(desc.surface_size.width(), |
|||
desc.surface_size.height(), |
|||
ViewIdentifier::Hash{}(desc.view_identifier)); |
|||
} |
|||
}; |
|||
|
|||
struct Equal { |
|||
bool operator()(const RenderTargetDescriptor& lhs, |
|||
const RenderTargetDescriptor& rhs) const { |
|||
return lhs.surface_size == rhs.surface_size && |
|||
ViewIdentifier::Equal{}(lhs.view_identifier, |
|||
rhs.view_identifier); |
|||
} |
|||
}; |
|||
}; |
|||
|
|||
using ViewIdentifierSet = |
|||
std::unordered_set<ViewIdentifier, ViewIdentifier::Hash, |
|||
ViewIdentifier::Equal>; |
|||
|
|||
using PendingViews = |
|||
std::unordered_map<ViewIdentifier, std::unique_ptr<EmbedderExternalView>, |
|||
ViewIdentifier::Hash, ViewIdentifier::Equal>; |
|||
|
|||
EmbedderExternalView(const SkISize& frame_size, |
|||
const SkMatrix& surface_transformation); |
|||
|
|||
EmbedderExternalView(const SkISize& frame_size, |
|||
const SkMatrix& surface_transformation, |
|||
ViewIdentifier view_identifier, |
|||
std::unique_ptr<EmbeddedViewParams> params); |
|||
|
|||
~EmbedderExternalView(); |
|||
|
|||
bool IsRootView() const; |
|||
|
|||
bool HasPlatformView() const; |
|||
|
|||
bool HasEngineRenderedContents() const; |
|||
|
|||
ViewIdentifier GetViewIdentifier() const; |
|||
|
|||
const EmbeddedViewParams* GetEmbeddedViewParams() const; |
|||
|
|||
RenderTargetDescriptor CreateRenderTargetDescriptor() const; |
|||
|
|||
SkCanvas* GetCanvas() const; |
|||
|
|||
SkISize GetRenderSurfaceSize() const; |
|||
|
|||
bool Render(const EmbedderRenderTarget& render_target); |
|||
|
|||
private: |
|||
const SkISize render_surface_size_; |
|||
const SkMatrix surface_transformation_; |
|||
ViewIdentifier view_identifier_; |
|||
std::unique_ptr<EmbeddedViewParams> embedded_view_params_; |
|||
std::unique_ptr<SkPictureRecorder> recorder_; |
|||
std::unique_ptr<CanvasSpy> canvas_spy_; |
|||
|
|||
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderExternalView); |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#include "embedder_external_view_embedder.h"
|
|||
|
|||
#include <algorithm>
|
|||
|
|||
#include "include/gpu/GrContext.h"
|
|||
#include "shell/platform/embedder/embedder_layers.h"
|
|||
#include "shell/platform/embedder/embedder_render_target.h"
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
EmbedderExternalViewEmbedder::EmbedderExternalViewEmbedder( |
|||
const CreateRenderTargetCallback& create_render_target_callback, |
|||
const PresentCallback& present_callback) |
|||
: create_render_target_callback_(create_render_target_callback), |
|||
present_callback_(present_callback) { |
|||
FML_DCHECK(create_render_target_callback_); |
|||
FML_DCHECK(present_callback_); |
|||
} |
|||
|
|||
EmbedderExternalViewEmbedder::~EmbedderExternalViewEmbedder() = default; |
|||
|
|||
void EmbedderExternalViewEmbedder::SetSurfaceTransformationCallback( |
|||
SurfaceTransformationCallback surface_transformation_callback) { |
|||
surface_transformation_callback_ = surface_transformation_callback; |
|||
} |
|||
|
|||
SkMatrix EmbedderExternalViewEmbedder::GetSurfaceTransformation() const { |
|||
if (!surface_transformation_callback_) { |
|||
return SkMatrix{}; |
|||
} |
|||
|
|||
return surface_transformation_callback_(); |
|||
} |
|||
|
|||
void EmbedderExternalViewEmbedder::Reset() { |
|||
pending_views_.clear(); |
|||
composition_order_.clear(); |
|||
} |
|||
|
|||
// |ExternalViewEmbedder|
|
|||
void EmbedderExternalViewEmbedder::CancelFrame() { Reset(); } |
|||
|
|||
// |ExternalViewEmbedder|
|
|||
void EmbedderExternalViewEmbedder::BeginFrame(SkISize frame_size, |
|||
GrContext* context, |
|||
double device_pixel_ratio) { |
|||
Reset(); |
|||
|
|||
pending_frame_size_ = frame_size; |
|||
pending_device_pixel_ratio_ = device_pixel_ratio; |
|||
pending_surface_transformation_ = GetSurfaceTransformation(); |
|||
|
|||
static const auto kRootViewIdentifier = |
|||
EmbedderExternalView::ViewIdentifier{}; |
|||
|
|||
pending_views_[kRootViewIdentifier] = std::make_unique<EmbedderExternalView>( |
|||
pending_frame_size_, pending_surface_transformation_); |
|||
composition_order_.push_back(kRootViewIdentifier); |
|||
} |
|||
|
|||
// |ExternalViewEmbedder|
|
|||
void EmbedderExternalViewEmbedder::PrerollCompositeEmbeddedView( |
|||
int view_id, std::unique_ptr<EmbeddedViewParams> params) { |
|||
FML_DCHECK(pending_views_.count(view_id) == 0); |
|||
|
|||
pending_views_[view_id] = std::make_unique<EmbedderExternalView>( |
|||
pending_frame_size_, // frame size
|
|||
pending_surface_transformation_, // surface xformation
|
|||
view_id, // view identifier
|
|||
std::move(params) // embedded view params
|
|||
); |
|||
composition_order_.push_back(view_id); |
|||
} |
|||
|
|||
// |ExternalViewEmbedder|
|
|||
SkCanvas* EmbedderExternalViewEmbedder::GetRootCanvas() { |
|||
auto found = pending_views_.find(EmbedderExternalView::ViewIdentifier{}); |
|||
if (found == pending_views_.end()) { |
|||
FML_DLOG(WARNING) |
|||
<< "No root canvas could be found. This is extremely unlikely and " |
|||
"indicates that the external view embedder did not receive the " |
|||
"notification to begin the frame."; |
|||
return nullptr; |
|||
} |
|||
return found->second->GetCanvas(); |
|||
} |
|||
|
|||
// |ExternalViewEmbedder|
|
|||
std::vector<SkCanvas*> EmbedderExternalViewEmbedder::GetCurrentCanvases() { |
|||
std::vector<SkCanvas*> canvases; |
|||
for (const auto& view : pending_views_) { |
|||
const auto& external_view = view.second; |
|||
// This method (for legacy reasons) expects non-root current canvases.
|
|||
if (!external_view->IsRootView()) { |
|||
canvases.push_back(external_view->GetCanvas()); |
|||
} |
|||
} |
|||
return canvases; |
|||
} |
|||
|
|||
// |ExternalViewEmbedder|
|
|||
SkCanvas* EmbedderExternalViewEmbedder::CompositeEmbeddedView(int view_id) { |
|||
auto found = pending_views_.find(view_id); |
|||
if (found == pending_views_.end()) { |
|||
FML_DCHECK(false) << "Attempted to composite a view that was not " |
|||
"pre-rolled."; |
|||
return nullptr; |
|||
} |
|||
return found->second->GetCanvas(); |
|||
} |
|||
|
|||
static UIWidgetsBackingStoreConfig MakeBackingStoreConfig( |
|||
const SkISize& backing_store_size) { |
|||
UIWidgetsBackingStoreConfig config = {}; |
|||
|
|||
config.struct_size = sizeof(config); |
|||
|
|||
config.size.width = backing_store_size.width(); |
|||
config.size.height = backing_store_size.height(); |
|||
|
|||
return config; |
|||
} |
|||
|
|||
// |ExternalViewEmbedder|
|
|||
bool EmbedderExternalViewEmbedder::SubmitFrame(GrContext* context, |
|||
SkCanvas* background_canvas) { |
|||
auto [matched_render_targets, pending_keys] = |
|||
render_target_cache_.GetExistingTargetsInCache(pending_views_); |
|||
|
|||
// This is where unused render targets will be collected. Control may flow to
|
|||
// the embedder. Here, the embedder has the opportunity to trample on the
|
|||
// OpenGL context.
|
|||
//
|
|||
// For optimum performance, we should tell the render target cache to clear
|
|||
// its unused entries before allocating new ones. This collection step before
|
|||
// allocating new render targets ameliorates peak memory usage within the
|
|||
// frame. But, this causes an issue in a known internal embedder. To work
|
|||
// around this issue while that embedder migrates, collection of render
|
|||
// targets is deferred after the presentation.
|
|||
//
|
|||
// @warning: Embedder may trample on our OpenGL context here.
|
|||
auto deferred_cleanup_render_targets = |
|||
render_target_cache_.ClearAllRenderTargetsInCache(); |
|||
|
|||
for (const auto& pending_key : pending_keys) { |
|||
const auto& external_view = pending_views_.at(pending_key); |
|||
|
|||
// If the external view does not have engine rendered contents, it makes no
|
|||
// sense to ask to embedder to create a render target for us as we don't
|
|||
// intend to render into it and ask the embedder for presentation anyway.
|
|||
// Save some memory.
|
|||
if (!external_view->HasEngineRenderedContents()) { |
|||
continue; |
|||
} |
|||
|
|||
// This is the size of render surface we want the embedder to create for
|
|||
// us. As or right now, this is going to always be equal to the frame size
|
|||
// post transformation. But, in case optimizations are applied that make
|
|||
// it so that embedder rendered into surfaces that aren't full screen,
|
|||
// this assumption will break. So it's just best to ask view for its size
|
|||
// directly.
|
|||
const auto render_surface_size = external_view->GetRenderSurfaceSize(); |
|||
|
|||
const auto backing_store_config = |
|||
MakeBackingStoreConfig(render_surface_size); |
|||
|
|||
// This is where the embedder will create render targets for us. Control
|
|||
// flow to the embedder makes the engine susceptible to having the embedder
|
|||
// trample on the OpenGL context. Before any Skia operations are performed,
|
|||
// the context must be reset.
|
|||
//
|
|||
// @warning: Embedder may trample on our OpenGL context here.
|
|||
auto render_target = |
|||
create_render_target_callback_(context, backing_store_config); |
|||
|
|||
if (!render_target) { |
|||
FML_LOG(ERROR) << "Embedder did not return a valid render target."; |
|||
return false; |
|||
} |
|||
matched_render_targets[pending_key] = std::move(render_target); |
|||
} |
|||
|
|||
// The OpenGL context could have been trampled by the embedder at this point
|
|||
// as it attempted to collect old render targets and create new ones. Tell
|
|||
// Skia to not rely on existing bindings.
|
|||
if (context) { |
|||
context->resetContext(kAll_GrBackendState); |
|||
} |
|||
|
|||
// Scribble embedder provide render targets. The order in which we scribble
|
|||
// into the buffers is irrelevant to the presentation order.
|
|||
for (const auto& render_target : matched_render_targets) { |
|||
if (!pending_views_.at(render_target.first) |
|||
->Render(*render_target.second)) { |
|||
FML_LOG(ERROR) |
|||
<< "Could not render into the embedder supplied render target."; |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
// We are going to be transferring control back over to the embedder there the
|
|||
// context may be trampled upon again. Flush all operations to the underlying
|
|||
// rendering API.
|
|||
//
|
|||
// @warning: Embedder may trample on our OpenGL context here.
|
|||
if (context) { |
|||
context->flush(GrFlushInfo()); |
|||
} |
|||
|
|||
// Submit the scribbled layer to the embedder for presentation.
|
|||
//
|
|||
// @warning: Embedder may trample on our OpenGL context here.
|
|||
{ |
|||
EmbedderLayers presented_layers(pending_frame_size_, |
|||
pending_device_pixel_ratio_, |
|||
pending_surface_transformation_); |
|||
// In composition order, submit backing stores and platform views to the
|
|||
// embedder.
|
|||
for (const auto& view_id : composition_order_) { |
|||
// If the external view has a platform view, ask the emebdder to place it
|
|||
// before the Flutter rendered contents for that interleaving level.
|
|||
const auto& external_view = pending_views_.at(view_id); |
|||
if (external_view->HasPlatformView()) { |
|||
presented_layers.PushPlatformViewLayer( |
|||
external_view->GetViewIdentifier() |
|||
.platform_view_id.value(), // view id
|
|||
*external_view->GetEmbeddedViewParams() // view params
|
|||
); |
|||
} |
|||
|
|||
// If the view has engine rendered contents, ask the embedder to place
|
|||
// Flutter rendered contents for this interleaving level on top of a
|
|||
// platform view.
|
|||
if (external_view->HasEngineRenderedContents()) { |
|||
const auto& exteral_render_target = matched_render_targets.at(view_id); |
|||
presented_layers.PushBackingStoreLayer( |
|||
exteral_render_target->GetBackingStore()); |
|||
} |
|||
} |
|||
|
|||
// Flush the layer description down to the embedder for presentation.
|
|||
//
|
|||
// @warning: Embedder may trample on our OpenGL context here.
|
|||
presented_layers.InvokePresentCallback(present_callback_); |
|||
} |
|||
|
|||
// See why this is necessary in the comment where this collection in realized.
|
|||
//
|
|||
// @warning: Embedder may trample on our OpenGL context here.
|
|||
deferred_cleanup_render_targets.clear(); |
|||
|
|||
// Hold all rendered layers in the render target cache for one frame to
|
|||
// see if they may be reused next frame.
|
|||
for (auto& render_target : matched_render_targets) { |
|||
render_target_cache_.CacheRenderTarget(render_target.first, |
|||
std::move(render_target.second)); |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
// |ExternalViewEmbedder|
|
|||
void EmbedderExternalViewEmbedder::FinishFrame() {} |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include <map> |
|||
#include <unordered_map> |
|||
|
|||
#include "flow/embedded_views.h" |
|||
#include "flutter/fml/hash_combine.h" |
|||
#include "flutter/fml/macros.h" |
|||
#include "shell/platform/embedder/embedder_external_view.h" |
|||
#include "shell/platform/embedder/embedder_render_target_cache.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class EmbedderExternalViewEmbedder final : public ExternalViewEmbedder { |
|||
public: |
|||
using CreateRenderTargetCallback = |
|||
std::function<std::unique_ptr<EmbedderRenderTarget>( |
|||
GrContext* context, const UIWidgetsBackingStoreConfig& config)>; |
|||
using PresentCallback = |
|||
std::function<bool(const std::vector<const UIWidgetsLayer*>& layers)>; |
|||
using SurfaceTransformationCallback = std::function<SkMatrix(void)>; |
|||
|
|||
EmbedderExternalViewEmbedder( |
|||
const CreateRenderTargetCallback& create_render_target_callback, |
|||
const PresentCallback& present_callback); |
|||
|
|||
~EmbedderExternalViewEmbedder() override; |
|||
|
|||
void SetSurfaceTransformationCallback( |
|||
SurfaceTransformationCallback surface_transformation_callback); |
|||
|
|||
private: |
|||
// |ExternalViewEmbedder| |
|||
void CancelFrame() override; |
|||
|
|||
// |ExternalViewEmbedder| |
|||
void BeginFrame(SkISize frame_size, GrContext* context, |
|||
double device_pixel_ratio) override; |
|||
|
|||
// |ExternalViewEmbedder| |
|||
void PrerollCompositeEmbeddedView( |
|||
int view_id, std::unique_ptr<EmbeddedViewParams> params) override; |
|||
|
|||
// |ExternalViewEmbedder| |
|||
std::vector<SkCanvas*> GetCurrentCanvases() override; |
|||
|
|||
// |ExternalViewEmbedder| |
|||
SkCanvas* CompositeEmbeddedView(int view_id) override; |
|||
|
|||
// |ExternalViewEmbedder| |
|||
bool SubmitFrame(GrContext* context, SkCanvas* background_canvas) override; |
|||
|
|||
// |ExternalViewEmbedder| |
|||
void FinishFrame() override; |
|||
|
|||
// |ExternalViewEmbedder| |
|||
SkCanvas* GetRootCanvas() override; |
|||
|
|||
private: |
|||
const CreateRenderTargetCallback create_render_target_callback_; |
|||
const PresentCallback present_callback_; |
|||
SurfaceTransformationCallback surface_transformation_callback_; |
|||
SkISize pending_frame_size_ = SkISize::Make(0, 0); |
|||
double pending_device_pixel_ratio_ = 1.0; |
|||
SkMatrix pending_surface_transformation_; |
|||
EmbedderExternalView::PendingViews pending_views_; |
|||
std::vector<EmbedderExternalView::ViewIdentifier> composition_order_; |
|||
EmbedderRenderTargetCache render_target_cache_; |
|||
|
|||
void Reset(); |
|||
|
|||
SkMatrix GetSurfaceTransformation() const; |
|||
|
|||
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderExternalViewEmbedder); |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#include "embedder_layers.h"
|
|||
|
|||
#include <algorithm>
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
EmbedderLayers::EmbedderLayers(SkISize frame_size, double device_pixel_ratio, |
|||
SkMatrix root_surface_transformation) |
|||
: frame_size_(frame_size), |
|||
device_pixel_ratio_(device_pixel_ratio), |
|||
root_surface_transformation_(root_surface_transformation) {} |
|||
|
|||
EmbedderLayers::~EmbedderLayers() = default; |
|||
|
|||
void EmbedderLayers::PushBackingStoreLayer(const UIWidgetsBackingStore* store) { |
|||
UIWidgetsLayer layer = {}; |
|||
|
|||
layer.struct_size = sizeof(UIWidgetsLayer); |
|||
layer.type = kUIWidgetsLayerContentTypeBackingStore; |
|||
layer.backing_store = store; |
|||
|
|||
const auto layer_bounds = |
|||
SkRect::MakeWH(frame_size_.width(), frame_size_.height()); |
|||
|
|||
const auto transformed_layer_bounds = |
|||
root_surface_transformation_.mapRect(layer_bounds); |
|||
|
|||
layer.offset.x = transformed_layer_bounds.x(); |
|||
layer.offset.y = transformed_layer_bounds.y(); |
|||
layer.size.width = transformed_layer_bounds.width(); |
|||
layer.size.height = transformed_layer_bounds.height(); |
|||
|
|||
presented_layers_.push_back(layer); |
|||
} |
|||
|
|||
static std::unique_ptr<UIWidgetsPlatformViewMutation> ConvertMutation( |
|||
double opacity) { |
|||
UIWidgetsPlatformViewMutation mutation = {}; |
|||
mutation.type = kUIWidgetsPlatformViewMutationTypeOpacity; |
|||
mutation.opacity = opacity; |
|||
return std::make_unique<UIWidgetsPlatformViewMutation>(mutation); |
|||
} |
|||
|
|||
static std::unique_ptr<UIWidgetsPlatformViewMutation> ConvertMutation( |
|||
const SkRect& rect) { |
|||
UIWidgetsPlatformViewMutation mutation = {}; |
|||
mutation.type = kUIWidgetsPlatformViewMutationTypeClipRect; |
|||
mutation.clip_rect.left = rect.left(); |
|||
mutation.clip_rect.top = rect.top(); |
|||
mutation.clip_rect.right = rect.right(); |
|||
mutation.clip_rect.bottom = rect.bottom(); |
|||
return std::make_unique<UIWidgetsPlatformViewMutation>(mutation); |
|||
} |
|||
|
|||
static UIWidgetsSize VectorToSize(const SkVector& vector) { |
|||
UIWidgetsSize size = {}; |
|||
size.width = vector.x(); |
|||
size.height = vector.y(); |
|||
return size; |
|||
} |
|||
|
|||
static std::unique_ptr<UIWidgetsPlatformViewMutation> ConvertMutation( |
|||
const SkRRect& rrect) { |
|||
UIWidgetsPlatformViewMutation mutation = {}; |
|||
mutation.type = kUIWidgetsPlatformViewMutationTypeClipRoundedRect; |
|||
const auto& rect = rrect.rect(); |
|||
mutation.clip_rounded_rect.rect.left = rect.left(); |
|||
mutation.clip_rounded_rect.rect.top = rect.top(); |
|||
mutation.clip_rounded_rect.rect.right = rect.right(); |
|||
mutation.clip_rounded_rect.rect.bottom = rect.bottom(); |
|||
mutation.clip_rounded_rect.upper_left_corner_radius = |
|||
VectorToSize(rrect.radii(SkRRect::Corner::kUpperLeft_Corner)); |
|||
mutation.clip_rounded_rect.upper_right_corner_radius = |
|||
VectorToSize(rrect.radii(SkRRect::Corner::kUpperRight_Corner)); |
|||
mutation.clip_rounded_rect.lower_right_corner_radius = |
|||
VectorToSize(rrect.radii(SkRRect::Corner::kLowerRight_Corner)); |
|||
mutation.clip_rounded_rect.lower_left_corner_radius = |
|||
VectorToSize(rrect.radii(SkRRect::Corner::kLowerLeft_Corner)); |
|||
return std::make_unique<UIWidgetsPlatformViewMutation>(mutation); |
|||
} |
|||
|
|||
static std::unique_ptr<UIWidgetsPlatformViewMutation> ConvertMutation( |
|||
const SkMatrix& matrix) { |
|||
UIWidgetsPlatformViewMutation mutation = {}; |
|||
mutation.type = kUIWidgetsPlatformViewMutationTypeTransformation; |
|||
mutation.transformation.scaleX = matrix[SkMatrix::kMScaleX]; |
|||
mutation.transformation.skewX = matrix[SkMatrix::kMSkewX]; |
|||
mutation.transformation.transX = matrix[SkMatrix::kMTransX]; |
|||
mutation.transformation.skewY = matrix[SkMatrix::kMSkewY]; |
|||
mutation.transformation.scaleY = matrix[SkMatrix::kMScaleY]; |
|||
mutation.transformation.transY = matrix[SkMatrix::kMTransY]; |
|||
mutation.transformation.pers0 = matrix[SkMatrix::kMPersp0]; |
|||
mutation.transformation.pers1 = matrix[SkMatrix::kMPersp1]; |
|||
mutation.transformation.pers2 = matrix[SkMatrix::kMPersp2]; |
|||
return std::make_unique<UIWidgetsPlatformViewMutation>(mutation); |
|||
} |
|||
|
|||
void EmbedderLayers::PushPlatformViewLayer( |
|||
UIWidgetsPlatformViewIdentifier identifier, |
|||
const EmbeddedViewParams& params) { |
|||
{ |
|||
UIWidgetsPlatformView view = {}; |
|||
view.struct_size = sizeof(UIWidgetsPlatformView); |
|||
view.identifier = identifier; |
|||
|
|||
const auto& mutators = params.mutatorsStack; |
|||
|
|||
std::vector<const UIWidgetsPlatformViewMutation*> mutations_array; |
|||
|
|||
for (auto i = mutators.Bottom(); i != mutators.Top(); ++i) { |
|||
const auto& mutator = *i; |
|||
switch (mutator->GetType()) { |
|||
case MutatorType::clip_rect: { |
|||
mutations_array.push_back( |
|||
mutations_referenced_ |
|||
.emplace_back(ConvertMutation(mutator->GetRect())) |
|||
.get()); |
|||
} break; |
|||
case MutatorType::clip_rrect: { |
|||
mutations_array.push_back( |
|||
mutations_referenced_ |
|||
.emplace_back(ConvertMutation(mutator->GetRRect())) |
|||
.get()); |
|||
} break; |
|||
case MutatorType::clip_path: { |
|||
// Unsupported mutation.
|
|||
} break; |
|||
case MutatorType::transform: { |
|||
const auto& matrix = mutator->GetMatrix(); |
|||
if (!matrix.isIdentity()) { |
|||
mutations_array.push_back( |
|||
mutations_referenced_.emplace_back(ConvertMutation(matrix)) |
|||
.get()); |
|||
} |
|||
} break; |
|||
case MutatorType::opacity: { |
|||
const double opacity = |
|||
std::clamp(mutator->GetAlphaFloat(), 0.0f, 1.0f); |
|||
if (opacity < 1.0) { |
|||
mutations_array.push_back( |
|||
mutations_referenced_.emplace_back(ConvertMutation(opacity)) |
|||
.get()); |
|||
} |
|||
} break; |
|||
} |
|||
} |
|||
|
|||
if (!mutations_array.empty()) { |
|||
// If there are going to be any mutations, they must first take into
|
|||
// account the root surface transformation.
|
|||
if (!root_surface_transformation_.isIdentity()) { |
|||
mutations_array.push_back( |
|||
mutations_referenced_ |
|||
.emplace_back(ConvertMutation(root_surface_transformation_)) |
|||
.get()); |
|||
} |
|||
|
|||
auto mutations = |
|||
std::make_unique<std::vector<const UIWidgetsPlatformViewMutation*>>( |
|||
mutations_array.rbegin(), mutations_array.rend()); |
|||
mutations_arrays_referenced_.emplace_back(std::move(mutations)); |
|||
|
|||
view.mutations_count = mutations_array.size(); |
|||
view.mutations = mutations_arrays_referenced_.back().get()->data(); |
|||
} |
|||
|
|||
platform_views_referenced_.emplace_back( |
|||
std::make_unique<UIWidgetsPlatformView>(view)); |
|||
} |
|||
|
|||
UIWidgetsLayer layer = {}; |
|||
|
|||
layer.struct_size = sizeof(UIWidgetsLayer); |
|||
layer.type = kUIWidgetsLayerContentTypePlatformView; |
|||
layer.platform_view = platform_views_referenced_.back().get(); |
|||
|
|||
const auto layer_bounds = |
|||
SkRect::MakeXYWH(params.offsetPixels.x(), //
|
|||
params.offsetPixels.y(), //
|
|||
params.sizePoints.width() * device_pixel_ratio_, //
|
|||
params.sizePoints.height() * device_pixel_ratio_ //
|
|||
); |
|||
|
|||
const auto transformed_layer_bounds = |
|||
root_surface_transformation_.mapRect(layer_bounds); |
|||
|
|||
layer.offset.x = transformed_layer_bounds.x(); |
|||
layer.offset.y = transformed_layer_bounds.y(); |
|||
layer.size.width = transformed_layer_bounds.width(); |
|||
layer.size.height = transformed_layer_bounds.height(); |
|||
|
|||
presented_layers_.push_back(layer); |
|||
} |
|||
|
|||
void EmbedderLayers::InvokePresentCallback( |
|||
const PresentCallback& callback) const { |
|||
std::vector<const UIWidgetsLayer*> presented_layers_pointers; |
|||
presented_layers_pointers.reserve(presented_layers_.size()); |
|||
for (const auto& layer : presented_layers_) { |
|||
presented_layers_pointers.push_back(&layer); |
|||
} |
|||
callback(std::move(presented_layers_pointers)); |
|||
} |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include <memory> |
|||
#include <vector> |
|||
|
|||
#include "flow/embedded_views.h" |
|||
#include "flutter/fml/macros.h" |
|||
#include "include/core/SkMatrix.h" |
|||
#include "include/core/SkSize.h" |
|||
#include "shell/platform/embedder/embedder.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class EmbedderLayers { |
|||
public: |
|||
EmbedderLayers(SkISize frame_size, double device_pixel_ratio, |
|||
SkMatrix root_surface_transformation); |
|||
|
|||
~EmbedderLayers(); |
|||
|
|||
void PushBackingStoreLayer(const UIWidgetsBackingStore* store); |
|||
|
|||
void PushPlatformViewLayer(UIWidgetsPlatformViewIdentifier identifier, |
|||
const EmbeddedViewParams& params); |
|||
|
|||
using PresentCallback = |
|||
std::function<bool(const std::vector<const UIWidgetsLayer*>& layers)>; |
|||
void InvokePresentCallback(const PresentCallback& callback) const; |
|||
|
|||
private: |
|||
const SkISize frame_size_; |
|||
const double device_pixel_ratio_; |
|||
const SkMatrix root_surface_transformation_; |
|||
std::vector<std::unique_ptr<UIWidgetsPlatformView>> |
|||
platform_views_referenced_; |
|||
std::vector<std::unique_ptr<UIWidgetsPlatformViewMutation>> |
|||
mutations_referenced_; |
|||
std::vector< |
|||
std::unique_ptr<std::vector<const UIWidgetsPlatformViewMutation*>>> |
|||
mutations_arrays_referenced_; |
|||
std::vector<UIWidgetsLayer> presented_layers_; |
|||
|
|||
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderLayers); |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#include "embedder_platform_message_response.h"
|
|||
|
|||
#include "flutter/fml/make_copyable.h"
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
EmbedderPlatformMessageResponse::EmbedderPlatformMessageResponse( |
|||
fml::RefPtr<fml::TaskRunner> runner, const Callback& callback) |
|||
: runner_(std::move(runner)), callback_(callback) {} |
|||
|
|||
EmbedderPlatformMessageResponse::~EmbedderPlatformMessageResponse() = default; |
|||
|
|||
// |PlatformMessageResponse|
|
|||
void EmbedderPlatformMessageResponse::Complete( |
|||
std::unique_ptr<fml::Mapping> data) { |
|||
if (!data) { |
|||
CompleteEmpty(); |
|||
return; |
|||
} |
|||
|
|||
runner_->PostTask( |
|||
fml::MakeCopyable([data = std::move(data), callback = callback_]() { |
|||
callback(data->GetMapping(), data->GetSize()); |
|||
})); |
|||
} |
|||
|
|||
// |PlatformMessageResponse|
|
|||
void EmbedderPlatformMessageResponse::CompleteEmpty() { |
|||
Complete(std::make_unique<fml::NonOwnedMapping>(nullptr, 0u)); |
|||
} |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include "flutter/fml/macros.h" |
|||
#include "flutter/fml/task_runner.h" |
|||
#include "lib/ui/window/platform_message_response.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class EmbedderPlatformMessageResponse : public PlatformMessageResponse { |
|||
public: |
|||
using Callback = std::function<void(const uint8_t* data, size_t size)>; |
|||
|
|||
EmbedderPlatformMessageResponse(fml::RefPtr<fml::TaskRunner> runner, |
|||
const Callback& callback); |
|||
|
|||
~EmbedderPlatformMessageResponse() override; |
|||
|
|||
private: |
|||
fml::RefPtr<fml::TaskRunner> runner_; |
|||
Callback callback_; |
|||
|
|||
// |PlatformMessageResponse| |
|||
void Complete(std::unique_ptr<fml::Mapping> data) override; |
|||
|
|||
// |PlatformMessageResponse| |
|||
void CompleteEmpty() override; |
|||
|
|||
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderPlatformMessageResponse); |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#pragma once
|
|||
|
|||
#include "embedder_render_target.h"
|
|||
|
|||
#include "flutter/fml/logging.h"
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
EmbedderRenderTarget::EmbedderRenderTarget(UIWidgetsBackingStore backing_store, |
|||
sk_sp<SkSurface> render_surface, |
|||
fml::closure on_release) |
|||
: backing_store_(backing_store), |
|||
render_surface_(std::move(render_surface)), |
|||
on_release_(on_release) { |
|||
// TODO(38468): The optimization to elide backing store updates between frames
|
|||
// has not been implemented yet.
|
|||
backing_store_.did_update = true; |
|||
FML_DCHECK(render_surface_); |
|||
} |
|||
|
|||
EmbedderRenderTarget::~EmbedderRenderTarget() { |
|||
if (on_release_) { |
|||
on_release_(); |
|||
} |
|||
} |
|||
|
|||
const UIWidgetsBackingStore* EmbedderRenderTarget::GetBackingStore() const { |
|||
return &backing_store_; |
|||
} |
|||
|
|||
sk_sp<SkSurface> EmbedderRenderTarget::GetRenderSurface() const { |
|||
return render_surface_; |
|||
} |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include "flutter/fml/closure.h" |
|||
#include "flutter/fml/macros.h" |
|||
#include "include/core/SkCanvas.h" |
|||
#include "include/core/SkSurface.h" |
|||
#include "shell/platform/embedder/embedder.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class EmbedderRenderTarget { |
|||
public: |
|||
EmbedderRenderTarget(UIWidgetsBackingStore backing_store, |
|||
sk_sp<SkSurface> render_surface, |
|||
fml::closure on_release); |
|||
~EmbedderRenderTarget(); |
|||
|
|||
sk_sp<SkSurface> GetRenderSurface() const; |
|||
|
|||
const UIWidgetsBackingStore* GetBackingStore() const; |
|||
|
|||
private: |
|||
UIWidgetsBackingStore backing_store_; |
|||
sk_sp<SkSurface> render_surface_; |
|||
fml::closure on_release_; |
|||
|
|||
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderRenderTarget); |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#include "embedder_render_target_cache.h"
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
EmbedderRenderTargetCache::EmbedderRenderTargetCache() = default; |
|||
|
|||
EmbedderRenderTargetCache::~EmbedderRenderTargetCache() = default; |
|||
|
|||
std::pair<EmbedderRenderTargetCache::RenderTargets, |
|||
EmbedderExternalView::ViewIdentifierSet> |
|||
EmbedderRenderTargetCache::GetExistingTargetsInCache( |
|||
const EmbedderExternalView::PendingViews& pending_views) { |
|||
RenderTargets resolved_render_targets; |
|||
EmbedderExternalView::ViewIdentifierSet unmatched_identifiers; |
|||
|
|||
for (const auto& view : pending_views) { |
|||
const auto& external_view = view.second; |
|||
if (!external_view->HasEngineRenderedContents()) { |
|||
continue; |
|||
} |
|||
auto& compatible_targets = |
|||
cached_render_targets_[external_view->CreateRenderTargetDescriptor()]; |
|||
if (compatible_targets.size() == 0) { |
|||
unmatched_identifiers.insert(view.first); |
|||
} else { |
|||
std::unique_ptr<EmbedderRenderTarget> target = |
|||
std::move(compatible_targets.top()); |
|||
compatible_targets.pop(); |
|||
resolved_render_targets[view.first] = std::move(target); |
|||
} |
|||
} |
|||
return {std::move(resolved_render_targets), std::move(unmatched_identifiers)}; |
|||
} |
|||
|
|||
std::set<std::unique_ptr<EmbedderRenderTarget>> |
|||
EmbedderRenderTargetCache::ClearAllRenderTargetsInCache() { |
|||
std::set<std::unique_ptr<EmbedderRenderTarget>> cleared_targets; |
|||
for (auto& targets : cached_render_targets_) { |
|||
auto& targets_stack = targets.second; |
|||
while (!targets_stack.empty()) { |
|||
cleared_targets.emplace(std::move(targets_stack.top())); |
|||
targets_stack.pop(); |
|||
} |
|||
} |
|||
cached_render_targets_.clear(); |
|||
return cleared_targets; |
|||
} |
|||
|
|||
void EmbedderRenderTargetCache::CacheRenderTarget( |
|||
EmbedderExternalView::ViewIdentifier view_identifier, |
|||
std::unique_ptr<EmbedderRenderTarget> target) { |
|||
if (target == nullptr) { |
|||
return; |
|||
} |
|||
auto surface = target->GetRenderSurface(); |
|||
auto desc = EmbedderExternalView::RenderTargetDescriptor{ |
|||
view_identifier, SkISize::Make(surface->width(), surface->height())}; |
|||
cached_render_targets_[desc].push(std::move(target)); |
|||
} |
|||
|
|||
size_t EmbedderRenderTargetCache::GetCachedTargetsCount() const { |
|||
size_t count = 0; |
|||
for (const auto& targets : cached_render_targets_) { |
|||
count += targets.second.size(); |
|||
} |
|||
return count; |
|||
} |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include <set> |
|||
#include <stack> |
|||
#include <tuple> |
|||
#include <unordered_map> |
|||
|
|||
#include "flutter/fml/macros.h" |
|||
#include "shell/platform/embedder/embedder_external_view.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class EmbedderRenderTargetCache { |
|||
public: |
|||
EmbedderRenderTargetCache(); |
|||
|
|||
~EmbedderRenderTargetCache(); |
|||
|
|||
using RenderTargets = |
|||
std::unordered_map<EmbedderExternalView::ViewIdentifier, |
|||
std::unique_ptr<EmbedderRenderTarget>, |
|||
EmbedderExternalView::ViewIdentifier::Hash, |
|||
EmbedderExternalView::ViewIdentifier::Equal>; |
|||
|
|||
std::pair<RenderTargets, EmbedderExternalView::ViewIdentifierSet> |
|||
GetExistingTargetsInCache( |
|||
const EmbedderExternalView::PendingViews& pending_views); |
|||
|
|||
std::set<std::unique_ptr<EmbedderRenderTarget>> |
|||
ClearAllRenderTargetsInCache(); |
|||
|
|||
void CacheRenderTarget(EmbedderExternalView::ViewIdentifier view_identifier, |
|||
std::unique_ptr<EmbedderRenderTarget> target); |
|||
|
|||
size_t GetCachedTargetsCount() const; |
|||
|
|||
private: |
|||
using CachedRenderTargets = |
|||
std::unordered_map<EmbedderExternalView::RenderTargetDescriptor, |
|||
std::stack<std::unique_ptr<EmbedderRenderTarget>>, |
|||
EmbedderExternalView::RenderTargetDescriptor::Hash, |
|||
EmbedderExternalView::RenderTargetDescriptor::Equal>; |
|||
|
|||
CachedRenderTargets cached_render_targets_; |
|||
|
|||
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderRenderTargetCache); |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#include "embedder_surface.h"
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
EmbedderSurface::EmbedderSurface() = default; |
|||
|
|||
EmbedderSurface::~EmbedderSurface() = default; |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include "flow/embedded_views.h" |
|||
#include "flutter/fml/macros.h" |
|||
#include "shell/common/surface.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class EmbedderSurface { |
|||
public: |
|||
EmbedderSurface(); |
|||
|
|||
virtual ~EmbedderSurface(); |
|||
|
|||
virtual bool IsValid() const = 0; |
|||
|
|||
virtual std::unique_ptr<Surface> CreateGPUSurface() = 0; |
|||
|
|||
virtual sk_sp<GrContext> CreateResourceContext() const = 0; |
|||
|
|||
private: |
|||
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderSurface); |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#include "embedder_surface_gl.h"
|
|||
|
|||
#include "shell/common/shell_io_manager.h"
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
EmbedderSurfaceGL::EmbedderSurfaceGL( |
|||
GLDispatchTable gl_dispatch_table, bool fbo_reset_after_present, |
|||
std::unique_ptr<EmbedderExternalViewEmbedder> external_view_embedder) |
|||
: gl_dispatch_table_(gl_dispatch_table), |
|||
fbo_reset_after_present_(fbo_reset_after_present), |
|||
external_view_embedder_(std::move(external_view_embedder)) { |
|||
// Make sure all required members of the dispatch table are checked.
|
|||
if (!gl_dispatch_table_.gl_make_current_callback || |
|||
!gl_dispatch_table_.gl_clear_current_callback || |
|||
!gl_dispatch_table_.gl_present_callback || |
|||
!gl_dispatch_table_.gl_fbo_callback) { |
|||
return; |
|||
} |
|||
|
|||
valid_ = true; |
|||
} |
|||
|
|||
EmbedderSurfaceGL::~EmbedderSurfaceGL() = default; |
|||
|
|||
// |EmbedderSurface|
|
|||
bool EmbedderSurfaceGL::IsValid() const { return valid_; } |
|||
|
|||
// |GPUSurfaceGLDelegate|
|
|||
bool EmbedderSurfaceGL::GLContextMakeCurrent() { |
|||
return gl_dispatch_table_.gl_make_current_callback(); |
|||
} |
|||
|
|||
// |GPUSurfaceGLDelegate|
|
|||
bool EmbedderSurfaceGL::GLContextClearCurrent() { |
|||
return gl_dispatch_table_.gl_clear_current_callback(); |
|||
} |
|||
|
|||
// |GPUSurfaceGLDelegate|
|
|||
bool EmbedderSurfaceGL::GLContextPresent() { |
|||
return gl_dispatch_table_.gl_present_callback(); |
|||
} |
|||
|
|||
// |GPUSurfaceGLDelegate|
|
|||
intptr_t EmbedderSurfaceGL::GLContextFBO() const { |
|||
return gl_dispatch_table_.gl_fbo_callback(); |
|||
} |
|||
|
|||
// |GPUSurfaceGLDelegate|
|
|||
bool EmbedderSurfaceGL::GLContextFBOResetAfterPresent() const { |
|||
return fbo_reset_after_present_; |
|||
} |
|||
|
|||
// |GPUSurfaceGLDelegate|
|
|||
SkMatrix EmbedderSurfaceGL::GLContextSurfaceTransformation() const { |
|||
auto callback = gl_dispatch_table_.gl_surface_transformation_callback; |
|||
if (!callback) { |
|||
SkMatrix matrix; |
|||
matrix.setIdentity(); |
|||
return matrix; |
|||
} |
|||
return callback(); |
|||
} |
|||
|
|||
// |GPUSurfaceGLDelegate|
|
|||
ExternalViewEmbedder* EmbedderSurfaceGL::GetExternalViewEmbedder() { |
|||
return external_view_embedder_.get(); |
|||
} |
|||
|
|||
// |GPUSurfaceGLDelegate|
|
|||
EmbedderSurfaceGL::GLProcResolver EmbedderSurfaceGL::GetGLProcResolver() const { |
|||
return gl_dispatch_table_.gl_proc_resolver; |
|||
} |
|||
|
|||
// |EmbedderSurface|
|
|||
std::unique_ptr<Surface> EmbedderSurfaceGL::CreateGPUSurface() { |
|||
const bool render_to_surface = !external_view_embedder_; |
|||
return std::make_unique<GPUSurfaceGL>(this, // GPU surface GL delegate
|
|||
render_to_surface // render to surface
|
|||
|
|||
); |
|||
} |
|||
|
|||
// |EmbedderSurface|
|
|||
sk_sp<GrContext> EmbedderSurfaceGL::CreateResourceContext() const { |
|||
auto callback = gl_dispatch_table_.gl_make_resource_current_callback; |
|||
if (callback && callback()) { |
|||
if (auto context = ShellIOManager::CreateCompatibleResourceLoadingContext( |
|||
GrBackend::kOpenGL_GrBackend, GetGLInterface())) { |
|||
return context; |
|||
} else { |
|||
FML_LOG(ERROR) |
|||
<< "Internal error: Resource context available but could not create " |
|||
"a compatible Skia context."; |
|||
return nullptr; |
|||
} |
|||
} |
|||
|
|||
// The callback was not available or failed.
|
|||
FML_LOG(ERROR) |
|||
<< "Could not create a resource context for async texture uploads. " |
|||
"Expect degraded performance. Set a valid make_resource_current " |
|||
"callback on FlutterOpenGLRendererConfig."; |
|||
return nullptr; |
|||
} |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include "flutter/fml/macros.h" |
|||
#include "shell/gpu/gpu_surface_gl.h" |
|||
#include "shell/platform/embedder/embedder_external_view_embedder.h" |
|||
#include "shell/platform/embedder/embedder_surface.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class EmbedderSurfaceGL final : public EmbedderSurface, |
|||
public GPUSurfaceGLDelegate { |
|||
public: |
|||
struct GLDispatchTable { |
|||
std::function<bool(void)> gl_make_current_callback; // required |
|||
std::function<bool(void)> gl_clear_current_callback; // required |
|||
std::function<bool(void)> gl_present_callback; // required |
|||
std::function<intptr_t(void)> gl_fbo_callback; // required |
|||
std::function<bool(void)> gl_make_resource_current_callback; // optional |
|||
std::function<SkMatrix(void)> |
|||
gl_surface_transformation_callback; // optional |
|||
std::function<void*(const char*)> gl_proc_resolver; // optional |
|||
}; |
|||
|
|||
EmbedderSurfaceGL( |
|||
GLDispatchTable gl_dispatch_table, bool fbo_reset_after_present, |
|||
std::unique_ptr<EmbedderExternalViewEmbedder> external_view_embedder); |
|||
|
|||
~EmbedderSurfaceGL() override; |
|||
|
|||
private: |
|||
bool valid_ = false; |
|||
GLDispatchTable gl_dispatch_table_; |
|||
bool fbo_reset_after_present_; |
|||
|
|||
std::unique_ptr<EmbedderExternalViewEmbedder> external_view_embedder_; |
|||
|
|||
// |EmbedderSurface| |
|||
bool IsValid() const override; |
|||
|
|||
// |EmbedderSurface| |
|||
std::unique_ptr<Surface> CreateGPUSurface() override; |
|||
|
|||
// |EmbedderSurface| |
|||
sk_sp<GrContext> CreateResourceContext() const override; |
|||
|
|||
// |GPUSurfaceGLDelegate| |
|||
bool GLContextMakeCurrent() override; |
|||
|
|||
// |GPUSurfaceGLDelegate| |
|||
bool GLContextClearCurrent() override; |
|||
|
|||
// |GPUSurfaceGLDelegate| |
|||
bool GLContextPresent() override; |
|||
|
|||
// |GPUSurfaceGLDelegate| |
|||
intptr_t GLContextFBO() const override; |
|||
|
|||
// |GPUSurfaceGLDelegate| |
|||
bool GLContextFBOResetAfterPresent() const override; |
|||
|
|||
// |GPUSurfaceGLDelegate| |
|||
SkMatrix GLContextSurfaceTransformation() const override; |
|||
|
|||
// |GPUSurfaceGLDelegate| |
|||
ExternalViewEmbedder* GetExternalViewEmbedder() override; |
|||
|
|||
// |GPUSurfaceGLDelegate| |
|||
GLProcResolver GetGLProcResolver() const override; |
|||
|
|||
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderSurfaceGL); |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#pragma once
|
|||
|
|||
#include "embedder_surface_software.h"
|
|||
|
|||
#include "flutter/fml/trace_event.h"
|
|||
#include "include/gpu/GrContext.h"
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
EmbedderSurfaceSoftware::EmbedderSurfaceSoftware( |
|||
SoftwareDispatchTable software_dispatch_table, |
|||
std::unique_ptr<EmbedderExternalViewEmbedder> external_view_embedder) |
|||
: software_dispatch_table_(software_dispatch_table), |
|||
external_view_embedder_(std::move(external_view_embedder)) { |
|||
if (!software_dispatch_table_.software_present_backing_store) { |
|||
return; |
|||
} |
|||
valid_ = true; |
|||
} |
|||
|
|||
EmbedderSurfaceSoftware::~EmbedderSurfaceSoftware() = default; |
|||
|
|||
// |EmbedderSurface|
|
|||
bool EmbedderSurfaceSoftware::IsValid() const { return valid_; } |
|||
|
|||
// |EmbedderSurface|
|
|||
std::unique_ptr<Surface> EmbedderSurfaceSoftware::CreateGPUSurface() { |
|||
if (!IsValid()) { |
|||
return nullptr; |
|||
} |
|||
const bool render_to_surface = !external_view_embedder_; |
|||
auto surface = std::make_unique<GPUSurfaceSoftware>(this, render_to_surface); |
|||
|
|||
if (!surface->IsValid()) { |
|||
return nullptr; |
|||
} |
|||
|
|||
return surface; |
|||
} |
|||
|
|||
// |EmbedderSurface|
|
|||
sk_sp<GrContext> EmbedderSurfaceSoftware::CreateResourceContext() const { |
|||
return nullptr; |
|||
} |
|||
|
|||
// |GPUSurfaceSoftwareDelegate|
|
|||
sk_sp<SkSurface> EmbedderSurfaceSoftware::AcquireBackingStore( |
|||
const SkISize& size) { |
|||
TRACE_EVENT0("flutter", "EmbedderSurfaceSoftware::AcquireBackingStore"); |
|||
if (!IsValid()) { |
|||
FML_LOG(ERROR) |
|||
<< "Could not acquire backing store for the software surface."; |
|||
return nullptr; |
|||
} |
|||
|
|||
if (sk_surface_ != nullptr && |
|||
SkISize::Make(sk_surface_->width(), sk_surface_->height()) == size) { |
|||
// The old and new surface sizes are the same. Nothing to do here.
|
|||
return sk_surface_; |
|||
} |
|||
|
|||
SkImageInfo info = SkImageInfo::MakeN32( |
|||
size.fWidth, size.fHeight, kPremul_SkAlphaType, SkColorSpace::MakeSRGB()); |
|||
sk_surface_ = SkSurface::MakeRaster(info, nullptr); |
|||
|
|||
if (sk_surface_ == nullptr) { |
|||
FML_LOG(ERROR) << "Could not create backing store for software rendering."; |
|||
return nullptr; |
|||
} |
|||
|
|||
return sk_surface_; |
|||
} |
|||
|
|||
// |GPUSurfaceSoftwareDelegate|
|
|||
bool EmbedderSurfaceSoftware::PresentBackingStore( |
|||
sk_sp<SkSurface> backing_store) { |
|||
if (!IsValid()) { |
|||
FML_LOG(ERROR) << "Tried to present an invalid software surface."; |
|||
return false; |
|||
} |
|||
|
|||
SkPixmap pixmap; |
|||
if (!backing_store->peekPixels(&pixmap)) { |
|||
FML_LOG(ERROR) << "Could not peek the pixels of the backing store."; |
|||
return false; |
|||
} |
|||
|
|||
// Some basic sanity checking.
|
|||
uint64_t expected_pixmap_data_size = pixmap.width() * pixmap.height() * 4; |
|||
|
|||
const size_t pixmap_size = pixmap.computeByteSize(); |
|||
|
|||
if (expected_pixmap_data_size != pixmap_size) { |
|||
FML_LOG(ERROR) << "Software backing store had unexpected size."; |
|||
return false; |
|||
} |
|||
|
|||
return software_dispatch_table_.software_present_backing_store( |
|||
pixmap.addr(), //
|
|||
pixmap.rowBytes(), //
|
|||
pixmap.height() //
|
|||
); |
|||
} |
|||
|
|||
// |GPUSurfaceSoftwareDelegate|
|
|||
ExternalViewEmbedder* EmbedderSurfaceSoftware::GetExternalViewEmbedder() { |
|||
return external_view_embedder_.get(); |
|||
} |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include "flutter/fml/macros.h" |
|||
#include "shell/gpu/gpu_surface_software.h" |
|||
#include "shell/platform/embedder/embedder_external_view_embedder.h" |
|||
#include "shell/platform/embedder/embedder_surface.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class EmbedderSurfaceSoftware final : public EmbedderSurface, |
|||
public GPUSurfaceSoftwareDelegate { |
|||
public: |
|||
struct SoftwareDispatchTable { |
|||
std::function<bool(const void* allocation, size_t row_bytes, size_t height)> |
|||
software_present_backing_store; // required |
|||
}; |
|||
|
|||
EmbedderSurfaceSoftware( |
|||
SoftwareDispatchTable software_dispatch_table, |
|||
std::unique_ptr<EmbedderExternalViewEmbedder> external_view_embedder); |
|||
|
|||
~EmbedderSurfaceSoftware() override; |
|||
|
|||
private: |
|||
bool valid_ = false; |
|||
SoftwareDispatchTable software_dispatch_table_; |
|||
sk_sp<SkSurface> sk_surface_; |
|||
std::unique_ptr<EmbedderExternalViewEmbedder> external_view_embedder_; |
|||
|
|||
// |EmbedderSurface| |
|||
bool IsValid() const override; |
|||
|
|||
// |EmbedderSurface| |
|||
std::unique_ptr<Surface> CreateGPUSurface() override; |
|||
|
|||
// |EmbedderSurface| |
|||
sk_sp<GrContext> CreateResourceContext() const override; |
|||
|
|||
// |GPUSurfaceSoftwareDelegate| |
|||
sk_sp<SkSurface> AcquireBackingStore(const SkISize& size) override; |
|||
|
|||
// |GPUSurfaceSoftwareDelegate| |
|||
bool PresentBackingStore(sk_sp<SkSurface> backing_store) override; |
|||
|
|||
// |GPUSurfaceSoftwareDelegate| |
|||
ExternalViewEmbedder* GetExternalViewEmbedder() override; |
|||
|
|||
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderSurfaceSoftware); |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#include "embedder_task_runner.h"
|
|||
|
|||
#include "flutter/fml/message_loop_impl.h"
|
|||
#include "flutter/fml/message_loop_task_queues.h"
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
EmbedderTaskRunner::EmbedderTaskRunner(DispatchTable table, |
|||
size_t embedder_identifier) |
|||
: TaskRunner(nullptr /* loop implemenation*/), |
|||
embedder_identifier_(embedder_identifier), |
|||
dispatch_table_(std::move(table)), |
|||
placeholder_id_( |
|||
fml::MessageLoopTaskQueues::GetInstance()->CreateTaskQueue()) { |
|||
FML_DCHECK(dispatch_table_.post_task_callback); |
|||
FML_DCHECK(dispatch_table_.runs_task_on_current_thread_callback); |
|||
} |
|||
|
|||
EmbedderTaskRunner::~EmbedderTaskRunner() = default; |
|||
|
|||
size_t EmbedderTaskRunner::GetEmbedderIdentifier() const { |
|||
return embedder_identifier_; |
|||
} |
|||
|
|||
void EmbedderTaskRunner::PostTask(const fml::closure& task) { |
|||
PostTaskForTime(task, fml::TimePoint::Now()); |
|||
} |
|||
|
|||
void EmbedderTaskRunner::PostTaskForTime(const fml::closure& task, |
|||
fml::TimePoint target_time) { |
|||
if (!task) { |
|||
return; |
|||
} |
|||
|
|||
uint64_t baton = 0; |
|||
|
|||
{ |
|||
// Release the lock before the jump via the dispatch table.
|
|||
std::scoped_lock lock(tasks_mutex_); |
|||
baton = ++last_baton_; |
|||
pending_tasks_[baton] = task; |
|||
} |
|||
|
|||
dispatch_table_.post_task_callback(this, baton, target_time); |
|||
} |
|||
|
|||
void EmbedderTaskRunner::PostDelayedTask(const fml::closure& task, |
|||
fml::TimeDelta delay) { |
|||
PostTaskForTime(task, fml::TimePoint::Now() + delay); |
|||
} |
|||
|
|||
bool EmbedderTaskRunner::RunsTasksOnCurrentThread() { |
|||
return dispatch_table_.runs_task_on_current_thread_callback(); |
|||
} |
|||
|
|||
bool EmbedderTaskRunner::PostTask(uint64_t baton) { |
|||
fml::closure task; |
|||
|
|||
{ |
|||
std::scoped_lock lock(tasks_mutex_); |
|||
auto found = pending_tasks_.find(baton); |
|||
if (found == pending_tasks_.end()) { |
|||
FML_LOG(ERROR) << "Embedder attempted to post an unknown task."; |
|||
return false; |
|||
} |
|||
task = found->second; |
|||
pending_tasks_.erase(found); |
|||
|
|||
// Let go of the tasks mutex before executing the task.
|
|||
} |
|||
|
|||
FML_DCHECK(task); |
|||
task(); |
|||
return true; |
|||
} |
|||
|
|||
// |fml::TaskRunner|
|
|||
fml::TaskQueueId EmbedderTaskRunner::GetTaskQueueId() { |
|||
return placeholder_id_; |
|||
} |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include <mutex> |
|||
#include <unordered_map> |
|||
|
|||
#include "flutter/fml/macros.h" |
|||
#include "flutter/fml/task_runner.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class EmbedderTaskRunner final : public fml::TaskRunner { |
|||
public: |
|||
struct DispatchTable { |
|||
std::function<void(EmbedderTaskRunner* task_runner, uint64_t task_baton, |
|||
fml::TimePoint target_time)> |
|||
post_task_callback; |
|||
|
|||
std::function<bool(void)> runs_task_on_current_thread_callback; |
|||
}; |
|||
|
|||
EmbedderTaskRunner(DispatchTable table, size_t embedder_identifier); |
|||
|
|||
~EmbedderTaskRunner() override; |
|||
|
|||
size_t GetEmbedderIdentifier() const; |
|||
|
|||
bool PostTask(uint64_t baton); |
|||
|
|||
private: |
|||
const size_t embedder_identifier_; |
|||
DispatchTable dispatch_table_; |
|||
std::mutex tasks_mutex_; |
|||
uint64_t last_baton_; |
|||
std::unordered_map<uint64_t, fml::closure> pending_tasks_; |
|||
fml::TaskQueueId placeholder_id_; |
|||
|
|||
void PostTask(const fml::closure& task) override; |
|||
|
|||
void PostTaskForTime(const fml::closure& task, |
|||
fml::TimePoint target_time) override; |
|||
|
|||
void PostDelayedTask(const fml::closure& task, fml::TimeDelta delay) override; |
|||
|
|||
bool RunsTasksOnCurrentThread() override; |
|||
|
|||
fml::TaskQueueId GetTaskQueueId() override; |
|||
|
|||
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderTaskRunner); |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#define FML_USED_ON_EMBEDDER
|
|||
|
|||
#include "embedder_thread_host.h"
|
|||
|
|||
#include <algorithm>
|
|||
|
|||
#include "flutter/fml/message_loop.h"
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
static std::pair<bool, fml::RefPtr<EmbedderTaskRunner>> |
|||
CreateEmbedderTaskRunner(const UIWidgetsTaskRunnerDescription* description) { |
|||
if (description == nullptr) { |
|||
// This is not embedder error. The embedder API will just have to create a
|
|||
// plain old task runner (and create a thread for it) instead of using a
|
|||
// task runner provided to us by the embedder.
|
|||
return {true, {}}; |
|||
} |
|||
|
|||
if (description->runs_task_on_current_thread_callback == nullptr) { |
|||
FML_LOG(ERROR) << "UIWidgetsTaskRunnerDescription.runs_task_on_current_" |
|||
"thread_callback was nullptr."; |
|||
return {false, {}}; |
|||
} |
|||
|
|||
if (description->post_task_callback == nullptr) { |
|||
FML_LOG(ERROR) |
|||
<< "UIWidgetsTaskRunnerDescription.post_task_callback was nullptr."; |
|||
return {false, {}}; |
|||
} |
|||
|
|||
auto user_data = description->user_data; |
|||
|
|||
auto post_task_callback_c = description->post_task_callback; |
|||
auto runs_task_on_current_thread_callback_c = |
|||
description->runs_task_on_current_thread_callback; |
|||
|
|||
EmbedderTaskRunner::DispatchTable task_runner_dispatch_table = { |
|||
// .post_task_callback
|
|||
[post_task_callback_c, user_data](EmbedderTaskRunner* task_runner, |
|||
uint64_t task_baton, |
|||
fml::TimePoint target_time) -> void { |
|||
UIWidgetsTask task = { |
|||
// runner
|
|||
reinterpret_cast<UIWidgetsTaskRunner>(task_runner), |
|||
// task
|
|||
task_baton, |
|||
}; |
|||
post_task_callback_c(task, target_time.ToEpochDelta().ToNanoseconds(), |
|||
user_data); |
|||
}, |
|||
// runs_task_on_current_thread_callback
|
|||
[runs_task_on_current_thread_callback_c, user_data]() -> bool { |
|||
return runs_task_on_current_thread_callback_c(user_data); |
|||
}}; |
|||
|
|||
return {true, fml::MakeRefCounted<EmbedderTaskRunner>( |
|||
task_runner_dispatch_table, description->identifier)}; |
|||
} |
|||
|
|||
static fml::RefPtr<fml::TaskRunner> GetCurrentThreadTaskRunner() { |
|||
fml::MessageLoop::EnsureInitializedForCurrentThread(); |
|||
return fml::MessageLoop::GetCurrent().GetTaskRunner(); |
|||
} |
|||
|
|||
constexpr const char* kUIWidgetsThreadName = "io.uiwidgets"; |
|||
|
|||
// static
|
|||
std::unique_ptr<EmbedderThreadHost> |
|||
EmbedderThreadHost::CreateEmbedderManagedThreadHost( |
|||
const UIWidgetsCustomTaskRunners* custom_task_runners) { |
|||
if (custom_task_runners == nullptr) { |
|||
return nullptr; |
|||
} |
|||
|
|||
// The IO threads are always created by the engine and the embedder
|
|||
// has no opportunity to specify task runners for the same.
|
|||
//
|
|||
// If/when more task runners are exposed, this mask will need to be updated.
|
|||
uint64_t engine_thread_host_mask = ThreadHost::Type::IO; |
|||
|
|||
auto platform_task_runner_pair = |
|||
CreateEmbedderTaskRunner(custom_task_runners->platform_task_runner); |
|||
auto render_task_runner_pair = |
|||
CreateEmbedderTaskRunner(custom_task_runners->render_task_runner); |
|||
auto ui_task_runner_pair = |
|||
CreateEmbedderTaskRunner(custom_task_runners->ui_task_runner); |
|||
|
|||
if (!platform_task_runner_pair.first || !render_task_runner_pair.first || |
|||
!ui_task_runner_pair.first) { |
|||
// User error while supplying a custom task runner. Return an invalid thread
|
|||
// host. This will abort engine initialization. Don't fallback to defaults
|
|||
// if the user wanted to specify a task runner but just messed up instead.
|
|||
return nullptr; |
|||
} |
|||
|
|||
// If the embedder has not supplied a GPU task runner, one needs to be
|
|||
// created.
|
|||
if (!render_task_runner_pair.second) { |
|||
engine_thread_host_mask |= ThreadHost::Type::GPU; |
|||
} |
|||
|
|||
// If both the platform task runner and the GPU task runner are specified and
|
|||
// have the same identifier, store only one.
|
|||
if (platform_task_runner_pair.second && render_task_runner_pair.second) { |
|||
if (platform_task_runner_pair.second->GetEmbedderIdentifier() == |
|||
render_task_runner_pair.second->GetEmbedderIdentifier()) { |
|||
render_task_runner_pair.second = platform_task_runner_pair.second; |
|||
} |
|||
} |
|||
|
|||
if (platform_task_runner_pair.second && ui_task_runner_pair.second) { |
|||
if (platform_task_runner_pair.second->GetEmbedderIdentifier() == |
|||
ui_task_runner_pair.second->GetEmbedderIdentifier()) { |
|||
ui_task_runner_pair.second = platform_task_runner_pair.second; |
|||
} |
|||
} |
|||
|
|||
// Create a thread host with just the threads that need to be managed by the
|
|||
// engine. The embedder has provided the rest.
|
|||
ThreadHost thread_host(kUIWidgetsThreadName, engine_thread_host_mask); |
|||
|
|||
// If the embedder has supplied a platform task runner, use that. If not, use
|
|||
// the current thread task runner.
|
|||
auto platform_task_runner = |
|||
platform_task_runner_pair.second |
|||
? static_cast<fml::RefPtr<fml::TaskRunner>>( |
|||
platform_task_runner_pair.second) |
|||
: GetCurrentThreadTaskRunner(); |
|||
|
|||
// If the embedder has supplied a GPU task runner, use that. If not, use the
|
|||
// one from our thread host.
|
|||
auto render_task_runner = render_task_runner_pair.second |
|||
? static_cast<fml::RefPtr<fml::TaskRunner>>( |
|||
render_task_runner_pair.second) |
|||
: thread_host.raster_thread->GetTaskRunner(); |
|||
|
|||
// If the embedder has supplied a ui task runner, use that. If not, use
|
|||
// the current thread task runner.
|
|||
auto ui_task_runner = ui_task_runner_pair.second |
|||
? static_cast<fml::RefPtr<fml::TaskRunner>>( |
|||
ui_task_runner_pair.second) |
|||
: GetCurrentThreadTaskRunner(); |
|||
|
|||
TaskRunners task_runners( |
|||
kUIWidgetsThreadName, |
|||
platform_task_runner, // platform
|
|||
render_task_runner, // raster
|
|||
ui_task_runner, // ui
|
|||
thread_host.io_thread->GetTaskRunner() // io (always engine managed)
|
|||
); |
|||
|
|||
if (!task_runners.IsValid()) { |
|||
return nullptr; |
|||
} |
|||
|
|||
std::set<fml::RefPtr<EmbedderTaskRunner>> embedder_task_runners; |
|||
|
|||
if (platform_task_runner_pair.second) { |
|||
embedder_task_runners.insert(platform_task_runner_pair.second); |
|||
} |
|||
|
|||
if (render_task_runner_pair.second) { |
|||
embedder_task_runners.insert(render_task_runner_pair.second); |
|||
} |
|||
|
|||
if (ui_task_runner_pair.second) { |
|||
embedder_task_runners.insert(ui_task_runner_pair.second); |
|||
} |
|||
|
|||
auto embedder_host = std::make_unique<EmbedderThreadHost>( |
|||
std::move(thread_host), task_runners, embedder_task_runners); |
|||
|
|||
if (embedder_host->IsValid()) { |
|||
return embedder_host; |
|||
} |
|||
|
|||
return nullptr; |
|||
} |
|||
|
|||
EmbedderThreadHost::EmbedderThreadHost( |
|||
ThreadHost host, TaskRunners runners, |
|||
const std::set<fml::RefPtr<EmbedderTaskRunner>>& embedder_task_runners) |
|||
: host_(std::move(host)), runners_(runners) { |
|||
for (const auto& runner : embedder_task_runners) { |
|||
runners_map_[reinterpret_cast<int64_t>(runner.get())] = runner; |
|||
} |
|||
} |
|||
|
|||
EmbedderThreadHost::~EmbedderThreadHost() = default; |
|||
|
|||
bool EmbedderThreadHost::IsValid() const { return runners_.IsValid(); } |
|||
|
|||
const TaskRunners& EmbedderThreadHost::GetTaskRunners() const { |
|||
return runners_; |
|||
} |
|||
|
|||
bool EmbedderThreadHost::PostTask(int64_t runner, uint64_t task) const { |
|||
auto found = runners_map_.find(runner); |
|||
if (found == runners_map_.end()) { |
|||
return false; |
|||
} |
|||
return found->second->PostTask(task); |
|||
} |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include <map> |
|||
#include <memory> |
|||
#include <set> |
|||
|
|||
#include "common/task_runners.h" |
|||
#include "embedder.h" |
|||
#include "embedder_task_runner.h" |
|||
#include "flutter/fml/macros.h" |
|||
#include "shell/common/thread_host.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class EmbedderThreadHost { |
|||
public: |
|||
static std::unique_ptr<EmbedderThreadHost> CreateEmbedderManagedThreadHost( |
|||
const UIWidgetsCustomTaskRunners* custom_task_runners); |
|||
|
|||
EmbedderThreadHost( |
|||
ThreadHost host, TaskRunners runners, |
|||
const std::set<fml::RefPtr<EmbedderTaskRunner>>& embedder_task_runners); |
|||
|
|||
~EmbedderThreadHost(); |
|||
|
|||
bool IsValid() const; |
|||
|
|||
const TaskRunners& GetTaskRunners() const; |
|||
|
|||
bool PostTask(int64_t runner, uint64_t task) const; |
|||
|
|||
private: |
|||
ThreadHost host_; |
|||
TaskRunners runners_; |
|||
std::map<int64_t, fml::RefPtr<EmbedderTaskRunner>> runners_map_; |
|||
|
|||
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderThreadHost); |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#include "platform_view_embedder.h"
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
PlatformViewEmbedder::PlatformViewEmbedder( |
|||
Delegate& delegate, TaskRunners task_runners, |
|||
EmbedderSurfaceGL::GLDispatchTable gl_dispatch_table, |
|||
bool fbo_reset_after_present, PlatformDispatchTable platform_dispatch_table, |
|||
std::unique_ptr<EmbedderExternalViewEmbedder> external_view_embedder) |
|||
: PlatformView(delegate, std::move(task_runners)), |
|||
embedder_surface_(std::make_unique<EmbedderSurfaceGL>( |
|||
gl_dispatch_table, fbo_reset_after_present, |
|||
std::move(external_view_embedder))), |
|||
platform_dispatch_table_(platform_dispatch_table) {} |
|||
|
|||
PlatformViewEmbedder::PlatformViewEmbedder( |
|||
Delegate& delegate, TaskRunners task_runners, |
|||
EmbedderSurfaceSoftware::SoftwareDispatchTable software_dispatch_table, |
|||
PlatformDispatchTable platform_dispatch_table, |
|||
std::unique_ptr<EmbedderExternalViewEmbedder> external_view_embedder) |
|||
: PlatformView(delegate, std::move(task_runners)), |
|||
embedder_surface_(std::make_unique<EmbedderSurfaceSoftware>( |
|||
software_dispatch_table, std::move(external_view_embedder))), |
|||
platform_dispatch_table_(platform_dispatch_table) {} |
|||
|
|||
PlatformViewEmbedder::~PlatformViewEmbedder() = default; |
|||
|
|||
void PlatformViewEmbedder::HandlePlatformMessage( |
|||
fml::RefPtr<PlatformMessage> message) { |
|||
if (!message) { |
|||
return; |
|||
} |
|||
|
|||
if (platform_dispatch_table_.platform_message_response_callback == nullptr) { |
|||
if (message->response()) { |
|||
message->response()->CompleteEmpty(); |
|||
} |
|||
return; |
|||
} |
|||
|
|||
platform_dispatch_table_.platform_message_response_callback( |
|||
std::move(message)); |
|||
} |
|||
|
|||
// |PlatformView|
|
|||
std::unique_ptr<Surface> PlatformViewEmbedder::CreateRenderingSurface() { |
|||
if (embedder_surface_ == nullptr) { |
|||
FML_LOG(ERROR) << "Embedder surface was null."; |
|||
return nullptr; |
|||
} |
|||
return embedder_surface_->CreateGPUSurface(); |
|||
} |
|||
|
|||
// |PlatformView|
|
|||
sk_sp<GrContext> PlatformViewEmbedder::CreateResourceContext() const { |
|||
if (embedder_surface_ == nullptr) { |
|||
FML_LOG(ERROR) << "Embedder surface was null."; |
|||
return nullptr; |
|||
} |
|||
return embedder_surface_->CreateResourceContext(); |
|||
} |
|||
|
|||
// |PlatformView|
|
|||
std::unique_ptr<VsyncWaiter> PlatformViewEmbedder::CreateVSyncWaiter() { |
|||
if (!platform_dispatch_table_.vsync_callback) { |
|||
// Superclass implementation creates a timer based fallback.
|
|||
return PlatformView::CreateVSyncWaiter(); |
|||
} |
|||
|
|||
return std::make_unique<VsyncWaiterEmbedder>( |
|||
platform_dispatch_table_.vsync_callback, task_runners_); |
|||
} |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include <functional> |
|||
|
|||
#include "flutter/fml/macros.h" |
|||
#include "shell/common/platform_view.h" |
|||
#include "shell/platform/embedder/embedder.h" |
|||
#include "shell/platform/embedder/embedder_surface.h" |
|||
#include "shell/platform/embedder/embedder_surface_gl.h" |
|||
#include "shell/platform/embedder/embedder_surface_software.h" |
|||
#include "shell/platform/embedder/vsync_waiter_embedder.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class PlatformViewEmbedder final : public PlatformView { |
|||
public: |
|||
using PlatformMessageResponseCallback = |
|||
std::function<void(fml::RefPtr<PlatformMessage>)>; |
|||
|
|||
struct PlatformDispatchTable { |
|||
PlatformMessageResponseCallback |
|||
platform_message_response_callback; // optional |
|||
VsyncWaiterEmbedder::VsyncCallback vsync_callback; // optional |
|||
}; |
|||
|
|||
// Creates a platform view that sets up an OpenGL rasterizer. |
|||
PlatformViewEmbedder( |
|||
PlatformView::Delegate& delegate, TaskRunners task_runners, |
|||
EmbedderSurfaceGL::GLDispatchTable gl_dispatch_table, |
|||
bool fbo_reset_after_present, |
|||
PlatformDispatchTable platform_dispatch_table, |
|||
std::unique_ptr<EmbedderExternalViewEmbedder> external_view_embedder); |
|||
|
|||
// Create a platform view that sets up a software rasterizer. |
|||
PlatformViewEmbedder( |
|||
PlatformView::Delegate& delegate, TaskRunners task_runners, |
|||
EmbedderSurfaceSoftware::SoftwareDispatchTable software_dispatch_table, |
|||
PlatformDispatchTable platform_dispatch_table, |
|||
std::unique_ptr<EmbedderExternalViewEmbedder> external_view_embedder); |
|||
|
|||
~PlatformViewEmbedder() override; |
|||
|
|||
// |PlatformView| |
|||
void HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) override; |
|||
|
|||
private: |
|||
std::unique_ptr<EmbedderSurface> embedder_surface_; |
|||
PlatformDispatchTable platform_dispatch_table_; |
|||
|
|||
// |PlatformView| |
|||
std::unique_ptr<Surface> CreateRenderingSurface() override; |
|||
|
|||
// |PlatformView| |
|||
sk_sp<GrContext> CreateResourceContext() const override; |
|||
|
|||
// |PlatformView| |
|||
std::unique_ptr<VsyncWaiter> CreateVSyncWaiter() override; |
|||
|
|||
FML_DISALLOW_COPY_AND_ASSIGN(PlatformViewEmbedder); |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#include "vsync_waiter_embedder.h"
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
VsyncWaiterEmbedder::VsyncWaiterEmbedder(const VsyncCallback& vsync_callback, |
|||
TaskRunners task_runners) |
|||
: VsyncWaiter(std::move(task_runners)), vsync_callback_(vsync_callback) { |
|||
FML_DCHECK(vsync_callback_); |
|||
} |
|||
|
|||
VsyncWaiterEmbedder::~VsyncWaiterEmbedder() = default; |
|||
|
|||
// |VsyncWaiter|
|
|||
void VsyncWaiterEmbedder::AwaitVSync() { |
|||
auto* weak_waiter = new std::weak_ptr<VsyncWaiter>(shared_from_this()); |
|||
vsync_callback_(reinterpret_cast<intptr_t>(weak_waiter)); |
|||
} |
|||
|
|||
// static
|
|||
bool VsyncWaiterEmbedder::OnEmbedderVsync(intptr_t baton, |
|||
fml::TimePoint frame_start_time, |
|||
fml::TimePoint frame_target_time) { |
|||
if (baton == 0) { |
|||
return false; |
|||
} |
|||
|
|||
auto* weak_waiter = reinterpret_cast<std::weak_ptr<VsyncWaiter>*>(baton); |
|||
auto strong_waiter = weak_waiter->lock(); |
|||
delete weak_waiter; |
|||
|
|||
if (!strong_waiter) { |
|||
return false; |
|||
} |
|||
|
|||
strong_waiter->FireCallback(frame_start_time, frame_target_time); |
|||
return true; |
|||
} |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include "flutter/fml/macros.h" |
|||
#include "shell/common/vsync_waiter.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class VsyncWaiterEmbedder final : public VsyncWaiter { |
|||
public: |
|||
using VsyncCallback = std::function<void(intptr_t)>; |
|||
|
|||
VsyncWaiterEmbedder(const VsyncCallback& callback, TaskRunners task_runners); |
|||
|
|||
~VsyncWaiterEmbedder() override; |
|||
|
|||
static bool OnEmbedderVsync(intptr_t baton, fml::TimePoint frame_start_time, |
|||
fml::TimePoint frame_target_time); |
|||
|
|||
private: |
|||
const VsyncCallback vsync_callback_; |
|||
|
|||
// |VsyncWaiter| |
|||
void AwaitVSync() override; |
|||
|
|||
FML_DISALLOW_COPY_AND_ASSIGN(VsyncWaiterEmbedder); |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#include "gfx_worker_task_runner.h"
|
|||
|
|||
#include <flutter/fml/logging.h>
|
|||
#include <flutter/fml/synchronization/waitable_event.h>
|
|||
#include <flutter/fml/time/time_point.h>
|
|||
|
|||
#include <atomic>
|
|||
#include <utility>
|
|||
|
|||
#include "uiwidgets_system.h"
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
GfxWorkerTaskRunner::GfxWorkerTaskRunner(std::thread::id gfx_worker_thread_id, |
|||
TaskExpiredCallback on_task_expired) |
|||
: gfx_worker_thread_id_(gfx_worker_thread_id), |
|||
on_task_expired_(std::move(on_task_expired)), |
|||
weak_factory_(this) {} |
|||
|
|||
GfxWorkerTaskRunner::~GfxWorkerTaskRunner() { |
|||
// drain pending tasks.
|
|||
fml::AutoResetWaitableEvent latch; |
|||
UIWidgetsSystem::GetInstancePtr()->PostTaskToGfxWorker( |
|||
[&latch]() -> void { latch.Signal(); }); |
|||
latch.Wait(); |
|||
} |
|||
|
|||
bool GfxWorkerTaskRunner::RunsTasksOnCurrentThread() const { |
|||
return std::this_thread::get_id() == gfx_worker_thread_id_; |
|||
} |
|||
|
|||
void GfxWorkerTaskRunner::PostTask(UIWidgetsTask uiwidgets_task, |
|||
uint64_t uiwidgets_target_time_nanos) { |
|||
FML_DCHECK(uiwidgets_target_time_nanos <= |
|||
fml::TimePoint::Now().ToEpochDelta().ToNanoseconds()); |
|||
|
|||
UIWidgetsSystem::GetInstancePtr()->PostTaskToGfxWorker( |
|||
[&on_task_expired = on_task_expired_, uiwidgets_task]() -> void { |
|||
on_task_expired(&uiwidgets_task); |
|||
}); |
|||
} |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include <windows.h> |
|||
|
|||
#include <chrono> |
|||
#include <deque> |
|||
#include <functional> |
|||
#include <mutex> |
|||
#include <queue> |
|||
#include <thread> |
|||
#include <flutter/fml/memory/weak_ptr.h> |
|||
|
|||
|
|||
#include "flutter/fml/macros.h" |
|||
#include "shell/platform/embedder/embedder.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class GfxWorkerTaskRunner { |
|||
public: |
|||
using TaskExpiredCallback = std::function<void(const UIWidgetsTask*)>; |
|||
|
|||
GfxWorkerTaskRunner(std::thread::id gfx_worker_thread_id, |
|||
TaskExpiredCallback on_task_expired); |
|||
|
|||
~GfxWorkerTaskRunner(); |
|||
|
|||
bool RunsTasksOnCurrentThread() const; |
|||
|
|||
void PostTask(UIWidgetsTask uiwidgets_task, |
|||
uint64_t uiwidgets_target_time_nanos); |
|||
|
|||
FML_DISALLOW_COPY_AND_ASSIGN(GfxWorkerTaskRunner); |
|||
|
|||
private: |
|||
using TaskTimePoint = std::chrono::steady_clock::time_point; |
|||
|
|||
std::thread::id gfx_worker_thread_id_; |
|||
TaskExpiredCallback on_task_expired_; |
|||
fml::WeakPtrFactory<GfxWorkerTaskRunner> weak_factory_; |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#include "uiwidgets_panel.h"
|
|||
|
|||
#include <Windows.h>
|
|||
#include <flutter/fml/synchronization/waitable_event.h>
|
|||
|
|||
#include <iostream>
|
|||
|
|||
#include "lib/ui/window/viewport_metrics.h"
|
|||
#include "runtime/mono_api.h"
|
|||
#include "shell/platform/embedder/embedder_engine.h"
|
|||
#include "uiwidgets_system.h"
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
fml::RefPtr<UIWidgetsPanel> UIWidgetsPanel::Create( |
|||
Mono_Handle handle, EntrypointCallback entrypoint_callback) { |
|||
return fml::MakeRefCounted<UIWidgetsPanel>(handle, entrypoint_callback); |
|||
} |
|||
|
|||
UIWidgetsPanel::UIWidgetsPanel(Mono_Handle handle, |
|||
EntrypointCallback entrypoint_callback) |
|||
: handle_(handle), entrypoint_callback_(entrypoint_callback) {} |
|||
|
|||
UIWidgetsPanel::~UIWidgetsPanel() = default; |
|||
|
|||
void UIWidgetsPanel::OnEnable(void* native_texture_ptr, size_t width, |
|||
size_t height, float device_pixel_ratio) { |
|||
surface_manager_ = std::make_unique<UnitySurfaceManager>( |
|||
UIWidgetsSystem::GetInstancePtr()->GetUnityInterfaces()); |
|||
|
|||
FML_DCHECK(fbo_ == 0); |
|||
surface_manager_->MakeCurrent(EGL_NO_DISPLAY); |
|||
fbo_ = surface_manager_->CreateRenderSurface(native_texture_ptr); |
|||
surface_manager_->ClearCurrent(); |
|||
|
|||
fml::AutoResetWaitableEvent latch; |
|||
std::thread::id gfx_worker_thread_id; |
|||
UIWidgetsSystem::GetInstancePtr()->PostTaskToGfxWorker( |
|||
[&latch, &gfx_worker_thread_id]() -> void { |
|||
gfx_worker_thread_id = std::this_thread::get_id(); |
|||
latch.Signal(); |
|||
}); |
|||
latch.Wait(); |
|||
|
|||
gfx_worker_task_runner_ = std::make_unique<GfxWorkerTaskRunner>( |
|||
gfx_worker_thread_id, [this](const auto* task) { |
|||
if (UIWidgetsEngineRunTask(engine_, task) != kSuccess) { |
|||
std::cerr << "Could not post an gfx worker task." << std::endl; |
|||
} |
|||
}); |
|||
|
|||
UIWidgetsTaskRunnerDescription render_task_runner = {}; |
|||
render_task_runner.struct_size = sizeof(UIWidgetsTaskRunnerDescription); |
|||
render_task_runner.identifier = 1; |
|||
render_task_runner.user_data = gfx_worker_task_runner_.get(); |
|||
render_task_runner.runs_task_on_current_thread_callback = |
|||
[](void* user_data) -> bool { |
|||
return static_cast<GfxWorkerTaskRunner*>(user_data) |
|||
->RunsTasksOnCurrentThread(); |
|||
}; |
|||
render_task_runner.post_task_callback = [](UIWidgetsTask task, |
|||
uint64_t target_time_nanos, |
|||
void* user_data) -> void { |
|||
static_cast<GfxWorkerTaskRunner*>(user_data)->PostTask(task, |
|||
target_time_nanos); |
|||
}; |
|||
|
|||
UIWidgetsRendererConfig config = {}; |
|||
config.type = kOpenGL; |
|||
config.open_gl.struct_size = sizeof(config.open_gl); |
|||
config.open_gl.clear_current = [](void* user_data) -> bool { |
|||
auto* panel = static_cast<UIWidgetsPanel*>(user_data); |
|||
return panel->surface_manager_->ClearCurrent(); |
|||
}; |
|||
config.open_gl.make_current = [](void* user_data) -> bool { |
|||
auto* panel = static_cast<UIWidgetsPanel*>(user_data); |
|||
return panel->surface_manager_->MakeCurrent(EGL_NO_DISPLAY); |
|||
}; |
|||
config.open_gl.make_resource_current = [](void* user_data) -> bool { |
|||
auto* panel = static_cast<UIWidgetsPanel*>(user_data); |
|||
return panel->surface_manager_->MakeResourceCurrent(); |
|||
}; |
|||
config.open_gl.fbo_callback = [](void* user_data) -> uint32_t { |
|||
auto* panel = static_cast<UIWidgetsPanel*>(user_data); |
|||
return panel->fbo_; |
|||
}; |
|||
config.open_gl.present = [](void* user_data) -> bool { return true; }; |
|||
config.open_gl.gl_proc_resolver = [](void* user_data, |
|||
const char* what) -> void* { |
|||
return reinterpret_cast<void*>(eglGetProcAddress(what)); |
|||
}; |
|||
config.open_gl.fbo_reset_after_present = true; |
|||
|
|||
task_runner_ = std::make_unique<Win32TaskRunner>( |
|||
GetCurrentThreadId(), [this](const auto* task) { |
|||
if (UIWidgetsEngineRunTask(engine_, task) != kSuccess) { |
|||
std::cerr << "Could not post an engine task." << std::endl; |
|||
} |
|||
}); |
|||
|
|||
UIWidgetsTaskRunnerDescription ui_task_runner = {}; |
|||
ui_task_runner.struct_size = sizeof(UIWidgetsTaskRunnerDescription); |
|||
ui_task_runner.identifier = 2; |
|||
ui_task_runner.user_data = task_runner_.get(); |
|||
ui_task_runner.runs_task_on_current_thread_callback = |
|||
[](void* user_data) -> bool { |
|||
return static_cast<Win32TaskRunner*>(user_data)->RunsTasksOnCurrentThread(); |
|||
}; |
|||
ui_task_runner.post_task_callback = [](UIWidgetsTask task, |
|||
uint64_t target_time_nanos, |
|||
void* user_data) -> void { |
|||
static_cast<Win32TaskRunner*>(user_data)->PostTask(task, target_time_nanos); |
|||
}; |
|||
|
|||
UIWidgetsCustomTaskRunners custom_task_runners = {}; |
|||
custom_task_runners.struct_size = sizeof(UIWidgetsCustomTaskRunners); |
|||
custom_task_runners.platform_task_runner = &ui_task_runner; |
|||
custom_task_runners.ui_task_runner = &ui_task_runner; |
|||
custom_task_runners.render_task_runner = &render_task_runner; |
|||
|
|||
UIWidgetsProjectArgs args = {}; |
|||
args.struct_size = sizeof(UIWidgetsProjectArgs); |
|||
|
|||
args.assets_path = ""; |
|||
args.icu_data_path = ""; |
|||
|
|||
args.command_line_argc = 0; |
|||
args.command_line_argv = nullptr; |
|||
|
|||
args.platform_message_callback = |
|||
[](const UIWidgetsPlatformMessage* engine_message, |
|||
void* user_data) -> void {}; |
|||
|
|||
args.custom_task_runners = &custom_task_runners; |
|||
args.task_observer_add = [](intptr_t key, void* callback, |
|||
void* user_data) -> void { |
|||
auto* panel = static_cast<UIWidgetsPanel*>(user_data); |
|||
panel->task_runner_->AddTaskObserver(key, |
|||
*static_cast<fml::closure*>(callback)); |
|||
}; |
|||
args.task_observer_remove = [](intptr_t key, void* user_data) -> void { |
|||
auto* panel = static_cast<UIWidgetsPanel*>(user_data); |
|||
panel->task_runner_->RemoveTaskObserver(key); |
|||
}; |
|||
|
|||
args.custom_mono_entrypoint = [](void* user_data) -> void { |
|||
auto* panel = static_cast<UIWidgetsPanel*>(user_data); |
|||
panel->MonoEntrypoint(); |
|||
}; |
|||
|
|||
args.vsync_callback = [](void* user_data, intptr_t baton) -> void { |
|||
auto* panel = static_cast<UIWidgetsPanel*>(user_data); |
|||
panel->VSyncCallback(baton); |
|||
}; |
|||
|
|||
args.initial_window_metrics.width = width; |
|||
args.initial_window_metrics.height = height; |
|||
args.initial_window_metrics.pixel_ratio = device_pixel_ratio; |
|||
|
|||
UIWidgetsEngine engine = nullptr; |
|||
auto result = UIWidgetsEngineInitialize(&config, &args, this, &engine); |
|||
|
|||
if (result != kSuccess || engine == nullptr) { |
|||
std::cerr << "Failed to start UIWidgets engine: error " << result |
|||
<< std::endl; |
|||
return; |
|||
} |
|||
|
|||
engine_ = engine; |
|||
UIWidgetsEngineRunInitialized(engine); |
|||
|
|||
UIWidgetsSystem::GetInstancePtr()->RegisterPanel(this); |
|||
} |
|||
|
|||
void UIWidgetsPanel::MonoEntrypoint() { entrypoint_callback_(handle_); } |
|||
|
|||
void UIWidgetsPanel::OnDisable() { |
|||
// drain pending messages
|
|||
ProcessMessages(); |
|||
|
|||
// drain pending vsync batons
|
|||
ProcessVSync(); |
|||
|
|||
UIWidgetsSystem::GetInstancePtr()->UnregisterPanel(this); |
|||
|
|||
if (engine_) { |
|||
UIWidgetsEngineShutdown(engine_); |
|||
engine_ = nullptr; |
|||
} |
|||
|
|||
gfx_worker_task_runner_ = nullptr; |
|||
task_runner_ = nullptr; |
|||
|
|||
if (fbo_) { |
|||
surface_manager_->MakeCurrent(EGL_NO_DISPLAY); |
|||
|
|||
surface_manager_->DestroyRenderSurface(); |
|||
fbo_ = 0; |
|||
|
|||
surface_manager_->ClearCurrent(); |
|||
} |
|||
|
|||
surface_manager_ = nullptr; |
|||
} |
|||
|
|||
void UIWidgetsPanel::OnRenderTexture(void* native_texture_ptr, size_t width, |
|||
size_t height, float device_pixel_ratio) { |
|||
reinterpret_cast<EmbedderEngine*>(engine_)->PostRenderThreadTask( |
|||
[this, native_texture_ptr]() -> void { |
|||
surface_manager_->MakeCurrent(EGL_NO_DISPLAY); |
|||
|
|||
if (fbo_) { |
|||
surface_manager_->DestroyRenderSurface(); |
|||
fbo_ = 0; |
|||
} |
|||
fbo_ = surface_manager_->CreateRenderSurface(native_texture_ptr); |
|||
|
|||
surface_manager_->ClearCurrent(); |
|||
}); |
|||
|
|||
ViewportMetrics metrics; |
|||
metrics.physical_width = width; |
|||
metrics.physical_height = height; |
|||
metrics.device_pixel_ratio = device_pixel_ratio; |
|||
reinterpret_cast<EmbedderEngine*>(engine_)->SetViewportMetrics(metrics); |
|||
} |
|||
|
|||
std::chrono::nanoseconds UIWidgetsPanel::ProcessMessages() { |
|||
return std::chrono::nanoseconds(task_runner_->ProcessTasks().count()); |
|||
} |
|||
|
|||
void UIWidgetsPanel::ProcessVSync() { |
|||
std::vector<intptr_t> batons; |
|||
vsync_batons_.swap(batons); |
|||
|
|||
for (intptr_t baton : batons) { |
|||
reinterpret_cast<EmbedderEngine*>(engine_)->OnVsyncEvent( |
|||
baton, fml::TimePoint::Now(), |
|||
fml::TimePoint::Now() + |
|||
fml::TimeDelta::FromNanoseconds(1000000000 / 60)); |
|||
} |
|||
} |
|||
|
|||
void UIWidgetsPanel::VSyncCallback(intptr_t baton) { |
|||
vsync_batons_.push_back(baton); |
|||
} |
|||
|
|||
using TimePoint = std::chrono::steady_clock::time_point; |
|||
|
|||
TimePoint next_flutter_event_time = TimePoint::clock::now(); |
|||
|
|||
UIWIDGETS_API(UIWidgetsPanel*) |
|||
UIWidgetsPanel_constructor( |
|||
Mono_Handle handle, |
|||
UIWidgetsPanel::EntrypointCallback entrypoint_callback) { |
|||
const auto panel = UIWidgetsPanel::Create(handle, entrypoint_callback); |
|||
panel->AddRef(); |
|||
return panel.get(); |
|||
} |
|||
|
|||
UIWIDGETS_API(void) UIWidgetsPanel_dispose(UIWidgetsPanel* panel) { |
|||
panel->Release(); |
|||
} |
|||
|
|||
UIWIDGETS_API(void) |
|||
UIWidgetsPanel_onEnable(UIWidgetsPanel* panel, void* native_texture_ptr, |
|||
size_t width, size_t height, float device_pixel_ratio) { |
|||
panel->OnEnable(native_texture_ptr, width, height, device_pixel_ratio); |
|||
} |
|||
|
|||
UIWIDGETS_API(void) UIWidgetsPanel_onDisable(UIWidgetsPanel* panel) { |
|||
panel->OnDisable(); |
|||
} |
|||
|
|||
UIWIDGETS_API(void) |
|||
UIWidgetsPanel_onRenderTexture(UIWidgetsPanel* panel, void* native_texture_ptr, |
|||
int width, int height, float dpi) { |
|||
panel->OnRenderTexture(native_texture_ptr, width, height, dpi); |
|||
} |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include <flutter/fml/memory/ref_counted.h> |
|||
|
|||
#include "gfx_worker_task_runner.h" |
|||
#include "runtime/mono_api.h" |
|||
#include "unity_surface_manager.h" |
|||
#include "win32_task_runner.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class UIWidgetsPanel : public fml::RefCountedThreadSafe<UIWidgetsPanel> { |
|||
FML_FRIEND_MAKE_REF_COUNTED(UIWidgetsPanel); |
|||
|
|||
public: |
|||
typedef void (*EntrypointCallback)(Mono_Handle handle); |
|||
|
|||
static fml::RefPtr<UIWidgetsPanel> Create( |
|||
Mono_Handle handle, EntrypointCallback entrypoint_callback); |
|||
|
|||
~UIWidgetsPanel(); |
|||
|
|||
void OnEnable(void* native_texture_ptr, size_t width, size_t height, |
|||
float device_pixel_ratio); |
|||
|
|||
void MonoEntrypoint(); |
|||
|
|||
void OnDisable(); |
|||
|
|||
void OnRenderTexture(void* native_texture_ptr, size_t width, size_t height, |
|||
float dpi); |
|||
|
|||
std::chrono::nanoseconds ProcessMessages(); |
|||
|
|||
void ProcessVSync(); |
|||
|
|||
void VSyncCallback(intptr_t baton); |
|||
|
|||
private: |
|||
UIWidgetsPanel(Mono_Handle handle, EntrypointCallback entrypoint_callback); |
|||
|
|||
Mono_Handle handle_; |
|||
EntrypointCallback entrypoint_callback_; |
|||
|
|||
std::unique_ptr<UnitySurfaceManager> surface_manager_; |
|||
GLuint fbo_ = 0; |
|||
|
|||
std::unique_ptr<GfxWorkerTaskRunner> gfx_worker_task_runner_; |
|||
std::unique_ptr<Win32TaskRunner> task_runner_; |
|||
UIWidgetsEngine engine_ = nullptr; |
|||
|
|||
std::vector<intptr_t> vsync_batons_; |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#include "uiwidgets_system.h"
|
|||
|
|||
#include <algorithm>
|
|||
#include <chrono>
|
|||
|
|||
#include "uiwidgets_panel.h"
|
|||
|
|||
namespace uiwidgets { |
|||
UIWidgetsSystem g_uiwidgets_system; |
|||
|
|||
UIWidgetsSystem::UIWidgetsSystem() = default; |
|||
|
|||
UIWidgetsSystem::~UIWidgetsSystem() = default; |
|||
|
|||
void UIWidgetsSystem::RegisterPanel(UIWidgetsPanel* panel) { |
|||
uiwidgets_panels_.insert(panel); |
|||
} |
|||
|
|||
void UIWidgetsSystem::UnregisterPanel(UIWidgetsPanel* panel) { |
|||
uiwidgets_panels_.erase(panel); |
|||
} |
|||
|
|||
void UIWidgetsSystem::Wait(std::chrono::nanoseconds max_duration) { |
|||
std::chrono::nanoseconds wait_duration = |
|||
std::max(std::chrono::nanoseconds(0), |
|||
next_uiwidgets_event_time_ - TimePoint::clock::now()); |
|||
|
|||
wait_duration = std::min(max_duration, wait_duration); |
|||
|
|||
::MsgWaitForMultipleObjects(0, nullptr, FALSE, |
|||
static_cast<DWORD>(wait_duration.count() / 1000), |
|||
QS_ALLINPUT); |
|||
} |
|||
|
|||
void UIWidgetsSystem::Update() { |
|||
TimePoint next_event_time = TimePoint::max(); |
|||
for (auto* uiwidgets_panel : uiwidgets_panels_) { |
|||
std::chrono::nanoseconds wait_duration = uiwidgets_panel->ProcessMessages(); |
|||
if (wait_duration != std::chrono::nanoseconds::max()) { |
|||
next_event_time = |
|||
std::min(next_event_time, TimePoint::clock::now() + wait_duration); |
|||
} |
|||
} |
|||
next_uiwidgets_event_time_ = next_event_time; |
|||
} |
|||
|
|||
void UIWidgetsSystem::VSync() { |
|||
for (auto* uiwidgets_panel : uiwidgets_panels_) { |
|||
uiwidgets_panel->ProcessVSync(); |
|||
} |
|||
|
|||
Update(); |
|||
} |
|||
|
|||
void UIWidgetsSystem::WakeUp() {} |
|||
|
|||
void UIWidgetsSystem::GfxWorkerCallback(int eventId, void* data) { |
|||
const fml::closure task(std::move(gfx_worker_tasks_[eventId])); |
|||
gfx_worker_tasks_.erase(eventId); |
|||
|
|||
task(); |
|||
} |
|||
|
|||
void UIWidgetsSystem::PostTaskToGfxWorker(const fml::closure& task) { |
|||
last_task_id_++; |
|||
|
|||
gfx_worker_tasks_[last_task_id_] = task; |
|||
unity_uiwidgets_->IssuePluginEventAndData(&_GfxWorkerCallback, last_task_id_, |
|||
nullptr); |
|||
} |
|||
|
|||
void UIWidgetsSystem::BindUnityInterfaces(IUnityInterfaces* unity_interfaces) { |
|||
unity_interfaces_ = unity_interfaces; |
|||
|
|||
unity_uiwidgets_ = unity_interfaces_->Get<UnityUIWidgets::IUnityUIWidgets>(); |
|||
unity_uiwidgets_->SetUpdateCallback(_Update); |
|||
unity_uiwidgets_->SetVSyncCallback(_VSync); |
|||
unity_uiwidgets_->SetWaitCallback(_Wait); |
|||
unity_uiwidgets_->SetWakeUpCallback(_WakeUp); |
|||
} |
|||
|
|||
void UIWidgetsSystem::UnBindUnityInterfaces() { |
|||
unity_uiwidgets_->SetUpdateCallback(nullptr); |
|||
unity_uiwidgets_->SetVSyncCallback(nullptr); |
|||
unity_uiwidgets_->SetWaitCallback(nullptr); |
|||
unity_uiwidgets_->SetWakeUpCallback(nullptr); |
|||
unity_uiwidgets_ = nullptr; |
|||
|
|||
unity_interfaces_ = nullptr; |
|||
} |
|||
|
|||
UIWidgetsSystem* UIWidgetsSystem::GetInstancePtr() { |
|||
return &g_uiwidgets_system; |
|||
} |
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include <flutter/fml/closure.h> |
|||
|
|||
#include <chrono> |
|||
#include <set> |
|||
#include <unordered_map> |
|||
|
|||
#include "Unity/IUnityInterface.h" |
|||
#include "Unity/IUnityUIWidgets.h" |
|||
#include "flutter/fml/macros.h" |
|||
#include "runtime/mono_api.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
using TimePoint = std::chrono::steady_clock::time_point; |
|||
|
|||
class UIWidgetsPanel; |
|||
|
|||
class UIWidgetsSystem { |
|||
public: |
|||
UIWidgetsSystem(); |
|||
~UIWidgetsSystem(); |
|||
|
|||
void RegisterPanel(UIWidgetsPanel* panel); |
|||
void UnregisterPanel(UIWidgetsPanel* panel); |
|||
|
|||
void PostTaskToGfxWorker(const fml::closure& task); |
|||
|
|||
void BindUnityInterfaces(IUnityInterfaces* unity_interfaces); |
|||
void UnBindUnityInterfaces(); |
|||
IUnityInterfaces* GetUnityInterfaces() { return unity_interfaces_; } |
|||
|
|||
static UIWidgetsSystem* GetInstancePtr(); |
|||
|
|||
FML_DISALLOW_COPY_AND_ASSIGN(UIWidgetsSystem); |
|||
|
|||
private: |
|||
UIWIDGETS_CALLBACK(void) _Update() { GetInstancePtr()->Update(); } |
|||
|
|||
UIWIDGETS_CALLBACK(void) _Wait(long max_duration) { |
|||
GetInstancePtr()->Wait(std::chrono::nanoseconds(max_duration)); |
|||
} |
|||
|
|||
UIWIDGETS_CALLBACK(void) _VSync() { GetInstancePtr()->VSync(); } |
|||
|
|||
UIWIDGETS_CALLBACK(void) _WakeUp() { GetInstancePtr()->WakeUp(); } |
|||
|
|||
UIWIDGETS_CALLBACK(void) _GfxWorkerCallback(int eventId, void* data) { |
|||
GetInstancePtr()->GfxWorkerCallback(eventId, data); |
|||
} |
|||
|
|||
void Update(); |
|||
void Wait(std::chrono::nanoseconds max_duration); |
|||
void VSync(); |
|||
void WakeUp(); |
|||
void GfxWorkerCallback(int eventId, void* data); |
|||
|
|||
IUnityInterfaces* unity_interfaces_ = nullptr; |
|||
UnityUIWidgets::IUnityUIWidgets* unity_uiwidgets_ = nullptr; |
|||
|
|||
std::unordered_map<int, fml::closure> gfx_worker_tasks_; |
|||
int last_task_id_ = 0; |
|||
|
|||
TimePoint next_uiwidgets_event_time_ = TimePoint::clock::now(); |
|||
std::set<UIWidgetsPanel*> uiwidgets_panels_; |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#include "unity_surface_manager.h"
|
|||
|
|||
#include <d3d11.h>
|
|||
#include <dxgi.h>
|
|||
#include <flutter/fml/logging.h>
|
|||
|
|||
#include "Unity/IUnityGraphics.h"
|
|||
#include "Unity/IUnityGraphicsD3D11.h"
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
UnitySurfaceManager::UnitySurfaceManager(IUnityInterfaces* unity_interfaces) |
|||
: egl_display_(EGL_NO_DISPLAY), |
|||
egl_context_(EGL_NO_CONTEXT), |
|||
egl_resource_context_(EGL_NO_CONTEXT), |
|||
egl_config_(nullptr) { |
|||
initialize_succeeded_ = Initialize(unity_interfaces); |
|||
} |
|||
|
|||
UnitySurfaceManager::~UnitySurfaceManager() { CleanUp(); } |
|||
|
|||
GLuint UnitySurfaceManager::CreateRenderSurface(void* native_texture_ptr) { |
|||
ID3D11Texture2D* d3d11_texture = |
|||
static_cast<ID3D11Texture2D*>(native_texture_ptr); |
|||
IDXGIResource* image_resource; |
|||
HRESULT hr = d3d11_texture->QueryInterface( |
|||
__uuidof(IDXGIResource), reinterpret_cast<void**>(&image_resource)); |
|||
FML_CHECK(SUCCEEDED(hr)) << "UnitySurfaceManager: QueryInterface() failed"; |
|||
|
|||
HANDLE shared_image_handle; |
|||
hr = image_resource->GetSharedHandle(&shared_image_handle); |
|||
FML_CHECK(SUCCEEDED(hr)) << "UnitySurfaceManager: GetSharedHandle() failed"; |
|||
|
|||
image_resource->Release(); |
|||
|
|||
FML_CHECK(shared_image_handle != nullptr) |
|||
<< "UnitySurfaceManager: shared_image_handle is nullptr, miscFlags " |
|||
"D3D11_RESOURCE_MISC_SHARED is needed"; |
|||
|
|||
IDXGIResource* dxgi_resource; |
|||
hr = d3d11_device_->OpenSharedResource( |
|||
shared_image_handle, __uuidof(ID3D11Resource), |
|||
reinterpret_cast<void**>(&dxgi_resource)); |
|||
FML_CHECK(SUCCEEDED(hr)) |
|||
<< "UnitySurfaceManager: failed to open shared resource"; |
|||
|
|||
ID3D11Texture2D* image_texture; |
|||
hr = dxgi_resource->QueryInterface(__uuidof(ID3D11Texture2D), |
|||
reinterpret_cast<void**>(&image_texture)); |
|||
FML_CHECK(SUCCEEDED(hr)) |
|||
<< "UnitySurfaceManager: failed to query interface ID3D11Texture2D"; |
|||
|
|||
dxgi_resource->Release(); |
|||
|
|||
const EGLint attribs[] = {EGL_NONE}; |
|||
FML_DCHECK(fbo_egl_image_ == nullptr); |
|||
fbo_egl_image_ = |
|||
eglCreateImageKHR(egl_display_, EGL_NO_CONTEXT, EGL_D3D11_TEXTURE_ANGLE, |
|||
static_cast<EGLClientBuffer>(image_texture), attribs); |
|||
FML_CHECK(fbo_egl_image_ != EGL_NO_IMAGE_KHR); |
|||
|
|||
image_texture->Release(); |
|||
|
|||
FML_DCHECK(fbo_texture_ == 0); |
|||
glGenTextures(1, &fbo_texture_); |
|||
glBindTexture(GL_TEXTURE_2D, fbo_texture_); |
|||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
|||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
|||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
|||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
|||
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, fbo_egl_image_); |
|||
|
|||
FML_DCHECK(fbo_ == 0); |
|||
glGenFramebuffers(1, &fbo_); |
|||
glBindFramebuffer(GL_FRAMEBUFFER, fbo_); |
|||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
|||
fbo_texture_, 0); |
|||
FML_CHECK(glCheckFramebufferStatus(GL_FRAMEBUFFER) == |
|||
GL_FRAMEBUFFER_COMPLETE); |
|||
|
|||
return fbo_; |
|||
} |
|||
|
|||
void UnitySurfaceManager::DestroyRenderSurface() { |
|||
FML_DCHECK(fbo_ != 0); |
|||
glDeleteFramebuffers(1, &fbo_); |
|||
fbo_ = 0; |
|||
|
|||
FML_DCHECK(fbo_texture_ != 0); |
|||
glDeleteTextures(1, &fbo_texture_); |
|||
fbo_texture_ = 0; |
|||
|
|||
FML_DCHECK(fbo_egl_image_ != nullptr); |
|||
eglDestroyImageKHR(egl_display_, fbo_egl_image_); |
|||
fbo_egl_image_ = nullptr; |
|||
} |
|||
|
|||
bool UnitySurfaceManager::ClearCurrent() { |
|||
return eglMakeCurrent(egl_display_, EGL_NO_SURFACE, EGL_NO_SURFACE, |
|||
EGL_NO_CONTEXT) == EGL_TRUE; |
|||
} |
|||
|
|||
bool UnitySurfaceManager::MakeCurrent(const EGLSurface surface) { |
|||
return eglMakeCurrent(egl_display_, surface, surface, egl_context_) == |
|||
EGL_TRUE; |
|||
} |
|||
|
|||
bool UnitySurfaceManager::MakeResourceCurrent() { |
|||
return eglMakeCurrent(egl_display_, EGL_NO_SURFACE, EGL_NO_SURFACE, |
|||
egl_resource_context_) == EGL_TRUE; |
|||
} |
|||
|
|||
bool UnitySurfaceManager::Initialize(IUnityInterfaces* unity_interfaces) { |
|||
IUnityGraphics* graphics = unity_interfaces->Get<IUnityGraphics>(); |
|||
FML_CHECK(graphics->GetRenderer() == kUnityGfxRendererD3D11) |
|||
<< "Renderer type is invalid"; |
|||
|
|||
IUnityGraphicsD3D11* d3d11 = unity_interfaces->Get<IUnityGraphicsD3D11>(); |
|||
ID3D11Device* d3d11_device = d3d11->GetDevice(); |
|||
|
|||
IDXGIDevice* dxgi_device; |
|||
HRESULT hr = d3d11_device->QueryInterface( |
|||
__uuidof(IDXGIDevice), reinterpret_cast<void**>(&dxgi_device)); |
|||
|
|||
FML_CHECK(SUCCEEDED(hr)) << "d3d11_device->QueryInterface(...) failed"; |
|||
|
|||
IDXGIAdapter* dxgi_adapter; |
|||
hr = dxgi_device->GetAdapter(&dxgi_adapter); |
|||
FML_CHECK(SUCCEEDED(hr)) << "dxgi_adapter->GetAdapter(...) failed"; |
|||
|
|||
dxgi_device->Release(); |
|||
|
|||
DXGI_ADAPTER_DESC adapter_desc; |
|||
hr = dxgi_adapter->GetDesc(&adapter_desc); |
|||
FML_CHECK(SUCCEEDED(hr)) << "dxgi_adapter->GetDesc(...) failed"; |
|||
|
|||
dxgi_adapter->Release(); |
|||
|
|||
EGLint displayAttribs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, |
|||
EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, |
|||
EGL_PLATFORM_ANGLE_D3D_LUID_HIGH_ANGLE, |
|||
adapter_desc.AdapterLuid.HighPart, |
|||
EGL_PLATFORM_ANGLE_D3D_LUID_LOW_ANGLE, |
|||
adapter_desc.AdapterLuid.LowPart, |
|||
EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, |
|||
EGL_TRUE, |
|||
EGL_NONE}; |
|||
|
|||
egl_display_ = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, |
|||
EGL_DEFAULT_DISPLAY, displayAttribs); |
|||
|
|||
FML_CHECK(egl_display_ != EGL_NO_DISPLAY) |
|||
<< "EGL: Failed to get a compatible EGLdisplay"; |
|||
|
|||
if (eglInitialize(egl_display_, nullptr, nullptr) == EGL_FALSE) { |
|||
FML_CHECK(false) << "EGL: Failed to initialize EGL"; |
|||
} |
|||
|
|||
EGLAttrib egl_device = 0; |
|||
eglQueryDisplayAttribEXT(egl_display_, EGL_DEVICE_EXT, &egl_device); |
|||
EGLAttrib angle_device = 0; |
|||
eglQueryDeviceAttribEXT(reinterpret_cast<EGLDeviceEXT>(egl_device), |
|||
EGL_D3D11_DEVICE_ANGLE, &angle_device); |
|||
d3d11_device_ = reinterpret_cast<ID3D11Device*>(angle_device); |
|||
|
|||
const EGLint configAttributes[] = {EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, |
|||
EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, |
|||
EGL_DEPTH_SIZE, 8, EGL_STENCIL_SIZE, 8, |
|||
EGL_NONE}; |
|||
|
|||
EGLint numConfigs = 0; |
|||
if (eglChooseConfig(egl_display_, configAttributes, &egl_config_, 1, |
|||
&numConfigs) == EGL_FALSE || |
|||
numConfigs == 0) { |
|||
FML_CHECK(false) << "EGL: Failed to choose first context"; |
|||
} |
|||
|
|||
const EGLint display_context_attributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, |
|||
EGL_NONE}; |
|||
|
|||
egl_context_ = eglCreateContext(egl_display_, egl_config_, EGL_NO_CONTEXT, |
|||
display_context_attributes); |
|||
if (egl_context_ == EGL_NO_CONTEXT) { |
|||
FML_CHECK(false) << "EGL: Failed to create EGL context"; |
|||
} |
|||
|
|||
egl_resource_context_ = eglCreateContext( |
|||
egl_display_, egl_config_, egl_context_, display_context_attributes); |
|||
|
|||
if (egl_resource_context_ == EGL_NO_CONTEXT) { |
|||
FML_CHECK(false) << "EGL: Failed to create EGL resource context"; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
void UnitySurfaceManager::CleanUp() { |
|||
EGLBoolean result = EGL_FALSE; |
|||
|
|||
if (egl_display_ != EGL_NO_DISPLAY && egl_context_ != EGL_NO_CONTEXT) { |
|||
result = eglDestroyContext(egl_display_, egl_context_); |
|||
egl_context_ = EGL_NO_CONTEXT; |
|||
|
|||
if (result == EGL_FALSE) { |
|||
FML_LOG(ERROR) << "EGL: Failed to destroy context"; |
|||
} |
|||
} |
|||
|
|||
d3d11_device_ = nullptr; |
|||
|
|||
if (egl_display_ != EGL_NO_DISPLAY && |
|||
egl_resource_context_ != EGL_NO_CONTEXT) { |
|||
result = eglDestroyContext(egl_display_, egl_resource_context_); |
|||
egl_resource_context_ = EGL_NO_CONTEXT; |
|||
|
|||
if (result == EGL_FALSE) { |
|||
FML_LOG(ERROR) << "EGL : Failed to destroy resource context"; |
|||
} |
|||
} |
|||
|
|||
if (egl_display_ != EGL_NO_DISPLAY) { |
|||
result = eglTerminate(egl_display_); |
|||
egl_display_ = EGL_NO_DISPLAY; |
|||
|
|||
if (result == EGL_FALSE) { |
|||
FML_LOG(ERROR) << "EGL : Failed to terminate EGL"; |
|||
} |
|||
} |
|||
} |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
// OpenGL ES and EGL includes |
|||
#include <EGL/egl.h> |
|||
#include <EGL/eglext.h> |
|||
#include <EGL/eglplatform.h> |
|||
#include <GLES2/gl2.h> |
|||
#include <GLES2/gl2ext.h> |
|||
#include <d3d11.h> |
|||
#include <windows.h> |
|||
|
|||
#include <cstdint> |
|||
|
|||
#include "Unity/IUnityInterface.h" |
|||
#include "flutter/fml/macros.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class UnitySurfaceManager { |
|||
public: |
|||
UnitySurfaceManager(IUnityInterfaces* unity_interfaces); |
|||
~UnitySurfaceManager(); |
|||
|
|||
GLuint CreateRenderSurface(void* native_texture_ptr); |
|||
void DestroyRenderSurface(); |
|||
|
|||
bool ClearCurrent(); |
|||
|
|||
bool MakeCurrent(const EGLSurface surface); |
|||
|
|||
bool MakeResourceCurrent(); |
|||
|
|||
FML_DISALLOW_COPY_AND_ASSIGN(UnitySurfaceManager); |
|||
|
|||
private: |
|||
bool Initialize(IUnityInterfaces* unity_interfaces); |
|||
void CleanUp(); |
|||
|
|||
EGLDisplay egl_display_; |
|||
EGLContext egl_context_; |
|||
EGLContext egl_resource_context_; |
|||
EGLConfig egl_config_; |
|||
bool initialize_succeeded_; |
|||
ID3D11Device* d3d11_device_; |
|||
|
|||
EGLImage fbo_egl_image_ = nullptr; |
|||
GLuint fbo_texture_ = 0; |
|||
GLuint fbo_ = 0; |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#include "win32_task_runner.h"
|
|||
|
|||
#include <flutter/fml/time/time_point.h>
|
|||
|
|||
#include <atomic>
|
|||
#include <utility>
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
Win32TaskRunner::Win32TaskRunner(DWORD main_thread_id, |
|||
const TaskExpiredCallback& on_task_expired) |
|||
: main_thread_id_(main_thread_id), |
|||
on_task_expired_(std::move(on_task_expired)) {} |
|||
|
|||
Win32TaskRunner::~Win32TaskRunner() = default; |
|||
|
|||
bool Win32TaskRunner::RunsTasksOnCurrentThread() const { |
|||
return GetCurrentThreadId() == main_thread_id_; |
|||
} |
|||
|
|||
std::chrono::nanoseconds Win32TaskRunner::ProcessTasks() { |
|||
const TaskTimePoint now = TaskTimePoint::clock::now(); |
|||
|
|||
std::vector<UIWidgetsTask> expired_tasks; |
|||
|
|||
// Process expired tasks.
|
|||
{ |
|||
std::lock_guard<std::mutex> lock(task_queue_mutex_); |
|||
while (!task_queue_.empty()) { |
|||
const auto& top = task_queue_.top(); |
|||
// If this task (and all tasks after this) has not yet expired, there is
|
|||
// nothing more to do. Quit iterating.
|
|||
if (top.fire_time > now) { |
|||
break; |
|||
} |
|||
|
|||
// Make a record of the expired task. Do NOT service the task here
|
|||
// because we are still holding onto the task queue mutex. We don't want
|
|||
// other threads to block on posting tasks onto this thread till we are
|
|||
// done processing expired tasks.
|
|||
expired_tasks.push_back(task_queue_.top().task); |
|||
|
|||
// Remove the tasks from the delayed tasks queue.
|
|||
task_queue_.pop(); |
|||
} |
|||
} |
|||
|
|||
// Fire expired tasks.
|
|||
{ |
|||
// Flushing tasks here without holing onto the task queue mutex.
|
|||
for (const auto& task : expired_tasks) { |
|||
on_task_expired_(&task); |
|||
|
|||
for (const auto& observer : task_observers_) { |
|||
observer.second(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (!expired_tasks.empty()) |
|||
{ |
|||
return ProcessTasks(); |
|||
} |
|||
|
|||
// Calculate duration to sleep for on next iteration.
|
|||
{ |
|||
std::lock_guard<std::mutex> lock(task_queue_mutex_); |
|||
const auto next_wake = task_queue_.empty() ? TaskTimePoint::max() |
|||
: task_queue_.top().fire_time; |
|||
|
|||
return std::min(next_wake - now, std::chrono::nanoseconds::max()); |
|||
} |
|||
} |
|||
|
|||
Win32TaskRunner::TaskTimePoint Win32TaskRunner::TimePointFromUIWidgetsTime( |
|||
uint64_t uiwidgets_target_time_nanos) { |
|||
const auto now = TaskTimePoint::clock::now(); |
|||
const auto uiwidgets_duration = |
|||
uiwidgets_target_time_nanos - |
|||
fml::TimePoint::Now().ToEpochDelta().ToNanoseconds(); |
|||
return now + std::chrono::nanoseconds(uiwidgets_duration); |
|||
} |
|||
|
|||
void Win32TaskRunner::PostTask(UIWidgetsTask uiwidgets_task, |
|||
uint64_t uiwidgets_target_time_nanos) { |
|||
static std::atomic_uint64_t sGlobalTaskOrder(0); |
|||
|
|||
Task task; |
|||
task.order = ++sGlobalTaskOrder; |
|||
task.fire_time = TimePointFromUIWidgetsTime(uiwidgets_target_time_nanos); |
|||
task.task = uiwidgets_task; |
|||
|
|||
{ |
|||
std::lock_guard<std::mutex> lock(task_queue_mutex_); |
|||
task_queue_.push(task); |
|||
|
|||
// Make sure the queue mutex is unlocked before waking up the loop. In case
|
|||
// the wake causes this thread to be descheduled for the primary thread to
|
|||
// process tasks, the acquisition of the lock on that thread while holding
|
|||
// the lock here momentarily till the end of the scope is a pessimization.
|
|||
} |
|||
|
|||
if (!PostThreadMessage(main_thread_id_, WM_NULL, 0, 0)) { |
|||
OutputDebugString(L"Failed to post message to main thread."); |
|||
} |
|||
} |
|||
|
|||
void Win32TaskRunner::AddTaskObserver(intptr_t key, |
|||
const fml::closure& callback) { |
|||
task_observers_[key] = callback; |
|||
} |
|||
|
|||
void Win32TaskRunner::RemoveTaskObserver(intptr_t key) { |
|||
task_observers_.erase(key); |
|||
} |
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include <flutter/fml/closure.h> |
|||
#include <windows.h> |
|||
|
|||
#include <chrono> |
|||
#include <deque> |
|||
#include <functional> |
|||
#include <map> |
|||
#include <mutex> |
|||
#include <queue> |
|||
#include <thread> |
|||
|
|||
#include "shell/platform/embedder/embedder.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class Win32TaskRunner { |
|||
public: |
|||
using TaskExpiredCallback = std::function<void(const UIWidgetsTask*)>; |
|||
|
|||
Win32TaskRunner(DWORD main_thread_id, |
|||
const TaskExpiredCallback& on_task_expired); |
|||
|
|||
~Win32TaskRunner(); |
|||
|
|||
// Returns if the current thread is the thread used by the win32 event loop. |
|||
bool RunsTasksOnCurrentThread() const; |
|||
|
|||
std::chrono::nanoseconds ProcessTasks(); |
|||
|
|||
// Post a Flutter engine tasks to the event loop for delayed execution. |
|||
void PostTask(UIWidgetsTask uiwidgets_task, |
|||
uint64_t uiwidgets_target_time_nanos); |
|||
|
|||
void AddTaskObserver(intptr_t key, const fml::closure& callback); |
|||
|
|||
void RemoveTaskObserver(intptr_t key); |
|||
|
|||
FML_DISALLOW_COPY_AND_ASSIGN(Win32TaskRunner); |
|||
|
|||
private: |
|||
using TaskTimePoint = std::chrono::steady_clock::time_point; |
|||
|
|||
struct Task { |
|||
uint64_t order; |
|||
TaskTimePoint fire_time; |
|||
UIWidgetsTask task; |
|||
|
|||
struct Comparer { |
|||
bool operator()(const Task& a, const Task& b) { |
|||
if (a.fire_time == b.fire_time) { |
|||
return a.order > b.order; |
|||
} |
|||
return a.fire_time > b.fire_time; |
|||
} |
|||
}; |
|||
}; |
|||
|
|||
DWORD main_thread_id_; |
|||
TaskExpiredCallback on_task_expired_; |
|||
std::mutex task_queue_mutex_; |
|||
std::priority_queue<Task, std::deque<Task>, Task::Comparer> task_queue_; |
|||
std::condition_variable task_queue_cv_; |
|||
|
|||
using TaskObservers = std::map<intptr_t, fml::closure>; |
|||
TaskObservers task_observers_; |
|||
|
|||
static TaskTimePoint TimePointFromUIWidgetsTime( |
|||
uint64_t flutter_target_time_nanos); |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
撰写
预览
正在加载...
取消
保存
Reference in new issue