c++ - 从外部 API 比较两个相同类型的结构
问题描述
所以基本上我正在尝试比较VkPhysicalDeviceFeatures
Vulkan 的两个,一个来自VkPhysicalDevice
我正在查看的,另一个对应于我实际需要的一组功能。VkPhysicalDeviceFeatures
结构仅包含VkBool32
成员(它们是 的 typedef )uint32_t
,但 vulkan 的每个次要版本都可以添加未知数量的这些功能。我想做的只是将每个结构的成员相互比较,而不是为了相等,更多的是逻辑比较。如果物理设备结构中的相应成员为假,但我的结构对该成员具有真,那么比较应该返回假。
我能想到的唯一方法就是这个答案发布的内容:
bool hasRequiredFeatures(VkPhysicalDevice physical_device,
VkPhysicalDeviceFeatures required_features) {
VkPhysicalDeviceFeatures physical_device_features = getSupportedFeatures(physical_device);
std::size_t struct_length = sizeof(VkPhysicalDeviceFeatures) / sizeof(VkBool32);
auto physical_device_features_bool_ptr = reinterpret_cast<VkBool32*>(&physical_device_features);
auto required_features_bool_ptr = reinterpret_cast<VkBool32*>(&required_features);
for(std::size_t i = 0; i < struct_length; ++i){
if(physical_device_features_bool_ptr[i] == VK_FALSE && required_features_bool_ptr[i] == VK_TRUE){
return false;
}
}
return true;
}
这就是我想要的(尽管有一种方法可以通过名称查看哪个特定成员未能通过比较,但我想如果没有反射这是不可能的)但我认为 C++ 不能保证像这样的严格对齐?我有没有跨平台的方式来完成这个?
解决方案
您的方法存在一个大问题,它与 C++ 的关系不大,而与 Vulkan 的关系更大。具体来说:
vulkan 的次要版本可以添加未知数量的这些结构
这告诉我您打算将此类技术应用于VkPhysicalDeviceFeatures2
,以及任何可能出现在其pNext
链中的特征结构。因此,“这些结构的数量未知”。
好吧,事情是这样的:VkPhysicalDeviceFeatures2
不只是一堆VkBool
s。它是一个可扩展的 Vulkan 结构,这意味着它以此类结构共有的sType
andpNext
字段开头。所有 1.0 后的 Vulkan 设备功能结构也是如此。
可以执行您在 1.0 后特性结构中声明的代码必须能够采用整个pNext
特性结构链并对其进行测试。为了做到这一点,你必须知道它们是什么。无法仅从指向任意数据的指针查询该数据包含 X 个VkBool
s。
要完成这项工作,您需要能够将sType
值映射到该结构的大小。因此,它不能自动扩展(不,C++ 反射不能解决这个问题;它不知道 struct avoid *pNext
指向什么);这将需要一定程度的手动维护。
幸运的是,Vulkan XML 规范描述文件清楚地指定了哪些结构可以存在于特定pNext
链中。因此,您可以编写一个工具来加载 XML、查找VkPhysicalDeviceFeatures2
和处理出现在其pNext
链中的所有结构(这部分说起来容易做起来难,因为 XML 格式只是为由 Khronos 自己的工具构建的)来查找哪个结构可用,并生成您需要的 C++ 信息。我相信你可以用任何脚本语言相对容易地编写这样的东西。
但是,由于您已经在(准合理的)XML 中获得了结构定义,并且您已经拥有了无论如何都会生成一些 C++ 代码的工具……您可以只生成实际的比较逻辑。也就是说,不用手写成员对成员的比较,只需生成成员对成员的比较。您甚至可以获得不匹配的成员名称。
如果您要处理任意pNext
链特征,那么您将需要某种生成器工具。如果您无论如何都需要生成器工具,只需使用它来解决整个问题。
现在,重要的是要意识到假设hasRequiredFeatures
实现的生成代码必须是半复杂的。如果您允许完整pNext
的结构链,那么您需要构建自己的相应等效结构链以用于从 Vulkan 进行查询。这并不是微不足道的。
您将需要遍历pNext
链并检查sType
每个结构的字段。但当然,pNext
是 a void*
,所以你将不得不撒谎/欺骗 C++ 的规则来阅读该sType
领域。基本上,您必须使用 to reinterpret_cast
,void*
读取VkStructureType*
值,将其与您正在使用的所有可能性进行比较,然后从那里继续。您应该跳过任何sType
您不知道的内容,这将需要更多的 C++ 技巧。
但是您使用的是低级 API;打破 C++ 的规则只是你必须习惯的事情。
对于每个这样的结构,您需要分配一个匹配的结构,sType
适当地填写它,然后将其添加到pNext
您正在构建的链中。
一旦你构建了所有这些,你就可以调用 Vulkan,进行比较,收集数据,最后删除整个结构链。
如果您的目标确实是坚持使用VkPhysicalDeviceFeatures
可扩展结构而不是可扩展结构,并且您只想要一种 C++ 可移植的方式来比较这些结构,那么只需memcpy
将它们放入一个VkBool
数组并比较两个数组是否不匹配。这两种类型都是可以简单复制的,所以从表面上看,这样做并不是非法的。
此代码尚未编译或测试。
bool hasRequiredFeatures(VkPhysicalDevice physical_device,
VkPhysicalDeviceFeatures required_features)
{
constexpr auto feature_count = sizeof(VkPhysicalDeviceFeatures) / sizeof(VkBool32);
using FeatureArray = std::array<VkBool, feature_count>;
auto physical_device_features = getSupportedFeatures(physical_device);
FeatureArray required;
memcpy(&required, &required_features, sizeof(FeatureArray));
FeatureArray retrieved;
memcpy(&retrieved, &physical_device_features, sizeof(FeatureArray));
bool did_mismatch = false;
for(auto it_pair = std::mismatch(required.begin(), required.end(), retrieved.begin());
it_pair.first != required.end();
it_pair = std::mismatch(it_pair.first, required.end(), it_pair.second))
{
did_mismatch = true
auto mismatch_index = it_pair.first - required.begin();
//Do something with mismatch_index
}
return did_mismatch;
}
推荐阅读
- git - Azure Pipeline,无法提示,因为终端提示已被禁用
- python - 如何通过引用单个列重新排序 CSV 文件中的行?
- c - 万圣节特卖 | 黑客等级
- bash - Bash:在变量名中使用变量
- apollo-client - 如何确定 Apollo 客户端的 InMemoryCache 的当前缓存大小
- python - Pyqt5 在按钮单击后冻结
- python - Python中具有属性like-c的结构
- c# - 无法在 .NET 中读取“脱机”文件
- python - sqlalchemy中表的after_update触发器
- reactjs - 错误:错误:找不到模块“webpack-cli/bin/config-yargs”需要堆栈: