am aae22498: am b34a078e: Merge "Update EGL wrappers and utilities to latest spec." into mnc-dev

* commit 'aae22498e1eeccd01689e9c789a5c51c79c51ca7':
  Update EGL wrappers and utilities to latest spec.
diff --git a/android/package/src/com/drawelements/deqp/testercore/DeqpInstrumentation.java b/android/package/src/com/drawelements/deqp/testercore/DeqpInstrumentation.java
index 466c6fd..f104310 100644
--- a/android/package/src/com/drawelements/deqp/testercore/DeqpInstrumentation.java
+++ b/android/package/src/com/drawelements/deqp/testercore/DeqpInstrumentation.java
@@ -35,6 +35,7 @@
 	private static final long	LAUNCH_TIMEOUT_MS		= 10000;
 	private static final long	NO_DATA_TIMEOUT_MS		= 1000;
 	private static final long	NO_ACTIVITY_SLEEP_MS	= 100;
+	private static final long	REMOTE_DEAD_SLEEP_MS	= 100;
 
 	private String				m_cmdLine;
 	private String				m_logFileName;
@@ -105,6 +106,20 @@
 
 			parser.init(this, m_logFileName, m_logData);
 
+			// parse until tester dies
+			{
+				while (true)
+				{
+					if (!parser.parse())
+					{
+						Thread.sleep(NO_ACTIVITY_SLEEP_MS);
+						if (!remoteApi.isRunning())
+							break;
+					}
+				}
+			}
+
+			// parse remaining messages
 			{
 				long lastDataMs = System.currentTimeMillis();
 
@@ -112,15 +127,16 @@
 				{
 					if (parser.parse())
 						lastDataMs = System.currentTimeMillis();
-					else if (!remoteApi.isRunning())
+					else
 					{
 						final long timeSinceLastDataMs = System.currentTimeMillis()-lastDataMs;
 
 						if (timeSinceLastDataMs > NO_DATA_TIMEOUT_MS)
 							break; // Assume no data is available for reading any more
+
+						// Remote is dead, wait a bit until trying to read again
+						Thread.sleep(REMOTE_DEAD_SLEEP_MS);
 					}
-					else
-						Thread.sleep(NO_ACTIVITY_SLEEP_MS);
 				}
 			}
 
diff --git a/android/package/src/com/drawelements/deqp/testercore/RemoteAPI.java b/android/package/src/com/drawelements/deqp/testercore/RemoteAPI.java
index 3c7fd7a..b1c515d 100644
--- a/android/package/src/com/drawelements/deqp/testercore/RemoteAPI.java
+++ b/android/package/src/com/drawelements/deqp/testercore/RemoteAPI.java
@@ -38,11 +38,13 @@
 	private Context						m_context;
 	private String						m_processName;
 	private String						m_logFileName;
+	private boolean						m_canBeRunning;
 
 	public RemoteAPI (Context context, String logFileName) {
 		m_context			= context;
 		m_processName		= m_context.getPackageName() + ":testercore";
 		m_logFileName		= logFileName;
+		m_canBeRunning		= false;
 	}
 
 	private ComponentName getDefaultTesterComponent () {
@@ -101,12 +103,15 @@
 			return false;
 		}
 
