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,
171 GL_MAP_WRITE_BIT,
172 GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
173 GL_DYNAMIC_STORAGE_BIT | GL_MAP_READ_BIT,
174 GL_DYNAMIC_STORAGE_BIT | GL_MAP_WRITE_BIT,
175 GL_DYNAMIC_STORAGE_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
176 GL_MAP_PERSISTENT_BIT | GL_MAP_READ_BIT,
177 GL_MAP_PERSISTENT_BIT | GL_MAP_WRITE_BIT,
178 GL_MAP_PERSISTENT_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
179 GL_MAP_PERSISTENT_BIT | GL_DYNAMIC_STORAGE_BIT | GL_MAP_READ_BIT,
180 GL_MAP_PERSISTENT_BIT | GL_DYNAMIC_STORAGE_BIT | GL_MAP_WRITE_BIT,
181 GL_MAP_PERSISTENT_BIT | GL_DYNAMIC_STORAGE_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
182 GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_READ_BIT,
183 GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_WRITE_BIT,
184 GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
185 GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_DYNAMIC_STORAGE_BIT | GL_MAP_READ_BIT,
186 GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_DYNAMIC_STORAGE_BIT | GL_MAP_WRITE_BIT,
187 GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_DYNAMIC_STORAGE_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
188 GL_CLIENT_STORAGE_BIT | GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_READ_BIT,
189 GL_CLIENT_STORAGE_BIT | GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_WRITE_BIT,
190 GL_CLIENT_STORAGE_BIT | GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
191 GL_CLIENT_STORAGE_BIT | GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_DYNAMIC_STORAGE_BIT | GL_MAP_READ_BIT,
192 GL_CLIENT_STORAGE_BIT | GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_DYNAMIC_STORAGE_BIT | GL_MAP_WRITE_BIT,
193 GL_CLIENT_STORAGE_BIT | GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_DYNAMIC_STORAGE_BIT | GL_MAP_READ_BIT |
194 GL_MAP_WRITE_BIT,
195 };
196
197 static const size_t n_storage_flags = sizeof(storage_flags) / sizeof(storage_flags[0]);
198
199 static const BufferEnums buffers[] = {
200 {GL_ARRAY_BUFFER, GL_MAX_VARYING_COMPONENTS},
201 {GL_ATOMIC_COUNTER_BUFFER, GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE},
202 {GL_COPY_READ_BUFFER, 0},
203 {GL_COPY_WRITE_BUFFER, 0},
204 {GL_DISPATCH_INDIRECT_BUFFER, 0},
205 {GL_DRAW_INDIRECT_BUFFER, 0},
206 {GL_ELEMENT_ARRAY_BUFFER, GL_MAX_ELEMENTS_INDICES},
207 {GL_PIXEL_PACK_BUFFER, 0},
208 {GL_PIXEL_UNPACK_BUFFER, 0},
209 {GL_QUERY_BUFFER, 0},
210 {GL_SHADER_STORAGE_BUFFER, GL_MAX_SHADER_STORAGE_BLOCK_SIZE},
211 {GL_TEXTURE_BUFFER, GL_MAX_TEXTURE_BUFFER_SIZE},
212 {GL_TRANSFORM_FEEDBACK_BUFFER, GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS},
213 {GL_UNIFORM_BUFFER, GL_MAX_UNIFORM_BLOCK_SIZE}};
214 static const size_t n_buffers = sizeof(buffers) / sizeof(buffers[0]);
215
216 const Functions &gl = m_context.getRenderContext().getFunctions();
217
218 std::vector<GLubyte> buffer_data;
219 size_t buffer_data_size = 0;
220 GLuint buffer_id = 0;
221 GLint buffer_size = 0;
222 GLint min_map_buffer_alignment = 0;
223 GLuint offset = 0;
224 bool test_result = true;
225
226 /* Get min alignment */
227 gl.getIntegerv(GL_MIN_MAP_BUFFER_ALIGNMENT, &min_map_buffer_alignment);
228 GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
229
230 /* Prepare storage */
231 buffer_data_size = 2 * min_map_buffer_alignment;
232 buffer_data.resize(buffer_data_size);
233
234 /* Prepare data */
235 for (size_t i = 0; i < buffer_data_size; ++i)
236 {
237 buffer_data[i] = (GLubyte)i;
238 }
239
240 /* Run test */
241 try
242 {
243 for (size_t buffer_idx = 0; buffer_idx < n_buffers; ++buffer_idx)
244 {
245 const BufferEnums &buffer = buffers[buffer_idx];
246
247 buffer_size = static_cast<GLint>(buffer_data_size);
248
249 /* Get max size */
250 if (0 != buffer.m_max_size)
251 {
252 gl.getIntegerv(buffer.m_max_size, &buffer_size);
253 GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
254 }
255
256 switch (buffer.m_max_size)
257 {
258 case GL_MAX_VARYING_COMPONENTS:
259 case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS:
260 buffer_size = static_cast<glw::GLint>(buffer_size * sizeof(GLfloat));
261 break;
262
263 case GL_MAX_ELEMENTS_INDICES:
264 buffer_size = static_cast<glw::GLint>(buffer_size * sizeof(GLuint));
265 break;
266
267 default:
268 break;
269 }
270
271 buffer_size = std::min(buffer_size, (GLint)buffer_data_size);
272 offset = std::min(buffer_size - 1, min_map_buffer_alignment - 1);
273
274 for (size_t set_idx = 0; set_idx < n_storage_flags; ++set_idx)
275 {
276 const GLenum &storage_set = storage_flags[set_idx];
277
278 /* Prepare buffer */
279 gl.genBuffers(1, &buffer_id);
280 GLU_EXPECT_NO_ERROR(gl.getError(), "GenBuffers");
281
282 gl.bindBuffer(buffer.m_target, buffer_id);
283 GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffer");
284
285 gl.bufferStorage(buffer.m_target, buffer_size, &buffer_data[0], storage_set);
286 GLU_EXPECT_NO_ERROR(gl.getError(), "BufferStorage");
287
288 /* Test MapBuffer */
289 GLenum map_buffer_access = GL_READ_WRITE;
290 if (0 == (storage_set & GL_MAP_READ_BIT))
291 {
292 map_buffer_access = GL_WRITE_ONLY;
293 }
294 else if (0 == (storage_set & GL_MAP_WRITE_BIT))
295 {
296 map_buffer_access = GL_READ_ONLY;
297 }
298
299 GLubyte *map_buffer_ptr = (GLubyte *)gl.mapBuffer(buffer.m_target, map_buffer_access);
300 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
301
302 if (GL_WRITE_ONLY != map_buffer_access)
303 {
304 for (size_t i = 0; i < (size_t)buffer_size; ++i)
305 {
306 if (buffer_data[i] != map_buffer_ptr[i])
307 {
308 test_result = false;
309 break;
310 }
311 }
312 }
313
314 gl.unmapBuffer(buffer.m_target);
315 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
316
317 /* Test MapBufferRange */
318 static const GLenum map_buffer_range_access_mask = GL_DYNAMIC_STORAGE_BIT | GL_CLIENT_STORAGE_BIT;
319 GLenum map_buffer_range_access = (storage_set & (~map_buffer_range_access_mask));
320
321 GLubyte *map_buffer_range_ptr = (GLubyte *)gl.mapBufferRange(
322 buffer.m_target, offset, buffer_size - offset, map_buffer_range_access);
323 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBufferRange");
324
325 if (0 != (GL_MAP_READ_BIT & map_buffer_range_access))
326 {
327 for (size_t i = 0; i < (size_t)buffer_size - (size_t)offset; ++i)
328 {
329 if (buffer_data[i + offset] != map_buffer_range_ptr[i])
330 {
331 test_result = false;
332 break;
333 }
334 }
335 }
336
337 gl.unmapBuffer(buffer.m_target);
338 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
339
340 gl.bindBuffer(buffer.m_target, 0 /* id */);
341 GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffer");
342
343 /* Remove buffer */
344 gl.deleteBuffers(1, &buffer_id);
345 GLU_EXPECT_NO_ERROR(gl.getError(), "DeleteBuffers");
346
347 buffer_id = 0;
348
349 /* Verify that pointers are properly aligned */
350 if (0 != ((GLintptr)map_buffer_ptr % min_map_buffer_alignment))
351 {
352 test_result = false;
353 break;
354 }
355
356 if (0 != (((GLintptr)map_buffer_range_ptr - offset) % min_map_buffer_alignment))
357 {
358 test_result = false;
359 break;
360 }
361 }
362 }
363 }
364 catch (const std::exception &exc)
365 {
366 if (0 != buffer_id)
367 {
368 gl.deleteBuffers(1, &buffer_id);
369 GLU_EXPECT_NO_ERROR(gl.getError(), "DeleteBuffers");
370 }
371
372 TCU_FAIL(exc.what());
373 }
374
375 /* Set result */
376 if (true == test_result)
377 {
378 m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
379 }
380 else
381 {
382 m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
383 }
384
385 /* Done */
386 return tcu::TestNode::STOP;
387 }
388 } // namespace MapBufferAlignment
389
390 /** Constructor.
391 *
392 * @param context Rendering context.
393 **/
MapBufferAlignmentTests(deqp::Context & context)394 MapBufferAlignmentTests::MapBufferAlignmentTests(deqp::Context &context)
395 : TestCaseGroup(context, "map_buffer_alignment", "Verifies \"map buffer alignment\" functionality")
396 {
397 /* Left blank on purpose */
398 }
399
400 /** Initializes a texture_storage_multisample test group.
401 *
402 **/
init(void)403 void MapBufferAlignmentTests::init(void)
404 {
405 addChild(new MapBufferAlignment::Query(m_context));
406 addChild(new MapBufferAlignment::Functional(m_context));
407 }
408
409 } // namespace gl4cts
410