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