Lugdunum  0.1.0
Gui.cpp
Go to the documentation of this file.
1 
2 #include <math.h>
4 
5 #include <imgui.h>
6 #include <imgui_freetype.h>
7 
21 
22 namespace lug {
23 namespace Graphics {
24 namespace Vulkan {
25 
26 Gui::Gui(lug::Graphics::Vulkan::Renderer& renderer, lug::Graphics::Vulkan::Render::Window& window) : _renderer(renderer), _window(window) {
27 }
28 
30  destroy();
31 }
32 
33 void Gui::destroy() {
35 
36  for (const auto& frameData: _framesData) {
37  if (frameData.vertexMemoryPtr) {
38  frameData.vertexMemory.unmap();
39  }
40 
41  if (frameData.indexMemoryPtr) {
42  frameData.indexMemory.unmap();
43  }
44 
45  for (const auto& descriptorSet : frameData.texturesDescriptorSets) {
46  _texturesDescriptorSetPool->free(descriptorSet);
47  }
48  }
49 
50  _framesData.clear();
51 
53 
54  if (_fontTexture) {
56  _fontTexture = nullptr;
57  }
58 
61 
62  _graphicQueue = nullptr;
63  _transferQueue = nullptr;
64 }
65 
66 bool Gui::init(const std::vector<API::ImageView>& imageViews) {
67  ImGuiIO& io = ImGui::GetIO();
68 
69  // Load default font if no font has been configured
70  if (!io.Fonts->Fonts.Size) {
71  io.Fonts->AddFontDefault();
72  }
73 
75 
76  io.DisplaySize = ImVec2(_window.getWidth(), _window.getHeight());
77  io.DisplayFramebufferScale = ImVec2(1.0f, 1.0f);
78 
79  API::Device& device = _renderer.getDevice();
80 
81  // Get graphic queue family and retrieve the first queue
82  {
83  _graphicQueue = device.getQueue("queue_graphics");
84  if (!_graphicQueue) {
85  LUG_LOG.error("Gui::init: Can't find graphic queue");
86  return false;
87  }
88 
89  }
90 
91  // Create command pool of graphic queue
92  {
93  VkResult result{VK_SUCCESS};
94  API::Builder::CommandPool commandPoolBuilder(device, *_graphicQueue->getQueueFamily());
95  if (!commandPoolBuilder.build(_graphicQueueCommandPool, &result)) {
96  LUG_LOG.error("Gui::init: Can't create a command pool: {}", result);
97  return false;
98  }
99  }
100 
102  commandBufferBuilder.setLevel(VK_COMMAND_BUFFER_LEVEL_PRIMARY);
103 
104  // Create command buffers (as a temporary vector first)
105  std::vector<Vulkan::API::CommandBuffer> commandBuffers(imageViews.size());
106 
107  // Command buffers
108  {
109  VkResult result{VK_SUCCESS};
110  if (!commandBufferBuilder.build(commandBuffers, &result)) {
111  LUG_LOG.error("Gui::init: Can't create the command buffer: {}", result);
112  return false;
113  }
114  }
115 
116  // Initialize FrameData's
117  _framesData.resize(imageViews.size());
118  for (uint32_t i = 0; i < imageViews.size(); ++i) {
119  _framesData[i].commandBuffer = std::move(commandBuffers[i]);
120  }
121  commandBuffers.clear(); // clear the array
122 
123  _texturesDescriptorSetPool = std::make_unique<Render::DescriptorSetPool::GuiTexture>(_renderer);
124  if (!_texturesDescriptorSetPool->init()) {
125  return false;
126  }
127 
128  return initFontsTexture() && initPipeline() && initFramebuffers(imageViews);
129 }
130 
132  ImGuiIO& io = ImGui::GetIO();
133 
134  // Keyboard mapping for specific shortcuts used by ImGui
135  io.KeyMap[ImGuiKey_Tab] = static_cast<int>(lug::Window::Keyboard::Key::Tab);
136  io.KeyMap[ImGuiKey_LeftArrow] = static_cast<int>(lug::Window::Keyboard::Key::Left);
137  io.KeyMap[ImGuiKey_RightArrow] = static_cast<int>(lug::Window::Keyboard::Key::Right);
138  io.KeyMap[ImGuiKey_UpArrow] = static_cast<int>(lug::Window::Keyboard::Key::Up);
139  io.KeyMap[ImGuiKey_DownArrow] = static_cast<int>(lug::Window::Keyboard::Key::Down);
140  io.KeyMap[ImGuiKey_PageUp] = static_cast<int>(lug::Window::Keyboard::Key::PageUp);
141  io.KeyMap[ImGuiKey_PageDown] = static_cast<int>(lug::Window::Keyboard::Key::PageDown);
142  io.KeyMap[ImGuiKey_Home] = static_cast<int>(lug::Window::Keyboard::Key::Home);
143  io.KeyMap[ImGuiKey_End] = static_cast<int>(lug::Window::Keyboard::Key::End);
144  io.KeyMap[ImGuiKey_Delete] = static_cast<int>(lug::Window::Keyboard::Key::Delete);
145  io.KeyMap[ImGuiKey_Backspace] = static_cast<int>(lug::Window::Keyboard::Key::BackSpace);
146  io.KeyMap[ImGuiKey_Enter] = static_cast<int>(lug::Window::Keyboard::Key::Return);
147  io.KeyMap[ImGuiKey_Escape] = static_cast<int>(lug::Window::Keyboard::Key::Escape);
148  io.KeyMap[ImGuiKey_A] = static_cast<int>(lug::Window::Keyboard::Key::A);
149  io.KeyMap[ImGuiKey_C] = static_cast<int>(lug::Window::Keyboard::Key::C);
150  io.KeyMap[ImGuiKey_V] = static_cast<int>(lug::Window::Keyboard::Key::V);
151  io.KeyMap[ImGuiKey_X] = static_cast<int>(lug::Window::Keyboard::Key::X);
152  io.KeyMap[ImGuiKey_Y] = static_cast<int>(lug::Window::Keyboard::Key::Y);
153  io.KeyMap[ImGuiKey_Z] = static_cast<int>(lug::Window::Keyboard::Key::Z);
154 }
155 
157  ImGuiIO& io = ImGui::GetIO();
158 
159  // Create font texture
160  unsigned char* fontData = nullptr;
161  uint32_t texWidth = 0;
162  uint32_t texHeight = 0;
163 
164  {
165  int tempWidth;
166  int tempHeight;
167  // See ImGuiFreeType::RasterizationFlags
168  unsigned int flags = ImGuiFreeType::NoHinting;
169  ImGuiFreeType::BuildFontAtlas(io.Fonts, flags);
170  io.Fonts->GetTexDataAsRGBA32(&fontData, &tempWidth, &tempHeight);
171  texWidth = static_cast<uint32_t>(tempWidth);
172  texHeight = static_cast<uint32_t>(tempHeight);
173  }
174 
175  API::Device &device = _renderer.getDevice();
176 
177  // Get transfer queue family and retrieve the first queue
178  {
179  _transferQueue = device.getQueue("queue_transfer");
180  if (!_transferQueue) {
181  LUG_LOG.error("Gui::initFontsTexture: Can't find transfer queue");
182  return false;
183  }
184  }
185 
186  // Create command pool of transfer queue
187  {
188  VkResult result{ VK_SUCCESS };
189  API::Builder::CommandPool commandPoolBuilder(device, *_transferQueue->getQueueFamily());
190  if (!commandPoolBuilder.build(_transferQueueCommandPool, &result)) {
191  LUG_LOG.error("Gui::initFontsTexture: Can't create a command pool: {}", result);
192  return false;
193  }
194  }
195 
196  // Create fonts texture
197  {
199 
200  if (!textureBuilder.addLayer(texWidth, texHeight, Render::Texture::Format::R8G8B8A8_UNORM, fontData)) {
201  LUG_LOG.error("Gui::initFontsTexture: Can't load fonts texture");
202  return false;
203  }
204 
207 
208  _fontTexture = textureBuilder.build();
209  if (!_fontTexture) {
210  LUG_LOG.error("Gui::initFontsTexture Can't create fonts texture");
211  return false;
212  }
213 
214  // Set font id to font texture
216  }
217 
218  if (initFrameData() == false) {
219  LUG_LOG.error("Gui::initFontsTexture: Failed to init frame data");
220  return false;
221  }
222 
223 
224  return true;
225 }
226 
228  API::Device &device = _renderer.getDevice();
229 
230  API::Builder::GraphicsPipeline graphicsPipelineBuilder(_renderer.getDevice());
231 
232  // Set shaders state
233  if (!graphicsPipelineBuilder.setShaderFromFile(VK_SHADER_STAGE_VERTEX_BIT, "main", _renderer.getInfo().shadersRoot + "gui.vert.spv")
234  || !graphicsPipelineBuilder.setShaderFromFile(VK_SHADER_STAGE_FRAGMENT_BIT, "main", _renderer.getInfo().shadersRoot + "gui.frag.spv")) {
235  LUG_LOG.error("ForwardRenderer: Can't create pipeline's shaders.");
236  return false;
237  }
238 
239  // Set vertex input state
240  auto vertexBinding = graphicsPipelineBuilder.addInputBinding(sizeof(ImDrawVert), VK_VERTEX_INPUT_RATE_VERTEX);
241 
242  vertexBinding.addAttributes(VK_FORMAT_R32G32B32_SFLOAT, offsetof(ImDrawVert, pos)); // Position
243  vertexBinding.addAttributes(VK_FORMAT_R32G32_SFLOAT, offsetof(ImDrawVert, uv)); // UV
244  vertexBinding.addAttributes(VK_FORMAT_R8G8B8A8_UNORM, offsetof(ImDrawVert, col)); // Color
245 
246  // Set viewport state
247  const VkViewport viewport{
248  /* viewport.x */ 0.0f,
249  /* viewport.y */ 0.0f,
250  /* viewport.width */ 0.0f,
251  /* viewport.height */ 0.0f,
252  /* viewport.minDepth */ 0.0f,
253  /* viewport.maxDepth */ 1.0f,
254  };
255 
256  const VkRect2D scissor{
257  /* scissor.offset */{ 0, 0 },
258  /* scissor.extent */{ 0, 0 }
259  };
260 
261  auto viewportState = graphicsPipelineBuilder.getViewportState();
262  viewportState.addViewport(viewport);
263  viewportState.addScissor(scissor);
264 
265  // Set rasterization state
266  auto rasterizationState = graphicsPipelineBuilder.getRasterizationState();
267  rasterizationState.setCullMode(VK_CULL_MODE_NONE);
268 
269  // Set color blend state
270  const VkPipelineColorBlendAttachmentState colorBlendAttachment{
271  /* colorBlendAttachment.blendEnable */ VK_TRUE,
272  /* colorBlendAttachment.srcColorBlendFactor */ VK_BLEND_FACTOR_SRC_ALPHA,
273  /* colorBlendAttachment.dstColorBlendFactor */ VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
274  /* colorBlendAttachment.colorBlendOp */ VK_BLEND_OP_ADD,
275  /* colorBlendAttachment.srcAlphaBlendFactor */ VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
276  /* colorBlendAttachment.dstAlphaBlendFactor */ VK_BLEND_FACTOR_ZERO,
277  /* colorBlendAttachment.alphaBlendOp */ VK_BLEND_OP_ADD,
278  /* colorBlendAttachment.colorWriteMask */ VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT
279  };
280 
281  auto colorBlendState = graphicsPipelineBuilder.getColorBlendState();
282  colorBlendState.addAttachment(colorBlendAttachment);
283 
284  // Set dynamic states
285  graphicsPipelineBuilder.setDynamicStates({
286  VK_DYNAMIC_STATE_VIEWPORT,
287  VK_DYNAMIC_STATE_SCISSOR
288  });
289 
290  std::vector<Vulkan::API::DescriptorSetLayout> descriptorSetLayouts;
291  {
292  // descriptorSetLayout
293  {
294  API::Builder::DescriptorSetLayout descriptorSetLayoutBuilder(device);
295 
296  // Camera uniform buffer
297  const VkDescriptorSetLayoutBinding binding{
298  /* binding.binding */ 0,
299  /* binding.descriptorType */ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
300  /* binding.descriptorCount */ 1,
301  /* binding.stageFlags */ VK_SHADER_STAGE_FRAGMENT_BIT,
302  /* binding.pImmutableSamplers */ nullptr
303  };
304 
305  descriptorSetLayoutBuilder.setBindings({ binding });
306 
307  // create descriptor set
308  VkResult result{VK_SUCCESS};
309  descriptorSetLayouts.resize(1);
310  if (!descriptorSetLayoutBuilder.build(descriptorSetLayouts[0], &result)) {
311  LUG_LOG.error("Gui::initPipeline: Can't create pipeline descriptor: {}", result);
312  return false;
313  }
314  }
315 
316  VkPushConstantRange pushConstant{
317  /*pushConstant.stageFlags*/ VK_SHADER_STAGE_VERTEX_BIT,
318  /*pushConstant.offset*/ 0,
319  /*pushConstant.size*/ sizeof(PushConstBlock)
320  };
321 
322  API::Builder::PipelineLayout pipelineLayoutBuilder(device);
323 
324  pipelineLayoutBuilder.setPushConstants({ pushConstant });
325  pipelineLayoutBuilder.setDescriptorSetLayouts(std::move(descriptorSetLayouts));
326 
327  VkResult result{VK_SUCCESS};
328  if (!pipelineLayoutBuilder.build(_pipelineLayout, &result)) {
329  LUG_LOG.error("Gui::initPipeline: Can't create pipeline layout: {}", result);
330  return false;
331  }
332  graphicsPipelineBuilder.setPipelineLayout(std::move(_pipelineLayout));
333  }
334 
335  // Set render pass
336  {
337  API::Builder::RenderPass renderPassBuilder(_renderer.getDevice());
338 
339  auto colorFormat = _window.getSwapchain().getFormat().format;
340 
341  const VkAttachmentDescription colorAttachment{
342  /* colorAttachment.flags */ 0,
343  /* colorAttachment.format */ colorFormat,
344  /* colorAttachment.samples */ VK_SAMPLE_COUNT_1_BIT,
345  /* colorAttachment.loadOp */ VK_ATTACHMENT_LOAD_OP_LOAD,
346  /* colorAttachment.storeOp */ VK_ATTACHMENT_STORE_OP_STORE,
347  /* colorAttachment.stencilLoadOp */ VK_ATTACHMENT_LOAD_OP_DONT_CARE,
348  /* colorAttachment.stencilStoreOp */ VK_ATTACHMENT_STORE_OP_DONT_CARE,
349  /* colorAttachment.initialLayout */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
350  /* colorAttachment.finalLayout */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
351  };
352 
353  auto colorAttachmentIndex = renderPassBuilder.addAttachment(colorAttachment);
354 
355  const API::Builder::RenderPass::SubpassDescription subpassDescription{
356  /* subpassDescription.pipelineBindPoint */ VK_PIPELINE_BIND_POINT_GRAPHICS,
357  /* subpassDescription.inputAttachments */{},
358  /* subpassDescription.colorAttachments */{ { colorAttachmentIndex, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL } },
359  /* subpassDescription.resolveAttachments */{},
360  /* subpassDescription.depthStencilAttachment */{},
361  /* subpassDescription.preserveAttachments */{},
362  };
363 
364  renderPassBuilder.addSubpass(subpassDescription);
365 
366  VkResult result{VK_SUCCESS};
367  API::RenderPass renderPass;
368  if (!renderPassBuilder.build(renderPass, &result)) {
369  LUG_LOG.error("Gui::initPipeline: Can't create render pass: {}", result);
370  return false;
371  }
372 
373  graphicsPipelineBuilder.setRenderPass(std::move(renderPass), 0);
374  }
375 
376  VkResult result{VK_SUCCESS};
377  if (!graphicsPipelineBuilder.build(_pipeline, &result)) {
378  LUG_LOG.error("Gui::initPipeline: Can't create pipeline: {}", result);
379  return false;
380  }
381 
382  return true;
383 }
384 
385 bool Gui::initFramebuffers(const std::vector<API::ImageView>& imageViews) {
386  const API::RenderPass* renderPass = _pipeline.getRenderPass();
387 
388  for (size_t i = 0; i < imageViews.size(); ++i) {
389  // Create depth buffer image view
390  API::Builder::Framebuffer framebufferBuilder(_renderer.getDevice());
391 
392  framebufferBuilder.setRenderPass(renderPass);
393  framebufferBuilder.addAttachment(&imageViews[i]);
394  framebufferBuilder.setWidth(imageViews[i].getImage()->getExtent().width);
395  framebufferBuilder.setHeight(imageViews[i].getImage()->getExtent().height);
396 
397  VkResult result{VK_SUCCESS};
398  if (!framebufferBuilder.build(_framesData[i].framebuffer, &result)) {
399  LUG_LOG.error("Gui::initFramebuffers: Can't create framebuffer: {}", result);
400  return false;
401  }
402  }
403 
404  return true;
405 }
406 
407 void Gui::beginFrame(const lug::System::Time& elapsedTime) {
408  ImGuiIO& io = ImGui::GetIO();
409 
410  io.DeltaTime = elapsedTime.getSeconds();
411 
412  io.DisplaySize = ImVec2(_window.getWidth(), _window.getHeight());
413 #if defined(LUG_SYSTEM_ANDROID)
414 io.MousePos = ImVec2(_window._touchScreenState.coordinates[0].x(), _window._touchScreenState.coordinates[0].y());
416 #else
417  const auto mousePos = _window.getMousePos();
418  io.MousePos = ImVec2(static_cast<float>(mousePos.x()), static_cast<float>(mousePos.y()));
419 
420  #endif
421  ImGui::NewFrame();
422 }
423 
424 bool Gui::endFrame(const std::vector<VkSemaphore>& waitSemaphores, uint32_t currentImageIndex) {
425  ImGui::Render();
426  FrameData& frameData = _framesData[currentImageIndex];
427 
428  if (!frameData.fence.wait()) {
429  return false;
430  }
431  frameData.fence.reset();
432  if (updateBuffers(currentImageIndex) == false) {
433  LUG_LOG.error("Gui::endFrame: Failed to update buffers");
434  return false;
435  }
436 
437  frameData.commandBuffer.reset();
438  frameData.commandBuffer.begin();
439 
440  ImGuiIO& io = ImGui::GetIO();
441 
442  io.MouseWheel = 0.f;
443 
444  // Init viewport
445  {
446  const VkViewport vkViewport{
447  /* vkViewport.x */ 0,
448  /* vkViewport.y */ 0,
449  /* vkViewport.width */ io.DisplaySize.x,
450  /* vkViewport.height */ io.DisplaySize.y,
451  /* vkViewport.minDepth */ 0.0f,
452  /* vkViewport.maxDepth */ 1.0f,
453  };
454 
455  frameData.commandBuffer.setViewport({vkViewport});
456  }
457 
458  const API::RenderPass* renderPass = _pipeline.getRenderPass();
459 
460  API::CommandBuffer::CmdBeginRenderPass beginRenderPass{
461  /* beginRenderPass.framebuffer */ frameData.framebuffer,
462  /* beginRenderPass.renderArea */{},
463  /* beginRenderPass.clearValues */{}
464  };
465 
466  beginRenderPass.renderArea.offset = { 0, 0 };
467  beginRenderPass.renderArea.extent = { _window.getWidth(), _window.getHeight() };
468 
469  frameData.commandBuffer.beginRenderPass(*renderPass, beginRenderPass);
470 
471  frameData.commandBuffer.bindPipeline(_pipeline);
472 
473  if (static_cast<VkBuffer>(frameData.vertexBuffer) != VK_NULL_HANDLE) {
474  frameData.commandBuffer.bindVertexBuffers({&frameData.vertexBuffer}, {0});
475  }
476 
477  if (static_cast<VkBuffer>(frameData.indexBuffer) != VK_NULL_HANDLE) {
478  frameData.commandBuffer.bindIndexBuffer(frameData.indexBuffer, VK_INDEX_TYPE_UINT16);
479  }
480 
481  // UI scale and translate via push constants
483  /* pushConstants.scale */ {2.0f / io.DisplaySize.x, 2.0f / io.DisplaySize.y},
484  /* pushConstants.translate */ {-1.0f, -1.0f}
485  };
486  const API::CommandBuffer::CmdPushConstants cmdPushConstants{
487  /* cmdPushConstants.layout */ static_cast<VkPipelineLayout>(*_pipeline.getLayout()),
488  /* cmdPushConstants.stageFlags */ VK_SHADER_STAGE_VERTEX_BIT,
489  /* cmdPushConstants.offset */ 0,
490  /* cmdPushConstants.size */ sizeof(pushConstants),
491  /* cmdPushConstants.values */ &pushConstants
492  };
493  frameData.commandBuffer.pushConstants(cmdPushConstants);
494 
495  // Temporary array of descriptor sets use to render this frame
496  // they will replace frameData.texturesDescriptorSets atfer the rendering
497  std::vector<const Render::DescriptorSetPool::DescriptorSet*> texturesDescriptorSets;
498 
499  // Render commands
500  ImDrawData* imDrawData = ImGui::GetDrawData();
501 
502  uint32_t vertexCount = 0;
503  uint32_t indexCount = 0;
504 
505  for (int32_t i = 0; i < imDrawData->CmdListsCount; i++) {
506  const ImDrawList* cmd_list = imDrawData->CmdLists[i];
507  for (int32_t j = 0; j < cmd_list->CmdBuffer.Size; j++) {
508  const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[j];
509 
510  const VkRect2D scissor{
511  /* scissor.offset */ {
512  std::max(static_cast<int32_t>(pcmd->ClipRect.x), 0),
513  std::max(static_cast<int32_t>(pcmd->ClipRect.y), 0)},
514  /* scissor.extent */ {
515  static_cast<uint32_t>(pcmd->ClipRect.z - pcmd->ClipRect.x),
516  static_cast<uint32_t>(pcmd->ClipRect.w - pcmd->ClipRect.y)
517  }
518  };
519  frameData.commandBuffer.setScissor({scissor});
520 
521  // Get the new (or old) textures descriptor set
522  const Render::DescriptorSetPool::DescriptorSet* texturesDescriptorSet = _texturesDescriptorSetPool->allocate(
523  _pipeline,
524  (Vulkan::Render::Texture*)pcmd->TextureId
525  );
526 
527  if (!texturesDescriptorSet) {
528  LUG_LOG.error("Gui::endFrame: Can't allocate textures descriptor set");
529  return false;
530  }
531 
532  texturesDescriptorSets.push_back(texturesDescriptorSet);
533 
534  // Bind descriptor set of the texture
535  {
536  const API::CommandBuffer::CmdBindDescriptors texturesBind{
537  /* texturesBind.pipelineLayout */ *_pipeline.getLayout(),
538  /* texturesBind.pipelineBindPoint */ VK_PIPELINE_BIND_POINT_GRAPHICS,
539  /* texturesBind.firstSet */ 0,
540  /* texturesBind.descriptorSets */ {&texturesDescriptorSet->getDescriptorSet()},
541  /* texturesBind.dynamicOffsets */ {}
542  };
543 
544  frameData.commandBuffer.bindDescriptorSets(texturesBind);
545  }
546 
547  const API::CommandBuffer::CmdDrawIndexed cmdDrawIndexed {
548  /* cmdDrawIndexed.indexCount */ pcmd->ElemCount,
549  /* cmdDrawIndexed.instanceCount */ 1,
550  /* cmdDrawIndexed.firstIndex */ indexCount,
551  /* cmdDrawIndexed.vertexOffset */ vertexCount,
552  /* cmdDrawIndexed.firstInstance */ 0
553  };
554  frameData.commandBuffer.drawIndexed(cmdDrawIndexed);
555 
556  indexCount += pcmd->ElemCount;
557  }
558  vertexCount += cmd_list->VtxBuffer.Size;
559  }
560 
561  // Free and replace previous texturesDescriptorSets
562  {
563  for (const auto& descriptorSet : frameData.texturesDescriptorSets) {
564  _texturesDescriptorSetPool->free(descriptorSet);
565  }
566 
567  frameData.texturesDescriptorSets = texturesDescriptorSets;
568  }
569 
570  frameData.commandBuffer.endRenderPass();
571  frameData.commandBuffer.end();
572 
573  std::vector<VkPipelineStageFlags> waitDstStageMasks(waitSemaphores.size(), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
574  if (_graphicQueue->submit(frameData.commandBuffer, { static_cast<VkSemaphore>(frameData.semaphore) }, waitSemaphores, waitDstStageMasks, static_cast<VkFence>(frameData.fence)) == false) {
575  LUG_LOG.error("GUI: Can't submit commandBuffer");
576  return false;
577  }
578 
579  return true;
580 }
581 
583  ImGuiIO& io = ImGui::GetIO();
584 
585  if (io.WantCaptureMouse) {
588  switch (event.mouse.code) {
590  io.MouseDown[0] = (event.type == lug::Window::Event::Type::ButtonPressed) ? true : false;
591  break;
593  io.MouseDown[1] = (event.type == lug::Window::Event::Type::ButtonPressed) ? true : false;
594  break;
596  io.MouseDown[2] = (event.type == lug::Window::Event::Type::ButtonPressed) ? true : false;
597  break;
599  io.MouseDown[3] = (event.type == lug::Window::Event::Type::ButtonPressed) ? true : false;
600  break;
602  io.MouseDown[4] = (event.type == lug::Window::Event::Type::ButtonPressed) ? true : false;
603  break;
604  default:
605  break;
606  }
607  return true;
608  } else if (event.type == lug::Window::Event::Type::MouseWheel) {
609  io.MouseWheel += static_cast<float>(event.mouse.scrollOffset.xOffset);
610  return true;
612  if (event.touchScreen.drag) {
613  float draggedDistance = sqrtf(((event.touchScreen.coordinates[0].x() - io.MousePosPrev.x ) * (event.touchScreen.coordinates[0].x() - io.MousePosPrev.x))
614  + ((event.touchScreen.coordinates[0].y() - io.MousePosPrev.y) * (event.touchScreen.coordinates[0].y() - io.MousePosPrev.y)));
615  if ((static_cast<float>(io.MousePosPrev.y) - event.touchScreen.coordinates[0].y()) > 0) {
616  io.MouseWheel -= draggedDistance / (io.DisplaySize.y - static_cast<float>(io.MousePosPrev.y));
617  } else {
618  io.MouseWheel += draggedDistance / (io.DisplaySize.y - static_cast<float>(io.MousePosPrev.y));
619  }
620  }
621  return true;
622  }
623  }
624 
625  if (io.WantCaptureKeyboard) {
628  io.KeysDown[static_cast<int>(event.key.code)] = (event.type == lug::Window::Event::Type::KeyPressed) ? true : false;
629 
630  io.KeyCtrl = static_cast<int>(event.key.ctrl);
631  io.KeyShift = static_cast<int>(event.key.shift);
632  io.KeyAlt = static_cast<int>(event.key.alt);
633  io.KeySuper = static_cast<int>(event.key.system);
634  return true;
635  } else if (event.type == lug::Window::Event::Type::CharEntered && isprint(event.character.val)) {
636  io.AddInputCharacter(static_cast<unsigned short>(event.character.val));
637  return true;
638  } else {
639  io.MouseWheel = 0;
640  }
641  }
642 
643  return false;
644 }
645 
646 const Vulkan::API::Semaphore& Gui::getSemaphore(uint32_t currentImageIndex) const {
647  return _framesData[currentImageIndex].semaphore;
648 }
649 
650 bool Gui::updateBuffers(uint32_t currentImageIndex) {
651  ImDrawData* imDrawData = ImGui::GetDrawData();
652  if (!imDrawData) {
653  LUG_LOG.error("Gui::updateBuffers: Failed to retrieve draw data from imgui");
654  return false;
655  }
656 
657  if (imDrawData->TotalVtxCount == 0 || imDrawData->TotalIdxCount == 0) {
658  return true;
659  }
660 
661  API::Device &device = _renderer.getDevice();
662  FrameData& frameData = _framesData[currentImageIndex];
663 
664  // Note: Alignment is done inside buffer creation
665  const VkDeviceSize vertexBufferSize = imDrawData->TotalVtxCount * sizeof(ImDrawVert);
666  const VkDeviceSize indexBufferSize = imDrawData->TotalIdxCount * sizeof(ImDrawIdx);
667 
668  // Update buffers only if vertex or index count has been changed compared to current buffer size
669  {
670  // Vertex buffer
671  if ((static_cast<VkBuffer>(frameData.vertexBuffer) == VK_NULL_HANDLE) || (vertexBufferSize > frameData.vertexBuffer.getRequirements().size)) {
672  {
673  // Create Vertex buffer
674  {
675  API::Builder::Buffer bufferBuilder(device);
677  bufferBuilder.setSize(vertexBufferSize);
678  bufferBuilder.setUsage(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
679 
680  VkResult result{VK_SUCCESS};
681  if (!bufferBuilder.build(frameData.vertexBuffer, &result)) {
682  LUG_LOG.error("Gui::updateBuffers: Can't create staging buffer: {}", result);
683  return false;
684  }
685  }
686 
687  if (frameData.vertexMemoryPtr) {
688  frameData.vertexMemory.unmap();
689  }
690 
691  API::Builder::DeviceMemory deviceMemoryBuilder(device);
692  deviceMemoryBuilder.setMemoryFlags(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
693  deviceMemoryBuilder.addBuffer(frameData.vertexBuffer);
694 
695  VkResult result{VK_SUCCESS};
696  if (!deviceMemoryBuilder.build(frameData.vertexMemory, &result)) {
697  LUG_LOG.error("Gui::updateBuffers: Can't create staging buffer device memory: {}", result);
698  return false;
699  }
700 
701  frameData.vertexMemoryPtr = frameData.vertexMemory.mapBuffer(frameData.vertexBuffer);
702  }
703  }
704 
705  // IndexBuffer
706  if ((static_cast<VkBuffer>(frameData.indexBuffer) == VK_NULL_HANDLE) || (indexBufferSize > frameData.indexBuffer.getRequirements().size)) {
707  {
708  // Create Index buffer
709  {
710  API::Builder::Buffer bufferBuilder(device);
712  bufferBuilder.setSize(indexBufferSize);
713  bufferBuilder.setUsage(VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
714 
715  VkResult result{VK_SUCCESS};
716  if (!bufferBuilder.build(frameData.indexBuffer, &result)) {
717  LUG_LOG.error("Gui::updateBuffers: Can't create staging buffer: {}", result);
718  return false;
719  }
720  }
721 
722  if (frameData.indexMemoryPtr) {
723  frameData.indexMemory.unmap();
724  }
725 
726  API::Builder::DeviceMemory deviceMemoryBuilder(device);
727  deviceMemoryBuilder.setMemoryFlags(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
728  deviceMemoryBuilder.addBuffer(frameData.indexBuffer);
729 
730  VkResult result{VK_SUCCESS};
731  if (!deviceMemoryBuilder.build(frameData.indexMemory, &result)) {
732  LUG_LOG.error("Gui::updateBuffers: Can't create staging buffer device memory: {}", result);
733  return false;
734  }
735 
736  frameData.indexMemoryPtr = frameData.indexMemory.mapBuffer(frameData.indexBuffer);
737  }
738  }
739  }
740 
741  // Upload data
742  {
743  ImDrawVert* vertexMemoryPtr = static_cast<ImDrawVert*>(frameData.vertexMemoryPtr);
744  ImDrawIdx* indexMemoryPtr = static_cast<ImDrawIdx*>(frameData.indexMemoryPtr);
745 
746  for (int n = 0; n < imDrawData->CmdListsCount; n++) {
747  const ImDrawList* cmd_list = imDrawData->CmdLists[n];
748  memcpy(vertexMemoryPtr, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
749  memcpy(indexMemoryPtr, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
750  vertexMemoryPtr += cmd_list->VtxBuffer.Size;
751  indexMemoryPtr += cmd_list->IdxBuffer.Size;
752  }
753  }
754 
755  return true;
756 }
757 
759 {
760  API::Device& device = _renderer.getDevice();
761 
762  for (auto& frameData : _framesData) {
763  // Build semaphore
764  {
765  API::Builder::Semaphore semaphoreBuilder(device);
766 
767  VkResult result{ VK_SUCCESS };
768  if (!semaphoreBuilder.build(frameData.semaphore, &result)) {
769  LUG_LOG.error("Gui::initFontsTexture: Can't create semaphore: {}", result);
770  return false;
771  }
772  }
773 
774  // Build fence
775  {
776  API::Builder::Fence fenceBuilder(device);
777  fenceBuilder.setFlags(VK_FENCE_CREATE_SIGNALED_BIT); // Signaled state
778 
779  VkResult result{ VK_SUCCESS };
780  if (!fenceBuilder.build(frameData.fence, &result)) {
781  LUG_LOG.error("Gui::initFontsTexture: Can't create fence: {}", result);
782  return false;
783  }
784  }
785  }
786 
787  return true;
788 }
789 
790 } // Vulkan
791 } // Graphics
792 } // lug
bool reset(bool releaseRessources=false) const
Represents an event.
Definition: Event.hpp:89
Gui(lug::Graphics::Vulkan::Renderer &renderer, lug::Graphics::Vulkan::Render::Window &window)
Definition: Gui.cpp:26
TouchScreenEvent _touchScreenState
Definition: Window.hpp:162
const API::Queue * _graphicQueue
Definition: Gui.hpp:99
bool build(API::DeviceMemory &instance, VkResult *returnResult=nullptr)
const API::Queue * _transferQueue
Definition: Gui.hpp:100
lug::Math::Vec2f coordinates[2]
The Touch coordinate.
Definition: Event.hpp:59
void beginFrame(const lug::System::Time &elapsedTime)
Definition: Gui.cpp:407
void setBindings(const std::vector< VkDescriptorSetLayoutBinding > &bindings)
const Math::Vec2i & getMousePos() const
Retrieves the mouses position.
Definition: Window.cpp:271
void setFlags(VkFenceCreateFlags flags)
Definition: Fence.inl:1
void setMinFilter(Render::Texture::Filter minFilter)
Definition: Texture.inl:17
bool build(API::Semaphore &instance, VkResult *returnResult=nullptr)
Definition: Semaphore.cpp:13
bool endFrame(const std::vector< VkSemaphore > &waitSemaphores, uint32_t currentImageIndex)
Definition: Gui.cpp:424
lug::Graphics::Resource::SharedPtr< lug::Graphics::Render::Texture > _fontTexture
Definition: Gui.hpp:107
API::GraphicsPipeline _pipeline
Definition: Gui.hpp:110
Vulkan::API::Buffer indexBuffer
Definition: Gui.hpp:59
void setQueueFamilyIndices(std::set< uint32_t > queueFamilyIndices)
Definition: Buffer.inl:17
const API::Queue * getQueue(const std::string &queueName) const
Definition: Device.cpp:70
bool submit(const CommandBuffer &commandBuffer, const std::vector< VkSemaphore > &signalSemaphores={}, const std::vector< VkSemaphore > &waitSemaphores={}, const std::vector< VkPipelineStageFlags > &waitDstStageMasks={}, VkFence fence=VK_NULL_HANDLE) const
Definition: Queue.cpp:32
bool build(API::Fence &instance, VkResult *returnResult=nullptr)
Definition: Fence.cpp:13
void setLevel(VkCommandBufferLevel level)
const VkMemoryRequirements & getRequirements() const
Definition: Buffer.inl:1
Vulkan::API::DeviceMemory indexMemory
Definition: Gui.hpp:56
bool build(API::Buffer &instance, VkResult *returnResult=nullptr)
Definition: Buffer.cpp:15
lug::Graphics::Vulkan::Render::Window & _window
Definition: Gui.hpp:97
void setSize(VkDeviceSize size)
Definition: Buffer.inl:1
Type type
The type of the event.
Definition: Event.hpp:110
MouseWheelRotated event.
const API::Swapchain & getSwapchain() const
Definition: Window.inl:1
void setMagFilter(Render::Texture::Filter magFilter)
Definition: Texture.inl:13
Mouse::Button code
The button that triggered the event.
Definition: Event.hpp:31
const VkSurfaceFormatKHR & getFormat() const
Definition: Swapchain.inl:17
API::CommandPool _transferQueueCommandPool
Definition: Gui.hpp:105
void * mapBuffer(const API::Buffer &buffer, VkDeviceSize size=VK_WHOLE_SIZE, VkDeviceSize offset=0) const
Vulkan::API::DeviceMemory vertexMemory
Definition: Gui.hpp:55
void beginRenderPass(const API::RenderPass &renderPass, const CmdBeginRenderPass &parameters, VkSubpassContents contents=VK_SUBPASS_CONTENTS_INLINE) const
bool build(API::DescriptorSetLayout &instance, VkResult *returnResult=nullptr)
bool addLayer(const std::string &filename, bool hdr=false)
Definition: Texture.cpp:98
const QueueFamily * getQueueFamily() const
Definition: Queue.cpp:86
Vulkan::API::CommandBuffer commandBuffer
Definition: Gui.hpp:51
bool processEvent(const lug::Window::Event event)
Definition: Gui.cpp:582
const Vulkan::API::Semaphore & getSemaphore(uint32_t currentImageIndex) const
Definition: Gui.cpp:646
Vulkan::API::Fence fence
Definition: Gui.hpp:50
TouchScreenEvent touchScreen
Definition: Event.hpp:120
static SharedPtr< T > cast(const SharedPtr< RhsT > &rhs)
Dynamic casting of a SharedPtr to another one (RhsT to T)
API::Framebuffer framebuffer
Definition: Gui.hpp:48
CharEvent character
A CharEvent.
Definition: Event.hpp:117
const InitInfo & getInfo() const
Definition: Renderer.inl:1
T getSeconds() const
void setMemoryFlags(VkMemoryPropertyFlags flags)
Definition: DeviceMemory.inl:1
bool updateBuffers(uint32_t currentImageIndex)
Definition: Gui.cpp:650
#define LUG_LOG
Definition: Logger.hpp:73
void setUsage(VkBufferUsageFlags usage)
Definition: Buffer.inl:9
const PipelineLayout * getLayout() const
std::vector< FrameData > _framesData
Definition: Gui.hpp:112
bool init(const std::vector< API::ImageView > &imageViews)
Definition: Gui.cpp:66
void setRenderPass(const API::RenderPass *renderPass)
Definition: Framebuffer.inl:1
lug::Graphics::Vulkan::Renderer & _renderer
Definition: Gui.hpp:96
bool initFramebuffers(const std::vector< API::ImageView > &)
Definition: Gui.cpp:385
void pushConstants(const CmdPushConstants &parameters) const
wchar_t val
Raw value of the character pressed (with accents, etc.)
Definition: Event.hpp:83
Resource::SharedPtr< Render::Texture > build()
Definition: Texture.cpp:37
Vulkan::API::Buffer vertexBuffer
Definition: Gui.hpp:58
std::vector< const Render::DescriptorSetPool::DescriptorSet * > texturesDescriptorSets
Definition: Gui.hpp:53
std::unique_ptr< Render::DescriptorSetPool::GuiTexture > _texturesDescriptorSetPool
Definition: Gui.hpp:102
uint16_t getHeight() const override final
Definition: Window.inl:9
uint16_t getWidth() const override final
Definition: Window.inl:5
bool begin(VkCommandBufferUsageFlags flags=VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) const
API::CommandPool _graphicQueueCommandPool
Definition: Gui.hpp:104
MouseEvent mouse
A MouseEvent.
Definition: Event.hpp:118
API::PipelineLayout _pipelineLayout
Definition: Gui.hpp:109