//
// Copyright 2019 The ANGLE Project. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

#include "common.h"

constant bool kCombineWithExistingResult [[function_constant(1000)]];

// Combine the visibility result of current render pass with previous value from previous render
// pass
struct CombineVisibilityResultOptions
{
    // Start offset in the render pass's visibility buffer allocated for the query.
    uint startOffset;
    // How many offsets in the render pass's visibility buffer is used for the query?
    uint numOffsets;
};

kernel void combineVisibilityResult(uint idx [[thread_position_in_grid]],
                                    constant CombineVisibilityResultOptions &options [[buffer(0)]],
                                    constant ushort4 *renderpassVisibilityResult [[buffer(1)]],
                                    device ushort4 *finalResults [[buffer(2)]])
{
    if (idx > 0)
    {
        // NOTE(hqle):
        // This is a bit wasteful to use a WARP of multiple threads just for combining one integer.
        // Consider a better approach.
        return;
    }
    ushort4 finalResult16x4;

    if (kCombineWithExistingResult)
    {
        finalResult16x4 = finalResults[0];
    }
    else
    {
        finalResult16x4 = ushort4(0, 0, 0, 0);
    }

    for (uint i = 0; i < options.numOffsets; ++i)
    {
        uint offset              = options.startOffset + i;
        ushort4 renderpassResult = renderpassVisibilityResult[offset];

        // Only boolean result is required, so bitwise OR is enough
        finalResult16x4          = finalResult16x4 | renderpassResult;
    }
    finalResults[0] = finalResult16x4;
}
