Merge "Improve texture border color handling."
diff --git a/framework/common/tcuTextureUtil.cpp b/framework/common/tcuTextureUtil.cpp
index 7edd3b8..7df2c31 100644
--- a/framework/common/tcuTextureUtil.cpp
+++ b/framework/common/tcuTextureUtil.cpp
@@ -632,15 +632,31 @@
 
 void fillWithComponentGradients (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal)
 {
-	if (access.getHeight() == 1 && access.getDepth() == 1)
-		fillWithComponentGradients1D(access, minVal, maxVal);
-	else if (access.getDepth() == 1)
-		fillWithComponentGradients2D(access, minVal, maxVal);
+	if (isCombinedDepthStencilType(access.getFormat().type))
+	{
+		const bool hasDepth		= access.getFormat().order == tcu::TextureFormat::DS || access.getFormat().order == tcu::TextureFormat::D;
+		const bool hasStencil	= access.getFormat().order == tcu::TextureFormat::DS || access.getFormat().order == tcu::TextureFormat::S;
+
+		DE_ASSERT(hasDepth || hasStencil);
+
+		// For combined formats, treat D and S as separate channels
+		if (hasDepth)
+			fillWithComponentGradients(getEffectiveDepthStencilAccess(access, tcu::Sampler::MODE_DEPTH), minVal, maxVal);
+		if (hasStencil)
+			fillWithComponentGradients(getEffectiveDepthStencilAccess(access, tcu::Sampler::MODE_STENCIL), minVal.swizzle(3,2,1,0), maxVal.swizzle(3,2,1,0));
+	}
 	else
-		fillWithComponentGradients3D(access, minVal, maxVal);
+	{
+		if (access.getHeight() == 1 && access.getDepth() == 1)
+			fillWithComponentGradients1D(access, minVal, maxVal);
+		else if (access.getDepth() == 1)
+			fillWithComponentGradients2D(access, minVal, maxVal);
+		else
+			fillWithComponentGradients3D(access, minVal, maxVal);
+	}
 }
 
-void fillWithGrid1D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
+static void fillWithGrid1D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
 {
 	for (int x = 0; x < access.getWidth(); x++)
 	{
@@ -653,7 +669,7 @@
 	}
 }
 
-void fillWithGrid2D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
+static void fillWithGrid2D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
 {
 	for (int y = 0; y < access.getHeight(); y++)
 	{
@@ -670,7 +686,7 @@
 	}
 }
 
