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