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