-void fillWithGrid3D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
+static void fillWithGrid3D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
 {
 	for (int z = 0; z < access.getDepth(); z++)
 	{
@@ -693,12 +709,28 @@
 
 void fillWithGrid (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
 {
-	if (access.getHeight() == 1 && access.getDepth() == 1)
-		fillWithGrid1D(access, cellSize, colorA, colorB);
-	else if (access.getDepth() == 1)
-		fillWithGrid2D(access, cellSize, colorA, colorB);
+	if (isCombinedDepthStencilType(access.getFormat().type))
+	{
+		const bool hasDepth		= access.getFormat().order == tcu::TextureFormat::DS || access.getFormat().order == tcu::TextureFormat::D;
+		const bool hasStencil	= access.getFormat().order == tcu::TextureFormat::DS || access.getFormat().order == tcu::TextureFormat::S;
+
+		DE_ASSERT(hasDepth || hasStencil);
+
+		// For combined formats, treat D and S as separate channels
+		if (hasDepth)
+			fillWithComponentGradients(getEffectiveDepthStencilAccess(access, tcu::Sampler::MODE_DEPTH), colorA, colorB);
+		if (hasStencil)
+			fillWithComponentGradients(getEffectiveDepthStencilAccess(access, tcu::Sampler::MODE_STENCIL), colorA.swizzle(3,2,1,0), colorB.swizzle(3,2,1,0));
+	}
 	else
-		fillWithGrid3D(access, cellSize, colorA, colorB);
+	{
+		if (access.getHeight() == 1 && access.getDepth() == 1)
+			fillWithGrid1D(access, cellSize, colorA, colorB);
+		else if (access.getDepth() == 1)
+			fillWithGrid2D(access, cellSize, colorA, colorB);
+		else
+			fillWithGrid3D(access, cellSize, colorA, colorB);
+	}
 }
 
 void fillWithRepeatableGradient (const PixelBufferAccess& access, const Vec4& colorA, const Vec4& colorB)
@@ -780,6 +812,11 @@
 	const bool	srcTightlyPacked	= (srcPixelSize == srcPixelPitch);
 	const bool	dstTightlyPacked	= (dstPixelSize == dstPixelPitch);
 
+	const bool	srcHasDepth			= (src.getFormat().order == tcu::TextureFormat::DS || src.getFormat().order == tcu::TextureFormat::D);
+	const bool	srcHasStencil		= (src.getFormat().order == tcu::TextureFormat::DS || src.getFormat().order == tcu::TextureFormat::S);
+	const bool	dstHasDepth			= (dst.getFormat().order == tcu::TextureFormat::DS || dst.getFormat().order == tcu::TextureFormat::D);
+	const bool	dstHasStencil		= (dst.getFormat().order == tcu::TextureFormat::DS || dst.getFormat().order == tcu::TextureFormat::S);
+
 	if (src.getFormat() == dst.getFormat() && srcTightlyPacked && dstTightlyPacked)
 	{
 		// Fast-path for matching formats.
@@ -795,6 +832,36 @@
 		for (int x = 0; x < width; x++)
 			deMemcpy(dst.getPixelPtr(x, y, z), src.getPixelPtr(x, y, z), srcPixelSize);
 	}
+	else if (srcHasDepth || srcHasStencil || dstHasDepth || dstHasStencil)
+	{
+		DE_ASSERT((srcHasDepth && dstHasDepth) || (srcHasStencil && dstHasStencil)); // must have at least one common channel
+
+		if (dstHasDepth && srcHasDepth)
+		{
+			for (int z = 0; z < depth; z++)
+			for (int y = 0; y < height; y++)
+			for (int x = 0; x < width; x++)
+				dst.setPixDepth(src.getPixDepth(x, y, z), x, y, z);
+		}
+		else if (dstHasDepth && !srcHasDepth)
+		{
+			// consistency with color copies
+			tcu::clearDepth(dst, 0.0f);
+		}
+
+		if (dstHasStencil && srcHasStencil)
+		{
+			for (int z = 0; z < depth; z++)
+			for (int y = 0; y < height; y++)
+			for (int x = 0; x < width; x++)
+				dst.setPixStencil(src.getPixStencil(x, y, z), x, y, z);
+		}
+		else if (dstHasStencil && !srcHasStencil)
+		{
+			// consistency with color copies
+			tcu::clearStencil(dst, 0u);
+		}
+	}
 	else
 	{
 		TextureChannelClass		srcClass	= getTextureChannelClass(src.getFormat().type);
diff --git a/framework/delibs/dethread/unix/deThreadUnix.c b/framework/delibs/dethread/unix/deThreadUnix.c
index 260ba45..04035ef 100644
--- a/framework/delibs/dethread/unix/deThreadUnix.c
+++ b/framework/delibs/dethread/unix/deThreadUnix.c
@@ -26,6 +26,7 @@
 #if (DE_OS == DE_OS_UNIX || DE_OS == DE_OS_OSX || DE_OS == DE_OS_ANDROID || DE_OS == DE_OS_SYMBIAN || DE_OS == DE_OS_IOS)
 
 #include "deMemory.h"
+#include "deInt32.h"
 
 #if !defined(_XOPEN_SOURCE) || (_XOPEN_SOURCE < 500)
 #	error "You are using too old posix API!"
@@ -34,6 +35,7 @@
 #include <unistd.h>
 #include <pthread.h>
 #include <sched.h>
+#include <sys/syscall.h>
 
 #if (DE_OS == DE_OS_OSX) || (DE_OS == DE_OS_IOS)
 #	if !defined(_SC_NPROCESSORS_CONF)
@@ -156,32 +158,67 @@
 	sched_yield();
 }
 
-#if (DE_OS == DE_OS_UNIX) && defined(_GNU_SOURCE)
+#if (DE_OS == DE_OS_UNIX) || (DE_OS == DE_OS_ANDROID)
 
 deUint32 deGetNumAvailableLogicalCores (void)
 {
-	cpu_set_t	cpuSet;
+	unsigned long		mask		= 0;
+	const unsigned int	maskSize	= sizeof(mask);
+	long				ret;
 
-	CPU_ZERO(&cpuSet);
+	deMemset(&mask, 0, sizeof(mask));
 
-	if (sched_getaffinity(0, sizeof(cpuSet), &cpuSet) != 0)
+	ret = syscall(__NR_sched_getaffinity, 0, maskSize, &mask);
+
+	if (ret > 0)
+	{
+		return dePop64(mask);
+	}
+	else
+	{
+#if defined(_SC_NPROCESSORS_ONLN)
+		const int count = sysconf(_SC_NPROCESSORS_ONLN);
+
+		if (count <= 0)
+			return 1;
+		else
+			return (deUint32)count;
+#else
 		return 1;
-
-	return (deUint32)(CPU_COUNT(&cpuSet));
+#endif
+	}
 }
 
 #else
 
 deUint32 deGetNumAvailableLogicalCores (void)
 {
-	return (deUint32)sysconf(_SC_NPROCESSORS_ONLN);
+#if defined(_SC_NPROCESSORS_ONLN)
+	const int count = sysconf(_SC_NPROCESSORS_ONLN);
+
+	if (count <= 0)
+		return 1;
+	else
+		return (deUint32)count;
+#else
+	return 1;
+#endif
 }
 
 #endif
 
 deUint32 deGetNumTotalLogicalCores (void)
 {
-	return (deUint32)sysconf(_SC_NPROCESSORS_CONF);
+#if defined(_SC_NPROCESSORS_CONF)
+	const int count = sysconf(_SC_NPROCESSORS_CONF);
+
+	if (count <= 0)
+		return 1;
+	else
+		return (deUint32)count;
+#else
+	return 1;
+#endif
 }
 
 deUint32 deGetNumTotalPhysicalCores (void)
diff --git a/framework/opengl/simplereference/sglrReferenceContext.cpp b/framework/opengl/simplereference/sglrReferenceContext.cpp
index ce0d09b..9abd42c 100644
--- a/framework/opengl/simplereference/sglrReferenceContext.cpp
+++ b/framework/opengl/simplereference/sglrReferenceContext.cpp
@@ -392,7 +392,7 @@
 	m_emptyTex1D.getSampler().magFilter	= tcu::Sampler::NEAREST;
 	m_emptyTex1D.allocLevel(0, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), 1);
 	m_emptyTex1D.getLevel(0).setPixel(Vec4(0.0f, 0.0f, 0.0f, 1.0f), 0, 0);
-	m_emptyTex1D.updateView();
+	m_emptyTex1D.updateView(tcu::Sampler::MODE_LAST);
 
 	m_emptyTex2D.getSampler().wrapS		= tcu::Sampler::CLAMP_TO_EDGE;
 	m_emptyTex2D.getSampler().wrapT		= tcu::Sampler::CLAMP_TO_EDGE;
@@ -400,7 +400,7 @@
 	m_emptyTex2D.getSampler().magFilter	= tcu::Sampler::NEAREST;
 	m_emptyTex2D.allocLevel(0, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), 1, 1);
 	m_emptyTex2D.getLevel(0).setPixel(Vec4(0.0f, 0.0f, 0.0f, 1.0f), 0, 0);
-	m_emptyTex2D.updateView();
+	m_emptyTex2D.updateView(tcu::Sampler::MODE_LAST);
 
 	m_emptyTexCube.getSampler().wrapS		= tcu::Sampler::CLAMP_TO_EDGE;
 	m_emptyTexCube.getSampler().wrapT		= tcu::Sampler::CLAMP_TO_EDGE;
@@ -411,7 +411,7 @@
 		m_emptyTexCube.allocFace(0, (tcu::CubeFace)face, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), 1, 1);
 		m_emptyTexCube.getFace(0, (tcu::CubeFace)face).setPixel(Vec4(0.0f, 0.0f, 0.0f, 1.0f), 0, 0);
 	}
