init
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
////
|
||||
- Copyright (c) 2023, Mobica Limited
|
||||
-
|
||||
- SPDX-License-Identifier: Apache-2.0
|
||||
-
|
||||
- Licensed under the Apache License, Version 2.0 the "License";
|
||||
- you may not use this file except in compliance with the License.
|
||||
- You may obtain a copy of the License at
|
||||
-
|
||||
- http://www.apache.org/licenses/LICENSE-2.0
|
||||
-
|
||||
- Unless required by applicable law or agreed to in writing, software
|
||||
- distributed under the License is distributed on an "AS IS" BASIS,
|
||||
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
- See the License for the specific language governing permissions and
|
||||
- limitations under the License.
|
||||
-
|
||||
////
|
||||
|
||||
== Sparse image
|
||||
|
||||
ifdef::site-gen-antora[]
|
||||
TIP: The source for this sample can be found in the https://github.com/KhronosGroup/Vulkan-Samples/tree/main/samples/extensions/sparse_image[Khronos Vulkan samples github repository].
|
||||
endif::[]
|
||||
|
||||
image::./images/sparse_image_screenshot.png[Sample]
|
||||
|
||||
== Overview
|
||||
|
||||
The usage of
|
||||
https://registry.khronos.org/vulkan/site/spec/latest/chapters/sparsemem.html[Sparse
|
||||
Resources] allows for less restrict memory binding in comparison to a
|
||||
standard resource.
|
||||
|
||||
The key differences between standard and sparse resources, showcased in
|
||||
this sample are:
|
||||
|
||||
* Sparse resources can be bound non-contiguously to one or more
|
||||
VkDeviceMemory allocations;
|
||||
* Sparse resources can be re-bound to different memory allocations over
|
||||
the lifetime of the resource;
|
||||
|
||||
The sample demonstrates usage of the Sparse Image feature by rendering a
|
||||
high-resolution texture with only a fraction of the total image size
|
||||
actually allocated on the device's memory. This is possible by
|
||||
dynamically loading required memory areas, generating mip levels for
|
||||
outer parts, removing unused memory and finally: binding an image in
|
||||
real-time.
|
||||
|
||||
== Enabling features
|
||||
|
||||
There are 3 features to be enabled:
|
||||
|
||||
* sparseBinding;
|
||||
* sparseResidencyImage2D;
|
||||
* shaderResourceResidency;
|
||||
|
||||
First two, are the key features required for the usage of the sparse
|
||||
image resources. The last one - shaderResourceResidency, is required for
|
||||
the fragment shader to be able to detect which parts of the image are
|
||||
allocated in the memory.
|
||||
|
||||
[source,c++]
|
||||
----
|
||||
void SparseImage::request_gpu_features(vkb::PhysicalDevice &gpu)
|
||||
{
|
||||
if (gpu.get_features().sparseBinding && gpu.get_features().sparseResidencyImage2D && gpu.get_features().shaderResourceResidency)
|
||||
{
|
||||
gpu.get_mutable_requested_features().sparseBinding = VK_TRUE;
|
||||
gpu.get_mutable_requested_features().sparseResidencyImage2D = VK_TRUE;
|
||||
gpu.get_mutable_requested_features().shaderResourceResidency = VK_TRUE;
|
||||
}
|
||||
----
|
||||
|
||||
== Enabling extensions
|
||||
|
||||
There is a single extensions used in this sample:
|
||||
|
||||
* GL_ARB_sparse_texture2;
|
||||
|
||||
This extension is used only by the fragment shader, but requires
|
||||
shaderResourceResidency feature to be enabled first. What this extension
|
||||
does, is allowing the fragment to check if the memory for the particular
|
||||
fragment is actually allocated or not. Because of this extension, it is
|
||||
possible to keep checking the residency from the fragment shader, and
|
||||
basically use the most detailed data available.
|
||||
|
||||
[source,glsl]
|
||||
----
|
||||
#extension GL_ARB_sparse_texture2 : enable
|
||||
----
|
||||
|
||||
[source,glsl]
|
||||
----
|
||||
for(; (lod <= maxLOD) && !sparseTexelsResidentARB(residencyCode); lod += 1)
|
||||
{
|
||||
residencyCode = sparseTextureLodARB(texSampler, fragTexCoord, lod, color);
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
== How is required LOD calculated?
|
||||
|
||||
The whole method is well-described in the source file. In general, the
|
||||
value of LOD is obtained by calculating: What is the ratio between x or y
|
||||
movement on the screen, to the u or v movement on the texture?
|
||||
|
||||
The idea is, that when moving pixel-by-pixel along the x or y axis
|
||||
on-screen, if the small on-screen step causes a significant step
|
||||
on-texture, then the area is far away from the observer and
|
||||
a less-detailed mip-level is required.
|
||||
|
||||
The formula used for those calculations is:
|
||||
|
||||
LOD = log2 (max(dT / dx, dT / dy)); where:
|
||||
|
||||
* dT is an on-texture-step in texels,
|
||||
* dx, dy are on-screen-steps in pixels.
|
||||
|
||||
|
||||
== User Interface
|
||||
|
||||
The user can alter the application by using the GUI.
|
||||
|
||||
These are available options:
|
||||
|
||||
* Color highlight - if enabled, areas of a particular LOD usage are
|
||||
color-highlighted.
|
||||
* Memory defragmentation - if enabled, memory pages are reallocated from
|
||||
low-occupied sectors to higher-occupied (but available) sectors to keep the
|
||||
overall number of allocations as low as possible.
|
||||
* Update prioritization - if enabled, the application is focused on
|
||||
processing the most actual requests and discards remainings from the
|
||||
previous requests. This can be observed when dynamically moving the
|
||||
camera around.
|
||||
* Blocks per cycle - describes up to how many blocks can be updated per
|
||||
a single render cycle. The total number of blocks is defined as: (Vertical
|
||||
blocks) * (Horizontal blocks).
|
||||
* Vertical blocks - describes the number of columns the texture is
|
||||
divided into.
|
||||
* Horizontal blocks - describes the number of rows the texture is
|
||||
divided into.
|
||||
|
||||
Additionally, GUI contains memory usage data. It describes (in pages)
|
||||
what are the virtual requirements (what if the whole image was allocated
|
||||
in the memory) and what is the actual, current allocation on the
|
||||
device.
|
||||
|
||||
|
||||
== Conclusion
|
||||
|
||||
The primary usage of the sparse image feature is generally speaking
|
||||
dedicated for cases where too much device's memory is occupied. Keeping
|
||||
a low-detailed mip-level constantly in the memory and dynamically
|
||||
loading required areas when the camera changes, is the way to handle
|
||||
terrain mega-textures. The downside of these solution is that there is a
|
||||
possibility of a bottleneck problem when constantly transferring
|
||||
required memory chunks from the CPU to the device. The other downside is
|
||||
that since the application decides what memory is going to be allocated,
|
||||
it must take care of the calculations such as: "`what level of detail is
|
||||
required?`". This creates an unwanted CPU overhead.
|
||||
Reference in New Issue
Block a user