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