-	m_emptyTexCube.updateView();
+	m_emptyTexCube.updateView(tcu::Sampler::MODE_LAST);
 
 	m_emptyTex2DArray.getSampler().wrapS		= tcu::Sampler::CLAMP_TO_EDGE;
 	m_emptyTex2DArray.getSampler().wrapT		= tcu::Sampler::CLAMP_TO_EDGE;
@@ -419,7 +419,7 @@
 	m_emptyTex2DArray.getSampler().magFilter	= tcu::Sampler::NEAREST;
 	m_emptyTex2DArray.allocLevel(0, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), 1, 1, 1);
 	m_emptyTex2DArray.getLevel(0).setPixel(Vec4(0.0f, 0.0f, 0.0f, 1.0f), 0, 0);
-	m_emptyTex2DArray.updateView();
+	m_emptyTex2DArray.updateView(tcu::Sampler::MODE_LAST);
 
 	m_emptyTex3D.getSampler().wrapS		= tcu::Sampler::CLAMP_TO_EDGE;
 	m_emptyTex3D.getSampler().wrapT		= tcu::Sampler::CLAMP_TO_EDGE;
@@ -428,7 +428,7 @@
 	m_emptyTex3D.getSampler().magFilter	= tcu::Sampler::NEAREST;
 	m_emptyTex3D.allocLevel(0, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), 1, 1, 1);
 	m_emptyTex3D.getLevel(0).setPixel(Vec4(0.0f, 0.0f, 0.0f, 1.0f), 0, 0);
-	m_emptyTex3D.updateView();
+	m_emptyTex3D.updateView(tcu::Sampler::MODE_LAST);
 
 	m_emptyTexCubeArray.getSampler().wrapS		= tcu::Sampler::CLAMP_TO_EDGE;
 	m_emptyTexCubeArray.getSampler().wrapT		= tcu::Sampler::CLAMP_TO_EDGE;
@@ -437,7 +437,7 @@
 	m_emptyTexCubeArray.allocLevel(0, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), 1, 1, 6);
 	for (int faceNdx = 0; faceNdx < 6; faceNdx++)
 		m_emptyTexCubeArray.getLevel(0).setPixel(Vec4(0.0f, 0.0f, 0.0f, 1.0f), 0, 0, faceNdx);