+		m_canBeRunning = true;
 		return true;
 	}
 
 	public boolean kill () {
 		ActivityManager.RunningAppProcessInfo processInfo = findProcess(m_processName);
 
+		// \note not mutating m_canBeRunning yet since process does not die immediately
+
 		if (processInfo != null) {
 			Log.d(LOG_TAG, "Killing " + m_processName);
 			Process.killProcess(processInfo.pid);
@@ -119,7 +124,15 @@
 	}
 
 	public boolean isRunning () {
-		return isProcessRunning(m_processName);
+		if (!m_canBeRunning) {
+			return false;
+		} else if (isProcessRunning(m_processName)) {
+			return true;
+		} else {
+			// Cache result. Safe, because only start() can spawn the process
+			m_canBeRunning = false;
+			return false;
+		}
 	}
 
 	public String getLogFileName () {
diff --git a/framework/common/tcuResultCollector.hpp b/framework/common/tcuResultCollector.hpp
index d4af499..7fb8ed2 100644
--- a/framework/common/tcuResultCollector.hpp
+++ b/framework/common/tcuResultCollector.hpp
@@ -43,24 +43,25 @@
 class ResultCollector
 {
 public:
-					ResultCollector			(void);
-					ResultCollector			(TestLog& log, const std::string& prefix = "");
+						ResultCollector			(void);
+						ResultCollector			(TestLog& log, const std::string& prefix = "");
 
-	qpTestResult	getResult				(void) const  { return m_result; }
+	qpTestResult		getResult				(void) const { return m_result;		}
+	const std::string	getMessage				(void) const { return m_message;	}
 
-	void			fail					(const std::string& msg);
-	bool			check					(bool condition, const std::string& msg);
+	void				fail					(const std::string& msg);
+	bool				check					(bool condition, const std::string& msg);
 
-	void			addResult				(qpTestResult result, const std::string& msg);
-	bool			checkResult				(bool condition, qpTestResult result, const std::string& msg);
+	void				addResult				(qpTestResult result, const std::string& msg);
+	bool				checkResult				(bool condition, qpTestResult result, const std::string& msg);
 
-	void			setTestContextResult	(TestContext& testCtx);
+	void				setTestContextResult	(TestContext& testCtx);
 
 private:
-	TestLog*		m_log;
-	std::string		m_prefix;
-	qpTestResult	m_result;
-	std::string		m_message;
+	TestLog* const		m_log;
+	const std::string	m_prefix;
+	qpTestResult		m_result;
+	std::string			m_message;
 } DE_WARN_UNUSED_TYPE;
 
 } // tcu
diff --git a/framework/common/tcuTexLookupVerifier.cpp b/framework/common/tcuTexLookupVerifier.cpp
index 4a70168..7f3e277 100644
--- a/framework/common/tcuTexLookupVerifier.cpp
+++ b/framework/common/tcuTexLookupVerifier.cpp
@@ -293,6 +293,8 @@
 {
 	DE_ASSERT(xBounds.x() <= xBounds.y());
 	DE_ASSERT(yBounds.x() <= yBounds.y());
+	DE_ASSERT(xBounds.x() + searchStep > xBounds.x()); // step is not effectively 0
+	DE_ASSERT(xBounds.y() + searchStep > xBounds.y());
 
 	if (!isInColorBounds(prec, quad, result))
 		return false;
@@ -322,6 +324,10 @@
 	DE_ASSERT(xBounds.x() <= xBounds.y());
 	DE_ASSERT(yBounds.x() <= yBounds.y());
 	DE_ASSERT(zBounds.x() <= zBounds.y());
+	DE_ASSERT(xBounds.x() + searchStep > xBounds.x()); // step is not effectively 0
+	DE_ASSERT(xBounds.y() + searchStep > xBounds.y());
+	DE_ASSERT(yBounds.x() + searchStep > yBounds.x());
+	DE_ASSERT(yBounds.y() + searchStep > yBounds.y());
 
 	if (!isInColorBounds(prec, quad0, quad1, result))
 		return false;
@@ -354,6 +360,10 @@
 {
 	DE_ASSERT(xBounds0.x() <= xBounds0.y());
 	DE_ASSERT(xBounds1.x() <= xBounds1.y());
+	DE_ASSERT(xBounds0.x() + searchStep > xBounds0.x()); // step is not effectively 0
+	DE_ASSERT(xBounds0.y() + searchStep > xBounds0.y());
+	DE_ASSERT(xBounds1.x() + searchStep > xBounds1.x());
+	DE_ASSERT(xBounds1.y() + searchStep > xBounds1.y());
 
 	if (!isInColorBounds(prec, line0, line1, result))
 		return false;
@@ -391,6 +401,14 @@
 	DE_ASSERT(yBounds0.x() <= yBounds0.y());
 	DE_ASSERT(xBounds1.x() <= xBounds1.y());
 	DE_ASSERT(yBounds1.x() <= yBounds1.y());
+	DE_ASSERT(xBounds0.x() + searchStep > xBounds0.x()); // step is not effectively 0
+	DE_ASSERT(xBounds0.y() + searchStep > xBounds0.y());
+	DE_ASSERT(yBounds0.x() + searchStep > yBounds0.x());
+	DE_ASSERT(yBounds0.y() + searchStep > yBounds0.y());
+	DE_ASSERT(xBounds1.x() + searchStep > xBounds1.x());
+	DE_ASSERT(xBounds1.y() + searchStep > xBounds1.y());
+	DE_ASSERT(yBounds1.x() + searchStep > yBounds1.x());
+	DE_ASSERT(yBounds1.y() + searchStep > yBounds1.y());
 
 	if (!isInColorBounds(prec, quad0, quad1, result))
 		return false;
@@ -442,6 +460,18 @@
 	DE_ASSERT(xBounds1.x() <= xBounds1.y());
 	DE_ASSERT(yBounds1.x() <= yBounds1.y());
 	DE_ASSERT(zBounds1.x() <= zBounds1.y());
+	DE_ASSERT(xBounds0.x() + searchStep > xBounds0.x()); // step is not effectively 0
+	DE_ASSERT(xBounds0.y() + searchStep > xBounds0.y());
+	DE_ASSERT(yBounds0.x() + searchStep > yBounds0.x());
+	DE_ASSERT(yBounds0.y() + searchStep > yBounds0.y());
+	DE_ASSERT(zBounds0.x() + searchStep > zBounds0.x());
+	DE_ASSERT(zBounds0.y() + searchStep > zBounds0.y());
+	DE_ASSERT(xBounds1.x() + searchStep > xBounds1.x());
+	DE_ASSERT(xBounds1.y() + searchStep > xBounds1.y());
+	DE_ASSERT(yBounds1.x() + searchStep > yBounds1.x());
+	DE_ASSERT(yBounds1.y() + searchStep > yBounds1.y());
+	DE_ASSERT(zBounds1.x() + searchStep > zBounds1.x());
+	DE_ASSERT(zBounds1.y() + searchStep > zBounds1.y());
 
 	if (!isInColorBounds(prec, quad00, quad01, quad10, quad11, result))
 		return false;
@@ -603,6 +633,15 @@
 
 	const int					w				= level.getWidth();
 
+	const TextureFormat			format			= level.getFormat();
+	const TextureChannelClass	texClass		= getTextureChannelClass(format.type);
+
+	DE_ASSERT(texClass == TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT	||
+			  texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT	||
+			  texClass == TEXTURECHANNELCLASS_FLOATING_POINT);
+	DE_UNREF(texClass);
+	DE_UNREF(format);
+
 	for (int i = minI; i <= maxI; i++)
 	{
 		// Wrapped coordinates
@@ -647,6 +686,10 @@
 												  texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT	? computeBilinearSearchStepForSnorm(prec) :
 												  0.0f; // Step is computed for floating-point quads based on texel values.
 
+	DE_ASSERT(texClass == TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT	||
+			  texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT	||
+			  texClass == TEXTURECHANNELCLASS_FLOATING_POINT);
+
 	// \todo [2013-07-03 pyry] This could be optimized by first computing ranges based on wrap mode.
 
 	for (int j = minJ; j <= maxJ; j++)
@@ -706,6 +749,10 @@
 												  texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT	? computeBilinearSearchStepForSnorm(prec) :
 												  0.0f; // Step is computed for floating-point quads based on texel values.
 
+	DE_ASSERT(texClass == TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT	||
+			  texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT	||
+			  texClass == TEXTURECHANNELCLASS_FLOATING_POINT);
+
 	// \todo [2013-07-03 pyry] This could be optimized by first computing ranges based on wrap mode.
 
 	for (int k = minK; k <= maxK; k++)
@@ -910,8 +957,8 @@
 	const int					w0				= level0.getWidth();
 	const int					w1				= level1.getWidth();
 
-	const Vec2					uBounds0		= computeNonNormalizedCoordBounds(sampler.normalizedCoords, w0,	coordX, prec.coordBits.x(), prec.uvwBits.x());
-	const Vec2					uBounds1		= computeNonNormalizedCoordBounds(sampler.normalizedCoords, w1,	coordX, prec.coordBits.x(), prec.uvwBits.x());
+	const Vec2					uBounds0		= computeNonNormalizedCoordBounds(sampler.normalizedCoords, w0, coordX, prec.coordBits.x(), prec.uvwBits.x());
+	const Vec2					uBounds1		= computeNonNormalizedCoordBounds(sampler.normalizedCoords, w1, coordX, prec.coordBits.x(), prec.uvwBits.x());
 
 	// Integer coordinates - without wrap mode
 	const int					minI0			= deFloorFloatToInt32(uBounds0.x()-0.5f);
@@ -924,6 +971,10 @@
 												  texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT	? computeBilinearSearchStepForSnorm(prec) :
 												  0.0f; // Step is computed for floating-point quads based on texel values.
 
+	DE_ASSERT(texClass == TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT	||
+			  texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT	||
+			  texClass == TEXTURECHANNELCLASS_FLOATING_POINT);
+
 	for (int i0 = minI0; i0 <= maxI0; i0++)
 	{
 		ColorLine	line0;
@@ -1007,6 +1058,10 @@
 												  texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT	? computeBilinearSearchStepForSnorm(prec) :
 												  0.0f; // Step is computed for floating-point quads based on texel values.
 
+	DE_ASSERT(texClass == TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT	||
+			  texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT	||
+			  texClass == TEXTURECHANNELCLASS_FLOATING_POINT);
+
 	for (int j0 = minJ0; j0 <= maxJ0; j0++)
 	{
 		for (int i0 = minI0; i0 <= maxI0; i0++)
@@ -1112,6 +1167,10 @@
 												  texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT	? computeBilinearSearchStepForSnorm(prec) :
 												  0.0f; // Step is computed for floating-point quads based on texel values.
 
+	DE_ASSERT(texClass == TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT	||
+			  texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT	||
+			  texClass == TEXTURECHANNELCLASS_FLOATING_POINT);
+
 	for (int k0 = minK0; k0 <= maxK0; k0++)
 	{
 		for (int j0 = minJ0; j0 <= maxJ0; j0++)
@@ -1403,6 +1462,10 @@
 												  texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT	? computeBilinearSearchStepForSnorm(prec) :
 												  0.0f; // Step is computed for floating-point quads based on texel values.
 
+	DE_ASSERT(texClass == TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT	||
+			  texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT	||
+			  texClass == TEXTURECHANNELCLASS_FLOATING_POINT);
+
 	for (int j = minJ; j <= maxJ; j++)
 	{
 		for (int i = minI; i <= maxI; i++)
@@ -1474,6 +1537,10 @@
 												  texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT	? computeBilinearSearchStepForSnorm(prec) :
 												  0.0f; // Step is computed for floating-point quads based on texel values.
 
+	DE_ASSERT(texClass == TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT	||
+			  texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT	||
+			  texClass == TEXTURECHANNELCLASS_FLOATING_POINT);
+
 	for (int j0 = minJ0; j0 <= maxJ0; j0++)
 	{
 		for (int i0 = minI0; i0 <= maxI0; i0++)
@@ -1570,7 +1637,7 @@
 }
 
 static bool isCubeMipmapLinearSampleResultValid (const ConstPixelBufferAccess	(&faces0)[CUBEFACE_LAST],
-												const ConstPixelBufferAccess	(&faces1)[CUBEFACE_LAST],
+												 const ConstPixelBufferAccess	(&faces1)[CUBEFACE_LAST],
 												 const Sampler&					sampler,
 												 const Sampler::FilterMode		levelFilter,
 												 const LookupPrecision&			prec,
@@ -2264,8 +2331,8 @@
 										const IVec2						(&offsets)[4],
 										const Vector<ScalarType, 4>&	result)
 {
-	const Vec2	uBounds		= computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getWidth(),	coord.x(), prec.coordBits.x(), prec.uvwBits.x());
-	const Vec2	vBounds		= computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getHeight(),	coord.y(), prec.coordBits.y(), prec.uvwBits.y());
+	const Vec2	uBounds		= computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getWidth(), coord.x(), prec.coordBits.x(), prec.uvwBits.x());
+	const Vec2	vBounds		= computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getHeight(), coord.y(), prec.coordBits.y(), prec.uvwBits.y());
 
 	// Integer coordinate bounds for (x0, y0) - without wrap mode
 	const int	minI		= deFloorFloatToInt32(uBounds.x()-0.5f);
diff --git a/framework/common/tcuTexture.cpp b/framework/common/tcuTexture.cpp
index 6fb69f0..d546cee 100644
--- a/framework/common/tcuTexture.cpp
+++ b/framework/common/tcuTexture.cpp
@@ -405,7 +405,6 @@
 	static const TextureSwizzle ARGB	= {{ TextureSwizzle::CHANNEL_1,		TextureSwizzle::CHANNEL_2,		TextureSwizzle::CHANNEL_3,		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_ZERO,	TextureSwizzle::CHANNEL_ZERO,	TextureSwizzle::CHANNEL_1	}};
 
 	switch (order)
 	{
@@ -426,7 +425,11 @@
 		case TextureFormat::sRGBA:		return RGBA;
 		case TextureFormat::D:			return D;
 		case TextureFormat::S:			return S;
-		case TextureFormat::DS:			return DS;
+
+		case TextureFormat::DS:
+			DE_ASSERT(false); // combined formats cannot be read from
+			return INV;
+
 		default:
 			DE_ASSERT(DE_FALSE);
 			return INV;
@@ -452,7 +455,6 @@
 	static const TextureSwizzle ARGB	= {{ TextureSwizzle::CHANNEL_3,		TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_1,		TextureSwizzle::CHANNEL_2		}};
 	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	}};
-	static const TextureSwizzle DS		= {{ TextureSwizzle::CHANNEL_0,		TextureSwizzle::CHANNEL_3,		TextureSwizzle::CHANNEL_LAST,	TextureSwizzle::CHANNEL_LAST	}};
 
 	switch (order)
 	{
@@ -473,7 +475,11 @@
 		case TextureFormat::sRGBA:		return RGBA;
 		case TextureFormat::D:			return D;
 		case TextureFormat::S:			return S;
-		case TextureFormat::DS:			return DS;
+
+		case TextureFormat::DS:
+			DE_ASSERT(false); // combined formats cannot be written to
+			return INV;
+
 		default:
 			DE_ASSERT(DE_FALSE);
 			return INV;
@@ -610,8 +616,10 @@
 	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 deUint8* pixelPtr = (const deUint8*)getDataPtr() + z*m_pitch.z() + y*m_pitch.y() + x*m_pitch.x();
+	const deUint8* pixelPtr = (const deUint8*)getPixelPtr(x, y, z);
 
 	// Optimized fomats.
 	if (m_format.type == TextureFormat::UNORM_INT8)
@@ -639,25 +647,6 @@
 		case TextureFormat::UNSIGNED_INT_1010102_REV:	return UVec4(UB32(0, 10), UB32(10, 10), UB32(20, 10), UB32(30, 2)).cast<float>();
 		case TextureFormat::UNSIGNED_INT_999_E5_REV:	return unpackRGB999E5(*((const deUint32*)pixelPtr));
 
-		case TextureFormat::UNSIGNED_INT_24_8:
-			switch (m_format.order)
-			{
-				// \note Stencil is always ignored.
-				case TextureFormat::D:	return Vec4(NB32(8, 24), 0.0f, 0.0f, 1.0f);
-				case TextureFormat::DS:	return Vec4(NB32(8, 24), 0.0f, 0.0f, 1.0f /* (float)UB32(0, 8) */);
-				default:
-					DE_ASSERT(false);
-			}
-
-		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
-		{
-			DE_ASSERT(m_format.order == TextureFormat::DS);
-			float	d	= *((const float*)pixelPtr);
-			// \note Stencil is ignored.
-//			deUint8	s	= *((const deUint32*)(pixelPtr+4)) & 0xff;
-			return Vec4(d, 0.0f, 0.0f, 1.0f);
-		}
-
 		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:
 			return Vec4(Float11(UB32(0, 11)).asFloat(), Float11(UB32(11, 11)).asFloat(), Float10(UB32(22, 10)).asFloat(), 1.0f);
 
@@ -707,8 +696,10 @@
 	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 deUint8* const	pixelPtr = (const deUint8*)getDataPtr() + z*m_pitch.z() + y*m_pitch.y() + x*m_pitch.x();
+	const deUint8* const	pixelPtr = (const deUint8*)getPixelPtr(x, y, z);
 	IVec4					result;
 
 	// Optimized fomats.
@@ -731,25 +722,6 @@
 		case TextureFormat::UNORM_INT_1010102_REV:		return UVec4(U32( 0, 10), U32(10, 10), U32(20, 10), U32(30, 2)).cast<int>();
 		case TextureFormat::UNSIGNED_INT_1010102_REV:	return UVec4(U32( 0, 10), U32(10, 10), U32(20, 10), U32(30, 2)).cast<int>();
 
-		case TextureFormat::UNSIGNED_INT_24_8:
-			switch (m_format.order)
-			{
-				case TextureFormat::D:	return UVec4(U32(8, 24), 0, 0, 1).cast<int>();
-				case TextureFormat::S:	return UVec4(0, 0, 0, U32(8, 24)).cast<int>();
-				case TextureFormat::DS:	return UVec4(U32(8, 24), 0, 0, U32(0, 8)).cast<int>();
-				default:
-					DE_ASSERT(false);
-			}
-
-		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
-		{
-			DE_ASSERT(m_format.order == TextureFormat::DS);
-			float	d	= *((const float*)pixelPtr);
-			deUint8	s	= *((const deUint32*)(pixelPtr+4)) & 0xffu;
-			// \note Returns bit-representation of depth floating-point value.
-			return UVec4(tcu::Float32(d).bits(), 0, 0, s).cast<int>();
-		}
-
 		default:
 			break; // To generic path.
 	}
@@ -812,7 +784,7 @@
 	DE_ASSERT(de::inBounds(y, 0, getHeight()));
 	DE_ASSERT(de::inBounds(z, 0, getDepth()));
 
-	const deUint8* const pixelPtr = (const deUint8*)getDataPtr() + z*m_pitch.z() + y*m_pitch.y() + x*m_pitch.x();
+	const deUint8* const pixelPtr = (const deUint8*)getPixelPtr(x, y, z);
 
 #define UB32(OFFS, COUNT) ((*((const deUint32*)pixelPtr) >> (OFFS)) & ((1<<(COUNT))-1))
 #define NB32(OFFS, COUNT) channelToNormFloat(UB32(OFFS, COUNT), (COUNT))
@@ -837,7 +809,7 @@
 			return *((const float*)pixelPtr);
 
 		default:
-			DE_ASSERT(m_format.order == TextureFormat::D || m_format.order == TextureFormat::DS);
+			DE_ASSERT(m_format.order == TextureFormat::D); // no other combined depth stencil types
 			return channelToFloat(pixelPtr, m_format.type);
 	}
 
@@ -851,7 +823,7 @@
 	DE_ASSERT(de::inBounds(y, 0, getHeight()));
 	DE_ASSERT(de::inBounds(z, 0, getDepth()));
 
-	const deUint8* const pixelPtr = (const deUint8*)getDataPtr() + z*m_pitch.z() + y*m_pitch.y() + x*m_pitch.x();
+	const deUint8* const pixelPtr = (const deUint8*)getPixelPtr(x, y, z);
 
 	switch (m_format.type)
 	{
@@ -872,14 +844,8 @@
 
 		default:
 		{
-			if (m_format.order == TextureFormat::S)
-				return channelToInt(pixelPtr, m_format.type);
-			else
-			{
-				DE_ASSERT(m_format.order == TextureFormat::DS);
-				const int stencilChannelIndex = 3;
-				return channelToInt(pixelPtr + getChannelSize(m_format.type)*stencilChannelIndex, m_format.type);
-			}
+			DE_ASSERT(m_format.order == TextureFormat::S); // no other combined depth stencil types
+			return channelToInt(pixelPtr, m_format.type);
 		}
 	}
 }
@@ -889,8 +855,10 @@
 	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
 
-	deUint8* const pixelPtr = (deUint8*)getDataPtr() + z*m_pitch.z() + y*m_pitch.y() + x*m_pitch.x();
+	deUint8* const pixelPtr = (deUint8*)getPixelPtr(x, y, z);
 
 	// Optimized fomats.
 	if (m_format.type == TextureFormat::UNORM_INT8)
@@ -934,31 +902,6 @@
 			*((deUint32*)pixelPtr) = packRGB999E5(color);
 			break;
 
-		case TextureFormat::UNSIGNED_INT_24_8:
-			switch (m_format.order)
-			{
-				case TextureFormat::D:		*((deUint32*)pixelPtr) = PN(color[0], 8, 24);									break;
-				case TextureFormat::S:		*((deUint32*)pixelPtr) = PN(color[3], 8, 24);									break;
-				case TextureFormat::DS:		*((deUint32*)pixelPtr) = PN(color[0], 8, 24) | PU((deUint32)color[3], 0, 8);	break;
-				default:
-					DE_ASSERT(false);
-			}
-			break;
-
-		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
-			DE_ASSERT(m_format.order == TextureFormat::DS);
-			*((float*)pixelPtr)			= color[0];
-			*((deUint32*)(pixelPtr+4))	= PU((deUint32)color[3], 0, 8);
-			break;
-
-		case TextureFormat::FLOAT:
-			if (m_format.order == TextureFormat::D)
-			{
-				*((float*)pixelPtr) = color[0];
-				break;
-			}
-			// else fall-through to default case!
-
 		default:
 		{
 			// Generic path.
@@ -984,8 +927,10 @@
 	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
 
-	deUint8* const pixelPtr = (deUint8*)getDataPtr() + z*m_pitch.z() + y*m_pitch.y() + x*m_pitch.x();
+	deUint8* const pixelPtr = (deUint8*)getPixelPtr(x, y, z);
 
 	// Optimized fomats.
 	if (m_format.type == TextureFormat::UNORM_INT8)
@@ -1006,23 +951,6 @@
 		case TextureFormat::UNORM_INT_1010102_REV:		*((deUint32*)pixelPtr) = PU(color[0],  0, 10) | PU(color[1], 10, 10) | PU(color[2], 20, 10) | PU(color[3], 30, 2);			break;
 		case TextureFormat::UNSIGNED_INT_1010102_REV:	*((deUint32*)pixelPtr) = PU(color[0],  0, 10) | PU(color[1], 10, 10) | PU(color[2], 20, 10) | PU(color[3], 30, 2);			break;
 
-		case TextureFormat::UNSIGNED_INT_24_8:
-			switch (m_format.order)
-			{
-				case TextureFormat::D:		*((deUint32*)pixelPtr) = PU(color[0], 8, 24);										break;
-				case TextureFormat::S:		*((deUint32*)pixelPtr) = PU(color[3], 8, 24);										break;
-				case TextureFormat::DS:		*((deUint32*)pixelPtr) = PU(color[0], 8, 24) | PU((deUint32)color[3], 0, 8);		break;
-				default:
-					DE_ASSERT(false);
-			}
-			break;
-
-		case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
-			DE_ASSERT(m_format.order == TextureFormat::DS);
-			*((deUint32*)pixelPtr)		= color[0];
-			*((deUint32*)(pixelPtr+4))	= PU((deUint32)color[3], 0, 8);
-			break;
-
 		default:
 		{
 			// Generic path.
@@ -1048,7 +976,7 @@
 	DE_ASSERT(de::inBounds(y, 0, getHeight()));
 	DE_ASSERT(de::inBounds(z, 0, getDepth()));
 
-	deUint8* const pixelPtr = (deUint8*)getDataPtr() + z*m_pitch.z() + y*m_pitch.y() + x*m_pitch.x();
+	deUint8* const pixelPtr = (deUint8*)getPixelPtr(x, y, z);
 
 #define PN(VAL, OFFS, BITS) (normFloatToChannel((VAL), (BITS)) << (OFFS))
 
@@ -1070,7 +998,7 @@
 			break;
 
 		default:
-			DE_ASSERT(m_format.order == TextureFormat::D || m_format.order == TextureFormat::DS);
+			DE_ASSERT(m_format.order == TextureFormat::D); // no other combined depth stencil types
 			floatToChannel(pixelPtr, depth, m_format.type);
 			break;
 	}
@@ -1084,7 +1012,7 @@
 	DE_ASSERT(de::inBounds(y, 0, getHeight()));
 	DE_ASSERT(de::inBounds(z, 0, getDepth()));
 
-	deUint8* const pixelPtr = (deUint8*)getDataPtr() + z*m_pitch.z() + y*m_pitch.y() + x*m_pitch.x();
+	deUint8* const pixelPtr = (deUint8*)getPixelPtr(x, y, z);
 
 #define PU(VAL, OFFS, BITS) (uintToChannel((deUint32)(VAL), (BITS)) << (OFFS))
 
@@ -1106,15 +1034,8 @@
 			break;
 
 		default:
-			if (m_format.order == TextureFormat::S)
-				intToChannel(pixelPtr, stencil, m_format.type);
-			else
-			{
-				DE_ASSERT(m_format.order == TextureFormat::DS);
-				const int stencilChannelIndex = 3;
-				intToChannel(pixelPtr + getChannelSize(m_format.type)*stencilChannelIndex, stencil, m_format.type);
-			}
-
+			DE_ASSERT(m_format.order == TextureFormat::S);  // no other combined depth stencil types
+			intToChannel(pixelPtr, stencil, m_format.type);
 			break;
 	}
 
@@ -1201,31 +1122,18 @@
 
 static bool isFixedPointDepthTextureFormat (const tcu::TextureFormat& format)
 {
+	DE_ASSERT(format.order == TextureFormat::D);
+
 	const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(format.type);
-
-	if (format.order == TextureFormat::D)
+	if (channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT)
+		return false;
+	else if (channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
+		return true;
+	else
 	{
-		// depth internal formats cannot be non-normalized integers
-		return channelClass != tcu::TEXTURECHANNELCLASS_FLOATING_POINT;
+		DE_ASSERT(false);
+		return false;
 	}
-	else if (format.order == TextureFormat::DS)
-	{
-		// combined formats have no single channel class, detect format manually
-		switch (format.type)
-		{
-			case tcu::TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:	return false;
-			case tcu::TextureFormat::UNSIGNED_INT_24_8:				return true;
-
-			default:
-			{
-				// unknown format
-				DE_ASSERT(false);
-				return true;
-			}
-		}
-	}
-
-	return false;
 }
 
 // Texel lookup with color conversion.
diff --git a/framework/delibs/decpp/deSpinBarrier.cpp b/framework/delibs/decpp/deSpinBarrier.cpp
index 150bbc2..efba57b 100644
--- a/framework/delibs/decpp/deSpinBarrier.cpp
+++ b/framework/delibs/decpp/deSpinBarrier.cpp
@@ -32,9 +32,11 @@
 {
 
 SpinBarrier::SpinBarrier (deInt32 numThreads)
-	: m_numThreads	(numThreads)
+	: m_numCores	(deGetNumAvailableLogicalCores())
+	, m_numThreads	(numThreads)
 	, m_numEntered	(0)
 	, m_numLeaving	(0)
+	, m_numRemoved	(0)
 {
 	DE_ASSERT(numThreads > 0);
 }
@@ -44,12 +46,41 @@
 	DE_ASSERT(m_numEntered == 0 && m_numLeaving == 0);
 }
 
-void SpinBarrier::sync (WaitMode mode)
+void SpinBarrier::reset (deUint32 numThreads)
 {
-	DE_ASSERT(mode == WAIT_MODE_YIELD || mode == WAIT_MODE_BUSY);
+	// If last threads were removed, m_numEntered > 0 && m_numRemoved > 0
+	DE_ASSERT(m_numLeaving == 0);
+	DE_ASSERT(numThreads > 0);
+	m_numThreads = numThreads;
+	m_numEntered = 0;
+	m_numLeaving = 0;
+	m_numRemoved = 0;
+}
+
+inline SpinBarrier::WaitMode getWaitMode (SpinBarrier::WaitMode requested, deUint32 numCores, deInt32 numThreads)
+{
+	if (requested == SpinBarrier::WAIT_MODE_AUTO)
+		return ((deUint32)numThreads <= numCores) ? SpinBarrier::WAIT_MODE_BUSY : SpinBarrier::WAIT_MODE_YIELD;
+	else
+		return requested;
+}
+
+inline void wait (SpinBarrier::WaitMode mode)
+{
+	DE_ASSERT(mode == SpinBarrier::WAIT_MODE_YIELD || mode == SpinBarrier::WAIT_MODE_BUSY);
+
+	if (mode == SpinBarrier::WAIT_MODE_YIELD)
+		deYield();
+}
+
+void SpinBarrier::sync (WaitMode requestedMode)
+{
+	const WaitMode	waitMode	= getWaitMode(requestedMode, m_numCores, m_numThreads);
 
 	deMemoryReadWriteFence();
 
+	// m_numEntered must not be touched until all threads have had
+	// a chance to observe it being 0.
 	if (m_numLeaving > 0)
 	{
 		for (;;)
@@ -57,16 +88,25 @@
 			if (m_numLeaving == 0)
 				break;
 
-			if (mode == WAIT_MODE_YIELD)
-				deYield();
+			wait(waitMode);
 		}
 	}
 
 	if (deAtomicIncrement32(&m_numEntered) == m_numThreads)
 	{
-		m_numLeaving = m_numThreads;
+		m_numLeaving  = m_numThreads;
 		deMemoryReadWriteFence();
-		m_numEntered = 0;
+
+		// m_numLeaving must be set > 0 when manipulating m_numRemoved
+		// to prevent other threads from touching m_numRemoved.
+		// Since this thread has not been removed, m_numLeaving will be >= 1
+		// until m_numLeaving is decremented at the end of this function.
+		m_numThreads -= m_numRemoved;
+		m_numLeaving -= m_numRemoved;
+		m_numRemoved  = 0;
+
+		deMemoryReadWriteFence();
+		m_numEntered  = 0;
 	}
 	else
 	{
@@ -75,8 +115,7 @@
 			if (m_numEntered == 0)
 				break;
 
-			if (mode == WAIT_MODE_YIELD)
-				deYield();
+			wait(waitMode);
 		}
 	}
 
@@ -84,6 +123,44 @@
 	deMemoryReadWriteFence();
 }
 
+void SpinBarrier::removeThread (WaitMode requestedMode)
+{
+	const WaitMode	waitMode	= getWaitMode(requestedMode, m_numCores, m_numThreads);
+
+	// Wait for other threads exiting previous barrier
+	if (m_numLeaving > 0)
+	{
+		for (;;)
+		{
+			if (m_numLeaving == 0)
+				break;
+
+			wait(waitMode);
+		}
+	}
+
+	// Ask for last thread entering barrier to adjust thread count
+	deAtomicIncrement32(&m_numRemoved);
+
+	if (deAtomicIncrement32(&m_numEntered) == m_numThreads)
+	{
+		m_numLeaving  = m_numThreads;
+		deMemoryReadWriteFence();
+
+		// See sync() - m_numLeaving > 0 when manipulating m_numRemoved.
+		// This thread must not be removed from m_numLeaving until
+		// m_numRemoved has been updated.
+		m_numThreads -= m_numRemoved;
+		m_numLeaving -= (m_numRemoved-1);
+		m_numRemoved  = 0;
+
+		deMemoryReadWriteFence();
+		m_numEntered  = 0;
+
+		deAtomicDecrement32(&m_numLeaving);
+	}
+}
+
 namespace
 {
 
@@ -99,12 +176,12 @@
 class TestThread : public de::Thread
 {
 public:
-	TestThread (SpinBarrier& barrier, volatile deInt32* sharedVar, int numThreads, int threadNdx, bool busyOk)
+	TestThread (SpinBarrier& barrier, volatile deInt32* sharedVar, int numThreads, int threadNdx)
 		: m_barrier		(barrier)
 		, m_sharedVar	(sharedVar)
 		, m_numThreads	(numThreads)
 		, m_threadNdx	(threadNdx)
-		, m_busyOk		(busyOk)
+		, m_busyOk		((deUint32)m_numThreads <= deGetNumAvailableLogicalCores())
 	{
 	}
 
@@ -138,18 +215,23 @@
 	}
 
 private:
-	SpinBarrier&		m_barrier;
-	volatile deInt32*	m_sharedVar;
-	int					m_numThreads;
-	int					m_threadNdx;
-	bool				m_busyOk;
+	SpinBarrier&			m_barrier;
+	volatile deInt32* const	m_sharedVar;
+	const int				m_numThreads;
+	const int				m_threadNdx;
+	const bool				m_busyOk;
 
 	SpinBarrier::WaitMode getWaitMode (de::Random& rnd)
 	{
-		if (m_busyOk && rnd.getBool())
-			return SpinBarrier::WAIT_MODE_BUSY;
-		else
-			return SpinBarrier::WAIT_MODE_YIELD;
+		static const SpinBarrier::WaitMode	s_allModes[]	=
+		{
+			SpinBarrier::WAIT_MODE_YIELD,
+			SpinBarrier::WAIT_MODE_AUTO,
+			SpinBarrier::WAIT_MODE_BUSY,
+		};
+		const int							numModes		= DE_LENGTH_OF_ARRAY(s_allModes) - (m_busyOk ? 0 : 1);
+
+		return rnd.choose<SpinBarrier::WaitMode>(DE_ARRAY_BEGIN(s_allModes), DE_ARRAY_BEGIN(s_allModes) + numModes);
 	}
 };
 
@@ -159,14 +241,9 @@
 	volatile deInt32			sharedVar	= 0;
 	std::vector<TestThread*>	threads		(numThreads, static_cast<TestThread*>(DE_NULL));
 
-	// Going over logical cores with busy-waiting will cause priority inversion and make tests take
-	// excessive amount of time. Use busy waiting only when number of threads is at most one per
-	// core.
-	const bool					busyOk		= (deUint32)numThreads <= deGetNumAvailableLogicalCores();
-
 	for (int ndx = 0; ndx < numThreads; ndx++)
 	{
-		threads[ndx] = new TestThread(barrier, &sharedVar, numThreads, ndx, busyOk);
+		threads[ndx] = new TestThread(barrier, &sharedVar, numThreads, ndx);
 		DE_TEST_ASSERT(threads[ndx]);
 		threads[ndx]->start();
 	}
@@ -180,17 +257,104 @@
 	DE_TEST_ASSERT(sharedVar == 0);
 }
 
