Flutter Impeller
imgui_impl_impeller.cc File Reference
#include "imgui_impl_impeller.h"
#include <algorithm>
#include <climits>
#include <memory>
#include <vector>
#include "fml/mapping.h"
#include "impeller/core/buffer_view.h"
#include "impeller/core/host_buffer.h"
#include "impeller/geometry/scalar.h"
#include "impeller/geometry/vector.h"
#include "impeller/playground/imgui/imgui_raster.frag.h"
#include "impeller/playground/imgui/imgui_raster.vert.h"
#include "third_party/imgui/imgui.h"
#include "impeller/core/allocator.h"
#include "impeller/core/formats.h"
#include "impeller/core/range.h"
#include "impeller/core/sampler.h"
#include "impeller/core/texture.h"
#include "impeller/core/texture_descriptor.h"
#include "impeller/core/vertex_buffer.h"
#include "impeller/geometry/matrix.h"
#include "impeller/geometry/point.h"
#include "impeller/geometry/rect.h"
#include "impeller/geometry/size.h"
#include "impeller/renderer/context.h"
#include "impeller/renderer/pipeline_builder.h"
#include "impeller/renderer/pipeline_descriptor.h"
#include "impeller/renderer/pipeline_library.h"
#include "impeller/renderer/render_pass.h"

Go to the source code of this file.

Classes

struct  ImGui_ImplImpeller_Data
 

Functions

static ImGui_ImplImpeller_DataImGui_ImplImpeller_GetBackendData ()
 
bool ImGui_ImplImpeller_Init (const std::shared_ptr< impeller::Context > &context)
 
void ImGui_ImplImpeller_Shutdown ()
 
void ImGui_ImplImpeller_RenderDrawData (ImDrawData *draw_data, impeller::RenderPass &render_pass, impeller::HostBuffer &host_buffer)
 

Function Documentation

◆ ImGui_ImplImpeller_GetBackendData()

static ImGui_ImplImpeller_Data* ImGui_ImplImpeller_GetBackendData ( )
static

Definition at line 49 of file imgui_impl_impeller.cc.

49  {
50  return ImGui::GetCurrentContext()
51  ? static_cast<ImGui_ImplImpeller_Data*>(
52  ImGui::GetIO().BackendRendererUserData)
53  : nullptr;
54 }

Referenced by ImGui_ImplImpeller_RenderDrawData(), and ImGui_ImplImpeller_Shutdown().

◆ ImGui_ImplImpeller_Init()

bool ImGui_ImplImpeller_Init ( const std::shared_ptr< impeller::Context > &  context)

Definition at line 56 of file imgui_impl_impeller.cc.