-	m_emptyTexCubeArray.updateView();
+	m_emptyTexCubeArray.updateView(tcu::Sampler::MODE_LAST);
 
 	if (glu::isContextTypeGLCore(getType()))
 		m_sRGBUpdateEnabled = false;
@@ -972,12 +972,25 @@
 	DE_ASSERT(src.getWidth() == width && src.getHeight() == height && src.getDepth() == depth);
 
 	// clamping copy
-	for (int z = 0; z < depth; z++)
-	for (int y = 0; y < height; y++)
-	for (int x = 0; x < width; x++)
+
+	if (src.getFormat().order == tcu::TextureFormat::DS && dst.getFormat().order == tcu::TextureFormat::DS)
 	{
-		const Vec4 data = src.getPixel(x, y, z);
-		dst.setPixel(Vec4(de::clamp(data.x(), 0.0f, 1.0f), data.y(), data.z(), data.w()), x, y, z);
+		// copy only depth and stencil
+		for (int z = 0; z < depth; z++)
+		for (int y = 0; y < height; y++)
+		for (int x = 0; x < width; x++)
+		{
+			dst.setPixDepth(de::clamp(src.getPixDepth(x, y, z), 0.0f, 1.0f), x, y, z);
+			dst.setPixStencil(src.getPixStencil(x, y, z), x, y, z);
+		}
+	}
+	else
+	{
+		// copy only depth
+		for (int z = 0; z < depth; z++)
+		for (int y = 0; y < height; y++)
+		for (int x = 0; x < width; x++)
+			dst.setPixDepth(de::clamp(src.getPixDepth(x, y, z), 0.0f, 1.0f), x, y, z);
 	}
 }
 
@@ -991,6 +1004,20 @@
 	texImage3D(target, level, internalFormat, width, height, 1, border, format, type, data);
 }
 
+static void clearToTextureInitialValue (PixelBufferAccess access)
+{
+	const bool hasDepth		= access.getFormat().order == tcu::TextureFormat::D || access.getFormat().order == tcu::TextureFormat::DS;
+	const bool hasStencil	= access.getFormat().order == tcu::TextureFormat::S || access.getFormat().order == tcu::TextureFormat::DS;
+	const bool hasColor		= !hasDepth && !hasStencil;
+
+	if (hasDepth)
+		tcu::clearDepth(access, 0.0f);
+	if (hasStencil)
+		tcu::clearStencil(access, 0u);
+	if (hasColor)
+		tcu::clear(access, Vec4(0.0f, 0.0f, 0.0f, 1.0f));
+}
+
 void ReferenceContext::texImage3D (deUint32 target, int level, deUint32 internalFormat, int width, int height, int depth, int border, deUint32 format, deUint32 type, const void* data)
 {
 	TextureUnit&		unit					= m_textureUnits[m_activeTexture];
@@ -1043,9 +1070,8 @@
 		}
 		else
 		{
-			// No data supplied, clear to black.
-			PixelBufferAccess dst = texture->getLevel(level);
-			tcu::clear(dst, Vec4(0.0f, 0.0f, 0.0f, 1.0f));
+			// No data supplied, clear to initial
+			clearToTextureInitialValue(texture->getLevel(level));
 		}
 	}
 	else if (target == GL_TEXTURE_2D)
@@ -1080,9 +1106,8 @@
 		}
 		else
 		{
-			// No data supplied, clear to black.
-			PixelBufferAccess dst = texture->getLevel(level);
-			tcu::clear(dst, Vec4(0.0f, 0.0f, 0.0f, 1.0f));
+			// No data supplied, clear to initial
+			clearToTextureInitialValue(texture->getLevel(level));
 		}
 	}
 	else if (target == GL_TEXTURE_CUBE_MAP_NEGATIVE_X ||
@@ -1123,9 +1148,8 @@
 		}
 		else
 		{
-			// No data supplied, clear to black.
-			PixelBufferAccess dst = texture->getFace(level, face);
-			tcu::clear(dst, Vec4(0.0f, 0.0f, 0.0f, 1.0f));
+			// No data supplied, clear to initial
+			clearToTextureInitialValue(texture->getFace(level, face));
 		}
 	}
 	else if (target == GL_TEXTURE_2D_ARRAY)
@@ -1163,9 +1187,8 @@
 		}
 		else
 		{
-			// No data supplied, clear to black.
-			PixelBufferAccess dst = texture->getLevel(level);
-			tcu::clear(dst, Vec4(0.0f, 0.0f, 0.0f, 1.0f));
+			// No data supplied, clear to initial
+			clearToTextureInitialValue(texture->getLevel(level));
 		}
 	}
 	else if (target == GL_TEXTURE_3D)
