Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
playground.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <array>
6#include <memory>
7#include <optional>
8#include <sstream>
9
10#include "fml/closure.h"
11#include "fml/time/time_point.h"
18#include "third_party/googletest/googletest/include/gtest/gtest.h"
19
20#define GLFW_INCLUDE_NONE
21#include "third_party/glfw/include/GLFW/glfw3.h"
22
23#include "flutter/fml/paths.h"
38#include "third_party/imgui/backends/imgui_impl_glfw.h"
39#include "third_party/imgui/imgui.h"
40
41#if FML_OS_MACOSX
43#endif // FML_OS_MACOSX
44
45#if IMPELLER_ENABLE_VULKAN
47#endif // IMPELLER_ENABLE_VULKAN
48
49namespace impeller {
50
51namespace {
52std::string GetTestName() {
53 std::string suite_name =
54 ::testing::UnitTest::GetInstance()->current_test_suite()->name();
55 std::string test_name =
56 ::testing::UnitTest::GetInstance()->current_test_info()->name();
57 std::stringstream ss;
58 ss << "impeller_" << suite_name << "_" << test_name;
59 std::string result = ss.str();
60 // Make sure there are no slashes in the test name.
61 std::replace(result.begin(), result.end(), '/', '_');
62 return result;
63}
64
65std::string GetGoldenFilename(const std::string& postfix = "") {
66 return GetTestName() + postfix + ".png";
67}
68} // namespace
69
71 switch (backend) {
73 return "Metal";
75 return "MetalSDF";
77 return "OpenGLES";
79 return "OpenGLESSDF";
81 return "Vulkan";
82 }
84}
85
86std::atomic<bool> Playground::glfw_initialized_ = false;
87
88void Playground::InitializeGLFWOnce() {
89 // This guard is a hack to work around a problem where glfwCreateWindow
90 // hangs when opening a second window after GLFW has been reinitialized (for
91 // example, when flipping through multiple playground tests).
92 //
93 // Explanation:
94 // * glfwCreateWindow calls [NSApp run], which begins running the event
95 // loop on the current thread.
96 // * GLFW then immediately stops the loop when
97 // applicationDidFinishLaunching is fired.
98 // * applicationDidFinishLaunching is only ever fired once during the
99 // application's lifetime, so subsequent calls to [NSApp run] will always
100 // hang with this setup.
101 // * glfwInit resets the flag that guards against [NSApp run] being
102 // called a second time, which causes the subsequent `glfwCreateWindow`
103 // to hang indefinitely in the event loop, because
104 // applicationDidFinishLaunching is never fired.
105 static std::once_flag sOnceInitializer;
106 std::call_once(sOnceInitializer, []() {
107 ::glfwSetErrorCallback([](int code, const char* description) {
108 FML_LOG(ERROR) << "GLFW Error '" << description << "' (" << code << ").";
109 });
110 FML_CHECK(::glfwInit() == GLFW_TRUE);
111 glfw_initialized_ = true;
112 });
113}
114
116 if (glfw_initialized_) {
117 ::glfwTerminate();
118 }
119}
120
124
126 const PlaygroundSwitches& switches)
127 : backend_(backend), switches_(switches) {
128 InitializeGLFWOnce();
130}
131
132Playground::~Playground() = default;
133
135 FML_CHECK(!context_) << "Must be called before a context is created.";
136 switches_.can_share_context = false;
137}
138
140#if __arm64__ && FML_OS_MACOSX
141 switch (backend_) {
144 return true;
148 return false;
149 }
150#else
151 return false;
152#endif
153}
154
156 // We could call GetContext(), but we don't want to cause it to be
157 // created just yet. So, we make some assumptions here. If they are
158 // insufficient then we should beef them up rather than just calling
159 // GetContext() if we can.
160 // Also, technically, we should check if it supports OffscreenMSAA
161 // which might be a subset of supporting MSAA on screen, but for now
162 // they seem to be closely related.
163 switch (backend_) {
166 return true;
169 return false;
171 return true;
172 }
173}
174
178
180 PipelineDescriptor& desc) const {
181 // Match the golden/verirication harness render target:
182 // - msaa or single samples depending on the Context
183 // - no depth or stencil
187 return true;
188}
189
191 FML_CHECK(!context_) << "Must be called before a context is created.";
193 return false;
194 }
195 switches_.enable_wide_gamut = true;
196 return true;
197}
198
199std::shared_ptr<Context> Playground::GetContext() const {
200 if (!context_) {
201 SetupContext();
202 }
203 return context_;
204}
205
206std::shared_ptr<Context> Playground::MakeContext() const {
207 // This method is used to get a unique context that is not shared with
208 // other playground tests. It requires that the test has called the
209 // |EnsureContextIsUnique| method before it calls this method. We
210 // verify those conditions here and then set up the context.
211 FML_CHECK(!context_) << "MakeContext can only be called once";
212 FML_CHECK(!switches_.can_share_context)
213 << "MakeContext should only be called after EnsureContextIsUnique()";
214 SetupContext();
215
216 return context_;
217}
218
220 if (!content_context_) {
221 content_context_ =
222 std::make_unique<ContentContext>(GetContext(), GetTypographerContext());
223 FML_CHECK(content_context_) << "Failed to create ContentContext";
224 }
225 return *content_context_;
226}
227
228std::shared_ptr<TypographerContext> Playground::GetTypographerContext() const {
229 if (!typographer_context_) {
230 typographer_context_ = TypographerContextSkia::Make();
231 }
232 return typographer_context_;
233}
234
236 std::shared_ptr<TypographerContext> typographer_context) {
237 FML_CHECK(!typographer_context_)
238 << "SetTypographerContext called after it has already been initialized";
239 typographer_context_ = std::move(typographer_context);
240}
241
243 switch (backend) {
246#if IMPELLER_ENABLE_METAL
247 return true;
248#else // IMPELLER_ENABLE_METAL
249 return false;
250#endif // IMPELLER_ENABLE_METAL
253#if IMPELLER_ENABLE_OPENGLES
254 return true;
255#else // IMPELLER_ENABLE_OPENGLES
256 return false;
257#endif // IMPELLER_ENABLE_OPENGLES
259#if IMPELLER_ENABLE_VULKAN
261#else // IMPELLER_ENABLE_VULKAN
262 return false;
263#endif // IMPELLER_ENABLE_VULKAN
264 }
266}
267
268std::unique_ptr<PlaygroundImpl>& Playground::GetImpl() const {
269 if (!impl_) {
270 SetupContext();
271 }
272 FML_CHECK(impl_);
273 return impl_;
274}
275
276void Playground::SetupContext() const {
277 FML_CHECK(SupportsBackend(backend_));
278
279 impl_ = PlaygroundImpl::Create(backend_, switches_);
280 if (!impl_) {
281 FML_LOG(WARNING) << "PlaygroundImpl::Create failed.";
282 return;
283 }
284
285 context_ = impl_->GetContext();
286}
287
288void Playground::SetupWindow() {
289 if (!context_) {
290 FML_LOG(WARNING) << "Asked to set up a window with no context (call "
291 "SetupContext first).";
292 return;
293 }
294 start_time_ = fml::TimePoint::Now().ToEpochDelta();
295}
296
298 return switches_.enable_playground;
299}
300
302 if (content_context_) {
303 FML_CHECK(context_);
304 [[maybe_unused]] auto result = context_->FlushCommandBuffers();
305 content_context_.reset();
306 }
307 if (host_buffer_) {
308 host_buffer_.reset();
309 }
310 if (context_) {
311 context_->Shutdown();
312 }
313 context_.reset();
314 impl_.reset();
315}
316
317static std::atomic_bool gShouldOpenNewPlaygrounds = true;
318
322
323static void PlaygroundKeyCallback(GLFWwindow* window,
324 int key,
325 int scancode,
326 int action,
327 int mods) {
328 if ((key == GLFW_KEY_ESCAPE) && action == GLFW_RELEASE) {
329 if (mods & (GLFW_MOD_CONTROL | GLFW_MOD_SUPER | GLFW_MOD_SHIFT)) {
331 }
332 ::glfwSetWindowShouldClose(window, GLFW_TRUE);
333 }
334}
335
337 return cursor_position_;
338}
339
341 return window_size_;
342}
343
345 return IRect::MakeSize(window_size_);
346}
347
349 return GetImpl()->GetContentScale();
350}
351
353 return (fml::TimePoint::Now().ToEpochDelta() - start_time_).ToSecondsF();
354}
355
356void Playground::SetCursorPosition(Point pos) {
357 cursor_position_ = pos;
358}
359
361 return should_write_golden_;
362}
363
364void Playground::SetEnableWriteGolden(bool write_golden) {
365 should_write_golden_ = write_golden;
366}
367
368bool Playground::RenderImage(const RenderCallback& callback,
369 bool write_result) {
370 std::shared_ptr<Context> context = GetContext();
371 if (!context) {
372 return false;
373 }
374
375 AiksContext renderer(context, typographer_context_);
376 Point content_scale = GetContentScale();
377 ISize size(std::round(GetWindowSize().width * content_scale.x),
378 std::round(GetWindowSize().height * content_scale.y));
379
380 std::string label =
381 write_result ? "Golden Render Pass" : "Playground Verification Pass";
382 RenderTargetAllocator render_target_allocator(
383 context->GetResourceAllocator());
384 RenderTarget render_target;
385 if (context->GetCapabilities()->SupportsOffscreenMSAA()) {
386 render_target = render_target_allocator.CreateOffscreenMSAA(
387 *context, size, /*mip_count=*/1, label + " (MSAA)",
389 /*stencil_attachment_config=*/std::nullopt);
390 } else {
391 render_target = render_target_allocator.CreateOffscreen(
392 *context, size, /*mip_count=*/1, label,
394 /*stencil_attachment_config=*/std::nullopt);
395 }
396 if (!render_target.IsValid()) {
397 return false;
398 }
399 if (!callback(render_target)) {
400 return false;
401 }
402 if (write_result && !WriteGoldenImage(render_target)) {
403 return false;
404 }
405 return true;
406}
407
408bool Playground::WriteGoldenImage(const RenderTarget& render_target,
409 const std::string& postfix) {
410 testing::GoldenDigestManager* digest = GetGoldenDigestManager();
411 if (!digest) {
412 FML_LOG(ERROR) << "Golden image has no working directory";
413 return false;
414 }
415
416 std::shared_ptr<Context> context = GetContext();
417 if (!context) {
418 return false;
419 }
420
421 digest->AddDimension("gpu_string", context->DescribeGpuModel());
422
423 std::string test_name = GetTestName();
424
425 std::unique_ptr<testing::Screenshot> screenshot =
427 context, render_target.GetRenderTargetTexture());
428 if (!screenshot || !screenshot->GetBytes()) {
429 FML_LOG(ERROR) << "Failed to collect screenshot for test " << test_name;
430 return false;
431 }
432
433 std::string filename = GetGoldenFilename(postfix);
434 std::string filenamepath = digest->GetFullPath(filename);
435 if (!screenshot->WriteToPNG(filenamepath)) {
436 FML_LOG(ERROR) << "Failed to write screenshot to " << filenamepath;
437 return false;
438 }
439 digest->AddImage(test_name, filename, //
440 screenshot->GetWidth(), screenshot->GetHeight());
441
442 return true;
443}
444
446 const Playground::RenderCallback& render_callback) {
447 std::shared_ptr<Context> context = GetContext();
449
450 if (!render_callback) {
451 return true;
452 }
453
454 auto window = reinterpret_cast<GLFWwindow*>(impl_->GetWindowHandle());
455 if (!window) {
456 return false;
457 }
458 ::glfwSetWindowSize(window, GetWindowSize().width, GetWindowSize().height);
459
460 bool writing_golden = GetGoldenDigestManager() && should_write_golden_;
461 if (!switches_.enable_playground || writing_golden) {
462 bool success = RenderImage(render_callback, false);
463 if (success && writing_golden) {
464 // Render twice for a golden result so the second pass observes warmed
465 // pipeline and resource caches.
466 success = RenderImage(render_callback, true);
467 }
468 if (!success || !switches_.enable_playground) {
469 return success;
470 }
471 }
472 FML_CHECK(switches_.enable_playground);
473
474 IMGUI_CHECKVERSION();
475 ImGui::CreateContext();
476 fml::ScopedCleanupClosure destroy_imgui_context(
477 []() { ImGui::DestroyContext(); });
478 ImGui::StyleColorsDark();
479
480 auto& io = ImGui::GetIO();
481 io.IniFilename = nullptr;
482 io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
483 io.ConfigWindowsResizeFromEdges = true;
484
485 ::glfwSetWindowTitle(window, GetWindowTitle().c_str());
486 ::glfwSetWindowUserPointer(window, this);
487 ::glfwSetWindowSizeCallback(
488 window, [](GLFWwindow* window, int width, int height) -> void {
489 auto playground =
490 reinterpret_cast<Playground*>(::glfwGetWindowUserPointer(window));
491 if (!playground) {
492 return;
493 }
494 playground->SetWindowSize(ISize{width, height}.Max({}));
495 });
496 ::glfwSetKeyCallback(window, &PlaygroundKeyCallback);
497 ::glfwSetCursorPosCallback(window, [](GLFWwindow* window, double x,
498 double y) {
499 reinterpret_cast<Playground*>(::glfwGetWindowUserPointer(window))
500 ->SetCursorPosition({static_cast<Scalar>(x), static_cast<Scalar>(y)});
501 });
502
503 ImGui_ImplGlfw_InitForOther(window, true);
504 fml::ScopedCleanupClosure shutdown_imgui([]() { ImGui_ImplGlfw_Shutdown(); });
505
507 fml::ScopedCleanupClosure shutdown_imgui_impeller(
508 []() { ImGui_ImplImpeller_Shutdown(); });
509
510 ImGui::SetNextWindowPos({10, 10});
511
512 ::glfwSetWindowPos(window, 200, 100);
513 ::glfwShowWindow(window);
514
515 while (true) {
516#if FML_OS_MACOSX
518#endif
519 ::glfwPollEvents();
520
521 if (::glfwWindowShouldClose(window)) {
522 return true;
523 }
524
525 ImGui_ImplGlfw_NewFrame();
526
527 auto surface = GetImpl()->AcquireSurfaceFrame(context);
528 RenderTarget render_target = surface->GetRenderTarget();
529
530 ImGui::NewFrame();
531 ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport(),
532 ImGuiDockNodeFlags_PassthruCentralNode);
533 bool result = render_callback(render_target);
534 ImGui::Render();
535
536 // Render ImGui overlay.
537 {
538 auto buffer = context->CreateCommandBuffer();
539 if (!buffer) {
540 VALIDATION_LOG << "Could not create command buffer.";
541 return false;
542 }
543 buffer->SetLabel("ImGui Command Buffer");
544
545 auto color0 = render_target.GetColorAttachment(0);
547 if (color0.resolve_texture) {
548 color0.texture = color0.resolve_texture;
549 color0.resolve_texture = nullptr;
550 color0.store_action = StoreAction::kStore;
551 }
552 render_target.SetColorAttachment(color0, 0);
553 render_target.SetStencilAttachment(std::nullopt);
554 render_target.SetDepthAttachment(std::nullopt);
555
556 auto pass = buffer->CreateRenderPass(render_target);
557 if (!pass) {
558 VALIDATION_LOG << "Could not create render pass.";
559 return false;
560 }
561 pass->SetLabel("ImGui Render Pass");
562 if (!host_buffer_) {
563 host_buffer_ = HostBuffer::Create(
564 context->GetResourceAllocator(), context->GetIdleWaiter(),
565 context->GetCapabilities()->GetMinimumUniformAlignment());
566 }
567
568 ImGui_ImplImpeller_RenderDrawData(ImGui::GetDrawData(), *pass,
569 *host_buffer_);
570
571 pass->EncodeCommands();
572
573 if (!context->GetCommandQueue()->Submit({buffer}).ok()) {
574 return false;
575 }
576 }
577
578 if (!result || !surface->Present()) {
579 return false;
580 }
581
582 if (!ShouldKeepRendering()) {
583 break;
584 }
585 }
586
587 ::glfwHideWindow(window);
588
589 return true;
590}
591
593 return OpenPlaygroundHere(
594 [context = GetContext(), &pass_callback](RenderTarget& render_target) {
595 auto buffer = context->CreateCommandBuffer();
596 if (!buffer) {
597 return false;
598 }
599 buffer->SetLabel("Playground Command Buffer");
600
601 auto pass = buffer->CreateRenderPass(render_target);
602 if (!pass) {
603 return false;
604 }
605 pass->SetLabel("Playground Render Pass");
606
607 if (!pass_callback(*pass)) {
608 return false;
609 }
610
611 pass->EncodeCommands();
612 if (!context->GetCommandQueue()->Submit({buffer}).ok()) {
613 return false;
614 }
615 return true;
616 });
617}
618
619std::shared_ptr<CompressedImage> Playground::LoadFixtureImageCompressed(
620 std::shared_ptr<fml::Mapping> mapping) {
621 auto compressed_image = CompressedImageSkia::Create(std::move(mapping));
622 if (!compressed_image) {
623 VALIDATION_LOG << "Could not create compressed image.";
624 return nullptr;
625 }
626
627 return compressed_image;
628}
629
630std::optional<DecompressedImage> Playground::DecodeImageRGBA(
631 const std::shared_ptr<CompressedImage>& compressed) {
632 if (compressed == nullptr) {
633 return std::nullopt;
634 }
635 // The decoded image is immediately converted into RGBA as that format is
636 // known to be supported everywhere. For image sources that don't need 32
637 // bit pixel strides, this is overkill. Since this is a test fixture we
638 // aren't necessarily trying to eke out memory savings here and instead
639 // favor simplicity.
640 auto image = compressed->Decode().ConvertToRGBA();
641 if (!image.IsValid()) {
642 VALIDATION_LOG << "Could not decode image.";
643 return std::nullopt;
644 }
645
646 return image;
647}
648
649static std::shared_ptr<Texture> CreateTextureForDecompressedImage(
650 const std::shared_ptr<Context>& context,
651 DecompressedImage& decompressed_image,
652 bool enable_mipmapping) {
653 TextureDescriptor texture_descriptor;
654 texture_descriptor.storage_mode = StorageMode::kDevicePrivate;
655 texture_descriptor.format = PixelFormat::kR8G8B8A8UNormInt;
656 texture_descriptor.size = decompressed_image.GetSize();
657 texture_descriptor.mip_count =
658 enable_mipmapping ? decompressed_image.GetSize().MipCount() : 1u;
659
660 auto texture =
661 context->GetResourceAllocator()->CreateTexture(texture_descriptor);
662 if (!texture) {
663 VALIDATION_LOG << "Could not allocate texture for fixture.";
664 return nullptr;
665 }
666
667 auto command_buffer = context->CreateCommandBuffer();
668 if (!command_buffer) {
669 FML_DLOG(ERROR) << "Could not create command buffer for mipmap generation.";
670 return nullptr;
671 }
672 command_buffer->SetLabel("Mipmap Command Buffer");
673
674 auto blit_pass = command_buffer->CreateBlitPass();
675 auto buffer_view = DeviceBuffer::AsBufferView(
676 context->GetResourceAllocator()->CreateBufferWithCopy(
677 *decompressed_image.GetAllocation()));
678 blit_pass->AddCopy(buffer_view, texture);
679 if (enable_mipmapping) {
680 blit_pass->SetLabel("Mipmap Blit Pass");
681 blit_pass->GenerateMipmap(texture);
682 }
683 blit_pass->EncodeCommands();
684 if (!context->GetCommandQueue()->Submit({command_buffer}).ok()) {
685 FML_DLOG(ERROR) << "Failed to submit blit pass command buffer.";
686 return nullptr;
687 }
688 return texture;
689}
690
691std::shared_ptr<Texture> Playground::CreateTextureForMapping(
692 const std::shared_ptr<Context>& context,
693 std::shared_ptr<fml::Mapping> mapping,
694 bool enable_mipmapping) {
696 Playground::LoadFixtureImageCompressed(std::move(mapping)));
697 if (!image.has_value()) {
698 return nullptr;
699 }
701 enable_mipmapping);
702}
703
704std::shared_ptr<Texture> Playground::CreateTextureForFixture(
705 const char* fixture_name,
706 bool enable_mipmapping) const {
708 GetContext(), OpenAssetAsMapping(fixture_name), enable_mipmapping);
709 if (texture == nullptr) {
710 return nullptr;
711 }
712 texture->SetLabel(fixture_name);
713 return texture;
714}
715
717 std::array<const char*, 6> fixture_names) const {
718 std::array<DecompressedImage, 6> images;
719 for (size_t i = 0; i < fixture_names.size(); i++) {
720 auto image = DecodeImageRGBA(
722 if (!image.has_value()) {
723 return nullptr;
724 }
725 images[i] = image.value();
726 }
727
728 TextureDescriptor texture_descriptor;
729 texture_descriptor.storage_mode = StorageMode::kDevicePrivate;
730 texture_descriptor.type = TextureType::kTextureCube;
731 texture_descriptor.format = PixelFormat::kR8G8B8A8UNormInt;
732 texture_descriptor.size = images[0].GetSize();
733 texture_descriptor.mip_count = 1u;
734
735 auto texture =
736 GetContext()->GetResourceAllocator()->CreateTexture(texture_descriptor);
737 if (!texture) {
738 VALIDATION_LOG << "Could not allocate texture cube.";
739 return nullptr;
740 }
741 texture->SetLabel("Texture cube");
742
743 auto cmd_buffer = GetContext()->CreateCommandBuffer();
744 auto blit_pass = cmd_buffer->CreateBlitPass();
745 for (size_t i = 0; i < fixture_names.size(); i++) {
746 auto device_buffer =
747 GetContext()->GetResourceAllocator()->CreateBufferWithCopy(
748 *images[i].GetAllocation());
749 blit_pass->AddCopy(DeviceBuffer::AsBufferView(device_buffer), texture, {},
750 "", /*mip_level=*/0, /*slice=*/i);
751 }
752
753 if (!blit_pass->EncodeCommands() ||
754 !GetContext()->GetCommandQueue()->Submit({std::move(cmd_buffer)}).ok()) {
755 VALIDATION_LOG << "Could not upload texture to device memory.";
756 return nullptr;
757 }
758
759 return texture;
760}
761
763 window_size_ = size;
764}
765
767 return true;
768}
769
771 const std::shared_ptr<Capabilities>& capabilities) {
772 return GetImpl()->SetCapabilities(capabilities);
773}
774
776 const {
777 return GetImpl()->CreateGLProcAddressResolver();
778}
779
781 const {
782 return GetImpl()->CreateVKProcAddressResolver();
783}
784
785void Playground::SetGPUDisabled(bool value) const {
786 GetImpl()->SetGPUDisabled(value);
787}
788
790 return GetImpl()->GetRuntimeStageBackend();
791}
792
793} // namespace impeller
Wraps a closure that is invoked in the destructor unless released by the caller.
Definition closure.h:32
constexpr TimeDelta ToEpochDelta() const
Definition time_point.h:52
static TimePoint Now()
Definition time_point.cc:49
static std::shared_ptr< CompressedImage > Create(std::shared_ptr< const fml::Mapping > allocation)
const std::shared_ptr< const fml::Mapping > & GetAllocation() const
const ISize & GetSize() const
static BufferView AsBufferView(std::shared_ptr< DeviceBuffer > buffer)
Create a buffer view of this entire buffer.
static std::shared_ptr< HostBuffer > Create(const std::shared_ptr< Allocator > &allocator, const std::shared_ptr< const IdleWaiter > &idle_waiter, size_t minimum_uniform_alignment, std::shared_ptr< const GpuSubmissionTracker > submission_tracker=nullptr)
PipelineDescriptor & SetSampleCount(SampleCount samples)
bool OpenPlaygroundHere(const RenderCallback &render_callback)
std::shared_ptr< Context > MakeContext() const
bool IsPlaygroundEnabled() const
static void OnTearDownTestEnvironment()
virtual bool EnsureContextSupportsWideGamut()
Make sure that when the context is later created that it will support wide gamuts if the platform sup...
virtual bool ShouldKeepRendering() const
bool ShouldWriteGoldenImage()
Whether this instance will write a golden image of the output from |OpenPlaygroundHere|.
static bool ShouldOpenNewPlaygrounds()
bool PlatformSupportsWideGamutTests() const
Returns true if the platform can support wide gamuts.
Point GetCursorPosition() const
void SetWindowSize(ISize size)
static std::shared_ptr< CompressedImage > LoadFixtureImageCompressed(std::shared_ptr< fml::Mapping > mapping)
ISize GetWindowSize() const
bool RenderingSupportsMSAA() const
Returns true if the rendering path supports MSAA rendering.
std::function< bool(RenderPass &pass)> SinglePassCallback
Definition playground.h:44
GLProcAddressResolver CreateGLProcAddressResolver() const
RuntimeStageBackend GetRuntimeStageBackend() const
virtual std::string GetWindowTitle() const =0
ContentContext & GetContentContext() const
std::function< bool(RenderTarget &render_target)> RenderCallback
Definition playground.h:77
void SetGPUDisabled(bool disabled) const
Mark the GPU as unavilable.
std::shared_ptr< TypographerContext > GetTypographerContext() const
virtual testing::GoldenDigestManager * GetGoldenDigestManager() const
bool InitializePipelineDescriptorForRendering(PipelineDescriptor &desc) const
Initializes the provided |PipelineDescriptor| with appropriate default values to match the conditions...
std::shared_ptr< Context > GetContext() const
static bool SupportsBackend(PlaygroundBackend backend)
SampleCount GetDefaultSampleCount() const
Returns the default sample count of the rendering path.
static std::shared_ptr< Texture > CreateTextureForMapping(const std::shared_ptr< Context > &context, std::shared_ptr< fml::Mapping > mapping, bool enable_mipmapping=false)
virtual void EnsureContextIsUnique()
Make sure that when the context is later created that it will not be shared with any other playground...
IRect GetWindowBounds() const
virtual std::unique_ptr< fml::Mapping > OpenAssetAsMapping(std::string asset_name) const =0
Point GetContentScale() const
void SetEnableWriteGolden(bool write_golden)
Sets a particular test to either write a golden or not, false by default.
std::shared_ptr< Texture > CreateTextureForFixture(const char *fixture_name, bool enable_mipmapping=false) const
Scalar GetSecondsElapsed() const
Get the amount of time elapsed from the start of the playground's execution.
Playground(PlaygroundBackend backend, const PlaygroundSwitches &switches)
std::function< void *(void *instance, const char *proc_name)> VKProcAddressResolver
Definition playground.h:123
std::function< void *(const char *proc_name)> GLProcAddressResolver
Definition playground.h:119
void SetTypographerContext(std::shared_ptr< TypographerContext > typographer_context)
static std::optional< DecompressedImage > DecodeImageRGBA(const std::shared_ptr< CompressedImage > &compressed)
std::shared_ptr< Texture > CreateTextureCubeForFixture(std::array< const char *, 6 > fixture_names) const
fml::Status SetCapabilities(const std::shared_ptr< Capabilities > &capabilities)
VKProcAddressResolver CreateVKProcAddressResolver() const
static std::unique_ptr< PlaygroundImpl > Create(PlaygroundBackend backend, PlaygroundSwitches switches)
ColorAttachment GetColorAttachment(size_t index) const
Get the color attachment at [index].
static constexpr AttachmentConfig kDefaultColorAttachmentConfig
static constexpr AttachmentConfigMSAA kDefaultColorAttachmentConfigMSAA
RenderTarget & SetColorAttachment(const ColorAttachment &attachment, size_t index)
RenderTarget & SetDepthAttachment(std::optional< DepthAttachment > attachment)
RenderTarget & SetStencilAttachment(std::optional< StencilAttachment > attachment)
static std::shared_ptr< TypographerContext > Make()
static std::unique_ptr< Screenshot > MakeScreenshot(std::shared_ptr< Context > &context, const std::shared_ptr< Texture > &texture)
int32_t value
int32_t x
FlutterVulkanImage * image
GLFWwindow * window
Definition main.cc:60
VkSurfaceKHR surface
Definition main.cc:65
#define GLFW_TRUE
FlutterDesktopBinaryReply callback
#define FML_DLOG(severity)
Definition logging.h:121
#define FML_LOG(severity)
Definition logging.h:101
#define FML_CHECK(condition)
Definition logging.h:104
#define FML_UNREACHABLE()
Definition logging.h:128
void ImGui_ImplImpeller_RenderDrawData(ImDrawData *draw_data, impeller::RenderPass &render_pass, impeller::HostBuffer &host_buffer)
bool ImGui_ImplImpeller_Init(const std::shared_ptr< impeller::Context > &context)
void ImGui_ImplImpeller_Shutdown()
FlTexture * texture
std::array< MockImage, 3 > images
double y
void SetupSwiftshaderOnce(bool use_swiftshader)
Find and setup the installable client driver for a locally built SwiftShader at known paths....
static std::shared_ptr< Texture > CreateTextureForDecompressedImage(const std::shared_ptr< Context > &context, DecompressedImage &decompressed_image, bool enable_mipmapping)
std::string PlaygroundBackendToString(PlaygroundBackend backend)
Definition playground.cc:70
float Scalar
Definition scalar.h:19
static void PlaygroundKeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods)
TPoint< Scalar > Point
Definition point.h:426
static std::atomic_bool gShouldOpenNewPlaygrounds
PlaygroundBackend
Definition playground.h:32
ISize64 ISize
Definition size.h:162
std::shared_ptr< ContextGLES > context
std::shared_ptr< CommandBuffer > command_buffer
int32_t height
int32_t width
LoadAction load_action
Definition formats.h:911
static constexpr TRect MakeSize(const TSize< U > &size)
Definition rect.h:150
constexpr TSize Max(const TSize &o) const
Definition size.h:97
constexpr size_t MipCount() const
Return the mip count of the texture.
Definition size.h:137
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
#define VALIDATION_LOG
Definition validation.h:91