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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

### Improvements:
- Add `validate` analysis check to report unratified extensions in profiles files
- Add `transform --strip unratified` to remove all unratified extensions in profiles files

## [Vulkan Profiles Tools 1.4.363](https://github.com/KhronosGroup/Vulkan-Profiles/tree/sdk-1.4.363.0) - September 2026

Expand Down
4 changes: 4 additions & 0 deletions scripts/source/main_transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
from source.transform_strip_helper_values import strip_helper_values_profiles_files
from source.transform_strip_duplication import strip_duplication_profiles_files
from source.transform_strip_promoted_extensions import strip_promoted_extensions_profiles_files
from source.transform_strip_unratified import strip_unratified_extensions_profiles_files
from source.transform_sort import sort_profiles_files
from source.main_validate import main_validate

Expand Down Expand Up @@ -77,6 +78,9 @@ def transform_profiles_files(
if StripBits.PROMOTED_EXTENSIONS in strip_modes:
strip_promoted_extensions_profiles_files(vk, json_files_dict)

if StripBits.UNRATIFIED in strip_modes:
strip_unratified_extensions_profiles_files(vk, json_files_dict)

if sort:
sort_profiles_files(vk, json_files_dict)

Expand Down
124 changes: 124 additions & 0 deletions scripts/source/transform_strip_unratified.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#!/usr/bin/python3
#
# Copyright (c) 2026-2026 Google, Inc.
# Copyright (C) 2026-2026 Valve Corporation
# Copyright (c) 2026-2026 LunarG, Inc.
#
# 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.
#
# Authors:
# - Christophe Riccio <christophe@lunarg.com>

from source.vulkan_object_utils import (
VulkanObject,
VK_VERSION,
is_extension_struct_name,
getStructDefiningExtensions,
getExtensionPromotedTo,
)
from source.profiles_json_utils import (
collect_block_names,
get_topologically_sorted_file_keys
)


def strip_unratified_extensions_capabilities_block(
vk: VulkanObject, version: VK_VERSION, json_profiles_capabilities_block: dict
):
if not isinstance(json_profiles_capabilities_block, dict):
return

# 1. Remove unratified extensions from "extensions"
block_exts = json_profiles_capabilities_block.get("extensions")
if isinstance(block_exts, dict):
exts_to_remove = [
ext_name for ext_name in block_exts.keys()
if ext_name in vk.extensions and not vk.extensions[ext_name].ratified
]

for ext_name in exts_to_remove:
del block_exts[ext_name]

if not block_exts:
del json_profiles_capabilities_block["extensions"]

# 2. Remove structures defined by unratified extensions
remaining_exts = set(json_profiles_capabilities_block.get("extensions", {}).keys())

categories_to_check = [
cat for cat, val in list(json_profiles_capabilities_block.items())
if cat != "extensions" and isinstance(val, dict)
]

for category in categories_to_check:
category_dict = json_profiles_capabilities_block[category]
structs_to_remove = []

for struct_name in list(category_dict.keys()):
if is_extension_struct_name(vk, struct_name):
def_exts = getStructDefiningExtensions(vk, struct_name)
if def_exts:
retained = False
for ext_name in def_exts:
# Retain if the defining extension was promoted to core at or below target version
promoted = getExtensionPromotedTo(vk, ext_name)
for p_target in promoted:
p_ver = VK_VERSION.from_string(p_target)
if p_ver != VK_VERSION.NONE and version >= p_ver:
retained = True
break
if retained:
break

# Retain if the defining extension is ratified and declared in the block
if ext_name in vk.extensions and vk.extensions[ext_name].ratified:
if ext_name in remaining_exts:
retained = True
break

if not retained:
structs_to_remove.append(struct_name)

for struct_name in structs_to_remove:
del category_dict[struct_name]

if not category_dict:
del json_profiles_capabilities_block[category]


def strip_unratified_extensions_profiles_file(vk: VulkanObject, json_file_data: dict):
profiles_data = json_file_data.get("profiles", {})
json_profiles_capabilities = json_file_data.get("capabilities", {})

for profile_key, profile_obj in profiles_data.items():
api_version = VK_VERSION.from_string(profile_obj.get("api-version", "1.0.0"))
block_names = collect_block_names(profile_obj.get("capabilities", []))

for block_name in block_names:
if block_name in json_profiles_capabilities:
strip_unratified_extensions_capabilities_block(
vk, api_version, json_profiles_capabilities[block_name]
)


def strip_unratified_extensions_profiles_files(vk: VulkanObject, json_files_dict: dict):
if not isinstance(json_files_dict, dict):
return

if "profiles" in json_files_dict or "capabilities" in json_files_dict:
strip_unratified_extensions_profiles_file(vk, json_files_dict)
return

sorted_file_keys = get_topologically_sorted_file_keys(json_files_dict)
for file_key in sorted_file_keys:
strip_unratified_extensions_profiles_file(vk, json_files_dict[file_key])
1 change: 1 addition & 0 deletions scripts/source/transform_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class StripBits(str, Enum):
HELPER_VALUES = 'helper-values' # Removes non-bitpos bitmask helper values (composites, all-flags, and zero/none constants) from capability blocks.
DUPLICATION = 'duplication' # Removes redundant duplicate features, properties, and extension requirements across inheritance trees and within blocks.
PROMOTED_EXTENSIONS = 'promoted-extensions' # Removes extensions that are already promoted to the profile's target core Vulkan version.
UNRATIFIED = 'unratified' # Removes extensions and extension structures that are not ratified for Vulkan.


class CategoryPriority(IntEnum):
Expand Down
18 changes: 14 additions & 4 deletions scripts/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,22 @@

find_package(Python3 REQUIRED COMPONENTS Interpreter)

# Use PYTHON_EXECUTABLE set by root CMakeLists.txt, or fallback to Python3_EXECUTABLE
if(NOT PYTHON_EXECUTABLE)
if(VENV_PYTHON_EXECUTABLE AND NOT SKIP_PYTHON_AUTO_INSTALL)
set(PYTHON_EXECUTABLE "${VENV_PYTHON_EXECUTABLE}")
else()
set(PYTHON_EXECUTABLE "${Python3_EXECUTABLE}")
endif()
endif()

function(add_vulkan_python_test TARGET_NAME SCRIPT_FILENAME)
set(REGISTRY_PATH "${VULKAN_HEADERS_INSTALL_DIR}/${CMAKE_INSTALL_DATADIR}/vulkan/registry")
set(FULL_SCRIPT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${SCRIPT_FILENAME}")

# Register the script as a CTest test case
add_test(NAME ${TARGET_NAME}
COMMAND ${VENV_PYTHON_EXECUTABLE} "${FULL_SCRIPT_PATH}" --registry "${REGISTRY_PATH}/vk.xml"
COMMAND ${PYTHON_EXECUTABLE} "${FULL_SCRIPT_PATH}" --registry "${REGISTRY_PATH}/vk.xml"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
)

Expand All @@ -32,7 +41,7 @@ function(add_vulkan_python_test TARGET_NAME SCRIPT_FILENAME)
)
endfunction()

if(NOT APPLE) # macOS doesn't handle dynamically loading Python jsonschema'
if(NOT APPLE) # macOS does not handle dynamically loading Python jsonschema
add_vulkan_python_test(VkProfiles_TestVulkanProfilesUtil test_util.py)
add_vulkan_python_test(VkProfiles_TestVulkanObjectEmpty test_init.py)
add_vulkan_python_test(VkProfiles_TestVulkanVersion test_vulkan_version.py)
Expand Down Expand Up @@ -60,6 +69,7 @@ if(NOT APPLE) # macOS doesn't handle dynamically loading Python jsonschema'
add_vulkan_python_test(VkProfiles_TestTransformStripHelper test_transform_strip_helper.py)
add_vulkan_python_test(VkProfiles_TestTransformStripDups test_transform_strip_duplication.py)
add_vulkan_python_test(VkProfiles_TestTransformStripPromotedExts test_transform_strip_promoted_exts.py)
add_vulkan_python_test(VkProfiles_TestTransformStripUnratified test_transform_strip_unratified.py)
add_vulkan_python_test(VkProfiles_TestTransformSort test_transform_sort.py)
add_vulkan_python_test(VkProfiles_TestExtract test_extract.py)
add_vulkan_python_test(VkProfiles_TestMinApiVersion test_min_api_version.py)
Expand All @@ -74,7 +84,7 @@ set(PROFILES_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/profiles")
add_custom_target(VpGenerate-Profiles-Android ALL
COMMAND ${CMAKE_COMMAND} -E make_directory "${PROFILES_OUTPUT_DIR}"
COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${REGISTRY_PATH}"
${VENV_PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/../vkprofiles.py" transform
${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/../vkprofiles.py" transform
--registry "${REGISTRY_PATH}/vk.xml"
--input "${PROFILES_INPUT_DIR}"
--output "${PROFILES_OUTPUT_DIR}"
Expand All @@ -88,4 +98,4 @@ add_custom_target(VpGenerate-Profiles-Android ALL
VERBATIM
)
set_target_properties(VpGenerate-Profiles-Android PROPERTIES FOLDER "Profiles generator")
add_dependencies(VpGenerate-Profiles-Android VpProfilesProcessor)
add_dependencies(VpGenerate-Profiles-Android VpProfilesProcessor)
Loading
Loading