1 /*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
4 *
5 * Copyright (c) 2014-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 #include "gluDefs.hpp"
25 #include "glwEnums.hpp"
26 #include "glwFunctions.hpp"
27 #include "tcuTestLog.hpp"
28
29 #include "esextcGeometryShaderAdjacency.hpp"
30 #include <math.h>
31
32 namespace glcts
33 {
34 /** Constructor
35 *
36 **/
AdjacencyGrid()37 AdjacencyGrid::AdjacencyGrid()
38 : m_line_segments(0), m_points(0), m_triangles(0), m_n_points(0), m_n_segments(0), m_n_triangles(0)
39 {
40 /* Nothing to be done here */
41 }
42
43 /** Destructor
44 *
45 **/
~AdjacencyGrid()46 AdjacencyGrid::~AdjacencyGrid()
47 {
48 if (m_line_segments)
49 {
50 delete[] m_line_segments;
51 m_line_segments = 0;
52 }
53
54 if (m_points)
55 {
56 delete[] m_points;
57 m_points = 0;
58 }
59
60 if (m_triangles)
61 {
62 delete[] m_triangles;
63 m_triangles = 0;
64 }
65 }
66
67 /** Constructor
68 *
69 **/
AdjacencyGridStrip()70 AdjacencyGridStrip::AdjacencyGridStrip() : m_n_points(0), m_points(0)
71 {
72 /* Nothing to be done here */
73 }
74
75 /** Destructor
76 *
77 **/
~AdjacencyGridStrip()78 AdjacencyGridStrip::~AdjacencyGridStrip()
79 {
80 if (m_points)
81 {
82 delete[] m_points;
83 }
84 }
85
86 /** Constructor
87 *
88 **/
AdjacencyTestData()89 AdjacencyTestData::AdjacencyTestData()
90 : m_gs_code(0)
91 , m_mode(0)
92 , m_n_vertices(0)
93 , m_grid(0)
94 , m_geometry_bo_size(0)
95 , m_index_data_bo_size(0)
96 , m_vertex_data_bo_size(0)
97 , m_expected_adjacency_geometry(0)
98 , m_expected_geometry(0)
99 , m_alternate_expected_adjacency_geometry(0)
100 , m_alternate_expected_geometry(0)
101 , m_index_data(0)
102 , m_tf_mode(0)
103 , m_vertex_data(0)
104 {
105 /* Nothing to be done here */
106 }
107
108 /** Destructor
109 *
110 **/
~AdjacencyTestData()111 AdjacencyTestData::~AdjacencyTestData()
112 {
113 if (m_expected_adjacency_geometry)
114 {
115 delete[] m_expected_adjacency_geometry;
116 m_expected_adjacency_geometry = 0;
117 }
118
119 if (m_expected_geometry)
120 {
121 delete[] m_expected_geometry;
122 m_expected_geometry = 0;
123 }
124
125 if (m_alternate_expected_adjacency_geometry)
126 {
127 delete[] m_alternate_expected_adjacency_geometry;
128 m_alternate_expected_adjacency_geometry = 0;
129 }
130
131 if (m_alternate_expected_geometry)
132 {
133 delete[] m_alternate_expected_geometry;
134 m_alternate_expected_geometry = 0;
135 }
136
137 if (m_vertex_data)
138 {
139 delete[] m_vertex_data;
140 m_vertex_data = 0;
141 }
142
143 if (m_index_data)
144 {
145 delete[] m_index_data;
146 m_index_data = 0;
147 }
148
149 if (m_grid)
150 {
151 delete m_grid;
152 m_grid = 0;
153 }
154 }
155
156 /** Constructor
157 *
158 * @param context Test context
159 * @param name Test case's name
160 * @param description Test case's desricption
161 **/
GeometryShaderAdjacency(Context & context,const ExtParameters & extParams,const char * name,const char * description,AdjacencyTestData & testData)162 GeometryShaderAdjacency::GeometryShaderAdjacency(Context& context, const ExtParameters& extParams, const char* name,
163 const char* description, AdjacencyTestData& testData)
164 : TestCaseBase(context, extParams, name, description)
165 , m_adjacency_geometry_bo_id(0)
166 , m_fs_id(0)
167 , m_geometry_bo_id(0)
168 , m_gs_id(0)
169 , m_index_data_bo_id(0)
170 , m_vertex_data_bo_id(0)
171 , m_po_id(0)
172 , m_test_data(testData)
173 , m_vao_id(0)
174 , m_vs_id(0)
175 , m_components_input(2)
176 , m_epsilon(0.00001F)
177 , m_position_attribute_location(0)
178 {
179 /* Nothing to be done here */
180 }
181
182 /** Deinitializes GLES objects created during the test.
183 *
184 */
deinit(void)185 void GeometryShaderAdjacency::deinit(void)
186 {
187 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
188
189 /* Reset OpenGL ES state */
190 gl.useProgram(0);
191 gl.bindVertexArray(0);
192 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
193 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 1, 0);
194 gl.bindBuffer(GL_ARRAY_BUFFER, 0);
195
196 if (m_po_id != 0)
197 {
198 gl.deleteProgram(m_po_id);
199 }
200
201 if (m_fs_id != 0)
202 {
203 gl.deleteShader(m_fs_id);
204 }
205
206 if (m_gs_id != 0)
207 {
208 gl.deleteShader(m_gs_id);
209 }
210
211 if (m_vs_id != 0)
212 {
213 gl.deleteShader(m_vs_id);
214 }
215
216 if (m_adjacency_geometry_bo_id != 0)
217 {
218 gl.deleteBuffers(1, &m_adjacency_geometry_bo_id);
219 }
220 if (m_geometry_bo_id != 0)
221 {
222 gl.deleteBuffers(1, &m_geometry_bo_id);
223 }
224
225 if (m_index_data_bo_id != 0)
226 {
227 gl.deleteBuffers(1, &m_index_data_bo_id);
228 }
229
230 if (m_vertex_data_bo_id != 0)
231 {
232 gl.deleteBuffers(1, &m_vertex_data_bo_id);
233 }
234
235 if (m_vao_id != 0)
236 {
237 gl.deleteVertexArrays(1, &m_vao_id);
238 }
239
240 TestCaseBase::deinit();
241 }
242
243 /** Returns code for Fragment Shader
244 * @return pointer to literal with Fragment Shader code
245 **/
getFragmentShaderCode()246 const char* GeometryShaderAdjacency::getFragmentShaderCode()
247 {
248 static const char* result = "${VERSION}\n"
249 "\n"
250 "precision highp float;\n"
251 "\n"
252 "void main()\n"
253 "{\n"
254 "}\n";
255 return result;
256 }
257
258 /** Returns code for Vertex Shader
259 * @return pointer to literal with Vertex Shader code
260 **/
getVertexShaderCode()261 const char* GeometryShaderAdjacency::getVertexShaderCode()
262 {
263 static const char* result = "${VERSION}\n"
264 "\n"
265 "precision highp float;\n"
266 "\n"
267 "layout(location = 0) in vec2 position_data;\n"
268 "\n"
269 "void main()\n"
270 "{\n"
271 " gl_Position = vec4(position_data, 0, 1);\n"
272 "}\n";
273 return result;
274 }
275
276 /** Initializes GLES objects used during the test.
277 *
278 **/
initTest(void)279 void GeometryShaderAdjacency::initTest(void)
280 {
281 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
282
283 /* check if EXT_geometry_shader extension is supported */
284 if (!m_is_geometry_shader_extension_supported)
285 {
286 throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
287 }
288
289 gl.genVertexArrays(1, &m_vao_id);
290 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
291
292 /* Get shader code */
293 const char* fsCode = getFragmentShaderCode();
294 const char* gsCode = m_test_data.m_gs_code;
295 const char* vsCode = getVertexShaderCode();
296
297 /* Create shader and program objects */
298 m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
299 m_vs_id = gl.createShader(GL_VERTEX_SHADER);
300 m_gs_id = gl.createShader(m_glExtTokens.GEOMETRY_SHADER);
301 m_po_id = gl.createProgram();
302
303 GLU_EXPECT_NO_ERROR(gl.getError(), "Error creating program/shader objects.");
304
305 /* If gs code is available set gs out data for transformfeedback*/
306 if (m_test_data.m_gs_code)
307 {
308 const char* varyings[] = { "out_adjacent_geometry", "out_geometry" };
309
310 gl.transformFeedbackVaryings(m_po_id, 2, varyings, GL_SEPARATE_ATTRIBS);
311 }
312 else
313 {
314 const char* varyings[] = { "gl_Position" };
315
316 gl.transformFeedbackVaryings(m_po_id, 1, varyings, GL_SEPARATE_ATTRIBS);
317 }
318 GLU_EXPECT_NO_ERROR(gl.getError(), "Error configuring vertex array object!");
319
320 /* Build program */
321 if (!buildProgram(m_po_id, m_fs_id, 1, /* parts */ &fsCode, (gsCode) ? m_gs_id : 0, (gsCode) ? 1 : 0,
322 (gsCode) ? &gsCode : 0, m_vs_id, 1, /* parts */ &vsCode))
323 {
324 TCU_FAIL("Could not create a program object from a valid shader!");
325 }
326
327 /* Generate buffers for input/output vertex data */
328 gl.genBuffers(1, &m_vertex_data_bo_id);
329 gl.genBuffers(1, &m_adjacency_geometry_bo_id);
330 gl.genBuffers(1, &m_geometry_bo_id);
331
332 /* Configure buffers for input/output vertex data */
333 gl.bindBuffer(GL_ARRAY_BUFFER, m_adjacency_geometry_bo_id);
334 gl.bufferData(GL_ARRAY_BUFFER, m_test_data.m_geometry_bo_size * 4, 0, GL_DYNAMIC_DRAW);
335 gl.bindBuffer(GL_ARRAY_BUFFER, m_geometry_bo_id);
336 gl.bufferData(GL_ARRAY_BUFFER, m_test_data.m_geometry_bo_size * 4, 0, GL_DYNAMIC_DRAW);
337 gl.bindBuffer(GL_ARRAY_BUFFER, m_vertex_data_bo_id);
338 gl.bufferData(GL_ARRAY_BUFFER, m_test_data.m_vertex_data_bo_size, m_test_data.m_vertex_data, GL_DYNAMIC_DRAW);
339 gl.bindBuffer(GL_ARRAY_BUFFER, 0);
340
341 GLU_EXPECT_NO_ERROR(gl.getError(), "Error configuring vertex buffer objects for vertex data!");
342
343 /* Configure buffer for index data */
344 if (m_test_data.m_index_data_bo_size > 0)
345 {
346 gl.genBuffers(1, &m_index_data_bo_id);
347 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_index_data_bo_id);
348 gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, m_test_data.m_index_data_bo_size, m_test_data.m_index_data,
349 GL_DYNAMIC_DRAW);
350 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
351
352 GLU_EXPECT_NO_ERROR(gl.getError(), "Error configuring vertex buffer objects for index data!");
353 }
354 }
355
356 /** Executes the test.
357 * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
358 * @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
359 * Note the function throws exception should an error occur!
360 **/
iterate(void)361 tcu::TestNode::IterateResult GeometryShaderAdjacency::iterate(void)
362 {
363 initTest();
364
365 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
366
367 /** Bind a vertex array object */
368 gl.bindVertexArray(m_vao_id);
369 GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
370
371 /* Bind buffer objects used as data store for transform feedback to TF binding points*/
372 if (m_test_data.m_gs_code)
373 {
374 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_adjacency_geometry_bo_id);
375 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 1, m_geometry_bo_id);
376 }
377 else
378 {
379 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_geometry_bo_id);
380 }
381
382 GLU_EXPECT_NO_ERROR(gl.getError(), "Error configuring transform feedback buffer binding points!");
383
384 gl.bindBuffer(GL_ARRAY_BUFFER, m_vertex_data_bo_id);
385 m_position_attribute_location = gl.getAttribLocation(m_po_id, "position_data");
386 gl.vertexAttribPointer(m_position_attribute_location, m_components_input, GL_FLOAT, GL_FALSE, 0, 0);
387 gl.enableVertexAttribArray(m_position_attribute_location);
388 GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting vertex attribute array for position_data attribute");
389
390 /* bind index buffer */
391 if (m_test_data.m_index_data_bo_size > 0)
392 {
393 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_index_data_bo_id);
394 }
395 GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding index data buffer");
396
397 /* Configure program */
398 gl.enable(GL_RASTERIZER_DISCARD);
399 gl.useProgram(m_po_id);
400 gl.beginTransformFeedback(m_test_data.m_tf_mode);
401
402 glw::GLuint nVertices = m_test_data.m_n_vertices * ((m_test_data.m_mode == m_glExtTokens.LINE_STRIP_ADJACENCY ||
403 m_test_data.m_mode == m_glExtTokens.TRIANGLE_STRIP_ADJACENCY) ?
404 1 :
405 2 /* include adjacency info */);
406
407 /* Use glDrawElements if data is indicied */
408 if (m_test_data.m_index_data_bo_size > 0)
409 {
410 gl.drawElements(m_test_data.m_mode, nVertices, GL_UNSIGNED_INT, 0);
411 }
412 /* Use glDrawArrays if data is non indicied */
413 else
414 {
415 gl.drawArrays(m_test_data.m_mode, 0, nVertices);
416 }
417 GLU_EXPECT_NO_ERROR(gl.getError(), "Error while trying to render");
418
419 gl.disable(GL_RASTERIZER_DISCARD);
420 gl.endTransformFeedback();
421
422 /* Map result buffer objects into client space */
423 float* result_adjacency_geometry_ptr = 0;
424 float* result_geometry_ptr = 0;
425
426 bool hasAlternateData = m_test_data.m_alternate_expected_geometry != nullptr &&
427 m_test_data.m_alternate_expected_adjacency_geometry != nullptr;
428 bool adjacentMatchesExpected = true;
429 bool adjacentMatchesAlternateExpected = hasAlternateData;
430
431 /* If gs is available read adjacency data using TF and compare with expected data*/
432 if (m_test_data.m_gs_code)
433 {
434 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_adjacency_geometry_bo_id);
435 result_adjacency_geometry_ptr =
436 (float*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_test_data.m_geometry_bo_size, GL_MAP_READ_BIT);
437 GLU_EXPECT_NO_ERROR(gl.getError(), "Error when mapping data to client space");
438
439 std::stringstream sstreamExpected;
440 std::stringstream sstreamAlternateExpected;
441 std::stringstream sstreamResult;
442 sstreamExpected << "[";
443 if (hasAlternateData)
444 sstreamAlternateExpected << "[";
445 sstreamResult << "[";
446
447 unsigned int differentExpectedIndex = 0;
448 unsigned int differentAlternateExpectedIndex = 0;
449 for (unsigned int n = 0; n < m_test_data.m_geometry_bo_size / sizeof(float); ++n)
450 {
451 sstreamExpected << m_test_data.m_expected_adjacency_geometry[n] << ", ";
452 if (hasAlternateData)
453 sstreamAlternateExpected << m_test_data.m_alternate_expected_adjacency_geometry[n] << ", ";
454 sstreamResult << result_adjacency_geometry_ptr[n] << ", ";
455
456 if (adjacentMatchesExpected &&
457 de::abs(result_adjacency_geometry_ptr[n] -
458 m_test_data.m_expected_adjacency_geometry[n]) >= m_epsilon)
459 {
460 adjacentMatchesExpected = false;
461 differentExpectedIndex = n;
462 }
463 if (adjacentMatchesAlternateExpected &&
464 de::abs(result_adjacency_geometry_ptr[n] - m_test_data.m_alternate_expected_adjacency_geometry[n]) >=
465 m_epsilon)
466 {
467 adjacentMatchesAlternateExpected = false;
468 differentAlternateExpectedIndex = n;
469 }
470 if (!adjacentMatchesExpected && !adjacentMatchesAlternateExpected)
471 {
472 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
473
474 m_testCtx.getLog() << tcu::TestLog::Message << "At [" << differentExpectedIndex
475 << "] position adjacency buffer position Reference value is different than the "
476 "rendered data (epsilon "
477 << m_epsilon << " )"
478 << " (" << m_test_data.m_expected_adjacency_geometry[differentExpectedIndex]
479 << ") vs "
480 << "(" << result_adjacency_geometry_ptr[differentExpectedIndex] << ")"
481 << tcu::TestLog::EndMessage;
482
483 if (hasAlternateData)
484 {
485 m_testCtx.getLog()
486 << tcu::TestLog::Message << "At [" << differentAlternateExpectedIndex
487 << "] alternate position adjacency buffer position Reference value is different than the "
488 "rendered data (epsilon "
489 << m_epsilon << " )"
490 << " (" << m_test_data.m_alternate_expected_adjacency_geometry[differentAlternateExpectedIndex]
491 << ") vs "
492 << "(" << result_adjacency_geometry_ptr[differentAlternateExpectedIndex] << ")"
493 << tcu::TestLog::EndMessage;
494 }
495
496 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
497 return STOP;
498 }
499 }
500
501 sstreamExpected << "]";
502 if (hasAlternateData)
503 sstreamAlternateExpected << "]";
504 sstreamResult << "]";
505 m_testCtx.getLog() << tcu::TestLog::Message << "Adjacency Expected: " << sstreamExpected.str().c_str()
506 << tcu::TestLog::EndMessage;
507 if (hasAlternateData)
508 m_testCtx.getLog() << tcu::TestLog::Message
509 << "Alternate adjacency Expected: " << sstreamAlternateExpected.str().c_str()
510 << tcu::TestLog::EndMessage;
511 m_testCtx.getLog() << tcu::TestLog::Message << "Adjacency Result: " << sstreamResult.str().c_str()
512 << tcu::TestLog::EndMessage;
513
514 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
515 }
516
517 /* Read vertex data using TF and compare with expected data*/
518 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_geometry_bo_id);
519 result_geometry_ptr =
520 (float*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_test_data.m_geometry_bo_size, GL_MAP_READ_BIT);
521 GLU_EXPECT_NO_ERROR(gl.getError(), "Error when mapping data to client space");
522
523 std::stringstream sstreamExpected;
524 std::stringstream sstreamAlternateExpected;
525 std::stringstream sstreamResult;
526 sstreamExpected << "[";
527 if (hasAlternateData)
528 {
529 sstreamAlternateExpected << "[";
530 }
531 sstreamResult << "[";
532
533 bool matchesExpected = true;
534 bool matchesAlternateExpected = hasAlternateData;
535 unsigned int differentIndex = 0;
536 unsigned int differentAlternateIndex = 0;
537
538 for (unsigned int n = 0; n < m_test_data.m_geometry_bo_size / sizeof(float); ++n)
539 {
540 sstreamExpected << m_test_data.m_expected_geometry[n] << ", ";
541 if (hasAlternateData)
542 {
543 sstreamAlternateExpected << m_test_data.m_alternate_expected_geometry[n] << ", ";
544 }
545 sstreamResult << result_geometry_ptr[n] << ", ";
546
547 if (matchesExpected && de::abs(result_geometry_ptr[n] - m_test_data.m_expected_geometry[n]) >= m_epsilon)
548 {
549 matchesExpected = false;
550 differentIndex = n;
551 }
552 if (matchesAlternateExpected &&
553 de::abs(result_geometry_ptr[n] - m_test_data.m_alternate_expected_geometry[n]) >= m_epsilon)
554 {
555 matchesAlternateExpected = false;
556 differentAlternateIndex = n;
557 }
558 if (!matchesExpected && !matchesAlternateExpected)
559 {
560 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
561
562 m_testCtx.getLog()
563 << tcu::TestLog::Message << "At [" << differentIndex
564 << "] position geometry buffer position Reference value is different than the rendered data (epsilon "
565 << m_epsilon << " )"
566 << " (" << m_test_data.m_expected_geometry[differentIndex] << ") vs "
567 << "(" << result_geometry_ptr[differentIndex] << ")" << tcu::TestLog::EndMessage;
568
569 if (hasAlternateData)
570 {
571 m_testCtx.getLog()
572 << tcu::TestLog::Message << "At [" << differentAlternateIndex
573 << "] alternate position geometry buffer position Reference value is different than the rendered data (epsilon "
574 << m_epsilon << " )"
575 << " (" << m_test_data.m_alternate_expected_geometry[differentAlternateIndex] << ") vs "
576 << "(" << result_geometry_ptr[differentAlternateIndex] << ")" << tcu::TestLog::EndMessage;
577 }
578
579 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
580 return STOP;
581 }
582 }
583
584 if (matchesExpected && !adjacentMatchesExpected)
585 {
586 m_testCtx.getLog() << tcu::TestLog::Message
587 << "Geometry matches OpenGL ordering but adjacent geometry matches Vulkan ordering"
588 << tcu::TestLog::EndMessage;
589
590 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
591 return STOP;
592 }
593 if (matchesAlternateExpected && !adjacentMatchesAlternateExpected)
594 {
595 m_testCtx.getLog() << tcu::TestLog::Message
596 << "Geometry matches Vulkan ordering but adjacent geometry matches OpenGL ordering"
597 << tcu::TestLog::EndMessage;
598
599 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
600 return STOP;
601 }
602
603 sstreamExpected << "]";
604 sstreamResult << "]";
605 if (hasAlternateData)
606 {
607 sstreamAlternateExpected << "]";
608
609 sstreamExpected << "\nor\n" << sstreamAlternateExpected.str();
610 }
611 m_testCtx.getLog() << tcu::TestLog::Message << "Expected: " << sstreamExpected.str().c_str()
612 << tcu::TestLog::EndMessage;
613 m_testCtx.getLog() << tcu::TestLog::Message << "Result: " << sstreamResult.str().c_str()
614 << tcu::TestLog::EndMessage;
615
616 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
617
618 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
619 return STOP;
620 }
621
622 } // namespace glcts
623