I’ve been having some trouble with the VkGetDeviceQueue function.
I have a class for handling my vulkan instance, and variables.
#pragma once
#include <iostream>
#include <vulkan/vulkan.h>
#include <string>
#include "_Error.h"
#include "GLFW/glfw3.h"
using namespace std;
class vulkanHandler
{
private:
//Structure holding logic device information, queues, and the logical device
struct logicDevice
{
string type;
float Priority = 1.0f;
VkQueue graphicsQueue;
VkDevice device;
VkDeviceCreateInfo createInfo;
VkDeviceQueueCreateInfo Q_createInfo;
};
//Create a structure of queue counts since you can't have an vector with an array type.
struct queueCounts
{
int Graphics;
int Compute;
int Transfer;
int Sparce;
};
//define a struct to hold all of the device information for each GPU
struct GPUwrapper
{
VkPhysicalDevice Device; //Physical device
VkPhysicalDeviceProperties DeviceProperties; //It's properties
vector<VkQueueFamilyProperties> QueueProperties;//It's Queue properties
vector<queueCounts> queueCounts; //Queue counts per family. indicies will match with queueproperties
};
//Holds all the information relating to the instance;
struct instanceProperties
{
VkApplicationInfo appInfo;
VkInstanceCreateInfo createInfo;
vector<VkExtensionProperties> vulkanExtensions;
};
//Declarations
VkInstance instance; //The vulkan instance
instanceProperties instanceProperties; //It's corrosponding properties
vector<GPUwrapper> GPU; //A vector array of the available GPU's on the system
vector<logicDevice> logic; //A vector array of logic devices.
Console dev; //Creates a debug console(externally defined)
uint32_t glfwExtensionCount; //The required amount of extensions for glfw
uint32_t extensionCount; //Vulkan extensions
public:
vulkanHandler(GLFWwindow* Window)
{
//Upon declaring the vulkanHandler object this code will run. Initializing the instance
//We populate our ApplicationInfo variable with the proper information
instanceProperties.appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; //Structure Type
instanceProperties.appInfo.pApplicationName = "Game"; //Application Name
instanceProperties.appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); //Current version of the app
instanceProperties.appInfo.pEngineName = "beta"; //Engine name
instanceProperties.appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); //Build version
instanceProperties.appInfo.apiVersion = VK_API_VERSION_1_0; //Vulkan API version
//We attach the application info variable to the instance creation information variable
instanceProperties.createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; //Structure type
instanceProperties.createInfo.pApplicationInfo = &instanceProperties.appInfo; //Pointer to our appinfo var
const char** glfwExtensions; //the count of glfwExtension
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
//Amount of GLFW req extensions
instanceProperties.createInfo.enabledExtensionCount = glfwExtensionCount; //Tell the instance create info
instanceProperties.createInfo.ppEnabledExtensionNames = glfwExtensions; //About glfw extensions
instanceProperties.createInfo.enabledLayerCount = 0; //Total number of global layers
//Create an instance with the information we just populated.
if (!vkCreateInstance(&instanceProperties.createInfo, nullptr, &instance) == VK_SUCCESS) {
//If failed, log the failure
dev.Log("Failed to create Vulkan instance", { 3,VK_ERROR_INSTANCE });
//TODO !!! ADD ERROR CORRECTION ATTEMPTS, AND A COMPLETE FAIL CONDITION
}
//Get the required vulkan extensions and store them in a vector array for later.
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
instanceProperties.vulkanExtensions.resize(extensionCount);
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, instanceProperties.vulkanExtensions.data());
//After initializing the instance, we move to physical devices.
physicalDevice();
}
private:
void physicalDevice()
{
//Define temporary varibles that way we can push them to our arrays
VkPhysicalDeviceProperties buffer;
GPUwrapper gpuBuffer;
uint32_t intbuffer;
/*This will define the required structures that make up a physical device.*/
vkEnumeratePhysicalDevices(instance, &intbuffer, nullptr); //Querery cDevice
vector<VkPhysicalDevice> devicePool(intbuffer); //Vector array to hold the physical devices
vkEnumeratePhysicalDevices(instance, &intbuffer, devicePool.data()); //Populate
//Acquire the physical device properties for each device, and create a GPU for it.
for each (VkPhysicalDevice device in devicePool)
{
//Using the current device in the for look, we get it's corrosponding properties
vkGetPhysicalDeviceProperties(device, &buffer);
//Store the data to a buffer GPU object
gpuBuffer.Device = device; gpuBuffer.DeviceProperties = buffer;
//Get the properties for the available queue families.
vkGetPhysicalDeviceQueueFamilyProperties(device, &intbuffer, nullptr);
gpuBuffer.QueueProperties.resize(intbuffer);
vkGetPhysicalDeviceQueueFamilyProperties(device, &intbuffer, gpuBuffer.QueueProperties.data());
//Push the buffer to the stack, this will keep things organized.
GPU.push_back(gpuBuffer);
//Do I need to define new here? gpuBuffer = *new GPUwrapper;
//I only have 1 GPU, so I wouldn't see an error here if I needed another.
}
//After getting the physical devices, we're going to move on to the logical devices
primaryLogicDevice();
}
void primaryLogicDevice()
{
//buffer.device = * new VkDevice;
queueCounts buf;
logicDevice buffer;
/* procress The queue families information we acquired in physicalDevice() */
uint32_t G = 0, C = 0, T = 0, S = 0; //Store queue index with the greatest count of queues (Naive logic?)
//Buffer value
int i = 0;
for each (GPUwrapper gpu in GPU)
{
cout << gpu.DeviceProperties.deviceName _;
cout << gpu.DeviceProperties.apiVersion _;
//Reset the value of i since each GPU is it's own object and the parent of these children
i = 0;
for each (VkQueueFamilyProperties queueFamily in gpu.QueueProperties)
{
buf = *new queueCounts;
//For each device, and each QueueFamilyProperty, check it's functionality.
if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT)
{
//.Indicies.graphicIndicies.push_back(i); //And store away it's index
//gpu.Counts[0] += queueFamily.queueCount;
buf.Graphics = queueFamily.queueCount;
if (queueFamily.queueCount > G)
{
G = i;
}
}
if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_COMPUTE_BIT)
{
//gpu.Indicies.computeIndicies.push_back(i);
//gpu.Counts[1] += queueFamily.queueCount;
buf.Compute = queueFamily.queueCount;
if (queueFamily.queueCount > C)
{
C = i;
}
}
if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_TRANSFER_BIT)
{
//gpu.Indicies.transferIndicies.push_back(i);
//gpu.Counts[2] += queueFamily.queueCount;
buf.Transfer = queueFamily.queueCount;
if (queueFamily.queueCount > T)
{
T = i;
}
}
if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_SPARSE_BINDING_BIT)
{
//gpu.Indicies.sparceIndicies.push_back(i);
//gpu.Counts[3] += queueFamily.queueCount;
buf.Sparce = queueFamily.queueCount;
if (queueFamily.queueCount > S)
{
S = i;
}
}
//Since each device might have multiple queue gamilies, we'll incremement.
gpu.queueCounts.push_back(buf);
cout << " Queue Family: " << i _; //Note '_;' Is a #define for '<< endl'; Just my shorthand
cout << " Graphics: " << buf.Graphics _;
cout << " Compute: " << buf.Compute _;
cout << " Transfer: " << buf.Transfer _;
cout << " Sparce: " << buf.Sparce _;
i++;
buf.Compute = 0;
buf.Graphics = 0;
buf.Transfer = 0;
buf.Sparce = 0;
}
//Populate the required Structs to create the logic device, and queue
buffer.Q_createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
buffer.Q_createInfo.queueFamilyIndex = G; //Use the queue with the highest score for graphics
buffer.Q_createInfo.queueCount = 1; //Supposedly high queueCounts cause driver crashes?
buffer.Q_createInfo.pQueuePriorities = &buffer.Priority;//Queue priority
buffer.type = "Graphics"; //Populate the structure I made that holds logic device info
buffer.createInfo.enabledLayerCount = 0; //No validation layers yet :C
buffer.createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
buffer.createInfo.enabledExtensionCount = 0;
buffer.createInfo.pQueueCreateInfos = &buffer.Q_createInfo;
buffer.createInfo.pEnabledFeatures = NULL;
//Attempt to create the logic device.
if (vkCreateDevice(gpu.Device, &buffer.createInfo, NULL, &buffer.device) != VK_SUCCESS)
{
//If failed, cry about it and give up
dev.Log("You done goofed, kid");
}
cout << endl << "Logical device created with graphics queue" << endl;
logic.push_back(buffer); //Now that it's been created, add it to the pool of logic devices
for each(logicDevice device in logic) //For each logic device we have in logic(just one in this case)
{
if (device.type == "Graphics") //Which we explicitly stated was true earlier
{
//Try to bind the queue handler to our device.graphicsQueue variable
vkGetDeviceQueue(device.device, G, 0, &device.graphicsQueue); //TODO !!!!!! THROWS EXCEPTION
cout << "Bound queue to device" _;
}
}
}
}
public:
//TODO: KILLALL(), CLOSE(), CLEANUP() FUNCTIONS
};
Essentially my goal here is when I create a vulkanHandler object in my main function, it will set up the required information and then I can access the instance through helper functions, mitigating cluttered code.
I tend to run into trouble sometimes with pointers, so I believe that may be my issue.
The issue I’m running into, is after I call the VkGetDeviceQueue function, it returns the VkQueue object pointer as 0x00000000. I’ve attached watches on my objects and I see right before the function is called, everything seems to be correctly populated(except for functions, but I have function count at 0, could that be an issue?)
This of course throws an access write violation.
I think my issue may be with memory management. I’m just not sure what exactly.
I really would appreciate any help c: