Add support for 10 and 12bit packed unorm formats

10 and 12bit unsigned normalized values are packed into highers bits
of 16bit unsigned int.

Change-Id: I18a88547ba29003961bf0806a50cb17995c72f13
Components: Framework
(cherry picked from commit 07621ffcf0362606afeccf2c2deac35bc0f3668a)
diff --git a/external/vulkancts/modules/vulkan/texture/vktSampleVerifierUtil.cpp b/external/vulkancts/modules/vulkan/texture/vktSampleVerifierUtil.cpp
index 5e1d378..6b0a763 100644
--- a/external/vulkancts/modules/vulkan/texture/vktSampleVerifierUtil.cpp
+++ b/external/vulkancts/modules/vulkan/texture/vktSampleVerifierUtil.cpp
@@ -653,7 +653,7 @@
 
 bool isPackedType (const TextureFormat::ChannelType type)
 {
-	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 38);
+	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 40);
 
 	switch (type)
 	{
@@ -678,7 +678,7 @@
 				  IVec4& bitOffsets,
 				  int& baseTypeBytes)
 {
-	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 38);
+	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 40);
 
 	switch (texFormat.type)
 	{
diff --git a/framework/common/tcuTexture.cpp b/framework/common/tcuTexture.cpp
index 52b6cf8..957a952 100644
--- a/framework/common/tcuTexture.cpp
+++ b/framework/common/tcuTexture.cpp
@@ -257,10 +257,24 @@
 	return de::min(rounded, maxUint24);
 }
 
+inline deUint16 convertSatRteUint10 (float f)
+{
+	const deUint16 rounded		= convertSatRte<deUint16>(f);
+	const deUint16 maxUint10	= 0x3FFu;
+	return de::min(rounded, maxUint10);
+}
+
+inline deUint16 convertSatRteUint12 (float f)
+{
+	const deUint16 rounded		= convertSatRte<deUint16>(f);
+	const deUint16 maxUint12	= 0xFFFu;
+	return de::min(rounded, maxUint12);
+}
+
 inline float channelToFloat (const deUint8* value, TextureFormat::ChannelType type)
 {
 	// make sure this table is updated if format table is updated
-	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 38);
+	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 40);
 
 	switch (type)
 	{
@@ -281,6 +295,8 @@
 		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 deUint16*)value)) >> 6u) / 1023.0f;
+		case TextureFormat::UNORM_SHORT_12:		return (float)((*((const deUint16*)value)) >> 4u) / 4095.0f;
 		default:
 			DE_ASSERT(DE_FALSE);
 			return 0.0f;