-} // namespace
+void singleThreadRemoveTest (SpinBarrier::WaitMode mode)
+{
+	SpinBarrier barrier(3);
+
+	barrier.removeThread(mode);
+	barrier.removeThread(mode);
+	barrier.sync(mode);
+	barrier.removeThread(mode);
+
+	barrier.reset(1);
+	barrier.sync(mode);
+
+	barrier.reset(2);
+	barrier.removeThread(mode);
+	barrier.sync(mode);
+}
+
+class TestExitThread : public de::Thread
+{
+public:
+	TestExitThread (SpinBarrier& barrier, int numThreads, int threadNdx, SpinBarrier::WaitMode waitMode)
+		: m_barrier		(barrier)
+		, m_numThreads	(numThreads)
+		, m_threadNdx	(threadNdx)
+		, m_waitMode	(waitMode)
+	{
+	}
+
+	void run (void)
+	{
+		const int	numIters	= 10000;
+		de::Random	rnd			(deInt32Hash(m_numThreads) ^ deInt32Hash(m_threadNdx) ^ deInt32Hash((deInt32)m_waitMode));
+		const int	invExitProb	= 1000;
+
+		for (int iterNdx = 0; iterNdx < numIters; iterNdx++)
+		{
+			if (rnd.getInt(0, invExitProb) == 0)
+			{
+				m_barrier.removeThread(m_waitMode);
+				break;
+			}
+			else
+				m_barrier.sync(m_waitMode);
+		}
+	}
+
+private:
+	SpinBarrier&				m_barrier;
+	const int					m_numThreads;
+	const int					m_threadNdx;
+	const SpinBarrier::WaitMode	m_waitMode;
+};
+
+void multiThreadRemoveTest (int numThreads, SpinBarrier::WaitMode waitMode)
+{
+	SpinBarrier						barrier		(numThreads);
+	std::vector<TestExitThread*>	threads		(numThreads, static_cast<TestExitThread*>(DE_NULL));
+
+	for (int ndx = 0; ndx < numThreads; ndx++)
+	{
+		threads[ndx] = new TestExitThread(barrier, numThreads, ndx, waitMode);
+		DE_TEST_ASSERT(threads[ndx]);
+		threads[ndx]->start();
+	}
+
+	for (int ndx = 0; ndx < numThreads; ndx++)
+	{
+		threads[ndx]->join();
+		delete threads[ndx];
+	}
+}
+
+} // anonymous
 
 void SpinBarrier_selfTest (void)
 {
 	singleThreadTest(SpinBarrier::WAIT_MODE_YIELD);
 	singleThreadTest(SpinBarrier::WAIT_MODE_BUSY);
+	singleThreadTest(SpinBarrier::WAIT_MODE_AUTO);
 	multiThreadTest(1);
 	multiThreadTest(2);
 	multiThreadTest(4);
 	multiThreadTest(8);
 	multiThreadTest(16);
+
+	singleThreadRemoveTest(SpinBarrier::WAIT_MODE_YIELD);
+	singleThreadRemoveTest(SpinBarrier::WAIT_MODE_BUSY);
+	singleThreadRemoveTest(SpinBarrier::WAIT_MODE_AUTO);
+	multiThreadRemoveTest(1, SpinBarrier::WAIT_MODE_BUSY);
+	multiThreadRemoveTest(2, SpinBarrier::WAIT_MODE_AUTO);
+	multiThreadRemoveTest(4, SpinBarrier::WAIT_MODE_AUTO);
+	multiThreadRemoveTest(8, SpinBarrier::WAIT_MODE_AUTO);
+	multiThreadRemoveTest(16, SpinBarrier::WAIT_MODE_AUTO);
+	multiThreadRemoveTest(1, SpinBarrier::WAIT_MODE_YIELD);
+	multiThreadRemoveTest(2, SpinBarrier::WAIT_MODE_YIELD);
+	multiThreadRemoveTest(4, SpinBarrier::WAIT_MODE_YIELD);
+	multiThreadRemoveTest(8, SpinBarrier::WAIT_MODE_YIELD);
+	multiThreadRemoveTest(16, SpinBarrier::WAIT_MODE_YIELD);
 }
 
 } // de
