1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 Module
3 * -------------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Stencil texturing tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es31fStencilTexturingTests.hpp"
25
26#include "gluStrUtil.hpp"
27#include "gluObjectWrapper.hpp"
28#include "gluRenderContext.hpp"
29#include "gluShaderProgram.hpp"
30#include "gluDrawUtil.hpp"
31#include "gluPixelTransfer.hpp"
32#include "gluTextureUtil.hpp"
33#include "gluContextInfo.hpp"
34
35#include "glsTextureTestUtil.hpp"
36
37#include "tcuVector.hpp"
38#include "tcuTexture.hpp"
39#include "tcuTextureUtil.hpp"
40#include "tcuTestLog.hpp"
41#include "tcuTexLookupVerifier.hpp"
42
43#include "glwFunctions.hpp"
44#include "glwEnums.hpp"
45
46#include "deStringUtil.hpp"
47
48namespace deqp
49{
50namespace gles31
51{
52namespace Functional
53{
54
55using std::vector;
56using std::string;
57using tcu::IVec4;
58using tcu::Vec2;
59using tcu::Vec4;
60using tcu::TestLog;
61using tcu::TextureLevel;
62using tcu::TextureFormat;
63
64namespace
65{
66
67static void genTestRects (vector<IVec4>& rects, int width, int height)
68{
69	int curWidth	= width;
70	int curHeight	= height;
71	int ndx			= 0;
72
73	for (;;)
74	{
75		rects.push_back(IVec4(width-curWidth, height-curHeight, curWidth, curHeight));
76
77		DE_ASSERT(curWidth >= 1 && curHeight >= 1);
78		if (curWidth == 1 && curHeight == 1)
79			break;
80		else if (curHeight > 1 && ((ndx%2) == 0 || curWidth == 1))
81			curHeight -= 1;
82		else
83			curWidth -= 1;
84
85		ndx += 1;
86	}
87}
88
89static void rectsToTriangles (const vector<IVec4>& rects, int width, int height, vector<Vec2>& positions, vector<deUint16>& indices)
90{
91	const float		w		= float(width);
92	const float		h		= float(height);
93
94	positions.resize(rects.size()*4);
95	indices.resize(rects.size()*6);
96
97	for (int rectNdx = 0; rectNdx < (int)rects.size(); rectNdx++)
98	{
99		const int		rx		= rects[rectNdx].x();
100		const int		ry		= rects[rectNdx].y();
101		const int		rw		= rects[rectNdx].z();
102		const int		rh		= rects[rectNdx].w();
103
104		const float		x0		= float(rx*2)/w - 1.0f;
105		const float		x1		= float((rx+rw)*2)/w - 1.0f;
106		const float		y0		= float(ry*2)/h - 1.0f;
107		const float		y1		= float((ry+rh)*2)/h - 1.0f;
108
109		positions[rectNdx*4 + 0] = Vec2(x0, y0);
110		positions[rectNdx*4 + 1] = Vec2(x1, y0);
111		positions[rectNdx*4 + 2] = Vec2(x0, y1);
112		positions[rectNdx*4 + 3] = Vec2(x1, y1);
113
114		indices[rectNdx*6 + 0] = rectNdx*4 + 0;
115		indices[rectNdx*6 + 1] = rectNdx*4 + 1;
116		indices[rectNdx*6 + 2] = rectNdx*4 + 2;
117		indices[rectNdx*6 + 3] = rectNdx*4 + 2;
118		indices[rectNdx*6 + 4] = rectNdx*4 + 1;
119		indices[rectNdx*6 + 5] = rectNdx*4 + 3;
120	}
121}
122
123static void drawTestPattern (const glu::RenderContext& renderCtx, int width, int height)
124{
125	const glu::ShaderProgram program(renderCtx, glu::ProgramSources()
126		<< glu::VertexSource(
127			"#version 300 es\n"
128			"in highp vec4 a_position;\n"
129			"void main (void)\n"
130			"{\n"
131			"	gl_Position = a_position;\n"
132			"}\n")
133		<< glu::FragmentSource(
134			"#version 300 es\n"
135			"void main (void) {}\n"));
136
137	const glw::Functions&	gl		= renderCtx.getFunctions();
138	vector<IVec4>			rects;
139	vector<Vec2>			positions;
140	vector<deUint16>		indices;
141
142	if (!program.isOk())
143		throw tcu::TestError("Compile failed");
144
145	gl.useProgram	(program.getProgram());
146	gl.viewport		(0, 0, width, height);
147	gl.clear		(GL_STENCIL_BUFFER_BIT);
148	gl.enable		(GL_STENCIL_TEST);
149	gl.stencilOp	(GL_KEEP, GL_KEEP, GL_INCR_WRAP);
150	gl.stencilFunc	(GL_ALWAYS, 0, ~0u);
151	GLU_EXPECT_NO_ERROR(gl.getError(), "State setup failed");
152
153	genTestRects	(rects, width, height);
154	rectsToTriangles(rects, width, height, positions, indices);
155
156	{
157		const glu::VertexArrayBinding posBinding = glu::va::Float("a_position", 2, (int)positions.size(), 0, positions[0].getPtr());
158		glu::draw(renderCtx, program.getProgram(), 1, &posBinding, glu::pr::Triangles((int)indices.size(), &indices[0]));
159	}
160
161	gl.disable(GL_STENCIL_TEST);
162}
163
164static void renderTestPatternReference (const tcu::PixelBufferAccess& dst)
165{
166	const int		stencilBits		= tcu::getTextureFormatBitDepth(dst.getFormat()).w();
167	const deUint32	stencilMask		= (1u<<stencilBits)-1u;
168	vector<IVec4>	rects;
169
170	DE_ASSERT(dst.getFormat().order == TextureFormat::S || dst.getFormat().order == TextureFormat::DS);
171
172	tcu::clear(dst, IVec4(0));
173
174	genTestRects(rects, dst.getWidth(), dst.getHeight());
175
176	for (vector<IVec4>::const_iterator rectIter = rects.begin(); rectIter != rects.end(); ++rectIter)
177	{
178		const int	x0		= rectIter->x();
179		const int	y0		= rectIter->y();
180		const int	x1		= x0+rectIter->z();
181		const int	y1		= y0+rectIter->w();
182
183		for (int y = y0; y < y1; y++)
184		{
185			for (int x = x0; x < x1; x++)
186			{
187				const int oldVal	= dst.getPixStencil(x, y);
188				const int newVal	= (oldVal+1)&stencilMask;
189
190				dst.setPixStencil(newVal, x, y);
191			}
192		}
193	}
194}
195
196static void blitStencilToColor2D (const glu::RenderContext& renderCtx, deUint32 srcTex, int width, int height)
197{
198	const glu::ShaderProgram program(renderCtx, glu::ProgramSources()
199		<< glu::VertexSource(
200			"#version 300 es\n"
201			"in highp vec4 a_position;\n"
202			"in highp vec2 a_texCoord;\n"
203			"out highp vec2 v_texCoord;\n"
204			"void main (void)\n"
205			"{\n"
206			"	gl_Position = a_position;\n"
207			"	v_texCoord = a_texCoord;\n"
208			"}\n")
209		<< glu::FragmentSource(
210			"#version 300 es\n"
211			"uniform highp usampler2D u_sampler;\n"
212			"in highp vec2 v_texCoord;\n"
213			"layout(location = 0) out highp uint o_stencil;\n"
214			"void main (void)\n"
215			"{\n"
216			"	o_stencil = texture(u_sampler, v_texCoord).x;\n"
217			"}\n"));
218
219	const float positions[] =
220	{
221		-1.0f, -1.0f,
222		+1.0f, -1.0f,
223		-1.0f, +1.0f,
224		+1.0f, +1.0f
225	};
226	const float texCoord[] =
227	{
228		0.0f, 0.0f,
229		1.0f, 0.0f,
230		0.0f, 1.0f,
231		1.0f, 1.0f
232	};
233	const glu::VertexArrayBinding vertexArrays[] =
234	{
235		glu::va::Float("a_position", 2, 4, 0, &positions[0]),
236		glu::va::Float("a_texCoord", 2, 4, 0, &texCoord[0])
237	};
238	const deUint8 indices[] = { 0, 1, 2, 2, 1, 3 };
239
240	const glw::Functions& gl = renderCtx.getFunctions();
241
242	if (!program.isOk())
243		throw tcu::TestError("Compile failed");
244
245	gl.activeTexture(GL_TEXTURE0);
246	gl.bindTexture(GL_TEXTURE_2D, srcTex);
247	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
248	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
249	gl.texParameteri(GL_TEXTURE_2D, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX);
250	GLU_EXPECT_NO_ERROR(gl.getError(), "Texture state setup failed");
251
252	gl.useProgram(program.getProgram());
253	gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_sampler"), 0);
254	GLU_EXPECT_NO_ERROR(gl.getError(), "Program setup failed");
255
256	gl.viewport(0, 0, width, height);
257	glu::draw(renderCtx, program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), &vertexArrays[0],
258			  glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
259}
260
261static void blitStencilToColor2DArray (const glu::RenderContext& renderCtx, deUint32 srcTex, int width, int height, int level)
262{
263	const glu::ShaderProgram program(renderCtx, glu::ProgramSources()
264		<< glu::VertexSource(
265			"#version 300 es\n"
266			"in highp vec4 a_position;\n"
267			"in highp vec3 a_texCoord;\n"
268			"out highp vec3 v_texCoord;\n"
269			"void main (void)\n"
270			"{\n"
271			"	gl_Position = a_position;\n"
272			"	v_texCoord = a_texCoord;\n"
273			"}\n")
274		<< glu::FragmentSource(
275			"#version 300 es\n"
276			"uniform highp usampler2DArray u_sampler;\n"
277			"in highp vec3 v_texCoord;\n"
278			"layout(location = 0) out highp uint o_stencil;\n"
279			"void main (void)\n"
280			"{\n"
281			"	o_stencil = texture(u_sampler, v_texCoord).x;\n"
282			"}\n"));
283
284	const float positions[] =
285	{
286		-1.0f, -1.0f,
287		+1.0f, -1.0f,
288		-1.0f, +1.0f,
289		+1.0f, +1.0f
290	};
291	const float texCoord[] =
292	{
293		0.0f, 0.0f, float(level),
294		1.0f, 0.0f, float(level),
295		0.0f, 1.0f, float(level),
296		1.0f, 1.0f, float(level)
297	};
298	const glu::VertexArrayBinding vertexArrays[] =
299	{
300		glu::va::Float("a_position", 2, 4, 0, &positions[0]),
301		glu::va::Float("a_texCoord", 3, 4, 0, &texCoord[0])
302	};
303	const deUint8 indices[] = { 0, 1, 2, 2, 1, 3 };
304
305	const glw::Functions& gl = renderCtx.getFunctions();
306
307	if (!program.isOk())
308		throw tcu::TestError("Compile failed");
309
310	gl.activeTexture(GL_TEXTURE0);
311	gl.bindTexture(GL_TEXTURE_2D_ARRAY, srcTex);
312	gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
313	gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
314	gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX);
315	GLU_EXPECT_NO_ERROR(gl.getError(), "Texture state setup failed");
316
317	gl.useProgram(program.getProgram());
318	gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_sampler"), 0);
319	GLU_EXPECT_NO_ERROR(gl.getError(), "Program setup failed");
320
321	gl.viewport(0, 0, width, height);
322	glu::draw(renderCtx, program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), &vertexArrays[0],
323			  glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
324}
325
326static void blitStencilToColorCube (const glu::RenderContext& renderCtx, deUint32 srcTex, const float* texCoord, int width, int height)
327{
328	const glu::ShaderProgram program(renderCtx, glu::ProgramSources()
329		<< glu::VertexSource(
330			"#version 300 es\n"
331			"in highp vec4 a_position;\n"
332			"in highp vec3 a_texCoord;\n"
333			"out highp vec3 v_texCoord;\n"
334			"void main (void)\n"
335			"{\n"
336			"	gl_Position = a_position;\n"
337			"	v_texCoord = a_texCoord;\n"
338			"}\n")
339		<< glu::FragmentSource(
340			"#version 300 es\n"
341			"uniform highp usamplerCube u_sampler;\n"
342			"in highp vec3 v_texCoord;\n"
343			"layout(location = 0) out highp vec4 o_color;\n"
344			"void main (void)\n"
345			"{\n"
346			"	o_color.x = float(texture(u_sampler, v_texCoord).x) / 255.0;\n"
347			"	o_color.yzw = vec3(0.0, 0.0, 1.0);\n"
348			"}\n"));
349
350	const float positions[] =
351	{
352		-1.0f, -1.0f,
353		-1.0f, +1.0f,
354		+1.0f, -1.0f,
355		+1.0f, +1.0f
356	};
357	const glu::VertexArrayBinding vertexArrays[] =
358	{
359		glu::va::Float("a_position", 2, 4, 0, &positions[0]),
360		glu::va::Float("a_texCoord", 3, 4, 0, texCoord)
361	};
362	const deUint8 indices[] = { 0, 1, 2, 2, 1, 3 };
363
364	const glw::Functions& gl = renderCtx.getFunctions();
365
366	if (!program.isOk())
367		throw tcu::TestError("Compile failed");
368
369	gl.activeTexture(GL_TEXTURE0);
370	gl.bindTexture(GL_TEXTURE_CUBE_MAP, srcTex);
371	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
372	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
373	gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX);
374	GLU_EXPECT_NO_ERROR(gl.getError(), "Texture state setup failed");
375
376	gl.useProgram(program.getProgram());
377	gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_sampler"), 0);
378	GLU_EXPECT_NO_ERROR(gl.getError(), "Program setup failed");
379
380	gl.viewport(0, 0, width, height);
381	glu::draw(renderCtx, program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), &vertexArrays[0],
382			  glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
383}
384
385static inline tcu::ConstPixelBufferAccess stencilToRedAccess (const tcu::ConstPixelBufferAccess& access)
386{
387	DE_ASSERT(access.getFormat() == TextureFormat(TextureFormat::S, TextureFormat::UNSIGNED_INT8));
388	return tcu::ConstPixelBufferAccess(TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT8),
389									   access.getWidth(), access.getHeight(), access.getDepth(), access.getRowPitch(), access.getSlicePitch(), access.getDataPtr());
390}
391
392static bool compareStencilToRed (tcu::TestLog& log, const tcu::ConstPixelBufferAccess& stencilRef, const tcu::ConstPixelBufferAccess& result)
393{
394	const int		maxPrints		= 10;
395	int				numFailed		= 0;
396
397	DE_ASSERT(stencilRef.getFormat().order == TextureFormat::S);
398	DE_ASSERT(stencilRef.getWidth() == result.getWidth() && stencilRef.getHeight() == result.getHeight());
399
400	for (int y = 0; y < stencilRef.getHeight(); y++)
401	{
402		for (int x = 0; x < stencilRef.getWidth(); x++)
403		{
404			const int		ref		= stencilRef.getPixStencil(x, y);
405			const int		res		= result.getPixelInt(x, y).x();
406
407			if (ref != res)
408			{
409				if (numFailed < maxPrints)
410					log << TestLog::Message << "ERROR: Expected " << ref << ", got " << res << " at (" << x << ", " << y << ")" << TestLog::EndMessage;
411				else if (numFailed == maxPrints)
412					log << TestLog::Message << "..." << TestLog::EndMessage;
413
414				numFailed += 1;
415			}
416		}
417	}
418
419	log << TestLog::Message << "Found " << numFailed << " faulty pixels, comparison " << (numFailed == 0 ? "passed." : "FAILED!") << TestLog::EndMessage;
420
421	log << TestLog::ImageSet("ComparisonResult", "Image comparison result")
422		<< TestLog::Image("Result", "Result stencil buffer", result);
423
424	if (numFailed > 0)
425		log << TestLog::Image("Reference", "Reference stencil buffer", stencilToRedAccess(stencilRef));
426
427	log << TestLog::EndImageSet;
428
429	return numFailed == 0;
430}
431
432static bool compareRedChannel (tcu::TestLog& log, const tcu::ConstPixelBufferAccess& result, int reference)
433{
434	const int		maxPrints		= 10;
435	int				numFailed		= 0;
436
437	for (int y = 0; y < result.getHeight(); y++)
438	{
439		for (int x = 0; x < result.getWidth(); x++)
440		{
441			const int res = result.getPixelInt(x, y).x();
442
443			if (reference != res)
444			{
445				if (numFailed < maxPrints)
446					log << TestLog::Message << "ERROR: Expected " << reference << ", got " << res << " at (" << x << ", " << y << ")" << TestLog::EndMessage;
447				else if (numFailed == maxPrints)
448					log << TestLog::Message << "..." << TestLog::EndMessage;
449
450				numFailed += 1;
451			}
452		}
453	}
454
455	log << TestLog::Message << "Found " << numFailed << " faulty pixels, comparison " << (numFailed == 0 ? "passed." : "FAILED!") << TestLog::EndMessage;
456
457	log << TestLog::ImageSet("ComparisonResult", "Image comparison result")
458		<< TestLog::Image("Result", "Result stencil buffer", result);
459
460	log << TestLog::EndImageSet;
461
462	return numFailed == 0;
463}
464
465static void stencilToUnorm8 (const tcu::TextureCube& src, tcu::TextureCube& dst)
466{
467	for (int levelNdx = 0; levelNdx < src.getNumLevels(); levelNdx++)
468	{
469		for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
470		{
471			const tcu::CubeFace face = tcu::CubeFace(faceNdx);
472
473			if (!src.isLevelEmpty(face, levelNdx))
474			{
475				dst.allocLevel(face, levelNdx);
476
477				const tcu::ConstPixelBufferAccess	srcLevel	= src.getLevelFace(levelNdx, face);
478				const tcu::PixelBufferAccess		dstLevel	= dst.getLevelFace(levelNdx, face);
479
480				for (int y = 0; y < src.getSize(); y++)
481				for (int x = 0; x < src.getSize(); x++)
482					dstLevel.setPixel(Vec4(float(srcLevel.getPixStencil(x, y)) / 255.f, 0.f, 0.f, 1.f), x, y);
483			}
484		}
485	}
486}
487
488static void checkDepthStencilFormatSupport (const glu::ContextInfo& ctxInfo, deUint32 format)
489{
490	if (format == GL_STENCIL_INDEX8)
491	{
492		const char* reqExt = "GL_OES_texture_stencil8";
493		if (!ctxInfo.isExtensionSupported(reqExt))
494			throw tcu::NotSupportedError(glu::getPixelFormatStr(format).toString() + " requires " + reqExt);
495	}
496	else
497	{
498		DE_ASSERT(format == GL_DEPTH32F_STENCIL8 || format == GL_DEPTH24_STENCIL8);
499	}
500}
501
502static void checkFramebufferStatus (const glw::Functions& gl)
503{
504	const deUint32 status = gl.checkFramebufferStatus(GL_FRAMEBUFFER);
505
506	if (status == GL_FRAMEBUFFER_UNSUPPORTED)
507		throw tcu::NotSupportedError("Unsupported framebuffer configuration");
508	else if (status != GL_FRAMEBUFFER_COMPLETE)
509		throw tcu::TestError("Incomplete framebuffer: " + glu::getFramebufferStatusStr(status).toString());
510}
511
512class UploadTex2DCase : public TestCase
513{
514public:
515	UploadTex2DCase (Context& context, const char* name, deUint32 format)
516		: TestCase	(context, name, glu::getPixelFormatName(format))
517		, m_format	(format)
518	{
519	}
520
521	IterateResult iterate (void)
522	{
523		const glu::RenderContext&	renderCtx			= m_context.getRenderContext();
524		const glw::Functions&		gl					= renderCtx.getFunctions();
525		const int					width				= 129;
526		const int					height				= 113;
527		glu::Framebuffer			fbo					(renderCtx);
528		glu::Renderbuffer			colorBuf			(renderCtx);
529		glu::Texture				depthStencilTex		(renderCtx);
530		TextureLevel				uploadLevel			(glu::mapGLInternalFormat(m_format), width, height);
531		TextureLevel				readLevel			(TextureFormat(TextureFormat::RGBA, TextureFormat::UNSIGNED_INT32), width, height);
532		TextureLevel				stencilOnlyLevel	(TextureFormat(TextureFormat::S, TextureFormat::UNSIGNED_INT8), width, height);
533
534		checkDepthStencilFormatSupport(m_context.getContextInfo(), m_format);
535
536		renderTestPatternReference(uploadLevel);
537		renderTestPatternReference(stencilOnlyLevel);
538
539		gl.bindTexture(GL_TEXTURE_2D, *depthStencilTex);
540		gl.texStorage2D(GL_TEXTURE_2D, 1, m_format, width, height);
541		glu::texSubImage2D(renderCtx, GL_TEXTURE_2D, 0, 0, 0, uploadLevel);
542		GLU_EXPECT_NO_ERROR(gl.getError(), "Uploading texture data failed");
543
544		gl.bindRenderbuffer(GL_RENDERBUFFER, *colorBuf);
545		gl.renderbufferStorage(GL_RENDERBUFFER, GL_R32UI, width, height);
546
547		gl.bindFramebuffer(GL_FRAMEBUFFER, *fbo);
548		gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, *colorBuf);
549		checkFramebufferStatus(gl);
550
551		blitStencilToColor2D(renderCtx, *depthStencilTex, width, height);
552		glu::readPixels(renderCtx, 0, 0, readLevel);
553
554		{
555			const bool compareOk = compareStencilToRed(m_testCtx.getLog(), stencilOnlyLevel, readLevel);
556			m_testCtx.setTestResult(compareOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
557									compareOk ? "Pass"				: "Image comparison failed");
558		}
559
560		return STOP;
561	}
562
563private:
564	const deUint32 m_format;
565};
566
567class UploadTex2DArrayCase : public TestCase
568{
569public:
570	UploadTex2DArrayCase (Context& context, const char* name, deUint32 format)
571		: TestCase	(context, name, glu::getPixelFormatName(format))
572		, m_format	(format)
573	{
574	}
575
576	IterateResult iterate (void)
577	{
578		const glu::RenderContext&	renderCtx			= m_context.getRenderContext();
579		const glw::Functions&		gl					= renderCtx.getFunctions();
580		const int					width				= 41;
581		const int					height				= 13;
582		const int					levels				= 7;
583		const int					ptrnLevel			= 3;
584		glu::Framebuffer			fbo					(renderCtx);
585		glu::Renderbuffer			colorBuf			(renderCtx);
586		glu::Texture				depthStencilTex		(renderCtx);
587		TextureLevel				uploadLevel			(glu::mapGLInternalFormat(m_format), width, height, levels);
588
589		checkDepthStencilFormatSupport(m_context.getContextInfo(), m_format);
590
591		for (int levelNdx = 0; levelNdx < levels; levelNdx++)
592		{
593			const tcu::PixelBufferAccess levelAccess = tcu::getSubregion(uploadLevel.getAccess(), 0, 0, levelNdx, width, height, 1);
594
595			if (levelNdx == ptrnLevel)
596				renderTestPatternReference(levelAccess);
597			else
598				tcu::clear(levelAccess, IVec4(0, 0, 0, levelNdx));
599		}
600
601		gl.bindTexture(GL_TEXTURE_2D_ARRAY, *depthStencilTex);
602		gl.texStorage3D(GL_TEXTURE_2D_ARRAY, 1, m_format, width, height, levels);
603		glu::texSubImage3D(renderCtx, GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, uploadLevel);
604		GLU_EXPECT_NO_ERROR(gl.getError(), "Uploading texture data failed");
605
606		gl.bindRenderbuffer(GL_RENDERBUFFER, *colorBuf);
607		gl.renderbufferStorage(GL_RENDERBUFFER, GL_R32UI, width, height);
608
609		gl.bindFramebuffer(GL_FRAMEBUFFER, *fbo);
610		gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, *colorBuf);
611		checkFramebufferStatus(gl);
612
613		{
614			TextureLevel	readLevel		(TextureFormat(TextureFormat::RGBA, TextureFormat::UNSIGNED_INT32), width, height);
615			bool			allLevelsOk		= true;
616
617			for (int levelNdx = 0; levelNdx < levels; levelNdx++)
618			{
619				tcu::ScopedLogSection section(m_testCtx.getLog(), "Level" + de::toString(levelNdx), "Level " + de::toString(levelNdx));
620				bool levelOk;
621
622				blitStencilToColor2DArray(renderCtx, *depthStencilTex, width, height, levelNdx);
623				glu::readPixels(renderCtx, 0, 0, readLevel);
624
625				if (levelNdx == ptrnLevel)
626				{
627					TextureLevel reference(TextureFormat(TextureFormat::S, TextureFormat::UNSIGNED_INT8), width, height);
628					renderTestPatternReference(reference);
629
630					levelOk = compareStencilToRed(m_testCtx.getLog(), reference, readLevel);
631				}
632				else
633					levelOk = compareRedChannel(m_testCtx.getLog(), readLevel, levelNdx);
634
635				if (!levelOk)
636				{
637					allLevelsOk = false;
638					break;
639				}
640			}
641
642			m_testCtx.setTestResult(allLevelsOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
643									allLevelsOk ? "Pass"				: "Image comparison failed");
644		}
645
646		return STOP;
647	}
648
649private:
650	const deUint32 m_format;
651};
652
653class UploadTexCubeCase : public TestCase
654{
655public:
656	UploadTexCubeCase (Context& context, const char* name, deUint32 format)
657		: TestCase	(context, name, glu::getPixelFormatName(format))
658		, m_format	(format)
659	{
660	}
661
662	IterateResult iterate (void)
663	{
664		const glu::RenderContext&	renderCtx			= m_context.getRenderContext();
665		const glw::Functions&		gl					= renderCtx.getFunctions();
666		const int					size				= 64;
667		const int					renderWidth			= 128;
668		const int					renderHeight		= 128;
669		vector<float>				texCoord;
670		glu::Framebuffer			fbo					(renderCtx);
671		glu::Renderbuffer			colorBuf			(renderCtx);
672		glu::Texture				depthStencilTex		(renderCtx);
673		tcu::TextureCube			texData				(glu::mapGLInternalFormat(m_format), size);
674		tcu::TextureLevel			result				(TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8), renderWidth, renderHeight);
675
676		checkDepthStencilFormatSupport(m_context.getContextInfo(), m_format);
677
678		for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
679		{
680			const tcu::CubeFace		face		= tcu::CubeFace(faceNdx);
681			const int				stencilVal	= 42*faceNdx;
682
683			texData.allocLevel(face, 0);
684			tcu::clear(texData.getLevelFace(0, face), IVec4(0, 0, 0, stencilVal));
685		}
686
687		gls::TextureTestUtil::computeQuadTexCoordCube(texCoord, tcu::CUBEFACE_NEGATIVE_X, Vec2(-1.5f, -1.3f), Vec2(1.3f, 1.4f));
688
689		gl.bindTexture(GL_TEXTURE_CUBE_MAP, *depthStencilTex);
690		gl.texStorage2D(GL_TEXTURE_CUBE_MAP, 1, m_format, size, size);
691
692		for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
693			glu::texSubImage2D(renderCtx, glu::getGLCubeFace(tcu::CubeFace(faceNdx)), 0, 0, 0, texData.getLevelFace(0, tcu::CubeFace(faceNdx)));
694
695		GLU_EXPECT_NO_ERROR(gl.getError(), "Uploading texture data failed");
696
697		gl.bindRenderbuffer(GL_RENDERBUFFER, *colorBuf);
698		gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, renderWidth, renderHeight);
699
700		gl.bindFramebuffer(GL_FRAMEBUFFER, *fbo);
701		gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, *colorBuf);
702		checkFramebufferStatus(gl);
703
704		blitStencilToColorCube(renderCtx, *depthStencilTex, &texCoord[0], renderWidth, renderHeight);
705		glu::readPixels(renderCtx, 0, 0, result);
706
707		{
708			using namespace gls::TextureTestUtil;
709
710			tcu::TextureCube		redTex			(TextureFormat(TextureFormat::R, TextureFormat::UNORM_INT8), size);
711			const ReferenceParams	sampleParams	(TEXTURETYPE_CUBE, tcu::Sampler(tcu::Sampler::CLAMP_TO_EDGE,
712																					tcu::Sampler::CLAMP_TO_EDGE,
713																					tcu::Sampler::CLAMP_TO_EDGE,
714																					tcu::Sampler::NEAREST,
715																					tcu::Sampler::NEAREST));
716			tcu::LookupPrecision	lookupPrec;
717			tcu::LodPrecision		lodPrec;
718			bool					compareOk;
719
720			lookupPrec.colorMask		= tcu::BVec4(true, true, true, true);
721			lookupPrec.colorThreshold	= tcu::computeFixedPointThreshold(IVec4(8, 8, 8, 8));
722			lookupPrec.coordBits		= tcu::IVec3(22, 22, 22);
723			lookupPrec.uvwBits			= tcu::IVec3(5, 5, 0);
724			lodPrec.lodBits				= 7;
725			lodPrec.derivateBits		= 16;
726
727			stencilToUnorm8(texData, redTex);
728
729			compareOk = verifyTextureResult(m_testCtx, result, redTex, &texCoord[0], sampleParams, lookupPrec, lodPrec, tcu::PixelFormat(8, 8, 8, 8));
730
731			m_testCtx.setTestResult(compareOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
732									compareOk ? "Pass"				: "Image comparison failed");
733		}
734
735		return STOP;
736	}
737
738private:
739	const deUint32 m_format;
740};
741
742class RenderTex2DCase : public TestCase
743{
744public:
745	RenderTex2DCase (Context& context, const char* name, deUint32 format)
746		: TestCase	(context, name, glu::getPixelFormatName(format))
747		, m_format	(format)
748	{
749	}
750
751	IterateResult iterate (void)
752	{
753		const glu::RenderContext&	renderCtx		= m_context.getRenderContext();
754		const glw::Functions&		gl				= renderCtx.getFunctions();
755		const int					width			= 117;
756		const int					height			= 193;
757		glu::Framebuffer			fbo				(renderCtx);
758		glu::Renderbuffer			colorBuf		(renderCtx);
759		glu::Texture				depthStencilTex	(renderCtx);
760		TextureLevel				result			(TextureFormat(TextureFormat::RGBA, TextureFormat::UNSIGNED_INT32), width, height);
761		TextureLevel				reference		(TextureFormat(TextureFormat::S, TextureFormat::UNSIGNED_INT8), width, height);
762
763		checkDepthStencilFormatSupport(m_context.getContextInfo(), m_format);
764
765		gl.bindRenderbuffer(GL_RENDERBUFFER, *colorBuf);
766		gl.renderbufferStorage(GL_RENDERBUFFER, GL_R32UI, width, height);
767
768		gl.bindTexture(GL_TEXTURE_2D, *depthStencilTex);
769		gl.texStorage2D(GL_TEXTURE_2D, 1, m_format, width, height);
770
771		gl.bindFramebuffer(GL_FRAMEBUFFER, *fbo);
772		gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, *colorBuf);
773		gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, *depthStencilTex, 0);
774		checkFramebufferStatus(gl);
775
776		drawTestPattern(renderCtx, width, height);
777
778		gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
779		checkFramebufferStatus(gl);
780
781		blitStencilToColor2D(renderCtx, *depthStencilTex, width, height);
782		glu::readPixels(renderCtx, 0, 0, result.getAccess());
783
784		renderTestPatternReference(reference);
785
786		{
787			const bool compareOk = compareStencilToRed(m_testCtx.getLog(), reference, result);
788			m_testCtx.setTestResult(compareOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
789									compareOk ? "Pass"				: "Image comparison failed");
790		}
791
792		return STOP;
793	}
794
795private:
796	const deUint32 m_format;
797};
798
799class ClearTex2DCase : public TestCase
800{
801public:
802	ClearTex2DCase (Context& context, const char* name, deUint32 format)
803		: TestCase	(context, name, glu::getPixelFormatName(format))
804		, m_format	(format)
805	{
806	}
807
808	IterateResult iterate (void)
809	{
810		const glu::RenderContext&	renderCtx		= m_context.getRenderContext();
811		const glw::Functions&		gl				= renderCtx.getFunctions();
812		const int					width			= 125;
813		const int					height			= 117;
814		const int					cellSize		= 8;
815		glu::Framebuffer			fbo				(renderCtx);
816		glu::Renderbuffer			colorBuf		(renderCtx);
817		glu::Texture				depthStencilTex	(renderCtx);
818		TextureLevel				result			(TextureFormat(TextureFormat::RGBA, TextureFormat::UNSIGNED_INT32), width, height);
819		TextureLevel				reference		(TextureFormat(TextureFormat::S, TextureFormat::UNSIGNED_INT8), width, height);
820
821		checkDepthStencilFormatSupport(m_context.getContextInfo(), m_format);
822
823		gl.bindRenderbuffer(GL_RENDERBUFFER, *colorBuf);
824		gl.renderbufferStorage(GL_RENDERBUFFER, GL_R32UI, width, height);
825
826		gl.bindTexture(GL_TEXTURE_2D, *depthStencilTex);
827		gl.texStorage2D(GL_TEXTURE_2D, 1, m_format, width, height);
828
829		gl.bindFramebuffer(GL_FRAMEBUFFER, *fbo);
830		gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, *colorBuf);
831		gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, *depthStencilTex, 0);
832		checkFramebufferStatus(gl);
833
834		gl.enable(GL_SCISSOR_TEST);
835
836		for (int y = 0; y < height; y += cellSize)
837		{
838			for (int x = 0; x < width; x += cellSize)
839			{
840				const int		clearW		= de::min(cellSize, width-x);
841				const int		clearH		= de::min(cellSize, height-y);
842				const int		stencil		= int((deInt32Hash(x) ^ deInt32Hash(y)) & 0xff);
843
844				gl.clearStencil(stencil);
845				gl.scissor(x, y, clearW, clearH);
846				gl.clear(GL_STENCIL_BUFFER_BIT);
847
848				tcu::clear(tcu::getSubregion(reference.getAccess(), x, y, clearW, clearH), IVec4(0, 0, 0, stencil));
849			}
850		}
851
852		gl.disable(GL_SCISSOR_TEST);
853
854		gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
855		checkFramebufferStatus(gl);
856
857		blitStencilToColor2D(renderCtx, *depthStencilTex, width, height);
858		glu::readPixels(renderCtx, 0, 0, result.getAccess());
859
860		{
861			const bool compareOk = compareStencilToRed(m_testCtx.getLog(), reference, result);
862			m_testCtx.setTestResult(compareOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
863									compareOk ? "Pass"				: "Image comparison failed");
864		}
865
866		return STOP;
867	}
868
869private:
870	const deUint32 m_format;
871};
872
873class CompareModeCase : public TestCase
874{
875public:
876	CompareModeCase (Context& context, const char* name, deUint32 format)
877		: TestCase	(context, name, glu::getPixelFormatName(format))
878		, m_format	(format)
879	{
880	}
881
882	IterateResult iterate (void)
883	{
884		const glu::RenderContext&	renderCtx			= m_context.getRenderContext();
885		const glw::Functions&		gl					= renderCtx.getFunctions();
886		const int					width				= 64;
887		const int					height				= 64;
888		glu::Framebuffer			fbo					(renderCtx);
889		glu::Renderbuffer			colorBuf			(renderCtx);
890		glu::Texture				depthStencilTex		(renderCtx);
891		TextureLevel				uploadLevel			(glu::mapGLInternalFormat(m_format), width, height);
892		TextureLevel				readLevel			(TextureFormat(TextureFormat::RGBA, TextureFormat::UNSIGNED_INT32), width, height);
893		TextureLevel				stencilOnlyLevel	(TextureFormat(TextureFormat::S, TextureFormat::UNSIGNED_INT8), width, height);
894
895		checkDepthStencilFormatSupport(m_context.getContextInfo(), m_format);
896
897		m_testCtx.getLog() << TestLog::Message << "NOTE: Texture compare mode has no effect when reading stencil values." << TestLog::EndMessage;
898
899		renderTestPatternReference(uploadLevel);
900		renderTestPatternReference(stencilOnlyLevel);
901
902		gl.bindTexture(GL_TEXTURE_2D, *depthStencilTex);
903		gl.texStorage2D(GL_TEXTURE_2D, 1, m_format, width, height);
904		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
905		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
906		glu::texSubImage2D(renderCtx, GL_TEXTURE_2D, 0, 0, 0, uploadLevel);
907		GLU_EXPECT_NO_ERROR(gl.getError(), "Uploading texture data failed");
908
909		gl.bindRenderbuffer(GL_RENDERBUFFER, *colorBuf);
910		gl.renderbufferStorage(GL_RENDERBUFFER, GL_R32UI, width, height);
911
912		gl.bindFramebuffer(GL_FRAMEBUFFER, *fbo);
913		gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, *colorBuf);
914		checkFramebufferStatus(gl);
915
916		blitStencilToColor2D(renderCtx, *depthStencilTex, width, height);
917		glu::readPixels(renderCtx, 0, 0, readLevel);
918
919		{
920			const bool compareOk = compareStencilToRed(m_testCtx.getLog(), stencilOnlyLevel, readLevel);
921			m_testCtx.setTestResult(compareOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
922									compareOk ? "Pass"				: "Image comparison failed");
923		}
924
925		return STOP;
926	}
927
928private:
929	const deUint32 m_format;
930};
931
932class BaseLevelCase : public TestCase
933{
934public:
935	BaseLevelCase (Context& context, const char* name, deUint32 format)
936		: TestCase	(context, name, glu::getPixelFormatName(format))
937		, m_format	(format)
938	{
939	}
940
941	IterateResult iterate (void)
942	{
943		const glu::RenderContext&	renderCtx			= m_context.getRenderContext();
944		const glw::Functions&		gl					= renderCtx.getFunctions();
945		const int					width				= 128;
946		const int					height				= 128;
947		const int					levelNdx			= 2;
948		const int					levelWidth			= width>>levelNdx;
949		const int					levelHeight			= height>>levelNdx;
950		glu::Framebuffer			fbo					(renderCtx);
951		glu::Renderbuffer			colorBuf			(renderCtx);
952		glu::Texture				depthStencilTex		(renderCtx);
953		TextureLevel				uploadLevel			(glu::mapGLInternalFormat(m_format), levelWidth, levelHeight);
954		TextureLevel				readLevel			(TextureFormat(TextureFormat::RGBA, TextureFormat::UNSIGNED_INT32), levelWidth, levelHeight);
955		TextureLevel				stencilOnlyLevel	(TextureFormat(TextureFormat::S, TextureFormat::UNSIGNED_INT8), levelWidth, levelHeight);
956
957		checkDepthStencilFormatSupport(m_context.getContextInfo(), m_format);
958
959		m_testCtx.getLog() << TestLog::Message << "GL_TEXTURE_BASE_LEVEL = " << levelNdx << TestLog::EndMessage;
960
961		renderTestPatternReference(uploadLevel);
962		renderTestPatternReference(stencilOnlyLevel);
963
964		gl.bindTexture(GL_TEXTURE_2D, *depthStencilTex);
965		gl.texStorage2D(GL_TEXTURE_2D, deLog2Floor32(de::max(width, height))+1, m_format, width, height);
966		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, levelNdx);
967		glu::texSubImage2D(renderCtx, GL_TEXTURE_2D, levelNdx, 0, 0, uploadLevel);
968		GLU_EXPECT_NO_ERROR(gl.getError(), "Uploading texture data failed");
969
970		gl.bindRenderbuffer(GL_RENDERBUFFER, *colorBuf);
971		gl.renderbufferStorage(GL_RENDERBUFFER, GL_R32UI, levelWidth, levelHeight);
972
973		gl.bindFramebuffer(GL_FRAMEBUFFER, *fbo);
974		gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, *colorBuf);
975		checkFramebufferStatus(gl);
976
977		blitStencilToColor2D(renderCtx, *depthStencilTex, levelWidth, levelHeight);
978		glu::readPixels(renderCtx, 0, 0, readLevel);
979
980		{
981			const bool compareOk = compareStencilToRed(m_testCtx.getLog(), stencilOnlyLevel, readLevel);
982			m_testCtx.setTestResult(compareOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
983									compareOk ? "Pass"				: "Image comparison failed");
984		}
985
986		return STOP;
987	}
988
989private:
990	const deUint32 m_format;
991};
992
993} // anonymous
994
995StencilTexturingTests::StencilTexturingTests (Context& context)
996	: TestCaseGroup(context, "stencil_texturing", "Stencil texturing tests")
997{
998}
999
1000StencilTexturingTests::~StencilTexturingTests (void)
1001{
1002}
1003
1004void StencilTexturingTests::init (void)
1005{
1006	// .format
1007	{
1008		tcu::TestCaseGroup* const formatGroup = new tcu::TestCaseGroup(m_testCtx, "format", "Formats");
1009		addChild(formatGroup);
1010
1011		formatGroup->addChild(new UploadTex2DCase		(m_context, "depth32f_stencil8_2d",			GL_DEPTH32F_STENCIL8));
1012		formatGroup->addChild(new UploadTex2DArrayCase	(m_context, "depth32f_stencil8_2d_array",	GL_DEPTH32F_STENCIL8));
1013		formatGroup->addChild(new UploadTexCubeCase		(m_context, "depth32f_stencil8_cube",		GL_DEPTH32F_STENCIL8));
1014		formatGroup->addChild(new UploadTex2DCase		(m_context, "depth24_stencil8_2d",			GL_DEPTH24_STENCIL8));
1015		formatGroup->addChild(new UploadTex2DArrayCase	(m_context, "depth24_stencil8_2d_array",	GL_DEPTH24_STENCIL8));
1016		formatGroup->addChild(new UploadTexCubeCase		(m_context, "depth24_stencil8_cube",		GL_DEPTH24_STENCIL8));
1017
1018		// OES_texture_stencil8
1019		formatGroup->addChild(new UploadTex2DCase		(m_context, "stencil_index8_2d",			GL_STENCIL_INDEX8));
1020		formatGroup->addChild(new UploadTex2DArrayCase	(m_context, "stencil_index8_2d_array",		GL_STENCIL_INDEX8));
1021		formatGroup->addChild(new UploadTexCubeCase		(m_context, "stencil_index8_cube",			GL_STENCIL_INDEX8));
1022	}
1023
1024	// .render
1025	{
1026		tcu::TestCaseGroup* const readRenderGroup = new tcu::TestCaseGroup(m_testCtx, "render", "Read rendered stencil values");
1027		addChild(readRenderGroup);
1028
1029		readRenderGroup->addChild(new ClearTex2DCase	(m_context, "depth32f_stencil8_clear",	GL_DEPTH32F_STENCIL8));
1030		readRenderGroup->addChild(new RenderTex2DCase	(m_context, "depth32f_stencil8_draw",	GL_DEPTH32F_STENCIL8));
1031		readRenderGroup->addChild(new ClearTex2DCase	(m_context, "depth24_stencil8_clear",	GL_DEPTH24_STENCIL8));
1032		readRenderGroup->addChild(new RenderTex2DCase	(m_context, "depth24_stencil8_draw",	GL_DEPTH24_STENCIL8));
1033	}
1034
1035	// .misc
1036	{
1037		tcu::TestCaseGroup* const miscGroup = new tcu::TestCaseGroup(m_testCtx, "misc", "Misc cases");
1038		addChild(miscGroup);
1039
1040		miscGroup->addChild(new CompareModeCase	(m_context, "compare_mode_effect",	GL_DEPTH24_STENCIL8));
1041		miscGroup->addChild(new BaseLevelCase	(m_context, "base_level",			GL_DEPTH24_STENCIL8));
1042	}
1043}
1044
1045} // Functional
1046} // gles31
1047} // deqp
1048