1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.0 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 Buffer Object Query tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es3fBufferObjectQueryTests.hpp"
25#include "glsStateQueryUtil.hpp"
26#include "es3fApiCase.hpp"
27#include "gluRenderContext.hpp"
28#include "glwEnums.hpp"
29#include "glwFunctions.hpp"
30#include "deRandom.hpp"
31#include "deMath.h"
32
33#include <limits>
34
35using namespace glw; // GLint and other GL types
36using deqp::gls::StateQueryUtil::StateQueryMemoryWriteGuard;
37
38
39namespace deqp
40{
41namespace gles3
42{
43namespace Functional
44{
45namespace BufferParamVerifiers
46{
47
48void checkIntEquals (tcu::TestContext& testCtx, GLint got, GLint expected)
49{
50	using tcu::TestLog;
51
52	if (got != expected)
53	{
54		testCtx.getLog() << TestLog::Message << "// ERROR: Expected " << expected << "; got " << got << TestLog::EndMessage;
55		if (testCtx.getTestResult() == QP_TEST_RESULT_PASS)
56			testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid value");
57	}
58}
59
60void checkPointerEquals (tcu::TestContext& testCtx, const void* got, const void* expected)
61{
62	using tcu::TestLog;
63
64	if (got != expected)
65	{
66		testCtx.getLog() << TestLog::Message << "// ERROR: Expected " << expected << "; got " << got << TestLog::EndMessage;
67		if (testCtx.getTestResult() == QP_TEST_RESULT_PASS)
68			testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid value");
69	}
70}
71
72class BufferParamVerifier : protected glu::CallLogWrapper
73{
74public:
75						BufferParamVerifier		(const glw::Functions& gl, tcu::TestLog& log, const char* testNamePostfix);
76	virtual				~BufferParamVerifier	(); // make GCC happy
77
78	const char*			getTestNamePostfix		(void) const;
79
80	virtual void		verifyInteger			(tcu::TestContext& testCtx, GLenum target, GLenum name, GLint reference)	= DE_NULL;
81	virtual void		verifyInteger64			(tcu::TestContext& testCtx, GLenum target, GLenum name, GLint64 reference)	= DE_NULL;
82private:
83	const char*	const	m_testNamePostfix;
84};
85
86BufferParamVerifier::BufferParamVerifier (const glw::Functions& gl, tcu::TestLog& log, const char* testNamePostfix)
87	: glu::CallLogWrapper	(gl, log)
88	, m_testNamePostfix		(testNamePostfix)
89{
90	enableLogging(true);
91}
92
93BufferParamVerifier::~BufferParamVerifier ()
94{
95}
96
97const char* BufferParamVerifier::getTestNamePostfix (void) const
98{
99	return m_testNamePostfix;
100}
101
102class GetBufferParameterIVerifier : public BufferParamVerifier
103{
104public:
105			GetBufferParameterIVerifier	(const glw::Functions& gl, tcu::TestLog& log);
106
107	void	verifyInteger								(tcu::TestContext& testCtx, GLenum target, GLenum name, GLint reference);
108	void	verifyInteger64								(tcu::TestContext& testCtx, GLenum target, GLenum name, GLint64 reference);
109};
110
111GetBufferParameterIVerifier::GetBufferParameterIVerifier (const glw::Functions& gl, tcu::TestLog& log)
112	: BufferParamVerifier(gl, log, "_getbufferparameteri")
113{
114}
115
116void GetBufferParameterIVerifier::verifyInteger (tcu::TestContext& testCtx, GLenum target, GLenum name, GLint reference)
117{
118	using tcu::TestLog;
119
120	StateQueryMemoryWriteGuard<GLint> state;
121	glGetBufferParameteriv(target, name, &state);
122
123	if (!state.verifyValidity(testCtx))
124		return;
125
126	if (state != reference)
127	{
128		testCtx.getLog() << TestLog::Message << "// ERROR: expected " << reference << "; got " << state << TestLog::EndMessage;
129
130		if (testCtx.getTestResult() == QP_TEST_RESULT_PASS)
131			testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid value");
132	}
133}
134
135void GetBufferParameterIVerifier::verifyInteger64 (tcu::TestContext& testCtx, GLenum target, GLenum name, GLint64 reference)
136{
137	using tcu::TestLog;
138
139	StateQueryMemoryWriteGuard<GLint> state;
140	glGetBufferParameteriv(target, name, &state);
141
142	if (!state.verifyValidity(testCtx))
143		return;
144
145	// check that the converted value would be in the correct range, otherwise checking wont tell us anything
146	if (!de::inRange(reference, (GLint64)std::numeric_limits<GLint>::min(), (GLint64)std::numeric_limits<GLint>::max()))
147		return;
148
149	if (state != reference)
150	{
151		testCtx.getLog() << TestLog::Message << "// ERROR: expected " << reference << "; got " << state << TestLog::EndMessage;
152
153		if (testCtx.getTestResult() == QP_TEST_RESULT_PASS)
154			testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid value");
155	}
156}
157
158class GetBufferParameterI64Verifier : public BufferParamVerifier
159{
160public:
161			GetBufferParameterI64Verifier	(const glw::Functions& gl, tcu::TestLog& log);
162
163	void	verifyInteger					(tcu::TestContext& testCtx, GLenum target, GLenum name, GLint reference);
164	void	verifyInteger64					(tcu::TestContext& testCtx, GLenum target, GLenum name, GLint64 reference);
165};
166
167GetBufferParameterI64Verifier::GetBufferParameterI64Verifier (const glw::Functions& gl, tcu::TestLog& log)
168	: BufferParamVerifier(gl, log, "_getbufferparameteri64")
169{
170}
171
172void GetBufferParameterI64Verifier::verifyInteger (tcu::TestContext& testCtx, GLenum target, GLenum name, GLint reference)
173{
174	using tcu::TestLog;
175
176	StateQueryMemoryWriteGuard<GLint64> state;
177	glGetBufferParameteri64v(target, name, &state);
178
179	if (!state.verifyValidity(testCtx))
180		return;
181
182	if (state != reference)
183	{
184		testCtx.getLog() << TestLog::Message << "// ERROR: expected " << reference << "; got " << state << TestLog::EndMessage;
185
186		if (testCtx.getTestResult() == QP_TEST_RESULT_PASS)
187			testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid value");
188	}
189}
190
191void GetBufferParameterI64Verifier::verifyInteger64 (tcu::TestContext& testCtx, GLenum target, GLenum name, GLint64 reference)
192{
193	using tcu::TestLog;
194
195	StateQueryMemoryWriteGuard<GLint64> state;
196	glGetBufferParameteri64v(target, name, &state);
197
198	if (!state.verifyValidity(testCtx))
199		return;
200
201	if (state != reference)
202	{
203		testCtx.getLog() << TestLog::Message << "// ERROR: expected " << reference << "; got " << state << TestLog::EndMessage;
204
205		if (testCtx.getTestResult() == QP_TEST_RESULT_PASS)
206			testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid value");
207	}
208}
209
210
211} // BufferParamVerifiers
212
213namespace
214{
215
216using namespace BufferParamVerifiers;
217
218// Tests
219
220class BufferCase : public ApiCase
221{
222public:
223	BufferCase (Context& context, BufferParamVerifier* verifier, const char* name, const char* description)
224		: ApiCase			(context, name, description)
225		, m_bufferTarget	(0)
226		, m_verifier		(verifier)
227		, m_testAllTargets	(false)
228	{
229	}
230
231	virtual void testBuffer (void) = DE_NULL;
232
233	void test (void)
234	{
235		const GLenum bufferTargets[] =
236		{
237			GL_ARRAY_BUFFER, GL_COPY_READ_BUFFER,
238			GL_TRANSFORM_FEEDBACK_BUFFER, GL_UNIFORM_BUFFER,
239
240			GL_COPY_WRITE_BUFFER, GL_ELEMENT_ARRAY_BUFFER,
241			GL_PIXEL_PACK_BUFFER, GL_PIXEL_UNPACK_BUFFER
242		};
243
244		// most test need only to be run with a subset of targets
245		const int targets = m_testAllTargets ? DE_LENGTH_OF_ARRAY(bufferTargets) : 4;
246
247		for (int ndx = 0; ndx < targets; ++ndx)
248		{
249			m_bufferTarget = bufferTargets[ndx];
250
251			GLuint bufferId = 0;
252			glGenBuffers(1, &bufferId);
253			glBindBuffer(m_bufferTarget, bufferId);
254			expectError(GL_NO_ERROR);
255
256			testBuffer();
257
258			glDeleteBuffers(1, &bufferId);
259			expectError(GL_NO_ERROR);
260		}
261	}
262
263protected:
264	GLenum					m_bufferTarget;
265	BufferParamVerifier*	m_verifier;
266	bool					m_testAllTargets;
267};
268
269class BufferSizeCase : public BufferCase
270{
271public:
272	BufferSizeCase (Context& context, BufferParamVerifier* verifier, const char* name, const char* description)
273		: BufferCase(context, verifier, name, description)
274	{
275		m_testAllTargets = true;
276	}
277
278	void testBuffer (void)
279	{
280		de::Random rnd(0xabcdef);
281
282		m_verifier->verifyInteger64(m_testCtx, m_bufferTarget, GL_BUFFER_SIZE, 0);
283
284		const int numIterations = 16;
285		for (int i = 0; i < numIterations; ++i)
286		{
287			const GLint len = rnd.getInt(0, 1024);
288			glBufferData(m_bufferTarget, len, DE_NULL, GL_STREAM_DRAW);
289			expectError(GL_NO_ERROR);
290
291			m_verifier->verifyInteger64(m_testCtx, m_bufferTarget, GL_BUFFER_SIZE, len);
292			expectError(GL_NO_ERROR);
293		}
294	}
295};
296
297class BufferUsageCase : public BufferCase
298{
299public:
300	BufferUsageCase (Context& context, BufferParamVerifier* verifier, const char* name, const char* description)
301		: BufferCase(context, verifier, name, description)
302	{
303	}
304
305	void testBuffer (void)
306	{
307		m_verifier->verifyInteger(m_testCtx, m_bufferTarget, GL_BUFFER_USAGE, GL_STATIC_DRAW);
308
309		const GLenum usages[] =
310		{
311			GL_STREAM_DRAW, GL_STREAM_READ,
312			GL_STREAM_COPY, GL_STATIC_DRAW,
313			GL_STATIC_READ, GL_STATIC_COPY,
314			GL_DYNAMIC_DRAW, GL_DYNAMIC_READ,
315			GL_DYNAMIC_COPY
316		};
317
318		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(usages); ++ndx)
319		{
320			glBufferData(m_bufferTarget, 16, DE_NULL, usages[ndx]);
321			expectError(GL_NO_ERROR);
322
323			m_verifier->verifyInteger(m_testCtx, m_bufferTarget, GL_BUFFER_USAGE, usages[ndx]);
324			expectError(GL_NO_ERROR);
325		}
326	}
327};
328
329class BufferAccessFlagsCase : public BufferCase
330{
331public:
332	BufferAccessFlagsCase (Context& context, BufferParamVerifier* verifier, const char* name, const char* description)
333		: BufferCase(context, verifier, name, description)
334	{
335	}
336
337	void testBuffer (void)
338	{
339		m_verifier->verifyInteger(m_testCtx, m_bufferTarget, GL_BUFFER_ACCESS_FLAGS, 0);
340
341		const GLenum accessFlags[] =
342		{
343			GL_MAP_READ_BIT,
344
345			GL_MAP_WRITE_BIT,
346			GL_MAP_WRITE_BIT																	| GL_MAP_INVALIDATE_RANGE_BIT,
347			GL_MAP_WRITE_BIT																									| GL_MAP_INVALIDATE_BUFFER_BIT,
348			GL_MAP_WRITE_BIT																	| GL_MAP_INVALIDATE_RANGE_BIT	| GL_MAP_INVALIDATE_BUFFER_BIT,
349
350			GL_MAP_WRITE_BIT									| GL_MAP_FLUSH_EXPLICIT_BIT,
351			GL_MAP_WRITE_BIT									| GL_MAP_FLUSH_EXPLICIT_BIT		| GL_MAP_INVALIDATE_RANGE_BIT,
352			GL_MAP_WRITE_BIT									| GL_MAP_FLUSH_EXPLICIT_BIT										| GL_MAP_INVALIDATE_BUFFER_BIT,
353			GL_MAP_WRITE_BIT									| GL_MAP_FLUSH_EXPLICIT_BIT		| GL_MAP_INVALIDATE_RANGE_BIT	| GL_MAP_INVALIDATE_BUFFER_BIT,
354
355			GL_MAP_WRITE_BIT	| GL_MAP_UNSYNCHRONIZED_BIT,
356			GL_MAP_WRITE_BIT	| GL_MAP_UNSYNCHRONIZED_BIT										| GL_MAP_INVALIDATE_RANGE_BIT,
357			GL_MAP_WRITE_BIT	| GL_MAP_UNSYNCHRONIZED_BIT																		| GL_MAP_INVALIDATE_BUFFER_BIT,
358			GL_MAP_WRITE_BIT	| GL_MAP_UNSYNCHRONIZED_BIT										| GL_MAP_INVALIDATE_RANGE_BIT	| GL_MAP_INVALIDATE_BUFFER_BIT,
359
360			GL_MAP_WRITE_BIT	| GL_MAP_UNSYNCHRONIZED_BIT		| GL_MAP_FLUSH_EXPLICIT_BIT,
361			GL_MAP_WRITE_BIT	| GL_MAP_UNSYNCHRONIZED_BIT		| GL_MAP_FLUSH_EXPLICIT_BIT		| GL_MAP_INVALIDATE_RANGE_BIT,
362			GL_MAP_WRITE_BIT	| GL_MAP_UNSYNCHRONIZED_BIT		| GL_MAP_FLUSH_EXPLICIT_BIT										| GL_MAP_INVALIDATE_BUFFER_BIT,
363			GL_MAP_WRITE_BIT	| GL_MAP_UNSYNCHRONIZED_BIT		| GL_MAP_FLUSH_EXPLICIT_BIT		| GL_MAP_INVALIDATE_RANGE_BIT	| GL_MAP_INVALIDATE_BUFFER_BIT,
364
365		};
366
367		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(accessFlags); ++ndx)
368		{
369			glBufferData(m_bufferTarget, 16, DE_NULL, GL_DYNAMIC_COPY);
370			glMapBufferRange(m_bufferTarget, 0, 16, accessFlags[ndx]);
371			expectError(GL_NO_ERROR);
372
373			m_verifier->verifyInteger(m_testCtx, m_bufferTarget, GL_BUFFER_ACCESS_FLAGS, accessFlags[ndx]);
374			expectError(GL_NO_ERROR);
375
376			glUnmapBuffer(m_bufferTarget);
377			expectError(GL_NO_ERROR);
378		}
379	}
380};
381
382class BufferMappedCase : public BufferCase
383{
384public:
385	BufferMappedCase (Context& context, BufferParamVerifier* verifier, const char* name, const char* description)
386		: BufferCase(context, verifier, name, description)
387	{
388	}
389
390	void testBuffer (void)
391	{
392		m_verifier->verifyInteger(m_testCtx, m_bufferTarget, GL_BUFFER_MAPPED, GL_FALSE);
393
394		glBufferData(m_bufferTarget, 16, DE_NULL, GL_DYNAMIC_COPY);
395		glMapBufferRange(m_bufferTarget, 0, 16, GL_MAP_WRITE_BIT);
396		expectError(GL_NO_ERROR);
397
398		m_verifier->verifyInteger(m_testCtx, m_bufferTarget, GL_BUFFER_MAPPED, GL_TRUE);
399		expectError(GL_NO_ERROR);
400
401		glUnmapBuffer(m_bufferTarget);
402		expectError(GL_NO_ERROR);
403	}
404};
405
406class BufferOffsetLengthCase : public BufferCase
407{
408public:
409	BufferOffsetLengthCase (Context& context, BufferParamVerifier* verifier, const char* name, const char* description)
410		: BufferCase(context, verifier, name, description)
411	{
412	}
413
414	void testBuffer (void)
415	{
416		m_verifier->verifyInteger(m_testCtx, m_bufferTarget, GL_BUFFER_MAP_OFFSET, 0);
417		m_verifier->verifyInteger(m_testCtx, m_bufferTarget, GL_BUFFER_MAP_LENGTH, 0);
418
419		glBufferData(m_bufferTarget, 16, DE_NULL, GL_DYNAMIC_COPY);
420
421		const struct BufferRange
422		{
423			int offset;
424			int length;
425		} ranges[] =
426		{
427			{ 0, 16 },
428			{ 4, 12 },
429			{ 0, 12 },
430			{ 8,  8 },
431		};
432
433		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(ranges); ++ndx)
434		{
435			glMapBufferRange(m_bufferTarget, ranges[ndx].offset, ranges[ndx].length, GL_MAP_WRITE_BIT);
436			expectError(GL_NO_ERROR);
437
438			m_verifier->verifyInteger(m_testCtx, m_bufferTarget, GL_BUFFER_MAP_OFFSET, ranges[ndx].offset);
439			m_verifier->verifyInteger(m_testCtx, m_bufferTarget, GL_BUFFER_MAP_LENGTH, ranges[ndx].length);
440			expectError(GL_NO_ERROR);
441
442			glUnmapBuffer(m_bufferTarget);
443			expectError(GL_NO_ERROR);
444		}
445	}
446};
447
448class BufferPointerCase : public ApiCase
449{
450public:
451	BufferPointerCase (Context& context, const char* name, const char* description)
452		: ApiCase(context, name, description)
453	{
454	}
455
456	void test (void)
457	{
458		GLuint bufferId = 0;
459		glGenBuffers(1, &bufferId);
460		glBindBuffer(GL_ARRAY_BUFFER, bufferId);
461		expectError(GL_NO_ERROR);
462
463		StateQueryMemoryWriteGuard<GLvoid*> initialState;
464		glGetBufferPointerv(GL_ARRAY_BUFFER, GL_BUFFER_MAP_POINTER, &initialState);
465		initialState.verifyValidity(m_testCtx);
466		checkPointerEquals(m_testCtx, initialState, 0);
467
468		glBufferData(GL_ARRAY_BUFFER, 8, DE_NULL, GL_DYNAMIC_COPY);
469		GLvoid* mapPointer = glMapBufferRange(GL_ARRAY_BUFFER, 0, 8, GL_MAP_READ_BIT);
470		expectError(GL_NO_ERROR);
471
472		StateQueryMemoryWriteGuard<GLvoid*> mapPointerState;
473		glGetBufferPointerv(GL_ARRAY_BUFFER, GL_BUFFER_MAP_POINTER, &mapPointerState);
474		mapPointerState.verifyValidity(m_testCtx);
475		checkPointerEquals(m_testCtx, mapPointerState, mapPointer);
476
477		glDeleteBuffers(1, &bufferId);
478		expectError(GL_NO_ERROR);
479	}
480};
481
482} // anonymous
483
484#define FOR_EACH_VERIFIER(VERIFIERS, CODE_BLOCK)												\
485	for (int _verifierNdx = 0; _verifierNdx < DE_LENGTH_OF_ARRAY(VERIFIERS); _verifierNdx++)	\
486	{																							\
487		BufferParamVerifier* verifier = VERIFIERS[_verifierNdx];								\
488		CODE_BLOCK;																				\
489	}
490
491BufferObjectQueryTests::BufferObjectQueryTests (Context& context)
492	: TestCaseGroup		(context, "buffer_object", "Buffer Object Query tests")
493	, m_verifierInt		(DE_NULL)
494	, m_verifierInt64	(DE_NULL)
495{
496}
497
498BufferObjectQueryTests::~BufferObjectQueryTests (void)
499{
500	deinit();
501}
502
503void BufferObjectQueryTests::init (void)
504{
505	using namespace BufferParamVerifiers;
506
507	DE_ASSERT(m_verifierInt == DE_NULL);
508	DE_ASSERT(m_verifierInt64 == DE_NULL);
509
510	m_verifierInt		= new GetBufferParameterIVerifier	(m_context.getRenderContext().getFunctions(), m_context.getTestContext().getLog());
511	m_verifierInt64		= new GetBufferParameterI64Verifier	(m_context.getRenderContext().getFunctions(), m_context.getTestContext().getLog());
512	BufferParamVerifier* verifiers[] = {m_verifierInt, m_verifierInt64};
513
514	FOR_EACH_VERIFIER(verifiers, addChild(new BufferSizeCase		(m_context, verifier,	(std::string("buffer_size")				+ verifier->getTestNamePostfix()).c_str(), "BUFFER_SIZE")));
515	FOR_EACH_VERIFIER(verifiers, addChild(new BufferUsageCase		(m_context, verifier,	(std::string("buffer_usage")			+ verifier->getTestNamePostfix()).c_str(), "BUFFER_USAGE")));
516	FOR_EACH_VERIFIER(verifiers, addChild(new BufferAccessFlagsCase	(m_context, verifier,	(std::string("buffer_access_flags")		+ verifier->getTestNamePostfix()).c_str(), "BUFFER_ACCESS_FLAGS")));
517	FOR_EACH_VERIFIER(verifiers, addChild(new BufferMappedCase		(m_context, verifier,	(std::string("buffer_mapped")			+ verifier->getTestNamePostfix()).c_str(), "BUFFER_MAPPED")));
518	FOR_EACH_VERIFIER(verifiers, addChild(new BufferOffsetLengthCase(m_context, verifier,	(std::string("buffer_map_offset_length")+ verifier->getTestNamePostfix()).c_str(), "BUFFER_MAP_OFFSET and BUFFER_MAP_LENGTH")));
519
520	addChild(new BufferPointerCase(m_context, "buffer_pointer", "GetBufferPointerv"));
521}
522
523void BufferObjectQueryTests::deinit (void)
524{
525	if (m_verifierInt)
526	{
527		delete m_verifierInt;
528		m_verifierInt = NULL;
529	}
530	if (m_verifierInt64)
531	{
532		delete m_verifierInt64;
533		m_verifierInt64 = NULL;
534	}
535}
536
537} // Functional
538} // gles3
539} // deqp
540