diff --git a/framework/delibs/decpp/deSpinBarrier.hpp b/framework/delibs/decpp/deSpinBarrier.hpp
index 6679f8d..484d57a 100644
--- a/framework/delibs/decpp/deSpinBarrier.hpp
+++ b/framework/delibs/decpp/deSpinBarrier.hpp
@@ -35,14 +35,21 @@
  * SpinBarrier provides barrier implementation that uses spin loop for
  * waiting for other threads. Threads may choose to wait in tight loop
  * (WAIT_MODE_BUSY) or yield between iterations (WAIT_MODE_YIELD).
+ *
+ * It is not recommended to use WAIT_MODE_BUSY when there are more threads
+ * than number of cores participating in the barrier as it will lead to
+ * priority inversion and dramatic slowdown. For that reason WAIT_MODE_AUTO
+ * is provided, which selects between busy and yielding waiting based on
+ * number of threads.
  *//*--------------------------------------------------------------------*/
 class SpinBarrier
 {
 public:
 	enum WaitMode
 	{
-		WAIT_MODE_BUSY = 0,
-		WAIT_MODE_YIELD,
+		WAIT_MODE_BUSY = 0,	//! Wait in tight spin loop.
+		WAIT_MODE_YIELD,	//! Call deYield() between spin loop iterations.
+		WAIT_MODE_AUTO,		//! Use WAIT_MODE_BUSY loop if #threads <= #cores, otherwise WAIT_MODE_YIELD.
 
 		WAIT_MODE_LAST
 	};
@@ -50,15 +57,28 @@
 						SpinBarrier		(deInt32 numThreads);
 						~SpinBarrier	(void);
 
+	//! Reset barrier. Not thread-safe, e.g. no other thread can
+	//! be calling sync() or removeThread() at the same time.
+	void				reset			(deUint32 numThreads);
+
+	//! Wait until all threads (determined by active thread count)
+	//! have entered sync().
 	void				sync			(WaitMode mode);
 
+	//! Remove thread from barrier (decrements active thread count).
+	//! Can be called concurrently with sync() or removeThread().
+	void				removeThread	(WaitMode mode);
+
 private:
 						SpinBarrier		(const SpinBarrier&);
 	SpinBarrier			operator=		(const SpinBarrier&);
 
-	const deInt32		m_numThreads;
+	const deUint32		m_numCores;
+
+	volatile deInt32	m_numThreads;
 	volatile deInt32	m_numEntered;
 	volatile deInt32	m_numLeaving;
+	volatile deInt32	m_numRemoved;
 };
 
 void	SpinBarrier_selfTest	(void);