@@ -290,7 +306,7 @@
 inline int channelToInt (const deUint8* value, TextureFormat::ChannelType type)
 {
 	// make sure this table is updated if format table is updated
-	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 38);
+	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 40);
 
 	switch (type)
 	{
@@ -311,6 +327,8 @@
 		case TextureFormat::HALF_FLOAT:			return (int)deFloat16To32(*(const deFloat16*)value);
 		case TextureFormat::FLOAT:				return (int)*((const float*)value);
 		case TextureFormat::FLOAT64:			return (int)*((const double*)value);
+		case TextureFormat::UNORM_SHORT_10:		return (int)((*(((const deUint16*)value))) >> 6u);
+		case TextureFormat::UNORM_SHORT_12:		return (int)((*(((const deUint16*)value))) >> 4u);
 		default:
 			DE_ASSERT(DE_FALSE);
 			return 0;
@@ -320,27 +338,29 @@
 void floatToChannel (deUint8* dst, float src, TextureFormat::ChannelType type)
 {
 	// make sure this table is updated if format table is updated
-	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 38);
+	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 40);
 
 	switch (type)
 	{
-		case TextureFormat::SNORM_INT8:			*((deInt8*)dst)			= convertSatRte<deInt8>		(src * 127.0f);			break;
-		case TextureFormat::SNORM_INT16:		*((deInt16*)dst)		= convertSatRte<deInt16>	(src * 32767.0f);		break;
-		case TextureFormat::SNORM_INT32:		*((deInt32*)dst)		= convertSatRte<deInt32>	(src * 2147483647.0f);	break;
-		case TextureFormat::UNORM_INT8:			*((deUint8*)dst)		= convertSatRte<deUint8>	(src * 255.0f);			break;
-		case TextureFormat::UNORM_INT16:		*((deUint16*)dst)		= convertSatRte<deUint16>	(src * 65535.0f);		break;
-		case TextureFormat::UNORM_INT24:		writeUint24(dst,		  convertSatRteUint24		(src * 16777215.0f));	break;
-		case TextureFormat::UNORM_INT32:		*((deUint32*)dst)		= convertSatRte<deUint32>	(src * 4294967295.0f);	break;
-		case TextureFormat::SIGNED_INT8:		*((deInt8*)dst)			= convertSatRte<deInt8>		(src);					break;
-		case TextureFormat::SIGNED_INT16:		*((deInt16*)dst)		= convertSatRte<deInt16>	(src);					break;
-		case TextureFormat::SIGNED_INT32:		*((deInt32*)dst)		= convertSatRte<deInt32>	(src);					break;
-		case TextureFormat::UNSIGNED_INT8:		*((deUint8*)dst)		= convertSatRte<deUint8>	(src);					break;
-		case TextureFormat::UNSIGNED_INT16:		*((deUint16*)dst)		= convertSatRte<deUint16>	(src);					break;
-		case TextureFormat::UNSIGNED_INT24:		writeUint24(dst,		  convertSatRteUint24		(src));					break;
-		case TextureFormat::UNSIGNED_INT32:		*((deUint32*)dst)		= convertSatRte<deUint32>	(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::SNORM_INT8:			*((deInt8*)dst)			= convertSatRte<deInt8>		(src * 127.0f);				break;
+		case TextureFormat::SNORM_INT16:		*((deInt16*)dst)		= convertSatRte<deInt16>	(src * 32767.0f);			break;
+		case TextureFormat::SNORM_INT32:		*((deInt32*)dst)		= convertSatRte<deInt32>	(src * 2147483647.0f);		break;
+		case TextureFormat::UNORM_INT8:			*((deUint8*)dst)		= convertSatRte<deUint8>	(src * 255.0f);				break;
+		case TextureFormat::UNORM_INT16:		*((deUint16*)dst)		= convertSatRte<deUint16>	(src * 65535.0f);			break;
+		case TextureFormat::UNORM_INT24:		writeUint24(dst,		  convertSatRteUint24		(src * 16777215.0f));		break;
+		case TextureFormat::UNORM_INT32:		*((deUint32*)dst)		= convertSatRte<deUint32>	(src * 4294967295.0f);		break;
+		case TextureFormat::SIGNED_INT8:		*((deInt8*)dst)			= convertSatRte<deInt8>		(src);						break;
+		case TextureFormat::SIGNED_INT16:		*((deInt16*)dst)		= convertSatRte<deInt16>	(src);						break;
+		case TextureFormat::SIGNED_INT32:		*((deInt32*)dst)		= convertSatRte<deInt32>	(src);						break;
+		case TextureFormat::UNSIGNED_INT8:		*((deUint8*)dst)		= convertSatRte<deUint8>	(src);						break;
+		case TextureFormat::UNSIGNED_INT16:		*((deUint16*)dst)		= convertSatRte<deUint16>	(src);						break;
+		case TextureFormat::UNSIGNED_INT24:		writeUint24(dst,		  convertSatRteUint24		(src));						break;
+		case TextureFormat::UNSIGNED_INT32:		*((deUint32*)dst)		= convertSatRte<deUint32>	(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:		*((deUint16*)dst)		= (deUint16)(convertSatRteUint10(src * 1023.0f) << 6u);	break;
+		case TextureFormat::UNORM_SHORT_12:		*((deUint16*)dst)		= (deUint16)(convertSatRteUint12(src * 4095.0f) << 4u);	break;
 		default:
 			DE_ASSERT(DE_FALSE);
 	}
@@ -374,10 +394,38 @@
 		return (deUint32)src;
 }
 
+template <typename S>
+static inline deUint16 convertSatUint10 (S src)
+{
+	S min = (S)0u;
+	S max = (S)0x3FFu;
+
+	if (src < min)
+		return (deUint16)min;
+	else if (src > max)
+		return (deUint16)max;
+	else
+		return (deUint16)src;
+}
+
+template <typename S>
+static inline deUint16 convertSatUint12 (S src)
+{
+	S min = (S)0u;
+	S max = (S)0xFFFu;
+
+	if (src < min)
+		return (deUint16)min;
+	else if (src > max)
+		return (deUint16)max;
+	else
+		return (deUint16)src;
+}
+
 void intToChannel (deUint8* dst, int src, TextureFormat::ChannelType type)
 {
 	// make sure this table is updated if format table is updated
-	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 38);
+	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 40);
 
 	switch (type)
 	{
@@ -396,6 +444,8 @@
 		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:		*((deUint16*)dst)		= (deUint16)(convertSatUint10(src) << 6u);	break;
+		case TextureFormat::UNORM_SHORT_12:		*((deUint16*)dst)		= (deUint16)(convertSatUint12(src) << 4u);	break;
 		default:
 			DE_ASSERT(DE_FALSE);
 	}
