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