diff --git a/framework/platform/null/tcuNullRenderContext.cpp b/framework/platform/null/tcuNullRenderContext.cpp
index f82267a..b91d2ee 100644
--- a/framework/platform/null/tcuNullRenderContext.cpp
+++ b/framework/platform/null/tcuNullRenderContext.cpp
@@ -92,6 +92,7 @@
 	string					shadingLanguageVersion;
 	string					extensions;
 	vector<string>			extensionList;
+	vector<deUint32>		compressedTextureList;
 
 	GLenum					lastError;
 
@@ -146,7 +147,7 @@
 		addExtension("GL_OES_sample_shading");
 		addExtension("GL_OES_sample_variables");
 		addExtension("GL_OES_shader_multisample_interpolation");
-		addExtension("GL_OES_shader_image_atomics");
+		addExtension("GL_OES_shader_image_atomic");
 		addExtension("GL_OES_texture_storage_multisample_2d_array");
 		addExtension("GL_KHR_blend_equation_advanced");
 		addExtension("GL_KHR_blend_equation_advanced_coherent");
@@ -156,6 +157,16 @@
 		addExtension("GL_EXT_tessellation_shader");
 		addExtension("GL_EXT_tessellation_point_size");
 		addExtension("GL_EXT_gpu_shader5");
