| Flutter Impeller |

Classes | Public Types | Public Member Functions | Static Public Member Functions | Protected Member Functions | Protected Attributes | List of all members
impeller::Playground Class Referenceabstract

`#include <playground.h>`

Inheritance diagram for impeller::Playground:

## Classes
struct | GLFWInitializer

## Public Types
using | SinglePassCallback = std::function< bool(RenderPass &pass)>

## Public Member Functions
| Playground (PlaygroundSwitches switches)
virtual | ~Playground ()
void | SetupContext (PlaygroundBackend backend)
void | SetupWindow ()
void | TeardownWindow ()
Point | GetCursorPosition () const
ISize | GetWindowSize () const
Point | GetContentScale () const
Scalar | GetSecondsElapsed () const
| Get the amount of time elapsed from the start of the playground's execution. More...
std::shared_ptr< Context > | GetContext () const
bool | OpenPlaygroundHere (const Renderer::RenderCallback &render_callback)
bool | OpenPlaygroundHere (SinglePassCallback pass_callback)
std::shared_ptr< Texture > | CreateTextureForFixture (const char *fixture_name, bool enable_mipmapping=false) const
std::shared_ptr< Texture > | CreateTextureCubeForFixture (std::array< const char *, 6 > fixture_names) const
virtual std::unique_ptr< fml::Mapping > | OpenAssetAsMapping (std::string asset_name) const =0
virtual std::string | GetWindowTitle () const =0

## Static Public Member Functions
static bool | ShouldOpenNewPlaygrounds ()
static std::shared_ptr< CompressedImage > | LoadFixtureImageCompressed (std::shared_ptr< fml::Mapping > mapping)
static std::optional< DecompressedImage > | DecodeImageRGBA (const std::shared_ptr< CompressedImage > &compressed)
static std::shared_ptr< Texture > | CreateTextureForMapping (const std::shared_ptr< Context > &context, std::shared_ptr< fml::Mapping > mapping, bool enable_mipmapping=false)
static bool | SupportsBackend (PlaygroundBackend backend)

## Protected Member Functions
virtual bool | ShouldKeepRendering () const

## Protected Attributes
const PlaygroundSwitches | switches_

## Detailed Description

Definition at line 33 of file playground.h.

## Member Typedef Documentation

## ◆ SinglePassCallback

using impeller::Playground::SinglePassCallback = std::function<bool(RenderPass& pass)>

Definition at line 35 of file playground.h.

## Constructor & Destructor Documentation

## ◆ Playground()

impeller::Playground::Playground | ( | PlaygroundSwitches | switches | ) |
| explicit

Definition at line 80 of file playground.cc.

81 : switches_(switches),
82 glfw_initializer_(std::make_unique<GLFWInitializer>()) {}

## ◆ ~Playground()

impeller::Playground::~Playground | ( |  | ) |
| virtual default

## Member Function Documentation

## ◆ CreateTextureCubeForFixture()

std::shared_ptr< Texture > impeller::Playground::CreateTextureCubeForFixture | ( | std::array< const char *, 6 > | fixture_names | ) | const

Definition at line 487 of file playground.cc.

488 {
489 std::array<DecompressedImage, 6> images;
490 for (size_t i = 0; i < fixture_names.size(); i++) {
491 auto image = DecodeImageRGBA(
492 LoadFixtureImageCompressed(OpenAssetAsMapping(fixture_names[i])));
493 if (!image.has_value()) {
494 return nullptr;
495 }
496 images[i] = image.value();
497 }
498
499 auto texture_descriptor = TextureDescriptor{};
500 texture_descriptor.storage_mode = StorageMode::kHostVisible;
501 texture_descriptor.type = TextureType::kTextureCube;
502 texture_descriptor.format = PixelFormat::kR8G8B8A8UNormInt;
503 texture_descriptor.size = images[0].GetSize();
504 texture_descriptor.mip_count = 1u;
505
506 auto texture = renderer_->GetContext()->GetResourceAllocator()->CreateTexture(
507 texture_descriptor);
508 if (!texture) {
509 VALIDATION_LOG << "Could not allocate texture cube.";
510 return nullptr;
511 }
512 texture->SetLabel("Texture cube");
513
514 for (size_t i = 0; i < fixture_names.size(); i++) {
515 auto uploaded =
516 texture->SetContents(images[i].GetAllocation()->GetMapping(),
517 images[i].GetAllocation()->GetSize(), i);
518 if (!uploaded) {
519 VALIDATION_LOG << "Could not upload texture to device memory.";
520 return nullptr;
521 }
522 }
523
524 return texture;
525 }

