Vulkan With QtQuick Lab

include

QVulkanApp.h

#ifndef Q_VULKANAPP_H
#define Q_VULKANAPP_H

#include <QQuickItem>
#include <QQuickWindow>

#define RESOURCE
#define FUNCTION
#define Q_RESOURCE

class VkRenderer;

class QVulkanApp : public QQuickItem {
    Q_OBJECT
public:
    QVulkanApp();
    
public slots:
    void sync();
    void cleanup();
    
private slots:
    void slotWindowChanged(QQuickWindow*);
    
private RESOURCE:
    VkRenderer* _renderer = nullptr;
    
private FUNCTION:
    void freeResource();
    
};

#endif


VkRenderer.h

#ifndef VKRENDERER_H
#define VKRENDERER_H

#include <QRunnable>
#include <QQuickWindow>
#include <QVulkanInstance>
#include <QVulkanFunctions>
#include <QSGRendererInterface>

#define RESOURCE
#define FUNCTION
#define Q_RESOURCE

#define _DEBUG

class QVulkanApp;

class VkRenderer: public QObject {
    Q_OBJECT friend QVulkanApp;
public:
        VkRenderer() = default;
    virtual 
        ~VkRenderer();
    
public slots:
    void slotRenderStart();
    void slotRenderPassRecStart();
    
public FUNCTION:
    void setWindow(QQuickWindow* window)    {_window = window;}
    void setViewportSize(const QSize &size) {_viewportSize = size;}
    void setExtentWidth(const uint32_t w)   {_swapChainExtent.width = w;}
    void setExtentHeight(const uint32_t h)  {_swapChainExtent.height = h;}
    
private Q_RESOURCE:
    QQuickWindow* 
        _window     = nullptr;
    QVulkanInstance*
        _instance   = nullptr;
    QVulkanDeviceFunctions*
        _devFunc    = nullptr;
    QVulkanFunctions*
        _func       = nullptr;
    QSGRendererInterface*
        _rItf       = nullptr;

private RESOURCE:
    enum class RenderStage {
        VERTEX_STAGE,
        FRAGMENT_STAGE
    };
    const static int
        MAX_FRAME_IN_FLIGHT = 3;
    const static int
        UBUF_SIZE           = 4;
    bool
        _initialized        = false;
    QSize       
        _viewportSize;
    VkExtent2D
        _swapChainExtent    = {};
    VkPhysicalDevice
        _gpu                = VK_NULL_HANDLE;
    VkDevice
        _device             = VK_NULL_HANDLE;
    
    VkDescriptorSet
        _descriptorSet      = VK_NULL_HANDLE;
    VkDescriptorPool
        _descriptorPool     = VK_NULL_HANDLE;
    VkDescriptorSetLayout
        _descriptorLayout   = VK_NULL_HANDLE;
    
    VkBuffer 
        _uBuffer            = VK_NULL_HANDLE;
    VkDeviceMemory 
        _uBufferMem         = VK_NULL_HANDLE;
    VkBuffer 
        _vertBuffer         = VK_NULL_HANDLE;
    VkDeviceMemory 
        _vertBufferMem      = VK_NULL_HANDLE;
    VkDeviceSize 
        _allocPerUbuf       = 0;
    
    VkPhysicalDeviceProperties 
        _gpuProps           = {};
    VkPhysicalDeviceMemoryProperties
        _gpuMemProps        = {};
    
    VkRenderPass
        _renderPass         = {};
    VkPipelineLayout
        _pipelineLayout     = {};
    VkPipelineCache
        _pipelineCache      = VK_NULL_HANDLE;
    VkPipeline
        _graphicsPipeline   = {};
    
    std::vector<const char*> validationLayers = {
		"VK_LAYER_LUNARG_standard_validation"
	};
    
private FUNCTION:
    void 
        init();
    void 
        createGraphicsPipeline();
    void 
        createDescriptorPool();
    void
        createDescriptorLayout();
    VkShaderModule
        createShaderModule(const QByteArray&);
    uint32_t
        findMemoryType(uint32_t, VkMemoryPropertyFlags);
    void 
        createBuffer(
            VkDeviceSize, 
            VkBufferUsageFlags,
            VkMemoryPropertyFlags, 
            VkBuffer&,
            VkDeviceMemory&
        );
};


