How To Create Array of Structs?

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Thu Sep 2 20:46:21 UTC 2021


This is good info, thanks Rado.

On a sidenote, it's a bit sad that jextract does not generate a layout 
for VkSemaphore - we will look into that.

Cheers
Maurizio



On 02/09/2021 19:45, Rado Smogura wrote:
> Hi Michael,
>
>
> That's a great question.
>
>
> Looking at Vulkan docs and source code [1] the 
> VK_DEFINE_NON_DISPATCHABLE_HANDLE is typedef to semaphore struct 
> pointer, so
>
> VkSemaphore is already pointer. In order to create semaphore you 
> should call vkCreateSemaphore ([2]) and pass the pointer to this pointer.
>
>
> So, you have to allocate pointer type from Java and pass an address to 
> vkCreateSemaphore. I guess vkCreateSemaphore does memory allocation on 
> its own, and as well initializes memory behind pointer (that's quite 
> common approach).
>
> I've found C example here [3] - I guess you already have seen it.
>
>
> I hope I could help,
>
> Rado
>
>
> [1] 
> https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_DEFINE_NON_DISPATCHABLE_HANDLE.html
>
> [2] 
> https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkCreateSemaphore.html
>
> [3] 
> https://vulkan-tutorial.com/Drawing_a_triangle/Drawing/Rendering_and_presentation
>
> On 02.09.2021 20:16, Michael Ennen wrote:
>> Quick question that is now happening while trying to replicate the 
>> fix when
>> I don't have an explicit struct handle like in the case of VkSemaphore:
>>
>> https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkSemaphore.html 
>>
>>
>> For those types I don't have a struct layout to work with so I have been
>> just declaring a double pointer:
>>
>> var pVkPipeline =
>> SegmentAllocator.ofScope(scope).allocate(C_POINTER.byteSize());
>>
>> and then using MemoryAccess.getAddress(pVkPipeline).
>>
>> So in this case how can I create an array of VkSemaphore structs without
>> knowing anything about the struct (it is an opaque handle?).
>>
>> Hope that makes sense.
>>
>> On Thu, Sep 2, 2021 at 11:06 AM Michael Ennen <mike.ennen at gmail.com> 
>> wrote:
>>
>>> Jorn,
>>>
>>> Thank you so much - that was exactly what I was looking for. I don't 
>>> know
>>> why I had such trouble trying to create an array of structs rather 
>>> than an
>>> array of points to structs.
>>>
>>> Thank you both.
>>>
>>> On Thu, Sep 2, 2021 at 4:54 AM Jorn Vernee <jorn.vernee at oracle.com> 
>>> wrote:
>>>
>>>> Additionally, it looks like you're allocating an array of pointers for
>>>> pStages, and it looks like the API expects an array of structs.
>>>>
>>>> Instead of allocating the different VkPipelineShaderStageCreateInfo
>>>> individually, you should allocate the array of struct upfront, and 
>>>> then
>>>> fill in the different structs in-place.
>>>>
>>>> Like:
>>>>
>>>> diff --git a/src/main/java/com/brcolow/game/Vulkan.java
>>>> b/src/main/java/com/brcolow/game/Vulkan.java
>>>> index f0cd278..520513b 100644
>>>> --- a/src/main/java/com/brcolow/game/Vulkan.java
>>>> +++ b/src/main/java/com/brcolow/game/Vulkan.java
>>>> @@ -429,17 +429,17 @@ public class Vulkan {
>>>>                var pVertShaderModule =
>>>> getShaderModule(MemoryAccess.getAddress(pVkDevice), vertShaderBytes,
>>>> scope);
>>>>                var pFragShaderModule =
>>>> getShaderModule(MemoryAccess.getAddress(pVkDevice), fragShaderBytes,
>>>> scope);
>>>>
>>>> -            var pVertShaderStageInfo =
>>>> VkPipelineShaderStageCreateInfo.allocate(scope);
>>>> - VkPipelineShaderStageCreateInfo.sType$set(pVertShaderStageInfo,
>>>> vulkan_h.VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO());
>>>> - VkPipelineShaderStageCreateInfo.stage$set(pVertShaderStageInfo,
>>>> vulkan_h.VK_SHADER_STAGE_VERTEX_BIT());
>>>> - VkPipelineShaderStageCreateInfo.module$set(pVertShaderStageInfo,
>>>> MemoryAccess.getAddress(pVertShaderModule));
>>>> - VkPipelineShaderStageCreateInfo.pName$set(pVertShaderStageInfo,
>>>> CLinker.toCString("main", scope).address());
>>>> -
>>>> -            var pFragShaderStageInfo =
>>>> VkPipelineShaderStageCreateInfo.allocate(scope);
>>>> - VkPipelineShaderStageCreateInfo.sType$set(pFragShaderStageInfo,
>>>> vulkan_h.VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO());
>>>> - VkPipelineShaderStageCreateInfo.stage$set(pFragShaderStageInfo,
>>>> vulkan_h.VK_SHADER_STAGE_FRAGMENT_BIT());
>>>> - VkPipelineShaderStageCreateInfo.module$set(pFragShaderStageInfo,
>>>> MemoryAccess.getAddress(pFragShaderModule));
>>>> - VkPipelineShaderStageCreateInfo.pName$set(pFragShaderStageInfo,
>>>> CLinker.toCString("main", scope).address());
>>>> +            MemorySegment pStages =
>>>> SegmentAllocator.ofScope(scope).allocateArray(VkPipelineShaderStageCreateInfo.$LAYOUT(), 
>>>>
>>>>
>>>> 2);
>>>> +
>>>> + VkPipelineShaderStageCreateInfo.sType$set(pStages, 0,
>>>> vulkan_h.VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO());
>>>> + VkPipelineShaderStageCreateInfo.stage$set(pStages, 0,
>>>> vulkan_h.VK_SHADER_STAGE_VERTEX_BIT());
>>>> + VkPipelineShaderStageCreateInfo.module$set(pStages, 0,
>>>> MemoryAccess.getAddress(pVertShaderModule));
>>>> + VkPipelineShaderStageCreateInfo.pName$set(pStages, 0,
>>>> CLinker.toCString("main", scope).address());
>>>> +
>>>> + VkPipelineShaderStageCreateInfo.sType$set(pStages, 1,
>>>> vulkan_h.VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO());
>>>> + VkPipelineShaderStageCreateInfo.stage$set(pStages, 1,
>>>> vulkan_h.VK_SHADER_STAGE_FRAGMENT_BIT());
>>>> + VkPipelineShaderStageCreateInfo.module$set(pStages, 1,
>>>> MemoryAccess.getAddress(pFragShaderModule));
>>>> + VkPipelineShaderStageCreateInfo.pName$set(pStages, 1,
>>>> CLinker.toCString("main", scope).address());
>>>>
>>>>                var pVertexInputStateInfo =
>>>> VkPipelineVertexInputStateCreateInfo.allocate(scope);
>>>> VkPipelineVertexInputStateCreateInfo.sType$set(pVertexInputStateInfo,
>>>> vulkan_h.VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO());
>>>> @@ -581,16 +581,14 @@ public class Vulkan {
>>>>                // If we change stageCount to 2 we get a crash....
>>>>                // I think we are creating the pStages array 
>>>> incorrectly.
>>>> This is also manifesting further down when trying
>>>>                // to create arrays pWaitSemaphores, 
>>>> pSignalSemaphores, etc.
>>>> - VkGraphicsPipelineCreateInfo.stageCount$set(pPipelineCreateInfo, 1);
>>>> -            MemorySegment pStages =
>>>> SegmentAllocator.ofScope(scope).allocateArray(C_POINTER, new
>>>> Addressable[]{
>>>> -                    pVertShaderStageInfo, pFragShaderStageInfo});
>>>> -            System.out.println("pStages: " + pStages);
>>>> -            System.out.println("pStages[0]: " +
>>>> VkPipelineShaderStageCreateInfo.ofAddress(MemoryAccess.getAddressAtIndex(pStages, 
>>>>
>>>>
>>>> 0), scope));
>>>> -            System.out.println("pStages[0].sType: " +
>>>> VkPipelineShaderStageCreateInfo.sType$get(VkPipelineShaderStageCreateInfo.ofAddress(MemoryAccess.getAddressAtIndex(pStages, 
>>>>
>>>>
>>>> 0), scope)));
>>>> -            System.out.println("pStages[1]: " +
>>>> VkPipelineShaderStageCreateInfo.ofAddress(MemoryAccess.getAddressAtIndex(pStages, 
>>>>
>>>>
>>>> 1), scope));
>>>> -            System.out.println("pStages[1].sType: " +
>>>> VkPipelineShaderStageCreateInfo.sType$get(VkPipelineShaderStageCreateInfo.ofAddress(MemoryAccess.getAddressAtIndex(pStages, 
>>>>
>>>>
>>>> 1), scope)));
>>>> -
>>>> - VkGraphicsPipelineCreateInfo.pStages$set(pPipelineCreateInfo,
>>>> MemoryAccess.getAddress(pStages));
>>>> + VkGraphicsPipelineCreateInfo.stageCount$set(pPipelineCreateInfo, 2);
>>>> +            System.out.println("pStages: " + pStages.address());
>>>> +            System.out.println("pStages[0]: " + pStages.asSlice(0,
>>>> VkPipelineShaderStageCreateInfo.$LAYOUT().byteSize()));
>>>> +            System.out.println("pStages[0].sType: " +
>>>> VkPipelineShaderStageCreateInfo.sType$get(pStages, 0));
>>>> +            System.out.println("pStages[1]: " +
>>>> pStages.asSlice(VkPipelineShaderStageCreateInfo.$LAYOUT().byteSize(),
>>>> VkPipelineShaderStageCreateInfo.$LAYOUT().byteSize()));
>>>> +            System.out.println("pStages[1].sType: " +
>>>> VkPipelineShaderStageCreateInfo.sType$get(pStages, 1));
>>>> +
>>>> + VkGraphicsPipelineCreateInfo.pStages$set(pPipelineCreateInfo,
>>>> pStages.address());
>>>> VkGraphicsPipelineCreateInfo.pVertexInputState$set(pPipelineCreateInfo, 
>>>>
>>>> pVertexInputStateInfo.address());
>>>> VkGraphicsPipelineCreateInfo.pInputAssemblyState$set(pPipelineCreateInfo, 
>>>>
>>>> pPipelineInputAssemblyStateInfo.address());
>>>> VkGraphicsPipelineCreateInfo.pViewportState$set(pPipelineCreateInfo,
>>>> pPipelineViewportStateInfo.address());
>>>>
>>>> HTH,
>>>> Jorn
>>>>
>>>> On 02/09/2021 11:56, Maurizio Cimadamore wrote:
>>>>> Hi Michael,
>>>>> very interesting experiments - thanks for reaching out.
>>>>>
>>>>> Eyeballing your code, I zoomed into this line:
>>>>>
>>>>>
>>>> https://github.com/brcolow/java-vulkan/blob/master/src/main/java/com/brcolow/game/Vulkan.java#L593 
>>>>
>>>>>
>>>>> Here you want to set the `pStages` pointer, a pointer to a memory
>>>>> region which presumably has to contain exactly `stageCount` 
>>>>> structs of
>>>>> type `VkPipelineShaderStageCreateInfo`.
>>>>>
>>>>> I believe there's an extra getAddress in there; this:
>>>>>
>>>>> ```
>>>>> VkGraphicsPipelineCreateInfo.pStages$set(pPipelineCreateInfo,
>>>>> MemoryAccess.getAddress(pStages));
>>>>> ```
>>>>>
>>>>> should be:
>>>>>
>>>>> ```
>>>>> VkGraphicsPipelineCreateInfo.pStages$set(pPipelineCreateInfo, 
>>>>> pStages);
>>>>> ```
>>>>>
>>>>> That is, you want to pass the pointer to the `pStages` region you 
>>>>> just
>>>>> created, so that Vulkan will be able to see all elements. If you call
>>>>> "MemoryAccess::getAddress" your code will read the first 64 bits from
>>>>> the `pStages` region, turn those into a MemoryAddress, and set that
>>>>> into the enclosing `pPipelineCreateInfo` struct. Which I don't think
>>>>> is what you want?
>>>>>
>>>>> Let me know if this works.
>>>>>
>>>>> Cheers
>>>>> Maurizio
>>>>>
>>>>>
>>>>> On 02/09/2021 06:35, Michael Ennen wrote:
>>>>>> I have been doing more exploring with the panama-foreign, ffi, and
>>>>>> jextract
>>>>>> branches - this time messing around with seeing if I can get a 
>>>>>> rainbow
>>>>>> triangle to be rendered on the screen with Vulkan.
>>>>>>
>>>>>> I am really close. There is one problem I am having which is how to
>>>>>> create
>>>>>> an array of structs?
>>>>>>
>>>>>> See this, for example:
>>>>>>
>>>>>>
>>>> https://github.com/brcolow/java-vulkan/blob/master/src/main/java/com/brcolow/game/Vulkan.java#L581 
>>>>
>>>>>>
>>>>>> If I set the stageCount to 2, then I get a validation exception 
>>>>>> about
>>>>>> the
>>>>>> second shader module having bogus values. I believe this is 
>>>>>> caused by
>>>> me
>>>>>> creating the array of structs incorrectly.
>>>>>>
>>>>>> I am trying to set the pStages element of this struct:
>>>>>>
>>>> https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkGraphicsPipelineCreateInfo.html 
>>>>
>>>>>>
>>>>>> to an array containing pVertShaderStageInfo and 
>>>>>> pFragShaderStageInfo.
>>>>>>
>>>>>> My attempt (I have tried other ways that also fail) to do that is:
>>>>>>
>>>>>> MemorySegment pStages = 
>>>>>> SegmentAllocator.ofScope(scope).allocateArray(
>>>>>> C_POINTER, new Addressable[]{
>>>>>> pVertShaderStageInfo, pFragShaderStageInfo});
>>>>>> VkGraphicsPipelineCreateInfo.pStages$set(pPipelineCreateInfo,
>>>>>> MemoryAccess.getAddress(pStages));
>>>>>>
>>>>>>
>>>>>> If anyone could assist me with the proper way to create the
>>>>>> VkPipelineShaderStageCreateInfo* array containing
>>>>>> pVertShaderStageInfoand
>>>>>> pFragShaderStageInfo - it would be greatly appreciated!
>>>>>>
>>>
>>> -- 
>>> Michael Ennen
>>>
>>


More information about the panama-dev mailing list