@@ -1203,9 +1226,8 @@
 		}
 		else
 		{
-			// No data supplied, clear to black.
-			PixelBufferAccess dst = texture->getLevel(level);
-			tcu::clear(dst, Vec4(0.0f, 0.0f, 0.0f, 1.0f));
+			// No data supplied, clear to initial
+			clearToTextureInitialValue(texture->getLevel(level));
 		}
 	}
 	else if (target == GL_TEXTURE_CUBE_MAP_ARRAY)
@@ -1244,9 +1266,8 @@
 		}
 		else
 		{
-			// No data supplied, clear to black.
-			PixelBufferAccess dst = texture->getLevel(level);
-			tcu::clear(dst, Vec4(0.0f, 0.0f, 0.0f, 1.0f));
+			// No data supplied, clear to initial
+			clearToTextureInitialValue(texture->getLevel(level));
 		}
 	}
 	else
@@ -3214,8 +3235,8 @@
 
 	if ((mask & GL_DEPTH_BUFFER_BIT) && m_depthMask)
 	{
-		rr::MultisampleConstPixelBufferAccess	src		= rr::getSubregion(getReadDepthbuffer(), srcRect.x(), srcRect.y(), srcRect.z(), srcRect.w());
-		rr::MultisamplePixelBufferAccess		dst		= rr::getSubregion(getDrawDepthbuffer(), dstRect.x(), dstRect.y(), dstRect.z(), dstRect.w());
+		rr::MultisampleConstPixelBufferAccess	src		= getDepthMultisampleAccess(rr::getSubregion(getReadDepthbuffer(), srcRect.x(), srcRect.y(), srcRect.z(), srcRect.w()));
+		rr::MultisamplePixelBufferAccess		dst		= getDepthMultisampleAccess(rr::getSubregion(getDrawDepthbuffer(), dstRect.x(), dstRect.y(), dstRect.z(), dstRect.w()));
 
 		for (int yo = 0; yo < dstRect.w(); yo++)
 		{
@@ -3228,7 +3249,7 @@
 				float	sX	= transform(0, 0)*dX + transform(0, 1)*dY + transform(0, 2);
 				float	sY	= transform(1, 0)*dX + transform(1, 1)*dY + transform(1, 2);
 
-				writeDepthOnly(dst, sampleNdx, xo, yo, src.raw().getPixel(sampleNdx, deFloorFloatToInt32(sX), deFloorFloatToInt32(sY)).x());
+				writeDepthOnly(dst, sampleNdx, xo, yo, src.raw().getPixDepth(sampleNdx, deFloorFloatToInt32(sX), deFloorFloatToInt32(sY)));
 			}
 		}
 	}
@@ -4260,8 +4281,8 @@
 		return;
 
 	rr::MultisamplePixelBufferAccess	colorBuf0	= getDrawColorbuffer();
-	rr::MultisamplePixelBufferAccess	depthBuf	= getDrawDepthbuffer();
-	rr::MultisamplePixelBufferAccess	stencilBuf	= getDrawStencilbuffer();
+	rr::MultisamplePixelBufferAccess	depthBuf	= getDepthMultisampleAccess(getDrawDepthbuffer());
+	rr::MultisamplePixelBufferAccess	stencilBuf	= getStencilMultisampleAccess(getDrawStencilbuffer());
 	const bool							hasStencil	= !isEmpty(stencilBuf);
 	const int							stencilBits	= (hasStencil) ? (getNumStencilBits(stencilBuf.raw().getFormat())) : (0);
 
