blob: 7d31ca853bc813b20ccf29fb8cb74ba082f4cde4 [file] [log] [blame]
//
// 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 kSourceBufferAligned[[function_constant(0)]];
constant bool kSourceIndexIsU8[[function_constant(1)]];
constant bool kSourceIndexIsU16[[function_constant(2)]];
constant bool kSourceIndexIsU32[[function_constant(3)]];
constant bool kSourceBufferUnaligned = !kSourceBufferAligned;
constant bool kUseSourceBufferU8 = kSourceIndexIsU8 || kSourceBufferUnaligned;
constant bool kUseSourceBufferU16 = kSourceIndexIsU16 && kSourceBufferAligned;
constant bool kUseSourceBufferU32 = kSourceIndexIsU32 && kSourceBufferAligned;
struct IndexConversionParams
{
uint32_t srcOffset; // offset in bytes
uint32_t indexCount;
};
#define ANGLE_IDX_CONVERSION_GUARD(IDX, OPTS) ANGLE_KERNEL_GUARD(IDX, OPTS.indexCount)
inline ushort getIndexAligned(constant ushort *inputAligned, uint offset, uint idx)
{
return inputAligned[offset / 2 + idx];
}
inline uint getIndexAligned(constant uint *inputAligned, uint offset, uint idx)
{
return inputAligned[offset / 4 + idx];
}
inline uchar getIndexAligned(constant uchar *input, uint offset, uint idx)
{
return input[offset + idx];
}
inline ushort getIndexUnalignedU16(constant uchar *input, uint offset, uint idx)
{
ushort inputLo = input[offset + 2 * idx];
ushort inputHi = input[offset + 2 * idx + 1];
// Little endian conversion:
return inputLo | (inputHi << 8);
}
inline uint getIndexUnalignedU32(constant uchar *input, uint offset, uint idx)
{
uint input0 = input[offset + 4 * idx];
uint input1 = input[offset + 4 * idx + 1];
uint input2 = input[offset + 4 * idx + 2];
uint input3 = input[offset + 4 * idx + 3];
// Little endian conversion:
return input0 | (input1 << 8) | (input2 << 16) | (input3 << 24);
}
kernel void convertIndexU8ToU16(uint idx[[thread_position_in_grid]],
constant IndexConversionParams &options[[buffer(0)]],
constant uchar *input[[buffer(1)]],
device ushort *output[[buffer(2)]])
{
ANGLE_IDX_CONVERSION_GUARD(idx, options);
output[idx] = getIndexAligned(input, options.srcOffset, idx);
}
kernel void convertIndexU16(
uint idx[[thread_position_in_grid]],
constant IndexConversionParams &options[[buffer(0)]],
constant uchar *input[[ buffer(1), function_constant(kSourceBufferUnaligned) ]],
constant ushort *inputAligned[[ buffer(1), function_constant(kSourceBufferAligned) ]],
device ushort *output[[buffer(2)]])
{
ANGLE_IDX_CONVERSION_GUARD(idx, options);
ushort value;
if (kSourceBufferAligned)
{
value = getIndexAligned(inputAligned, options.srcOffset, idx);
}
else
{
value = getIndexUnalignedU16(input, options.srcOffset, idx);
}
output[idx] = value;
}
kernel void convertIndexU32(
uint idx[[thread_position_in_grid]],
constant IndexConversionParams &options[[buffer(0)]],
constant uchar *input[[ buffer(1), function_constant(kSourceBufferUnaligned) ]],
constant uint *inputAligned[[ buffer(1), function_constant(kSourceBufferAligned) ]],
device uint *output[[buffer(2)]])
{
ANGLE_IDX_CONVERSION_GUARD(idx, options);
uint value;
if (kSourceBufferAligned)
{
value = getIndexAligned(inputAligned, options.srcOffset, idx);
}
else
{
value = getIndexUnalignedU32(input, options.srcOffset, idx);
}
output[idx] = value;
}
struct TriFanArrayParams
{
uint firstVertex;
uint vertexCountFrom3rd; // vertex count excluding the 1st & 2nd vertices.
};
kernel void genTriFanIndicesFromArray(uint idx[[thread_position_in_grid]],
constant TriFanArrayParams &options[[buffer(0)]],
device uint *output[[buffer(2)]])
{
ANGLE_KERNEL_GUARD(idx, options.vertexCountFrom3rd);
uint vertexIdx = options.firstVertex + 2 + idx;
output[3 * idx] = options.firstVertex;
output[3 * idx + 1] = vertexIdx - 1;
output[3 * idx + 2] = vertexIdx;
}
inline uint getIndexU32(uint offset,
uint idx,
constant uchar *inputU8[[function_constant(kUseSourceBufferU8)]],
constant ushort *inputU16[[function_constant(kUseSourceBufferU16)]],
constant uint *inputU32[[function_constant(kUseSourceBufferU32)]])
{
if (kUseSourceBufferU8)
{
if (kSourceIndexIsU16)
{
return getIndexUnalignedU16(inputU8, offset, idx);
}
else if (kSourceIndexIsU32)
{
return getIndexUnalignedU32(inputU8, offset, idx);
}
return getIndexAligned(inputU8, offset, idx);
}
else if (kUseSourceBufferU16)
{
return getIndexAligned(inputU16, offset, idx);
}
else if (kUseSourceBufferU32)
{
return getIndexAligned(inputU32, offset, idx);
}
return 0;
}
// Generate triangle fan indices from an indices buffer. indexCount options indicates number
// of indices starting from the 3rd.
kernel void genTriFanIndicesFromElements(
uint idx[[thread_position_in_grid]],
constant IndexConversionParams &options[[buffer(0)]],
constant uchar *inputU8[[ buffer(1), function_constant(kUseSourceBufferU8) ]],
constant ushort *inputU16[[ buffer(1), function_constant(kUseSourceBufferU16) ]],
constant uint *inputU32[[ buffer(1), function_constant(kUseSourceBufferU32) ]],
device uint *output[[buffer(2)]])
{
ANGLE_IDX_CONVERSION_GUARD(idx, options);
uint elemIdx = 2 + idx;
output[3 * idx] = getIndexU32(options.srcOffset, 0, inputU8, inputU16, inputU32);
output[3 * idx + 1] = getIndexU32(options.srcOffset, elemIdx - 1, inputU8, inputU16, inputU32);
output[3 * idx + 2] = getIndexU32(options.srcOffset, elemIdx, inputU8, inputU16, inputU32);
}