1527 lines
65 KiB
Plaintext
1527 lines
65 KiB
Plaintext
// 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.
|
||
** 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
|
||
====
|
||
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 pname:sparseResidency feature allows the sparse resource 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:sparseResidencyNonResidentStrict.
|
||
|
||
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.
|
||
|
||
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
|
||
|
||
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:
|
||
+
|
||
--
|
||
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[]
|
||
|
||
fname:vkGetPhysicalDeviceSparseImageFormatProperties returns an
|
||
array of sname: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 bitfield 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.
|
||
|
||
include::../validity/protos/vkGetPhysicalDeviceSparseImageFormatProperties.txt[]
|
||
|
||
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.
|
||
|
||
|
||
[[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
|
||
|
||
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[]
|
||
|
||
Query sparse memory requirements for an image by calling:
|
||
|
||
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.
|
||
|
||
include::../validity/protos/vkGetImageSparseMemoryRequirements.txt[]
|
||
|
||
[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.
|
||
====
|
||
|
||
|
||
[[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
|
||
|
||
include::../enums/VkSparseMemoryBindFlagBits.txt[]
|
||
include::../flags/VkSparseMemoryBindFlags.txt[]
|
||
|
||
* ename:VK_SPARSE_MEMORY_BIND_METADATA_BIT is used to indicate
|
||
that the memory being bound is only for the metadata aspect.
|
||
|
||
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 code: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 code:VK_NULL_HANDLE,
|
||
this value is ignored.
|
||
* pname:flags are sparse memory binding flags.
|
||
|
||
include::../validity/structs/VkSparseMemoryBind.txt[]
|
||
|
||
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}})$].
|
||
|
||
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[]
|
||
|
||
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.
|
||
==================
|
||
|
||
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[]
|
||
|
||
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 code:VK_NULL_HANDLE,
|
||
the sparse image blocks are unbound.
|
||
* pname:memoryOffset is an offset into sname:VkDeviceMemory object. If
|
||
pname:memory is code:VK_NULL_HANDLE, this value is ignored.
|
||
* pname:flags are sparse memory binding flags.
|
||
|
||
include::../validity/structs/VkSparseImageMemoryBind.txt[]
|
||
|
||
Sparse binding operations are submitted to a queue for execution via the
|
||
command:
|
||
|
||
include::../protos/vkQueueBindSparse.txt[]
|
||
|
||
* pname:queue is the queue to submit the sparse binding operation to.
|
||
* pname:bindInfoCount is the size of the array pointed to by
|
||
pname:pBindInfo.
|
||
* pname:pBindInfo is an array of slink:VkBindSparseInfo structures
|
||
each specifying the parameters of a sparse binding operation batch as
|
||
described below.
|
||
* pname:fence, if not code:VK_NULL_HANDLE, is a fence to be signaled
|
||
once the sparse binding operation completes.
|
||
|
||
Each batch of sparse binding operations is represented by a list of
|
||
slink:VkSparseBufferMemoryBindInfo, slink:VkSparseImageOpaqueMemoryBindInfo,
|
||
and slink:VkSparseImageMemoryBindInfo structures (encapsulated in a
|
||
slink:VkBindSparseInfo structure), each preceded by a list of semaphores
|
||
upon which to wait before beginning execution of the operations, and
|
||
followed by a second list of semaphores to signal upon completion of the
|
||
operations.
|
||
|
||
When all sparse binding operations in pname:pBindInfo have completed
|
||
execution, the status of pname:fence is set to signaled, providing certain
|
||
<<synchronization-implicit-ordering,implicit ordering guarantees>>.
|
||
|
||
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.
|
||
|
||
include::../validity/protos/vkQueueBindSparse.txt[]
|
||
|
||
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 before executing the sparse binding operations in the batch.
|
||
* pname:bufferBindCount is the number of sparse buffer bindings to
|
||
perform.
|
||
* pname:pBufferBinds is an array of slink:VkSparseBufferMemoryBindInfo
|
||
structures, indicating sparse buffer bindings to perform as described
|
||
above.
|
||
* pname:imageOpaqueBindCount is the number of opaque sparse image bindings
|
||
to perform.
|
||
* pname:pImageOpaqueBinds is an array of
|
||
slink:VkSparseImageOpaqueMemoryBindInfo structures, indicating opaque
|
||
sparse image bindings to perform as described above.
|
||
* pname:imageBindCount is the number of sparse image bindings to perform.
|
||
* pname:pImageBinds is an array of slink:VkSparseImageMemoryBindInfo
|
||
structures, indicating sparse image bindings to perform as described
|
||
above.
|
||
* 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.
|
||
|
||
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);
|
||
---------------------------------------------------
|