References DecodeImageRGBA(), impeller::kHostVisible, impeller::kR8G8B8A8UNormInt, impeller::kTextureCube, LoadFixtureImageCompressed(), OpenAssetAsMapping(), impeller::TextureDescriptor::storage_mode, and VALIDATION_LOG.

## ◆ CreateTextureForFixture()

std::shared_ptr< Texture > impeller::Playground::CreateTextureForFixture | ( | const char * | fixture_name,
|  | bool | enable_mipmapping = `false`
| ) |  | const

Definition at line 474 of file playground.cc.

476 {
477 auto texture = CreateTextureForMapping(renderer_->GetContext(),
478 OpenAssetAsMapping(fixture_name),
479 enable_mipmapping);
480 if (texture == nullptr) {
481 return nullptr;
482 }
483 texture->SetLabel(fixture_name);
484 return texture;
485 }

References CreateTextureForMapping(), and OpenAssetAsMapping().

## ◆ CreateTextureForMapping()

std::shared_ptr< Texture > impeller::Playground::CreateTextureForMapping | ( | const std::shared_ptr< Context > & | context,
|  | std::shared_ptr< fml::Mapping > | mapping,
|  | bool | enable_mipmapping = `false`
| ) |  |
| static

Definition at line 461 of file playground.cc.

464 {
465 auto image = Playground::DecodeImageRGBA(
466 Playground::LoadFixtureImageCompressed(std::move(mapping)));
467 if (!image.has_value()) {
468 return nullptr;
469 }
470 return CreateTextureForDecompressedImage(context, image.value(),
471 enable_mipmapping);
472 }

References impeller::CreateTextureForDecompressedImage(), DecodeImageRGBA(), and LoadFixtureImageCompressed().

Referenced by impeller::GoldenPlaygroundTest::CreateTextureForFixture(), and CreateTextureForFixture().

## ◆ DecodeImageRGBA()

std::optional< DecompressedImage > impeller::Playground::DecodeImageRGBA | ( | const std::shared_ptr< CompressedImage > & | compressed | ) |
| static

Definition at line 365 of file playground.cc.

366 {
367 if (compressed == nullptr) {
368 return std::nullopt;
369 }
370 // The decoded image is immediately converted into RGBA as that format is
371 // known to be supported everywhere. For image sources that don't need 32
372 // bit pixel strides, this is overkill. Since this is a test fixture we
373 // aren't necessarily trying to eke out memory savings here and instead
374 // favor simplicity.
375 auto image = compressed->Decode().ConvertToRGBA();
376 if (!image.IsValid()) {
377 VALIDATION_LOG << "Could not decode image.";
378 return std::nullopt;
379 }
380
381 return image;
382 }

References VALIDATION_LOG.

Referenced by CreateTextureCubeForFixture(), and CreateTextureForMapping().

## ◆ GetContentScale()

Point impeller::Playground::GetContentScale | ( |  | ) | const

Definition at line 177 of file playground.cc.

177 {
178 return impl_->GetContentScale();
179 }

Referenced by impeller::testing::CanRenderConicalGradientWithDithering(), and impeller::testing::CanRenderSweepGradientWithDithering().

## ◆ GetContext()

std::shared_ptr< Context > impeller::Playground::GetContext | ( |  | ) | const

Definition at line 86 of file playground.cc.

86 {
87 return context_;
88 }

Referenced by impeller::testing::RendererDartTest::GetIsolate(), impeller::DlPlayground::OpenPlaygroundHere(), impeller::EntityPlayground::OpenPlaygroundHere(), impeller::AiksPlayground::OpenPlaygroundHere(), OpenPlaygroundHere(), and impeller::RuntimeStagePlayground::RegisterStage().

## ◆ GetCursorPosition()

Point impeller::Playground::GetCursorPosition | ( |  | ) | const

Definition at line 169 of file playground.cc.

169 {
170 return cursor_position_;
171 }

## ◆ GetSecondsElapsed()