57  {
58  ImGuiIO& io = ImGui::GetIO();
59  IM_ASSERT(io.BackendRendererUserData == nullptr &&
60  "Already initialized a renderer backend!");
61 
62  // Setup backend capabilities flags
63  auto* bd =
64  new ImGui_ImplImpeller_Data(context->GetSamplerLibrary()->GetSampler({}));
65  io.BackendRendererUserData = reinterpret_cast<void*>(bd);
66  io.BackendRendererName = "imgui_impl_impeller";
67  io.BackendFlags |=
68  ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the
69  // ImDrawCmd::VtxOffset field,
70  // allowing for large meshes.
71 
72  bd->context = context;
73 
74  // Generate/upload the font atlas.
75  {
76  unsigned char* pixels;
77  int width, height;
78  io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
79 
80  impeller::TextureDescriptor texture_descriptor;
83  texture_descriptor.size = {width, height};
84  texture_descriptor.mip_count = 1u;
85 
86  bd->font_texture =
87  context->GetResourceAllocator()->CreateTexture(texture_descriptor);
88  IM_ASSERT(bd->font_texture != nullptr &&
89  "Could not allocate ImGui font texture.");
90  bd->font_texture->SetLabel("ImGui Font Texture");
91 
92  auto command_buffer = context->CreateCommandBuffer();
93  auto blit_pass = command_buffer->CreateBlitPass();
94  auto mapping = std::make_shared<fml::NonOwnedMapping>(
95  reinterpret_cast<const uint8_t*>(pixels),
96  texture_descriptor.GetByteSizeOfBaseMipLevel());
97  auto device_buffer =
98  context->GetResourceAllocator()->CreateBufferWithCopy(*mapping);
99 
100  blit_pass->AddCopy(impeller::DeviceBuffer::AsBufferView(device_buffer),
101  bd->font_texture);
102  blit_pass->EncodeCommands();
103 
104  [[maybe_unused]] bool uploaded =
105  context->GetCommandQueue()->Submit({command_buffer}).ok();
106  IM_ASSERT(uploaded &&
107  "Could not upload ImGui font texture to device memory.");
108  }
109 
110  // Build the raster pipeline.
111  {
112  auto desc = impeller::PipelineBuilder<impeller::ImguiRasterVertexShader,
113  impeller::ImguiRasterFragmentShader>::
114  MakeDefaultPipelineDescriptor(*context);
115  IM_ASSERT(desc.has_value() && "Could not create Impeller pipeline");
116  if (desc.has_value()) { // Needed to silence clang-tidy check
117  // bugprone-unchecked-optional-access.
118  desc->ClearStencilAttachments();
119  desc->ClearDepthAttachment();
120  }
121 
122  bd->pipeline =
123  context->GetPipelineLibrary()->GetPipeline(std::move(desc)).Get();
124  IM_ASSERT(bd->pipeline != nullptr && "Could not create ImGui pipeline.");
125  IM_ASSERT(bd->pipeline != nullptr && "Could not create ImGui sampler.");
126  }
127 
128  return true;
129 }
static BufferView AsBufferView(std::shared_ptr< DeviceBuffer > buffer)
Create a buffer view of this entire buffer.
An optional (but highly recommended) utility for creating pipelines from reflected shader information...
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
constexpr size_t GetByteSizeOfBaseMipLevel() const

References impeller::DeviceBuffer::AsBufferView(), impeller::TextureDescriptor::format, impeller::TextureDescriptor::GetByteSizeOfBaseMipLevel(), impeller::kDevicePrivate, impeller::kR8G8B8A8UNormInt, impeller::TextureDescriptor::mip_count, impeller::TextureDescriptor::size, and impeller::TextureDescriptor::storage_mode.

Referenced by impeller::Playground::OpenPlaygroundHere().

◆ ImGui_ImplImpeller_RenderDrawData()

void ImGui_ImplImpeller_RenderDrawData ( ImDrawData *  draw_data,
impeller::RenderPass render_pass,
impeller::HostBuffer host_buffer 
)

Definition at line 138 of file imgui_impl_impeller.cc.

