JNA toArray() 重置结构字段?
JNA toArray() resets structure fields?
考虑以下 JNA 结构:
public class VkDeviceQueueCreateInfo extends VulkanStructure {
public VkStructureType sType = VkStructureType.VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
public Pointer pNext;
public int flags;
public int queueFamilyIndex;
public int queueCount;
public Pointer pQueuePriorities;
}
sType
字段是原生层用来识别结构类型的常量值。这适用于使用 new
.
创建的 class 的 单个 实例
但是,如果我们使用 toArray()
分配此结构的 array,则 sType
将重置为默认值 after 已为每个数组元素调用构造函数。即它清除了字段!
无效的替代方案:
- 在构造函数中显式设置字段无效(它仍会被重置)。
- 同上制作字段
final
。
- 我们尝试使用默认构造函数还是使用 JNA
Pointer
参数似乎并不重要。
唯一似乎有效的方法是关闭结构的自动读取:
public class VkDeviceQueueCreateInfo extends VulkanStructure {
...
public VkDeviceQueueCreateInfo() {
setAutoRead(false);
}
}
(请注意,此结构仅用于写入本机层,不读回任何内容)。
这有效,但它实际上在做什么?为什么 JNA 在结构还没有时将结构重置为原始值?有没有办法全局关闭该字段的自动读取?
这对于单个结构来说不是什么大问题,但在这个项目中有数百个代码是从本机层生成的,其中大部分(但不是全部)都带有 sType
pre-如上例填充。很明显,预填充该字段不是可行的方法,但有什么替代方法呢?是否需要使用上述 fiddle 重新生成每个结构?
编辑:思考这个问题后想到的另一个相关问题 - 结构中的数组类型如何?它们是否被自动读取的东西重置为 null
?代码生成的结构初始化任何数组以调整结构的大小,例如public float[] colour = new float[4];
您指出 auto-read()
是这里问题的一部分,您是在正确的轨道上。当您调用 toArray()
时,您(通常)将数组的内存支持更改为新的本机内存分配(自动分配将内存清零)。所以所有这些 0 都加载到您的数组中。
为了您的方便,内部结构 toArray()
保留第一个元素的值,但不对其余元素执行任何操作,这些元素是在循环内使用 newInstance()
实例化的。这是导致您的问题的两行:
array[i] = newInstance(getClass(), memory.share(i*size, size));
array[i].conditionalAutoRead();
我的建议是在您自己的 VulkanStructure
结构中覆盖 toArray()
其他人继承的结构。您可以复制现有代码并根据需要对其进行修改(例如,删除 autoRead)。
或者您可以重载一个 toArray()
,该 toArray()
会传递一个结构集合,并在将其读取到新集合之前从旧集合复制后备内存。或者,如果调用 toArray()
时原始内存支持足够大,则不会清除内存。所以你可以分配你自己足够大的内存,在第一个元素上使用 useMemory()
来改变它的后备,然后复制后备内存字节;它们将被自动读入新的数组版本。
考虑以下 JNA 结构:
public class VkDeviceQueueCreateInfo extends VulkanStructure {
public VkStructureType sType = VkStructureType.VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
public Pointer pNext;
public int flags;
public int queueFamilyIndex;
public int queueCount;
public Pointer pQueuePriorities;
}
sType
字段是原生层用来识别结构类型的常量值。这适用于使用 new
.
但是,如果我们使用 toArray()
分配此结构的 array,则 sType
将重置为默认值 after 已为每个数组元素调用构造函数。即它清除了字段!
无效的替代方案:
- 在构造函数中显式设置字段无效(它仍会被重置)。
- 同上制作字段
final
。 - 我们尝试使用默认构造函数还是使用 JNA
Pointer
参数似乎并不重要。
唯一似乎有效的方法是关闭结构的自动读取:
public class VkDeviceQueueCreateInfo extends VulkanStructure {
...
public VkDeviceQueueCreateInfo() {
setAutoRead(false);
}
}
(请注意,此结构仅用于写入本机层,不读回任何内容)。
这有效,但它实际上在做什么?为什么 JNA 在结构还没有时将结构重置为原始值?有没有办法全局关闭该字段的自动读取?
这对于单个结构来说不是什么大问题,但在这个项目中有数百个代码是从本机层生成的,其中大部分(但不是全部)都带有 sType
pre-如上例填充。很明显,预填充该字段不是可行的方法,但有什么替代方法呢?是否需要使用上述 fiddle 重新生成每个结构?
编辑:思考这个问题后想到的另一个相关问题 - 结构中的数组类型如何?它们是否被自动读取的东西重置为 null
?代码生成的结构初始化任何数组以调整结构的大小,例如public float[] colour = new float[4];
您指出 auto-read()
是这里问题的一部分,您是在正确的轨道上。当您调用 toArray()
时,您(通常)将数组的内存支持更改为新的本机内存分配(自动分配将内存清零)。所以所有这些 0 都加载到您的数组中。
为了您的方便,内部结构 toArray()
保留第一个元素的值,但不对其余元素执行任何操作,这些元素是在循环内使用 newInstance()
实例化的。这是导致您的问题的两行:
array[i] = newInstance(getClass(), memory.share(i*size, size));
array[i].conditionalAutoRead();
我的建议是在您自己的 VulkanStructure
结构中覆盖 toArray()
其他人继承的结构。您可以复制现有代码并根据需要对其进行修改(例如,删除 autoRead)。
或者您可以重载一个 toArray()
,该 toArray()
会传递一个结构集合,并在将其读取到新集合之前从旧集合复制后备内存。或者,如果调用 toArray()
时原始内存支持足够大,则不会清除内存。所以你可以分配你自己足够大的内存,在第一个元素上使用 useMemory()
来改变它的后备,然后复制后备内存字节;它们将被自动读入新的数组版本。