//
// Copyright 2019 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// ConvertArrayIndirectLineloop.comp: Construct an index buffer for an indirect
// draw that draws all the specified vertices and repeats the last vertex at
// the end to give lineloop behavior.
// Will also output a new indirect "command" buffer with adjusted index values.
//
//

#version 450 core

layout (local_size_x = 64, local_size_y = 1, local_size_z = 1) in;

layout (set = 0, binding = 0) readonly buffer srcIndirectBuf
{
    // Shader invocations read the cmd data to determine what indices to convert
    // Command data at offset cmdOffset of buffer
    uint indirectBuf[];
};

layout (set = 0, binding = 1) buffer dstIndirectBuf
{
    // Shader outputs updated indirect buffer here.
    uint indexIndirectBuf[];
};

layout (set = 0, binding = 2) buffer dstIndexBuf
{
    // Shader invocation outputs linelist(s) here.
    uint dstData[];
};

layout (push_constant) uniform PushConstants
{
    // Read offset in bytes into the indirectBuf, divided by four.
    uint indirectBufferOffsetDiv4;
    // Dst command offset in bytes into the indexIndirectBuff, divided by four.
    uint indexIndirectBufOffsetDiv4;
    // Write offset in bytes into the dstData array, divided by four.
    uint dstDataOffsetDiv4;
};

// Structure of command data loaded at offset indirectBufferOffsetDiv4 of the indirectBuf buffer
// struct VkDrawIndirectCommand {
//     uint32_t    vertexCount;
//     uint32_t    instanceCount;
//     uint32_t    firstVertex;
//     uint32_t    firstInstance;
// };

// Structure of command data loaded at offset indexIndirectBufferOffsetDiv4 of the
// indexIndirectBuf buffer
// struct VkDrawIndexedIndirectCommand {
//     uint32_t    indexCount;
//     uint32_t    instanceCount;
//     uint32_t    firstIndex;
//     int32_t     vertexOffset;
//     uint32_t    firstInstance;
// };

void main()
{
    // Load the relevant command info from cmdData
    uint vertexCount = indirectBuf[indirectBufferOffsetDiv4];
    uint firstVertex = indirectBuf[indirectBufferOffsetDiv4 + 2];

    // Only first invocation does the work
    if (gl_GlobalInvocationID.x >= 1)
        return;

    for (uint i = 0; i < vertexCount; i++)
    {
        dstData[dstDataOffsetDiv4 + i] = firstVertex + i;
    }
    if (vertexCount > 1)
    {
        dstData[dstDataOffsetDiv4 + vertexCount] = firstVertex;
        vertexCount++;
    }

    // Write new indirect data in indexIndirectBuf.
    indexIndirectBuf[indexIndirectBufOffsetDiv4] = vertexCount;
    indexIndirectBuf[indexIndirectBufOffsetDiv4 + 1] = indirectBuf[indirectBufferOffsetDiv4 + 1];
    indexIndirectBuf[indexIndirectBufOffsetDiv4 + 2] = 0;
    indexIndirectBuf[indexIndirectBufOffsetDiv4 + 3] = 0;
    indexIndirectBuf[indexIndirectBufOffsetDiv4 + 4] = indirectBuf[indirectBufferOffsetDiv4 + 3];
}