140  {
141  if (draw_data->CmdListsCount == 0) {
142  return; // Nothing to render.
143  }
144 
145  using VS = impeller::ImguiRasterVertexShader;
146  using FS = impeller::ImguiRasterFragmentShader;
147 
149  IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplImpeller_Init()?");
150 
151  size_t total_vtx_bytes = draw_data->TotalVtxCount * sizeof(VS::PerVertexData);
152  size_t total_idx_bytes = draw_data->TotalIdxCount * sizeof(ImDrawIdx);
153  if (!total_vtx_bytes || !total_idx_bytes) {
154  return; // Nothing to render.
155  }
156 
157  // Allocate buffer for vertices + indices.
159  buffer_desc.size = total_vtx_bytes + total_idx_bytes;
161 
162  auto buffer = bd->context->GetResourceAllocator()->CreateBuffer(buffer_desc);
163  buffer->SetLabel(impeller::SPrintF("ImGui vertex+index buffer"));
164 
165  auto display_rect = impeller::Rect::MakeXYWH(
166  draw_data->DisplayPos.x, draw_data->DisplayPos.y,
167  draw_data->DisplaySize.x, draw_data->DisplaySize.y);
168 
169  auto viewport = impeller::Viewport{
170  .rect = display_rect.Scale(draw_data->FramebufferScale.x,
171  draw_data->FramebufferScale.y)};
172 
173  // Allocate vertex shader uniform buffer.
174  VS::UniformBuffer uniforms;
175  uniforms.mvp = impeller::Matrix::MakeOrthographic(display_rect.GetSize())
176  .Translate(-display_rect.GetOrigin());
177  auto vtx_uniforms = host_buffer.EmplaceUniform(uniforms);
178 
179  size_t vertex_buffer_offset = 0;
180  size_t index_buffer_offset = total_vtx_bytes;
181 
182  for (int draw_list_i = 0; draw_list_i < draw_data->CmdListsCount;
183  draw_list_i++) {
184  const ImDrawList* cmd_list = draw_data->CmdLists[draw_list_i];
185 
186  // Convert ImGui's per-vertex data (`ImDrawVert`) into the per-vertex data
187  // required by the shader (`VS::PerVectexData`). The only difference is that
188  // `ImDrawVert` uses an `int` for the color and the impeller shader uses 4
189  // floats.
190 
191  // TODO(102778): Remove the need for this by adding support for attribute
192  // mapping of uint32s host-side to vec4s shader-side in
193  // impellerc.
194  std::vector<VS::PerVertexData> vtx_data;
195  vtx_data.reserve(cmd_list->VtxBuffer.size());
196  for (const auto& v : cmd_list->VtxBuffer) {
197  ImVec4 color = ImGui::ColorConvertU32ToFloat4(v.col);
198  vtx_data.push_back({{v.pos.x, v.pos.y}, //
199  {v.uv.x, v.uv.y}, //
200  {color.x, color.y, color.z, color.w}});
201  }
202 
203  auto draw_list_vtx_bytes =
204  static_cast<size_t>(vtx_data.size() * sizeof(VS::PerVertexData));
205  auto draw_list_idx_bytes =
206  static_cast<size_t>(cmd_list->IdxBuffer.size_in_bytes());
207  if (!buffer->CopyHostBuffer(reinterpret_cast<uint8_t*>(vtx_data.data()),
208  impeller::Range{0, draw_list_vtx_bytes},
209  vertex_buffer_offset)) {
210  IM_ASSERT(false && "Could not copy vertices to buffer.");
211  }
212  if (!buffer->CopyHostBuffer(
213  reinterpret_cast<uint8_t*>(cmd_list->IdxBuffer.Data),
214  impeller::Range{0, draw_list_idx_bytes}, index_buffer_offset)) {
215  IM_ASSERT(false && "Could not copy indices to buffer.");
216  }
217 
218  for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) {
219  const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
220 
221  if (pcmd->UserCallback) {
222  pcmd->UserCallback(cmd_list, pcmd);
223  } else {
224  // Make the clip rect relative to the viewport.
225  auto clip_rect = impeller::Rect::MakeLTRB(
226  (pcmd->ClipRect.x - draw_data->DisplayPos.x) *
227  draw_data->FramebufferScale.x,
228  (pcmd->ClipRect.y - draw_data->DisplayPos.y) *
229  draw_data->FramebufferScale.y,
230  (pcmd->ClipRect.z - draw_data->DisplayPos.x) *
231  draw_data->FramebufferScale.x,
232  (pcmd->ClipRect.w - draw_data->DisplayPos.y) *
233  draw_data->FramebufferScale.y);
234  {
235  // Clamp the clip to the viewport bounds.
236  auto visible_clip = clip_rect.Intersection(viewport.rect);
237  if (!visible_clip.has_value()) {
238  continue; // Nothing to render.
239  }
240  clip_rect = visible_clip.value();
241  }
242  {
243  // Clamp the clip to ensure it never goes outside of the render
244  // target.
245  auto visible_clip = clip_rect.Intersection(
247  if (!visible_clip.has_value()) {
248  continue; // Nothing to render.
249  }
250  clip_rect = visible_clip.value();
251  }
252 
254  "ImGui draw list %d (command %d)", draw_list_i, cmd_i));
255  render_pass.SetViewport(viewport);
256  render_pass.SetScissor(impeller::IRect::RoundOut(clip_rect));
257  render_pass.SetPipeline(bd->pipeline);
258  VS::BindUniformBuffer(render_pass, vtx_uniforms);
259  FS::BindTex(render_pass, bd->font_texture, bd->sampler);
260 
261  size_t vb_start =
262  vertex_buffer_offset + pcmd->VtxOffset * sizeof(ImDrawVert);
263 
264  impeller::VertexBuffer vertex_buffer;
265  vertex_buffer.vertex_buffer = impeller::BufferView(
266  buffer, impeller::Range(vb_start, draw_list_vtx_bytes - vb_start));
267  vertex_buffer.index_buffer = impeller::BufferView(
268  buffer, impeller::Range(index_buffer_offset +
269  pcmd->IdxOffset * sizeof(ImDrawIdx),
270  pcmd->ElemCount * sizeof(ImDrawIdx)));
271  vertex_buffer.vertex_count = pcmd->ElemCount;
272  vertex_buffer.index_type = impeller::IndexType::k16bit;
273  render_pass.SetVertexBuffer(std::move(vertex_buffer));
274  render_pass.SetBaseVertex(pcmd->VtxOffset);
275 
276  render_pass.Draw().ok();
277  }
278  }
279 
280  vertex_buffer_offset += draw_list_vtx_bytes;
281  index_buffer_offset += draw_list_idx_bytes;
282  }
283  host_buffer.Reset();
284 }
BufferView EmplaceUniform(const UniformType &uniform)
Emplace uniform data onto the host buffer. Ensure that backend specific uniform alignment requirement...
Definition: host_buffer.h:47
void Reset()
Resets the contents of the HostBuffer to nothing so it can be reused.
Definition: host_buffer.cc:229
virtual bool SetVertexBuffer(VertexBuffer buffer)
Specify the vertex and index buffer to use for this command.
Definition: render_pass.cc:127
virtual void SetScissor(IRect scissor)
Definition: render_pass.cc:115
virtual void SetPipeline(PipelineRef pipeline)
The pipeline to use for this command.
Definition: render_pass.cc:86
ISize GetRenderTargetSize() const
Definition: render_pass.cc:47
virtual fml::Status Draw()
Record the currently pending command.
Definition: render_pass.cc:208
virtual void SetCommandLabel(std::string_view label)
The debugging label to use for the command.
Definition: render_pass.cc:97
virtual void SetBaseVertex(uint64_t value)
Definition: render_pass.cc:107
virtual void SetViewport(Viewport viewport)
Definition: render_pass.cc:111
static ImGui_ImplImpeller_Data * ImGui_ImplImpeller_GetBackendData()
std::string SPrintF(const char *format,...)
Definition: strings.cc:12
LinePipeline::FragmentShader FS
LinePipeline::VertexShader VS
static constexpr Matrix MakeOrthographic(TSize< T > size)
Definition: matrix.h:566
constexpr Matrix Translate(const Vector3 &t) const
Definition: matrix.h:263
RoundOut(const TRect< U > &r)
Definition: rect.h:683
constexpr TRect Scale(Type scale) const
Definition: rect.h:206
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition: rect.h:136
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:150
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition: rect.h:129
BufferView index_buffer
The index buffer binding used by the vertex shader stage.
Definition: vertex_buffer.h:20