Scalar impeller::Playground::GetSecondsElapsed | ( |  | ) | const

Get the amount of time elapsed from the start of the playground's execution.

Definition at line 181 of file playground.cc.

181 {
182 return (fml::TimePoint::Now().ToEpochDelta() - start_time_).ToSecondsF();
183 }

## ◆ GetWindowSize()

ISize impeller::Playground::GetWindowSize | ( |  | ) | const

Definition at line 173 of file playground.cc.

173 {
174 return window_size_;
175 }

Referenced by OpenPlaygroundHere().

## ◆ GetWindowTitle()

virtual std::string impeller::Playground::GetWindowTitle | ( |  | ) | const
| pure virtual

Implemented in impeller::PlaygroundTest, and impeller::ComputePlaygroundTest.

Referenced by OpenPlaygroundHere().

## ◆ LoadFixtureImageCompressed()

std::shared_ptr< CompressedImage > impeller::Playground::LoadFixtureImageCompressed | ( | std::shared_ptr< fml::Mapping > | mapping | ) |
| static

Definition at line 354 of file playground.cc.

355 {
356 auto compressed_image = CompressedImageSkia::Create(std::move(mapping));
357 if (!compressed_image) {
358 VALIDATION_LOG << "Could not create compressed image.";
359 return nullptr;
360 }
361
362 return compressed_image;
363 }

References impeller::CompressedImageSkia::Create(), and VALIDATION_LOG.

Referenced by CreateTextureCubeForFixture(), and CreateTextureForMapping().

## ◆ OpenAssetAsMapping()

virtual std::unique_ptr<fml::Mapping> impeller::Playground::OpenAssetAsMapping | ( | std::string | asset_name | ) | const
| pure virtual

Implemented in impeller::PlaygroundTest, and impeller::ComputePlaygroundTest.

Referenced by CreateTextureCubeForFixture(), and CreateTextureForFixture().

## ◆ OpenPlaygroundHere() [1/2]

bool impeller::Playground::OpenPlaygroundHere | ( | const Renderer::RenderCallback & | render_callback | ) |

Definition at line 189 of file playground.cc.

