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 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR,
213 .pNext = nullptr,
214 .driverID = static_cast<VkDriverId>(0),
215 .driverName = {},
216 .driverInfo = {},
217 .conformanceVersion = {},
218 };
219
220 VkPhysicalDeviceProperties2 devprops { };
221 devprops.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
222 devprops.pNext = &driverprops;
223
224 proc(m_window->physicalDevice(), &devprops);
225 m_debugInfo.insert("drivername", driverprops.driverName);
226 m_debugInfo.insert("driverinfo", driverprops.driverInfo);
227 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Driver name : %1").arg(driverprops.driverName));
228 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Driver info : %1").arg(driverprops.driverInfo));
229 }
230 }
231
232 m_debugInfo.insert("devicename", props->deviceName);
233 m_debugInfo.insert("devicetype", deviceType(props->deviceType));
234 m_debugInfo.insert("apiversion", version(props->apiVersion));
235
236 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Qt platform : %1").arg(QGuiApplication::platformName()));
237 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Device name : %1").arg(props->deviceName));
238 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Device type : %1").arg(deviceType(props->deviceType)));
239 LOG(VB_GENERAL, LOG_INFO, LOC + QString("API version : %1").arg(version(props->apiVersion)));
240 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Device ID : 0x%1").arg(props->deviceID, 0, 16));
241 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Driver version : %1").arg(version(props->driverVersion)));
242 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Max image size : %1x%1").arg(limits.maxImageDimension2D));
243 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Max framebuffer : %1x%2")
244 .arg(limits.maxFramebufferWidth).arg(limits.maxFramebufferHeight));
245 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Max allocations : %1").arg(limits.maxMemoryAllocationCount));
246 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Max samplers : %1").arg(limits.maxSamplerAllocationCount));
247 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Min alignment : %1").arg(limits.minMemoryMapAlignment));
248
249 if (VERBOSE_LEVEL_CHECK(VB_GENERAL, LOG_DEBUG))
250 {
251 LOG(VB_GENERAL, LOG_INFO, QString("%1 device extensions supported:").arg(devextensions.size()));
252 for (const auto& extension : std::as_const(devextensions))
253 LOG(VB_GENERAL, LOG_INFO, LOC + QString("%1 Version: %2").arg(extension.name.constData()).arg(extension.version));
254
255 LOG(VB_GENERAL, LOG_INFO, QString("%1 instance extensions supported:").arg(instextensions.size()));
256 for (const auto& extension : std::as_const(instextensions))
257 LOG(VB_GENERAL, LOG_INFO, LOC + QString("%1 Version: %2").arg(extension.name.constData()).arg(extension.version));
258
259 auto layers = m_window->vulkanInstance()->supportedLayers();
260 LOG(VB_GENERAL, LOG_INFO, QString("%1 layer types supported:").arg(layers.size()));
261 for (const auto& layer : std::as_const(layers))
262 LOG(VB_GENERAL, LOG_INFO, QString("%1 Version: %2").arg(layer.name.constData()).arg(layer.version));
263 }
264}
265
267{
268 LOG(VB_GENERAL, LOG_INFO, LOC + __FUNCTION__);
269}
270
272{
273 LOG(VB_GENERAL, LOG_INFO, LOC + __FUNCTION__);
274}
275
277{
278 delete m_debugMarker;
279
280 LOG(VB_GENERAL, LOG_INFO, LOC + __FUNCTION__);
281 emit DoFreeResources();
282 m_devFuncs = nullptr;
283 m_funcs = nullptr;
284 m_device = nullptr;
285 m_debugMarker = nullptr;
286 m_frameStarted = false;
287 m_frameExpected = false;
288 m_phyDevLimits = { };
289 m_phyDevFeatures = { };
290}
291
293{
294 LOG(VB_GENERAL, LOG_INFO, LOC + __FUNCTION__);
295 emit PhysicalDeviceLost();
296}
297
299{
300 LOG(VB_GENERAL, LOG_INFO, LOC + __FUNCTION__);
301 emit LogicalDeviceLost();
302}
303
305{
306 if (m_frameExpected)
307 LOG(VB_GENERAL, LOG_ERR, LOC + "Starting frame rendering before last is finished");
308 m_frameExpected = true;
309}
310
312{
313 return m_frameExpected;
314}
315
317{
318 return m_frameStarted;
319}
320
322{
323 // essentially ignore spontaneous requests
324 if (!m_frameExpected)
325 {
326 LOG(VB_GENERAL, LOG_INFO, LOC + "Spontaneous frame");
327 m_window->frameReady();
328 return;
329 }
330
331 m_frameExpected = false;
332 BeginFrame();
333}
334
336{
337 m_frameStarted = true;
338
339 // clear the framebuffer
340 VkClearColorValue clearColor = {{ 0.0F, 0.0F, 0.0F, 1.0F }};
341 VkClearDepthStencilValue clearDS = { 1.0F, 0 };
342 std::array<VkClearValue,2> clearValues {};
343 clearValues[0].color = clearColor;
344 clearValues[1].depthStencil = clearDS;
345
346 // begin pass
347 VkCommandBuffer commandbuffer = m_window->currentCommandBuffer();
348 QSize size = m_window->swapChainImageSize();
349 VkRenderPassBeginInfo rpBeginInfo;
350 memset(&rpBeginInfo, 0, sizeof(rpBeginInfo));
351 rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
352 rpBeginInfo.renderPass = m_window->defaultRenderPass();
353 rpBeginInfo.framebuffer = m_window->currentFramebuffer();
354 rpBeginInfo.clearValueCount = 2;
355 rpBeginInfo.pClearValues = clearValues.data();
356 rpBeginInfo.renderArea.extent.width = static_cast<uint32_t>(size.width());
357 rpBeginInfo.renderArea.extent.height = static_cast<uint32_t>(size.height());
358 m_devFuncs->vkCmdBeginRenderPass(commandbuffer, &rpBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
359}
360
362{
363 if (m_frameStarted)
364 {
365 m_devFuncs->vkCmdEndRenderPass(m_window->currentCommandBuffer());
366 m_window->frameReady();
367 }
368 m_frameStarted = false;
369}
370
372 VkImageLayout OldLayout,
373 VkImageLayout NewLayout,
374 VkCommandBuffer CommandBuffer)
375{
376
377 VkCommandBuffer commandbuffer = CommandBuffer ? CommandBuffer : CreateSingleUseCommandBuffer();
378
379 VkImageMemoryBarrier barrier{};
380 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
381 barrier.oldLayout = OldLayout;
382 barrier.newLayout = NewLayout;
383 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
384 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
385 barrier.image = Image;
386 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
387 barrier.subresourceRange.baseMipLevel = 0;
388 barrier.subresourceRange.levelCount = 1;
389 barrier.subresourceRange.baseArrayLayer = 0;
390 barrier.subresourceRange.layerCount = 1;
391
392 VkPipelineStageFlags sourceStage = 0;
393 VkPipelineStageFlags destinationStage = 0;
394 if (OldLayout == VK_IMAGE_LAYOUT_UNDEFINED && NewLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
395 {
396 barrier.srcAccessMask = 0;
397 barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
398 sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
399 destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
400 }
401 else if (OldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && NewLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
402 {
403 barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
404 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
405 sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
406 destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
407 }
408 else
409 {
410 LOG(VB_GENERAL, LOG_WARNING, LOC + "Unsupported layout transition");
411 }
412
413 m_devFuncs->vkCmdPipelineBarrier(commandbuffer, sourceStage, destinationStage,
414 0, 0, nullptr, 0, nullptr, 1, &barrier);
415 if (!CommandBuffer)
416 FinishSingleUseCommandBuffer(commandbuffer);
417}
418
419void MythRenderVulkan::CopyBufferToImage(VkBuffer Buffer, VkImage Image,
420 uint32_t Width, uint32_t Height,
421 VkCommandBuffer CommandBuffer)
422{
423 VkCommandBuffer commandbuffer = CommandBuffer ? CommandBuffer : CreateSingleUseCommandBuffer();
424 VkBufferImageCopy region { };
425 region.bufferOffset = 0;
426 region.bufferRowLength = 0;
427 region.bufferImageHeight = 0;
428 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
429 region.imageSubresource.mipLevel = 0;
430 region.imageSubresource.baseArrayLayer = 0;
431 region.imageSubresource.layerCount = 1;
432 region.imageOffset = { .x=0, .y=0, .z=0 };
433 region.imageExtent = { .width=Width, .height=Height, .depth=1 };
434 m_devFuncs->vkCmdCopyBufferToImage(commandbuffer, Buffer, Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
435 if (!CommandBuffer)
436 FinishSingleUseCommandBuffer(commandbuffer);
437}
438
439void MythRenderVulkan::CopyBuffer(VkBuffer Src, VkBuffer Dst, VkDeviceSize Size, VkCommandBuffer CommandBuffer)
440{
441 VkBufferCopy region { };
442 region.size = Size;
443
444 if (CommandBuffer)
445 {
446 m_devFuncs->vkCmdCopyBuffer(CommandBuffer, Src, Dst, 1, &region);
447 }
448 else
449 {
450 VkCommandBuffer cmdbuf = CreateSingleUseCommandBuffer();
451 m_devFuncs->vkCmdCopyBuffer(cmdbuf, Src, Dst, 1, &region);
453 }
454}
455
456bool MythRenderVulkan::CreateBuffer(VkDeviceSize Size,
457 VkBufferUsageFlags Usage,
458 VkMemoryPropertyFlags Properties,
459 VkBuffer &Buffer,
460 VkDeviceMemory &Memory)
461{
462 VkBufferCreateInfo bufferInfo { };
463 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
464 bufferInfo.size = Size;
465 bufferInfo.usage = Usage;
466 bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
467
468 if (m_devFuncs->vkCreateBuffer(m_device, &bufferInfo, nullptr, &Buffer) != VK_SUCCESS)
469 {
470 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create buffer");
471 return false;
472 }
473
474 VkMemoryRequirements requirements;
475 m_devFuncs->vkGetBufferMemoryRequirements(m_device, Buffer, &requirements);
476
477 VkMemoryAllocateInfo allocInfo { };
478 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
479 allocInfo.allocationSize = requirements.size;
480 if (auto type = FindMemoryType(requirements.memoryTypeBits, Properties))
481 {
482 allocInfo.memoryTypeIndex = type.value();
483 if (m_devFuncs->vkAllocateMemory(m_device, &allocInfo, nullptr, &Memory) == VK_SUCCESS)
484 {
485 m_devFuncs->vkBindBufferMemory(m_device, Buffer, Memory, 0);
486 return true;
487 }
488 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to allocate buffer memory");
489 }
490 else
491 {
492 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to deduce buffer memory type");
493 }
494
495 m_devFuncs->vkDestroyBuffer(m_device, Buffer, nullptr);
496 return false;
497}
498
499VkSampler MythRenderVulkan::CreateSampler(VkFilter Min, VkFilter Mag)
500{
501 VkSampler result = MYTH_NULL_DISPATCH;
502 VkSamplerCreateInfo samplerinfo { };
503 memset(&samplerinfo, 0, sizeof(samplerinfo));
504 samplerinfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
505 samplerinfo.minFilter = Min;
506 samplerinfo.magFilter = Mag;
507 samplerinfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
508 samplerinfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
509 samplerinfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
510 samplerinfo.anisotropyEnable = VK_FALSE;
511 samplerinfo.maxAnisotropy = 1;
512 samplerinfo.borderColor = VK_BORDER_COLOR_INT_TRANSPARENT_BLACK;
513 samplerinfo.unnormalizedCoordinates = VK_FALSE;
514 samplerinfo.compareEnable = VK_FALSE;
515 samplerinfo.compareOp = VK_COMPARE_OP_ALWAYS;
516 samplerinfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
517 if (m_devFuncs->vkCreateSampler(m_device, &samplerinfo, nullptr, &result) != VK_SUCCESS)
518 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create image sampler");
519 return result;
520}
521
522VkPhysicalDeviceFeatures MythRenderVulkan::GetPhysicalDeviceFeatures() const
523{
524 return m_phyDevFeatures;
525}
526
527VkPhysicalDeviceLimits MythRenderVulkan::GetPhysicalDeviceLimits() const
528{
529 return m_phyDevLimits;
530}
531
532void MythRenderVulkan::BeginDebugRegion(VkCommandBuffer CommandBuffer, const char *Name,
533 const MythVulkan4F Color)
534{
535 if (m_debugMarker && CommandBuffer)
536 m_debugMarker->BeginRegion(CommandBuffer, Name, Color);
537}
538
539void MythRenderVulkan::EndDebugRegion(VkCommandBuffer CommandBuffer)
540{
541 if (m_debugMarker && CommandBuffer)
542 m_debugMarker->EndRegion(CommandBuffer);
543}
544
546 VkFormat Format,
547 VkImageTiling Tiling,
548 VkImageUsageFlags Usage,
549 VkMemoryPropertyFlags Properties,
550 VkImage &Image,
551 VkDeviceMemory &ImageMemory)
552{
553 VkImageCreateInfo imageinfo {
554 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
555 .pNext = nullptr,
556 .flags = static_cast<VkImageCreateFlags>(0),
557 .imageType = VK_IMAGE_TYPE_2D,
558 .format = Format,
559 .extent = {
560 .width = static_cast<uint32_t>(Size.width()),
561 .height = static_cast<uint32_t>(Size.height()),
562 .depth = 1,
563 },
564 .mipLevels = 1,
565 .arrayLayers = 1,
566 .samples = VK_SAMPLE_COUNT_1_BIT,
567 .tiling = Tiling,
568 .usage = Usage,
569 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
570 .queueFamilyIndexCount = 0,
571 .pQueueFamilyIndices = nullptr,
572 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
573 };
574
575 if (m_devFuncs->vkCreateImage(m_device, &imageinfo, nullptr, &Image) != VK_SUCCESS)
576 {
577 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create Vulkan image");
578 return false;
579 }
580
581 VkMemoryRequirements requirements;
582 m_devFuncs->vkGetImageMemoryRequirements(m_device, Image, &requirements);
583
584 VkMemoryAllocateInfo allocinfo { };
585 allocinfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
586 allocinfo.allocationSize = requirements.size;
587 if (auto type = FindMemoryType(requirements.memoryTypeBits, Properties))
588 {
589 allocinfo.memoryTypeIndex = type.value();
590 if (m_devFuncs->vkAllocateMemory(m_device, &allocinfo, nullptr, &ImageMemory) == VK_SUCCESS)
591 {
592 m_devFuncs->vkBindImageMemory(m_device, Image, ImageMemory, 0U);
593 return true;
594 }
595 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to allocate image memory");
596 }
597 else
598 {
599 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to deduce image memory type");
600 }
601
602 m_devFuncs->vkDestroyImage(m_device, Image, nullptr);
603 return false;
604}
605
606std::optional<uint32_t> MythRenderVulkan::FindMemoryType(uint32_t Filter, VkMemoryPropertyFlags Properties)
607{
608 std::optional<uint32_t> result;
609 VkPhysicalDeviceMemoryProperties memoryprops;
610 m_funcs->vkGetPhysicalDeviceMemoryProperties(m_window->physicalDevice(), &memoryprops);
611
612 for (uint32_t i = 0; i < memoryprops.memoryTypeCount; i++)
613 {
614 if ((Filter & (1 << i)) && (memoryprops.memoryTypes[i].propertyFlags & Properties) == Properties)
615 {
616 result = i;
617 break;
618 }
619 }
620
621 return result;
622}
623
625{
626 VkCommandBufferAllocateInfo allocinfo { };
627 allocinfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
628 allocinfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
629 allocinfo.commandPool = m_window->graphicsCommandPool();
630 allocinfo.commandBufferCount = 1;
631 VkCommandBuffer commandbuffer = nullptr;
632 m_devFuncs->vkAllocateCommandBuffers(m_device, &allocinfo, &commandbuffer);
633 VkCommandBufferBeginInfo begininfo { };
634 begininfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
635 begininfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
636 m_devFuncs->vkBeginCommandBuffer(commandbuffer, &begininfo);
637 return commandbuffer;
638}
639
641{
642 m_devFuncs->vkEndCommandBuffer(Buffer);
643 VkSubmitInfo submitinfo{};
644 submitinfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
645 submitinfo.commandBufferCount = 1;
646 submitinfo.pCommandBuffers = &Buffer;
647 m_devFuncs->vkQueueSubmit(m_window->graphicsQueue(), 1, &submitinfo, MYTH_NULL_DISPATCH);
648 m_devFuncs->vkQueueWaitIdle(m_window->graphicsQueue());
649 m_devFuncs->vkFreeCommandBuffers(m_device, m_window->graphicsCommandPool(), 1, &Buffer);
650}
651
653 const QRect Viewport,
654 std::vector<VkDynamicState> Dynamic)
655{
656 if (!(Shader && Viewport.isValid()))
657 return MYTH_NULL_DISPATCH;
658
659 // shaders
660 const auto & shaderstages = Shader->Stages();
661
662 // primitives
663 VkPipelineInputAssemblyStateCreateInfo inputassembly { };
664 inputassembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
665 inputassembly.topology = Shader->GetTopology();
666 inputassembly.primitiveRestartEnable = VK_FALSE;
667
668 // viewport - N.B. static
669 VkViewport viewport { };
670 viewport.x = static_cast<float>(Viewport.left());
671 viewport.y = static_cast<float>(Viewport.left());
672 viewport.width = static_cast<float>(Viewport.width());
673 viewport.height = static_cast<float>(Viewport.height());
674 viewport.minDepth = 0.0F;
675 viewport.maxDepth = 1.0F;
676
677 VkRect2D scissor { };
678 scissor.offset = { .x=Viewport.left(), .y=Viewport.top() };
679 scissor.extent = { .width=static_cast<uint32_t>(Viewport.width()),
680 .height=static_cast<uint32_t>(Viewport.height()) };
681
682 VkPipelineViewportStateCreateInfo viewportstate { };
683 viewportstate.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
684 viewportstate.viewportCount = 1;
685 viewportstate.pViewports = &viewport;
686 viewportstate.scissorCount = 1;
687 viewportstate.pScissors = &scissor;
688
689 // Vertex input - from the shader
690 VkPipelineVertexInputStateCreateInfo vertexinput { };
691 const auto & vertexattribs = Shader->GetVertexAttributes();
692 if (vertexattribs.empty())
693 {
694 vertexinput.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
695 vertexinput.vertexBindingDescriptionCount = 0;
696 vertexinput.pVertexBindingDescriptions = nullptr;
697 vertexinput.vertexAttributeDescriptionCount = 0;
698 vertexinput.pVertexAttributeDescriptions = nullptr;
699 }
700 else
701 {
702 vertexinput.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
703 vertexinput.vertexBindingDescriptionCount = 1;
704 vertexinput.pVertexBindingDescriptions = &Shader->GetVertexBindingDesc();
705 vertexinput.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertexattribs.size());
706 vertexinput.pVertexAttributeDescriptions = vertexattribs.data();
707 }
708
709 // multisampling - no thanks
710 VkPipelineMultisampleStateCreateInfo multisampling {
711 .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
712 .pNext = nullptr,
713 .flags = 0,
714 .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
715 .sampleShadingEnable = VK_FALSE,
716 .minSampleShading = 0.0F,
717 .pSampleMask = nullptr,
718 .alphaToCoverageEnable = VK_FALSE,
719 .alphaToOneEnable = VK_FALSE,
720 };
721
722 // blending - regular alpha blend
723 VkPipelineColorBlendAttachmentState colorblendattachment { };
724 colorblendattachment.blendEnable = VK_TRUE;
725 colorblendattachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
726 colorblendattachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
727 colorblendattachment.colorBlendOp = VK_BLEND_OP_ADD;
728 colorblendattachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
729 colorblendattachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
730 colorblendattachment.alphaBlendOp = VK_BLEND_OP_ADD;
731 colorblendattachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
732 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
733
734 VkPipelineColorBlendStateCreateInfo colorBlending{};
735 colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
736 colorBlending.logicOpEnable = VK_FALSE;
737 colorBlending.logicOp = VK_LOGIC_OP_COPY;
738 colorBlending.attachmentCount = 1;
739 colorBlending.pAttachments = &colorblendattachment;
740 colorBlending.blendConstants[0] = 0.0F;
741 colorBlending.blendConstants[1] = 0.0F;
742 colorBlending.blendConstants[2] = 0.0F;
743 colorBlending.blendConstants[3] = 0.0F;
744
745 // rasterizer
746 VkPipelineRasterizationStateCreateInfo rasterizer { };
747 rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
748 rasterizer.depthClampEnable = VK_FALSE;
749 rasterizer.rasterizerDiscardEnable = VK_FALSE;
750 rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
751 rasterizer.lineWidth = 1.0F;
752 rasterizer.cullMode = VK_CULL_MODE_NONE;
753 rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
754 rasterizer.depthBiasEnable = VK_FALSE;
755
756 // depth/stencil test (required as Qt creates a depth/stencil attachment)
757 VkPipelineDepthStencilStateCreateInfo depthstencil { };
758 depthstencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
759 depthstencil.pNext = nullptr;
760 depthstencil.flags = 0;
761 depthstencil.depthTestEnable = VK_FALSE;
762 depthstencil.depthWriteEnable = VK_FALSE;
763 depthstencil.depthCompareOp = VK_COMPARE_OP_NEVER;
764 depthstencil.depthBoundsTestEnable = VK_FALSE;
765 depthstencil.stencilTestEnable = VK_FALSE;
766 depthstencil.front = { };
767 depthstencil.back = { };
768 depthstencil.minDepthBounds = 0.0F;
769 depthstencil.maxDepthBounds = 1.0F;
770
771 // setup dynamic state
772 VkPipelineDynamicStateCreateInfo dynamic { };
773 dynamic.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
774 dynamic.dynamicStateCount = Dynamic.empty() ? 0 : static_cast<uint32_t>(Dynamic.size());
775 dynamic.pDynamicStates = Dynamic.empty() ? nullptr : Dynamic.data();
776
777 // and breathe
778 VkGraphicsPipelineCreateInfo pipelinecreate { };
779 pipelinecreate.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
780 pipelinecreate.pNext = nullptr;
781 pipelinecreate.flags = 0;
782 pipelinecreate.stageCount = static_cast<uint32_t>(shaderstages.size());
783 pipelinecreate.pStages = shaderstages.data();
784 pipelinecreate.pVertexInputState = &vertexinput;
785 pipelinecreate.pInputAssemblyState = &inputassembly;
786 pipelinecreate.pTessellationState = nullptr;
787 pipelinecreate.pViewportState = &viewportstate;
788 pipelinecreate.pRasterizationState = &rasterizer;
789 pipelinecreate.pMultisampleState = &multisampling;
790 pipelinecreate.pDepthStencilState = &depthstencil;
791 pipelinecreate.pColorBlendState = &colorBlending;
792 pipelinecreate.pDynamicState = &dynamic;
793 pipelinecreate.layout = Shader->GetPipelineLayout();
794 pipelinecreate.renderPass = m_window->defaultRenderPass();
795 pipelinecreate.subpass = 0;
796 pipelinecreate.basePipelineHandle = MYTH_NULL_DISPATCH;
797 pipelinecreate.basePipelineIndex = 0;
798
799 VkPipeline result = MYTH_NULL_DISPATCH;
800 if (m_devFuncs->vkCreateGraphicsPipelines(m_device, MYTH_NULL_DISPATCH, 1, &pipelinecreate, nullptr, &result) == VK_SUCCESS)
801 return result;
802
803 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create graphics pipeline");
804 return MYTH_NULL_DISPATCH;
805}
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