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"
38#if 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 <<
").";
102#if IMPELLER_ENABLE_METAL
108#if IMPELLER_ENABLE_OPENGLES
114#if IMPELLER_ENABLE_VULKAN
129 FML_LOG(WARNING) <<
"PlaygroundImpl::Create failed.";
133 context_ = impl_->GetContext();
138 FML_LOG(WARNING) <<
"Asked to set up a window with no context (call "
139 "SetupContext first).";
142 auto renderer = std::make_unique<Renderer>(context_);
143 if (!renderer->IsValid()) {
146 renderer_ = std::move(renderer);
157 context_->Shutdown();
175 if ((
key == GLFW_KEY_ESCAPE) &&
action == GLFW_RELEASE) {
176 if (mods & (GLFW_MOD_CONTROL | GLFW_MOD_SUPER | GLFW_MOD_SHIFT)) {
184 return cursor_position_;
192 return impl_->GetContentScale();
199void Playground::SetCursorPosition(
Point pos) {
200 cursor_position_ =
pos;
209 if (!render_callback) {
213 if (!renderer_ || !renderer_->IsValid()) {
217 IMGUI_CHECKVERSION();
218 ImGui::CreateContext();
220 []() { ImGui::DestroyContext(); });
221 ImGui::StyleColorsDark();
223 auto& io = ImGui::GetIO();
224 io.IniFilename =
nullptr;
225 io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
226 io.ConfigWindowsResizeFromEdges =
true;
228 auto window =
reinterpret_cast<GLFWwindow*
>(impl_->GetWindowHandle());
233 ::glfwSetWindowUserPointer(
window,
this);
234 ::glfwSetWindowSizeCallback(
244 ::glfwSetCursorPosCallback(
window, [](GLFWwindow*
window,
double x,
247 ->SetCursorPosition({
static_cast<Scalar>(
x),
static_cast<Scalar>(
y)});
250 ImGui_ImplGlfw_InitForOther(
window,
true);
257 ImGui::SetNextWindowPos({10, 10});
260 ::glfwSetWindowPos(
window, 200, 100);
269 if (::glfwWindowShouldClose(
window)) {
273 ImGui_ImplGlfw_NewFrame();
277 &renderer = renderer_](
RenderTarget& render_target) ->
bool {
279 ImGui::DockSpaceOverViewport(ImGui::GetMainViewport(),
280 ImGuiDockNodeFlags_PassthruCentralNode);
281 bool result = render_callback(render_target);
286 auto buffer = renderer->GetContext()->CreateCommandBuffer();
290 buffer->SetLabel(
"ImGui Command Buffer");
292 if (render_target.GetColorAttachments().empty()) {
296 auto color0 = render_target.GetColorAttachments().find(0)->second;
298 if (color0.resolve_texture) {
299 color0.texture = color0.resolve_texture;
300 color0.resolve_texture =
nullptr;
303 render_target.SetColorAttachment(color0, 0);
305 render_target.SetStencilAttachment(std::nullopt);
306 render_target.SetDepthAttachment(std::nullopt);
308 auto pass =
buffer->CreateRenderPass(render_target);
312 pass->SetLabel(
"ImGui Render Pass");
316 pass->EncodeCommands();
317 if (!renderer->GetContext()->GetCommandQueue()->Submit({buffer}).ok()) {
325 if (!renderer_->Render(impl_->AcquireSurfaceFrame(renderer_->GetContext()),
344 auto buffer = context->CreateCommandBuffer();
348 buffer->SetLabel(
"Playground Command Buffer");
350 auto pass =
buffer->CreateRenderPass(render_target);
354 pass->SetLabel(
"Playground Render Pass");
356 if (!pass_callback(*pass)) {
360 pass->EncodeCommands();
361 if (!context->GetCommandQueue()->Submit({buffer}).ok()) {
369 std::shared_ptr<fml::Mapping> mapping) {
371 if (!compressed_image) {
376 return compressed_image;
380 const std::shared_ptr<CompressedImage>& compressed) {
381 if (compressed ==
nullptr) {
389 auto image = compressed->Decode().ConvertToRGBA();
390 if (!
image.IsValid()) {
399 const std::shared_ptr<Context>& context,
401 bool enable_mipmapping) {
405 texture_descriptor.size = decompressed_image.
GetSize();
406 texture_descriptor.mip_count =
410 context->GetResourceAllocator()->CreateTexture(texture_descriptor);
418 VALIDATION_LOG <<
"Could not upload texture to device memory for fixture.";
421 if (enable_mipmapping) {
422 auto command_buffer = context->CreateCommandBuffer();
423 if (!command_buffer) {
425 <<
"Could not create command buffer for mipmap generation.";
428 command_buffer->SetLabel(
"Mipmap Command Buffer");
429 auto blit_pass = command_buffer->CreateBlitPass();
430 blit_pass->SetLabel(
"Mipmap Blit Pass");
431 blit_pass->GenerateMipmap(
texture);
432 blit_pass->EncodeCommands(context->GetResourceAllocator());
433 if (!context->GetCommandQueue()->Submit({command_buffer}).ok()) {
434 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 {
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()) {
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 for (
size_t i = 0; i < fixture_names.size(); i++) {
496 texture->SetContents(
images[i].GetAllocation()->GetMapping(),
497 images[i].GetAllocation()->GetSize(), i);
516 const std::shared_ptr<Capabilities>& capabilities) {
517 return impl_->SetCapabilities(capabilities);
Wraps a closure that is invoked in the destructor unless released by the caller.
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 bool IsVulkanDriverPresent()
static std::unique_ptr< PlaygroundImpl > Create(PlaygroundBackend backend, PlaygroundSwitches switches)
Playground(PlaygroundSwitches switches)
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)
bool WillRenderSomething() const
virtual std::string GetWindowTitle() const =0
const PlaygroundSwitches switches_
std::shared_ptr< Context > GetContext() const
bool OpenPlaygroundHere(const Renderer::RenderCallback &render_callback)
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 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.
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)
std::function< bool(RenderTarget &render_target)> RenderCallback
static const uint8_t buffer[]
#define FML_DLOG(severity)
#define FML_LOG(severity)
#define FML_CHECK(condition)
#define FML_UNREACHABLE()
bool ImGui_ImplImpeller_Init(const std::shared_ptr< impeller::Context > &context)
void ImGui_ImplImpeller_RenderDrawData(ImDrawData *draw_data, impeller::RenderPass &render_pass)
void ImGui_ImplImpeller_Shutdown()
std::array< MockImage, 3 > images
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
void SetupSwiftshaderOnce(bool use_swiftshader)
Find and setup the installable client driver for a locally built SwiftShader at known paths....
constexpr TSize Max(const TSize &o) const
constexpr size_t MipCount() const
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...