@@ -584,12 +634,16 @@
 		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 == 38);
+	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 40);
 }
 
 int getNumUsedChannels (TextureFormat::ChannelOrder order)
@@ -629,7 +683,7 @@
 int getChannelSize (TextureFormat::ChannelType type)
 {
 	// make sure this table is updated if format table is updated
-	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 38);
+	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 40);
 
 	switch (type)
 	{
@@ -650,6 +704,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;
 		default:
 			DE_ASSERT(DE_FALSE);
 			return 0;
@@ -665,7 +721,7 @@
 	DE_ASSERT(isValid(format));
 
 	// make sure this table is updated if format table is updated
-	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 38);
+	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 40);
 
 	switch (type)
 	{
@@ -3803,7 +3859,9 @@
 		"HALF_FLOAT",
 		"FLOAT",
 		"FLOAT64",
-		"FLOAT_UNSIGNED_INT_24_8_REV"
+		"FLOAT_UNSIGNED_INT_24_8_REV",
+		"UNORM_SHORT_10",
+		"UNORM_SHORT_12"
 	};
 
 	return str << de::getSizedArrayElement<TextureFormat::CHANNELTYPE_LAST>(typeStrings, type);
diff --git a/framework/common/tcuTexture.hpp b/framework/common/tcuTexture.hpp
index cf30b08..67010b4 100644
--- a/framework/common/tcuTexture.hpp
+++ b/framework/common/tcuTexture.hpp
@@ -110,6 +110,9 @@
 		FLOAT64,
 		FLOAT_UNSIGNED_INT_24_8_REV,
 
+		UNORM_SHORT_10,
+		UNORM_SHORT_12,
+
 		CHANNELTYPE_LAST
 	};
 
diff --git a/framework/common/tcuTextureUtil.cpp b/framework/common/tcuTextureUtil.cpp
index aaa2221..48e49e2 100644
--- a/framework/common/tcuTextureUtil.cpp
+++ b/framework/common/tcuTextureUtil.cpp
@@ -120,7 +120,7 @@
 bool isCombinedDepthStencilType (TextureFormat::ChannelType type)
 {
 	// make sure to update this if type table is updated
-	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 38);
+	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 40);
 
 	return	type == TextureFormat::UNSIGNED_INT_16_8_8			||
 			type == TextureFormat::UNSIGNED_INT_24_8			||
@@ -162,7 +162,7 @@
 TextureChannelClass getTextureChannelClass (TextureFormat::ChannelType channelType)
 {
 	// make sure this table is updated if format table is updated
-	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 38);
+	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 40);
 
 	switch (channelType)
 	{
@@ -204,6 +204,8 @@
 		case TextureFormat::FLOAT:							return TEXTURECHANNELCLASS_FLOATING_POINT;
 		case TextureFormat::FLOAT64:						return TEXTURECHANNELCLASS_FLOATING_POINT;
 		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:	return TEXTURECHANNELCLASS_LAST;					//!< packed float32-pad24-uint8
+		case TextureFormat::UNORM_SHORT_10:					return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
+		case TextureFormat::UNORM_SHORT_12:					return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
 		default:
 			DE_FATAL("Unknown channel type");
 			return TEXTURECHANNELCLASS_LAST;
@@ -347,7 +349,7 @@
 static Vec2 getFloatChannelValueRange (TextureFormat::ChannelType channelType)
 {
 	// make sure this table is updated if format table is updated
-	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 38);
+	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 40);
 
 	float cMin = 0.0f;
 	float cMax = 0.0f;