@@ -4384,7 +4405,8 @@
 	// Set shader samplers
 	for (size_t uniformNdx = 0; uniformNdx < m_currentProgram->m_program->m_uniforms.size(); ++uniformNdx)
 	{
-		const int texNdx = m_currentProgram->m_program->m_uniforms[uniformNdx].value.i;
+		const tcu::Sampler::DepthStencilMode	depthStencilMode	= tcu::Sampler::MODE_DEPTH; // \todo[jarkko] support sampler state
+		const int								texNdx				= m_currentProgram->m_program->m_uniforms[uniformNdx].value.i;
 
 		switch (m_currentProgram->m_program->m_uniforms[uniformNdx].type)
 		{
@@ -4399,7 +4421,7 @@
 
 				if (tex && tex->isComplete())
 				{
-					tex->updateView();
+					tex->updateView(depthStencilMode);
 					m_currentProgram->m_program->m_uniforms[uniformNdx].sampler.tex1D = tex;
 				}
 				else
@@ -4418,7 +4440,7 @@
 
 				if (tex && tex->isComplete())
 				{
-					tex->updateView();
+					tex->updateView(depthStencilMode);
 					m_currentProgram->m_program->m_uniforms[uniformNdx].sampler.tex2D = tex;
 				}
 				else
@@ -4437,7 +4459,7 @@
 
 				if (tex && tex->isComplete())
 				{
-					tex->updateView();
+					tex->updateView(depthStencilMode);
 					m_currentProgram->m_program->m_uniforms[uniformNdx].sampler.texCube = tex;
 				}
 				else
@@ -4456,7 +4478,7 @@
 
 				if (tex && tex->isComplete())
 				{
-					tex->updateView();
+					tex->updateView(depthStencilMode);
 					m_currentProgram->m_program->m_uniforms[uniformNdx].sampler.tex2DArray = tex;
 				}
 				else
@@ -4475,7 +4497,7 @@
 
 				if (tex && tex->isComplete())
 				{
-					tex->updateView();
+					tex->updateView(depthStencilMode);
 					m_currentProgram->m_program->m_uniforms[uniformNdx].sampler.tex3D = tex;
 				}
 				else
@@ -4494,7 +4516,7 @@
 
 				if (tex && tex->isComplete())
 				{
-					tex->updateView();
+					tex->updateView(depthStencilMode);
 					m_currentProgram->m_program->m_uniforms[uniformNdx].sampler.texCubeArray = tex;
 				}
 				else
@@ -4677,6 +4699,12 @@
 	m_access[level] = PixelBufferAccess();
 }
 
+void TextureLevelArray::updateSamplerMode (tcu::Sampler::DepthStencilMode mode)
+{
+	for (int levelNdx = 0; hasLevel(levelNdx); ++levelNdx)
+		m_effectiveAccess[levelNdx] = tcu::getEffectiveDepthStencilAccess(m_access[levelNdx], mode);
+}
+
 Texture::Texture (deUint32 name, Type type)
 	: NamedObject	(name)
 	, m_type		(type)
@@ -4778,7 +4806,7 @@
 	}
 }
 
-void Texture1D::updateView (void)
+void Texture1D::updateView (tcu::Sampler::DepthStencilMode mode)
 {
 	const int baseLevel	= getBaseLevel();
 
@@ -4788,7 +4816,8 @@
 		const bool	isMipmap	= isMipmapFilter(getSampler().minFilter);
 		const int	numLevels	= isMipmap ? de::min(getMaxLevel()-baseLevel+1, getNumMipLevels1D(width)) : 1;
 
-		m_view = tcu::Texture2DView(numLevels, m_levels.getLevels() + baseLevel);
+		m_levels.updateSamplerMode(mode);
+		m_view = tcu::Texture2DView(numLevels, m_levels.getEffectiveLevels() + baseLevel);
 	}
 	else
 		m_view = tcu::Texture2DView(0, DE_NULL);
@@ -4849,7 +4878,7 @@
 		return false;
 }
 
-void Texture2D::updateView (void)
+void Texture2D::updateView (tcu::Sampler::DepthStencilMode mode)
 {
 	const int baseLevel	= getBaseLevel();
 
@@ -4861,7 +4890,8 @@
 		const bool	isMipmap	= isMipmapFilter(getSampler().minFilter);
 		const int	numLevels	= isMipmap ? de::min(getMaxLevel()-baseLevel+1, getNumMipLevels2D(width, height)) : 1;
 
-		m_view = tcu::Texture2DView(numLevels, m_levels.getLevels() + baseLevel);
+		m_levels.updateSamplerMode(mode);
+		m_view = tcu::Texture2DView(numLevels, m_levels.getEffectiveLevels() + baseLevel);
 	}
 	else
 		m_view = tcu::Texture2DView(0, DE_NULL);
@@ -4960,7 +4990,7 @@
 		return false;
 }
 
-void TextureCube::updateView (void)
+void TextureCube::updateView (tcu::Sampler::DepthStencilMode mode)
 {
 	const int							baseLevel	= getBaseLevel();
 	const tcu::ConstPixelBufferAccess*	faces[tcu::CUBEFACE_LAST];
@@ -4974,7 +5004,10 @@
 		const int	numLevels	= isMipmap ? de::min(getMaxLevel()-baseLevel+1, getNumMipLevels1D(size)) : 1;
 
 		for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
-			faces[face] = m_levels[face].getLevels() + baseLevel;
+		{
+			m_levels[face].updateSamplerMode(mode);
+			faces[face] = m_levels[face].getEffectiveLevels() + baseLevel;
+		}
 
 		m_view = tcu::TextureCubeView(numLevels, faces);
 	}
@@ -5079,7 +5112,7 @@
 		return false;
 }
 
-void Texture2DArray::updateView (void)
+void Texture2DArray::updateView (tcu::Sampler::DepthStencilMode mode)
 {
 	const int baseLevel	= getBaseLevel();
 
@@ -5090,7 +5123,8 @@
 		const bool	isMipmap	= isMipmapFilter(getSampler().minFilter);
 		const int	numLevels	= isMipmap ? de::min(getMaxLevel()-baseLevel+1, getNumMipLevels2D(width, height)) : 1;
 
-		m_view = tcu::Texture2DArrayView(numLevels, m_levels.getLevels() + baseLevel);
+		m_levels.updateSamplerMode(mode);
+		m_view = tcu::Texture2DArrayView(numLevels, m_levels.getEffectiveLevels() + baseLevel);
 	}
 	else
 		m_view = tcu::Texture2DArrayView(0, DE_NULL);
