{"record":{"id":"353d59bbbbfdc360","repo":"stride3d/stride","slug":"no-suitable-memory-type","errorCode":null,"errorMessage":"No suitable memory type","messagePattern":"No suitable memory type","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"critical","filePath":"sources/shaders/Stride.Shaders.Tests/FrameRenderer.Vulkan.cs","lineNumber":251,"sourceCode":"            queueCreateInfoCount = 1,\n            pQueueCreateInfos = &queueCreateInfo,\n            enabledExtensionCount = ppEnabledExtensionNames.Length,\n            ppEnabledExtensionNames = ppEnabledExtensionNames,\n        };\n        Check(instanceApi.vkCreateDevice(physicalDevice, in createInfo, null, out device));\n        deviceApi = new VkDeviceApi(instanceApi, in device);\n        deviceApi.vkGetDeviceQueue(device, queueFamily, 0, out queue);\n    }\n\n    private static uint FindMemoryType(uint typeBits, VkMemoryPropertyFlags required)\n    {\n        instanceApi.vkGetPhysicalDeviceMemoryProperties(physicalDevice, out var memoryProperties);\n        for (uint i = 0; i < memoryProperties.memoryTypeCount; i++)\n        {\n            if ((typeBits & (1u << (int)i)) != 0 && (memoryProperties.memoryTypes[(int)i].propertyFlags & required) == required)\n                return i;\n        }\n        throw new InvalidOperationException(\"No suitable memory type\");\n    }\n\n    private (VkBuffer Buffer, VkDeviceMemory Memory) CreateHostBuffer(ulong size, VkBufferUsageFlags usage, ReadOnlySpan<byte> data = default)\n    {\n        var createInfo = new VkBufferCreateInfo\n        {\n            sType = VkStructureType.BufferCreateInfo,\n            size = size,\n            usage = usage,\n            sharingMode = VkSharingMode.Exclusive,\n        };\n        Check(deviceApi.vkCreateBuffer(device, &createInfo, null, out var buffer));\n        deviceApi.vkGetBufferMemoryRequirements(device, buffer, out var requirements);\n        var allocateInfo = new VkMemoryAllocateInfo\n        {\n            sType = VkStructureType.MemoryAllocateInfo,\n            allocationSize = requirements.size,\n            memoryTypeIndex = FindMemoryType(requirements.memoryTypeBits, VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent),","sourceCodeStart":233,"sourceCodeEnd":269,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/shaders/Stride.Shaders.Tests/FrameRenderer.Vulkan.cs#L233-L269","documentation":"Thrown by FindMemoryType when scanning the physical device's memory properties and no memory type both satisfies the required type bits and carries all required property flags. Vulkan memory types are device-specific, so a combination like HOST_VISIBLE|HOST_COHERENT|DEVICE_LOCAL may simply not exist on a given GPU.","triggerScenarios":"Calling CreateHostBuffer/AllocateBuffer which computes a memoryTypeIndex from vkGetPhysicalDeviceMemoryProperties with (typeBits & (1<<i)) != 0 && (propertyFlags & required) == required; no type matches, so the loop falls through to the throw.","commonSituations":"Requesting DEVICE_LOCAL plus HOST_VISIBLE staging memory on devices with small BAR (no ReBAR); asking for properties no available type offers (e.g. HOST_CACHED on some iGPUs); passing wrong typeBits from vkGetBufferMemoryRequirements so allowed types exclude the desired properties.","solutions":["Relax the required property flags: for a host upload buffer, HOST_VISIBLE|HOST_COHERENT is usually enough — drop DEVICE_LOCAL from the requirement.","Two-step allocation: create a DEVICE_LOCAL device buffer and a separate HOST_VISIBLE staging buffer, then copy with vkCmdCopyBuffer.","Add a fallback pass in FindMemoryType that retries with a reduced `required` mask and logs the downgrade.","Dump memoryProperties (types and heaps) to confirm which property combinations the device actually supports."],"exampleFix":"// before\nvar (buffer, memory) = CreateHostBuffer(size, usage, data, required: VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);\n// after\nvar (buffer, memory) = CreateHostBuffer(size, usage, data, required: VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);","handlingStrategy":"fallback","validationCode":"static bool HasMemoryType(VkPhysicalDeviceMemoryProperties props, uint typeBits, VkMemoryPropertyFlags required)\n{\n    for (uint i = 0; i < props.memoryTypeCount; i++)\n        if ((typeBits & (1u << (int)i)) != 0 && (props.memoryTypes[i].propertyFlags & required) == required)\n            return true;\n    return false;\n}","typeGuard":null,"tryCatchPattern":"try\n{\n    AllocateBuffer(size, usage, required);\n}\ncatch (InvalidOperationException ex) when (ex.Message == \"No suitable memory type\")\n{\n    AllocateBuffer(size, usage, required & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); // relax and retry\n}","preventionTips":["Never require DEVICE_LOCAL together with HOST_VISIBLE unless you've verified ReBAR/large-BAR support.","Cache the device's memory properties once and consult them when choosing flags.","Design allocations as staging+device-local pairs instead of one buffer with all properties."],"tags":["vulkan","memory","allocation"],"backgroundTag":"resource-not-found","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}