1/*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
4 *
5 * Copyright (c) 2021 Google Inc.
6 * Copyright (c) 2021 The Khronos Group Inc.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 *      http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 */ /*!
21 * \file glcTexSubImageTests.cpp
22 * \brief Texture compatibility tests
23 */ /*-------------------------------------------------------------------*/
24
25#include "glcTextureCompatibilityTests.hpp"
26
27#include "glwEnums.hpp"
28#include "glwFunctions.hpp"
29
30#include "tcuImageCompare.hpp"
31#include "tcuStringTemplate.hpp"
32#include "tcuSurface.hpp"
33#include "tcuTestLog.hpp"
34#include "tcuTextureUtil.hpp"
35
36#include "gluDefs.hpp"
37#include "gluDrawUtil.hpp"
38#include "gluPixelTransfer.hpp"
39#include "gluShaderProgram.hpp"
40#include "gluStrUtil.hpp"
41#include "gluTextureUtil.hpp"
42
43#include <map>
44#include <memory>
45#include <vector>
46
47namespace glcts
48{
49namespace
50{
51const float		vertexPositions[]	=
52{
53	-1.0f,	-1.0f,
54	1.0f,	-1.0f,
55	-1.0f,	1.0f,
56	1.0f,	1.0f,
57};
58
59const float		vertexTexCoords[]	=
60{
61	0.0f,	0.0f,
62	1.0f,	0.0f,
63	0.0f,	1.0f,
64	1.0f,	1.0f,
65};
66
67const char*		vertShader			=
68	"${VERSION}\n"
69	"in highp vec4 in_position;\n"
70	"in highp vec2 in_texCoord;\n"
71	"out highp vec2 v_texCoord;\n"
72	"void main (void)\n"
73	"{\n"
74	"	gl_Position = in_position;\n"
75	"	v_texCoord = in_texCoord;\n"
76	"}\n";
77
78const char*		fragShader			=
79	"${VERSION}\n"
80	"precision mediump float;\n"
81	"uniform sampler2D texture0;\n"
82	"in vec2 v_texCoord;\n"
83	"out vec4 color;\n"
84	"void main(void)\n"
85	"{\n"
86	"	color = texture(texture0, v_texCoord);\n"
87	"}";
88
89struct TestParameters
90{
91	std::string		testName;
92	glw::GLenum		internalFormat;
93	glw::GLenum		format;
94	glw::GLenum		testType;
95};
96
97static const TestParameters testParameters[] =
98{
99	{ "rgba4_unsigned_byte",		GL_RGBA4,				GL_RGBA,			GL_UNSIGNED_BYTE				},
100	{ "rgb5_a1_unsigned_byte",		GL_RGB5_A1,				GL_RGBA,			GL_UNSIGNED_BYTE				},
101	{ "rgb5_a1_unsigned_int_10_a2",	GL_RGB5_A1,				GL_RGBA,			GL_UNSIGNED_INT_2_10_10_10_REV	},
102	{ "r16f_float",					GL_R16F,				GL_RED,				GL_FLOAT						},
103	{ "rg16f_float",				GL_RG16F,				GL_RG,				GL_FLOAT						},
104	{ "rgb16f_float",				GL_RGB16F,				GL_RGB,				GL_FLOAT						},
105	{ "rgba16f_float",				GL_RGBA16F,				GL_RGBA,			GL_FLOAT						},
106	{ "r11f_g11f_b10f_half_float",	GL_R11F_G11F_B10F,		GL_RGB,				GL_HALF_FLOAT					},
107	{ "r11f_g11f_b10f_float",		GL_R11F_G11F_B10F,		GL_RGB,				GL_FLOAT						},
108	{ "rgb9_e5_half_float",			GL_RGB9_E5,				GL_RGB,				GL_HALF_FLOAT					},
109	{ "rgb9_e5_float",				GL_RGB9_E5,				GL_RGB,				GL_FLOAT						},
110	{ "rgb565_unsigned_byte",		GL_RGB565,				GL_RGB,				GL_UNSIGNED_BYTE				},
111	{ "depth_component16_uint",		GL_DEPTH_COMPONENT16,	GL_DEPTH_COMPONENT,	GL_UNSIGNED_INT					}
112};
113
114class SubImageFormatTest : public deqp::TestCase
115{
116public:
117	SubImageFormatTest(deqp::Context& context, const TestParameters testParam, glw::GLsizei textureSize);
118
119	virtual ~SubImageFormatTest();
120
121	virtual void			init		(void);
122	virtual void			deinit		(void);
123
124	virtual IterateResult	iterate		(void);
125
126private:
127	void setTextureParameters			(glw::GLenum target);
128	void drawTexture					(void);
129
130	void initializeProgram();
131	void setVertexBufferObjects();
132	void setVertexArrayObjects();
133
134	std::shared_ptr<glu::ShaderProgram>	m_program;
135
136	TestParameters						m_testParams;
137	glw::GLsizei						m_textureSize;
138	glw::GLuint							m_texId;
139	glw::GLuint							m_vaoId;
140	glw::GLenum							m_vboIds[2];
141};
142
143SubImageFormatTest::SubImageFormatTest	(deqp::Context& context, const TestParameters testParams, glw::GLsizei textureSize)
144	: deqp::TestCase					(context, ("texsubimage_format_" + testParams.testName).c_str(), "Pass glTexSubImage with different client format to glTexImage")
145	, m_testParams						(testParams)
146	, m_textureSize						(textureSize)
147	, m_texId							(0)
148	, m_vaoId							(0)
149	, m_vboIds							{ 0, 0 }
150{
151}
152
153SubImageFormatTest::~SubImageFormatTest()
154{
155}
156
157void SubImageFormatTest::init(void)
158{
159	initializeProgram();
160	setVertexBufferObjects();
161	setVertexArrayObjects();
162}
163
164void SubImageFormatTest::deinit(void)
165{
166	const auto& gl = m_context.getRenderContext().getFunctions();
167
168	gl.deleteTextures(1, &m_texId);
169	GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteTextures() failed");
170
171	gl.deleteBuffers(1, &m_vaoId);
172	GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers() failed");
173
174	gl.deleteBuffers(DE_LENGTH_OF_ARRAY(m_vboIds), m_vboIds);
175	GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers() failed");
176}
177
178SubImageFormatTest::IterateResult SubImageFormatTest::iterate(void)
179{
180	const auto&			gl					= m_context.getRenderContext().getFunctions();
181
182	m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
183
184	// Render buffer
185	glw::GLuint			rboId;
186	gl.genRenderbuffers(1, &rboId);
187	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenRenderbuffers() failed");
188	gl.bindRenderbuffer(GL_RENDERBUFFER, rboId);
189	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer() failed");
190	gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, m_textureSize, m_textureSize);
191	GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage() failed");
192	gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
193
194	// Frame buffer
195	glw::GLuint			fboId;
196	gl.genFramebuffers(1, &fboId);
197	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() failed");
198	gl.bindFramebuffer(GL_FRAMEBUFFER, fboId);
199	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() failed");
200	gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rboId);
201	GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferRenderbuffer() failed");
202
203	gl.viewport(0, 0, m_textureSize, m_textureSize);
204	GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() failed");
205
206	gl.disable(GL_BLEND);
207
208	gl.bindTexture(GL_TEXTURE_2D, m_texId);
209	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() failed");
210
211	gl.bindVertexArray(m_vaoId);
212	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() failed");
213
214	// Create main texture.
215	tcu::TextureFormat	refTexFormat		(glu::mapGLInternalFormat(m_testParams.internalFormat));
216	glu::TransferFormat	refTransferFormat	= glu::getTransferFormat(refTexFormat);
217	tcu::Texture2D		refTexture			(refTexFormat, m_textureSize, m_textureSize, 1);
218
219	refTexture.allocLevel(0);
220	tcu::fillWithComponentGradients(refTexture.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
221
222	// Create variables for reference sub texture.
223	tcu::TextureFormat	refTexFormatSub		= glu::mapGLInternalFormat(m_testParams.internalFormat);
224	tcu::Texture2D		refSubTexture		(refTexFormatSub, m_textureSize / 2, m_textureSize / 2, 1);
225	tcu::Surface		refSurface			(m_textureSize, m_textureSize);
226
227	refSubTexture.allocLevel(0);
228	tcu::fillWithComponentGradients(refSubTexture.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
229
230	// Upload the main texture data.
231	gl.texImage2D(GL_TEXTURE_2D, 0, m_testParams.internalFormat, m_textureSize, m_textureSize, 0, refTransferFormat.format, refTransferFormat.dataType, refTexture.getLevel(0).getDataPtr());
232	GLU_EXPECT_NO_ERROR(gl.getError(), ("gltexImage2D() failed" + glu::getTextureFormatStr(m_testParams.internalFormat).toString()).c_str());
233
234	// Update the content of a previously allocated texture with reference sub texture.
235	// Reference sub texture is using the same format and data type than main texture.
236	gl.texSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_textureSize / 2, m_textureSize / 2, refTransferFormat.format, refTransferFormat.dataType, refSubTexture.getLevel(0).getDataPtr());
237	GLU_EXPECT_NO_ERROR(gl.getError(), ("gltexSubImage2D() failed" + glu::getTextureFormatStr(m_testParams.internalFormat).toString()).c_str());
238
239	setTextureParameters(GL_TEXTURE_2D);
240
241	drawTexture();
242
243	m_context.getTestContext().getLog() << tcu::TestLog::Message << m_testParams.testName.c_str() << " ("
244		<< m_textureSize << " x " << m_textureSize << ")" << tcu::TestLog::EndMessage;
245
246	// Read rendered pixels to reference surface.
247	glu::readPixels(m_context.getRenderContext(), 0, 0, refSurface.getAccess());
248
249	// Create variables for test sub texture.
250	tcu::TextureFormat	testTexFormatSub	= glu::mapGLTransferFormat(m_testParams.format, m_testParams.testType);
251	tcu::Texture2D		testSubTexture		(testTexFormatSub, m_textureSize / 2, m_textureSize / 2, 1);
252	tcu::Surface		testSurface			(m_textureSize, m_textureSize);
253
254	testSubTexture.allocLevel(0);
255	tcu::fillWithComponentGradients(testSubTexture.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
256
257	// Upload the main texture data again.
258	gl.texImage2D(GL_TEXTURE_2D, 0, m_testParams.internalFormat, m_textureSize, m_textureSize, 0, refTransferFormat.format, refTransferFormat.dataType, refTexture.getLevel(0).getDataPtr());
259	GLU_EXPECT_NO_ERROR(gl.getError(), ("gltexImage2D() failed" + glu::getTextureFormatStr(m_testParams.internalFormat).toString()).c_str());
260
261	// Update the content of a previously allocated texture with sub texture but different data type.
262	gl.texSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_textureSize / 2, m_textureSize / 2, m_testParams.format, m_testParams.testType, testSubTexture.getLevel(0).getDataPtr());
263	GLU_EXPECT_NO_ERROR(gl.getError(), ("gltexSubImage2D() failed" + glu::getTextureFormatStr(m_testParams.internalFormat).toString()).c_str());
264
265	setTextureParameters(GL_TEXTURE_2D);
266
267	drawTexture();
268
269	// Read rendered pixels to test surface.
270	readPixels(m_context.getRenderContext(), 0, 0, testSurface.getAccess());
271
272	// Execute the comparison.
273	if (tcu::fuzzyCompare(m_testCtx.getLog(), "texsubimage_format_", "Pass glTexSubImage with different client format to glTexImage",
274		refSurface, testSurface, 0.001f, tcu::COMPARE_LOG_RESULT))
275	{
276		m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
277	}
278
279	// Cleanup
280	gl.bindTexture(GL_TEXTURE_2D, 0);
281	gl.bindFramebuffer(GL_FRAMEBUFFER, fboId);
282	gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
283	gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
284	gl.deleteFramebuffers(1, &fboId);
285
286	return IterateResult::STOP;
287}
288
289void SubImageFormatTest::setTextureParameters(glw::GLenum target)
290{
291	const auto& gl = m_context.getRenderContext().getFunctions();
292
293	gl.texParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
294	GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri() failed");
295
296	gl.texParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
297	GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri() failed");
298
299	gl.texParameteri(target, GL_TEXTURE_BASE_LEVEL, 0);
300	GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri() failed");
301
302	gl.texParameteri(target, GL_TEXTURE_MAX_LEVEL, 0);
303	GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri() failed");
304
305	gl.texParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
306	GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri() failed");
307
308	gl.texParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
309	GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri() failed");
310
311	gl.texParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
312	GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri() failed");
313}
314
315void SubImageFormatTest::drawTexture(void)
316{
317	const auto& gl = m_context.getRenderContext().getFunctions();
318
319	gl.useProgram(m_program->getProgram());
320	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed");
321
322	gl.clearColor(1.0f, 0.0f, 1.0f, 1.0f);
323	gl.clear(GL_COLOR_BUFFER_BIT);
324	GLU_EXPECT_NO_ERROR(gl.getError(), "glClear() failed");
325
326	gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
327	GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed");
328
329	gl.finish();
330}
331
332void SubImageFormatTest::setVertexBufferObjects()
333{
334	const auto& gl = m_context.getRenderContext().getFunctions();
335
336	gl.genBuffers(DE_LENGTH_OF_ARRAY(m_vboIds), m_vboIds);
337	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed");
338
339	gl.bindBuffer(GL_ARRAY_BUFFER, m_vboIds[0]);
340	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
341
342	gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW);
343	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed");
344
345	gl.bindBuffer(GL_ARRAY_BUFFER, m_vboIds[1]);
346	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
347
348	gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertexTexCoords), vertexTexCoords, GL_STATIC_DRAW);
349	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed");
350
351	gl.bindBuffer(GL_ARRAY_BUFFER, 0);
352	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
353}
354
355void SubImageFormatTest::setVertexArrayObjects()
356{
357	const auto&	gl			= m_context.getRenderContext().getFunctions();
358	const auto	program		= m_program->getProgram();
359	const auto	positionLoc	= gl.getAttribLocation(program, "in_position");
360	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetAttribLocation() failed");
361
362	const auto	texCoordLoc	= gl.getAttribLocation(program, "in_texCoord");
363	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetAttribLocation() failed");
364
365	gl.genVertexArrays(1, &m_vaoId);
366	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() failed");
367
368	gl.bindVertexArray(m_vaoId);
369	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() failed");
370
371	gl.bindBuffer(GL_ARRAY_BUFFER, m_vboIds[0]);
372	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
373
374	gl.enableVertexAttribArray(positionLoc);
375	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray() failed");
376
377	gl.vertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);
378	GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer() failed");
379
380	gl.bindBuffer(GL_ARRAY_BUFFER, m_vboIds[1]);
381	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
382
383	gl.enableVertexAttribArray(texCoordLoc);
384	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray() failed");
385
386	gl.vertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);
387	GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer() failed");
388
389	gl.bindVertexArray(0);
390	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() failed");
391}
392
393void SubImageFormatTest::initializeProgram()
394{
395	const auto&	gl				= m_context.getRenderContext().getFunctions();
396
397	gl.genTextures(1, &m_texId);
398	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() failed");
399
400	const bool	supportsES32	= glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
401	const auto	glslVersion		= glu::getGLSLVersionDeclaration(supportsES32 ? glu::GLSLVersion::GLSL_VERSION_320_ES : glu::GLSLVersion::GLSL_VERSION_310_ES);
402	const auto	args			= std::map<std::string, std::string>{ { "VERSION", glslVersion } };
403	const auto	vs				= tcu::StringTemplate(vertShader).specialize(args);
404	const auto	fs				= tcu::StringTemplate(fragShader).specialize(args);
405
406	m_program = std::make_shared<glu::ShaderProgram>(m_context.getRenderContext(),
407		glu::ProgramSources() << glu::VertexSource(vs) << glu::FragmentSource(fs));
408
409	if (!m_program->isOk())
410		throw std::runtime_error("Compiling shader program failed.");
411}
412
413} // <anonymous>
414
415TextureCompatibilityTests::TextureCompatibilityTests(deqp::Context& context)
416	: deqp::TestCaseGroup(context, "texture_compatibility", "Tests for texture format compatibility")
417{
418}
419
420TextureCompatibilityTests::~TextureCompatibilityTests(void)
421{
422}
423
424void TextureCompatibilityTests::init(void)
425{
426	for (const auto& test : testParameters)
427		addChild(new SubImageFormatTest(m_context, test, 32));
428}
429
430} // glcts
431