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