Stack allocation converting to Buffer

Started by szg, January 08, 2022, 11:41:23

Previous topic - Next topic

szg

Hello All,
I am following the Vulkan tutorial and trying to refactor code. During this I reached a code which looks like this (only scheleton):
shaderStages = VkPipelineShaderStageCreateInfo.calloc(2, stack);
VkPipelineShaderStageCreateInfo vertShaderStageInfo = shaderStages.get(0);
//removed
VkPipelineShaderStageCreateInfo fragShaderStageInfo = shaderStages.get(1);
//removed
return shaderStages;

I would like to change this to this style:
VkPipelineShaderStageCreateInfo vertShaderStageInfo = VkPipelineShaderStageCreateInfo.calloc(stack);;
//removed
VkPipelineShaderStageCreateInfo fragShaderStageInfo = VkPipelineShaderStageCreateInfo.calloc(stack);
return convertStackToBuffer(vertShaderStageInfo.address(), 2); 
//pseudocode - first parameter is the starting addrss of the buffer, second is the number of elements, most probably I need also the size


I was not able to find in the API anything in this direction (the convertStackToBuffer part). Is there any method which can achieve this?
Thanks

spasi

Hey szg, there's the create method:

return VkPipelineShaderStageCreateInfo.create(vertShaderStageInfo.address(), 2);

szg

Unfortunatelly both of these tries fails with some sun.misc.Unsafe error at VM level (invalid memory allocation or usage)
long startAddress = 0;
        for (int i = 0; i< shaderByteBuffers.length; i++) {
            VkPipelineShaderStageCreateInfo info = VkPipelineShaderStageCreateInfo.calloc(stack);//In the real code I initialize the parameters
            if (i == 0) {
                startAddress = info.address();
            }
        }
        shaderStages = VkPipelineShaderStageCreateInfo.create(startAddress, 2);

or
//same code as in previous example with the exception of the last line
shaderStages = new VkPipelineShaderStageCreateInfo.Buffer(startAddress, 2);

I have a supposition that the consecutive allocation on the stack may not result a consecutive bunch of memory allocation (this would explain the errors). So:
//1st
VkPipelineShaderStageCreateInfo.calloc(stack);
VkPipelineShaderStageCreateInfo.calloc(stack);
//2nd
VkPipelineShaderStageCreateInfo.calloc(2, stack);

the 1st and 2nd code may result in a different memory structure.
Am I right with this supposition?
Thanks

spasi

It fails because the MemoryStack in LWJGL grows "downwards", i.e. if you stack allocate A then B of the same type, they will be contiguous in memory but B will have a lower memory address than A. This is unspecified, just like you can't assume anything about two local variables in C declared next to each other. You can probably get away with using the fragment shader address instead, it should work, but there are no guarantees it won't break in the future (if the MemoryStack implementation changes for whatever reason).

Not sure what your goal is, but if you're trying to minimize local variables, the struct DSL allows it, like this:

VkPipelineShaderStageCreateInfo.calloc(2, stack)
    .apply(0, vsh -> vsh
        .sType$Default()
        .stage(VK_SHADER_STAGE_VERTEX_BIT)
        .module(createShaderModule(vshCode))
        .pName(stack.UTF8("main")))
    .apply(1, fsh -> fsh
        .sType$Default()
        .stage(VK_SHADER_STAGE_FRAGMENT_BIT)
        .module(createShaderModule(fshCode))
        .pName(stack.UTF8("main")));


and you pass that directly to VkGraphicsPipelineCreateInfo::pStages().

szg

Thank you Spasi,
for your explanation and code. I try to learn the memory model and to understand better how lwjgl and vulkan works.

Your code nailed what I tried to achieve, and answers my current questions regarding this topic.

From my point we can close this thread