1/****************************************************************************
2**
3** Copyright (C) 2019 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the demonstration applications of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:BSD$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** BSD License Usage
18** Alternatively, you may use this file under the terms of the BSD license
19** as follows:
20**
21** "Redistribution and use in source and binary forms, with or without
22** modification, are permitted provided that the following conditions are
23** met:
24** * Redistributions of source code must retain the above copyright
25** notice, this list of conditions and the following disclaimer.
26** * Redistributions in binary form must reproduce the above copyright
27** notice, this list of conditions and the following disclaimer in
28** the documentation and/or other materials provided with the
29** distribution.
30** * Neither the name of The Qt Company Ltd nor the names of its
31** contributors may be used to endorse or promote products derived
32** from this software without specific prior written permission.
33**
34**
35** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46**
47** $QT_END_LICENSE$
48**
49****************************************************************************/
50
51#include "vulkantextureimport.h"
52
53#include <QtGui/QScreen>
54#include <QtQuick/QQuickWindow>
55#include <QtQuick/QSGTextureProvider>
56#include <QtQuick/QSGSimpleTextureNode>
57
58#include <QVulkanInstance>
59#include <QVulkanFunctions>
60
61class CustomTextureNode : public QSGTextureProvider, public QSGSimpleTextureNode
62{
63 Q_OBJECT
64
65public:
66 CustomTextureNode(QQuickItem *item);
67 ~CustomTextureNode() override;
68
69 QSGTexture *texture() const override;
70
71 void sync();
72
73private slots:
74 void render();
75
76private:
77 enum Stage {
78 VertexStage,
79 FragmentStage
80 };
81 void prepareShader(Stage stage);
82 bool buildTexture(const QSize &size);
83 void freeTexture();
84 bool createRenderPass();
85 bool initialize();
86
87 QQuickItem *m_item;
88 QQuickWindow *m_window;
89 QSize m_size;
90 qreal m_dpr;
91
92 QByteArray m_vert;
93 QByteArray m_frag;
94
95 VkImage m_texture = VK_NULL_HANDLE;
96 VkDeviceMemory m_textureMemory = VK_NULL_HANDLE;
97 VkFramebuffer m_textureFramebuffer = VK_NULL_HANDLE;
98 VkImageView m_textureView = VK_NULL_HANDLE;
99
100 bool m_initialized = false;
101
102 float m_t;
103
104 VkPhysicalDevice m_physDev = VK_NULL_HANDLE;
105 VkDevice m_dev = VK_NULL_HANDLE;
106 QVulkanDeviceFunctions *m_devFuncs = nullptr;
107 QVulkanFunctions *m_funcs = nullptr;
108
109 VkBuffer m_vbuf = VK_NULL_HANDLE;
110 VkDeviceMemory m_vbufMem = VK_NULL_HANDLE;
111 VkBuffer m_ubuf = VK_NULL_HANDLE;
112 VkDeviceMemory m_ubufMem = VK_NULL_HANDLE;
113 VkDeviceSize m_allocPerUbuf = 0;
114
115 VkPipelineCache m_pipelineCache = VK_NULL_HANDLE;
116
117 VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE;
118 VkDescriptorSetLayout m_resLayout = VK_NULL_HANDLE;
119 VkPipeline m_pipeline = VK_NULL_HANDLE;
120
121 VkDescriptorPool m_descriptorPool = VK_NULL_HANDLE;
122 VkDescriptorSet m_ubufDescriptor = VK_NULL_HANDLE;
123
124 VkRenderPass m_renderPass = VK_NULL_HANDLE;
125};
126
127CustomTextureItem::CustomTextureItem()
128{
129 setFlag(flag: ItemHasContents, enabled: true);
130}
131
132void CustomTextureItem::invalidateSceneGraph() // called on the render thread when the scenegraph is invalidated
133{
134 m_node = nullptr;
135}
136
137void CustomTextureItem::releaseResources() // called on the gui thread if the item is removed from scene
138{
139 m_node = nullptr;
140}
141
142QSGNode *CustomTextureItem::updatePaintNode(QSGNode *node, UpdatePaintNodeData *)
143{
144 CustomTextureNode *n = static_cast<CustomTextureNode *>(node);
145
146 if (!n && (width() <= 0 || height() <= 0))
147 return nullptr;
148
149 if (!n) {
150 m_node = new CustomTextureNode(this);
151 n = m_node;
152 }
153
154 m_node->sync();
155
156 n->setTextureCoordinatesTransform(QSGSimpleTextureNode::NoTransform);
157 n->setFiltering(QSGTexture::Linear);
158 n->setRect(x: 0, y: 0, w: width(), h: height());
159
160 window()->update(); // ensure getting to beforeRendering() at some point
161
162 return n;
163}
164
165void CustomTextureItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
166{
167 QQuickItem::geometryChanged(newGeometry, oldGeometry);
168
169 if (newGeometry.size() != oldGeometry.size())
170 update();
171}
172
173void CustomTextureItem::setT(qreal t)
174{
175 if (t == m_t)
176 return;
177
178 m_t = t;
179 emit tChanged();
180
181 update();
182}
183
184CustomTextureNode::CustomTextureNode(QQuickItem *item)
185 : m_item(item)
186{
187 m_window = m_item->window();
188 connect(sender: m_window, signal: &QQuickWindow::beforeRendering, receiver: this, slot: &CustomTextureNode::render);
189 connect(sender: m_window, signal: &QQuickWindow::screenChanged, context: this, slot: [this]() {
190 if (m_window->effectiveDevicePixelRatio() != m_dpr)
191 m_item->update();
192 });
193}
194
195CustomTextureNode::~CustomTextureNode()
196{
197 m_devFuncs->vkDestroyBuffer(m_dev, m_vbuf, nullptr);
198 m_devFuncs->vkDestroyBuffer(m_dev, m_ubuf, nullptr);
199 m_devFuncs->vkFreeMemory(m_dev, m_vbufMem, nullptr);
200 m_devFuncs->vkFreeMemory(m_dev, m_ubufMem, nullptr);
201
202 m_devFuncs->vkDestroyPipelineCache(m_dev, m_pipelineCache, nullptr);
203 m_devFuncs->vkDestroyPipelineLayout(m_dev, m_pipelineLayout, nullptr);
204 m_devFuncs->vkDestroyPipeline(m_dev, m_pipeline, nullptr);
205
206 m_devFuncs->vkDestroyRenderPass(m_dev, m_renderPass, nullptr);
207
208 m_devFuncs->vkDestroyDescriptorSetLayout(m_dev, m_resLayout, nullptr);
209 m_devFuncs->vkDestroyDescriptorPool(m_dev, m_descriptorPool, nullptr);
210
211 delete texture();
212 freeTexture();
213}
214
215QSGTexture *CustomTextureNode::texture() const
216{
217 return QSGSimpleTextureNode::texture();
218}
219
220static const float vertices[] = {
221 -1, -1,
222 1, -1,
223 -1, 1,
224 1, 1
225};
226
227const int UBUF_SIZE = 4;
228
229
230bool CustomTextureNode::buildTexture(const QSize &size)
231{
232 VkImageCreateInfo imageInfo;
233 memset(s: &imageInfo, c: 0, n: sizeof(imageInfo));
234 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
235 imageInfo.flags = 0;
236 imageInfo.imageType = VK_IMAGE_TYPE_2D;
237 imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
238 imageInfo.extent.width = uint32_t(size.width());
239 imageInfo.extent.height = uint32_t(size.height());
240 imageInfo.extent.depth = 1;
241 imageInfo.mipLevels = 1;
242 imageInfo.arrayLayers = 1;
243 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
244 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
245 imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
246
247 imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
248 imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
249
250 VkImage image = VK_NULL_HANDLE;
251 if (m_devFuncs->vkCreateImage(m_dev, &imageInfo, nullptr, &image) != VK_SUCCESS) {
252 qCritical(msg: "VulkanWrapper: failed to create image!");
253 return false;
254 }
255
256 m_texture = image;
257
258 VkMemoryRequirements memReq;
259 m_devFuncs->vkGetImageMemoryRequirements(m_dev, image, &memReq);
260
261 quint32 memIndex = 0;
262 VkPhysicalDeviceMemoryProperties physDevMemProps;
263 m_window->vulkanInstance()->functions()->vkGetPhysicalDeviceMemoryProperties(m_physDev, &physDevMemProps);
264 for (uint32_t i = 0; i < physDevMemProps.memoryTypeCount; ++i) {
265 if (!(memReq.memoryTypeBits & (1 << i)))
266 continue;
267 memIndex = i;
268 }
269
270 VkMemoryAllocateInfo allocInfo = {
271 .sType: VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
272 .pNext: nullptr,
273 .allocationSize: memReq.size,
274 .memoryTypeIndex: memIndex
275 };
276
277 VkResult err = m_devFuncs->vkAllocateMemory(m_dev, &allocInfo, nullptr, &m_textureMemory);
278 if (err != VK_SUCCESS) {
279 qWarning(msg: "Failed to allocate memory for linear image: %d", err);
280 return false;
281 }
282
283 err = m_devFuncs->vkBindImageMemory(m_dev, image, m_textureMemory, 0);
284 if (err != VK_SUCCESS) {
285 qWarning(msg: "Failed to bind linear image memory: %d", err);
286 return false;
287 }
288
289 VkImageViewCreateInfo viewInfo;
290 memset(s: &viewInfo, c: 0, n: sizeof(viewInfo));
291 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
292 viewInfo.image = image;
293 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
294 viewInfo.format = imageInfo.format;
295 viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
296 viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
297 viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
298 viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
299 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
300 viewInfo.subresourceRange.baseMipLevel = 0;
301 viewInfo.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
302 viewInfo.subresourceRange.baseArrayLayer = 0;
303 viewInfo.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
304
305 err = m_devFuncs->vkCreateImageView(m_dev, &viewInfo, nullptr, &m_textureView);
306 if (err != VK_SUCCESS) {
307 qWarning(msg: "Failed to create render target image view: %d", err);
308 return false;
309 }
310
311 VkFramebufferCreateInfo fbInfo;
312 memset(s: &fbInfo, c: 0, n: sizeof(fbInfo));
313 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
314 fbInfo.renderPass = m_renderPass;
315 fbInfo.attachmentCount = 1;
316 fbInfo.pAttachments = &m_textureView;
317 fbInfo.width = uint32_t(size.width());
318 fbInfo.height = uint32_t(size.height());
319 fbInfo.layers = 1;
320
321 err = m_devFuncs->vkCreateFramebuffer(m_dev, &fbInfo, nullptr, &m_textureFramebuffer);
322 if (err != VK_SUCCESS) {
323 qWarning(msg: "Failed to create framebuffer: %d", err);
324 return false;
325 }
326 return true;
327}
328
329void CustomTextureNode::freeTexture()
330{
331 if (m_texture) {
332 m_devFuncs->vkDestroyFramebuffer(m_dev, m_textureFramebuffer, nullptr);
333 m_textureFramebuffer = VK_NULL_HANDLE;
334 m_devFuncs->vkFreeMemory(m_dev, m_textureMemory, nullptr);
335 m_textureMemory = VK_NULL_HANDLE;
336 m_devFuncs->vkDestroyImageView(m_dev, m_textureView, nullptr);
337 m_textureView = VK_NULL_HANDLE;
338 m_devFuncs->vkDestroyImage(m_dev, m_texture, nullptr);
339 m_texture = VK_NULL_HANDLE;
340 }
341}
342
343
344
345static inline VkDeviceSize aligned(VkDeviceSize v, VkDeviceSize byteAlign)
346{
347 return (v + byteAlign - 1) & ~(byteAlign - 1);
348}
349
350bool CustomTextureNode::createRenderPass()
351{
352 const VkFormat vkformat = VK_FORMAT_R8G8B8A8_UNORM;
353 const VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT;
354 VkAttachmentDescription colorAttDesc;
355 memset(s: &colorAttDesc, c: 0, n: sizeof(colorAttDesc));
356 colorAttDesc.format = vkformat;
357 colorAttDesc.samples = samples;
358 colorAttDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
359 colorAttDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
360 colorAttDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
361 colorAttDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
362 colorAttDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
363 colorAttDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
364
365 const VkAttachmentReference colorRef = { .attachment: 0, .layout: VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
366
367 VkSubpassDescription subpassDesc;
368 memset(s: &subpassDesc, c: 0, n: sizeof(subpassDesc));
369 subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
370 subpassDesc.colorAttachmentCount = 1;
371 subpassDesc.pColorAttachments = &colorRef;
372 subpassDesc.pDepthStencilAttachment = nullptr;
373 subpassDesc.pResolveAttachments = nullptr;
374
375 VkRenderPassCreateInfo rpInfo;
376 memset(s: &rpInfo, c: 0, n: sizeof(rpInfo));
377 rpInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
378 rpInfo.attachmentCount = 1;
379 rpInfo.pAttachments = &colorAttDesc;
380 rpInfo.subpassCount = 1;
381 rpInfo.pSubpasses = &subpassDesc;
382
383 VkResult err = m_devFuncs->vkCreateRenderPass(m_dev, &rpInfo, nullptr, &m_renderPass);
384 if (err != VK_SUCCESS) {
385 qWarning(msg: "Failed to create renderpass: %d", err);
386 return false;
387 }
388
389 return true;
390}
391
392bool CustomTextureNode::initialize()
393{
394 const int framesInFlight = m_window->graphicsStateInfo().framesInFlight;
395 m_initialized = true;
396
397 QSGRendererInterface *rif = m_window->rendererInterface();
398 QVulkanInstance *inst = reinterpret_cast<QVulkanInstance *>(
399 rif->getResource(window: m_window, resource: QSGRendererInterface::VulkanInstanceResource));
400 Q_ASSERT(inst && inst->isValid());
401
402 m_physDev = *static_cast<VkPhysicalDevice *>(rif->getResource(window: m_window, resource: QSGRendererInterface::PhysicalDeviceResource));
403 m_dev = *static_cast<VkDevice *>(rif->getResource(window: m_window, resource: QSGRendererInterface::DeviceResource));
404 Q_ASSERT(m_physDev && m_dev);
405
406 m_devFuncs = inst->deviceFunctions(device: m_dev);
407 m_funcs = inst->functions();
408 Q_ASSERT(m_devFuncs && m_funcs);
409
410 createRenderPass();
411
412 VkPhysicalDeviceProperties physDevProps;
413 m_funcs->vkGetPhysicalDeviceProperties(m_physDev, &physDevProps);
414
415 VkPhysicalDeviceMemoryProperties physDevMemProps;
416 m_funcs->vkGetPhysicalDeviceMemoryProperties(m_physDev, &physDevMemProps);
417
418 VkBufferCreateInfo bufferInfo;
419 memset(s: &bufferInfo, c: 0, n: sizeof(bufferInfo));
420 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
421 bufferInfo.size = sizeof(vertices);
422 bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
423 VkResult err = m_devFuncs->vkCreateBuffer(m_dev, &bufferInfo, nullptr, &m_vbuf);
424 if (err != VK_SUCCESS)
425 qFatal(msg: "Failed to create vertex buffer: %d", err);
426
427 VkMemoryRequirements memReq;
428 m_devFuncs->vkGetBufferMemoryRequirements(m_dev, m_vbuf, &memReq);
429 VkMemoryAllocateInfo allocInfo;
430 memset(s: &allocInfo, c: 0, n: sizeof(allocInfo));
431 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
432 allocInfo.allocationSize = memReq.size;
433
434 uint32_t memTypeIndex = uint32_t(-1);
435 const VkMemoryType *memType = physDevMemProps.memoryTypes;
436 for (uint32_t i = 0; i < physDevMemProps.memoryTypeCount; ++i) {
437 if (memReq.memoryTypeBits & (1 << i)) {
438 if ((memType[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
439 && (memType[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
440 {
441 memTypeIndex = i;
442 break;
443 }
444 }
445 }
446 if (memTypeIndex == uint32_t(-1))
447 qFatal(msg: "Failed to find host visible and coherent memory type");
448
449 allocInfo.memoryTypeIndex = memTypeIndex;
450 err = m_devFuncs->vkAllocateMemory(m_dev, &allocInfo, nullptr, &m_vbufMem);
451 if (err != VK_SUCCESS)
452 qFatal(msg: "Failed to allocate vertex buffer memory of size %u: %d", uint(allocInfo.allocationSize), err);
453
454 void *p = nullptr;
455 err = m_devFuncs->vkMapMemory(m_dev, m_vbufMem, 0, allocInfo.allocationSize, 0, &p);
456 if (err != VK_SUCCESS || !p)
457 qFatal(msg: "Failed to map vertex buffer memory: %d", err);
458 memcpy(dest: p, src: vertices, n: sizeof(vertices));
459 m_devFuncs->vkUnmapMemory(m_dev, m_vbufMem);
460 err = m_devFuncs->vkBindBufferMemory(m_dev, m_vbuf, m_vbufMem, 0);
461 if (err != VK_SUCCESS)
462 qFatal(msg: "Failed to bind vertex buffer memory: %d", err);
463
464 m_allocPerUbuf = aligned(v: UBUF_SIZE, byteAlign: physDevProps.limits.minUniformBufferOffsetAlignment);
465
466 bufferInfo.size = framesInFlight * m_allocPerUbuf;
467 bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
468 err = m_devFuncs->vkCreateBuffer(m_dev, &bufferInfo, nullptr, &m_ubuf);
469 if (err != VK_SUCCESS)
470 qFatal(msg: "Failed to create uniform buffer: %d", err);
471 m_devFuncs->vkGetBufferMemoryRequirements(m_dev, m_ubuf, &memReq);
472 memTypeIndex = -1;
473 for (uint32_t i = 0; i < physDevMemProps.memoryTypeCount; ++i) {
474 if (memReq.memoryTypeBits & (1 << i)) {
475 if ((memType[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
476 && (memType[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
477 {
478 memTypeIndex = i;
479 break;
480 }
481 }
482 }
483 if (memTypeIndex == uint32_t(-1))
484 qFatal(msg: "Failed to find host visible and coherent memory type");
485
486 allocInfo.allocationSize = qMax(a: memReq.size, b: framesInFlight * m_allocPerUbuf);
487 allocInfo.memoryTypeIndex = memTypeIndex;
488 err = m_devFuncs->vkAllocateMemory(m_dev, &allocInfo, nullptr, &m_ubufMem);
489 if (err != VK_SUCCESS)
490 qFatal(msg: "Failed to allocate uniform buffer memory of size %u: %d", uint(allocInfo.allocationSize), err);
491
492 err = m_devFuncs->vkBindBufferMemory(m_dev, m_ubuf, m_ubufMem, 0);
493 if (err != VK_SUCCESS)
494 qFatal(msg: "Failed to bind uniform buffer memory: %d", err);
495
496 // Now onto the pipeline.
497
498 VkPipelineCacheCreateInfo pipelineCacheInfo;
499 memset(s: &pipelineCacheInfo, c: 0, n: sizeof(pipelineCacheInfo));
500 pipelineCacheInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
501 err = m_devFuncs->vkCreatePipelineCache(m_dev, &pipelineCacheInfo, nullptr, &m_pipelineCache);
502 if (err != VK_SUCCESS)
503 qFatal(msg: "Failed to create pipeline cache: %d", err);
504
505 VkDescriptorSetLayoutBinding descLayoutBinding;
506 memset(s: &descLayoutBinding, c: 0, n: sizeof(descLayoutBinding));
507 descLayoutBinding.binding = 0;
508 descLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
509 descLayoutBinding.descriptorCount = 1;
510 descLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
511 VkDescriptorSetLayoutCreateInfo layoutInfo;
512 memset(s: &layoutInfo, c: 0, n: sizeof(layoutInfo));
513 layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
514 layoutInfo.bindingCount = 1;
515 layoutInfo.pBindings = &descLayoutBinding;
516 err = m_devFuncs->vkCreateDescriptorSetLayout(m_dev, &layoutInfo, nullptr, &m_resLayout);
517 if (err != VK_SUCCESS)
518 qFatal(msg: "Failed to create descriptor set layout: %d", err);
519
520 VkPipelineLayoutCreateInfo pipelineLayoutInfo;
521 memset(s: &pipelineLayoutInfo, c: 0, n: sizeof(pipelineLayoutInfo));
522 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
523 pipelineLayoutInfo.setLayoutCount = 1;
524 pipelineLayoutInfo.pSetLayouts = &m_resLayout;
525 err = m_devFuncs->vkCreatePipelineLayout(m_dev, &pipelineLayoutInfo, nullptr, &m_pipelineLayout);
526 if (err != VK_SUCCESS)
527 qWarning(msg: "Failed to create pipeline layout: %d", err);
528
529 VkGraphicsPipelineCreateInfo pipelineInfo;
530 memset(s: &pipelineInfo, c: 0, n: sizeof(pipelineInfo));
531 pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
532
533 VkShaderModuleCreateInfo shaderInfo;
534 memset(s: &shaderInfo, c: 0, n: sizeof(shaderInfo));
535 shaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
536 shaderInfo.codeSize = m_vert.size();
537 shaderInfo.pCode = reinterpret_cast<const quint32 *>(m_vert.constData());
538 VkShaderModule vertShaderModule;
539 err = m_devFuncs->vkCreateShaderModule(m_dev, &shaderInfo, nullptr, &vertShaderModule);
540 if (err != VK_SUCCESS)
541 qFatal(msg: "Failed to create vertex shader module: %d", err);
542
543 shaderInfo.codeSize = m_frag.size();
544 shaderInfo.pCode = reinterpret_cast<const quint32 *>(m_frag.constData());
545 VkShaderModule fragShaderModule;
546 err = m_devFuncs->vkCreateShaderModule(m_dev, &shaderInfo, nullptr, &fragShaderModule);
547 if (err != VK_SUCCESS)
548 qFatal(msg: "Failed to create fragment shader module: %d", err);
549
550 VkPipelineShaderStageCreateInfo stageInfo[2];
551 memset(s: &stageInfo, c: 0, n: sizeof(stageInfo));
552 stageInfo[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
553 stageInfo[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
554 stageInfo[0].module = vertShaderModule;
555 stageInfo[0].pName = "main";
556 stageInfo[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
557 stageInfo[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
558 stageInfo[1].module = fragShaderModule;
559 stageInfo[1].pName = "main";
560 pipelineInfo.stageCount = 2;
561 pipelineInfo.pStages = stageInfo;
562
563 VkVertexInputBindingDescription vertexBinding = {
564 .binding: 0, // binding
565 .stride: 2 * sizeof(float), // stride
566 .inputRate: VK_VERTEX_INPUT_RATE_VERTEX
567 };
568 VkVertexInputAttributeDescription vertexAttr = {
569 .location: 0, // location
570 .binding: 0, // binding
571 .format: VK_FORMAT_R32G32_SFLOAT, // 'vertices' only has 2 floats per vertex
572 .offset: 0 // offset
573 };
574 VkPipelineVertexInputStateCreateInfo vertexInputInfo;
575 memset(s: &vertexInputInfo, c: 0, n: sizeof(vertexInputInfo));
576 vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
577 vertexInputInfo.vertexBindingDescriptionCount = 1;
578 vertexInputInfo.pVertexBindingDescriptions = &vertexBinding;
579 vertexInputInfo.vertexAttributeDescriptionCount = 1;
580 vertexInputInfo.pVertexAttributeDescriptions = &vertexAttr;
581 pipelineInfo.pVertexInputState = &vertexInputInfo;
582
583 VkDynamicState dynStates[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
584 VkPipelineDynamicStateCreateInfo dynamicInfo;
585 memset(s: &dynamicInfo, c: 0, n: sizeof(dynamicInfo));
586 dynamicInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
587 dynamicInfo.dynamicStateCount = 2;
588 dynamicInfo.pDynamicStates = dynStates;
589 pipelineInfo.pDynamicState = &dynamicInfo;
590
591 VkPipelineViewportStateCreateInfo viewportInfo;
592 memset(s: &viewportInfo, c: 0, n: sizeof(viewportInfo));
593 viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
594 viewportInfo.viewportCount = viewportInfo.scissorCount = 1;
595 pipelineInfo.pViewportState = &viewportInfo;
596
597 VkPipelineInputAssemblyStateCreateInfo iaInfo;
598 memset(s: &iaInfo, c: 0, n: sizeof(iaInfo));
599 iaInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
600 iaInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
601 pipelineInfo.pInputAssemblyState = &iaInfo;
602
603 VkPipelineRasterizationStateCreateInfo rsInfo;
604 memset(s: &rsInfo, c: 0, n: sizeof(rsInfo));
605 rsInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
606 rsInfo.lineWidth = 1.0f;
607 pipelineInfo.pRasterizationState = &rsInfo;
608
609 VkPipelineMultisampleStateCreateInfo msInfo;
610 memset(s: &msInfo, c: 0, n: sizeof(msInfo));
611 msInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
612 msInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
613 pipelineInfo.pMultisampleState = &msInfo;
614
615 VkPipelineDepthStencilStateCreateInfo dsInfo;
616 memset(s: &dsInfo, c: 0, n: sizeof(dsInfo));
617 dsInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
618 pipelineInfo.pDepthStencilState = &dsInfo;
619
620 // SrcAlpha, One
621 VkPipelineColorBlendStateCreateInfo blendInfo;
622 memset(s: &blendInfo, c: 0, n: sizeof(blendInfo));
623 blendInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
624 VkPipelineColorBlendAttachmentState blend;
625 memset(s: &blend, c: 0, n: sizeof(blend));
626 blend.blendEnable = true;
627 blend.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
628 blend.dstColorBlendFactor = VK_BLEND_FACTOR_ONE;
629 blend.colorBlendOp = VK_BLEND_OP_ADD;
630 blend.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
631 blend.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
632 blend.alphaBlendOp = VK_BLEND_OP_ADD;
633 blend.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT
634 | VK_COLOR_COMPONENT_A_BIT;
635 blendInfo.attachmentCount = 1;
636 blendInfo.pAttachments = &blend;
637 pipelineInfo.pColorBlendState = &blendInfo;
638
639 pipelineInfo.layout = m_pipelineLayout;
640
641 pipelineInfo.renderPass = m_renderPass;
642
643 err = m_devFuncs->vkCreateGraphicsPipelines(m_dev, m_pipelineCache, 1, &pipelineInfo, nullptr, &m_pipeline);
644
645 m_devFuncs->vkDestroyShaderModule(m_dev, vertShaderModule, nullptr);
646 m_devFuncs->vkDestroyShaderModule(m_dev, fragShaderModule, nullptr);
647
648 if (err != VK_SUCCESS)
649 qFatal(msg: "Failed to create graphics pipeline: %d", err);
650
651 // Now just need some descriptors.
652 VkDescriptorPoolSize descPoolSizes[] = {
653 { .type: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, .descriptorCount: 1 }
654 };
655 VkDescriptorPoolCreateInfo descPoolInfo;
656 memset(s: &descPoolInfo, c: 0, n: sizeof(descPoolInfo));
657 descPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
658 descPoolInfo.flags = 0; // won't use vkFreeDescriptorSets
659 descPoolInfo.maxSets = 1;
660 descPoolInfo.poolSizeCount = sizeof(descPoolSizes) / sizeof(descPoolSizes[0]);
661 descPoolInfo.pPoolSizes = descPoolSizes;
662 err = m_devFuncs->vkCreateDescriptorPool(m_dev, &descPoolInfo, nullptr, &m_descriptorPool);
663 if (err != VK_SUCCESS)
664 qFatal(msg: "Failed to create descriptor pool: %d", err);
665
666 VkDescriptorSetAllocateInfo descAllocInfo;
667 memset(s: &descAllocInfo, c: 0, n: sizeof(descAllocInfo));
668 descAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
669 descAllocInfo.descriptorPool = m_descriptorPool;
670 descAllocInfo.descriptorSetCount = 1;
671 descAllocInfo.pSetLayouts = &m_resLayout;
672 err = m_devFuncs->vkAllocateDescriptorSets(m_dev, &descAllocInfo, &m_ubufDescriptor);
673 if (err != VK_SUCCESS)
674 qFatal(msg: "Failed to allocate descriptor set");
675
676 VkWriteDescriptorSet writeInfo;
677 memset(s: &writeInfo, c: 0, n: sizeof(writeInfo));
678 writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
679 writeInfo.dstSet = m_ubufDescriptor;
680 writeInfo.dstBinding = 0;
681 writeInfo.descriptorCount = 1;
682 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
683 VkDescriptorBufferInfo bufInfo;
684 bufInfo.buffer = m_ubuf;
685 bufInfo.offset = 0; // dynamic offset is used so this is ignored
686 bufInfo.range = UBUF_SIZE;
687 writeInfo.pBufferInfo = &bufInfo;
688
689 m_devFuncs->vkUpdateDescriptorSets(m_dev, 1, &writeInfo, 0, nullptr);
690 return true;
691}
692
693void CustomTextureNode::sync()
694{
695 m_dpr = m_window->effectiveDevicePixelRatio();
696 const QSize newSize = m_window->size() * m_dpr;
697 bool needsNew = false;
698
699 if (!m_initialized) {
700 prepareShader(stage: VertexStage);
701 prepareShader(stage: FragmentStage);
702 initialize();
703 m_initialized = true;
704 }
705
706 if (!texture())
707 needsNew = true;
708
709 if (newSize != m_size) {
710 needsNew = true;
711 m_size = newSize;
712 }
713
714 if (needsNew) {
715 delete texture();
716 freeTexture();
717 buildTexture(size: m_size);
718 QSGTexture *wrapper = m_window->createTextureFromNativeObject(type: QQuickWindow::NativeObjectTexture,
719 nativeObjectPtr: &m_texture,
720 nativeLayout: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
721 size: m_size);
722 setTexture(wrapper);
723 }
724
725 m_t = float(static_cast<CustomTextureItem *>(m_item)->t());
726}
727
728void CustomTextureNode::render()
729{
730 if (!m_initialized)
731 return;
732
733 VkResult err = VK_SUCCESS;
734
735 uint currentFrameSlot = m_window->graphicsStateInfo().currentFrameSlot;
736 VkDeviceSize ubufOffset = currentFrameSlot * m_allocPerUbuf;
737 void *p = nullptr;
738 err = m_devFuncs->vkMapMemory(m_dev, m_ubufMem, ubufOffset, m_allocPerUbuf, 0, &p);
739 if (err != VK_SUCCESS || !p)
740 qFatal(msg: "Failed to map uniform buffer memory: %d", err);
741 float t = m_t;
742 memcpy(dest: p, src: &t, n: 4);
743 m_devFuncs->vkUnmapMemory(m_dev, m_ubufMem);
744
745 VkClearValue clearColor = {.color: { .float32: {0, 0, 0, 1} }};
746
747 VkRenderPassBeginInfo rpBeginInfo = {};
748 rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
749 rpBeginInfo.renderPass = m_renderPass;
750 rpBeginInfo.framebuffer = m_textureFramebuffer;
751 rpBeginInfo.renderArea.extent.width = m_size.width();
752 rpBeginInfo.renderArea.extent.height = m_size.height();
753 rpBeginInfo.clearValueCount = 1;
754 rpBeginInfo.pClearValues = &clearColor;
755
756 QSGRendererInterface *rif = m_window->rendererInterface();
757 VkCommandBuffer cmdBuf = *reinterpret_cast<VkCommandBuffer *>(
758 rif->getResource(window: m_window, resource: QSGRendererInterface::CommandListResource));
759
760 m_devFuncs->vkCmdBeginRenderPass(cmdBuf, &rpBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
761
762 m_devFuncs->vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline);
763
764 VkDeviceSize vbufOffset = 0;
765 m_devFuncs->vkCmdBindVertexBuffers(cmdBuf, 0, 1, &m_vbuf, &vbufOffset);
766
767 uint32_t dynamicOffset = m_allocPerUbuf * currentFrameSlot;
768 m_devFuncs->vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1,
769 &m_ubufDescriptor, 1, &dynamicOffset);
770
771 VkViewport vp = { .x: 0, .y: 0, .width: float(m_size.width()), .height: float(m_size.height()), .minDepth: 0.0f, .maxDepth: 1.0f };
772 m_devFuncs->vkCmdSetViewport(cmdBuf, 0, 1, &vp);
773 VkRect2D scissor = { .offset: { .x: 0, .y: 0 }, .extent: { .width: uint32_t(m_size.width()), .height: uint32_t(m_size.height()) } };
774 m_devFuncs->vkCmdSetScissor(cmdBuf, 0, 1, &scissor);
775
776 m_devFuncs->vkCmdDraw(cmdBuf, 4, 1, 0, 0);
777 m_devFuncs->vkCmdEndRenderPass(cmdBuf);
778
779 // Memory barrier before the texture can be used as a source.
780 // Since we are not using a sub-pass, we have to do this explicitly.
781
782 VkImageMemoryBarrier imageTransitionBarrier = {};
783 imageTransitionBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
784 imageTransitionBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
785 imageTransitionBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
786 imageTransitionBarrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
787 imageTransitionBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
788 imageTransitionBarrier.image = m_texture;
789 imageTransitionBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
790 imageTransitionBarrier.subresourceRange.levelCount = imageTransitionBarrier.subresourceRange.layerCount = 1;
791
792 m_devFuncs->vkCmdPipelineBarrier(cmdBuf,
793 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
794 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
795 0, 0, nullptr, 0, nullptr,
796 1, &imageTransitionBarrier);
797}
798
799void CustomTextureNode::prepareShader(Stage stage)
800{
801 QString filename;
802 if (stage == VertexStage) {
803 filename = QLatin1String(":/scenegraph/vulkantextureimport/squircle.vert.spv");
804 } else {
805 Q_ASSERT(stage == FragmentStage);
806 filename = QLatin1String(":/scenegraph/vulkantextureimport/squircle.frag.spv");
807 }
808 QFile f(filename);
809 if (!f.open(flags: QIODevice::ReadOnly))
810 qFatal(msg: "Failed to read shader %s", qPrintable(filename));
811
812 const QByteArray contents = f.readAll();
813
814 if (stage == VertexStage) {
815 m_vert = contents;
816 Q_ASSERT(!m_vert.isEmpty());
817 } else {
818 m_frag = contents;
819 Q_ASSERT(!m_frag.isEmpty());
820 }
821}
822
823#include "vulkantextureimport.moc"
824

source code of qtdeclarative/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.cpp