Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion layer_gpu_support/README_LAYER.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,16 +175,28 @@ allocated and handled by the driver.
per component setting. Images that do not support a fixed rate compression
level that meets this bit rate requirement will be left at the original
application setting.
* If `disable_external_compression` option is set to `1` , all the possible measures
are taken so that external compression is disabled. In case is not possible to garantuee
that external compression is used, the layer will return VK_ERROR_FEATURE_NOT_PRESENT.
It should be set to `2` only if the application is not presenting, and is targeting vkCreateImage.
Option `2` is an heuristic, compression could be disabled accidentally on internal images,
and is also possible that it misses external images, if they lack COLOR_ATTACHMENT_BIT.
Feel free to tune the heuristic to your specific use case.

#### Configuration options

```jsonc
"framebuffer": {
"disable_compression": false, // Disable all use of compression
"force_default_compression": false, // Force driver default compression
"force_fixed_rate_compression": 0 // Force use of fixed rate compression as close
"force_fixed_rate_compression": 0, // Force use of fixed rate compression as close
// to this bits-per-channel as possible, but
// no lower (0 = do not force)
"disable_external_compression": 0, // 0 = Perform no operation, passthrough
// 1 = Force disable external compression, requires image presentation
// 2 = Force disable external compression also without
// presentation, requires only the use of vkCreateImage
// WARNING! Currently implemented as an heuristic
}
```

Expand Down
3 changes: 2 additions & 1 deletion layer_gpu_support/layer_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"framebuffer": {
"disable_compression": false,
"force_default_compression": false,
"force_fixed_rate_compression": 0
"force_fixed_rate_compression": 0,
"disable_external_compression": 0
}
}
5 changes: 4 additions & 1 deletion layer_gpu_support/source/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,14 @@ add_library(
layer_config.cpp
layer_device_functions_dispatch.cpp
layer_device_functions_image.cpp
layer_device_functions_swapchain.cpp
layer_device_functions_allocate_memory.cpp
layer_device_functions_pipelines.cpp
layer_device_functions_queue.cpp
layer_device_functions_render_pass.cpp
layer_device_functions_trace_rays.cpp
layer_device_functions_transfer.cpp)
layer_device_functions_transfer.cpp
layer_instance_functions_get_physical_properties.cpp)

target_include_directories(
${VK_LAYER} PRIVATE
Expand Down
10 changes: 10 additions & 0 deletions layer_gpu_support/source/layer_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ void LayerConfig::parse_framebuffer_options(const json& config)
bool disable_all_compression = framebuffer.at("disable_compression");
bool default_all_compression = framebuffer.at("force_default_compression");
uint64_t force_fixed_rate_compression = framebuffer.at("force_fixed_rate_compression");
int disable_external_compression = framebuffer.at("disable_external_compression");

// Apply precedence ladder
if (disable_all_compression)
Expand Down Expand Up @@ -228,13 +229,16 @@ void LayerConfig::parse_framebuffer_options(const json& config)
conf_framebuffer_disable_compression = disable_all_compression;
conf_framebuffer_force_default_compression = default_all_compression;
conf_framebuffer_force_fixed_rate_compression = fixed_rate_mask;
conf_disable_external_compression = disable_external_compression;

LAYER_LOG("Layer framebuffer configuration");
LAYER_LOG("===============================");
LAYER_LOG(" - Disable framebuffer compression: %d", conf_framebuffer_disable_compression);
LAYER_LOG(" - Force default framebuffer compression: %d", conf_framebuffer_force_default_compression);
LAYER_LOG(" - Force fixed rate compression: %lu bpc", force_fixed_rate_compression);
LAYER_LOG(" - Force fixed rate compression mask: %08x", conf_framebuffer_force_fixed_rate_compression);
LAYER_LOG(" - Force disable external compression: %d", conf_disable_external_compression);

}

/* See header for documentation. */
Expand Down Expand Up @@ -430,3 +434,9 @@ uint32_t LayerConfig::framebuffer_force_fixed_rate_compression() const
{
return conf_framebuffer_force_fixed_rate_compression;
}

/* See header for documentation. */
int LayerConfig::disable_external_compression() const
{
return conf_disable_external_compression;
}
22 changes: 22 additions & 0 deletions layer_gpu_support/source/layer_config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,15 @@ class LayerConfig
*/
uint32_t framebuffer_force_fixed_rate_compression() const;


/**
* @brief External compression control for swapchains/images.
* 0 = passthrough (default),
* 1 = strip compression on external images,
* 2 = strip compression on external images even without presentation, using heuristic (no garantuee!)
*/
int disable_external_compression() const;

private:
/**
* @brief Parse the configuration options for the feature module.
Expand Down Expand Up @@ -315,4 +324,17 @@ class LayerConfig
* If zero, then no force is set and default compression will be used.
*/
uint32_t conf_framebuffer_force_fixed_rate_compression {0};