@@ -372,7 +374,9 @@
 		case TextureFormat::UNORM_SHORT_5551:
 		case TextureFormat::UNORM_SHORT_1555:
 		case TextureFormat::UNORM_INT_101010:
-		case TextureFormat::UNORM_INT_1010102_REV:			cMin = 0.0f;			cMax = 1.0f;			break;
+		case TextureFormat::UNORM_INT_1010102_REV:
+		case TextureFormat::UNORM_SHORT_10:
+		case TextureFormat::UNORM_SHORT_12:					cMin = 0.0f;			cMax = 1.0f;			break;
 
 		// Misc formats.
 		case TextureFormat::SIGNED_INT8:					cMin = -128.0f;			cMax = 127.0f;			break;
@@ -514,7 +518,7 @@
 static IVec4 getChannelBitDepth (TextureFormat::ChannelType channelType)
 {
 	// make sure this table is updated if format table is updated
-	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 38);
+	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 40);
 
 	switch (channelType)
 	{
@@ -556,6 +560,8 @@
 		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:	return IVec4(11,11,10,0);
 		case TextureFormat::UNSIGNED_INT_999_E5_REV:		return IVec4(9,9,9,0);
 		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:	return IVec4(32,8,0,0);
+		case TextureFormat::UNORM_SHORT_10:					return IVec4(10);
+		case TextureFormat::UNORM_SHORT_12:					return IVec4(12);
 		default:
 			DE_ASSERT(false);
 			return IVec4(0);
@@ -581,7 +587,7 @@
 static IVec4 getChannelMantissaBitDepth (TextureFormat::ChannelType channelType)
 {
 	// make sure this table is updated if format table is updated
-	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 38);
+	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 40);
 
 	switch (channelType)
 	{
@@ -618,6 +624,8 @@
 		case TextureFormat::UNSIGNED_INT_24_8:
 		case TextureFormat::UNSIGNED_INT_24_8_REV:
 		case TextureFormat::UNSIGNED_INT_999_E5_REV:
+		case TextureFormat::UNORM_SHORT_10:
+		case TextureFormat::UNORM_SHORT_12:
 			return getChannelBitDepth(channelType);
 
 		case TextureFormat::HALF_FLOAT:						return IVec4(10);
@@ -1256,7 +1264,7 @@
 static AccessType toSamplerAccess (const AccessType& baseAccess, Sampler::DepthStencilMode mode)
 {
 	// make sure to update this if type table is updated
-	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 38);
+	DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 40);
 
 	if (!isCombinedDepthStencilType(baseAccess.getFormat().type))
 		return baseAccess;
diff --git a/modules/internal/ditTextureFormatTests.cpp b/modules/internal/ditTextureFormatTests.cpp
index 60fbd0a..7cbc5f8 100644
--- a/modules/internal/ditTextureFormatTests.cpp
+++ b/modules/internal/ditTextureFormatTests.cpp
@@ -1029,6 +1029,88 @@
 	0x000000b3, 0x00000000, 0x00000000, 0x00000001,
 };
 
