10 #include "fml/time/time_point.h"
16 #define GLFW_INCLUDE_NONE
17 #include "third_party/glfw/include/GLFW/glfw3.h"
19 #include "flutter/fml/paths.h"
31 #include "third_party/imgui/backends/imgui_impl_glfw.h"
32 #include "third_party/imgui/imgui.h"
35 #include "fml/platform/darwin/scoped_nsautorelease_pool.h"
36 #endif // FML_OS_MACOSX
38 #if IMPELLER_ENABLE_VULKAN
40 #endif // IMPELLER_ENABLE_VULKAN
73 static std::once_flag sOnceInitializer;
74 std::call_once(sOnceInitializer, []() {
75 ::glfwSetErrorCallback([](
int code,
const char* description) {
76 FML_LOG(ERROR) <<
"GLFW Error '" << description <<
"' (" << code <<
").";
78 FML_CHECK(::glfwInit() == GLFW_TRUE);
102 #if IMPELLER_ENABLE_METAL
104 #else // IMPELLER_ENABLE_METAL
106 #endif // IMPELLER_ENABLE_METAL
108 #if IMPELLER_ENABLE_OPENGLES
110 #else // IMPELLER_ENABLE_OPENGLES
112 #endif // IMPELLER_ENABLE_OPENGLES
114 #if IMPELLER_ENABLE_VULKAN
116 #else // IMPELLER_ENABLE_VULKAN
118 #endif // IMPELLER_ENABLE_VULKAN
128 FML_LOG(WARNING) <<
"PlaygroundImpl::Create failed.";
132 context_ = impl_->GetContext();
137 FML_LOG(WARNING) <<
"Asked to set up a window with no context (call "
138 "SetupContext first).";
141 auto renderer = std::make_unique<Renderer>(context_);
142 if (!renderer->IsValid()) {
145 renderer_ = std::move(renderer);
147 start_time_ = fml::TimePoint::Now().ToEpochDelta();
152 context_->Shutdown();
170 if ((key == GLFW_KEY_ESCAPE) && action == GLFW_RELEASE) {
171 if (mods & (GLFW_MOD_CONTROL | GLFW_MOD_SUPER | GLFW_MOD_SHIFT)) {
174 ::glfwSetWindowShouldClose(window, GLFW_TRUE);
179 return cursor_position_;
187 return impl_->GetContentScale();
191 return (fml::TimePoint::Now().ToEpochDelta() - start_time_).ToSecondsF();
194 void Playground::SetCursorPosition(
Point pos) {
195 cursor_position_ = pos;
204 if (!render_callback) {
208 if (!renderer_ || !renderer_->IsValid()) {
212 IMGUI_CHECKVERSION();
213 ImGui::CreateContext();
214 fml::ScopedCleanupClosure destroy_imgui_context(
215 []() { ImGui::DestroyContext(); });
216 ImGui::StyleColorsDark();
218 auto& io = ImGui::GetIO();
219 io.IniFilename =
nullptr;
220 io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
221 io.ConfigWindowsResizeFromEdges =
true;
223 auto window =
reinterpret_cast<GLFWwindow*
>(impl_->GetWindowHandle());
228 ::glfwSetWindowUserPointer(window,
this);
229 ::glfwSetWindowSizeCallback(
230 window, [](GLFWwindow* window,
int width,
int height) ->
void {
232 reinterpret_cast<Playground*
>(::glfwGetWindowUserPointer(window));
239 ::glfwSetCursorPosCallback(window, [](GLFWwindow* window,
double x,
241 reinterpret_cast<Playground*
>(::glfwGetWindowUserPointer(window))
242 ->SetCursorPosition({
static_cast<Scalar>(x),
static_cast<Scalar>(y)});
245 ImGui_ImplGlfw_InitForOther(window,
true);
246 fml::ScopedCleanupClosure shutdown_imgui([]() { ImGui_ImplGlfw_Shutdown(); });
249 fml::ScopedCleanupClosure shutdown_imgui_impeller(
252 ImGui::SetNextWindowPos({10, 10});
255 ::glfwSetWindowPos(window, 200, 100);
256 ::glfwShowWindow(window);
260 fml::ScopedNSAutoreleasePool pool;
264 if (::glfwWindowShouldClose(window)) {
268 ImGui_ImplGlfw_NewFrame();
272 &renderer = renderer_](
RenderTarget& render_target) ->
bool {
274 ImGui::DockSpaceOverViewport(ImGui::GetMainViewport(),
275 ImGuiDockNodeFlags_PassthruCentralNode);
276 bool result = render_callback(render_target);
281 auto buffer = renderer->GetContext()->CreateCommandBuffer();
285 buffer->SetLabel(
"ImGui Command Buffer");
287 if (render_target.GetColorAttachments().empty()) {
291 auto color0 = render_target.GetColorAttachments().find(0)->second;
293 if (color0.resolve_texture) {
294 color0.texture = color0.resolve_texture;
295 color0.resolve_texture =
nullptr;
298 render_target.SetColorAttachment(color0, 0);
300 render_target.SetStencilAttachment(std::nullopt);
301 render_target.SetDepthAttachment(std::nullopt);
303 auto pass = buffer->CreateRenderPass(render_target);
307 pass->SetLabel(
"ImGui Render Pass");
311 pass->EncodeCommands();
312 if (!renderer->GetContext()->GetCommandQueue()->Submit({buffer}).ok()) {
320 if (!renderer_->Render(impl_->AcquireSurfaceFrame(renderer_->GetContext()),
331 ::glfwHideWindow(window);
339 auto buffer = context->CreateCommandBuffer();
343 buffer->SetLabel(
"Playground Command Buffer");
345 auto pass = buffer->CreateRenderPass(render_target);
349 pass->SetLabel(
"Playground Render Pass");
351 if (!pass_callback(*pass)) {
355 pass->EncodeCommands();
356 if (!context->GetCommandQueue()->Submit({buffer}).ok()) {
364 std::shared_ptr<fml::Mapping> mapping) {
366 if (!compressed_image) {
371 return compressed_image;
375 const std::shared_ptr<CompressedImage>& compressed) {
376 if (compressed ==
nullptr) {
384 auto image = compressed->Decode().ConvertToRGBA();
385 if (!image.IsValid()) {
394 const std::shared_ptr<Context>& context,
396 bool enable_mipmapping) {
400 texture_descriptor.size = decompressed_image.
GetSize();
401 texture_descriptor.mip_count =
405 context->GetResourceAllocator()->CreateTexture(texture_descriptor);
411 auto uploaded = texture->SetContents(decompressed_image.
GetAllocation());
413 VALIDATION_LOG <<
"Could not upload texture to device memory for fixture.";
416 if (enable_mipmapping) {
417 auto command_buffer = context->CreateCommandBuffer();
418 if (!command_buffer) {
420 <<
"Could not create command buffer for mipmap generation.";
423 command_buffer->SetLabel(
"Mipmap Command Buffer");
424 auto blit_pass = command_buffer->CreateBlitPass();
425 blit_pass->SetLabel(
"Mipmap Blit Pass");
426 blit_pass->GenerateMipmap(texture);
427 blit_pass->EncodeCommands(context->GetResourceAllocator());
428 if (!context->GetCommandQueue()->Submit({command_buffer}).ok()) {
429 FML_DLOG(ERROR) <<
"Failed to submit blit pass command buffer.";
437 const std::shared_ptr<Context>& context,
438 std::shared_ptr<fml::Mapping> mapping,
439 bool enable_mipmapping) {
442 if (!image.has_value()) {
450 const char* fixture_name,
451 bool enable_mipmapping)
const {
455 if (texture ==
nullptr) {
458 texture->SetLabel(fixture_name);
463 std::array<const char*, 6> fixture_names)
const {
464 std::array<DecompressedImage, 6> images;
465 for (
size_t i = 0; i < fixture_names.size(); i++) {
468 if (!image.has_value()) {
471 images[i] = image.value();
478 texture_descriptor.size = images[0].GetSize();
479 texture_descriptor.mip_count = 1u;
481 auto texture = renderer_->GetContext()->GetResourceAllocator()->CreateTexture(
487 texture->SetLabel(
"Texture cube");
489 for (
size_t i = 0; i < fixture_names.size(); i++) {
491 texture->SetContents(images[i].GetAllocation()->GetMapping(),
492 images[i].GetAllocation()->GetSize(), i);
511 const std::shared_ptr<Capabilities>& capabilities) {
512 return impl_->SetCapabilities(capabilities);