190 {
191 if (!switches_.enable_playground) {
192 return true;
193 }
194
195 if (!render_callback) {
196 return true;
197 }
198
199 if (!renderer_ || !renderer_->IsValid()) {
200 return false;
201 }
202
203 IMGUI_CHECKVERSION();
204 ImGui::CreateContext();
205 fml::ScopedCleanupClosure destroy_imgui_context(
206 []() { ImGui::DestroyContext(); });
207 ImGui::StyleColorsDark();
208
209 auto& io = ImGui::GetIO();
210 io.IniFilename = nullptr;
211 io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
212 io.ConfigWindowsResizeFromEdges = true;
213
214 auto window = reinterpret_cast<GLFWwindow*>(impl_->GetWindowHandle());
215 if (!window) {
216 return false;
217 }
218 ::glfwSetWindowTitle(window, GetWindowTitle().c_str());
219 ::glfwSetWindowUserPointer(window, this);
220 ::glfwSetWindowSizeCallback(
221 window, [](GLFWwindow* window, int width, int height) -> void {
222 auto playground =
223 reinterpret_cast<Playground*>(::glfwGetWindowUserPointer(window));
224 if (!playground) {
225 return;
226 }
227 playground->SetWindowSize(ISize{width, height}.Max({}));
228 });
229 ::glfwSetKeyCallback(window, &PlaygroundKeyCallback);
230 ::glfwSetCursorPosCallback(window, [](GLFWwindow* window, double x,
231 double y) {
232 reinterpret_cast<Playground*>(::glfwGetWindowUserPointer(window))
233 ->SetCursorPosition({static_cast<Scalar>(x), static_cast<Scalar>(y)});
234 });
235
236 ImGui_ImplGlfw_InitForOther(window, true);
237 fml::ScopedCleanupClosure shutdown_imgui([]() { ImGui_ImplGlfw_Shutdown(); });
238
239 ImGui_ImplImpeller_Init(renderer_->GetContext());
240 fml::ScopedCleanupClosure shutdown_imgui_impeller(
241 []() { ImGui_ImplImpeller_Shutdown(); });
242
243 ImGui::SetNextWindowPos({10, 10});
244
245 ::glfwSetWindowSize(window, GetWindowSize().width, GetWindowSize().height);
246 ::glfwSetWindowPos(window, 200, 100);
247 ::glfwShowWindow(window);
248
249 while (true) {
250 #if FML_OS_MACOSX
251 fml::ScopedNSAutoreleasePool pool;
252 #endif
253 ::glfwPollEvents();
254
255 if (::glfwWindowShouldClose(window)) {
256 return true;
257 }
258
259 ImGui_ImplGlfw_NewFrame();
260
261 Renderer::RenderCallback wrapped_callback =
262 [render_callback,
263 &renderer = renderer_](RenderTarget& render_target) -> bool {
264 ImGui::NewFrame();
265 ImGui::DockSpaceOverViewport(ImGui::GetMainViewport(),
266 ImGuiDockNodeFlags_PassthruCentralNode);
267 bool result = render_callback(render_target);
268 ImGui::Render();
269
270 // Render ImGui overlay.
271 {
272 auto buffer = renderer->GetContext()->CreateCommandBuffer();
273 if (!buffer) {
274 return false;
275 }
276 buffer->SetLabel("ImGui Command Buffer");
277
278 if (render_target.GetColorAttachments().empty()) {
279 return false;
280 }
281
282 auto color0 = render_target.GetColorAttachments().find(0)->second;
283 color0.load_action = LoadAction::kLoad;
284 if (color0.resolve_texture) {
285 color0.texture = color0.resolve_texture;
286 color0.resolve_texture = nullptr;
287 color0.store_action = StoreAction::kStore;
288 }
289 render_target.SetColorAttachment(color0, 0);
290
291 render_target.SetStencilAttachment(std::nullopt);
292 render_target.SetDepthAttachment(std::nullopt);
293
294 auto pass = buffer->CreateRenderPass(render_target);
295 if (!pass) {
296 return false;
297 }
298 pass->SetLabel("ImGui Render Pass");
299
300 ImGui_ImplImpeller_RenderDrawData(ImGui::GetDrawData(), *pass);
301
302 pass->EncodeCommands();
303 if (!buffer->SubmitCommands()) {
304 return false;
305 }
306 }
307
308 return result;
309 };
310
311 if (!renderer_->Render(impl_->AcquireSurfaceFrame(renderer_->GetContext()),
312 wrapped_callback)) {
313 VALIDATION_LOG << "Could not render into the surface.";
314 return false;
315 }
316
317 if (!ShouldKeepRendering()) {
318 break;
319 }
320 }
321
322 ::glfwHideWindow(window);
323
324 return true;
325 }

References impeller::PlaygroundSwitches::enable_playground, GetWindowSize(), GetWindowTitle(), ImGui_ImplImpeller_Init(), ImGui_ImplImpeller_RenderDrawData(), ImGui_ImplImpeller_Shutdown(), impeller::kLoad, impeller::kStore, impeller::TSize< T >::Max(), impeller::PlaygroundKeyCallback(), ShouldKeepRendering(), switches_, and VALIDATION_LOG.

Referenced by impeller::DlPlayground::OpenPlaygroundHere(), impeller::EntityPlayground::OpenPlaygroundHere(), impeller::AiksPlayground::OpenPlaygroundHere(), and OpenPlaygroundHere().

## ◆ OpenPlaygroundHere() [2/2]

bool impeller::Playground::OpenPlaygroundHere | ( | SinglePassCallback | pass_callback | ) |

Definition at line 327 of file playground.cc.

327 {
328 return OpenPlaygroundHere(
329 [context = GetContext(), &pass_callback](RenderTarget& render_target) {
330 auto buffer = context->CreateCommandBuffer();
331 if (!buffer) {
332 return false;
333 }
334 buffer->SetLabel("Playground Command Buffer");
335
336 auto pass = buffer->CreateRenderPass(render_target);
337 if (!pass) {
338 return false;
339 }
340 pass->SetLabel("Playground Render Pass");
341
342 if (!pass_callback(*pass)) {
343 return false;
344 }
345
346 pass->EncodeCommands();
347 if (!buffer->SubmitCommands()) {
348 return false;
349 }
350 return true;
351 });
352 }

References GetContext(), and OpenPlaygroundHere().

## ◆ SetupContext()

