mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-11-04 05:30:32 -05:00 
			
		
		
		
	
		
			
	
	
		
			345 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			345 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
								 | 
							
								///////////////////////////////////////////////////////////////////////////////////
							 | 
						||
| 
								 | 
							
								// Copyright (C) 2023 Jon Beniston, M7RCE                                        //
							 | 
						||
| 
								 | 
							
								//                                                                               //
							 | 
						||
| 
								 | 
							
								// This program is free software; you can redistribute it and/or modify          //
							 | 
						||
| 
								 | 
							
								// it under the terms of the GNU General Public License as published by          //
							 | 
						||
| 
								 | 
							
								// the Free Software Foundation as version 3 of the License, or                  //
							 | 
						||
| 
								 | 
							
								// (at your option) any later version.                                           //
							 | 
						||
| 
								 | 
							
								//                                                                               //
							 | 
						||
| 
								 | 
							
								// This program is distributed in the hope that it will be useful,               //
							 | 
						||
| 
								 | 
							
								// but WITHOUT ANY WARRANTY; without even the implied warranty of                //
							 | 
						||
| 
								 | 
							
								// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
							 | 
						||
| 
								 | 
							
								// GNU General Public License V3 for more details.                               //
							 | 
						||
| 
								 | 
							
								//                                                                               //
							 | 
						||
| 
								 | 
							
								// You should have received a copy of the GNU General Public License             //
							 | 
						||
| 
								 | 
							
								// along with this program. If not, see <http://www.gnu.org/licenses/>.          //
							 | 
						||