+		addExtension("GL_EXT_shader_implicit_conversions");
+		addExtension("GL_EXT_texture_buffer");
+		addExtension("GL_EXT_texture_cube_map_array");
+		addExtension("GL_EXT_draw_buffers_indexed");
+		addExtension("GL_EXT_texture_sRGB_decode");
+		addExtension("GL_EXT_texture_border_clamp");
+		addExtension("GL_KHR_debug");
+		addExtension("GL_EXT_primitive_bounding_box");
+		addExtension("GL_ANDROID_extension_pack_es31a");
+		addExtension("GL_EXT_copy_image");
 	}
 	else if (glu::isContextTypeGLCore(ctxType) && ctxType.getMajorVersion() == 3)
 	{
@@ -171,7 +182,61 @@
 		throw tcu::NotSupportedError("Unsupported GL version", "", __FILE__, __LINE__);
 
 	if (isContextTypeES(ctxType))
+	{
 		addExtension("GL_EXT_color_buffer_float");
+		addExtension("GL_EXT_color_buffer_half_float");
+	}
+
+	// support compressed formats
+	{
+		static deUint32 compressedFormats[] =
+		{
+			GL_ETC1_RGB8_OES,
+			GL_COMPRESSED_R11_EAC,
+			GL_COMPRESSED_SIGNED_R11_EAC,
+			GL_COMPRESSED_RG11_EAC,
+			GL_COMPRESSED_SIGNED_RG11_EAC,
+			GL_COMPRESSED_RGB8_ETC2,
+			GL_COMPRESSED_SRGB8_ETC2,
+			GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,
+			GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2,
+			GL_COMPRESSED_RGBA8_ETC2_EAC,
+			GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC,
+			GL_COMPRESSED_RGBA_ASTC_4x4_KHR,
+			GL_COMPRESSED_RGBA_ASTC_5x4_KHR,
+			GL_COMPRESSED_RGBA_ASTC_5x5_KHR,
+			GL_COMPRESSED_RGBA_ASTC_6x5_KHR,
+			GL_COMPRESSED_RGBA_ASTC_6x6_KHR,
+			GL_COMPRESSED_RGBA_ASTC_8x5_KHR,
+			GL_COMPRESSED_RGBA_ASTC_8x6_KHR,
+			GL_COMPRESSED_RGBA_ASTC_8x8_KHR,
+			GL_COMPRESSED_RGBA_ASTC_10x5_KHR,
+			GL_COMPRESSED_RGBA_ASTC_10x6_KHR,
+			GL_COMPRESSED_RGBA_ASTC_10x8_KHR,
+			GL_COMPRESSED_RGBA_ASTC_10x10_KHR,
+			GL_COMPRESSED_RGBA_ASTC_12x10_KHR,
+			GL_COMPRESSED_RGBA_ASTC_12x12_KHR,
+			GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR,
+			GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR,
+			GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR,
+			GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR,
+			GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR,
+			GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR,
+			GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR,
+			GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR,
+			GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR,
+			GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR,
+			GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR,
+			GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR,
+			GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR,
+			GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR,
+		};
+
+		addExtension("GL_KHR_texture_compression_astc_hdr");
+		addExtension("GL_KHR_texture_compression_astc_ldr");
+		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(compressedFormats); ++ndx)
+			compressedTextureList.push_back(compressedFormats[ndx]);
+	}
 }
 
 Context::~Context (void)
