text: /*-------------------------------------------------------------------------
   * drawElements Quality Program OpenGL ES 3.0 Module
   * -------------------------------------------------
   *
   * Copyright 2014 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   *//*!
   * \file
   * \brief Depth & stencil tests.
   *//*--------------------------------------------------------------------*/
  
  #include "es3fDepthStencilTests.hpp"
  #include "glsFragmentOpUtil.hpp"
  #include "gluPixelTransfer.hpp"
  #include "gluStrUtil.hpp"
  #include "tcuSurface.hpp"
  #include "tcuRenderTarget.hpp"
  #include "tcuTestLog.hpp"
  #include "tcuImageCompare.hpp"
  #include "tcuCommandLine.hpp"
  #include "tcuTextureUtil.hpp"
  #include "deRandom.hpp"
  #include "deStringUtil.hpp"
  #include "deMemory.h"
  #include "deString.h"
  #include "rrFragmentOperations.hpp"
  #include "sglrReferenceUtils.hpp"
  
  #include <algorithm>
  #include <sstream>
  
  #include "glw.h"
  
  namespace deqp
  {
  namespace gles3
  {
  namespace Functional
  {
  
  using std::vector;
  using tcu::IVec2;
  using tcu::Vec2;
  using tcu::Vec4;
  using tcu::TestLog;
  using std::ostringstream;
  
  enum
  {
  	VIEWPORT_WIDTH			= 4*3*4,
  	VIEWPORT_HEIGHT			= 4*12,
  
  	NUM_RANDOM_CASES		= 25,
  	NUM_RANDOM_SUB_CASES	= 10
  };
  
  namespace DepthStencilCaseUtil
  {
  
  struct StencilParams
  {
  	deUint32	function;
  	int			reference;
  	deUint32	compareMask;
  
  	deUint32	stencilFailOp;
  	deUint32	depthFailOp;
  	deUint32	depthPassOp;
  
  	deUint32	writeMask;
  
  	StencilParams (void)
  		: function		(0)
  		, reference		(0)
  		, compareMask	(0)
  		, stencilFailOp	(0)
  		, depthFailOp	(0)
  		, depthPassOp	(0)
  		, writeMask		(0)
  	{
  	}
  };
  
  struct DepthStencilParams
  {
  	rr::FaceType	visibleFace;			//!< Quad visible face.
  
  	bool			stencilTestEnabled;
  	StencilParams	stencil[rr::FACETYPE_LAST];
  
  	bool			depthTestEnabled;
  	deUint32		depthFunc;
  	float			depth;
  	bool			depthWriteMask;
  
  	DepthStencilParams (void)
  		: visibleFace			(rr::FACETYPE_LAST)
  		, stencilTestEnabled	(false)
  		, depthTestEnabled		(false)
  		, depthFunc				(0)
  		, depth					(0.0f)
  		, depthWriteMask		(false)
  	{
  	}
  };
  
  tcu::TestLog& operator<< (tcu::TestLog& log, const StencilParams& params)
  {
  	log << TestLog::Message << "  func = " << glu::getCompareFuncStr(params.function) << "\n"
  							<< "  ref = " << params.reference << "\n"
  							<< "  compare mask = " << tcu::toHex(params.compareMask) << "\n"
  							<< "  stencil fail = " << glu::getStencilOpStr(params.stencilFailOp) << "\n"
  							<< "  depth fail = " << glu::getStencilOpStr(params.depthFailOp) << "\n"
  							<< "  depth pass = " << glu::getStencilOpStr(params.depthPassOp) << "\n"
  							<< "  write mask = " << tcu::toHex(params.writeMask) << "\n"
  		<< TestLog::EndMessage;
  	return log;
  }
  
  tcu::TestLog& operator<< (tcu::TestLog& log, const DepthStencilParams& params)
  {
  	log << TestLog::Message << "Stencil test: " << (params.stencilTestEnabled ? "enabled" : "disabled") << TestLog::EndMessage;
  	if (params.stencilTestEnabled)
  	{
  		log << TestLog::Message << "Front-face stencil state: " << TestLog::EndMessage;
  		log << params.stencil[rr::FACETYPE_FRONT];
  
  		log << TestLog::Message << "Back-face stencil state: " << TestLog::EndMessage;
  		log << params.stencil[rr::FACETYPE_BACK];
  	}
  
  	log << TestLog::Message << "Depth test: " << (params.depthTestEnabled ? "enabled" : "disabled") << TestLog::EndMessage;
  	if (params.depthTestEnabled)
  	{
  		log << TestLog::Message << "  func = " << glu::getCompareFuncStr(params.depthFunc) << "\n"
  								   "  depth value = " << params.depth << "\n"
  								   "  write mask = " << (params.depthWriteMask ? "true" : "false") << "\n"
  			<< TestLog::EndMessage;
  	}
  
  	log << TestLog::Message << "Triangles are " << (params.visibleFace == rr::FACETYPE_FRONT ? "front" : "back") << "-facing" << TestLog::EndMessage;
  
  	return log;
  }
  
  struct ClearCommand
  {
  	rr::WindowRectangle	rect;
  	deUint32			buffers;
  	tcu::Vec4			color;
  	int					stencil;
  	// \note No depth here - don't use clears for setting depth values; use quad rendering instead. Cleared depths are in [0, 1] to begin with,
  	//		 whereas rendered depths are given in [-1, 1] and then mapped to [0, 1]; this discrepancy could cause precision issues in depth tests.
  
  	ClearCommand (void)
  		: rect		(0, 0, 0, 0)
  		, buffers	(0)
  		, stencil	(0)
  	{
  	}
  
  	ClearCommand (const rr::WindowRectangle&	rect_,
  				  deUint32						buffers_,
  				  const tcu::Vec4&				color_,
  				  int							stencil_)
  		: rect		(rect_)
  		, buffers	(buffers_)
  		, color		(color_)
  		, stencil	(stencil_)
  	{
  	}
  };
  
  struct RenderCommand
  {
  	DepthStencilParams		params;
  	rr::WindowRectangle		rect;
  	tcu::Vec4				color;
  	tcu::BVec4				colorMask;
  
  	RenderCommand (void)
  		: rect(0, 0, 0, 0)
  	{
  	}
  };
  
  struct RefRenderCommand
  {
  	gls::FragmentOpUtil::IntegerQuad	quad;
  	rr::FragmentOperationState			state;
  };
  
  struct TestRenderTarget
  {
  	int		width;
  	int		height;
  	int		depthBits;
  	int		stencilBits;
  
  	TestRenderTarget (int width_,
  					  int height_,
  					  int depthBits_,
  					  int stencilBits_)
  		: width			(width_)
  		, height		(height_)
  		, depthBits		(depthBits_)
  		, stencilBits	(stencilBits_)
  	{
  	}
  
  	TestRenderTarget (void)
  		: width			(0)
  		, height		(0)
  		, depthBits		(0)
  		, stencilBits	(0)
  	{
  	}
  };
  
  void getStencilTestValues (int stencilBits, int numValues, int* values)
  {
  	int numLowest		= numValues/2;
  	int	numHighest		= numValues-numLowest;
  	int	maxVal			= (1<<stencilBits)-1;
  
  	for (int ndx = 0; ndx < numLowest; ndx++)
  		values[ndx] = ndx;
  
  	for (int ndx = 0; ndx < numHighest; ndx++)
  		values[numValues-ndx-1] = maxVal-ndx;
  }
  
  void generateBaseClearAndDepthCommands (const TestRenderTarget& target, vector<ClearCommand>& clearCommands, vector<RenderCommand>& renderCommands)
  {
  	DE_ASSERT(clearCommands.empty());
  	DE_ASSERT(renderCommands.empty());
  
  	const int		numL0CellsX		= 4;
  	const int		numL0CellsY		= 4;
  	const int		numL1CellsX		= 3;
  	const int		numL1CellsY		= 1;
  	int				cellL0Width		= target.width/numL0CellsX;
  	int				cellL0Height	= target.height/numL0CellsY;
  	int				cellL1Width		= cellL0Width/numL1CellsX;
  	int				cellL1Height	= cellL0Height/numL1CellsY;
  
  	int				stencilValues[numL0CellsX*numL0CellsY];
  	float			depthValues[numL1CellsX*numL1CellsY];
  
  	if (cellL0Width <= 0 || cellL1Width <= 0 || cellL0Height <= 0 || cellL1Height <= 0)
  		throw tcu::NotSupportedError("Too small render target");
  
  	// Fullscreen clear to black.
  	clearCommands.push_back(ClearCommand(rr::WindowRectangle(0, 0, target.width, target.height), GL_COLOR_BUFFER_BIT, Vec4(0.0f, 0.0f, 0.0f, 1.0f), 0));
  
  	// Compute stencil values: numL0CellsX*numL0CellsY combinations of lowest and highest bits.
  	getStencilTestValues(target.stencilBits, numL0CellsX*numL0CellsY, &stencilValues[0]);
  
  	// Compute depth values
  	{
  		int		numValues		= DE_LENGTH_OF_ARRAY(depthValues);
  		float	depthStep		= 2.0f/(float)(numValues-1);
  
  		for (int ndx = 0; ndx < numValues; ndx++)
  			depthValues[ndx] = -1.0f + depthStep*(float)ndx;
  	}
  
  	for (int y0 = 0; y0 < numL0CellsY; y0++)
  	{
  		for (int x0 = 0; x0 < numL0CellsX; x0++)
  		{
  			int stencilValue = stencilValues[y0*numL0CellsX + x0];
  
  			for (int y1 = 0; y1 < numL1CellsY; y1++)
  			{
  				for (int x1 = 0; x1 < numL1CellsX; x1++)
  				{
  					int					x			= x0*cellL0Width + x1*cellL1Width;
  					int					y			= y0*cellL0Height + y1*cellL1Height;
  					rr::WindowRectangle	cellL1Rect	(x, y, cellL1Width, cellL1Height);
  
  					clearCommands.push_back(ClearCommand(cellL1Rect, GL_STENCIL_BUFFER_BIT, Vec4(0), stencilValue));
  
  					RenderCommand renderCmd;
  					renderCmd.params.visibleFace		= rr::FACETYPE_FRONT;
  					renderCmd.params.depth				= depthValues[y1*numL1CellsX + x1];;
  					renderCmd.params.depthTestEnabled	= true;
  					renderCmd.params.depthFunc			= GL_ALWAYS;
  					renderCmd.params.depthWriteMask		= true;
  					renderCmd.colorMask					= tcu::BVec4(false);
  					renderCmd.rect						= cellL1Rect;
  
  					renderCommands.push_back(renderCmd);
  				}
  			}
  		}
  	}
  }
  
  void generateDepthVisualizeCommands (const TestRenderTarget& target, vector<RenderCommand>& commands)
  {
  	const float			epsilon			= -0.05f;
  	static const float	depthSteps[]	= {-1.0f, -0.5f, 0.0f, 0.5f, 1.0f};
  	int					numSteps		= DE_LENGTH_OF_ARRAY(depthSteps);
  	const float			colorStep		= 1.0f / (float)(numSteps-1);
  
  	for (int ndx = 0; ndx < numSteps; ndx++)
  	{
  		RenderCommand cmd;
  
  		cmd.params.visibleFace		= rr::FACETYPE_FRONT;
  		cmd.rect					= rr::WindowRectangle(0, 0, target.width, target.height);
  		cmd.color					= Vec4(0.0f, 0.0f, colorStep*(float)ndx, 0.0f);
  		cmd.colorMask				= tcu::BVec4(false, false, true, false);
  		cmd.params.depth			= depthSteps[ndx]+epsilon;
  		cmd.params.depthTestEnabled	= true;
  		cmd.params.depthFunc		= GL_LESS;
  		cmd.params.depthWriteMask	= false;
  
  		commands.push_back(cmd);
  	}
  }
  
  void generateStencilVisualizeCommands (const TestRenderTarget& target, vector<RenderCommand>& commands)
  {
  	const int	numValues		= 4*4;
  	float		colorStep		= 1.0f / numValues; // 0 is reserved for non-matching.
  	int			stencilValues[numValues];
  
  	getStencilTestValues(target.stencilBits, numValues, &stencilValues[0]);
  
  	for (int ndx = 0; ndx < numValues; ndx++)
  	{
  		RenderCommand cmd;
  
  		cmd.params.visibleFace							= rr::FACETYPE_FRONT;
  		cmd.rect										= rr::WindowRectangle(0, 0, target.width, target.height);
  		cmd.color										= Vec4(0.0f, colorStep*float(ndx+1), 0.0f, 0.0f);
  		cmd.colorMask									= tcu::BVec4(false, true, false, false);
  		cmd.params.stencilTestEnabled					= true;
  
  		cmd.params.stencil[rr::FACETYPE_FRONT].function			= GL_EQUAL;
  		cmd.params.stencil[rr::FACETYPE_FRONT].reference		= stencilValues[ndx];
  		cmd.params.stencil[rr::FACETYPE_FRONT].compareMask		= ~0u;
  		cmd.params.stencil[rr::FACETYPE_FRONT].stencilFailOp	= GL_KEEP;
  		cmd.params.stencil[rr::FACETYPE_FRONT].depthFailOp		= GL_KEEP;
  		cmd.params.stencil[rr::FACETYPE_FRONT].depthPassOp		= GL_KEEP;
  		cmd.params.stencil[rr::FACETYPE_FRONT].writeMask		= 0u;
  
  		cmd.params.stencil[rr::FACETYPE_BACK] = cmd.params.stencil[rr::FACETYPE_FRONT];
  
  		commands.push_back(cmd);
  	}
  }
  
  void translateStencilState (const StencilParams& src, rr::StencilState& dst)
  {
  	dst.func		= sglr::rr_util::mapGLTestFunc(src.function);
  	dst.ref			= src.reference;
  	dst.compMask	= src.compareMask;
  	dst.sFail		= sglr::rr_util::mapGLStencilOp(src.stencilFailOp);
  	dst.dpFail		= sglr::rr_util::mapGLStencilOp(src.depthFailOp);
  	dst.dpPass		= sglr::rr_util::mapGLStencilOp(src.depthPassOp);
  	dst.writeMask	= src.writeMask;
  }
  
  void translateCommand (const RenderCommand& src, RefRenderCommand& dst, const TestRenderTarget& renderTarget)
  {
  	const float		far				= 1.0f;
  	const float		near			= 0.0f;
  	bool			hasDepth		= renderTarget.depthBits > 0;
  	bool			hasStencil		= renderTarget.stencilBits > 0;
  	bool			isFrontFacing	= src.params.visibleFace == rr::FACETYPE_FRONT;
  
  	dst.quad.posA = IVec2(isFrontFacing ? src.rect.left : (src.rect.left+src.rect.width-1), src.rect.bottom);
  	dst.quad.posB = IVec2(isFrontFacing ? (src.rect.left+src.rect.width-1) : src.rect.left, src.rect.bottom+src.rect.height-1);
  
  	std::fill(DE_ARRAY_BEGIN(dst.quad.color), DE_ARRAY_END(dst.quad.color), src.color);
  	std::fill(DE_ARRAY_BEGIN(dst.quad.depth), DE_ARRAY_END(dst.quad.depth), ((far-near)/2.0f) * src.params.depth + (near+far)/2.0f);
  
  	dst.state.colorMask = src.colorMask;
  
  	dst.state.scissorTestEnabled		= false;
  	dst.state.stencilTestEnabled		= hasStencil && src.params.stencilTestEnabled;
  	dst.state.depthTestEnabled			= hasDepth && src.params.depthTestEnabled;
  	dst.state.blendMode					= rr::BLENDMODE_NONE;
  	dst.state.numStencilBits			= renderTarget.stencilBits;
  
  	if (dst.state.depthTestEnabled)
  	{
  		dst.state.depthFunc					= sglr::rr_util::mapGLTestFunc(src.params.depthFunc);
  		dst.state.depthMask					= src.params.depthWriteMask;
  	}
  
  	if (dst.state.stencilTestEnabled)
  	{
  		translateStencilState(src.params.stencil[rr::FACETYPE_BACK],	dst.state.stencilStates[rr::FACETYPE_BACK]);
  		translateStencilState(src.params.stencil[rr::FACETYPE_FRONT],	dst.state.stencilStates[rr::FACETYPE_FRONT]);
  	}
  }
  
  void render (const vector<ClearCommand>& clears, int viewportX, int viewportY)
  {
  	glEnable(GL_SCISSOR_TEST);
  
  	for (int ndx = 0; ndx < (int)clears.size(); ndx++)
  	{
  		const ClearCommand& clear = clears[ndx];
  
  		if (clear.buffers & GL_COLOR_BUFFER_BIT)	glClearColor(clear.color.x(), clear.color.y(), clear.color.z(), clear.color.w());
  		if (clear.buffers & GL_STENCIL_BUFFER_BIT)	glClearStencil(clear.stencil);
  
  		DE_ASSERT(clear.buffers == (clear.buffers & (GL_COLOR_BUFFER_BIT|GL_STENCIL_BUFFER_BIT))); // \note Don't use clear for depths.
  
  		glScissor(clear.rect.left+viewportX, clear.rect.bottom+viewportY, clear.rect.width, clear.rect.height);
  		glClear(clear.buffers);
  	}
  
  	glDisable(GL_SCISSOR_TEST);
  }
  
  void render (gls::FragmentOpUtil::QuadRenderer& renderer, const RenderCommand& command, int viewportX, int viewportY)
  {
  	if (command.params.stencilTestEnabled)
  	{
  		glEnable(GL_STENCIL_TEST);
  
  		for (int face = 0; face < rr::FACETYPE_LAST; face++)
  		{
  			deUint32				glFace	= face == rr::FACETYPE_BACK ? GL_BACK : GL_FRONT;
  			const StencilParams&	sParams	= command.params.stencil[face];
  
  			glStencilFuncSeparate(glFace, sParams.function, sParams.reference, sParams.compareMask);
  			glStencilOpSeparate(glFace, sParams.stencilFailOp, sParams.depthFailOp, sParams.depthPassOp);
  			glStencilMaskSeparate(glFace, sParams.writeMask);
  		}
  	}
  	else
  		glDisable(GL_STENCIL_TEST);
  
  	if (command.params.depthTestEnabled)
  	{
  		glEnable(GL_DEPTH_TEST);
  		glDepthFunc(command.params.depthFunc);
  		glDepthMask(command.params.depthWriteMask ? GL_TRUE : GL_FALSE);
  	}
  	else
  		glDisable(GL_DEPTH_TEST);
  
  	glColorMask(command.colorMask[0] ? GL_TRUE : GL_FALSE,
  				command.colorMask[1] ? GL_TRUE : GL_FALSE,
  				command.colorMask[2] ? GL_TRUE : GL_FALSE,
  				command.colorMask[3] ? GL_TRUE : GL_FALSE);
  	glViewport(command.rect.left+viewportX, command.rect.bottom+viewportY, command.rect.width, command.rect.height);
  
  	gls::FragmentOpUtil::Quad quad;
  
  	bool isFrontFacing = command.params.visibleFace == rr::FACETYPE_FRONT;
  	quad.posA = Vec2(isFrontFacing ? -1.0f :  1.0f, -1.0f);
  	quad.posB = Vec2(isFrontFacing ?  1.0f : -1.0f,  1.0f);
  
  	std::fill(DE_ARRAY_BEGIN(quad.color), DE_ARRAY_END(quad.color), command.color);
  	std::fill(DE_ARRAY_BEGIN(quad.depth), DE_ARRAY_END(quad.depth), command.params.depth);
  
  	renderer.render(quad);
  	GLU_CHECK();
  }
  
  void renderReference (const vector<ClearCommand>& clears, const tcu::PixelBufferAccess& dstColor, const tcu::PixelBufferAccess& dstStencil, int stencilBits)
  {
  	for (int ndx = 0; ndx < (int)clears.size(); ndx++)
  	{
  		const ClearCommand& clear = clears[ndx];
  
  		if (clear.buffers & GL_COLOR_BUFFER_BIT)
  			tcu::clear(tcu::getSubregion(dstColor, clear.rect.left, clear.rect.bottom, clear.rect.width, clear.rect.height), clear.color);
  
  		if (clear.buffers & GL_STENCIL_BUFFER_BIT && stencilBits > 0)
  		{
  			int maskedVal = clear.stencil & ((1<<stencilBits)-1);
  			tcu::clearStencil(tcu::getSubregion(dstStencil, clear.rect.left, clear.rect.bottom, clear.rect.width, clear.rect.height), maskedVal);
  		}
  
  		DE_ASSERT(clear.buffers == (clear.buffers & (GL_COLOR_BUFFER_BIT|GL_STENCIL_BUFFER_BIT))); // \note Don't use clear for depths.
  	}
  }
  
  } // DepthStencilCaseUtil
  
  using namespace DepthStencilCaseUtil;
  
  class DepthStencilCase : public TestCase
  {
  public:
  							DepthStencilCase		(Context& context, const char* name, const char* desc, const std::vector<DepthStencilParams>& cases);
  							~DepthStencilCase		(void);
  
  	void					init					(void);
  	void					deinit					(void);
  
  	IterateResult			iterate					(void);
  
  private:
  							DepthStencilCase		(const DepthStencilCase& other);
  	DepthStencilCase&		operator=				(const DepthStencilCase& other);
  
  	std::vector<DepthStencilParams>					m_cases;
  
  	TestRenderTarget								m_renderTarget;
  	std::vector<ClearCommand>						m_baseClears;
  	std::vector<RenderCommand>						m_baseDepthRenders;
  	std::vector<RenderCommand>						m_visualizeCommands;
  	std::vector<RefRenderCommand>					m_refBaseDepthRenders;
  	std::vector<RefRenderCommand>					m_refVisualizeCommands;
  
  	gls::FragmentOpUtil::QuadRenderer*				m_renderer;
  	tcu::Surface*									m_refColorBuffer;
  	tcu::TextureLevel*								m_refDepthBuffer;
  	tcu::TextureLevel*								m_refStencilBuffer;
  	gls::FragmentOpUtil::ReferenceQuadRenderer*		m_refRenderer;
  
  	int												m_iterNdx;
  };
  
  DepthStencilCase::DepthStencilCase (Context& context, const char* name, const char* desc, const std::vector<DepthStencilParams>& cases)
  	: TestCase				(context, name, desc)
  	, m_cases				(cases)
  	, m_renderer			(DE_NULL)
  	, m_refColorBuffer		(DE_NULL)
  	, m_refDepthBuffer		(DE_NULL)
  	, m_refStencilBuffer	(DE_NULL)
  	, m_refRenderer			(DE_NULL)
  	, m_iterNdx				(0)
  {
  }
  
  DepthStencilCase::~DepthStencilCase (void)
  {
  	delete m_renderer;
  	delete m_refColorBuffer;
  	delete m_refDepthBuffer;
  	delete m_refStencilBuffer;
  	delete m_refRenderer;
  }
  
  void DepthStencilCase::init (void)
  {
  	DE_ASSERT(!m_renderer && !m_refColorBuffer && !m_refDepthBuffer && !m_refStencilBuffer && !m_refRenderer);
  
  	// Compute render target.
  	int viewportW	= de::min<int>(m_context.getRenderTarget().getWidth(), VIEWPORT_WIDTH);
  	int viewportH	= de::min<int>(m_context.getRenderTarget().getHeight(), VIEWPORT_HEIGHT);
  	m_renderTarget	= TestRenderTarget(viewportW, viewportH, m_context.getRenderTarget().getDepthBits(), m_context.getRenderTarget().getStencilBits());
  
  	// Compute base clears & visualization commands.
  	generateBaseClearAndDepthCommands(m_renderTarget, m_baseClears, m_baseDepthRenders);
  	generateDepthVisualizeCommands(m_renderTarget, m_visualizeCommands);
  	generateStencilVisualizeCommands(m_renderTarget, m_visualizeCommands);
  
  	// Translate to ref commands.
  	m_refBaseDepthRenders.resize(m_baseDepthRenders.size());
  	for (int ndx = 0; ndx < (int)m_baseDepthRenders.size(); ndx++)
  		translateCommand(m_baseDepthRenders[ndx], m_refBaseDepthRenders[ndx], m_renderTarget);
  
  	m_refVisualizeCommands.resize(m_visualizeCommands.size());
  	for (int ndx = 0; ndx < (int)m_visualizeCommands.size(); ndx++)
  		translateCommand(m_visualizeCommands[ndx], m_refVisualizeCommands[ndx], m_renderTarget);
  
  	m_renderer			= new gls::FragmentOpUtil::QuadRenderer(m_context.getRenderContext(), glu::GLSL_VERSION_300_ES);
  	m_refColorBuffer	= new tcu::Surface(viewportW, viewportH);
  	m_refDepthBuffer	= new tcu::TextureLevel(tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::FLOAT),			viewportW, viewportH);
  	m_refStencilBuffer	= new tcu::TextureLevel(tcu::TextureFormat(tcu::TextureFormat::S, tcu::TextureFormat::UNSIGNED_INT32),	viewportW, viewportH);
  	m_refRenderer		= new gls::FragmentOpUtil::ReferenceQuadRenderer();
  
  	m_iterNdx			= 0;
  	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
  }
  
  void DepthStencilCase::deinit (void)
  {
  	delete m_renderer;
  	delete m_refColorBuffer;
  	delete m_refDepthBuffer;
  	delete m_refStencilBuffer;
  	delete m_refRenderer;
  
  	m_renderer			= DE_NULL;
  	m_refColorBuffer	= DE_NULL;
  	m_refDepthBuffer	= DE_NULL;
  	m_refStencilBuffer	= DE_NULL;
  	m_refRenderer		= DE_NULL;
  
  	m_baseClears.clear();
  	m_baseDepthRenders.clear();
  	m_visualizeCommands.clear();
  	m_refBaseDepthRenders.clear();
  	m_refVisualizeCommands.clear();
  }
  
  DepthStencilCase::IterateResult DepthStencilCase::iterate (void)
  {
  	de::Random				rnd				(deStringHash(getName()) ^ deInt32Hash(m_iterNdx));
  	int						viewportX		= rnd.getInt(0, m_context.getRenderTarget().getWidth()-m_renderTarget.width);
  	int						viewportY		= rnd.getInt(0, m_context.getRenderTarget().getHeight()-m_renderTarget.height);
  	RenderCommand			testCmd;
  
  	tcu::Surface			renderedImg		(m_renderTarget.width, m_renderTarget.height);
  	tcu::RGBA				threshold		= m_context.getRenderTarget().getPixelFormat().getColorThreshold();
  
  	// Fill in test command for this iteration.
  	testCmd.color		= Vec4(1.0f, 0.0f, 0.0f, 1.0f);
  	testCmd.colorMask	= tcu::BVec4(true);
  	testCmd.rect		= rr::WindowRectangle(0, 0, m_renderTarget.width, m_renderTarget.height);
  	testCmd.params		= m_cases[m_iterNdx];
  
  	if (m_iterNdx == 0)
  	{
  		m_testCtx.getLog() << TestLog::Message << "Channels:\n"
  													"  RED: passing pixels\n"
  													"  GREEN: stencil values\n"
  													"  BLUE: depth values"
  							<< TestLog::EndMessage;
  	}
  
  	if (m_cases.size() > 1)
  		m_testCtx.getLog() << TestLog::Message << "Iteration " << m_iterNdx << "..." << TestLog::EndMessage;
  
  	m_testCtx.getLog() << m_cases[m_iterNdx];
  
  	// Submit render commands to gl GL.
  
  	// Base clears.
  	render(m_baseClears, viewportX, viewportY);
  
  	// Base depths.
  	for (vector<RenderCommand>::const_iterator cmd = m_baseDepthRenders.begin(); cmd != m_baseDepthRenders.end(); ++cmd)
  		render(*m_renderer, *cmd, viewportX, viewportY);
  
  	// Test command.
  	render(*m_renderer, testCmd, viewportX, viewportY);
  
  	// Visualization commands.
  	for (vector<RenderCommand>::const_iterator cmd = m_visualizeCommands.begin(); cmd != m_visualizeCommands.end(); ++cmd)
  		render(*m_renderer, *cmd, viewportX, viewportY);
  
  	// Re-enable all write masks.
  	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  	glDepthMask(GL_TRUE);
  	glStencilMask(~0u);
  
  	// Ask GPU to start rendering.
  	glFlush();
  
  	// Render reference while GPU is doing work.
  	{
  		RefRenderCommand refTestCmd;
  		translateCommand(testCmd, refTestCmd, m_renderTarget);
  
  		// Base clears.
  		renderReference(m_baseClears, m_refColorBuffer->getAccess(), m_refStencilBuffer->getAccess(), m_renderTarget.stencilBits);
  
  		// Base depths.
  		for (vector<RefRenderCommand>::const_iterator cmd = m_refBaseDepthRenders.begin(); cmd != m_refBaseDepthRenders.end(); ++cmd)
  			m_refRenderer->render(gls::FragmentOpUtil::getMultisampleAccess(m_refColorBuffer->getAccess()),
  								  gls::FragmentOpUtil::getMultisampleAccess(m_refDepthBuffer->getAccess()),
  								  gls::FragmentOpUtil::getMultisampleAccess(m_refStencilBuffer->getAccess()),
  								  cmd->quad, cmd->state);
  
  		// Test command.
  		m_refRenderer->render(gls::FragmentOpUtil::getMultisampleAccess(m_refColorBuffer->getAccess()),
  							  gls::FragmentOpUtil::getMultisampleAccess(m_refDepthBuffer->getAccess()),
  							  gls::FragmentOpUtil::getMultisampleAccess(m_refStencilBuffer->getAccess()),
  							  refTestCmd.quad, refTestCmd.state);
  
  		// Visualization commands.
  		for (vector<RefRenderCommand>::const_iterator cmd = m_refVisualizeCommands.begin(); cmd != m_refVisualizeCommands.end(); ++cmd)
  			m_refRenderer->render(gls::FragmentOpUtil::getMultisampleAccess(m_refColorBuffer->getAccess()),
  								  gls::FragmentOpUtil::getMultisampleAccess(m_refDepthBuffer->getAccess()),
  								  gls::FragmentOpUtil::getMultisampleAccess(m_refStencilBuffer->getAccess()),
  								  cmd->quad, cmd->state);
  	}
  
  	// Read rendered image.
  	glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, renderedImg.getAccess());
  
  	m_iterNdx += 1;
  
  	// Compare to reference.
  	bool	isLastIter	= m_iterNdx >= (int)m_cases.size();
  	bool	compareOk	= tcu::pixelThresholdCompare(m_testCtx.getLog(), "CompareResult", "Image Comparison Result", *m_refColorBuffer, renderedImg, threshold,
  													 tcu::COMPARE_LOG_RESULT);
  
  	m_testCtx.getLog() << TestLog::Message << (compareOk ? "  Passed." : "  FAILED!") << TestLog::EndMessage;
  	if (!compareOk)
  		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
  
  	if (compareOk && !isLastIter)
  		return CONTINUE;
  	else
  		return STOP;
  }
  
  DepthStencilTests::DepthStencilTests (Context& context)
  	: TestCaseGroup(context, "depth_stencil", "Depth and Stencil Op Tests")
  {
  }
  
  DepthStencilTests::~DepthStencilTests (void)
  {
  }
  
  static void randomDepthStencilState (de::Random& rnd, DepthStencilParams& params)
  {
  	const float stencilTestProbability	= 0.8f;
  	const float depthTestProbability	= 0.7f;
  
  	static const deUint32 compareFuncs[] =
  	{
  		GL_NEVER,
  		GL_ALWAYS,
  		GL_LESS,
  		GL_LEQUAL,
  		GL_EQUAL,
  		GL_GEQUAL,
  		GL_GREATER,
  		GL_NOTEQUAL
  	};
  
  	static const deUint32 stencilOps[] =
  	{
  		GL_KEEP,
  		GL_ZERO,
  		GL_REPLACE,
  		GL_INCR,
  		GL_DECR,
  		GL_INVERT,
  		GL_INCR_WRAP,
  		GL_DECR_WRAP
  	};
  
  	static const float depthValues[] = { -1.0f, -0.8f, -0.6f, -0.4f, -0.2f, 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f };
  
  	params.visibleFace			= rnd.getBool() ? rr::FACETYPE_FRONT : rr::FACETYPE_BACK;
  	params.stencilTestEnabled	= rnd.getFloat() < stencilTestProbability;
  	params.depthTestEnabled		= !params.stencilTestEnabled || (rnd.getFloat() < depthTestProbability);
  
  	if (params.stencilTestEnabled)
  	{
  		for (int ndx = 0; ndx < 2; ndx++)
  		{
  			params.stencil[ndx].function		= rnd.choose<deUint32>(DE_ARRAY_BEGIN(compareFuncs), DE_ARRAY_END(compareFuncs));
  			params.stencil[ndx].reference		= rnd.getInt(-2, 260);
  			params.stencil[ndx].compareMask		= rnd.getUint32();
  			params.stencil[ndx].stencilFailOp	= rnd.choose<deUint32>(DE_ARRAY_BEGIN(stencilOps), DE_ARRAY_END(stencilOps));
  			params.stencil[ndx].depthFailOp		= rnd.choose<deUint32>(DE_ARRAY_BEGIN(stencilOps), DE_ARRAY_END(stencilOps));
  			params.stencil[ndx].depthPassOp		= rnd.choose<deUint32>(DE_ARRAY_BEGIN(stencilOps), DE_ARRAY_END(stencilOps));
  			params.stencil[ndx].writeMask		= rnd.getUint32();
  		}
  	}
  
  	if (params.depthTestEnabled)
  	{
  		params.depthFunc		= rnd.choose<deUint32>(DE_ARRAY_BEGIN(compareFuncs), DE_ARRAY_END(compareFuncs));
  		params.depth			= rnd.choose<float>(DE_ARRAY_BEGIN(depthValues), DE_ARRAY_END(depthValues));
  		params.depthWriteMask	= rnd.getBool();
  	}
  }
  
  void DepthStencilTests::init (void)
  {
  	static const struct
  	{
  		const char*	name;
  		deUint32	func;
  	} compareFuncs[] =
  	{
  		{ "never",		GL_NEVER	},
  		{ "always",		GL_ALWAYS	},
  		{ "less",		GL_LESS		},
  		{ "lequal",		GL_LEQUAL	},
  		{ "equal",		GL_EQUAL	},
  		{ "gequal",		GL_GEQUAL	},
  		{ "greater",	GL_GREATER	},
  		{ "notequal",	GL_NOTEQUAL	}
  	};
  
  	static const struct
  	{
  		const char*	name;
  		deUint32	op;
  	} stencilOps[] =
  	{
  		{ "keep",		GL_KEEP			},
  		{ "zero",		GL_ZERO			},
  		{ "replace",	GL_REPLACE		},
  		{ "incr",		GL_INCR			},
  		{ "decr",		GL_DECR			},
  		{ "invert",		GL_INVERT		},
  		{ "incr_wrap",	GL_INCR_WRAP	},
  		{ "decr_wrap",	GL_DECR_WRAP	}
  	};
  
  	static const struct
  	{
  		rr::FaceType	visibleFace;
  		deUint32		sFail;
  		deUint32		dFail;
  		deUint32		dPass;
  		int				stencilRef;
  		deUint32		compareMask;
  		deUint32		writeMask;
  		float			depth;
  	} functionCases[] =
  	{
  		{ rr::FACETYPE_BACK,	GL_DECR,		GL_INCR,	GL_INVERT,		4,	~0u, ~0u,	-0.7f },
  		{ rr::FACETYPE_FRONT,	GL_DECR,		GL_INCR,	GL_INVERT,		2,	~0u, ~0u,	0.0f },
  		{ rr::FACETYPE_BACK,	GL_DECR,		GL_INCR,	GL_INVERT,		1,	~0u, ~0u,	0.2f },
  		{ rr::FACETYPE_FRONT,	GL_DECR_WRAP,	GL_INVERT,	GL_REPLACE,		4,	~0u, ~0u,	1.0f }
  	};
  
  	// All combinations of depth stencil functions.
  	{
  		tcu::TestCaseGroup* functionsGroup = new tcu::TestCaseGroup(m_testCtx, "stencil_depth_funcs", "Combinations of Depth and Stencil Functions");
  		addChild(functionsGroup);
  
  		for (int stencilFunc = 0; stencilFunc < DE_LENGTH_OF_ARRAY(compareFuncs)+1; stencilFunc++)
  		{
  			// One extra: depth test disabled.
  			for (int depthFunc = 0; depthFunc < DE_LENGTH_OF_ARRAY(compareFuncs)+1; depthFunc++)
  			{
  				DepthStencilParams	params;
  				ostringstream		name;
  				bool				hasStencilFunc	= de::inBounds(stencilFunc, 0, DE_LENGTH_OF_ARRAY(compareFuncs));
  				bool				hasDepthFunc	= de::inBounds(depthFunc, 0, DE_LENGTH_OF_ARRAY(compareFuncs));
  
  				if (hasStencilFunc)
  					name << "stencil_" << compareFuncs[stencilFunc].name << "_";
  				else
  					name << "no_stencil_";
  
  				if (hasDepthFunc)
  					name << "depth_" << compareFuncs[depthFunc].name;
  				else
  					name << "no_depth";
  
  				params.depthFunc			= hasDepthFunc ? compareFuncs[depthFunc].func : 0;
  				params.depthTestEnabled		= hasDepthFunc;
  				params.depthWriteMask		= true;
  
  				params.stencilTestEnabled	= hasStencilFunc;
  
  				vector<DepthStencilParams> cases;
  				for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(functionCases); ndx++)
  				{
  					rr::FaceType	visible		= functionCases[ndx].visibleFace;
  					rr::FaceType	notVisible	= visible == rr::FACETYPE_FRONT ? rr::FACETYPE_BACK : rr::FACETYPE_FRONT;
  
  					params.depth								= functionCases[ndx].depth;
  					params.visibleFace							= visible;
  
  					params.stencil[visible].function			= hasStencilFunc ? compareFuncs[stencilFunc].func : 0;
  					params.stencil[visible].reference			= functionCases[ndx].stencilRef;
  					params.stencil[visible].stencilFailOp		= functionCases[ndx].sFail;
  					params.stencil[visible].depthFailOp			= functionCases[ndx].dFail;
  					params.stencil[visible].depthPassOp			= functionCases[ndx].dPass;
  					params.stencil[visible].compareMask			= functionCases[ndx].compareMask;
  					params.stencil[visible].writeMask			= functionCases[ndx].writeMask;
  
  					params.stencil[notVisible].function			= GL_ALWAYS;
  					params.stencil[notVisible].reference		= 0;
  					params.stencil[notVisible].stencilFailOp	= GL_REPLACE;
  					params.stencil[notVisible].depthFailOp		= GL_REPLACE;
  					params.stencil[notVisible].depthPassOp		= GL_REPLACE;
  					params.stencil[notVisible].compareMask		= 0u;
  					params.stencil[notVisible].writeMask		= ~0u;
  
  
  					cases.push_back(params);
  				}
  
  				functionsGroup->addChild(new DepthStencilCase(m_context, name.str().c_str(), "", cases));
  			}
  		}
  	}
  
  	static const struct
  	{
  		rr::FaceType	visibleFace;
  		deUint32		func;
  		int				ref;
  		deUint32		compareMask;
  		deUint32		writeMask;
  	} opCombinationCases[] =
  	{
  		{ rr::FACETYPE_BACK,	GL_LESS,		4,		~0u,	~0u	},
  		{ rr::FACETYPE_FRONT,	GL_GREATER,		2,		~0u,	~0u	},
  		{ rr::FACETYPE_BACK,	GL_EQUAL,		3,		~2u,	~0u	},
  		{ rr::FACETYPE_FRONT,	GL_NOTEQUAL,	1,		~0u,	~1u	}
  	};
  
  	// All combinations of stencil ops.
  	{
  		tcu::TestCaseGroup* opCombinationGroup = new tcu::TestCaseGroup(m_testCtx, "stencil_ops", "Stencil Op Combinations");
  		addChild(opCombinationGroup);
  
  		for (int sFail = 0; sFail < DE_LENGTH_OF_ARRAY(stencilOps); sFail++)
  		{
  			for (int dFail = 0; dFail < DE_LENGTH_OF_ARRAY(stencilOps); dFail++)
  			{
  				for (int dPass = 0; dPass < DE_LENGTH_OF_ARRAY(stencilOps); dPass++)
  				{
  					DepthStencilParams	params;
  					ostringstream		name;
  
  					name << stencilOps[sFail].name << "_" << stencilOps[dFail].name << "_" << stencilOps[dPass].name;
  
  					params.depthFunc			= GL_LEQUAL;
  					params.depth				= 0.0f;
  					params.depthTestEnabled		= true;
  					params.depthWriteMask		= true;
  
  					params.stencilTestEnabled	= true;
  
  					vector<DepthStencilParams> cases;
  					for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(opCombinationCases); ndx++)
  					{
  						rr::FaceType	visible		= opCombinationCases[ndx].visibleFace;
  						rr::FaceType	notVisible	= visible == rr::FACETYPE_FRONT ? rr::FACETYPE_BACK : rr::FACETYPE_FRONT;
  
  						params.visibleFace							= visible;
  
  						params.stencil[visible].function			= opCombinationCases[ndx].func;
  						params.stencil[visible].reference			= opCombinationCases[ndx].ref;
  						params.stencil[visible].stencilFailOp		= stencilOps[sFail].op;
  						params.stencil[visible].depthFailOp			= stencilOps[dFail].op;
  						params.stencil[visible].depthPassOp			= stencilOps[dPass].op;
  						params.stencil[visible].compareMask			= opCombinationCases[ndx].compareMask;
  						params.stencil[visible].writeMask			= opCombinationCases[ndx].writeMask;
  
  						params.stencil[notVisible].function			= GL_ALWAYS;
  						params.stencil[notVisible].reference		= 0;
  						params.stencil[notVisible].stencilFailOp	= GL_REPLACE;
  						params.stencil[notVisible].depthFailOp		= GL_REPLACE;
  						params.stencil[notVisible].depthPassOp		= GL_REPLACE;
  						params.stencil[notVisible].compareMask		= 0u;
  						params.stencil[notVisible].writeMask		= ~0u;
  
  
  						cases.push_back(params);
  					}
  
  					opCombinationGroup->addChild(new DepthStencilCase(m_context, name.str().c_str(), "", cases));
  				}
  			}
  		}
  	}
  
  	// Write masks
  	{
  		tcu::TestCaseGroup* writeMaskGroup = new tcu::TestCaseGroup(m_testCtx, "write_mask", "Depth and Stencil Write Masks");
  		addChild(writeMaskGroup);
  
  		// Depth mask
  		{
  			DepthStencilParams params;
  
  			params.depthFunc			= GL_LEQUAL;
  			params.depth				= 0.0f;
  			params.depthTestEnabled		= true;
  			params.stencilTestEnabled	= true;
  
  			params.stencil[rr::FACETYPE_FRONT].function			= GL_NOTEQUAL;
  			params.stencil[rr::FACETYPE_FRONT].reference		= 1;
  			params.stencil[rr::FACETYPE_FRONT].stencilFailOp	= GL_INVERT;
  			params.stencil[rr::FACETYPE_FRONT].depthFailOp		= GL_INCR;
  			params.stencil[rr::FACETYPE_FRONT].depthPassOp		= GL_DECR;
  			params.stencil[rr::FACETYPE_FRONT].compareMask		= ~0u;
  			params.stencil[rr::FACETYPE_FRONT].writeMask		= ~0u;
  
  			params.stencil[rr::FACETYPE_BACK].function			= GL_ALWAYS;
  			params.stencil[rr::FACETYPE_BACK].reference			= 0;
  			params.stencil[rr::FACETYPE_BACK].stencilFailOp		= GL_REPLACE;
  			params.stencil[rr::FACETYPE_BACK].depthFailOp		= GL_INVERT;
  			params.stencil[rr::FACETYPE_BACK].depthPassOp		= GL_INCR;
  			params.stencil[rr::FACETYPE_BACK].compareMask		= ~0u;
  			params.stencil[rr::FACETYPE_BACK].writeMask		= ~0u;
  
  			vector<DepthStencilParams> cases;
  
  			// Case 1: front, depth write enabled
  			params.visibleFace		= rr::FACETYPE_FRONT;
  			params.depthWriteMask	= true;
  			cases.push_back(params);
  
  			// Case 2: front, depth write disabled
  			params.visibleFace		= rr::FACETYPE_FRONT;
  			params.depthWriteMask	= false;
  			cases.push_back(params);
  
  			// Case 3: back, depth write enabled
  			params.visibleFace		= rr::FACETYPE_BACK;
  			params.depthWriteMask	= true;
  			cases.push_back(params);
  
  			// Case 4: back, depth write disabled
  			params.visibleFace		= rr::FACETYPE_BACK;
  			params.depthWriteMask	= false;
  			cases.push_back(params);
  
  			writeMaskGroup->addChild(new DepthStencilCase(m_context, "depth", "Depth Write Mask", cases));
  		}
  
  		// Stencil write masks.
  		{
  			static const struct
  			{
  				rr::FaceType	visibleFace;
  				deUint32		frontWriteMask;
  				deUint32		backWriteMask;
  			} stencilWmaskCases[] =
  			{
  				{ rr::FACETYPE_FRONT,	~0u,	0u		},
  				{ rr::FACETYPE_FRONT,	0u,		~0u		},
  				{ rr::FACETYPE_FRONT,	0xfu,	0xf0u	},
  				{ rr::FACETYPE_FRONT,	0x2u,	0x4u	},
  				{ rr::FACETYPE_BACK,	0u,		~0u		},
  				{ rr::FACETYPE_BACK,	~0u,	0u		},
  				{ rr::FACETYPE_BACK,	0xf0u,	0xfu	},
  				{ rr::FACETYPE_BACK,	0x4u,	0x2u	}
  			};
  
  			DepthStencilParams params;
  
  			params.depthFunc			= GL_LEQUAL;
  			params.depth				= 0.0f;
  			params.depthTestEnabled		= true;
  			params.depthWriteMask		= true;
  			params.stencilTestEnabled	= true;
  
  			params.stencil[rr::FACETYPE_FRONT].function			= GL_NOTEQUAL;
  			params.stencil[rr::FACETYPE_FRONT].reference		= 1;
  			params.stencil[rr::FACETYPE_FRONT].stencilFailOp	= GL_INVERT;
  			params.stencil[rr::FACETYPE_FRONT].depthFailOp		= GL_INCR;
  			params.stencil[rr::FACETYPE_FRONT].depthPassOp		= GL_DECR;
  			params.stencil[rr::FACETYPE_FRONT].compareMask		= ~0u;
  
  			params.stencil[rr::FACETYPE_BACK].function			= GL_ALWAYS;
  			params.stencil[rr::FACETYPE_BACK].reference			= 0;
  			params.stencil[rr::FACETYPE_BACK].stencilFailOp		= GL_REPLACE;
  			params.stencil[rr::FACETYPE_BACK].depthFailOp		= GL_INVERT;
  			params.stencil[rr::FACETYPE_BACK].depthPassOp		= GL_INCR;
  			params.stencil[rr::FACETYPE_BACK].compareMask		= ~0u;
  
  			vector<DepthStencilParams> cases;
  			for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(stencilWmaskCases); ndx++)
  			{
  				params.visibleFace								= stencilWmaskCases[ndx].visibleFace;
  				params.stencil[rr::FACETYPE_FRONT].writeMask	= stencilWmaskCases[ndx].frontWriteMask;
  				params.stencil[rr::FACETYPE_BACK].writeMask	= stencilWmaskCases[ndx].backWriteMask;
  				cases.push_back(params);
  			}
  
  			writeMaskGroup->addChild(new DepthStencilCase(m_context, "stencil", "Stencil Write Mask", cases));
  		}
  
  		// Depth & stencil write masks.
  		{
  			static const struct
  			{
  				bool			depthWriteMask;
  				rr::FaceType	visibleFace;
  				deUint32		frontWriteMask;
  				deUint32		backWriteMask;
  			} depthStencilWmaskCases[] =
  			{
  				{ false,	rr::FACETYPE_FRONT,		~0u,	0u		},
  				{ false,	rr::FACETYPE_FRONT,		0u,		~0u		},
  				{ false,	rr::FACETYPE_FRONT,		0xfu,	0xf0u	},
  				{ true,		rr::FACETYPE_FRONT,		~0u,	0u		},
  				{ true,		rr::FACETYPE_FRONT,		0u,		~0u		},
  				{ true,		rr::FACETYPE_FRONT,		0xfu,	0xf0u	},
  				{ false,	rr::FACETYPE_BACK,		0u,		~0u		},
  				{ false,	rr::FACETYPE_BACK,		~0u,	0u		},
  				{ false,	rr::FACETYPE_BACK,		0xf0u,	0xfu	},
  				{ true,		rr::FACETYPE_BACK,		0u,		~0u		},
  				{ true,		rr::FACETYPE_BACK,		~0u,	0u		},
  				{ true,		rr::FACETYPE_BACK,		0xf0u,	0xfu	}
  			};
  
  			DepthStencilParams params;
  
  			params.depthFunc			= GL_LEQUAL;
  			params.depth				= 0.0f;
  			params.depthTestEnabled		= true;
  			params.depthWriteMask		= true;
  			params.stencilTestEnabled	= true;
  
  			params.stencil[rr::FACETYPE_FRONT].function			= GL_NOTEQUAL;
  			params.stencil[rr::FACETYPE_FRONT].reference		= 1;
  			params.stencil[rr::FACETYPE_FRONT].stencilFailOp	= GL_INVERT;
  			params.stencil[rr::FACETYPE_FRONT].depthFailOp		= GL_INCR;
  			params.stencil[rr::FACETYPE_FRONT].depthPassOp		= GL_DECR;
  			params.stencil[rr::FACETYPE_FRONT].compareMask		= ~0u;
  
  			params.stencil[rr::FACETYPE_BACK].function			= GL_ALWAYS;
  			params.stencil[rr::FACETYPE_BACK].reference			= 0;
  			params.stencil[rr::FACETYPE_BACK].stencilFailOp		= GL_REPLACE;
  			params.stencil[rr::FACETYPE_BACK].depthFailOp		= GL_INVERT;
  			params.stencil[rr::FACETYPE_BACK].depthPassOp		= GL_INCR;
  			params.stencil[rr::FACETYPE_BACK].compareMask		= ~0u;
  
  			vector<DepthStencilParams> cases;
  			for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(depthStencilWmaskCases); ndx++)
  			{
  				params.depthWriteMask							= depthStencilWmaskCases[ndx].depthWriteMask;
  				params.visibleFace								= depthStencilWmaskCases[ndx].visibleFace;
  				params.stencil[rr::FACETYPE_FRONT].writeMask	= depthStencilWmaskCases[ndx].frontWriteMask;
  				params.stencil[rr::FACETYPE_BACK].writeMask		= depthStencilWmaskCases[ndx].backWriteMask;
  				cases.push_back(params);
  			}
  
  			writeMaskGroup->addChild(new DepthStencilCase(m_context, "both", "Depth and Stencil Write Masks", cases));
  		}
  	}
  
  	// Randomized cases
  	{
  		tcu::TestCaseGroup* randomGroup = new tcu::TestCaseGroup(m_testCtx, "random", "Randomized Depth and Stencil Test Cases");
  		addChild(randomGroup);
  
  		for (int caseNdx = 0; caseNdx < NUM_RANDOM_CASES; caseNdx++)
  		{
  			vector<DepthStencilParams>	subCases	(NUM_RANDOM_SUB_CASES);
  			de::Random					rnd			(deInt32Hash(caseNdx) ^ deInt32Hash(m_testCtx.getCommandLine().getBaseSeed()));
  
  			for (vector<DepthStencilParams>::iterator iter = subCases.begin(); iter != subCases.end(); ++iter)
  				randomDepthStencilState(rnd, *iter);
  
  			randomGroup->addChild(new DepthStencilCase(m_context, de::toString(caseNdx).c_str(), "", subCases));
  		}
  	}
  }
  
  } // Functional
  } // gles3
  } // deqp
  