13 #include "fml/mapping.h"
18 #include "impeller/playground/imgui/imgui_raster.frag.h"
19 #include "impeller/playground/imgui/imgui_raster.vert.h"
20 #include "third_party/imgui/imgui.h"
44 std::shared_ptr<impeller::Context>
context;
46 std::shared_ptr<impeller::Pipeline<impeller::PipelineDescriptor>>
pipeline;
51 return ImGui::GetCurrentContext()
53 ImGui::GetIO().BackendRendererUserData)
58 const std::shared_ptr<impeller::Context>& context) {
59 ImGuiIO& io = ImGui::GetIO();
60 IM_ASSERT(io.BackendRendererUserData ==
nullptr &&
61 "Already initialized a renderer backend!");
66 io.BackendRendererUserData =
reinterpret_cast<void*
>(bd);
67 io.BackendRendererName =
"imgui_impl_impeller";
69 ImGuiBackendFlags_RendererHasVtxOffset;
73 bd->context = context;
77 unsigned char* pixels;
79 io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
84 texture_descriptor.
size = {width, height};
88 context->GetResourceAllocator()->CreateTexture(texture_descriptor);
89 IM_ASSERT(bd->font_texture !=
nullptr &&
90 "Could not allocate ImGui font texture.");
91 bd->font_texture->SetLabel(
"ImGui Font Texture");
93 auto command_buffer = context->CreateCommandBuffer();
94 auto blit_pass = command_buffer->CreateBlitPass();
95 auto mapping = std::make_shared<fml::NonOwnedMapping>(
96 reinterpret_cast<const uint8_t*
>(pixels),
99 context->GetResourceAllocator()->CreateBufferWithCopy(*mapping);
103 blit_pass->EncodeCommands();
105 [[maybe_unused]]
bool uploaded =
106 context->GetCommandQueue()->Submit({command_buffer}).ok();
107 IM_ASSERT(uploaded &&
108 "Could not upload ImGui font texture to device memory.");
114 impeller::ImguiRasterFragmentShader>::
115 MakeDefaultPipelineDescriptor(*context);
116 IM_ASSERT(desc.has_value() &&
"Could not create Impeller pipeline");
117 if (desc.has_value()) {
119 desc->ClearStencilAttachments();
120 desc->ClearDepthAttachment();
124 context->GetPipelineLibrary()->GetPipeline(std::move(desc)).Get();
125 IM_ASSERT(bd->pipeline !=
nullptr &&
"Could not create ImGui pipeline.");
126 IM_ASSERT(bd->pipeline !=
nullptr &&
"Could not create ImGui sampler.");
134 IM_ASSERT(bd !=
nullptr &&
135 "No renderer backend to shutdown, or already shutdown?");
136 ImGuiIO& io = ImGui::GetIO();
138 io.BackendRendererName =
nullptr;
139 io.BackendRendererUserData =
nullptr;
140 io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset;
147 if (draw_data->CmdListsCount == 0) {
151 using VS = impeller::ImguiRasterVertexShader;
152 using FS = impeller::ImguiRasterFragmentShader;
155 IM_ASSERT(bd !=
nullptr &&
"Did you call ImGui_ImplImpeller_Init()?");
157 size_t total_vtx_bytes = draw_data->TotalVtxCount *
sizeof(VS::PerVertexData);
158 size_t total_idx_bytes = draw_data->TotalIdxCount *
sizeof(ImDrawIdx);
159 if (!total_vtx_bytes || !total_idx_bytes) {
165 buffer_desc.
size = total_vtx_bytes + total_idx_bytes;
168 auto buffer = bd->context->GetResourceAllocator()->CreateBuffer(buffer_desc);
169 buffer->SetLabel(
"ImGui vertex+index buffer");
172 draw_data->DisplayPos.x, draw_data->DisplayPos.y,
173 draw_data->DisplaySize.x, draw_data->DisplaySize.y);
176 .
rect = display_rect.
Scale(draw_data->FramebufferScale.x,
177 draw_data->FramebufferScale.y)};
180 VS::UniformBuffer uniforms;
185 size_t vertex_buffer_offset = 0;
186 size_t index_buffer_offset = total_vtx_bytes;
188 for (
int draw_list_i = 0; draw_list_i < draw_data->CmdListsCount;
190 const ImDrawList* cmd_list = draw_data->CmdLists[draw_list_i];
200 std::vector<VS::PerVertexData> vtx_data;
201 vtx_data.reserve(cmd_list->VtxBuffer.size());
202 for (
const auto& v : cmd_list->VtxBuffer) {
203 ImVec4 color = ImGui::ColorConvertU32ToFloat4(v.col);
204 vtx_data.push_back({{v.pos.x, v.pos.y},
206 {color.x, color.y, color.z, color.w}});
209 auto draw_list_vtx_bytes =
210 static_cast<size_t>(vtx_data.size() *
sizeof(VS::PerVertexData));
211 auto draw_list_idx_bytes =
212 static_cast<size_t>(cmd_list->IdxBuffer.size_in_bytes());
213 if (!buffer->CopyHostBuffer(
reinterpret_cast<uint8_t*
>(vtx_data.data()),
215 vertex_buffer_offset)) {
216 IM_ASSERT(
false &&
"Could not copy vertices to buffer.");
218 if (!buffer->CopyHostBuffer(
219 reinterpret_cast<uint8_t*
>(cmd_list->IdxBuffer.Data),
221 IM_ASSERT(
false &&
"Could not copy indices to buffer.");
224 for (
int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) {
225 const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
227 if (pcmd->UserCallback) {
228 pcmd->UserCallback(cmd_list, pcmd);
232 (pcmd->ClipRect.x - draw_data->DisplayPos.x) *
233 draw_data->FramebufferScale.x,
234 (pcmd->ClipRect.y - draw_data->DisplayPos.y) *
235 draw_data->FramebufferScale.y,
236 (pcmd->ClipRect.z - draw_data->DisplayPos.x) *
237 draw_data->FramebufferScale.x,
238 (pcmd->ClipRect.w - draw_data->DisplayPos.y) *
239 draw_data->FramebufferScale.y);
242 auto visible_clip = clip_rect.Intersection(viewport.rect);
243 if (!visible_clip.has_value()) {
246 clip_rect = visible_clip.value();
251 auto visible_clip = clip_rect.Intersection(
253 if (!visible_clip.has_value()) {
256 clip_rect = visible_clip.value();
260 std::format(
"ImGui draw list {} (command {})", draw_list_i, cmd_i));
264 VS::BindUniformBuffer(render_pass, vtx_uniforms);
265 FS::BindTex(render_pass, bd->font_texture, bd->sampler);
268 vertex_buffer_offset + pcmd->VtxOffset *
sizeof(ImDrawVert);
275 pcmd->IdxOffset *
sizeof(ImDrawIdx),
276 pcmd->ElemCount *
sizeof(ImDrawIdx)));
282 render_pass.
Draw().ok();
286 vertex_buffer_offset += draw_list_vtx_bytes;
287 index_buffer_offset += draw_list_idx_bytes;
static BufferView AsBufferView(std::shared_ptr< DeviceBuffer > buffer)
Create a buffer view of this entire buffer.
BufferView EmplaceUniform(const UniformType &uniform)
Emplace uniform data onto the host buffer. Ensure that backend specific uniform alignment requirement...
void Reset()
Resets the contents of the HostBuffer to nothing so it can be reused.
Render passes encode render commands directed as one specific render target into an underlying comman...
virtual bool SetVertexBuffer(VertexBuffer buffer)
Specify the vertex and index buffer to use for this command.
virtual void SetScissor(IRect32 scissor)
virtual void SetPipeline(PipelineRef pipeline)
The pipeline to use for this command.
ISize GetRenderTargetSize() const
virtual fml::Status Draw()
Record the currently pending command.
virtual void SetCommandLabel(std::string_view label)
The debugging label to use for the command.
virtual void SetBaseVertex(uint64_t value)
virtual void SetViewport(Viewport viewport)
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)
static ImGui_ImplImpeller_Data * ImGui_ImplImpeller_GetBackendData()
void ImGui_ImplImpeller_Shutdown()
LinePipeline::FragmentShader FS
LinePipeline::VertexShader VS
std::shared_ptr< impeller::Context > context
std::shared_ptr< impeller::Pipeline< impeller::PipelineDescriptor > > pipeline
std::shared_ptr< impeller::Texture > font_texture
impeller::raw_ptr< const impeller::Sampler > sampler
ImGui_ImplImpeller_Data(impeller::raw_ptr< const impeller::Sampler > p_sampler)
static constexpr Matrix MakeOrthographic(TSize< T > size)
constexpr Matrix Translate(const Vector3 &t) const
An optional (but highly recommended) utility for creating pipelines from reflected shader information...
RoundOut(const TRect< U > &r)
constexpr TRect Scale(Type scale) const
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
constexpr static TRect MakeSize(const TSize< U > &size)
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
constexpr size_t GetByteSizeOfBaseMipLevel() const
BufferView index_buffer
The index buffer binding used by the vertex shader stage.