diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /gfx/angle/checkout/src/image_util | |
parent | Initial commit. (diff) | |
download | firefox-esr-upstream.tar.xz firefox-esr-upstream.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/angle/checkout/src/image_util')
-rw-r--r-- | gfx/angle/checkout/src/image_util/copyimage.cpp | 74 | ||||
-rw-r--r-- | gfx/angle/checkout/src/image_util/copyimage.h | 46 | ||||
-rw-r--r-- | gfx/angle/checkout/src/image_util/copyimage.inc | 38 | ||||
-rw-r--r-- | gfx/angle/checkout/src/image_util/generatemip.h | 34 | ||||
-rw-r--r-- | gfx/angle/checkout/src/image_util/generatemip.inc | 268 | ||||
-rw-r--r-- | gfx/angle/checkout/src/image_util/imageformats.cpp | 1954 | ||||
-rw-r--r-- | gfx/angle/checkout/src/image_util/imageformats.h | 816 | ||||
-rw-r--r-- | gfx/angle/checkout/src/image_util/loadimage.cpp | 1796 | ||||
-rw-r--r-- | gfx/angle/checkout/src/image_util/loadimage.h | 976 | ||||
-rw-r--r-- | gfx/angle/checkout/src/image_util/loadimage.inc | 201 | ||||
-rw-r--r-- | gfx/angle/checkout/src/image_util/loadimage_astc.cpp | 84 | ||||
-rw-r--r-- | gfx/angle/checkout/src/image_util/loadimage_etc.cpp | 1994 | ||||
-rw-r--r-- | gfx/angle/checkout/src/image_util/loadimage_paletted.cpp | 158 |
13 files changed, 8439 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/image_util/copyimage.cpp b/gfx/angle/checkout/src/image_util/copyimage.cpp new file mode 100644 index 0000000000..b5c2773e21 --- /dev/null +++ b/gfx/angle/checkout/src/image_util/copyimage.cpp @@ -0,0 +1,74 @@ +// +// Copyright 2013 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. +// + +// copyimage.cpp: Defines image copying functions + +#include "image_util/copyimage.h" + +namespace angle +{ + +namespace +{ +inline uint32_t SwizzleBGRAToRGBA(uint32_t argb) +{ + return ((argb & 0x000000FF) << 16) | // Move BGRA blue to RGBA blue + ((argb & 0x00FF0000) >> 16) | // Move BGRA red to RGBA red + ((argb & 0xFF00FF00)); // Keep alpha and green +} + +void CopyBGRA8ToRGBA8Fast(const uint8_t *source, + int srcYAxisPitch, + uint8_t *dest, + int destYAxisPitch, + int destWidth, + int destHeight) +{ + for (int y = 0; y < destHeight; ++y) + { + const uint32_t *src32 = reinterpret_cast<const uint32_t *>(source + y * srcYAxisPitch); + uint32_t *dest32 = reinterpret_cast<uint32_t *>(dest + y * destYAxisPitch); + const uint32_t *end32 = src32 + destWidth; + while (src32 != end32) + { + *dest32++ = SwizzleBGRAToRGBA(*src32++); + } + } +} +} // namespace + +void CopyBGRA8ToRGBA8(const uint8_t *source, + int srcXAxisPitch, + int srcYAxisPitch, + uint8_t *dest, + int destXAxisPitch, + int destYAxisPitch, + int destWidth, + int destHeight) +{ + if (srcXAxisPitch == 4 && destXAxisPitch == 4) + { + CopyBGRA8ToRGBA8Fast(source, srcYAxisPitch, dest, destYAxisPitch, destWidth, destHeight); + return; + } + + for (int y = 0; y < destHeight; ++y) + { + uint8_t *dst = dest + y * destYAxisPitch; + const uint8_t *src = source + y * srcYAxisPitch; + const uint8_t *end = src + destWidth * srcXAxisPitch; + + while (src != end) + { + *reinterpret_cast<uint32_t *>(dst) = + SwizzleBGRAToRGBA(*reinterpret_cast<const uint32_t *>(src)); + src += srcXAxisPitch; + dst += destXAxisPitch; + } + } +} + +} // namespace angle diff --git a/gfx/angle/checkout/src/image_util/copyimage.h b/gfx/angle/checkout/src/image_util/copyimage.h new file mode 100644 index 0000000000..9825b86f98 --- /dev/null +++ b/gfx/angle/checkout/src/image_util/copyimage.h @@ -0,0 +1,46 @@ +// +// Copyright 2013 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. +// + +// copyimage.h: Defines image copying functions + +#ifndef IMAGEUTIL_COPYIMAGE_H_ +#define IMAGEUTIL_COPYIMAGE_H_ + +#include "common/Color.h" + +#include "image_util/imageformats.h" + +#include <stdint.h> + +namespace angle +{ + +template <typename sourceType, typename colorDataType> +void ReadColor(const uint8_t *source, uint8_t *dest); + +template <typename destType, typename colorDataType> +void WriteColor(const uint8_t *source, uint8_t *dest); + +template <typename SourceType> +void ReadDepthStencil(const uint8_t *source, uint8_t *dest); + +template <typename DestType> +void WriteDepthStencil(const uint8_t *source, uint8_t *dest); + +void CopyBGRA8ToRGBA8(const uint8_t *source, + int srcXAxisPitch, + int srcYAxisPitch, + uint8_t *dest, + int destXAxisPitch, + int destYAxisPitch, + int destWidth, + int destHeight); + +} // namespace angle + +#include "copyimage.inc" + +#endif // IMAGEUTIL_COPYIMAGE_H_ diff --git a/gfx/angle/checkout/src/image_util/copyimage.inc b/gfx/angle/checkout/src/image_util/copyimage.inc new file mode 100644 index 0000000000..42ad6b9421 --- /dev/null +++ b/gfx/angle/checkout/src/image_util/copyimage.inc @@ -0,0 +1,38 @@ +// +// Copyright 2014 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. +// + +// copyimage.inc: Defines image copying functions + +namespace angle +{ +template <typename sourceType, typename colorDataType> +void ReadColor(const uint8_t *source, uint8_t *dest) +{ + sourceType::readColor(reinterpret_cast<Color<colorDataType>*>(dest), + reinterpret_cast<const sourceType*>(source)); +} + +template <typename destType, typename colorDataType> +void WriteColor(const uint8_t *source, uint8_t *dest) +{ + destType::writeColor(reinterpret_cast<destType*>(dest), + reinterpret_cast<const Color<colorDataType>*>(source)); +} + +template <typename SourceType> +void ReadDepthStencil(const uint8_t *source, uint8_t *dest) +{ + SourceType::ReadDepthStencil(reinterpret_cast<DepthStencil *>(dest), + reinterpret_cast<const SourceType *>(source)); +} + +template <typename DestType> +void WriteDepthStencil(const uint8_t *source, uint8_t *dest) +{ + DestType::WriteDepthStencil(reinterpret_cast<DestType *>(dest), + reinterpret_cast<const DepthStencil *>(source)); +} +} // namespace angle diff --git a/gfx/angle/checkout/src/image_util/generatemip.h b/gfx/angle/checkout/src/image_util/generatemip.h new file mode 100644 index 0000000000..523c296298 --- /dev/null +++ b/gfx/angle/checkout/src/image_util/generatemip.h @@ -0,0 +1,34 @@ +// +// Copyright 2002 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. +// + +// generatemip.h: Defines the GenerateMip function, templated on the format +// type of the image for which mip levels are being generated. + +#ifndef IMAGEUTIL_GENERATEMIP_H_ +#define IMAGEUTIL_GENERATEMIP_H_ + +#include <stddef.h> +#include <stdint.h> + +namespace angle +{ + +template <typename T> +inline void GenerateMip(size_t sourceWidth, + size_t sourceHeight, + size_t sourceDepth, + const uint8_t *sourceData, + size_t sourceRowPitch, + size_t sourceDepthPitch, + uint8_t *destData, + size_t destRowPitch, + size_t destDepthPitch); + +} // namespace angle + +#include "generatemip.inc" + +#endif // IMAGEUTIL_GENERATEMIP_H_ diff --git a/gfx/angle/checkout/src/image_util/generatemip.inc b/gfx/angle/checkout/src/image_util/generatemip.inc new file mode 100644 index 0000000000..7a7f5abe9c --- /dev/null +++ b/gfx/angle/checkout/src/image_util/generatemip.inc @@ -0,0 +1,268 @@ +// +// Copyright 2015 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. +// + +// generatemip.inc: Defines the GenerateMip function, templated on the format +// type of the image for which mip levels are being generated. + +#include "common/mathutil.h" + +#include "image_util/imageformats.h" + +namespace angle +{ + +namespace priv +{ + +template <typename T> +static inline T *GetPixel(uint8_t *data, size_t x, size_t y, size_t z, size_t rowPitch, size_t depthPitch) +{ + return reinterpret_cast<T*>(data + (x * sizeof(T)) + (y * rowPitch) + (z * depthPitch)); +} + +template <typename T> +static inline const T *GetPixel(const uint8_t *data, size_t x, size_t y, size_t z, size_t rowPitch, size_t depthPitch) +{ + return reinterpret_cast<const T*>(data + (x * sizeof(T)) + (y * rowPitch) + (z * depthPitch)); +} + +template <typename T> +static void GenerateMip_Y(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth == 1); + ASSERT(sourceHeight > 1); + ASSERT(sourceDepth == 1); + + for (size_t y = 0; y < destHeight; y++) + { + const T *src0 = GetPixel<T>(sourceData, 0, y * 2, 0, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel<T>(sourceData, 0, y * 2 + 1, 0, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel<T>(destData, 0, y, 0, destRowPitch, destDepthPitch); + + T::average(dst, src0, src1); + } +} + +template <typename T> +static void GenerateMip_X(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth > 1); + ASSERT(sourceHeight == 1); + ASSERT(sourceDepth == 1); + + for (size_t x = 0; x < destWidth; x++) + { + const T *src0 = GetPixel<T>(sourceData, x * 2, 0, 0, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel<T>(sourceData, x * 2 + 1, 0, 0, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel<T>(destData, x, 0, 0, destRowPitch, destDepthPitch); + + T::average(dst, src0, src1); + } +} + +template <typename T> +static void GenerateMip_Z(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth == 1); + ASSERT(sourceHeight == 1); + ASSERT(sourceDepth > 1); + + for (size_t z = 0; z < destDepth; z++) + { + const T *src0 = GetPixel<T>(sourceData, 0, 0, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel<T>(sourceData, 0, 0, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel<T>(destData, 0, 0, z, destRowPitch, destDepthPitch); + + T::average(dst, src0, src1); + } +} + +template <typename T> +static void GenerateMip_XY(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth > 1); + ASSERT(sourceHeight > 1); + ASSERT(sourceDepth == 1); + + for (size_t y = 0; y < destHeight; y++) + { + for (size_t x = 0; x < destWidth; x++) + { + const T *src0 = GetPixel<T>(sourceData, x * 2, y * 2, 0, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel<T>(sourceData, x * 2, y * 2 + 1, 0, sourceRowPitch, sourceDepthPitch); + const T *src2 = GetPixel<T>(sourceData, x * 2 + 1, y * 2, 0, sourceRowPitch, sourceDepthPitch); + const T *src3 = GetPixel<T>(sourceData, x * 2 + 1, y * 2 + 1, 0, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel<T>(destData, x, y, 0, destRowPitch, destDepthPitch); + + T tmp0, tmp1; + + T::average(&tmp0, src0, src1); + T::average(&tmp1, src2, src3); + T::average(dst, &tmp0, &tmp1); + } + } +} + +template <typename T> +static void GenerateMip_YZ(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth == 1); + ASSERT(sourceHeight > 1); + ASSERT(sourceDepth > 1); + + for (size_t z = 0; z < destDepth; z++) + { + for (size_t y = 0; y < destHeight; y++) + { + const T *src0 = GetPixel<T>(sourceData, 0, y * 2, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel<T>(sourceData, 0, y * 2, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + const T *src2 = GetPixel<T>(sourceData, 0, y * 2 + 1, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src3 = GetPixel<T>(sourceData, 0, y * 2 + 1, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel<T>(destData, 0, y, z, destRowPitch, destDepthPitch); + + T tmp0, tmp1; + + T::average(&tmp0, src0, src1); + T::average(&tmp1, src2, src3); + T::average(dst, &tmp0, &tmp1); + } + } +} + +template <typename T> +static void GenerateMip_XZ(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth > 1); + ASSERT(sourceHeight == 1); + ASSERT(sourceDepth > 1); + + for (size_t z = 0; z < destDepth; z++) + { + for (size_t x = 0; x < destWidth; x++) + { + const T *src0 = GetPixel<T>(sourceData, x * 2, 0, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel<T>(sourceData, x * 2, 0, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + const T *src2 = GetPixel<T>(sourceData, x * 2 + 1, 0, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src3 = GetPixel<T>(sourceData, x * 2 + 1, 0, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel<T>(destData, x, 0, z, destRowPitch, destDepthPitch); + + T tmp0, tmp1; + + T::average(&tmp0, src0, src1); + T::average(&tmp1, src2, src3); + T::average(dst, &tmp0, &tmp1); + } + } +} + +template <typename T> +static void GenerateMip_XYZ(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth > 1); + ASSERT(sourceHeight > 1); + ASSERT(sourceDepth > 1); + + for (size_t z = 0; z < destDepth; z++) + { + for (size_t y = 0; y < destHeight; y++) + { + for (size_t x = 0; x < destWidth; x++) + { + const T *src0 = GetPixel<T>(sourceData, x * 2, y * 2, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel<T>(sourceData, x * 2, y * 2, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + const T *src2 = GetPixel<T>(sourceData, x * 2, y * 2 + 1, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src3 = GetPixel<T>(sourceData, x * 2, y * 2 + 1, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + const T *src4 = GetPixel<T>(sourceData, x * 2 + 1, y * 2, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src5 = GetPixel<T>(sourceData, x * 2 + 1, y * 2, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + const T *src6 = GetPixel<T>(sourceData, x * 2 + 1, y * 2 + 1, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src7 = GetPixel<T>(sourceData, x * 2 + 1, y * 2 + 1, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel<T>(destData, x, y, z, destRowPitch, destDepthPitch); + + T tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + + T::average(&tmp0, src0, src1); + T::average(&tmp1, src2, src3); + T::average(&tmp2, src4, src5); + T::average(&tmp3, src6, src7); + + T::average(&tmp4, &tmp0, &tmp1); + T::average(&tmp5, &tmp2, &tmp3); + + T::average(dst, &tmp4, &tmp5); + } + } + } +} + + +typedef void (*MipGenerationFunction)(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch); + +template <typename T> +static MipGenerationFunction GetMipGenerationFunction(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth) +{ + uint8_t index = ((sourceWidth > 1) ? 1 : 0) | + ((sourceHeight > 1) ? 2 : 0) | + ((sourceDepth > 1) ? 4 : 0); + + switch (index) + { + case 0: return nullptr; + case 1: return GenerateMip_X<T>; // W x 1 x 1 + case 2: return GenerateMip_Y<T>; // 1 x H x 1 + case 3: return GenerateMip_XY<T>; // W x H x 1 + case 4: return GenerateMip_Z<T>; // 1 x 1 x D + case 5: return GenerateMip_XZ<T>; // W x 1 x D + case 6: return GenerateMip_YZ<T>; // 1 x H x D + case 7: return GenerateMip_XYZ<T>; // W x H x D + } + + UNREACHABLE(); + return nullptr; +} + +} // namespace priv + +template <typename T> +inline void GenerateMip(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + size_t mipWidth = std::max<size_t>(1, sourceWidth >> 1); + size_t mipHeight = std::max<size_t>(1, sourceHeight >> 1); + size_t mipDepth = std::max<size_t>(1, sourceDepth >> 1); + + priv::MipGenerationFunction generationFunction = priv::GetMipGenerationFunction<T>(sourceWidth, sourceHeight, sourceDepth); + ASSERT(generationFunction != nullptr); + + generationFunction(sourceWidth, sourceHeight, sourceDepth, sourceData, sourceRowPitch, sourceDepthPitch, + mipWidth, mipHeight, mipDepth, destData, destRowPitch, destDepthPitch); +} + +} // namespace angle diff --git a/gfx/angle/checkout/src/image_util/imageformats.cpp b/gfx/angle/checkout/src/image_util/imageformats.cpp new file mode 100644 index 0000000000..368b6d95d7 --- /dev/null +++ b/gfx/angle/checkout/src/image_util/imageformats.cpp @@ -0,0 +1,1954 @@ +// +// Copyright 2016 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. +// + +// imageformats.cpp: Defines image format types with functions for mip generation +// and copying. + +#include "image_util/imageformats.h" + +#include "common/mathutil.h" + +namespace angle +{ + +void L8::readColor(gl::ColorF *dst, const L8 *src) +{ + const float lum = gl::normalizedToFloat(src->L); + dst->red = lum; + dst->green = lum; + dst->blue = lum; + dst->alpha = 1.0f; +} + +void L8::writeColor(L8 *dst, const gl::ColorF *src) +{ + dst->L = gl::floatToNormalized<uint8_t>(src->red); +} + +void L8::average(L8 *dst, const L8 *src1, const L8 *src2) +{ + dst->L = gl::average(src1->L, src2->L); +} + +void R8::readColor(gl::ColorUI *dst, const R8 *src) +{ + dst->red = src->R; + dst->green = 0; + dst->blue = 0; + dst->alpha = 1; +} + +void R8::readColor(gl::ColorF *dst, const R8 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R8::writeColor(R8 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast<uint8_t>(src->red); +} + +void R8::writeColor(R8 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<uint8_t>(src->red); +} + +void R8::average(R8 *dst, const R8 *src1, const R8 *src2) +{ + dst->R = gl::average(src1->R, src2->R); +} + +void A8::readColor(gl::ColorF *dst, const A8 *src) +{ + dst->red = 0.0f; + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = gl::normalizedToFloat(src->A); +} + +void A8::writeColor(A8 *dst, const gl::ColorF *src) +{ + dst->A = gl::floatToNormalized<uint8_t>(src->alpha); +} + +void A8::average(A8 *dst, const A8 *src1, const A8 *src2) +{ + dst->A = gl::average(src1->A, src2->A); +} + +void L8A8::readColor(gl::ColorF *dst, const L8A8 *src) +{ + const float lum = gl::normalizedToFloat(src->L); + dst->red = lum; + dst->green = lum; + dst->blue = lum; + dst->alpha = gl::normalizedToFloat(src->A); +} + +void L8A8::writeColor(L8A8 *dst, const gl::ColorF *src) +{ + dst->L = gl::floatToNormalized<uint8_t>(src->red); + dst->A = gl::floatToNormalized<uint8_t>(src->alpha); +} + +void L8A8::average(L8A8 *dst, const L8A8 *src1, const L8A8 *src2) +{ + *(uint16_t *)dst = (((*(uint16_t *)src1 ^ *(uint16_t *)src2) & 0xFEFE) >> 1) + + (*(uint16_t *)src1 & *(uint16_t *)src2); +} + +void A8L8::readColor(gl::ColorF *dst, const A8L8 *src) +{ + const float lum = gl::normalizedToFloat(src->L); + dst->red = lum; + dst->green = lum; + dst->blue = lum; + dst->alpha = gl::normalizedToFloat(src->A); +} + +void A8L8::writeColor(A8L8 *dst, const gl::ColorF *src) +{ + dst->L = gl::floatToNormalized<uint8_t>(src->red); + dst->A = gl::floatToNormalized<uint8_t>(src->alpha); +} + +void A8L8::average(A8L8 *dst, const A8L8 *src1, const A8L8 *src2) +{ + *(uint16_t *)dst = (((*(uint16_t *)src1 ^ *(uint16_t *)src2) & 0xFEFE) >> 1) + + (*(uint16_t *)src1 & *(uint16_t *)src2); +} + +void R8G8::readColor(gl::ColorUI *dst, const R8G8 *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = 0; + dst->alpha = 1; +} + +void R8G8::readColor(gl::ColorF *dst, const R8G8 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R8G8::writeColor(R8G8 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast<uint8_t>(src->red); + dst->G = static_cast<uint8_t>(src->green); +} + +void R8G8::writeColor(R8G8 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<uint8_t>(src->red); + dst->G = gl::floatToNormalized<uint8_t>(src->green); +} + +void R8G8::average(R8G8 *dst, const R8G8 *src1, const R8G8 *src2) +{ + *(uint16_t *)dst = (((*(uint16_t *)src1 ^ *(uint16_t *)src2) & 0xFEFE) >> 1) + + (*(uint16_t *)src1 & *(uint16_t *)src2); +} + +void R8G8B8::readColor(gl::ColorUI *dst, const R8G8B8 *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->G; + dst->alpha = 1; +} + +void R8G8B8::readColor(gl::ColorF *dst, const R8G8B8 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; +} + +void R8G8B8::writeColor(R8G8B8 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast<uint8_t>(src->red); + dst->G = static_cast<uint8_t>(src->green); + dst->B = static_cast<uint8_t>(src->blue); +} + +void R8G8B8::writeColor(R8G8B8 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<uint8_t>(src->red); + dst->G = gl::floatToNormalized<uint8_t>(src->green); + dst->B = gl::floatToNormalized<uint8_t>(src->blue); +} + +void R8G8B8::average(R8G8B8 *dst, const R8G8B8 *src1, const R8G8B8 *src2) +{ + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); +} + +void B8G8R8::readColor(gl::ColorUI *dst, const B8G8R8 *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->G; + dst->alpha = 1; +} + +void B8G8R8::readColor(gl::ColorF *dst, const B8G8R8 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; +} + +void B8G8R8::writeColor(B8G8R8 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast<uint8_t>(src->red); + dst->G = static_cast<uint8_t>(src->green); + dst->B = static_cast<uint8_t>(src->blue); +} + +void B8G8R8::writeColor(B8G8R8 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<uint8_t>(src->red); + dst->G = gl::floatToNormalized<uint8_t>(src->green); + dst->B = gl::floatToNormalized<uint8_t>(src->blue); +} + +void B8G8R8::average(B8G8R8 *dst, const B8G8R8 *src1, const B8G8R8 *src2) +{ + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); +} + +void R5G6B5::readColor(gl::ColorF *dst, const R5G6B5 *src) +{ + dst->red = gl::normalizedToFloat<5>(gl::getShiftedData<5, 11>(src->RGB)); + dst->green = gl::normalizedToFloat<6>(gl::getShiftedData<6, 5>(src->RGB)); + dst->blue = gl::normalizedToFloat<5>(gl::getShiftedData<5, 0>(src->RGB)); + dst->alpha = 1.0f; +} + +void R5G6B5::writeColor(R5G6B5 *dst, const gl::ColorF *src) +{ + dst->RGB = gl::shiftData<5, 11>(gl::floatToNormalized<5, uint16_t>(src->red)) | + gl::shiftData<6, 5>(gl::floatToNormalized<6, uint16_t>(src->green)) | + gl::shiftData<5, 0>(gl::floatToNormalized<5, uint16_t>(src->blue)); +} + +void R5G6B5::average(R5G6B5 *dst, const R5G6B5 *src1, const R5G6B5 *src2) +{ + dst->RGB = gl::shiftData<5, 11>(gl::average(gl::getShiftedData<5, 11>(src1->RGB), + gl::getShiftedData<5, 11>(src2->RGB))) | + gl::shiftData<6, 5>(gl::average(gl::getShiftedData<6, 5>(src1->RGB), + gl::getShiftedData<6, 5>(src2->RGB))) | + gl::shiftData<5, 0>(gl::average(gl::getShiftedData<5, 0>(src1->RGB), + gl::getShiftedData<5, 0>(src2->RGB))); +} + +void B5G6R5::readColor(gl::ColorF *dst, const B5G6R5 *src) +{ + dst->red = gl::normalizedToFloat<5>(gl::getShiftedData<5, 11>(src->BGR)); + dst->green = gl::normalizedToFloat<6>(gl::getShiftedData<6, 5>(src->BGR)); + dst->blue = gl::normalizedToFloat<5>(gl::getShiftedData<5, 0>(src->BGR)); + dst->alpha = 1.0f; +} + +void B5G6R5::writeColor(B5G6R5 *dst, const gl::ColorF *src) +{ + dst->BGR = gl::shiftData<5, 0>(gl::floatToNormalized<5, unsigned short>(src->blue)) | + gl::shiftData<6, 5>(gl::floatToNormalized<6, unsigned short>(src->green)) | + gl::shiftData<5, 11>(gl::floatToNormalized<5, unsigned short>(src->red)); +} + +void B5G6R5::average(B5G6R5 *dst, const B5G6R5 *src1, const B5G6R5 *src2) +{ + dst->BGR = gl::shiftData<5, 11>(gl::average(gl::getShiftedData<5, 11>(src1->BGR), + gl::getShiftedData<5, 11>(src2->BGR))) | + gl::shiftData<6, 5>(gl::average(gl::getShiftedData<6, 5>(src1->BGR), + gl::getShiftedData<6, 5>(src2->BGR))) | + gl::shiftData<5, 0>(gl::average(gl::getShiftedData<5, 0>(src1->BGR), + gl::getShiftedData<5, 0>(src2->BGR))); +} + +void A8R8G8B8::readColor(gl::ColorUI *dst, const A8R8G8B8 *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; +} + +void A8R8G8B8::readColor(gl::ColorF *dst, const A8R8G8B8 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); +} + +void A8R8G8B8::writeColor(A8R8G8B8 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast<uint8_t>(src->red); + dst->G = static_cast<uint8_t>(src->green); + dst->B = static_cast<uint8_t>(src->blue); + dst->A = static_cast<uint8_t>(src->alpha); +} + +void A8R8G8B8::writeColor(A8R8G8B8 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<uint8_t>(src->red); + dst->G = gl::floatToNormalized<uint8_t>(src->green); + dst->B = gl::floatToNormalized<uint8_t>(src->blue); + dst->A = gl::floatToNormalized<uint8_t>(src->alpha); +} + +void A8R8G8B8::average(A8R8G8B8 *dst, const A8R8G8B8 *src1, const A8R8G8B8 *src2) +{ + *(uint32_t *)dst = (((*(uint32_t *)src1 ^ *(uint32_t *)src2) & 0xFEFEFEFE) >> 1) + + (*(uint32_t *)src1 & *(uint32_t *)src2); +} + +void R8G8B8A8::readColor(gl::ColorUI *dst, const R8G8B8A8 *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; +} + +void R8G8B8A8::readColor(gl::ColorF *dst, const R8G8B8A8 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); +} + +void R8G8B8A8::writeColor(R8G8B8A8 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast<uint8_t>(src->red); + dst->G = static_cast<uint8_t>(src->green); + dst->B = static_cast<uint8_t>(src->blue); + dst->A = static_cast<uint8_t>(src->alpha); +} + +void R8G8B8A8::writeColor(R8G8B8A8 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<uint8_t>(src->red); + dst->G = gl::floatToNormalized<uint8_t>(src->green); + dst->B = gl::floatToNormalized<uint8_t>(src->blue); + dst->A = gl::floatToNormalized<uint8_t>(src->alpha); +} + +void R8G8B8A8::average(R8G8B8A8 *dst, const R8G8B8A8 *src1, const R8G8B8A8 *src2) +{ + *(uint32_t *)dst = (((*(uint32_t *)src1 ^ *(uint32_t *)src2) & 0xFEFEFEFE) >> 1) + + (*(uint32_t *)src1 & *(uint32_t *)src2); +} + +void R8G8B8A8SRGB::readColor(gl::ColorF *dst, const R8G8B8A8SRGB *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); +} + +void R8G8B8A8SRGB::writeColor(R8G8B8A8SRGB *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<uint8_t>(src->red); + dst->G = gl::floatToNormalized<uint8_t>(src->green); + dst->B = gl::floatToNormalized<uint8_t>(src->blue); + dst->A = gl::floatToNormalized<uint8_t>(src->alpha); +} + +void R8G8B8A8SRGB::average(R8G8B8A8SRGB *dst, const R8G8B8A8SRGB *src1, const R8G8B8A8SRGB *src2) +{ + dst->R = + gl::linearToSRGB(static_cast<uint8_t>((static_cast<uint16_t>(gl::sRGBToLinear(src1->R)) + + static_cast<uint16_t>(gl::sRGBToLinear(src2->R))) >> + 1)); + dst->G = + gl::linearToSRGB(static_cast<uint8_t>((static_cast<uint16_t>(gl::sRGBToLinear(src1->G)) + + static_cast<uint16_t>(gl::sRGBToLinear(src2->G))) >> + 1)); + dst->B = + gl::linearToSRGB(static_cast<uint8_t>((static_cast<uint16_t>(gl::sRGBToLinear(src1->B)) + + static_cast<uint16_t>(gl::sRGBToLinear(src2->B))) >> + 1)); + dst->A = static_cast<uint8_t>( + (static_cast<uint16_t>(src1->A) + static_cast<uint16_t>(src2->A)) >> 1); +} + +void B8G8R8A8::readColor(gl::ColorUI *dst, const B8G8R8A8 *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; +} + +void B8G8R8A8::readColor(gl::ColorF *dst, const B8G8R8A8 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); +} + +void B8G8R8A8::writeColor(B8G8R8A8 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast<uint8_t>(src->red); + dst->G = static_cast<uint8_t>(src->green); + dst->B = static_cast<uint8_t>(src->blue); + dst->A = static_cast<uint8_t>(src->alpha); +} + +void B8G8R8A8::writeColor(B8G8R8A8 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<uint8_t>(src->red); + dst->G = gl::floatToNormalized<uint8_t>(src->green); + dst->B = gl::floatToNormalized<uint8_t>(src->blue); + dst->A = gl::floatToNormalized<uint8_t>(src->alpha); +} + +void B8G8R8A8::average(B8G8R8A8 *dst, const B8G8R8A8 *src1, const B8G8R8A8 *src2) +{ + *(uint32_t *)dst = (((*(uint32_t *)src1 ^ *(uint32_t *)src2) & 0xFEFEFEFE) >> 1) + + (*(uint32_t *)src1 & *(uint32_t *)src2); +} + +void B8G8R8X8::readColor(gl::ColorUI *dst, const B8G8R8X8 *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1; +} + +void B8G8R8X8::readColor(gl::ColorF *dst, const B8G8R8X8 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; +} + +void B8G8R8X8::writeColor(B8G8R8X8 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast<uint8_t>(src->red); + dst->G = static_cast<uint8_t>(src->green); + dst->B = static_cast<uint8_t>(src->blue); + dst->X = 255; +} + +void B8G8R8X8::writeColor(B8G8R8X8 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<uint8_t>(src->red); + dst->G = gl::floatToNormalized<uint8_t>(src->green); + dst->B = gl::floatToNormalized<uint8_t>(src->blue); + dst->X = 255; +} + +void B8G8R8X8::average(B8G8R8X8 *dst, const B8G8R8X8 *src1, const B8G8R8X8 *src2) +{ + *(uint32_t *)dst = (((*(uint32_t *)src1 ^ *(uint32_t *)src2) & 0xFEFEFEFE) >> 1) + + (*(uint32_t *)src1 & *(uint32_t *)src2); + dst->X = 255; +} + +void R8G8B8X8::readColor(gl::ColorUI *dst, const R8G8B8X8 *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1; +} + +void R8G8B8X8::readColor(gl::ColorF *dst, const R8G8B8X8 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; +} + +void R8G8B8X8::writeColor(R8G8B8X8 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast<uint8_t>(src->red); + dst->G = static_cast<uint8_t>(src->green); + dst->B = static_cast<uint8_t>(src->blue); + dst->X = 255; +} + +void R8G8B8X8::writeColor(R8G8B8X8 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<uint8_t>(src->red); + dst->G = gl::floatToNormalized<uint8_t>(src->green); + dst->B = gl::floatToNormalized<uint8_t>(src->blue); + dst->X = 255; +} + +void R8G8B8X8::average(R8G8B8X8 *dst, const R8G8B8X8 *src1, const R8G8B8X8 *src2) +{ + *(uint32_t *)dst = (((*(uint32_t *)src1 ^ *(uint32_t *)src2) & 0xFEFEFEFE) >> 1) + + (*(uint32_t *)src1 & *(uint32_t *)src2); + dst->X = 255; +} + +void A1R5G5B5::readColor(gl::ColorF *dst, const A1R5G5B5 *src) +{ + dst->alpha = gl::normalizedToFloat<1>(gl::getShiftedData<1, 15>(src->ARGB)); + dst->red = gl::normalizedToFloat<5>(gl::getShiftedData<5, 10>(src->ARGB)); + dst->green = gl::normalizedToFloat<5>(gl::getShiftedData<5, 5>(src->ARGB)); + dst->blue = gl::normalizedToFloat<5>(gl::getShiftedData<5, 0>(src->ARGB)); +} + +void A1R5G5B5::writeColor(A1R5G5B5 *dst, const gl::ColorF *src) +{ + dst->ARGB = gl::shiftData<1, 15>(gl::floatToNormalized<1, uint16_t>(src->alpha)) | + gl::shiftData<5, 10>(gl::floatToNormalized<5, uint16_t>(src->red)) | + gl::shiftData<5, 5>(gl::floatToNormalized<5, uint16_t>(src->green)) | + gl::shiftData<5, 0>(gl::floatToNormalized<5, uint16_t>(src->blue)); +} + +void A1R5G5B5::average(A1R5G5B5 *dst, const A1R5G5B5 *src1, const A1R5G5B5 *src2) +{ + dst->ARGB = gl::shiftData<1, 15>(gl::average(gl::getShiftedData<1, 15>(src1->ARGB), + gl::getShiftedData<1, 15>(src2->ARGB))) | + gl::shiftData<5, 10>(gl::average(gl::getShiftedData<5, 10>(src1->ARGB), + gl::getShiftedData<5, 10>(src2->ARGB))) | + gl::shiftData<5, 5>(gl::average(gl::getShiftedData<5, 5>(src1->ARGB), + gl::getShiftedData<5, 5>(src2->ARGB))) | + gl::shiftData<5, 0>(gl::average(gl::getShiftedData<5, 0>(src1->ARGB), + gl::getShiftedData<5, 0>(src2->ARGB))); +} + +void R5G5B5A1::readColor(gl::ColorF *dst, const R5G5B5A1 *src) +{ + dst->red = gl::normalizedToFloat<5>(gl::getShiftedData<5, 11>(src->RGBA)); + dst->green = gl::normalizedToFloat<5>(gl::getShiftedData<5, 6>(src->RGBA)); + dst->blue = gl::normalizedToFloat<5>(gl::getShiftedData<5, 1>(src->RGBA)); + dst->alpha = gl::normalizedToFloat<1>(gl::getShiftedData<1, 0>(src->RGBA)); +} + +void R5G5B5A1::writeColor(R5G5B5A1 *dst, const gl::ColorF *src) +{ + dst->RGBA = gl::shiftData<5, 11>(gl::floatToNormalized<5, uint16_t>(src->red)) | + gl::shiftData<5, 6>(gl::floatToNormalized<5, uint16_t>(src->green)) | + gl::shiftData<5, 1>(gl::floatToNormalized<5, uint16_t>(src->blue)) | + gl::shiftData<1, 0>(gl::floatToNormalized<1, uint16_t>(src->alpha)); +} + +void R5G5B5A1::average(R5G5B5A1 *dst, const R5G5B5A1 *src1, const R5G5B5A1 *src2) +{ + dst->RGBA = gl::shiftData<5, 11>(gl::average(gl::getShiftedData<5, 11>(src1->RGBA), + gl::getShiftedData<5, 11>(src2->RGBA))) | + gl::shiftData<5, 6>(gl::average(gl::getShiftedData<5, 6>(src1->RGBA), + gl::getShiftedData<5, 6>(src2->RGBA))) | + gl::shiftData<5, 1>(gl::average(gl::getShiftedData<5, 1>(src1->RGBA), + gl::getShiftedData<5, 1>(src2->RGBA))) | + gl::shiftData<1, 0>(gl::average(gl::getShiftedData<1, 0>(src1->RGBA), + gl::getShiftedData<1, 0>(src2->RGBA))); +} + +void R4G4B4A4::readColor(gl::ColorF *dst, const R4G4B4A4 *src) +{ + dst->red = gl::normalizedToFloat<4>(gl::getShiftedData<4, 12>(src->RGBA)); + dst->green = gl::normalizedToFloat<4>(gl::getShiftedData<4, 8>(src->RGBA)); + dst->blue = gl::normalizedToFloat<4>(gl::getShiftedData<4, 4>(src->RGBA)); + dst->alpha = gl::normalizedToFloat<4>(gl::getShiftedData<4, 0>(src->RGBA)); +} + +void R4G4B4A4::writeColor(R4G4B4A4 *dst, const gl::ColorF *src) +{ + dst->RGBA = gl::shiftData<4, 12>(gl::floatToNormalized<4, uint16_t>(src->red)) | + gl::shiftData<4, 8>(gl::floatToNormalized<4, uint16_t>(src->green)) | + gl::shiftData<4, 4>(gl::floatToNormalized<4, uint16_t>(src->blue)) | + gl::shiftData<4, 0>(gl::floatToNormalized<4, uint16_t>(src->alpha)); +} + +void R4G4B4A4::average(R4G4B4A4 *dst, const R4G4B4A4 *src1, const R4G4B4A4 *src2) +{ + dst->RGBA = gl::shiftData<4, 12>(gl::average(gl::getShiftedData<4, 12>(src1->RGBA), + gl::getShiftedData<4, 12>(src2->RGBA))) | + gl::shiftData<4, 8>(gl::average(gl::getShiftedData<4, 8>(src1->RGBA), + gl::getShiftedData<4, 8>(src2->RGBA))) | + gl::shiftData<4, 4>(gl::average(gl::getShiftedData<4, 4>(src1->RGBA), + gl::getShiftedData<4, 4>(src2->RGBA))) | + gl::shiftData<4, 0>(gl::average(gl::getShiftedData<4, 0>(src1->RGBA), + gl::getShiftedData<4, 0>(src2->RGBA))); +} + +void A4R4G4B4::readColor(gl::ColorF *dst, const A4R4G4B4 *src) +{ + dst->alpha = gl::normalizedToFloat<4>(gl::getShiftedData<4, 12>(src->ARGB)); + dst->red = gl::normalizedToFloat<4>(gl::getShiftedData<4, 8>(src->ARGB)); + dst->green = gl::normalizedToFloat<4>(gl::getShiftedData<4, 4>(src->ARGB)); + dst->blue = gl::normalizedToFloat<4>(gl::getShiftedData<4, 0>(src->ARGB)); +} + +void A4R4G4B4::writeColor(A4R4G4B4 *dst, const gl::ColorF *src) +{ + dst->ARGB = gl::shiftData<4, 12>(gl::floatToNormalized<4, uint16_t>(src->alpha)) | + gl::shiftData<4, 8>(gl::floatToNormalized<4, uint16_t>(src->red)) | + gl::shiftData<4, 4>(gl::floatToNormalized<4, uint16_t>(src->green)) | + gl::shiftData<4, 0>(gl::floatToNormalized<4, uint16_t>(src->blue)); +} + +void A4R4G4B4::average(A4R4G4B4 *dst, const A4R4G4B4 *src1, const A4R4G4B4 *src2) +{ + dst->ARGB = gl::shiftData<4, 12>(gl::average(gl::getShiftedData<4, 12>(src1->ARGB), + gl::getShiftedData<4, 12>(src2->ARGB))) | + gl::shiftData<4, 8>(gl::average(gl::getShiftedData<4, 8>(src1->ARGB), + gl::getShiftedData<4, 8>(src2->ARGB))) | + gl::shiftData<4, 4>(gl::average(gl::getShiftedData<4, 4>(src1->ARGB), + gl::getShiftedData<4, 4>(src2->ARGB))) | + gl::shiftData<4, 0>(gl::average(gl::getShiftedData<4, 0>(src1->ARGB), + gl::getShiftedData<4, 0>(src2->ARGB))); +} + +void R16::readColor(gl::ColorUI *dst, const R16 *src) +{ + dst->red = src->R; + dst->green = 0; + dst->blue = 0; + dst->alpha = 1; +} + +void R16::readColor(gl::ColorF *dst, const R16 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R16::writeColor(R16 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast<uint16_t>(src->red); +} + +void R16::writeColor(R16 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<uint16_t>(src->red); +} + +void R16::average(R16 *dst, const R16 *src1, const R16 *src2) +{ + dst->R = gl::average(src1->R, src2->R); +} + +void R16G16::readColor(gl::ColorUI *dst, const R16G16 *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = 0; + dst->alpha = 1; +} + +void R16G16::readColor(gl::ColorF *dst, const R16G16 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R16G16::writeColor(R16G16 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast<uint16_t>(src->red); + dst->G = static_cast<uint16_t>(src->green); +} + +void R16G16::writeColor(R16G16 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<uint16_t>(src->red); + dst->G = gl::floatToNormalized<uint16_t>(src->green); +} + +void R16G16::average(R16G16 *dst, const R16G16 *src1, const R16G16 *src2) +{ + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); +} + +void R16G16B16::readColor(gl::ColorUI *dst, const R16G16B16 *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1; +} + +void R16G16B16::readColor(gl::ColorF *dst, const R16G16B16 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; +} + +void R16G16B16::writeColor(R16G16B16 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast<uint16_t>(src->red); + dst->G = static_cast<uint16_t>(src->green); + dst->B = static_cast<uint16_t>(src->blue); +} + +void R16G16B16::writeColor(R16G16B16 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<uint16_t>(src->red); + dst->G = gl::floatToNormalized<uint16_t>(src->green); + dst->B = gl::floatToNormalized<uint16_t>(src->blue); +} + +void R16G16B16::average(R16G16B16 *dst, const R16G16B16 *src1, const R16G16B16 *src2) +{ + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); +} + +void R16G16B16A16::readColor(gl::ColorUI *dst, const R16G16B16A16 *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; +} + +void R16G16B16A16::readColor(gl::ColorF *dst, const R16G16B16A16 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); +} + +void R16G16B16A16::writeColor(R16G16B16A16 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast<uint16_t>(src->red); + dst->G = static_cast<uint16_t>(src->green); + dst->B = static_cast<uint16_t>(src->blue); + dst->A = static_cast<uint16_t>(src->alpha); +} + +void R16G16B16A16::writeColor(R16G16B16A16 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<uint16_t>(src->red); + dst->G = gl::floatToNormalized<uint16_t>(src->green); + dst->B = gl::floatToNormalized<uint16_t>(src->blue); + dst->A = gl::floatToNormalized<uint16_t>(src->alpha); +} + +void R16G16B16A16::average(R16G16B16A16 *dst, const R16G16B16A16 *src1, const R16G16B16A16 *src2) +{ + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); +} + +void R32::readColor(gl::ColorUI *dst, const R32 *src) +{ + dst->red = src->R; + dst->green = 0; + dst->blue = 0; + dst->alpha = 1; +} + +void R32::readColor(gl::ColorF *dst, const R32 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R32::writeColor(R32 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast<uint32_t>(src->red); +} + +void R32::writeColor(R32 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<uint32_t>(src->red); +} + +void R32::average(R32 *dst, const R32 *src1, const R32 *src2) +{ + dst->R = gl::average(src1->R, src2->R); +} + +void R32G32::readColor(gl::ColorUI *dst, const R32G32 *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = 0; + dst->alpha = 1; +} + +void R32G32::readColor(gl::ColorF *dst, const R32G32 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R32G32::writeColor(R32G32 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast<uint32_t>(src->red); + dst->G = static_cast<uint32_t>(src->green); +} + +void R32G32::writeColor(R32G32 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<uint32_t>(src->red); + dst->G = gl::floatToNormalized<uint32_t>(src->green); +} + +void R32G32::average(R32G32 *dst, const R32G32 *src1, const R32G32 *src2) +{ + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); +} + +void R32G32B32::readColor(gl::ColorUI *dst, const R32G32B32 *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1; +} + +void R32G32B32::readColor(gl::ColorF *dst, const R32G32B32 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; +} + +void R32G32B32::writeColor(R32G32B32 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast<uint32_t>(src->red); + dst->G = static_cast<uint32_t>(src->green); + dst->B = static_cast<uint32_t>(src->blue); +} + +void R32G32B32::writeColor(R32G32B32 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<uint32_t>(src->red); + dst->G = gl::floatToNormalized<uint32_t>(src->green); + dst->B = gl::floatToNormalized<uint32_t>(src->blue); +} + +void R32G32B32::average(R32G32B32 *dst, const R32G32B32 *src1, const R32G32B32 *src2) +{ + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); +} + +void R32G32B32A32::readColor(gl::ColorUI *dst, const R32G32B32A32 *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; +} + +void R32G32B32A32::readColor(gl::ColorF *dst, const R32G32B32A32 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); +} + +void R32G32B32A32::writeColor(R32G32B32A32 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast<uint32_t>(src->red); + dst->G = static_cast<uint32_t>(src->green); + dst->B = static_cast<uint32_t>(src->blue); + dst->A = static_cast<uint32_t>(src->alpha); +} + +void R32G32B32A32::writeColor(R32G32B32A32 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<uint32_t>(src->red); + dst->G = gl::floatToNormalized<uint32_t>(src->green); + dst->B = gl::floatToNormalized<uint32_t>(src->blue); + dst->A = gl::floatToNormalized<uint32_t>(src->alpha); +} + +void R32G32B32A32::average(R32G32B32A32 *dst, const R32G32B32A32 *src1, const R32G32B32A32 *src2) +{ + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); +} + +void R8S::readColor(gl::ColorI *dst, const R8S *src) +{ + dst->red = src->R; + dst->green = 0; + dst->blue = 0; + dst->alpha = 1; +} + +void R8S::readColor(gl::ColorF *dst, const R8S *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R8S::writeColor(R8S *dst, const gl::ColorI *src) +{ + dst->R = static_cast<int8_t>(src->red); +} + +void R8S::writeColor(R8S *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<int8_t>(src->red); +} + +void R8S::average(R8S *dst, const R8S *src1, const R8S *src2) +{ + dst->R = static_cast<int8_t>(gl::average(src1->R, src2->R)); +} + +void R8G8S::readColor(gl::ColorI *dst, const R8G8S *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = 0; + dst->alpha = 1; +} + +void R8G8S::readColor(gl::ColorF *dst, const R8G8S *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R8G8S::writeColor(R8G8S *dst, const gl::ColorI *src) +{ + dst->R = static_cast<int8_t>(src->red); + dst->G = static_cast<int8_t>(src->green); +} + +void R8G8S::writeColor(R8G8S *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<int8_t>(src->red); + dst->G = gl::floatToNormalized<int8_t>(src->green); +} + +void R8G8S::average(R8G8S *dst, const R8G8S *src1, const R8G8S *src2) +{ + dst->R = static_cast<int8_t>(gl::average(src1->R, src2->R)); + dst->G = static_cast<int8_t>(gl::average(src1->G, src2->G)); +} + +void R8G8B8S::readColor(gl::ColorI *dst, const R8G8B8S *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1; +} + +void R8G8B8S::readColor(gl::ColorF *dst, const R8G8B8S *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; +} + +void R8G8B8S::writeColor(R8G8B8S *dst, const gl::ColorI *src) +{ + dst->R = static_cast<int8_t>(src->red); + dst->G = static_cast<int8_t>(src->green); + dst->B = static_cast<int8_t>(src->blue); +} + +void R8G8B8S::writeColor(R8G8B8S *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<int8_t>(src->red); + dst->G = gl::floatToNormalized<int8_t>(src->green); + dst->B = gl::floatToNormalized<int8_t>(src->blue); +} + +void R8G8B8S::average(R8G8B8S *dst, const R8G8B8S *src1, const R8G8B8S *src2) +{ + dst->R = static_cast<int8_t>(gl::average(src1->R, src2->R)); + dst->G = static_cast<int8_t>(gl::average(src1->G, src2->G)); + dst->B = static_cast<int8_t>(gl::average(src1->B, src2->B)); +} + +void R8G8B8A8S::readColor(gl::ColorI *dst, const R8G8B8A8S *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; +} + +void R8G8B8A8S::readColor(gl::ColorF *dst, const R8G8B8A8S *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); +} + +void R8G8B8A8S::writeColor(R8G8B8A8S *dst, const gl::ColorI *src) +{ + dst->R = static_cast<int8_t>(src->red); + dst->G = static_cast<int8_t>(src->green); + dst->B = static_cast<int8_t>(src->blue); + dst->A = static_cast<int8_t>(src->alpha); +} + +void R8G8B8A8S::writeColor(R8G8B8A8S *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<int8_t>(src->red); + dst->G = gl::floatToNormalized<int8_t>(src->green); + dst->B = gl::floatToNormalized<int8_t>(src->blue); + dst->A = gl::floatToNormalized<int8_t>(src->alpha); +} + +void R8G8B8A8S::average(R8G8B8A8S *dst, const R8G8B8A8S *src1, const R8G8B8A8S *src2) +{ + dst->R = static_cast<int8_t>(gl::average(src1->R, src2->R)); + dst->G = static_cast<int8_t>(gl::average(src1->G, src2->G)); + dst->B = static_cast<int8_t>(gl::average(src1->B, src2->B)); + dst->A = static_cast<int8_t>(gl::average(src1->A, src2->A)); +} + +void R16S::readColor(gl::ColorI *dst, const R16S *src) +{ + dst->red = src->R; + dst->green = 0; + dst->blue = 0; + dst->alpha = 1; +} + +void R16S::readColor(gl::ColorF *dst, const R16S *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R16S::writeColor(R16S *dst, const gl::ColorI *src) +{ + dst->R = static_cast<int16_t>(src->red); +} + +void R16S::writeColor(R16S *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<int16_t>(src->red); +} + +void R16S::average(R16S *dst, const R16S *src1, const R16S *src2) +{ + dst->R = gl::average(src1->R, src2->R); +} + +void R16G16S::readColor(gl::ColorI *dst, const R16G16S *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = 0; + dst->alpha = 1; +} + +void R16G16S::readColor(gl::ColorF *dst, const R16G16S *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R16G16S::writeColor(R16G16S *dst, const gl::ColorI *src) +{ + dst->R = static_cast<int16_t>(src->red); + dst->G = static_cast<int16_t>(src->green); +} + +void R16G16S::writeColor(R16G16S *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<int16_t>(src->red); + dst->G = gl::floatToNormalized<int16_t>(src->green); +} + +void R16G16S::average(R16G16S *dst, const R16G16S *src1, const R16G16S *src2) +{ + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); +} + +void R16G16B16S::readColor(gl::ColorI *dst, const R16G16B16S *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1; +} + +void R16G16B16S::readColor(gl::ColorF *dst, const R16G16B16S *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; +} + +void R16G16B16S::writeColor(R16G16B16S *dst, const gl::ColorI *src) +{ + dst->R = static_cast<int16_t>(src->red); + dst->G = static_cast<int16_t>(src->green); + dst->B = static_cast<int16_t>(src->blue); +} + +void R16G16B16S::writeColor(R16G16B16S *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<int16_t>(src->red); + dst->G = gl::floatToNormalized<int16_t>(src->green); + dst->B = gl::floatToNormalized<int16_t>(src->blue); +} + +void R16G16B16S::average(R16G16B16S *dst, const R16G16B16S *src1, const R16G16B16S *src2) +{ + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); +} + +void R16G16B16A16S::readColor(gl::ColorI *dst, const R16G16B16A16S *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; +} + +void R16G16B16A16S::readColor(gl::ColorF *dst, const R16G16B16A16S *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); +} + +void R16G16B16A16S::writeColor(R16G16B16A16S *dst, const gl::ColorI *src) +{ + dst->R = static_cast<int16_t>(src->red); + dst->G = static_cast<int16_t>(src->green); + dst->B = static_cast<int16_t>(src->blue); + dst->A = static_cast<int16_t>(src->alpha); +} + +void R16G16B16A16S::writeColor(R16G16B16A16S *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<int16_t>(src->red); + dst->G = gl::floatToNormalized<int16_t>(src->green); + dst->B = gl::floatToNormalized<int16_t>(src->blue); + dst->A = gl::floatToNormalized<int16_t>(src->alpha); +} + +void R16G16B16A16S::average(R16G16B16A16S *dst, + const R16G16B16A16S *src1, + const R16G16B16A16S *src2) +{ + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); +} + +void R32S::readColor(gl::ColorI *dst, const R32S *src) +{ + dst->red = src->R; + dst->green = 0; + dst->blue = 0; + dst->alpha = 1; +} + +void R32S::readColor(gl::ColorF *dst, const R32S *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R32S::writeColor(R32S *dst, const gl::ColorI *src) +{ + dst->R = static_cast<int32_t>(src->red); +} + +void R32S::writeColor(R32S *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<int32_t>(src->red); +} + +void R32S::average(R32S *dst, const R32S *src1, const R32S *src2) +{ + dst->R = gl::average(src1->R, src2->R); +} + +void R32G32S::readColor(gl::ColorI *dst, const R32G32S *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = 0; + dst->alpha = 1; +} + +void R32G32S::readColor(gl::ColorF *dst, const R32G32S *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R32G32S::writeColor(R32G32S *dst, const gl::ColorI *src) +{ + dst->R = static_cast<int32_t>(src->red); + dst->G = static_cast<int32_t>(src->green); +} + +void R32G32S::writeColor(R32G32S *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<int32_t>(src->red); + dst->G = gl::floatToNormalized<int32_t>(src->green); +} + +void R32G32S::average(R32G32S *dst, const R32G32S *src1, const R32G32S *src2) +{ + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); +} + +void R32G32B32S::readColor(gl::ColorI *dst, const R32G32B32S *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1; +} + +void R32G32B32S::readColor(gl::ColorF *dst, const R32G32B32S *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; +} + +void R32G32B32S::writeColor(R32G32B32S *dst, const gl::ColorI *src) +{ + dst->R = static_cast<int32_t>(src->red); + dst->G = static_cast<int32_t>(src->green); + dst->B = static_cast<int32_t>(src->blue); +} + +void R32G32B32S::writeColor(R32G32B32S *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<int32_t>(src->red); + dst->G = gl::floatToNormalized<int32_t>(src->green); + dst->B = gl::floatToNormalized<int32_t>(src->blue); +} + +void R32G32B32S::average(R32G32B32S *dst, const R32G32B32S *src1, const R32G32B32S *src2) +{ + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); +} + +void R32G32B32A32S::readColor(gl::ColorI *dst, const R32G32B32A32S *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; +} + +void R32G32B32A32S::readColor(gl::ColorF *dst, const R32G32B32A32S *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); +} + +void R32G32B32A32S::writeColor(R32G32B32A32S *dst, const gl::ColorI *src) +{ + dst->R = static_cast<int32_t>(src->red); + dst->G = static_cast<int32_t>(src->green); + dst->B = static_cast<int32_t>(src->blue); + dst->A = static_cast<int32_t>(src->alpha); +} + +void R32G32B32A32S::writeColor(R32G32B32A32S *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<int32_t>(src->red); + dst->G = gl::floatToNormalized<int32_t>(src->green); + dst->B = gl::floatToNormalized<int32_t>(src->blue); + dst->A = gl::floatToNormalized<int32_t>(src->alpha); +} + +void R32G32B32A32S::average(R32G32B32A32S *dst, + const R32G32B32A32S *src1, + const R32G32B32A32S *src2) +{ + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); +} + +void A16B16G16R16F::readColor(gl::ColorF *dst, const A16B16G16R16F *src) +{ + dst->red = gl::float16ToFloat32(src->R); + dst->green = gl::float16ToFloat32(src->G); + dst->blue = gl::float16ToFloat32(src->B); + dst->alpha = gl::float16ToFloat32(src->A); +} + +void A16B16G16R16F::writeColor(A16B16G16R16F *dst, const gl::ColorF *src) +{ + dst->R = gl::float32ToFloat16(src->red); + dst->G = gl::float32ToFloat16(src->green); + dst->B = gl::float32ToFloat16(src->blue); + dst->A = gl::float32ToFloat16(src->alpha); +} + +void A16B16G16R16F::average(A16B16G16R16F *dst, + const A16B16G16R16F *src1, + const A16B16G16R16F *src2) +{ + dst->R = gl::averageHalfFloat(src1->R, src2->R); + dst->G = gl::averageHalfFloat(src1->G, src2->G); + dst->B = gl::averageHalfFloat(src1->B, src2->B); + dst->A = gl::averageHalfFloat(src1->A, src2->A); +} + +void R16G16B16A16F::readColor(gl::ColorF *dst, const R16G16B16A16F *src) +{ + dst->red = gl::float16ToFloat32(src->R); + dst->green = gl::float16ToFloat32(src->G); + dst->blue = gl::float16ToFloat32(src->B); + dst->alpha = gl::float16ToFloat32(src->A); +} + +void R16G16B16A16F::writeColor(R16G16B16A16F *dst, const gl::ColorF *src) +{ + dst->R = gl::float32ToFloat16(src->red); + dst->G = gl::float32ToFloat16(src->green); + dst->B = gl::float32ToFloat16(src->blue); + dst->A = gl::float32ToFloat16(src->alpha); +} + +void R16G16B16A16F::average(R16G16B16A16F *dst, + const R16G16B16A16F *src1, + const R16G16B16A16F *src2) +{ + dst->R = gl::averageHalfFloat(src1->R, src2->R); + dst->G = gl::averageHalfFloat(src1->G, src2->G); + dst->B = gl::averageHalfFloat(src1->B, src2->B); + dst->A = gl::averageHalfFloat(src1->A, src2->A); +} + +void R16F::readColor(gl::ColorF *dst, const R16F *src) +{ + dst->red = gl::float16ToFloat32(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R16F::writeColor(R16F *dst, const gl::ColorF *src) +{ + dst->R = gl::float32ToFloat16(src->red); +} + +void R16F::average(R16F *dst, const R16F *src1, const R16F *src2) +{ + dst->R = gl::averageHalfFloat(src1->R, src2->R); +} + +void A16F::readColor(gl::ColorF *dst, const A16F *src) +{ + dst->red = 0.0f; + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = gl::float16ToFloat32(src->A); +} + +void A16F::writeColor(A16F *dst, const gl::ColorF *src) +{ + dst->A = gl::float32ToFloat16(src->alpha); +} + +void A16F::average(A16F *dst, const A16F *src1, const A16F *src2) +{ + dst->A = gl::averageHalfFloat(src1->A, src2->A); +} + +void L16F::readColor(gl::ColorF *dst, const L16F *src) +{ + float lum = gl::float16ToFloat32(src->L); + dst->red = lum; + dst->green = lum; + dst->blue = lum; + dst->alpha = 1.0f; +} + +void L16F::writeColor(L16F *dst, const gl::ColorF *src) +{ + dst->L = gl::float32ToFloat16(src->red); +} + +void L16F::average(L16F *dst, const L16F *src1, const L16F *src2) +{ + dst->L = gl::averageHalfFloat(src1->L, src2->L); +} + +void L16A16F::readColor(gl::ColorF *dst, const L16A16F *src) +{ + float lum = gl::float16ToFloat32(src->L); + dst->red = lum; + dst->green = lum; + dst->blue = lum; + dst->alpha = gl::float16ToFloat32(src->A); +} + +void L16A16F::writeColor(L16A16F *dst, const gl::ColorF *src) +{ + dst->L = gl::float32ToFloat16(src->red); + dst->A = gl::float32ToFloat16(src->alpha); +} + +void L16A16F::average(L16A16F *dst, const L16A16F *src1, const L16A16F *src2) +{ + dst->L = gl::averageHalfFloat(src1->L, src2->L); + dst->A = gl::averageHalfFloat(src1->A, src2->A); +} + +void R16G16F::readColor(gl::ColorF *dst, const R16G16F *src) +{ + dst->red = gl::float16ToFloat32(src->R); + dst->green = gl::float16ToFloat32(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R16G16F::writeColor(R16G16F *dst, const gl::ColorF *src) +{ + dst->R = gl::float32ToFloat16(src->red); + dst->G = gl::float32ToFloat16(src->green); +} + +void R16G16F::average(R16G16F *dst, const R16G16F *src1, const R16G16F *src2) +{ + dst->R = gl::averageHalfFloat(src1->R, src2->R); + dst->G = gl::averageHalfFloat(src1->G, src2->G); +} + +void R16G16B16F::readColor(gl::ColorF *dst, const R16G16B16F *src) +{ + dst->red = gl::float16ToFloat32(src->R); + dst->green = gl::float16ToFloat32(src->G); + dst->blue = gl::float16ToFloat32(src->B); + dst->alpha = 1.0f; +} + +void R16G16B16F::writeColor(R16G16B16F *dst, const gl::ColorF *src) +{ + dst->R = gl::float32ToFloat16(src->red); + dst->G = gl::float32ToFloat16(src->green); + dst->B = gl::float32ToFloat16(src->blue); +} + +void R16G16B16F::average(R16G16B16F *dst, const R16G16B16F *src1, const R16G16B16F *src2) +{ + dst->R = gl::averageHalfFloat(src1->R, src2->R); + dst->G = gl::averageHalfFloat(src1->G, src2->G); + dst->B = gl::averageHalfFloat(src1->B, src2->B); +} + +void A32B32G32R32F::readColor(gl::ColorF *dst, const A32B32G32R32F *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; +} + +void A32B32G32R32F::writeColor(A32B32G32R32F *dst, const gl::ColorF *src) +{ + dst->R = src->red; + dst->G = src->green; + dst->B = src->blue; + dst->A = src->alpha; +} + +void A32B32G32R32F::average(A32B32G32R32F *dst, + const A32B32G32R32F *src1, + const A32B32G32R32F *src2) +{ + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); +} + +void R32G32B32A32F::readColor(gl::ColorF *dst, const R32G32B32A32F *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; +} + +void R32G32B32A32F::writeColor(R32G32B32A32F *dst, const gl::ColorF *src) +{ + dst->R = src->red; + dst->G = src->green; + dst->B = src->blue; + dst->A = src->alpha; +} + +void R32G32B32A32F::average(R32G32B32A32F *dst, + const R32G32B32A32F *src1, + const R32G32B32A32F *src2) +{ + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); +} + +void R32F::readColor(gl::ColorF *dst, const R32F *src) +{ + dst->red = src->R; + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R32F::writeColor(R32F *dst, const gl::ColorF *src) +{ + dst->R = src->red; +} + +void R32F::average(R32F *dst, const R32F *src1, const R32F *src2) +{ + dst->R = gl::average(src1->R, src2->R); +} + +void A32F::readColor(gl::ColorF *dst, const A32F *src) +{ + dst->red = 0.0f; + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = src->A; +} + +void A32F::writeColor(A32F *dst, const gl::ColorF *src) +{ + dst->A = src->alpha; +} + +void A32F::average(A32F *dst, const A32F *src1, const A32F *src2) +{ + dst->A = gl::average(src1->A, src2->A); +} + +void L32F::readColor(gl::ColorF *dst, const L32F *src) +{ + dst->red = src->L; + dst->green = src->L; + dst->blue = src->L; + dst->alpha = 1.0f; +} + +void L32F::writeColor(L32F *dst, const gl::ColorF *src) +{ + dst->L = src->red; +} + +void L32F::average(L32F *dst, const L32F *src1, const L32F *src2) +{ + dst->L = gl::average(src1->L, src2->L); +} + +void L32A32F::readColor(gl::ColorF *dst, const L32A32F *src) +{ + dst->red = src->L; + dst->green = src->L; + dst->blue = src->L; + dst->alpha = src->A; +} + +void L32A32F::writeColor(L32A32F *dst, const gl::ColorF *src) +{ + dst->L = src->red; + dst->A = src->alpha; +} + +void L32A32F::average(L32A32F *dst, const L32A32F *src1, const L32A32F *src2) +{ + dst->L = gl::average(src1->L, src2->L); + dst->A = gl::average(src1->A, src2->A); +} + +void R32G32F::readColor(gl::ColorF *dst, const R32G32F *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R32G32F::writeColor(R32G32F *dst, const gl::ColorF *src) +{ + dst->R = src->red; + dst->G = src->green; +} + +void R32G32F::average(R32G32F *dst, const R32G32F *src1, const R32G32F *src2) +{ + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); +} + +void R32G32B32F::readColor(gl::ColorF *dst, const R32G32B32F *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1.0f; +} + +void R32G32B32F::writeColor(R32G32B32F *dst, const gl::ColorF *src) +{ + dst->R = src->red; + dst->G = src->green; + dst->B = src->blue; +} + +void R32G32B32F::average(R32G32B32F *dst, const R32G32B32F *src1, const R32G32B32F *src2) +{ + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); +} + +void R10G10B10A2::readColor(gl::ColorUI *dst, const R10G10B10A2 *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; +} + +void R10G10B10A2::readColor(gl::ColorF *dst, const R10G10B10A2 *src) +{ + dst->red = gl::normalizedToFloat<10>(src->R); + dst->green = gl::normalizedToFloat<10>(src->G); + dst->blue = gl::normalizedToFloat<10>(src->B); + dst->alpha = gl::normalizedToFloat<2>(src->A); +} + +void R10G10B10A2::writeColor(R10G10B10A2 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast<uint32_t>(src->red); + dst->G = static_cast<uint32_t>(src->green); + dst->B = static_cast<uint32_t>(src->blue); + dst->A = static_cast<uint32_t>(src->alpha); +} + +void R10G10B10A2::writeColor(R10G10B10A2 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<10, uint32_t>(src->red); + dst->G = gl::floatToNormalized<10, uint32_t>(src->green); + dst->B = gl::floatToNormalized<10, uint32_t>(src->blue); + dst->A = gl::floatToNormalized<2, uint32_t>(src->alpha); +} + +void R10G10B10A2::average(R10G10B10A2 *dst, const R10G10B10A2 *src1, const R10G10B10A2 *src2) +{ + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); +} + +void R10G10B10A2S::readColor(gl::ColorI *dst, const R10G10B10A2S *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; +} + +void R10G10B10A2S::readColor(gl::ColorF *dst, const R10G10B10A2S *src) +{ + dst->red = gl::normalizedToFloat<10>(src->R); + dst->green = gl::normalizedToFloat<10>(src->G); + dst->blue = gl::normalizedToFloat<10>(src->B); + dst->alpha = gl::normalizedToFloat<2>(src->A); +} + +void R10G10B10A2S::writeColor(R10G10B10A2S *dst, const gl::ColorI *src) +{ + dst->R = static_cast<int32_t>(src->red); + dst->G = static_cast<int32_t>(src->green); + dst->B = static_cast<int32_t>(src->blue); + dst->A = static_cast<int32_t>(src->alpha); +} + +void R10G10B10A2S::writeColor(R10G10B10A2S *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<10, int32_t>(src->red); + dst->G = gl::floatToNormalized<10, int32_t>(src->green); + dst->B = gl::floatToNormalized<10, int32_t>(src->blue); + dst->A = gl::floatToNormalized<2, int32_t>(src->alpha); +} + +void R10G10B10A2S::average(R10G10B10A2S *dst, const R10G10B10A2S *src1, const R10G10B10A2S *src2) +{ + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); +} + +void R10G10B10X2::readColor(gl::ColorUI *dst, const R10G10B10X2 *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 0x3; +} + +void R10G10B10X2::readColor(gl::ColorF *dst, const R10G10B10X2 *src) +{ + dst->red = gl::normalizedToFloat<10>(src->R); + dst->green = gl::normalizedToFloat<10>(src->G); + dst->blue = gl::normalizedToFloat<10>(src->B); + dst->alpha = 1.0f; +} + +void R10G10B10X2::writeColor(R10G10B10X2 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast<uint32_t>(src->red); + dst->G = static_cast<uint32_t>(src->green); + dst->B = static_cast<uint32_t>(src->blue); +} + +void R10G10B10X2::writeColor(R10G10B10X2 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<10, uint32_t>(src->red); + dst->G = gl::floatToNormalized<10, uint32_t>(src->green); + dst->B = gl::floatToNormalized<10, uint32_t>(src->blue); +} + +void R10G10B10X2::average(R10G10B10X2 *dst, const R10G10B10X2 *src1, const R10G10B10X2 *src2) +{ + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); +} + +void B10G10R10A2::readColor(gl::ColorUI *dst, const B10G10R10A2 *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; +} + +void B10G10R10A2::readColor(gl::ColorF *dst, const B10G10R10A2 *src) +{ + dst->red = gl::normalizedToFloat<10>(src->R); + dst->green = gl::normalizedToFloat<10>(src->G); + dst->blue = gl::normalizedToFloat<10>(src->B); + dst->alpha = gl::normalizedToFloat<2>(src->A); +} + +void B10G10R10A2::writeColor(B10G10R10A2 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast<uint32_t>(src->red); + dst->G = static_cast<uint32_t>(src->green); + dst->B = static_cast<uint32_t>(src->blue); + dst->A = static_cast<uint32_t>(src->alpha); +} + +void B10G10R10A2::writeColor(B10G10R10A2 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<10, uint32_t>(src->red); + dst->G = gl::floatToNormalized<10, uint32_t>(src->green); + dst->B = gl::floatToNormalized<10, uint32_t>(src->blue); + dst->A = gl::floatToNormalized<2, uint32_t>(src->alpha); +} + +void B10G10R10A2::average(B10G10R10A2 *dst, const B10G10R10A2 *src1, const B10G10R10A2 *src2) +{ + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); +} + +void R9G9B9E5::readColor(gl::ColorF *dst, const R9G9B9E5 *src) +{ + gl::convert999E5toRGBFloats(gl::bitCast<uint32_t>(*src), &dst->red, &dst->green, &dst->blue); + dst->alpha = 1.0f; +} + +void R9G9B9E5::writeColor(R9G9B9E5 *dst, const gl::ColorF *src) +{ + *reinterpret_cast<uint32_t *>(dst) = + gl::convertRGBFloatsTo999E5(src->red, src->green, src->blue); +} + +void R9G9B9E5::average(R9G9B9E5 *dst, const R9G9B9E5 *src1, const R9G9B9E5 *src2) +{ + float r1, g1, b1; + gl::convert999E5toRGBFloats(*reinterpret_cast<const uint32_t *>(src1), &r1, &g1, &b1); + + float r2, g2, b2; + gl::convert999E5toRGBFloats(*reinterpret_cast<const uint32_t *>(src2), &r2, &g2, &b2); + + *reinterpret_cast<uint32_t *>(dst) = + gl::convertRGBFloatsTo999E5(gl::average(r1, r2), gl::average(g1, g2), gl::average(b1, b2)); +} + +void R11G11B10F::readColor(gl::ColorF *dst, const R11G11B10F *src) +{ + dst->red = gl::float11ToFloat32(src->R); + dst->green = gl::float11ToFloat32(src->G); + dst->blue = gl::float10ToFloat32(src->B); + dst->alpha = 1.0f; +} + +void R11G11B10F::writeColor(R11G11B10F *dst, const gl::ColorF *src) +{ + dst->R = gl::float32ToFloat11(src->red); + dst->G = gl::float32ToFloat11(src->green); + dst->B = gl::float32ToFloat10(src->blue); +} + +void R11G11B10F::average(R11G11B10F *dst, const R11G11B10F *src1, const R11G11B10F *src2) +{ + dst->R = gl::averageFloat11(src1->R, src2->R); + dst->G = gl::averageFloat11(src1->G, src2->G); + dst->B = gl::averageFloat10(src1->B, src2->B); +} + +void D24S8::ReadDepthStencil(DepthStencil *dst, const D24S8 *src) +{ + dst->depth = gl::normalizedToFloat<24>(src->D); + dst->stencil = src->S; +} + +void D24S8::WriteDepthStencil(D24S8 *dst, const DepthStencil *src) +{ + dst->D = gl::floatToNormalized<24, uint32_t>(static_cast<float>(src->depth)); + dst->S = src->stencil & 0xFF; +} + +void S8::ReadDepthStencil(DepthStencil *dst, const S8 *src) +{ + dst->depth = 0; + dst->stencil = src->S; +} + +void S8::WriteDepthStencil(S8 *dst, const DepthStencil *src) +{ + dst->S = src->stencil & 0xFF; +} + +void D16::ReadDepthStencil(DepthStencil *dst, const D16 *src) +{ + dst->depth = gl::normalizedToFloat(src->D); + dst->stencil = 0; +} + +void D16::WriteDepthStencil(D16 *dst, const DepthStencil *src) +{ + dst->D = gl::floatToNormalized<uint16_t>(static_cast<float>(src->depth)); +} + +void D24X8::ReadDepthStencil(DepthStencil *dst, const D24X8 *src) +{ + dst->depth = gl::normalizedToFloat<24>(src->D & 0x00ffffff); +} + +void D24X8::WriteDepthStencil(D24X8 *dst, const DepthStencil *src) +{ + dst->D = gl::floatToNormalized<24, uint32_t>(static_cast<float>(src->depth)); +} + +void D32F::ReadDepthStencil(DepthStencil *dst, const D32F *src) +{ + dst->depth = src->D; +} + +void D32F::WriteDepthStencil(D32F *dst, const DepthStencil *src) +{ + dst->D = static_cast<float>(src->depth); +} + +void D32::ReadDepthStencil(DepthStencil *dst, const D32 *src) +{ + dst->depth = gl::normalizedToFloat(src->D); + dst->stencil = 0; +} + +void D32::WriteDepthStencil(D32 *dst, const DepthStencil *src) +{ + dst->D = gl::floatToNormalized<uint32_t>(static_cast<float>(src->depth)); +} + +void D32FS8X24::ReadDepthStencil(DepthStencil *dst, const D32FS8X24 *src) +{ + dst->depth = src->D; + dst->stencil = src->S; +} + +void D32FS8X24::WriteDepthStencil(D32FS8X24 *dst, const DepthStencil *src) +{ + dst->D = static_cast<float>(src->depth); + dst->S = src->stencil & 0xFF; +} +} // namespace angle diff --git a/gfx/angle/checkout/src/image_util/imageformats.h b/gfx/angle/checkout/src/image_util/imageformats.h new file mode 100644 index 0000000000..58fe5fe1a2 --- /dev/null +++ b/gfx/angle/checkout/src/image_util/imageformats.h @@ -0,0 +1,816 @@ +// +// Copyright 2013 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. +// + +// imageformats.h: Defines image format types with functions for mip generation +// and copying. + +#ifndef IMAGEUTIL_IMAGEFORMATS_H_ +#define IMAGEUTIL_IMAGEFORMATS_H_ + +#include "common/Color.h" + +#include <cstdint> + +namespace angle +{ + +// Several structures share functionality for reading, writing or mipmapping but the layout +// must match the texture format which the structure represents. If collapsing or typedefing +// structs in this header, make sure the functionality and memory layout is exactly the same. + +struct L8 +{ + uint8_t L; + + static void readColor(gl::ColorF *dst, const L8 *src); + static void writeColor(L8 *dst, const gl::ColorF *src); + static void average(L8 *dst, const L8 *src1, const L8 *src2); +}; + +struct R8 +{ + uint8_t R; + + static void readColor(gl::ColorF *dst, const R8 *src); + static void readColor(gl::ColorUI *dst, const R8 *src); + static void writeColor(R8 *dst, const gl::ColorF *src); + static void writeColor(R8 *dst, const gl::ColorUI *src); + static void average(R8 *dst, const R8 *src1, const R8 *src2); +}; + +struct A8 +{ + uint8_t A; + + static void readColor(gl::ColorF *dst, const A8 *src); + static void writeColor(A8 *dst, const gl::ColorF *src); + static void average(A8 *dst, const A8 *src1, const A8 *src2); +}; + +struct L8A8 +{ + uint8_t L; + uint8_t A; + + static void readColor(gl::ColorF *dst, const L8A8 *src); + static void writeColor(L8A8 *dst, const gl::ColorF *src); + static void average(L8A8 *dst, const L8A8 *src1, const L8A8 *src2); +}; + +struct A8L8 +{ + uint8_t A; + uint8_t L; + + static void readColor(gl::ColorF *dst, const A8L8 *src); + static void writeColor(A8L8 *dst, const gl::ColorF *src); + static void average(A8L8 *dst, const A8L8 *src1, const A8L8 *src2); +}; + +struct R8G8 +{ + uint8_t R; + uint8_t G; + + static void readColor(gl::ColorF *dst, const R8G8 *src); + static void readColor(gl::ColorUI *dst, const R8G8 *src); + static void writeColor(R8G8 *dst, const gl::ColorF *src); + static void writeColor(R8G8 *dst, const gl::ColorUI *src); + static void average(R8G8 *dst, const R8G8 *src1, const R8G8 *src2); +}; + +struct R8G8B8 +{ + uint8_t R; + uint8_t G; + uint8_t B; + + static void readColor(gl::ColorF *dst, const R8G8B8 *src); + static void readColor(gl::ColorUI *dst, const R8G8B8 *src); + static void writeColor(R8G8B8 *dst, const gl::ColorF *src); + static void writeColor(R8G8B8 *dst, const gl::ColorUI *src); + static void average(R8G8B8 *dst, const R8G8B8 *src1, const R8G8B8 *src2); +}; + +struct B8G8R8 +{ + uint8_t B; + uint8_t G; + uint8_t R; + + static void readColor(gl::ColorF *dst, const B8G8R8 *src); + static void readColor(gl::ColorUI *dst, const B8G8R8 *src); + static void writeColor(B8G8R8 *dst, const gl::ColorF *src); + static void writeColor(B8G8R8 *dst, const gl::ColorUI *src); + static void average(B8G8R8 *dst, const B8G8R8 *src1, const B8G8R8 *src2); +}; + +struct R5G6B5 +{ + // OpenGL ES 2.0.25 spec Section 3.6.2: "Components are packed with the first component in the + // most significant bits of the bitfield, and successive component occupying progressively less + // significant locations" + uint16_t RGB; + + static void readColor(gl::ColorF *dst, const R5G6B5 *src); + static void writeColor(R5G6B5 *dst, const gl::ColorF *src); + static void average(R5G6B5 *dst, const R5G6B5 *src1, const R5G6B5 *src2); +}; + +struct B5G6R5 +{ + uint16_t BGR; + + static void readColor(gl::ColorF *dst, const B5G6R5 *src); + static void writeColor(B5G6R5 *dst, const gl::ColorF *src); + static void average(B5G6R5 *dst, const B5G6R5 *src1, const B5G6R5 *src2); +}; + +struct A8R8G8B8 +{ + uint8_t A; + uint8_t R; + uint8_t G; + uint8_t B; + + static void readColor(gl::ColorF *dst, const A8R8G8B8 *src); + static void readColor(gl::ColorUI *dst, const A8R8G8B8 *src); + static void writeColor(A8R8G8B8 *dst, const gl::ColorF *src); + static void writeColor(A8R8G8B8 *dst, const gl::ColorUI *src); + static void average(A8R8G8B8 *dst, const A8R8G8B8 *src1, const A8R8G8B8 *src2); +}; + +struct R8G8B8A8 +{ + uint8_t R; + uint8_t G; + uint8_t B; + uint8_t A; + + static void readColor(gl::ColorF *dst, const R8G8B8A8 *src); + static void readColor(gl::ColorUI *dst, const R8G8B8A8 *src); + static void writeColor(R8G8B8A8 *dst, const gl::ColorF *src); + static void writeColor(R8G8B8A8 *dst, const gl::ColorUI *src); + static void average(R8G8B8A8 *dst, const R8G8B8A8 *src1, const R8G8B8A8 *src2); +}; + +struct R8G8B8A8SRGB +{ + uint8_t R; + uint8_t G; + uint8_t B; + uint8_t A; + + static void readColor(gl::ColorF *dst, const R8G8B8A8SRGB *src); + static void writeColor(R8G8B8A8SRGB *dst, const gl::ColorF *src); + static void average(R8G8B8A8SRGB *dst, const R8G8B8A8SRGB *src1, const R8G8B8A8SRGB *src2); +}; + +struct B8G8R8A8 +{ + uint8_t B; + uint8_t G; + uint8_t R; + uint8_t A; + + static void readColor(gl::ColorF *dst, const B8G8R8A8 *src); + static void readColor(gl::ColorUI *dst, const B8G8R8A8 *src); + static void writeColor(B8G8R8A8 *dst, const gl::ColorF *src); + static void writeColor(B8G8R8A8 *dst, const gl::ColorUI *src); + static void average(B8G8R8A8 *dst, const B8G8R8A8 *src1, const B8G8R8A8 *src2); +}; + +struct B8G8R8X8 +{ + uint8_t B; + uint8_t G; + uint8_t R; + uint8_t X; + + static void readColor(gl::ColorF *dst, const B8G8R8X8 *src); + static void readColor(gl::ColorUI *dst, const B8G8R8X8 *src); + static void writeColor(B8G8R8X8 *dst, const gl::ColorF *src); + static void writeColor(B8G8R8X8 *dst, const gl::ColorUI *src); + static void average(B8G8R8X8 *dst, const B8G8R8X8 *src1, const B8G8R8X8 *src2); +}; + +struct R8G8B8X8 +{ + uint8_t R; + uint8_t G; + uint8_t B; + uint8_t X; + + static void readColor(gl::ColorF *dst, const R8G8B8X8 *src); + static void readColor(gl::ColorUI *dst, const R8G8B8X8 *src); + static void writeColor(R8G8B8X8 *dst, const gl::ColorF *src); + static void writeColor(R8G8B8X8 *dst, const gl::ColorUI *src); + static void average(R8G8B8X8 *dst, const R8G8B8X8 *src1, const R8G8B8X8 *src2); +}; + +struct A1R5G5B5 +{ + uint16_t ARGB; + + static void readColor(gl::ColorF *dst, const A1R5G5B5 *src); + static void writeColor(A1R5G5B5 *dst, const gl::ColorF *src); + static void average(A1R5G5B5 *dst, const A1R5G5B5 *src1, const A1R5G5B5 *src2); +}; + +struct R5G5B5A1 +{ + // OpenGL ES 2.0.25 spec Section 3.6.2: "Components are packed with the first component in the + // most significant + // bits of the bitfield, and successive component occupying progressively less significant + // locations" + uint16_t RGBA; + + static void readColor(gl::ColorF *dst, const R5G5B5A1 *src); + static void writeColor(R5G5B5A1 *dst, const gl::ColorF *src); + static void average(R5G5B5A1 *dst, const R5G5B5A1 *src1, const R5G5B5A1 *src2); +}; + +struct R4G4B4A4 +{ + // OpenGL ES 2.0.25 spec Section 3.6.2: "Components are packed with the first component in the + // most significant + // bits of the bitfield, and successive component occupying progressively less significant + // locations" + uint16_t RGBA; + + static void readColor(gl::ColorF *dst, const R4G4B4A4 *src); + static void writeColor(R4G4B4A4 *dst, const gl::ColorF *src); + static void average(R4G4B4A4 *dst, const R4G4B4A4 *src1, const R4G4B4A4 *src2); +}; + +struct A4R4G4B4 +{ + uint16_t ARGB; + + static void readColor(gl::ColorF *dst, const A4R4G4B4 *src); + static void writeColor(A4R4G4B4 *dst, const gl::ColorF *src); + static void average(A4R4G4B4 *dst, const A4R4G4B4 *src1, const A4R4G4B4 *src2); +}; + +struct R16 +{ + uint16_t R; + + static void readColor(gl::ColorF *dst, const R16 *src); + static void readColor(gl::ColorUI *dst, const R16 *src); + static void writeColor(R16 *dst, const gl::ColorF *src); + static void writeColor(R16 *dst, const gl::ColorUI *src); + static void average(R16 *dst, const R16 *src1, const R16 *src2); +}; + +struct R16G16 +{ + uint16_t R; + uint16_t G; + + static void readColor(gl::ColorF *dst, const R16G16 *src); + static void readColor(gl::ColorUI *dst, const R16G16 *src); + static void writeColor(R16G16 *dst, const gl::ColorF *src); + static void writeColor(R16G16 *dst, const gl::ColorUI *src); + static void average(R16G16 *dst, const R16G16 *src1, const R16G16 *src2); +}; + +struct R16G16B16 +{ + uint16_t R; + uint16_t G; + uint16_t B; + + static void readColor(gl::ColorF *dst, const R16G16B16 *src); + static void readColor(gl::ColorUI *dst, const R16G16B16 *src); + static void writeColor(R16G16B16 *dst, const gl::ColorF *src); + static void writeColor(R16G16B16 *dst, const gl::ColorUI *src); + static void average(R16G16B16 *dst, const R16G16B16 *src1, const R16G16B16 *src2); +}; + +struct R16G16B16A16 +{ + uint16_t R; + uint16_t G; + uint16_t B; + uint16_t A; + + static void readColor(gl::ColorF *dst, const R16G16B16A16 *src); + static void readColor(gl::ColorUI *dst, const R16G16B16A16 *src); + static void writeColor(R16G16B16A16 *dst, const gl::ColorF *src); + static void writeColor(R16G16B16A16 *dst, const gl::ColorUI *src); + static void average(R16G16B16A16 *dst, const R16G16B16A16 *src1, const R16G16B16A16 *src2); +}; + +struct R32 +{ + uint32_t R; + + static void readColor(gl::ColorF *dst, const R32 *src); + static void readColor(gl::ColorUI *dst, const R32 *src); + static void writeColor(R32 *dst, const gl::ColorF *src); + static void writeColor(R32 *dst, const gl::ColorUI *src); + static void average(R32 *dst, const R32 *src1, const R32 *src2); +}; + +struct R32G32 +{ + uint32_t R; + uint32_t G; + + static void readColor(gl::ColorF *dst, const R32G32 *src); + static void readColor(gl::ColorUI *dst, const R32G32 *src); + static void writeColor(R32G32 *dst, const gl::ColorF *src); + static void writeColor(R32G32 *dst, const gl::ColorUI *src); + static void average(R32G32 *dst, const R32G32 *src1, const R32G32 *src2); +}; + +struct R32G32B32 +{ + uint32_t R; + uint32_t G; + uint32_t B; + + static void readColor(gl::ColorF *dst, const R32G32B32 *src); + static void readColor(gl::ColorUI *dst, const R32G32B32 *src); + static void writeColor(R32G32B32 *dst, const gl::ColorF *src); + static void writeColor(R32G32B32 *dst, const gl::ColorUI *src); + static void average(R32G32B32 *dst, const R32G32B32 *src1, const R32G32B32 *src2); +}; + +struct R32G32B32A32 +{ + uint32_t R; + uint32_t G; + uint32_t B; + uint32_t A; + + static void readColor(gl::ColorF *dst, const R32G32B32A32 *src); + static void readColor(gl::ColorUI *dst, const R32G32B32A32 *src); + static void writeColor(R32G32B32A32 *dst, const gl::ColorF *src); + static void writeColor(R32G32B32A32 *dst, const gl::ColorUI *src); + static void average(R32G32B32A32 *dst, const R32G32B32A32 *src1, const R32G32B32A32 *src2); +}; + +struct R8S +{ + int8_t R; + + static void readColor(gl::ColorF *dst, const R8S *src); + static void readColor(gl::ColorI *dst, const R8S *src); + static void writeColor(R8S *dst, const gl::ColorF *src); + static void writeColor(R8S *dst, const gl::ColorI *src); + static void average(R8S *dst, const R8S *src1, const R8S *src2); +}; + +struct R8G8S +{ + int8_t R; + int8_t G; + + static void readColor(gl::ColorF *dst, const R8G8S *src); + static void readColor(gl::ColorI *dst, const R8G8S *src); + static void writeColor(R8G8S *dst, const gl::ColorF *src); + static void writeColor(R8G8S *dst, const gl::ColorI *src); + static void average(R8G8S *dst, const R8G8S *src1, const R8G8S *src2); +}; + +struct R8G8B8S +{ + int8_t R; + int8_t G; + int8_t B; + + static void readColor(gl::ColorF *dst, const R8G8B8S *src); + static void readColor(gl::ColorI *dst, const R8G8B8S *src); + static void writeColor(R8G8B8S *dst, const gl::ColorF *src); + static void writeColor(R8G8B8S *dst, const gl::ColorI *src); + static void average(R8G8B8S *dst, const R8G8B8S *src1, const R8G8B8S *src2); +}; + +struct R8G8B8A8S +{ + int8_t R; + int8_t G; + int8_t B; + int8_t A; + + static void readColor(gl::ColorF *dst, const R8G8B8A8S *src); + static void readColor(gl::ColorI *dst, const R8G8B8A8S *src); + static void writeColor(R8G8B8A8S *dst, const gl::ColorF *src); + static void writeColor(R8G8B8A8S *dst, const gl::ColorI *src); + static void average(R8G8B8A8S *dst, const R8G8B8A8S *src1, const R8G8B8A8S *src2); +}; + +struct R16S +{ + int16_t R; + + static void readColor(gl::ColorF *dst, const R16S *src); + static void readColor(gl::ColorI *dst, const R16S *src); + static void writeColor(R16S *dst, const gl::ColorF *src); + static void writeColor(R16S *dst, const gl::ColorI *src); + static void average(R16S *dst, const R16S *src1, const R16S *src2); +}; + +struct R16G16S +{ + int16_t R; + int16_t G; + + static void readColor(gl::ColorF *dst, const R16G16S *src); + static void readColor(gl::ColorI *dst, const R16G16S *src); + static void writeColor(R16G16S *dst, const gl::ColorF *src); + static void writeColor(R16G16S *dst, const gl::ColorI *src); + static void average(R16G16S *dst, const R16G16S *src1, const R16G16S *src2); +}; + +struct R16G16B16S +{ + int16_t R; + int16_t G; + int16_t B; + + static void readColor(gl::ColorF *dst, const R16G16B16S *src); + static void readColor(gl::ColorI *dst, const R16G16B16S *src); + static void writeColor(R16G16B16S *dst, const gl::ColorF *src); + static void writeColor(R16G16B16S *dst, const gl::ColorI *src); + static void average(R16G16B16S *dst, const R16G16B16S *src1, const R16G16B16S *src2); +}; + +struct R16G16B16A16S +{ + int16_t R; + int16_t G; + int16_t B; + int16_t A; + + static void readColor(gl::ColorF *dst, const R16G16B16A16S *src); + static void readColor(gl::ColorI *dst, const R16G16B16A16S *src); + static void writeColor(R16G16B16A16S *dst, const gl::ColorF *src); + static void writeColor(R16G16B16A16S *dst, const gl::ColorI *src); + static void average(R16G16B16A16S *dst, const R16G16B16A16S *src1, const R16G16B16A16S *src2); +}; + +struct R32S +{ + int32_t R; + + static void readColor(gl::ColorF *dst, const R32S *src); + static void readColor(gl::ColorI *dst, const R32S *src); + static void writeColor(R32S *dst, const gl::ColorF *src); + static void writeColor(R32S *dst, const gl::ColorI *src); + static void average(R32S *dst, const R32S *src1, const R32S *src2); +}; + +struct R32G32S +{ + int32_t R; + int32_t G; + + static void readColor(gl::ColorF *dst, const R32G32S *src); + static void readColor(gl::ColorI *dst, const R32G32S *src); + static void writeColor(R32G32S *dst, const gl::ColorF *src); + static void writeColor(R32G32S *dst, const gl::ColorI *src); + static void average(R32G32S *dst, const R32G32S *src1, const R32G32S *src2); +}; + +struct R32G32B32S +{ + int32_t R; + int32_t G; + int32_t B; + + static void readColor(gl::ColorF *dst, const R32G32B32S *src); + static void readColor(gl::ColorI *dst, const R32G32B32S *src); + static void writeColor(R32G32B32S *dst, const gl::ColorF *src); + static void writeColor(R32G32B32S *dst, const gl::ColorI *src); + static void average(R32G32B32S *dst, const R32G32B32S *src1, const R32G32B32S *src2); +}; + +struct R32G32B32A32S +{ + int32_t R; + int32_t G; + int32_t B; + int32_t A; + + static void readColor(gl::ColorF *dst, const R32G32B32A32S *src); + static void readColor(gl::ColorI *dst, const R32G32B32A32S *src); + static void writeColor(R32G32B32A32S *dst, const gl::ColorF *src); + static void writeColor(R32G32B32A32S *dst, const gl::ColorI *src); + static void average(R32G32B32A32S *dst, const R32G32B32A32S *src1, const R32G32B32A32S *src2); +}; + +struct A16B16G16R16F +{ + uint16_t A; + uint16_t R; + uint16_t G; + uint16_t B; + + static void readColor(gl::ColorF *dst, const A16B16G16R16F *src); + static void writeColor(A16B16G16R16F *dst, const gl::ColorF *src); + static void average(A16B16G16R16F *dst, const A16B16G16R16F *src1, const A16B16G16R16F *src2); +}; + +struct R16G16B16A16F +{ + uint16_t R; + uint16_t G; + uint16_t B; + uint16_t A; + + static void readColor(gl::ColorF *dst, const R16G16B16A16F *src); + static void writeColor(R16G16B16A16F *dst, const gl::ColorF *src); + static void average(R16G16B16A16F *dst, const R16G16B16A16F *src1, const R16G16B16A16F *src2); +}; + +struct R16F +{ + uint16_t R; + + static void readColor(gl::ColorF *dst, const R16F *src); + static void writeColor(R16F *dst, const gl::ColorF *src); + static void average(R16F *dst, const R16F *src1, const R16F *src2); +}; + +struct A16F +{ + uint16_t A; + + static void readColor(gl::ColorF *dst, const A16F *src); + static void writeColor(A16F *dst, const gl::ColorF *src); + static void average(A16F *dst, const A16F *src1, const A16F *src2); +}; + +struct L16F +{ + uint16_t L; + + static void readColor(gl::ColorF *dst, const L16F *src); + static void writeColor(L16F *dst, const gl::ColorF *src); + static void average(L16F *dst, const L16F *src1, const L16F *src2); +}; + +struct L16A16F +{ + uint16_t L; + uint16_t A; + + static void readColor(gl::ColorF *dst, const L16A16F *src); + static void writeColor(L16A16F *dst, const gl::ColorF *src); + static void average(L16A16F *dst, const L16A16F *src1, const L16A16F *src2); +}; + +struct R16G16F +{ + uint16_t R; + uint16_t G; + + static void readColor(gl::ColorF *dst, const R16G16F *src); + static void writeColor(R16G16F *dst, const gl::ColorF *src); + static void average(R16G16F *dst, const R16G16F *src1, const R16G16F *src2); +}; + +struct R16G16B16F +{ + uint16_t R; + uint16_t G; + uint16_t B; + + static void readColor(gl::ColorF *dst, const R16G16B16F *src); + static void writeColor(R16G16B16F *dst, const gl::ColorF *src); + static void average(R16G16B16F *dst, const R16G16B16F *src1, const R16G16B16F *src2); +}; + +struct A32B32G32R32F +{ + float A; + float R; + float G; + float B; + + static void readColor(gl::ColorF *dst, const A32B32G32R32F *src); + static void writeColor(A32B32G32R32F *dst, const gl::ColorF *src); + static void average(A32B32G32R32F *dst, const A32B32G32R32F *src1, const A32B32G32R32F *src2); +}; + +struct R32G32B32A32F +{ + float R; + float G; + float B; + float A; + + static void readColor(gl::ColorF *dst, const R32G32B32A32F *src); + static void writeColor(R32G32B32A32F *dst, const gl::ColorF *src); + static void average(R32G32B32A32F *dst, const R32G32B32A32F *src1, const R32G32B32A32F *src2); +}; + +struct R32F +{ + float R; + + static void readColor(gl::ColorF *dst, const R32F *src); + static void writeColor(R32F *dst, const gl::ColorF *src); + static void average(R32F *dst, const R32F *src1, const R32F *src2); +}; + +struct A32F +{ + float A; + + static void readColor(gl::ColorF *dst, const A32F *src); + static void writeColor(A32F *dst, const gl::ColorF *src); + static void average(A32F *dst, const A32F *src1, const A32F *src2); +}; + +struct L32F +{ + float L; + + static void readColor(gl::ColorF *dst, const L32F *src); + static void writeColor(L32F *dst, const gl::ColorF *src); + static void average(L32F *dst, const L32F *src1, const L32F *src2); +}; + +struct L32A32F +{ + float L; + float A; + + static void readColor(gl::ColorF *dst, const L32A32F *src); + static void writeColor(L32A32F *dst, const gl::ColorF *src); + static void average(L32A32F *dst, const L32A32F *src1, const L32A32F *src2); +}; + +struct R32G32F +{ + float R; + float G; + + static void readColor(gl::ColorF *dst, const R32G32F *src); + static void writeColor(R32G32F *dst, const gl::ColorF *src); + static void average(R32G32F *dst, const R32G32F *src1, const R32G32F *src2); +}; + +struct R32G32B32F +{ + float R; + float G; + float B; + + static void readColor(gl::ColorF *dst, const R32G32B32F *src); + static void writeColor(R32G32B32F *dst, const gl::ColorF *src); + static void average(R32G32B32F *dst, const R32G32B32F *src1, const R32G32B32F *src2); +}; + +struct R10G10B10A2 +{ + uint32_t R : 10; + uint32_t G : 10; + uint32_t B : 10; + uint32_t A : 2; + + static void readColor(gl::ColorF *dst, const R10G10B10A2 *src); + static void readColor(gl::ColorUI *dst, const R10G10B10A2 *src); + static void writeColor(R10G10B10A2 *dst, const gl::ColorF *src); + static void writeColor(R10G10B10A2 *dst, const gl::ColorUI *src); + static void average(R10G10B10A2 *dst, const R10G10B10A2 *src1, const R10G10B10A2 *src2); +}; +static_assert(sizeof(R10G10B10A2) == 4, "R10G10B10A2 struct not 32-bits."); + +struct R10G10B10A2S +{ + int32_t R : 10; + int32_t G : 10; + int32_t B : 10; + int32_t A : 2; + + static void readColor(gl::ColorF *dst, const R10G10B10A2S *src); + static void readColor(gl::ColorI *dst, const R10G10B10A2S *src); + static void writeColor(R10G10B10A2S *dst, const gl::ColorF *src); + static void writeColor(R10G10B10A2S *dst, const gl::ColorI *src); + static void average(R10G10B10A2S *dst, const R10G10B10A2S *src1, const R10G10B10A2S *src2); +}; +static_assert(sizeof(R10G10B10A2S) == 4, "R10G10B10A2S struct not 32-bits."); + +struct R10G10B10X2 +{ + uint32_t R : 10; + uint32_t G : 10; + uint32_t B : 10; + + static void readColor(gl::ColorF *dst, const R10G10B10X2 *src); + static void readColor(gl::ColorUI *dst, const R10G10B10X2 *src); + static void writeColor(R10G10B10X2 *dst, const gl::ColorF *src); + static void writeColor(R10G10B10X2 *dst, const gl::ColorUI *src); + static void average(R10G10B10X2 *dst, const R10G10B10X2 *src1, const R10G10B10X2 *src2); +}; +static_assert(sizeof(R10G10B10X2) == 4, "R10G10B10X2 struct not 32-bits."); + +struct B10G10R10A2 +{ + uint32_t B : 10; + uint32_t G : 10; + uint32_t R : 10; + uint32_t A : 2; + + static void readColor(gl::ColorF *dst, const B10G10R10A2 *src); + static void readColor(gl::ColorUI *dst, const B10G10R10A2 *src); + static void writeColor(B10G10R10A2 *dst, const gl::ColorF *src); + static void writeColor(B10G10R10A2 *dst, const gl::ColorUI *src); + static void average(B10G10R10A2 *dst, const B10G10R10A2 *src1, const B10G10R10A2 *src2); +}; +static_assert(sizeof(B10G10R10A2) == 4, "B10G10R10A2 struct not 32-bits."); + +struct R9G9B9E5 +{ + uint32_t R : 9; + uint32_t G : 9; + uint32_t B : 9; + uint32_t E : 5; + + static void readColor(gl::ColorF *dst, const R9G9B9E5 *src); + static void writeColor(R9G9B9E5 *dst, const gl::ColorF *src); + static void average(R9G9B9E5 *dst, const R9G9B9E5 *src1, const R9G9B9E5 *src2); +}; +static_assert(sizeof(R9G9B9E5) == 4, "R9G9B9E5 struct not 32-bits."); + +struct R11G11B10F +{ + uint32_t R : 11; + uint32_t G : 11; + uint32_t B : 10; + + static void readColor(gl::ColorF *dst, const R11G11B10F *src); + static void writeColor(R11G11B10F *dst, const gl::ColorF *src); + static void average(R11G11B10F *dst, const R11G11B10F *src1, const R11G11B10F *src2); +}; +static_assert(sizeof(R11G11B10F) == 4, "R11G11B10F struct not 32-bits."); + +struct D24S8 +{ + uint32_t S : 8; + uint32_t D : 24; + + static void ReadDepthStencil(DepthStencil *dst, const D24S8 *src); + static void WriteDepthStencil(D24S8 *dst, const DepthStencil *src); +}; + +struct S8 +{ + uint8_t S; + + static void ReadDepthStencil(DepthStencil *dst, const S8 *src); + static void WriteDepthStencil(S8 *dst, const DepthStencil *src); +}; + +struct D16 +{ + uint16_t D; + + static void ReadDepthStencil(DepthStencil *dst, const D16 *src); + static void WriteDepthStencil(D16 *dst, const DepthStencil *src); +}; + +struct D24X8 +{ + uint32_t D : 24; + uint32_t X : 8; + + static void ReadDepthStencil(DepthStencil *dst, const D24X8 *src); + static void WriteDepthStencil(D24X8 *dst, const DepthStencil *src); +}; + +struct D32F +{ + float D; + + static void ReadDepthStencil(DepthStencil *dst, const D32F *src); + static void WriteDepthStencil(D32F *dst, const DepthStencil *src); +}; + +struct D32 +{ + uint32_t D; + + static void ReadDepthStencil(DepthStencil *dst, const D32 *src); + static void WriteDepthStencil(D32 *dst, const DepthStencil *src); +}; + +struct D32FS8X24 +{ + float D; + uint32_t S; + + static void ReadDepthStencil(DepthStencil *dst, const D32FS8X24 *src); + static void WriteDepthStencil(D32FS8X24 *dst, const DepthStencil *src); +}; +} // namespace angle + +#endif // IMAGEUTIL_IMAGEFORMATS_H_ diff --git a/gfx/angle/checkout/src/image_util/loadimage.cpp b/gfx/angle/checkout/src/image_util/loadimage.cpp new file mode 100644 index 0000000000..97169c00f5 --- /dev/null +++ b/gfx/angle/checkout/src/image_util/loadimage.cpp @@ -0,0 +1,1796 @@ +// +// Copyright 2013 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. +// + +// angle_loadimage.cpp: Defines image loading functions. + +#include "image_util/loadimage.h" + +#include "common/mathutil.h" +#include "common/platform.h" +#include "image_util/imageformats.h" + +namespace angle +{ + +void LoadA8ToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ +#if defined(ANGLE_USE_SSE) + if (gl::supportsSSE2()) + { + __m128i zeroWide = _mm_setzero_si128(); + + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *source = + priv::OffsetDataPointer<uint8_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = priv::OffsetDataPointer<uint32_t>(output, y, z, outputRowPitch, + outputDepthPitch); + + size_t x = 0; + + // Make output writes aligned + for (; ((reinterpret_cast<intptr_t>(&dest[x]) & 0xF) != 0 && x < width); x++) + { + dest[x] = static_cast<uint32_t>(source[x]) << 24; + } + + for (; x + 7 < width; x += 8) + { + __m128i sourceData = + _mm_loadl_epi64(reinterpret_cast<const __m128i *>(&source[x])); + // Interleave each byte to 16bit, make the lower byte to zero + sourceData = _mm_unpacklo_epi8(zeroWide, sourceData); + // Interleave each 16bit to 32bit, make the lower 16bit to zero + __m128i lo = _mm_unpacklo_epi16(zeroWide, sourceData); + __m128i hi = _mm_unpackhi_epi16(zeroWide, sourceData); + + _mm_store_si128(reinterpret_cast<__m128i *>(&dest[x]), lo); + _mm_store_si128(reinterpret_cast<__m128i *>(&dest[x + 4]), hi); + } + + // Handle the remainder + for (; x < width; x++) + { + dest[x] = static_cast<uint32_t>(source[x]) << 24; + } + } + } + + return; + } +#endif + + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *source = + priv::OffsetDataPointer<uint8_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = + priv::OffsetDataPointer<uint32_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = static_cast<uint32_t>(source[x]) << 24; + } + } + } +} + +void LoadA8ToBGRA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + // Same as loading to RGBA + LoadA8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, + outputRowPitch, outputDepthPitch); +} + +void LoadA32FToRGBA32F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *source = + priv::OffsetDataPointer<float>(input, y, z, inputRowPitch, inputDepthPitch); + float *dest = + priv::OffsetDataPointer<float>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = 0.0f; + dest[4 * x + 1] = 0.0f; + dest[4 * x + 2] = 0.0f; + dest[4 * x + 3] = source[x]; + } + } + } +} + +void LoadA16FToRGBA16F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = + priv::OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = + priv::OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = 0; + dest[4 * x + 1] = 0; + dest[4 * x + 2] = 0; + dest[4 * x + 3] = source[x]; + } + } + } +} + +void LoadL8ToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *source = + priv::OffsetDataPointer<uint8_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = + priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint8_t sourceVal = source[x]; + dest[4 * x + 0] = sourceVal; + dest[4 * x + 1] = sourceVal; + dest[4 * x + 2] = sourceVal; + dest[4 * x + 3] = 0xFF; + } + } + } +} + +void LoadL8ToBGRA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + // Same as loading to RGBA + LoadL8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, + outputRowPitch, outputDepthPitch); +} + +void LoadL32FToRGBA32F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *source = + priv::OffsetDataPointer<float>(input, y, z, inputRowPitch, inputDepthPitch); + float *dest = + priv::OffsetDataPointer<float>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = source[x]; + dest[4 * x + 1] = source[x]; + dest[4 * x + 2] = source[x]; + dest[4 * x + 3] = 1.0f; + } + } + } +} + +void LoadL16FToRGBA16F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = + priv::OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = + priv::OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = source[x]; + dest[4 * x + 1] = source[x]; + dest[4 * x + 2] = source[x]; + dest[4 * x + 3] = gl::Float16One; + } + } + } +} + +void LoadLA8ToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *source = + priv::OffsetDataPointer<uint8_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = + priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = source[2 * x + 0]; + dest[4 * x + 1] = source[2 * x + 0]; + dest[4 * x + 2] = source[2 * x + 0]; + dest[4 * x + 3] = source[2 * x + 1]; + } + } + } +} + +void LoadLA8ToBGRA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + // Same as loading to RGBA + LoadLA8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, + outputRowPitch, outputDepthPitch); +} + +void LoadLA32FToRGBA32F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *source = + priv::OffsetDataPointer<float>(input, y, z, inputRowPitch, inputDepthPitch); + float *dest = + priv::OffsetDataPointer<float>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = source[2 * x + 0]; + dest[4 * x + 1] = source[2 * x + 0]; + dest[4 * x + 2] = source[2 * x + 0]; + dest[4 * x + 3] = source[2 * x + 1]; + } + } + } +} + +void LoadLA16FToRGBA16F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = + priv::OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = + priv::OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = source[2 * x + 0]; + dest[4 * x + 1] = source[2 * x + 0]; + dest[4 * x + 2] = source[2 * x + 0]; + dest[4 * x + 3] = source[2 * x + 1]; + } + } + } +} + +void LoadRGB8ToBGR565(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *source = + priv::OffsetDataPointer<uint8_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = + priv::OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint8_t r8 = source[x * 3 + 0]; + uint8_t g8 = source[x * 3 + 1]; + uint8_t b8 = source[x * 3 + 2]; + auto r5 = static_cast<uint16_t>(r8 >> 3); + auto g6 = static_cast<uint16_t>(g8 >> 2); + auto b5 = static_cast<uint16_t>(b8 >> 3); + dest[x] = (r5 << 11) | (g6 << 5) | b5; + } + } + } +} + +void LoadRGB565ToBGR565(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = + priv::OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = + priv::OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + // The GL type RGB is packed with with red in the MSB, while the D3D11 type BGR + // is packed with red in the LSB + auto rgb = source[x]; + uint16_t r5 = gl::getShiftedData<5, 11>(rgb); + uint16_t g6 = gl::getShiftedData<6, 5>(rgb); + uint16_t b5 = gl::getShiftedData<5, 0>(rgb); + dest[x] = (r5 << 11) | (g6 << 5) | b5; + } + } + } +} + +void LoadRGB8ToBGRX8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *source = + priv::OffsetDataPointer<uint8_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = + priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = source[x * 3 + 2]; + dest[4 * x + 1] = source[x * 3 + 1]; + dest[4 * x + 2] = source[x * 3 + 0]; + dest[4 * x + 3] = 0xFF; + } + } + } +} + +void LoadRG8ToBGRX8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *source = + priv::OffsetDataPointer<uint8_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = + priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = 0x00; + dest[4 * x + 1] = source[x * 2 + 1]; + dest[4 * x + 2] = source[x * 2 + 0]; + dest[4 * x + 3] = 0xFF; + } + } + } +} + +void LoadR8ToBGRX8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *source = + priv::OffsetDataPointer<uint8_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = + priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = 0x00; + dest[4 * x + 1] = 0x00; + dest[4 * x + 2] = source[x]; + dest[4 * x + 3] = 0xFF; + } + } + } +} + +void LoadR5G6B5ToBGRA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = + priv::OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = + priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t rgb = source[x]; + dest[4 * x + 0] = + static_cast<uint8_t>(((rgb & 0x001F) << 3) | ((rgb & 0x001F) >> 2)); + dest[4 * x + 1] = + static_cast<uint8_t>(((rgb & 0x07E0) >> 3) | ((rgb & 0x07E0) >> 9)); + dest[4 * x + 2] = + static_cast<uint8_t>(((rgb & 0xF800) >> 8) | ((rgb & 0xF800) >> 13)); + dest[4 * x + 3] = 0xFF; + } + } + } +} + +void LoadR5G6B5ToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = + priv::OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = + priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t rgb = source[x]; + dest[4 * x + 0] = + static_cast<uint8_t>(((rgb & 0xF800) >> 8) | ((rgb & 0xF800) >> 13)); + dest[4 * x + 1] = + static_cast<uint8_t>(((rgb & 0x07E0) >> 3) | ((rgb & 0x07E0) >> 9)); + dest[4 * x + 2] = + static_cast<uint8_t>(((rgb & 0x001F) << 3) | ((rgb & 0x001F) >> 2)); + dest[4 * x + 3] = 0xFF; + } + } + } +} + +void LoadRGBA8ToBGRA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ +#if defined(ANGLE_USE_SSE) + if (gl::supportsSSE2()) + { + __m128i brMask = _mm_set1_epi32(0x00ff00ff); + + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = + priv::OffsetDataPointer<uint32_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = priv::OffsetDataPointer<uint32_t>(output, y, z, outputRowPitch, + outputDepthPitch); + + size_t x = 0; + + // Make output writes aligned + for (; ((reinterpret_cast<intptr_t>(&dest[x]) & 15) != 0) && x < width; x++) + { + uint32_t rgba = source[x]; + dest[x] = (ANGLE_ROTL(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00); + } + + for (; x + 3 < width; x += 4) + { + __m128i sourceData = + _mm_loadu_si128(reinterpret_cast<const __m128i *>(&source[x])); + // Mask out g and a, which don't change + __m128i gaComponents = _mm_andnot_si128(brMask, sourceData); + // Mask out b and r + __m128i brComponents = _mm_and_si128(sourceData, brMask); + // Swap b and r + __m128i brSwapped = _mm_shufflehi_epi16( + _mm_shufflelo_epi16(brComponents, _MM_SHUFFLE(2, 3, 0, 1)), + _MM_SHUFFLE(2, 3, 0, 1)); + __m128i result = _mm_or_si128(gaComponents, brSwapped); + _mm_store_si128(reinterpret_cast<__m128i *>(&dest[x]), result); + } + + // Perform leftover writes + for (; x < width; x++) + { + uint32_t rgba = source[x]; + dest[x] = (ANGLE_ROTL(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00); + } + } + } + + return; + } +#endif + + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = + priv::OffsetDataPointer<uint32_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = + priv::OffsetDataPointer<uint32_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint32_t rgba = source[x]; + dest[x] = (ANGLE_ROTL(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00); + } + } + } +} + +void LoadRGBA8ToBGRA4(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = + priv::OffsetDataPointer<uint32_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = + priv::OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint32_t rgba8 = source[x]; + auto r4 = static_cast<uint16_t>((rgba8 & 0x000000FF) >> 4); + auto g4 = static_cast<uint16_t>((rgba8 & 0x0000FF00) >> 12); + auto b4 = static_cast<uint16_t>((rgba8 & 0x00FF0000) >> 20); + auto a4 = static_cast<uint16_t>((rgba8 & 0xFF000000) >> 28); + dest[x] = (a4 << 12) | (r4 << 8) | (g4 << 4) | b4; + } + } + } +} + +void LoadRGBA8ToRGBA4(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = + priv::OffsetDataPointer<uint32_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = + priv::OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint32_t rgba8 = source[x]; + auto r4 = static_cast<uint16_t>((rgba8 & 0x000000FF) >> 4); + auto g4 = static_cast<uint16_t>((rgba8 & 0x0000FF00) >> 12); + auto b4 = static_cast<uint16_t>((rgba8 & 0x00FF0000) >> 20); + auto a4 = static_cast<uint16_t>((rgba8 & 0xFF000000) >> 28); + dest[x] = (r4 << 12) | (g4 << 8) | (b4 << 4) | a4; + } + } + } +} + +void LoadRGBA4ToARGB4(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = + priv::OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = + priv::OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = ANGLE_ROTR16(source[x], 4); + } + } + } +} + +void LoadRGBA4ToBGRA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = + priv::OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = + priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t rgba = source[x]; + dest[4 * x + 0] = + static_cast<uint8_t>(((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4)); + dest[4 * x + 1] = + static_cast<uint8_t>(((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8)); + dest[4 * x + 2] = + static_cast<uint8_t>(((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12)); + dest[4 * x + 3] = + static_cast<uint8_t>(((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0)); + } + } + } +} + +void LoadRGBA4ToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = + priv::OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = + priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t rgba = source[x]; + dest[4 * x + 0] = + static_cast<uint8_t>(((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12)); + dest[4 * x + 1] = + static_cast<uint8_t>(((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8)); + dest[4 * x + 2] = + static_cast<uint8_t>(((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4)); + dest[4 * x + 3] = + static_cast<uint8_t>(((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0)); + } + } + } +} + +void LoadBGRA4ToBGRA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = + priv::OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = + priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t bgra = source[x]; + dest[4 * x + 0] = + static_cast<uint8_t>(((bgra & 0xF000) >> 8) | ((bgra & 0xF000) >> 12)); + dest[4 * x + 1] = + static_cast<uint8_t>(((bgra & 0x0F00) >> 4) | ((bgra & 0x0F00) >> 8)); + dest[4 * x + 2] = + static_cast<uint8_t>(((bgra & 0x00F0) << 0) | ((bgra & 0x00F0) >> 4)); + dest[4 * x + 3] = + static_cast<uint8_t>(((bgra & 0x000F) << 4) | ((bgra & 0x000F) >> 0)); + } + } + } +} + +void LoadRGBA8ToBGR5A1(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = + priv::OffsetDataPointer<uint32_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = + priv::OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint32_t rgba8 = source[x]; + auto r5 = static_cast<uint16_t>((rgba8 & 0x000000FF) >> 3); + auto g5 = static_cast<uint16_t>((rgba8 & 0x0000FF00) >> 11); + auto b5 = static_cast<uint16_t>((rgba8 & 0x00FF0000) >> 19); + auto a1 = static_cast<uint16_t>((rgba8 & 0xFF000000) >> 31); + dest[x] = (a1 << 15) | (r5 << 10) | (g5 << 5) | b5; + } + } + } +} + +void LoadRGBA8ToRGB5A1(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = + priv::OffsetDataPointer<uint32_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = + priv::OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint32_t rgba8 = source[x]; + auto r5 = static_cast<uint16_t>((rgba8 & 0x000000FF) >> 3); + auto g5 = static_cast<uint16_t>((rgba8 & 0x0000FF00) >> 11); + auto b5 = static_cast<uint16_t>((rgba8 & 0x00FF0000) >> 19); + auto a1 = static_cast<uint16_t>((rgba8 & 0xFF000000) >> 31); + dest[x] = (r5 << 11) | (g5 << 6) | (b5 << 1) | a1; + } + } + } +} + +void LoadRGB10A2ToBGR5A1(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const R10G10B10A2 *source = + priv::OffsetDataPointer<R10G10B10A2>(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = + priv::OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + R10G10B10A2 rgb10a2 = source[x]; + + uint16_t r5 = static_cast<uint16_t>(rgb10a2.R >> 5u); + uint16_t g5 = static_cast<uint16_t>(rgb10a2.G >> 5u); + uint16_t b5 = static_cast<uint16_t>(rgb10a2.B >> 5u); + uint16_t a1 = static_cast<uint16_t>(rgb10a2.A >> 1u); + + dest[x] = (a1 << 15) | (r5 << 10) | (g5 << 5) | b5; + } + } + } +} + +void LoadRGB10A2ToRGB5A1(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const R10G10B10A2 *source = + priv::OffsetDataPointer<R10G10B10A2>(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = + priv::OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + R10G10B10A2 rgb10a2 = source[x]; + + uint16_t r5 = static_cast<uint16_t>(rgb10a2.R >> 5u); + uint16_t g5 = static_cast<uint16_t>(rgb10a2.G >> 5u); + uint16_t b5 = static_cast<uint16_t>(rgb10a2.B >> 5u); + uint16_t a1 = static_cast<uint16_t>(rgb10a2.A >> 1u); + + dest[x] = (r5 << 11) | (g5 << 6) | (b5 << 1) | a1; + } + } + } +} + +void LoadRGB5A1ToA1RGB5(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = + priv::OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = + priv::OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = ANGLE_ROTR16(source[x], 1); + } + } + } +} + +void LoadRGB5A1ToBGR5A1(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = + priv::OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = + priv::OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t rgba = source[x]; + auto r5 = static_cast<uint16_t>((rgba & 0xF800) >> 11); + auto g5 = static_cast<uint16_t>((rgba & 0x07c0) >> 6); + auto b5 = static_cast<uint16_t>((rgba & 0x003e) >> 1); + auto a1 = static_cast<uint16_t>((rgba & 0x0001)); + dest[x] = (b5 << 11) | (g5 << 6) | (r5 << 1) | a1; + } + } + } +} + +void LoadRGB5A1ToBGRA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = + priv::OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = + priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t rgba = source[x]; + dest[4 * x + 0] = + static_cast<uint8_t>(((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3)); + dest[4 * x + 1] = + static_cast<uint8_t>(((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8)); + dest[4 * x + 2] = + static_cast<uint8_t>(((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13)); + dest[4 * x + 3] = static_cast<uint8_t>((rgba & 0x0001) ? 0xFF : 0); + } + } + } +} + +void LoadRGB5A1ToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = + priv::OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = + priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t rgba = source[x]; + dest[4 * x + 0] = + static_cast<uint8_t>(((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13)); + dest[4 * x + 1] = + static_cast<uint8_t>(((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8)); + dest[4 * x + 2] = + static_cast<uint8_t>(((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3)); + dest[4 * x + 3] = static_cast<uint8_t>((rgba & 0x0001) ? 0xFF : 0); + } + } + } +} + +void LoadBGR5A1ToBGRA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = + priv::OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = + priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t bgra = source[x]; + dest[4 * x + 0] = + static_cast<uint8_t>(((bgra & 0xF800) >> 8) | ((bgra & 0xF800) >> 13)); + dest[4 * x + 1] = + static_cast<uint8_t>(((bgra & 0x07C0) >> 3) | ((bgra & 0x07C0) >> 8)); + dest[4 * x + 2] = + static_cast<uint8_t>(((bgra & 0x003E) << 2) | ((bgra & 0x003E) >> 3)); + dest[4 * x + 3] = static_cast<uint8_t>((bgra & 0x0001) ? 0xFF : 0); + } + } + } +} + +void LoadRGB10A2ToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = + priv::OffsetDataPointer<uint32_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = + priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint32_t rgba = source[x]; + dest[4 * x + 0] = static_cast<uint8_t>((rgba & 0x000003FF) >> 2); + dest[4 * x + 1] = static_cast<uint8_t>((rgba & 0x000FFC00) >> 12); + dest[4 * x + 2] = static_cast<uint8_t>((rgba & 0x3FF00000) >> 22); + dest[4 * x + 3] = static_cast<uint8_t>(((rgba & 0xC0000000) >> 30) * 0x55); + } + } + } +} + +void LoadRGB10A2ToRGB10X2(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = + priv::OffsetDataPointer<uint32_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = + priv::OffsetDataPointer<uint32_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = source[x] | 0xC0000000; + } + } + } +} + +void LoadRGB16FToRGB9E5(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = + priv::OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = + priv::OffsetDataPointer<uint32_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = gl::convertRGBFloatsTo999E5(gl::float16ToFloat32(source[x * 3 + 0]), + gl::float16ToFloat32(source[x * 3 + 1]), + gl::float16ToFloat32(source[x * 3 + 2])); + } + } + } +} + +void LoadRGB32FToRGB9E5(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *source = + priv::OffsetDataPointer<float>(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = + priv::OffsetDataPointer<uint32_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = gl::convertRGBFloatsTo999E5(source[x * 3 + 0], source[x * 3 + 1], + source[x * 3 + 2]); + } + } + } +} + +void LoadRGB16FToRG11B10F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = + priv::OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = + priv::OffsetDataPointer<uint32_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = (gl::float32ToFloat11(gl::float16ToFloat32(source[x * 3 + 0])) << 0) | + (gl::float32ToFloat11(gl::float16ToFloat32(source[x * 3 + 1])) << 11) | + (gl::float32ToFloat10(gl::float16ToFloat32(source[x * 3 + 2])) << 22); + } + } + } +} + +void LoadRGB32FToRG11B10F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *source = + priv::OffsetDataPointer<float>(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = + priv::OffsetDataPointer<uint32_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = (gl::float32ToFloat11(source[x * 3 + 0]) << 0) | + (gl::float32ToFloat11(source[x * 3 + 1]) << 11) | + (gl::float32ToFloat10(source[x * 3 + 2]) << 22); + } + } + } +} + +void LoadG8R24ToR24G8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = + priv::OffsetDataPointer<uint32_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = + priv::OffsetDataPointer<uint32_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint32_t d = source[x] >> 8; + uint8_t s = source[x] & 0xFF; + dest[x] = d | (s << 24); + } + } + } +} + +void LoadD24S8ToD32FS8X24(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = + priv::OffsetDataPointer<uint32_t>(input, y, z, inputRowPitch, inputDepthPitch); + float *destDepth = + priv::OffsetDataPointer<float>(output, y, z, outputRowPitch, outputDepthPitch); + uint32_t *destStencil = + priv::OffsetDataPointer<uint32_t>(output, y, z, outputRowPitch, outputDepthPitch) + + 1; + for (size_t x = 0; x < width; x++) + { + destDepth[x * 2] = (source[x] & 0xFFFFFF) / static_cast<float>(0xFFFFFF); + destStencil[x * 2] = source[x] & 0xFF000000; + } + } + } +} + +void LoadD24S8ToD32F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = + priv::OffsetDataPointer<uint32_t>(input, y, z, inputRowPitch, inputDepthPitch); + float *destDepth = + priv::OffsetDataPointer<float>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint32_t sourcePixel = (source[x] >> 8) & 0xFFFFFF; + destDepth[x] = sourcePixel / static_cast<float>(0xFFFFFF); + } + } + } +} + +void LoadD32ToD32FX32(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = + priv::OffsetDataPointer<uint32_t>(input, y, z, inputRowPitch, inputDepthPitch); + float *destDepth = + priv::OffsetDataPointer<float>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + destDepth[x * 2] = source[x] / static_cast<float>(0xFFFFFFFF); + } + } + } +} + +void LoadD32ToD32F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = + priv::OffsetDataPointer<uint32_t>(input, y, z, inputRowPitch, inputDepthPitch); + float *destDepth = + priv::OffsetDataPointer<float>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint32_t sourcePixel = source[x]; + destDepth[x] = sourcePixel / static_cast<float>(0xFFFFFFFF); + } + } + } +} + +void LoadD32FToD32F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *source = + priv::OffsetDataPointer<float>(input, y, z, inputRowPitch, inputDepthPitch); + float *dest = + priv::OffsetDataPointer<float>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = gl::clamp01(source[x]); + } + } + } +} + +void LoadD32FS8X24ToD24S8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *sourceDepth = + priv::OffsetDataPointer<float>(input, y, z, inputRowPitch, inputDepthPitch); + const uint32_t *sourceStencil = + priv::OffsetDataPointer<uint32_t>(input, y, z, inputRowPitch, inputDepthPitch) + 1; + uint32_t *dest = + priv::OffsetDataPointer<uint32_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint32_t d = static_cast<uint32_t>(gl::clamp01(sourceDepth[x * 2]) * 0xFFFFFF); + uint32_t s = sourceStencil[x * 2] & 0xFF000000; + dest[x] = d | s; + } + } + } +} + +void LoadX24S8ToS8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = reinterpret_cast<const uint32_t *>( + input + (y * inputRowPitch) + (z * inputDepthPitch)); + uint8_t *destStencil = + reinterpret_cast<uint8_t *>(output + (y * outputRowPitch) + (z * outputDepthPitch)); + for (size_t x = 0; x < width; x++) + { + destStencil[x] = (source[x] & 0xFF); + } + } + } +} + +void LoadX32S8ToS8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = reinterpret_cast<const uint32_t *>( + input + (y * inputRowPitch) + (z * inputDepthPitch)); + uint8_t *destStencil = + reinterpret_cast<uint8_t *>(output + (y * outputRowPitch) + (z * outputDepthPitch)); + for (size_t x = 0; x < width; x++) + { + destStencil[x] = (source[(x * 2) + 1] & 0xFF); + } + } + } +} + +void LoadD32FS8X24ToD32F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *sourceDepth = + priv::OffsetDataPointer<float>(input, y, z, inputRowPitch, inputDepthPitch); + float *destDepth = + priv::OffsetDataPointer<float>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + destDepth[x] = gl::clamp01(sourceDepth[x * 2]); + } + } + } +} + +void LoadD32FS8X24ToD32FS8X24(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *sourceDepth = + priv::OffsetDataPointer<float>(input, y, z, inputRowPitch, inputDepthPitch); + const uint32_t *sourceStencil = + priv::OffsetDataPointer<uint32_t>(input, y, z, inputRowPitch, inputDepthPitch) + 1; + float *destDepth = + priv::OffsetDataPointer<float>(output, y, z, outputRowPitch, outputDepthPitch); + uint32_t *destStencil = + priv::OffsetDataPointer<uint32_t>(output, y, z, outputRowPitch, outputDepthPitch) + + 1; + for (size_t x = 0; x < width; x++) + { + destDepth[x * 2] = gl::clamp01(sourceDepth[x * 2]); + destStencil[x * 2] = sourceStencil[x * 2] & 0xFF000000; + } + } + } +} + +void LoadRGB32FToRGBA16F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *source = + priv::OffsetDataPointer<float>(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = + priv::OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x * 4 + 0] = gl::float32ToFloat16(source[x * 3 + 0]); + dest[x * 4 + 1] = gl::float32ToFloat16(source[x * 3 + 1]); + dest[x * 4 + 2] = gl::float32ToFloat16(source[x * 3 + 2]); + dest[x * 4 + 3] = gl::Float16One; + } + } + } +} + +void LoadRGB32FToRGB16F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *source = + priv::OffsetDataPointer<float>(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = + priv::OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x * 3 + 0] = gl::float32ToFloat16(source[x * 3 + 0]); + dest[x * 3 + 1] = gl::float32ToFloat16(source[x * 3 + 1]); + dest[x * 3 + 2] = gl::float32ToFloat16(source[x * 3 + 2]); + } + } + } +} + +void LoadR32ToR16(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = + priv::OffsetDataPointer<uint32_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = + priv::OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = source[x] >> 16; + } + } + } +} + +void LoadR32ToR24G8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = + priv::OffsetDataPointer<uint32_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = + priv::OffsetDataPointer<uint32_t>(output, y, z, outputRowPitch, outputDepthPitch); + + for (size_t x = 0; x < width; x++) + { + dest[x] = source[x] >> 8; + } + } + } +} + +// This conversion was added to support using a 32F depth buffer +// as emulation for 16unorm depth buffer in Metal. +// See angleproject:6597 +void LoadUNorm16To32F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = + priv::OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + float *dest = + priv::OffsetDataPointer<float>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = static_cast<float>(source[x]) / 0xFFFF; + } + } + } +} + +// This conversion was added to support using a 32F depth buffer +// as emulation for 16unorm depth buffer in Metal. In OpenGL ES 3.0 +// you're allowed to pass UNSIGNED_INT as input to texImage2D and +// so this conversion is neccasary. +// +// See angleproject:6597 +void LoadUNorm32To32F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = + priv::OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + float *dest = + priv::OffsetDataPointer<float>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = static_cast<float>(source[x]) / static_cast<float>(0xFFFFFFFFU); + } + } + } +} + +void LoadYuvToNative(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + // For YUV formats it is assumed that source has tightly packed data. + memcpy(output, input, inputDepthPitch); +} + +} // namespace angle diff --git a/gfx/angle/checkout/src/image_util/loadimage.h b/gfx/angle/checkout/src/image_util/loadimage.h new file mode 100644 index 0000000000..5ae4d47938 --- /dev/null +++ b/gfx/angle/checkout/src/image_util/loadimage.h @@ -0,0 +1,976 @@ +// +// Copyright 2013 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. +// + +// loadimage.h: Defines image loading functions + +#ifndef IMAGEUTIL_LOADIMAGE_H_ +#define IMAGEUTIL_LOADIMAGE_H_ + +#include <stddef.h> +#include <stdint.h> + +namespace angle +{ + +void LoadA8ToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadA8ToBGRA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadA32FToRGBA32F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadA16FToRGBA16F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadL8ToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadL8ToBGRA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadL32FToRGBA32F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadL16FToRGBA16F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadLA8ToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadLA8ToBGRA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadLA32FToRGBA32F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadLA16FToRGBA16F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadRGB8ToBGR565(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadRGB565ToBGR565(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadRGB8ToBGRX8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadRG8ToBGRX8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadR8ToBGRX8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadR5G6B5ToBGRA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadR5G6B5ToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadRGBA8ToBGRA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadRGBA8ToBGRA4(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadRGBA8ToRGBA4(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadRGBA4ToARGB4(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadRGBA4ToRGBA4(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadRGBA4ToBGRA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadRGBA4ToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadBGRA4ToBGRA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadRGBA8ToBGR5A1(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadRGBA8ToRGB5A1(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadRGB10A2ToBGR5A1(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadRGB10A2ToRGB5A1(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadRGB5A1ToRGB5A1(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadRGB5A1ToBGR5A1(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadRGB5A1ToA1RGB5(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadRGB5A1ToBGRA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadRGB5A1ToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadBGR5A1ToBGRA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadRGB10A2ToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadRGB10A2ToRGB10X2(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadRGB16FToRGB9E5(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadRGB32FToRGB9E5(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadRGB16FToRG11B10F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadRGB32FToRG11B10F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadG8R24ToR24G8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadD24S8ToD32FS8X24(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadD24S8ToD32F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadD32ToD32FX32(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadD32ToD32F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadD32FToD32F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadD32FS8X24ToD24S8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadX24S8ToS8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadX32S8ToS8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadD32FS8X24ToD32F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadD32FS8X24ToD32FS8X24(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +template <typename type, size_t componentCount> +inline void LoadToNative(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +template <typename type, uint32_t fourthComponentBits> +inline void LoadToNative3To4(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +template <size_t componentCount> +inline void Load32FTo16F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadUNorm16To32F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadUNorm32To32F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadRGB32FToRGBA16F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadRGB32FToRGB16F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +template <size_t blockWidth, size_t blockHeight, size_t blockDepth, size_t blockSize> +inline void LoadCompressedToNative(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadR32ToR16(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +template <typename type, + uint32_t firstBits, + uint32_t secondBits, + uint32_t thirdBits, + uint32_t fourthBits> +inline void Initialize4ComponentData(size_t width, + size_t height, + size_t depth, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadR32ToR24G8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadETC1RGB8ToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadASTCToRGBA8Inner(size_t width, + size_t height, + size_t depth, + uint32_t blockWidth, + uint32_t blockHeight, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +template <size_t blockWidth, size_t blockHeight> +inline void LoadASTCToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadETC1RGB8ToBC1(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadEACR11ToR8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadEACR11SToR8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadEACRG11ToRG8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadEACRG11SToRG8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadEACR11ToR16(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadEACR11SToR16(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadEACRG11ToRG16(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadEACRG11SToRG16(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadEACR11ToR16F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadEACR11SToR16F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadEACRG11ToRG16F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadEACRG11SToRG16F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadETC2RGB8ToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadETC2RGB8ToBC1(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadETC2SRGB8ToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadETC2SRGB8ToBC1(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadETC2RGB8A1ToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadETC2RGB8A1ToBC1(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadETC2SRGB8A1ToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadETC2SRGB8A1ToBC1(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadETC2RGBA8ToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadETC2SRGBA8ToSRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadYuvToNative(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadPalettedToRGBA8Impl(size_t width, + size_t height, + size_t depth, + uint32_t indexBits, + uint32_t redBlueBits, + uint32_t greenBits, + uint32_t alphaBits, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +template <uint32_t indexBits, uint32_t redBlueBits, uint32_t greenBits, uint32_t alphaBits> +inline void LoadPalettedToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +} // namespace angle + +#include "loadimage.inc" + +#endif // IMAGEUTIL_LOADIMAGE_H_ diff --git a/gfx/angle/checkout/src/image_util/loadimage.inc b/gfx/angle/checkout/src/image_util/loadimage.inc new file mode 100644 index 0000000000..58c0b9faf5 --- /dev/null +++ b/gfx/angle/checkout/src/image_util/loadimage.inc @@ -0,0 +1,201 @@ +// +// Copyright 2014 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. +// + +#include "common/mathutil.h" + +#include <string.h> + +namespace angle +{ + +namespace priv +{ + +template <typename T> +inline T *OffsetDataPointer(uint8_t *data, size_t y, size_t z, size_t rowPitch, size_t depthPitch) +{ + return reinterpret_cast<T*>(data + (y * rowPitch) + (z * depthPitch)); +} + +template <typename T> +inline const T *OffsetDataPointer(const uint8_t *data, size_t y, size_t z, size_t rowPitch, size_t depthPitch) +{ + return reinterpret_cast<const T*>(data + (y * rowPitch) + (z * depthPitch)); +} + +} // namespace priv + +template <typename type, size_t componentCount> +inline void LoadToNative(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + const size_t rowSize = width * sizeof(type) * componentCount; + const size_t layerSize = rowSize * height; + const size_t imageSize = layerSize * depth; + + if (layerSize == inputDepthPitch && layerSize == outputDepthPitch) + { + ASSERT(rowSize == inputRowPitch && rowSize == outputRowPitch); + memcpy(output, input, imageSize); + } + else if (rowSize == inputRowPitch && rowSize == outputRowPitch) + { + for (size_t z = 0; z < depth; z++) + { + const type *source = priv::OffsetDataPointer<type>(input, 0, z, inputRowPitch, inputDepthPitch); + type *dest = priv::OffsetDataPointer<type>(output, 0, z, outputRowPitch, outputDepthPitch); + + memcpy(dest, source, layerSize); + } + } + else + { + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const type *source = priv::OffsetDataPointer<type>(input, y, z, inputRowPitch, inputDepthPitch); + type *dest = priv::OffsetDataPointer<type>(output, y, z, outputRowPitch, outputDepthPitch); + memcpy(dest, source, width * sizeof(type) * componentCount); + } + } + } +} + +template <typename type, uint32_t fourthComponentBits> +inline void LoadToNative3To4(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + const type fourthValue = gl::bitCast<type>(fourthComponentBits); + + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const type *source = priv::OffsetDataPointer<type>(input, y, z, inputRowPitch, inputDepthPitch); + type *dest = priv::OffsetDataPointer<type>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + memcpy(&dest[x * 4], &source[x * 3], sizeof(type) * 3); + dest[x * 4 + 3] = fourthValue; + } + } + } +} + +template <size_t componentCount> +inline void Load32FTo16F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + const size_t elementWidth = componentCount * width; + + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *source = priv::OffsetDataPointer<float>(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = priv::OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch); + + for (size_t x = 0; x < elementWidth; x++) + { + dest[x] = gl::float32ToFloat16(source[x]); + } + } + } +} + +template <size_t blockWidth, size_t blockHeight, size_t blockDepth, size_t blockSize> +inline void LoadCompressedToNative(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + const size_t columns = (width + (blockWidth - 1)) / blockWidth; + const size_t rows = (height + (blockHeight - 1)) / blockHeight; + const size_t layers = (depth + (blockDepth - 1)) / blockDepth; + + for (size_t z = 0; z < layers; ++z) + { + for (size_t y = 0; y < rows; ++y) + { + const uint8_t *source = priv::OffsetDataPointer<uint8_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + memcpy(dest, source, columns * blockSize); + } + } +} + +template <typename type, uint32_t firstBits, uint32_t secondBits, uint32_t thirdBits, uint32_t fourthBits> +inline void Initialize4ComponentData(size_t width, size_t height, size_t depth, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + type writeValues[4] = + { + gl::bitCast<type>(firstBits), + gl::bitCast<type>(secondBits), + gl::bitCast<type>(thirdBits), + gl::bitCast<type>(fourthBits), + }; + + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + type *destRow = priv::OffsetDataPointer<type>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + type* destPixel = destRow + x * 4; + + // This could potentially be optimized by generating an entire row of initialization + // data and copying row by row instead of pixel by pixel. + memcpy(destPixel, writeValues, sizeof(type) * 4); + } + } + } +} + +template <size_t blockWidth, size_t blockHeight> +inline void LoadASTCToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + LoadASTCToRGBA8Inner(width, height, depth, blockWidth, blockHeight, input, inputRowPitch, + inputDepthPitch, output, outputRowPitch, outputDepthPitch); +} + +template <uint32_t indexBits, uint32_t redBlueBits, uint32_t greenBits, uint32_t alphaBits> +inline void LoadPalettedToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + static_assert(indexBits == 4 || indexBits == 8); + static_assert(redBlueBits == 4 || redBlueBits == 5 || redBlueBits == 8); + static_assert(greenBits == 4 || greenBits == 5 || greenBits == 6 || greenBits == 8); + static_assert(alphaBits == 0 || alphaBits == 1 || alphaBits == 4 || alphaBits == 8); + constexpr uint32_t colorBits = 2 * redBlueBits + greenBits + alphaBits; + static_assert(colorBits == 16 || colorBits == 24 || colorBits == 32); + + LoadPalettedToRGBA8Impl(width, height, depth, + indexBits, redBlueBits, greenBits, alphaBits, + input, inputRowPitch, inputDepthPitch, + output, outputRowPitch, outputDepthPitch); +} + +} // namespace angle diff --git a/gfx/angle/checkout/src/image_util/loadimage_astc.cpp b/gfx/angle/checkout/src/image_util/loadimage_astc.cpp new file mode 100644 index 0000000000..34fd164322 --- /dev/null +++ b/gfx/angle/checkout/src/image_util/loadimage_astc.cpp @@ -0,0 +1,84 @@ +// +// Copyright 2022 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. +// + +// loadimage_astc.cpp: Decodes ASTC encoded textures. + +#ifdef ANGLE_HAS_ASTCENC +# include <astcenc.h> +#endif + +#include "image_util/loadimage.h" + +namespace angle +{ + +void LoadASTCToRGBA8Inner(size_t width, + size_t height, + size_t depth, + uint32_t blockWidth, + uint32_t blockHeight, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ +#ifdef ANGLE_HAS_ASTCENC + astcenc_config config; + + constexpr unsigned int kBlockZ = 1; + + const float kQuality = ASTCENC_PRE_MEDIUM; + constexpr astcenc_profile kProfile = ASTCENC_PRF_LDR; + + astcenc_error status; + status = astcenc_config_init(kProfile, blockWidth, blockHeight, kBlockZ, kQuality, + ASTCENC_FLG_DECOMPRESS_ONLY, &config); + if (status != ASTCENC_SUCCESS) + { + WARN() << "astcenc config init failed: " << astcenc_get_error_string(status); + return; + } + + constexpr unsigned int kThreadCount = 1; + + astcenc_context *context; + status = astcenc_context_alloc(&config, kThreadCount, &context); + if (status != ASTCENC_SUCCESS) + { + WARN() << "Could not allocate astcenc context: " << astcenc_get_error_string(status); + return; + } + + // Compute the number of ASTC blocks in each dimension + uint32_t blockCountX = (static_cast<uint32_t>(width) + config.block_x - 1) / config.block_x; + uint32_t blockCountY = (static_cast<uint32_t>(height) + config.block_y - 1) / config.block_y; + + // Space needed for 16 bytes of output per compressed block + size_t blockSize = blockCountX * blockCountY * 16; + + astcenc_image image; + image.dim_x = static_cast<uint32_t>(width); + image.dim_y = static_cast<uint32_t>(height); + image.dim_z = 1; + image.data_type = ASTCENC_TYPE_U8; + image.data = reinterpret_cast<void **>(&output); + + constexpr astcenc_swizzle swizzle{ASTCENC_SWZ_R, ASTCENC_SWZ_G, ASTCENC_SWZ_B, ASTCENC_SWZ_A}; + + status = astcenc_decompress_image(context, input, blockSize, &image, &swizzle, 0); + if (status != ASTCENC_SUCCESS) + { + WARN() << "astcenc decompress failed: " << astcenc_get_error_string(status); + } + + astcenc_context_free(context); +#else + ERR() << "Trying to decode ASTC without having ASTC support built."; +#endif +} +} // namespace angle diff --git a/gfx/angle/checkout/src/image_util/loadimage_etc.cpp b/gfx/angle/checkout/src/image_util/loadimage_etc.cpp new file mode 100644 index 0000000000..5eca88ef04 --- /dev/null +++ b/gfx/angle/checkout/src/image_util/loadimage_etc.cpp @@ -0,0 +1,1994 @@ +// +// Copyright 2013 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. +// + +// loadimage_etc.cpp: Decodes ETC and EAC encoded textures. + +#include "image_util/loadimage.h" + +#include <type_traits> +#include "common/mathutil.h" + +#include "image_util/imageformats.h" + +namespace angle +{ +namespace +{ + +using IntensityModifier = const int[4]; + +// Table 3.17.2 sorted according to table 3.17.3 +// clang-format off +static IntensityModifier intensityModifierDefault[] = +{ + { 2, 8, -2, -8 }, + { 5, 17, -5, -17 }, + { 9, 29, -9, -29 }, + { 13, 42, -13, -42 }, + { 18, 60, -18, -60 }, + { 24, 80, -24, -80 }, + { 33, 106, -33, -106 }, + { 47, 183, -47, -183 }, +}; +// clang-format on + +// Table C.12, intensity modifier for non opaque punchthrough alpha +// clang-format off +static IntensityModifier intensityModifierNonOpaque[] = +{ + { 0, 8, 0, -8 }, + { 0, 17, 0, -17 }, + { 0, 29, 0, -29 }, + { 0, 42, 0, -42 }, + { 0, 60, 0, -60 }, + { 0, 80, 0, -80 }, + { 0, 106, 0, -106 }, + { 0, 183, 0, -183 }, +}; +// clang-format on + +static const int kNumPixelsInBlock = 16; + +struct ETC2Block +{ + // Decodes unsigned single or dual channel ETC2 block to 8-bit color + void decodeAsSingleETC2Channel(uint8_t *dest, + size_t x, + size_t y, + size_t w, + size_t h, + size_t destPixelStride, + size_t destRowPitch, + bool isSigned) const + { + for (size_t j = 0; j < 4 && (y + j) < h; j++) + { + uint8_t *row = dest + (j * destRowPitch); + for (size_t i = 0; i < 4 && (x + i) < w; i++) + { + uint8_t *pixel = row + (i * destPixelStride); + if (isSigned) + { + *pixel = clampSByte(getSingleETC2Channel(i, j, isSigned)); + } + else + { + *pixel = clampByte(getSingleETC2Channel(i, j, isSigned)); + } + } + } + } + + // Decodes unsigned single or dual channel EAC block to 16-bit color + void decodeAsSingleEACChannel(uint16_t *dest, + size_t x, + size_t y, + size_t w, + size_t h, + size_t destPixelStride, + size_t destRowPitch, + bool isSigned, + bool isFloat) const + { + for (size_t j = 0; j < 4 && (y + j) < h; j++) + { + uint16_t *row = reinterpret_cast<uint16_t *>(reinterpret_cast<uint8_t *>(dest) + + (j * destRowPitch)); + for (size_t i = 0; i < 4 && (x + i) < w; i++) + { + uint16_t *pixel = row + (i * destPixelStride); + if (isSigned) + { + int16_t tempPixel = + renormalizeEAC<int16_t>(getSingleEACChannel(i, j, isSigned)); + *pixel = + isFloat ? gl::float32ToFloat16(float(gl::normalize(tempPixel))) : tempPixel; + } + else + { + uint16_t tempPixel = + renormalizeEAC<uint16_t>(getSingleEACChannel(i, j, isSigned)); + *pixel = + isFloat ? gl::float32ToFloat16(float(gl::normalize(tempPixel))) : tempPixel; + } + } + } + } + + // Decodes RGB block to rgba8 + void decodeAsRGB(uint8_t *dest, + size_t x, + size_t y, + size_t w, + size_t h, + size_t destRowPitch, + const uint8_t alphaValues[4][4], + bool punchThroughAlpha) const + { + bool opaqueBit = u.idht.mode.idm.diffbit; + bool nonOpaquePunchThroughAlpha = punchThroughAlpha && !opaqueBit; + // Select mode + if (u.idht.mode.idm.diffbit || punchThroughAlpha) + { + const auto &block = u.idht.mode.idm.colors.diff; + int r = (block.R + block.dR); + int g = (block.G + block.dG); + int b = (block.B + block.dB); + if (r < 0 || r > 31) + { + decodeTBlock(dest, x, y, w, h, destRowPitch, alphaValues, + nonOpaquePunchThroughAlpha); + } + else if (g < 0 || g > 31) + { + decodeHBlock(dest, x, y, w, h, destRowPitch, alphaValues, + nonOpaquePunchThroughAlpha); + } + else if (b < 0 || b > 31) + { + decodePlanarBlock(dest, x, y, w, h, destRowPitch, alphaValues); + } + else + { + decodeDifferentialBlock(dest, x, y, w, h, destRowPitch, alphaValues, + nonOpaquePunchThroughAlpha); + } + } + else + { + decodeIndividualBlock(dest, x, y, w, h, destRowPitch, alphaValues, + nonOpaquePunchThroughAlpha); + } + } + + // Transcodes RGB block to BC1 + void transcodeAsBC1(uint8_t *dest, + size_t x, + size_t y, + size_t w, + size_t h, + const uint8_t alphaValues[4][4], + bool punchThroughAlpha) const + { + bool opaqueBit = u.idht.mode.idm.diffbit; + bool nonOpaquePunchThroughAlpha = punchThroughAlpha && !opaqueBit; + // Select mode + if (u.idht.mode.idm.diffbit || punchThroughAlpha) + { + const auto &block = u.idht.mode.idm.colors.diff; + int r = (block.R + block.dR); + int g = (block.G + block.dG); + int b = (block.B + block.dB); + if (r < 0 || r > 31) + { + transcodeTBlockToBC1(dest, x, y, w, h, alphaValues, nonOpaquePunchThroughAlpha); + } + else if (g < 0 || g > 31) + { + transcodeHBlockToBC1(dest, x, y, w, h, alphaValues, nonOpaquePunchThroughAlpha); + } + else if (b < 0 || b > 31) + { + transcodePlanarBlockToBC1(dest, x, y, w, h, alphaValues); + } + else + { + transcodeDifferentialBlockToBC1(dest, x, y, w, h, alphaValues, + nonOpaquePunchThroughAlpha); + } + } + else + { + transcodeIndividualBlockToBC1(dest, x, y, w, h, alphaValues, + nonOpaquePunchThroughAlpha); + } + } + + private: + union + { + // Individual, differential, H and T modes + struct + { + union + { + // Individual and differential modes + struct + { + union + { + struct // Individual colors + { + unsigned char R2 : 4; + unsigned char R1 : 4; + unsigned char G2 : 4; + unsigned char G1 : 4; + unsigned char B2 : 4; + unsigned char B1 : 4; + } indiv; + struct // Differential colors + { + signed char dR : 3; + unsigned char R : 5; + signed char dG : 3; + unsigned char G : 5; + signed char dB : 3; + unsigned char B : 5; + } diff; + } colors; + bool flipbit : 1; + bool diffbit : 1; + unsigned char cw2 : 3; + unsigned char cw1 : 3; + } idm; + // T mode + struct + { + // Byte 1 + unsigned char TR1b : 2; + unsigned char TunusedB : 1; + unsigned char TR1a : 2; + unsigned char TunusedA : 3; + // Byte 2 + unsigned char TB1 : 4; + unsigned char TG1 : 4; + // Byte 3 + unsigned char TG2 : 4; + unsigned char TR2 : 4; + // Byte 4 + unsigned char Tdb : 1; + bool Tflipbit : 1; + unsigned char Tda : 2; + unsigned char TB2 : 4; + } tm; + // H mode + struct + { + // Byte 1 + unsigned char HG1a : 3; + unsigned char HR1 : 4; + unsigned char HunusedA : 1; + // Byte 2 + unsigned char HB1b : 2; + unsigned char HunusedC : 1; + unsigned char HB1a : 1; + unsigned char HG1b : 1; + unsigned char HunusedB : 3; + // Byte 3 + unsigned char HG2a : 3; + unsigned char HR2 : 4; + unsigned char HB1c : 1; + // Byte 4 + unsigned char Hdb : 1; + bool Hflipbit : 1; + unsigned char Hda : 1; + unsigned char HB2 : 4; + unsigned char HG2b : 1; + } hm; + } mode; + unsigned char pixelIndexMSB[2]; + unsigned char pixelIndexLSB[2]; + } idht; + // planar mode + struct + { + // Byte 1 + unsigned char GO1 : 1; + unsigned char RO : 6; + unsigned char PunusedA : 1; + // Byte 2 + unsigned char BO1 : 1; + unsigned char GO2 : 6; + unsigned char PunusedB : 1; + // Byte 3 + unsigned char BO3a : 2; + unsigned char PunusedD : 1; + unsigned char BO2 : 2; + unsigned char PunusedC : 3; + // Byte 4 + unsigned char RH2 : 1; + bool Pflipbit : 1; + unsigned char RH1 : 5; + unsigned char BO3b : 1; + // Byte 5 + unsigned char BHa : 1; + unsigned char GH : 7; + // Byte 6 + unsigned char RVa : 3; + unsigned char BHb : 5; + // Byte 7 + unsigned char GVa : 5; + unsigned char RVb : 3; + // Byte 8 + unsigned char BV : 6; + unsigned char GVb : 2; + } pblk; + // Single channel block + struct + { + union + { + unsigned char us; + signed char s; + } base_codeword; + unsigned char table_index : 4; + unsigned char multiplier : 4; + unsigned char mc1 : 2; + unsigned char mb : 3; + unsigned char ma : 3; + unsigned char mf1 : 1; + unsigned char me : 3; + unsigned char md : 3; + unsigned char mc2 : 1; + unsigned char mh : 3; + unsigned char mg : 3; + unsigned char mf2 : 2; + unsigned char mk1 : 2; + unsigned char mj : 3; + unsigned char mi : 3; + unsigned char mn1 : 1; + unsigned char mm : 3; + unsigned char ml : 3; + unsigned char mk2 : 1; + unsigned char mp : 3; + unsigned char mo : 3; + unsigned char mn2 : 2; + } scblk; + } u; + + static unsigned char clampByte(int value) + { + return static_cast<unsigned char>(gl::clamp(value, 0, 255)); + } + + static signed char clampSByte(int value) + { + return static_cast<signed char>(gl::clamp(value, -128, 127)); + } + + template <typename T> + static T renormalizeEAC(int value) + { + int upper = 0; + int lower = 0; + int shift = 0; + + if (std::is_same<T, int16_t>::value) + { + // The spec states that -1024 invalid and should be clamped to -1023 + upper = 1023; + lower = -1023; + shift = 5; + } + else if (std::is_same<T, uint16_t>::value) + { + upper = 2047; + lower = 0; + shift = 5; + } + else + { + // We currently only support renormalizing int16_t or uint16_t + UNREACHABLE(); + } + + return static_cast<T>(gl::clamp(value, lower, upper)) << shift; + } + + static R8G8B8A8 createRGBA(int red, int green, int blue, int alpha) + { + R8G8B8A8 rgba; + rgba.R = clampByte(red); + rgba.G = clampByte(green); + rgba.B = clampByte(blue); + rgba.A = clampByte(alpha); + return rgba; + } + + static R8G8B8A8 createRGBA(int red, int green, int blue) + { + return createRGBA(red, green, blue, 255); + } + + static int extend_4to8bits(int x) { return (x << 4) | x; } + static int extend_5to8bits(int x) { return (x << 3) | (x >> 2); } + static int extend_6to8bits(int x) { return (x << 2) | (x >> 4); } + static int extend_7to8bits(int x) { return (x << 1) | (x >> 6); } + + void decodeIndividualBlock(uint8_t *dest, + size_t x, + size_t y, + size_t w, + size_t h, + size_t destRowPitch, + const uint8_t alphaValues[4][4], + bool nonOpaquePunchThroughAlpha) const + { + const auto &block = u.idht.mode.idm.colors.indiv; + int r1 = extend_4to8bits(block.R1); + int g1 = extend_4to8bits(block.G1); + int b1 = extend_4to8bits(block.B1); + int r2 = extend_4to8bits(block.R2); + int g2 = extend_4to8bits(block.G2); + int b2 = extend_4to8bits(block.B2); + decodeIndividualOrDifferentialBlock(dest, x, y, w, h, destRowPitch, r1, g1, b1, r2, g2, b2, + alphaValues, nonOpaquePunchThroughAlpha); + } + + void decodeDifferentialBlock(uint8_t *dest, + size_t x, + size_t y, + size_t w, + size_t h, + size_t destRowPitch, + const uint8_t alphaValues[4][4], + bool nonOpaquePunchThroughAlpha) const + { + const auto &block = u.idht.mode.idm.colors.diff; + int b1 = extend_5to8bits(block.B); + int g1 = extend_5to8bits(block.G); + int r1 = extend_5to8bits(block.R); + int r2 = extend_5to8bits(block.R + block.dR); + int g2 = extend_5to8bits(block.G + block.dG); + int b2 = extend_5to8bits(block.B + block.dB); + decodeIndividualOrDifferentialBlock(dest, x, y, w, h, destRowPitch, r1, g1, b1, r2, g2, b2, + alphaValues, nonOpaquePunchThroughAlpha); + } + + void decodeIndividualOrDifferentialBlock(uint8_t *dest, + size_t x, + size_t y, + size_t w, + size_t h, + size_t destRowPitch, + int r1, + int g1, + int b1, + int r2, + int g2, + int b2, + const uint8_t alphaValues[4][4], + bool nonOpaquePunchThroughAlpha) const + { + const IntensityModifier *intensityModifier = + nonOpaquePunchThroughAlpha ? intensityModifierNonOpaque : intensityModifierDefault; + + R8G8B8A8 subblockColors0[4]; + R8G8B8A8 subblockColors1[4]; + for (size_t modifierIdx = 0; modifierIdx < 4; modifierIdx++) + { + const int i1 = intensityModifier[u.idht.mode.idm.cw1][modifierIdx]; + subblockColors0[modifierIdx] = createRGBA(r1 + i1, g1 + i1, b1 + i1); + + const int i2 = intensityModifier[u.idht.mode.idm.cw2][modifierIdx]; + subblockColors1[modifierIdx] = createRGBA(r2 + i2, g2 + i2, b2 + i2); + } + + if (u.idht.mode.idm.flipbit) + { + uint8_t *curPixel = dest; + for (size_t j = 0; j < 2 && (y + j) < h; j++) + { + R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel); + for (size_t i = 0; i < 4 && (x + i) < w; i++) + { + row[i] = subblockColors0[getIndex(i, j)]; + row[i].A = alphaValues[j][i]; + } + curPixel += destRowPitch; + } + for (size_t j = 2; j < 4 && (y + j) < h; j++) + { + R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel); + for (size_t i = 0; i < 4 && (x + i) < w; i++) + { + row[i] = subblockColors1[getIndex(i, j)]; + row[i].A = alphaValues[j][i]; + } + curPixel += destRowPitch; + } + } + else + { + uint8_t *curPixel = dest; + for (size_t j = 0; j < 4 && (y + j) < h; j++) + { + R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel); + for (size_t i = 0; i < 2 && (x + i) < w; i++) + { + row[i] = subblockColors0[getIndex(i, j)]; + row[i].A = alphaValues[j][i]; + } + for (size_t i = 2; i < 4 && (x + i) < w; i++) + { + row[i] = subblockColors1[getIndex(i, j)]; + row[i].A = alphaValues[j][i]; + } + curPixel += destRowPitch; + } + } + if (nonOpaquePunchThroughAlpha) + { + decodePunchThroughAlphaBlock(dest, x, y, w, h, destRowPitch); + } + } + + void decodeTBlock(uint8_t *dest, + size_t x, + size_t y, + size_t w, + size_t h, + size_t destRowPitch, + const uint8_t alphaValues[4][4], + bool nonOpaquePunchThroughAlpha) const + { + // Table C.8, distance index for T and H modes + const auto &block = u.idht.mode.tm; + + int r1 = extend_4to8bits(block.TR1a << 2 | block.TR1b); + int g1 = extend_4to8bits(block.TG1); + int b1 = extend_4to8bits(block.TB1); + int r2 = extend_4to8bits(block.TR2); + int g2 = extend_4to8bits(block.TG2); + int b2 = extend_4to8bits(block.TB2); + + static int distance[8] = {3, 6, 11, 16, 23, 32, 41, 64}; + const int d = distance[block.Tda << 1 | block.Tdb]; + + const R8G8B8A8 paintColors[4] = { + createRGBA(r1, g1, b1), + createRGBA(r2 + d, g2 + d, b2 + d), + createRGBA(r2, g2, b2), + createRGBA(r2 - d, g2 - d, b2 - d), + }; + + uint8_t *curPixel = dest; + for (size_t j = 0; j < 4 && (y + j) < h; j++) + { + R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel); + for (size_t i = 0; i < 4 && (x + i) < w; i++) + { + row[i] = paintColors[getIndex(i, j)]; + row[i].A = alphaValues[j][i]; + } + curPixel += destRowPitch; + } + + if (nonOpaquePunchThroughAlpha) + { + decodePunchThroughAlphaBlock(dest, x, y, w, h, destRowPitch); + } + } + + void decodeHBlock(uint8_t *dest, + size_t x, + size_t y, + size_t w, + size_t h, + size_t destRowPitch, + const uint8_t alphaValues[4][4], + bool nonOpaquePunchThroughAlpha) const + { + // Table C.8, distance index for T and H modes + const auto &block = u.idht.mode.hm; + + int r1 = extend_4to8bits(block.HR1); + int g1 = extend_4to8bits(block.HG1a << 1 | block.HG1b); + int b1 = extend_4to8bits(block.HB1a << 3 | block.HB1b << 1 | block.HB1c); + int r2 = extend_4to8bits(block.HR2); + int g2 = extend_4to8bits(block.HG2a << 1 | block.HG2b); + int b2 = extend_4to8bits(block.HB2); + + static const int distance[8] = {3, 6, 11, 16, 23, 32, 41, 64}; + const int orderingTrickBit = + ((r1 << 16 | g1 << 8 | b1) >= (r2 << 16 | g2 << 8 | b2) ? 1 : 0); + const int d = distance[(block.Hda << 2) | (block.Hdb << 1) | orderingTrickBit]; + + const R8G8B8A8 paintColors[4] = { + createRGBA(r1 + d, g1 + d, b1 + d), + createRGBA(r1 - d, g1 - d, b1 - d), + createRGBA(r2 + d, g2 + d, b2 + d), + createRGBA(r2 - d, g2 - d, b2 - d), + }; + + uint8_t *curPixel = dest; + for (size_t j = 0; j < 4 && (y + j) < h; j++) + { + R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel); + for (size_t i = 0; i < 4 && (x + i) < w; i++) + { + row[i] = paintColors[getIndex(i, j)]; + row[i].A = alphaValues[j][i]; + } + curPixel += destRowPitch; + } + + if (nonOpaquePunchThroughAlpha) + { + decodePunchThroughAlphaBlock(dest, x, y, w, h, destRowPitch); + } + } + + void decodePlanarBlock(uint8_t *dest, + size_t x, + size_t y, + size_t w, + size_t h, + size_t pitch, + const uint8_t alphaValues[4][4]) const + { + int ro = extend_6to8bits(u.pblk.RO); + int go = extend_7to8bits(u.pblk.GO1 << 6 | u.pblk.GO2); + int bo = + extend_6to8bits(u.pblk.BO1 << 5 | u.pblk.BO2 << 3 | u.pblk.BO3a << 1 | u.pblk.BO3b); + int rh = extend_6to8bits(u.pblk.RH1 << 1 | u.pblk.RH2); + int gh = extend_7to8bits(u.pblk.GH); + int bh = extend_6to8bits(u.pblk.BHa << 5 | u.pblk.BHb); + int rv = extend_6to8bits(u.pblk.RVa << 3 | u.pblk.RVb); + int gv = extend_7to8bits(u.pblk.GVa << 2 | u.pblk.GVb); + int bv = extend_6to8bits(u.pblk.BV); + + uint8_t *curPixel = dest; + for (size_t j = 0; j < 4 && (y + j) < h; j++) + { + R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel); + + int ry = static_cast<int>(j) * (rv - ro) + 2; + int gy = static_cast<int>(j) * (gv - go) + 2; + int by = static_cast<int>(j) * (bv - bo) + 2; + for (size_t i = 0; i < 4 && (x + i) < w; i++) + { + row[i] = createRGBA(((static_cast<int>(i) * (rh - ro) + ry) >> 2) + ro, + ((static_cast<int>(i) * (gh - go) + gy) >> 2) + go, + ((static_cast<int>(i) * (bh - bo) + by) >> 2) + bo, + alphaValues[j][i]); + } + curPixel += pitch; + } + } + + // Index for individual, differential, H and T modes + size_t getIndex(size_t x, size_t y) const + { + size_t bitIndex = x * 4 + y; + size_t bitOffset = bitIndex & 7; + size_t lsb = (u.idht.pixelIndexLSB[1 - (bitIndex >> 3)] >> bitOffset) & 1; + size_t msb = (u.idht.pixelIndexMSB[1 - (bitIndex >> 3)] >> bitOffset) & 1; + return (msb << 1) | lsb; + } + + void decodePunchThroughAlphaBlock(uint8_t *dest, + size_t x, + size_t y, + size_t w, + size_t h, + size_t destRowPitch) const + { + uint8_t *curPixel = dest; + for (size_t j = 0; j < 4 && (y + j) < h; j++) + { + R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel); + for (size_t i = 0; i < 4 && (x + i) < w; i++) + { + if (getIndex(i, j) == 2) // msb == 1 && lsb == 0 + { + row[i] = createRGBA(0, 0, 0, 0); + } + } + curPixel += destRowPitch; + } + } + + uint16_t RGB8ToRGB565(const R8G8B8A8 &rgba) const + { + return (static_cast<uint16_t>(rgba.R >> 3) << 11) | + (static_cast<uint16_t>(rgba.G >> 2) << 5) | + (static_cast<uint16_t>(rgba.B >> 3) << 0); + } + + uint32_t matchBC1Bits(const int *pixelIndices, + const int *pixelIndexCounts, + const R8G8B8A8 *subblockColors, + size_t numColors, + const R8G8B8A8 &minColor, + const R8G8B8A8 &maxColor, + bool nonOpaquePunchThroughAlpha) const + { + // Project each pixel on the (maxColor, minColor) line to decide which + // BC1 code to assign to it. + + uint8_t decodedColors[2][3] = {{maxColor.R, maxColor.G, maxColor.B}, + {minColor.R, minColor.G, minColor.B}}; + + int direction[3]; + for (int ch = 0; ch < 3; ch++) + { + direction[ch] = decodedColors[0][ch] - decodedColors[1][ch]; + } + + int stops[2]; + for (int i = 0; i < 2; i++) + { + stops[i] = decodedColors[i][0] * direction[0] + decodedColors[i][1] * direction[1] + + decodedColors[i][2] * direction[2]; + } + + ASSERT(numColors <= kNumPixelsInBlock); + + int encodedColors[kNumPixelsInBlock]; + if (nonOpaquePunchThroughAlpha) + { + for (size_t i = 0; i < numColors; i++) + { + const int count = pixelIndexCounts[i]; + if (count > 0) + { + // In non-opaque mode, 3 is for tranparent pixels. + + if (0 == subblockColors[i].A) + { + encodedColors[i] = 3; + } + else + { + const R8G8B8A8 &pixel = subblockColors[i]; + const int dot = pixel.R * direction[0] + pixel.G * direction[1] + + pixel.B * direction[2]; + const int factor = gl::clamp( + static_cast<int>( + (static_cast<float>(dot - stops[1]) / (stops[0] - stops[1])) * 2 + + 0.5f), + 0, 2); + switch (factor) + { + case 0: + encodedColors[i] = 0; + break; + case 1: + encodedColors[i] = 2; + break; + case 2: + default: + encodedColors[i] = 1; + break; + } + } + } + } + } + else + { + for (size_t i = 0; i < numColors; i++) + { + const int count = pixelIndexCounts[i]; + if (count > 0) + { + // In opaque mode, the code is from 0 to 3. + + const R8G8B8A8 &pixel = subblockColors[i]; + const int dot = + pixel.R * direction[0] + pixel.G * direction[1] + pixel.B * direction[2]; + const int factor = gl::clamp( + static_cast<int>( + (static_cast<float>(dot - stops[1]) / (stops[0] - stops[1])) * 3 + + 0.5f), + 0, 3); + switch (factor) + { + case 0: + encodedColors[i] = 1; + break; + case 1: + encodedColors[i] = 3; + break; + case 2: + encodedColors[i] = 2; + break; + case 3: + default: + encodedColors[i] = 0; + break; + } + } + } + } + + uint32_t bits = 0; + for (int i = kNumPixelsInBlock - 1; i >= 0; i--) + { + bits <<= 2; + bits |= encodedColors[pixelIndices[i]]; + } + + return bits; + } + + void packBC1(void *bc1, + const int *pixelIndices, + const int *pixelIndexCounts, + const R8G8B8A8 *subblockColors, + size_t numColors, + int minColorIndex, + int maxColorIndex, + bool nonOpaquePunchThroughAlpha) const + { + const R8G8B8A8 &minColor = subblockColors[minColorIndex]; + const R8G8B8A8 &maxColor = subblockColors[maxColorIndex]; + + uint32_t bits; + uint16_t max16 = RGB8ToRGB565(maxColor); + uint16_t min16 = RGB8ToRGB565(minColor); + if (max16 != min16) + { + // Find the best BC1 code for each pixel + bits = matchBC1Bits(pixelIndices, pixelIndexCounts, subblockColors, numColors, minColor, + maxColor, nonOpaquePunchThroughAlpha); + } + else + { + // Same colors, BC1 index 0 is the color in both opaque and transparent mode + bits = 0; + // BC1 index 3 is transparent + if (nonOpaquePunchThroughAlpha) + { + for (int i = 0; i < kNumPixelsInBlock; i++) + { + if (0 == subblockColors[pixelIndices[i]].A) + { + bits |= (3 << (i * 2)); + } + } + } + } + + if (max16 < min16) + { + std::swap(max16, min16); + + uint32_t xorMask = 0; + if (nonOpaquePunchThroughAlpha) + { + // In transparent mode switching the colors is doing the + // following code swap: 0 <-> 1. 0xA selects the second bit of + // each code, bits >> 1 selects the first bit of the code when + // the seconds bit is set (case 2 and 3). We invert all the + // non-selected bits, that is the first bit when the code is + // 0 or 1. + xorMask = ~((bits >> 1) | 0xAAAAAAAA); + } + else + { + // In opaque mode switching the two colors is doing the + // following code swaps: 0 <-> 1 and 2 <-> 3. This is + // equivalent to flipping the first bit of each code + // (5 = 0b0101) + xorMask = 0x55555555; + } + bits ^= xorMask; + } + + struct BC1Block + { + uint16_t color0; + uint16_t color1; + uint32_t bits; + }; + + // Encode the opaqueness in the order of the two BC1 colors + BC1Block *dest = reinterpret_cast<BC1Block *>(bc1); + if (nonOpaquePunchThroughAlpha) + { + dest->color0 = min16; + dest->color1 = max16; + } + else + { + dest->color0 = max16; + dest->color1 = min16; + } + dest->bits = bits; + } + + void transcodeIndividualBlockToBC1(uint8_t *dest, + size_t x, + size_t y, + size_t w, + size_t h, + const uint8_t alphaValues[4][4], + bool nonOpaquePunchThroughAlpha) const + { + const auto &block = u.idht.mode.idm.colors.indiv; + int r1 = extend_4to8bits(block.R1); + int g1 = extend_4to8bits(block.G1); + int b1 = extend_4to8bits(block.B1); + int r2 = extend_4to8bits(block.R2); + int g2 = extend_4to8bits(block.G2); + int b2 = extend_4to8bits(block.B2); + transcodeIndividualOrDifferentialBlockToBC1(dest, x, y, w, h, r1, g1, b1, r2, g2, b2, + alphaValues, nonOpaquePunchThroughAlpha); + } + + void transcodeDifferentialBlockToBC1(uint8_t *dest, + size_t x, + size_t y, + size_t w, + size_t h, + const uint8_t alphaValues[4][4], + bool nonOpaquePunchThroughAlpha) const + { + const auto &block = u.idht.mode.idm.colors.diff; + int b1 = extend_5to8bits(block.B); + int g1 = extend_5to8bits(block.G); + int r1 = extend_5to8bits(block.R); + int r2 = extend_5to8bits(block.R + block.dR); + int g2 = extend_5to8bits(block.G + block.dG); + int b2 = extend_5to8bits(block.B + block.dB); + transcodeIndividualOrDifferentialBlockToBC1(dest, x, y, w, h, r1, g1, b1, r2, g2, b2, + alphaValues, nonOpaquePunchThroughAlpha); + } + + void extractPixelIndices(int *pixelIndices, + int *pixelIndicesCounts, + size_t x, + size_t y, + size_t w, + size_t h, + bool flipbit, + size_t subblockIdx) const + { + size_t dxBegin = 0; + size_t dxEnd = 4; + size_t dyBegin = subblockIdx * 2; + size_t dyEnd = dyBegin + 2; + if (!flipbit) + { + std::swap(dxBegin, dyBegin); + std::swap(dxEnd, dyEnd); + } + + for (size_t j = dyBegin; j < dyEnd; j++) + { + int *row = &pixelIndices[j * 4]; + for (size_t i = dxBegin; i < dxEnd; i++) + { + const size_t pixelIndex = subblockIdx * 4 + getIndex(i, j); + row[i] = static_cast<int>(pixelIndex); + pixelIndicesCounts[pixelIndex]++; + } + } + } + + void selectEndPointPCA(const int *pixelIndexCounts, + const R8G8B8A8 *subblockColors, + size_t numColors, + int *minColorIndex, + int *maxColorIndex) const + { + // determine color distribution + int mu[3], min[3], max[3]; + for (int ch = 0; ch < 3; ch++) + { + int muv = 0; + int minv = 255; + int maxv = 0; + for (size_t i = 0; i < numColors; i++) + { + const int count = pixelIndexCounts[i]; + if (count > 0) + { + const auto &pixel = subblockColors[i]; + if (pixel.A > 0) + { + // Non-transparent pixels + muv += (&pixel.R)[ch] * count; + minv = std::min<int>(minv, (&pixel.R)[ch]); + maxv = std::max<int>(maxv, (&pixel.R)[ch]); + } + } + } + + mu[ch] = (muv + kNumPixelsInBlock / 2) / kNumPixelsInBlock; + min[ch] = minv; + max[ch] = maxv; + } + + // determine covariance matrix + int cov[6] = {0, 0, 0, 0, 0, 0}; + for (size_t i = 0; i < numColors; i++) + { + const int count = pixelIndexCounts[i]; + if (count > 0) + { + const auto &pixel = subblockColors[i]; + if (pixel.A > 0) + { + int r = pixel.R - mu[0]; + int g = pixel.G - mu[1]; + int b = pixel.B - mu[2]; + + cov[0] += r * r * count; + cov[1] += r * g * count; + cov[2] += r * b * count; + cov[3] += g * g * count; + cov[4] += g * b * count; + cov[5] += b * b * count; + } + } + } + + // Power iteration algorithm to get the eigenvalues and eigenvector + + // Starts with diagonal vector + float vfr = static_cast<float>(max[0] - min[0]); + float vfg = static_cast<float>(max[1] - min[1]); + float vfb = static_cast<float>(max[2] - min[2]); + float eigenvalue = 0.0f; + + constexpr size_t kPowerIterations = 4; + for (size_t i = 0; i < kPowerIterations; i++) + { + float r = vfr * cov[0] + vfg * cov[1] + vfb * cov[2]; + float g = vfr * cov[1] + vfg * cov[3] + vfb * cov[4]; + float b = vfr * cov[2] + vfg * cov[4] + vfb * cov[5]; + + vfr = r; + vfg = g; + vfb = b; + + eigenvalue = sqrt(r * r + g * g + b * b); + if (eigenvalue > 0) + { + float invNorm = 1.0f / eigenvalue; + vfr *= invNorm; + vfg *= invNorm; + vfb *= invNorm; + } + } + + int vr, vg, vb; + + static const float kDefaultLuminanceThreshold = 4.0f * 255; + static const float kQuantizeRange = 512.0f; + if (eigenvalue < kDefaultLuminanceThreshold) // too small, default to luminance + { + // Luminance weights defined by ITU-R Recommendation BT.601, scaled by 1000 + vr = 299; + vg = 587; + vb = 114; + } + else + { + // From the eigenvalue and eigenvector, choose the axis to project + // colors on. When projecting colors we want to do integer computations + // for speed, so we normalize the eigenvector to the [0, 512] range. + float magn = std::max(std::max(std::abs(vfr), std::abs(vfg)), std::abs(vfb)); + magn = kQuantizeRange / magn; + vr = static_cast<int>(vfr * magn); + vg = static_cast<int>(vfg * magn); + vb = static_cast<int>(vfb * magn); + } + + // Pick colors at extreme points + int minD = INT_MAX; + int maxD = 0; + size_t minIndex = 0; + size_t maxIndex = 0; + for (size_t i = 0; i < numColors; i++) + { + const int count = pixelIndexCounts[i]; + if (count > 0) + { + const auto &pixel = subblockColors[i]; + if (pixel.A > 0) + { + int dot = pixel.R * vr + pixel.G * vg + pixel.B * vb; + if (dot < minD) + { + minD = dot; + minIndex = i; + } + if (dot > maxD) + { + maxD = dot; + maxIndex = i; + } + } + } + } + + *minColorIndex = static_cast<int>(minIndex); + *maxColorIndex = static_cast<int>(maxIndex); + } + + void transcodeIndividualOrDifferentialBlockToBC1(uint8_t *dest, + size_t x, + size_t y, + size_t w, + size_t h, + int r1, + int g1, + int b1, + int r2, + int g2, + int b2, + const uint8_t alphaValues[4][4], + bool nonOpaquePunchThroughAlpha) const + { + // A BC1 block has 2 endpoints, pixels is encoded as linear + // interpolations of them. A ETC1/ETC2 individual or differential block + // has 2 subblocks. Each subblock has one color and a modifier. We + // select axis by principal component analysis (PCA) to use as + // our two BC1 endpoints and then map pixels to BC1 by projecting on the + // line between the two endpoints and choosing the right fraction. + + // The goal of this algorithm is make it faster than decode ETC to RGBs + // and then encode to BC. To achieve this, we only extract subblock + // colors, pixel indices, and counts of each pixel indices from ETC. + // With those information, we can only encode used subblock colors + // to BC1, and copy the bits to the right pixels. + // Fully decode and encode need to process 16 RGBA pixels. With this + // algorithm, it's 8 pixels at maximum for a individual or + // differential block. Saves us bandwidth and computations. + + static const size_t kNumColors = 8; + + const IntensityModifier *intensityModifier = + nonOpaquePunchThroughAlpha ? intensityModifierNonOpaque : intensityModifierDefault; + + // Compute the colors that pixels can have in each subblock both for + // the decoding of the RGBA data and BC1 encoding + R8G8B8A8 subblockColors[kNumColors]; + for (size_t modifierIdx = 0; modifierIdx < 4; modifierIdx++) + { + if (nonOpaquePunchThroughAlpha && (modifierIdx == 2)) + { + // In ETC opaque punch through formats, individual and + // differential blocks take index 2 as transparent pixel. + // Thus we don't need to compute its color, just assign it + // as black. + subblockColors[modifierIdx] = createRGBA(0, 0, 0, 0); + subblockColors[4 + modifierIdx] = createRGBA(0, 0, 0, 0); + } + else + { + const int i1 = intensityModifier[u.idht.mode.idm.cw1][modifierIdx]; + subblockColors[modifierIdx] = createRGBA(r1 + i1, g1 + i1, b1 + i1); + + const int i2 = intensityModifier[u.idht.mode.idm.cw2][modifierIdx]; + subblockColors[4 + modifierIdx] = createRGBA(r2 + i2, g2 + i2, b2 + i2); + } + } + + int pixelIndices[kNumPixelsInBlock]; + int pixelIndexCounts[kNumColors] = {0}; + // Extract pixel indices from a ETC block. + for (size_t blockIdx = 0; blockIdx < 2; blockIdx++) + { + extractPixelIndices(pixelIndices, pixelIndexCounts, x, y, w, h, u.idht.mode.idm.flipbit, + blockIdx); + } + + int minColorIndex, maxColorIndex; + selectEndPointPCA(pixelIndexCounts, subblockColors, kNumColors, &minColorIndex, + &maxColorIndex); + + packBC1(dest, pixelIndices, pixelIndexCounts, subblockColors, kNumColors, minColorIndex, + maxColorIndex, nonOpaquePunchThroughAlpha); + } + + void transcodeTBlockToBC1(uint8_t *dest, + size_t x, + size_t y, + size_t w, + size_t h, + const uint8_t alphaValues[4][4], + bool nonOpaquePunchThroughAlpha) const + { + static const size_t kNumColors = 4; + + // Table C.8, distance index for T and H modes + const auto &block = u.idht.mode.tm; + + int r1 = extend_4to8bits(block.TR1a << 2 | block.TR1b); + int g1 = extend_4to8bits(block.TG1); + int b1 = extend_4to8bits(block.TB1); + int r2 = extend_4to8bits(block.TR2); + int g2 = extend_4to8bits(block.TG2); + int b2 = extend_4to8bits(block.TB2); + + static int distance[8] = {3, 6, 11, 16, 23, 32, 41, 64}; + const int d = distance[block.Tda << 1 | block.Tdb]; + + // In ETC opaque punch through formats, index == 2 means transparent pixel. + // Thus we don't need to compute its color, just assign it as black. + const R8G8B8A8 paintColors[kNumColors] = { + createRGBA(r1, g1, b1), + createRGBA(r2 + d, g2 + d, b2 + d), + nonOpaquePunchThroughAlpha ? createRGBA(0, 0, 0, 0) : createRGBA(r2, g2, b2), + createRGBA(r2 - d, g2 - d, b2 - d), + }; + + int pixelIndices[kNumPixelsInBlock]; + int pixelIndexCounts[kNumColors] = {0}; + for (size_t j = 0; j < 4; j++) + { + int *row = &pixelIndices[j * 4]; + for (size_t i = 0; i < 4; i++) + { + const size_t pixelIndex = getIndex(i, j); + row[i] = static_cast<int>(pixelIndex); + pixelIndexCounts[pixelIndex]++; + } + } + + int minColorIndex, maxColorIndex; + selectEndPointPCA(pixelIndexCounts, paintColors, kNumColors, &minColorIndex, + &maxColorIndex); + + packBC1(dest, pixelIndices, pixelIndexCounts, paintColors, kNumColors, minColorIndex, + maxColorIndex, nonOpaquePunchThroughAlpha); + } + + void transcodeHBlockToBC1(uint8_t *dest, + size_t x, + size_t y, + size_t w, + size_t h, + const uint8_t alphaValues[4][4], + bool nonOpaquePunchThroughAlpha) const + { + static const size_t kNumColors = 4; + + // Table C.8, distance index for T and H modes + const auto &block = u.idht.mode.hm; + + int r1 = extend_4to8bits(block.HR1); + int g1 = extend_4to8bits(block.HG1a << 1 | block.HG1b); + int b1 = extend_4to8bits(block.HB1a << 3 | block.HB1b << 1 | block.HB1c); + int r2 = extend_4to8bits(block.HR2); + int g2 = extend_4to8bits(block.HG2a << 1 | block.HG2b); + int b2 = extend_4to8bits(block.HB2); + + static const int distance[8] = {3, 6, 11, 16, 23, 32, 41, 64}; + const int orderingTrickBit = + ((r1 << 16 | g1 << 8 | b1) >= (r2 << 16 | g2 << 8 | b2) ? 1 : 0); + const int d = distance[(block.Hda << 2) | (block.Hdb << 1) | orderingTrickBit]; + + // In ETC opaque punch through formats, index == 2 means transparent pixel. + // Thus we don't need to compute its color, just assign it as black. + const R8G8B8A8 paintColors[kNumColors] = { + createRGBA(r1 + d, g1 + d, b1 + d), + createRGBA(r1 - d, g1 - d, b1 - d), + nonOpaquePunchThroughAlpha ? createRGBA(0, 0, 0, 0) + : createRGBA(r2 + d, g2 + d, b2 + d), + createRGBA(r2 - d, g2 - d, b2 - d), + }; + + int pixelIndices[kNumPixelsInBlock]; + int pixelIndexCounts[kNumColors] = {0}; + for (size_t j = 0; j < 4; j++) + { + int *row = &pixelIndices[j * 4]; + for (size_t i = 0; i < 4; i++) + { + const size_t pixelIndex = getIndex(i, j); + row[i] = static_cast<int>(pixelIndex); + pixelIndexCounts[pixelIndex]++; + } + } + + int minColorIndex, maxColorIndex; + selectEndPointPCA(pixelIndexCounts, paintColors, kNumColors, &minColorIndex, + &maxColorIndex); + + packBC1(dest, pixelIndices, pixelIndexCounts, paintColors, kNumColors, minColorIndex, + maxColorIndex, nonOpaquePunchThroughAlpha); + } + + void transcodePlanarBlockToBC1(uint8_t *dest, + size_t x, + size_t y, + size_t w, + size_t h, + const uint8_t alphaValues[4][4]) const + { + static const size_t kNumColors = kNumPixelsInBlock; + + R8G8B8A8 rgbaBlock[kNumColors]; + decodePlanarBlock(reinterpret_cast<uint8_t *>(rgbaBlock), x, y, w, h, sizeof(R8G8B8A8) * 4, + alphaValues); + + // Planar block doesn't have a color table, fill indices as full + int pixelIndices[kNumPixelsInBlock] = {0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15}; + int pixelIndexCounts[kNumColors] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + + int minColorIndex, maxColorIndex; + selectEndPointPCA(pixelIndexCounts, rgbaBlock, kNumColors, &minColorIndex, &maxColorIndex); + + packBC1(dest, pixelIndices, pixelIndexCounts, rgbaBlock, kNumColors, minColorIndex, + maxColorIndex, false); + } + + // Single channel utility functions + int getSingleEACChannel(size_t x, size_t y, bool isSigned) const + { + int codeword = isSigned ? u.scblk.base_codeword.s : u.scblk.base_codeword.us; + int multiplier = (u.scblk.multiplier == 0) ? 1 : u.scblk.multiplier * 8; + return codeword * 8 + 4 + getSingleChannelModifier(x, y) * multiplier; + } + + int getSingleETC2Channel(size_t x, size_t y, bool isSigned) const + { + int codeword = isSigned ? u.scblk.base_codeword.s : u.scblk.base_codeword.us; + return codeword + getSingleChannelModifier(x, y) * u.scblk.multiplier; + } + + int getSingleChannelIndex(size_t x, size_t y) const + { + ASSERT(x < 4 && y < 4); + + // clang-format off + switch (x * 4 + y) + { + case 0: return u.scblk.ma; + case 1: return u.scblk.mb; + case 2: return u.scblk.mc1 << 1 | u.scblk.mc2; + case 3: return u.scblk.md; + case 4: return u.scblk.me; + case 5: return u.scblk.mf1 << 2 | u.scblk.mf2; + case 6: return u.scblk.mg; + case 7: return u.scblk.mh; + case 8: return u.scblk.mi; + case 9: return u.scblk.mj; + case 10: return u.scblk.mk1 << 1 | u.scblk.mk2; + case 11: return u.scblk.ml; + case 12: return u.scblk.mm; + case 13: return u.scblk.mn1 << 2 | u.scblk.mn2; + case 14: return u.scblk.mo; + case 15: return u.scblk.mp; + default: UNREACHABLE(); return 0; + } + // clang-format on + } + + int getSingleChannelModifier(size_t x, size_t y) const + { + // clang-format off + static const int modifierTable[16][8] = + { + { -3, -6, -9, -15, 2, 5, 8, 14 }, + { -3, -7, -10, -13, 2, 6, 9, 12 }, + { -2, -5, -8, -13, 1, 4, 7, 12 }, + { -2, -4, -6, -13, 1, 3, 5, 12 }, + { -3, -6, -8, -12, 2, 5, 7, 11 }, + { -3, -7, -9, -11, 2, 6, 8, 10 }, + { -4, -7, -8, -11, 3, 6, 7, 10 }, + { -3, -5, -8, -11, 2, 4, 7, 10 }, + { -2, -6, -8, -10, 1, 5, 7, 9 }, + { -2, -5, -8, -10, 1, 4, 7, 9 }, + { -2, -4, -8, -10, 1, 3, 7, 9 }, + { -2, -5, -7, -10, 1, 4, 6, 9 }, + { -3, -4, -7, -10, 2, 3, 6, 9 }, + { -1, -2, -3, -10, 0, 1, 2, 9 }, + { -4, -6, -8, -9, 3, 5, 7, 8 }, + { -3, -5, -7, -9, 2, 4, 6, 8 } + }; + // clang-format on + + return modifierTable[u.scblk.table_index][getSingleChannelIndex(x, y)]; + } +}; + +// clang-format off +static const uint8_t DefaultETCAlphaValues[4][4] = +{ + { 255, 255, 255, 255 }, + { 255, 255, 255, 255 }, + { 255, 255, 255, 255 }, + { 255, 255, 255, 255 }, +}; + +// clang-format on +void LoadR11EACToR8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch, + bool isSigned) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y += 4) + { + const ETC2Block *sourceRow = + priv::OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch); + uint8_t *destRow = + priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + + for (size_t x = 0; x < width; x += 4) + { + const ETC2Block *sourceBlock = sourceRow + (x / 4); + uint8_t *destPixels = destRow + x; + + sourceBlock->decodeAsSingleETC2Channel(destPixels, x, y, width, height, 1, + outputRowPitch, isSigned); + } + } + } +} + +void LoadRG11EACToRG8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch, + bool isSigned) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y += 4) + { + const ETC2Block *sourceRow = + priv::OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch); + uint8_t *destRow = + priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + + for (size_t x = 0; x < width; x += 4) + { + uint8_t *destPixelsRed = destRow + (x * 2); + const ETC2Block *sourceBlockRed = sourceRow + (x / 2); + sourceBlockRed->decodeAsSingleETC2Channel(destPixelsRed, x, y, width, height, 2, + outputRowPitch, isSigned); + + uint8_t *destPixelsGreen = destPixelsRed + 1; + const ETC2Block *sourceBlockGreen = sourceBlockRed + 1; + sourceBlockGreen->decodeAsSingleETC2Channel(destPixelsGreen, x, y, width, height, 2, + outputRowPitch, isSigned); + } + } + } +} + +void LoadR11EACToR16(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch, + bool isSigned, + bool isFloat) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y += 4) + { + const ETC2Block *sourceRow = + priv::OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch); + uint16_t *destRow = + priv::OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch); + + for (size_t x = 0; x < width; x += 4) + { + const ETC2Block *sourceBlock = sourceRow + (x / 4); + uint16_t *destPixels = destRow + x; + + sourceBlock->decodeAsSingleEACChannel(destPixels, x, y, width, height, 1, + outputRowPitch, isSigned, isFloat); + } + } + } +} + +void LoadRG11EACToRG16(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch, + bool isSigned, + bool isFloat) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y += 4) + { + const ETC2Block *sourceRow = + priv::OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch); + uint16_t *destRow = + priv::OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch); + + for (size_t x = 0; x < width; x += 4) + { + uint16_t *destPixelsRed = destRow + (x * 2); + const ETC2Block *sourceBlockRed = sourceRow + (x / 2); + sourceBlockRed->decodeAsSingleEACChannel(destPixelsRed, x, y, width, height, 2, + outputRowPitch, isSigned, isFloat); + + uint16_t *destPixelsGreen = destPixelsRed + 1; + const ETC2Block *sourceBlockGreen = sourceBlockRed + 1; + sourceBlockGreen->decodeAsSingleEACChannel(destPixelsGreen, x, y, width, height, 2, + outputRowPitch, isSigned, isFloat); + } + } + } +} + +void LoadETC2RGB8ToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch, + bool punchthroughAlpha) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y += 4) + { + const ETC2Block *sourceRow = + priv::OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch); + uint8_t *destRow = + priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + + for (size_t x = 0; x < width; x += 4) + { + const ETC2Block *sourceBlock = sourceRow + (x / 4); + uint8_t *destPixels = destRow + (x * 4); + + sourceBlock->decodeAsRGB(destPixels, x, y, width, height, outputRowPitch, + DefaultETCAlphaValues, punchthroughAlpha); + } + } + } +} + +void LoadETC2RGB8ToBC1(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch, + bool punchthroughAlpha) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y += 4) + { + const ETC2Block *sourceRow = + priv::OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch); + uint8_t *destRow = priv::OffsetDataPointer<uint8_t>(output, y / 4, z, outputRowPitch, + outputDepthPitch); + + for (size_t x = 0; x < width; x += 4) + { + const ETC2Block *sourceBlock = sourceRow + (x / 4); + uint8_t *destPixels = destRow + (x * 2); + + sourceBlock->transcodeAsBC1(destPixels, x, y, width, height, DefaultETCAlphaValues, + punchthroughAlpha); + } + } + } +} + +void LoadETC2RGBA8ToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch, + bool srgb) +{ + uint8_t decodedAlphaValues[4][4]; + + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y += 4) + { + const ETC2Block *sourceRow = + priv::OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch); + uint8_t *destRow = + priv::OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + + for (size_t x = 0; x < width; x += 4) + { + const ETC2Block *sourceBlockAlpha = sourceRow + (x / 2); + sourceBlockAlpha->decodeAsSingleETC2Channel( + reinterpret_cast<uint8_t *>(decodedAlphaValues), x, y, width, height, 1, 4, + false); + + uint8_t *destPixels = destRow + (x * 4); + const ETC2Block *sourceBlockRGB = sourceBlockAlpha + 1; + sourceBlockRGB->decodeAsRGB(destPixels, x, y, width, height, outputRowPitch, + decodedAlphaValues, false); + } + } + } +} + +} // anonymous namespace + +void LoadETC1RGB8ToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + LoadETC2RGB8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, + outputRowPitch, outputDepthPitch, false); +} + +void LoadETC1RGB8ToBC1(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + LoadETC2RGB8ToBC1(width, height, depth, input, inputRowPitch, inputDepthPitch, output, + outputRowPitch, outputDepthPitch, false); +} + +void LoadEACR11ToR8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + LoadR11EACToR8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, + outputRowPitch, outputDepthPitch, false); +} + +void LoadEACR11SToR8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + LoadR11EACToR8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, + outputRowPitch, outputDepthPitch, true); +} + +void LoadEACRG11ToRG8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + LoadRG11EACToRG8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, + outputRowPitch, outputDepthPitch, false); +} + +void LoadEACRG11SToRG8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + LoadRG11EACToRG8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, + outputRowPitch, outputDepthPitch, true); +} + +void LoadEACR11ToR16(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + LoadR11EACToR16(width, height, depth, input, inputRowPitch, inputDepthPitch, output, + outputRowPitch, outputDepthPitch, false, false); +} + +void LoadEACR11SToR16(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + LoadR11EACToR16(width, height, depth, input, inputRowPitch, inputDepthPitch, output, + outputRowPitch, outputDepthPitch, true, false); +} + +void LoadEACRG11ToRG16(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + LoadRG11EACToRG16(width, height, depth, input, inputRowPitch, inputDepthPitch, output, + outputRowPitch, outputDepthPitch, false, false); +} + +void LoadEACRG11SToRG16(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + LoadRG11EACToRG16(width, height, depth, input, inputRowPitch, inputDepthPitch, output, + outputRowPitch, outputDepthPitch, true, false); +} + +void LoadEACR11ToR16F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + LoadR11EACToR16(width, height, depth, input, inputRowPitch, inputDepthPitch, output, + outputRowPitch, outputDepthPitch, false, true); +} + +void LoadEACR11SToR16F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + LoadR11EACToR16(width, height, depth, input, inputRowPitch, inputDepthPitch, output, + outputRowPitch, outputDepthPitch, true, true); +} + +void LoadEACRG11ToRG16F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + LoadRG11EACToRG16(width, height, depth, input, inputRowPitch, inputDepthPitch, output, + outputRowPitch, outputDepthPitch, false, true); +} + +void LoadEACRG11SToRG16F(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + LoadRG11EACToRG16(width, height, depth, input, inputRowPitch, inputDepthPitch, output, + outputRowPitch, outputDepthPitch, true, true); +} + +void LoadETC2RGB8ToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + LoadETC2RGB8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, + outputRowPitch, outputDepthPitch, false); +} + +void LoadETC2RGB8ToBC1(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + LoadETC2RGB8ToBC1(width, height, depth, input, inputRowPitch, inputDepthPitch, output, + outputRowPitch, outputDepthPitch, false); +} + +void LoadETC2SRGB8ToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + LoadETC2RGB8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, + outputRowPitch, outputDepthPitch, false); +} + +void LoadETC2SRGB8ToBC1(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + LoadETC2RGB8ToBC1(width, height, depth, input, inputRowPitch, inputDepthPitch, output, + outputRowPitch, outputDepthPitch, false); +} + +void LoadETC2RGB8A1ToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + LoadETC2RGB8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, + outputRowPitch, outputDepthPitch, true); +} + +void LoadETC2RGB8A1ToBC1(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + LoadETC2RGB8ToBC1(width, height, depth, input, inputRowPitch, inputDepthPitch, output, + outputRowPitch, outputDepthPitch, true); +} + +void LoadETC2SRGB8A1ToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + LoadETC2RGB8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, + outputRowPitch, outputDepthPitch, true); +} + +void LoadETC2SRGB8A1ToBC1(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + LoadETC2RGB8ToBC1(width, height, depth, input, inputRowPitch, inputDepthPitch, output, + outputRowPitch, outputDepthPitch, true); +} + +void LoadETC2RGBA8ToRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + LoadETC2RGBA8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, + outputRowPitch, outputDepthPitch, false); +} + +void LoadETC2SRGBA8ToSRGBA8(size_t width, + size_t height, + size_t depth, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + LoadETC2RGBA8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, + outputRowPitch, outputDepthPitch, true); +} + +} // namespace angle diff --git a/gfx/angle/checkout/src/image_util/loadimage_paletted.cpp b/gfx/angle/checkout/src/image_util/loadimage_paletted.cpp new file mode 100644 index 0000000000..af36ce3cd6 --- /dev/null +++ b/gfx/angle/checkout/src/image_util/loadimage_paletted.cpp @@ -0,0 +1,158 @@ +// +// Copyright 2022 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. +// + +// loadimage_paletted.cpp: Decodes GL_PALETTE_* textures. + +#include "image_util/loadimage.h" + +#include <type_traits> +#include "common/mathutil.h" + +#include "image_util/imageformats.h" + +namespace angle +{ + +namespace +{ + +template <typename T> +R8G8B8A8 ReadColor(const T *src) +{ + gl::ColorF tmp; + T::readColor(&tmp, src); + R8G8B8A8 rgba; + R8G8B8A8::writeColor(&rgba, &tmp); + return rgba; +} + +size_t DecodeIndexIntoPalette(const uint8_t *row, size_t i, uint32_t indexBits) +{ + switch (indexBits) + { + case 4: + { + // From OES_compressed_paletted_texture, section Additions to + // Chapter 3 of the OpenGL 1.3 Specification (Rasterization): + // + // Texel Data Formats for compressed paletted textures + // + // PALETTE4_xxx: + // + // 7 6 5 4 3 2 1 0 + // --------------- + // | 1st | 2nd | + // | texel | texel | + // --------------- + + bool even = i % 2 == 0; + return (row[i / 2] >> (even ? 4 : 0)) & 0x0f; + } + + case 8: + return row[i]; + + default: + UNREACHABLE(); + return 0; + } +} + +R8G8B8A8 DecodeColor(const uint8_t *src, + uint32_t redBlueBits, + uint32_t greenBits, + uint32_t alphaBits) +{ + switch (redBlueBits) + { + case 8: + ASSERT(greenBits == 8); + switch (alphaBits) + { + case 0: + return ReadColor<>(reinterpret_cast<const R8G8B8 *>(src)); + case 8: + return ReadColor<>(reinterpret_cast<const R8G8B8A8 *>(src)); + default: + UNREACHABLE(); + break; + } + break; + + case 5: + switch (greenBits) + { + case 6: + ASSERT(alphaBits == 0); + return ReadColor<>(reinterpret_cast<const R5G6B5 *>(src)); + case 5: + ASSERT(alphaBits == 1); + return ReadColor<>(reinterpret_cast<const R5G5B5A1 *>(src)); + default: + UNREACHABLE(); + break; + } + break; + + case 4: + ASSERT(greenBits == 4 && alphaBits == 4); + return ReadColor<>(reinterpret_cast<const R4G4B4A4 *>(src)); + + default: + UNREACHABLE(); + break; + } + + UNREACHABLE(); + return R8G8B8A8{0, 0, 0, 255}; +} + +} // namespace + +// See LoadPalettedToRGBA8. +void LoadPalettedToRGBA8Impl(size_t width, + size_t height, + size_t depth, + uint32_t indexBits, + uint32_t redBlueBits, + uint32_t greenBits, + uint32_t alphaBits, + const uint8_t *input, + size_t inputRowPitch, + size_t inputDepthPitch, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch) +{ + size_t colorBytes = (redBlueBits + greenBits + redBlueBits + alphaBits) / 8; + size_t paletteSize = 1 << indexBits; + size_t paletteBytes = paletteSize * colorBytes; + + const uint8_t *palette = input; + + const uint8_t *texels = input + paletteBytes; // + TODO(http://anglebug.com/7688): mip levels + + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *srcRow = + priv::OffsetDataPointer<uint8_t>(texels, y, z, inputRowPitch, inputDepthPitch); + R8G8B8A8 *dstRow = + priv::OffsetDataPointer<R8G8B8A8>(output, y, z, outputRowPitch, outputDepthPitch); + + for (size_t x = 0; x < width; x++) + { + size_t indexIntoPalette = DecodeIndexIntoPalette(srcRow, x, indexBits); + + dstRow[x] = DecodeColor(palette + indexIntoPalette * colorBytes, redBlueBits, + greenBits, alphaBits); + } + } + } +} + +} // namespace angle |