## 11.6. Resource Memory Association

Resources are initially created as virtual allocations with no backing memory. Device memory is allocated separately (see Section 10.2, “Device Memory”) and then associated with the resource. This association is done differently for sparse and non-sparse resources.

Resources created with any of the sparse creation flags are considered sparse resources. Resources created without these flags are non-sparse. The details on resource memory association for sparse resources is described in Chapter 28, Sparse Resources.

Non-sparse resources must be bound completely and contiguously to a single `VkDeviceMemory` object before the resource is passed as a parameter to any of the following operations:

- creating image or buffer views
- updating descriptor sets
- recording commands in a command buffer

Once bound, the memory binding is immutable for the lifetime of the resource.

To determine the memory requirements for a buffer resource, call:

    void vkGetBufferMemoryRequirements(
        VkDevice                                    device,
        VkBuffer                                    buffer,
        VkMemoryRequirements*                       pMemoryRequirements);

- `device` is the logical device that owns the buffer.
- `buffer` is the buffer to query.
- `pMemoryRequirements` points to an instance of the `VkMemoryRequirements` structure in which the memory requirements of the buffer object are returned.

To determine the memory requirements for an image resource, call:

    void vkGetImageMemoryRequirements(
        VkDevice                                    device,
        VkImage                                     image,
        VkMemoryRequirements*                       pMemoryRequirements);

- `device` is the logical device that owns the image.
- `image` is the image to query.
- `pMemoryRequirements` points to an instance of the `VkMemoryRequirements` structure in which the memory requirements of the image object are returned.

The `VkMemoryRequirements` structure is defined as:

    typedef struct VkMemoryRequirements {
        VkDeviceSize    size;
        VkDeviceSize    alignment;
        uint32_t        memoryTypeBits;
    } VkMemoryRequirements;

- `size` is the size, in bytes, of the memory allocation required for the resource.
- `alignment` is the alignment, in bytes, of the offset within the allocation required for the resource.
- `memoryTypeBits` is a bitmask and contains one bit set for every supported memory type for the resource. Bit `i` is set if and only if the memory type `i` in the `VkPhysicalDeviceMemoryProperties` structure for the physical device is supported for the resource.

The implementation guarantees certain properties about the memory requirements returned by `vkGetBufferMemoryRequirements` and `vkGetImageMemoryRequirements`:

- The `memoryTypeBits` member always contains at least one bit set.
- If `buffer` is a `VkBuffer` not created with the `VK_BUFFER_CREATE_SPARSE_BINDING_BIT` bit set, or if `image` is a `VkImage` that was created with a `VK_IMAGE_TILING_LINEAR` value in the `tiling` member of the `VkImageCreateInfo` structure passed to `vkCreateImage`, then the `memoryTypeBits` member always contains at least one bit set corresponding to a `VkMemoryType` with a `propertyFlags` that has both the `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` bit and the `VK_MEMORY_PROPERTY_HOST_COHERENT_BIT` bit set. In other words, mappable coherent memory can always be attached to these objects.
- The `memoryTypeBits` member always contains at least one bit set corresponding to a `VkMemoryType` with a `propertyFlags` that has the `VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT` bit set.
- The `memoryTypeBits` member is identical for all `VkBuffer` objects created with the same value for the `flags` and `usage` members in the `VkBufferCreateInfo` structure passed to `vkCreateBuffer`. Further, if `usage1` and `usage2` of type `VkBufferUsageFlags` are such that the bits set in `usage2` are a subset of the bits set in `usage1`, and they have the same `flags`, then the bits set in `memoryTypeBits` returned for `usage1` must be a subset of the bits set in `memoryTypeBits` returned for `usage2`, for all values of `flags`.
- The `alignment` member is identical for all `VkBuffer` objects created with the same combination of values for the `usage` and `flags` members in the `VkBufferCreateInfo` structure passed to `vkCreateBuffer`.
- The `memoryTypeBits` member is identical for all `VkImage` objects created with the same combination of values for the `tiling` member and the `VK_IMAGE_CREATE_SPARSE_BINDING_BIT` bit of the `flags` member and the `VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT` of the `usage` member in the `VkImageCreateInfo` structure passed to `vkCreateImage`.
- If the memory requirements are for a `VkImage`, the `memoryTypeBits` member must not refer to a `VkMemoryType` with a `propertyFlags` that has the `VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT` bit set if the `vkGetImageMemoryRequirements`::`image` did not have `VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT` bit set in the `usage` member of the `VkImageCreateInfo` structure passed to `vkCreateImage`.

