MythTV master
mythrendervulkan.cpp
Go to the documentation of this file.
1// Qt
2#include <QGuiApplication>
3
4// MythTV
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{
32 {
35 {
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
78QVulkanDeviceFunctions* 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#if CONFIG_LIBGLSLANG
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#if CONFIG_LIBGLSLANG
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 = 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 : std::as_const(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 : std::as_const(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 : std::as_const(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
413void MythRenderVulkan::CopyBufferToImage(VkBuffer Buffer, VkImage Image,
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
433void 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
450bool 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
493VkSampler 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
516VkPhysicalDeviceFeatures MythRenderVulkan::GetPhysicalDeviceFeatures() const
517{
518 return m_phyDevFeatures;
519}
520
521VkPhysicalDeviceLimits MythRenderVulkan::GetPhysicalDeviceLimits() const
522{
523 return m_phyDevLimits;
524}
525
526void 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
533void 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
593std::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}
A device containing images (ie. USB stick, CD, storage group etc)
static MythDebugVulkan * Create(MythVulkanObject *Vulkan)
void EndRegion(VkCommandBuffer CmdBuffer)
void BeginRegion(VkCommandBuffer CmdBuffer, const char *Name, MythVulkan4F Color)
MythRender * GetRenderDevice()
static MythMainWindow * getMainWindow(bool UseDB=true)
Return the existing main window, or create one.
QVulkanFunctions * m_funcs
MythWindowVulkan * GetVulkanWindow(void)
bool GetFrameExpected(void) const
QVulkanDeviceFunctions * m_devFuncs
bool CreateImage(QSize Size, VkFormat Format, VkImageTiling Tiling, VkImageUsageFlags Usage, VkMemoryPropertyFlags Properties, VkImage &Image, VkDeviceMemory &ImageMemory)
void physicalDeviceLost(void) override
VkSampler CreateSampler(VkFilter Min, VkFilter Mag)
~MythRenderVulkan() override
void logicalDeviceLost(void) override
void PhysicalDeviceLost(void)
bool CreateBuffer(VkDeviceSize Size, VkBufferUsageFlags Usage, VkMemoryPropertyFlags Properties, VkBuffer &Buffer, VkDeviceMemory &Memory)
static MythRenderVulkan * GetVulkanRender(void)
void FinishSingleUseCommandBuffer(VkCommandBuffer &Buffer)
VkPhysicalDeviceFeatures GetPhysicalDeviceFeatures() const
void TransitionImageLayout(VkImage &Image, VkImageLayout OldLayout, VkImageLayout NewLayout, VkCommandBuffer CommandBuffer=nullptr)
void preInitResources(void) override
VkPhysicalDeviceFeatures m_phyDevFeatures
void releaseSwapChainResources(void) override
void EndDebugRegion(VkCommandBuffer CommandBuffer)
bool GetFrameStarted(void) const
void LogicalDeviceLost(void)
QMap< QString, QString > m_debugInfo
VkPipeline CreatePipeline(MythShaderVulkan *Shader, QRect Viewport, std::vector< VkDynamicState > Dynamic={ })
void CopyBuffer(VkBuffer Src, VkBuffer Dst, VkDeviceSize Size, VkCommandBuffer CommandBuffer=nullptr)
void initSwapChainResources(void) override
QStringList GetDescription(void) override
void SetVulkanWindow(MythWindowVulkan *VulkanWindow)
VkPhysicalDeviceLimits m_phyDevLimits
VkCommandBuffer CreateSingleUseCommandBuffer(void)
MythWindowVulkan * m_window
void CopyBufferToImage(VkBuffer Buffer, VkImage Image, uint32_t Width, uint32_t Height, VkCommandBuffer CommandBuffer=nullptr)
void startNextFrame(void) override
void SetFrameExpected(void)
void DoFreeResources(void)
VkPhysicalDeviceLimits GetPhysicalDeviceLimits() const
void releaseResources(void) override
std::optional< uint32_t > FindMemoryType(uint32_t Filter, VkMemoryPropertyFlags Properties)
MythDebugVulkan * m_debugMarker
void initResources(void) override
void BeginDebugRegion(VkCommandBuffer CommandBuffer, const char *Name, MythVulkan4F Color)
RenderType Type(void) const
Creates shader objects suitable for use with the Vulkan API.
VkPrimitiveTopology GetTopology() const
const std::vector< VkPipelineShaderStageCreateInfo > & Stages(void) const
const VkVertexInputBindingDescription & GetVertexBindingDesc(void) const
const MythVertexAttrs & GetVertexAttributes(void) const
VkPipelineLayout GetPipelineLayout(void) const
MythRenderVulkan * Render()
QVulkanDeviceFunctions * m_vulkanFuncs
MythRenderVulkan * m_vulkanRender
MythWindowVulkan * m_vulkanWindow
bool IsValidVulkan() const
MythWindowVulkan * Window()
QVulkanDeviceFunctions * Funcs()
static MythVulkanObject * Create(MythRenderVulkan *Render)
MythVulkanObject(MythRenderVulkan *Render)
static bool VERBOSE_LEVEL_CHECK(uint64_t mask, LogLevel_t level)
Definition: mythlogging.h:29
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
bool HasMythMainWindow(void)
@ kRenderVulkan
#define LOC
std::array< float, 4 > MythVulkan4F
#define MYTH_NULL_DISPATCH
string version
Definition: giantbomb.py:185
Definition: graphic.h:7
QMultiMap< QString, Property * > Properties