This commit is contained in:
xsl
2025-09-04 10:54:47 +08:00
commit 6bc8f61b18
1808 changed files with 208268 additions and 0 deletions
+32
View File
@@ -0,0 +1,32 @@
# Copyright (c) 2019-2021, Arm Limited and Contributors
#
# 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.
#
get_filename_component(FOLDER_NAME ${CMAKE_CURRENT_LIST_DIR} NAME)
get_filename_component(PARENT_DIR ${CMAKE_CURRENT_LIST_DIR} PATH)
get_filename_component(CATEGORY_NAME ${PARENT_DIR} NAME)
add_sample_with_tags(
ID ${FOLDER_NAME}
CATEGORY ${CATEGORY_NAME}
AUTHOR "Arm"
NAME "AFBC"
DESCRIPTION "Using framebuffer compression to reduce bandwidth."
TAGS
"arm"
SHADER_FILES_GLSL
"base.vert"
"base.frag")
+163
View File
@@ -0,0 +1,163 @@
////
- Copyright (c) 2019-2024, Arm Limited and Contributors
-
- 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.
-
////
= Enabling AFBC in your Vulkan Application
ifdef::site-gen-antora[]
TIP: The source for this sample can be found in the https://github.com/KhronosGroup/Vulkan-Samples/tree/main/samples/performance/afbc[Khronos Vulkan samples github repository].
endif::[]
== Overview
AFBC (Arm Frame Buffer Compression) is a real-time lossless compression algorithm found in Arm Mali GPUs, designed to tackle the ever-growing demand for higher resolution graphics.
This format is applied to the framebuffers that are to be written to the GPU.
This technology can offer bandwidth reductions of https://developer.arm.com/technologies/graphics-technologies/arm-frame-buffer-compression[up to 50%].
The sample is geared towards demonstrating the bandwidth that you can save by toggling AFBC on and off and displaying a real-time graph of the external bandwidth.
In this case we will be focusing on the swapchain images.
The Vulkan API allows the developer a level of control around how the `VkSwapchainKHR` is created and formatted.
It is here where we want to ensure that it is created and formatted in the right way so that the subsequent ``VkImage``'s that we query from it have AFBC appropriately applied.
It is important to note that from a device perspective to have AFBC enabled on Vulkan, you will need at least driver version `r16p0` and a `Mali G-51` or higher.
To find out your GPU and driver version, open the link:../../../docs/misc.adoc#Debug-Window[debug window] or follow the steps in this link:../../../docs/misc.adoc#Driver-Version[article].
____
Tested on: Samsung Galaxy S10, Huawei P30
____
== Enabling AFBC
AFBC is functionally transparent to the application and will be automatically applied on a per `VkImage` basis (provided multiple checks pass on various properties of your device and your images).
The driver will check the applications state along with the `VkImage` properties to determine if it will enable AFBC or just continue without it.
This section will detail the requirements.
`VkImage` requirements:
* `VkSampleCountFlagBits` must be `VK_SAMPLE_COUNT_1_BIT`
* `VkImageType` must be `VK_IMAGE_TYPE_2D`
* `VkImageTiling` must be `VK_IMAGE_TILING_OPTIMAL`
* `VkFormat` <<format-support,supported list>>
In addition to this, your `VkImage` needs to adhere to the following flags:
* `VkImageUsageFlags` must not contain:
** `VK_IMAGE_USAGE_STORAGE_BIT`
** `VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT`
** (Only for some devices with driver version `r16p0`) `VK_IMAGE_USAGE_TRANSFER_DST_BIT`
* `VkImageCreateFlags` must not contain:
** `VK_IMAGE_CREATE_ALIAS_BIT`
** `VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT`
== The AFBC Sample
The sample presents the user with Sponza, with a graph displaying bandwidth at the top and a configuration window at the bottom.
There is a back-and-forth oscillating camera to disable any GPU optimisations for frames that are identical.
The configuration itself is simple.
There is one checkbox (labelled "Enable AFBC") that will reload the swapchain when its value is changed.
image::./images/afbc_disabled.jpg[Sponza AFBC off]
Here the sample is in its default state: AFBC off.
At the top of the screen there is a graph displaying the external write bandwidth (measured from `L2_EXT_WRITE_BEATS`).
It is currently setting the `VK_IMAGE_USAGE_STORAGE_BIT` flag in the `VkImageUsageFlags` for the swapchain images, causing the driver to skip over applying AFBC to the swapchain images.
When we enable the check box, the sample will reload the swapchain with the right usage flags to have the driver enable AFBC.
image::./images/afbc_enabled.jpg[Sponza AFBC on]
Here is the same scene as before, except AFBC is now enabled.
The `VK_IMAGE_USAGE_STORAGE_BIT` flag is not being set and the swapchain is being created properly.
The bandwidth has dropped from 788.0 MiB/s to 528.6 MiB/s, this is approximately a 33% reduction.
You can also confirm these numbers in Streamline.
Here are some screenshots:
image:./images/streamline_disabled.png[Streamline AFBC Off] image:./images/streamline_enabled.png[Streamline AFBC On]
== Format Support
GPUs from Mali-G77 onwards support formats up to and including 32 bits per pixel regardless of color channel arrangement or sRBG.
Previous generations that support AFBC only support a subset of formats:
[cols=^]
|===
| Formats
| VK_FORMAT_R4G4B4A4_UNORM_PACK16
| VK_FORMAT_B4G4R4A4_UNORM_PACK16
| VK_FORMAT_R5G6B5_UNORM_PACK16
| VK_FORMAT_R5G5B5A1_UNORM_PACK16
| VK_FORMAT_B5G5R5A1_UNORM_PACK16
| VK_FORMAT_A1R5G5B5_UNORM_PACK16
| VK_FORMAT_B8G8R8_UNORM
| VK_FORMAT_B8G8R8A8_UNORM
| VK_FORMAT_B8G8R8A8_SRGB
| VK_FORMAT_A8B8G8R8_UNORM
| VK_FORMAT_A8B8G8R8_SRGB
| VK_FORMAT_A8R8G8B8_SRGB
| VK_FORMAT_B10G10R10A2_UNORM
| VK_FORMAT_R4G4B4A4_UNORM
| VK_FORMAT_R5G6B5_UNORM
| VK_FORMAT_R5G5B5A1_UNORM
| VK_FORMAT_R8_UNORM
| VK_FORMAT_R8G8_UNORM
| VK_FORMAT_R8G8B8_UNORM
| VK_FORMAT_R8G8B8A8_UNORM
| VK_FORMAT_R8G8B8A8_SRGB
| VK_FORMAT_A8R8G8B8_UNORM
| VK_FORMAT_R10G10B10A2_UNORM
| VK_FORMAT_D24_UNORM_S8_UINT
| VK_FORMAT_D16_UNORM
| VK_FORMAT_D32_SFLOAT
|===
== Further Reading
* https://www.arm.com/why-arm/technologies/graphics-technologies/arm-frame-buffer-compression[Arm Frame Buffer Compression] - developer.arm.com
== Best practice summary
*Do*
* Ensure that your swapchain is created correctly as per the requirements of AFBC.
* AFBC is not a replacement for (it is independent of) texture compression like ASTC, so always compress all of the things when possible.
* Avoid changing your image configuration at run-time (using `vkCmdCopyImage` with an invalid AFBC requirement) as it will trigger a decompression.
* Make sure you are resolving your images using `pResolveAttachments` when it comes to multisampling.
Any `VkImage` with `SAMPLE_COUNT > 1` will not have AFBC applied to it.
*Don't*
* Use image usage flags, such as `VK_IMAGE_USAGE_STORAGE_BIT`, unless you really need it (i.e.
for compute on a specific image).
*Impact*
* Having an incorrect configuration of your images will cause all your surface ``VkImage``'s to be uncompressed, losing out on considerable system wide bandwidth reductions.
*Debugging*
* To test if AFBC is enabled or disabled, you can use a profiler such as Streamline and record the bandwidth values when AFBC is enabled or when AFBC is disabled.
* You may also use the extension https://docs.vulkan.org/spec/latest/appendices/extensions.html#VK_EXT_image_compression_control[`VK_EXT_image_compression_control`] to query if AFBC is enabled.
See the xref:/samples/performance/image_compression_control/README.adoc[Image Compression Control sample] for more details.
+136
View File
@@ -0,0 +1,136 @@
/* Copyright (c) 2019-2025, Arm Limited and Contributors
*
* 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.
*/
#include "afbc.h"
#include "common/vk_common.h"
#include "filesystem/legacy.h"
#include "gltf_loader.h"
#include "gui.h"
#include "rendering/subpasses/forward_subpass.h"
#include "stats/stats.h"
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
# include "platform/android/android_platform.h"
#endif
#include "scene_graph/components/camera.h"
#include "scene_graph/components/transform.h"
#include "scene_graph/node.h"
AFBCSample::AFBCSample()
{
// Extension that may be used to query if AFBC is enabled
add_device_extension(VK_EXT_IMAGE_COMPRESSION_CONTROL_EXTENSION_NAME, true);
auto &config = get_configuration();
config.insert<vkb::BoolSetting>(0, afbc_enabled, false);
config.insert<vkb::BoolSetting>(1, afbc_enabled, true);
}
bool AFBCSample::prepare(const vkb::ApplicationOptions &options)
{
if (!VulkanSample::prepare(options))
{
return false;
}
// We want AFBC disabled at start-up
afbc_enabled = false;
recreate_swapchain();
load_scene("scenes/sponza/Sponza01.gltf");
auto &camera_node = vkb::add_free_camera(get_scene(), "main_camera", get_render_context().get_surface_extent());
camera = &camera_node.get_component<vkb::sg::Camera>();
vkb::ShaderSource vert_shader("base.vert.spv");
vkb::ShaderSource frag_shader("base.frag.spv");
auto scene_subpass = std::make_unique<vkb::ForwardSubpass>(get_render_context(), std::move(vert_shader), std::move(frag_shader), get_scene(), *camera);
auto render_pipeline = std::make_unique<vkb::RenderPipeline>();
render_pipeline->add_subpass(std::move(scene_subpass));
set_render_pipeline(std::move(render_pipeline));
get_stats().request_stats({vkb::StatIndex::gpu_ext_write_bytes});
create_gui(*window, &get_stats());
// Store the start time to calculate rotation
start_time = std::chrono::system_clock::now();
return true;
}
void AFBCSample::update(float delta_time)
{
if (afbc_enabled != afbc_enabled_last_value)
{
recreate_swapchain();
afbc_enabled_last_value = afbc_enabled;
}
/* Pan the camera back and forth. */
auto &camera_transform = camera->get_node()->get_component<vkb::sg::Transform>();
float rotation_factor = std::chrono::duration<float>(std::chrono::system_clock::now() - start_time).count();
glm::quat qy = glm::angleAxis(0.003f * sin(rotation_factor * 0.7f), glm::vec3(0.0f, 1.0f, 0.0f));
glm::quat orientation = glm::normalize(qy * camera_transform.get_rotation() * glm::angleAxis(0.0f, glm::vec3(1.0f, 0.0f, 0.0f)));
camera_transform.set_rotation(orientation);
VulkanSample::update(delta_time);
}
void AFBCSample::recreate_swapchain()
{
std::set<VkImageUsageFlagBits> image_usage_flags = {VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT};
if (!afbc_enabled)
{
// To force-disable AFBC, set an invalid image usage flag
image_usage_flags.insert(VK_IMAGE_USAGE_STORAGE_BIT);
}
get_device().wait_idle();
get_render_context().update_swapchain(image_usage_flags);
}
void AFBCSample::draw_gui()
{
get_gui().show_options_window(
/* body = */ [this]() {
ImGui::Checkbox("Enable AFBC", &afbc_enabled);
if (get_device().is_extension_enabled(VK_EXT_IMAGE_COMPRESSION_CONTROL_EXTENSION_NAME))
{
ImGui::SameLine();
ImGui::Text("(%s)", vkb::image_compression_flags_to_string(get_render_context().get_swapchain().get_applied_compression()).c_str());
}
},
/* lines = */ 1);
}
std::unique_ptr<vkb::VulkanSampleC> create_afbc()
{
return std::make_unique<AFBCSample>();
}
+53
View File
@@ -0,0 +1,53 @@
/* Copyright (c) 2019-2024, Arm Limited and Contributors
*
* 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.
*/
#pragma once
#include "rendering/render_pipeline.h"
#include "scene_graph/components/camera.h"
#include "timer.h"
#include "vulkan_sample.h"
/**
* @brief Using framebuffer compression to reduce bandwidth
*/
class AFBCSample : public vkb::VulkanSampleC
{
public:
AFBCSample();
virtual ~AFBCSample() = default;
virtual bool prepare(const vkb::ApplicationOptions &options) override;
virtual void update(float delta_time) override;
private:
vkb::sg::Camera *camera{nullptr};
virtual void draw_gui() override;
void recreate_swapchain();
bool afbc_enabled_last_value{false};
bool afbc_enabled{false};
std::chrono::system_clock::time_point start_time;
};
std::unique_ptr<vkb::VulkanSampleC> create_afbc();
Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB