Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ Common documentation

* [Building a layer](./docs/building.md)
* [Creating a new layer](./docs/creating.md)
* [Updating an existing layer](./docs/updating.md)
* [Running using a layer on Android](./docs/running_android.md)
* [Running using a layer on Linux](./docs/running_linux.md)
* [About layers design notes](./docs/about_layers.md)
Expand All @@ -86,7 +87,7 @@ or general mobile graphics development or technology, please submit them on the

- - -

_Copyright © 2024-2025, Arm Limited and contributors._
_Copyright © 2024-2026, Arm Limited and contributors._

[1]: https://community.arm.com/support-forums/f/graphics-gaming-and-vr-forum/
[2]: https://developer.arm.com/Tools%20and%20Software/Arm%20Performance%20Studio
70 changes: 70 additions & 0 deletions docs/updating.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Updating layers

This page gives you instructions for updating an existing layer to use a newer
version of Vulkan.

## Updating Vulkan version

When updating to a newer version of Vulkan, there are three things that need to
be updated in sync or things will break:

* Upstream Vulkan headers (submodule)
* Upstream Vulkan utilities library (submodule)
* Generated common code in libGPULayers

### Updating submodules

Updating Khronos Vulkan headers, e.g.:

```sh
pushd .
cd ./source_third_party/khronos/vulkan/
git checkout v1.4.359
popd
```

Updating Khronos Vulkan utilities library, e.g.:

```sh
pushd .
cd ./source_third_party/khronos/vulkan-utilities/
git checkout v1.4.359
popd
```

### Updating generated code

After you have updated the Khronos Vulkan headers, which includes the
machine-readable XML, you can regenerate the auto-generated common code:

```sh
python3 ./generator/generate_vulkan_common.py
```

### Committing your changes

All three of these changes need to land at the same time to avoid runtime
errors caused by any mismatches or unknown structures.

For maintainers updating GitHub, ensure you commit all three together when
raising a new PR to update Vulkan.

## Updating existing layers

When updating to a newer Vulkan version, existing layers might need to be
updated.

We recommend layers use a forwarding pattern, which returns Vulkan API handles
from the layer below to the application. This means that any new entrypoints
will see a valid handle, and will function as expected if a layer does not
intercept them. It is common that this style of layer needs no updates, unless
a new API function needs to be explicitly processed to implement the desired
functionality in the layer itself.

For maintainers updating GitHub, we usually commit layer updates to support new
API entry points as per-layer commits, separately from the triggering Vulkan
API update. This makes patch sets smaller and easier to review.

- - -

_Copyright © 2026, Arm Limited and contributors._
6 changes: 6 additions & 0 deletions source_common/framework/device_dispatch_table.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ static const struct DeviceInterceptTableEntry deviceIntercepts[] = {
ENTRY(vkCmdSetDiscardRectangleEXT),
ENTRY(vkCmdSetDiscardRectangleEnableEXT),
ENTRY(vkCmdSetDiscardRectangleModeEXT),
ENTRY(vkCmdSetDispatchParametersARM),
ENTRY(vkCmdSetEvent),
ENTRY(vkCmdSetEvent2),
ENTRY(vkCmdSetEvent2KHR),
Expand All @@ -292,6 +293,7 @@ static const struct DeviceInterceptTableEntry deviceIntercepts[] = {
ENTRY(vkCmdSetPolygonModeEXT),
ENTRY(vkCmdSetPrimitiveRestartEnable),
ENTRY(vkCmdSetPrimitiveRestartEnableEXT),
ENTRY(vkCmdSetPrimitiveRestartIndexEXT),
ENTRY(vkCmdSetPrimitiveTopology),
ENTRY(vkCmdSetPrimitiveTopologyEXT),
ENTRY(vkCmdSetProvokingVertexModeEXT),
Expand Down Expand Up @@ -828,6 +830,7 @@ struct DeviceDispatchTable {
PFN_vkCmdSetDiscardRectangleEXT vkCmdSetDiscardRectangleEXT;
PFN_vkCmdSetDiscardRectangleEnableEXT vkCmdSetDiscardRectangleEnableEXT;
PFN_vkCmdSetDiscardRectangleModeEXT vkCmdSetDiscardRectangleModeEXT;
PFN_vkCmdSetDispatchParametersARM vkCmdSetDispatchParametersARM;
PFN_vkCmdSetEvent vkCmdSetEvent;
PFN_vkCmdSetEvent2 vkCmdSetEvent2;
PFN_vkCmdSetEvent2KHR vkCmdSetEvent2KHR;
Expand All @@ -847,6 +850,7 @@ struct DeviceDispatchTable {
PFN_vkCmdSetPolygonModeEXT vkCmdSetPolygonModeEXT;
PFN_vkCmdSetPrimitiveRestartEnable vkCmdSetPrimitiveRestartEnable;
PFN_vkCmdSetPrimitiveRestartEnableEXT vkCmdSetPrimitiveRestartEnableEXT;
PFN_vkCmdSetPrimitiveRestartIndexEXT vkCmdSetPrimitiveRestartIndexEXT;
PFN_vkCmdSetPrimitiveTopology vkCmdSetPrimitiveTopology;
PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT;
PFN_vkCmdSetProvokingVertexModeEXT vkCmdSetProvokingVertexModeEXT;
Expand Down Expand Up @@ -1392,6 +1396,7 @@ static inline void initDriverDeviceDispatchTable(
ENTRY(vkCmdSetDiscardRectangleEXT);
ENTRY(vkCmdSetDiscardRectangleEnableEXT);
ENTRY(vkCmdSetDiscardRectangleModeEXT);
ENTRY(vkCmdSetDispatchParametersARM);
ENTRY(vkCmdSetEvent);
ENTRY(vkCmdSetEvent2);
ENTRY(vkCmdSetEvent2KHR);
Expand All @@ -1411,6 +1416,7 @@ static inline void initDriverDeviceDispatchTable(
ENTRY(vkCmdSetPolygonModeEXT);
ENTRY(vkCmdSetPrimitiveRestartEnable);
ENTRY(vkCmdSetPrimitiveRestartEnableEXT);
ENTRY(vkCmdSetPrimitiveRestartIndexEXT);
ENTRY(vkCmdSetPrimitiveTopology);
ENTRY(vkCmdSetPrimitiveTopologyEXT);
ENTRY(vkCmdSetProvokingVertexModeEXT);
Expand Down
36 changes: 35 additions & 1 deletion source_common/framework/device_functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3814,6 +3814,23 @@ VKAPI_ATTR void VKAPI_CALL layer_vkCmdSetDiscardRectangleModeEXT<default_tag>(
layer->driver.vkCmdSetDiscardRectangleModeEXT(commandBuffer, discardRectangleMode);
}

/* See Vulkan API for documentation. */
template <>
VKAPI_ATTR void VKAPI_CALL layer_vkCmdSetDispatchParametersARM<default_tag>(
VkCommandBuffer commandBuffer,
const VkDispatchParametersARM* pDispatchParameters
) {
LAYER_TRACE(__func__);

// Hold the lock to access layer-wide global store
std::unique_lock<std::mutex> lock { g_vulkanLock };
auto* layer = Device::retrieve(commandBuffer);

// Release the lock to call into the driver
lock.unlock();
layer->driver.vkCmdSetDispatchParametersARM(commandBuffer, pDispatchParameters);
}

/* See Vulkan API for documentation. */
template <>
VKAPI_ATTR void VKAPI_CALL layer_vkCmdSetEvent<default_tag>(
Expand Down Expand Up @@ -4144,6 +4161,23 @@ VKAPI_ATTR void VKAPI_CALL layer_vkCmdSetPrimitiveRestartEnableEXT<default_tag>(
layer->driver.vkCmdSetPrimitiveRestartEnableEXT(commandBuffer, primitiveRestartEnable);
}

/* See Vulkan API for documentation. */
template <>
VKAPI_ATTR void VKAPI_CALL layer_vkCmdSetPrimitiveRestartIndexEXT<default_tag>(
VkCommandBuffer commandBuffer,
uint32_t primitiveRestartIndex
) {
LAYER_TRACE(__func__);

// Hold the lock to access layer-wide global store
std::unique_lock<std::mutex> lock { g_vulkanLock };
auto* layer = Device::retrieve(commandBuffer);

// Release the lock to call into the driver
lock.unlock();
layer->driver.vkCmdSetPrimitiveRestartIndexEXT(commandBuffer, primitiveRestartIndex);
}

/* See Vulkan API for documentation. */
template <>
VKAPI_ATTR void VKAPI_CALL layer_vkCmdSetPrimitiveTopology<default_tag>(
Expand Down Expand Up @@ -8340,7 +8374,7 @@ VKAPI_ATTR VkResult VKAPI_CALL layer_vkGetPipelineKeyKHR<default_tag>(
template <>
VKAPI_ATTR VkResult VKAPI_CALL layer_vkGetPipelinePropertiesEXT<default_tag>(
VkDevice device,
const VkPipelineInfoEXT* pPipelineInfo,
const VkPipelineInfoKHR* pPipelineInfo,
VkBaseOutStructure* pPipelineProperties
) {
LAYER_TRACE(__func__);
Expand Down
30 changes: 28 additions & 2 deletions source_common/framework/device_functions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3261,6 +3261,19 @@ VKAPI_ATTR void VKAPI_CALL layer_vkCmdSetDiscardRectangleModeEXT<default_tag>(
VkCommandBuffer commandBuffer,
VkDiscardRectangleModeEXT discardRectangleMode);

/* See Vulkan API for documentation. */
/* Delete the generic match-all */
template <typename T>
VKAPI_ATTR void VKAPI_CALL layer_vkCmdSetDispatchParametersARM(
VkCommandBuffer commandBuffer,
const VkDispatchParametersARM* pDispatchParameters) = delete;

/* Default common code implementation. */
template <>
VKAPI_ATTR void VKAPI_CALL layer_vkCmdSetDispatchParametersARM<default_tag>(
VkCommandBuffer commandBuffer,
const VkDispatchParametersARM* pDispatchParameters);

/* See Vulkan API for documentation. */
/* Delete the generic match-all */
template <typename T>
Expand Down Expand Up @@ -3522,6 +3535,19 @@ VKAPI_ATTR void VKAPI_CALL layer_vkCmdSetPrimitiveRestartEnableEXT<default_tag>(
VkCommandBuffer commandBuffer,
VkBool32 primitiveRestartEnable);

/* See Vulkan API for documentation. */
/* Delete the generic match-all */
template <typename T>
VKAPI_ATTR void VKAPI_CALL layer_vkCmdSetPrimitiveRestartIndexEXT(
VkCommandBuffer commandBuffer,
uint32_t primitiveRestartIndex) = delete;

/* Default common code implementation. */
template <>
VKAPI_ATTR void VKAPI_CALL layer_vkCmdSetPrimitiveRestartIndexEXT<default_tag>(
VkCommandBuffer commandBuffer,
uint32_t primitiveRestartIndex);

/* See Vulkan API for documentation. */
/* Delete the generic match-all */
template <typename T>
Expand Down Expand Up @@ -7164,14 +7190,14 @@ VKAPI_ATTR VkResult VKAPI_CALL layer_vkGetPipelineKeyKHR<default_tag>(
template <typename T>
VKAPI_ATTR VkResult VKAPI_CALL layer_vkGetPipelinePropertiesEXT(
VkDevice device,
const VkPipelineInfoEXT* pPipelineInfo,
const VkPipelineInfoKHR* pPipelineInfo,
VkBaseOutStructure* pPipelineProperties) = delete;

/* Default common code implementation. */
template <>
VKAPI_ATTR VkResult VKAPI_CALL layer_vkGetPipelinePropertiesEXT<default_tag>(
VkDevice device,
const VkPipelineInfoEXT* pPipelineInfo,
const VkPipelineInfoKHR* pPipelineInfo,
VkBaseOutStructure* pPipelineProperties);

/* See Vulkan API for documentation. */
Expand Down
46 changes: 45 additions & 1 deletion source_common/framework/device_functions_query.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4563,6 +4563,28 @@ constexpr PFN_vkCmdSetDiscardRectangleModeEXT getLayerPtr_vkCmdSetDiscardRectang
}.operator()<user_tag>();
}

/* Test for user_tag availability. */
template <typename T>
concept hasLayerPtr_vkCmdSetDispatchParametersARM = requires(
VkCommandBuffer commandBuffer, const VkDispatchParametersARM* pDispatchParameters
) {
layer_vkCmdSetDispatchParametersARM<T>(commandBuffer, pDispatchParameters);
};

/* Function pointer resolution. */
constexpr PFN_vkCmdSetDispatchParametersARM getLayerPtr_vkCmdSetDispatchParametersARM()
{
return [] <typename T>
{
if constexpr(hasLayerPtr_vkCmdSetDispatchParametersARM<T>)
{
return layer_vkCmdSetDispatchParametersARM<T>;
}

return layer_vkCmdSetDispatchParametersARM<default_tag>;
}.operator()<user_tag>();
}

/* Test for user_tag availability. */
template <typename T>
concept hasLayerPtr_vkCmdSetEvent = requires(
Expand Down Expand Up @@ -4981,6 +5003,28 @@ constexpr PFN_vkCmdSetPrimitiveRestartEnableEXT getLayerPtr_vkCmdSetPrimitiveRes
}.operator()<user_tag>();
}

/* Test for user_tag availability. */
template <typename T>
concept hasLayerPtr_vkCmdSetPrimitiveRestartIndexEXT = requires(
VkCommandBuffer commandBuffer, uint32_t primitiveRestartIndex
) {
layer_vkCmdSetPrimitiveRestartIndexEXT<T>(commandBuffer, primitiveRestartIndex);
};

/* Function pointer resolution. */
constexpr PFN_vkCmdSetPrimitiveRestartIndexEXT getLayerPtr_vkCmdSetPrimitiveRestartIndexEXT()
{
return [] <typename T>
{
if constexpr(hasLayerPtr_vkCmdSetPrimitiveRestartIndexEXT<T>)
{
return layer_vkCmdSetPrimitiveRestartIndexEXT<T>;
}

return layer_vkCmdSetPrimitiveRestartIndexEXT<default_tag>;
}.operator()<user_tag>();
}

/* Test for user_tag availability. */
template <typename T>
concept hasLayerPtr_vkCmdSetPrimitiveTopology = requires(
Expand Down Expand Up @@ -10066,7 +10110,7 @@ constexpr PFN_vkGetPipelineKeyKHR getLayerPtr_vkGetPipelineKeyKHR()
/* Test for user_tag availability. */
template <typename T>
concept hasLayerPtr_vkGetPipelinePropertiesEXT = requires(
VkDevice device, const VkPipelineInfoEXT* pPipelineInfo, VkBaseOutStructure* pPipelineProperties
VkDevice device, const VkPipelineInfoKHR* pPipelineInfo, VkBaseOutStructure* pPipelineProperties
) {
layer_vkGetPipelinePropertiesEXT<T>(device, pPipelineInfo, pPipelineProperties);
};
Expand Down
11 changes: 11 additions & 0 deletions source_common/framework/instance_dispatch_table.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ static const struct InstanceInterceptTableEntry instanceIntercepts[] = {
ENTRY(vkGetInstanceProcAddr),
ENTRY(vkGetPhysicalDeviceCalibrateableTimeDomainsEXT),
ENTRY(vkGetPhysicalDeviceCalibrateableTimeDomainsKHR),
ENTRY(vkGetPhysicalDeviceCooperativeMatrixProperties2EXT),
ENTRY(vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR),
ENTRY(vkGetPhysicalDeviceDescriptorSizeEXT),
ENTRY(vkGetPhysicalDeviceDisplayPlaneProperties2KHR),
Expand Down Expand Up @@ -133,6 +134,8 @@ static const struct InstanceInterceptTableEntry instanceIntercepts[] = {
ENTRY(vkGetPhysicalDeviceProperties),
ENTRY(vkGetPhysicalDeviceProperties2),
ENTRY(vkGetPhysicalDeviceProperties2KHR),
ENTRY(vkGetPhysicalDeviceQueueFamilyDataGraphEngineOperationPropertiesARM),
ENTRY(vkGetPhysicalDeviceQueueFamilyDataGraphOpticalFlowImageFormatsARM),
ENTRY(vkGetPhysicalDeviceQueueFamilyDataGraphProcessingEnginePropertiesARM),
ENTRY(vkGetPhysicalDeviceQueueFamilyDataGraphPropertiesARM),
ENTRY(vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR),
Expand Down Expand Up @@ -361,6 +364,7 @@ static const struct InstanceInterceptTableEntry instanceIntercepts[] = {
ENTRY(vkCmdSetDiscardRectangleEXT),
ENTRY(vkCmdSetDiscardRectangleEnableEXT),
ENTRY(vkCmdSetDiscardRectangleModeEXT),
ENTRY(vkCmdSetDispatchParametersARM),
ENTRY(vkCmdSetEvent),
ENTRY(vkCmdSetEvent2),
ENTRY(vkCmdSetEvent2KHR),
Expand All @@ -380,6 +384,7 @@ static const struct InstanceInterceptTableEntry instanceIntercepts[] = {
ENTRY(vkCmdSetPolygonModeEXT),
ENTRY(vkCmdSetPrimitiveRestartEnable),
ENTRY(vkCmdSetPrimitiveRestartEnableEXT),
ENTRY(vkCmdSetPrimitiveRestartIndexEXT),
ENTRY(vkCmdSetPrimitiveTopology),
ENTRY(vkCmdSetPrimitiveTopologyEXT),
ENTRY(vkCmdSetProvokingVertexModeEXT),
Expand Down Expand Up @@ -740,6 +745,7 @@ struct InstanceDispatchTable {
PFN_vkGetDisplayPlaneSupportedDisplaysKHR vkGetDisplayPlaneSupportedDisplaysKHR;
PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT vkGetPhysicalDeviceCalibrateableTimeDomainsEXT;
PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsKHR vkGetPhysicalDeviceCalibrateableTimeDomainsKHR;
PFN_vkGetPhysicalDeviceCooperativeMatrixProperties2EXT vkGetPhysicalDeviceCooperativeMatrixProperties2EXT;
PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR;
PFN_vkGetPhysicalDeviceDescriptorSizeEXT vkGetPhysicalDeviceDescriptorSizeEXT;
PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR vkGetPhysicalDeviceDisplayPlaneProperties2KHR;
Expand Down Expand Up @@ -771,6 +777,8 @@ struct InstanceDispatchTable {
PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties;
PFN_vkGetPhysicalDeviceProperties2 vkGetPhysicalDeviceProperties2;
PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR;
PFN_vkGetPhysicalDeviceQueueFamilyDataGraphEngineOperationPropertiesARM vkGetPhysicalDeviceQueueFamilyDataGraphEngineOperationPropertiesARM;
PFN_vkGetPhysicalDeviceQueueFamilyDataGraphOpticalFlowImageFormatsARM vkGetPhysicalDeviceQueueFamilyDataGraphOpticalFlowImageFormatsARM;
PFN_vkGetPhysicalDeviceQueueFamilyDataGraphProcessingEnginePropertiesARM vkGetPhysicalDeviceQueueFamilyDataGraphProcessingEnginePropertiesARM;
PFN_vkGetPhysicalDeviceQueueFamilyDataGraphPropertiesARM vkGetPhysicalDeviceQueueFamilyDataGraphPropertiesARM;
PFN_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR;
Expand Down Expand Up @@ -837,6 +845,7 @@ static inline void initDriverInstanceDispatchTable(
ENTRY(vkGetDisplayPlaneSupportedDisplaysKHR);
ENTRY(vkGetPhysicalDeviceCalibrateableTimeDomainsEXT);
ENTRY(vkGetPhysicalDeviceCalibrateableTimeDomainsKHR);
ENTRY(vkGetPhysicalDeviceCooperativeMatrixProperties2EXT);
ENTRY(vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR);
ENTRY(vkGetPhysicalDeviceDescriptorSizeEXT);
ENTRY(vkGetPhysicalDeviceDisplayPlaneProperties2KHR);
Expand Down Expand Up @@ -868,6 +877,8 @@ static inline void initDriverInstanceDispatchTable(
ENTRY(vkGetPhysicalDeviceProperties);
ENTRY(vkGetPhysicalDeviceProperties2);
ENTRY(vkGetPhysicalDeviceProperties2KHR);
ENTRY(vkGetPhysicalDeviceQueueFamilyDataGraphEngineOperationPropertiesARM);
ENTRY(vkGetPhysicalDeviceQueueFamilyDataGraphOpticalFlowImageFormatsARM);
ENTRY(vkGetPhysicalDeviceQueueFamilyDataGraphProcessingEnginePropertiesARM);
ENTRY(vkGetPhysicalDeviceQueueFamilyDataGraphPropertiesARM);
ENTRY(vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR);
Expand Down
Loading