class Cleanup: public QRunnable {
public:
    explicit 
        Cleanup(VkRenderer* renderer): _renderer(renderer) {}
    void 
        run() override
    {
        delete _renderer;
        _renderer = nullptr;
    }
private:
    VkRenderer*     _renderer = nullptr;
};

#endif // VKRENDERER_H


VkDepending.h

#ifndef VKDEPENDING_H
#define VKDEPENDING_H

#pragma once

#include <glm/glm.hpp>
#include <glm/gtx/hash.hpp>
#include <vulkan/vulkan.h>

#include <array>
#include <vector>
#include <iostream>

struct Vertex {
	glm::vec3 pos;
	glm::vec3 color;
	glm::vec2 texCoord;	//儲存紋理的座標

	//-------------------明天注意下這塊-----------------------------
	static VkVertexInputBindingDescription getBindingDescription() {
		VkVertexInputBindingDescription bindingDescription = {};
		bindingDescription.binding = 0;
		bindingDescription.stride = sizeof(Vertex);
		bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;

		return bindingDescription;
	}

	static std::array<VkVertexInputAttributeDescription, 3>
		getAttributeDescriptions() {

		std::array<VkVertexInputAttributeDescription, 3> attributeDescriptions = {};

		//FORMAT_R32(1維)G32(2)B3(3)
		attributeDescriptions[0].binding = 0;
		attributeDescriptions[0].location = 0;
		attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
		attributeDescriptions[0].offset = offsetof(Vertex, pos);

		attributeDescriptions[1].binding = 0;
		attributeDescriptions[1].location = 1;
		attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
		attributeDescriptions[1].offset = offsetof(Vertex, color);

		attributeDescriptions[2].binding = 0;
		attributeDescriptions[2].location = 2;
		attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
		attributeDescriptions[2].offset = offsetof(Vertex, texCoord);

		return attributeDescriptions;
	}
	//----------------------------------------------------//
	bool operator==(const Vertex& other) const {
		return pos == other.pos && color == other.color && texCoord == other.texCoord;
	}
};

namespace std {
	template<> struct hash<Vertex> {
		size_t operator() (Vertex const& vertex) const {
			return (
				(hash<glm::vec3>()(vertex.pos) ^ (hash<glm::vec3>()(vertex.color) << 1))
				>> 1) ^
				(hash<glm::vec2>()(vertex.texCoord) << 1);
		}
	};
};

struct QueueFamilyIndices {
	int graphicsFamily = -1;
	int presentFamily = -1;

	bool isComplete() {
		return graphicsFamily >= 0 &&
			presentFamily >= 0;
	}
};

struct UniformBufferObject {
	glm::mat4		model;
	glm::mat4		view;
	glm::mat4		proj;
};

struct SwapChainSupportDetails {
	VkSurfaceCapabilitiesKHR capabilities;

	std::vector<VkSurfaceFormatKHR> formats;
	std::vector<VkPresentModeKHR>	presentModes;
};

static inline VkDeviceSize aligned(VkDeviceSize v, VkDeviceSize byteAlign) {
    return (v + byteAlign - 1) & ~(byteAlign - 1);
}

bool debugOutputFilter(
    VkDebugReportFlagsEXT       flags,
    VkDebugReportObjectTypeEXT  objectType,
    uint64_t                    object,
    size_t                      location,
    int32_t                     messageCode,
    const char*                 pLayerPrefix,
    const char*                 pMessage
);

#endif // VKDEPENDING_H

src

QVulkanApp.cxx

#include "QVulkanApp.h"
#include "VkRenderer.h"

#include <iostream>

QVulkanApp::QVulkanApp() {
    connect(
        this, &QQuickItem::windowChanged,
        this, &QVulkanApp::slotWindowChanged
    );
    std::cerr << "QVulkanApp is running as \"QQuickItem\"\n";
}