| 
								 | 
							
								///////////////////////////////////////////////////////////////////////////////////
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <QDebug>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "glslang_c_interface.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "dsp/vulkanvkfftengine.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class GLSInitialiser {
							 | 
						||
| 
								 | 
							
								public:
							 | 
						||
| 
								 | 
							
								    GLSInitialiser() {
							 | 
						||
| 
								 | 
							
								        glslang_initialize_process();
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    ~GLSInitialiser() {
							 | 
						||
| 
								 | 
							
								        glslang_finalize_process();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static GLSInitialiser glsInitialiser;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								VulkanvkFFTEngine::VulkanvkFFTEngine()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    VkFFTResult resFFT;
							 | 
						||
| 
								 | 
							
								    resFFT = gpuInit();
							 | 
						||
| 
								 | 
							
								    if (resFFT != VKFFT_SUCCESS)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        qDebug() << "VulkanvkFFTEngine::VulkanvkFFTEngine: Failed to initialise GPU:" << getVkFFTErrorString(resFFT);
							 | 
						||
| 
								 | 
							
								        delete vkGPU;
							 | 
						||
| 
								 | 
							
								        vkGPU = nullptr;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								VulkanvkFFTEngine::~VulkanvkFFTEngine()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if (vkGPU)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        freeAll();
							 | 
						||
| 
								 | 
							
								        vkDestroyFence(vkGPU->device, vkGPU->fence, nullptr);
							 | 
						||
| 
								 | 
							
								        vkDestroyCommandPool(vkGPU->device, vkGPU->commandPool, nullptr);
							 | 
						||
| 
								 | 
							
								        vkDestroyDevice(vkGPU->device, nullptr);
							 | 
						||
| 
								 | 
							
								        DestroyDebugUtilsMessengerEXT(vkGPU, nullptr);
							 | 
						||
| 
								 | 
							
								        vkDestroyInstance(vkGPU->instance, nullptr);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const QString VulkanvkFFTEngine::m_name = "vkFFT (Vulkan)";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								QString VulkanvkFFTEngine::getName() const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    return m_name;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								VkFFTResult VulkanvkFFTEngine::gpuInit()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    VkResult res = VK_SUCCESS;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // To enable validation on Windows:
							 | 
						||
| 
								 | 
							
								    // set VK_LAYER_PATH=%VULKAN_SDK%\Bin
							 | 
						||
| 
								 | 
							
								    // set VK_INSTANCE_LAYERS=VK_LAYER_LUNARG_api_dump;VK_LAYER_KHRONOS_validation
							 | 
						||
| 
								 | 
							
								    // https://vulkan.lunarg.com/doc/view/1.3.204.1/windows/layer_configuration.html
							 | 
						||
| 
								 | 
							
								    // Create vk_layer_settings.txt in working dir
							 | 
						||
| 
								 | 
							
								    // Or run vkconfig to do so
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Create instance - a connection between the application and the Vulkan library
							 | 
						||
| 
								 | 
							
								    res = createInstance(vkGPU, 0);
							 | 
						||
| 
								 | 
							
								    if (res != 0) {
							 | 
						||
| 
								 | 
							
								        return VKFFT_ERROR_FAILED_TO_CREATE_INSTANCE;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    // Set up the debugging messenger
							 | 
						||
| 
								 | 
							
								    res = setupDebugMessenger(vkGPU);
							 | 
						||
| 
								 | 
							
								    if (res != 0) {
							 | 
						||
| 
								 | 
							
								        return VKFFT_ERROR_FAILED_TO_SETUP_DEBUG_MESSENGER;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    // Check if there are GPUs that support Vulkan and select one
							 | 
						||
| 
								 | 
							
								    res = findPhysicalDevice(vkGPU);
							 | 
						||
| 
								 | 
							
								    if (res != 0) {
							 | 
						||
| 
								 | 
							
								        return VKFFT_ERROR_FAILED_TO_FIND_PHYSICAL_DEVICE;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    // Create logical device representation
							 | 
						||
| 
								 | 
							
								    res = createDevice(vkGPU, 0);
							 | 
						||
| 
								 | 
							
								    if (res != 0) {
							 | 
						||
| 
								 | 
							
								        return VKFFT_ERROR_FAILED_TO_CREATE_DEVICE;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    // Create fence for synchronization
							 | 
						||
| 
								 | 
							
								    res = createFence(vkGPU);
							 | 
						||
| 
								 | 
							
								    if (res != 0) {
							 | 
						||
| 
								 | 
							
								        return VKFFT_ERROR_FAILED_TO_CREATE_FENCE;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    // Create a place, command buffer memory is allocated from
							 | 
						||
| 
								 | 
							
								    res = createCommandPool(vkGPU);
							 | 
						||
| 
								 | 
							
								    if (res != 0) {
							 | 
						||
| 
								 | 
							
								        return VKFFT_ERROR_FAILED_TO_CREATE_COMMAND_POOL;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    vkGetPhysicalDeviceProperties(vkGPU->physicalDevice, &vkGPU->physicalDeviceProperties);
							 | 
						||
| 
								 | 
							
								    vkGetPhysicalDeviceMemoryProperties(vkGPU->physicalDevice, &vkGPU->physicalDeviceMemoryProperties);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return VKFFT_SUCCESS;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								VkFFTResult VulkanvkFFTEngine::gpuAllocateBuffers()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    VkFFTResult resFFT;
							 | 
						||
| 
								 | 
							
								    VulkanPlan *plan = reinterpret_cast<VulkanPlan *>(m_currentPlan);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Allocate GPU memory
							 | 
						||
| 
								 | 
							
								    resFFT = allocateBuffer(vkGPU,
							 | 
						||
| 
								 | 
							
								                            &plan->m_buffer,
							 | 
						||
| 
								 | 
							
								                            &plan->m_bufferDeviceMemory,
							 | 
						||
| 
								 | 
							
								                            VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
							 | 
						||
| 
								 | 
							
								                            VK_MEMORY_HEAP_DEVICE_LOCAL_BIT,
							 | 
						||
| 
								 | 
							
								                            plan->m_bufferSize);
							 | 
						||
| 
								 | 
							
								    if (resFFT != VKFFT_SUCCESS) {
							 | 
						||
| 
								 | 
							
								        return resFFT;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Allocate CPU/GPU memory (Requires m_currentPlan->m_buffer to have been created)
							 | 
						||
| 
								 | 
							
								    resFFT = vulkanAllocateIn(plan);
							 | 
						||
| 
								 | 
							
								    if (resFFT != VKFFT_SUCCESS) {
							 | 
						||
| 
								 | 
							
								        return resFFT;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    resFFT = vulkanAllocateOut(plan);
							 | 
						||
| 
								 | 
							
								    if (resFFT != VKFFT_SUCCESS) {
							 | 
						||
| 
								 | 
							
								        return resFFT;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    plan->m_configuration->buffer = &plan->m_buffer;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return VKFFT_SUCCESS;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								VkFFTResult VulkanvkFFTEngine::gpuConfigure()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    VkFFTResult resFFT;
							 | 
						||
| 
								 | 
							
								    VulkanPlan *plan = reinterpret_cast<VulkanPlan *>(m_currentPlan);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Allocate command buffer with command to perform FFT
							 | 
						||
| 
								 | 
							
								    resFFT = vulkanAllocateFFTCommand(plan);
							 | 
						||
| 
								 | 
							
								    if (resFFT != VKFFT_SUCCESS) {
							 | 
						||
| 
								 | 
							
								        return resFFT;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return VKFFT_SUCCESS;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Allocate CPU to GPU memory buffer
							 | 
						||
| 
								 | 
							
								VkFFTResult VulkanvkFFTEngine::vulkanAllocateIn(VulkanPlan *plan)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    VkFFTResult resFFT;
							 | 
						||
| 
								 | 
							
								    VkResult res = VK_SUCCESS;
							 | 
						||
| 
								 | 
							
								    VkBuffer* buffer = (VkBuffer*)&plan->m_buffer;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    resFFT = allocateBuffer(vkGPU, &plan->m_inBuffer, &plan->m_inMemory, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT, m_currentPlan->m_bufferSize);
							 | 
						||
| 
								 | 
							
								    if (resFFT != VKFFT_SUCCESS) {
							 | 
						||
| 
								 | 
							
								        return resFFT;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    void* data;
							 | 
						||
| 
								 | 
							
								    res = vkMapMemory(vkGPU->device, plan->m_inMemory, 0, plan->m_bufferSize, 0, &data);
							 | 
						||
| 
								 | 
							
								    if (res != VK_SUCCESS) {
							 | 
						||
| 
								 | 
							
								        return VKFFT_ERROR_FAILED_TO_MAP_MEMORY;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    plan->m_in = (Complex*) data;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return VKFFT_SUCCESS;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Allocate GPU to CPU memory buffer
							 | 
						||
| 
								 | 
							
								VkFFTResult VulkanvkFFTEngine::vulkanAllocateOut(VulkanPlan *plan)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    VkFFTResult resFFT;
							 | 
						||
| 
								 | 
							
								    VkResult res;
							 | 
						||
| 
								 | 
							
								    VkBuffer* buffer = (VkBuffer*)&plan->m_buffer;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    resFFT = allocateBuffer(vkGPU, &plan->m_outBuffer, &plan->m_outMemory, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT, m_currentPlan->m_bufferSize);
							 | 
						||
| 
								 | 
							
								    if (resFFT != VKFFT_SUCCESS) {
							 | 
						||
| 
								 | 
							
								        return resFFT;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    void* data;
							 | 
						||
| 
								 | 
							
								    res = vkMapMemory(vkGPU->device, plan->m_outMemory, 0, plan->m_bufferSize, 0, &data);
							 | 
						||
| 
								 | 
							
								    if (res != VK_SUCCESS) {
							 | 
						||
| 
								 | 
							
								        return VKFFT_ERROR_FAILED_TO_MAP_MEMORY;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    plan->m_out = (Complex*) data;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return VKFFT_SUCCESS;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void VulkanvkFFTEngine::vulkanDeallocateIn(VulkanPlan *plan)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    vkUnmapMemory(vkGPU->device, plan->m_inMemory);
							 | 
						||
| 
								 | 
							
								    vkDestroyBuffer(vkGPU->device, plan->m_inBuffer, nullptr);
							 | 
						||
| 
								 | 
							
								    vkFreeMemory(vkGPU->device, plan->m_inMemory, nullptr);
							 | 
						||
| 
								 | 
							
								    plan->m_in = nullptr;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void VulkanvkFFTEngine::vulkanDeallocateOut(VulkanPlan *plan)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    vkUnmapMemory(vkGPU->device, plan->m_outMemory);
							 | 
						||
| 
								 | 
							
								    vkDestroyBuffer(vkGPU->device, plan->m_outBuffer, nullptr);
							 | 
						||
| 
								 | 
							
								    vkFreeMemory(vkGPU->device, plan->m_outMemory, nullptr);
							 | 
						||
| 
								 | 
							
								    plan->m_out = nullptr;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								VkFFTResult VulkanvkFFTEngine::vulkanAllocateFFTCommand(VulkanPlan *plan)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    VkFFTResult resFFT;
							 | 
						||
| 
								 | 
							
								    VkResult res = VK_SUCCESS;
							 | 
						||
| 
								 | 
							
								    VkCommandBufferAllocateInfo commandBufferAllocateInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
							 | 
						||
| 
								 | 
							
								    commandBufferAllocateInfo.commandPool = vkGPU->commandPool;
							 | 
						||
| 
								 | 
							
								    commandBufferAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
							 | 
						||
| 
								 | 
							
								    commandBufferAllocateInfo.commandBufferCount = 1;
							 | 
						||
| 
								 | 
							
								    res = vkAllocateCommandBuffers(vkGPU->device, &commandBufferAllocateInfo, &plan->m_commandBuffer);
							 | 
						||
| 
								 | 
							
								    if (res != 0) {
							 | 
						||
| 
								 | 
							
								        return VKFFT_ERROR_FAILED_TO_ALLOCATE_COMMAND_BUFFERS;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    VkCommandBufferBeginInfo commandBufferBeginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
							 | 
						||
| 
								 | 
							
								    commandBufferBeginInfo.flags = 0;
							 | 
						||
| 
								 | 
							
								    res = vkBeginCommandBuffer(plan->m_commandBuffer, &commandBufferBeginInfo);
							 | 
						||
| 
								 | 
							
								    if (res != 0) {
							 | 
						||
| 
								 | 
							
								        return VKFFT_ERROR_FAILED_TO_BEGIN_COMMAND_BUFFER;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    VkBuffer* buffer = (VkBuffer*)&plan->m_buffer;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Copy from CPU to GPU
							 | 
						||
| 
								 | 
							
								    VkBufferCopy copyRegionIn = { 0 };
							 | 
						||
| 
								 | 
							
								    copyRegionIn.srcOffset = 0;
							 | 
						||
| 
								 | 
							
								    copyRegionIn.dstOffset = 0;
							 | 
						||
| 
								 | 
							
								    copyRegionIn.size = plan->m_bufferSize;
							 | 
						||
| 
								 | 
							
								    vkCmdCopyBuffer(plan->m_commandBuffer, plan->m_inBuffer, buffer[0], 1, ©RegionIn);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Wait for copy to complete
							 | 
						||
| 
								 | 
							
								    VkMemoryBarrier memoryBarrierIn = {
							 | 
						||
| 
								 | 
							
								            VK_STRUCTURE_TYPE_MEMORY_BARRIER,
							 | 
						||
| 
								 | 
							
								            0,
							 | 
						||
| 
								 | 
							
								            VK_ACCESS_SHADER_WRITE_BIT,
							 | 
						||
| 
								 | 
							
								            VK_ACCESS_SHADER_READ_BIT,
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								    vkCmdPipelineBarrier(
							 | 
						||
| 
								 | 
							
								        plan->m_commandBuffer,
							 | 
						||
| 
								 | 
							
								        VK_PIPELINE_STAGE_TRANSFER_BIT,
							 | 
						||
| 
								 | 
							
								        VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
							 | 
						||
| 
								 | 
							
								        0,
							 | 
						||
| 
								 | 
							
								        1,
							 | 
						||
| 
								 | 
							
								        &memoryBarrierIn,
							 | 
						||
| 
								 | 
							
								        0, 0, 0, 0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Perform FFT
							 | 
						||
| 
								 | 
							
								    VkFFTLaunchParams launchParams = {};
							 | 
						||
| 
								 | 
							
								    launchParams.commandBuffer = &plan->m_commandBuffer;
							 | 
						||
| 
								 | 
							
								    resFFT = VkFFTAppend(plan->m_app, plan->m_inverse, &launchParams);
							 | 
						||
| 
								 | 
							
								    if (resFFT != VKFFT_SUCCESS) {
							 | 
						||
| 
								 | 
							
								        return resFFT;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Wait for FFT to complete
							 | 
						||
| 
								 | 
							
								    VkMemoryBarrier memoryBarrierOut = {
							 | 
						||
| 
								 | 
							
								            VK_STRUCTURE_TYPE_MEMORY_BARRIER,
							 | 
						||
| 
								 | 
							
								            0,
							 | 
						||
| 
								 | 
							
								            VK_ACCESS_SHADER_WRITE_BIT,
							 | 
						||
| 
								 | 
							
								            VK_ACCESS_HOST_READ_BIT,
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								    vkCmdPipelineBarrier(
							 | 
						||
| 
								 | 
							
								        plan->m_commandBuffer,
							 | 
						||
| 
								 | 
							
								        VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
							 | 
						||
| 
								 | 
							
								        VK_PIPELINE_STAGE_HOST_BIT,
							 | 
						||
| 
								 | 
							
								        0,
							 | 
						||
| 
								 | 
							
								        1,
							 | 
						||
| 
								 | 
							
								        &memoryBarrierIn,
							 | 
						||
| 
								 | 
							
								        0, 0, 0, 0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Copy from GPU to CPU
							 | 
						||
| 
								 | 
							
								    VkBufferCopy copyRegionOut = { 0 };
							 | 
						||
| 
								 | 
							
								    copyRegionOut.srcOffset = 0;
							 | 
						||
| 
								 | 
							
								    copyRegionOut.dstOffset = 0;
							 | 
						||
| 
								 | 
							
								    copyRegionOut.size = plan->m_bufferSize;
							 | 
						||
| 
								 | 
							
								    vkCmdCopyBuffer(plan->m_commandBuffer, buffer[0], plan->m_outBuffer, 1, ©RegionOut);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    res = vkEndCommandBuffer(plan->m_commandBuffer);
							 | 
						||
| 
								 | 
							
								    if (res != 0) {
							 | 
						||
| 
								 | 
							
								        return VKFFT_ERROR_FAILED_TO_END_COMMAND_BUFFER;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return VKFFT_SUCCESS;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void VulkanvkFFTEngine::transform()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    PROFILER_START()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    VkResult res = VK_SUCCESS;
							 | 
						||
| 
								 | 
							
								    VulkanPlan *plan = reinterpret_cast<VulkanPlan *>(m_currentPlan);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
							 | 
						||
| 
								 | 
							
								    submitInfo.commandBufferCount = 1;
							 | 
						||
| 
								 | 
							
								    submitInfo.pCommandBuffers = &plan->m_commandBuffer;
							 | 
						||
| 
								 | 
							
								    res = vkQueueSubmit(vkGPU->queue, 1, &submitInfo, vkGPU->fence);
							 | 
						||
| 
								 | 
							
								    if (res != 0) {
							 | 
						||
| 
								 | 
							
								        qDebug() << "VulkanvkFFTEngine::transform: Failed to submit to queue";
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    res = vkWaitForFences(vkGPU->device, 1, &vkGPU->fence, VK_TRUE, 100000000000);
							 | 
						||
| 
								 | 
							
								    if (res != 0) {
							 | 
						||
| 
								 | 
							
								        qDebug() << "VulkanvkFFTEngine::transform: Failed to wait for fences";
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    res = vkResetFences(vkGPU->device, 1, &vkGPU->fence);
							 | 
						||
| 
								 | 
							
								    if (res != 0) {
							 | 
						||
| 
								 | 
							
								        qDebug() << "VulkanvkFFTEngine::transform: Failed to reset fences";
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    PROFILER_STOP(QString("%1 FFT %2").arg(getName()).arg(m_currentPlan->n))
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								vkFFTEngine::Plan *VulkanvkFFTEngine::gpuAllocatePlan()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    return new VulkanPlan();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void VulkanvkFFTEngine::gpuDeallocatePlan(Plan *p)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    VulkanPlan *plan = reinterpret_cast<VulkanPlan *>(p);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    vulkanDeallocateOut(plan);
							 | 
						||
| 
								 | 
							
								    vulkanDeallocateIn(plan);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    vkFreeCommandBuffers(vkGPU->device, vkGPU->commandPool, 1, &plan->m_commandBuffer);
							 | 
						||
| 
								 | 
							
								    vkDestroyBuffer(vkGPU->device, plan->m_buffer, nullptr);
							 | 
						||
| 
								 | 
							
								    vkFreeMemory(vkGPU->device, plan->m_bufferDeviceMemory, nullptr);
							 | 
						||
| 
								 | 
							
								}
							 |