10 #include "fml/closure.h"
11 #include "fml/time/time_point.h"
18 #define GLFW_INCLUDE_NONE
19 #include "third_party/glfw/include/GLFW/glfw3.h"
21 #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 start_time_ = fml::TimePoint::Now().ToEpochDelta();
152 context_->Shutdown();
169 if ((key == GLFW_KEY_ESCAPE) && action == GLFW_RELEASE) {
170 if (mods & (GLFW_MOD_CONTROL | GLFW_MOD_SUPER | GLFW_MOD_SHIFT)) {
173 ::glfwSetWindowShouldClose(window, GLFW_TRUE);
178 return cursor_position_;
186 return impl_->GetContentScale();
190 return (fml::TimePoint::Now().ToEpochDelta() - start_time_).ToSecondsF();
193 void Playground::SetCursorPosition(
Point pos) {
194 cursor_position_ = pos;
203 if (!render_callback) {
207 IMGUI_CHECKVERSION();
208 ImGui::CreateContext();
209 fml::ScopedCleanupClosure destroy_imgui_context(
210 []() { ImGui::DestroyContext(); });
211 ImGui::StyleColorsDark();
213 auto& io = ImGui::GetIO();
214 io.IniFilename =
nullptr;
215 io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
216 io.ConfigWindowsResizeFromEdges =
true;
218 auto window =
reinterpret_cast<GLFWwindow*
>(impl_->GetWindowHandle());
223 ::glfwSetWindowUserPointer(window,
this);
224 ::glfwSetWindowSizeCallback(
225 window, [](GLFWwindow* window,
int width,
int height) ->
void {
227 reinterpret_cast<Playground*
>(::glfwGetWindowUserPointer(window));
234 ::glfwSetCursorPosCallback(window, [](GLFWwindow* window,
double x,
236 reinterpret_cast<Playground*
>(::glfwGetWindowUserPointer(window))
237 ->SetCursorPosition({
static_cast<Scalar>(x),
static_cast<Scalar>(y)});
240 ImGui_ImplGlfw_InitForOther(window,
true);
241 fml::ScopedCleanupClosure shutdown_imgui([]() { ImGui_ImplGlfw_Shutdown(); });
244 fml::ScopedCleanupClosure shutdown_imgui_impeller(
247 ImGui::SetNextWindowPos({10, 10});
250 ::glfwSetWindowPos(window, 200, 100);
251 ::glfwShowWindow(window);
255 fml::ScopedNSAutoreleasePool pool;
259 if (::glfwWindowShouldClose(window)) {
263 ImGui_ImplGlfw_NewFrame();
265 auto surface = impl_->AcquireSurfaceFrame(context_);
266 RenderTarget render_target = surface->GetRenderTarget();
269 ImGui::DockSpaceOverViewport(ImGui::GetMainViewport(),
270 ImGuiDockNodeFlags_PassthruCentralNode);
271 bool result = render_callback(render_target);
276 auto buffer = context_->CreateCommandBuffer();
281 buffer->SetLabel(
"ImGui Command Buffer");
290 if (color0.resolve_texture) {
291 color0.texture = color0.resolve_texture;
292 color0.resolve_texture =
nullptr;
300 auto pass = buffer->CreateRenderPass(render_target);
305 pass->SetLabel(
"ImGui Render Pass");
309 pass->EncodeCommands();
311 if (!context_->GetCommandQueue()->Submit({buffer}).ok()) {
316 if (!result || !surface->Present()) {
325 ::glfwHideWindow(window);
333 auto buffer = context->CreateCommandBuffer();
337 buffer->SetLabel(
"Playground Command Buffer");
339 auto pass = buffer->CreateRenderPass(render_target);
343 pass->SetLabel(
"Playground Render Pass");
345 if (!pass_callback(*pass)) {
349 pass->EncodeCommands();
350 if (!context->GetCommandQueue()->Submit({buffer}).ok()) {
358 std::shared_ptr<fml::Mapping> mapping) {
360 if (!compressed_image) {
365 return compressed_image;
369 const std::shared_ptr<CompressedImage>& compressed) {
370 if (compressed ==
nullptr) {
378 auto image = compressed->Decode().ConvertToRGBA();
379 if (!image.IsValid()) {
388 const std::shared_ptr<Context>& context,
390 bool enable_mipmapping) {
394 texture_descriptor.size = decompressed_image.
GetSize();
395 texture_descriptor.mip_count =
399 context->GetResourceAllocator()->CreateTexture(texture_descriptor);
405 auto command_buffer = context->CreateCommandBuffer();
406 if (!command_buffer) {
407 FML_DLOG(ERROR) <<
"Could not create command buffer for mipmap generation.";
410 command_buffer->SetLabel(
"Mipmap Command Buffer");
412 auto blit_pass = command_buffer->CreateBlitPass();
414 context->GetResourceAllocator()->CreateBufferWithCopy(
417 if (enable_mipmapping) {
418 blit_pass->SetLabel(
"Mipmap Blit Pass");
419 blit_pass->GenerateMipmap(texture);
421 blit_pass->EncodeCommands(context->GetResourceAllocator());
422 if (!context->GetCommandQueue()->Submit({command_buffer}).ok()) {
423 FML_DLOG(ERROR) <<
"Failed to submit blit pass command buffer.";
430 const std::shared_ptr<Context>& context,
431 std::shared_ptr<fml::Mapping> mapping,
432 bool enable_mipmapping) {
435 if (!image.has_value()) {
443 const char* fixture_name,
444 bool enable_mipmapping)
const {
447 if (texture ==
nullptr) {
450 texture->SetLabel(fixture_name);
455 std::array<const char*, 6> fixture_names)
const {
456 std::array<DecompressedImage, 6> images;
457 for (
size_t i = 0; i < fixture_names.size(); i++) {
460 if (!image.has_value()) {
463 images[i] = image.value();
470 texture_descriptor.size = images[0].GetSize();
471 texture_descriptor.mip_count = 1u;
474 context_->GetResourceAllocator()->CreateTexture(texture_descriptor);
479 texture->SetLabel(
"Texture cube");
481 auto cmd_buffer = context_->CreateCommandBuffer();
482 auto blit_pass = cmd_buffer->CreateBlitPass();
483 for (
size_t i = 0; i < fixture_names.size(); i++) {
484 auto device_buffer = context_->GetResourceAllocator()->CreateBufferWithCopy(
485 *images[i].GetAllocation());
490 if (!blit_pass->EncodeCommands(context_->GetResourceAllocator()) ||
491 !context_->GetCommandQueue()->Submit({std::move(cmd_buffer)}).ok()) {
508 const std::shared_ptr<Capabilities>& capabilities) {
509 return impl_->SetCapabilities(capabilities);
518 return impl_->CreateGLProcAddressResolver();