I am getting a suprising warning from the native library I am using when passing a boolean
value in a JNA structure:
value of pCreateInfo->clipped (-1) is neither VK_TRUE nor VK_FALSE
In this library VK_TRUE
and VK_FALSE
are #defined as 1 and 0 respectively.
The structure itself isn't particularly complex and everything else appears to be working (the native library seems to treat the 'undefined' boolean as false), but here it is anyway:
public class VkSwapchainCreateInfoKHR extends Structure {
public int sType;
public Pointer pNext;
public int flags;
public Pointer surface;
public int minImageCount;
public int imageFormat;
public int imageColorSpace;
public VkExtent2D imageExtent;
public int imageArrayLayers;
public int imageUsage;
public int imageSharingMode;
public int queueFamilyIndexCount;
public Pointer pQueueFamilyIndices;
public int preTransform;
public int compositeAlpha;
public int presentMode;
public boolean clipped; // <--------- this is the field in question
public Pointer oldSwapchain;
}
If the clipped
field is false there is no warning, if it's true then I get the warning - it appears JNA is mapping true
to integer -1?
There are not many native boolean values used by this library but I get the same behaviour whenever one is set to true (and again everything else works fine).
In particular, if I change clipped
to be an int
and set the value explicitly to 1 or 0 everything works!
Is -1 the default value for JNA boolean true
?
If so, how would I go about over-riding the type mapping?
Or should I just use int
'manually'?
JNA maps to native libraries via libffi
. There is no bool
type in libffi
so other mappings must be used -- JNA's default type mapping chooses to map boolean
to ffi_type_uint32
. This works in the structure(s) because it happens to match the 32-bit mapping size, but not the definition: in C, 0 is false and anything nonzero is true. Only if the native type is also boolean
does this 0/non-zero interpretation regain meaning as false/true.
A web search using FFI
or JNI
and boolean
keywords can uncover multiple examples such as this one and this one where unpredictable results occur when libraries are accessed via FFI or JNI and do not conform to the 0 / 1 requirement for boolean values. The latter example appears very similar to this case where a true Java boolean
is interpreted as a C int
with a value other than 1.
Somewhere under the hood between FFI and your library, and possibly in compiled byte code and/or platform/compiler-dependent type conversions, it's likely that a bitwise "not" is being applied to 0x00000000
, turning it into 0xffffffff
which is still 'true' in C.
The bottom line is that JNA will by default map Java boolean false
to a 32-bit native value of 0, and a Java boolean true
to a 32-bit native value that is not 0, and that's all that can be assumed. If your library requires true
to have an integer value of 1, either use an integer type that you can specifically set, or use a custom Type Mapping for boolean
that sets an int
to 0 or 1 for you. JNA's W32APITypeMapper has an example of this conversion to 1 or 0 for the Windows BOOL
type.
In your case, assuming you are mapping the VkSwapchainCreateInfoKHR structure defined here, the type of clipped
is VkBool32:
typedef struct VkSwapchainCreateInfoKHR {
VkStructureType sType;
const void* pNext;
VkSwapchainCreateFlagsKHR flags;
VkSurfaceKHR surface;
uint32_t minImageCount;
VkFormat imageFormat;
VkColorSpaceKHR imageColorSpace;
VkExtent2D imageExtent;
uint32_t imageArrayLayers;
VkImageUsageFlags imageUsage;
VkSharingMode imageSharingMode;
uint32_t queueFamilyIndexCount;
const uint32_t* pQueueFamilyIndices;
VkSurfaceTransformFlagBitsKHR preTransform;
VkCompositeAlphaFlagBitsKHR compositeAlpha;
VkPresentModeKHR presentMode;
VkBool32 clipped;
VkSwapchainKHR oldSwapchain;
} VkSwapchainCreateInfoKHR;
Where...
typedef uint32_t VkBool32;
So int
is the correct mapping here -- you need to map clipped
to a 32-bit integer Edit: As you've pointed out in your answer, it is simple to add your own type mapper to better handle these int
values!
(While I'm reviewing the type mappings, you might find (Your mapping is correct for a variable length IntByReference
a better mapping than Pointer
for the pQueueFamilyIndices
field.)int
array.)