void QVulkanApp::slotWindowChanged(QQuickWindow* window) {
    if(window) {
        connect(
            window, &QQuickWindow::beforeSynchronizing,
            this, &QVulkanApp::sync, Qt::DirectConnection
        );
//        connect(
//            window, &QQuickWindow::sceneGraphInvalidated,
//            this, &QVulkanApp::cleanup, Qt::DirectConnection
//        );
        window->setColor(qRgba(0, 0, 0, 255));
    } else if(_renderer && _renderer->_initialized) {
        cleanup();
    }
}

void QVulkanApp::sync() {
    if(!_renderer) {
        _renderer = new VkRenderer;
        connect(
            window(),  &QQuickWindow::beforeRendering,
            _renderer, &VkRenderer::slotRenderStart, Qt::DirectConnection
        );
        connect(
            window(),  &QQuickWindow::beforeRenderPassRecording,
            _renderer, &VkRenderer::slotRenderPassRecStart, Qt::DirectConnection
        );
    }
    _renderer->setWindow(window());
    _renderer->setViewportSize(window()->size() * window()->devicePixelRatio());
}

void QVulkanApp::cleanup() {
    delete _renderer;
    _renderer = nullptr;
}

void QVulkanApp::freeResource() {
    window()->scheduleRenderJob(
        new Cleanup(_renderer), QQuickWindow::BeforeSynchronizingStage
    );
    _renderer = nullptr;
}

VkRenderer.cxx

#include "VkRenderer.h"
#include "VKDepending.h"
#include <include/LCBHSS/lcbhss_space.h>

void VkRenderer::init() {
    int framesInFlight;
    // check flight config
    {
        framesInFlight = _window->graphicsStateInfo().framesInFlight;
        assert(framesInFlight <= MAX_FRAME_IN_FLIGHT);
    }
    // init instance
    {
        _instance = reinterpret_cast<QVulkanInstance*>(
            _rItf->getResource(_window, QSGRendererInterface::VulkanInstanceResource)
        );
        _instance->installDebugOutputFilter(&debugOutputFilter);
        assert(_instance && _instance->isValid());
    }
    // init physical device
    {
        _gpu = *reinterpret_cast<VkPhysicalDevice*>(
            _rItf->getResource(_window, QSGRendererInterface::PhysicalDeviceResource)
        );
        assert(_gpu);
    }
    // init logical device 
    {
        _device = *reinterpret_cast<VkDevice*>(
            _rItf->getResource(_window, QSGRendererInterface::DeviceResource)
        );
        assert(_device);
    }
    // link vk functions
    {
        _devFunc = _instance->deviceFunctions(_device);
        _func    = _instance->functions();
        assert(_devFunc && _func);
    }
    // create render pass
    {
        VkRenderPass renderPass = *reinterpret_cast<VkRenderPass *>(
            _rItf->getResource(_window, QSGRendererInterface::RenderPassResource)
        );
        assert(renderPass);
    }
    // get physical device proerties
    {
        _func->vkGetPhysicalDeviceProperties(_gpu, &_gpuProps);
        _func->vkGetPhysicalDeviceMemoryProperties(_gpu, &_gpuMemProps);
        _allocPerUbuf = aligned(
            UBUF_SIZE, _gpuProps.limits.minUniformBufferOffsetAlignment
        );
    }
    // create descriptor layout
    {
        createBuffer(
            framesInFlight * _allocPerUbuf,
            VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
            VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
            VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
            _uBuffer, _uBufferMem
        );
        createDescriptorLayout();
    }
    // create graphics pipeline
    createGraphicsPipeline();
    // create descriptor pool
    createDescriptorPool();
    
    _initialized = true;
}

VkShaderModule VkRenderer::createShaderModule(
	const QByteArray& code
) {

	VkShaderModuleCreateInfo createInfo = {};
	createInfo.sType =
		VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
	createInfo.codeSize = code.size();
	createInfo.pCode = reinterpret_cast<const uint32_t*>(
		code.data());

	VkShaderModule shaderModule;
	if (_devFunc->vkCreateShaderModule(
		_device, &createInfo, nullptr, &shaderModule
	) != VK_SUCCESS) {
		throw std::runtime_error("failed to create shader module");
	}
	return shaderModule;
}