- If the memory requirements are for a `VkBuffer`, the `memoryTypeBits` member must not refer to a `VkMemoryType` with a `propertyFlags` that has the `VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT` bit set.

  | Note
  The implication of this requirement is that lazily allocated memory is disallowed for buffers in all cases.

To attach memory to a buffer object, call:

    VkResult vkBindBufferMemory(
        VkDevice                                    device,
        VkBuffer                                    buffer,
        VkDeviceMemory                              memory,
        VkDeviceSize                                memoryOffset);

- `device` is the logical device that owns the buffer and memory.
- `buffer` is the buffer.
- `memory` is a `VkDeviceMemory` object describing the device memory to attach.
- `memoryOffset` is the start offset of the region of `memory` which is to be bound to the buffer. The number of bytes returned in the `VkMemoryRequirements`::`size` member in `memory`, starting from `memoryOffset` bytes, will be bound to the specified buffer.

To attach memory to an image object, call:

    VkResult vkBindImageMemory(
        VkDevice                                    device,
        VkImage                                     image,
        VkDeviceMemory                              memory,
        VkDeviceSize                                memoryOffset);

- `device` is the logical device that owns the image and memory.
- `image` is the image.
- `memory` is the a `VkDeviceMemory` object describing the device memory to attach.
- `memoryOffset` is the start offset of the region of `memory` which is to be bound to the image. The number of bytes returned in the `VkMemoryRequirements`::`size` member in `memory`, starting from `memoryOffset` bytes, will be bound to the specified image.

Buffer-Image Granularity. There is an implementation-dependent limit, `bufferImageGranularity`, which specifies a page-like granularity at which buffer, linear image and optimal image resources must be placed in adjacent memory locations to avoid aliasing. Two resources which do not satisfy this granularity requirement are said to alias. Linear image resource are images created with `VK_IMAGE_TILING_LINEAR` and optimal image resources are those created with `VK_IMAGE_TILING_OPTIMAL`. `bufferImageGranularity` is specified in bytes, and must be a power of two. Implementations which do not require such an additional granularity may report a value of one.

| Note
`bufferImageGranularity` is really a granularity between "linear" resources, including buffers and images with linear tiling, vs. "optimal" resources, i.e. images with optimal tiling. It would have been better named "linearOptimalGranularity".

Given resourceA at the lower memory offset and resourceB at the higher memory offset in the same `VkDeviceMemory` object, where one of the resources is a buffer or a linear image and the other is an optimal image, and the following:

    resourceA.end       = resourceA.memoryOffset + resourceA.size - 1
    resourceA.endPage   = resourceA.end & ~(bufferImageGranularity-1)
    resourceB.start     = resourceB.memoryOffset
    resourceB.startPage = resourceB.start & ~(bufferImageGranularity-1)

The following property must hold:

    resourceA.endPage < resourceB.startPage

That is, the end of the first resource (A) and the beginning of the second resource (B) must be on separate “pages” of size `bufferImageGranularity`. `bufferImageGranularity` may be different than the physical page size of the memory heap. This restriction is only needed when a buffer or a linear image is at adjacent memory location with an optimal image and both will be used simultaneously. Adjacent buffers' or adjacent images' memory ranges can be closer than `bufferImageGranularity`, provided they meet the `alignment` requirement for the objects in question.

Sparse block size in bytes and sparse image and buffer memory alignments must all be multiples of the `bufferImageGranularity`. Therefore, memory bound to sparse resources naturally satisfies the `bufferImageGranularity`.