u/extension_list: Refactor and rename from u_string_list

Co-authored-by: Korcan Hussein <korcan.hussein@collabora.com>
Part-of: <https://gitlab.freedesktop.org/monado/monado/-/merge_requests/2693>
This commit is contained in:
Jakob BornecrantzandKorcan Hussein committed 2026-02-03 10:30:00 +00:00
1 parent ea9d89dae0
commit f874b12e43
25 files changed
+1275 -886

No files matched your search

+4 -4
View File
@@ -1,5 +1,5 @@
# Copyright 2019-2024, Collabora, Ltd.
# Copyright 2024-2025, NVIDIA CORPORATION.
# Copyright 2024-2026, NVIDIA CORPORATION.
# SPDX-License-Identifier: BSL-1.0
####
@@ -89,9 +89,9 @@ add_library(
u_session.h
u_space_overseer.c
u_space_overseer.h
u_string_list.cpp
u_string_list.h
u_string_list.hpp
u_extension_list.cpp
u_extension_list.h
u_extension_list.hpp
u_system.c
u_system.h
u_system_helpers.c
+449
View File
@@ -0,0 +1,449 @@
// Copyright 2021-2026, Collabora, Ltd.
// Copyright 2025-2026, NVIDIA CORPORATION.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief A collection of strings for extensions.
*
* @author Rylie Pavlik <rylie.pavlik@collabora.com>
* @ingroup aux_util
*
*/
#include "u_extension_list.h"
#include "u_extension_list.hpp"
#include <algorithm>
#include <cstring>
#include <string>
#include <string_view>
/*
*
* Defines and structs.
*
*/
using xrt::auxiliary::util::ExtensionList;
using xrt::auxiliary::util::ExtensionListBuilder;
struct u_extension_list
{
u_extension_list() = default;
u_extension_list(ExtensionList &&extension_list) : list(std::move(extension_list)) {}
ExtensionList list;
};
struct u_extension_list_builder
{
u_extension_list_builder() = default;
u_extension_list_builder(size_t capacity) : builder(capacity) {}
u_extension_list_builder(u_extension_list_builder &&) = delete;
u_extension_list_builder(u_extension_list_builder const &) = delete;
u_extension_list_builder &
operator=(u_extension_list_builder &&) = delete;
u_extension_list_builder &
operator=(u_extension_list_builder const &) = delete;
ExtensionListBuilder builder;
};
/*
*
* Helpers
*
*/
enum class ExtensionType
{
KHR = 0, // Khronos extensions
EXT = 1, // Multi-vendor extensions
VENDOR = 2, // Vendor-specific extensions (AMD, NV, INTEL, etc.)
EXPERIMENTAL = 3 // Experimental extensions
};
/*!
* @brief Helper class for sorting extension names.
*
* Encapsulates the sort key with comparison operators for cleaner sorting.
*/
struct ExtensionSortKey
{
std::string_view api_prefix;
ExtensionType type;
std::string_view name;
/*!
* Sorts in field declaration order:
*
* 1. API prefix (VK, XR, etc.)
* 2. Extension type (KHR < EXT < VENDOR < EXPERIMENTAL)
* 3. Alphabetically by full name
*/
auto
operator<=>(const ExtensionSortKey &other) const = default;
};
/*!
* @brief Check if a vendor string represents an experimental extension.
*
* Experimental extensions have vendor codes ending with 'X' optionally followed
* by digits.
*
* Examples: NVX, AMDX, NVX1, NVX2, INTELX
*
* Special case: QNX is a legitimate vendor (QNX operating system), not
* experimental.
*/
static bool
is_experimental_vendor(std::string_view vendor)
{
// Special case: QNX is a legitimate vendor, not experimental
if (vendor == "QNX") {
return false;
}
// Check if vendor ends with 'X' optionally followed by digits
if (vendor.empty()) {
return false;
}
size_t len = vendor.length();
size_t i = len - 1;
// Skip trailing digits
while (i > 0 && std::isdigit(vendor[i])) {
i--;
}
// Check if we found an 'X' and there's something before it
return (vendor[i] == 'X' && i > 0);
}
/*!
* @brief Get the extension type and API prefix for sorting purposes.
*
* Returns an ExtensionSortKey for comparison.
*/
static ExtensionSortKey
get_extension_sort_key(std::string_view name)
{
// Find the first underscore to separate API prefix (e.g., "VK", "XR")
size_t first_underscore = name.find('_');
if (first_underscore == std::string::npos) {
// No underscore, treat as is
return {name, ExtensionType::VENDOR, name};
}
std::string_view api_prefix = name.substr(0, first_underscore);
// Find the second underscore to get the vendor/type part
size_t second_underscore = name.find('_', first_underscore + 1);
if (second_underscore == std::string::npos) {
// Only one underscore, treat as vendor
return {api_prefix, ExtensionType::VENDOR, name};
}
std::string_view vendor = name.substr(first_underscore + 1, second_underscore - first_underscore - 1);
// Determine extension type based on vendor string
ExtensionType type;
if (vendor == "KHR") {
type = ExtensionType::KHR;
} else if (vendor == "EXT") {
type = ExtensionType::EXT;
} else if (is_experimental_vendor(vendor)) {
type = ExtensionType::EXPERIMENTAL;
} else {
type = ExtensionType::VENDOR;
}
return {api_prefix, type, name};
}
/*
*
* 'Exported' functions - Immutable Extension List
*
*/
struct u_extension_list *
u_extension_list_create()
{
try {
auto ret = std::make_unique<u_extension_list>();
return ret.release();
} catch (std::exception const &) {
return nullptr;
}
}
struct u_extension_list *
u_extension_list_create_from_array(const char *const *arr, uint32_t size)
{
if (arr == nullptr || size == 0) {
return u_extension_list_create();
}
try {
ExtensionListBuilder builder(size);
for (uint32_t i = 0; i < size; ++i) {
if (arr[i] != nullptr) {
builder.append(arr[i]);
}
}
auto ret = std::make_unique<u_extension_list>(std::move(builder).build());
return ret.release();
} catch (std::exception const &) {
return nullptr;
}
}
uint32_t
u_extension_list_get_size(const struct u_extension_list *uel)
{
if (uel == nullptr) {
return 0;
}
return uel->list.size();
}
const char *const *
u_extension_list_get_data(const struct u_extension_list *uel)
{
if (uel == nullptr) {
return nullptr;
}
return uel->list.data();
}
bool
u_extension_list_contains(const struct u_extension_list *uel, const char *str)
{
if (uel == nullptr || str == nullptr) {
return false;
}
return uel->list.contains(str);
}
bool
u_extension_list_contains_len(const struct u_extension_list *uel, const char *str, size_t len)
{
if (uel == nullptr || str == nullptr) {
return false;
}
return uel->list.contains(std::string_view(str, len));
}
void
u_extension_list_destroy(struct u_extension_list **list_ptr)
{
if (list_ptr == nullptr) {
return;
}
u_extension_list *list = *list_ptr;
if (list == nullptr) {
return;
}
delete list;
*list_ptr = nullptr;
}
/*
*
* Extension List Builder Methods
*
*/
void
ExtensionListBuilder::sortForExtensions()
{
if (strings.empty()) {
return;
}
// Sort using our custom comparison function that works with std::string
auto cmp = [](const std::string &a, const std::string &b) {
return get_extension_sort_key(a) < get_extension_sort_key(b);
};
std::sort(strings.begin(), strings.end(), cmp);
}
/*
*
* 'Exported' functions - Extension List Builder
*
*/
struct u_extension_list_builder *
u_extension_list_builder_create()
{
try {
auto ret = std::make_unique<u_extension_list_builder>();
return ret.release();
} catch (std::exception const &) {
return nullptr;
}
}
struct u_extension_list_builder *
u_extension_list_builder_create_with_capacity(uint32_t capacity)
{
try {
auto ret = std::make_unique<u_extension_list_builder>(capacity);
return ret.release();
} catch (std::exception const &) {
return nullptr;
}
}
struct u_extension_list_builder *
u_extension_list_builder_create_from_array(const char *const *arr, uint32_t size)
{
if (arr == nullptr || size == 0) {
return u_extension_list_builder_create();
}
try {
auto ret = std::make_unique<u_extension_list_builder>();
for (uint32_t i = 0; i < size; ++i) {
if (arr[i] != nullptr) {
ret->builder.append(arr[i]);
}
}
return ret.release();
} catch (std::exception const &) {
return nullptr;
}
}
int
u_extension_list_builder_append(struct u_extension_list_builder *uelb, const char *str)
{
if (uelb == nullptr || str == nullptr) {
return -1;
}
try {
uelb->builder.append(str);
return 1;
} catch (std::exception const &) {
return -1;
}
}
int
u_extension_list_builder_append_len(struct u_extension_list_builder *uelb, const char *str, size_t len)
{
if (uelb == nullptr || str == nullptr) {
return -1;
}
try {
uelb->builder.append(std::string_view(str, len));
return 1;
} catch (std::exception const &) {
return -1;
}
}
int
u_extension_list_builder_append_array(struct u_extension_list_builder *uelb, const char *const *arr, uint32_t size)
{
if (uelb == nullptr || arr == nullptr) {
return -1;
}
try {
for (uint32_t i = 0; i < size; ++i) {
if (arr[i] != nullptr) {
uelb->builder.append(arr[i]);
}
}
return 1;
} catch (std::exception const &) {
return -1;
}
}
int
u_extension_list_builder_append_unique(struct u_extension_list_builder *uelb, const char *str)
{
if (uelb == nullptr || str == nullptr) {
return -1;
}
try {
auto added = uelb->builder.appendUnique(str);
return added ? 1 : 0;
} catch (std::exception const &) {
return -1;
}
}
int
u_extension_list_builder_append_unique_len(struct u_extension_list_builder *uelb, const char *str, size_t len)
{
if (uelb == nullptr || str == nullptr) {
return -1;
}
try {
auto added = uelb->builder.appendUnique(std::string_view(str, len));
return added ? 1 : 0;
} catch (std::exception const &) {
return -1;
}
}
struct u_extension_list *
u_extension_list_builder_build(struct u_extension_list_builder **builder_ptr)
{
u_extension_list_builder *builder = *builder_ptr;
if (builder == nullptr) {
return nullptr;
}
try {
auto ret = std::make_unique<u_extension_list>(std::move(builder->builder).build());
delete builder;
*builder_ptr = nullptr;
return ret.release();
} catch (std::exception const &) {
return nullptr;
}
}
struct u_extension_list *
u_extension_list_builder_build_sorted_for_extensions(struct u_extension_list_builder **builder_ptr)
{
u_extension_list_builder *builder = *builder_ptr;
if (builder == nullptr) {
return nullptr;
}
try {
// Sort the builder in-place before building
builder->builder.sortForExtensions();
// Now build the sorted list
auto ret = std::make_unique<u_extension_list>(std::move(builder->builder).build());
delete builder;
*builder_ptr = nullptr;
return ret.release();
} catch (std::exception const &) {
return nullptr;
}
}
void
u_extension_list_builder_destroy(struct u_extension_list_builder **builder_ptr)
{
u_extension_list_builder *builder = *builder_ptr;
if (builder == nullptr) {
return;
}
delete builder;
*builder_ptr = nullptr;
}
+283
View File
@@ -0,0 +1,283 @@
// Copyright 2021, Collabora, Ltd.
// Copyright 2025-2026, NVIDIA CORPORATION.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief A collection of strings, like a list of extensions to enable
*
* @author Rylie Pavlik <rylie.pavlik@collabora.com>
* @ingroup aux_util
*
*/
#pragma once
#include "xrt/xrt_compiler.h"
#ifdef __cplusplus
extern "C" {
#endif
/*!
* @brief An immutable collection of extension strings, these are used to
* interface with APIs such as Vulkan and OpenXR who use strings for extensions.
*
* This structure stores copies of strings internally and provides read-only access.
*
* @see xrt::auxiliary::util::ExtensionList
*/
struct u_extension_list;
/*!
* @brief A builder for constructing immutable extension lists.
*
* This structure allows write-only operations to build up a list of extension
* strings.
*
* @see xrt::auxiliary::util::ExtensionListBuilder
*/
struct u_extension_list_builder;
/*
*
* Immutable Extension List API
*
*/
/*!
* @brief Create an empty extension list, some APIs might require an extension
* list to be passed in so there is some utility for this function.
*
* @public @memberof u_extension_list
*/
struct u_extension_list *
u_extension_list_create(void);
/*!
* @brief Create a new extension list from an array of strings.
*
* The strings are copied into the list.
*
* @param arr an array of zero or more non-null, null-terminated strings.
* @param size the number of elements in the array.
*
* @public @memberof u_extension_list
*/
struct u_extension_list *
u_extension_list_create_from_array(const char *const *arr, uint32_t size);
/*!
* @brief Retrieve the number of elements in the list
*
* @public @memberof u_extension_list
*/
uint32_t
u_extension_list_get_size(const struct u_extension_list *uel);
/*!
* @brief Retrieve the data pointer of the list
*
* @public @memberof u_extension_list
*/
const char *const *
u_extension_list_get_data(const struct u_extension_list *uel);
/*!
* @brief Check if the string is in the list.
*
* (Comparing string contents, not pointers)
*
* @param usl self pointer
* @param str a non-null, null-terminated string.
*
* @return true if the string is in the list.
*
* @public @memberof u_extension_list
*/
bool
u_extension_list_contains(const struct u_extension_list *uel, const char *str);
/*!
* @brief Check if the string is in the list.
*
* (Comparing string contents, not pointers)
*
* @param usl self pointer
* @param str a string pointer.
* @param len the length of the string.
*
* @return true if the string is in the list.
*
* @public @memberof u_extension_list
*/
bool
u_extension_list_contains_len(const struct u_extension_list *uel, const char *str, size_t len);
/*!
* @brief Destroy an extension list.
*
* Performs null checks and sets your pointer to zero.
*
* @public @memberof u_extension_list
*/
void
u_extension_list_destroy(struct u_extension_list **list_ptr);
/*
*
* Extension List Builder API
*
*/
/*!
* @brief Create an extension list builder.
*
* @public @memberof u_extension_list_builder
*/
struct u_extension_list_builder *
u_extension_list_builder_create(void);
/*!
* @brief Create an extension list builder with room for at least the given number of strings.
*
* @public @memberof u_extension_list_builder
*/
struct u_extension_list_builder *
u_extension_list_builder_create_with_capacity(uint32_t capacity);
/*!
* @brief Create an extension list builder from an array of strings.
*
* The strings are copied into the builder.
*
* @param arr an array of zero or more non-null, null-terminated strings.
* @param size the number of elements in the array.
*
* @public @memberof u_extension_list_builder
*/
struct u_extension_list_builder *
u_extension_list_builder_create_from_array(const char *const *arr, uint32_t size);
/*!
* @brief Append a new string to the builder.
*
* The string is copied into the builder.
*
* @param uslb self pointer
* @param str a non-null, null-terminated string.
* @return 1 if successfully added, negative for errors.
*
* @public @memberof u_extension_list_builder
*/
int
u_extension_list_builder_append(struct u_extension_list_builder *uelb, const char *str);
/*!
* @brief Append a new string to the builder.
*
* The string is copied into the builder.
*
* @param uslb self pointer
* @param str a string pointer.
* @param len the length of the string.
* @return 1 if successfully added, negative for errors.
*
* @public @memberof u_extension_list_builder
*/
int
u_extension_list_builder_append_len(struct u_extension_list_builder *uelb, const char *str, size_t len);
/*!
* @brief Append an array of new strings to the builder.
*
* The strings are copied into the builder.
*
* @param uslb self pointer
* @param arr an array of zero or more non-null, null-terminated strings.
* @param size the number of elements in the array.
* @return 1 if successfully added, negative for errors.
*
* @public @memberof u_extension_list_builder
*/
int
u_extension_list_builder_append_array(struct u_extension_list_builder *uelb, const char *const *arr, uint32_t size);
/*!
* @brief Append a new string to the builder, if it's not the same as a string already in the builder.
*
* (Comparing string contents, not pointers)
*
* The string is copied into the builder.
*
* @param uslb self pointer
* @param str a non-null, null-terminated string.
* @return 1 if successfully added, 0 if already existing so not added, negative for errors.
*
* @public @memberof u_extension_list_builder
*/
int
u_extension_list_builder_append_unique(struct u_extension_list_builder *uelb, const char *str);
/*!
* @brief Append a new string to the builder, if it's not the same as a string already in the builder.
*
* (Comparing string contents, not pointers)
*
* The string is copied into the builder.
*
* @param uslb self pointer
* @param str a string pointer.
* @param len the length of the string.
* @return 1 if successfully added, 0 if already existing so not added, negative for errors.
*
* @public @memberof u_extension_list_builder
*/
int
u_extension_list_builder_append_unique_len(struct u_extension_list_builder *uelb, const char *str, size_t len);
/*!
* @brief Build an immutable extension list from the builder.
*
* After calling this, the builder is destroyed and the pointer is set to NULL.
*
* @param builder_ptr pointer to self pointer
* @return a new immutable extension list, or NULL on error.
*
* @public @memberof u_extension_list_builder
*/
XRT_NONNULL_ALL struct u_extension_list *
u_extension_list_builder_build(struct u_extension_list_builder **builder_ptr);
/*!
* @brief Build an immutable extension list from the builder and sort it for
* extension lists.
*
* The list will be sorted first by API (VK, XR, etc.), then all KHR extensions,
* then all EXT extensions, then all Vendor extensions, then all experimental
* extensions. (Alphabetical within each group.)
*
* After calling this, the builder is destroyed and the pointer is set to NULL.
*
* @param builder_ptr pointer to self pointer
* @return a new immutable extension list, sorted for extension lists, or NULL on error.
*
* @public @memberof u_extension_list_builder
*/
XRT_NONNULL_ALL struct u_extension_list *
u_extension_list_builder_build_sorted_for_extensions(struct u_extension_list_builder **builder_ptr);
/*!
* @brief Destroy an extension list builder.
*
* Performs null checks and sets your pointer to zero.
*
* @public @memberof u_extension_list_builder
*/
XRT_NONNULL_ALL void
u_extension_list_builder_destroy(struct u_extension_list_builder **builder_ptr);
#ifdef __cplusplus
} // extern "C"
#endif
+249
View File
@@ -0,0 +1,249 @@
// Copyright 2021, Collabora, Ltd.
// Copyright 2025-2026, NVIDIA CORPORATION.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief A collection of strings, like a list of extensions to enable
*
* @author Rylie Pavlik <rylie.pavlik@collabora.com>
* @ingroup aux_util
*
*/
#pragma once
#include "u_extension_list.h"
#include <memory>
#include <vector>
#include <limits>
#include <stdexcept>
#include <string>
#include <string_view>
#include <algorithm>
#include <unordered_set>
namespace xrt::auxiliary::util {
// Forward declaration
class ExtensionListBuilder;
/*!
* @brief An immutable collection of strings, like a list of extensions to enable.
*
* This class stores copies of strings internally and provides read-only access.
*
* Size is limited to one less than the max value of uint32_t which shouldn't be a problem,
* the size really should be much smaller.
*/
class ExtensionList
{
public:
//! Default constructor - creates an empty list
ExtensionList() = default;
//! Move constructor
ExtensionList(ExtensionList &&) = default;
//! Copy constructor, makes sure to do a deep copy.
ExtensionList(ExtensionList const &other) : ExtensionList({other.strings.begin(), other.strings.end()}) {}
//! Move assignment
ExtensionList &
operator=(ExtensionList &&) = default;
//! Copy assignment
ExtensionList &
operator=(ExtensionList const &other)
{
/*
* This uses the move assignment to set this to a deep copy of
* the other list. We need to do a deep copy of the other list
* so that the set and pointers are correctly recalculated using
* the new strings.
*/
return *this = ExtensionList(other);
}
/*!
* @brief Get the size of the array (the number of strings)
*/
uint32_t
size() const noexcept
{
return static_cast<uint32_t>(ptrs.size());
}
/*!
* @brief Get the data pointer of the array (array of const char*)
*/
const char *const *
data() const noexcept
{
return ptrs.data();
}
/*!
* @brief Check if the string is in the list.
*
* (Comparing string contents)
*
* @param str a string view to search for.
*
* @return true if the string is in the list.
*/
bool
contains(std::string_view str) const
{
return set.find(str) != set.end();
}
private:
friend class ExtensionListBuilder;
//! Main storage of strings.
std::vector<std::string> strings;
/*!
* Internal set of strings for fast lookup, memory kept alive by the
* strings vector. Used to quickly check if a string is in the list.
*/
std::unordered_set<std::string_view> set;
/*!
* Internal vector of pointers to the strings, memory kept alive by the
* strings vector.
*/
std::vector<const char *> ptrs;
private:
// Internal constructor used by ExtensionListBuilder
ExtensionList(std::vector<std::string> &&strings_) : strings(std::move(strings_))
{
ptrs.reserve(strings.size());
for (const auto &s : strings) {
set.insert(s);
ptrs.push_back(s.c_str());
}
}
};
/*!
* @brief A builder for constructing ExtensionList objects.
*
* This class allows write-only operations to build up an extension list,
* which can then be converted to an immutable ExtensionList.
*/
class ExtensionListBuilder
{
public:
//! Default constructor
ExtensionListBuilder() = default;
//! Construct with capacity hint
explicit ExtensionListBuilder(uint32_t capacity)
{
strings.reserve(capacity);
}
//! Construct from an array of strings
template <uint32_t N> explicit ExtensionListBuilder(const char *(&arr)[N])
{
strings.reserve(N);
for (auto &&elt : arr) {
append(elt);
}
}
ExtensionListBuilder(ExtensionListBuilder &&) = delete;
ExtensionListBuilder(ExtensionListBuilder const &) = delete;
ExtensionListBuilder &
operator=(ExtensionListBuilder &&) = delete;
ExtensionListBuilder &
operator=(ExtensionListBuilder const &) = delete;
/*!
* @brief Append a new string to the builder.
*
* @param str a string view to append.
*
* @throws std::out_of_range if you have a ridiculous number of strings in your list already.
*/
void
append(std::string_view str)
{
if (strings.size() > (std::numeric_limits<uint32_t>::max)() - 1) {
throw std::out_of_range("Size limit reached");
}
strings.emplace_back(str);
}
/*!
* @brief Append a new string to the builder if it doesn't match any existing string.
*
* (Comparing string contents)
*
* @param str a string view to append.
*
* @return true if we added it
*
* @throws std::out_of_range if you have a ridiculous number of strings in your list already.
*/
bool
appendUnique(std::string_view str)
{
if (strings.size() > (std::numeric_limits<uint32_t>::max)() - 1) {
throw std::out_of_range("Size limit reached");
}
auto it =
std::find_if(strings.begin(), strings.end(), [str](const std::string &elt) { return str == elt; });
if (it != strings.end()) {
// already have it
return false;
}
strings.emplace_back(str);
return true;
}
/*!
* @brief Sort the strings in the builder suitable for extension lists.
*
* The list will be sorted first by API (VK, XR, etc.), then all KHR extensions,
* then all EXT extensions, then all Vendor extensions, then all experimental
* extensions. (Alphabetical within each group.)
*
* This modifies the builder in-place.
*/
void
sortForExtensions();
/*!
* @brief Build and return an immutable ExtensionList.
*
* This function consumes the builder by moving its internal data into
* the returned ExtensionList. After calling this, the builder is left in a
* valid but empty state.
*
* The && qualifier (rvalue reference qualifier) means this can only be
* called on rvalue references, i.e. on:
* - Temporaries: `ExtensionListBuilder().build()`
* - Moved objects: `std::move(builder).build()`
*
* This prevents accidentally calling build() twice on the same builder,
* which would be a bug.
*/
ExtensionList
build() &&
{
return ExtensionList(std::move(strings));
}
private:
std::vector<std::string> strings;
};
} // namespace xrt::auxiliary::util
+18 -18
View File
@@ -11,7 +11,7 @@
#include "xrt/xrt_macro_lists.h"
#include "util/u_misc.h"
#include "util/u_string_list.h"
#include "util/u_extension_list.h"
#include "util/u_pretty_print.h"
#include <assert.h>
@@ -87,14 +87,14 @@ stack_only_sink(void *ptr, const char *str, size_t length)
}
int
update_longest_extension_name_length(struct u_string_list *list, int current_longest_extension)
update_longest_extension_name_length(struct u_extension_list *list, int current_longest_extension)
{
if (list == NULL) {
return current_longest_extension;
}
size_t count = u_string_list_get_size(list);
const char *const *data = u_string_list_get_data(list);
size_t count = u_extension_list_get_size(list);
const char *const *data = u_extension_list_get_data(list);
for (size_t i = 0; i < count; i++) {
int len = (int)strlen(data[i]);
@@ -498,15 +498,15 @@ u_pp_array2d_f64(u_pp_delegate_t dg, const double *arr, size_t n, size_t m, cons
/*
*
* String list printers.
* Extension list printers.
*
*/
void
u_pp_string_list(struct u_pp_delegate dg, struct u_string_list *usl, const char *prefix)
u_pp_string_list(struct u_pp_delegate dg, struct u_extension_list *usl, const char *prefix)
{
uint32_t count = u_string_list_get_size(usl);
const char *const *data = u_string_list_get_data(usl);
uint32_t count = u_extension_list_get_size(usl);
const char *const *data = u_extension_list_get_data(usl);
for (uint32_t i = 0; i < count; i++) {
u_pp(dg, "%s%s", prefix, data[i]);
@@ -515,15 +515,15 @@ u_pp_string_list(struct u_pp_delegate dg, struct u_string_list *usl, const char
void
u_pp_string_list_extensions(struct u_pp_delegate dg,
struct u_string_list *enabled_list,
struct u_string_list *optional_list,
struct u_string_list *skipped_list)
struct u_extension_list *enabled_list,
struct u_extension_list *optional_list,
struct u_extension_list *skipped_list)
{
assert(optional_list != NULL);
assert(skipped_list != NULL);
uint32_t count = u_string_list_get_size(enabled_list);
const char *const *data = u_string_list_get_data(enabled_list);
uint32_t count = u_extension_list_get_size(enabled_list);
const char *const *data = u_extension_list_get_data(enabled_list);
// Find the longest extension name for alignment
int longest_extension = update_longest_extension_name_length(enabled_list, 0);
@@ -536,7 +536,7 @@ u_pp_string_list_extensions(struct u_pp_delegate dg,
uint32_t optional_enabled_count = 0;
for (uint32_t i = 0; i < count; i++) {
const char *ext = data[i];
bool is_optional = u_string_list_contains(optional_list, ext);
bool is_optional = u_extension_list_contains(optional_list, ext);
if (is_optional) {
optional_enabled_count++;
}
@@ -545,22 +545,22 @@ u_pp_string_list_extensions(struct u_pp_delegate dg,
}
// All optional extensions have been enabled.
uint32_t optional_count = u_string_list_get_size(optional_list);
uint32_t optional_count = u_extension_list_get_size(optional_list);
if (optional_enabled_count == optional_count) {
return;
}
// Print optional extensions that were not enabled
u_pp(dg, "\n\tNot enabled optional extensions:");
const char *const *optional_data = u_string_list_get_data(optional_list);
const char *const *optional_data = u_extension_list_get_data(optional_list);
for (uint32_t i = 0; i < optional_count; i++) {
const char *ext = optional_data[i];
if (u_string_list_contains(enabled_list, ext)) {
if (u_extension_list_contains(enabled_list, ext)) {
continue;
}
// Check if this extension was skipped or unsupported
bool was_skipped = u_string_list_contains(skipped_list, ext);
bool was_skipped = u_extension_list_contains(skipped_list, ext);
const char *reason = was_skipped ? "skipped" : "unsupported";
u_pp(dg, "\n\t\t%-*s %s", longest_extension, ext, reason);
+7 -7
View File
@@ -238,11 +238,11 @@ u_pp_array2d_f64(u_pp_delegate_t dg, const double *arr, size_t n, size_t m, cons
/*
*
* String list printers.
* Extension list printers.
*
*/
struct u_string_list;
struct u_extension_list;
/*!
* @brief Print all the strings in the list with the given prefix.
@@ -253,10 +253,10 @@ struct u_string_list;
* @ingroup aux_pretty
*/
XRT_NONNULL_ALL void
u_pp_string_list(struct u_pp_delegate dg, struct u_string_list *usl, const char *prefix);
u_pp_string_list(struct u_pp_delegate dg, struct u_extension_list *usl, const char *prefix);
/*!
* @brief Pretty print the string list with extension information.
* @brief Pretty print the extension list with extension information.
*
* It will start on a new line with the enabled extensions, showing which are
* required vs optional. Then if there are optional extensions not enabled it
@@ -270,9 +270,9 @@ u_pp_string_list(struct u_pp_delegate dg, struct u_string_list *usl, const char
*/
XRT_NONNULL_ALL void
u_pp_string_list_extensions(struct u_pp_delegate dg,
struct u_string_list *enabled_list,
struct u_string_list *optional_list,
struct u_string_list *skipped_list);
struct u_extension_list *enabled_list,
struct u_extension_list *optional_list,
struct u_extension_list *skipped_list);
/*
-311
View File
@@ -1,311 +0,0 @@
// Copyright 2021, Collabora, Ltd.
// Copyright 2025-2026, NVIDIA CORPORATION.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief A collection of strings, like a list of extensions to enable
*
* @author Rylie Pavlik <rylie.pavlik@collabora.com>
* @ingroup aux_util
*
*/
#include "u_string_list.h"
#include "u_string_list.hpp"
#include <algorithm>
#include <cstring>
#include <string>
/*
*
* Defines and structs.
*
*/
using xrt::auxiliary::util::StringList;
struct u_string_list
{
u_string_list() = default;
u_string_list(StringList &&sl) : list(std::move(sl)) {}
StringList list;
};
/*
*
* Helpers
*
*/
enum class ExtensionType
{
KHR = 0, // Khronos extensions
EXT = 1, // Multi-vendor extensions
VENDOR = 2, // Vendor-specific extensions (AMD, NV, INTEL, etc.)
EXPERIMENTAL = 3 // Experimental extensions
};
/*!
* @brief Helper class for sorting extension names.
*
* Encapsulates the sort key with comparison operators for cleaner sorting.
*/
struct ExtensionSortKey
{
std::string api_prefix;
ExtensionType type;
std::string name;
/*!
* Sorts in field declaration order:
*
* 1. API prefix (VK, XR, etc.)
* 2. Extension type (KHR < EXT < VENDOR < EXPERIMENTAL)
* 3. Alphabetically by full name
*/
auto
operator<=>(const ExtensionSortKey &other) const = default;
};
/*!
* @brief Check if a vendor string represents an experimental extension.
*
* Experimental extensions have vendor codes ending with 'X' optionally followed
* by digits.
*
* Examples: NVX, AMDX, NVX1, NVX2, INTELX
*
* Special case: QNX is a legitimate vendor (QNX operating system), not
* experimental.
*/
static bool
is_experimental_vendor(const std::string &vendor)
{
// Special case: QNX is a legitimate vendor, not experimental
if (vendor == "QNX") {
return false;
}
// Check if vendor ends with 'X' optionally followed by digits
if (vendor.empty()) {
return false;
}
size_t len = vendor.length();
size_t i = len - 1;
// Skip trailing digits
while (i > 0 && std::isdigit(vendor[i])) {
i--;
}
// Check if we found an 'X' and there's something before it
return (vendor[i] == 'X' && i > 0);
}
/*!
* @brief Get the extension type and API prefix for sorting purposes.
*
* Returns an ExtensionSortKey for comparison.
*/
static ExtensionSortKey
get_extension_sort_key(const char *ext)
{
std::string name(ext);
// Find the first underscore to separate API prefix (e.g., "VK", "XR")
size_t first_underscore = name.find('_');
if (first_underscore == std::string::npos) {
// No underscore, treat as is
return {name, ExtensionType::VENDOR, name};
}
std::string api_prefix = name.substr(0, first_underscore);
// Find the second underscore to get the vendor/type part
size_t second_underscore = name.find('_', first_underscore + 1);
if (second_underscore == std::string::npos) {
// Only one underscore, treat as vendor
return {api_prefix, ExtensionType::VENDOR, name};
}
std::string vendor = name.substr(first_underscore + 1, second_underscore - first_underscore - 1);
// Determine extension type based on vendor string
ExtensionType type;
if (vendor == "KHR") {
type = ExtensionType::KHR;
} else if (vendor == "EXT") {
type = ExtensionType::EXT;
} else if (is_experimental_vendor(vendor)) {
type = ExtensionType::EXPERIMENTAL;
} else {
type = ExtensionType::VENDOR;
}
return {api_prefix, type, name};
}
/*
*
* 'Exported' functions.
*
*/
struct u_string_list *
u_string_list_create()
{
try {
auto ret = std::make_unique<u_string_list>();
return ret.release();
} catch (std::exception const &) {
return nullptr;
}
}
struct u_string_list *
u_string_list_create_with_capacity(uint32_t capacity)
{
try {
auto ret = std::make_unique<u_string_list>(xrt::auxiliary::util::StringList{capacity});
return ret.release();
} catch (std::exception const &) {
return nullptr;
}
}
struct u_string_list *
u_string_list_create_from_list(struct u_string_list *usl)
{
try {
auto ret = std::make_unique<u_string_list>(xrt::auxiliary::util::StringList{usl->list});
return ret.release();
} catch (std::exception const &) {
return nullptr;
}
}
struct u_string_list *
u_string_list_create_from_array(const char *const *arr, uint32_t size)
{
if (arr == nullptr || size == 0) {
return u_string_list_create();
}
try {
auto ret = std::make_unique<u_string_list>(xrt::auxiliary::util::StringList{size});
for (uint32_t i = 0; i < size; ++i) {
ret->list.push_back(arr[i]);
}
return ret.release();
} catch (std::exception const &) {
return nullptr;
}
}
uint32_t
u_string_list_get_size(const struct u_string_list *usl)
{
if (usl == nullptr) {
return 0;
}
return usl->list.size();
}
const char *const *
u_string_list_get_data(const struct u_string_list *usl)
{
if (usl == nullptr) {
return nullptr;
}
return usl->list.data();
}
int
u_string_list_append(struct u_string_list *usl, const char *str)
{
if (usl == nullptr) {
return -1;
}
try {
usl->list.push_back(str);
return 1;
} catch (std::exception const &) {
return -1;
}
}
int
u_string_list_append_array(struct u_string_list *usl, const char *const *arr, uint32_t size)
{
if (usl == nullptr) {
return -1;
}
try {
for (uint32_t i = 0; i < size; ++i) {
usl->list.push_back(arr[i]);
}
return 1;
} catch (std::exception const &) {
return -1;
}
}
int
u_string_list_append_unique(struct u_string_list *usl, const char *str)
{
if (usl == nullptr) {
return -1;
}
try {
auto added = usl->list.push_back_unique(str);
return added ? 1 : 0;
} catch (std::exception const &) {
return -1;
}
}
bool
u_string_list_contains(struct u_string_list *usl, const char *str)
{
return usl->list.contains(str);
}
void
u_string_list_sort_extensions(struct u_string_list *usl)
{
if (usl == nullptr || usl->list.size() == 0) {
return;
}
// Get the data pointer and size from the StringList
// We need to const_cast because std::sort needs non-const iterators
auto data_ptr = const_cast<const char **>(usl->list.data());
auto count = usl->list.size();
auto cmp = [](const char *a, const char *b) { return get_extension_sort_key(a) < get_extension_sort_key(b); };
// Sort using our custom comparison function
std::sort(data_ptr, data_ptr + count, cmp);
}
void
u_string_list_destroy(struct u_string_list **list_ptr)
{
if (list_ptr == nullptr) {
return;
}
u_string_list *list = *list_ptr;
if (list == nullptr) {
return;
}
delete list;
*list_ptr = nullptr;
}
-161
View File
@@ -1,161 +0,0 @@
// Copyright 2021, Collabora, Ltd.
// Copyright 2025-2026, NVIDIA CORPORATION.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief A collection of strings, like a list of extensions to enable
*
* @author Rylie Pavlik <rylie.pavlik@collabora.com>
* @ingroup aux_util
*
*/
#pragma once
#include "xrt/xrt_compiler.h"
#ifdef __cplusplus
extern "C" {
#endif
/*!
* @brief A collection of string literals (const char *), such as used for extension name lists.
*
* @see xrt::auxiliary::util::StringList
*/
struct u_string_list;
/*!
* @brief Create a string list with room for at least the given number of strings.
*
* @public @memberof u_string_list
*/
struct u_string_list *
u_string_list_create(void);
/*!
* @brief Create a string list with room for at least the given number of strings.
*
* @public @memberof u_string_list
*/
struct u_string_list *
u_string_list_create_with_capacity(uint32_t capacity);
/*!
* @brief Create a new string list from an existing string list.
*
* @public @memberof u_string_list
*/
struct u_string_list *
u_string_list_create_from_list(struct u_string_list *usl);
/*!
* @brief Create a new string list from an array of suitable strings.
*
* @param arr an array of zero or more non-null, null-terminated string that must live at least as long as the list,
* preferably string literals.
* @param size the number of elements in the array.
*
* @public @memberof u_string_list
*/
struct u_string_list *
u_string_list_create_from_array(const char *const *arr, uint32_t size);
/*!
* @brief Retrieve the number of elements in the list
*
* @public @memberof u_string_list
*/
uint32_t
u_string_list_get_size(const struct u_string_list *usl);
/*!
* @brief Retrieve the data pointer of the list
*
* @public @memberof u_string_list
*/
const char *const *
u_string_list_get_data(const struct u_string_list *usl);
/*!
* @brief Append a new string literal to the list.
*
* @param usl self pointer
* @param str a non-null, null-terminated string that must live at least as long as the list, preferably a string
* literal.
* @return 1 if successfully added, negative for errors.
*
* @public @memberof u_string_list
*/
int
u_string_list_append(struct u_string_list *usl, const char *str);
/*!
* @brief Append an array of new string literals to the list.
*
* @param usl self pointer
* @param arr an array of zero or more non-null, null-terminated string that must live at least as long as the list,
* preferably string literals.
* @param size the number of elements in the array.
* @return 1 if successfully added, negative for errors.
*
* @public @memberof u_string_list
*/
int
u_string_list_append_array(struct u_string_list *usl, const char *const *arr, uint32_t size);
/*!
* @brief Append a new string literal to the list, if it's not the same as a string already in the list.
*
* (Comparing string contents, not pointers)
*
* @param usl self pointer
* @param str a non-null, null-terminated string that must live at least as long as the list, preferably a string
* literal.
* @return 1 if successfully added, 0 if already existing so not added, negative for errors.
*
* @public @memberof u_string_list
*/
int
u_string_list_append_unique(struct u_string_list *usl, const char *str);
/*!
* @brief Check if the string is in the list.
*
* (Comparing string contents, not pointers)
*
* @param usl self pointer
* @param str a non-null, null-terminated string.
*
* @return true if the string is in the list.
*/
bool
u_string_list_contains(struct u_string_list *usl, const char *str);
/*!
* @brief Sort the list of strings suitable for extension lists.
*
* The list will be sorted first by API (VK, XR, etc.), then all KHR extensions,
* then all EXT extensions, then all Vendor extensions, then all experimental
* extensions. (Alphabetical within each group.)
*
* @param usl self pointer
*/
void
u_string_list_sort_extensions(struct u_string_list *usl);
/*!
* @brief Destroy a string list.
*
* Performs null checks and sets your pointer to zero.
*
* @public @memberof u_string_list
*/
void
u_string_list_destroy(struct u_string_list **list_ptr);
#ifdef __cplusplus
} // extern "C"
#endif
-169
View File
@@ -1,169 +0,0 @@
// Copyright 2021, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief A collection of strings, like a list of extensions to enable
*
* @author Rylie Pavlik <rylie.pavlik@collabora.com>
* @ingroup aux_util
*
*/
#pragma once
#include "u_string_list.h"
#include <memory>
#include <vector>
#include <limits>
#include <stdexcept>
#include <string>
#include <algorithm>
namespace xrt::auxiliary::util {
/*!
* @brief A collection of strings (const char *), like a list of extensions to enable.
*
* This version is only for use with strings that will outlive this object, preferably string literals.
*
* Size is limited to one less than the max value of uint32_t which shouldn't be a problem,
* the size really should be much smaller (especially if you use push_back_unique()).
*/
class StringList
{
public:
/// Construct a string list.
StringList() = default;
/// Construct a string list with the given capacity.
StringList(uint32_t capacity) : vec(capacity, nullptr)
{
// best way I know to create with capacity
vec.clear();
}
StringList(StringList &&) = default;
StringList(StringList const &) = default;
StringList &
operator=(StringList &&) = default;
StringList &
operator=(StringList const &) = default;
/// Construct a string list with the given items
template <uint32_t N> StringList(const char *(&arr)[N]) : StringList(N)
{
for (auto &&elt : arr) {
push_back(elt);
}
}
/*!
* @brief Get the size of the array (the number of strings)
*/
uint32_t
size() const noexcept
{
return static_cast<uint32_t>(vec.size());
}
/*!
* @brief Get the data pointer of the array
*/
const char *const *
data() const noexcept
{
return vec.data();
}
/*!
* @brief Append a new string to the list.
*
* @param str a non-null, null-terminated string that must live at least as long as the list,
* preferably a string literal.
*
* @throws std::out_of_range if you have a ridiculous number of strings in your list already,
* std::invalid_argument if you pass a null pointer.
*/
void
push_back(const char *str)
{
if (vec.size() > (std::numeric_limits<uint32_t>::max)() - 1) {
throw std::out_of_range("Size limit reached");
}
if (str == nullptr) {
throw std::invalid_argument("Cannot pass a null pointer");
}
vec.push_back(str);
}
/// Add all given items
/// @throws the same as what push_back() throws
template <uint32_t N>
void
push_back_all(const char *(&arr)[N])
{
for (auto &&elt : arr) {
push_back(elt);
}
}
/*!
* @brief Check if the string is in the list.
*
* (Comparing string contents, not pointers)
*
* @param str a non-null, null-terminated string.
*
* @return true if the string is in the list.
*/
bool
contains(const char *str)
{
if (str == nullptr) {
throw std::invalid_argument("Cannot pass a null pointer");
}
std::string needle{str};
auto it = std::find_if(vec.begin(), vec.end(), [needle](const char *elt) { return needle == elt; });
return it != vec.end();
}
/*!
* @brief Append a new string to the list if it doesn't match any existing string.
*
* (Comparing string contents, not pointers)
*
* This does a simple linear search, because it is assumed that the size of this list is fairly small.
*
* @param str a non-null, null-terminated string that must live at least as long as the list,
* preferably a string literal.
*
* @return true if we added it
*
* @throws std::out_of_range if you have a ridiculous number of strings in your list already,
* std::invalid_argument if you pass a null pointer.
*/
bool
push_back_unique(const char *str)
{
if (vec.size() > (std::numeric_limits<uint32_t>::max)() - 1) {
throw std::out_of_range("Size limit reached");
}
if (str == nullptr) {
throw std::invalid_argument("Cannot pass a null pointer");
}
std::string needle{str};
auto it = std::find_if(vec.begin(), vec.end(), [needle](const char *elt) { return needle == elt; });
if (it != vec.end()) {
// already have it
return false;
}
vec.push_back(str);
return true;
}
private:
std::vector<const char *> vec;
};
} // namespace xrt::auxiliary::util
+22 -22
View File
@@ -31,14 +31,14 @@
static bool
should_skip_optional_instance_ext(struct vk_bundle *vk,
struct u_string_list *required_instance_ext_list,
struct u_string_list *optional_instance_ext_list,
struct u_extension_list *required_instance_ext_list,
struct u_extension_list *optional_instance_ext_list,
const char *ext)
{
#ifdef VK_EXT_display_surface_counter
if (strcmp(ext, VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME) == 0) {
// it does not make sense to enable surface counter on anything that does not use a VkDisplayKHR
if (!u_string_list_contains(required_instance_ext_list, VK_KHR_DISPLAY_EXTENSION_NAME)) {
if (!u_extension_list_contains(required_instance_ext_list, VK_KHR_DISPLAY_EXTENSION_NAME)) {
VK_DEBUG(vk, "Skipping optional instance extension %s because %s is not enabled", ext,
VK_KHR_DISPLAY_EXTENSION_NAME);
return true;
@@ -52,8 +52,8 @@ should_skip_optional_instance_ext(struct vk_bundle *vk,
static bool
should_skip_optional_device_ext(struct vk_bundle *vk,
struct u_string_list *required_device_ext_list,
struct u_string_list *optional_device_ext_list,
struct u_extension_list *required_device_ext_list,
struct u_extension_list *optional_device_ext_list,
const char *ext)
{
#ifdef VK_EXT_display_control
@@ -80,9 +80,9 @@ should_skip_optional_device_ext(struct vk_bundle *vk,
VkResult
vk_build_instance_extensions(struct vk_bundle *vk,
struct u_string_list *required_instance_ext_list,
struct u_string_list *optional_instance_ext_list,
struct u_string_list **out_instance_ext_list)
struct u_extension_list *required_instance_ext_list,
struct u_extension_list *optional_instance_ext_list,
struct u_extension_list **out_instance_ext_list)
{
return vk_build_instance_extensions_with_skip( //
vk, //
@@ -93,7 +93,7 @@ vk_build_instance_extensions(struct vk_bundle *vk,
}
VkResult
vk_check_required_instance_extensions(struct vk_bundle *vk, struct u_string_list *required_instance_ext_list)
vk_check_required_instance_extensions(struct vk_bundle *vk, struct u_extension_list *required_instance_ext_list)
{
VkExtensionProperties *props = NULL;
uint32_t prop_count = 0;
@@ -109,8 +109,8 @@ vk_check_required_instance_extensions(struct vk_bundle *vk, struct u_string_list
return ret; // Already logged.
}
// Convert to string list for easier checking.
struct u_string_list *available_ext_list = vk_convert_extension_properties_to_string_list(props, prop_count);
// Convert to extension list for easier checking.
struct u_extension_list *available_ext_list = vk_convert_extension_properties_to_string_list(props, prop_count);
// Clean up props.
free(props);
@@ -119,13 +119,13 @@ vk_check_required_instance_extensions(struct vk_bundle *vk, struct u_string_list
ret = vk_check_required_extensions(vk, available_ext_list, required_instance_ext_list, "instance");
// Clean up.
u_string_list_destroy(&available_ext_list);
u_extension_list_destroy(&available_ext_list);
return ret;
}
void
vk_fill_in_has_instance_extensions(struct vk_bundle *vk, struct u_string_list *ext_list)
vk_fill_in_has_instance_extensions(struct vk_bundle *vk, struct u_extension_list *ext_list)
{
// Include the generated extension detection code.
#include "vk_bundle_init_instance_ext.c.inc"
@@ -651,7 +651,7 @@ err_free:
}
static void
fill_in_has_device_extensions(struct vk_bundle *vk, struct u_string_list *ext_list)
fill_in_has_device_extensions(struct vk_bundle *vk, struct u_extension_list *ext_list)
{
#include "vk_bundle_init_device_ext.c.inc"
}
@@ -931,11 +931,11 @@ vk_create_device(struct vk_bundle *vk,
int forced_index,
bool only_compute,
VkQueueGlobalPriorityEXT global_priority,
struct u_string_list *required_device_ext_list,
struct u_string_list *optional_device_ext_list,
struct u_extension_list *required_device_ext_list,
struct u_extension_list *optional_device_ext_list,
const struct vk_device_features *optional_device_features)
{
struct u_string_list *device_ext_list = NULL;
struct u_extension_list *device_ext_list = NULL;
VkResult ret;
ret = select_physical_device(vk, forced_index);
@@ -1021,7 +1021,7 @@ vk_create_device(struct vk_bundle *vk,
#ifdef VK_KHR_video_encode_queue
// Video encode queue
struct vk_queue_pair encode_queue = VK_NULL_QUEUE_PAIR;
if (u_string_list_contains(device_ext_list, VK_KHR_VIDEO_ENCODE_QUEUE_EXTENSION_NAME)) {
if (u_extension_list_contains(device_ext_list, VK_KHR_VIDEO_ENCODE_QUEUE_EXTENSION_NAME)) {
struct vk_queue_family encode_queue_family = {0};
ret = find_queue_family(vk, VK_QUEUE_VIDEO_ENCODE_BIT_KHR, &encode_queue_family);
if (ret == VK_SUCCESS) {
@@ -1131,8 +1131,8 @@ vk_create_device(struct vk_bundle *vk,
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
.queueCreateInfoCount = queue_create_info_count,
.pQueueCreateInfos = queue_create_info,
.enabledExtensionCount = u_string_list_get_size(device_ext_list),
.ppEnabledExtensionNames = u_string_list_get_data(device_ext_list),
.enabledExtensionCount = u_extension_list_get_size(device_ext_list),
.ppEnabledExtensionNames = u_extension_list_get_data(device_ext_list),
.pEnabledFeatures = &enabled_features,
};
@@ -1191,7 +1191,7 @@ vk_create_device(struct vk_bundle *vk,
ret = vk->vkCreateDevice(vk->physical_device, &device_create_info, NULL, &vk->device);
// Destroy the list now.
u_string_list_destroy(&device_ext_list);
u_extension_list_destroy(&device_ext_list);
if (ret == VK_ERROR_NOT_PERMITTED_EXT) {
// Don't spam the not permitted returns as we try all of the different priorities.
@@ -1230,7 +1230,7 @@ err_destroy:
}
// Safe to call even if null.
u_string_list_destroy(&device_ext_list);
u_extension_list_destroy(&device_ext_list);
return ret;
}
+65 -61
View File
@@ -19,13 +19,13 @@
*
*/
static struct u_string_list *
static struct u_extension_list *
build_extension_list(struct vk_bundle *vk,
struct u_string_list *available_ext_list,
struct u_string_list *required_ext_list,
struct u_string_list *optional_ext_list,
struct u_extension_list *available_ext_list,
struct u_extension_list *required_ext_list,
struct u_extension_list *optional_ext_list,
vk_should_skip_ext_func_t skip_func,
struct u_string_list **out_skipped_ext_list)
struct u_extension_list **out_skipped_ext_list)
{
assert(available_ext_list != NULL);
assert(required_ext_list != NULL);
@@ -34,14 +34,18 @@ build_extension_list(struct vk_bundle *vk,
assert(out_skipped_ext_list != NULL);
// Start with required extensions (assumed to be supported).
struct u_string_list *list = u_string_list_create_from_list(required_ext_list);
uint32_t required_ext_count = u_extension_list_get_size(required_ext_list);
struct u_extension_list_builder *builder =
u_extension_list_builder_create_with_capacity(required_ext_count + 16);
u_extension_list_builder_append_array(builder, u_extension_list_get_data(required_ext_list),
required_ext_count);
// Create skipped list.
struct u_string_list *skipped_list = u_string_list_create();
// Create skipped list builder.
struct u_extension_list_builder *skipped_builder = u_extension_list_builder_create();
// Check any supported optional extensions.
uint32_t optional_ext_count = u_string_list_get_size(optional_ext_list);
const char *const *optional_exts = u_string_list_get_data(optional_ext_list);
uint32_t optional_ext_count = u_extension_list_get_size(optional_ext_list);
const char *const *optional_exts = u_extension_list_get_data(optional_ext_list);
for (uint32_t i = 0; i < optional_ext_count; i++) {
const char *optional_ext = optional_exts[i];
@@ -50,25 +54,26 @@ build_extension_list(struct vk_bundle *vk,
bool skip = skip_func(vk, required_ext_list, optional_ext_list, optional_ext);
if (skip) {
// Track skipped extensions.
u_string_list_append_unique(skipped_list, optional_ext);
u_extension_list_builder_append_unique(skipped_builder, optional_ext);
continue;
}
// Check if the extension is available.
if (!u_string_list_contains(available_ext_list, optional_ext)) {
if (!u_extension_list_contains(available_ext_list, optional_ext)) {
continue;
}
int added = u_string_list_append_unique(list, optional_ext);
int added = u_extension_list_builder_append_unique(builder, optional_ext);
if (added != 1) {
VK_WARN(vk, "Duplicate extension %s not added twice", optional_ext);
}
}
// Return skipped list.
*out_skipped_ext_list = skipped_list;
// Build and return skipped list (sorted for consistent output).
*out_skipped_ext_list = u_extension_list_builder_build_sorted_for_extensions(&skipped_builder);
return list;
// Build and return the extension list (sorted for consistent output).
return u_extension_list_builder_build_sorted_for_extensions(&builder);
}
@@ -78,28 +83,27 @@ build_extension_list(struct vk_bundle *vk,
*
*/
struct u_string_list *
struct u_extension_list *
vk_convert_extension_properties_to_string_list(VkExtensionProperties *props, uint32_t prop_count)
{
struct u_string_list *list = u_string_list_create();
struct u_extension_list_builder *builder = u_extension_list_builder_create_with_capacity(prop_count);
for (uint32_t i = 0; i < prop_count; i++) {
u_string_list_append_unique(list, props[i].extensionName);
u_extension_list_builder_append_unique(builder, props[i].extensionName);
}
return list;
return u_extension_list_builder_build_sorted_for_extensions(&builder);
}
void
vk_log_extension_list(struct vk_bundle *vk,
struct u_string_list *ext_list,
struct u_string_list *optional_ext_list,
struct u_string_list *skipped_ext_list,
struct u_extension_list *ext_list,
struct u_extension_list *optional_ext_list,
struct u_extension_list *skipped_ext_list,
const char *ext_type_name,
enum u_logging_level log_level)
{
struct u_pp_sink_stack_only sink;
u_pp_delegate_t dg = u_pp_sink_stack_only_init(&sink);
u_string_list_sort_extensions(ext_list);
u_pp_string_list_extensions(dg, ext_list, optional_ext_list, skipped_ext_list);
U_LOG_IFL(log_level, vk->log_level, "Vulkan %s extensions list(s):%s", ext_type_name, sink.buffer);
@@ -107,8 +111,8 @@ vk_log_extension_list(struct vk_bundle *vk,
VkResult
vk_check_required_extensions(struct vk_bundle *vk,
struct u_string_list *available_ext_list,
struct u_string_list *required_ext_list,
struct u_extension_list *available_ext_list,
struct u_extension_list *required_ext_list,
const char *ext_type_name)
{
struct u_pp_sink_stack_only sink;
@@ -118,12 +122,12 @@ vk_check_required_extensions(struct vk_bundle *vk,
u_pp_delegate_t dg = u_pp_sink_stack_only_init(&sink);
// Check if required extensions are supported.
uint32_t required_ext_count = u_string_list_get_size(required_ext_list);
const char *const *required_exts = u_string_list_get_data(required_ext_list);
uint32_t required_ext_count = u_extension_list_get_size(required_ext_list);
const char *const *required_exts = u_extension_list_get_data(required_ext_list);
for (uint32_t i = 0; i < required_ext_count; i++) {
const char *required_ext = required_exts[i];
if (u_string_list_contains(available_ext_list, required_ext)) {
if (u_extension_list_contains(available_ext_list, required_ext)) {
continue;
}
@@ -148,10 +152,10 @@ vk_check_required_extensions(struct vk_bundle *vk,
VkResult
vk_build_instance_extensions_with_skip(struct vk_bundle *vk,
struct u_string_list *required_instance_ext_list,
struct u_string_list *optional_instance_ext_list,
struct u_extension_list *required_instance_ext_list,
struct u_extension_list *optional_instance_ext_list,
vk_should_skip_ext_func_t skip_func,
struct u_string_list **out_instance_ext_list)
struct u_extension_list **out_instance_ext_list)
{
VkExtensionProperties *props = NULL;
uint32_t prop_count = 0;
@@ -165,8 +169,8 @@ vk_build_instance_extensions_with_skip(struct vk_bundle *vk,
&props); // out_props
VK_CHK_AND_RET(ret, "vk_enumerate_instance_extensions_properties");
// Convert to string list for easier checking.
struct u_string_list *available_ext_list = vk_convert_extension_properties_to_string_list(props, prop_count);
// Convert to extension list for easier checking.
struct u_extension_list *available_ext_list = vk_convert_extension_properties_to_string_list(props, prop_count);
// Clean up props.
free(props);
@@ -174,28 +178,28 @@ vk_build_instance_extensions_with_skip(struct vk_bundle *vk,
// Check if all required extensions are available.
ret = vk_check_required_extensions(vk, available_ext_list, required_instance_ext_list, "instance");
if (ret != VK_SUCCESS) {
u_string_list_destroy(&available_ext_list);
u_extension_list_destroy(&available_ext_list);
return ret;
}
// Build the extension list and track skipped extensions.
struct u_string_list *skipped_list = NULL;
struct u_string_list *list = build_extension_list( //
vk, //
available_ext_list, //
required_instance_ext_list, //
optional_instance_ext_list, //
skip_func, //
&skipped_list); //
struct u_extension_list *skipped_list = NULL;
struct u_extension_list *list = build_extension_list( //
vk, //
available_ext_list, //
required_instance_ext_list, //
optional_instance_ext_list, //
skip_func, //
&skipped_list); //
// Clean up available list.
u_string_list_destroy(&available_ext_list);
u_extension_list_destroy(&available_ext_list);
// Log the result.
vk_log_extension_list(vk, list, optional_instance_ext_list, skipped_list, "instance", U_LOGGING_INFO);
// Clean up skipped list.
u_string_list_destroy(&skipped_list);
u_extension_list_destroy(&skipped_list);
// Return the list.
*out_instance_ext_list = list;
@@ -213,10 +217,10 @@ vk_build_instance_extensions_with_skip(struct vk_bundle *vk,
VkResult
vk_build_device_extensions_with_skip(struct vk_bundle *vk,
VkPhysicalDevice physical_device,
struct u_string_list *required_device_ext_list,
struct u_string_list *optional_device_ext_list,
struct u_extension_list *required_device_ext_list,
struct u_extension_list *optional_device_ext_list,
vk_should_skip_ext_func_t skip_func,
struct u_string_list **out_device_ext_list)
struct u_extension_list **out_device_ext_list)
{
VkExtensionProperties *props = NULL;
uint32_t prop_count = 0;
@@ -230,8 +234,8 @@ vk_build_device_extensions_with_skip(struct vk_bundle *vk,
&props); // out_props
VK_CHK_AND_RET(ret, "vk_enumerate_physical_device_extension_properties");
// Convert to string list for easier checking.
struct u_string_list *available_ext_list = vk_convert_extension_properties_to_string_list(props, prop_count);
// Convert to extension list for easier checking.
struct u_extension_list *available_ext_list = vk_convert_extension_properties_to_string_list(props, prop_count);
// Clean up props.
free(props);
@@ -239,28 +243,28 @@ vk_build_device_extensions_with_skip(struct vk_bundle *vk,
// Check if all required extensions are available.
ret = vk_check_required_extensions(vk, available_ext_list, required_device_ext_list, "device");
if (ret != VK_SUCCESS) {
u_string_list_destroy(&available_ext_list);
u_extension_list_destroy(&available_ext_list);
return ret;
}
// Build the extension list and track skipped extensions.
struct u_string_list *skipped_list = NULL;
struct u_string_list *list = build_extension_list( //
vk, //
available_ext_list, //
required_device_ext_list, //
optional_device_ext_list, //
skip_func, //
&skipped_list); //
struct u_extension_list *skipped_list = NULL;
struct u_extension_list *list = build_extension_list( //
vk, //
available_ext_list, //
required_device_ext_list, //
optional_device_ext_list, //
skip_func, //
&skipped_list); //
// Clean up available list.
u_string_list_destroy(&available_ext_list);
u_extension_list_destroy(&available_ext_list);
// Log the result.
vk_log_extension_list(vk, list, optional_device_ext_list, skipped_list, "device", U_LOGGING_DEBUG);
// Clean up skipped list.
u_string_list_destroy(&skipped_list);
u_extension_list_destroy(&skipped_list);
// Return the list.
*out_device_ext_list = list;
+15 -15
View File
@@ -22,15 +22,15 @@ extern "C" {
* Callback type for checking if an optional extension should be skipped.
*/
typedef bool (*vk_should_skip_ext_func_t)(struct vk_bundle *vk,
struct u_string_list *required_ext_list,
struct u_string_list *optional_ext_list,
struct u_extension_list *required_ext_list,
struct u_extension_list *optional_ext_list,
const char *ext);
/*!
* Convert VkExtensionProperties array to u_string_list.
* Convert VkExtensionProperties array to u_extension_list.
*/
struct u_string_list *
struct u_extension_list *
vk_convert_extension_properties_to_string_list(VkExtensionProperties *props, uint32_t prop_count);
/*!
@@ -41,9 +41,9 @@ vk_convert_extension_properties_to_string_list(VkExtensionProperties *props, uin
*/
void
vk_log_extension_list(struct vk_bundle *vk,
struct u_string_list *ext_list,
struct u_string_list *optional_ext_list,
struct u_string_list *skipped_ext_list,
struct u_extension_list *ext_list,
struct u_extension_list *optional_ext_list,
struct u_extension_list *skipped_ext_list,
const char *ext_type_name,
enum u_logging_level log_level);
@@ -55,8 +55,8 @@ vk_log_extension_list(struct vk_bundle *vk,
*/
VkResult
vk_check_required_extensions(struct vk_bundle *vk,
struct u_string_list *available_ext_list,
struct u_string_list *required_ext_list,
struct u_extension_list *available_ext_list,
struct u_extension_list *required_ext_list,
const char *ext_type_name);
/*!
@@ -74,10 +74,10 @@ vk_check_required_extensions(struct vk_bundle *vk,
*/
VkResult
vk_build_instance_extensions_with_skip(struct vk_bundle *vk,
struct u_string_list *required_instance_ext_list,
struct u_string_list *optional_instance_ext_list,
struct u_extension_list *required_instance_ext_list,
struct u_extension_list *optional_instance_ext_list,
vk_should_skip_ext_func_t skip_func,
struct u_string_list **out_instance_ext_list);
struct u_extension_list **out_instance_ext_list);
/*!
* Build device extensions from required and optional device extensions with
@@ -92,10 +92,10 @@ vk_build_instance_extensions_with_skip(struct vk_bundle *vk,
VkResult
vk_build_device_extensions_with_skip(struct vk_bundle *vk,
VkPhysicalDevice physical_device,
struct u_string_list *required_device_ext_list,
struct u_string_list *optional_device_ext_list,
struct u_extension_list *required_device_ext_list,
struct u_extension_list *optional_device_ext_list,
vk_should_skip_ext_func_t skip_func,
struct u_string_list **out_device_ext_list);
struct u_extension_list **out_device_ext_list);
#ifdef __cplusplus
@@ -465,7 +465,7 @@ def generate_ext_check(exts):
condition_line = conditional.process_condition(compute_condition((ext,)))
if condition_line:
yield condition_line
yield "\tvk->{} = u_string_list_contains(ext_list, {});".format(
yield "\tvk->{} = u_extension_list_contains(ext_list, {});".format(
make_ext_member_name(ext), make_ext_name_define(ext))
# close any trailing conditions
condition_line = conditional.finish()
+8 -8
View File
@@ -23,7 +23,7 @@
#include "xrt/xrt_vulkan_includes.h"
#include "xrt/xrt_handles.h"
#include "util/u_logging.h"
#include "util/u_string_list.h"
#include "util/u_extension_list.h"
#include "os/os_threading.h"
#ifdef __cplusplus
@@ -781,7 +781,7 @@ vk_get_device_functions(struct vk_bundle *vk);
* @ingroup aux_vk
*/
VkResult
vk_check_required_instance_extensions(struct vk_bundle *vk, struct u_string_list *required_instance_ext_list);
vk_check_required_instance_extensions(struct vk_bundle *vk, struct u_extension_list *required_instance_ext_list);
/*!
* Build instance extensions from required and optional instance extensions.
@@ -793,15 +793,15 @@ vk_check_required_instance_extensions(struct vk_bundle *vk, struct u_string_list
*/
VkResult
vk_build_instance_extensions(struct vk_bundle *vk,
struct u_string_list *required_instance_ext_list,
struct u_string_list *optional_instance_ext_list,
struct u_string_list **out_instance_ext_list);
struct u_extension_list *required_instance_ext_list,
struct u_extension_list *optional_instance_ext_list,
struct u_extension_list **out_instance_ext_list);
/*!
* Fills in has_* in vk_bundle given a string of prefiltered instance extensions
*/
void
vk_fill_in_has_instance_extensions(struct vk_bundle *vk, struct u_string_list *ext_list);
vk_fill_in_has_instance_extensions(struct vk_bundle *vk, struct u_extension_list *ext_list);
/*!
* Setup the physical device, this is called by vk_create_device but has uses
@@ -843,8 +843,8 @@ vk_create_device(struct vk_bundle *vk,
int forced_index,
bool only_compute,
VkQueueGlobalPriorityEXT global_priority,
struct u_string_list *required_device_ext_list,
struct u_string_list *optional_device_ext_list,
struct u_extension_list *required_device_ext_list,
struct u_extension_list *optional_device_ext_list,
const struct vk_device_features *optional_device_features);
/*!
@@ -1,4 +1,5 @@
// Copyright 2022, Collabora, Ltd.
// Copyright 2025-2026, NVIDIA CORPORATION.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
@@ -19,7 +20,7 @@
#include "xrt/xrt_vulkan_includes.h"
#include "util/u_logging.h"
#include "util/u_string_list.h"
#include "util/u_extension_list.h"
#include "vk/vk_helpers.h"
+44 -28
View File
@@ -1,5 +1,5 @@
// Copyright 2019-2024, Collabora, Ltd.
// Copyright 2025, NVIDIA CORPORATION.
// Copyright 2025-2026, NVIDIA CORPORATION.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
@@ -613,10 +613,12 @@ static const char *optional_device_extensions[] = {
};
static bool
select_instances_extensions(struct comp_compositor *c, struct u_string_list *required, struct u_string_list *optional)
select_instances_extensions(struct comp_compositor *c,
struct u_extension_list_builder *required_builder,
struct u_extension_list_builder *optional_builder)
{
#ifdef XRT_FEATURE_WINDOW_PEEK
if (!comp_window_peek_get_vk_instance_exts(required)) {
if (!comp_window_peek_get_vk_instance_exts(required_builder)) {
COMP_ERROR(c, "Failed to get required vulkan instance extensions for peek window.");
return false;
}
@@ -638,62 +640,76 @@ compositor_init_vulkan(struct comp_compositor *c)
* Instance extensions.
*/
struct u_string_list *required_instance_ext_list = u_string_list_create();
struct u_string_list *optional_instance_ext_list = u_string_list_create();
struct u_extension_list_builder *required_instance_ext_builder = u_extension_list_builder_create();
struct u_extension_list_builder *optional_instance_ext_builder = u_extension_list_builder_create();
// Every backend needs at least the common extensions.
u_string_list_append_array( //
required_instance_ext_list, //
u_extension_list_builder_append_array( //
required_instance_ext_builder, //
instance_extensions_common, //
ARRAY_SIZE(instance_extensions_common)); //
// Add per target required extensions.
u_string_list_append_array( //
required_instance_ext_list, //
u_extension_list_builder_append_array( //
required_instance_ext_builder, //
c->target_factory->required_instance_extensions, //
c->target_factory->required_instance_extension_count); //
// Optional instance extensions.
u_string_list_append_array( //
optional_instance_ext_list, //
u_extension_list_builder_append_array( //
optional_instance_ext_builder, //
optional_instance_extensions, //
ARRAY_SIZE(optional_instance_extensions)); //
if (!select_instances_extensions(c, required_instance_ext_list, optional_instance_ext_list)) {
if (!select_instances_extensions(c, required_instance_ext_builder, optional_instance_ext_builder)) {
COMP_ERROR(c, "Failed to select additional instance extensions.");
u_string_list_destroy(&required_instance_ext_list);
u_string_list_destroy(&optional_instance_ext_list);
u_extension_list_builder_destroy(&required_instance_ext_builder);
u_extension_list_builder_destroy(&optional_instance_ext_builder);
return false;
}
// Consumes the builder and returns a new list.
struct u_extension_list *required_instance_ext_list =
u_extension_list_builder_build(&required_instance_ext_builder);
struct u_extension_list *optional_instance_ext_list =
u_extension_list_builder_build(&optional_instance_ext_builder);
/*
* Device extensions.
*/
struct u_string_list *required_device_extension_list = u_string_list_create();
struct u_string_list *optional_device_extension_list = u_string_list_create();
struct u_extension_list_builder *required_device_ext_builder = u_extension_list_builder_create();
struct u_extension_list_builder *optional_device_ext_builder = u_extension_list_builder_create();
// Required device extensions.
u_string_list_append_array( //
required_device_extension_list, //
u_extension_list_builder_append_array( //
required_device_ext_builder, //
required_device_extensions, //
ARRAY_SIZE(required_device_extensions)); //
// Optional device extensions.
u_string_list_append_array( //
optional_device_extension_list, //
u_extension_list_builder_append_array( //
optional_device_ext_builder, //
optional_device_extensions, //
ARRAY_SIZE(optional_device_extensions)); //
// Add per target optional device extensions.
u_string_list_append_array( //
optional_device_extension_list, //
u_extension_list_builder_append_array( //
optional_device_ext_builder, //
c->target_factory->optional_device_extensions, //
c->target_factory->optional_device_extension_count); //
// Consumes the builder and returns a new list.
struct u_extension_list *required_device_ext_list =
u_extension_list_builder_build(&required_device_ext_builder);
struct u_extension_list *optional_device_ext_list =
u_extension_list_builder_build(&optional_device_ext_builder);
// Select required Vulkan version, suitable for both compositor and target
uint32_t required_instance_version = MAX(c->target_factory->required_instance_version, VK_API_VERSION_1_0);
/*
* Create the device.
*/
@@ -703,8 +719,8 @@ compositor_init_vulkan(struct comp_compositor *c)
.required_instance_version = required_instance_version,
.required_instance_extensions = required_instance_ext_list,
.optional_instance_extensions = optional_instance_ext_list,
.required_device_extensions = required_device_extension_list,
.optional_device_extensions = optional_device_extension_list,
.required_device_extensions = required_device_ext_list,
.optional_device_extensions = optional_device_ext_list,
.log_level = c->settings.log_level,
.only_compute_queue = c->settings.use_compute,
.selected_gpu_index = c->settings.selected_gpu_index,
@@ -715,10 +731,10 @@ compositor_init_vulkan(struct comp_compositor *c)
struct comp_vulkan_results vk_res = {0};
bool bundle_ret = comp_vulkan_init_bundle(vk, &vk_args, &vk_res);
u_string_list_destroy(&required_instance_ext_list);
u_string_list_destroy(&optional_instance_ext_list);
u_string_list_destroy(&required_device_extension_list);
u_string_list_destroy(&optional_device_extension_list);
u_extension_list_destroy(&required_instance_ext_list);
u_extension_list_destroy(&optional_instance_ext_list);
u_extension_list_destroy(&required_device_ext_list);
u_extension_list_destroy(&optional_device_ext_list);
if (!bundle_ret) {
return false;
+6 -5
View File
@@ -1,5 +1,6 @@
// Copyright 2022, Simon Zeni <simon@bl4ckb0ne.ca>
// Copyright 2022-2023, Collabora, Ltd.
// Copyright 2025-2026, NVIDIA CORPORATION.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
@@ -13,7 +14,7 @@
#include "main/comp_window_peek.h"
#include "util/u_debug.h"
#include "util/u_string_list.h"
#include "util/u_extension_list.h"
#ifdef XRT_HAVE_SDL2
#include <SDL2/SDL.h>
@@ -473,10 +474,10 @@ comp_window_peek_get_eye(struct comp_window_peek *w)
}
bool
comp_window_peek_get_vk_instance_exts(struct u_string_list *out_required_list)
comp_window_peek_get_vk_instance_exts(struct u_extension_list_builder *out_required_builder)
{
if (out_required_list == NULL) {
U_LOG_E("comp_window_peek: out_required_list is null.");
if (out_required_builder == NULL) {
U_LOG_E("comp_window_peek: out_required_builder is null.");
return false;
}
@@ -532,7 +533,7 @@ comp_window_peek_get_vk_instance_exts(struct u_string_list *out_required_list)
}
for (uint32_t i = 0; i < size; ++i) {
if (u_string_list_append_unique(out_required_list, instance_ext_names[i]) == 0) {
if (u_extension_list_builder_append_unique(out_required_builder, instance_ext_names[i]) == 0) {
U_LOG_T("comp_window_peek: required instance extension: %s already exits, ignored.",
instance_ext_names[i]);
} else {
+5 -4
View File
@@ -1,4 +1,5 @@
// Copyright 2022, Simon Zeni <simon@bl4ckb0ne.ca>
// Copyright 2025-2026, NVIDIA CORPORATION.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
@@ -56,12 +57,12 @@ comp_window_peek_get_eye(struct comp_window_peek *w);
/*!
* Gets the required vulkan instance extensions for comp_window_peek support
*
* @param[inout] out_required_list list of string containing the required instance extensions to enable,
* the list may already contain some/all of the required, duplicates will
* not be added.
* @param[inout] out_required_builder builder for the list of required instance extensions to enable,
* the builder may already contain some/all of the required, duplicates will
* not be added.
*/
bool
comp_window_peek_get_vk_instance_exts(struct u_string_list *out_required_list);
comp_window_peek_get_vk_instance_exts(struct u_extension_list_builder *out_required_builder);
#ifdef __cplusplus
}
+26 -16
View File
@@ -1,4 +1,5 @@
// Copyright 2019-2024, Collabora, Ltd.
// Copyright 2025-2026, NVIDIA CORPORATION.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
@@ -146,10 +147,12 @@ static const char *optional_device_extensions[] = {
};
static VkResult
select_instances_extensions(struct null_compositor *c, struct u_string_list *required, struct u_string_list *optional)
select_instances_extensions(struct null_compositor *c,
struct u_extension_list_builder *required_builder,
struct u_extension_list_builder *optional_builder)
{
#ifdef VK_EXT_display_surface_counter
u_string_list_append(optional, VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME);
u_extension_list_builder_append(optional_builder, VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME);
#endif
return VK_SUCCESS;
@@ -162,25 +165,32 @@ compositor_init_vulkan(struct null_compositor *c)
VkResult ret;
// every backend needs at least the common extensions
struct u_string_list *required_instance_ext_list =
u_string_list_create_from_array(instance_extensions_common, ARRAY_SIZE(instance_extensions_common));
struct u_extension_list_builder *required_instance_ext_builder = u_extension_list_builder_create_from_array( //
instance_extensions_common, //
ARRAY_SIZE(instance_extensions_common)); //
struct u_string_list *optional_instance_ext_list = u_string_list_create();
struct u_extension_list_builder *optional_instance_ext_builder = u_extension_list_builder_create();
ret = select_instances_extensions(c, required_instance_ext_list, optional_instance_ext_list);
ret = select_instances_extensions(c, required_instance_ext_builder, optional_instance_ext_builder);
if (ret != VK_SUCCESS) {
VK_ERROR(vk, "select_instances_extensions: %s\n\tFailed to select instance extensions.",
vk_result_string(ret));
u_string_list_destroy(&required_instance_ext_list);
u_string_list_destroy(&optional_instance_ext_list);
u_extension_list_builder_destroy(&required_instance_ext_builder);
u_extension_list_builder_destroy(&optional_instance_ext_builder);
return ret;
}
struct u_string_list *required_device_extension_list =
u_string_list_create_from_array(required_device_extensions, ARRAY_SIZE(required_device_extensions));
// Consumes the builder and returns a new list.
struct u_extension_list *required_instance_ext_list =
u_extension_list_builder_build(&required_instance_ext_builder);
struct u_extension_list *optional_instance_ext_list =
u_extension_list_builder_build(&optional_instance_ext_builder);
struct u_string_list *optional_device_extension_list =
u_string_list_create_from_array(optional_device_extensions, ARRAY_SIZE(optional_device_extensions));
struct u_extension_list *required_device_extension_list =
u_extension_list_create_from_array(required_device_extensions, ARRAY_SIZE(required_device_extensions));
struct u_extension_list *optional_device_extension_list =
u_extension_list_create_from_array(optional_device_extensions, ARRAY_SIZE(optional_device_extensions));
struct comp_vulkan_arguments vk_args = {
.get_instance_proc_address = vkGetInstanceProcAddr,
@@ -199,10 +209,10 @@ compositor_init_vulkan(struct null_compositor *c)
struct comp_vulkan_results vk_res = {0};
bool bundle_ret = comp_vulkan_init_bundle(vk, &vk_args, &vk_res);
u_string_list_destroy(&required_instance_ext_list);
u_string_list_destroy(&optional_instance_ext_list);
u_string_list_destroy(&required_device_extension_list);
u_string_list_destroy(&optional_device_extension_list);
u_extension_list_destroy(&required_instance_ext_list);
u_extension_list_destroy(&optional_instance_ext_list);
u_extension_list_destroy(&required_device_extension_list);
u_extension_list_destroy(&optional_device_extension_list);
if (!bundle_ret) {
return false;
+4 -4
View File
@@ -178,7 +178,7 @@ fill_in_results(struct vk_bundle *vk, const struct comp_vulkan_arguments *vk_arg
static VkResult
create_instance(struct vk_bundle *vk, const struct comp_vulkan_arguments *vk_args)
{
struct u_string_list *instance_ext_list = NULL;
struct u_extension_list *instance_ext_list = NULL;
VkResult ret;
assert(vk_args->required_instance_version != 0);
@@ -217,8 +217,8 @@ create_instance(struct vk_bundle *vk, const struct comp_vulkan_arguments *vk_arg
VkInstanceCreateInfo instance_info = {
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
.pApplicationInfo = &app_info,
.enabledExtensionCount = u_string_list_get_size(instance_ext_list),
.ppEnabledExtensionNames = u_string_list_get_data(instance_ext_list),
.enabledExtensionCount = u_extension_list_get_size(instance_ext_list),
.ppEnabledExtensionNames = u_extension_list_get_data(instance_ext_list),
};
ret = vk->vkCreateInstance(&instance_info, NULL, &vk->instance);
@@ -239,7 +239,7 @@ create_instance(struct vk_bundle *vk, const struct comp_vulkan_arguments *vk_arg
// Needs to be filled in before getting functions.
vk_fill_in_has_instance_extensions(vk, instance_ext_list);
u_string_list_destroy(&instance_ext_list);
u_extension_list_destroy(&instance_ext_list);
ret = vk_get_instance_functions(vk);
if (ret != VK_SUCCESS) {
+6 -5
View File
@@ -1,4 +1,5 @@
// Copyright 2019-2021, Collabora, Ltd.
// Copyright 2025-2026, NVIDIA CORPORATION.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
@@ -11,7 +12,7 @@
#include "xrt/xrt_compositor.h"
#include "util/u_logging.h"
#include "util/u_string_list.h"
#include "util/u_extension_list.h"
#include "vk/vk_helpers.h"
@@ -32,16 +33,16 @@ struct comp_vulkan_arguments
PFN_vkGetInstanceProcAddr get_instance_proc_address;
//! Extensions that the instance is created with.
struct u_string_list *required_instance_extensions;
struct u_extension_list *required_instance_extensions;
//! Extensions that the instance is created with.
struct u_string_list *optional_instance_extensions;
struct u_extension_list *optional_instance_extensions;
//! Extensions that the device is created with.
struct u_string_list *required_device_extensions;
struct u_extension_list *required_device_extensions;
//! Extensions that the device is created with.
struct u_string_list *optional_device_extensions;
struct u_extension_list *optional_device_extensions;
//! Logging level to be set on the @ref vk_bundle.
enum u_logging_level log_level;
+21 -18
View File
@@ -1,5 +1,5 @@
// Copyright 2018-2024, Collabora, Ltd.
// Copyright 2024-2025, NVIDIA CORPORATION.
// Copyright 2024-2026, NVIDIA CORPORATION.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
@@ -15,7 +15,7 @@
#include "util/u_misc.h"
#include "util/u_debug.h"
#include "util/u_string_list.h"
#include "util/u_extension_list.h"
#include "vk/vk_helpers.h"
@@ -249,7 +249,7 @@ oxr_vk_create_vulkan_instance(struct oxr_logger *log,
return res;
}
struct u_string_list *instance_ext_list = u_string_list_create_from_array(
struct u_extension_list_builder *instance_ext_builder = u_extension_list_builder_create_from_array(
required_vk_instance_extensions, ARRAY_SIZE(required_vk_instance_extensions));
#if defined(VK_EXT_debug_utils)
@@ -263,7 +263,7 @@ oxr_vk_create_vulkan_instance(struct oxr_logger *log,
continue;
}
u_string_list_append_unique(instance_ext_list, optional_vk_instance_extensions[i]);
u_extension_list_builder_append_unique(instance_ext_builder, optional_vk_instance_extensions[i]);
#if defined(VK_EXT_debug_utils)
if (strcmp(optional_vk_instance_extensions[i], VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0) {
@@ -273,13 +273,15 @@ oxr_vk_create_vulkan_instance(struct oxr_logger *log,
}
for (uint32_t i = 0; i < createInfo->vulkanCreateInfo->enabledExtensionCount; i++) {
u_string_list_append_unique(instance_ext_list,
createInfo->vulkanCreateInfo->ppEnabledExtensionNames[i]);
u_extension_list_builder_append_unique(instance_ext_builder,
createInfo->vulkanCreateInfo->ppEnabledExtensionNames[i]);
}
struct u_extension_list *instance_ext_list = u_extension_list_builder_build(&instance_ext_builder);
VkInstanceCreateInfo modified_info = *createInfo->vulkanCreateInfo;
modified_info.ppEnabledExtensionNames = u_string_list_get_data(instance_ext_list);
modified_info.enabledExtensionCount = u_string_list_get_size(instance_ext_list);
modified_info.ppEnabledExtensionNames = u_extension_list_get_data(instance_ext_list);
modified_info.enabledExtensionCount = u_extension_list_get_size(instance_ext_list);
*vulkanResult = loaded_CreateInstance(&modified_info, createInfo->vulkanAllocator, vulkanInstance);
@@ -305,7 +307,7 @@ oxr_vk_create_vulkan_instance(struct oxr_logger *log,
}
#endif
u_string_list_destroy(&instance_ext_list);
u_extension_list_destroy(&instance_ext_list);
return XR_SUCCESS;
}
@@ -400,12 +402,12 @@ oxr_vk_create_vulkan_device(struct oxr_logger *log,
VkPhysicalDevice physical_device = createInfo->vulkanPhysicalDevice;
struct u_string_list *device_extension_list =
u_string_list_create_from_array(required_vk_device_extensions, ARRAY_SIZE(required_vk_device_extensions));
struct u_extension_list_builder *device_extension_builder = u_extension_list_builder_create_from_array(
required_vk_device_extensions, ARRAY_SIZE(required_vk_device_extensions));
for (uint32_t i = 0; i < createInfo->vulkanCreateInfo->enabledExtensionCount; i++) {
u_string_list_append_unique(device_extension_list,
createInfo->vulkanCreateInfo->ppEnabledExtensionNames[i]);
u_extension_list_builder_append_unique(device_extension_builder,
createInfo->vulkanCreateInfo->ppEnabledExtensionNames[i]);
}
@@ -431,7 +433,7 @@ oxr_vk_create_vulkan_device(struct oxr_logger *log,
continue;
}
u_string_list_append_unique(device_extension_list, optional_device_extensions[i]);
u_extension_list_builder_append_unique(device_extension_builder, optional_device_extensions[i]);
#if defined(XRT_GRAPHICS_SYNC_HANDLE_IS_FD)
if (strcmp(optional_device_extensions[i], VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME) == 0) {
@@ -449,6 +451,7 @@ oxr_vk_create_vulkan_device(struct oxr_logger *log,
free(props);
struct u_extension_list *device_extension_list = u_extension_list_builder_build(&device_extension_builder);
VkPhysicalDeviceFeatures2KHR physical_device_features = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR,
@@ -462,7 +465,7 @@ oxr_vk_create_vulkan_device(struct oxr_logger *log,
.timelineSemaphore = VK_FALSE,
};
if (u_string_list_contains(device_extension_list, VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME)) {
if (u_extension_list_contains(device_extension_list, VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME)) {
physical_device_features.pNext = &timeline_semaphore_info;
}
#endif
@@ -475,8 +478,8 @@ oxr_vk_create_vulkan_device(struct oxr_logger *log,
VkDeviceCreateInfo modified_info = *createInfo->vulkanCreateInfo;
modified_info.ppEnabledExtensionNames = u_string_list_get_data(device_extension_list);
modified_info.enabledExtensionCount = u_string_list_get_size(device_extension_list);
modified_info.ppEnabledExtensionNames = u_extension_list_get_data(device_extension_list);
modified_info.enabledExtensionCount = u_extension_list_get_size(device_extension_list);
#ifdef VK_KHR_timeline_semaphore
VkPhysicalDeviceTimelineSemaphoreFeatures timeline_semaphore = {
@@ -554,7 +557,7 @@ oxr_vk_create_vulkan_device(struct oxr_logger *log,
}
#endif
u_string_list_destroy(&device_extension_list);
u_extension_list_destroy(&device_extension_list);
return XR_SUCCESS;
}
+26 -16
View File
@@ -1,4 +1,5 @@
// Copyright 2019-2023, Collabora, Ltd.
// Copyright 2025-2026, NVIDIA CORPORATION.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
@@ -133,10 +134,12 @@ static const char *optional_device_extensions[] = {
};
static VkResult
select_instances_extensions(struct sdl_compositor *c, struct u_string_list *required, struct u_string_list *optional)
select_instances_extensions(struct sdl_compositor *c,
struct u_extension_list_builder *required_builder,
struct u_extension_list_builder *optional_builder)
{
#ifdef VK_EXT_display_surface_counter
u_string_list_append(optional, VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME);
u_extension_list_builder_append(optional_builder, VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME);
#endif
return VK_SUCCESS;
@@ -149,25 +152,32 @@ compositor_init_vulkan(struct sdl_compositor *c, enum u_logging_level log_level)
VkResult ret;
// every backend needs at least the common extensions
struct u_string_list *required_instance_ext_list =
u_string_list_create_from_array(instance_extensions_common, ARRAY_SIZE(instance_extensions_common));
struct u_extension_list_builder *required_instance_ext_builder = u_extension_list_builder_create_from_array( //
instance_extensions_common, //
ARRAY_SIZE(instance_extensions_common)); //
struct u_string_list *optional_instance_ext_list = u_string_list_create();
struct u_extension_list_builder *optional_instance_ext_builder = u_extension_list_builder_create();
ret = select_instances_extensions(c, required_instance_ext_list, optional_instance_ext_list);
ret = select_instances_extensions(c, required_instance_ext_builder, optional_instance_ext_builder);
if (ret != VK_SUCCESS) {
VK_ERROR(vk, "select_instances_extensions: %s\n\tFailed to select instance extensions.",
vk_result_string(ret));
u_string_list_destroy(&required_instance_ext_list);
u_string_list_destroy(&optional_instance_ext_list);
u_extension_list_builder_destroy(&required_instance_ext_builder);
u_extension_list_builder_destroy(&optional_instance_ext_builder);
return ret;
}
struct u_string_list *required_device_extension_list =
u_string_list_create_from_array(required_device_extensions, ARRAY_SIZE(required_device_extensions));
// Consumes the builder and returns a new list.
struct u_extension_list *required_instance_ext_list =
u_extension_list_builder_build(&required_instance_ext_builder);
struct u_extension_list *optional_instance_ext_list =
u_extension_list_builder_build(&optional_instance_ext_builder);
struct u_string_list *optional_device_extension_list =
u_string_list_create_from_array(optional_device_extensions, ARRAY_SIZE(optional_device_extensions));
struct u_extension_list *required_device_extension_list =
u_extension_list_create_from_array(required_device_extensions, ARRAY_SIZE(required_device_extensions));
struct u_extension_list *optional_device_extension_list =
u_extension_list_create_from_array(optional_device_extensions, ARRAY_SIZE(optional_device_extensions));
struct comp_vulkan_arguments vk_args = {
.get_instance_proc_address = vkGetInstanceProcAddr,
@@ -186,10 +196,10 @@ compositor_init_vulkan(struct sdl_compositor *c, enum u_logging_level log_level)
struct comp_vulkan_results vk_res = {0};
bool bundle_ret = comp_vulkan_init_bundle(vk, &vk_args, &vk_res);
u_string_list_destroy(&required_instance_ext_list);
u_string_list_destroy(&optional_instance_ext_list);
u_string_list_destroy(&required_device_extension_list);
u_string_list_destroy(&optional_device_extension_list);
u_extension_list_destroy(&required_instance_ext_list);
u_extension_list_destroy(&optional_instance_ext_list);
u_extension_list_destroy(&required_device_extension_list);
u_extension_list_destroy(&optional_device_extension_list);
if (!bundle_ret) {
return false;
+7 -6
View File
@@ -1,4 +1,5 @@
// Copyright 2022-2024, Collabora, Ltd.
// Copyright 2025-2026, NVIDIA CORPORATION.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
@@ -20,7 +21,7 @@
#include "catch_amalgamated.hpp"
#include "util/comp_vulkan.h"
#include "util/u_logging.h"
#include "util/u_string_list.h"
#include "util/u_extension_list.h"
#include "vk/vk_helpers.h"
#include "xrt/xrt_compositor.h"
#include <xrt/xrt_deleters.hpp>
@@ -85,7 +86,7 @@ static const char *required_device_extensions[] = {
using unique_string_list =
std::unique_ptr<u_string_list, xrt::deleters::ptr_ptr_deleter<u_string_list, &u_string_list_destroy>>;
std::unique_ptr<u_extension_list, xrt::deleters::ptr_ptr_deleter<u_extension_list, &u_extension_list_destroy>>;
static void
xrt_comp_vk_destroy(struct xrt_compositor_vk **ptr_xcvk)
@@ -108,14 +109,14 @@ TEST_CASE("client_compositor", "[.][needgpu]")
// every backend needs at least the common extensions
unique_string_list required_instance_ext_list{
u_string_list_create_from_array(instance_extensions_common, ARRAY_SIZE(instance_extensions_common))};
u_extension_list_create_from_array(instance_extensions_common, ARRAY_SIZE(instance_extensions_common))};
unique_string_list optional_instance_ext_list{u_string_list_create()};
unique_string_list optional_instance_ext_list{u_extension_list_create()};
unique_string_list required_device_extension_list{
u_string_list_create_from_array(required_device_extensions, ARRAY_SIZE(required_device_extensions))};
u_extension_list_create_from_array(required_device_extensions, ARRAY_SIZE(required_device_extensions))};
unique_string_list optional_device_extension_list{u_string_list_create()};
unique_string_list optional_device_extension_list{u_extension_list_create()};
comp_vulkan_arguments args{VK_MAKE_VERSION(1, 0, 0),
vkGetInstanceProcAddr,
+7 -6
View File
@@ -1,4 +1,5 @@
// Copyright 2019-2022, Collabora, Ltd.
// Copyright 2025-2026, NVIDIA CORPORATION.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
@@ -18,7 +19,7 @@
#include <xrt/xrt_vulkan_includes.h>
#include <vk/vk_helpers.h>
#include <util/comp_vulkan.h>
#include <util/u_string_list.hpp>
#include <util/u_extension_list.hpp>
static const char *instance_extensions_common[] = {
@@ -71,7 +72,7 @@ static const char *optional_device_extensions[] = {
#endif
};
using unique_string_list =
std::unique_ptr<u_string_list, xrt::deleters::ptr_ptr_deleter<u_string_list, &u_string_list_destroy>>;
std::unique_ptr<u_extension_list, xrt::deleters::ptr_ptr_deleter<u_extension_list, &u_extension_list_destroy>>;
struct VkBundleDestroyer
{
@@ -119,15 +120,15 @@ vktest_init_bundle(struct vk_bundle *vk)
{
// every backend needs at least the common extensions
unique_string_list required_instance_ext_list{
u_string_list_create_from_array(instance_extensions_common, ARRAY_SIZE(instance_extensions_common))};
u_extension_list_create_from_array(instance_extensions_common, ARRAY_SIZE(instance_extensions_common))};
unique_string_list optional_instance_ext_list{u_string_list_create()};
unique_string_list optional_instance_ext_list{u_extension_list_create()};
unique_string_list required_device_extension_list{
u_string_list_create_from_array(required_device_extensions, ARRAY_SIZE(required_device_extensions))};
u_extension_list_create_from_array(required_device_extensions, ARRAY_SIZE(required_device_extensions))};
unique_string_list optional_device_extension_list{
u_string_list_create_from_array(optional_device_extensions, ARRAY_SIZE(optional_device_extensions))};
u_extension_list_create_from_array(optional_device_extensions, ARRAY_SIZE(optional_device_extensions))};
U_ZERO(vk);
comp_vulkan_arguments args{VK_MAKE_VERSION(1, 0, 0),