+static const deUint8 s_unormShort10In[] =
+{
+	0x80, 0x84, 0x40, 0x3b,
+	0x40, 0xfd, 0x80, 0x1a,
+	0x80, 0x0c, 0x80, 0x15,
+	0x40, 0x11, 0x80, 0xc3,
+	0x80, 0xc8, 0x80, 0xd5,
+	0xc0, 0xf9, 0x00, 0x0a,
+	0xc0, 0x39, 0x40, 0xd5,
+	0xc0, 0x4d, 0xc0, 0x26
+};
+static const deUint32 s_unormShort10FloatRef[] =
+{
+	0x3f04a128, 0x3e6d3b4f,
+	0x3f7d7f60, 0x3dd4350d,
+	0x3d48320d, 0x3dac2b0b,
+	0x3d8a2289, 0x3f43b0ec,
+	0x3f48b22d, 0x3f55b56d,
+	0x3f79fe80, 0x3d20280a,
+	0x3e6739ce, 0x3f55755d,
+	0x3e9ba6ea, 0x3e1b26ca
+};
+static const deUint32 s_unormShort10UintRef[] =
+{
+	0x212, 0x0ed, 0x3f5, 0x06a,
+	0x032, 0x056, 0x045, 0x30e,
+	0x322, 0x356, 0x3e7, 0x028,
+	0x0e7, 0x355, 0x137, 0x09b,
+};
+static const deUint32 s_unormShort10IntRef[] =
+{
+	0x212, 0x0ed, 0x3f5, 0x06a,
+	0x032, 0x056, 0x045, 0x30e,
+	0x322, 0x356, 0x3e7, 0x028,
+	0x0e7, 0x355, 0x137, 0x09b,
+};
+
+static const deUint8 s_unormShort12In[] =
+{
+	0x30, 0x46, 0xf0, 0x38,
+	0x90, 0x85, 0xf0, 0x88,
+	0x90, 0x92, 0x30, 0x5d,
+	0x30, 0x3a, 0x00, 0xc9,
+	0x00, 0x64, 0xb0, 0x9b,
+	0x20, 0x71, 0xd0, 0x5b,
+	0xa0, 0xc5, 0x70, 0x27,
+	0x30, 0x0b, 0xa0, 0x53
+};
+static const deUint32 s_unormShort12FloatRef[] =
+{
+	0x3e8c68c7, 0x3e63ce3d,
+	0x3f05985a, 0x3f08f890,
+	0x3f12992a, 0x3eba6ba7,
+	0x3e68ce8d, 0x3f490c91,
+	0x3ec80c81, 0x3f1bb9bc,
+	0x3ee24e25, 0x3eb7ab7b,
+	0x3f45ac5b, 0x3e1dc9dd,
+	0x3d330b31, 0x3ea74a75
+};
+static const deUint32 s_unormShort12UintRef[] =
+{
+	0x463, 0x38f,
+	0x859, 0x88f,
+	0x929, 0x5d3,
+	0x3a3, 0xc90,
+	0x640, 0x9bb,
+	0x712, 0x5bd,
+	0xc5a, 0x277,
+	0x0b3, 0x53a
+};
+static const deUint32 s_unormShort12IntRef[] =
+{
+	0x463, 0x38f,
+	0x859, 0x88f,
+	0x929, 0x5d3,
+	0x3a3, 0xc90,
+	0x640, 0x9bb,
+	0x712, 0x5bd,
+	0xc5a, 0x277,
+	0x0b3, 0x53a
+};
+
 // \todo [2015-10-12 pyry] Collapse duplicate ref arrays
 
 static const struct
@@ -1085,6 +1167,9 @@
 	{ s_floatIn,					DE_LENGTH_OF_ARRAY(s_floatIn),						s_floatFloatRef,					s_floatIntRef,					s_floatUintRef					},
 	{ s_float64In,					DE_LENGTH_OF_ARRAY(s_float64In),					s_float64FloatRef,					s_float64IntRef,				s_float64IntRef					},
 	{ s_floatUnsignedInt248RevIn,	DE_LENGTH_OF_ARRAY(s_floatUnsignedInt248RevIn),		s_floatUnsignedInt248RevFloatRef,	DE_NULL,						s_floatUnsignedInt248RevUintRef	},
+
+	{ s_unormShort10In,				DE_LENGTH_OF_ARRAY(s_unormShort10In),				s_unormShort10FloatRef,				s_unormShort10IntRef,			s_unormShort10UintRef			},
+	{ s_unormShort12In,				DE_LENGTH_OF_ARRAY(s_unormShort12In),				s_unormShort12FloatRef,				s_unormShort12IntRef,			s_unormShort12UintRef			},
 };
 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_formatData) == TextureFormat::CHANNELTYPE_LAST);