References impeller::RenderPass::Draw(), impeller::HostBuffer::EmplaceUniform(), impeller::RenderPass::GetRenderTargetSize(), ImGui_ImplImpeller_GetBackendData(), impeller::VertexBuffer::index_buffer, impeller::VertexBuffer::index_type, impeller::k16bit, impeller::kHostVisible, impeller::TRect< Scalar >::MakeLTRB(), impeller::Matrix::MakeOrthographic(), impeller::TRect< Scalar >::MakeSize(), impeller::TRect< Scalar >::MakeXYWH(), impeller::Viewport::rect, impeller::HostBuffer::Reset(), impeller::TRect< T >::RoundOut(), impeller::TRect< T >::Scale(), impeller::RenderPass::SetBaseVertex(), impeller::RenderPass::SetCommandLabel(), impeller::RenderPass::SetPipeline(), impeller::RenderPass::SetScissor(), impeller::RenderPass::SetVertexBuffer(), impeller::RenderPass::SetViewport(), impeller::DeviceBufferDescriptor::size, impeller::SPrintF(), impeller::DeviceBufferDescriptor::storage_mode, impeller::Matrix::Translate(), impeller::VertexBuffer::vertex_buffer, and impeller::VertexBuffer::vertex_count.

Referenced by impeller::Playground::OpenPlaygroundHere().

◆ ImGui_ImplImpeller_Shutdown()

void ImGui_ImplImpeller_Shutdown ( )

Definition at line 131 of file imgui_impl_impeller.cc.

131  {
133  IM_ASSERT(bd != nullptr &&
134  "No renderer backend to shutdown, or already shutdown?");
135  delete bd;
136 }

References ImGui_ImplImpeller_GetBackendData().

Referenced by impeller::Playground::OpenPlaygroundHere().