void VkRenderer::createDescriptorLayout() {
    VkDescriptorSetLayoutBinding uboLayoutBingding {};
    {
        // 對應的頂點着色器中的參數
        uboLayoutBingding.binding = 0;                  
        uboLayoutBingding.descriptorType =
            VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
        uboLayoutBingding.descriptorCount = 1;
        uboLayoutBingding.stageFlags =
            VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
        // 用於圖像採樣相關的描述符
        uboLayoutBingding.pImmutableSamplers = nullptr; 
    }
    // config sampler
    VkDescriptorSetLayoutBinding samplerLayoutBinding = {};
    {
        samplerLayoutBinding.binding = 1;
        samplerLayoutBinding.descriptorCount = 1;
        samplerLayoutBinding.descriptorType =
            VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
        samplerLayoutBinding.pImmutableSamplers = nullptr;
        samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
    } 
    std::array<VkDescriptorSetLayoutBinding, 2> bindings = {
            uboLayoutBingding, samplerLayoutBinding
    };
    VkDescriptorSetLayoutCreateInfo layoutInfo {};
    {
        layoutInfo.sType =
                VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
        layoutInfo.bindingCount = static_cast<uint32_t>(bindings.size());
        layoutInfo.pBindings = bindings.data();
    }
    if (_devFunc->vkCreateDescriptorSetLayout(
                _device, &layoutInfo, nullptr, &_descriptorLayout
    ) != VK_SUCCESS)
        throw std::runtime_error("Failed to create descriptor set layout: %d");
}

void VkRenderer::createGraphicsPipeline() {
    // create pipeline cache
    {
        VkPipelineCacheCreateInfo pipelineCacheInfo {};
        pipelineCacheInfo.sType =
            VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
        
        if (_devFunc->vkCreatePipelineCache(
            _device, &pipelineCacheInfo, nullptr, &_pipelineCache
        ) != VK_SUCCESS)
            throw std::runtime_error("failed to create pipeline cache: %d");
    }
    // create pipeline layout
    {
        VkPipelineLayoutCreateInfo pipelineLayoutInfo {};
        pipelineLayoutInfo.sType =
            VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
        pipelineLayoutInfo.setLayoutCount = 1;
        pipelineLayoutInfo.pSetLayouts = &_descriptorLayout;
        if (_devFunc->vkCreatePipelineLayout(
            _device, &pipelineLayoutInfo, nullptr, &_pipelineLayout
        ) != VK_SUCCESS)
            throw std::runtime_error("failed to create pipeline layout");
    }
    
    VkGraphicsPipelineCreateInfo pipelineInfo = {};
	pipelineInfo.sType =
		VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
    
    //-------------load shader bin code--------------//
    auto vertShaderPath =
            QLatin1String(":/resource/shader/compiledShader/vert.spv");
    auto fragShaderPath =
            QLatin1String(":/resource/shader/compiledShader/frag.spv");
    VkShaderModule vertShaderModule = {};
    VkShaderModule fragShaderModule = {};
    {
        QFile vertShader(vertShaderPath);
        if(!vertShader.open(QIODevice::ReadOnly))
            throw std::runtime_error("failed to read vert shader");
        const QByteArray vertShaderCode = 
                vertShader.readAll();
        assert(!vertShaderCode.isEmpty());
        
        vertShaderModule = createShaderModule(vertShaderCode);
    }
    {
        QFile fragShader(fragShaderPath);
        if(!fragShader.open(QIODevice::ReadOnly))
            throw std::runtime_error("failed to read frag shader");
        const QByteArray fragShaderCode = 
                fragShader.readAll();
        assert(!fragShaderCode.isEmpty());
        
        fragShaderModule = createShaderModule(fragShaderCode);
    }
    
    //--------------config shader applied stage-------------//
    VkPipelineShaderStageCreateInfo vertShaderStageInfo = {};
    {
        vertShaderStageInfo.sType =
            VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
        vertShaderStageInfo.stage = 
            VK_SHADER_STAGE_VERTEX_BIT;
        vertShaderStageInfo.module =
            vertShaderModule;
        // 着色器函數名稱
        vertShaderStageInfo.pName = "main";
    }
    VkPipelineShaderStageCreateInfo fragShaderStageInfo = {};
    {
        fragShaderStageInfo.sType =
            VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
        fragShaderStageInfo.stage = 
            VK_SHADER_STAGE_FRAGMENT_BIT;
        fragShaderStageInfo.module =
            fragShaderModule;
        // 着色器函數名稱
        fragShaderStageInfo.pName = "main";
    }
    
    VkPipelineShaderStageCreateInfo shaderStages[] = {
        vertShaderStageInfo, fragShaderStageInfo
    };
    // 頂點輸入狀態
    VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
    {
        vertexInputInfo.sType =
            VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
        auto bindingDescription = Vertex::getBindingDescription();
        auto attributeDescriptions = Vertex::getAttributeDescriptions();
        
        vertexInputInfo.vertexBindingDescriptionCount = 1;
        vertexInputInfo.vertexAttributeDescriptionCount =
            static_cast<uint32_t>(attributeDescriptions.size());
    
        vertexInputInfo.pVertexBindingDescriptions =
            &bindingDescription;
        vertexInputInfo.pVertexAttributeDescriptions =
            attributeDescriptions.data();
    }
    
    VkDynamicState dynStates[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
    VkPipelineDynamicStateCreateInfo dynamicInfo {};
    {
        dynamicInfo.sType =
                VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
        dynamicInfo.dynamicStateCount = 2;
        dynamicInfo.pDynamicStates = dynStates;
    }

    VkPipelineViewportStateCreateInfo viewportInfo {};
    {
        viewportInfo.sType = 
                VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
        viewportInfo.viewportCount = viewportInfo.scissorCount = 1;
    }
    
    
    VkPipelineInputAssemblyStateCreateInfo inputAssembly {};
    {
        inputAssembly.sType =
            VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
        inputAssembly.topology =
            VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; //三個頂點構成一個圖元
        inputAssembly.primitiveRestartEnable = VK_FALSE;
    }
    
    VkPipelineRasterizationStateCreateInfo rsInfo {};
    {
        rsInfo.sType =
            VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
        rsInfo.lineWidth = 1.0f;
    }

    VkPipelineMultisampleStateCreateInfo msInfo {};
    {
        msInfo.sType =
                VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
        msInfo.rasterizationSamples =
                VK_SAMPLE_COUNT_1_BIT;
    }

    VkPipelineDepthStencilStateCreateInfo dsInfo {};
    dsInfo.sType = 
        VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;

    // SrcAlpha, One
    VkPipelineColorBlendStateCreateInfo blendInfo {};
    blendInfo.sType =
        VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
    VkPipelineColorBlendAttachmentState blend {};
    blend.blendEnable = true;
    blend.srcColorBlendFactor   = VK_BLEND_FACTOR_SRC_ALPHA;
    blend.dstColorBlendFactor   = VK_BLEND_FACTOR_ONE;
    blend.colorBlendOp          = VK_BLEND_OP_ADD;
    blend.srcAlphaBlendFactor   = VK_BLEND_FACTOR_SRC_ALPHA;
    blend.dstAlphaBlendFactor   = VK_BLEND_FACTOR_ONE;
    blend.alphaBlendOp          = VK_BLEND_OP_ADD;
    blend.colorWriteMask =
            VK_COLOR_COMPONENT_R_BIT |
            VK_COLOR_COMPONENT_G_BIT |
            VK_COLOR_COMPONENT_B_BIT |
            VK_COLOR_COMPONENT_A_BIT;
    blendInfo.attachmentCount = 1;
    blendInfo.pAttachments = &blend;
    
    // set up pipeline create info
    {
        pipelineInfo.stageCount             = 2;
        pipelineInfo.pStages                = shaderStages;
        pipelineInfo.pVertexInputState      = &vertexInputInfo;
        pipelineInfo.pDynamicState          = &dynamicInfo;
        pipelineInfo.pViewportState         = &viewportInfo;
        pipelineInfo.pInputAssemblyState    = &inputAssembly;
        pipelineInfo.pRasterizationState    = &rsInfo;
        pipelineInfo.pMultisampleState      = &msInfo;
        pipelineInfo.pDepthStencilState     = &dsInfo;
        pipelineInfo.pColorBlendState       = &blendInfo;
        pipelineInfo.layout                 = _pipelineLayout;
        pipelineInfo.renderPass             = _renderPass;
    }
    
	if (_devFunc->vkCreateGraphicsPipelines(
		_device, _pipelineCache, 1, &pipelineInfo, nullptr, &_graphicsPipeline
	) != VK_SUCCESS) {
		throw std::runtime_error("failed to create graphics pipeline");
	}

	_devFunc->vkDestroyShaderModule(_device, fragShaderModule, nullptr);
	_devFunc->vkDestroyShaderModule(_device, vertShaderModule, nullptr);
}

void VkRenderer::createDescriptorPool() {
    // 創建&分配描述符池
    VkDescriptorPoolSize descPoolSizes[] = {
        { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1 }
    };
    VkDescriptorPoolCreateInfo descPoolInfo {};
    {
        descPoolInfo.sType = 
            VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
        descPoolInfo.flags = 0; // won't use vkFreeDescriptorSets
        descPoolInfo.maxSets = 1;
        descPoolInfo.poolSizeCount = sizeof(descPoolSizes) / sizeof(descPoolSizes[0]);
        descPoolInfo.pPoolSizes = descPoolSizes;
    }
    
    if (_devFunc->vkCreateDescriptorPool(
        _device, &descPoolInfo, nullptr, &_descriptorPool
    ) != VK_SUCCESS) {
        throw std::runtime_error("failed to create descriptor pool");
    }
    
    VkDescriptorSetAllocateInfo descAllocInfo {};
    {
        descAllocInfo.sType = 
            VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
        descAllocInfo.descriptorPool = _descriptorPool;
        descAllocInfo.descriptorSetCount = 1;
        descAllocInfo.pSetLayouts = &_descriptorLayout;
    }
    
    if (_devFunc->vkAllocateDescriptorSets(
        _device, &descAllocInfo, &_descriptorSet
    ) != VK_SUCCESS) 
        throw std::runtime_error("failed to allocate descriptor set");

    VkWriteDescriptorSet writeInfo {};
    {
        writeInfo.sType =
            VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
        writeInfo.dstSet = _descriptorSet;
        writeInfo.dstBinding = 0;
        writeInfo.descriptorCount = 1;
        writeInfo.descriptorType =
            VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
    }
    VkDescriptorBufferInfo bufInfo {};
    {
        bufInfo.buffer = _uBuffer;
        // 使用動態座標
        bufInfo.offset = 0; 
        bufInfo.range = UBUF_SIZE;
        writeInfo.pBufferInfo = &bufInfo;
    }
    _devFunc->vkUpdateDescriptorSets(_device, 1, &writeInfo, 0, nullptr);
}

void VkRenderer::createBuffer(
	VkDeviceSize                size, 
	VkBufferUsageFlags          usage,
	VkMemoryPropertyFlags       properties,
	VkBuffer&                   buffer,
	VkDeviceMemory&             bufferMemory
) {
	VkBufferCreateInfo bufferInfo = {};
	bufferInfo.sType =
		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
	bufferInfo.size = size;
	bufferInfo.usage = usage;
	bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
	
	if (_devFunc->vkCreateBuffer(_device, &bufferInfo, nullptr, &buffer)
		!= VK_SUCCESS
	) {
		throw std::runtime_error("failed to create buffer");
	}

	VkMemoryRequirements memRequirements;
	_devFunc->vkGetBufferMemoryRequirements(
		_device, buffer, &memRequirements
	);
	VkMemoryAllocateInfo allocInfo = {};
	allocInfo.sType =
		VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
	allocInfo.allocationSize = memRequirements.size;
	allocInfo.memoryTypeIndex = findMemoryType(
		memRequirements.memoryTypeBits, properties
	);

	if (_devFunc->vkAllocateMemory(
		_device, &allocInfo, nullptr, &bufferMemory
	) != VK_SUCCESS) {
		throw std::runtime_error("failed to allocate buffer memory");
	}

	_devFunc->vkBindBufferMemory(_device, buffer, bufferMemory, 0);
}

uint32_t VkRenderer::findMemoryType(
	uint32_t                typeFilter,
	VkMemoryPropertyFlags   properties
) {
	for (uint32_t i = 0; i < _gpuMemProps.memoryTypeCount; i++) {
		if ((typeFilter & (1 << i)) &&
			((_gpuMemProps.memoryTypes[i].propertyFlags & properties) == 
			properties)
		) {
			return i;
		}
	}
	throw std::runtime_error("failed to find suitable memory type");
}



void VkRenderer::slotRenderStart() {
    _rItf = _window->rendererInterface();
    
    assert(_rItf->graphicsApi() == QSGRendererInterface::VulkanRhi);
    
    if(!_initialized) {
        init();
    }
}

void VkRenderer::slotRenderPassRecStart() {
    // update vertex 
    // update uniform
    // start external render work
    // end external render work
    const QQuickWindow::GraphicsStateInfo &stateInfo(
        _window->graphicsStateInfo()
    );
    VkDeviceSize ubufOffset = stateInfo.currentFrameSlot * _allocPerUbuf;
    void* data = nullptr;
    if(_devFunc->vkMapMemory(
        _device, _uBufferMem, ubufOffset, _allocPerUbuf, 0, &data
    ) != VK_SUCCESS) {
        throw std::runtime_error("failed to map uniform buffer memeory");
    }
    //memcpyxxxx
    _devFunc->vkUnmapMemory(_device, _uBufferMem);
    
    _window->beginExternalCommands();
    VkCommandBuffer cmdBuf = *reinterpret_cast<VkCommandBuffer*>(
        _rItf->getResource(_window, QSGRendererInterface::CommandListResource)
    );
    assert(cmdBuf);
    // bind graphics pipeline
    
}

VkRenderer::~VkRenderer() {
    if(!_devFunc) {
        return;
    } else {
        std::cerr << "cleanup event\n";
        _devFunc->vkDestroyPipeline(_device, _graphicsPipeline, nullptr);
        _devFunc->vkDestroyPipelineLayout(_device, _pipelineLayout, nullptr);
        
        _devFunc->vkDestroyDescriptorSetLayout(_device, _descriptorLayout, nullptr);
        _devFunc->vkDestroyDescriptorPool(_device, _descriptorPool, nullptr);
        
        _devFunc->vkDestroyPipelineCache(_device, _pipelineCache, nullptr);
        
        _devFunc->vkDestroyBuffer(_device, _uBuffer, nullptr);
        _devFunc->vkFreeMemory(_device, _uBufferMem, nullptr);
        std::cerr << "cleanup finished\n";
    }
}


main.cxx

#include <QtQml>
#include <QQuickView>
#include <QGuiApplication>
#include "src/QVulkanApp/QVulkanApp.h"

int main(int argc, char *argv[]) {
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    
    qmlRegisterType<QVulkanApp>("VulkanApp", 1, 14, "VulkanScene");
    
    QQuickWindow::setSceneGraphBackend(QSGRendererInterface::VulkanRhi);
    
    QGuiApplication app(argc, argv);
    
    QQuickView view;
    
    view.setResizeMode(QQuickView::SizeRootObjectToView);
    view.setSource(QUrl("qrc:/qml/main.qml"));
    view.show();
    
    return app.exec();
}

VkRawFunction.cxx

#include "VKDepending.h"

bool debugOutputFilter(
        VkDebugReportFlagsEXT       flags,
        VkDebugReportObjectTypeEXT  objectType,
        uint64_t                    object,
        size_t                      location,
        int32_t                     messageCode,
        const char*                 pLayerPrefix,
        const char*                 pMessage
) {
    // add filter process here
    std::cerr
		<< "validation layer catched an exception\n"
		<< "[ReportFlag]: "     << flags        << "\n"
		<< "[ObjectType]: "     << objectType   << "\n"
		<< "[ThreadLocation]: " << location     << "\n"
		<< "[Object]: "         << object       << "\n"
		<< "[MessageCode]"      << messageCode  << "\n"
		<< "[LayerPrefix]: "    << pLayerPrefix << "\n"
		<< "****[Message]*** "  << pMessage     << "\n";
    return false;
}

qml.qrc

main.qml

import QtQuick 2.14
import QtQuick.Controls 2.14
import VulkanApp 1.14

VulkanScene {
    id:         vkScene
    width:      1280
    height:     720
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章