// // 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. // // common.h: Common header for other metal source code. #ifndef LIBANGLE_RENDERER_METAL_SHADERS_COMMON_H_ #define LIBANGLE_RENDERER_METAL_SHADERS_COMMON_H_ // clang-format off #ifndef SKIP_STD_HEADERS @@# include @@# include #endif #include "constants.h" #define ANGLE_KERNEL_GUARD(IDX, MAX_COUNT) \ if (IDX >= MAX_COUNT) \ { \ return; \ } using namespace metal; // clang-format on // Common constant defined number of color outputs constant uint32_t kNumColorOutputs [[function_constant(0)]]; constant bool kColorOutputAvailable0 = kNumColorOutputs > 0; constant bool kColorOutputAvailable1 = kNumColorOutputs > 1; constant bool kColorOutputAvailable2 = kNumColorOutputs > 2; constant bool kColorOutputAvailable3 = kNumColorOutputs > 3; namespace rx { namespace mtl_shader { // Full screen triangle's vertices constant float2 gCorners[3] = {float2(-1.0f, -1.0f), float2(3.0f, -1.0f), float2(-1.0f, 3.0f)}; template struct MultipleColorOutputs { vec color0 [[color(0), function_constant(kColorOutputAvailable0)]]; vec color1 [[color(1), function_constant(kColorOutputAvailable1)]]; vec color2 [[color(2), function_constant(kColorOutputAvailable2)]]; vec color3 [[color(3), function_constant(kColorOutputAvailable3)]]; }; #define ANGLE_ASSIGN_COLOR_OUPUT(STRUCT_VARIABLE, COLOR_INDEX, VALUE) \ do \ { \ if (kColorOutputAvailable##COLOR_INDEX) \ { \ STRUCT_VARIABLE.color##COLOR_INDEX = VALUE; \ } \ } while (0) template static inline MultipleColorOutputs toMultipleColorOutputs(vec color) { MultipleColorOutputs re; ANGLE_ASSIGN_COLOR_OUPUT(re, 0, color); ANGLE_ASSIGN_COLOR_OUPUT(re, 1, color); ANGLE_ASSIGN_COLOR_OUPUT(re, 2, color); ANGLE_ASSIGN_COLOR_OUPUT(re, 3, color); return re; } static inline float3 cubeTexcoords(float2 texcoords, int face) { texcoords = 2.0 * texcoords - 1.0; switch (face) { case 0: return float3(1.0, -texcoords.y, -texcoords.x); case 1: return float3(-1.0, -texcoords.y, texcoords.x); case 2: return float3(texcoords.x, 1.0, texcoords.y); case 3: return float3(texcoords.x, -1.0, -texcoords.y); case 4: return float3(texcoords.x, -texcoords.y, 1.0); case 5: return float3(-texcoords.x, -texcoords.y, -1.0); } return float3(texcoords, 0); } template static inline vec resolveTextureMS(texture2d_ms srcTexture, uint2 coords) { uint samples = srcTexture.get_num_samples(); vec output(0); for (uint sample = 0; sample < samples; ++sample) { output += srcTexture.read(coords, sample); } output = output / samples; return output; } static inline float4 sRGBtoLinear(float4 color) { float3 linear1 = color.rgb / 12.92; float3 linear2 = pow((color.rgb + float3(0.055)) / 1.055, 2.4); float3 factor = float3(color.rgb <= float3(0.04045)); float4 linear = float4(factor * linear1 + float3(1.0 - factor) * linear2, color.a); return linear; } static inline float linearToSRGB(float color) { if (color <= 0.0f) return 0.0f; else if (color < 0.0031308f) return 12.92f * color; else if (color < 1.0f) return 1.055f * pow(color, 0.41666f) - 0.055f; else return 1.0f; } static inline float4 linearToSRGB(float4 color) { return float4(linearToSRGB(color.r), linearToSRGB(color.g), linearToSRGB(color.b), color.a); } template static inline Short bytesToShort(constant uchar *input, uint offset) { Short inputLo = input[offset]; Short inputHi = input[offset + 1]; // Little endian conversion: return inputLo | (inputHi << 8); } template static inline Int bytesToInt(constant uchar *input, uint offset) { Int input0 = input[offset]; Int input1 = input[offset + 1]; Int input2 = input[offset + 2]; Int input3 = input[offset + 3]; // Little endian conversion: return input0 | (input1 << 8) | (input2 << 16) | (input3 << 24); } template static inline void shortToBytes(Short val, uint offset, device uchar *output) { ushort valUnsigned = as_type(val); output[offset] = valUnsigned & 0xff; output[offset + 1] = (valUnsigned >> 8) & 0xff; } template static inline void intToBytes(Int val, uint offset, device uchar *output) { uint valUnsigned = as_type(val); output[offset] = valUnsigned & 0xff; output[offset + 1] = (valUnsigned >> 8) & 0xff; output[offset + 2] = (valUnsigned >> 16) & 0xff; output[offset + 3] = (valUnsigned >> 24) & 0xff; } static inline void floatToBytes(float val, uint offset, device uchar *output) { intToBytes(as_type(val), offset, output); } static inline void int24bitToBytes(uint val, uint offset, device uchar *output) { output[offset] = val & 0xff; output[offset + 1] = (val >> 8) & 0xff; output[offset + 2] = (val >> 16) & 0xff; } template static inline T getShiftedData(T input) { static_assert(inputBitCount + inputBitStart <= (sizeof(T) * 8), "T must have at least as many bits as inputBitCount + inputBitStart."); const T mask = (1 << inputBitCount) - 1; return (input >> inputBitStart) & mask; } template static inline T shiftData(T input) { static_assert(inputBitCount + inputBitStart <= (sizeof(T) * 8), "T must have at least as many bits as inputBitCount + inputBitStart."); const T mask = (1 << inputBitCount) - 1; return (input & mask) << inputBitStart; } template static inline float normalizedToFloat(T input) { static_assert(inputBitCount <= (sizeof(T) * 8), "T must have more bits than or same bits as inputBitCount."); static_assert(inputBitCount <= 23, "Only single precision is supported"); constexpr float inverseMax = 1.0f / ((1 << inputBitCount) - 1); return input * inverseMax; } template static inline float normalizedToFloat(T input) { return normalizedToFloat(input); } template <> inline float normalizedToFloat(short input) { constexpr float inverseMax = 1.0f / 0x7fff; return static_cast(input) * inverseMax; } template <> inline float normalizedToFloat(int input) { constexpr float inverseMax = 1.0f / 0x7fffffff; return static_cast(input) * inverseMax; } template <> inline float normalizedToFloat(uint input) { constexpr float inverseMax = 1.0f / 0xffffffff; return static_cast(input) * inverseMax; } template static inline T floatToNormalized(float input) { static_assert(outputBitCount <= (sizeof(T) * 8), "T must have more bits than or same bits as inputBitCount."); static_assert(outputBitCount <= 23, "Only single precision is supported"); return static_cast(((1 << outputBitCount) - 1) * input + 0.5f); } template static inline T floatToNormalized(float input) { return floatToNormalized(input); } } // namespace mtl_shader } // namespace rx #endif /* LIBANGLE_RENDERER_METAL_SHADERS_COMMON_H_ */