Vulkan-Docs/doc/specs/vulkan/chapters/sparsemem.txt

1576 lines
67 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright (c) 2015-2016 The Khronos Group Inc.
// Copyright notice at https://www.khronos.org/registry/speccopyright.html
[[sparsememory]]
= Sparse Resources
As documented in <<resources-association,Resource Memory Association>>,
sname:VkBuffer and sname:VkImage resources in Vulkan must: be bound
completely and contiguously to a single sname:VkDeviceMemory object.
This binding must: be done before the resource is used, and the
binding is immutable for the lifetime of the resource.
_Sparse resources_ relax these restrictions and provide these additional
features:
* Sparse resources can: be bound non-contiguously to one or more
sname:VkDeviceMemory allocations.
* Sparse resources can: be re-bound to different memory allocations over
the lifetime of the resource.
* Sparse resources can: have descriptors generated and used orthogonally
with memory binding commands.
[[sparsememory-sparseresourcefeatures]]
== Sparse Resource Features
Sparse resources have several features that must: be enabled explicitly at
resource creation time. The features are enabled by including bits in the
pname:flags parameter of slink:VkImageCreateInfo or
slink:VkBufferCreateInfo. Each feature also has one or more corresponding
feature enables specified in slink:VkPhysicalDeviceFeatures.
* <<features-features-sparseBinding,Sparse binding>> is the base
feature, and provides the following capabilities:
** Resources can: be bound at some defined (sparse block) granularity.
** The entire resource must: be bound to memory before use regardless of
regions actually accessed.
** No specific mapping of image region to memory offset is defined, i.e.
the location that each texel corresponds to in memory is
implementation-dependent.
** Sparse buffers have a well-defined mapping of buffer range to memory
range, where an offset into a range of the buffer that is bound to
a single contiguous range of memory corresponds to an identical offset
within that range of memory.
** Requested via the ename:VK_IMAGE_CREATE_SPARSE_BINDING_BIT and
ename:VK_BUFFER_CREATE_SPARSE_BINDING_BIT bits.
** A sparse image created using ename:VK_IMAGE_CREATE_SPARSE_BINDING_BIT
(but not ename:VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT) supports all
formats that non-sparse usage supports, and supports both
ename:VK_IMAGE_TILING_OPTIMAL and ename:VK_IMAGE_TILING_LINEAR tiling.
* _Sparse Residency_ builds on (and requires) the pname:sparseBinding
feature. It includes the following capabilities:
** Resources do not have to be completely bound to memory before use on
the device.
** Images have a prescribed sparse image block layout, allowing specific
rectangular regions of the image to be bound to specific offsets in
memory allocations.
** Consistency of access to unbound regions of the resource is defined by
the absence or presence of
sname:VkPhysicalDeviceSparseProperties::pname:residencyNonResidentStrict.
If this property is present, accesses to unbound regions of the
resource are well defined and behave as if the data bound is populated
with all zeros; writes are discarded. When this property is absent,
accesses are considered safe, but reads will return undefined values.
** Requested via the ename:VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT and
ename:VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT bits.
** [[features-features-sparseResidency,Sparse residency support]] is
advertised on a finer grain via the following features:
+
--
*** <<features-features-sparseResidencyBuffer,pname:sparseResidencyBuffer>>:
Support for creating sname:VkBuffer objects with the
ename:VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT.
*** <<features-features-sparseResidencyImage2D,pname:sparseResidencyImage2D>>:
Support for creating 2D single-sampled sname:VkImage objects with
ename:VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT.
*** <<features-features-sparseResidencyImage3D,pname:sparseResidencyImage3D>>:
Support for creating 3D sname:VkImage objects with
ename:VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT.
*** <<features-features-sparseResidency2Samples,pname:sparseResidency2Samples>>:
Support for creating 2D sname:VkImage objects with 2 samples and
ename:VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT.
*** <<features-features-sparseResidency4Samples,pname:sparseResidency4Samples>>:
Support for creating 2D sname:VkImage objects with 4 samples and
ename:VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT.
*** <<features-features-sparseResidency8Samples,pname:sparseResidency8Samples>>:
Support for creating 2D sname:VkImage objects with 8 samples and
ename:VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT.
*** <<features-features-sparseResidency16Samples,pname:sparseResidency16Samples>>:
Support for creating 2D sname:VkImage objects with 16 samples and
ename:VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT.
Implementations supporting pname:sparseResidencyImage2D are only
required: to support sparse 2D, single-sampled images. Support is
not required: for sparse 3D and MSAA images and is enabled via
pname:sparseResidencyImage3D, pname:sparseResidency2Samples,
pname:sparseResidency4Samples, pname:sparseResidency8Samples, and
pname:sparseResidency16Samples.
--
** A sparse image created using ename:VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT
supports all non-compressed color formats with power-of-two texel size
that non-sparse usage supports. Additional formats may: also be
supported and can: be queried via
flink:vkGetPhysicalDeviceSparseImageFormatProperties.
ename:VK_IMAGE_TILING_LINEAR tiling is not supported.
* <<features-features-sparseResidencyAliased,Sparse aliasing>>
provides the following capability that can: be enabled per resource:
+
Allows physical memory ranges to be shared between multiple locations in
the same sparse resource or between multiple sparse resources, with each
binding of a memory location observing a consistent interpretation of the
memory contents.
+
See <<sparsememory-sparse-memory-aliasing,Sparse Memory Aliasing>> for
more information.
[[sparsememory-fully-resident]]
== Sparse Buffers and Fully-Resident Images
Both sname:VkBuffer and sname:VkImage objects created with the
ename:VK_IMAGE_CREATE_SPARSE_BINDING_BIT or
ename:VK_BUFFER_CREATE_SPARSE_BINDING_BIT bits can: be thought of as a
linear region of address space. In the sname:VkImage case if
ename:VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT is not used, this linear
region is entirely opaque, meaning that there is no application-visible
mapping between pixel location and memory offset.
Unless ename:VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT or
ename:VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT are also used, the entire
resource must: be bound to one or more sname:VkDeviceMemory objects before
use.
=== Sparse Buffer and Fully-Resident Image Block Size
The sparse block size in bytes for sparse buffers and fully-resident images is
reported as sname:VkMemoryRequirements::pname:alignment. pname:alignment
represents both the memory alignment requirement and the binding granularity
(in bytes) for sparse resources.
[[sparsememory-partially-resident-buffers]]
== Sparse Partially-Resident Buffers
sname:VkBuffer objects created with the
ename:VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT bit allow the buffer to be made
only partially resident. Partially resident sname:VkBuffer objects are
allocated and bound identically to sname:VkBuffer objects using only the
ename:VK_BUFFER_CREATE_SPARSE_BINDING_BIT feature. The only difference is
the ability for some regions of the buffer to be unbound during device use.
[[sparsememory-partially-resident-images]]
== Sparse Partially-Resident Images
sname:VkImage objects created with the
ename:VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT bit allow specific rectangular
regions of the image called sparse image blocks to be bound to specific
ranges of memory. This allows the application to manage residency at either
image subresource or sparse image block granularity. Each image subresource
(outside of the <<sparsememory-miptail,mip tail>>) starts on a sparse block
boundary and has dimensions that are integer multiples of the corresponding
dimensions of the sparse image block.
[NOTE]
.Note
====
Applications can: use these types of images to control level-of-detail based
on total memory consumption. If memory pressure becomes an issue the
application can: unbind and disable specific mipmap levels of images without
having to recreate resources or modify pixel data of unaffected levels.
The application can: also use this functionality to access subregions of the
image in a ``megatexture'' fashion. The application can: create a large
image and only populate the region of the image that is currently being used
in the scene.
====
[[sparsememory-accessing-unbound]]
=== Accessing Unbound Regions
The following member of sname:VkPhysicalDeviceSparseProperties affects how
data in unbound regions of sparse resources are handled by the
implementation:
* pname:residencyNonResidentStrict
If this property is not present, reads of unbound regions of the image will
return undefined values. Both reads and writes are still considered _safe_
and will not affect other resources or populated regions of the image.
If this property is present, all reads of unbound regions of the image will
behave as if the region was bound to memory populated with all zeros;
writes will be discarded.
Formatted accesses to unbound memory may: still
alter some component values in the natural way for those accesses, e.g.
substituting a value of one for alpha in formats that do not have an alpha
component.
=======
Example: Reading the alpha component of an unbacked
ename:VK_FORMAT_R8_UNORM image will return a value of latexmath:[$1.0f$].
=======
See <<devsandqueues-physical-device-enumeration,Physical Device
Enumeration>> for instructions for retrieving physical device properties.
ifdef::implementation-guide[]
.Implementor's Note
****
For hardware that cannot: natively handle access to unbound regions of a
resource, the implementation may: allocate and bind memory to the
unbound regions. Reads and writes to unbound regions will access the
implementation-managed memory instead of causing a hardware fault.
Given that reads of unbound regions are undefined in this scenario,
implementations may: use the same physical memory for unbound regions of
multiple resources within the same process.
****
endif::implementation-guide[]
[[sparsememory-miptail]]
=== Mip Tail Regions
Sparse images created using ename:VK_IMAGE_CREATE_SPARSE_BINDING_BIT
(without also using ename:VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT) have no
specific mapping of image region or image subresource to memory offset
defined, so the entire image can: be thought of as a linear opaque address
region. However, images created with
ename:VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT do have a prescribed sparse image
block layout, and hence each image subresource must: start on a sparse block
boundary. Within each array layer, the set of mip-levels that have a smaller
size than the sparse block size in bytes are grouped together into a _mip
tail region_.
If the ename:VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT flag is present in
the pname:flags member of sname:VkSparseImageFormatProperties, for the
image's pname:format, then any mip-level which has dimensions that are not
integer multiples of the corresponding dimensions of the sparse image block,
and all subsequent mip-levels, are also included in the mip tail region.
The following member of sname:VkPhysicalDeviceSparseProperties may: affect
how the implementation places mip levels in the mip tail region:
* pname:residencyAlignedMipSize
Each mip tail region is bound to memory as an opaque region (i.e. must: be
bound using a slink:VkSparseImageOpaqueMemoryBindInfo structure) and may: be
of a size greater than or equal to the sparse block size in bytes. This size
is guaranteed to be an integer multiple of the sparse block size in bytes.
An implementation may: choose to allow each array-layer's mip tail region to
be bound to memory independently or require that all array-layer's mip tail
regions be treated as one. This is dictated by
ename:VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT in
sname:VkSparseImageMemoryRequirements::pname:flags.
The following diagrams depict how
ename:VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT and
ename:VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT alter memory usage and
requirements.
image::images/sparseimage.{svgpdf}[align="center", title="Sparse Image"]
In the absence of ename:VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT and
ename:VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT, each array layer contains a
mip tail region containing pixel data for all mip levels smaller than the
sparse image block in any dimension.
Mip levels that are as large or larger than a sparse image block in all
dimensions can: be bound individually. Right-edges and bottom-edges of each
level are allowed to have partially used sparse blocks. Any bound
partially-used-sparse-blocks must: still have their full sparse block
size in bytes allocated in memory.
image::images/sparseimage_singlemiptail.{svgpdf}[align="center", title="Sparse Image with Single Mip Tail"]
When ename:VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT is present all array
layers will share a single mip tail region.
image::images/sparseimage_alignedmipsize.{svgpdf}[align="center", title="Sparse Image with Aligned Mip Size"]
[NOTE]
.Note
====
The mip tail regions are presented here in 2D arrays simply for figure size
reasons. Each mip tail is logically a single array of sparse blocks with an
implementation-dependent mapping of pixels to sparse blocks.
====
When ename:VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT is present the first
mip level that would contain partially used sparse blocks begins the mip tail
region. This level and all subsequent levels are placed in the mip tail.
Only the first latexmath:[$N$] mip levels whose dimensions are an exact
multiple of the sparse image block dimensions can: be bound and unbound on a
sparse block basis.
image::images/sparseimage_alignedmipsize_singlemiptail.{svgpdf}[align="center", title="Sparse Image with Aligned Mip Size and Single Mip Tail"]
[NOTE]
.Note
====
The mip tail region is presented here in a 2D array simply for figure size
reasons. It is logically a single array of sparse blocks with an
implementation-dependent mapping of pixels to sparse blocks.
====
When both ename:VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT and
ename:VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT are present the constraints
from each of these flags are in effect.
[[sparsememory-standard-shapes]]
=== Standard Sparse Image Block Shapes
Standard sparse image block shapes define a standard set of dimensions for
sparse image blocks that depend on the format of the image. Layout of pixels
within a sparse image block is implementation dependent. All currently defined
standard sparse image block shapes are 64 KB in size.
For block-compressed formats (e.g. ename:VK_FORMAT_BC5_UNORM_BLOCK), the
pixel size is the size of the compressed texel block (128-bit for etext:BC5)
thus the dimensions of the standard sparse image block shapes apply in terms
of compressed texel blocks.
[NOTE]
.Note
====
For block-compressed formats, the dimensions of a sparse image block in terms
of texels can: be calculated by multiplying the sparse image block dimensions
by the compressed texel block dimensions.
====
<<<
[[sparsememory-sparseblockshapessingle]]
.Standard Sparse Image Block Shapes (Single Sample)
[options="header"]
|====
| PIXEL SIZE (bits) | Block Shape (2D) | Block Shape (3D)
| *8-Bit* | 256 × 256 × 1 | 64 × 32 × 32
| *16-Bit* | 256 × 128 × 1 | 32 × 32 × 32
| *32-Bit* | 128 × 128 × 1 | 32 × 32 × 16
| *64-Bit* | 128 × 64 × 1 | 32 × 16 × 16
| *128-Bit* | 64 × 64 × 1 | 16 × 16 × 16
|====
[[sparsememory-sparseblockshapesmsaa]]
.Standard Sparse Image Block Shapes (MSAA)
[options="header"]
|====
| PIXEL SIZE (bits)| Block Shape (2X)| Block Shape (4X) | Block Shape (8X) | Block Shape (16X)
| *8-Bit* | 128 × 256 × 1 | 128 × 128 × 1 | 64 × 128 × 1 | 64 × 64 × 1
| *16-Bit* | 128 × 128 × 1 | 128 × 64 × 1 | 64 × 64 × 1 | 64 × 32 × 1
| *32-Bit* | 64 × 128 × 1 | 64 × 64 × 1 | 32 × 64 × 1 | 32 × 32 × 1
| *64-Bit* | 64 × 64 × 1 | 64 × 32 × 1 | 32 × 32 × 1 | 32 × 16 × 1
| *128-Bit* | 32 × 64 × 1 | 32 × 32 × 1 | 16 × 32 × 1 | 16 × 16 × 1
|====
Implementations that support the standard sparse image block shape for all
applicable formats may: advertise the following
sname:VkPhysicalDeviceSparseProperties:
* pname:residencyStandard2DBlockShape
* pname:residencyStandard2DMultisampleBlockShape
* pname:residencyStandard3DBlockShape
Reporting each of these features does _not_ imply that all possible image
types are supported as sparse. Instead, this indicates that no supported
sparse image of the corresponding type will use custom sparse image block
dimensions for any formats that have a corresponding standard sparse image
block shape.
[[sparsememory-custom-shapes]]
=== Custom Sparse Image Block Shapes
An implementation that does not support a standard image block shape for a
particular sparse partially-resident image may: choose to support a custom
sparse image block shape for it instead. The dimensions of such a custom
sparse image block shape are reported in
sname:VkSparseImageFormatProperties::pname:imageGranularity. As with standard
sparse image block shapes, the size in bytes of the custom sparse image
block shape will be reported in sname:VkMemoryRequirements::pname:alignment.
Custom sparse image block dimensions are reported through
fname:vkGetPhysicalDeviceSparseImageFormatProperties and
fname:vkGetImageSparseMemoryRequirements.
An implementation mustnot: support both the standard sparse image block shape
and a custom sparse image block shape for the same image. The standard sparse
image block shape must: be used if it is supported.
[[sparsememory-multiaspect]]
=== Multiple Aspects
Partially resident images are allowed to report separate sparse properties
for different aspects of the image. One example is for depth/stencil images
where the implementation separates the depth and stencil data into separate
planes. Another reason for multiple aspects is to allow the application to
manage memory allocation for implementation-private _metadata_ associated
with the image. See the figure below:
image::images/sparseimage_multiaspect.{svgpdf}[align="center",title="Multiple Aspect Sparse Image"]
[NOTE]
.Note
====
The mip tail regions are presented here in 2D arrays simply for figure size
reasons. Each mip tail is logically a single array of sparse blocks with an
implementation-dependent mapping of pixels to sparse blocks.
====
In the figure above the depth, stencil, and metadata aspects all have unique
sparse properties. The per-pixel stencil data is
latexmath:[${}^{1}\!/\!{}_4$] the size of the depth data, hence the stencil
sparse blocks include latexmath:[$4x$] the number of pixels. The sparse block
size in bytes for all of the aspects is identical and defined by
sname:VkMemoryRequirements::pname:alignment.
==== Metadata
The metadata aspect of an image has the following constraints:
* All metadata is reported in the mip tail region of the metadata aspect.
* All metadata must: be bound prior to device use of the sparse image.
[[sparsememory-sparse-memory-aliasing]]
== Sparse Memory Aliasing
By default sparse resources have the same aliasing rules as
non-sparse resources. See <<resources-memory-aliasing,Memory Aliasing>> for
more information.
sname:VkDevice objects that have the
<<features-features-sparseResidencyAliased,sparseResidencyAliased>> feature
enabled are able to use the ename:VK_BUFFER_CREATE_SPARSE_ALIASED_BIT and
ename:VK_IMAGE_CREATE_SPARSE_ALIASED_BIT flags for resource creation. These
flags allow resources to access physical memory bound into multiple
locations within one or more sparse resources in a _data consistent_
fashion. This means that reading physical memory from multiple aliased
locations will return the same value.
Care must: be taken when performing a write operation to aliased physical
memory. Memory dependencies must: be used to separate writes to one alias
from reads or writes to another alias. Writes to aliased memory that are not
properly guarded against accesses to different aliases will have undefined
results for all accesses to the aliased memory.
Applications that wish to make use of data consistent sparse memory aliasing
must: abide by the following guidelines:
* All sparse resources that are bound to aliased physical memory must: be
created with the ename:VK_BUFFER_CREATE_SPARSE_ALIASED_BIT /
ename:VK_IMAGE_CREATE_SPARSE_ALIASED_BIT flag.
* All resources that access aliased physical memory must: interpret the
memory in the same way. This implies the following:
** Buffers and images cannot: alias the same physical memory in a data
consistent fashion. The physical memory ranges must: be used
exclusively by buffers or used exclusively by images for data
consistency to be guaranteed.
** Memory in sparse image mip tail regions cannot: access
aliased memory in a data consistent fashion.
** Sparse images that alias the same physical memory must: have compatible
formats and be using the same sparse image block shape in order to access
aliased memory in a data consistent fashion.
Failure to follow any of the above guidelines will require the application
to abide by the normal, non-sparse resource <<resources-memory-aliasing,
aliasing rules>>. In this case memory cannot: be accessed in a data
consistent fashion.
[NOTE]
.Note
====
Enabling sparse resource memory aliasing can: be a way to lower physical
memory use, but it may: reduce performance on some implementations. An
application developer can: test on their target HW and balance the memory /
performance trade-offs measured.
====
ifdef::implementation-guide[]
== Sparse Resource Implementation Guidelines
****
This section is Informative. It is included to aid in implementors'
understanding of sparse resources.
.Device Virtual Address
The basic pname:sparseBinding feature allows the resource to reserve its own
device virtual address range at resource creation time rather than relying on a
bind operation to set this. Without any other creation flags, no other
constraints are relaxed compared to normal resources. All pages must: be
bound to physical memory before the device accesses the resource.
The <<features-features-sparseResidency,sparse residency>> features allow
sparse resources to be used even
when not all pages are bound to memory. Hardware that supports access to
unbound pages without causing a fault may: support
pname:residencyNonResidentStrict.
Not faulting on access to unbound pages is not enough to support
pname:sparseResidencyNonResidentStrict. An implementation must: also
guarantee that reads after writes to unbound regions of the resource always
return data for the read as if the memory contains zeros. Depending on the
cache implementation of the hardware this may: not always be possible.
Hardware that does not fault, but does not guarantee correct read values
will not require dummy pages, but also mustnot: support
pname:sparseResidencyNonResidentStrict.
Hardware that cannot: access unbound pages without causing a fault will
require the implementation to bind the entire device virtual address range
to physical memory. Any pages that the application does not bind to memory
may: be bound to one (or more) ``dummy'' physical page(s) allocated by the
implementation. Given the following properties:
* A process mustnot: access memory from another process
* Reads return undefined values
It is sufficient for each host process to allocate these dummy
pages and use them for all resources in that process. Implementations may:
allocate more often (per instance, per device, or per resource).
.Binding Memory
The byte size reported in sname:VkMemoryRequirements::pname:size must: be
greater than or equal to the amount of physical memory required: to fully
populate the resource. Some hardware requires ``holes'' in the device
virtual address range that are never accessed. These holes may: be included
in the pname:size reported for the resource.
Including or not including the device virtual address holes in the resource
size will alter how the implementation provides support for
sname:VkSparseImageOpaqueMemoryBindInfo. This operation must: be supported
for all sparse images, even ones created with
ename:VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT.
ifdef::editing-notes[]
[NOTE]
.editing-note
====
@ntrevett suggested expanding the NOTE tag below to encompass everything
from ``The cost is...'' in the first bullet point through the current note.
TBD.
====
endif::editing-notes[]
* If the holes are included in the size, this bind function becomes very
easy. In most cases the pname:resourceOffset is simply a device virtual
address offset and the implementation does not require any sophisticated
logic to determine what device virtual address to bind. The cost is that
the application can: allocate more physical memory for the resource than
it needs.
* If the holes are not included in the size, the application can: allocate
less physical memory than otherwise for the resource. However, in this
case the implementation must: account for the holes when mapping
pname:resourceOffset to the actual device virtual address intended to be
mapped.
[NOTE]
.Note
====
If the application always uses sname:VkSparseImageMemoryBindInfo to bind
memory for the non-mip-tail levels, any holes that are present in the
resource size may: never be bound.
Since sname:VkSparseImageMemoryBindInfo uses pixel locations to determine
which device virtual addresses to bind, it is impossible to bind device
virtual address holes with this operation.
====
.Binding Metadata Memory
All metadata for sparse images have their own sparse properties and are
embedded in the mip tail region for said properties. See the
<<sparsememory-multiaspect,Multiaspect>> section for details.
Given that metadata is in a mip tail region, and the mip tail region must:
be reported as contiguous (either globally or per-array-layer), some
implementations will have to resort to complicated offset -> device virtual
address mapping for handling sname:VkSparseImageOpaqueMemoryBindInfo.
To make this easier on the implementation, the
ename:VK_SPARSE_MEMORY_BIND_METADATA_BIT explicitly denotes when
metadata is bound with sname:VkSparseImageOpaqueMemoryBindInfo. When this
flag is not present, the pname:resourceOffset may: be treated as a strict
device virtual address offset.
When ename:VK_SPARSE_MEMORY_BIND_METADATA_BIT is present, the
pname:resourceOffset must: have been derived explicitly from the
pname:imageMipTailOffset in the sparse resource properties returned for the
metadata aspect. By manipulating the value returned for
pname:imageMipTailOffset, the pname:resourceOffset does not have to
correlate directly to a device virtual address offset, and may: instead be
whatever values makes it easiest for the implementation to derive the
correct device virtual address.
****
endif::implementation-guide[]
[[sparsememory-resourceapi]]
== Sparse Resource API
The APIs related to sparse resources are grouped into the following
categories:
* <<sparsememory-physicalfeatures,Physical Device Features>>
* <<sparsememory-physicalprops,Physical Device Sparse Properties>>
* <<sparsememory-format-props,Sparse Image Format Properties>>
* <<sparsememory-resource-creation,Sparse Resource Creation>>
* <<sparsememory-memory-requirements,Sparse Resource Memory Requirements>>
* <<sparsememory-resource-binding,Binding Resource Memory>>
[[sparsememory-physicalfeatures]]
=== Physical Device Features
Some sparse-resource related features are reported and enabled in
sname:VkPhysicalDeviceFeatures. These features must: be supported and
enabled on the sname:VkDevice object before applications can: use them. See
<<features-features,Physical Device Features>> for information on how to get
and set enabled device features, and for more detailed explanations of these
features.
==== Sparse Physical Device Features
* pname:sparseBinding: Support for creating sname:VkBuffer and
sname:VkImage objects with the ename:VK_BUFFER_CREATE_SPARSE_BINDING_BIT
and ename:VK_IMAGE_CREATE_SPARSE_BINDING_BIT flags, respectively.
* pname:sparseResidencyBuffer: Support for creating sname:VkBuffer
objects with the ename:VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT flag.
* pname:sparseResidencyImage2D: Support for creating 2D single-sampled
sname:VkImage objects with ename:VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT.
* pname:sparseResidencyImage3D: Support for creating 3D sname:VkImage
objects with ename:VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT.
* pname:sparseResidency2Samples: Support for creating 2D sname:VkImage
objects with 2 samples and ename:VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT.
* pname:sparseResidency4Samples: Support for creating 2D sname:VkImage
objects with 4 samples and ename:VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT.
* pname:sparseResidency8Samples: Support for creating 2D sname:VkImage
objects with 8 samples and ename:VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT.
* pname:sparseResidency16Samples: Support for creating 2D sname:VkImage
objects with 16 samples and ename:VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT.
* pname:sparseResidencyAliased: Support for creating sname:VkBuffer and
sname:VkImage objects with the ename:VK_BUFFER_CREATE_SPARSE_ALIASED_BIT
and ename:VK_IMAGE_CREATE_SPARSE_ALIASED_BIT flags, respectively.
[[sparsememory-physicalprops]]
=== Physical Device Sparse Properties
Some features of the implementation are not possible to disable, and are
reported to allow applications to alter their sparse resource usage
accordingly. These read-only capabilites are reported in the
slink:VkPhysicalDeviceProperties::pname:sparseProperties member, which is a
structure of type sname:VkPhysicalDeviceSparseProperties.
// refBegin VkPhysicalDeviceSparseProperties - Structure specifying physical device sparse memory properties
The sname:VkPhysicalDeviceSparseProperties structure is defined as:
include::../structs/VkPhysicalDeviceSparseProperties.txt[]
* pname:residencyStandard2DBlockShape is ename:VK_TRUE if the physical
device will access all single-sample 2D sparse resources using the
standard sparse image block shapes (based on image format), as described
in the <<sparsememory-sparseblockshapessingle,Standard Sparse Image Block
Shapes (Single Sample)>> table. If this property is not supported the
value returned in the pname:imageGranularity member of the
sname:VkSparseImageFormatProperties structure for single-sample 2D
images is not required: to match the standard sparse image block
dimensions listed in the table.
* pname:residencyStandard2DMultisampleBlockShape is ename:VK_TRUE if the
physical device will access all multisample 2D sparse resources using
the standard sparse image block shapes (based on image format), as
described in the <<sparsememory-sparseblockshapesmsaa,Standard Sparse
Image Block Shapes (MSAA)>> table. If this property is not supported, the
value returned in the pname:imageGranularity member of the
sname:VkSparseImageFormatProperties structure for multisample 2D images
is not required: to match the standard sparse image block dimensions
listed in the table.
* pname:residencyStandard3DBlockShape is ename:VK_TRUE if the physical
device will access all 3D sparse resources using the standard sparse image
block shapes (based on image format), as described in the
<<sparsememory-sparseblockshapessingle,Standard Sparse Image Block
Shapes (Single Sample)>> table. If this property is not supported, the
value returned in the pname:imageGranularity member of the
sname:VkSparseImageFormatProperties structure for 3D images is not
required: to match the standard sparse image block dimensions listed in
the table.
* pname:residencyAlignedMipSize is ename:VK_TRUE if images with mip level
dimensions that are not integer multiples of the corresponding dimensions
of the sparse image block may: be placed in the mip tail. If this property
is not reported, only mip levels with dimensions smaller than the
pname:imageGranularity member of the sname:VkSparseImageFormatProperties
structure will be placed in the mip tail. If this property is reported the
implementation is allowed to return
ename:VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT in the pname:flags
member of sname:VkSparseImageFormatProperties, indicating that mip level
dimensions that are not integer multiples of the corresponding dimensions
of the sparse image block will be placed in the mip tail.
* pname:residencyNonResidentStrict specifies whether the physical device
can: consistently access non-resident regions of a resource. If this
property is ename:VK_TRUE, access to non-resident regions of resources
will be guaranteed to return values as if the resource were populated
with 0; writes to non-resident regions will be discarded.
include::../validity/structs/VkPhysicalDeviceSparseProperties.txt[]
[[sparsememory-format-props]]
=== Sparse Image Format Properties
Given that certain aspects of sparse image support, including the
sparse image block dimensions, may: be implementation-dependent,
flink:vkGetPhysicalDeviceSparseImageFormatProperties can: be used to
query for sparse image format properties prior to resource creation. This
command is used to check whether a given set of sparse image parameters is
supported and what the sparse image block shape will be.
==== Sparse Image Format Properties API
// refBegin VkSparseImageFormatProperties - Structure specifying sparse image format properties
The sname:VkSparseImageFormatProperties structure is defined as:
include::../structs/VkSparseImageFormatProperties.txt[]
* pname:aspectMask is a bitmask of elink:VkImageAspectFlagBits specifying
which aspects of the image the properties apply to.
* pname:imageGranularity is the width, height, and depth of the
sparse image block in texels or compressed texel blocks.
* pname:flags is a bitmask specifying additional information about the
sparse resource. Bits which can: be set include:
+
--
// refBegin VkSparseImageFormatFlagBits - Bitmask specifying additional information about a sparse image resource
include::../enums/VkSparseImageFormatFlagBits.txt[]
--
** If ename:VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT is set, the image
uses a single mip tail region for all array layers.
** If ename:VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT is set, the first
mip level whose dimensions are not integer multiples of the corresponding
dimensions of the sparse image block begins the mip tail region.
** If ename:VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT is set, the
image uses non-standard sparse image block dimensions, and the
pname:imageGranularity values do not match the standard sparse image
block dimensions for the given pixel format.
include::../validity/structs/VkSparseImageFormatProperties.txt[]
// refBegin vkGetPhysicalDeviceSparseImageFormatProperties Retrieve properties of an image format applied to sparse images.
fname:vkGetPhysicalDeviceSparseImageFormatProperties returns an
array of slink:VkSparseImageFormatProperties. Each element will describe
properties for one set of image aspects that are bound simultaneously in the
image. This is usually one element for each aspect in the image, but for
interleaved depth/stencil images there is only one element describing the
combined aspects.
include::../protos/vkGetPhysicalDeviceSparseImageFormatProperties.txt[]
* pname:physicalDevice is the physical device from which to query the
sparse image capabilities.
* pname:format is the image format.
* pname:type is the dimensionality of image.
* pname:samples is the number of samples per pixel as defined in
elink:VkSampleCountFlagBits.
* pname:usage is a bitmask describing the intended usage of the image.
* pname:tiling is the tiling arrangement of the data elements in memory.
* pname:pPropertyCount is a pointer to an integer related to the number of
sparse format properties available or queried, as described below.
* pname:pProperties is either `NULL` or a pointer to an array of
slink:VkSparseImageFormatProperties structures.
If pname:pProperties is `NULL`, then the number of sparse format properties
available is returned in pname:pPropertyCount. Otherwise,
pname:pPropertyCount must: point to a variable set by the user to the number
of elements in the pname:pProperties array, and on return the variable is
overwritten with the number of structures actually written to
pname:pProperties. If pname:pPropertyCount is less than the
number of sparse format properties available, at most pname:pPropertyCount
structures will be written.
If ename:VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT is not supported for the given
arguments, pname:pPropertyCount will be set to zero upon return, and no data
will be written to pname:pProperties.
Multiple aspects are returned for depth/stencil images that are implemented
as separate planes by the implementation. The depth and stencil data planes
each have unique sname:VkSparseImageFormatProperties data.
Depth/stencil images with depth and stencil data interleaved into a single
plane will return a single sname:VkSparseImageFormatProperties structure
with the pname:aspectMask set to ename:VK_IMAGE_ASPECT_DEPTH_BIT |
ename:VK_IMAGE_ASPECT_STENCIL_BIT.
include::../validity/protos/vkGetPhysicalDeviceSparseImageFormatProperties.txt[]
[[sparsememory-resource-creation]]
=== Sparse Resource Creation
Sparse resources require that one or more sparse feature flags be specified
(as part of the sname:VkPhysicalDeviceFeatures structure described
previously in the <<sparsememory-physicalfeatures,Physical Device Features>>
section) at CreateDevice time. When the appropriate device features are
enabled, the etext:VK_BUFFER_CREATE_SPARSE_* and
etext:VK_IMAGE_CREATE_SPARSE_* flags can: be used. See flink:vkCreateBuffer
and flink:vkCreateImage for details of the resource creation APIs.
[NOTE]
.Note
====
Specifying ename:VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT or
ename:VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT requires specifying
ename:VK_BUFFER_CREATE_SPARSE_BINDING_BIT or
ename:VK_IMAGE_CREATE_SPARSE_BINDING_BIT, respectively, as well. This means
that resources must: be created with the appropriate etext:*_SPARSE_BINDING_BIT
to be used with the sparse binding command (fname:vkQueueBindSparse).
====
[[sparsememory-memory-requirements]]
=== Sparse Resource Memory Requirements
Sparse resources have specific memory requirements related to binding sparse
memory. These memory requirements are reported differently for
sname:VkBuffer objects and sname:VkImage objects.
[[sparsememory-memory-buffer-fully-resident]]
==== Buffer and Fully-Resident Images
Buffers (both fully and partially resident) and fully-resident images can:
be bound to memory using only the data from sname:VkMemoryRequirements. For
all sparse resources the sname:VkMemoryRequirements::pname:alignment member
denotes both the bindable sparse block size in bytes and required: alignment
of sname:VkDeviceMemory.
[[sparsememory-memory-partially-resident]]
==== Partially Resident Images
Partially resident images have a different method for binding memory. As
with buffers and fully resident images, the
sname:VkMemoryRequirements::pname:alignment field denotes the bindable sparse
block size in bytes for the image.
Requesting sparse memory requirements for sname:VkImage objects using
fname:vkGetImageSparseMemoryRequirements will return an array of one or more
sname:VkSparseImageMemoryRequirements structures. Each structure describes
the sparse memory requirements for a group of aspects of the image.
The sparse image must: have been created using the
ename:VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT flag to retrieve valid sparse
image memory requirements.
==== Sparse Image Memory Requirements
// refBegin VkSparseImageMemoryRequirements - Structure specifying sparse image memory requirements
The sname:VkSparseImageMemoryRequirements structure is defined as:
include::../structs/VkSparseImageMemoryRequirements.txt[]
* pname:formatProperties.aspectMask is the set of aspects of the image
that this sparse memory requirement applies to. This will usually have a
single aspect specified. However, depth/stencil images may: have depth
and stencil data interleaved in the same sparse block, in which case
both ename:VK_IMAGE_ASPECT_DEPTH_BIT and
ename:VK_IMAGE_ASPECT_STENCIL_BIT would be present.
* pname:formatProperties.imageGranularity describes the dimensions of a
single bindable sparse image block in pixel units. For aspect
ename:VK_IMAGE_ASPECT_METADATA_BIT, all dimensions will be zero
pixels. All metadata is located in the mip tail region.
* pname:formatProperties.flags is a bitmask of
elink:VkSparseImageFormatFlagBits:
** If ename:VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT is set the image
uses a single mip tail region for all array layers.
** If ename:VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT is set the
dimensions of mip levels must: be integer multiples of the corresponding
dimensions of the sparse image block for levels not located in the mip
tail.
** If ename:VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT is set the
image uses non-standard sparse image block dimensions. The
pname:formatProperties.imageGranularity values do not match the
standard sparse image block dimension corresponding to the image's
pixel format.
* pname:imageMipTailFirstLod is the first mip level at which image
subresources are included in the mip tail region.
* pname:imageMipTailSize is the memory size (in bytes) of the mip tail
region. If pname:formatProperties.flags contains
ename:VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT, this is the size of the
whole mip tail, otherwise this is the size of the mip tail of a single
array layer. This value is guaranteed to be a multiple of the sparse block
size in bytes.
* pname:imageMipTailOffset is the opaque memory offset used with
slink:VkSparseImageOpaqueMemoryBindInfo to bind the mip tail region(s).
* pname:imageMipTailStride is the offset stride between each array-layer's
mip tail, if pname:formatProperties.flags does not contain
ename:VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT (otherwise the value is
undefined).
include::../validity/structs/VkSparseImageMemoryRequirements.txt[]
// refBegin vkGetImageSparseMemoryRequirements Query the memory requirements for a sparse image.
To query sparse memory requirements for an image, call:
include::../protos/vkGetImageSparseMemoryRequirements.txt[]
* pname:device is the logical device that owns the image.
* pname:image is the sname:VkImage object to get the memory requirements
for.
* pname:pSparseMemoryRequirementCount is a pointer to an integer related
to the number of sparse memory requirements available or queried, as
described below.
* pname:pSparseMemoryRequirements is either `NULL` or a pointer to an
array of sname:VkSparseImageMemoryRequirements structures.
If pname:pSparseMemoryRequirements is `NULL`, then the number of sparse
memory requirements available is returned in
pname:pSparseMemoryRequirementCount. Otherwise,
pname:pSparseMemoryRequirementCount must: point to a variable set by the
user to the number of elements in the pname:pSparseMemoryRequirements array,
and on return the variable is overwritten with the number of structures
actually written to pname:pSparseMemoryRequirements. If
pname:pSparseMemoryRequirementCount is less than the number of sparse memory
requirements available, at most pname:pSparseMemoryRequirementCount
structures will be written.
If the image was not created with ename:VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT
then pname:pSparseMemoryRequirementCount will be set to zero and
pname:pSparseMemoryRequirements will not be written to.
[NOTE]
.Note
====
It is legal for an implementation to report a larger value in
sname:VkMemoryRequirements::pname:size than would be obtained by adding
together memory sizes for all sname:VkSparseImageMemoryRequirements returned
by fname:vkGetImageSparseMemoryRequirements. This may: occur when the
hardware requires unused padding in the address range describing the
resource.
====
include::../validity/protos/vkGetImageSparseMemoryRequirements.txt[]
[[sparsememory-resource-binding]]
=== Binding Resource Memory
Non-sparse resources are backed by a single physical allocation prior to
device use (via fname:vkBindImageMemory or fname:vkBindBufferMemory), and
their backing mustnot: be changed. On the other hand, sparse resources can:
be bound to memory non-contiguously and these bindings can: be altered
during the lifetime of the resource.
[NOTE]
.Note
====
It is important to note that freeing a sname:VkDeviceMemory object with
fname:vkFreeMemory will not cause resources (or resource regions) bound to
the memory object to become unbound. Access to resources that are bound to
memory objects that have been freed will result in undefined behavior,
potentially including application termination.
Implementations must: ensure that no access to physical memory
owned by the system or another process will occur in this scenario. In other
words, accessing resources bound to freed memory may: result in application
termination, but mustnot: result in system termination or in reading
non-process-accessible memory.
====
Sparse memory bindings execute on a queue that includes the
ename:VK_QUEUE_SPARSE_BINDING_BIT bit. Applications must: use
<<synchronization,synchronization primitives>>
to guarantee that other queues do not access ranges of memory
concurrently with a binding change. Accessing memory in a range while it is
being rebound results in undefined behavior. It is valid to access other
ranges of the same resource while a bind operation is executing.
[NOTE]
.Note
====
Implementations must: provide a guarantee that simultaneously binding sparse
blocks while another queue accesses those same sparse blocks via a sparse
resource mustnot: access memory owned by another process or otherwise corrupt
the system.
====
While some implementations may: include ename:VK_QUEUE_SPARSE_BINDING_BIT
support in queue families that also include graphics and compute support,
other implementations may: only expose a
ename:VK_QUEUE_SPARSE_BINDING_BIT-only queue family. In either case,
applications must: use <<synchronization,synchronization primitives>> to
explicitly request any ordering dependencies between sparse memory binding
operations and other graphics/compute/transfer operations, as sparse binding
operations are not automatically ordered against command buffer execution,
even within a single queue.
When binding memory explicitly for the ename:VK_IMAGE_ASPECT_METADATA_BIT
the application must: use the ename:VK_SPARSE_MEMORY_BIND_METADATA_BIT in
the sname:VkSparseMemoryBind::pname:flags field when binding memory. Binding
memory for metadata is done the same way as binding memory for the mip tail,
with the addition of the ename:VK_SPARSE_MEMORY_BIND_METADATA_BIT flag.
Binding the mip tail for any aspect must: only be performed using
slink:VkSparseImageOpaqueMemoryBindInfo. If pname:formatProperties.flags
contains ename:VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT, then it can: be
bound with a single slink:VkSparseMemoryBind structure, with
pname:resourceOffset = pname:imageMipTailOffset and pname:size =
pname:imageMipTailSize.
If pname:formatProperties.flags does not contain
ename:VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT then the offset for the mip
tail in each array layer is given as:
[source,{basebackend@docbook:c++:cpp}]
--
arrayMipTailOffset = imageMipTailOffset + arrayLayer * imageMipTailStride;
--
and the mip tail can: be bound with code:layerCount slink:VkSparseMemoryBind
structures, each using pname:size = pname:imageMipTailSize and
pname:resourceOffset = ptext:arrayMipTailOffset as defined above.
Sparse memory binding is handled by the following APIs and related data
structures.
[[sparsemem-memory-binding]]
==== Sparse Memory Binding Functions
// refBegin VkSparseMemoryBind - Structure specifying a sparse memory bind operation
The sname:VkSparseMemoryBind structure is defined as:
include::../structs/VkSparseMemoryBind.txt[]
* pname:resourceOffset is the offset into the resource.
* pname:size is the size of the memory region to be bound.
* pname:memory is the sname:VkDeviceMemory object that the range of the
resource is bound to. If pname:memory is dlink:VK_NULL_HANDLE, the range
is unbound.
* pname:memoryOffset is the offset into the sname:VkDeviceMemory object to
bind the resource range to. If pname:memory is dlink:VK_NULL_HANDLE,
this value is ignored.
* pname:flags is a bitmask specifying usage of the binding operation. Bits
which can: be set include:
+
--
// refBegin VkSparseMemoryBindFlagBits - Bitmask specifying usage of a sparse memory binding operation
include::../enums/VkSparseMemoryBindFlagBits.txt[]
--
+
** ename:VK_SPARSE_MEMORY_BIND_METADATA_BIT indicates that the memory
being bound is only for the metadata aspect.
The _binding range_ latexmath:[$[\mathit{resourceOffset},
\mathit{resourceOffset} + \mathit{size})$] has different constraints based
on pname:flags. If pname:flags contains
ename:VK_SPARSE_MEMORY_BIND_METADATA_BIT, the binding range must: be within
the mip tail region of the metadata aspect. This metadata region is defined
by:
[latexmath]
++++++++++++++++++++++++++
\begin{align*}
\mathit{metadataRegion} = [&
\mathit{imageMipTailOffset} + \mathit{imageMipTailStride} \times n,\\
&\mathit{imageMipTailOffset} +
\mathit{imageMipTailStride} \times n + \mathit{imageMipTailSize})
\end{align*}
++++++++++++++++++++++++++
Where pname:imageMipTailOffset, pname:imageMipTailSize, and
pname:imageMipTailStride values are from the
slink:VkSparseImageMemoryRequirements that correspond to the metadata aspect
of the image. The term latexmath:[$n$] is a valid array layer index for the
image.
pname:imageMipTailStride is considered to be zero for aspects where
sname:VkSparseImageMemoryRequirements::pname:formatProperties.flags contains
ename:VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT.
If pname:flags does not contain ename:VK_SPARSE_MEMORY_BIND_METADATA_BIT,
the binding range must: be within the range
latexmath:[$[0, {\mathit{VkMemoryRequirements}::\mathit{size}})$].
include::../validity/structs/VkSparseMemoryBind.txt[]
// refBegin VkSparseBufferMemoryBindInfo - Structure specifying a sparse buffer memory bind operation
Memory is bound to sname:VkBuffer objects created with the
ename:VK_BUFFER_CREATE_SPARSE_BINDING_BIT flag using the following
structure:
include::../structs/VkSparseBufferMemoryBindInfo.txt[]
* pname:buffer is the sname:VkBuffer object to be bound.
* pname:bindCount is the number of sname:VkSparseMemoryBind structures in
the pname:pBinds array.
* pname:pBinds is a pointer to array of sname:VkSparseMemoryBind
structures.
include::../validity/structs/VkSparseBufferMemoryBindInfo.txt[]
// refBegin VkSparseImageOpaqueMemoryBindInfo - Structure specifying sparse image opaque memory bind info
Memory is bound to opaque regions of sname:VkImage objects created with the
ename:VK_IMAGE_CREATE_SPARSE_BINDING_BIT flag using the following
structure:
include::../structs/VkSparseImageOpaqueMemoryBindInfo.txt[]
* pname:image is the sname:VkImage object to be bound.
* pname:bindCount is the number of sname:VkSparseMemoryBind structures in
the pname:pBinds array.
* pname:pBinds is a pointer to array of sname:VkSparseMemoryBind
structures.
include::../validity/structs/VkSparseImageOpaqueMemoryBindInfo.txt[]
[NOTE]
.Note
==================
This operation is normally used to bind memory to fully-resident sparse
images or for mip tail regions of partially resident images. However, it
can: also be used to bind memory for the entire binding range of partially
resident images.
In case pname:flags does not contain
ename:VK_SPARSE_MEMORY_BIND_METADATA_BIT, the pname:resourceOffset is in the
range latexmath:[$[0, {\mathit{VkMemoryRequirements}::\mathit{size}})$].
This range includes data from all aspects of the image, including metadata.
For most implementations this will probably mean that the
pname:resourceOffset is a simple device address offset within the resource.
It is possible for an application to bind a range of memory that includes
both resource data and metadata. However, the application would not know
what part of the image the memory is used for, or if any range is being used
for metadata.
When pname:flags contains ename:VK_SPARSE_MEMORY_BIND_METADATA_BIT, the
binding range specified must: be within the mip tail region of the metadata
aspect. In this case the pname:resourceOffset is not required: to be a
simple device address offset within the resource. However, it _is_ defined
to be within [imageMipTailOffset, imageMipTailOffset + imageMipTailSize) for
the metadata aspect. See slink:VkSparseMemoryBind for the full constraints
on binding region with this flag present.
==================
ifdef::editing-notes[]
[NOTE]
.editing-note
====
(Jon) The preceding NOTE refers to pname:flags, which is presumably a
reference to slink:VkSparseMemoryBind above, even though that is not
contextually clear.
====
endif::editing-notes[]
// refBegin VkSparseImageMemoryBindInfo - Structure specifying sparse image memory bind info
Memory can: be bound to sparse image blocks of sname:VkImage objects created
with the ename:VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT flag using the following
structure:
include::../structs/VkSparseImageMemoryBindInfo.txt[]
* pname:image is the sname:VkImage object to be bound
* pname:bindCount is the number of sname:VkSparseImageMemoryBind
structures in pBinds array
* pname:pBinds is a pointer to array of sname:VkSparseImageMemoryBind
structures
include::../validity/structs/VkSparseImageMemoryBindInfo.txt[]
// refBegin VkSparseImageMemoryBind - Structure specifying sparse image memory bind
The sname:VkSparseImageMemoryBind structure is defined as:
include::../structs/VkSparseImageMemoryBind.txt[]
* pname:subresource is the aspectMask and region of interest in the image.
* pname:offset are the coordinates of the first texel within the image
subresource to bind.
* pname:extent is the size in texels of the region within the image
subresource to bind. The extent must: be a multiple of the sparse image
block dimensions, except when binding sparse image blocks along the edge
of an image subresource it can: instead be such that any coordinate of
latexmath:[$\mathit{offset} + \mathit{extent}$] equals the corresponding
dimensions of the image subresource.
* pname:memory is the sname:VkDeviceMemory object that the sparse image
blocks of the image are bound to. If pname:memory is dlink:VK_NULL_HANDLE,
the sparse image blocks are unbound.
* pname:memoryOffset is an offset into sname:VkDeviceMemory object. If
pname:memory is dlink:VK_NULL_HANDLE, this value is ignored.
* pname:flags are sparse memory binding flags.
include::../validity/structs/VkSparseImageMemoryBind.txt[]
// refBegin vkQueueBindSparse Bind device memory to a sparse resource object.
To submit sparse binding operations to a queue, call:
include::../protos/vkQueueBindSparse.txt[]
* pname:queue is the queue that the sparse binding operations will be submitted to.
* pname:bindInfoCount is the number of elements in the pname:pBindInfo array.
* pname:pBindInfo is an array of slink:VkBindSparseInfo structures,
each specifying a sparse binding submission batch.
* pname:fence is an optional handle to a fence to be signaled. If
pname:fence is not dlink:VK_NULL_HANDLE, it defines a
<<synchronization-fences-signaling, fence signal operation>>.
fname:vkQueueBindSparse is a
<<devsandqueues-submission,queue submission command>>, with each batch
defined by an element of pname:pBindInfo as an instance of the
slink:VkBindSparseInfo structure.
Within a batch, a given range of a resource must: not be bound more than
once. Across batches, if a range is to be bound to one allocation and offset
and then to another allocation and offset, then the application must:
guarantee (usually using semaphores) that the binding operations are
executed in the correct order, as well as to order binding operations
against the execution of command buffer submissions.
As no operation to flink:vkQueueBindSparse causes any pipeline stage to
access memory, synchronization primitives used in this command effectively
only define execution dependencies.
Additional information about fence and semaphore operation is described in
<<synchronization, the synchronization chapter>>.
include::../validity/protos/vkQueueBindSparse.txt[]
// refBegin VkBindSparseInfo - Structure specifying a sparse binding operation
The sname:VkBindSparseInfo structure is defined as:
include::../structs/VkBindSparseInfo.txt[]
* pname:sType is the type of this structure.
* pname:pNext is `NULL` or a pointer to an extension-specific structure.
* pname:waitSemaphoreCount is the number of semaphores upon which to
wait before executing the sparse binding operations for the batch.
* pname:pWaitSemaphores is a pointer to an array of semaphores upon which
to wait on before the sparse binding operations for this batch begin
execution. If semaphores to wait on are provided, they define a
<<synchronization-semaphores-waiting, semaphore wait operation>>.
* pname:bufferBindCount is the number of sparse buffer bindings to
perform in the batch.
* pname:pBufferBinds is a pointer to an array of
slink:VkSparseBufferMemoryBindInfo structures.
* pname:imageOpaqueBindCount is the number of opaque sparse image bindings
to perform.
* pname:pImageOpaqueBinds is a pointer to an array of
slink:VkSparseImageOpaqueMemoryBindInfo structures, indicating opaque
sparse image bindings to perform.
* pname:imageBindCount is the number of sparse image bindings to perform.
* pname:pImageBinds is a pointer to an array of
slink:VkSparseImageMemoryBindInfo structures, indicating sparse image
bindings to perform.
* pname:signalSemaphoreCount is the number of semaphores to be
signaled once the sparse binding operations specified by the structure
have completed execution.
* pname:pSignalSemaphores is a pointer to an array of semaphores which
will be signaled when the sparse binding operations for this batch have
completed execution.
If semaphores to be signaled are provided, they define a
<<synchronization-semaphores-signaling, semaphore signal operation>>.
include::../validity/structs/VkBindSparseInfo.txt[]
[[sparsememory-examples]]
== Examples
The following examples illustrate basic creation of sparse images and
binding them to physical memory.
[[sparsememory-examples-basic]]
=== Basic Sparse Resources
This basic example creates a normal sname:VkImage object but uses
fine-grained memory allocation to back the resource with multiple memory
ranges.
[source,{basebackend@docbook:c++:cpp}]
---------------------------------------------------
VkDevice device;
VkQueue queue;
VkImage sparseImage;
VkMemoryRequirements memoryRequirements = {};
VkDeviceSize offset = 0;
VkSparseMemoryBind binds[MAX_CHUNKS] = {}; // MAX_CHUNKS is NOT part of Vulkan
uint32_t bindCount = 0;
// ...
// Allocate image object
const VkImageCreateInfo sparseImageInfo =
{
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // sType
NULL, // pNext
VK_IMAGE_CREATE_SPARSE_BINDING_BIT | ..., // flags
...
};
vkCreateImage(device, &sparseImageInfo, &sparseImage);
// Get memory requirements
vkGetImageMemoryRequirements(
device,
sparseImage,
&memoryRequirements);
// Bind memory in fine-grained fashion, find available memory ranges
// from potentially multiple VkDeviceMemory pools.
// (Illustration purposes only, can be optimized for perf)
while (memoryRequirements.size && bindCount < MAX_CHUNKS)
{
VkSparseMemoryBind* pBind = &binds[bindCount];
pBind->resourceOffset = offset;
AllocateOrGetMemoryRange(
device,
&memoryRequirements,
&pBind->memory,
&pBind->memoryOffset,
&pBind->size);
// memory ranges must be sized as multiples of the alignment
assert(IsMultiple(pBind->size, memoryRequirements.alignment));
assert(IsMultiple(pBind->memoryOffset, memoryRequirements.alignment));
memoryRequirements.size -= pBind->size;
offset += pBind->size;
bindCount++;
}
// Ensure all image has backing
if (memoryRequirements.size)
{
// Error condition - too many chunks
}
const VkSparseImageOpaqueMemoryBindInfo opaqueBindInfo =
{
sparseImage, // image
bindCount, // bindCount
binds // pBinds
};
const VkBindSparseInfo bindSparseInfo =
{
VK_STRUCTURE_TYPE_BIND_SPARSE_INFO, // sType
NULL, // pNext
...
1, // imageOpaqueBindCount
&opaqueBindInfo, // pImageOpaqueBinds
...
};
// vkQueueBindSparse is application synchronized per queue object.
AcquireQueueOwnership(queue);
// Actually bind memory
vkQueueBindSparse(queue, 1, &bindSparseInfo, VK_NULL_HANDLE);
ReleaseQueueOwnership(queue);
---------------------------------------------------
[[sparsememory-examples-advanced]]
=== Advanced Sparse Resources
This more advanced example creates an arrayed color attachment / texture
image and binds only LOD zero and the required: metadata to physical memory.
[source,{basebackend@docbook:c++:cpp}]
---------------------------------------------------
VkDevice device;
VkQueue queue;
VkImage sparseImage;
VkMemoryRequirements memoryRequirements = {};
uint32_t sparseRequirementsCount = 0;
VkSparseImageMemoryRequirements* pSparseReqs = NULL;
VkSparseMemoryBind binds[MY_IMAGE_ARRAY_SIZE] = {};
VkSparseImageMemoryBind imageBinds[MY_IMAGE_ARRAY_SIZE] = {};
uint32_t bindCount = 0;
// Allocate image object (both renderable and sampleable)
const VkImageCreateInfo sparseImageInfo =
{
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // sType
NULL, // pNext
VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT | ..., // flags
...
VK_FORMAT_R8G8B8A8_UNORM, // format
...
MY_IMAGE_ARRAY_SIZE, // arrayLayers
...
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT, // usage
...
};
vkCreateImage(device, &sparseImageInfo, &sparseImage);
// Get memory requirements
vkGetImageMemoryRequirements(
device,
sparseImage,
&memoryRequirements);
// Get sparse image aspect properties
vkGetImageSparseMemoryRequirements(
device,
sparseImage,
&sparseRequirementsCount,
NULL);
pSparseReqs = (VkSparseImageMemoryRequirements*)
malloc(sparseRequirementsCount * sizeof(VkSparseImageMemoryRequirements));
vkGetImageSparseMemoryRequirements(
device,
sparseImage,
&sparseRequirementsCount,
pSparseReqs);
// Bind LOD level 0 and any required metadata to memory
for (uint32_t i = 0; i < sparseRequirementsCount; ++i)
{
if (pSparseReqs[i].formatProperties.aspectMask &
VK_IMAGE_ASPECT_METADATA_BIT)
{
// Metadata must not be combined with other aspects
assert(pSparseReqs[i].formatProperties.aspectMask ==
VK_IMAGE_ASPECT_METADATA_BIT);
if (pSparseReqs[i].formatProperties.flags &
VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT)
{
VkSparseMemoryBind* pBind = &binds[bindCount];
pBind->memorySize = pSparseReqs[i].imageMipTailSize;
bindCount++;
// ... Allocate memory range
pBind->resourceOffset = pSparseReqs[i].imageMipTailOffset;
pBind->memoryOffset = /* allocated memoryOffset */;
pBind->memory = /* allocated memory */;
pBind->flags = VK_SPARSE_MEMORY_BIND_METADATA_BIT;
}
else
{
// Need a mip tail region per array layer.
for (uint32_t a = 0; a < sparseImageInfo.arrayLayers; ++a)
{
VkSparseMemoryBind* pBind = &binds[bindCount];
pBind->memorySize = pSparseReqs[i].imageMipTailSize;
bindCount++;
// ... Allocate memory range
pBind->resourceOffset = pSparseReqs[i].imageMipTailOffset +
(a * pSparseReqs[i].imageMipTailStride);
pBind->memoryOffset = /* allocated memoryOffset */;
pBind->memory = /* allocated memory */
pBind->flags = VK_SPARSE_MEMORY_BIND_METADATA_BIT;
}
}
}
else
{
// resource data
VkExtent3D lod0BlockSize =
{
AlignedDivide(
sparseImageInfo.extent.width,
pSparseReqs[i].formatProperties.imageGranularity.width);
AlignedDivide(
sparseImageInfo.extent.height,
pSparseReqs[i].formatProperties.imageGranularity.height);
AlignedDivide(
sparseImageInfo.extent.depth,
pSparseReqs[i].formatProperties.imageGranularity.depth);
}
size_t totalBlocks =
lod0BlockSize.width *
lod0BlockSize.height *
lod0BlockSize.depth;
VkDeviceSize lod0MemSize = totalBlocks * memoryRequirements.alignment;
// Allocate memory for each array layer
for (uint32_t a = 0; a < sparseImageInfo.arrayLayers; ++a)
{
// ... Allocate memory range
VkSparseImageMemoryBind* pBind = &imageBinds[a];
pBind->subresource.aspectMask = pSparseReqs[i].formatProperties.aspectMask;
pBind->subresource.mipLevel = 0;
pBind->subresource.arrayLayer = a;
pBind->offset = (VkOffset3D){0, 0, 0};
pBind->extent = sparseImageInfo.extent;
pBind->memoryOffset = /* allocated memoryOffset */;
pBind->memory = /* allocated memory */;
pBind->flags = 0;
}
}
free(pSparseReqs);
}
const VkSparseImageOpaqueMemoryBindInfo opaqueBindInfo =
{
sparseImage, // image
bindCount, // bindCount
binds // pBinds
};
const VkSparseImageMemoryBindInfo imageBindInfo =
{
sparseImage, // image
sparseImageInfo.arrayLayers, // bindCount
imageBinds // pBinds
};
const VkBindSparseInfo bindSparseInfo =
{
VK_STRUCTURE_TYPE_BIND_SPARSE_INFO, // sType
NULL, // pNext
...
1, // imageOpaqueBindCount
&opaqueBindInfo, // pImageOpaqueBinds
1, // imageBindCount
&imageBindInfo, // pImageBinds
...
};
// vkQueueBindSparse is application synchronized per queue object.
AcquireQueueOwnership(queue);
// Actually bind memory
vkQueueBindSparse(queue, 1, &bindSparseInfo, VK_NULL_HANDLE);
ReleaseQueueOwnership(queue);
---------------------------------------------------