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