Using Vulkan memory allocator with Volk - c++

I'm currently trying to use Vulkan memory allocator with the meta loader Volk
here is the link of the two: https://github.com/zeux/volk
https://gpuopen.com/vulkan-memory-allocator/
But I have trouble with creating the VmaAllocator, here is my code:
void VulkApp::Init(PipelineFlags t_Conf, entt::registry& t_reg)
{
volkInitialize();
WindowProps props = {};
props.Height = 600;
props.Width = 800;
props.Title = "Engine";
currentWindow = EngWindow::Create(props);
//Create all physical, logical, instance for vulkan
Prepare();
VolkDeviceTable test;
volkLoadDeviceTable(&test, m_LogicalDevice->GetVkDevice());
VmaAllocatorCreateInfo allocatorCreateInfo = {};
allocatorCreateInfo.vulkanApiVersion = VK_API_VERSION_1_2;
allocatorCreateInfo.physicalDevice = m_PhysicalDevice->GetVkPhysicalDevice();
allocatorCreateInfo.device = m_LogicalDevice->GetVkDevice();
allocatorCreateInfo.instance = m_Instance->GetRawVkInstance();
allocatorCreateInfo.pVulkanFunctions = reinterpret_cast<const VmaVulkanFunctions*> (&test);
VmaAllocator allocator;
vmaCreateAllocator(&allocatorCreateInfo, &allocator);
BuildRenderPipelines(t_Conf, t_reg);
}
void VulkApp::Prepare()
{
m_Instance = std::make_unique<VulkInst>();
volkLoadInstance(m_Instance->GetRawVkInstance());
currentWindow->CreateSurface(m_Instance->GetRawVkInstance(), &m_Surface);
m_PhysicalDevice = std::make_unique<PhysicalDevice>(*m_Instance);
m_LogicalDevice = std::make_unique<LogicalDevice>(*m_Instance, *m_PhysicalDevice, m_Surface);
volkLoadDevice(m_LogicalDevice->GetVkDevice());
m_SwapChain = std::make_unique<SwapChain>(ChooseSwapExtent(), *m_LogicalDevice, *m_PhysicalDevice, m_Surface);
GraphicsHelpers::CreateCommandPool(m_CommandPool, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); //TODO: added Transient bit
CreateFrameSyncResources();
/*
Create Camera
*/
BuildSwapChainResources();
}
I don't have any error when i build, but when i execute, the VmaCreateAllocator return an error:
Exception raised at 0x00007FFAB0CD836B (VkLayer_khronos_validation.dll) in My_Game.exe : 0xC0000005 : access violation reading location 0x0000000000000120.
Not very useful, but it stops on the line 14082 of the file vk_mem_alloc.h:
(*m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties)(m_PhysicalDevice, &m_MemProps);
The program check all the vulkan validation function so my vulkan function table must be good. But still the allocation fail.
I'm sorry i don't put a 'minimal' code, but with vulkan, even the minimum is really long. So, as a first test, maybe some of you have an insight of the error?

If you use a loader like Volk, you need to provide all memory related Vulkan function pointers used by VMA yourself.
This is done via the pVulkanFunctions member of the VmaAllocatorCreateInfo structure.
So when creating your VmaAllactor you set the function pointer in that to those fetched via Volk like this:
VmaVulkanFunctions vma_vulkan_func{};
vma_vulkan_func.vkAllocateMemory = vkAllocateMemory;
vma_vulkan_func.vkBindBufferMemory = vkBindBufferMemory;
vma_vulkan_func.vkBindImageMemory = vkBindImageMemory;
vma_vulkan_func.vkCreateBuffer = vkCreateBuffer;
vma_vulkan_func.vkCreateImage = vkCreateImage;
vma_vulkan_func.vkDestroyBuffer = vkDestroyBuffer;
vma_vulkan_func.vkDestroyImage = vkDestroyImage;
vma_vulkan_func.vkFlushMappedMemoryRanges = vkFlushMappedMemoryRanges;
vma_vulkan_func.vkFreeMemory = vkFreeMemory;
vma_vulkan_func.vkGetBufferMemoryRequirements = vkGetBufferMemoryRequirements;
vma_vulkan_func.vkGetImageMemoryRequirements = vkGetImageMemoryRequirements;
vma_vulkan_func.vkGetPhysicalDeviceMemoryProperties = vkGetPhysicalDeviceMemoryProperties;
vma_vulkan_func.vkGetPhysicalDeviceProperties = vkGetPhysicalDeviceProperties;
vma_vulkan_func.vkInvalidateMappedMemoryRanges = vkInvalidateMappedMemoryRanges;
vma_vulkan_func.vkMapMemory = vkMapMemory;
vma_vulkan_func.vkUnmapMemory = vkUnmapMemory;
vma_vulkan_func.vkCmdCopyBuffer = vkCmdCopyBuffer;
And then pass those to the create info:
VmaAllocatorCreateInfo allocator_info{};
...
allocator_info.pVulkanFunctions = &vma_vulkan_func;