@@ -234,13 +299,52 @@
 		case GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS:
 		case GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS:
 		case GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS:
-			*params = 16;
+			*params = 32;
+			break;
+
+		case GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS:
+		case GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS:
+		case GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS:
+		case GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS:
+		case GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS:
+		case GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS:
+			*params = 8;
+			break;
+
+		case GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS:
+		case GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS:
+		case GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS:
+		case GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS:
+		case GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS:
+		case GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS:
+			*params = 8;
+			break;
+
+		case GL_MAX_SHADER_STORAGE_BLOCK_SIZE:
+			*params = 1u << 25;
+			break;
+
+		case GL_MAX_GEOMETRY_OUTPUT_VERTICES:
+			*params = 256;
+			break;
+
+		case GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS:
+			*params = 2048;
+			break;
+
+		case GL_MAX_GEOMETRY_SHADER_INVOCATIONS:
+			*params = 4;
+			break;
+
+		case GL_MAX_COLOR_TEXTURE_SAMPLES:
+			*params = 8;
 			break;
 
 		case GL_MAX_TEXTURE_SIZE:
 		case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
 		case GL_MAX_3D_TEXTURE_SIZE:
 		case GL_MAX_RENDERBUFFER_SIZE:
+		case GL_MAX_TEXTURE_BUFFER_SIZE:
 			*params = 2048;
 			break;
 
