MythTV  master
mythrendervulkan.cpp
Go to the documentation of this file.
1 // Qt
2 #include <QGuiApplication>
3 
4 // MythTV
5 #include "mythlogging.h"
6 #include "mythimage.h"
7 #include "mythmainwindow.h"
13 
14 #define LOC QString("VulkanRender: ")
15 
17 {
18  MythVulkanObject* result = nullptr;
19  result = new MythVulkanObject(Render);
20  if (result && !result->IsValidVulkan())
21  {
22  delete result;
23  result = nullptr;
24  }
25  return result;
26 }
27 
29  : m_vulkanRender(Render)
30 {
31  if (m_vulkanRender)
32  {
34  if (m_vulkanWindow)
35  {
36  m_vulkanDevice = m_vulkanWindow->device();
37  if (m_vulkanDevice)
38  m_vulkanFuncs = m_vulkanWindow->vulkanInstance()->deviceFunctions(m_vulkanDevice);
39  }
40  }
41 
42  CheckValid();
43 }
44 
46  : m_vulkanRender(Other ? Other->Render() : nullptr),
47  m_vulkanDevice(Other ? Other->Device() : nullptr),
48  m_vulkanFuncs(Other ? Other->Funcs() : nullptr),
49  m_vulkanWindow(Other ? Other->Window() : nullptr)
50 {
51  CheckValid();
52 }
53 
55 {
57  {
58  m_vulkanValid = false;
59  LOG(VB_GENERAL, LOG_ERR, "VulkanBase: Invalid Myth vulkan object");
60  }
61 }
62 
64 {
65  return m_vulkanValid;
66 }
67 
69 {
70  return m_vulkanRender;
71 }
72 
74 {
75  return m_vulkanDevice;
76 }
77 
78 QVulkanDeviceFunctions* MythVulkanObject::Funcs()
79 {
80  return m_vulkanFuncs;
81 }
82 
84 {
85  return m_vulkanWindow;
86 }
87 
89 {
90  MythRenderVulkan* result = nullptr;
91 
92  // Don't try and create the window
93  if (!HasMythMainWindow())
94  return result;
95 
97  if (window)
98  result = dynamic_cast<MythRenderVulkan*>(window->GetRenderDevice());
99  return result;
100 }
101 
104 {
105 #ifdef USING_GLSLANG
106  // take a top level 'reference' to libglslang to ensure it is persistent
107  if (!MythShaderVulkan::InitGLSLang())
108  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to initialise GLSLang");
109 #endif
110  LOG(VB_GENERAL, LOG_INFO, LOC + "Created");
111 }
112 
114 {
115 #ifdef USING_GLSLANG
116  MythShaderVulkan::InitGLSLang(true);
117 #endif
118  LOG(VB_GENERAL, LOG_INFO, LOC + "Destroyed");
119 }
120 
122 {
123  m_window = VulkanWindow;
124 }
125 
127 {
128  return m_window;
129 }
130 
132 {
133  LOG(VB_GENERAL, LOG_INFO, LOC + __FUNCTION__);
134 }
135 
137 {
138  LOG(VB_GENERAL, LOG_INFO, LOC + __FUNCTION__);
139  m_device = m_window->device();
140  m_funcs = m_window->vulkanInstance()->functions();
141  m_devFuncs = m_window->vulkanInstance()->deviceFunctions(m_device);
142 
143  static bool s_debugged = false;
144  if (!s_debugged)
145  {
146  s_debugged = true;
147  DebugVulkan();
148  }
149 
150  // retrieve physical device features and limits
151  m_window->vulkanInstance()->functions()
152  ->vkGetPhysicalDeviceFeatures(m_window->physicalDevice(), &m_phyDevFeatures);
153  m_phyDevLimits = m_window->physicalDeviceProperties()->limits;
154 
155  if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
156  {
157  MythVulkanObject temp(this);
159  }
160 }
161 
163 {
164  QStringList result;
165  result.append(tr("QPA platform") + "\t: " + QGuiApplication::platformName());
166  result.append(tr("Vulkan details:"));
167  result.append(tr("Driver name") + "\t: " + m_debugInfo["drivername"]);
168  result.append(tr("Driver info") + "\t: " + m_debugInfo["driverinfo"]);
169  result.append(tr("Device name") + "\t: " + m_debugInfo["devicename"]);
170  result.append(tr("Device type") + "\t: " + m_debugInfo["devicetype"]);
171  result.append(tr("API version") + "\t: " + m_debugInfo["apiversion"]);
172  return result;
173 }
174 
176 {
177  auto deviceType = [](VkPhysicalDeviceType Type)
178  {
179  switch (Type)
180  {
181  case VK_PHYSICAL_DEVICE_TYPE_CPU: return "Software";
182  case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: return "Integrated GPU";
183  case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: return "Discrete GPU";
184  case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: return "Virtual GPU";
185  default: break;
186  }
187  return "Unknown";
188  };
189 
190  auto version = [](uint32_t Version)
191  {
192  return QString("%1.%2.%3").arg(VK_VERSION_MAJOR(Version))
193  .arg(VK_VERSION_MINOR(Version))
194  .arg(VK_VERSION_PATCH(Version));
195  };
196 
197  const auto * props = reinterpret_cast<const VkPhysicalDeviceProperties*>(m_window->physicalDeviceProperties());
198  if (!props)
199  return;
200  const auto & limits = props->limits;
201  auto devextensions = m_window->supportedDeviceExtensions();
202  auto instextensions = m_window->vulkanInstance()->supportedExtensions();
203 
204  if (instextensions.contains(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME))
205  {
206  auto raw = m_window->vulkanInstance()->getInstanceProcAddr("vkGetPhysicalDeviceProperties2");
207  auto proc = reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2>(raw);
208  if (proc)
209  {
210  VkPhysicalDeviceDriverPropertiesKHR driverprops { };
211  driverprops.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR;
212  driverprops.pNext = nullptr;
213 
214  VkPhysicalDeviceProperties2 devprops { };
215  devprops.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
216  devprops.pNext = &driverprops;
217 
218  proc(m_window->physicalDevice(), &devprops);
219  m_debugInfo.insert("drivername", driverprops.driverName);
220  m_debugInfo.insert("driverinfo", driverprops.driverInfo);
221  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Driver name : %1").arg(driverprops.driverName));
222  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Driver info : %1").arg(driverprops.driverInfo));
223  }
224  }
225 
226  m_debugInfo.insert("devicename", props->deviceName);
227  m_debugInfo.insert("devicetype", deviceType(props->deviceType));
228  m_debugInfo.insert("apiversion", version(props->apiVersion));
229 
230  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Qt platform : %1").arg(QGuiApplication::platformName()));
231  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Device name : %1").arg(props->deviceName));
232  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Device type : %1").arg(deviceType(props->deviceType)));
233  LOG(VB_GENERAL, LOG_INFO, LOC + QString("API version : %1").arg(version(props->apiVersion)));
234  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Device ID : 0x%1").arg(props->deviceID, 0, 16));
235  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Driver version : %1").arg(version(props->driverVersion)));
236  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Max image size : %1x%1").arg(limits.maxImageDimension2D));
237  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Max framebuffer : %1x%2")
238  .arg(limits.maxFramebufferWidth).arg(limits.maxFramebufferHeight));
239  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Max allocations : %1").arg(limits.maxMemoryAllocationCount));
240  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Max samplers : %1").arg(limits.maxSamplerAllocationCount));
241  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Min alignment : %1").arg(limits.minMemoryMapAlignment));
242 
243  if (VERBOSE_LEVEL_CHECK(VB_GENERAL, LOG_DEBUG))
244  {
245  LOG(VB_GENERAL, LOG_INFO, QString("%1 device extensions supported:").arg(devextensions.size()));
246  for (const auto& extension : devextensions)
247  LOG(VB_GENERAL, LOG_INFO, LOC + QString("%1 Version: %2").arg(extension.name.constData()).arg(extension.version));
248 
249  LOG(VB_GENERAL, LOG_INFO, QString("%1 instance extensions supported:").arg(instextensions.size()));
250  for (const auto& extension : instextensions)
251  LOG(VB_GENERAL, LOG_INFO, LOC + QString("%1 Version: %2").arg(extension.name.constData()).arg(extension.version));
252 
253  auto layers = m_window->vulkanInstance()->supportedLayers();
254  LOG(VB_GENERAL, LOG_INFO, QString("%1 layer types supported:").arg(layers.size()));
255  for (const auto& layer : layers)
256  LOG(VB_GENERAL, LOG_INFO, QString("%1 Version: %2").arg(layer.name.constData()).arg(layer.version));
257  }
258 }
259 
261 {
262  LOG(VB_GENERAL, LOG_INFO, LOC + __FUNCTION__);
263 }
264 
266 {
267  LOG(VB_GENERAL, LOG_INFO, LOC + __FUNCTION__);
268 }
269 
271 {
272  delete m_debugMarker;
273 
274  LOG(VB_GENERAL, LOG_INFO, LOC + __FUNCTION__);
275  emit DoFreeResources();
276  m_devFuncs = nullptr;
277  m_funcs = nullptr;
278  m_device = nullptr;
279  m_debugMarker = nullptr;
280  m_frameStarted = false;
281  m_frameExpected = false;
282  m_phyDevLimits = { };
283  m_phyDevFeatures = { };
284 }
285 
287 {
288  LOG(VB_GENERAL, LOG_INFO, LOC + __FUNCTION__);
289  emit PhysicalDeviceLost();
290 }
291 
293 {
294  LOG(VB_GENERAL, LOG_INFO, LOC + __FUNCTION__);
295  emit LogicalDeviceLost();
296 }
297 
299 {
300  if (m_frameExpected)
301  LOG(VB_GENERAL, LOG_ERR, LOC + "Starting frame rendering before last is finished");
302  m_frameExpected = true;
303 }
304 
306 {
307  return m_frameExpected;
308 }
309 
311 {
312  return m_frameStarted;
313 }
314 
316 {
317  // essentially ignore spontaneous requests
318  if (!m_frameExpected)
319  {
320  LOG(VB_GENERAL, LOG_INFO, LOC + "Spontaneous frame");
321  m_window->frameReady();
322  return;
323  }
324 
325  m_frameExpected = false;
326  BeginFrame();
327 }
328 
330 {
331  m_frameStarted = true;
332 
333  // clear the framebuffer
334  VkClearColorValue clearColor = {{ 0.0F, 0.0F, 0.0F, 1.0F }};
335  VkClearDepthStencilValue clearDS = { 1.0F, 0 };
336  std::array<VkClearValue,2> clearValues {};
337  clearValues[0].color = clearColor;
338  clearValues[1].depthStencil = clearDS;
339 
340  // begin pass
341  VkCommandBuffer commandbuffer = m_window->currentCommandBuffer();
342  QSize size = m_window->swapChainImageSize();
343  VkRenderPassBeginInfo rpBeginInfo;
344  memset(&rpBeginInfo, 0, sizeof(rpBeginInfo));
345  rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
346  rpBeginInfo.renderPass = m_window->defaultRenderPass();
347  rpBeginInfo.framebuffer = m_window->currentFramebuffer();
348  rpBeginInfo.clearValueCount = 2;
349  rpBeginInfo.pClearValues = clearValues.data();
350  rpBeginInfo.renderArea.extent.width = static_cast<uint32_t>(size.width());
351  rpBeginInfo.renderArea.extent.height = static_cast<uint32_t>(size.height());
352  m_devFuncs->vkCmdBeginRenderPass(commandbuffer, &rpBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
353 }
354 
356 {
357  if (m_frameStarted)
358  {
359  m_devFuncs->vkCmdEndRenderPass(m_window->currentCommandBuffer());
360  m_window->frameReady();
361  }
362  m_frameStarted = false;
363 }
364 
366  VkImageLayout OldLayout,
367  VkImageLayout NewLayout,
368  VkCommandBuffer CommandBuffer)
369 {
370 
371  VkCommandBuffer commandbuffer = CommandBuffer ? CommandBuffer : CreateSingleUseCommandBuffer();
372 
373  VkImageMemoryBarrier barrier{};
374  barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
375  barrier.oldLayout = OldLayout;
376  barrier.newLayout = NewLayout;
377  barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
378  barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
379  barrier.image = Image;
380  barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
381  barrier.subresourceRange.baseMipLevel = 0;
382  barrier.subresourceRange.levelCount = 1;
383  barrier.subresourceRange.baseArrayLayer = 0;
384  barrier.subresourceRange.layerCount = 1;
385 
386  VkPipelineStageFlags sourceStage = 0;
387  VkPipelineStageFlags destinationStage = 0;
388  if (OldLayout == VK_IMAGE_LAYOUT_UNDEFINED && NewLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
389  {
390  barrier.srcAccessMask = 0;
391  barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
392  sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
393  destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
394  }
395  else if (OldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && NewLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
396  {
397  barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
398  barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
399  sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
400  destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
401  }
402  else
403  {
404  LOG(VB_GENERAL, LOG_WARNING, LOC + "Unsupported layout transition");
405  }
406 
407  m_devFuncs->vkCmdPipelineBarrier(commandbuffer, sourceStage, destinationStage,
408  0, 0, nullptr, 0, nullptr, 1, &barrier);
409  if (!CommandBuffer)
410  FinishSingleUseCommandBuffer(commandbuffer);
411 }
412 
414  uint32_t Width, uint32_t Height,
415  VkCommandBuffer CommandBuffer)
416 {
417  VkCommandBuffer commandbuffer = CommandBuffer ? CommandBuffer : CreateSingleUseCommandBuffer();
418  VkBufferImageCopy region { };
419  region.bufferOffset = 0;
420  region.bufferRowLength = 0;
421  region.bufferImageHeight = 0;
422  region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
423  region.imageSubresource.mipLevel = 0;
424  region.imageSubresource.baseArrayLayer = 0;
425  region.imageSubresource.layerCount = 1;
426  region.imageOffset = { 0, 0, 0 };
427  region.imageExtent = { Width, Height, 1 };
428  m_devFuncs->vkCmdCopyBufferToImage(commandbuffer, Buffer, Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
429  if (!CommandBuffer)
430  FinishSingleUseCommandBuffer(commandbuffer);
431 }
432 
433 void MythRenderVulkan::CopyBuffer(VkBuffer Src, VkBuffer Dst, VkDeviceSize Size, VkCommandBuffer CommandBuffer)
434 {
435  VkBufferCopy region { };
436  region.size = Size;
437 
438  if (CommandBuffer)
439  {
440  m_devFuncs->vkCmdCopyBuffer(CommandBuffer, Src, Dst, 1, &region);
441  }
442  else
443  {
444  VkCommandBuffer cmdbuf = CreateSingleUseCommandBuffer();
445  m_devFuncs->vkCmdCopyBuffer(cmdbuf, Src, Dst, 1, &region);
447  }
448 }
449 
450 bool MythRenderVulkan::CreateBuffer(VkDeviceSize Size,
451  VkBufferUsageFlags Usage,
452  VkMemoryPropertyFlags Properties,
453  VkBuffer &Buffer,
454  VkDeviceMemory &Memory)
455 {
456  VkBufferCreateInfo bufferInfo { };
457  bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
458  bufferInfo.size = Size;
459  bufferInfo.usage = Usage;
460  bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
461 
462  if (m_devFuncs->vkCreateBuffer(m_device, &bufferInfo, nullptr, &Buffer) != VK_SUCCESS)
463  {
464  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create buffer");
465  return false;
466  }
467 
468  VkMemoryRequirements requirements;
469  m_devFuncs->vkGetBufferMemoryRequirements(m_device, Buffer, &requirements);
470 
471  VkMemoryAllocateInfo allocInfo { };
472  allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
473  allocInfo.allocationSize = requirements.size;
474  if (auto type = FindMemoryType(requirements.memoryTypeBits, Properties))
475  {
476  allocInfo.memoryTypeIndex = type.value();
477  if (m_devFuncs->vkAllocateMemory(m_device, &allocInfo, nullptr, &Memory) == VK_SUCCESS)
478  {
479  m_devFuncs->vkBindBufferMemory(m_device, Buffer, Memory, 0);
480  return true;
481  }
482  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to allocate buffer memory");
483  }
484  else
485  {
486  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to deduce buffer memory type");
487  }
488 
489  m_devFuncs->vkDestroyBuffer(m_device, Buffer, nullptr);
490  return false;
491 }
492 
493 VkSampler MythRenderVulkan::CreateSampler(VkFilter Min, VkFilter Mag)
494 {
495  VkSampler result = MYTH_NULL_DISPATCH;
496  VkSamplerCreateInfo samplerinfo { };
497  memset(&samplerinfo, 0, sizeof(samplerinfo));
498  samplerinfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
499  samplerinfo.minFilter = Min;
500  samplerinfo.magFilter = Mag;
501  samplerinfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
502  samplerinfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
503  samplerinfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
504  samplerinfo.anisotropyEnable = VK_FALSE;
505  samplerinfo.maxAnisotropy = 1;
506  samplerinfo.borderColor = VK_BORDER_COLOR_INT_TRANSPARENT_BLACK;
507  samplerinfo.unnormalizedCoordinates = VK_FALSE;
508  samplerinfo.compareEnable = VK_FALSE;
509  samplerinfo.compareOp = VK_COMPARE_OP_ALWAYS;
510  samplerinfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
511  if (m_devFuncs->vkCreateSampler(m_device, &samplerinfo, nullptr, &result) != VK_SUCCESS)
512  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create image sampler");
513  return result;
514 }
515 
516 VkPhysicalDeviceFeatures MythRenderVulkan::GetPhysicalDeviceFeatures() const
517 {
518  return m_phyDevFeatures;
519 }
520 
521 VkPhysicalDeviceLimits MythRenderVulkan::GetPhysicalDeviceLimits() const
522 {
523  return m_phyDevLimits;
524 }
525 
526 void MythRenderVulkan::BeginDebugRegion(VkCommandBuffer CommandBuffer, const char *Name,
527  const MythVulkan4F Color)
528 {
529  if (m_debugMarker && CommandBuffer)
530  m_debugMarker->BeginRegion(CommandBuffer, Name, Color);
531 }
532 
533 void MythRenderVulkan::EndDebugRegion(VkCommandBuffer CommandBuffer)
534 {
535  if (m_debugMarker && CommandBuffer)
536  m_debugMarker->EndRegion(CommandBuffer);
537 }
538 
540  VkFormat Format,
541  VkImageTiling Tiling,
542  VkImageUsageFlags Usage,
543  VkMemoryPropertyFlags Properties,
544  VkImage &Image,
545  VkDeviceMemory &ImageMemory)
546 {
547  VkImageCreateInfo imageinfo { };
548  imageinfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
549  imageinfo.imageType = VK_IMAGE_TYPE_2D;
550  imageinfo.extent.width = static_cast<uint32_t>(Size.width());
551  imageinfo.extent.height = static_cast<uint32_t>(Size.height());
552  imageinfo.extent.depth = 1;
553  imageinfo.mipLevels = 1;
554  imageinfo.arrayLayers = 1;
555  imageinfo.format = Format;
556  imageinfo.tiling = Tiling;
557  imageinfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
558  imageinfo.usage = Usage;
559  imageinfo.samples = VK_SAMPLE_COUNT_1_BIT;
560  imageinfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
561 
562  if (m_devFuncs->vkCreateImage(m_device, &imageinfo, nullptr, &Image) != VK_SUCCESS)
563  {
564  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create Vulkan image");
565  return false;
566  }
567 
568  VkMemoryRequirements requirements;
569  m_devFuncs->vkGetImageMemoryRequirements(m_device, Image, &requirements);
570 
571  VkMemoryAllocateInfo allocinfo { };
572  allocinfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
573  allocinfo.allocationSize = requirements.size;
574  if (auto type = FindMemoryType(requirements.memoryTypeBits, Properties))
575  {
576  allocinfo.memoryTypeIndex = type.value();
577  if (m_devFuncs->vkAllocateMemory(m_device, &allocinfo, nullptr, &ImageMemory) == VK_SUCCESS)
578  {
579  m_devFuncs->vkBindImageMemory(m_device, Image, ImageMemory, 0U);
580  return true;
581  }
582  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to allocate image memory");
583  }
584  else
585  {
586  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to deduce image memory type");
587  }
588 
589  m_devFuncs->vkDestroyImage(m_device, Image, nullptr);
590  return false;
591 }
592 
593 std::optional<uint32_t> MythRenderVulkan::FindMemoryType(uint32_t Filter, VkMemoryPropertyFlags Properties)
594 {
595  std::optional<uint32_t> result;
596  VkPhysicalDeviceMemoryProperties memoryprops;
597  m_funcs->vkGetPhysicalDeviceMemoryProperties(m_window->physicalDevice(), &memoryprops);
598 
599  for (uint32_t i = 0; i < memoryprops.memoryTypeCount; i++)
600  {
601  if ((Filter & (1 << i)) && (memoryprops.memoryTypes[i].propertyFlags & Properties) == Properties)
602  {
603  result = i;
604  break;
605  }
606  }
607 
608  return result;
609 }
610 
612 {
613  VkCommandBufferAllocateInfo allocinfo { };
614  allocinfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
615  allocinfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
616  allocinfo.commandPool = m_window->graphicsCommandPool();
617  allocinfo.commandBufferCount = 1;
618  VkCommandBuffer commandbuffer = nullptr;
619  m_devFuncs->vkAllocateCommandBuffers(m_device, &allocinfo, &commandbuffer);
620  VkCommandBufferBeginInfo begininfo { };
621  begininfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
622  begininfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
623  m_devFuncs->vkBeginCommandBuffer(commandbuffer, &begininfo);
624  return commandbuffer;
625 }
626 
628 {
629  m_devFuncs->vkEndCommandBuffer(Buffer);
630  VkSubmitInfo submitinfo{};
631  submitinfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
632  submitinfo.commandBufferCount = 1;
633  submitinfo.pCommandBuffers = &Buffer;
634  m_devFuncs->vkQueueSubmit(m_window->graphicsQueue(), 1, &submitinfo, MYTH_NULL_DISPATCH);
635  m_devFuncs->vkQueueWaitIdle(m_window->graphicsQueue());
636  m_devFuncs->vkFreeCommandBuffers(m_device, m_window->graphicsCommandPool(), 1, &Buffer);
637 }
638 
640  const QRect Viewport,
641  std::vector<VkDynamicState> Dynamic)
642 {
643  if (!(Shader && Viewport.isValid()))
644  return MYTH_NULL_DISPATCH;
645 
646  // shaders
647  const auto & shaderstages = Shader->Stages();
648 
649  // primitives
650  VkPipelineInputAssemblyStateCreateInfo inputassembly { };
651  inputassembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
652  inputassembly.topology = Shader->GetTopology();
653  inputassembly.primitiveRestartEnable = VK_FALSE;
654 
655  // viewport - N.B. static
656  VkViewport viewport { };
657  viewport.x = static_cast<float>(Viewport.left());
658  viewport.y = static_cast<float>(Viewport.left());
659  viewport.width = static_cast<float>(Viewport.width());
660  viewport.height = static_cast<float>(Viewport.height());
661  viewport.minDepth = 0.0F;
662  viewport.maxDepth = 1.0F;
663 
664  VkRect2D scissor { };
665  scissor.offset = { Viewport.left(), Viewport.top() };
666  scissor.extent = { static_cast<uint32_t>(Viewport.width()), static_cast<uint32_t>(Viewport.height()) };
667 
668  VkPipelineViewportStateCreateInfo viewportstate { };
669  viewportstate.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
670  viewportstate.viewportCount = 1;
671  viewportstate.pViewports = &viewport;
672  viewportstate.scissorCount = 1;
673  viewportstate.pScissors = &scissor;
674 
675  // Vertex input - from the shader
676  VkPipelineVertexInputStateCreateInfo vertexinput { };
677  const auto & vertexattribs = Shader->GetVertexAttributes();
678  if (vertexattribs.empty())
679  {
680  vertexinput.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
681  vertexinput.vertexBindingDescriptionCount = 0;
682  vertexinput.pVertexBindingDescriptions = nullptr;
683  vertexinput.vertexAttributeDescriptionCount = 0;
684  vertexinput.pVertexAttributeDescriptions = nullptr;
685  }
686  else
687  {
688  vertexinput.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
689  vertexinput.vertexBindingDescriptionCount = 1;
690  vertexinput.pVertexBindingDescriptions = &Shader->GetVertexBindingDesc();
691  vertexinput.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertexattribs.size());
692  vertexinput.pVertexAttributeDescriptions = vertexattribs.data();
693  }
694 
695  // multisampling - no thanks
696  VkPipelineMultisampleStateCreateInfo multisampling { };
697  multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
698  multisampling.sampleShadingEnable = VK_FALSE;
699  multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
700 
701  // blending - regular alpha blend
702  VkPipelineColorBlendAttachmentState colorblendattachment { };
703  colorblendattachment.blendEnable = VK_TRUE;
704  colorblendattachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
705  colorblendattachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
706  colorblendattachment.colorBlendOp = VK_BLEND_OP_ADD;
707  colorblendattachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
708  colorblendattachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
709  colorblendattachment.alphaBlendOp = VK_BLEND_OP_ADD;
710  colorblendattachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
711  VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
712 
713  VkPipelineColorBlendStateCreateInfo colorBlending{};
714  colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
715  colorBlending.logicOpEnable = VK_FALSE;
716  colorBlending.logicOp = VK_LOGIC_OP_COPY;
717  colorBlending.attachmentCount = 1;
718  colorBlending.pAttachments = &colorblendattachment;
719  colorBlending.blendConstants[0] = 0.0F;
720  colorBlending.blendConstants[1] = 0.0F;
721  colorBlending.blendConstants[2] = 0.0F;
722  colorBlending.blendConstants[3] = 0.0F;
723 
724  // rasterizer
725  VkPipelineRasterizationStateCreateInfo rasterizer { };
726  rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
727  rasterizer.depthClampEnable = VK_FALSE;
728  rasterizer.rasterizerDiscardEnable = VK_FALSE;
729  rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
730  rasterizer.lineWidth = 1.0F;
731  rasterizer.cullMode = VK_CULL_MODE_NONE;
732  rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
733  rasterizer.depthBiasEnable = VK_FALSE;
734 
735  // depth/stencil test (required as Qt creates a depth/stencil attachment)
736  VkPipelineDepthStencilStateCreateInfo depthstencil { };
737  depthstencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
738  depthstencil.pNext = nullptr;
739  depthstencil.flags = 0;
740  depthstencil.depthTestEnable = VK_FALSE;
741  depthstencil.depthWriteEnable = VK_FALSE;
742  depthstencil.depthCompareOp = VK_COMPARE_OP_NEVER;
743  depthstencil.depthBoundsTestEnable = VK_FALSE;
744  depthstencil.stencilTestEnable = VK_FALSE;
745  depthstencil.front = { };
746  depthstencil.back = { };
747  depthstencil.minDepthBounds = 0.0F;
748  depthstencil.maxDepthBounds = 1.0F;
749 
750  // setup dynamic state
751  VkPipelineDynamicStateCreateInfo dynamic { };
752  dynamic.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
753  dynamic.dynamicStateCount = Dynamic.empty() ? 0 : static_cast<uint32_t>(Dynamic.size());
754  dynamic.pDynamicStates = Dynamic.empty() ? nullptr : Dynamic.data();
755 
756  // and breathe
757  VkGraphicsPipelineCreateInfo pipelinecreate { };
758  pipelinecreate.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
759  pipelinecreate.pNext = nullptr;
760  pipelinecreate.flags = 0;
761  pipelinecreate.stageCount = static_cast<uint32_t>(shaderstages.size());
762  pipelinecreate.pStages = shaderstages.data();
763  pipelinecreate.pVertexInputState = &vertexinput;
764  pipelinecreate.pInputAssemblyState = &inputassembly;
765  pipelinecreate.pTessellationState = nullptr;
766  pipelinecreate.pViewportState = &viewportstate;
767  pipelinecreate.pRasterizationState = &rasterizer;
768  pipelinecreate.pMultisampleState = &multisampling;
769  pipelinecreate.pDepthStencilState = &depthstencil;
770  pipelinecreate.pColorBlendState = &colorBlending;
771  pipelinecreate.pDynamicState = &dynamic;
772  pipelinecreate.layout = Shader->GetPipelineLayout();
773  pipelinecreate.renderPass = m_window->defaultRenderPass();
774  pipelinecreate.subpass = 0;
775  pipelinecreate.basePipelineHandle = MYTH_NULL_DISPATCH;
776  pipelinecreate.basePipelineIndex = 0;
777 
778  VkPipeline result = MYTH_NULL_DISPATCH;
779  if (m_devFuncs->vkCreateGraphicsPipelines(m_device, MYTH_NULL_DISPATCH, 1, &pipelinecreate, nullptr, &result) == VK_SUCCESS)
780  return result;
781 
782  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create graphics pipeline");
783  return MYTH_NULL_DISPATCH;
784 }
mythwindowvulkan.h
MythRenderVulkan::preInitResources
void preInitResources(void) override
Definition: mythrendervulkan.cpp:131
mythtexturevulkan.h
MythRenderVulkan::CopyBuffer
void CopyBuffer(VkBuffer Src, VkBuffer Dst, VkDeviceSize Size, VkCommandBuffer CommandBuffer=nullptr)
Definition: mythrendervulkan.cpp:433
MythRenderVulkan::DoFreeResources
void DoFreeResources(void)
MythRenderVulkan::physicalDeviceLost
void physicalDeviceLost(void) override
Definition: mythrendervulkan.cpp:286
MythRenderVulkan::initResources
void initResources(void) override
Definition: mythrendervulkan.cpp:136
mythdebugvulkan.h
MythVulkanObject::MythVulkanObject
MythVulkanObject(MythRenderVulkan *Render)
Definition: mythrendervulkan.cpp:28
MythRenderVulkan::initSwapChainResources
void initSwapChainResources(void) override
Definition: mythrendervulkan.cpp:260
MythRenderVulkan::CopyBufferToImage
void CopyBufferToImage(VkBuffer Buffer, VkImage Image, uint32_t Width, uint32_t Height, VkCommandBuffer CommandBuffer=nullptr)
Definition: mythrendervulkan.cpp:413
MythVulkanObject
Definition: mythrendervulkan.h:29
MYTH_NULL_DISPATCH
#define MYTH_NULL_DISPATCH
Definition: mythrendervulkan.h:25
MythRenderVulkan::GetVulkanRender
static MythRenderVulkan * GetVulkanRender(void)
Definition: mythrendervulkan.cpp:88
arg
arg(title).arg(filename).arg(doDelete))
MythShaderVulkan::GetVertexBindingDesc
const VkVertexInputBindingDescription & GetVertexBindingDesc(void) const
Definition: mythshadervulkan.cpp:453
MythRenderVulkan::m_frameStarted
bool m_frameStarted
Definition: mythrendervulkan.h:125
MythDate::Format
Format
Definition: mythdate.h:13
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
LOC
#define LOC
Definition: mythrendervulkan.cpp:14
MythRenderVulkan::GetDescription
QStringList GetDescription(void) override
Definition: mythrendervulkan.cpp:162
MythRenderVulkan::GetFrameExpected
bool GetFrameExpected(void) const
Definition: mythrendervulkan.cpp:305
Device
A device containing images (ie. USB stick, CD, storage group etc)
Definition: imagemanager.cpp:34
MythRenderVulkan::CreateSingleUseCommandBuffer
VkCommandBuffer CreateSingleUseCommandBuffer(void)
Definition: mythrendervulkan.cpp:611
MythVulkanObject::m_vulkanValid
bool m_vulkanValid
Definition: mythrendervulkan.h:43
MythMainWindow::GetRenderDevice
MythRender * GetRenderDevice()
Definition: mythmainwindow.cpp:298
MythRenderVulkan::GetPhysicalDeviceLimits
VkPhysicalDeviceLimits GetPhysicalDeviceLimits() const
Definition: mythrendervulkan.cpp:521
MythVulkanObject::Create
static MythVulkanObject * Create(MythRenderVulkan *Render)
Definition: mythrendervulkan.cpp:16
MythRenderVulkan::CreateSampler
VkSampler CreateSampler(VkFilter Min, VkFilter Mag)
Definition: mythrendervulkan.cpp:493
MythWindowVulkan
Definition: mythwindowvulkan.h:11
Image
Definition: image.h:31
HasMythMainWindow
bool HasMythMainWindow(void)
Definition: mythmainwindow.cpp:113
MythRenderVulkan::m_debugInfo
QMap< QString, QString > m_debugInfo
Definition: mythrendervulkan.h:126
kRenderVulkan
@ kRenderVulkan
Definition: mythrender_base.h:20
MythMainWindow::getMainWindow
static MythMainWindow * getMainWindow(bool useDB=true)
Return the existing main window, or create one.
Definition: mythmainwindow.cpp:84
MythVulkanObject::m_vulkanDevice
VkDevice m_vulkanDevice
Definition: mythrendervulkan.h:45
MythRenderVulkan::GetVulkanWindow
MythWindowVulkan * GetVulkanWindow(void)
Definition: mythrendervulkan.cpp:126
MythRenderVulkan::m_devFuncs
QVulkanDeviceFunctions * m_devFuncs
Definition: mythrendervulkan.h:121
MythDebugVulkan::Create
static MythDebugVulkan * Create(MythVulkanObject *Vulkan)
Definition: mythdebugvulkan.cpp:14
MythRenderVulkan::GetPhysicalDeviceFeatures
VkPhysicalDeviceFeatures GetPhysicalDeviceFeatures() const
Definition: mythrendervulkan.cpp:516
MythRenderVulkan::BeginDebugRegion
void BeginDebugRegion(VkCommandBuffer CommandBuffer, const char *Name, MythVulkan4F Color)
Definition: mythrendervulkan.cpp:526
MythShaderVulkan::Stages
const std::vector< VkPipelineShaderStageCreateInfo > & Stages(void) const
Definition: mythshadervulkan.cpp:442
MythVulkanObject::m_vulkanRender
MythRenderVulkan * m_vulkanRender
Definition: mythrendervulkan.h:44
mythlogging.h
MythShaderVulkan::GetPipelineLayout
VkPipelineLayout GetPipelineLayout(void) const
Definition: mythshadervulkan.cpp:458
MythRenderVulkan::m_frameExpected
bool m_frameExpected
Definition: mythrendervulkan.h:124
MythRenderVulkan::CreateImage
bool CreateImage(QSize Size, VkFormat Format, VkImageTiling Tiling, VkImageUsageFlags Usage, VkMemoryPropertyFlags Properties, VkImage &Image, VkDeviceMemory &ImageMemory)
Definition: mythrendervulkan.cpp:539
MythRenderVulkan::LogicalDeviceLost
void LogicalDeviceLost(void)
MythDebugVulkan::BeginRegion
void BeginRegion(VkCommandBuffer CmdBuffer, const char *Name, MythVulkan4F Color)
Definition: mythdebugvulkan.cpp:51
Properties
QMultiMap< QString, Property * > Properties
Definition: upnpcdsobjects.h:95
MythRenderVulkan::BeginFrame
void BeginFrame(void)
Definition: mythrendervulkan.cpp:329
MythRenderVulkan::SetFrameExpected
void SetFrameExpected(void)
Definition: mythrendervulkan.cpp:298
mythshadervulkan.h
MythRenderVulkan::FindMemoryType
std::optional< uint32_t > FindMemoryType(uint32_t Filter, VkMemoryPropertyFlags Properties)
Definition: mythrendervulkan.cpp:593
MythRenderVulkan::DebugVulkan
void DebugVulkan(void)
Definition: mythrendervulkan.cpp:175
MythVulkanObject::Device
VkDevice Device()
Definition: mythrendervulkan.cpp:73
MythVulkanObject::m_vulkanFuncs
QVulkanDeviceFunctions * m_vulkanFuncs
Definition: mythrendervulkan.h:46
MythRenderVulkan::SetVulkanWindow
void SetVulkanWindow(MythWindowVulkan *VulkanWindow)
Definition: mythrendervulkan.cpp:121
MythRenderVulkan::startNextFrame
void startNextFrame(void) override
Definition: mythrendervulkan.cpp:315
MythVulkan4F
std::array< float, 4 > MythVulkan4F
Definition: mythrendervulkan.h:19
MythShaderVulkan::GetTopology
VkPrimitiveTopology GetTopology() const
Definition: mythshadervulkan.cpp:478
MythRenderVulkan::EndDebugRegion
void EndDebugRegion(VkCommandBuffer CommandBuffer)
Definition: mythrendervulkan.cpp:533
MythRenderVulkan::m_debugMarker
MythDebugVulkan * m_debugMarker
Definition: mythrendervulkan.h:127
mythimage.h
Buffer
Definition: MythExternControl.h:37
VERBOSE_LEVEL_CHECK
#define VERBOSE_LEVEL_CHECK(_MASK_, _LEVEL_)
Definition: mythlogging.h:14
MythRenderVulkan::releaseSwapChainResources
void releaseSwapChainResources(void) override
Definition: mythrendervulkan.cpp:265
MythVulkanObject::CheckValid
void CheckValid()
Definition: mythrendervulkan.cpp:54
MythRenderVulkan::CreatePipeline
VkPipeline CreatePipeline(MythShaderVulkan *Shader, QRect Viewport, std::vector< VkDynamicState > Dynamic={ })
Definition: mythrendervulkan.cpp:639
Min
const T & Min(const T &x, const T &y)
Definition: upnputil.h:30
MythRender
Definition: mythrender_base.h:24
MythRenderVulkan::logicalDeviceLost
void logicalDeviceLost(void) override
Definition: mythrendervulkan.cpp:292
Name
Definition: channelsettings.cpp:47
MythVulkanObject::Window
MythWindowVulkan * Window()
Definition: mythrendervulkan.cpp:83
MythRenderVulkan::m_funcs
QVulkanFunctions * m_funcs
Definition: mythrendervulkan.h:120
MythRenderVulkan::EndFrame
void EndFrame(void)
Definition: mythrendervulkan.cpp:355
MythRenderVulkan::m_phyDevLimits
VkPhysicalDeviceLimits m_phyDevLimits
Definition: mythrendervulkan.h:123
MythRenderVulkan::GetFrameStarted
bool GetFrameStarted(void) const
Definition: mythrendervulkan.cpp:310
MythRenderVulkan::m_device
VkDevice m_device
Definition: mythrendervulkan.h:119
MythVulkanObject::m_vulkanWindow
MythWindowVulkan * m_vulkanWindow
Definition: mythrendervulkan.h:47
MythRenderVulkan::m_phyDevFeatures
VkPhysicalDeviceFeatures m_phyDevFeatures
Definition: mythrendervulkan.h:122
MythVulkanObject::IsValidVulkan
bool IsValidVulkan() const
Definition: mythrendervulkan.cpp:63
MythRenderVulkan::PhysicalDeviceLost
void PhysicalDeviceLost(void)
MythRenderVulkan::MythRenderVulkan
MythRenderVulkan()
Definition: mythrendervulkan.cpp:102
MythShaderVulkan::GetVertexAttributes
const MythVertexAttrs & GetVertexAttributes(void) const
Definition: mythshadervulkan.cpp:448
MythRenderVulkan::m_window
MythWindowVulkan * m_window
Definition: mythrendervulkan.h:118
MythRenderVulkan
Definition: mythrendervulkan.h:54
MythRender::Type
RenderType Type(void) const
Definition: mythrender_base.h:32
mythrendervulkan.h
MythVulkanObject::Funcs
QVulkanDeviceFunctions * Funcs()
Definition: mythrendervulkan.cpp:78
MythShaderVulkan
Creates shader objects suitable for use with the Vulkan API.
Definition: mythshadervulkan.h:21
MythRenderVulkan::releaseResources
void releaseResources(void) override
Definition: mythrendervulkan.cpp:270
MythRenderVulkan::FinishSingleUseCommandBuffer
void FinishSingleUseCommandBuffer(VkCommandBuffer &Buffer)
Definition: mythrendervulkan.cpp:627
mythmainwindow.h
MythDebugVulkan::EndRegion
void EndRegion(VkCommandBuffer CmdBuffer)
Definition: mythdebugvulkan.cpp:59
MythRenderVulkan::~MythRenderVulkan
~MythRenderVulkan() override
Definition: mythrendervulkan.cpp:113
nv_python_libs.bbciplayer.bbciplayer_api.version
string version
Definition: bbciplayer_api.py:81
MythVulkanObject::Render
MythRenderVulkan * Render()
Definition: mythrendervulkan.cpp:68
MythRenderVulkan::TransitionImageLayout
void TransitionImageLayout(VkImage &Image, VkImageLayout OldLayout, VkImageLayout NewLayout, VkCommandBuffer CommandBuffer=nullptr)
Definition: mythrendervulkan.cpp:365
MythRenderVulkan::CreateBuffer
bool CreateBuffer(VkDeviceSize Size, VkBufferUsageFlags Usage, VkMemoryPropertyFlags Properties, VkBuffer &Buffer, VkDeviceMemory &Memory)
Definition: mythrendervulkan.cpp:450
MythMainWindow
Definition: mythmainwindow.h:35
Color
Definition: graphic.h:7