Memory type index selection table is broken

Selection of device local heap on the current NV driver 368.81 is broken. I have been able to recreate the problem using the lunarg cube demo by forcing texture upload to always use the staging textures path.

On the current NV driver 368.81, the memory type selection table is as follows on a 650M:

BEGINNING HEAP DUMP: HEAP_COUNT = 2, TYPE_COUNT = 11
HEAP INDEX 0, flags = 1, size= 536870912
HEAP INDEX 1, flags = 0, size= 4229955584
MEMORY TYPE 0, flags = 0, heap= 1
MEMORY TYPE 1, flags = 0, heap= 1
MEMORY TYPE 2, flags = 0, heap= 1
MEMORY TYPE 3, flags = 0, heap= 1
MEMORY TYPE 4, flags = 0, heap= 1
MEMORY TYPE 5, flags = 0, heap= 1
MEMORY TYPE 6, flags = 0, heap= 1
MEMORY TYPE 7, flags = 1, heap= 0
MEMORY TYPE 8, flags = 1, heap= 0
MEMORY TYPE 9, flags = 6, heap= 1
MEMORY TYPE 10, flags = 14, heap= 1
SELECTED: Device Local = 7, Host_Visible = 10

A straightforward algorithm will pick index 7 for device local memory which will crash the driver upon use.
However, while using memory type 7 will result in a crash, type index 8 works fine despite the fact that there is no difference in the flags and heap index. The cube demo uses the first viable memory type and therefore also hits the same issue.

EDIT: Issue appears with driver version 368.69 by the way.

I just checked with 368.81 on my GTX980 (Windows 10, x64) and everything works fine. My examples do staging and getting a device local buffer from index 7 works fine.

It actually shouldn’t make a difference if you request a device local buffer from mem type 7 or 8 since they both refer to the same device local heap.

According to https://github.com/RPCS3/rpcs3/issues/1922#issuecomment-233139208
setting index type to 8 results in different behaviour than 7 although it should not. I also uploaded the cube test there and it was confirmed to crash on nvidia.

Code that reliably crashes NV here: http://pastebin.com/p17rLYKt
I simply added an "if (0 && " to always use the staging path regardless of whether the arg was set or not.

Where did you take that source from? It contains lots of errors, and if you enable the validation layers you get this one during the staging part:

Cannot map an image with layout VK_IMAGE_LAYOUT_UNDEFINED. Only GENERAL or PREINITIALIZED are supported.

so the staging part in that example is simply wrong and what’s causing the crash as the device gets lost during presentation (which I could reproduce on my GTX 980).

Using the recent version of that example from LunarG’s repository works fine with staging, even on NVIDIA.

One hint tough: That example uses linear tiled images as the source for staging. That’s not optimal and it’s advises to stage from a buffer instead of an image.

The source was just to trigger that error. Its from the original vulkan cube demo from launch, although I may have tinkered with it when I was still learning the api back then.

All this is because I’m trying to pinpoint an nvidia specific crash on the rpcs3 emulator project and is thus much more difficult to show here. NV crashes with newer drivers and when someone was regress testing they found that selecting memory type 8 instead of 7 from the table I posted above “fixed” the error although theoretically there should be no difference.

Issue is resolved for me.

I misunderstood the significance of the type index, assuming that memory types with similar flags and the same heap were substitutable.

Similarly, a test example that I wrote allocates memory on a 1080 Ti and slices it into buffers. If i use memory type 7, the application works. If i choose type 8, the application crashes with an illegal access in the nVidia driver (398.11).

Memory Types 11
[0] Property Flags --NONE–
Heap Index 1
[1] Property Flags --NONE–
Heap Index 1
[2] Property Flags --NONE–
Heap Index 1
[3] Property Flags --NONE–
Heap Index 1
[4] Property Flags --NONE–
Heap Index 1
[5] Property Flags --NONE–
Heap Index 1
[6] Property Flags --NONE–
Heap Index 1
[7] Property Flags DEVICE_LOCAL
Heap Index 0
[8] Property Flags DEVICE_LOCAL
Heap Index 0
[9] Property Flags HOST_VISIBLE | HOST_COHERENT
Heap Index 1
[10] Property Flags HOST_VISIBLE | HOST_COHERENT | HOST_CACHED
Heap Index 1

You are pretty much forced to discover the correct memory type for an allocation since it depends on the resources you want to bind to it. Each resource has an allowed set of memory types in VkMemoryRequirements::memoryTypeBits returned from vkGet*MemoryRequirements. For example, two buffers with different usages may have different allowed memory types. You need to filter the available memory types for the device memory based on the memoryTypeBits of the resources you want to bind to it.

Thank you virtual_storm! I was unaware of vkGetBufferMemoryRequirements.

This solves my issue, as memory type 8 is unsupported for buffers on my graphics card.