19#define GLFW_INCLUDE_NONE
20#include "third_party/glfw/include/GLFW/glfw3.h"
35#include "third_party/imgui/backends/imgui_impl_glfw.h"
36#include "third_party/imgui/imgui.h"
42#if IMPELLER_ENABLE_VULKAN
81 static std::once_flag sOnceInitializer;
82 std::call_once(sOnceInitializer, []() {
83 ::glfwSetErrorCallback([](
int code,
const char* description) {
84 FML_LOG(ERROR) <<
"GLFW Error '" << description <<
"' (" << code <<
").";
92 : backend_(backend), switches_(switches) {
100 FML_CHECK(!context_) <<
"Must be called before a context is created.";
105#if __arm64__ && FML_OS_MACOSX
113 FML_CHECK(!context_) <<
"Must be called before a context is created.";
122 FML_CHECK(!context_) <<
"Must be called before a context is created.";
138 FML_CHECK(!context_) <<
"MakeContext can only be called once";
140 <<
"MakeContext should only be called after EnsureContextIsUnique()";
147 if (!content_context_) {
150 FML_CHECK(content_context_) <<
"Failed to create ContentContext";
152 return *content_context_;
156 if (!typographer_context_) {
159 return typographer_context_;
163 std::shared_ptr<TypographerContext> typographer_context) {
165 <<
"SetTypographerContext called after it has already been initialized";
166 typographer_context_ = std::move(typographer_context);
173#if IMPELLER_ENABLE_METAL
180#if IMPELLER_ENABLE_OPENGLES
186#if IMPELLER_ENABLE_VULKAN
195std::unique_ptr<PlaygroundImpl>& Playground::GetImpl()
const {
203void Playground::SetupContext()
const {
208 FML_LOG(WARNING) <<
"PlaygroundImpl::Create failed.";
212 context_ = impl_->GetContext();
215void Playground::SetupWindow() {
217 FML_LOG(WARNING) <<
"Asked to set up a window with no context (call "
218 "SetupContext first).";
229 if (content_context_) {
231 [[maybe_unused]]
auto result = context_->FlushCommandBuffers();
232 content_context_.reset();
235 host_buffer_.reset();
238 context_->Shutdown();
255 if ((
key == GLFW_KEY_ESCAPE) &&
action == GLFW_RELEASE) {
256 if (mods & (GLFW_MOD_CONTROL | GLFW_MOD_SUPER | GLFW_MOD_SHIFT)) {
264 return cursor_position_;
276 return GetImpl()->GetContentScale();
283void Playground::SetCursorPosition(
Point pos) {
284 cursor_position_ = pos;
296 if (!render_callback) {
300 IMGUI_CHECKVERSION();
301 ImGui::CreateContext();
303 []() { ImGui::DestroyContext(); });
304 ImGui::StyleColorsDark();
306 auto& io = ImGui::GetIO();
307 io.IniFilename =
nullptr;
308 io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
309 io.ConfigWindowsResizeFromEdges =
true;
311 auto window =
reinterpret_cast<GLFWwindow*
>(GetImpl()->GetWindowHandle());
316 ::glfwSetWindowUserPointer(
window,
this);
317 ::glfwSetWindowSizeCallback(
327 ::glfwSetCursorPosCallback(
window, [](GLFWwindow*
window,
double x,
330 ->SetCursorPosition({
static_cast<Scalar>(
x),
static_cast<Scalar>(
y)});
333 ImGui_ImplGlfw_InitForOther(
window,
true);
340 ImGui::SetNextWindowPos({10, 10});
343 ::glfwSetWindowPos(
window, 200, 100);
352 if (::glfwWindowShouldClose(
window)) {
356 ImGui_ImplGlfw_NewFrame();
362 ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport(),
363 ImGuiDockNodeFlags_PassthruCentralNode);
364 bool result = render_callback(render_target);
369 auto buffer =
context->CreateCommandBuffer();
374 buffer->SetLabel(
"ImGui Command Buffer");
378 if (color0.resolve_texture) {
379 color0.texture = color0.resolve_texture;
380 color0.resolve_texture =
nullptr;
387 auto pass = buffer->CreateRenderPass(render_target);
392 pass->SetLabel(
"ImGui Render Pass");
396 context->GetCapabilities()->GetMinimumUniformAlignment());
402 pass->EncodeCommands();
404 if (!
context->GetCommandQueue()->Submit({buffer}).ok()) {
409 if (!result || !
surface->Present()) {
426 auto buffer =
context->CreateCommandBuffer();
430 buffer->SetLabel(
"Playground Command Buffer");
432 auto pass = buffer->CreateRenderPass(render_target);
436 pass->SetLabel(
"Playground Render Pass");
438 if (!pass_callback(*pass)) {
442 pass->EncodeCommands();
443 if (!
context->GetCommandQueue()->Submit({buffer}).ok()) {
451 std::shared_ptr<fml::Mapping> mapping) {
453 if (!compressed_image) {
458 return compressed_image;
462 const std::shared_ptr<CompressedImage>& compressed) {
463 if (compressed ==
nullptr) {
471 auto image = compressed->Decode().ConvertToRGBA();
472 if (!
image.IsValid()) {
481 const std::shared_ptr<Context>&
context,
483 bool enable_mipmapping) {
487 texture_descriptor.
size = decompressed_image.
GetSize();
492 context->GetResourceAllocator()->CreateTexture(texture_descriptor);
500 FML_DLOG(ERROR) <<
"Could not create command buffer for mipmap generation.";
507 context->GetResourceAllocator()->CreateBufferWithCopy(
509 blit_pass->AddCopy(buffer_view,
texture);
510 if (enable_mipmapping) {
511 blit_pass->SetLabel(
"Mipmap Blit Pass");
512 blit_pass->GenerateMipmap(
texture);
514 blit_pass->EncodeCommands();
515 if (!
context->GetCommandQueue()->Submit({command_buffer}).ok()) {
516 FML_DLOG(ERROR) <<
"Failed to submit blit pass command buffer.";
523 const std::shared_ptr<Context>&
context,
524 std::shared_ptr<fml::Mapping> mapping,
525 bool enable_mipmapping) {
528 if (!
image.has_value()) {
536 const char* fixture_name,
537 bool enable_mipmapping)
const {
543 texture->SetLabel(fixture_name);
548 std::array<const char*, 6> fixture_names)
const {
549 std::array<DecompressedImage, 6>
images;
550 for (
size_t i = 0;
i < fixture_names.size();
i++) {
553 if (!
image.has_value()) {
563 texture_descriptor.
size =
images[0].GetSize();
567 GetContext()->GetResourceAllocator()->CreateTexture(texture_descriptor);
572 texture->SetLabel(
"Texture cube");
574 auto cmd_buffer =
GetContext()->CreateCommandBuffer();
575 auto blit_pass = cmd_buffer->CreateBlitPass();
576 for (
size_t i = 0;
i < fixture_names.size();
i++) {
578 GetContext()->GetResourceAllocator()->CreateBufferWithCopy(
584 if (!blit_pass->EncodeCommands() ||
585 !
GetContext()->GetCommandQueue()->Submit({std::move(cmd_buffer)}).ok()) {
602 const std::shared_ptr<Capabilities>& capabilities) {
603 return GetImpl()->SetCapabilities(capabilities);
612 return GetImpl()->CreateGLProcAddressResolver();
617 return GetImpl()->CreateVKProcAddressResolver();
621 GetImpl()->SetGPUDisabled(
value);
625 return GetImpl()->GetRuntimeStageBackend();
Wraps a closure that is invoked in the destructor unless released by the caller.
constexpr TimeDelta ToEpochDelta() const
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)
bool OpenPlaygroundHere(const RenderCallback &render_callback)
std::shared_ptr< Context > MakeContext() const
bool IsPlaygroundEnabled() const
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
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
std::function< bool(RenderPass &pass)> SinglePassCallback
GLProcAddressResolver CreateGLProcAddressResolver() const
bool WillRenderSomething() const
Returns true if OpenPlaygroundHere will actually render anything.
RuntimeStageBackend GetRuntimeStageBackend() const
void TearDownContextData()
virtual std::string GetWindowTitle() const =0
ContentContext & GetContentContext() const
std::function< bool(RenderTarget &render_target)> RenderCallback
void SetGPUDisabled(bool disabled) const
Mark the GPU as unavilable.
std::shared_ptr< TypographerContext > GetTypographerContext() const
std::shared_ptr< Context > GetContext() const
static bool SupportsBackend(PlaygroundBackend backend)
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
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)
virtual void EnsureContextSupportsAntialiasLines()
Make sure that when the context is later created that it will support the experimental AA lines flag.
std::function< void *(void *instance, const char *proc_name)> VKProcAddressResolver
std::function< void *(const char *proc_name)> GLProcAddressResolver
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)
static bool IsVulkanDriverPresent()
ColorAttachment GetColorAttachment(size_t index) const
Get the color attachment at [index].
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()
FlutterVulkanImage * image
#define FML_DLOG(severity)
#define FML_LOG(severity)
#define FML_CHECK(condition)
#define FML_UNREACHABLE()
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()
std::array< MockImage, 3 > images
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)
static void PlaygroundKeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods)
static void InitializeGLFWOnce()
static std::atomic_bool gShouldOpenNewPlaygrounds
std::shared_ptr< ContextGLES > context
std::shared_ptr< CommandBuffer > command_buffer
bool antialiased_lines
When turned on DrawLine will use the experimental antialiased path.
static constexpr TRect MakeSize(const TSize< U > &size)
constexpr TSize Max(const TSize &o) const
constexpr size_t MipCount() const
Return the mip count of the texture.
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...