Related

Is there anyway to set the VkDescriptorImageInfo to null or have some way of skipping using a VkWriteDescriptorSet without vulkan complaining

Some of the mesh that I'll be using doesn't always have a DiffuseMap or a SpecularMap. When I try to load something without a diffuse and specular map the program crashes because there's nothing in the DiffuseMap.ImageView/SpecularMap.ImageView because it isn't pointing to anything. If I try to set the imageview/sample to VK_NULL_HANDLE the program gives me this and crashes at the vkUpdateDescriptorSets:
Validation Layer: Invalid VkImageView Object 0x0. The Vulkan spec states: If descriptorType is VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, or VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, the imageView and imageLayout members of each element of pImageInfo must be a valid VkImageView and VkImageLayout, respectively (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkWriteDescriptorSet-descriptorType-00326)
Then if I just try set the binding to null, I get this:
Validation Layer: vkUpdateDescriptorSets: required parameter pDescriptorWrites[2].dstSet specified as VK_NULL_HANDLE
Validation Layer: Cannot call vkUpdateDescriptorSets() on VkDescriptorSet 0x0[] that has not been allocated.
This is what the base code looks like right now. This is the area that defines the descriptor sets to make it bit easier to see what's going on:
void Mesh::CreateDescriptorSets(VulkanRenderer& Renderer)
{
BaseMesh::CreateDescriptorSets(Renderer, *GetDescriptorSetLayout(Renderer));
VkDescriptorImageInfo DiffuseMap = {};
DiffuseMap.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
DiffuseMap.imageView = TextureList[0].textureImageView;
DiffuseMap.sampler = TextureList[0].textureSampler;
VkDescriptorImageInfo SpecularMap = {};
SpecularMap.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
SpecularMap.imageView = TextureList[1].textureImageView;
SpecularMap.sampler = TextureList[1].textureSampler;
for (size_t i = 0; i < GetSwapChainImageCount(Renderer); i++)
{
VkDescriptorBufferInfo PositionInfo = {};
PositionInfo.buffer = uniformBuffers[i];
PositionInfo.offset = 0;
PositionInfo.range = sizeof(UniformBufferObject);
VkDescriptorBufferInfo AmbiantLightInfo = {};
AmbiantLightInfo.buffer = AmbientLightUniformBuffers[i];
AmbiantLightInfo.offset = 0;
AmbiantLightInfo.range = sizeof(AmbientLightUniformBuffer);
VkDescriptorBufferInfo LightInfo = {};
LightInfo.buffer = LighterUniformBuffers[i];
LightInfo.offset = 0;
LightInfo.range = sizeof(Lighter);
std::array<WriteDescriptorSetInfo, 5> WriteDescriptorInfo = {};
WriteDescriptorInfo[0].DstBinding = 0;
WriteDescriptorInfo[0].DstSet = descriptorSets[i];
WriteDescriptorInfo[0].DescriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
WriteDescriptorInfo[0].DescriptorBufferInfo = PositionInfo;
WriteDescriptorInfo[1].DstBinding = 1;
WriteDescriptorInfo[1].DstSet = descriptorSets[i];
WriteDescriptorInfo[1].DescriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
WriteDescriptorInfo[1].DescriptorImageInfo = DiffuseMap;
WriteDescriptorInfo[2].DstBinding = 2;
WriteDescriptorInfo[2].DstSet = descriptorSets[i];
WriteDescriptorInfo[2].DescriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
WriteDescriptorInfo[2].DescriptorImageInfo = SpecularMap;
WriteDescriptorInfo[3].DstBinding = 3;
WriteDescriptorInfo[3].DstSet = descriptorSets[i];
WriteDescriptorInfo[3].DescriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
WriteDescriptorInfo[3].DescriptorBufferInfo = AmbiantLightInfo;
WriteDescriptorInfo[4].DstBinding = 4;
WriteDescriptorInfo[4].DstSet = descriptorSets[i];
WriteDescriptorInfo[4].DescriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
WriteDescriptorInfo[4].DescriptorBufferInfo = LightInfo;
Mesh::CreateDescriptorSetsData(Renderer, std::vector<WriteDescriptorSetInfo>(WriteDescriptorInfo.begin(), WriteDescriptorInfo.end()));
}
}
Until Vulkan 1.2, Vulkan did not recognize the possibility of a descriptor being "empty". When a descriptor set is created, the descriptors are (mostly) uninitialized. It's OK to have a set with an uninitialized descriptor, so long as the pipeline which consumes it does not statically use the descriptor. Since you are presumably trying to use the same pipeline for objects with diffuse maps and objects without them, your shader reads from the image based on a variable you provide. That represents static use of the descriptor, so you need an image there.
The typical way to deal with this is to create a tiny image of a reasonable format and stuff that into the descriptor. You can use the same image for essentially any "null" texture you want to use.
Vulkan 1.2, as part of the VK_EXT_descriptor_indexing extension promoted to core, allows for the possibility of partially bound descriptors. Basically, if the descriptorBindingPartiallyBound feature is available and requested, then you can allocate a descriptor set using the VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT bit. This means that it's OK to leave a descriptor undefined so long as it is not dynamically used.
So you simply wouldn't write a value for that descriptor.
Of course, this requires 1.2 (or the aforementioned extension), as well as requesting the feature.
You are not quite correct, a combined image sampler still requires a valid sampler for some reason, and not only that, a nullDescriptor functionality have to be enabled. I run into exactly the same problem. What noone ever tells is that partly bound descriptors is not the same as sparsly bound descriptors, so it basicaly means y can bind X descriptors out of N if X<N but all those X must be valid, the specs is realy thin on this and there is no good examples.

