10 #include "fml/closure.h"
11 #include "fml/time/time_point.h"
19 #define GLFW_INCLUDE_NONE
20 #include "third_party/glfw/include/GLFW/glfw3.h"
22 #include "flutter/fml/paths.h"
23 #include "flutter/testing/test_swiftshader_utils.h"
34 #include "third_party/imgui/backends/imgui_impl_glfw.h"
35 #include "third_party/imgui/imgui.h"
38 #include "fml/platform/darwin/scoped_nsautorelease_pool.h"
41 #if IMPELLER_ENABLE_VULKAN
78 static std::once_flag sOnceInitializer;
79 std::call_once(sOnceInitializer, []() {
80 ::glfwSetErrorCallback([](
int code,
const char* description) {
81 FML_LOG(ERROR) <<
"GLFW Error '" << description <<
"' (" << code <<
").";
83 FML_CHECK(::glfwInit() == GLFW_TRUE);
108 #if IMPELLER_ENABLE_METAL
114 #if IMPELLER_ENABLE_OPENGLES
120 #if IMPELLER_ENABLE_VULKAN
135 FML_LOG(WARNING) <<
"PlaygroundImpl::Create failed.";
139 context_ = impl_->GetContext();
144 FML_LOG(WARNING) <<
"Asked to set up a window with no context (call "
145 "SetupContext first).";
148 start_time_ = fml::TimePoint::Now().ToEpochDelta();
157 host_buffer_.reset();
160 context_->Shutdown();
177 if ((key == GLFW_KEY_ESCAPE) && action == GLFW_RELEASE) {
178 if (mods & (GLFW_MOD_CONTROL | GLFW_MOD_SUPER | GLFW_MOD_SHIFT)) {
181 ::glfwSetWindowShouldClose(window, GLFW_TRUE);
186 return cursor_position_;
194 return impl_->GetContentScale();
198 return (fml::TimePoint::Now().ToEpochDelta() - start_time_).ToSecondsF();
201 void Playground::SetCursorPosition(
Point pos) {
202 cursor_position_ = pos;
211 if (!render_callback) {
215 IMGUI_CHECKVERSION();
217 fml::ScopedCleanupClosure destroy_imgui_context(
218 []() { ImGui::DestroyContext(); });
219 ImGui::StyleColorsDark();
221 auto& io = ImGui::GetIO();
222 io.IniFilename =
nullptr;
223 io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
224 io.ConfigWindowsResizeFromEdges =
true;
226 auto window =
reinterpret_cast<GLFWwindow*
>(impl_->GetWindowHandle());
231 ::glfwSetWindowUserPointer(window,
this);
232 ::glfwSetWindowSizeCallback(
233 window, [](GLFWwindow* window,
int width,
int height) ->
void {
235 reinterpret_cast<Playground*
>(::glfwGetWindowUserPointer(window));
242 ::glfwSetCursorPosCallback(window, [](GLFWwindow* window,
double x,
244 reinterpret_cast<Playground*
>(::glfwGetWindowUserPointer(window))
245 ->SetCursorPosition({
static_cast<Scalar>(
x),
static_cast<Scalar>(y)});
248 ImGui_ImplGlfw_InitForOther(window,
true);
249 fml::ScopedCleanupClosure shutdown_imgui([]() { ImGui_ImplGlfw_Shutdown(); });
252 fml::ScopedCleanupClosure shutdown_imgui_impeller(
255 ImGui::SetNextWindowPos({10, 10});
258 ::glfwSetWindowPos(window, 200, 100);
259 ::glfwShowWindow(window);
263 fml::ScopedNSAutoreleasePool pool;
267 if (::glfwWindowShouldClose(window)) {
271 ImGui_ImplGlfw_NewFrame();
273 auto surface = impl_->AcquireSurfaceFrame(context_);
274 RenderTarget render_target = surface->GetRenderTarget();
277 ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport(),
278 ImGuiDockNodeFlags_PassthruCentralNode);
279 bool result = render_callback(render_target);
284 auto buffer = context_->CreateCommandBuffer();
289 buffer->SetLabel(
"ImGui Command Buffer");
293 if (color0.resolve_texture) {
294 color0.texture = color0.resolve_texture;
295 color0.resolve_texture =
nullptr;
302 auto pass = buffer->CreateRenderPass(render_target);
307 pass->SetLabel(
"ImGui Render Pass");
310 context_->GetResourceAllocator(), context_->GetIdleWaiter(),
311 context_->GetCapabilities()->GetMinimumUniformAlignment());
317 pass->EncodeCommands();
319 if (!context_->GetCommandQueue()->Submit({buffer}).ok()) {
324 if (!result || !surface->Present()) {
333 ::glfwHideWindow(window);
341 auto buffer = context->CreateCommandBuffer();
345 buffer->SetLabel(
"Playground Command Buffer");
347 auto pass = buffer->CreateRenderPass(render_target);
351 pass->SetLabel(
"Playground Render Pass");
353 if (!pass_callback(*pass)) {
357 pass->EncodeCommands();
358 if (!context->GetCommandQueue()->Submit({buffer}).ok()) {
366 std::shared_ptr<fml::Mapping> mapping) {
368 if (!compressed_image) {
373 return compressed_image;
377 const std::shared_ptr<CompressedImage>& compressed) {
378 if (compressed ==
nullptr) {
386 auto image = compressed->Decode().ConvertToRGBA();
387 if (!image.IsValid()) {
396 const std::shared_ptr<Context>& context,
398 bool enable_mipmapping) {
402 texture_descriptor.
size = decompressed_image.
GetSize();
407 context->GetResourceAllocator()->CreateTexture(texture_descriptor);
413 auto command_buffer = context->CreateCommandBuffer();
414 if (!command_buffer) {
415 FML_DLOG(ERROR) <<
"Could not create command buffer for mipmap generation.";
418 command_buffer->SetLabel(
"Mipmap Command Buffer");
420 auto blit_pass = command_buffer->CreateBlitPass();
422 context->GetResourceAllocator()->CreateBufferWithCopy(
424 blit_pass->AddCopy(buffer_view, texture);
425 if (enable_mipmapping) {
426 blit_pass->SetLabel(
"Mipmap Blit Pass");
427 blit_pass->GenerateMipmap(texture);
429 blit_pass->EncodeCommands();
430 if (!context->GetCommandQueue()->Submit({command_buffer}).ok()) {
431 FML_DLOG(ERROR) <<
"Failed to submit blit pass command buffer.";
438 const std::shared_ptr<Context>& context,
439 std::shared_ptr<fml::Mapping> mapping,
440 bool enable_mipmapping) {
443 if (!image.has_value()) {
451 const char* fixture_name,
452 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();
482 context_->GetResourceAllocator()->CreateTexture(texture_descriptor);
487 texture->SetLabel(
"Texture cube");
489 auto cmd_buffer = context_->CreateCommandBuffer();
490 auto blit_pass = cmd_buffer->CreateBlitPass();
491 for (
size_t i = 0; i < fixture_names.size(); i++) {
492 auto device_buffer = context_->GetResourceAllocator()->CreateBufferWithCopy(
493 *images[i].GetAllocation());
498 if (!blit_pass->EncodeCommands() ||
499 !context_->GetCommandQueue()->Submit({std::move(cmd_buffer)}).ok()) {
516 const std::shared_ptr<Capabilities>& capabilities) {
517 return impl_->SetCapabilities(capabilities);
526 return impl_->CreateGLProcAddressResolver();
531 return impl_->CreateVKProcAddressResolver();
535 impl_->SetGPUDisabled(
value);
539 return impl_->GetRuntimeStageBackend();
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)
Playground(PlaygroundSwitches switches)
bool OpenPlaygroundHere(const RenderCallback &render_callback)
std::shared_ptr< Context > MakeContext() const
bool IsPlaygroundEnabled() const
virtual bool ShouldKeepRendering() const
static bool ShouldOpenNewPlaygrounds()
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
void SetupContext(PlaygroundBackend backend, const PlaygroundSwitches &switches)
GLProcAddressResolver CreateGLProcAddressResolver() const
bool WillRenderSomething() const
Returns true if OpenPlaygroundHere will actually render anything.
RuntimeStageBackend GetRuntimeStageBackend() const
virtual std::string GetWindowTitle() const =0
virtual std::unique_ptr< fml::Mapping > OpenAssetAsMapping(std::string asset_name) const =0
std::function< bool(RenderTarget &render_target)> RenderCallback
void SetGPUDisabled(bool disabled) const
Mark the GPU as unavilable.
const PlaygroundSwitches switches_
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)
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.
std::function< void *(void *instance, const char *proc_name)> VKProcAddressResolver
std::function< void *(const char *proc_name)> GLProcAddressResolver
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)
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::shared_ptr< ContextVK > CreateContext()
std::string PlaygroundBackendToString(PlaygroundBackend backend)
static void PlaygroundKeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods)
static void InitializeGLFWOnce()
static std::shared_ptr< Texture > CreateTextureForDecompressedImage(const std::shared_ptr< Context > &context, DecompressedImage &decompressed_image, bool enable_mipmapping)
static std::atomic_bool gShouldOpenNewPlaygrounds
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...