10 #include "fml/closure.h"
11 #include "fml/time/time_point.h"
17 #define GLFW_INCLUDE_NONE
18 #include "third_party/glfw/include/GLFW/glfw3.h"
20 #include "flutter/fml/paths.h"
32 #include "third_party/imgui/backends/imgui_impl_glfw.h"
33 #include "third_party/imgui/imgui.h"
36 #include "fml/platform/darwin/scoped_nsautorelease_pool.h"
37 #endif // FML_OS_MACOSX
39 #if IMPELLER_ENABLE_VULKAN
41 #endif // IMPELLER_ENABLE_VULKAN
74 static std::once_flag sOnceInitializer;
75 std::call_once(sOnceInitializer, []() {
76 ::glfwSetErrorCallback([](
int code,
const char* description) {
77 FML_LOG(ERROR) <<
"GLFW Error '" << description <<
"' (" << code <<
").";
79 FML_CHECK(::glfwInit() == GLFW_TRUE);
103 #if IMPELLER_ENABLE_METAL
105 #else // IMPELLER_ENABLE_METAL
107 #endif // IMPELLER_ENABLE_METAL
109 #if IMPELLER_ENABLE_OPENGLES
111 #else // IMPELLER_ENABLE_OPENGLES
113 #endif // IMPELLER_ENABLE_OPENGLES
115 #if IMPELLER_ENABLE_VULKAN
117 #else // IMPELLER_ENABLE_VULKAN
119 #endif // IMPELLER_ENABLE_VULKAN
130 FML_LOG(WARNING) <<
"PlaygroundImpl::Create failed.";
134 context_ = impl_->GetContext();
139 FML_LOG(WARNING) <<
"Asked to set up a window with no context (call "
140 "SetupContext first).";
143 auto renderer = std::make_unique<Renderer>(context_);
144 if (!renderer->IsValid()) {
147 renderer_ = std::move(renderer);
149 start_time_ = fml::TimePoint::Now().ToEpochDelta();
158 context_->Shutdown();
176 if ((key == GLFW_KEY_ESCAPE) && action == GLFW_RELEASE) {
177 if (mods & (GLFW_MOD_CONTROL | GLFW_MOD_SUPER | GLFW_MOD_SHIFT)) {
180 ::glfwSetWindowShouldClose(window, GLFW_TRUE);
185 return cursor_position_;
193 return impl_->GetContentScale();
197 return (fml::TimePoint::Now().ToEpochDelta() - start_time_).ToSecondsF();
200 void Playground::SetCursorPosition(
Point pos) {
201 cursor_position_ = pos;
210 if (!render_callback) {
214 if (!renderer_ || !renderer_->IsValid()) {
218 IMGUI_CHECKVERSION();
219 ImGui::CreateContext();
220 fml::ScopedCleanupClosure destroy_imgui_context(
221 []() { ImGui::DestroyContext(); });
222 ImGui::StyleColorsDark();
224 auto& io = ImGui::GetIO();
225 io.IniFilename =
nullptr;
226 io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
227 io.ConfigWindowsResizeFromEdges =
true;
229 auto window =
reinterpret_cast<GLFWwindow*
>(impl_->GetWindowHandle());
234 ::glfwSetWindowUserPointer(window,
this);
235 ::glfwSetWindowSizeCallback(
236 window, [](GLFWwindow* window,
int width,
int height) ->
void {
238 reinterpret_cast<Playground*
>(::glfwGetWindowUserPointer(window));
245 ::glfwSetCursorPosCallback(window, [](GLFWwindow* window,
double x,
247 reinterpret_cast<Playground*
>(::glfwGetWindowUserPointer(window))
248 ->SetCursorPosition({
static_cast<Scalar>(x),
static_cast<Scalar>(y)});
251 ImGui_ImplGlfw_InitForOther(window,
true);
252 fml::ScopedCleanupClosure shutdown_imgui([]() { ImGui_ImplGlfw_Shutdown(); });
255 fml::ScopedCleanupClosure shutdown_imgui_impeller(
258 ImGui::SetNextWindowPos({10, 10});
261 ::glfwSetWindowPos(window, 200, 100);
262 ::glfwShowWindow(window);
266 fml::ScopedNSAutoreleasePool pool;
270 if (::glfwWindowShouldClose(window)) {
274 ImGui_ImplGlfw_NewFrame();
278 &renderer = renderer_](
RenderTarget& render_target) ->
bool {
280 ImGui::DockSpaceOverViewport(ImGui::GetMainViewport(),
281 ImGuiDockNodeFlags_PassthruCentralNode);
282 bool result = render_callback(render_target);
287 auto buffer = renderer->GetContext()->CreateCommandBuffer();
291 buffer->SetLabel(
"ImGui Command Buffer");
293 if (render_target.GetColorAttachments().empty()) {
297 auto color0 = render_target.GetColorAttachments().find(0)->second;
299 if (color0.resolve_texture) {
300 color0.texture = color0.resolve_texture;
301 color0.resolve_texture =
nullptr;
304 render_target.SetColorAttachment(color0, 0);
306 render_target.SetStencilAttachment(std::nullopt);
307 render_target.SetDepthAttachment(std::nullopt);
309 auto pass = buffer->CreateRenderPass(render_target);
313 pass->SetLabel(
"ImGui Render Pass");
317 pass->EncodeCommands();
318 if (!renderer->GetContext()->GetCommandQueue()->Submit({buffer}).ok()) {
326 if (!renderer_->Render(impl_->AcquireSurfaceFrame(renderer_->GetContext()),
337 ::glfwHideWindow(window);
345 auto buffer = context->CreateCommandBuffer();
349 buffer->SetLabel(
"Playground Command Buffer");
351 auto pass = buffer->CreateRenderPass(render_target);
355 pass->SetLabel(
"Playground Render Pass");
357 if (!pass_callback(*pass)) {
361 pass->EncodeCommands();
362 if (!context->GetCommandQueue()->Submit({buffer}).ok()) {
370 std::shared_ptr<fml::Mapping> mapping) {
372 if (!compressed_image) {
377 return compressed_image;
381 const std::shared_ptr<CompressedImage>& compressed) {
382 if (compressed ==
nullptr) {
390 auto image = compressed->Decode().ConvertToRGBA();
391 if (!image.IsValid()) {
400 const std::shared_ptr<Context>& context,
402 bool enable_mipmapping) {
406 texture_descriptor.size = decompressed_image.
GetSize();
407 texture_descriptor.mip_count =
411 context->GetResourceAllocator()->CreateTexture(texture_descriptor);
417 auto command_buffer = context->CreateCommandBuffer();
418 if (!command_buffer) {
419 FML_DLOG(ERROR) <<
"Could not create command buffer for mipmap generation.";
422 command_buffer->SetLabel(
"Mipmap Command Buffer");
424 auto blit_pass = command_buffer->CreateBlitPass();
426 context->GetResourceAllocator()->CreateBufferWithCopy(
429 if (enable_mipmapping) {
430 blit_pass->SetLabel(
"Mipmap Blit Pass");
431 blit_pass->GenerateMipmap(texture);
433 blit_pass->EncodeCommands(context->GetResourceAllocator());
434 if (!context->GetCommandQueue()->Submit({command_buffer}).ok()) {
435 FML_DLOG(ERROR) <<
"Failed to submit blit pass command buffer.";
442 const std::shared_ptr<Context>& context,
443 std::shared_ptr<fml::Mapping> mapping,
444 bool enable_mipmapping) {
447 if (!image.has_value()) {
455 const char* fixture_name,
456 bool enable_mipmapping)
const {
460 if (texture ==
nullptr) {
463 texture->SetLabel(fixture_name);
468 std::array<const char*, 6> fixture_names)
const {
469 std::array<DecompressedImage, 6> images;
470 for (
size_t i = 0; i < fixture_names.size(); i++) {
473 if (!image.has_value()) {
476 images[i] = image.value();
483 texture_descriptor.size = images[0].GetSize();
484 texture_descriptor.mip_count = 1u;
486 auto texture = renderer_->GetContext()->GetResourceAllocator()->CreateTexture(
492 texture->SetLabel(
"Texture cube");
494 auto cmd_buffer = renderer_->GetContext()->CreateCommandBuffer();
495 auto blit_pass = cmd_buffer->CreateBlitPass();
496 for (
size_t i = 0; i < fixture_names.size(); i++) {
498 renderer_->GetContext()->GetResourceAllocator()->CreateBufferWithCopy(
499 *images[i].GetAllocation());
504 if (!blit_pass->EncodeCommands(
505 renderer_->GetContext()->GetResourceAllocator()) ||
506 !renderer_->GetContext()
508 ->Submit({std::move(cmd_buffer)})
526 const std::shared_ptr<Capabilities>& capabilities) {
527 return impl_->SetCapabilities(capabilities);