@@ -5184,7 +5218,7 @@
 		return false;
 }
 
-void TextureCubeArray::updateView (void)
+void TextureCubeArray::updateView (tcu::Sampler::DepthStencilMode mode)
 {
 	const int baseLevel	= getBaseLevel();
 
@@ -5195,7 +5229,8 @@
 		const bool	isMipmap	= isMipmapFilter(getSampler().minFilter);
 		const int	numLevels	= isMipmap ? de::min(getMaxLevel()-baseLevel+1, getNumMipLevels2D(width, height)) : 1;
 
-		m_view = tcu::TextureCubeArrayView(numLevels, m_levels.getLevels() + baseLevel);
+		m_levels.updateSamplerMode(mode);
+		m_view = tcu::TextureCubeArrayView(numLevels, m_levels.getEffectiveLevels() + baseLevel);
 	}
 	else
 		m_view = tcu::TextureCubeArrayView(0, DE_NULL);
@@ -5336,7 +5371,7 @@
 	}
 }
 
-void Texture3D::updateView (void)
+void Texture3D::updateView (tcu::Sampler::DepthStencilMode mode)
 {
 	const int baseLevel	= getBaseLevel();
 
@@ -5348,7 +5383,8 @@
 		const bool	isMipmap	= isMipmapFilter(getSampler().minFilter);
 		const int	numLevels	= isMipmap ? de::min(getMaxLevel()-baseLevel+1, getNumMipLevels3D(width, height, depth)) : 1;
 
-		m_view = tcu::Texture3DView(numLevels, m_levels.getLevels() + baseLevel);
+		m_levels.updateSamplerMode(mode);
+		m_view = tcu::Texture3DView(numLevels, m_levels.getEffectiveLevels() + baseLevel);
 	}
 	else
 		m_view = tcu::Texture3DView(0, DE_NULL);
diff --git a/framework/opengl/simplereference/sglrReferenceContext.hpp b/framework/opengl/simplereference/sglrReferenceContext.hpp
index a0ce306..dfdb294 100644
--- a/framework/opengl/simplereference/sglrReferenceContext.hpp
+++ b/framework/opengl/simplereference/sglrReferenceContext.hpp
@@ -123,15 +123,19 @@
 	const tcu::ConstPixelBufferAccess&	getLevel			(int level) const	{ DE_ASSERT(hasLevel(level)); return m_access[level];									}
 
 	const tcu::ConstPixelBufferAccess*	getLevels			(void) const		{ return &m_access[0];																	}
+	const tcu::ConstPixelBufferAccess*	getEffectiveLevels	(void) const		{ return &m_effectiveAccess[0];															}
 
 	void								allocLevel			(int level, const tcu::TextureFormat& format, int width, int height, int depth);
 	void								clearLevel			(int level);
 
 	void								clear				(void);
 
+	void								updateSamplerMode	(tcu::Sampler::DepthStencilMode);
+
 private:
 	de::ArrayBuffer<deUint8>			m_data[MAX_TEXTURE_SIZE_LOG2];
 	tcu::PixelBufferAccess				m_access[MAX_TEXTURE_SIZE_LOG2];
+	tcu::ConstPixelBufferAccess			m_effectiveAccess[MAX_TEXTURE_SIZE_LOG2];	//!< the currently effective sampling mode. For Depth-stencil texture always either Depth or stencil.
 };
 
 class Texture1D : public Texture
@@ -150,7 +154,7 @@
 
 	bool								isComplete		(void) const;
 
-	void								updateView		(void); // \note View must be refreshed after texture parameter/size changes, before calling sample*()
+	void								updateView		(tcu::Sampler::DepthStencilMode mode); // \note View must be refreshed after texture parameter/size changes, before calling sample*()
 
 	tcu::Vec4							sample			(float s, float lod) const;
 	void								sample4			(tcu::Vec4 output[4], const float packetTexcoords[4], float lodBias = 0.0f) const;
@@ -176,7 +180,7 @@
 
 	bool								isComplete		(void) const;
 
-	void								updateView		(void); // \note View must be refreshed after texture parameter/size changes, before calling sample*()
+	void								updateView		(tcu::Sampler::DepthStencilMode mode); // \note View must be refreshed after texture parameter/size changes, before calling sample*()
 
 	tcu::Vec4							sample			(float s, float t, float lod) const;
 	void								sample4			(tcu::Vec4 output[4], const tcu::Vec2 packetTexcoords[4], float lodBias = 0.0f) const;
