//
// Copyright 2010 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.
//

#ifdef UNSAFE_BUFFERS_BUILD
#    pragma allow_unsafe_libc_calls
#endif

#include "libANGLE/Uniform.h"
#include "common/BinaryStream.h"
#include "libANGLE/ProgramLinkedResources.h"

#include <cstring>

namespace gl
{

LinkedUniform::LinkedUniform(GLenum typeIn,
                             GLenum precisionIn,
                             const std::vector<unsigned int> &arraySizesIn,
                             const int bindingIn,
                             const int offsetIn,
                             const int locationIn,
                             const int bufferIndexIn,
                             const sh::BlockMemberInfo &blockInfoIn)
{
    // arrays are always flattened, which means at most 1D array
    ASSERT(arraySizesIn.size() <= 1);

    memset(this, 0, sizeof(*this));
    pod.typeIndex = GetUniformTypeIndex(typeIn);
    SetBitField(pod.precision, precisionIn);
    pod.location = locationIn;
    SetBitField(pod.binding, bindingIn);
    SetBitField(pod.offset, offsetIn);
    SetBitField(pod.bufferIndex, bufferIndexIn);
    pod.outerArraySizeProduct = 1;
    SetBitField(pod.arraySize, arraySizesIn.empty() ? 1u : arraySizesIn[0]);
    SetBitField(pod.flagBits.isArray, !arraySizesIn.empty());
    if (!(blockInfoIn == sh::kDefaultBlockMemberInfo))
    {
        pod.flagBits.isBlock               = 1;
        pod.flagBits.blockIsRowMajorMatrix = blockInfoIn.isRowMajorMatrix;
        SetBitField(pod.blockOffset, blockInfoIn.offset);
        SetBitField(pod.blockArrayStride, blockInfoIn.arrayStride);
        SetBitField(pod.blockMatrixStride, blockInfoIn.matrixStride);
    }
}

LinkedUniform::LinkedUniform(const UsedUniform &usedUniform)
{
    ASSERT(!usedUniform.isArrayOfArrays());
    ASSERT(!usedUniform.isStruct());
    ASSERT(usedUniform.active);
    ASSERT(usedUniform.blockInfo == sh::kDefaultBlockMemberInfo);

    // Note: Ensure every data member is initialized.
    pod.flagBitsAsUByte = 0;
    pod.typeIndex       = GetUniformTypeIndex(usedUniform.type);
    SetBitField(pod.precision, usedUniform.precision);
    SetBitField(pod.imageUnitFormat, usedUniform.imageUnitFormat);
    pod.location          = usedUniform.location;
    pod.blockOffset       = 0;
    pod.blockArrayStride  = 0;
    pod.blockMatrixStride = 0;
    SetBitField(pod.binding, usedUniform.binding);
    SetBitField(pod.offset, usedUniform.offset);

    SetBitField(pod.bufferIndex, usedUniform.bufferIndex);
    SetBitField(pod.parentArrayIndex, usedUniform.parentArrayIndex());
    SetBitField(pod.outerArraySizeProduct, ArraySizeProduct(usedUniform.outerArraySizes));
    SetBitField(pod.outerArrayOffset, usedUniform.outerArrayOffset);
    SetBitField(pod.arraySize, usedUniform.isArray() ? usedUniform.getArraySizeProduct() : 1u);
    SetBitField(pod.flagBits.isArray, usedUniform.isArray());

    pod.id            = usedUniform.id;
    pod.activeUseBits = usedUniform.activeVariable.activeShaders();
    pod.ids           = usedUniform.activeVariable.getIds();

    SetBitField(pod.flagBits.isFragmentInOut, usedUniform.isFragmentInOut);
    SetBitField(pod.flagBits.texelFetchStaticUse, usedUniform.texelFetchStaticUse);
    SetBitField(pod.flagBits.isFloat16, usedUniform.isFloat16);
    ASSERT(!usedUniform.isArray() || pod.arraySize == usedUniform.getArraySizeProduct());
}

BufferVariable::BufferVariable()
{
    memset(&pod, 0, sizeof(pod));
    pod.bufferIndex       = -1;
    pod.blockInfo         = sh::kDefaultBlockMemberInfo;
    pod.topLevelArraySize = -1;
}

BufferVariable::BufferVariable(GLenum type,
                               GLenum precision,
                               const std::string &name,
                               const std::vector<unsigned int> &arraySizes,
                               const int bufferIndex,
                               int topLevelArraySize,
                               const sh::BlockMemberInfo &blockInfo)
    : name(name)
{
    memset(&pod, 0, sizeof(pod));
    SetBitField(pod.type, type);
    SetBitField(pod.precision, precision);
    SetBitField(pod.bufferIndex, bufferIndex);
    pod.blockInfo = blockInfo;
    SetBitField(pod.topLevelArraySize, topLevelArraySize);
    pod.isArray = !arraySizes.empty();
    SetBitField(pod.basicTypeElementCount, arraySizes.empty() ? 1u : arraySizes.back());
}

AtomicCounterBuffer::AtomicCounterBuffer()
{
    memset(&pod, 0, sizeof(pod));
}

void AtomicCounterBuffer::unionReferencesWith(const LinkedUniform &other)
{
    pod.activeUseBits |= other.pod.activeUseBits;
    for (const ShaderType shaderType : AllShaderTypes())
    {
        ASSERT(pod.ids[shaderType] == 0 || other.getId(shaderType) == 0 ||
               pod.ids[shaderType] == other.getId(shaderType));
        if (pod.ids[shaderType] == 0)
        {
            pod.ids[shaderType] = other.getId(shaderType);
        }
    }
}

InterfaceBlock::InterfaceBlock()
{
    memset(&pod, 0, sizeof(pod));
}

InterfaceBlock::InterfaceBlock(const std::string &name,
                               const std::string &mappedName,
                               bool isArray,
                               bool isReadOnly,
                               unsigned int arrayElementIn,
                               unsigned int firstFieldArraySizeIn,
                               int binding)
    : name(name), mappedName(mappedName)
{
    memset(&pod, 0, sizeof(pod));

    SetBitField(pod.isArray, isArray);
    SetBitField(pod.isReadOnly, isReadOnly);
    SetBitField(pod.inShaderBinding, binding);
    pod.arrayElement        = arrayElementIn;
    pod.firstFieldArraySize = firstFieldArraySizeIn;
}

std::string InterfaceBlock::nameWithArrayIndex() const
{
    std::stringstream fullNameStr;
    fullNameStr << name;
    if (pod.isArray)
    {
        fullNameStr << "[" << pod.arrayElement << "]";
    }

    return fullNameStr.str();
}

std::string InterfaceBlock::mappedNameWithArrayIndex() const
{
    std::stringstream fullNameStr;
    fullNameStr << mappedName;
    if (pod.isArray)
    {
        fullNameStr << "[" << pod.arrayElement << "]";
    }

    return fullNameStr.str();
}
}  // namespace gl