Is there a method available for UWP apps to get available disk space

I am working on a UWP app that depends on available storage space, and would like to have that information prior to a save fail. I have tried the RetrievePropertiesAsync calls on the known folders, but do not get a Freespace or Capacity property in the resultant list. Is there a method available for this?
Code used to access properties:
auto basicProperties = co_await videosFolder->GetBasicPropertiesAsync();
auto retrievedProperties = co_await basicProperties->RetrievePropertiesAsync(propertiesToRetrieve);
unsigned long freeSpace = retrievedProperties->Size;
auto it = retrievedProperties->First();
bool validData = (it != nullptr);
while (validData)
{
String^ text = it->Current->Key;
validData = it->MoveNext();
}

LibCinder: Default Variable Names for Shader Parameters

I've been working through the
OpenGL guide for libCinder, in particular the shaders section.
Unfortunately, libCinder doesn't use the OpenGL variable names for default inputs to vertex and fragment shaders. E.g., gl_position is remapped to ciPosition.
Can anyone provide a list with a mapping from OpenGL to libCinder input variable names?
This is not the cleanest way, but you can see them inside the source code here:
sDefaultAttribNameToSemanticMap["ciPosition"] = geom::Attrib::POSITION;
sDefaultAttribNameToSemanticMap["ciNormal"] = geom::Attrib::NORMAL;
sDefaultAttribNameToSemanticMap["ciTangent"] = geom::Attrib::TANGENT;
sDefaultAttribNameToSemanticMap["ciBitangent"] = geom::Attrib::BITANGENT;
sDefaultAttribNameToSemanticMap["ciTexCoord0"] = geom::Attrib::TEX_COORD_0;
sDefaultAttribNameToSemanticMap["ciTexCoord1"] = geom::Attrib::TEX_COORD_1;
sDefaultAttribNameToSemanticMap["ciTexCoord2"] = geom::Attrib::TEX_COORD_2;
sDefaultAttribNameToSemanticMap["ciTexCoord3"] = geom::Attrib::TEX_COORD_3;
sDefaultAttribNameToSemanticMap["ciColor"] = geom::Attrib::COLOR;
sDefaultAttribNameToSemanticMap["ciBoneIndex"] = geom::Attrib::BONE_INDEX;
sDefaultAttribNameToSemanticMap["ciBoneWeight"] = geom::Attrib::BONE_WEIGHT;
And also:
sDefaultUniformNameToSemanticMap["ciModelMatrix"] = UNIFORM_MODEL_MATRIX;
sDefaultUniformNameToSemanticMap["ciModelMatrixInverse"] = UNIFORM_MODEL_MATRIX_INVERSE;
sDefaultUniformNameToSemanticMap["ciModelMatrixInverseTranspose"] = UNIFORM_MODEL_MATRIX_INVERSE_TRANSPOSE;
sDefaultUniformNameToSemanticMap["ciViewMatrix"] = UNIFORM_VIEW_MATRIX;
sDefaultUniformNameToSemanticMap["ciViewMatrixInverse"] = UNIFORM_VIEW_MATRIX_INVERSE;
sDefaultUniformNameToSemanticMap["ciModelView"] = UNIFORM_MODEL_VIEW;
sDefaultUniformNameToSemanticMap["ciModelViewInverse"] = UNIFORM_MODEL_VIEW_INVERSE;
sDefaultUniformNameToSemanticMap["ciModelViewInverseTranspose"] = UNIFORM_MODEL_VIEW_INVERSE_TRANSPOSE;
sDefaultUniformNameToSemanticMap["ciModelViewProjection"] = UNIFORM_MODEL_VIEW_PROJECTION;
sDefaultUniformNameToSemanticMap["ciModelViewProjectionInverse"] = UNIFORM_MODEL_VIEW_PROJECTION_INVERSE;
sDefaultUniformNameToSemanticMap["ciProjectionMatrix"] = UNIFORM_PROJECTION_MATRIX;
sDefaultUniformNameToSemanticMap["ciProjectionMatrixInverse"] = UNIFORM_PROJECTION_MATRIX_INVERSE;
sDefaultUniformNameToSemanticMap["ciViewProjection"] = UNIFORM_VIEW_PROJECTION;
sDefaultUniformNameToSemanticMap["ciNormalMatrix"] = UNIFORM_NORMAL_MATRIX;
sDefaultUniformNameToSemanticMap["ciViewportMatrix"] = UNIFORM_VIEWPORT_MATRIX;
sDefaultUniformNameToSemanticMap["ciWindowSize"] = UNIFORM_WINDOW_SIZE;
sDefaultUniformNameToSemanticMap["ciElapsedSeconds"] = UNIFORM_ELAPSED_SECONDS;