@@ -201,7 +205,7 @@
 	void								allocFace		(int level, tcu::CubeFace face, const tcu::TextureFormat& format, int width, int height);
 
 	bool								isComplete		(void) const;
-	void								updateView		(void); // \note View must be refreshed after texture parameter/size changes, before calling sample*()
+	void								updateView		(tcu::Sampler::DepthStencilMode mode); // \note View must be refreshed after texture parameter/size changes, before calling sample*()
 
 	tcu::Vec4							sample			(float s, float t, float p, float lod) const;
 	void								sample4			(tcu::Vec4 output[4], const tcu::Vec3 packetTexcoords[4], float lodBias = 0.0f) const;
@@ -227,7 +231,7 @@
 
 	bool								isComplete		(void) const;
 
-	void								updateView		(void); // \note View must be refreshed after texture parameter/size changes, before calling sample*()
+	void								updateView		(tcu::Sampler::DepthStencilMode mode); // \note View must be refreshed after texture parameter/size changes, before calling sample*()
 
 	tcu::Vec4							sample			(float s, float t, float r, float lod) const;
 	void								sample4			(tcu::Vec4 output[4], const tcu::Vec3 packetTexcoords[4], float lodBias = 0.0f) const;
@@ -253,7 +257,7 @@
 
 	bool								isComplete		(void) const;
 
-	void								updateView		(void); // \note View must be refreshed after texture parameter/size changes, before calling sample*()
+	void								updateView		(tcu::Sampler::DepthStencilMode mode); // \note View must be refreshed after texture parameter/size changes, before calling sample*()
 
 	tcu::Vec4							sample			(float s, float t, float r, float lod) const;
 	void								sample4			(tcu::Vec4 output[4], const tcu::Vec3 packetTexcoords[4], float lodBias = 0.0f) const;
@@ -279,7 +283,7 @@
 
 	bool								isComplete			(void) const;
 
-	void								updateView			(void); // \note View must be refreshed after texture parameter/size changes, before calling sample*()
+	void								updateView			(tcu::Sampler::DepthStencilMode mode); // \note View must be refreshed after texture parameter/size changes, before calling sample*()
 
 	tcu::Vec4							sample				(float s, float t, float r, float q, float lod) const;
 	void								sample4				(tcu::Vec4 output[4], const tcu::Vec4 packetTexcoords[4], float lodBias = 0.0f) const;
diff --git a/modules/gles3/functional/es3fTextureSpecificationTests.cpp b/modules/gles3/functional/es3fTextureSpecificationTests.cpp
index b42d4d5..92765ab 100644
--- a/modules/gles3/functional/es3fTextureSpecificationTests.cpp
+++ b/modules/gles3/functional/es3fTextureSpecificationTests.cpp
@@ -125,9 +125,21 @@
 	}
 }
 
+static IVec4 getEffectiveTextureFormatBitDepth (tcu::TextureFormat textureFormat)
+{
+	if (textureFormat.order == tcu::TextureFormat::DS)
+	{
+		// When sampling depth-stencil texture, we actually sample just
+		// the depth component.
+		return tcu::getTextureFormatBitDepth(tcu::getEffectiveDepthStencilTextureFormat(textureFormat, tcu::Sampler::MODE_DEPTH));
+	}
+	else
+		return tcu::getTextureFormatBitDepth(textureFormat);
+}
+
 static tcu::UVec4 computeCompareThreshold (const tcu::PixelFormat& pixelFormat, tcu::TextureFormat textureFormat)
 {
-	const IVec4		texFormatBits		= tcu::getTextureFormatBitDepth(textureFormat);
+	const IVec4		texFormatBits		= getEffectiveTextureFormatBitDepth(textureFormat);
 	const IVec4		pixelFormatBits		= getPixelFormatCompareDepth(pixelFormat, textureFormat);
 	const IVec4		accurateFmtBits		= min(pixelFormatBits, texFormatBits);
 	const IVec4		compareBits			= select(accurateFmtBits, IVec4(8), greaterThan(accurateFmtBits, IVec4(0))) - 1;
diff --git a/modules/gles31/functional/es31fStencilTexturingTests.cpp b/modules/gles31/functional/es31fStencilTexturingTests.cpp
index 1133992..80cc264 100644
--- a/modules/gles31/functional/es31fStencilTexturingTests.cpp
+++ b/modules/gles31/functional/es31fStencilTexturingTests.cpp
@@ -170,7 +170,9 @@
 	DE_ASSERT(dst.getFormat().order == TextureFormat::S || dst.getFormat().order == TextureFormat::DS);
 
 	// clear depth and stencil
-	tcu::clear(dst, IVec4(0));
+	if (dst.getFormat().order == TextureFormat::DS)
+		tcu::clearDepth(dst, 0.0f);
+	tcu::clearStencil(dst, 0u);
 
 	genTestRects(rects, dst.getWidth(), dst.getHeight());