blob: f943e96207395cb5c3a8f26c10556071ebcd6925 [file] [log] [blame]
/*-------------------------------------------------------------------------
* drawElements Quality Program Tester Core
* ----------------------------------------
*
* Copyright 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file
* \brief Reference Texture Implementation.
*//*--------------------------------------------------------------------*/
#include "tcuTexture.hpp"
#include "deInt32.h"
#include "deFloat16.h"
#include "deMath.h"
#include "deMemory.h"
#include "tcuTestLog.hpp"
#include "tcuSurface.hpp"
#include "tcuFloat.hpp"
#include "tcuTextureUtil.hpp"
#include "deStringUtil.hpp"
#include "deArrayUtil.hpp"
#include "tcuMatrix.hpp"
#include <limits>
namespace tcu
{
// \note No sign. Denorms are supported.
typedef Float<uint32_t, 5, 6, 15, FLOAT_SUPPORT_DENORM> Float11;
typedef Float<uint32_t, 5, 5, 15, FLOAT_SUPPORT_DENORM> Float10;
namespace
{
// Optimized getters for common formats.
// \todo [2012-11-14 pyry] Use intrinsics if available.
inline Vec4 readRGBA8888Float(const uint8_t *ptr)
{
return Vec4(ptr[0] / 255.0f, ptr[1] / 255.0f, ptr[2] / 255.0f, ptr[3] / 255.0f);
}
inline Vec4 readRGB888Float(const uint8_t *ptr)
{
return Vec4(ptr[0] / 255.0f, ptr[1] / 255.0f, ptr[2] / 255.0f, 1.0f);
}
inline IVec4 readRGBA8888Int(const uint8_t *ptr)
{
return IVec4(ptr[0], ptr[1], ptr[2], ptr[3]);
}
inline IVec4 readRGB888Int(const uint8_t *ptr)
{
return IVec4(ptr[0], ptr[1], ptr[2], 1);
}
// Optimized setters.
inline void writeRGBA8888Int(uint8_t *ptr, const IVec4 &val)
{
ptr[0] = (uint8_t)de::clamp(val[0], 0, 255);
ptr[1] = (uint8_t)de::clamp(val[1], 0, 255);
ptr[2] = (uint8_t)de::clamp(val[2], 0, 255);
ptr[3] = (uint8_t)de::clamp(val[3], 0, 255);
}
inline void writeRGB888Int(uint8_t *ptr, const IVec4 &val)
{
ptr[0] = (uint8_t)de::clamp(val[0], 0, 255);
ptr[1] = (uint8_t)de::clamp(val[1], 0, 255);
ptr[2] = (uint8_t)de::clamp(val[2], 0, 255);
}
inline void writeRGBA8888Float(uint8_t *ptr, const Vec4 &val)
{
ptr[0] = floatToU8(val[0]);
ptr[1] = floatToU8(val[1]);
ptr[2] = floatToU8(val[2]);
ptr[3] = floatToU8(val[3]);
}
inline void writeRGB888Float(uint8_t *ptr, const Vec4 &val)
{
ptr[0] = floatToU8(val[0]);
ptr[1] = floatToU8(val[1]);
ptr[2] = floatToU8(val[2]);
}
inline void writeUint24(uint8_t *dst, uint32_t val)
{
#if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
dst[0] = (uint8_t)((val & 0x0000FFu) >> 0u);
dst[1] = (uint8_t)((val & 0x00FF00u) >> 8u);
dst[2] = (uint8_t)((val & 0xFF0000u) >> 16u);
#else
dst[0] = (uint8_t)((val & 0xFF0000u) >> 16u);
dst[1] = (uint8_t)((val & 0x00FF00u) >> 8u);
dst[2] = (uint8_t)((val & 0x0000FFu) >> 0u);
#endif
}
inline uint32_t readUint24(const uint8_t *src)
{
#if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
return (((uint32_t)src[0]) << 0u) | (((uint32_t)src[1]) << 8u) | (((uint32_t)src[2]) << 16u);
#else
return (((uint32_t)src[0]) << 16u) | (((uint32_t)src[1]) << 8u) | (((uint32_t)src[2]) << 0u);
#endif
}
inline uint8_t readUint32Low8(const uint8_t *src)
{
#if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
const uint32_t uint32ByteOffsetBits0To8 = 0; //!< least significant byte in the lowest address
#else
const uint32_t uint32ByteOffsetBits0To8 = 3; //!< least significant byte in the highest address
#endif
return src[uint32ByteOffsetBits0To8];
}
inline uint8_t readUint32High8(const uint8_t *src)
{
#if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
const uint32_t uint32ByteOffsetBits24To32 = 3;
#else
const uint32_t uint32ByteOffsetBits24To32 = 0;
#endif
return src[uint32ByteOffsetBits24To32];
}
inline void writeUint32Low8(uint8_t *dst, uint8_t val)
{
#if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
const uint32_t uint32ByteOffsetBits0To8 = 0; //!< least significant byte in the lowest address
#else
const uint32_t uint32ByteOffsetBits0To8 = 3; //!< least significant byte in the highest address
#endif
dst[uint32ByteOffsetBits0To8] = val;
}
inline void writeUint32High8(uint8_t *dst, uint8_t val)
{
#if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
const uint32_t uint32ByteOffsetBits24To32 = 3;
#else
const uint32_t uint32ByteOffsetBits24To32 = 0;
#endif
dst[uint32ByteOffsetBits24To32] = val;
}
inline uint32_t readUint32High16(const uint8_t *src)
{
#if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
const uint32_t uint32ByteOffset16To32 = 2;
#else
const uint32_t uint32ByteOffset16To32 = 0;
#endif
return *(const uint16_t *)(src + uint32ByteOffset16To32);
}
inline void writeUint32High16(uint8_t *dst, uint16_t val)
{
#if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
const uint32_t uint32ByteOffset16To32 = 2;
#else
const uint32_t uint32ByteOffset16To32 = 0;
#endif
*(uint16_t *)(dst + uint32ByteOffset16To32) = val;
}
inline uint32_t readUint32Low24(const uint8_t *src)
{
#if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
const uint32_t uint32ByteOffset0To24 = 0;
#else
const uint32_t uint32ByteOffset0To24 = 1;
#endif
return readUint24(src + uint32ByteOffset0To24);
}
inline uint32_t readUint32High24(const uint8_t *src)
{
#if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
const uint32_t uint32ByteOffset8To32 = 1;
#else
const uint32_t uint32ByteOffset8To32 = 0;
#endif
return readUint24(src + uint32ByteOffset8To32);
}
inline void writeUint32Low24(uint8_t *dst, uint32_t val)
{
#if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
const uint32_t uint32ByteOffset0To24 = 0;
#else
const uint32_t uint32ByteOffset0To24 = 1;
#endif
writeUint24(dst + uint32ByteOffset0To24, val);
}
inline void writeUint32High24(uint8_t *dst, uint32_t val)
{
#if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
const uint32_t uint32ByteOffset8To32 = 1;
#else
const uint32_t uint32ByteOffset8To32 = 0;
#endif
writeUint24(dst + uint32ByteOffset8To32, val);
}
// \todo [2011-09-21 pyry] Move to tcutil?
template <typename T>
inline T convertSatRte(float f)
{
// \note Doesn't work for 64-bit types
DE_STATIC_ASSERT(sizeof(T) < sizeof(uint64_t));
DE_STATIC_ASSERT((-3 % 2 != 0) && (-4 % 2 == 0));
int64_t minVal = std::numeric_limits<T>::min();
int64_t maxVal = std::numeric_limits<T>::max();
float q = deFloatFrac(f);
int64_t intVal = (int64_t)(f - q);
// Rounding.
if (q == 0.5f)
{
if (intVal % 2 != 0)
intVal++;
}
else if (q > 0.5f)
intVal++;
// else Don't add anything
// Saturate.
intVal = de::max(minVal, de::min(maxVal, intVal));
return (T)intVal;
}
inline uint32_t convertSatRteUint24(float f)
{
const uint32_t rounded = convertSatRte<uint32_t>(f);
const uint32_t maxUint24 = 0xFFFFFFu;
return de::min(rounded, maxUint24);
}
inline uint16_t convertSatRteUint10(float f)
{
const uint16_t rounded = convertSatRte<uint16_t>(f);
const uint16_t maxUint10 = 0x3FFu;
return de::min(rounded, maxUint10);
}
inline uint16_t convertSatRteUint12(float f)
{
const uint16_t rounded = convertSatRte<uint16_t>(f);
const uint16_t maxUint12 = 0xFFFu;
return de::min(rounded, maxUint12);
}
inline float channelToFloat(const uint8_t *value, TextureFormat::ChannelType type)
{
// make sure this table is updated if format table is updated
DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
switch (type)
{
case TextureFormat::SNORM_INT8:
return de::max(-1.0f, (float)*((const int8_t *)value) / 127.0f);
case TextureFormat::SNORM_INT16:
return de::max(-1.0f, (float)*((const int16_t *)value) / 32767.0f);
case TextureFormat::SNORM_INT32:
return de::max(-1.0f, (float)*((const int32_t *)value) / 2147483647.0f);
case TextureFormat::UNORM_INT8:
return (float)*((const uint8_t *)value) / 255.0f;
case TextureFormat::UNORM_INT16:
return (float)*((const uint16_t *)value) / 65535.0f;
case TextureFormat::UNORM_INT24:
return (float)readUint24(value) / 16777215.0f;
case TextureFormat::UNORM_INT32:
return (float)*((const uint32_t *)value) / 4294967295.0f;
case TextureFormat::SIGNED_INT8:
return (float)*((const int8_t *)value);
case TextureFormat::SIGNED_INT16:
return (float)*((const int16_t *)value);
case TextureFormat::SIGNED_INT32:
return (float)*((const int32_t *)value);
case TextureFormat::SIGNED_INT64:
return (float)*((const int64_t *)value);
case TextureFormat::UNSIGNED_INT8:
return (float)*((const uint8_t *)value);
case TextureFormat::UNSIGNED_INT16:
return (float)*((const uint16_t *)value);
case TextureFormat::UNSIGNED_INT24:
return (float)readUint24(value);
case TextureFormat::UNSIGNED_INT32:
return (float)*((const uint32_t *)value);
case TextureFormat::UNSIGNED_INT64:
return (float)*((const uint64_t *)value);
case TextureFormat::HALF_FLOAT:
return deFloat16To32(*(const deFloat16 *)value);
case TextureFormat::FLOAT:
return *((const float *)value);
case TextureFormat::FLOAT64:
return (float)*((const double *)value);
case TextureFormat::UNORM_SHORT_10:
return (float)((*((const uint16_t *)value)) >> 6u) / 1023.0f;
case TextureFormat::UNORM_SHORT_12:
return (float)((*((const uint16_t *)value)) >> 4u) / 4095.0f;
case TextureFormat::USCALED_INT8:
return (float)*((const uint8_t *)value);
case TextureFormat::USCALED_INT16:
return (float)*((const uint16_t *)value);
case TextureFormat::SSCALED_INT8:
return (float)*((const int8_t *)value);
case TextureFormat::SSCALED_INT16:
return (float)*((const int16_t *)value);
default:
DE_ASSERT(false);
return 0.0f;
}
}
template <class T>
inline T channelToIntType(const uint8_t *value, TextureFormat::ChannelType type)
{
// make sure this table is updated if format table is updated
DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
switch (type)
{
case TextureFormat::SNORM_INT8:
return (T) * ((const int8_t *)value);
case TextureFormat::SNORM_INT16:
return (T) * ((const int16_t *)value);
case TextureFormat::SNORM_INT32:
return (T) * ((const int32_t *)value);
case TextureFormat::UNORM_INT8:
return (T) * ((const uint8_t *)value);
case TextureFormat::UNORM_INT16:
return (T) * ((const uint16_t *)value);
case TextureFormat::UNORM_INT24:
return (T)readUint24(value);
case TextureFormat::UNORM_INT32:
return (T) * ((const uint32_t *)value);
case TextureFormat::SIGNED_INT8:
return (T) * ((const int8_t *)value);
case TextureFormat::SIGNED_INT16:
return (T) * ((const int16_t *)value);
case TextureFormat::SIGNED_INT32:
return (T) * ((const int32_t *)value);
case TextureFormat::SIGNED_INT64:
return (T) * ((const int64_t *)value);
case TextureFormat::UNSIGNED_INT8:
return (T) * ((const uint8_t *)value);
case TextureFormat::UNSIGNED_INT16:
return (T) * ((const uint16_t *)value);
case TextureFormat::UNSIGNED_INT24:
return (T)readUint24(value);
case TextureFormat::UNSIGNED_INT32:
return (T) * ((const uint32_t *)value);
case TextureFormat::UNSIGNED_INT64:
return (T) * ((const uint64_t *)value);
case TextureFormat::HALF_FLOAT:
return (T)deFloat16To32(*(const deFloat16 *)value);
case TextureFormat::FLOAT:
return (T) * ((const float *)value);
case TextureFormat::FLOAT64:
return (T) * ((const double *)value);
case TextureFormat::UNORM_SHORT_10:
return (T)((*(((const uint16_t *)value))) >> 6u);
case TextureFormat::UNORM_SHORT_12:
return (T)((*(((const uint16_t *)value))) >> 4u);
case TextureFormat::USCALED_INT8:
return (T) * ((const uint8_t *)value);
case TextureFormat::USCALED_INT16:
return (T) * ((const uint16_t *)value);
case TextureFormat::SSCALED_INT8:
return (T) * ((const int8_t *)value);
case TextureFormat::SSCALED_INT16:
return (T) * ((const int16_t *)value);
default:
DE_ASSERT(false);
return 0;
}
}
inline uint64_t retrieveChannelBitsAsUint64(const uint8_t *value, TextureFormat::ChannelType type)
{
// make sure this table is updated if format table is updated
DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
switch (type)
{
case TextureFormat::SNORM_INT8:
return (uint64_t) * ((const uint8_t *)value);
case TextureFormat::SNORM_INT16:
return (uint64_t) * ((const uint16_t *)value);
case TextureFormat::SNORM_INT32:
return (uint64_t) * ((const uint32_t *)value);
case TextureFormat::UNORM_INT8:
return (uint64_t) * ((const uint8_t *)value);
case TextureFormat::UNORM_INT16:
return (uint64_t) * ((const uint16_t *)value);
case TextureFormat::UNORM_INT24:
return (uint64_t)readUint24(value);
case TextureFormat::UNORM_INT32:
return (uint64_t) * ((const uint32_t *)value);
case TextureFormat::SIGNED_INT8:
return (uint64_t) * ((const uint8_t *)value);
case TextureFormat::SIGNED_INT16:
return (uint64_t) * ((const uint16_t *)value);
case TextureFormat::SIGNED_INT32:
return (uint64_t) * ((const uint32_t *)value);
case TextureFormat::SIGNED_INT64:
return (uint64_t) * ((const uint64_t *)value);
case TextureFormat::UNSIGNED_INT8:
return (uint64_t) * ((const uint8_t *)value);
case TextureFormat::UNSIGNED_INT16:
return (uint64_t) * ((const uint16_t *)value);
case TextureFormat::UNSIGNED_INT24:
return (uint64_t)readUint24(value);
case TextureFormat::UNSIGNED_INT32:
return (uint64_t) * ((const uint32_t *)value);
case TextureFormat::UNSIGNED_INT64:
return (uint64_t) * ((const uint64_t *)value);
case TextureFormat::HALF_FLOAT:
return (uint64_t) * ((const uint16_t *)value);
case TextureFormat::FLOAT:
return (uint64_t) * ((const uint32_t *)value);
case TextureFormat::FLOAT64:
return (uint64_t) * ((const uint64_t *)value);
case TextureFormat::UNORM_SHORT_10:
return (uint64_t)((*((const uint16_t *)value)) >> 6u);
case TextureFormat::UNORM_SHORT_12:
return (uint64_t)((*((const uint16_t *)value)) >> 4u);
case TextureFormat::USCALED_INT8:
return (uint64_t) * ((const uint8_t *)value);
case TextureFormat::USCALED_INT16:
return (uint64_t) * ((const uint16_t *)value);
case TextureFormat::SSCALED_INT8:
return (uint64_t) * ((const uint8_t *)value);
case TextureFormat::SSCALED_INT16:
return (uint64_t) * ((const uint16_t *)value);
default:
DE_ASSERT(false);
return 0;
}
}
inline int channelToInt(const uint8_t *value, TextureFormat::ChannelType type)
{
return channelToIntType<int>(value, type);
}
void floatToChannel(uint8_t *dst, float src, TextureFormat::ChannelType type)
{
// make sure this table is updated if format table is updated
DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
switch (type)
{
case TextureFormat::SNORM_INT8:
*((int8_t *)dst) = convertSatRte<int8_t>(src * 127.0f);
break;
case TextureFormat::SNORM_INT16:
*((int16_t *)dst) = convertSatRte<int16_t>(src * 32767.0f);
break;
case TextureFormat::SNORM_INT32:
*((int32_t *)dst) = convertSatRte<int32_t>(src * 2147483647.0f);
break;
case TextureFormat::UNORM_INT8:
*((uint8_t *)dst) = convertSatRte<uint8_t>(src * 255.0f);
break;
case TextureFormat::UNORM_INT16:
*((uint16_t *)dst) = convertSatRte<uint16_t>(src * 65535.0f);
break;
case TextureFormat::UNORM_INT24:
writeUint24(dst, convertSatRteUint24(src * 16777215.0f));
break;
case TextureFormat::UNORM_INT32:
*((uint32_t *)dst) = convertSatRte<uint32_t>(src * 4294967295.0f);
break;
case TextureFormat::SIGNED_INT8:
*((int8_t *)dst) = convertSatRte<int8_t>(src);
break;
case TextureFormat::SIGNED_INT16:
*((int16_t *)dst) = convertSatRte<int16_t>(src);
break;
case TextureFormat::SIGNED_INT32:
*((int32_t *)dst) = convertSatRte<int32_t>(src);
break;
case TextureFormat::UNSIGNED_INT8:
*((uint8_t *)dst) = convertSatRte<uint8_t>(src);
break;
case TextureFormat::UNSIGNED_INT16:
*((uint16_t *)dst) = convertSatRte<uint16_t>(src);
break;
case TextureFormat::UNSIGNED_INT24:
writeUint24(dst, convertSatRteUint24(src));
break;
case TextureFormat::UNSIGNED_INT32:
*((uint32_t *)dst) = convertSatRte<uint32_t>(src);
break;
case TextureFormat::HALF_FLOAT:
*((deFloat16 *)dst) = deFloat32To16(src);
break;
case TextureFormat::FLOAT:
*((float *)dst) = src;
break;
case TextureFormat::FLOAT64:
*((double *)dst) = (double)src;
break;
case TextureFormat::UNORM_SHORT_10:
*((uint16_t *)dst) = (uint16_t)(convertSatRteUint10(src * 1023.0f) << 6u);
break;
case TextureFormat::UNORM_SHORT_12:
*((uint16_t *)dst) = (uint16_t)(convertSatRteUint12(src * 4095.0f) << 4u);
break;
case TextureFormat::USCALED_INT8:
*((uint8_t *)dst) = convertSatRte<uint8_t>(src);
break;
case TextureFormat::USCALED_INT16:
*((uint16_t *)dst) = convertSatRte<uint16_t>(src);
break;
case TextureFormat::SSCALED_INT8:
*((int8_t *)dst) = convertSatRte<int8_t>(src);
break;
case TextureFormat::SSCALED_INT16:
*((int16_t *)dst) = convertSatRte<int16_t>(src);
break;
default:
DE_ASSERT(false);
}
}
template <typename T, typename S>
static inline T convertSat(S src)
{
S min = (S)std::numeric_limits<T>::min();
S max = (S)std::numeric_limits<T>::max();
if (src < min)
return (T)min;
else if (src > max)
return (T)max;
else
return (T)src;
}
template <typename S>
static inline uint32_t convertSatUint24(S src)
{
S min = (S)0u;
S max = (S)0xFFFFFFu;
if (src < min)
return (uint32_t)min;
else if (src > max)
return (uint32_t)max;
else
return (uint32_t)src;
}
template <typename S>
static inline uint16_t convertSatUint10(S src)
{
S min = (S)0u;
S max = (S)0x3FFu;
if (src < min)
return (uint16_t)min;
else if (src > max)
return (uint16_t)max;
else
return (uint16_t)src;
}
template <typename S>
static inline uint16_t convertSatUint12(S src)
{
S min = (S)0u;
S max = (S)0xFFFu;
if (src < min)
return (uint16_t)min;
else if (src > max)
return (uint16_t)max;
else
return (uint16_t)src;
}
void intToChannel(uint8_t *dst, int src, TextureFormat::ChannelType type)
{
// make sure this table is updated if format table is updated
DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
switch (type)
{
case TextureFormat::SNORM_INT8:
*((int8_t *)dst) = convertSat<int8_t>(src);
break;
case TextureFormat::SNORM_INT16:
*((int16_t *)dst) = convertSat<int16_t>(src);
break;
case TextureFormat::UNORM_INT8:
*((uint8_t *)dst) = convertSat<uint8_t>(src);
break;
case TextureFormat::UNORM_INT16:
*((uint16_t *)dst) = convertSat<uint16_t>(src);
break;
case TextureFormat::UNORM_INT24:
writeUint24(dst, convertSatUint24(src));
break;
case TextureFormat::SIGNED_INT8:
*((int8_t *)dst) = convertSat<int8_t>(src);
break;
case TextureFormat::SIGNED_INT16:
*((int16_t *)dst) = convertSat<int16_t>(src);
break;
case TextureFormat::SIGNED_INT32:
*((int32_t *)dst) = convertSat<int32_t>(src);
break;
case TextureFormat::SIGNED_INT64:
*((int64_t *)dst) = convertSat<int64_t>((int64_t)src);
break;
case TextureFormat::UNSIGNED_INT8:
*((uint8_t *)dst) = convertSat<uint8_t>((uint32_t)src);
break;
case TextureFormat::UNSIGNED_INT16:
*((uint16_t *)dst) = convertSat<uint16_t>((uint32_t)src);
break;
case TextureFormat::UNSIGNED_INT24:
writeUint24(dst, convertSatUint24((uint32_t)src));
break;
case TextureFormat::UNSIGNED_INT32:
*((uint32_t *)dst) = convertSat<uint32_t>((uint32_t)src);
break;
case TextureFormat::UNSIGNED_INT64:
*((uint64_t *)dst) = convertSat<uint64_t>((uint64_t)src);
break;
case TextureFormat::HALF_FLOAT:
*((deFloat16 *)dst) = deFloat32To16((float)src);
break;
case TextureFormat::FLOAT:
*((float *)dst) = (float)src;
break;
case TextureFormat::FLOAT64:
*((double *)dst) = (double)src;
break;
case TextureFormat::UNORM_SHORT_10:
*((uint16_t *)dst) = (uint16_t)(convertSatUint10(src) << 6u);
break;
case TextureFormat::UNORM_SHORT_12:
*((uint16_t *)dst) = (uint16_t)(convertSatUint12(src) << 4u);
break;
case TextureFormat::USCALED_INT8:
*((uint8_t *)dst) = convertSat<uint8_t>((uint32_t)src);
break;
case TextureFormat::USCALED_INT16:
*((uint16_t *)dst) = convertSat<uint16_t>((uint32_t)src);
break;
case TextureFormat::SSCALED_INT8:
*((int8_t *)dst) = convertSat<int8_t>(src);
break;
case TextureFormat::SSCALED_INT16:
*((int16_t *)dst) = convertSat<int16_t>(src);
break;
default:
DE_ASSERT(false);
}
}
inline float channelToUnormFloat(uint32_t src, int bits)
{
const uint32_t maxVal = (1u << bits) - 1;
// \note Will lose precision if bits > 23
return (float)src / (float)maxVal;
}
//! Extend < 32b signed integer to 32b
inline int32_t signExtend(uint32_t src, int bits)
{
const uint32_t signBit = 1u << (bits - 1);
src |= ~((src & signBit) - 1);
return (int32_t)src;
}
inline float channelToSnormFloat(uint32_t src, int bits)
{
const uint32_t range = (1u << (bits - 1)) - 1;
// \note Will lose precision if bits > 24
return de::max(-1.0f, (float)signExtend(src, bits) / (float)range);
}
inline uint32_t unormFloatToChannel(float src, int bits)
{
const uint32_t maxVal = (1u << bits) - 1;
const uint32_t intVal = convertSatRte<uint32_t>(src * (float)maxVal);
return de::min(intVal, maxVal);
}
inline uint32_t snormFloatToChannel(float src, int bits)
{
const int32_t range = (int32_t)((1u << (bits - 1)) - 1u);
const uint32_t mask = (1u << bits) - 1;
const int32_t intVal = convertSatRte<int32_t>(src * (float)range);
return (uint32_t)de::clamp(intVal, -range, range) & mask;
}
inline uint32_t uintToChannel(uint32_t src, int bits)
{
const uint32_t maxVal = (1u << bits) - 1;
return de::min(src, maxVal);
}
inline uint32_t intToChannel(int32_t src, int bits)
{
const int32_t minVal = -(int32_t)(1u << (bits - 1));
const int32_t maxVal = (int32_t)((1u << (bits - 1)) - 1u);
const uint32_t mask = (1u << bits) - 1;
return (uint32_t)de::clamp(src, minVal, maxVal) & mask;
}
tcu::Vec4 unpackRGB999E5(uint32_t color)
{
const int mBits = 9;
const int eBias = 15;
uint32_t exp = color >> 27;
uint32_t bs = (color >> 18) & ((1 << 9) - 1);
uint32_t gs = (color >> 9) & ((1 << 9) - 1);
uint32_t rs = color & ((1 << 9) - 1);
float e = deFloatPow(2.0f, (float)((int)exp - eBias - mBits));
float r = (float)rs * e;
float g = (float)gs * e;
float b = (float)bs * e;
return tcu::Vec4(r, g, b, 1.0f);
}
bool isColorOrder(TextureFormat::ChannelOrder order)
{
DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 22);
switch (order)
{
case TextureFormat::R:
case TextureFormat::A:
case TextureFormat::I:
case TextureFormat::L:
case TextureFormat::LA:
case TextureFormat::RG:
case TextureFormat::RA:
case TextureFormat::RGB:
case TextureFormat::RGBA:
case TextureFormat::ARGB:
case TextureFormat::ABGR:
case TextureFormat::BGR:
case TextureFormat::BGRA:
case TextureFormat::sR:
case TextureFormat::sRG:
case TextureFormat::sRGB:
case TextureFormat::sRGBA:
case TextureFormat::sBGR:
case TextureFormat::sBGRA:
return true;
default:
return false;
}
}
float getImageViewMinLod(ImageViewMinLod &l)
{
return (l.mode == IMAGEVIEWMINLODMODE_PREFERRED) ? l.value : deFloatFloor(l.value);
}
} // namespace
bool isValid(TextureFormat format)
{
const bool isColor = isColorOrder(format.order);
switch (format.type)
{
case TextureFormat::SNORM_INT8:
case TextureFormat::SNORM_INT16:
case TextureFormat::SNORM_INT32:
return isColor;
case TextureFormat::UNORM_INT8:
case TextureFormat::UNORM_INT16:
case TextureFormat::UNORM_INT24:
case TextureFormat::UNORM_INT32:
return isColor || format.order == TextureFormat::D;
case TextureFormat::UNORM_BYTE_44:
case TextureFormat::UNSIGNED_BYTE_44:
return format.order == TextureFormat::RG;
case TextureFormat::UNORM_SHORT_565:
case TextureFormat::UNORM_SHORT_555:
case TextureFormat::UNSIGNED_SHORT_565:
return format.order == TextureFormat::RGB || format.order == TextureFormat::BGR;
case TextureFormat::UNORM_SHORT_4444:
case TextureFormat::UNORM_SHORT_5551:
case TextureFormat::UNSIGNED_SHORT_4444:
case TextureFormat::UNSIGNED_SHORT_5551:
return format.order == TextureFormat::RGBA || format.order == TextureFormat::BGRA ||
format.order == TextureFormat::ARGB || format.order == TextureFormat::ABGR;
case TextureFormat::UNORM_SHORT_1555:
return format.order == TextureFormat::ARGB || format.order == TextureFormat::ABGR;
case TextureFormat::UNORM_INT_101010:
return format.order == TextureFormat::RGB;
case TextureFormat::SNORM_INT_1010102_REV:
case TextureFormat::UNORM_INT_1010102_REV:
case TextureFormat::SIGNED_INT_1010102_REV:
case TextureFormat::UNSIGNED_INT_1010102_REV:
case TextureFormat::USCALED_INT_1010102_REV:
case TextureFormat::SSCALED_INT_1010102_REV:
return format.order == TextureFormat::RGBA || format.order == TextureFormat::BGRA;
case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:
case TextureFormat::UNSIGNED_INT_999_E5_REV:
return format.order == TextureFormat::RGB;
case TextureFormat::UNSIGNED_INT_16_8_8:
return format.order == TextureFormat::DS;
case TextureFormat::UNSIGNED_INT_24_8:
case TextureFormat::UNSIGNED_INT_24_8_REV:
return format.order == TextureFormat::D || format.order == TextureFormat::DS;
case TextureFormat::SIGNED_INT8:
case TextureFormat::SIGNED_INT16:
case TextureFormat::SIGNED_INT32:
case TextureFormat::SSCALED_INT8:
case TextureFormat::SSCALED_INT16:
case TextureFormat::SIGNED_INT64:
return isColor;
case TextureFormat::UNSIGNED_INT8:
case TextureFormat::UNSIGNED_INT16:
case TextureFormat::UNSIGNED_INT24:
case TextureFormat::UNSIGNED_INT32:
case TextureFormat::USCALED_INT8:
case TextureFormat::USCALED_INT16:
case TextureFormat::UNSIGNED_INT64:
return isColor || format.order == TextureFormat::S;
case TextureFormat::HALF_FLOAT:
case TextureFormat::FLOAT:
case TextureFormat::FLOAT64:
return isColor || format.order == TextureFormat::D;
case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
return format.order == TextureFormat::DS;
case TextureFormat::UNORM_SHORT_10:
case TextureFormat::UNORM_SHORT_12:
return isColor;
default:
DE_FATAL("Unknown format");
return 0u;
}
DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
}
int getNumUsedChannels(TextureFormat::ChannelOrder order)
{
// make sure this table is updated if type table is updated
DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 22);
switch (order)
{
case TextureFormat::R:
return 1;
case TextureFormat::A:
return 1;
case TextureFormat::I:
return 1;
case TextureFormat::L:
return 1;
case TextureFormat::LA:
return 2;
case TextureFormat::RG:
return 2;
case TextureFormat::RA:
return 2;
case TextureFormat::RGB:
return 3;
case TextureFormat::RGBA:
return 4;
case TextureFormat::ARGB:
return 4;
case TextureFormat::ABGR:
return 4;
case TextureFormat::BGR:
return 3;
case TextureFormat::BGRA:
return 4;
case TextureFormat::sR:
return 1;
case TextureFormat::sRG:
return 2;
case TextureFormat::sRGB:
return 3;
case TextureFormat::sRGBA:
return 4;
case TextureFormat::sBGR:
return 3;
case TextureFormat::sBGRA:
return 4;
case TextureFormat::D:
return 1;
case TextureFormat::S:
return 1;
case TextureFormat::DS:
return 2;
default:
DE_ASSERT(false);
return 0;
}
}
bool hasAlphaChannel(TextureFormat::ChannelOrder order)
{
// make sure this table is updated if type table is updated
DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 22);
switch (order)
{
case TextureFormat::A:
case TextureFormat::LA:
case TextureFormat::RG:
case TextureFormat::RA:
case TextureFormat::RGBA:
case TextureFormat::ARGB:
case TextureFormat::ABGR:
case TextureFormat::BGRA:
case TextureFormat::sRGBA:
case TextureFormat::sBGRA:
return true;
default:
return false;
}
}
int getChannelSize(TextureFormat::ChannelType type)
{
// make sure this table is updated if format table is updated
DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
switch (type)
{
case TextureFormat::SNORM_INT8:
return 1;
case TextureFormat::SNORM_INT16:
return 2;
case TextureFormat::SNORM_INT32:
return 4;
case TextureFormat::UNORM_INT8:
return 1;
case TextureFormat::UNORM_INT16:
return 2;
case TextureFormat::UNORM_INT24:
return 3;
case TextureFormat::UNORM_INT32:
return 4;
case TextureFormat::SIGNED_INT8:
return 1;
case TextureFormat::SIGNED_INT16:
return 2;
case TextureFormat::SIGNED_INT32:
return 4;
case TextureFormat::SIGNED_INT64:
return 8;
case TextureFormat::UNSIGNED_INT8:
return 1;
case TextureFormat::UNSIGNED_INT16:
return 2;
case TextureFormat::UNSIGNED_INT24:
return 3;
case TextureFormat::UNSIGNED_INT32:
return 4;
case TextureFormat::UNSIGNED_INT64:
return 8;
case TextureFormat::HALF_FLOAT:
return 2;
case TextureFormat::FLOAT:
return 4;
case TextureFormat::FLOAT64:
return 8;
case TextureFormat::UNORM_SHORT_10:
return 2;
case TextureFormat::UNORM_SHORT_12:
return 2;
case TextureFormat::USCALED_INT8:
return 1;
case TextureFormat::USCALED_INT16:
return 2;
case TextureFormat::SSCALED_INT8:
return 1;
case TextureFormat::SSCALED_INT16:
return 2;
default:
DE_ASSERT(false);
return 0;
}
}
/** Get pixel size in bytes. */
int getPixelSize(TextureFormat format)
{
const TextureFormat::ChannelOrder order = format.order;
const TextureFormat::ChannelType type = format.type;
DE_ASSERT(isValid(format));
// make sure this table is updated if format table is updated
DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
switch (type)
{
case TextureFormat::UNORM_BYTE_44:
case TextureFormat::UNSIGNED_BYTE_44:
return 1;
case TextureFormat::UNORM_SHORT_565:
case TextureFormat::UNORM_SHORT_555:
case TextureFormat::UNORM_SHORT_4444:
case TextureFormat::UNORM_SHORT_5551:
case TextureFormat::UNORM_SHORT_1555:
case TextureFormat::UNSIGNED_SHORT_565:
case TextureFormat::UNSIGNED_SHORT_4444:
case TextureFormat::UNSIGNED_SHORT_5551:
return 2;
case TextureFormat::UNORM_INT_101010:
case TextureFormat::UNSIGNED_INT_999_E5_REV:
case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:
case TextureFormat::SNORM_INT_1010102_REV:
case TextureFormat::UNORM_INT_1010102_REV:
case TextureFormat::SIGNED_INT_1010102_REV:
case TextureFormat::UNSIGNED_INT_1010102_REV:
case TextureFormat::UNSIGNED_INT_24_8:
case TextureFormat::UNSIGNED_INT_24_8_REV:
case TextureFormat::UNSIGNED_INT_16_8_8:
case TextureFormat::USCALED_INT_1010102_REV:
case TextureFormat::SSCALED_INT_1010102_REV:
return 4;
case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
return 8;
default:
return getNumUsedChannels(order) * getChannelSize(type);
}
}
int TextureFormat::getPixelSize(void) const
{
return ::tcu::getPixelSize(*this);
}
const TextureSwizzle &getChannelReadSwizzle(TextureFormat::ChannelOrder order)
{
// make sure to update these tables when channel orders are updated
DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 22);
static const TextureSwizzle INV = {{TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO,
TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ONE}};
static const TextureSwizzle R = {{TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_ZERO,
TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ONE}};
static const TextureSwizzle A = {{TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO,
TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_0}};
static const TextureSwizzle I = {
{TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0}};
static const TextureSwizzle L = {
{TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_ONE}};
static const TextureSwizzle LA = {
{TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1}};
static const TextureSwizzle RG = {{TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1,
TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ONE}};
static const TextureSwizzle RA = {{TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_ZERO,
TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_1}};
static const TextureSwizzle RGB = {
{TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_ONE}};
static const TextureSwizzle RGBA = {
{TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_3}};
static const TextureSwizzle BGR = {
{TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_ONE}};
static const TextureSwizzle BGRA = {
{TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3}};
static const TextureSwizzle ARGB = {
{TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_3, TextureSwizzle::CHANNEL_0}};
static const TextureSwizzle ABGR = {
{TextureSwizzle::CHANNEL_3, TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_0}};
static const TextureSwizzle D = {{TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_ZERO,
TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ONE}};
static const TextureSwizzle S = {{TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_ZERO,
TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ONE}};
static const TextureSwizzle DS = {{TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1,
TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ONE}};
switch (order)
{
case TextureFormat::R:
return R;
case TextureFormat::A:
return A;
case TextureFormat::I:
return I;
case TextureFormat::L:
return L;
case TextureFormat::LA:
return LA;
case TextureFormat::RG:
return RG;
case TextureFormat::RA:
return RA;
case TextureFormat::RGB:
return RGB;
case TextureFormat::RGBA:
return RGBA;
case TextureFormat::ARGB:
return ARGB;
case TextureFormat::ABGR:
return ABGR;
case TextureFormat::BGR:
return BGR;
case TextureFormat::BGRA:
return BGRA;
case TextureFormat::sR:
return R;
case TextureFormat::sRG:
return RG;
case TextureFormat::sRGB:
return RGB;
case TextureFormat::sRGBA:
return RGBA;
case TextureFormat::sBGR:
return BGR;
case TextureFormat::sBGRA:
return BGRA;
case TextureFormat::D:
return D;
case TextureFormat::S:
return S;
case TextureFormat::DS:
return DS;
default:
DE_ASSERT(false);
return INV;
}
}
const TextureSwizzle &getChannelWriteSwizzle(TextureFormat::ChannelOrder order)
{
// make sure to update these tables when channel orders are updated
DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 22);
static const TextureSwizzle INV = {{TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST,
TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST}};
static const TextureSwizzle R = {{TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_LAST,
TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST}};
static const TextureSwizzle A = {{TextureSwizzle::CHANNEL_3, TextureSwizzle::CHANNEL_LAST,
TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST}};
static const TextureSwizzle I = {{TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_LAST,
TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST}};
static const TextureSwizzle L = {{TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_LAST,
TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST}};
static const TextureSwizzle LA = {{TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3,
TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST}};
static const TextureSwizzle RG = {{TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1,
TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST}};
static const TextureSwizzle RA = {{TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3,
TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST}};
static const TextureSwizzle RGB = {{TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_2,
TextureSwizzle::CHANNEL_LAST}};
static const TextureSwizzle RGBA = {
{TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_3}};
static const TextureSwizzle BGR = {{TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_0,
TextureSwizzle::CHANNEL_LAST}};
static const TextureSwizzle BGRA = {
{TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3}};
static const TextureSwizzle ARGB = {
{TextureSwizzle::CHANNEL_3, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_2}};
static const TextureSwizzle ABGR = {
{TextureSwizzle::CHANNEL_3, TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_0}};
static const TextureSwizzle D = {{TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_LAST,
TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST}};
static const TextureSwizzle S = {{TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_LAST,
TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST}};
switch (order)
{
case TextureFormat::R:
return R;
case TextureFormat::A:
return A;
case TextureFormat::I:
return I;
case TextureFormat::L:
return L;
case TextureFormat::LA:
return LA;
case TextureFormat::RG:
return RG;
case TextureFormat::RA:
return RA;
case TextureFormat::RGB:
return RGB;
case TextureFormat::RGBA:
return RGBA;
case TextureFormat::ARGB:
return ARGB;
case TextureFormat::ABGR:
return ABGR;
case TextureFormat::BGR:
return BGR;
case TextureFormat::BGRA:
return BGRA;
case TextureFormat::sR:
return R;
case TextureFormat::sRG:
return RG;
case TextureFormat::sRGB:
return RGB;
case TextureFormat::sRGBA:
return RGBA;
case TextureFormat::sBGR:
return BGR;
case TextureFormat::sBGRA:
return BGRA;
case TextureFormat::D:
return D;
case TextureFormat::S:
return S;
case TextureFormat::DS:
DE_ASSERT(false); // combined formats cannot be written to
return INV;
default:
DE_ASSERT(false);
return INV;
}
}
IVec3 calculatePackedPitch(const TextureFormat &format, const IVec3 &size)
{
const int pixelSize = format.getPixelSize();
const int rowPitch = pixelSize * size.x();
const int slicePitch = rowPitch * size.y();
return IVec3(pixelSize, rowPitch, slicePitch);
}
ConstPixelBufferAccess::ConstPixelBufferAccess(void) : m_size(0), m_pitch(0), m_divider(1, 1, 1), m_data(DE_NULL)
{
}
ConstPixelBufferAccess::ConstPixelBufferAccess(const TextureFormat &format, int width, int height, int depth,
const void *data)
: m_format(format)
, m_size(width, height, depth)
, m_pitch(calculatePackedPitch(m_format, m_size))
, m_divider(1, 1, 1)
, m_data((void *)data)
{
DE_ASSERT(isValid(format));
}
ConstPixelBufferAccess::ConstPixelBufferAccess(const TextureFormat &format, const IVec3 &size, const void *data)
: m_format(format)
, m_size(size)
, m_pitch(calculatePackedPitch(m_format, m_size))
, m_divider(1, 1, 1)
, m_data((void *)data)
{
DE_ASSERT(isValid(format));
}
ConstPixelBufferAccess::ConstPixelBufferAccess(const TextureFormat &format, int width, int height, int depth,
int rowPitch, int slicePitch, const void *data)
: m_format(format)
, m_size(width, height, depth)
, m_pitch(format.getPixelSize(), rowPitch, slicePitch)
, m_divider(1, 1, 1)
, m_data((void *)data)
{
DE_ASSERT(isValid(format));
}
ConstPixelBufferAccess::ConstPixelBufferAccess(const TextureFormat &format, const IVec3 &size, const IVec3 &pitch,
const void *data)
: m_format(format)
, m_size(size)
, m_pitch(pitch)
, m_divider(1, 1, 1)
, m_data((void *)data)
{
DE_ASSERT(isValid(format));
DE_ASSERT(m_format.getPixelSize() <= m_pitch.x());
}
ConstPixelBufferAccess::ConstPixelBufferAccess(const TextureFormat &format, const IVec3 &size, const IVec3 &pitch,
const IVec3 &block, const void *data)
: m_format(format)
, m_size(size)
, m_pitch(pitch)
, m_divider(block)
, m_data((void *)data)
{
DE_ASSERT(isValid(format));
DE_ASSERT(m_format.getPixelSize() <= m_pitch.x());
}
ConstPixelBufferAccess::ConstPixelBufferAccess(const TextureLevel &level)
: m_format(level.getFormat())
, m_size(level.getSize())
, m_pitch(calculatePackedPitch(m_format, m_size))
, m_divider(1, 1, 1)
, m_data((void *)level.getPtr())
{
}
PixelBufferAccess::PixelBufferAccess(const TextureFormat &format, int width, int height, int depth, void *data)
: ConstPixelBufferAccess(format, width, height, depth, data)
{
}
PixelBufferAccess::PixelBufferAccess(const TextureFormat &format, const IVec3 &size, void *data)
: ConstPixelBufferAccess(format, size, data)
{
}
PixelBufferAccess::PixelBufferAccess(const TextureFormat &format, int width, int height, int depth, int rowPitch,
int slicePitch, void *data)
: ConstPixelBufferAccess(format, width, height, depth, rowPitch, slicePitch, data)
{
}
PixelBufferAccess::PixelBufferAccess(const TextureFormat &format, const IVec3 &size, const IVec3 &pitch, void *data)
: ConstPixelBufferAccess(format, size, pitch, data)
{
}
PixelBufferAccess::PixelBufferAccess(const TextureFormat &format, const IVec3 &size, const IVec3 &pitch,
const IVec3 &block, void *data)
: ConstPixelBufferAccess(format, size, pitch, block, data)
{
}
PixelBufferAccess::PixelBufferAccess(TextureLevel &level) : ConstPixelBufferAccess(level)
{
}
//! Swizzle generally based on channel order.
template <typename T>
Vector<T, 4> swizzleGe(const Vector<T, 4> &v, TextureFormat::ChannelOrder src, TextureFormat::ChannelOrder dst)
{
if (src == dst)
return v;
else
{
if ((src == TextureFormat::RGBA && dst == TextureFormat::ARGB) ||
(src == TextureFormat::BGRA && dst == TextureFormat::ABGR))
return v.swizzle(3, 0, 1, 2);
if ((src == TextureFormat::ARGB && dst == TextureFormat::RGBA) ||
(src == TextureFormat::ABGR && dst == TextureFormat::BGRA))
return v.swizzle(1, 2, 3, 0);
if ((src == TextureFormat::BGRA && dst == TextureFormat::ARGB) ||
(src == TextureFormat::ABGR && dst == TextureFormat::RGBA) ||
(src == TextureFormat::RGBA && dst == TextureFormat::ABGR) ||
(src == TextureFormat::ARGB && dst == TextureFormat::BGRA))
return v.swizzle(3, 2, 1, 0);
if ((src == TextureFormat::RGB && dst == TextureFormat::BGR) ||
(src == TextureFormat::BGR && dst == TextureFormat::RGB) ||
(src == TextureFormat::RGBA && dst == TextureFormat::BGRA) ||
(src == TextureFormat::BGRA && dst == TextureFormat::RGBA))
return v.swizzle(2, 1, 0, 3);
DE_ASSERT(false);
return v;
}
}
Vec4 ConstPixelBufferAccess::getPixel(int x, int y, int z) const
{
DE_ASSERT(de::inBounds(x, 0, m_size.x()));
DE_ASSERT(de::inBounds(y, 0, m_size.y()));
DE_ASSERT(de::inBounds(z, 0, m_size.z()));
DE_ASSERT(!isCombinedDepthStencilType(m_format.type)); // combined types cannot be accessed directly
DE_ASSERT(m_format.order != TextureFormat::DS); // combined formats cannot be accessed directly
const uint8_t *pixelPtr = (const uint8_t *)getPixelPtr(x, y, z);
// Optimized fomats.
if (m_format.type == TextureFormat::UNORM_INT8)
{
if (m_format.order == TextureFormat::RGBA || m_format.order == TextureFormat::sRGBA)
return readRGBA8888Float(pixelPtr);
else if (m_format.order == TextureFormat::RGB || m_format.order == TextureFormat::sRGB)
return readRGB888Float(pixelPtr);
}
#define UI8(OFFS, COUNT) ((*((const uint8_t *)pixelPtr) >> (OFFS)) & ((1 << (COUNT)) - 1))
#define UI16(OFFS, COUNT) ((*((const uint16_t *)pixelPtr) >> (OFFS)) & ((1 << (COUNT)) - 1))
#define UI32(OFFS, COUNT) ((*((const uint32_t *)pixelPtr) >> (OFFS)) & ((1 << (COUNT)) - 1))
#define SI32(OFFS, COUNT) signExtend(UI32(OFFS, COUNT), (COUNT))
#define UN8(OFFS, COUNT) channelToUnormFloat(UI8(OFFS, COUNT), (COUNT))
#define UN16(OFFS, COUNT) channelToUnormFloat(UI16(OFFS, COUNT), (COUNT))
#define UN32(OFFS, COUNT) channelToUnormFloat(UI32(OFFS, COUNT), (COUNT))
#define SN32(OFFS, COUNT) channelToSnormFloat(UI32(OFFS, COUNT), (COUNT))
// Packed formats.
switch (m_format.type)
{
case TextureFormat::UNORM_BYTE_44:
return Vec4(UN8(4, 4), UN8(0, 4), 0.0f, 1.0f);
case TextureFormat::UNSIGNED_BYTE_44:
return UVec4(UI8(4, 4), UI8(0, 4), 0u, 1u).cast<float>();
case TextureFormat::UNORM_SHORT_565:
return swizzleGe(Vec4(UN16(11, 5), UN16(5, 6), UN16(0, 5), 1.0f), m_format.order, TextureFormat::RGB);
case TextureFormat::UNSIGNED_SHORT_565:
return swizzleGe(UVec4(UI16(11, 5), UI16(5, 6), UI16(0, 5), 1u), m_format.order, TextureFormat::RGB)
.cast<float>();
case TextureFormat::UNORM_SHORT_555:
return swizzleGe(Vec4(UN16(10, 5), UN16(5, 5), UN16(0, 5), 1.0f), m_format.order, TextureFormat::RGB);
case TextureFormat::UNORM_SHORT_4444:
return swizzleGe(Vec4(UN16(12, 4), UN16(8, 4), UN16(4, 4), UN16(0, 4)), m_format.order, TextureFormat::RGBA);
case TextureFormat::UNSIGNED_SHORT_4444:
return swizzleGe(UVec4(UI16(12, 4), UI16(8, 4), UI16(4, 4), UI16(0, 4)), m_format.order, TextureFormat::RGBA)
.cast<float>();
case TextureFormat::UNORM_SHORT_5551:
return swizzleGe(Vec4(UN16(11, 5), UN16(6, 5), UN16(1, 5), UN16(0, 1)), m_format.order, TextureFormat::RGBA);
case TextureFormat::UNSIGNED_SHORT_5551:
return swizzleGe(UVec4(UI16(11, 5), UI16(6, 5), UI16(1, 5), UI16(0, 1)), m_format.order, TextureFormat::RGBA)
.cast<float>();
case TextureFormat::UNORM_SHORT_1555:
return swizzleGe(Vec4(UN16(15, 1), UN16(10, 5), UN16(5, 5), UN16(0, 5)), m_format.order, TextureFormat::RGBA);
case TextureFormat::UNORM_INT_101010:
return Vec4(UN32(22, 10), UN32(12, 10), UN32(2, 10), 1.0f);
case TextureFormat::UNORM_INT_1010102_REV:
return swizzleGe(Vec4(UN32(0, 10), UN32(10, 10), UN32(20, 10), UN32(30, 2)), m_format.order,
TextureFormat::RGBA);
case TextureFormat::SNORM_INT_1010102_REV:
return swizzleGe(Vec4(SN32(0, 10), SN32(10, 10), SN32(20, 10), SN32(30, 2)), m_format.order,
TextureFormat::RGBA);
case TextureFormat::USCALED_INT_1010102_REV:
case TextureFormat::UNSIGNED_INT_1010102_REV:
return swizzleGe(UVec4(UI32(0, 10), UI32(10, 10), UI32(20, 10), UI32(30, 2)), m_format.order,
TextureFormat::RGBA)
.cast<float>();
case TextureFormat::SSCALED_INT_1010102_REV:
case TextureFormat::SIGNED_INT_1010102_REV:
return swizzleGe(UVec4(SI32(0, 10), SI32(10, 10), SI32(20, 10), SI32(30, 2)), m_format.order,
TextureFormat::RGBA)
.cast<float>();
case TextureFormat::UNSIGNED_INT_999_E5_REV:
return unpackRGB999E5(*((const uint32_t *)pixelPtr));
case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:
return Vec4(Float11(UI32(0, 11)).asFloat(), Float11(UI32(11, 11)).asFloat(), Float10(UI32(22, 10)).asFloat(),
1.0f);
default:
break;
}
#undef UN8
#undef UN16
#undef UN32
#undef SN32
#undef SI32
#undef UI8
#undef UI16
#undef UI32
// Generic path.
Vec4 result;
const TextureSwizzle::Channel *channelMap = getChannelReadSwizzle(m_format.order).components;
int channelSize = getChannelSize(m_format.type);
for (int c = 0; c < 4; c++)
{
switch (channelMap[c])
{
case TextureSwizzle::CHANNEL_0:
case TextureSwizzle::CHANNEL_1:
case TextureSwizzle::CHANNEL_2:
case TextureSwizzle::CHANNEL_3:
result[c] = channelToFloat(pixelPtr + channelSize * ((int)channelMap[c]), m_format.type);
break;
case TextureSwizzle::CHANNEL_ZERO:
result[c] = 0.0f;
break;
case TextureSwizzle::CHANNEL_ONE:
result[c] = 1.0f;
break;
default:
DE_ASSERT(false);
}
}
return result;
}
template <typename T>
static tcu::Vector<T, 4> getPixelIntGeneric(const uint8_t *pixelPtr, const tcu::TextureFormat &format)
{
tcu::Vector<T, 4> result;
// Generic path.
const TextureSwizzle::Channel *channelMap = getChannelReadSwizzle(format.order).components;
int channelSize = getChannelSize(format.type);
for (int c = 0; c < 4; c++)
{
switch (channelMap[c])
{
case TextureSwizzle::CHANNEL_0:
case TextureSwizzle::CHANNEL_1:
case TextureSwizzle::CHANNEL_2:
case TextureSwizzle::CHANNEL_3:
result[c] = channelToIntType<T>(pixelPtr + channelSize * ((int)channelMap[c]), format.type);
break;
case TextureSwizzle::CHANNEL_ZERO:
result[c] = 0;
break;
case TextureSwizzle::CHANNEL_ONE:
result[c] = 1;
break;
default:
DE_ASSERT(false);
}
}
return result;
}
static U64Vec4 getPixelAsBitsUint64(const uint8_t *pixelPtr, const tcu::TextureFormat &format)
{
U64Vec4 result;
// Generic path.
const TextureSwizzle::Channel *channelMap = getChannelReadSwizzle(format.order).components;
int channelSize = getChannelSize(format.type);
for (int c = 0; c < 4; c++)
{
switch (channelMap[c])
{
case TextureSwizzle::CHANNEL_0:
case TextureSwizzle::CHANNEL_1:
case TextureSwizzle::CHANNEL_2:
case TextureSwizzle::CHANNEL_3:
result[c] = retrieveChannelBitsAsUint64(pixelPtr + channelSize * ((int)channelMap[c]), format.type);
break;
case TextureSwizzle::CHANNEL_ZERO:
result[c] = 0;
break;
case TextureSwizzle::CHANNEL_ONE:
result[c] = 1;
break;
default:
DE_ASSERT(false);
}
}
return result;
}
IVec4 ConstPixelBufferAccess::getPixelInt(int x, int y, int z) const
{
DE_ASSERT(de::inBounds(x, 0, m_size.x()));
DE_ASSERT(de::inBounds(y, 0, m_size.y()));
DE_ASSERT(de::inBounds(z, 0, m_size.z()));
DE_ASSERT(!isCombinedDepthStencilType(m_format.type)); // combined types cannot be accessed directly
DE_ASSERT(m_format.order != TextureFormat::DS); // combined formats cannot be accessed directly
const uint8_t *const pixelPtr = (const uint8_t *)getPixelPtr(x, y, z);
// Optimized fomats.
if (m_format.type == TextureFormat::UNORM_INT8)
{
if (m_format.order == TextureFormat::RGBA || m_format.order == TextureFormat::sRGBA)
return readRGBA8888Int(pixelPtr);
else if (m_format.order == TextureFormat::RGB || m_format.order == TextureFormat::sRGB)
return readRGB888Int(pixelPtr);
}
#define U8(OFFS, COUNT) ((*((const uint8_t *)pixelPtr) >> (OFFS)) & ((1 << (COUNT)) - 1))
#define U16(OFFS, COUNT) ((*((const uint16_t *)pixelPtr) >> (OFFS)) & ((1 << (COUNT)) - 1))
#define U32(OFFS, COUNT) ((*((const uint32_t *)pixelPtr) >> (OFFS)) & ((1 << (COUNT)) - 1))
#define S32(OFFS, COUNT) signExtend(U32(OFFS, COUNT), (COUNT))
switch (m_format.type)
{
case TextureFormat::UNSIGNED_BYTE_44: // Fall-through
case TextureFormat::UNORM_BYTE_44:
return UVec4(U8(4, 4), U8(0, 4), 0u, 1u).cast<int>();
case TextureFormat::UNSIGNED_SHORT_565: // Fall-through
case TextureFormat::UNORM_SHORT_565:
return swizzleGe(UVec4(U16(11, 5), U16(5, 6), U16(0, 5), 1).cast<int>(), m_format.order, TextureFormat::RGB);
case TextureFormat::UNORM_SHORT_555:
return swizzleGe(UVec4(U16(10, 5), U16(5, 5), U16(0, 5), 1).cast<int>(), m_format.order, TextureFormat::RGB);
case TextureFormat::UNSIGNED_SHORT_4444: // Fall-through
case TextureFormat::UNORM_SHORT_4444:
return swizzleGe(UVec4(U16(12, 4), U16(8, 4), U16(4, 4), U16(0, 4)).cast<int>(), m_format.order,
TextureFormat::RGBA);
case TextureFormat::UNSIGNED_SHORT_5551: // Fall-through
case TextureFormat::UNORM_SHORT_5551:
return swizzleGe(UVec4(U16(11, 5), U16(6, 5), U16(1, 5), U16(0, 1)).cast<int>(), m_format.order,
TextureFormat::RGBA);
case TextureFormat::UNORM_SHORT_1555:
return swizzleGe(UVec4(U16(15, 1), U16(10, 5), U16(5, 5), U16(0, 5)).cast<int>(), m_format.order,
TextureFormat::RGBA);
case TextureFormat::UNORM_INT_101010:
return UVec4(U32(22, 10), U32(12, 10), U32(2, 10), 1).cast<int>();
case TextureFormat::UNORM_INT_1010102_REV: // Fall-through
case TextureFormat::USCALED_INT_1010102_REV: // Fall-through
case TextureFormat::UNSIGNED_INT_1010102_REV:
return swizzleGe(UVec4(U32(0, 10), U32(10, 10), U32(20, 10), U32(30, 2)), m_format.order, TextureFormat::RGBA)
.cast<int>();
case TextureFormat::SNORM_INT_1010102_REV: // Fall-through
case TextureFormat::SSCALED_INT_1010102_REV: // Fall-through
case TextureFormat::SIGNED_INT_1010102_REV:
return swizzleGe(IVec4(S32(0, 10), S32(10, 10), S32(20, 10), S32(30, 2)), m_format.order, TextureFormat::RGBA);
default:
break; // To generic path.
}
#undef U8
#undef U16
#undef U32
#undef S32
// Generic path.
return getPixelIntGeneric<int>(pixelPtr, m_format);
}
I64Vec4 ConstPixelBufferAccess::getPixelInt64(int x, int y, int z) const
{
// Rely on getPixelInt() for some formats.
if (m_format.type == TextureFormat::UNORM_INT8 &&
(m_format.order == TextureFormat::RGBA || m_format.order == TextureFormat::sRGBA ||
m_format.order == TextureFormat::RGB || m_format.order == TextureFormat::sRGB))
{
return getPixelInt(x, y, z).cast<int64_t>();
}
switch (m_format.type)
{
case TextureFormat::UNSIGNED_BYTE_44:
case TextureFormat::UNORM_BYTE_44:
case TextureFormat::UNSIGNED_SHORT_565:
case TextureFormat::UNORM_SHORT_565:
case TextureFormat::UNORM_SHORT_555:
case TextureFormat::UNSIGNED_SHORT_4444:
case TextureFormat::UNORM_SHORT_4444:
case TextureFormat::UNSIGNED_SHORT_5551:
case TextureFormat::UNORM_SHORT_5551:
case TextureFormat::UNORM_INT_101010:
case TextureFormat::UNORM_INT_1010102_REV:
case TextureFormat::USCALED_INT_1010102_REV:
case TextureFormat::UNSIGNED_INT_1010102_REV:
case TextureFormat::SNORM_INT_1010102_REV:
case TextureFormat::SSCALED_INT_1010102_REV:
case TextureFormat::SIGNED_INT_1010102_REV:
case TextureFormat::UNORM_SHORT_1555:
return getPixelInt(x, y, z).cast<int64_t>();
default:
break; // To generic path.
}
// Generic path.
auto pixelPtr = reinterpret_cast<const uint8_t *>(getPixelPtr(x, y, z));
return getPixelIntGeneric<int64_t>(pixelPtr, m_format);
}
U64Vec4 ConstPixelBufferAccess::getPixelBitsAsUint64(int x, int y, int z) const
{
DE_ASSERT(de::inBounds(x, 0, m_size.x()));
DE_ASSERT(de::inBounds(y, 0, m_size.y()));
DE_ASSERT(de::inBounds(z, 0, m_size.z()));
DE_ASSERT(!isCombinedDepthStencilType(m_format.type)); // combined types cannot be accessed directly
DE_ASSERT(m_format.order != TextureFormat::DS); // combined formats cannot be accessed directly
const uint8_t *const pixelPtr = (const uint8_t *)getPixelPtr(x, y, z);
if (m_format.type == TextureFormat::UNORM_INT8)
{
if (m_format.order == TextureFormat::RGBA || m_format.order == TextureFormat::sRGBA)
return U64Vec4(pixelPtr[0], pixelPtr[1], pixelPtr[2], pixelPtr[3]);
else if (m_format.order == TextureFormat::RGB || m_format.order == TextureFormat::sRGB)
return U64Vec4(pixelPtr[0], pixelPtr[1], pixelPtr[2], 1);
}
#define U8(OFFS, COUNT) ((*((const uint8_t *)pixelPtr) >> (OFFS)) & ((1 << (COUNT)) - 1))
#define U16(OFFS, COUNT) ((*((const uint16_t *)pixelPtr) >> (OFFS)) & ((1 << (COUNT)) - 1))
#define U32(OFFS, COUNT) ((*((const uint32_t *)pixelPtr) >> (OFFS)) & ((1 << (COUNT)) - 1))
switch (m_format.type)
{
case TextureFormat::UNSIGNED_BYTE_44: // Fall-through
case TextureFormat::UNORM_BYTE_44:
return U64Vec4(U8(4, 4), U8(0, 4), 0u, 1u);
case TextureFormat::UNSIGNED_SHORT_565: // Fall-through
case TextureFormat::UNORM_SHORT_565:
return swizzleGe(U64Vec4(U16(11, 5), U16(5, 6), U16(0, 5), 1), m_format.order, TextureFormat::RGB);
case TextureFormat::UNORM_SHORT_555:
return swizzleGe(U64Vec4(U16(10, 5), U16(5, 5), U16(0, 5), 1), m_format.order, TextureFormat::RGB);
case TextureFormat::UNSIGNED_SHORT_4444: // Fall-through
case TextureFormat::UNORM_SHORT_4444:
return swizzleGe(U64Vec4(U16(12, 4), U16(8, 4), U16(4, 4), U16(0, 4)), m_format.order, TextureFormat::RGBA);
case TextureFormat::UNSIGNED_SHORT_5551: // Fall-through
case TextureFormat::UNORM_SHORT_5551:
return swizzleGe(U64Vec4(U16(11, 5), U16(6, 5), U16(1, 5), U16(0, 1)), m_format.order, TextureFormat::RGBA);
case TextureFormat::UNORM_INT_101010:
return U64Vec4(U32(22, 10), U32(12, 10), U32(2, 10), 1);
case TextureFormat::UNORM_INT_1010102_REV: // Fall-through
case TextureFormat::USCALED_INT_1010102_REV: // Fall-through
case TextureFormat::UNSIGNED_INT_1010102_REV:
return swizzleGe(U64Vec4(U32(0, 10), U32(10, 10), U32(20, 10), U32(30, 2)), m_format.order,
TextureFormat::RGBA);
case TextureFormat::SNORM_INT_1010102_REV: // Fall-through
case TextureFormat::SSCALED_INT_1010102_REV: // Fall-through
case TextureFormat::SIGNED_INT_1010102_REV:
return swizzleGe(U64Vec4(U32(0, 10), U32(10, 10), U32(20, 10), U32(30, 2)), m_format.order,
TextureFormat::RGBA);
case TextureFormat::UNORM_SHORT_1555:
return swizzleGe(U64Vec4(U16(15, 1), U16(10, 5), U16(5, 5), U16(0, 5)), m_format.order, TextureFormat::RGBA);
default:
break; // To generic path.
}
#undef U8
#undef U16
#undef U32
// Generic path.
return getPixelAsBitsUint64(pixelPtr, m_format);
}
template <>
Vec4 ConstPixelBufferAccess::getPixelT(int x, int y, int z) const
{
return getPixel(x, y, z);
}
template <>
IVec4 ConstPixelBufferAccess::getPixelT(int x, int y, int z) const
{
return getPixelInt(x, y, z);
}
template <>
UVec4 ConstPixelBufferAccess::getPixelT(int x, int y, int z) const
{
return getPixelUint(x, y, z);
}
template <>
I64Vec4 ConstPixelBufferAccess::getPixelT(int x, int y, int z) const
{
return getPixelInt64(x, y, z);
}
template <>
U64Vec4 ConstPixelBufferAccess::getPixelT(int x, int y, int z) const
{
return getPixelUint64(x, y, z);
}
float ConstPixelBufferAccess::getPixDepth(int x, int y, int z) const
{
DE_ASSERT(de::inBounds(x, 0, getWidth()));
DE_ASSERT(de::inBounds(y, 0, getHeight()));
DE_ASSERT(de::inBounds(z, 0, getDepth()));
const uint8_t *const pixelPtr = (const uint8_t *)getPixelPtr(x, y, z);
switch (m_format.type)
{
case TextureFormat::UNSIGNED_INT_16_8_8:
DE_ASSERT(m_format.order == TextureFormat::DS);
return (float)readUint32High16(pixelPtr) / 65535.0f;
case TextureFormat::UNSIGNED_INT_24_8:
DE_ASSERT(m_format.order == TextureFormat::D || m_format.order == TextureFormat::DS);
return (float)readUint32High24(pixelPtr) / 16777215.0f;
case TextureFormat::UNSIGNED_INT_24_8_REV:
DE_ASSERT(m_format.order == TextureFormat::D || m_format.order == TextureFormat::DS);
return (float)readUint32Low24(pixelPtr) / 16777215.0f;
case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
DE_ASSERT(m_format.order == TextureFormat::DS);
return *((const float *)pixelPtr);
default:
DE_ASSERT(m_format.order == TextureFormat::D); // no other combined depth stencil types
return channelToFloat(pixelPtr, m_format.type);
}
}
int ConstPixelBufferAccess::getPixStencil(int x, int y, int z) const
{
DE_ASSERT(de::inBounds(x, 0, getWidth()));
DE_ASSERT(de::inBounds(y, 0, getHeight()));
DE_ASSERT(de::inBounds(z, 0, getDepth()));
const uint8_t *const pixelPtr = (const uint8_t *)getPixelPtr(x, y, z);
switch (m_format.type)
{
case TextureFormat::UNSIGNED_INT_24_8_REV:
DE_ASSERT(m_format.order == TextureFormat::DS);
return (int)readUint32High8(pixelPtr);
case TextureFormat::UNSIGNED_INT_16_8_8:
case TextureFormat::UNSIGNED_INT_24_8:
DE_ASSERT(m_format.order == TextureFormat::DS);
return (int)readUint32Low8(pixelPtr);
case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
DE_ASSERT(m_format.order == TextureFormat::DS);
return (int)readUint32Low8(pixelPtr + 4);
default:
{
DE_ASSERT(m_format.order == TextureFormat::S); // no other combined depth stencil types
return channelToInt(pixelPtr, m_format.type);
}
}
}
void PixelBufferAccess::setPixel(const Vec4 &color, int x, int y, int z) const
{
DE_ASSERT(de::inBounds(x, 0, getWidth()));
DE_ASSERT(de::inBounds(y, 0, getHeight()));
DE_ASSERT(de::inBounds(z, 0, getDepth()));
DE_ASSERT(!isCombinedDepthStencilType(m_format.type)); // combined types cannot be accessed directly
DE_ASSERT(m_format.order != TextureFormat::DS); // combined formats cannot be accessed directly
uint8_t *const pixelPtr = (uint8_t *)getPixelPtr(x, y, z);
// Optimized fomats.
if (m_format.type == TextureFormat::UNORM_INT8)
{
if (m_format.order == TextureFormat::RGBA || m_format.order == TextureFormat::sRGBA)
{
writeRGBA8888Float(pixelPtr, color);
return;
}
else if (m_format.order == TextureFormat::RGB || m_format.order == TextureFormat::sRGB)
{
writeRGB888Float(pixelPtr, color);
return;
}
}
#define PN(VAL, OFFS, BITS) (unormFloatToChannel((VAL), (BITS)) << (OFFS))
#define PS(VAL, OFFS, BITS) (snormFloatToChannel((VAL), (BITS)) << (OFFS))
#define PU(VAL, OFFS, BITS) (uintToChannel((VAL), (BITS)) << (OFFS))
#define PI(VAL, OFFS, BITS) (intToChannel((VAL), (BITS)) << (OFFS))
switch (m_format.type)
{
case TextureFormat::UNORM_BYTE_44:
*((uint8_t *)pixelPtr) = (uint8_t)(PN(color[0], 4, 4) | PN(color[1], 0, 4));
break;
case TextureFormat::UNSIGNED_BYTE_44:
*((uint8_t *)pixelPtr) = (uint8_t)(PU((uint32_t)color[0], 4, 4) | PU((uint32_t)color[1], 0, 4));
break;
case TextureFormat::UNORM_INT_101010:
*((uint32_t *)pixelPtr) = PN(color[0], 22, 10) | PN(color[1], 12, 10) | PN(color[2], 2, 10);
break;
case TextureFormat::UNORM_SHORT_565:
{
const Vec4 swizzled = swizzleGe(color, TextureFormat::RGB, m_format.order);
*((uint16_t *)pixelPtr) = (uint16_t)(PN(swizzled[0], 11, 5) | PN(swizzled[1], 5, 6) | PN(swizzled[2], 0, 5));
break;
}
case TextureFormat::UNSIGNED_SHORT_565:
{
const UVec4 swizzled = swizzleGe(color.cast<uint32_t>(), TextureFormat::RGB, m_format.order);
*((uint16_t *)pixelPtr) = (uint16_t)(PU(swizzled[0], 11, 5) | PU(swizzled[1], 5, 6) | PU(swizzled[2], 0, 5));
break;
}
case TextureFormat::UNORM_SHORT_555:
{
const Vec4 swizzled = swizzleGe(color, TextureFormat::RGB, m_format.order);
*((uint16_t *)pixelPtr) = (uint16_t)(PN(swizzled[0], 10, 5) | PN(swizzled[1], 5, 5) | PN(swizzled[2], 0, 5));
break;
}
case TextureFormat::UNORM_SHORT_4444:
{
const Vec4 swizzled = swizzleGe(color, TextureFormat::RGBA, m_format.order);
*((uint16_t *)pixelPtr) =
(uint16_t)(PN(swizzled[0], 12, 4) | PN(swizzled[1], 8, 4) | PN(swizzled[2], 4, 4) | PN(swizzled[3], 0, 4));
break;
}
case TextureFormat::UNSIGNED_SHORT_4444:
{
const UVec4 swizzled = swizzleGe(color.cast<uint32_t>(), TextureFormat::RGBA, m_format.order);
*((uint16_t *)pixelPtr) =
(uint16_t)(PU(swizzled[0], 12, 4) | PU(swizzled[1], 8, 4) | PU(swizzled[2], 4, 4) | PU(swizzled[3], 0, 4));
break;
}
case TextureFormat::UNORM_SHORT_5551:
{
const Vec4 swizzled = swizzleGe(color, TextureFormat::RGBA, m_format.order);
*((uint16_t *)pixelPtr) =
(uint16_t)(PN(swizzled[0], 11, 5) | PN(swizzled[1], 6, 5) | PN(swizzled[2], 1, 5) | PN(swizzled[3], 0, 1));
break;
}
case TextureFormat::UNORM_SHORT_1555:
{
const Vec4 swizzled = swizzleGe(color, TextureFormat::RGBA, m_format.order);
*((uint16_t *)pixelPtr) =
(uint16_t)(PN(swizzled[0], 15, 1) | PN(swizzled[1], 10, 5) | PN(swizzled[2], 5, 5) | PN(swizzled[3], 0, 5));
break;
}
case TextureFormat::UNSIGNED_SHORT_5551:
{
const UVec4 swizzled = swizzleGe(color.cast<uint32_t>(), TextureFormat::RGBA, m_format.order);
*((uint16_t *)pixelPtr) =
(uint16_t)(PU(swizzled[0], 11, 5) | PU(swizzled[1], 6, 5) | PU(swizzled[2], 1, 5) | PU(swizzled[3], 0, 1));
break;
}
case TextureFormat::UNORM_INT_1010102_REV:
{
const Vec4 u = swizzleGe(color, TextureFormat::RGBA, m_format.order);
*((uint32_t *)pixelPtr) = PN(u[0], 0, 10) | PN(u[1], 10, 10) | PN(u[2], 20, 10) | PN(u[3], 30, 2);
break;
}
case TextureFormat::SNORM_INT_1010102_REV:
{
const Vec4 u = swizzleGe(color, TextureFormat::RGBA, m_format.order);
*((uint32_t *)pixelPtr) = PS(u[0], 0, 10) | PS(u[1], 10, 10) | PS(u[2], 20, 10) | PS(u[3], 30, 2);
break;
}
case TextureFormat::UNSIGNED_INT_1010102_REV:
case TextureFormat::USCALED_INT_1010102_REV:
{
const UVec4 u = swizzleGe(color.cast<uint32_t>(), TextureFormat::RGBA, m_format.order);
*((uint32_t *)pixelPtr) = PU(u[0], 0, 10) | PU(u[1], 10, 10) | PU(u[2], 20, 10) | PU(u[3], 30, 2);
break;
}
case TextureFormat::SIGNED_INT_1010102_REV:
case TextureFormat::SSCALED_INT_1010102_REV:
{
const IVec4 u = swizzleGe(color.cast<int32_t>(), TextureFormat::RGBA, m_format.order);
*((uint32_t *)pixelPtr) = PI(u[0], 0, 10) | PI(u[1], 10, 10) | PI(u[2], 20, 10) | PI(u[3], 30, 2);
break;
}
case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:
*((uint32_t *)pixelPtr) =
Float11(color[0]).bits() | (Float11(color[1]).bits() << 11) | (Float10(color[2]).bits() << 22);
break;
case TextureFormat::UNSIGNED_INT_999_E5_REV:
*((uint32_t *)pixelPtr) = packRGB999E5(color);
break;
default:
{
// Generic path.
int numChannels = getNumUsedChannels(m_format.order);
const TextureSwizzle::Channel *map = getChannelWriteSwizzle(m_format.order).components;
int channelSize = getChannelSize(m_format.type);
for (int c = 0; c < numChannels; c++)
{
DE_ASSERT(deInRange32(map[c], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3));
floatToChannel(pixelPtr + channelSize * c, color[map[c]], m_format.type);
}
break;
}
}
#undef PN
#undef PS
#undef PU
#undef PI
}
void PixelBufferAccess::setPixel(const IVec4 &color, int x, int y, int z) const
{
DE_ASSERT(de::inBounds(x, 0, getWidth()));
DE_ASSERT(de::inBounds(y, 0, getHeight()));
DE_ASSERT(de::inBounds(z, 0, getDepth()));
DE_ASSERT(!isCombinedDepthStencilType(m_format.type)); // combined types cannot be accessed directly
DE_ASSERT(m_format.order != TextureFormat::DS); // combined formats cannot be accessed directly
uint8_t *const pixelPtr = (uint8_t *)getPixelPtr(x, y, z);
// Optimized fomats.
if (m_format.type == TextureFormat::UNORM_INT8)
{
if (m_format.order == TextureFormat::RGBA || m_format.order == TextureFormat::sRGBA)
{
writeRGBA8888Int(pixelPtr, color);
return;
}
else if (m_format.order == TextureFormat::RGB || m_format.order == TextureFormat::sRGB)
{
writeRGB888Int(pixelPtr, color);
return;
}
}
#define PU(VAL, OFFS, BITS) (uintToChannel((uint32_t)(VAL), (BITS)) << (OFFS))
#define PI(VAL, OFFS, BITS) (intToChannel((uint32_t)(VAL), (BITS)) << (OFFS))
switch (m_format.type)
{
case TextureFormat::UNSIGNED_BYTE_44: // Fall-through
case TextureFormat::UNORM_BYTE_44:
*((uint8_t *)pixelPtr) = (uint8_t)(PU(color[0], 4, 4) | PU(color[1], 0, 4));
break;
case TextureFormat::UNORM_INT_101010:
*((uint32_t *)pixelPtr) = PU(color[0], 22, 10) | PU(color[1], 12, 10) | PU(color[2], 2, 10);
break;
case TextureFormat::UNORM_SHORT_565:
case TextureFormat::UNSIGNED_SHORT_565:
{
const IVec4 swizzled = swizzleGe(color, TextureFormat::RGB, m_format.order);
*((uint16_t *)pixelPtr) = (uint16_t)(PU(swizzled[0], 11, 5) | PU(swizzled[1], 5, 6) | PU(swizzled[2], 0, 5));
break;
}
case TextureFormat::UNORM_SHORT_555:
{
const IVec4 swizzled = swizzleGe(color, TextureFormat::RGB, m_format.order);
*((uint16_t *)pixelPtr) = (uint16_t)(PU(swizzled[0], 10, 5) | PU(swizzled[1], 5, 5) | PU(swizzled[2], 0, 5));
break;
}
case TextureFormat::UNORM_SHORT_4444:
case TextureFormat::UNSIGNED_SHORT_4444:
{
const IVec4 swizzled = swizzleGe(color, TextureFormat::RGBA, m_format.order);
*((uint16_t *)pixelPtr) =
(uint16_t)(PU(swizzled[0], 12, 4) | PU(swizzled[1], 8, 4) | PU(swizzled[2], 4, 4) | PU(swizzled[3], 0, 4));
break;
}
case TextureFormat::UNORM_SHORT_5551:
case TextureFormat::UNSIGNED_SHORT_5551:
{
const IVec4 swizzled = swizzleGe(color, TextureFormat::RGBA, m_format.order);
*((uint16_t *)pixelPtr) =
(uint16_t)(PU(swizzled[0], 11, 5) | PU(swizzled[1], 6, 5) | PU(swizzled[2], 1, 5) | PU(swizzled[3], 0, 1));
break;
}
case TextureFormat::UNORM_SHORT_1555:
{
const IVec4 swizzled = swizzleGe(color, TextureFormat::RGBA, m_format.order);
*((uint16_t *)pixelPtr) =
(uint16_t)(PU(swizzled[0], 15, 1) | PU(swizzled[1], 10, 5) | PU(swizzled[2], 5, 5) | PU(swizzled[3], 0, 5));
break;
}
case TextureFormat::UNORM_INT_1010102_REV:
case TextureFormat::UNSIGNED_INT_1010102_REV:
case TextureFormat::USCALED_INT_1010102_REV:
{
const IVec4 swizzled = swizzleGe(color, TextureFormat::RGBA, m_format.order);
*((uint32_t *)pixelPtr) =
PU(swizzled[0], 0, 10) | PU(swizzled[1], 10, 10) | PU(swizzled[2], 20, 10) | PU(swizzled[3], 30, 2);
break;
}
case TextureFormat::SNORM_INT_1010102_REV:
case TextureFormat::SIGNED_INT_1010102_REV:
case TextureFormat::SSCALED_INT_1010102_REV:
{
const IVec4 swizzled = swizzleGe(color, TextureFormat::RGBA, m_format.order);
*((uint32_t *)pixelPtr) =
PI(swizzled[0], 0, 10) | PI(swizzled[1], 10, 10) | PI(swizzled[2], 20, 10) | PI(swizzled[3], 30, 2);
break;
}
default:
{
// Generic path.
int numChannels = getNumUsedChannels(m_format.order);
const TextureSwizzle::Channel *map = getChannelWriteSwizzle(m_format.order).components;
int channelSize = getChannelSize(m_format.type);
for (int c = 0; c < numChannels; c++)
{
DE_ASSERT(deInRange32(map[c], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3));
intToChannel(pixelPtr + channelSize * c, color[map[c]], m_format.type);
}
break;
}
}
#undef PU
#undef PI
}
void PixelBufferAccess::setPixDepth(float depth, int x, int y, int z) const
{
DE_ASSERT(de::inBounds(x, 0, getWidth()));
DE_ASSERT(de::inBounds(y, 0, getHeight()));
DE_ASSERT(de::inBounds(z, 0, getDepth()));
uint8_t *const pixelPtr = (uint8_t *)getPixelPtr(x, y, z);
switch (m_format.type)
{
case TextureFormat::UNSIGNED_INT_16_8_8:
DE_ASSERT(m_format.order == TextureFormat::DS);
writeUint32High16(pixelPtr, convertSatRte<uint16_t>(depth * 65535.0f));
break;
case TextureFormat::UNSIGNED_INT_24_8:
DE_ASSERT(m_format.order == TextureFormat::D || m_format.order == TextureFormat::DS);
writeUint32High24(pixelPtr, convertSatRteUint24(depth * 16777215.0f));
break;
case TextureFormat::UNSIGNED_INT_24_8_REV:
DE_ASSERT(m_format.order == TextureFormat::D || m_format.order == TextureFormat::DS);
writeUint32Low24(pixelPtr, convertSatRteUint24(depth * 16777215.0f));
break;
case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
DE_ASSERT(m_format.order == TextureFormat::DS);
*((float *)pixelPtr) = depth;
break;
default:
DE_ASSERT(m_format.order == TextureFormat::D); // no other combined depth stencil types
floatToChannel(pixelPtr, depth, m_format.type);
break;
}
}
void PixelBufferAccess::setPixStencil(int stencil, int x, int y, int z) const
{
DE_ASSERT(de::inBounds(x, 0, getWidth()));
DE_ASSERT(de::inBounds(y, 0, getHeight()));
DE_ASSERT(de::inBounds(z, 0, getDepth()));
uint8_t *const pixelPtr = (uint8_t *)getPixelPtr(x, y, z);
switch (m_format.type)
{
case TextureFormat::UNSIGNED_INT_16_8_8:
case TextureFormat::UNSIGNED_INT_24_8:
DE_ASSERT(m_format.order == TextureFormat::DS);
writeUint32Low8(pixelPtr, convertSat<uint8_t>((uint32_t)stencil));
break;
case TextureFormat::UNSIGNED_INT_24_8_REV:
DE_ASSERT(m_format.order == TextureFormat::DS);
writeUint32High8(pixelPtr, convertSat<uint8_t>((uint32_t)stencil));
break;
case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
DE_ASSERT(m_format.order == TextureFormat::DS);
writeUint32Low8(pixelPtr + 4, convertSat<uint8_t>((uint32_t)stencil));
break;
default:
DE_ASSERT(m_format.order == TextureFormat::S); // no other combined depth stencil types
intToChannel(pixelPtr, stencil, m_format.type);
break;
}
}
static inline int imod(int a, int b)
{
int m = a % b;
return m < 0 ? m + b : m;
}
static inline int mirror(int a)
{
return a >= 0 ? a : -(1 + a);
}
// Nearest-even rounding in case of tie (fractional part 0.5), otherwise ordinary rounding.
static inline float rint(float a)
{
DE_STATIC_ASSERT((-3 % 2 != 0) && (-4 % 2 == 0));
float fracVal = deFloatFrac(a);
if (fracVal != 0.5f)
return deFloatRound(a); // Ordinary case.
float floorVal = a - fracVal;
bool roundUp = (int64_t)floorVal % 2 != 0;
return floorVal + (roundUp ? 1.0f : 0.0f);
}
static inline int wrap(Sampler::WrapMode mode, int c, int size)
{
switch (mode)
{
case tcu::Sampler::CLAMP_TO_BORDER:
return deClamp32(c, -1, size);
case tcu::Sampler::CLAMP_TO_EDGE:
return deClamp32(c, 0, size - 1);
case tcu::Sampler::REPEAT_GL:
return imod(c, size);
case tcu::Sampler::REPEAT_CL:
return imod(c, size);
case tcu::Sampler::MIRRORED_ONCE:
c = deClamp32(c, -size, size);
// Fall-through
case tcu::Sampler::MIRRORED_REPEAT_GL:
return (size - 1) - mirror(imod(c, 2 * size) - size);
case tcu::Sampler::MIRRORED_REPEAT_CL:
return deClamp32(c, 0, size - 1); // \note Actual mirroring done already in unnormalization function.
default:
DE_ASSERT(false);
return 0;
}
}
// Special unnormalization for REPEAT_CL and MIRRORED_REPEAT_CL wrap modes; otherwise ordinary unnormalization.
static inline float unnormalize(Sampler::WrapMode mode, float c, int size)
{
switch (mode)
{
case tcu::Sampler::CLAMP_TO_EDGE:
case tcu::Sampler::CLAMP_TO_BORDER:
case tcu::Sampler::REPEAT_GL:
case tcu::Sampler::MIRRORED_REPEAT_GL:
case tcu::Sampler::MIRRORED_ONCE: // Fall-through (ordinary case).
return (float)size * c;
case tcu::Sampler::REPEAT_CL:
return (float)size * (c - deFloatFloor(c));
case tcu::Sampler::MIRRORED_REPEAT_CL:
return (float)size * deFloatAbs(c - 2.0f * rint(0.5f * c));
default:
DE_ASSERT(false);
return 0.0f;
}
}
static bool isFixedPointDepthTextureFormat(const tcu::TextureFormat &format)
{
DE_ASSERT(format.order == TextureFormat::D || format.order == TextureFormat::R);
const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(format.type);
if (channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT)
return false;
else if (channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
return true;
else
{
DE_ASSERT(false);
return false;
}
}
// Texel lookup with color conversion.
static inline Vec4 lookup(const ConstPixelBufferAccess &access, int i, int j, int k)
{
const TextureFormat &format = access.getFormat();
if (isSRGB(format))
{
if (format.type == TextureFormat::UNORM_INT8 && format.order == TextureFormat::sRGB)
return sRGB8ToLinear(access.getPixelUint(i, j, k));
else if (format.type == TextureFormat::UNORM_INT8 && format.order == TextureFormat::sRGBA)
return sRGBA8ToLinear(access.getPixelUint(i, j, k));
else
return sRGBToLinear(access.getPixel(i, j, k));
}
else
{
return access.getPixel(i, j, k);
}
}
// Border texel lookup with color conversion.
static inline Vec4 lookupBorder(const tcu::TextureFormat &format, const tcu::Sampler &sampler)
{
// "lookup" for a combined format does not make sense, disallow
DE_ASSERT(!isCombinedDepthStencilType(format.type));
const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(format.type);
const bool isFloat = channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT;
const bool isFixed = channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT ||
channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
const bool isPureInteger = channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER;
const bool isPureUnsignedInteger = channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
if (isFloat || isFixed)
return sampleTextureBorder<float>(format, sampler);
else if (isPureInteger)
return sampleTextureBorder<int32_t>(format, sampler).cast<float>();
else if (isPureUnsignedInteger)
return sampleTextureBorder<uint32_t>(format, sampler).cast<float>();
else
{
DE_ASSERT(false);
return Vec4(-1.0);
}
}
static inline float execCompare(const tcu::Vec4 &color, Sampler::CompareMode compare, int chanNdx, float ref_,
bool isFixedPoint)
{
const bool clampValues =
isFixedPoint; // if comparing against a floating point texture, ref (and value) is not clamped
const float cmp = (clampValues) ? (de::clamp(color[chanNdx], 0.0f, 1.0f)) : (color[chanNdx]);
const float ref = (clampValues) ? (de::clamp(ref_, 0.0f, 1.0f)) : (ref_);
bool res = false;
switch (compare)
{
case Sampler::COMPAREMODE_LESS:
res = ref < cmp;
break;
case Sampler::COMPAREMODE_LESS_OR_EQUAL:
res = ref <= cmp;
break;
case Sampler::COMPAREMODE_GREATER:
res = ref > cmp;
break;
case Sampler::COMPAREMODE_GREATER_OR_EQUAL:
res = ref >= cmp;
break;
case Sampler::COMPAREMODE_EQUAL:
res = ref == cmp;
break;
case Sampler::COMPAREMODE_NOT_EQUAL:
res = ref != cmp;
break;
case Sampler::COMPAREMODE_ALWAYS:
res = true;
break;
case Sampler::COMPAREMODE_NEVER:
res = false;
break;
default:
DE_ASSERT(false);
}
return res ? 1.0f : 0.0f;
}
static Vec4 sampleNearest1D(const ConstPixelBufferAccess &access, const Sampler &sampler, float u, const IVec2 &offset)
{
int width = access.getWidth();
int x = deFloorFloatToInt32(u) + offset.x();
// Check for CLAMP_TO_BORDER.
if (sampler.wrapS == Sampler::CLAMP_TO_BORDER && !deInBounds32(x, 0, width))
return lookupBorder(access.getFormat(), sampler);
int i = wrap(sampler.wrapS, x, width);
return lookup(access, i, offset.y(), 0);
}
static Vec4 sampleNearest2D(const ConstPixelBufferAccess &access, const Sampler &sampler, float u, float v,
const IVec3 &offset)
{
int width = access.getWidth();
int height = access.getHeight();
int x = deFloorFloatToInt32(u) + offset.x();
int y = deFloorFloatToInt32(v) + offset.y();
// Check for CLAMP_TO_BORDER.
if ((sampler.wrapS == Sampler::CLAMP_TO_BORDER && !deInBounds32(x, 0, width)) ||
(sampler.wrapT == Sampler::CLAMP_TO_BORDER && !deInBounds32(y, 0, height)))
return lookupBorder(access.getFormat(), sampler);
int