Vookoo
vku_framework.hpp
1 //
3 // Demo framework for the Vookoo for the Vookoo high level C++ Vulkan interface.
4 //
5 // (C) Andy Thomason 2017 MIT License
6 //
7 // This is an optional demo framework for the Vookoo high level C++ Vulkan interface.
8 //
10 
11 #ifndef VKU_FRAMEWORK_HPP
12 #define VKU_FRAMEWORK_HPP
13 
14 #ifdef _WIN32
15 #define VK_USE_PLATFORM_WIN32_KHR
16 #define GLFW_EXPOSE_NATIVE_WIN32
17 #define VKU_SURFACE "VK_KHR_win32_surface"
18 #pragma warning(disable : 4005)
19 #else
20 #define VK_USE_PLATFORM_XLIB_KHR
21 #define GLFW_EXPOSE_NATIVE_X11
22 #define VKU_SURFACE "VK_KHR_xlib_surface"
23 #endif
24 
25 #ifndef VKU_NO_GLFW
26 #define GLFW_INCLUDE_VULKAN
27 #include <GLFW/glfw3.h>
28 #include <GLFW/glfw3native.h>
29 #endif
30 
31 // Undo damage done by windows.h
32 #undef APIENTRY
33 #undef None
34 #undef max
35 #undef min
36 
37 #include <array>
38 #include <fstream>
39 #include <iostream>
40 #include <unordered_map>
41 #include <vector>
42 #include <thread>
43 #include <chrono>
44 #include <functional>
45 #include <cstddef>
46 
47 #include <vulkan/vulkan.hpp>
48 #include <vku/vku.hpp>
49 
50 namespace vku {
51 
56 class Framework {
57 public:
58  Framework() {
59  }
60 
61  // Construct a framework containing the instance, a device and one or more queues.
62  Framework(const std::string &name) {
63  std::vector<const char *> layers;
64  layers.push_back("VK_LAYER_LUNARG_standard_validation");
65 
66  std::vector<const char *> instance_extensions;
67  instance_extensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
68  instance_extensions.push_back(VKU_SURFACE);
69  instance_extensions.push_back("VK_KHR_surface");
70 
71  auto appinfo = vk::ApplicationInfo{};
72  instance_ = vk::createInstanceUnique(vk::InstanceCreateInfo{
73  {}, &appinfo, (uint32_t)layers.size(),
74  layers.data(), (uint32_t)instance_extensions.size(),
75  instance_extensions.data()});
76 
77  auto ci = vk::DebugReportCallbackCreateInfoEXT{
78  //vk::DebugReportFlagBitsEXT::eInformation |
79  vk::DebugReportFlagBitsEXT::eWarning |
80  vk::DebugReportFlagBitsEXT::ePerformanceWarning |
81  vk::DebugReportFlagBitsEXT::eError,
82  //vk::DebugReportFlagBitsEXT::eDebug,
83  &debugCallback};
84  const VkDebugReportCallbackCreateInfoEXT &cir = ci;
85 
86  auto vkCreateDebugReportCallbackEXT =
87  (PFN_vkCreateDebugReportCallbackEXT)instance_->getProcAddr(
88  "vkCreateDebugReportCallbackEXT");
89 
90  VkDebugReportCallbackEXT cb;
91  vkCreateDebugReportCallbackEXT(
92  *instance_, &(const VkDebugReportCallbackCreateInfoEXT &)ci,
93  nullptr, &cb);
94  callback_ = cb;
95 
96  auto pds = instance_->enumeratePhysicalDevices();
97  physical_device_ = pds[0];
98  auto qprops = physical_device_.getQueueFamilyProperties();
99  const auto badQueue = ~(uint32_t)0;
100  graphicsQueueFamilyIndex_ = badQueue;
101  computeQueueFamilyIndex_ = badQueue;
102  vk::QueueFlags search = vk::QueueFlagBits::eGraphics|vk::QueueFlagBits::eCompute;
103 
104  // Look for an omnipurpose queue family first
105  // It is better if we can schedule operations without barriers and semaphores.
106  // The Spec says: "If an implementation exposes any queue family that supports graphics operations,
107  // at least one queue family of at least one physical device exposed by the implementation
108  // must support both graphics and compute operations."
109  // Also: All commands that are allowed on a queue that supports transfer operations are
110  // also allowed on a queue that supports either graphics or compute operations...
111  // As a result we can expect a queue family with at least all three and maybe all four modes.
112  for (uint32_t qi = 0; qi != qprops.size(); ++qi) {
113  auto &qprop = qprops[qi];
114  //std::cout << vk::to_string(qprop.queueFlags) << "\n";
115  if ((qprop.queueFlags & search) == search) {
116  graphicsQueueFamilyIndex_ = qi;
117  computeQueueFamilyIndex_ = qi;
118  break;
119  }
120  }
121 
122  if (graphicsQueueFamilyIndex_ == badQueue || computeQueueFamilyIndex_ == badQueue) {
123  std::cout << "oops, missing a queue\n";
124  return;
125  }
126 
127  memprops_ = physical_device_.getMemoryProperties();
128 
129  // todo: find optimal texture format
130  // auto rgbaprops = physical_device_.getFormatProperties(vk::Format::eR8G8B8A8Unorm);
131 
132  std::vector<const char *> device_extensions;
133  device_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
134 
135  float queue_priorities[] = {0.0f};
136  std::vector<vk::DeviceQueueCreateInfo> qci;
137 
138  qci.emplace_back(vk::DeviceQueueCreateFlags{}, graphicsQueueFamilyIndex_, 1,
139  queue_priorities);
140 
141  if (computeQueueFamilyIndex_ != graphicsQueueFamilyIndex_) {
142  qci.emplace_back(vk::DeviceQueueCreateFlags{}, computeQueueFamilyIndex_, 1,
143  queue_priorities);
144  };
145 
146  float graphicsQueue_priorities[] = {0.0f};
147  device_ = physical_device_.createDeviceUnique(vk::DeviceCreateInfo{
148  {}, (uint32_t)qci.size(), qci.data(),
149  (uint32_t)layers.size(), layers.data(),
150  (uint32_t)device_extensions.size(), device_extensions.data()});
151 
152  //vk::Queue graphicsQueue_ = device_->getQueue(graphicsQueueFamilyIndex_, 0);
153  //vk::Queue computeQueue_ = device_->getQueue(computeQueueFamilyIndex_, 0);
154 
155  vk::PipelineCacheCreateInfo pipelineCacheInfo{};
156  pipelineCache_ = device_->createPipelineCacheUnique(pipelineCacheInfo);
157 
158  std::vector<vk::DescriptorPoolSize> poolSizes;
159  poolSizes.emplace_back(vk::DescriptorType::eUniformBuffer, 128);
160  poolSizes.emplace_back(vk::DescriptorType::eCombinedImageSampler, 128);
161  poolSizes.emplace_back(vk::DescriptorType::eStorageBuffer, 128);
162 
163  // Create an arbitrary number of descriptors in a pool.
164  // Allow the descriptors to be freed, possibly not optimal behaviour.
165  vk::DescriptorPoolCreateInfo descriptorPoolInfo{};
166  descriptorPoolInfo.flags = vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet;
167  descriptorPoolInfo.maxSets = 256;
168  descriptorPoolInfo.poolSizeCount = (uint32_t)poolSizes.size();
169  descriptorPoolInfo.pPoolSizes = poolSizes.data();
170  descriptorPool_ = device_->createDescriptorPoolUnique(descriptorPoolInfo);
171 
172  ok_ = true;
173  }
174 
175  void dumpCaps(std::ostream &os) const {
176  os << "Memory Types\n";
177  for (uint32_t i = 0; i != memprops_.memoryTypeCount; ++i) {
178  os << " type" << i << " heap" << memprops_.memoryTypes[i].heapIndex << " " << vk::to_string(memprops_.memoryTypes[i].propertyFlags) << "\n";
179  }
180  os << "Heaps\n";
181  for (uint32_t i = 0; i != memprops_.memoryHeapCount; ++i) {
182  os << " heap" << vk::to_string(memprops_.memoryHeaps[i].flags) << " " << memprops_.memoryHeaps[i].size << "\n";
183  }
184  }
185 
187  const vk::Instance instance() const { return *instance_; }
188 
190  const vk::Device device() const { return *device_; }
191 
193  const vk::Queue graphicsQueue() const { return device_->getQueue(graphicsQueueFamilyIndex_, 0); }
194 
196  const vk::Queue computeQueue() const { return device_->getQueue(computeQueueFamilyIndex_, 0); }
197 
199  const vk::PhysicalDevice &physicalDevice() const { return physical_device_; }
200 
202  const vk::PipelineCache pipelineCache() const { return *pipelineCache_; }
203 
205  const vk::DescriptorPool descriptorPool() const { return *descriptorPool_; }
206 
208  uint32_t graphicsQueueFamilyIndex() const { return graphicsQueueFamilyIndex_; }
209 
211  uint32_t computeQueueFamilyIndex() const { return computeQueueFamilyIndex_; }
212 
213  const vk::PhysicalDeviceMemoryProperties &memprops() const { return memprops_; }
214 
217  if (device_) {
218  device_->waitIdle();
219  if (pipelineCache_) {
220  pipelineCache_.reset();
221  }
222  if (descriptorPool_) {
223  descriptorPool_.reset();
224  }
225  device_.reset();
226  }
227 
228  if (instance_) {
229  auto vkDestroyDebugReportCallbackEXT =
230  (PFN_vkDestroyDebugReportCallbackEXT)instance_->getProcAddr(
231  "vkDestroyDebugReportCallbackEXT");
232  vkDestroyDebugReportCallbackEXT(*instance_, callback_, nullptr);
233  instance_.reset();
234  }
235  }
236 
237  Framework &operator=(Framework &&rhs) = default;
238 
240  bool ok() const { return ok_; }
241 
242 private:
243  // Report any errors or warnings.
244  static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
245  VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType,
246  uint64_t object, size_t location, int32_t messageCode,
247  const char *pLayerPrefix, const char *pMessage, void *pUserData) {
248  printf("%08x debugCallback: %s\n", flags, pMessage);
249  return VK_FALSE;
250  }
251 
252  vk::UniqueInstance instance_;
253  vk::UniqueDevice device_;
254  vk::DebugReportCallbackEXT callback_;
255  vk::PhysicalDevice physical_device_;
256  vk::UniquePipelineCache pipelineCache_;
257  vk::UniqueDescriptorPool descriptorPool_;
258  uint32_t graphicsQueueFamilyIndex_;
259  uint32_t computeQueueFamilyIndex_;
260  vk::PhysicalDeviceMemoryProperties memprops_;
261  bool ok_ = false;
262 };
263 
265 class Window {
266 public:
267  Window() {
268  }
269 
270 #ifndef VKU_NO_GLFW
271  Window(const vk::Instance &instance, const vk::Device &device, const vk::PhysicalDevice &physicalDevice, uint32_t graphicsQueueFamilyIndex, GLFWwindow *window) {
273 #ifdef VK_USE_PLATFORM_WIN32_KHR
274  auto module = GetModuleHandle(nullptr);
275  auto handle = glfwGetWin32Window(window);
276  auto ci = vk::Win32SurfaceCreateInfoKHR{{}, module, handle};
277  auto surface = instance.createWin32SurfaceKHR(ci);
278 #endif
279 #ifdef VK_USE_PLATFORM_XLIB_KHR
280  auto display = glfwGetX11Display();
281  auto x11window = glfwGetX11Window(window);
282  auto ci = vk::XlibSurfaceCreateInfoKHR{{}, display, x11window};
283  auto surface = instance.createXlibSurfaceKHR(ci);
284 #endif
285  init(instance, device, physicalDevice, graphicsQueueFamilyIndex, surface);
286  }
287 #endif
288 
289  Window(const vk::Instance &instance, const vk::Device &device, const vk::PhysicalDevice &physicalDevice, uint32_t graphicsQueueFamilyIndex, vk::SurfaceKHR surface) {
290  init(instance, device, physicalDevice, graphicsQueueFamilyIndex, surface);
291  }
292 
293  void init(const vk::Instance &instance, const vk::Device &device, const vk::PhysicalDevice &physicalDevice, uint32_t graphicsQueueFamilyIndex, vk::SurfaceKHR surface) {
294  //surface_ = vk::UniqueSurfaceKHR(surface);
295  //surface_ = vk::UniqueSurfaceKHR(surface, vk::SurfaceKHRDeleter{ instance });
296  surface_ = surface;
297  instance_ = instance;
298  device_ = device;
299  presentQueueFamily_ = 0;
300  auto &pd = physicalDevice;
301  auto qprops = pd.getQueueFamilyProperties();
302  bool found = false;
303  for (uint32_t qi = 0; qi != qprops.size(); ++qi) {
304  if (pd.getSurfaceSupportKHR(qi, surface_)) {
305  presentQueueFamily_ = qi;
306  found = true;
307  break;
308  }
309  }
310 
311  if (!found) {
312  std::cout << "No Vulkan present queues found\n";
313  return;
314  }
315 
316  auto fmts = pd.getSurfaceFormatsKHR(surface_);
317  swapchainImageFormat_ = fmts[0].format;
318  swapchainColorSpace_ = fmts[0].colorSpace;
319  if (fmts.size() == 1 && swapchainImageFormat_ == vk::Format::eUndefined) {
320  swapchainImageFormat_ = vk::Format::eB8G8R8A8Unorm;
321  swapchainColorSpace_ = vk::ColorSpaceKHR::eSrgbNonlinear;
322  } else {
323  for (auto &fmt : fmts) {
324  if (fmt.format == vk::Format::eB8G8R8A8Unorm) {
325  swapchainImageFormat_ = fmt.format;
326  swapchainColorSpace_ = fmt.colorSpace;
327  }
328  }
329  }
330 
331  auto surfaceCaps = pd.getSurfaceCapabilitiesKHR(surface_);
332  width_ = surfaceCaps.currentExtent.width;
333  height_ = surfaceCaps.currentExtent.height;
334 
335  auto pms = pd.getSurfacePresentModesKHR(surface_);
336  vk::PresentModeKHR presentMode = pms[0];
337  if (std::find(pms.begin(), pms.end(), vk::PresentModeKHR::eFifo) != pms.end()) {
338  presentMode = vk::PresentModeKHR::eFifo;
339  } else {
340  std::cout << "No fifo mode available\n";
341  return;
342  }
343 
344  //std::cout << "using " << vk::to_string(presentMode) << "\n";
345 
346  vk::SwapchainCreateInfoKHR swapinfo{};
347  std::array<uint32_t, 2> queueFamilyIndices = { graphicsQueueFamilyIndex, presentQueueFamily_ };
348  bool sameQueues = queueFamilyIndices[0] == queueFamilyIndices[1];
349  vk::SharingMode sharingMode = !sameQueues ? vk::SharingMode::eConcurrent : vk::SharingMode::eExclusive;
350  swapinfo.imageExtent = surfaceCaps.currentExtent;
351  swapinfo.surface = surface_;
352  swapinfo.minImageCount = surfaceCaps.minImageCount + 1;
353  swapinfo.imageFormat = swapchainImageFormat_;
354  swapinfo.imageColorSpace = swapchainColorSpace_;
355  swapinfo.imageExtent = surfaceCaps.currentExtent;
356  swapinfo.imageArrayLayers = 1;
357  swapinfo.imageUsage = vk::ImageUsageFlagBits::eColorAttachment;
358  swapinfo.imageSharingMode = sharingMode;
359  swapinfo.queueFamilyIndexCount = !sameQueues ? 2 : 0;
360  swapinfo.pQueueFamilyIndices = queueFamilyIndices.data();
361  swapinfo.preTransform = surfaceCaps.currentTransform;;
362  swapinfo.compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eOpaque;
363  swapinfo.presentMode = presentMode;
364  swapinfo.clipped = 1;
365  swapinfo.oldSwapchain = vk::SwapchainKHR{};
366  swapchain_ = device.createSwapchainKHRUnique(swapinfo);
367 
368  images_ = device.getSwapchainImagesKHR(*swapchain_);
369  for (auto &img : images_) {
370  vk::ImageViewCreateInfo ci{};
371  ci.image = img;
372  ci.viewType = vk::ImageViewType::e2D;
373  ci.format = swapchainImageFormat_;
374  ci.subresourceRange = {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1};
375  imageViews_.emplace_back(device.createImageView(ci));
376  }
377 
378  auto memprops = physicalDevice.getMemoryProperties();
379  depthStencilImage_ = vku::DepthStencilImage(device, memprops, width_, height_);
380 
381  // Build the renderpass using two attachments, colour and depth/stencil.
383 
384  // The only colour attachment.
385  rpm.attachmentBegin(swapchainImageFormat_);
386  rpm.attachmentLoadOp(vk::AttachmentLoadOp::eClear);
387  rpm.attachmentStoreOp(vk::AttachmentStoreOp::eStore);
388  rpm.attachmentFinalLayout(vk::ImageLayout::ePresentSrcKHR);
389 
390  // The depth/stencil attachment.
391  rpm.attachmentBegin(depthStencilImage_.format());
392  rpm.attachmentLoadOp(vk::AttachmentLoadOp::eClear);
393  rpm.attachmentStencilLoadOp(vk::AttachmentLoadOp::eDontCare);
394  rpm.attachmentFinalLayout(vk::ImageLayout::eDepthStencilAttachmentOptimal);
395 
396  // A subpass to render using the above two attachments.
397  rpm.subpassBegin(vk::PipelineBindPoint::eGraphics);
398  rpm.subpassColorAttachment(vk::ImageLayout::eColorAttachmentOptimal, 0);
399  rpm.subpassDepthStencilAttachment(vk::ImageLayout::eDepthStencilAttachmentOptimal, 1);
400 
401  // A dependency to reset the layout of both attachments.
402  rpm.dependencyBegin(VK_SUBPASS_EXTERNAL, 0);
403  rpm.dependencySrcStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput);
404  rpm.dependencyDstStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput);
405  rpm.dependencyDstAccessMask(vk::AccessFlagBits::eColorAttachmentRead|vk::AccessFlagBits::eColorAttachmentWrite);
406 
407  // Use the maker object to construct the vulkan object
408  renderPass_ = rpm.createUnique(device);
409 
410  for (int i = 0; i != imageViews_.size(); ++i) {
411  vk::ImageView attachments[2] = {imageViews_[i], depthStencilImage_.imageView()};
412  vk::FramebufferCreateInfo fbci{{}, *renderPass_, 2, attachments, width_, height_, 1 };
413  framebuffers_.push_back(device.createFramebufferUnique(fbci));
414  }
415 
416  vk::SemaphoreCreateInfo sci;
417  imageAcquireSemaphore_ = device.createSemaphoreUnique(sci);
418  commandCompleteSemaphore_ = device.createSemaphoreUnique(sci);
419  dynamicSemaphore_ = device.createSemaphoreUnique(sci);
420 
421  typedef vk::CommandPoolCreateFlagBits ccbits;
422 
423  vk::CommandPoolCreateInfo cpci{ ccbits::eTransient|ccbits::eResetCommandBuffer, graphicsQueueFamilyIndex };
424  commandPool_ = device.createCommandPoolUnique(cpci);
425 
426  // Create static draw buffers
427  vk::CommandBufferAllocateInfo cbai{ *commandPool_, vk::CommandBufferLevel::ePrimary, (uint32_t)framebuffers_.size() };
428  staticDrawBuffers_ = device.allocateCommandBuffersUnique(cbai);
429  dynamicDrawBuffers_ = device.allocateCommandBuffersUnique(cbai);
430 
431  // Create a set of fences to protect the command buffers from re-writing.
432  for (int i = 0; i != staticDrawBuffers_.size(); ++i) {
433  vk::FenceCreateInfo fci;
434  fci.flags = vk::FenceCreateFlagBits::eSignaled;
435  commandBufferFences_.emplace_back(device.createFence(fci));
436  }
437 
438  for (int i = 0; i != staticDrawBuffers_.size(); ++i) {
439  vk::CommandBuffer cb = *staticDrawBuffers_[i];
440  vk::CommandBufferBeginInfo bi{};
441  cb.begin(bi);
442  cb.end();
443  }
444 
445  ok_ = true;
446  }
447 
449  void dumpCaps(std::ostream &os, vk::PhysicalDevice pd) const {
450  os << "Surface formats\n";
451  auto fmts = pd.getSurfaceFormatsKHR(surface_);
452  for (auto &fmt : fmts) {
453  auto fmtstr = vk::to_string(fmt.format);
454  auto cstr = vk::to_string(fmt.colorSpace);
455  os << "format=" << fmtstr << " colorSpace=" << cstr << "\n";
456  }
457 
458  os << "Present Modes\n";
459  auto presentModes = pd.getSurfacePresentModesKHR(surface_);
460  for (auto pm : presentModes) {
461  std::cout << vk::to_string(pm) << "\n";
462  }
463  }
464 
465  static void defaultRenderFunc(vk::CommandBuffer cb, int imageIndex, vk::RenderPassBeginInfo &rpbi) {
466  vk::CommandBufferBeginInfo bi{};
467  cb.begin(bi);
468  cb.end();
469  }
470 
471  typedef void (renderFunc_t)(vk::CommandBuffer cb, int imageIndex, vk::RenderPassBeginInfo &rpbi);
472 
474  void setStaticCommands(const std::function<renderFunc_t> &func) {
475  for (int i = 0; i != staticDrawBuffers_.size(); ++i) {
476  vk::CommandBuffer cb = *staticDrawBuffers_[i];
477 
478  std::array<float, 4> clearColorValue{0.75f, 0.75f, 0.75f, 1};
479  vk::ClearDepthStencilValue clearDepthValue{ 1.0f, 0 };
480  std::array<vk::ClearValue, 2> clearColours{vk::ClearValue{clearColorValue}, clearDepthValue};
481  vk::RenderPassBeginInfo rpbi;
482  rpbi.renderPass = *renderPass_;
483  rpbi.framebuffer = *framebuffers_[i];
484  rpbi.renderArea = vk::Rect2D{{0, 0}, {width_, height_}};
485  rpbi.clearValueCount = (uint32_t)clearColours.size();
486  rpbi.pClearValues = clearColours.data();
487 
488  func(cb, i, rpbi);
489  }
490  }
491 
494  void draw(const vk::Device &device, const vk::Queue &graphicsQueue, const std::function<void (vk::CommandBuffer cb, int imageIndex, vk::RenderPassBeginInfo &rpbi)> &dynamic = defaultRenderFunc) {
495  static auto start = std::chrono::high_resolution_clock::now();
496  auto time = std::chrono::high_resolution_clock::now();
497  auto delta = time - start;
498  start = time;
499  // uncomment to get frame time.
500  //std::cout << std::chrono::duration_cast<std::chrono::microseconds>(delta).count() << "us frame time\n";
501 
502  auto umax = std::numeric_limits<uint64_t>::max();
503  uint32_t imageIndex = 0;
504  device.acquireNextImageKHR(*swapchain_, umax, *imageAcquireSemaphore_, vk::Fence(), &imageIndex);
505 
506  vk::PipelineStageFlags waitStages = vk::PipelineStageFlagBits::eColorAttachmentOutput;
507  vk::Semaphore ccSema = *commandCompleteSemaphore_;
508  vk::Semaphore iaSema = *imageAcquireSemaphore_;
509  vk::Semaphore psSema = *dynamicSemaphore_;
510  vk::CommandBuffer cb = *staticDrawBuffers_[imageIndex];
511  vk::CommandBuffer pscb = *dynamicDrawBuffers_[imageIndex];
512 
513  vk::Fence cbFence = commandBufferFences_[imageIndex];
514  device.waitForFences(cbFence, 1, umax);
515  device.resetFences(cbFence);
516 
517  std::array<float, 4> clearColorValue{0.75f, 0.75f, 0.75f, 1};
518  vk::ClearDepthStencilValue clearDepthValue{ 1.0f, 0 };
519  std::array<vk::ClearValue, 2> clearColours{vk::ClearValue{clearColorValue}, clearDepthValue};
520  vk::RenderPassBeginInfo rpbi;
521  rpbi.renderPass = *renderPass_;
522  rpbi.framebuffer = *framebuffers_[imageIndex];
523  rpbi.renderArea = vk::Rect2D{{0, 0}, {width_, height_}};
524  rpbi.clearValueCount = (uint32_t)clearColours.size();
525  rpbi.pClearValues = clearColours.data();
526  dynamic(pscb, imageIndex, rpbi);
527 
528  vk::SubmitInfo submit;
529  submit.waitSemaphoreCount = 1;
530  submit.pWaitSemaphores = &iaSema;
531  submit.pWaitDstStageMask = &waitStages;
532  submit.commandBufferCount = 1;
533  submit.pCommandBuffers = &pscb;
534  submit.signalSemaphoreCount = 1;
535  submit.pSignalSemaphores = &psSema;
536  graphicsQueue.submit(1, &submit, vk::Fence{});
537 
538  submit.waitSemaphoreCount = 1;
539  submit.pWaitSemaphores = &psSema;
540  submit.pWaitDstStageMask = &waitStages;
541  submit.commandBufferCount = 1;
542  submit.pCommandBuffers = &cb;
543  submit.signalSemaphoreCount = 1;
544  submit.pSignalSemaphores = &ccSema;
545  graphicsQueue.submit(1, &submit, cbFence);
546 
547  vk::PresentInfoKHR presentInfo;
548  vk::SwapchainKHR swapchain = *swapchain_;
549  presentInfo.pSwapchains = &swapchain;
550  presentInfo.swapchainCount = 1;
551  presentInfo.pImageIndices = &imageIndex;
552  presentInfo.waitSemaphoreCount = 1;
553  presentInfo.pWaitSemaphores = &ccSema;
554  presentQueue().presentKHR(presentInfo);
555  }
556 
558  uint32_t presentQueueFamily() const { return presentQueueFamily_; }
559 
561  const vk::Queue presentQueue() const { return device_.getQueue(presentQueueFamily_, 0); }
562 
564  bool ok() const { return ok_; }
565 
567  vk::RenderPass renderPass() const { return *renderPass_; }
568 
570  const std::vector<vk::UniqueFramebuffer> &framebuffers() const { return framebuffers_; }
571 
574  for (auto &iv : imageViews_) {
575  device_.destroyImageView(iv);
576  }
577  for (auto &f : commandBufferFences_) {
578  device_.destroyFence(f);
579  }
580  swapchain_ = vk::UniqueSwapchainKHR{};
581  }
582 
583  Window &operator=(Window &&rhs) = default;
584 
586  uint32_t width() const { return width_; }
587 
589  uint32_t height() const { return height_; }
590 
592  vk::Format swapchainImageFormat() const { return swapchainImageFormat_; }
593 
595  vk::ColorSpaceKHR swapchainColorSpace() const { return swapchainColorSpace_; }
596 
598  const vk::SwapchainKHR swapchain() const { return *swapchain_; }
599 
601  const std::vector<vk::ImageView> &imageViews() const { return imageViews_; }
602 
604  const std::vector<vk::Image> &images() const { return images_; }
605 
607  const std::vector<vk::UniqueCommandBuffer> &commandBuffers() const { return staticDrawBuffers_; }
608 
610  const std::vector<vk::Fence> &commandBufferFences() const { return commandBufferFences_; }
611 
613  vk::Semaphore imageAcquireSemaphore() const { return *imageAcquireSemaphore_; }
614 
616  vk::Semaphore commandCompleteSemaphore() const { return *commandCompleteSemaphore_; }
617 
619  vk::CommandPool commandPool() const { return *commandPool_; }
620 
622  int numImageIndices() const { return (int)images_.size(); }
623 
624 private:
625  vk::Instance instance_;
626  vk::SurfaceKHR surface_;
627  vk::UniqueSwapchainKHR swapchain_;
628  vk::UniqueRenderPass renderPass_;
629  vk::UniqueSemaphore imageAcquireSemaphore_;
630  vk::UniqueSemaphore commandCompleteSemaphore_;
631  vk::UniqueSemaphore dynamicSemaphore_;
632  vk::UniqueCommandPool commandPool_;
633 
634  std::vector<vk::ImageView> imageViews_;
635  std::vector<vk::Image> images_;
636  std::vector<vk::Fence> commandBufferFences_;
637  std::vector<vk::UniqueFramebuffer> framebuffers_;
638  std::vector<vk::UniqueCommandBuffer> staticDrawBuffers_;
639  std::vector<vk::UniqueCommandBuffer> dynamicDrawBuffers_;
640 
641  vku::DepthStencilImage depthStencilImage_;
642 
643  uint32_t presentQueueFamily_ = 0;
644  uint32_t width_;
645  uint32_t height_;
646  vk::Format swapchainImageFormat_ = vk::Format::eB8G8R8A8Unorm;
647  vk::ColorSpaceKHR swapchainColorSpace_ = vk::ColorSpaceKHR::eSrgbNonlinear;
648  vk::Device device_;
649  bool ok_;
650 };
651 
652 } // namespace vku
653 
654 #endif // VKU_FRAMEWORK_HPP
void setStaticCommands(const std::function< renderFunc_t > &func)
Build a static draw buffer. This will be rendered after any dynamic content generated in draw() ...
Definition: vku_framework.hpp:474
const vk::PipelineCache pipelineCache() const
Get the default pipeline cache (you can use your own if you like).
Definition: vku_framework.hpp:202
This class wraps a window, a surface and a swap chain for that surface.
Definition: vku_framework.hpp:265
vk::RenderPass renderPass() const
Return the renderpass used by this window.
Definition: vku_framework.hpp:567
uint32_t height() const
Return the height of the display.
Definition: vku_framework.hpp:589
const std::vector< vk::Image > & images() const
Return the swap chain images.
Definition: vku_framework.hpp:604
const std::vector< vk::ImageView > & imageViews() const
Return the views of the swap chain images.
Definition: vku_framework.hpp:601
const vk::PhysicalDevice & physicalDevice() const
Get the physical device.
Definition: vku_framework.hpp:199
const vk::Instance instance() const
Get the Vulkan instance.
Definition: vku_framework.hpp:187
vk::ColorSpaceKHR swapchainColorSpace() const
Return the colour space of the back buffer (Usually sRGB)
Definition: vku_framework.hpp:595
void subpassBegin(vk::PipelineBindPoint bp)
Definition: vku.hpp:334
~Window()
Destroy resources when shutting down.
Definition: vku_framework.hpp:573
const vk::Queue computeQueue() const
Get the queue used to submit compute jobs.
Definition: vku_framework.hpp:196
Definition: vku.hpp:309
uint32_t width() const
Return the width of the display.
Definition: vku_framework.hpp:586
const vk::Queue graphicsQueue() const
Get the queue used to submit graphics jobs.
Definition: vku_framework.hpp:193
const std::vector< vk::UniqueCommandBuffer > & commandBuffers() const
Return the static command buffers.
Definition: vku_framework.hpp:607
bool ok() const
Returns true if the Framework has been built correctly.
Definition: vku_framework.hpp:240
uint32_t computeQueueFamilyIndex() const
Get the family index for the compute queues.
Definition: vku_framework.hpp:211
const vk::DescriptorPool descriptorPool() const
Get the default descriptor pool (you can use your own if you like).
Definition: vku_framework.hpp:205
void dumpCaps(std::ostream &os, vk::PhysicalDevice pd) const
Dump the capabilities of the physical device used by this window.
Definition: vku_framework.hpp:449
void attachmentBegin(vk::Format format)
Definition: vku.hpp:316
const vk::Queue presentQueue() const
Get the queue used to submit graphics jobs.
Definition: vku_framework.hpp:561
bool ok() const
Return true if this window was created sucessfully.
Definition: vku_framework.hpp:564
~Framework()
Clean up the framework satisfying the Vulkan verification layers.
Definition: vku_framework.hpp:216
void draw(const vk::Device &device, const vk::Queue &graphicsQueue, const std::function< void(vk::CommandBuffer cb, int imageIndex, vk::RenderPassBeginInfo &rpbi)> &dynamic=defaultRenderFunc)
Definition: vku_framework.hpp:494
uint32_t graphicsQueueFamilyIndex() const
Get the family index for the graphics queues.
Definition: vku_framework.hpp:208
const vk::Device device() const
Get the Vulkan device.
Definition: vku_framework.hpp:190
const vk::SwapchainKHR swapchain() const
Return the swapchain object.
Definition: vku_framework.hpp:598
vk::Format swapchainImageFormat() const
Return the format of the back buffer.
Definition: vku_framework.hpp:592
vk::Semaphore commandCompleteSemaphore() const
Return the semaphore signalled when the command buffers are finished.
Definition: vku_framework.hpp:616
Definition: vku_framework.hpp:56
vk::Semaphore imageAcquireSemaphore() const
Return the semaphore signalled when an image is acquired.
Definition: vku_framework.hpp:613
const std::vector< vk::UniqueFramebuffer > & framebuffers() const
Return the frame buffers used by this window.
Definition: vku_framework.hpp:570
uint32_t presentQueueFamily() const
Return the queue family index used to present the surface to the display.
Definition: vku_framework.hpp:558
int numImageIndices() const
Return the number of swap chain images.
Definition: vku_framework.hpp:622
vk::CommandPool commandPool() const
Return a defult command Pool to use to create new command buffers.
Definition: vku_framework.hpp:619
const std::vector< vk::Fence > & commandBufferFences() const
Return the fences used to control the static buffers.
Definition: vku_framework.hpp:610
An image to use as a depth buffer on a renderpass.
Definition: vku.hpp:1460
Vookoo high level C++ Vulkan interface.
Definition: vku.hpp:34