/**
* @brief Forces disabling external compression.
*
* 0 = Perform no operation, passthrough.
* 1 = Force disable external compression, requires image presentation.
* 2 = Force disable external compression also without.
* presentation, requires only the use of vkCreateImage.
*
* WARNING! Currently implemented as an heuristic.
*/
int conf_disable_external_compression {0};

};
20 changes: 20 additions & 0 deletions layer_gpu_support/source/layer_device_functions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -369,3 +369,23 @@ VKAPI_ATTR VkResult VKAPI_CALL layer_vkCreateImage<user_tag>(VkDevice device,
const VkImageCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkImage* pImage);


// Functions for swapchains

/* See Vulkan API for documentation. */
template <>
VKAPI_ATTR VkResult VKAPI_CALL layer_vkCreateSwapchainKHR<user_tag>(VkDevice device,
const VkSwapchainCreateInfoKHR* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkSwapchainKHR* pSwapchain
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Closing brace on same line as last parameter to keep clang=tidy happy. Ditto below.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reformatted everywhere, I hope. Do we have something to check that all the formatting is compliant?

);

// Functions for external DMA-buf

template <>
VKAPI_ATTR VkResult VKAPI_CALL layer_vkAllocateMemory<user_tag>(VkDevice device,
const VkMemoryAllocateInfo* pAllocateInfo,
const VkAllocationCallbacks* pAllocator,
VkDeviceMemory* pMemory
);
112 changes: 112 additions & 0 deletions layer_gpu_support/source/layer_device_functions_allocate_memory.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
* SPDX-License-Identifier: MIT
* ----------------------------------------------------------------------------
* Copyright (c) 2025 Arm Limited
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
* ----------------------------------------------------------------------------
*/
#include <vulkan/utility/vk_safe_struct.hpp>
#include <vulkan/utility/vk_struct_helper.hpp>

#include "device.hpp"
#include "framework/device_dispatch_table.hpp"

#include <bit>
#include <mutex>

extern std::mutex g_vulkanLock;

/**
* @brief Intercept vkAllocateMemory and hard-fail on external memory imports
* that could mandate external compression; otherwise pass through to the driver.
*
* @details Scans @p pAllocateInfo->pNext for import structs. If it finds
* VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID or
* VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR with
* VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, it returns
* VK_ERROR_FEATURE_NOT_PRESENT to preserve the guarantee that
* external compression is not used. When no such imports are present, the
* call is forwarded unchanged.
*
* @param device Logical device allocating the memory.
* @param pAllocateInfo Allocation parameters; its pNext chain is inspected
* for import info.
* @param pAllocator Optional allocation callbacks.
* @param pMemory Receives the allocated device memory on success.
*
* @return VK_SUCCESS on success, or a VkResult propagated from the driver.
* Returns VK_ERROR_FEATURE_NOT_PRESENT when disallowed external
* import types are detected in the pNext chain.
*
* @note This is a strict policy check; additional import structures may be
* rejected in the future to maintain the compression-off guarantee.
*/

/* See Vulkan API for documentation. */
template <>
VKAPI_ATTR VkResult VKAPI_CALL layer_vkAllocateMemory<user_tag>(
VkDevice device,
const VkMemoryAllocateInfo* pAllocateInfo,
const VkAllocationCallbacks* pAllocator,
VkDeviceMemory* pMemory
) {

LAYER_TRACE(__func__);

//fprintf(stderr, "[libGPULayers] HIT %s\n", __func__); fflush(stderr);

std::unique_lock<std::mutex> lock { g_vulkanLock };
auto* layer = Device::retrieve(device);
const auto& config = layer->instance->config;

int disable_external_compression = config.disable_external_compression();

//absolute passthrough if feature is off
if (disable_external_compression == 0) {
lock.unlock();
return layer->driver.vkAllocateMemory(device, pAllocateInfo, pAllocator, pMemory);
}

// Scan pNext for imports that we cannot sanitize -> hard-fail to keep the 100% guarantee that we can disable external compression
for (const VkBaseInStructure* n = (const VkBaseInStructure*)pAllocateInfo->pNext; n; n = n->pNext) {

if (n->sType == VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID) {
printf("[libGPULayers] vkAllocateMemory: AHardwareBuffer IMPORT detected. "
"Cannot guarantee external compression is disabled (buffer created outside Vulkan). Failing by policy.\n");
return VK_ERROR_FEATURE_NOT_PRESENT;
}

if (n->sType == VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR) {
const VkImportMemoryFdInfoKHR* fdInfo = (const VkImportMemoryFdInfoKHR*)n;
if (fdInfo->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT) {
printf("[libGPULayers] vkAllocateMemory: DMA-BUF memory IMPORT detected (fd=%d). "
"Cannot guarantee external compression (DRM modifier may imply compression). Failing by policy.\n",
fdInfo->fd);
return VK_ERROR_FEATURE_NOT_PRESENT;
}
}

}

// Release the lock to call into the driver
lock.unlock();
return layer->driver.vkAllocateMemory(device, pAllocateInfo, pAllocator, pMemory);

}
Loading