@@ -253,7 +357,11 @@
 			break;
 
 		case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
-			*params = 0;
+			*params = (int)ctx->compressedTextureList.size();
+			break;
+
+		case GL_COMPRESSED_TEXTURE_FORMATS:
+			deMemcpy(params, &ctx->compressedTextureList[0], (int)ctx->compressedTextureList.size());
 			break;
 
 		case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS:
@@ -313,6 +421,29 @@
 	}
 }
 
+GLW_APICALL void GLW_APIENTRY glGetInternalformativ (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params)
+{
+	static const int s_sampleCounts[] = { 16, 8, 4, 2, 1 };
+
+	DE_UNREF(internalformat);
+	DE_UNREF(target);
+
+	switch (pname)
+	{
+		case GL_NUM_SAMPLE_COUNTS:
+			if (bufSize >= 1)
+				*params = DE_LENGTH_OF_ARRAY(s_sampleCounts);
+			break;
+
+		case GL_SAMPLES:
+			deMemcpy(params, s_sampleCounts, de::min(bufSize, DE_LENGTH_OF_ARRAY(s_sampleCounts)));
+			break;
+
+		default:
+			break;
+	}
+}
+
 GLW_APICALL const glw::GLubyte* GLW_APIENTRY glGetString (GLenum name)
 {
 	Context* const ctx = getCurrentContext();
@@ -579,6 +710,12 @@
 			ctx->pixelPackBufferBufferBinding = 0;
 }
 
+GLW_APICALL GLint GLW_APIENTRY glGetAttribLocation (GLuint program, const GLchar* name)
+{
+	DE_UNREF(program);
+	return (GLint)(deStringHash(name) & 0x7FFFFFFF);
+}
+
 void initFunctions (glw::Functions* gl)
 {
 #	include "tcuNullRenderContextInitFuncs.inl"
diff --git a/framework/platform/null/tcuNullRenderContextFuncs.inl b/framework/platform/null/tcuNullRenderContextFuncs.inl
index 60c4a71..46e7d7e 100644
--- a/framework/platform/null/tcuNullRenderContextFuncs.inl
+++ b/framework/platform/null/tcuNullRenderContextFuncs.inl
@@ -1591,14 +1591,6 @@
 
 }
 
-GLW_APICALL GLint GLW_APIENTRY glGetAttribLocation (GLuint program, const GLchar *name)
-{
-	DE_UNREF(program);
-	DE_UNREF(name);
-
-	return (GLint)0;
-}
-
 GLW_APICALL void GLW_APIENTRY glGetBooleani_v (GLenum target, GLuint index, GLboolean *data)
 {
 	DE_UNREF(target);
@@ -1781,16 +1773,6 @@
 
 }
 
-GLW_APICALL void GLW_APIENTRY glGetInternalformativ (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params)
-{
-	DE_UNREF(target);
-	DE_UNREF(internalformat);
-	DE_UNREF(pname);
-	DE_UNREF(bufSize);
-	DE_UNREF(params);
-
-}
-
 GLW_APICALL void GLW_APIENTRY glGetMultisamplefv (GLenum pname, GLuint index, GLfloat *val)
 {
 	DE_UNREF(pname);
diff --git a/scripts/opengl/gen_null_render_context.py b/scripts/opengl/gen_null_render_context.py
index 36a2d5e..3693433 100644
--- a/scripts/opengl/gen_null_render_context.py
+++ b/scripts/opengl/gen_null_render_context.py
@@ -43,11 +43,13 @@
 	"glGenSamplers",
 	"glGenTransformFeedbacks",
 	"glGenProgramPipelines",
+	"glGetInternalformativ",
 	"glMapBufferRange",
 	"glCheckFramebufferStatus",
 	"glReadPixels",
 	"glBindBuffer",
-	"glDeleteBuffers"
+	"glDeleteBuffers",
+	"glGetAttribLocation",
 ])
 
 NULL_PLATFORM_DIR = os.path.normpath(os.path.join(SCRIPTS_DIR, "..", "..", "framework", "platform", "null"))