Trouble creating pointer to abstract class

I coded some smiley faces into my app recently, but I'm having trouble calling it in my option interface. The reason I'm wanting to call it from optioninterface is I want to add 2 sets of emojis, and if the value of Setting.nEmoji is 0 or 1 call a different set. The function loademojis() gets called when the application starts (it's technically coded in the interface solution). I can call it from a function that handles user input, but it generated horrible lag, I assume because each time a letter was typed, it cleared the array and loaded the emojis in again. So long story short, I was wondering if there's any way at all to create a pointer to a abstract class so I could call this from my option menu. Everytime I create a pointer and call it from theoption menu it crashes. Here's how I'm creating the pointer
MDrawContext* pDC
void MDrawContext::LoadEmojis()
{
if (Z_VIDEO_EMOJIS == 1)
{
m_Emoji[";)"] = "wink.png";
m_Emoji[":)"] = "smile.png";
m_Emoji[":D"] = "biggrin.png";
m_Emoji[":("] = "frown.png";
m_Emoji[":O"] = "eek.png";
m_Emoji[":P"] = "tongue.png";
m_Emoji[":?"] = "confused.png";
m_Emoji[":4"] = "cool.png";
m_Emoji[":3"] = "redface.png";
m_Emoji[":#"] = "mad.png";
m_Emoji[":I"] = "rolleyes.png";
m_Emoji[":K"] = "kappa.png";
}
else
{
m_Emoji[";)"] = "wink2.png";
m_Emoji[":)"] = "smile2.png";
m_Emoji[":D"] = "biggrin2.png";
m_Emoji[":("] = "frown2.png";
m_Emoji[":O"] = "eek2.png";
m_Emoji[":P"] = "tongue2.png";
}
}
//custom: reloademojis allows players to choose between ios/forum emojis
void MDrawContext::ReloadEmojis()
{
m_Emoji[";)"].clear();
m_Emoji[":)"].clear();
m_Emoji[":D"].clear();
m_Emoji[":("].clear();
m_Emoji[":O"].clear();
m_Emoji[":P"].clear();
m_Emoji[":?"].clear();
m_Emoji[":4"].clear();
m_Emoji[":3"].clear();
m_Emoji[":#"].clear();
m_Emoji[":I"].clear();
m_Emoji[":K"].clear();
LoadEmojis();
}
//Calling the pointer (different cpp)
int nEmojiType = 0;
if(nEmojiType != Z_VIDEO_EMOJI)
{
pDC->ReloadEmojis();
nEmojiType = Z_VIDEO_EMOJI;
}

Dynamics GP Web Services: SalesInvoice Creation with Lot Allocation

I'm trying to use the following code to create a new SalesInvoice based on an existing SalesOrder:
SalesInvoice invoice = new SalesInvoice();
invoice.DocumentTypeKey = new SalesDocumentTypeKey { Type = SalesDocumentType.Invoice };
invoice.CustomerKey = originalOrder.CustomerKey;
invoice.BatchKey = originalOrder.BatchKey;
invoice.Terms = new SalesTerms { DiscountTakenAmount = new MoneyAmount { Value = 0, Currency = "USD", DecimalDigits = 2 }, DiscountAvailableAmount = new MoneyAmount { Value = 0, Currency = "USD", DecimalDigits = 0 } };
invoice.OriginalSalesDocumentKey = originalOrder.Key;
List<SalesInvoiceLine> lineList = new List<SalesInvoiceLine>();
for (int i = 0; i < originalOrder.Lines.Length; i++)
{
SalesInvoiceLine line = new SalesInvoiceLine();
line.ItemKey = originalOrder.Lines[i].ItemKey;
line.Key = new SalesLineKey { LineSequenceNumber = originalOrder.Lines[i].Key.LineSequenceNumber; }
SalesLineLot lot = new SalesLineLot();
lot.LotNumber = originalOrder.Lines[i].Lots[0].LotNumber;
lot.Quantity = new Quantity { Value = 2200 };
lot.Key = new SalesLineLotKey { SequenceNumber = originalOrder.Lines[i].Lots[0].Key.SequenceNumber };
line.Lots = new SalesLineLot[] { lot };
line.Quantity = new Quantity { Value = 2200 };
lineList.Add(line);
}
invoice.Lines = lineList.ToArray();
DynamicsWS.CreateSalesInvoice(invoice, DynamicsContext, DynamicsWS.GetPolicyByOperation("CreateSalesInvoice", DynamicsContext));
When executed, I receive the following error:
SQL Server Exception: Operation expects a parameter which was not supplied.
And the more detailed exception from the Exception Console in Dynamics:
Procedure or function 'taSopLotAuto' expects parameter '#I_vLNITMSEQ',
which was not supplied.
After a considerable amount of digging through Google, I discovered a few things.
'taSopLotAuto' is an eConnect procedure within the Sales Order Processing component that attempts to automatically fill lots. I do not want the lots automatically filled, which is why I try to fill them manually in the code. I've also modified the CreateSalesInvoice policy from Automatic lot fulfillment to Manual lot fulfillment for the GP web services user, but that didn't change which eConnect procedure was called.
'#I_vLNITMSEQ' refers to the LineSequenceNumber. The LineSequenceNumber and SequenceNumber (of the Lot itself) must match. In my case they are both the default: 16384. Not only is this parameter set in the code above, but it also appears in the SOAP message that the server attempted to process - hardly "not supplied."
I can create an invoice sans line items without a hitch, but if I add line items it fails. I do not understand why I am receiving an error for a missing parameter that is clearly present.
Any ideas on how to successfully create a SalesInvoice through Dynamics GP 10.0 Web Services?
Maybe you mess to add the line key to the lot:
lot.Key = new SalesLineKey();
lot.Key.SalesDocumentKey = new SalesDocumentKey();
lot.Key.SalesDocumentKey.Id = seq.ToString();