void impeller::Playground::SetupContext | ( | PlaygroundBackend | backend | ) |

Definition at line 114 of file playground.cc.

114 {
115 FML_CHECK(SupportsBackend(backend));
116
117 impl_ = PlaygroundImpl::Create(backend, switches_);
118 if (!impl_) {
119 FML_LOG(WARNING) << "PlaygroundImpl::Create failed.";
120 return;
121 }
122
123 context_ = impl_->GetContext();
124 }

References impeller::PlaygroundImpl::Create(), SupportsBackend(), and switches_.

Referenced by impeller::ComputePlaygroundTest::SetUp(), and impeller::PlaygroundTest::SetUp().

## ◆ SetupWindow()

void impeller::Playground::SetupWindow | ( |  | ) |

Definition at line 126 of file playground.cc.

126 {
127 if (!context_) {
128 FML_LOG(WARNING) << "Asked to set up a window with no context (call "
129 "SetupContext first).";
130 return;
131 }
132 auto renderer = std::make_unique<Renderer>(context_);
133 if (!renderer->IsValid()) {
134 return;
135 }
136 renderer_ = std::move(renderer);
137
138 start_time_ = fml::TimePoint::Now().ToEpochDelta();
139 }

Referenced by impeller::ComputePlaygroundTest::SetUp(), and impeller::PlaygroundTest::SetUp().

## ◆ ShouldKeepRendering()

bool impeller::Playground::ShouldKeepRendering | ( |  | ) | const
| protected virtual

Definition at line 531 of file playground.cc.

531 {
532 return true;
533 }

Referenced by OpenPlaygroundHere().

## ◆ ShouldOpenNewPlaygrounds()

bool impeller::Playground::ShouldOpenNewPlaygrounds | ( |  | ) |
| static

Definition at line 152 of file playground.cc.

152 {
153 return gShouldOpenNewPlaygrounds;
154 }

References impeller::gShouldOpenNewPlaygrounds.

Referenced by impeller::ComputePlaygroundTest::SetUp(), and impeller::PlaygroundTest::SetUp().

## ◆ SupportsBackend()

bool impeller::Playground::SupportsBackend | ( | PlaygroundBackend | backend | ) |
| static

Definition at line 90 of file playground.cc.

90 {
91 switch (backend) {
92 case PlaygroundBackend::kMetal:
93 #if IMPELLER_ENABLE_METAL
94 return true;
95 #else // IMPELLER_ENABLE_METAL
96 return false;
97 #endif // IMPELLER_ENABLE_METAL
98 case PlaygroundBackend::kOpenGLES:
99 #if IMPELLER_ENABLE_OPENGLES
100 return true;
101 #else // IMPELLER_ENABLE_OPENGLES
102 return false;
103 #endif // IMPELLER_ENABLE_OPENGLES
104 case PlaygroundBackend::kVulkan:
105 #if IMPELLER_ENABLE_VULKAN
106 return true;
107 #else // IMPELLER_ENABLE_VULKAN
108 return false;
109 #endif // IMPELLER_ENABLE_VULKAN
110 }
111 FML_UNREACHABLE();
112 }

References impeller::kMetal, impeller::kOpenGLES, and impeller::kVulkan.

Referenced by impeller::ComputePlaygroundTest::SetUp(), impeller::PlaygroundTest::SetUp(), and SetupContext().

## ◆ TeardownWindow()

void impeller::Playground::TeardownWindow | ( |  | ) |

Definition at line 141 of file playground.cc.

141 {
142 if (context_) {
143 context_->Shutdown();
144 }
145 context_.reset();
146 renderer_.reset();
147 impl_.reset();
148 }

Referenced by impeller::ComputePlaygroundTest::TearDown(), and impeller::PlaygroundTest::TearDown().

## Member Data Documentation

## ◆ switches_

const PlaygroundSwitches impeller::Playground::switches_
| protected

Definition at line 91 of file playground.h.

Referenced by impeller::DlPlayground::OpenPlaygroundHere(), impeller::EntityPlayground::OpenPlaygroundHere(), impeller::AiksPlayground::OpenPlaygroundHere(), OpenPlaygroundHere(), and SetupContext().

The documentation for this class was generated from the following files:

- impeller/playground/playground.h
- impeller/playground/playground.cc

impeller::LoadAction::kLoad
@ kLoad
impeller::PlaygroundBackend::kVulkan
@ kVulkan
impeller::CreateTextureForDecompressedImage
static std::shared_ptr< Texture > CreateTextureForDecompressedImage(const std::shared_ptr< Context > &context, DecompressedImage &decompressed_image, bool enable_mipmapping)
Definition: playground.cc:384
impeller::Scalar
float Scalar
Definition: scalar.h:15
impeller::Playground::ShouldKeepRendering
virtual bool ShouldKeepRendering() const
Definition: playground.cc:531
impeller::Renderer::RenderCallback
std::function< bool(RenderTarget &render_target)> RenderCallback
Definition: renderer.h:25
impeller::Playground::DecodeImageRGBA
static std::optional< DecompressedImage > DecodeImageRGBA(const std::shared_ptr< CompressedImage > &compressed)
Definition: playground.cc:365
impeller::Playground::GetWindowSize
ISize GetWindowSize() const
Definition: playground.cc:173
impeller::PlaygroundBackend::kMetal
@ kMetal
impeller::PlaygroundKeyCallback
static void PlaygroundKeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods)
Definition: playground.cc:156
impeller::CompressedImageSkia::Create
static std::shared_ptr< CompressedImage > Create(std::shared_ptr< const fml::Mapping > allocation)
Definition: compressed_image_skia.cc:18
impeller::PixelFormat::kR8G8B8A8UNormInt
@ kR8G8B8A8UNormInt
impeller::StorageMode::kHostVisible
@ kHostVisible
impeller::gShouldOpenNewPlaygrounds
static std::atomic_bool gShouldOpenNewPlaygrounds
Definition: playground.cc:150
impeller::TSize::Max
constexpr TSize Max(const TSize &o) const
Definition: size.h:78
impeller::Playground::switches_
const PlaygroundSwitches switches_
Definition: playground.h:91
impeller::TextureType::kTextureCube
@ kTextureCube
impeller::StoreAction::kStore
@ kStore
impeller::PlaygroundImpl::Create
static std::unique_ptr< PlaygroundImpl > Create(PlaygroundBackend backend, PlaygroundSwitches switches)
Definition: playground_impl.cc:24
impeller::ISize
TSize< int64_t > ISize
Definition: size.h:136
ImGui_ImplImpeller_Shutdown
void ImGui_ImplImpeller_Shutdown()
Definition: imgui_impl_impeller.cc:115
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:60
ImGui_ImplImpeller_RenderDrawData
void ImGui_ImplImpeller_RenderDrawData(ImDrawData *draw_data, impeller::RenderPass &render_pass)
Definition: imgui_impl_impeller.cc:122
impeller::PlaygroundBackend::kOpenGLES
@ kOpenGLES
impeller::Playground::CreateTextureForMapping
static std::shared_ptr< Texture > CreateTextureForMapping(const std::shared_ptr< Context > &context, std::shared_ptr< fml::Mapping > mapping, bool enable_mipmapping=false)
Definition: playground.cc:461
impeller::Playground::LoadFixtureImageCompressed
static std::shared_ptr< CompressedImage > LoadFixtureImageCompressed(std::shared_ptr< fml::Mapping > mapping)
Definition: playground.cc:354
impeller::Playground::GetWindowTitle
virtual std::string GetWindowTitle() const =0
impeller::Playground::OpenAssetAsMapping
virtual std::unique_ptr< fml::Mapping > OpenAssetAsMapping(std::string asset_name) const =0
impeller::Playground::SupportsBackend
static bool SupportsBackend(PlaygroundBackend backend)
Definition: playground.cc:90
impeller::Playground::OpenPlaygroundHere
bool OpenPlaygroundHere(const Renderer::RenderCallback &render_callback)
Definition: playground.cc:189
ImGui_ImplImpeller_Init
bool ImGui_ImplImpeller_Init(const std::shared_ptr< impeller::Context > &context)
Definition: imgui_impl_impeller.cc:51
impeller::Playground::Playground
Playground(PlaygroundSwitches switches)
Definition: playground.cc:80
impeller::Playground::GetContext
std::shared_ptr< Context > GetContext() const
Definition: playground.cc:86
impeller::PlaygroundSwitches::enable_playground
bool enable_playground
Definition: switches.h:16