• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * OpenGL Conformance Test Suite
3  * -----------------------------
4  *
5  * Copyright (c) 2015-2016 The Khronos Group Inc.
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
22  */ /*-------------------------------------------------------------------*/
23 
24 /**
25  * \file  gl4cMapBufferAlignmentTests.cpp
26  * \brief Implements conformance tests for "Map Buffer Alignment" functionality.
27  */ /*-------------------------------------------------------------------*/
28 
29 #include "gl4cMapBufferAlignmentTests.hpp"
30 
31 #include "gluContextInfo.hpp"
32 #include "gluDefs.hpp"
33 #include "glwEnums.hpp"
34 #include "glwFunctions.hpp"
35 
36 #include <algorithm>
37 #include <vector>
38 
39 using namespace glw;
40 
41 namespace gl4cts
42 {
43 namespace MapBufferAlignment
44 {
45 /** Implementation of Query test, description follows:
46  *
47  * Verify that GetInteger returns at least 64 when MIN_MAP_BUFFER_ALIGNEMENT is
48  * requested.
49  **/
50 class Query : public deqp::TestCase
51 {
52 public:
53 	/* Public methods */
Query(deqp::Context & context)54 	Query(deqp::Context& context) : TestCase(context, "query", "Verifies value of MIN_MAP_BUFFER_ALIGNEMENT")
55 	{
56 		/* Nothing to be done */
57 	}
~Query()58 	virtual ~Query()
59 	{
60 		/* Nothing to be done */
61 	}
62 
63 	/** Execute test
64 	 *
65 	 * @return tcu::TestNode::STOP
66 	 **/
67 	virtual tcu::TestNode::IterateResult iterate(void);
68 
69 	static const GLint m_min_map_buffer_alignment = 64;
70 };
71 
72 /** Implementation of Functional test, description follows:
73  *
74  * Verifies that results of MapBuffer operations are as required.
75  *
76  * Steps:
77  * - prepare buffer filled with specific content;
78  * - map buffer with MapBuffer;
79  * - verify that returned data match contents of the buffer;
80  * - unmap buffer;
81  * - map buffer with MapBufferRange;
82  * - verify that returned data match contents of the buffer;
83  * - unmap buffer;
84  * - verify that pointers returned by map operations fulfil alignment
85  * requirements.
86  *
87  * Repeat steps for all valid:
88  * - <buffer> values;
89  * - <access> combinations.
90  *
91  * <offset> should be set to MIN_MAP_BUFFER_ALIGNEMENT - 1.
92  **/
93 class Functional : public deqp::TestCase
94 {
95 public:
96 	/* Public methods */
Functional(deqp::Context & context)97 	Functional(deqp::Context& context)
98 		: TestCase(context, "functional", "Verifies alignment of memory returned by MapBuffer operations")
99 	{
100 		/* Nothing to be done */
101 	}
102 
~Functional()103 	virtual ~Functional()
104 	{
105 		/* Nothing to be done */
106 	}
107 
108 	void init();
109 	/** Execute test
110 	 *
111 	 * @return tcu::TestNode::STOP
112 	 **/
113 	virtual tcu::TestNode::IterateResult iterate(void);
114 };
115 
116 /** Execute test
117  *
118  * @return tcu::TestNode::STOP
119  **/
iterate()120 tcu::TestNode::IterateResult Query::iterate()
121 {
122 	GLint min_map_buffer_alignment = 0;
123 	bool  test_result			   = true;
124 
125 	const Functions& gl = m_context.getRenderContext().getFunctions();
126 
127 	gl.getIntegerv(GL_MIN_MAP_BUFFER_ALIGNMENT, &min_map_buffer_alignment);
128 	GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
129 
130 	if (m_min_map_buffer_alignment > min_map_buffer_alignment)
131 	{
132 		test_result = false;
133 	}
134 
135 	/* Set result */
136 	if (true == test_result)
137 	{
138 		m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
139 	}
140 	else
141 	{
142 		m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
143 	}
144 
145 	/* Done */
146 	return tcu::TestNode::STOP;
147 }
148 
149 struct BufferEnums
150 {
151 	GLenum m_target;
152 	GLenum m_max_size;
153 };
154 
init(void)155 void Functional::init(void)
156 {
157 	if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_buffer_storage"))
158 	{
159 		TCU_THROW(NotSupportedError, "GL_ARB_buffer_storage not supported");
160 	}
161 }
162 
163 /** Execute test
164  *
165  * @return tcu::TestNode::STOP
166  **/
iterate()167 tcu::TestNode::IterateResult Functional::iterate()
168 {
169 	static const GLenum storage_flags[] = {
170 		GL_MAP_READ_BIT, GL_MAP_WRITE_BIT, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, GL_DYNAMIC_STORAGE_BIT | GL_MAP_READ_BIT,
171 		GL_DYNAMIC_STORAGE_BIT | GL_MAP_WRITE_BIT, GL_DYNAMIC_STORAGE_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
172 		GL_MAP_PERSISTENT_BIT | GL_MAP_READ_BIT, GL_MAP_PERSISTENT_BIT | GL_MAP_WRITE_BIT,
173 		GL_MAP_PERSISTENT_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
174 		GL_MAP_PERSISTENT_BIT | GL_DYNAMIC_STORAGE_BIT | GL_MAP_READ_BIT,
175 		GL_MAP_PERSISTENT_BIT | GL_DYNAMIC_STORAGE_BIT | GL_MAP_WRITE_BIT,
176 		GL_MAP_PERSISTENT_BIT | GL_DYNAMIC_STORAGE_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
177 		GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_READ_BIT,
178 		GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_WRITE_BIT,
179 		GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
180 		GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_DYNAMIC_STORAGE_BIT | GL_MAP_READ_BIT,
181 		GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_DYNAMIC_STORAGE_BIT | GL_MAP_WRITE_BIT,
182 		GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_DYNAMIC_STORAGE_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
183 		GL_CLIENT_STORAGE_BIT | GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_READ_BIT,
184 		GL_CLIENT_STORAGE_BIT | GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_WRITE_BIT,
185 		GL_CLIENT_STORAGE_BIT | GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
186 		GL_CLIENT_STORAGE_BIT | GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_DYNAMIC_STORAGE_BIT | GL_MAP_READ_BIT,
187 		GL_CLIENT_STORAGE_BIT | GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_DYNAMIC_STORAGE_BIT | GL_MAP_WRITE_BIT,
188 		GL_CLIENT_STORAGE_BIT | GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_DYNAMIC_STORAGE_BIT | GL_MAP_READ_BIT |
189 			GL_MAP_WRITE_BIT,
190 	};
191 
192 	static const size_t n_storage_flags = sizeof(storage_flags) / sizeof(storage_flags[0]);
193 
194 	static const BufferEnums buffers[] = {
195 		{ GL_ARRAY_BUFFER, GL_MAX_VARYING_COMPONENTS },
196 		{ GL_ATOMIC_COUNTER_BUFFER, GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE },
197 		{ GL_COPY_READ_BUFFER, 0 },
198 		{ GL_COPY_WRITE_BUFFER, 0 },
199 		{ GL_DISPATCH_INDIRECT_BUFFER, 0 },
200 		{ GL_DRAW_INDIRECT_BUFFER, 0 },
201 		{ GL_ELEMENT_ARRAY_BUFFER, GL_MAX_ELEMENTS_INDICES },
202 		{ GL_PIXEL_PACK_BUFFER, 0 },
203 		{ GL_PIXEL_UNPACK_BUFFER, 0 },
204 		{ GL_QUERY_BUFFER, 0 },
205 		{ GL_SHADER_STORAGE_BUFFER, GL_MAX_SHADER_STORAGE_BLOCK_SIZE },
206 		{ GL_TEXTURE_BUFFER, GL_MAX_TEXTURE_BUFFER_SIZE },
207 		{ GL_TRANSFORM_FEEDBACK_BUFFER, GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS },
208 		{ GL_UNIFORM_BUFFER, GL_MAX_UNIFORM_BLOCK_SIZE }
209 	};
210 	static const size_t n_buffers = sizeof(buffers) / sizeof(buffers[0]);
211 
212 	const Functions& gl = m_context.getRenderContext().getFunctions();
213 
214 	std::vector<GLubyte> buffer_data;
215 	size_t				 buffer_data_size		  = 0;
216 	GLuint				 buffer_id				  = 0;
217 	GLint				 buffer_size			  = 0;
218 	GLint				 min_map_buffer_alignment = 0;
219 	GLuint				 offset					  = 0;
220 	bool				 test_result			  = true;
221 
222 	/* Get min alignment */
223 	gl.getIntegerv(GL_MIN_MAP_BUFFER_ALIGNMENT, &min_map_buffer_alignment);
224 	GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
225 
226 	/* Prepare storage */
227 	buffer_data_size = 2 * min_map_buffer_alignment;
228 	buffer_data.resize(buffer_data_size);
229 
230 	/* Prepare data */
231 	for (size_t i = 0; i < buffer_data_size; ++i)
232 	{
233 		buffer_data[i] = (GLubyte)i;
234 	}
235 
236 	/* Run test */
237 	try
238 	{
239 		for (size_t buffer_idx = 0; buffer_idx < n_buffers; ++buffer_idx)
240 		{
241 			const BufferEnums& buffer = buffers[buffer_idx];
242 
243 			buffer_size = static_cast<GLint>(buffer_data_size);
244 
245 			/* Get max size */
246 			if (0 != buffer.m_max_size)
247 			{
248 				gl.getIntegerv(buffer.m_max_size, &buffer_size);
249 				GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
250 			}
251 
252 			switch (buffer.m_max_size)
253 			{
254 			case GL_MAX_VARYING_COMPONENTS:
255 			case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS:
256 				buffer_size = static_cast<glw::GLint>(buffer_size * sizeof(GLfloat));
257 				break;
258 
259 			case GL_MAX_ELEMENTS_INDICES:
260 				buffer_size = static_cast<glw::GLint>(buffer_size * sizeof(GLuint));
261 				break;
262 
263 			default:
264 				break;
265 			}
266 
267 			buffer_size = std::min(buffer_size, (GLint)buffer_data_size);
268 			offset		= std::min(buffer_size - 1, min_map_buffer_alignment - 1);
269 
270 			for (size_t set_idx = 0; set_idx < n_storage_flags; ++set_idx)
271 			{
272 				const GLenum& storage_set = storage_flags[set_idx];
273 
274 				/* Prepare buffer */
275 				gl.genBuffers(1, &buffer_id);
276 				GLU_EXPECT_NO_ERROR(gl.getError(), "GenBuffers");
277 
278 				gl.bindBuffer(buffer.m_target, buffer_id);
279 				GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffer");
280 
281 				gl.bufferStorage(buffer.m_target, buffer_size, &buffer_data[0], storage_set);
282 				GLU_EXPECT_NO_ERROR(gl.getError(), "BufferStorage");
283 
284 				/* Test MapBuffer */
285 				GLenum map_buffer_access = GL_READ_WRITE;
286 				if (0 == (storage_set & GL_MAP_READ_BIT))
287 				{
288 					map_buffer_access = GL_WRITE_ONLY;
289 				}
290 				else if (0 == (storage_set & GL_MAP_WRITE_BIT))
291 				{
292 					map_buffer_access = GL_READ_ONLY;
293 				}
294 
295 				GLubyte* map_buffer_ptr = (GLubyte*)gl.mapBuffer(buffer.m_target, map_buffer_access);
296 				GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
297 
298 				if (GL_WRITE_ONLY != map_buffer_access)
299 				{
300 					for (size_t i = 0; i < (size_t)buffer_size; ++i)
301 					{
302 						if (buffer_data[i] != map_buffer_ptr[i])
303 						{
304 							test_result = false;
305 							break;
306 						}
307 					}
308 				}
309 
310 				gl.unmapBuffer(buffer.m_target);
311 				GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
312 
313 				/* Test MapBufferRange */
314 				static const GLenum map_buffer_range_access_mask = GL_DYNAMIC_STORAGE_BIT | GL_CLIENT_STORAGE_BIT;
315 				GLenum				map_buffer_range_access		 = (storage_set & (~map_buffer_range_access_mask));
316 
317 				GLubyte* map_buffer_range_ptr =
318 					(GLubyte*)gl.mapBufferRange(buffer.m_target, offset, buffer_size - offset, map_buffer_range_access);
319 				GLU_EXPECT_NO_ERROR(gl.getError(), "MapBufferRange");
320 
321 				if (0 != (GL_MAP_READ_BIT & map_buffer_range_access))
322 				{
323 					for (size_t i = 0; i < (size_t)buffer_size - (size_t)offset; ++i)
324 					{
325 						if (buffer_data[i + offset] != map_buffer_range_ptr[i])
326 						{
327 							test_result = false;
328 							break;
329 						}
330 					}
331 				}
332 
333 				gl.unmapBuffer(buffer.m_target);
334 				GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
335 
336 				gl.bindBuffer(buffer.m_target, 0 /* id */);
337 				GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffer");
338 
339 				/* Remove buffer */
340 				gl.deleteBuffers(1, &buffer_id);
341 				GLU_EXPECT_NO_ERROR(gl.getError(), "DeleteBuffers");
342 
343 				buffer_id = 0;
344 
345 				/* Verify that pointers are properly aligned */
346 				if (0 != ((GLintptr)map_buffer_ptr % min_map_buffer_alignment))
347 				{
348 					test_result = false;
349 					break;
350 				}
351 
352 				if (0 != (((GLintptr)map_buffer_range_ptr - offset) % min_map_buffer_alignment))
353 				{
354 					test_result = false;
355 					break;
356 				}
357 			}
358 		}
359 	}
360 	catch (const std::exception& exc)
361 	{
362 		if (0 != buffer_id)
363 		{
364 			gl.deleteBuffers(1, &buffer_id);
365 			GLU_EXPECT_NO_ERROR(gl.getError(), "DeleteBuffers");
366 		}
367 
368 		TCU_FAIL(exc.what());
369 	}
370 
371 	/* Set result */
372 	if (true == test_result)
373 	{
374 		m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
375 	}
376 	else
377 	{
378 		m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
379 	}
380 
381 	/* Done */
382 	return tcu::TestNode::STOP;
383 }
384 } /* MapBufferAlignment namespace */
385 
386 /** Constructor.
387  *
388  *  @param context Rendering context.
389  **/
MapBufferAlignmentTests(deqp::Context & context)390 MapBufferAlignmentTests::MapBufferAlignmentTests(deqp::Context& context)
391 	: TestCaseGroup(context, "map_buffer_alignment", "Verifies \"map buffer alignment\" functionality")
392 {
393 	/* Left blank on purpose */
394 }
395 
396 /** Initializes a texture_storage_multisample test group.
397  *
398  **/
init(void)399 void MapBufferAlignmentTests::init(void)
400 {
401 	addChild(new MapBufferAlignment::Query(m_context));
402 	addChild(new MapBufferAlignment::Functional(m_context));
403 }
404 
405 } /* gl4cts namespace */
406