1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 Module
3 * -------------------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Tessellation and geometry shader interaction tests.
22 *//*--------------------------------------------------------------------*/
24 #include "es31fTessellationGeometryInteractionTests.hpp"
26 #include "tcuTestLog.hpp"
27 #include "tcuRenderTarget.hpp"
28 #include "tcuSurface.hpp"
29 #include "tcuImageCompare.hpp"
30 #include "tcuVectorUtil.hpp"
31 #include "tcuTextureUtil.hpp"
32 #include "gluRenderContext.hpp"
33 #include "gluShaderProgram.hpp"
34 #include "gluStrUtil.hpp"
35 #include "gluContextInfo.hpp"
36 #include "gluObjectWrapper.hpp"
37 #include "gluPixelTransfer.hpp"
38 #include "glwFunctions.hpp"
39 #include "glwEnums.hpp"
40 #include "deStringUtil.hpp"
41 #include "deUniquePtr.hpp"
56 static const char* const s_positionVertexShader = "#version 310 es\n"
57 "in highp vec4 a_position;\n"
60 " gl_Position = a_position;\n"
62 static const char* const s_whiteOutputFragmentShader = "#version 310 es\n"
63 "layout(location = 0) out mediump vec4 fragColor;\n"
66 " fragColor = vec4(1.0);\n"
69 static bool isBlack (const tcu::RGBA& c)
71 return c.getRed() == 0 && c.getGreen() == 0 && c.getBlue() == 0;
74 class IdentityShaderCase : public TestCase
77 IdentityShaderCase (Context& context, const char* name, const char* description);
80 const char* getVertexSource (void) const;
81 const char* getFragmentSource (void) const;
84 IdentityShaderCase::IdentityShaderCase (Context& context, const char* name, const char* description)
85 : TestCase(context, name, description)
89 const char* IdentityShaderCase::getVertexSource (void) const
91 return "#version 310 es\n"
92 "in highp vec4 a_position;\n"
93 "out highp vec4 v_vertex_color;\n"
96 " gl_Position = a_position;\n"
97 " v_vertex_color = vec4(a_position.x * 0.5 + 0.5, a_position.y * 0.5 + 0.5, 1.0, 0.4);\n"
101 const char* IdentityShaderCase::getFragmentSource (void) const
103 return "#version 310 es\n"
104 "in mediump vec4 v_fragment_color;\n"
105 "layout(location = 0) out mediump vec4 fragColor;\n"
108 " fragColor = v_fragment_color;\n"
112 class IdentityGeometryShaderCase : public IdentityShaderCase
122 IdentityGeometryShaderCase (Context& context, const char* name, const char* description, CaseType caseType);
123 ~IdentityGeometryShaderCase (void);
128 IterateResult iterate (void);
130 std::string getTessellationControlSource (void) const;
131 std::string getTessellationEvaluationSource (bool geometryActive) const;
132 std::string getGeometrySource (void) const;
139 const CaseType m_case;
140 deUint32 m_patchBuffer;
143 IdentityGeometryShaderCase::IdentityGeometryShaderCase (Context& context, const char* name, const char* description, CaseType caseType)
144 : IdentityShaderCase (context, name, description)
150 IdentityGeometryShaderCase::~IdentityGeometryShaderCase (void)
155 void IdentityGeometryShaderCase::init (void)
159 if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader") ||
160 !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
161 throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader and GL_EXT_geometry_shader extensions");
163 if (m_context.getRenderTarget().getWidth() < RENDER_SIZE ||
164 m_context.getRenderTarget().getHeight() < RENDER_SIZE)
165 throw tcu::NotSupportedError("Test requires " + de::toString<int>(RENDER_SIZE) + "x" + de::toString<int>(RENDER_SIZE) + " or larger render target.");
170 << tcu::TestLog::Message
171 << "Testing tessellating shader program output does not change when a passthrough geometry shader is attached.\n"
172 << "Rendering two images, first with and second without a geometry shader. Expecting similar results.\n"
173 << "Using additive blending to detect overlap.\n"
174 << tcu::TestLog::EndMessage;
179 static const tcu::Vec4 patchBufferData[4] =
181 tcu::Vec4( -0.9f, -0.9f, 0.0f, 1.0f ),
182 tcu::Vec4( -0.9f, 0.9f, 0.0f, 1.0f ),
183 tcu::Vec4( 0.9f, -0.9f, 0.0f, 1.0f ),
184 tcu::Vec4( 0.9f, 0.9f, 0.0f, 1.0f ),
187 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
189 gl.genBuffers(1, &m_patchBuffer);
190 gl.bindBuffer(GL_ARRAY_BUFFER, m_patchBuffer);
191 gl.bufferData(GL_ARRAY_BUFFER, sizeof(patchBufferData), patchBufferData, GL_STATIC_DRAW);
192 GLU_EXPECT_NO_ERROR(gl.getError(), "gen buffer");
196 void IdentityGeometryShaderCase::deinit (void)
200 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_patchBuffer);
205 IdentityGeometryShaderCase::IterateResult IdentityGeometryShaderCase::iterate (void)
207 const float innerTessellationLevel = 14.0f;
208 const float outerTessellationLevel = 14.0f;
209 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
210 tcu::Surface resultWithGeometry (RENDER_SIZE, RENDER_SIZE);
211 tcu::Surface resultWithoutGeometry (RENDER_SIZE, RENDER_SIZE);
216 const char* description;
217 bool containsGeometryShader;
218 tcu::PixelBufferAccess surfaceAccess;
221 { "RenderWithGeometryShader", "Render with geometry shader", true, resultWithGeometry.getAccess() },
222 { "RenderWithoutGeometryShader", "Render without geometry shader", false, resultWithoutGeometry.getAccess() },
225 gl.viewport(0, 0, RENDER_SIZE, RENDER_SIZE);
226 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
227 GLU_EXPECT_NO_ERROR(gl.getError(), "set viewport");
230 gl.blendFunc(GL_SRC_ALPHA, GL_ONE);
231 gl.blendEquation(GL_FUNC_ADD);
232 GLU_EXPECT_NO_ERROR(gl.getError(), "set blend");
234 m_testCtx.getLog() << tcu::TestLog::Message << "Tessellation level: inner " << innerTessellationLevel << ", outer " << outerTessellationLevel << tcu::TestLog::EndMessage;
236 // render with and without geometry shader
237 for (int renderNdx = 0; renderNdx < DE_LENGTH_OF_ARRAY(renderTargets); ++renderNdx)
239 const tcu::ScopedLogSection section (m_testCtx.getLog(), renderTargets[renderNdx].name, renderTargets[renderNdx].description);
240 glu::ProgramSources sources;
242 sources << glu::VertexSource(getVertexSource())
243 << glu::FragmentSource(getFragmentSource())
244 << glu::TessellationControlSource(getTessellationControlSource())
245 << glu::TessellationEvaluationSource(getTessellationEvaluationSource(renderTargets[renderNdx].containsGeometryShader));
247 if (renderTargets[renderNdx].containsGeometryShader)
248 sources << glu::GeometrySource(getGeometrySource());
251 const glu::ShaderProgram program (m_context.getRenderContext(), sources);
252 const glu::VertexArray vao (m_context.getRenderContext());
253 const int posLocation = gl.getAttribLocation(program.getProgram(), "a_position");
254 const int innerTessellationLoc = gl.getUniformLocation(program.getProgram(), "u_innerTessellationLevel");
255 const int outerTessellationLoc = gl.getUniformLocation(program.getProgram(), "u_outerTessellationLevel");
257 m_testCtx.getLog() << program;
260 throw tcu::TestError("could not build program");
261 if (posLocation == -1)
262 throw tcu::TestError("a_position location was -1");
263 if (outerTessellationLoc == -1)
264 throw tcu::TestError("u_outerTessellationLevel location was -1");
266 gl.bindVertexArray(*vao);
267 gl.bindBuffer(GL_ARRAY_BUFFER, m_patchBuffer);
268 gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
269 gl.enableVertexAttribArray(posLocation);
270 GLU_EXPECT_NO_ERROR(gl.getError(), "setup attribs");
272 gl.useProgram(program.getProgram());
273 gl.uniform1f(outerTessellationLoc, outerTessellationLevel);
275 if (innerTessellationLoc == -1)
276 gl.uniform1f(innerTessellationLoc, innerTessellationLevel);
278 GLU_EXPECT_NO_ERROR(gl.getError(), "use program");
280 gl.patchParameteri(GL_PATCH_VERTICES, (m_case == CASE_TRIANGLES) ? (3): (4));
281 GLU_EXPECT_NO_ERROR(gl.getError(), "set patch param");
283 gl.clear(GL_COLOR_BUFFER_BIT);
284 GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
286 gl.drawArrays(GL_PATCHES, 0, 4);
287 GLU_EXPECT_NO_ERROR(gl.getError(), "draw patches");
289 glu::readPixels(m_context.getRenderContext(), 0, 0, renderTargets[renderNdx].surfaceAccess);
293 if (tcu::intThresholdPositionDeviationCompare(m_testCtx.getLog(),
296 resultWithoutGeometry.getAccess(),
297 resultWithGeometry.getAccess(),
298 tcu::UVec4(8, 8, 8, 255),
301 tcu::COMPARE_LOG_RESULT))
302 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
304 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
309 std::string IdentityGeometryShaderCase::getTessellationControlSource (void) const
311 std::ostringstream buf;
313 buf << "#version 310 es\n"
314 "#extension GL_EXT_tessellation_shader : require\n"
315 "layout(vertices = 4) out;\n"
317 "uniform highp float u_innerTessellationLevel;\n"
318 "uniform highp float u_outerTessellationLevel;\n"
319 "in highp vec4 v_vertex_color[];\n"
320 "out highp vec4 v_patch_color[];\n"
324 " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
325 " v_patch_color[gl_InvocationID] = v_vertex_color[gl_InvocationID];\n"
328 if (m_case == CASE_TRIANGLES)
329 buf << " gl_TessLevelOuter[0] = u_outerTessellationLevel;\n"
330 " gl_TessLevelOuter[1] = u_outerTessellationLevel;\n"
331 " gl_TessLevelOuter[2] = u_outerTessellationLevel;\n"
332 " gl_TessLevelInner[0] = u_innerTessellationLevel;\n";
333 else if (m_case == CASE_QUADS)
334 buf << " gl_TessLevelOuter[0] = u_outerTessellationLevel;\n"
335 " gl_TessLevelOuter[1] = u_outerTessellationLevel;\n"
336 " gl_TessLevelOuter[2] = u_outerTessellationLevel;\n"
337 " gl_TessLevelOuter[3] = u_outerTessellationLevel;\n"
338 " gl_TessLevelInner[0] = u_innerTessellationLevel;\n"
339 " gl_TessLevelInner[1] = u_innerTessellationLevel;\n";
340 else if (m_case == CASE_ISOLINES)
341 buf << " gl_TessLevelOuter[0] = u_outerTessellationLevel;\n"
342 " gl_TessLevelOuter[1] = u_outerTessellationLevel;\n";
351 std::string IdentityGeometryShaderCase::getTessellationEvaluationSource (bool geometryActive) const
353 const char* const colorOutputName = ((geometryActive) ? ("v_evaluated_color") : ("v_fragment_color"));
354 std::ostringstream buf;
356 buf << "#version 310 es\n"
357 "#extension GL_EXT_tessellation_shader : require\n"
359 << ((m_case == CASE_TRIANGLES) ? ("triangles") : (m_case == CASE_QUADS) ? ("quads") : ("isolines"))
362 "in highp vec4 v_patch_color[];\n"
363 "out highp vec4 " << colorOutputName << ";\n"
368 if (m_case == CASE_TRIANGLES)
369 buf << " vec3 weights = vec3(pow(gl_TessCoord.x, 1.3), pow(gl_TessCoord.y, 1.3), pow(gl_TessCoord.z, 1.3));\n"
370 " vec3 cweights = gl_TessCoord;\n"
371 " gl_Position = vec4(weights.x * gl_in[0].gl_Position.xyz + weights.y * gl_in[1].gl_Position.xyz + weights.z * gl_in[2].gl_Position.xyz, 1.0);\n"
372 " " << colorOutputName << " = cweights.x * v_patch_color[0] + cweights.y * v_patch_color[1] + cweights.z * v_patch_color[2];\n";
373 else if (m_case == CASE_QUADS || m_case == CASE_ISOLINES)
374 buf << " vec2 normalizedCoord = (gl_TessCoord.xy * 2.0 - vec2(1.0));\n"
375 " vec2 normalizedWeights = normalizedCoord * (vec2(1.0) - 0.3 * cos(normalizedCoord.yx * 1.57));\n"
376 " vec2 weights = normalizedWeights * 0.5 + vec2(0.5);\n"
377 " vec2 cweights = gl_TessCoord.xy;\n"
378 " gl_Position = mix(mix(gl_in[0].gl_Position, gl_in[1].gl_Position, weights.y), mix(gl_in[2].gl_Position, gl_in[3].gl_Position, weights.y), weights.x);\n"
379 " " << colorOutputName << " = mix(mix(v_patch_color[0], v_patch_color[1], cweights.y), mix(v_patch_color[2], v_patch_color[3], cweights.y), cweights.x);\n";
388 std::string IdentityGeometryShaderCase::getGeometrySource (void) const
390 const char* const geometryInputPrimitive = (m_case == CASE_ISOLINES) ? ("lines") : ("triangles");
391 const char* const geometryOutputPrimitive = (m_case == CASE_ISOLINES) ? ("line_strip") : ("triangle_strip");
392 const int numEmitVertices = (m_case == CASE_ISOLINES) ? (2) : (3);
393 std::ostringstream buf;
395 buf << "#version 310 es\n"
396 "#extension GL_EXT_geometry_shader : require\n"
397 "layout(" << geometryInputPrimitive << ") in;\n"
398 "layout(" << geometryOutputPrimitive << ", max_vertices=" << numEmitVertices <<") out;\n"
400 "in highp vec4 v_evaluated_color[];\n"
401 "out highp vec4 v_fragment_color;\n"
405 " for (int ndx = 0; ndx < gl_in.length(); ++ndx)\n"
407 " gl_Position = gl_in[ndx].gl_Position;\n"
408 " v_fragment_color = v_evaluated_color[ndx];\n"
416 class IdentityTessellationShaderCase : public IdentityShaderCase
425 IdentityTessellationShaderCase (Context& context, const char* name, const char* description, CaseType caseType);
426 ~IdentityTessellationShaderCase (void);
431 IterateResult iterate (void);
433 std::string getTessellationControlSource (void) const;
434 std::string getTessellationEvaluationSource (void) const;
435 std::string getGeometrySource (bool tessellationActive) const;
442 const CaseType m_case;
443 deUint32 m_dataBuffer;
446 IdentityTessellationShaderCase::IdentityTessellationShaderCase (Context& context, const char* name, const char* description, CaseType caseType)
447 : IdentityShaderCase (context, name, description)
453 IdentityTessellationShaderCase::~IdentityTessellationShaderCase (void)
458 void IdentityTessellationShaderCase::init (void)
462 if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader") ||
463 !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
464 throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader and GL_EXT_geometry_shader extensions");
466 if (m_context.getRenderTarget().getWidth() < RENDER_SIZE ||
467 m_context.getRenderTarget().getHeight() < RENDER_SIZE)
468 throw tcu::NotSupportedError("Test requires " + de::toString<int>(RENDER_SIZE) + "x" + de::toString<int>(RENDER_SIZE) + " or larger render target.");
473 << tcu::TestLog::Message
474 << "Testing geometry shading shader program output does not change when a passthrough tessellation shader is attached.\n"
475 << "Rendering two images, first with and second without a tessellation shader. Expecting similar results.\n"
476 << "Using additive blending to detect overlap.\n"
477 << tcu::TestLog::EndMessage;
482 static const tcu::Vec4 pointData[] =
484 tcu::Vec4( -0.4f, 0.4f, 0.0f, 1.0f ),
485 tcu::Vec4( 0.0f, -0.5f, 0.0f, 1.0f ),
486 tcu::Vec4( 0.4f, 0.4f, 0.0f, 1.0f ),
488 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
490 gl.genBuffers(1, &m_dataBuffer);
491 gl.bindBuffer(GL_ARRAY_BUFFER, m_dataBuffer);
492 gl.bufferData(GL_ARRAY_BUFFER, sizeof(pointData), pointData, GL_STATIC_DRAW);
493 GLU_EXPECT_NO_ERROR(gl.getError(), "gen buffer");
497 void IdentityTessellationShaderCase::deinit (void)
501 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_dataBuffer);
506 IdentityTessellationShaderCase::IterateResult IdentityTessellationShaderCase::iterate (void)
508 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
509 tcu::Surface resultWithTessellation (RENDER_SIZE, RENDER_SIZE);
510 tcu::Surface resultWithoutTessellation (RENDER_SIZE, RENDER_SIZE);
511 const int numPrimitiveVertices = (m_case == CASE_TRIANGLES) ? (3) : (2);
516 const char* description;
517 bool containsTessellationShaders;
518 tcu::PixelBufferAccess surfaceAccess;
521 { "RenderWithTessellationShader", "Render with tessellation shader", true, resultWithTessellation.getAccess() },
522 { "RenderWithoutTessellationShader", "Render without tessellation shader", false, resultWithoutTessellation.getAccess() },
525 gl.viewport(0, 0, RENDER_SIZE, RENDER_SIZE);
526 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
527 GLU_EXPECT_NO_ERROR(gl.getError(), "set viewport");
530 gl.blendFunc(GL_SRC_ALPHA, GL_ONE);
531 gl.blendEquation(GL_FUNC_ADD);
532 GLU_EXPECT_NO_ERROR(gl.getError(), "set blend");
534 // render with and without tessellation shader
535 for (int renderNdx = 0; renderNdx < DE_LENGTH_OF_ARRAY(renderTargets); ++renderNdx)
537 const tcu::ScopedLogSection section (m_testCtx.getLog(), renderTargets[renderNdx].name, renderTargets[renderNdx].description);
538 glu::ProgramSources sources;
540 sources << glu::VertexSource(getVertexSource())
541 << glu::FragmentSource(getFragmentSource())
542 << glu::GeometrySource(getGeometrySource(renderTargets[renderNdx].containsTessellationShaders));
544 if (renderTargets[renderNdx].containsTessellationShaders)
545 sources << glu::TessellationControlSource(getTessellationControlSource())
546 << glu::TessellationEvaluationSource(getTessellationEvaluationSource());
549 const glu::ShaderProgram program (m_context.getRenderContext(), sources);
550 const glu::VertexArray vao (m_context.getRenderContext());
551 const int posLocation = gl.getAttribLocation(program.getProgram(), "a_position");
553 m_testCtx.getLog() << program;
556 throw tcu::TestError("could not build program");
557 if (posLocation == -1)
558 throw tcu::TestError("a_position location was -1");
560 gl.bindVertexArray(*vao);
561 gl.bindBuffer(GL_ARRAY_BUFFER, m_dataBuffer);
562 gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
563 gl.enableVertexAttribArray(posLocation);
564 GLU_EXPECT_NO_ERROR(gl.getError(), "setup attribs");
566 gl.useProgram(program.getProgram());
567 GLU_EXPECT_NO_ERROR(gl.getError(), "use program");
569 gl.clear(GL_COLOR_BUFFER_BIT);
570 GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
572 if (renderTargets[renderNdx].containsTessellationShaders)
574 gl.patchParameteri(GL_PATCH_VERTICES, numPrimitiveVertices);
575 GLU_EXPECT_NO_ERROR(gl.getError(), "set patch param");
577 gl.drawArrays(GL_PATCHES, 0, numPrimitiveVertices);
578 GLU_EXPECT_NO_ERROR(gl.getError(), "draw patches");
582 gl.drawArrays((m_case == CASE_TRIANGLES) ? (GL_TRIANGLES) : (GL_LINES), 0, numPrimitiveVertices);
583 GLU_EXPECT_NO_ERROR(gl.getError(), "draw primitives");
586 glu::readPixels(m_context.getRenderContext(), 0, 0, renderTargets[renderNdx].surfaceAccess);
594 if (m_context.getRenderTarget().getNumSamples() > 1)
595 imageOk = tcu::fuzzyCompare(m_testCtx.getLog(),
598 resultWithoutTessellation.getAccess(),
599 resultWithTessellation.getAccess(),
601 tcu::COMPARE_LOG_RESULT);
603 imageOk = tcu::intThresholdPositionDeviationCompare(m_testCtx.getLog(),
606 resultWithoutTessellation.getAccess(),
607 resultWithTessellation.getAccess(),
608 tcu::UVec4(8, 8, 8, 255), //!< threshold
609 tcu::IVec3(1, 1, 0), //!< 3x3 search kernel
610 true, //!< fragments may end up over the viewport, just ignore them
611 tcu::COMPARE_LOG_RESULT);
614 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
616 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
622 std::string IdentityTessellationShaderCase::getTessellationControlSource (void) const
624 std::ostringstream buf;
626 buf << "#version 310 es\n"
627 "#extension GL_EXT_tessellation_shader : require\n"
628 "layout(vertices = " << ((m_case == CASE_TRIANGLES) ? (3) : (2)) << ") out;\n"
630 "in highp vec4 v_vertex_color[];\n"
631 "out highp vec4 v_control_color[];\n"
635 " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
636 " v_control_color[gl_InvocationID] = v_vertex_color[gl_InvocationID];\n"
639 if (m_case == CASE_TRIANGLES)
640 buf << " gl_TessLevelOuter[0] = 1.0;\n"
641 " gl_TessLevelOuter[1] = 1.0;\n"
642 " gl_TessLevelOuter[2] = 1.0;\n"
643 " gl_TessLevelInner[0] = 1.0;\n";
644 else if (m_case == CASE_ISOLINES)
645 buf << " gl_TessLevelOuter[0] = 1.0;\n"
646 " gl_TessLevelOuter[1] = 1.0;\n";
655 std::string IdentityTessellationShaderCase::getTessellationEvaluationSource (void) const
657 std::ostringstream buf;
659 buf << "#version 310 es\n"
660 "#extension GL_EXT_tessellation_shader : require\n"
662 << ((m_case == CASE_TRIANGLES) ? ("triangles") : ("isolines"))
665 "in highp vec4 v_control_color[];\n"
666 "out highp vec4 v_evaluated_color;\n"
671 if (m_case == CASE_TRIANGLES)
672 buf << " gl_Position = gl_TessCoord.x * gl_in[0].gl_Position + gl_TessCoord.y * gl_in[1].gl_Position + gl_TessCoord.z * gl_in[2].gl_Position;\n"
673 " v_evaluated_color = gl_TessCoord.x * v_control_color[0] + gl_TessCoord.y * v_control_color[1] + gl_TessCoord.z * v_control_color[2];\n";
674 else if (m_case == CASE_ISOLINES)
675 buf << " gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
676 " v_evaluated_color = mix(v_control_color[0], v_control_color[1], gl_TessCoord.x);\n";
685 std::string IdentityTessellationShaderCase::getGeometrySource (bool tessellationActive) const
687 const char* const colorSourceName = (tessellationActive) ? ("v_evaluated_color") : ("v_vertex_color");
688 const char* const geometryInputPrimitive = (m_case == CASE_ISOLINES) ? ("lines") : ("triangles");
689 const char* const geometryOutputPrimitive = (m_case == CASE_ISOLINES) ? ("line_strip") : ("triangle_strip");
690 const int numEmitVertices = (m_case == CASE_ISOLINES) ? (11) : (8);
691 std::ostringstream buf;
693 buf << "#version 310 es\n"
694 "#extension GL_EXT_geometry_shader : require\n"
695 "layout(" << geometryInputPrimitive << ") in;\n"
696 "layout(" << geometryOutputPrimitive << ", max_vertices=" << numEmitVertices <<") out;\n"
698 "in highp vec4 " << colorSourceName << "[];\n"
699 "out highp vec4 v_fragment_color;\n"
704 if (m_case == CASE_TRIANGLES)
706 buf << " vec4 centerPos = (gl_in[0].gl_Position + gl_in[1].gl_Position + gl_in[2].gl_Position) / 3.0f;\n"
708 " for (int ndx = 0; ndx < 4; ++ndx)\n"
710 " gl_Position = centerPos + (centerPos - gl_in[ndx % 3].gl_Position);\n"
711 " v_fragment_color = " << colorSourceName << "[ndx % 3];\n"
714 " gl_Position = centerPos + 0.7 * (centerPos - gl_in[ndx % 3].gl_Position);\n"
715 " v_fragment_color = " << colorSourceName << "[ndx % 3];\n"
720 else if (m_case == CASE_ISOLINES)
722 buf << " vec4 mdir = vec4(gl_in[0].gl_Position.y - gl_in[1].gl_Position.y, gl_in[1].gl_Position.x - gl_in[0].gl_Position.x, 0.0, 0.0);\n"
723 " for (int i = 0; i <= 10; ++i)\n"
725 " float xweight = cos(float(i) / 10.0 * 6.28) * 0.5 + 0.5;\n"
726 " float mweight = sin(float(i) / 10.0 * 6.28) * 0.1 + 0.1;\n"
727 " gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, xweight) + mweight * mdir;\n"
728 " v_fragment_color = mix(" << colorSourceName << "[0], " << colorSourceName << "[1], xweight);\n"
740 class FeedbackPrimitiveTypeCase : public TestCase
743 enum TessellationOutputType
745 TESSELLATION_OUT_TRIANGLES = 0,
746 TESSELLATION_OUT_QUADS,
747 TESSELLATION_OUT_ISOLINES,
749 TESSELLATION_OUT_LAST
751 enum TessellationPointMode
753 TESSELLATION_POINTMODE_OFF = 0,
754 TESSELLATION_POINTMODE_ON,
756 TESSELLATION_POINTMODE_LAST
758 enum GeometryOutputType
760 GEOMETRY_OUTPUT_POINTS = 0,
761 GEOMETRY_OUTPUT_LINES,
762 GEOMETRY_OUTPUT_TRIANGLES,
767 FeedbackPrimitiveTypeCase (Context& context,
769 const char* description,
770 TessellationOutputType tessellationOutput,
771 TessellationPointMode tessellationPointMode,
772 GeometryOutputType geometryOutputType);
773 ~FeedbackPrimitiveTypeCase (void);
778 IterateResult iterate (void);
780 void renderWithFeedback (tcu::Surface& dst);
781 void renderWithoutFeedback (tcu::Surface& dst);
782 void verifyFeedbackResults (const std::vector<tcu::Vec4>& feedbackResult);
783 void verifyRenderedImage (const tcu::Surface& image, const std::vector<tcu::Vec4>& vertices);
785 void genTransformFeedback (void);
786 int getNumGeneratedElementsPerPrimitive (void) const;
787 int getNumGeneratedPrimitives (void) const;
788 int getNumTessellatedPrimitives (void) const;
789 int getGeometryAmplification (void) const;
791 const char* getVertexSource (void) const;
792 const char* getFragmentSource (void) const;
793 std::string getTessellationControlSource (void) const;
794 std::string getTessellationEvaluationSource (void) const;
795 std::string getGeometrySource (void) const;
797 static const char* getTessellationOutputDescription (TessellationOutputType tessellationOutput,
798 TessellationPointMode tessellationPointMode);
799 static const char* getGeometryInputDescription (TessellationOutputType tessellationOutput,
800 TessellationPointMode tessellationPointMode);
801 static const char* getGeometryOutputDescription (GeometryOutputType geometryOutput);
802 glw::GLenum getOutputPrimitiveGLType (void) const;
809 const TessellationOutputType m_tessellationOutput;
810 const TessellationPointMode m_tessellationPointMode;
811 const GeometryOutputType m_geometryOutputType;
813 glu::ShaderProgram* m_feedbackProgram;
814 glu::ShaderProgram* m_nonFeedbackProgram;
815 deUint32 m_patchBuffer;
816 deUint32 m_feedbackID;
817 deUint32 m_feedbackBuffer;
820 FeedbackPrimitiveTypeCase::FeedbackPrimitiveTypeCase (Context& context,
822 const char* description,
823 TessellationOutputType tessellationOutput,
824 TessellationPointMode tessellationPointMode,
825 GeometryOutputType geometryOutputType)
826 : TestCase (context, name, description)
827 , m_tessellationOutput (tessellationOutput)
828 , m_tessellationPointMode (tessellationPointMode)
829 , m_geometryOutputType (geometryOutputType)
830 , m_feedbackProgram (DE_NULL)
831 , m_nonFeedbackProgram (DE_NULL)
834 , m_feedbackBuffer (0)
836 DE_ASSERT(tessellationOutput < TESSELLATION_OUT_LAST);
837 DE_ASSERT(tessellationPointMode < TESSELLATION_POINTMODE_LAST);
838 DE_ASSERT(geometryOutputType < GEOMETRY_OUTPUT_LAST);
841 FeedbackPrimitiveTypeCase::~FeedbackPrimitiveTypeCase (void)
846 void FeedbackPrimitiveTypeCase::init (void)
848 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
852 if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader") ||
853 !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
854 throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader and GL_EXT_geometry_shader extensions");
856 if (m_context.getRenderTarget().getWidth() < RENDER_SIZE ||
857 m_context.getRenderTarget().getHeight() < RENDER_SIZE)
858 throw tcu::NotSupportedError("Test requires " + de::toString<int>(RENDER_SIZE) + "x" + de::toString<int>(RENDER_SIZE) + " or larger render target.");
863 << tcu::TestLog::Message
865 << getTessellationOutputDescription(m_tessellationOutput, m_tessellationPointMode)
867 << getGeometryInputDescription(m_tessellationOutput, m_tessellationPointMode)
868 << " primitive conversion with and without transform feedback.\n"
869 << "Sending a patch of 4 vertices (2x2 uniform grid) to tessellation control shader.\n"
870 << "Control shader emits a patch of 9 vertices (3x3 uniform grid).\n"
871 << "Setting outer tessellation level = 3, inner = 3.\n"
872 << "Primitive generator emits " << getTessellationOutputDescription(m_tessellationOutput, m_tessellationPointMode) << "\n"
873 << "Geometry shader transforms emitted primitives to " << getGeometryOutputDescription(m_geometryOutputType) << "\n"
874 << "Reading back vertex positions of generated primitives using transform feedback.\n"
875 << "Verifying rendered image and feedback vertices are consistent.\n"
876 << "Rendering scene again with identical shader program, but without setting feedback varying. Expecting similar output image."
877 << tcu::TestLog::EndMessage;
882 static const tcu::Vec4 patchBufferData[4] =
884 tcu::Vec4( -0.9f, -0.9f, 0.0f, 1.0f ),
885 tcu::Vec4( -0.9f, 0.9f, 0.0f, 1.0f ),
886 tcu::Vec4( 0.9f, -0.9f, 0.0f, 1.0f ),
887 tcu::Vec4( 0.9f, 0.9f, 0.0f, 1.0f ),
890 gl.genBuffers(1, &m_patchBuffer);
891 gl.bindBuffer(GL_ARRAY_BUFFER, m_patchBuffer);
892 gl.bufferData(GL_ARRAY_BUFFER, sizeof(patchBufferData), patchBufferData, GL_STATIC_DRAW);
893 GLU_EXPECT_NO_ERROR(gl.getError(), "gen buffer");
896 m_feedbackProgram = new glu::ShaderProgram(m_context.getRenderContext(),
897 glu::ProgramSources()
898 << glu::VertexSource(getVertexSource())
899 << glu::FragmentSource(getFragmentSource())
900 << glu::TessellationControlSource(getTessellationControlSource())
901 << glu::TessellationEvaluationSource(getTessellationEvaluationSource())
902 << glu::GeometrySource(getGeometrySource())
903 << glu::TransformFeedbackVarying("tf_someVertexPosition")
904 << glu::TransformFeedbackMode(GL_INTERLEAVED_ATTRIBS));
905 m_testCtx.getLog() << *m_feedbackProgram;
906 if (!m_feedbackProgram->isOk())
907 throw tcu::TestError("failed to build program");
909 m_nonFeedbackProgram = new glu::ShaderProgram(m_context.getRenderContext(),
910 glu::ProgramSources()
911 << glu::VertexSource(getVertexSource())
912 << glu::FragmentSource(getFragmentSource())
913 << glu::TessellationControlSource(getTessellationControlSource())
914 << glu::TessellationEvaluationSource(getTessellationEvaluationSource())
915 << glu::GeometrySource(getGeometrySource()));
916 if (!m_nonFeedbackProgram->isOk())
918 m_testCtx.getLog() << *m_nonFeedbackProgram;
919 throw tcu::TestError("failed to build program");
922 genTransformFeedback();
925 void FeedbackPrimitiveTypeCase::deinit (void)
929 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_patchBuffer);
933 if (m_feedbackBuffer)
935 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_feedbackBuffer);
936 m_feedbackBuffer = 0;
941 m_context.getRenderContext().getFunctions().deleteTransformFeedbacks(1, &m_feedbackID);
945 if (m_feedbackProgram)
947 delete m_feedbackProgram;
948 m_feedbackProgram = DE_NULL;
951 if (m_nonFeedbackProgram)
953 delete m_nonFeedbackProgram;
954 m_nonFeedbackProgram = DE_NULL;
958 FeedbackPrimitiveTypeCase::IterateResult FeedbackPrimitiveTypeCase::iterate (void)
960 tcu::Surface feedbackResult (RENDER_SIZE, RENDER_SIZE);
961 tcu::Surface nonFeedbackResult (RENDER_SIZE, RENDER_SIZE);
963 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
965 // render with and without XFB
966 renderWithFeedback(feedbackResult);
967 renderWithoutFeedback(nonFeedbackResult);
973 m_testCtx.getLog() << tcu::TestLog::Message << "Comparing the image rendered with no transform feedback against the image rendered with enabled transform feedback." << tcu::TestLog::EndMessage;
975 if (m_context.getRenderTarget().getNumSamples() > 1)
976 imageOk = tcu::fuzzyCompare(m_testCtx.getLog(),
979 feedbackResult.getAccess(),
980 nonFeedbackResult.getAccess(),
982 tcu::COMPARE_LOG_RESULT);
984 imageOk = tcu::intThresholdPositionDeviationCompare(m_testCtx.getLog(),
987 feedbackResult.getAccess(),
988 nonFeedbackResult.getAccess(),
989 tcu::UVec4(8, 8, 8, 255), //!< threshold
990 tcu::IVec3(1, 1, 0), //!< 3x3 search kernel
991 true, //!< fragments may end up over the viewport, just ignore them
992 tcu::COMPARE_LOG_RESULT);
995 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
1001 void FeedbackPrimitiveTypeCase::renderWithFeedback(tcu::Surface& dst)
1003 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1004 const glu::VertexArray vao (m_context.getRenderContext());
1005 const glu::Query primitivesGeneratedQuery (m_context.getRenderContext());
1006 const int posLocation = gl.getAttribLocation(m_feedbackProgram->getProgram(), "a_position");
1007 const glw::GLenum feedbackPrimitiveMode = getOutputPrimitiveGLType();
1009 if (posLocation == -1)
1010 throw tcu::TestError("a_position was -1");
1012 m_testCtx.getLog() << tcu::TestLog::Message << "Rendering with transform feedback" << tcu::TestLog::EndMessage;
1014 gl.viewport(0, 0, dst.getWidth(), dst.getHeight());
1015 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1016 gl.clear(GL_COLOR_BUFFER_BIT);
1017 GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
1019 gl.bindVertexArray(*vao);
1020 gl.bindBuffer(GL_ARRAY_BUFFER, m_patchBuffer);
1021 gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
1022 gl.enableVertexAttribArray(posLocation);
1023 GLU_EXPECT_NO_ERROR(gl.getError(), "setup attribs");
1025 gl.useProgram(m_feedbackProgram->getProgram());
1026 GLU_EXPECT_NO_ERROR(gl.getError(), "use program");
1028 gl.patchParameteri(GL_PATCH_VERTICES, 4);
1029 GLU_EXPECT_NO_ERROR(gl.getError(), "set patch param");
1031 gl.beginQuery(GL_PRIMITIVES_GENERATED, *primitivesGeneratedQuery);
1032 GLU_EXPECT_NO_ERROR(gl.getError(), "begin GL_PRIMITIVES_GENERATED query");
1034 m_testCtx.getLog() << tcu::TestLog::Message << "Begin transform feedback with mode " << glu::getPrimitiveTypeStr(feedbackPrimitiveMode) << tcu::TestLog::EndMessage;
1036 gl.beginTransformFeedback(feedbackPrimitiveMode);
1037 GLU_EXPECT_NO_ERROR(gl.getError(), "begin xfb");
1039 m_testCtx.getLog() << tcu::TestLog::Message << "Calling drawArrays with mode GL_PATCHES" << tcu::TestLog::EndMessage;
1041 gl.drawArrays(GL_PATCHES, 0, 4);
1042 GLU_EXPECT_NO_ERROR(gl.getError(), "draw patches");
1044 gl.endTransformFeedback();
1045 GLU_EXPECT_NO_ERROR(gl.getError(), "end xfb");
1047 gl.endQuery(GL_PRIMITIVES_GENERATED);
1048 GLU_EXPECT_NO_ERROR(gl.getError(), "end GL_PRIMITIVES_GENERATED query");
1050 glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
1051 GLU_EXPECT_NO_ERROR(gl.getError(), "readPixels");
1053 // verify GL_PRIMITIVES_GENERATED
1055 glw::GLuint primitivesGeneratedResult = 0;
1056 gl.getQueryObjectuiv(*primitivesGeneratedQuery, GL_QUERY_RESULT, &primitivesGeneratedResult);
1057 GLU_EXPECT_NO_ERROR(gl.getError(), "get GL_PRIMITIVES_GENERATED value");
1059 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying GL_PRIMITIVES_GENERATED, expecting " << getNumGeneratedPrimitives() << tcu::TestLog::EndMessage;
1061 if ((int)primitivesGeneratedResult != getNumGeneratedPrimitives())
1063 m_testCtx.getLog() << tcu::TestLog::Message << "Error, GL_PRIMITIVES_GENERATED was " << primitivesGeneratedResult << tcu::TestLog::EndMessage;
1064 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got unexpected GL_PRIMITIVES_GENERATED");
1067 m_testCtx.getLog() << tcu::TestLog::Message << "GL_PRIMITIVES_GENERATED valid." << tcu::TestLog::EndMessage;
1072 std::vector<tcu::Vec4> feedbackResults (getNumGeneratedElementsPerPrimitive() * getNumGeneratedPrimitives());
1073 const void* mappedPtr = gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, (glw::GLsizeiptr)(feedbackResults.size() * sizeof(tcu::Vec4)), GL_MAP_READ_BIT);
1074 glw::GLboolean unmapResult;
1076 GLU_EXPECT_NO_ERROR(gl.getError(), "mapBufferRange");
1078 m_testCtx.getLog() << tcu::TestLog::Message << "Reading transform feedback buffer." << tcu::TestLog::EndMessage;
1080 throw tcu::TestError("mapBufferRange returned null");
1082 deMemcpy(feedbackResults[0].getPtr(), mappedPtr, (int)(feedbackResults.size() * sizeof(tcu::Vec4)));
1084 unmapResult = gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
1085 GLU_EXPECT_NO_ERROR(gl.getError(), "unmapBuffer");
1087 if (unmapResult != GL_TRUE)
1088 throw tcu::TestError("unmapBuffer failed, did not return true");
1090 // verify transform results
1091 verifyFeedbackResults(feedbackResults);
1093 // verify feedback results are consistent with rendered image
1094 verifyRenderedImage(dst, feedbackResults);
1098 void FeedbackPrimitiveTypeCase::renderWithoutFeedback (tcu::Surface& dst)
1100 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1101 const glu::VertexArray vao (m_context.getRenderContext());
1102 const int posLocation = gl.getAttribLocation(m_nonFeedbackProgram->getProgram(), "a_position");
1104 if (posLocation == -1)
1105 throw tcu::TestError("a_position was -1");
1107 m_testCtx.getLog() << tcu::TestLog::Message << "Rendering without transform feedback" << tcu::TestLog::EndMessage;
1109 gl.viewport(0, 0, dst.getWidth(), dst.getHeight());
1110 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1111 gl.clear(GL_COLOR_BUFFER_BIT);
1112 GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
1114 gl.bindVertexArray(*vao);
1115 gl.bindBuffer(GL_ARRAY_BUFFER, m_patchBuffer);
1116 gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
1117 gl.enableVertexAttribArray(posLocation);
1118 GLU_EXPECT_NO_ERROR(gl.getError(), "setup attribs");
1120 gl.useProgram(m_nonFeedbackProgram->getProgram());
1121 GLU_EXPECT_NO_ERROR(gl.getError(), "use program");
1123 gl.patchParameteri(GL_PATCH_VERTICES, 4);
1124 GLU_EXPECT_NO_ERROR(gl.getError(), "set patch param");
1126 m_testCtx.getLog() << tcu::TestLog::Message << "Calling drawArrays with mode GL_PATCHES" << tcu::TestLog::EndMessage;
1128 gl.drawArrays(GL_PATCHES, 0, 4);
1129 GLU_EXPECT_NO_ERROR(gl.getError(), "draw patches");
1131 glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
1132 GLU_EXPECT_NO_ERROR(gl.getError(), "readPixels");
1135 void FeedbackPrimitiveTypeCase::verifyFeedbackResults (const std::vector<tcu::Vec4>& feedbackResult)
1137 const int geometryAmplification = getGeometryAmplification();
1138 const int elementsPerPrimitive = getNumGeneratedElementsPerPrimitive();
1139 const int errorFloodThreshold = 8;
1143 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying feedback results." << tcu::TestLog::EndMessage;
1145 for (int tessellatedPrimitiveNdx = 0; tessellatedPrimitiveNdx < getNumTessellatedPrimitives(); ++tessellatedPrimitiveNdx)
1147 const tcu::Vec4 primitiveVertex = feedbackResult[readNdx];
1149 // check the generated vertices are in the proper range (range: -0.4 <-> 0.4)
1151 const float equalThreshold = 1.0e-6f;
1152 const bool centroidOk = (primitiveVertex.x() >= -0.4f - equalThreshold) &&
1153 (primitiveVertex.x() <= 0.4f + equalThreshold) &&
1154 (primitiveVertex.y() >= -0.4f - equalThreshold) &&
1155 (primitiveVertex.y() <= 0.4f + equalThreshold) &&
1156 (de::abs(primitiveVertex.z()) < equalThreshold) &&
1157 (de::abs(primitiveVertex.w() - 1.0f) < equalThreshold);
1159 if (!centroidOk && numErrors++ < errorFloodThreshold)
1162 << tcu::TestLog::Message
1163 << "Element at index " << (readNdx) << " (tessellation invocation " << tessellatedPrimitiveNdx << ")\n"
1164 << "\texpected vertex in range: ( [-0.4, 0.4], [-0.4, 0.4], 0.0, 1.0 )\n"
1165 << "\tgot: " << primitiveVertex
1166 << tcu::TestLog::EndMessage;
1168 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "invalid feedback output");
1175 // check all other primitives generated from this tessellated primitive have the same feedback value
1176 for (int generatedPrimitiveNdx = 0; generatedPrimitiveNdx < geometryAmplification; ++generatedPrimitiveNdx)
1177 for (int primitiveVertexNdx = 0; primitiveVertexNdx < elementsPerPrimitive; ++primitiveVertexNdx)
1179 const tcu::Vec4 generatedElementVertex = feedbackResult[readNdx];
1180 const tcu::Vec4 equalThreshold (1.0e-6f);
1182 if (tcu::boolAny(tcu::greaterThan(tcu::abs(primitiveVertex - generatedElementVertex), equalThreshold)))
1184 if (numErrors++ < errorFloodThreshold)
1187 << tcu::TestLog::Message
1188 << "Element at index " << (readNdx) << " (tessellation invocation " << tessellatedPrimitiveNdx << ", geometry primitive " << generatedPrimitiveNdx << ", emitted vertex " << primitiveVertexNdx << "):\n"
1189 << "\tfeedback result was not contant over whole primitive.\n"
1190 << "\tfirst emitted value: " << primitiveVertex << "\n"
1191 << "\tcurrent emitted value:" << generatedElementVertex << "\n"
1192 << tcu::TestLog::EndMessage;
1195 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got multiple different feedback values for a single primitive");
1202 if (numErrors > errorFloodThreshold)
1203 m_testCtx.getLog() << tcu::TestLog::Message << "Omitted " << (numErrors - errorFloodThreshold) << " error(s)." << tcu::TestLog::EndMessage;
1206 static bool feedbackResultCompare (const tcu::Vec4& a, const tcu::Vec4& b)
1213 return a.y() < b.y();
1216 void FeedbackPrimitiveTypeCase::verifyRenderedImage (const tcu::Surface& image, const std::vector<tcu::Vec4>& tfVertices)
1218 std::vector<tcu::Vec4> vertices;
1220 m_testCtx.getLog() << tcu::TestLog::Message << "Comparing result image against feedback results." << tcu::TestLog::EndMessage;
1222 // Check only unique vertices
1223 std::unique_copy(tfVertices.begin(), tfVertices.end(), std::back_insert_iterator<std::vector<tcu::Vec4> >(vertices));
1224 std::sort(vertices.begin(), vertices.end(), feedbackResultCompare);
1225 vertices.erase(std::unique(vertices.begin(), vertices.end()), vertices.end());
1227 // Verifying vertices recorded with feedback actually ended up on the result image
1228 for (int ndx = 0; ndx < (int)vertices.size(); ++ndx)
1230 // Rasterization (of lines) may deviate by one pixel. In addition to that, allow minimal errors in rasterized position vs. feedback result.
1231 // This minimal error could result in a difference in rounding => allow one additional pixel in deviation
1233 const int rasterDeviation = 2;
1234 const tcu::IVec2 rasterPos ((int)deFloatRound((vertices[ndx].x() * 0.5f + 0.5f) * image.getWidth()), (int)deFloatRound((vertices[ndx].y() * 0.5f + 0.5f) * image.getHeight()));
1236 // Find produced rasterization results
1239 for (int dy = -rasterDeviation; dy <= rasterDeviation && !found; ++dy)
1240 for (int dx = -rasterDeviation; dx <= rasterDeviation && !found; ++dx)
1242 // Raster result could end up outside the viewport
1243 if (rasterPos.x() + dx < 0 || rasterPos.x() + dx >= image.getWidth() ||
1244 rasterPos.y() + dy < 0 || rasterPos.y() + dy >= image.getHeight())
1248 const tcu::RGBA result = image.getPixel(rasterPos.x() + dx, rasterPos.y() + dy);
1250 if(!isBlack(result))
1258 << tcu::TestLog::Message
1259 << "Vertex " << vertices[ndx] << "\n"
1260 << "\tCould not find rasterization output for vertex.\n"
1261 << "\tExpected non-black pixels near " << rasterPos
1262 << tcu::TestLog::EndMessage;
1264 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "invalid result image");
1269 void FeedbackPrimitiveTypeCase::genTransformFeedback (void)
1271 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1272 const int elementsPerPrimitive = getNumGeneratedElementsPerPrimitive();
1273 const int feedbackPrimitives = getNumGeneratedPrimitives();
1274 const int feedbackElements = elementsPerPrimitive * feedbackPrimitives;
1275 const std::vector<tcu::Vec4> initialBuffer (feedbackElements, tcu::Vec4(-1.0f, -1.0f, -1.0f, -1.0f));
1277 gl.genTransformFeedbacks(1, &m_feedbackID);
1278 gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_feedbackID);
1279 GLU_EXPECT_NO_ERROR(gl.getError(), "gen transform feedback");
1281 gl.genBuffers(1, &m_feedbackBuffer);
1282 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_feedbackBuffer);
1283 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(tcu::Vec4) * initialBuffer.size(), initialBuffer[0].getPtr(), GL_STATIC_COPY);
1284 GLU_EXPECT_NO_ERROR(gl.getError(), "gen feedback buffer");
1286 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_feedbackBuffer);
1287 GLU_EXPECT_NO_ERROR(gl.getError(), "bind feedback buffer");
1290 static int getTriangleNumOutputPrimitives (int tessellationLevel)
1292 if (tessellationLevel == 1)
1294 else if (tessellationLevel == 2)
1297 return 3 * (2 + 2 * (tessellationLevel - 2)) + getTriangleNumOutputPrimitives(tessellationLevel - 2);
1300 static int getTriangleNumOutputPrimitivesPoints (int tessellationLevel)
1302 if (tessellationLevel == 0)
1304 else if (tessellationLevel == 1)
1307 return 3 + 3 * (tessellationLevel - 1) + getTriangleNumOutputPrimitivesPoints(tessellationLevel - 2);
1310 int FeedbackPrimitiveTypeCase::getNumGeneratedElementsPerPrimitive (void) const
1312 if (m_geometryOutputType == GEOMETRY_OUTPUT_TRIANGLES)
1314 else if (m_geometryOutputType == GEOMETRY_OUTPUT_LINES)
1316 else if (m_geometryOutputType == GEOMETRY_OUTPUT_POINTS)
1325 int FeedbackPrimitiveTypeCase::getNumGeneratedPrimitives (void) const
1327 return getNumTessellatedPrimitives() * getGeometryAmplification();
1330 int FeedbackPrimitiveTypeCase::getNumTessellatedPrimitives (void) const
1332 const int tessellationLevel = 3;
1334 if (m_tessellationPointMode == TESSELLATION_POINTMODE_OFF)
1336 if (m_tessellationOutput == TESSELLATION_OUT_TRIANGLES)
1337 return getTriangleNumOutputPrimitives(tessellationLevel);
1338 else if (m_tessellationOutput == TESSELLATION_OUT_QUADS)
1339 return tessellationLevel * tessellationLevel * 2; // tessellated as triangles
1340 else if (m_tessellationOutput == TESSELLATION_OUT_ISOLINES)
1341 return tessellationLevel * tessellationLevel;
1343 else if (m_tessellationPointMode == TESSELLATION_POINTMODE_ON)
1345 if (m_tessellationOutput == TESSELLATION_OUT_TRIANGLES)
1346 return getTriangleNumOutputPrimitivesPoints(tessellationLevel);
1347 else if (m_tessellationOutput == TESSELLATION_OUT_QUADS)
1348 return (tessellationLevel + 1) * (tessellationLevel + 1);
1349 else if (m_tessellationOutput == TESSELLATION_OUT_ISOLINES)
1350 return tessellationLevel * (tessellationLevel + 1);
1357 int FeedbackPrimitiveTypeCase::getGeometryAmplification (void) const
1359 const int outputAmplification = (m_geometryOutputType == GEOMETRY_OUTPUT_LINES) ? (2) : (1);
1360 const int numInputVertices = (m_tessellationPointMode) ? (1) : (m_tessellationOutput == TESSELLATION_OUT_ISOLINES) ? (2) : (3);
1362 return outputAmplification * numInputVertices;
1365 glw::GLenum FeedbackPrimitiveTypeCase::getOutputPrimitiveGLType (void) const
1367 if (m_geometryOutputType == GEOMETRY_OUTPUT_TRIANGLES)
1368 return GL_TRIANGLES;
1369 else if (m_geometryOutputType == GEOMETRY_OUTPUT_LINES)
1371 else if (m_geometryOutputType == GEOMETRY_OUTPUT_POINTS)
1380 const char* FeedbackPrimitiveTypeCase::getVertexSource (void) const
1382 return s_positionVertexShader;
1385 const char* FeedbackPrimitiveTypeCase::getFragmentSource (void) const
1387 return s_whiteOutputFragmentShader;
1390 std::string FeedbackPrimitiveTypeCase::getTessellationControlSource (void) const
1392 std::ostringstream buf;
1394 buf << "#version 310 es\n"
1395 "#extension GL_EXT_tessellation_shader : require\n"
1396 "layout(vertices = 9) out;\n"
1398 "uniform highp float u_innerTessellationLevel;\n"
1399 "uniform highp float u_outerTessellationLevel;\n"
1401 "void main (void)\n"
1403 " if (gl_PatchVerticesIn != 4)\n"
1406 " // Convert input 2x2 grid to 3x3 grid\n"
1407 " float xweight = float(gl_InvocationID % 3) / 2.0f;\n"
1408 " float yweight = float(gl_InvocationID / 3) / 2.0f;\n"
1410 " vec4 y0 = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, yweight);\n"
1411 " vec4 y1 = mix(gl_in[2].gl_Position, gl_in[3].gl_Position, yweight);\n"
1413 " gl_out[gl_InvocationID].gl_Position = mix(y0, y1, xweight);\n"
1416 if (m_tessellationOutput == TESSELLATION_OUT_TRIANGLES)
1417 buf << " gl_TessLevelOuter[0] = 3.0;\n"
1418 " gl_TessLevelOuter[1] = 3.0;\n"
1419 " gl_TessLevelOuter[2] = 3.0;\n"
1420 " gl_TessLevelInner[0] = 3.0;\n";
1421 else if (m_tessellationOutput == TESSELLATION_OUT_QUADS)
1422 buf << " gl_TessLevelOuter[0] = 3.0;\n"
1423 " gl_TessLevelOuter[1] = 3.0;\n"
1424 " gl_TessLevelOuter[2] = 3.0;\n"
1425 " gl_TessLevelOuter[3] = 3.0;\n"
1426 " gl_TessLevelInner[0] = 3.0;\n"
1427 " gl_TessLevelInner[1] = 3.0;\n";
1428 else if (m_tessellationOutput == TESSELLATION_OUT_ISOLINES)
1429 buf << " gl_TessLevelOuter[0] = 3.0;\n"
1430 " gl_TessLevelOuter[1] = 3.0;\n";
1439 std::string FeedbackPrimitiveTypeCase::getTessellationEvaluationSource (void) const
1441 std::ostringstream buf;
1443 buf << "#version 310 es\n"
1444 "#extension GL_EXT_tessellation_shader : require\n"
1446 << ((m_tessellationOutput == TESSELLATION_OUT_TRIANGLES) ? ("triangles") : (m_tessellationOutput == TESSELLATION_OUT_QUADS) ? ("quads") : ("isolines"))
1447 << ((m_tessellationPointMode) ? (", point_mode") : (""))
1450 "out highp vec4 v_tessellationCoords;\n"
1452 "void main (void)\n"
1454 " if (gl_PatchVerticesIn != 9)\n"
1457 " vec4 patchCentroid = vec4(0.0);\n"
1458 " for (int ndx = 0; ndx < gl_PatchVerticesIn; ++ndx)\n"
1459 " patchCentroid += gl_in[ndx].gl_Position;\n"
1460 " patchCentroid /= patchCentroid.w;\n"
1463 if (m_tessellationOutput == TESSELLATION_OUT_TRIANGLES)
1464 buf << " // map barycentric coords to 2d coords\n"
1465 " const vec3 tessDirX = vec3( 0.4, 0.4, 0.0);\n"
1466 " const vec3 tessDirY = vec3( 0.0, -0.4, 0.0);\n"
1467 " const vec3 tessDirZ = vec3(-0.4, 0.4, 0.0);\n"
1468 " gl_Position = patchCentroid + vec4(gl_TessCoord.x * tessDirX + gl_TessCoord.y * tessDirY + gl_TessCoord.z * tessDirZ, 0.0);\n";
1469 else if (m_tessellationOutput == TESSELLATION_OUT_QUADS || m_tessellationOutput == TESSELLATION_OUT_ISOLINES)
1470 buf << " gl_Position = patchCentroid + vec4(gl_TessCoord.x * 0.8 - 0.4, gl_TessCoord.y * 0.8 - 0.4, 0.0, 0.0);\n";
1474 buf << " v_tessellationCoords = vec4(gl_TessCoord, 0.0);\n"
1480 std::string FeedbackPrimitiveTypeCase::getGeometrySource (void) const
1482 const char* const geometryInputPrimitive = (m_tessellationPointMode) ? ("points") : (m_tessellationOutput == TESSELLATION_OUT_ISOLINES) ? ("lines") : ("triangles");
1483 const char* const geometryOutputPrimitive = (m_geometryOutputType == GEOMETRY_OUTPUT_POINTS) ? ("points") : (m_geometryOutputType == GEOMETRY_OUTPUT_LINES) ? ("line_strip") : ("triangle_strip");
1484 const int numInputVertices = (m_tessellationPointMode) ? (1) : (m_tessellationOutput == TESSELLATION_OUT_ISOLINES) ? (2) : (3);
1485 const int numSingleVertexOutputVertices = (m_geometryOutputType == GEOMETRY_OUTPUT_POINTS) ? (1) : (m_geometryOutputType == GEOMETRY_OUTPUT_LINES) ? (4) : (3);
1486 const int numEmitVertices = numInputVertices * numSingleVertexOutputVertices;
1487 std::ostringstream buf;
1489 buf << "#version 310 es\n"
1490 "#extension GL_EXT_geometry_shader : require\n"
1491 "layout(" << geometryInputPrimitive << ") in;\n"
1492 "layout(" << geometryOutputPrimitive << ", max_vertices=" << numEmitVertices <<") out;\n"
1494 "in highp vec4 v_tessellationCoords[];\n"
1495 "out highp vec4 tf_someVertexPosition;\n"
1497 "void main (void)\n"
1499 " // Emit primitive\n"
1500 " for (int ndx = 0; ndx < gl_in.length(); ++ndx)\n"
1503 switch (m_geometryOutputType)
1505 case GEOMETRY_OUTPUT_POINTS:
1506 buf << " // Draw point on vertex\n"
1507 " gl_Position = gl_in[ndx].gl_Position;\n"
1508 " tf_someVertexPosition = gl_in[gl_in.length() - 1].gl_Position;\n"
1512 case GEOMETRY_OUTPUT_LINES:
1513 buf << " // Draw cross on vertex\n"
1514 " gl_Position = gl_in[ndx].gl_Position + vec4(-0.02, -0.02, 0.0, 0.0);\n"
1515 " tf_someVertexPosition = gl_in[gl_in.length() - 1].gl_Position;\n"
1517 " gl_Position = gl_in[ndx].gl_Position + vec4( 0.02, 0.02, 0.0, 0.0);\n"
1518 " tf_someVertexPosition = gl_in[gl_in.length() - 1].gl_Position;\n"
1520 " EndPrimitive();\n"
1521 " gl_Position = gl_in[ndx].gl_Position + vec4( 0.02, -0.02, 0.0, 0.0);\n"
1522 " tf_someVertexPosition = gl_in[gl_in.length() - 1].gl_Position;\n"
1524 " gl_Position = gl_in[ndx].gl_Position + vec4(-0.02, 0.02, 0.0, 0.0);\n"
1525 " tf_someVertexPosition = gl_in[gl_in.length() - 1].gl_Position;\n"
1527 " EndPrimitive();\n";
1530 case GEOMETRY_OUTPUT_TRIANGLES:
1531 buf << " // Draw triangle on vertex\n"
1532 " gl_Position = gl_in[ndx].gl_Position + vec4( 0.00, -0.02, 0.0, 0.0);\n"
1533 " tf_someVertexPosition = gl_in[gl_in.length() - 1].gl_Position;\n"
1535 " gl_Position = gl_in[ndx].gl_Position + vec4( 0.02, 0.00, 0.0, 0.0);\n"
1536 " tf_someVertexPosition = gl_in[gl_in.length() - 1].gl_Position;\n"
1538 " gl_Position = gl_in[ndx].gl_Position + vec4( -0.02, 0.00, 0.0, 0.0);\n"
1539 " tf_someVertexPosition = gl_in[gl_in.length() - 1].gl_Position;\n"
1541 " EndPrimitive();\n";
1555 const char* FeedbackPrimitiveTypeCase::getTessellationOutputDescription (TessellationOutputType tessellationOutput, TessellationPointMode pointMode)
1557 switch (tessellationOutput)
1559 case TESSELLATION_OUT_TRIANGLES: return (pointMode) ? ("points (triangles in point mode)") : ("triangles");
1560 case TESSELLATION_OUT_QUADS: return (pointMode) ? ("points (quads in point mode)") : ("quads");
1561 case TESSELLATION_OUT_ISOLINES: return (pointMode) ? ("points (isolines in point mode)") : ("isolines");
1568 const char* FeedbackPrimitiveTypeCase::getGeometryInputDescription (TessellationOutputType tessellationOutput, TessellationPointMode pointMode)
1570 switch (tessellationOutput)
1572 case TESSELLATION_OUT_TRIANGLES: return (pointMode) ? ("points") : ("triangles");
1573 case TESSELLATION_OUT_QUADS: return (pointMode) ? ("points") : ("triangles");
1574 case TESSELLATION_OUT_ISOLINES: return (pointMode) ? ("points") : ("lines");
1581 const char* FeedbackPrimitiveTypeCase::getGeometryOutputDescription (GeometryOutputType geometryOutput)
1583 switch (geometryOutput)
1585 case GEOMETRY_OUTPUT_POINTS: return "points";
1586 case GEOMETRY_OUTPUT_LINES: return "lines";
1587 case GEOMETRY_OUTPUT_TRIANGLES: return "triangles";
1594 class PointSizeCase : public TestCase
1599 FLAG_VERTEX_SET = 0x01, // !< set gl_PointSize in vertex shader
1600 FLAG_TESSELLATION_CONTROL_SET = 0x02, // !< set gl_PointSize in tessellation evaluation shader
1601 FLAG_TESSELLATION_EVALUATION_SET = 0x04, // !< set gl_PointSize in tessellation control shader
1602 FLAG_TESSELLATION_ADD = 0x08, // !< read and add to gl_PointSize in tessellation shader pair
1603 FLAG_TESSELLATION_DONT_SET = 0x10, // !< don't set gl_PointSize in tessellation shader
1604 FLAG_GEOMETRY_SET = 0x20, // !< set gl_PointSize in geometry shader
1605 FLAG_GEOMETRY_ADD = 0x40, // !< read and add to gl_PointSize in geometry shader
1606 FLAG_GEOMETRY_DONT_SET = 0x80, // !< don't set gl_PointSize in geometry shader
1609 PointSizeCase (Context& context, const char* name, const char* description, int flags);
1610 ~PointSizeCase (void);
1612 static std::string genTestCaseName (int flags);
1613 static std::string genTestCaseDescription (int flags);
1618 IterateResult iterate (void);
1620 void checkExtensions (void) const;
1621 void checkPointSizeRequirements (void) const;
1623 void renderTo (tcu::Surface& dst);
1624 bool verifyImage (const tcu::Surface& src);
1625 int getExpectedPointSize (void) const;
1627 std::string genVertexSource (void) const;
1628 const char* genFragmentSource (void) const;
1629 std::string genTessellationControlSource (void) const;
1630 std::string genTessellationEvaluationSource (void) const;
1631 std::string genGeometrySource (void) const;
1639 glu::ShaderProgram* m_program;
1642 PointSizeCase::PointSizeCase (Context& context, const char* name, const char* description, int flags)
1643 : TestCase (context, name, description)
1645 , m_program (DE_NULL)
1649 PointSizeCase::~PointSizeCase (void)
1654 std::string PointSizeCase::genTestCaseName (int flags)
1656 std::ostringstream buf;
1658 // join per-bit descriptions into a single string with '_' separator
1659 if (flags & FLAG_VERTEX_SET) buf << "vertex_set";
1660 if (flags & FLAG_TESSELLATION_CONTROL_SET) buf << ((flags & (FLAG_TESSELLATION_CONTROL_SET-1)) ? ("_") : ("")) << "control_set";
1661 if (flags & FLAG_TESSELLATION_EVALUATION_SET) buf << ((flags & (FLAG_TESSELLATION_EVALUATION_SET-1)) ? ("_") : ("")) << "evaluation_set";
1662 if (flags & FLAG_TESSELLATION_ADD) buf << ((flags & (FLAG_TESSELLATION_ADD-1)) ? ("_") : ("")) << "control_pass_eval_add";
1663 if (flags & FLAG_TESSELLATION_DONT_SET) buf << ((flags & (FLAG_TESSELLATION_DONT_SET-1)) ? ("_") : ("")) << "eval_default";
1664 if (flags & FLAG_GEOMETRY_SET) buf << ((flags & (FLAG_GEOMETRY_SET-1)) ? ("_") : ("")) << "geometry_set";
1665 if (flags & FLAG_GEOMETRY_ADD) buf << ((flags & (FLAG_GEOMETRY_ADD-1)) ? ("_") : ("")) << "geometry_add";
1666 if (flags & FLAG_GEOMETRY_DONT_SET) buf << ((flags & (FLAG_GEOMETRY_DONT_SET-1)) ? ("_") : ("")) << "geometry_default";
1671 std::string PointSizeCase::genTestCaseDescription (int flags)
1673 std::ostringstream buf;
1675 // join per-bit descriptions into a single string with ", " separator
1676 if (flags & FLAG_VERTEX_SET) buf << "set point size in vertex shader";
1677 if (flags & FLAG_TESSELLATION_CONTROL_SET) buf << ((flags & (FLAG_TESSELLATION_CONTROL_SET-1)) ? (", ") : ("")) << "set point size in tessellation control shader";
1678 if (flags & FLAG_TESSELLATION_EVALUATION_SET) buf << ((flags & (FLAG_TESSELLATION_EVALUATION_SET-1)) ? (", ") : ("")) << "set point size in tessellation evaluation shader";
1679 if (flags & FLAG_TESSELLATION_ADD) buf << ((flags & (FLAG_TESSELLATION_ADD-1)) ? (", ") : ("")) << "add to point size in tessellation shader";
1680 if (flags & FLAG_TESSELLATION_DONT_SET) buf << ((flags & (FLAG_TESSELLATION_DONT_SET-1)) ? (", ") : ("")) << "don't set point size in tessellation evaluation shader";
1681 if (flags & FLAG_GEOMETRY_SET) buf << ((flags & (FLAG_GEOMETRY_SET-1)) ? (", ") : ("")) << "set point size in geometry shader";
1682 if (flags & FLAG_GEOMETRY_ADD) buf << ((flags & (FLAG_GEOMETRY_ADD-1)) ? (", ") : ("")) << "add to point size in geometry shader";
1683 if (flags & FLAG_GEOMETRY_DONT_SET) buf << ((flags & (FLAG_GEOMETRY_DONT_SET-1)) ? (", ") : ("")) << "don't set point size in geometry shader";
1688 void PointSizeCase::init (void)
1691 checkPointSizeRequirements();
1695 if (m_flags & FLAG_VERTEX_SET)
1696 m_testCtx.getLog() << tcu::TestLog::Message << "Setting point size in vertex shader to 2.0." << tcu::TestLog::EndMessage;
1697 if (m_flags & FLAG_TESSELLATION_CONTROL_SET)
1698 m_testCtx.getLog() << tcu::TestLog::Message << "Setting point size in tessellation control shader to 4.0. (And ignoring it in evaluation)." << tcu::TestLog::EndMessage;
1699 if (m_flags & FLAG_TESSELLATION_EVALUATION_SET)
1700 m_testCtx.getLog() << tcu::TestLog::Message << "Setting point size in tessellation evaluation shader to 4.0." << tcu::TestLog::EndMessage;
1701 if (m_flags & FLAG_TESSELLATION_ADD)
1702 m_testCtx.getLog() << tcu::TestLog::Message << "Reading point size in tessellation control shader and adding 2.0 to it in evaluation." << tcu::TestLog::EndMessage;
1703 if (m_flags & FLAG_TESSELLATION_DONT_SET)
1704 m_testCtx.getLog() << tcu::TestLog::Message << "Not setting point size in tessellation evaluation shader (resulting in the default point size)." << tcu::TestLog::EndMessage;
1705 if (m_flags & FLAG_GEOMETRY_SET)
1706 m_testCtx.getLog() << tcu::TestLog::Message << "Setting point size in geometry shader to 6.0." << tcu::TestLog::EndMessage;
1707 if (m_flags & FLAG_GEOMETRY_ADD)
1708 m_testCtx.getLog() << tcu::TestLog::Message << "Reading point size in geometry shader and adding 2.0." << tcu::TestLog::EndMessage;
1709 if (m_flags & FLAG_GEOMETRY_DONT_SET)
1710 m_testCtx.getLog() << tcu::TestLog::Message << "Not setting point size in geometry shader (resulting in the default point size)." << tcu::TestLog::EndMessage;
1715 glu::ProgramSources sources;
1716 sources << glu::VertexSource(genVertexSource())
1717 << glu::FragmentSource(genFragmentSource());
1719 if (m_flags & (FLAG_TESSELLATION_CONTROL_SET | FLAG_TESSELLATION_EVALUATION_SET | FLAG_TESSELLATION_ADD | FLAG_TESSELLATION_DONT_SET))
1720 sources << glu::TessellationControlSource(genTessellationControlSource())
1721 << glu::TessellationEvaluationSource(genTessellationEvaluationSource());
1723 if (m_flags & (FLAG_GEOMETRY_SET | FLAG_GEOMETRY_ADD | FLAG_GEOMETRY_DONT_SET))
1724 sources << glu::GeometrySource(genGeometrySource());
1726 m_program = new glu::ShaderProgram(m_context.getRenderContext(), sources);
1728 m_testCtx.getLog() << *m_program;
1729 if (!m_program->isOk())
1730 throw tcu::TestError("failed to build program");
1734 void PointSizeCase::deinit (void)
1737 m_program = DE_NULL;
1740 PointSizeCase::IterateResult PointSizeCase::iterate (void)
1742 tcu::Surface resultImage(RENDER_SIZE, RENDER_SIZE);
1744 renderTo(resultImage);
1746 if (verifyImage(resultImage))
1747 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1749 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
1754 void PointSizeCase::checkExtensions (void) const
1756 std::vector<std::string> requiredExtensions;
1759 if (m_flags & (FLAG_TESSELLATION_CONTROL_SET | FLAG_TESSELLATION_EVALUATION_SET | FLAG_TESSELLATION_ADD | FLAG_TESSELLATION_DONT_SET))
1760 requiredExtensions.push_back("GL_EXT_tessellation_shader");
1762 if (m_flags & (FLAG_TESSELLATION_CONTROL_SET | FLAG_TESSELLATION_EVALUATION_SET | FLAG_TESSELLATION_ADD))
1763 requiredExtensions.push_back("GL_EXT_tessellation_point_size");
1765 if (m_flags & (m_flags & (FLAG_GEOMETRY_SET | FLAG_GEOMETRY_ADD | FLAG_GEOMETRY_DONT_SET)))
1766 requiredExtensions.push_back("GL_EXT_geometry_shader");
1768 if (m_flags & (m_flags & (FLAG_GEOMETRY_SET | FLAG_GEOMETRY_ADD)))
1769 requiredExtensions.push_back("GL_EXT_geometry_point_size");
1771 for (int ndx = 0; ndx < (int)requiredExtensions.size(); ++ndx)
1772 if (!m_context.getContextInfo().isExtensionSupported(requiredExtensions[ndx].c_str()))
1777 std::ostringstream extensionList;
1779 for (int ndx = 0; ndx < (int)requiredExtensions.size(); ++ndx)
1782 extensionList << ", ";
1783 extensionList << requiredExtensions[ndx];
1786 throw tcu::NotSupportedError("Test requires {" + extensionList.str() + "} extension(s)");
1790 void PointSizeCase::checkPointSizeRequirements (void) const
1792 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1793 float aliasedSizeRange[2] = { 0.0f, 0.0f };
1794 const int requiredSize = getExpectedPointSize();
1796 gl.getFloatv(GL_ALIASED_POINT_SIZE_RANGE, aliasedSizeRange);
1798 if (float(requiredSize) > aliasedSizeRange[1])
1799 throw tcu::NotSupportedError("Test requires point size " + de::toString(requiredSize));
1802 void PointSizeCase::renderTo (tcu::Surface& dst)
1804 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1805 const bool tessellationActive = (m_flags & (FLAG_TESSELLATION_CONTROL_SET | FLAG_TESSELLATION_EVALUATION_SET | FLAG_TESSELLATION_ADD | FLAG_TESSELLATION_DONT_SET)) != 0;
1806 const int positionLocation = gl.getAttribLocation(m_program->getProgram(), "a_position");
1807 const glu::VertexArray vao (m_context.getRenderContext());
1809 m_testCtx.getLog() << tcu::TestLog::Message << "Rendering single point." << tcu::TestLog::EndMessage;
1811 if (positionLocation == -1)
1812 throw tcu::TestError("Attribute a_position location was -1");
1814 gl.viewport(0, 0, RENDER_SIZE, RENDER_SIZE);
1815 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1816 gl.clear(GL_COLOR_BUFFER_BIT);
1817 GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
1819 gl.bindVertexArray(*vao);
1820 GLU_EXPECT_NO_ERROR(gl.getError(), "bind vao");
1822 gl.useProgram(m_program->getProgram());
1823 GLU_EXPECT_NO_ERROR(gl.getError(), "use program");
1825 gl.vertexAttrib4f(positionLocation, 0.0f, 0.0f, 0.0f, 1.0f);
1827 if (tessellationActive)
1829 gl.patchParameteri(GL_PATCH_VERTICES, 1);
1830 GLU_EXPECT_NO_ERROR(gl.getError(), "set patch param");
1832 gl.drawArrays(GL_PATCHES, 0, 1);
1833 GLU_EXPECT_NO_ERROR(gl.getError(), "draw patches");
1837 gl.drawArrays(GL_POINTS, 0, 1);
1838 GLU_EXPECT_NO_ERROR(gl.getError(), "draw points");
1841 glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
1844 bool PointSizeCase::verifyImage (const tcu::Surface& src)
1846 const bool MSAATarget = (m_context.getRenderTarget().getNumSamples() > 1);
1847 const int expectedSize = getExpectedPointSize();
1849 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying rendered point size. Expecting " << expectedSize << " pixels." << tcu::TestLog::EndMessage;
1850 m_testCtx.getLog() << tcu::TestLog::Image("RenderImage", "Rendered image", src.getAccess());
1853 bool resultAreaFound = false;
1854 tcu::IVec4 resultArea;
1856 // Find rasterization output area
1858 for (int y = 0; y < src.getHeight(); ++y)
1859 for (int x = 0; x < src.getWidth(); ++x)
1861 if (!isBlack(src.getPixel(x, y)))
1863 if (!resultAreaFound)
1866 resultArea = tcu::IVec4(x, y, x + 1, y + 1);
1867 resultAreaFound = true;
1872 resultArea.x() = de::min(resultArea.x(), x);
1873 resultArea.y() = de::min(resultArea.y(), y);
1874 resultArea.z() = de::max(resultArea.z(), x+1);
1875 resultArea.w() = de::max(resultArea.w(), y+1);
1880 if (!resultAreaFound)
1882 m_testCtx.getLog() << tcu::TestLog::Message << "Verification failed, could not find any point fragments." << tcu::TestLog::EndMessage;
1889 const tcu::IVec2 pointSize = resultArea.swizzle(2,3) - resultArea.swizzle(0, 1);
1891 // MSAA: edges may be a little fuzzy
1892 if (de::abs(pointSize.x() - pointSize.y()) > 1)
1894 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Rasterized point is not a square. Detected point size was " << pointSize << tcu::TestLog::EndMessage;
1898 // MSAA may produce larger areas, allow one pixel larger
1899 if (expectedSize != de::max(pointSize.x(), pointSize.y()) && (expectedSize+1) != de::max(pointSize.x(), pointSize.y()))
1901 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Point size invalid, expected " << expectedSize << ", got " << de::max(pointSize.x(), pointSize.y()) << tcu::TestLog::EndMessage;
1907 const tcu::IVec2 pointSize = resultArea.swizzle(2,3) - resultArea.swizzle(0, 1);
1909 if (pointSize.x() != pointSize.y())
1911 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Rasterized point is not a square. Point size was " << pointSize << tcu::TestLog::EndMessage;
1915 if (pointSize.x() != expectedSize)
1917 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Point size invalid, expected " << expectedSize << ", got " << pointSize.x() << tcu::TestLog::EndMessage;
1926 int PointSizeCase::getExpectedPointSize (void) const
1931 if (m_flags & FLAG_GEOMETRY_DONT_SET)
1933 else if (m_flags & FLAG_GEOMETRY_SET)
1935 else if (m_flags & FLAG_GEOMETRY_ADD)
1939 if (m_flags & FLAG_TESSELLATION_EVALUATION_SET)
1940 return 4 + addition;
1941 else if (m_flags & FLAG_TESSELLATION_ADD)
1943 else if (m_flags & (FLAG_TESSELLATION_CONTROL_SET | FLAG_TESSELLATION_DONT_SET))
1945 DE_ASSERT((m_flags & FLAG_GEOMETRY_ADD) == 0); // reading pointSize undefined
1950 if (m_flags & FLAG_VERTEX_SET)
1951 return 2 + addition;
1958 std::string PointSizeCase::genVertexSource (void) const
1960 std::ostringstream buf;
1962 buf << "#version 310 es\n"
1963 << "in highp vec4 a_position;\n"
1966 << " gl_Position = a_position;\n";
1968 if (m_flags & FLAG_VERTEX_SET)
1969 buf << " gl_PointSize = 2.0;\n";
1976 const char* PointSizeCase::genFragmentSource (void) const
1978 return s_whiteOutputFragmentShader;
1981 std::string PointSizeCase::genTessellationControlSource (void) const
1983 std::ostringstream buf;
1985 buf << "#version 310 es\n"
1986 << "#extension GL_EXT_tessellation_shader : require\n"
1987 << ((m_flags & FLAG_TESSELLATION_DONT_SET) ? ("") : ("#extension GL_EXT_tessellation_point_size : require\n"))
1988 << "layout(vertices = 1) out;\n"
1991 << " gl_TessLevelOuter[0] = 3.0;\n"
1992 << " gl_TessLevelOuter[1] = 3.0;\n"
1993 << " gl_TessLevelOuter[2] = 3.0;\n"
1994 << " gl_TessLevelInner[0] = 3.0;\n"
1995 << " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n";
1997 if (m_flags & FLAG_TESSELLATION_ADD)
1998 buf << " // pass as is to eval\n"
1999 << " gl_out[gl_InvocationID].gl_PointSize = gl_in[gl_InvocationID].gl_PointSize;\n";
2000 else if (m_flags & FLAG_TESSELLATION_CONTROL_SET)
2001 buf << " // thrown away\n"
2002 << " gl_out[gl_InvocationID].gl_PointSize = 4.0;\n";
2009 std::string PointSizeCase::genTessellationEvaluationSource (void) const
2011 std::ostringstream buf;
2013 buf << "#version 310 es\n"
2014 << "#extension GL_EXT_tessellation_shader : require\n"
2015 << ((m_flags & FLAG_TESSELLATION_DONT_SET) ? ("") : ("#extension GL_EXT_tessellation_point_size : require\n"))
2016 << "layout(triangles, point_mode) in;\n"
2019 << " // hide all but one vertex\n"
2020 << " if (gl_TessCoord.x < 0.99)\n"
2021 << " gl_Position = vec4(-2.0, 0.0, 0.0, 1.0);\n"
2023 << " gl_Position = gl_in[0].gl_Position;\n";
2025 if (m_flags & FLAG_TESSELLATION_ADD)
2027 << " // add to point size\n"
2028 << " gl_PointSize = gl_in[0].gl_PointSize + 2.0;\n";
2029 else if (m_flags & FLAG_TESSELLATION_EVALUATION_SET)
2031 << " // set point size\n"
2032 << " gl_PointSize = 4.0;\n";
2039 std::string PointSizeCase::genGeometrySource (void) const
2041 std::ostringstream buf;
2043 buf << "#version 310 es\n"
2044 << "#extension GL_EXT_geometry_shader : require\n"
2045 << ((m_flags & FLAG_GEOMETRY_DONT_SET) ? ("") : ("#extension GL_EXT_geometry_point_size : require\n"))
2046 << "layout (points) in;\n"
2047 << "layout (points, max_vertices=1) out;\n"
2052 if (m_flags & FLAG_GEOMETRY_SET)
2053 buf << " gl_Position = gl_in[0].gl_Position;\n"
2054 << " gl_PointSize = 6.0;\n";
2055 else if (m_flags & FLAG_GEOMETRY_ADD)
2056 buf << " gl_Position = gl_in[0].gl_Position;\n"
2057 << " gl_PointSize = gl_in[0].gl_PointSize + 2.0;\n";
2058 else if (m_flags & FLAG_GEOMETRY_DONT_SET)
2059 buf << " gl_Position = gl_in[0].gl_Position;\n";
2061 buf << " EmitVertex();\n"
2067 class AllowedRenderFailureException : public std::runtime_error
2070 AllowedRenderFailureException (const char* message) : std::runtime_error(message) { }
2073 class GridRenderCase : public TestCase
2078 FLAG_TESSELLATION_MAX_SPEC = 0x0001,
2079 FLAG_TESSELLATION_MAX_IMPLEMENTATION = 0x0002,
2080 FLAG_GEOMETRY_MAX_SPEC = 0x0004,
2081 FLAG_GEOMETRY_MAX_IMPLEMENTATION = 0x0008,
2082 FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC = 0x0010,
2083 FLAG_GEOMETRY_INVOCATIONS_MAX_IMPLEMENTATION = 0x0020,
2085 FLAG_GEOMETRY_SCATTER_INSTANCES = 0x0040,
2086 FLAG_GEOMETRY_SCATTER_PRIMITIVES = 0x0080,
2087 FLAG_GEOMETRY_SEPARATE_PRIMITIVES = 0x0100, //!< if set, geometry shader outputs separate grid cells and not continuous slices
2088 FLAG_GEOMETRY_SCATTER_LAYERS = 0x0200,
2090 FLAG_ALLOW_OUT_OF_MEMORY = 0x0400, //!< allow draw command to set GL_OUT_OF_MEMORY
2093 GridRenderCase (Context& context, const char* name, const char* description, int flags);
2094 ~GridRenderCase (void);
2099 IterateResult iterate (void);
2101 void renderTo (std::vector<tcu::Surface>& dst);
2102 bool verifyResultLayer (int layerNdx, const tcu::Surface& dst);
2104 const char* getVertexSource (void);
2105 const char* getFragmentSource (void);
2106 std::string getTessellationControlSource (int tessLevel);
2107 std::string getTessellationEvaluationSource (int tessLevel);
2108 std::string getGeometryShaderSource (int numPrimitives, int numInstances, int tessLevel);
2117 glu::ShaderProgram* m_program;
2122 GridRenderCase::GridRenderCase (Context& context, const char* name, const char* description, int flags)
2123 : TestCase (context, name, description)
2125 , m_program (DE_NULL)
2129 DE_ASSERT(((m_flags & FLAG_TESSELLATION_MAX_SPEC) == 0) || ((m_flags & FLAG_TESSELLATION_MAX_IMPLEMENTATION) == 0));
2130 DE_ASSERT(((m_flags & FLAG_GEOMETRY_MAX_SPEC) == 0) || ((m_flags & FLAG_GEOMETRY_MAX_IMPLEMENTATION) == 0));
2131 DE_ASSERT(((m_flags & FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC) == 0) || ((m_flags & FLAG_GEOMETRY_INVOCATIONS_MAX_IMPLEMENTATION) == 0));
2132 DE_ASSERT(((m_flags & (FLAG_GEOMETRY_SCATTER_PRIMITIVES | FLAG_GEOMETRY_SCATTER_LAYERS)) != 0) == ((m_flags & FLAG_GEOMETRY_SEPARATE_PRIMITIVES) != 0));
2135 GridRenderCase::~GridRenderCase (void)
2140 void GridRenderCase::init (void)
2142 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2146 if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader") ||
2147 !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
2148 throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader and GL_EXT_geometry_shader extensions");
2150 if ((m_flags & FLAG_GEOMETRY_SCATTER_LAYERS) == 0)
2152 if (m_context.getRenderTarget().getWidth() < RENDER_SIZE ||
2153 m_context.getRenderTarget().getHeight() < RENDER_SIZE)
2154 throw tcu::NotSupportedError("Test requires " + de::toString<int>(RENDER_SIZE) + "x" + de::toString<int>(RENDER_SIZE) + " or larger render target.");
2160 << tcu::TestLog::Message
2161 << "Testing tessellation and geometry shaders that output a large number of primitives.\n"
2163 << tcu::TestLog::EndMessage;
2166 if (m_flags & FLAG_GEOMETRY_SCATTER_LAYERS)
2171 m_testCtx.getLog() << tcu::TestLog::Message << "Rendering to 2d texture array, numLayers = " << m_numLayers << tcu::TestLog::EndMessage;
2173 gl.genTextures(1, &m_texture);
2174 gl.bindTexture(GL_TEXTURE_2D_ARRAY, m_texture);
2175 gl.texStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, RENDER_SIZE, RENDER_SIZE, m_numLayers);
2177 gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2178 gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2179 gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2180 gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2182 GLU_EXPECT_NO_ERROR(gl.getError(), "gen texture");
2187 glu::ProgramSources sources;
2188 int tessGenLevel = -1;
2190 sources << glu::VertexSource(getVertexSource())
2191 << glu::FragmentSource(getFragmentSource());
2193 // Tessellation limits
2195 if (m_flags & FLAG_TESSELLATION_MAX_IMPLEMENTATION)
2197 gl.getIntegerv(GL_MAX_TESS_GEN_LEVEL, &tessGenLevel);
2198 GLU_EXPECT_NO_ERROR(gl.getError(), "query tessellation limits");
2200 else if (m_flags & FLAG_TESSELLATION_MAX_SPEC)
2210 << tcu::TestLog::Message
2211 << "Tessellation level: " << tessGenLevel << ", mode = quad.\n"
2212 << "\tEach input patch produces " << (tessGenLevel*tessGenLevel) << " (" << (tessGenLevel*tessGenLevel*2) << " triangles)\n"
2213 << tcu::TestLog::EndMessage;
2215 sources << glu::TessellationControlSource(getTessellationControlSource(tessGenLevel))
2216 << glu::TessellationEvaluationSource(getTessellationEvaluationSource(tessGenLevel));
2221 int geometryOutputComponents = -1;
2222 int geometryOutputVertices = -1;
2223 int geometryTotalOutputComponents = -1;
2224 int geometryShaderInvocations = -1;
2225 bool logGeometryLimits = false;
2226 bool logInvocationLimits = false;
2228 if (m_flags & FLAG_GEOMETRY_MAX_IMPLEMENTATION)
2230 m_testCtx.getLog() << tcu::TestLog::Message << "Using implementation maximum geometry shader output limits." << tcu::TestLog::EndMessage;
2232 gl.getIntegerv(GL_MAX_GEOMETRY_OUTPUT_COMPONENTS, &geometryOutputComponents);
2233 gl.getIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, &geometryOutputVertices);
2234 gl.getIntegerv(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS, &geometryTotalOutputComponents);
2235 GLU_EXPECT_NO_ERROR(gl.getError(), "query geometry limits");
2237 logGeometryLimits = true;
2239 else if (m_flags & FLAG_GEOMETRY_MAX_SPEC)
2241 m_testCtx.getLog() << tcu::TestLog::Message << "Using geometry shader extension minimum maximum output limits." << tcu::TestLog::EndMessage;
2243 geometryOutputComponents = 128;
2244 geometryOutputVertices = 256;
2245 geometryTotalOutputComponents = 1024;
2246 logGeometryLimits = true;
2250 geometryOutputComponents = 128;
2251 geometryOutputVertices = 16;
2252 geometryTotalOutputComponents = 1024;
2255 if (m_flags & FLAG_GEOMETRY_INVOCATIONS_MAX_IMPLEMENTATION)
2257 gl.getIntegerv(GL_MAX_GEOMETRY_SHADER_INVOCATIONS, &geometryShaderInvocations);
2258 GLU_EXPECT_NO_ERROR(gl.getError(), "query geometry invocation limits");
2260 logInvocationLimits = true;
2262 else if (m_flags & FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC)
2264 geometryShaderInvocations = 32;
2265 logInvocationLimits = true;
2269 geometryShaderInvocations = 4;
2272 if (logGeometryLimits || logInvocationLimits)
2274 tcu::MessageBuilder msg(&m_testCtx.getLog());
2276 msg << "Geometry shader, targeting following limits:\n";
2278 if (logGeometryLimits)
2279 msg << "\tGL_MAX_GEOMETRY_OUTPUT_COMPONENTS = " << geometryOutputComponents << "\n"
2280 << "\tGL_MAX_GEOMETRY_OUTPUT_VERTICES = " << geometryOutputVertices << "\n"
2281 << "\tGL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS = " << geometryTotalOutputComponents << "\n";
2283 if (logInvocationLimits)
2284 msg << "\tGL_MAX_GEOMETRY_SHADER_INVOCATIONS = " << geometryShaderInvocations;
2286 msg << tcu::TestLog::EndMessage;
2290 const bool separatePrimitives = (m_flags & FLAG_GEOMETRY_SEPARATE_PRIMITIVES) != 0;
2291 const int numComponentsPerVertex = 8; // vec4 pos, vec4 color
2292 int numVerticesPerInvocation;
2293 int numPrimitivesPerInvocation;
2294 int geometryVerticesPerPrimitive;
2295 int geometryPrimitivesOutPerPrimitive;
2297 if (separatePrimitives)
2299 const int numComponentLimit = geometryTotalOutputComponents / (4 * numComponentsPerVertex);
2300 const int numOutputLimit = geometryOutputVertices / 4;
2302 numPrimitivesPerInvocation = de::min(numComponentLimit, numOutputLimit);
2303 numVerticesPerInvocation = numPrimitivesPerInvocation * 4;
2307 // If FLAG_GEOMETRY_SEPARATE_PRIMITIVES is not set, geometry shader fills a rectangle area in slices.
2308 // Each slice is a triangle strip and is generated by a single shader invocation.
2309 // One slice with 4 segment ends (nodes) and 3 segments:
2314 const int numSliceNodesComponentLimit = geometryTotalOutputComponents / (2 * numComponentsPerVertex); // each node 2 vertices
2315 const int numSliceNodesOutputLimit = geometryOutputVertices / 2; // each node 2 vertices
2316 const int numSliceNodes = de::min(numSliceNodesComponentLimit, numSliceNodesOutputLimit);
2318 numVerticesPerInvocation = numSliceNodes * 2;
2319 numPrimitivesPerInvocation = (numSliceNodes - 1) * 2;
2322 geometryVerticesPerPrimitive = numVerticesPerInvocation * geometryShaderInvocations;
2323 geometryPrimitivesOutPerPrimitive = numPrimitivesPerInvocation * geometryShaderInvocations;
2326 << tcu::TestLog::Message
2327 << "Geometry shader:\n"
2328 << "\tTotal output vertex count per invocation: " << (numVerticesPerInvocation) << "\n"
2329 << "\tTotal output primitive count per invocation: " << (numPrimitivesPerInvocation) << "\n"
2330 << "\tNumber of invocations per primitive: " << geometryShaderInvocations << "\n"
2331 << "\tTotal output vertex count per input primitive: " << (geometryVerticesPerPrimitive) << "\n"
2332 << "\tTotal output primitive count per input primitive: " << (geometryPrimitivesOutPerPrimitive) << "\n"
2333 << tcu::TestLog::EndMessage;
2335 sources << glu::GeometrySource(getGeometryShaderSource(numPrimitivesPerInvocation, geometryShaderInvocations, tessGenLevel));
2338 << tcu::TestLog::Message
2340 << "\tTotal program output vertices count per input patch: " << (tessGenLevel*tessGenLevel*2 * geometryVerticesPerPrimitive) << "\n"
2341 << "\tTotal program output primitive count per input patch: " << (tessGenLevel*tessGenLevel*2 * geometryPrimitivesOutPerPrimitive) << "\n"
2342 << tcu::TestLog::EndMessage;
2346 m_program = new glu::ShaderProgram(m_context.getRenderContext(), sources);
2347 m_testCtx.getLog() << *m_program;
2348 if (!m_program->isOk())
2349 throw tcu::TestError("failed to build program");
2353 void GridRenderCase::deinit (void)
2356 m_program = DE_NULL;
2360 m_context.getRenderContext().getFunctions().deleteTextures(1, &m_texture);
2365 GridRenderCase::IterateResult GridRenderCase::iterate (void)
2367 std::vector<tcu::Surface> renderedLayers (m_numLayers);
2368 bool allLayersOk = true;
2370 for (int ndx = 0; ndx < m_numLayers; ++ndx)
2371 renderedLayers[ndx].setSize(RENDER_SIZE, RENDER_SIZE);
2373 m_testCtx.getLog() << tcu::TestLog::Message << "Rendering single point at the origin. Expecting yellow and green colored grid-like image. (High-frequency grid may appear unicolored)." << tcu::TestLog::EndMessage;
2377 renderTo(renderedLayers);
2379 catch (const AllowedRenderFailureException& ex)
2381 // Got accepted failure
2383 << tcu::TestLog::Message
2384 << "Could not render, reason: " << ex.what() << "\n"
2385 << "Failure is allowed."
2386 << tcu::TestLog::EndMessage;
2388 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2392 for (int ndx = 0; ndx < m_numLayers; ++ndx)
2393 allLayersOk &= verifyResultLayer(ndx, renderedLayers[ndx]);
2396 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2398 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
2402 void GridRenderCase::renderTo (std::vector<tcu::Surface>& dst)
2404 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2405 const int positionLocation = gl.getAttribLocation(m_program->getProgram(), "a_position");
2406 const glu::VertexArray vao (m_context.getRenderContext());
2407 de::MovePtr<glu::Framebuffer> fbo;
2409 if (positionLocation == -1)
2410 throw tcu::TestError("Attribute a_position location was -1");
2412 gl.viewport(0, 0, dst.front().getWidth(), dst.front().getHeight());
2413 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
2414 GLU_EXPECT_NO_ERROR(gl.getError(), "viewport");
2416 gl.bindVertexArray(*vao);
2417 GLU_EXPECT_NO_ERROR(gl.getError(), "bind vao");
2419 gl.useProgram(m_program->getProgram());
2420 GLU_EXPECT_NO_ERROR(gl.getError(), "use program");
2422 gl.patchParameteri(GL_PATCH_VERTICES, 1);
2423 GLU_EXPECT_NO_ERROR(gl.getError(), "set patch param");
2425 gl.vertexAttrib4f(positionLocation, 0.0f, 0.0f, 0.0f, 1.0f);
2427 if (m_flags & FLAG_GEOMETRY_SCATTER_LAYERS)
2429 // clear texture contents
2431 glu::Framebuffer clearFbo(m_context.getRenderContext());
2432 gl.bindFramebuffer(GL_FRAMEBUFFER, *clearFbo);
2434 for (int layerNdx = 0; layerNdx < m_numLayers; ++layerNdx)
2436 gl.framebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture, 0, layerNdx);
2437 gl.clear(GL_COLOR_BUFFER_BIT);
2440 GLU_EXPECT_NO_ERROR(gl.getError(), "clear tex contents");
2443 // create and bind layered fbo
2445 fbo = de::MovePtr<glu::Framebuffer>(new glu::Framebuffer(m_context.getRenderContext()));
2447 gl.bindFramebuffer(GL_FRAMEBUFFER, **fbo);
2448 gl.framebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture, 0);
2449 GLU_EXPECT_NO_ERROR(gl.getError(), "gen fbo");
2454 gl.clear(GL_COLOR_BUFFER_BIT);
2459 glw::GLenum glerror;
2461 gl.drawArrays(GL_PATCHES, 0, 1);
2463 glerror = gl.getError();
2464 if (glerror == GL_OUT_OF_MEMORY && (m_flags & FLAG_ALLOW_OUT_OF_MEMORY))
2465 throw AllowedRenderFailureException("got GL_OUT_OF_MEMORY while drawing");
2467 GLU_EXPECT_NO_ERROR(glerror, "draw patches");
2472 if (m_flags & FLAG_GEOMETRY_SCATTER_LAYERS)
2474 glu::Framebuffer readFbo(m_context.getRenderContext());
2475 gl.bindFramebuffer(GL_FRAMEBUFFER, *readFbo);
2477 for (int layerNdx = 0; layerNdx < m_numLayers; ++layerNdx)
2479 gl.framebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture, 0, layerNdx);
2480 glu::readPixels(m_context.getRenderContext(), 0, 0, dst[layerNdx].getAccess());
2481 GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels");
2486 glu::readPixels(m_context.getRenderContext(), 0, 0, dst.front().getAccess());
2487 GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels");
2491 bool GridRenderCase::verifyResultLayer (int layerNdx, const tcu::Surface& image)
2493 tcu::Surface errorMask (image.getWidth(), image.getHeight());
2494 bool foundError = false;
2496 tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
2498 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying output layer " << layerNdx << tcu::TestLog::EndMessage;
2500 for (int y = 0; y < image.getHeight(); ++y)
2501 for (int x = 0; x < image.getWidth(); ++x)
2503 const int threshold = 8;
2504 const tcu::RGBA color = image.getPixel(x, y);
2506 // Color must be a linear combination of green and yellow
2507 if (color.getGreen() < 255 - threshold || color.getBlue() > threshold)
2509 errorMask.setPixel(x, y, tcu::RGBA::red);
2517 << tcu::TestLog::Message << "Image valid." << tcu::TestLog::EndMessage
2518 << tcu::TestLog::ImageSet("ImageVerification", "Image verification")
2519 << tcu::TestLog::Image("Result", "Rendered result", image.getAccess())
2520 << tcu::TestLog::EndImageSet;
2526 << tcu::TestLog::Message << "Image verification failed, found invalid pixels." << tcu::TestLog::EndMessage
2527 << tcu::TestLog::ImageSet("ImageVerification", "Image verification")
2528 << tcu::TestLog::Image("Result", "Rendered result", image.getAccess())
2529 << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask.getAccess())
2530 << tcu::TestLog::EndImageSet;
2535 const char* GridRenderCase::getVertexSource (void)
2537 return s_positionVertexShader;
2540 const char* GridRenderCase::getFragmentSource (void)
2542 return "#version 310 es\n"
2543 "flat in mediump vec4 v_color;\n"
2544 "layout(location = 0) out mediump vec4 fragColor;\n"
2545 "void main (void)\n"
2547 " fragColor = v_color;\n"
2551 std::string GridRenderCase::getTessellationControlSource (int tessLevel)
2553 std::ostringstream buf;
2555 buf << "#version 310 es\n"
2556 "#extension GL_EXT_tessellation_shader : require\n"
2557 "layout(vertices=1) out;\n"
2561 " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
2562 " gl_TessLevelOuter[0] = " << tessLevel << ".0;\n"
2563 " gl_TessLevelOuter[1] = " << tessLevel << ".0;\n"
2564 " gl_TessLevelOuter[2] = " << tessLevel << ".0;\n"
2565 " gl_TessLevelOuter[3] = " << tessLevel << ".0;\n"
2566 " gl_TessLevelInner[0] = " << tessLevel << ".0;\n"
2567 " gl_TessLevelInner[1] = " << tessLevel << ".0;\n"
2573 std::string GridRenderCase::getTessellationEvaluationSource (int tessLevel)
2575 std::ostringstream buf;
2577 buf << "#version 310 es\n"
2578 "#extension GL_EXT_tessellation_shader : require\n"
2579 "layout(quads) in;\n"
2581 "out mediump ivec2 v_tessellationGridPosition;\n"
2583 "void main (void)\n"
2586 if (m_flags & (FLAG_GEOMETRY_SCATTER_INSTANCES | FLAG_GEOMETRY_SCATTER_PRIMITIVES | FLAG_GEOMETRY_SCATTER_LAYERS))
2587 buf << " // Cover only a small area in a corner. The area will be expanded in geometry shader to cover whole viewport\n"
2588 " gl_Position = vec4(gl_TessCoord.x * 0.3 - 1.0, gl_TessCoord.y * 0.3 - 1.0, 0.0, 1.0);\n";
2590 buf << " // Fill the whole viewport\n"
2591 " gl_Position = vec4(gl_TessCoord.x * 2.0 - 1.0, gl_TessCoord.y * 2.0 - 1.0, 0.0, 1.0);\n";
2593 buf << " // Calculate position in tessellation grid\n"
2594 " v_tessellationGridPosition = ivec2(round(gl_TessCoord.xy * float(" << tessLevel << ")));\n"
2600 std::string GridRenderCase::getGeometryShaderSource (int numPrimitives, int numInstances, int tessLevel)
2602 std::ostringstream buf;
2604 buf << "#version 310 es\n"
2605 "#extension GL_EXT_geometry_shader : require\n"
2606 "layout(triangles, invocations=" << numInstances << ") in;\n"
2607 "layout(triangle_strip, max_vertices=" << ((m_flags & FLAG_GEOMETRY_SEPARATE_PRIMITIVES) ? (4 * numPrimitives) : (numPrimitives + 2)) << ") out;\n"
2609 "in mediump ivec2 v_tessellationGridPosition[];\n"
2610 "flat out highp vec4 v_color;\n"
2614 " const float equalThreshold = 0.001;\n"
2615 " const float gapOffset = 0.0001; // subdivision performed by the geometry shader might produce gaps. Fill potential gaps by enlarging the output slice a little.\n"
2617 " // Input triangle is generated from an axis-aligned rectangle by splitting it in half\n"
2618 " // Original rectangle can be found by finding the bounding AABB of the triangle\n"
2619 " vec4 aabb = vec4(min(gl_in[0].gl_Position.x, min(gl_in[1].gl_Position.x, gl_in[2].gl_Position.x)),\n"
2620 " min(gl_in[0].gl_Position.y, min(gl_in[1].gl_Position.y, gl_in[2].gl_Position.y)),\n"
2621 " max(gl_in[0].gl_Position.x, max(gl_in[1].gl_Position.x, gl_in[2].gl_Position.x)),\n"
2622 " max(gl_in[0].gl_Position.y, max(gl_in[1].gl_Position.y, gl_in[2].gl_Position.y)));\n"
2624 " // Location in tessellation grid\n"
2625 " ivec2 gridPosition = ivec2(min(v_tessellationGridPosition[0], min(v_tessellationGridPosition[1], v_tessellationGridPosition[2])));\n"
2627 " // Which triangle of the two that split the grid cell\n"
2628 " int numVerticesOnBottomEdge = 0;\n"
2629 " for (int ndx = 0; ndx < 3; ++ndx)\n"
2630 " if (abs(gl_in[ndx].gl_Position.y - aabb.w) < equalThreshold)\n"
2631 " ++numVerticesOnBottomEdge;\n"
2632 " bool isBottomTriangle = numVerticesOnBottomEdge == 2;\n"
2635 if (m_flags & FLAG_GEOMETRY_SCATTER_PRIMITIVES)
2637 // scatter primitives
2638 buf << " // Draw grid cells\n"
2639 " int inputTriangleNdx = gl_InvocationID * 2 + ((isBottomTriangle) ? (1) : (0));\n"
2640 " for (int ndx = 0; ndx < " << numPrimitives << "; ++ndx)\n"
2642 " ivec2 dstGridSize = ivec2(" << tessLevel << " * " << numPrimitives << ", 2 * " << tessLevel << " * " << numInstances << ");\n"
2643 " ivec2 dstGridNdx = ivec2(" << tessLevel << " * ndx + gridPosition.x, " << tessLevel << " * inputTriangleNdx + 2 * gridPosition.y + ndx * 127) % dstGridSize;\n"
2645 " dstArea.x = float(dstGridNdx.x) / float(dstGridSize.x) * 2.0 - 1.0 - gapOffset;\n"
2646 " dstArea.y = float(dstGridNdx.y) / float(dstGridSize.y) * 2.0 - 1.0 - gapOffset;\n"
2647 " dstArea.z = float(dstGridNdx.x+1) / float(dstGridSize.x) * 2.0 - 1.0 + gapOffset;\n"
2648 " dstArea.w = float(dstGridNdx.y+1) / float(dstGridSize.y) * 2.0 - 1.0 + gapOffset;\n"
2650 " vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
2651 " vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
2652 " vec4 outputColor = (((dstGridNdx.y + dstGridNdx.x) % 2) == 0) ? (green) : (yellow);\n"
2654 " gl_Position = vec4(dstArea.x, dstArea.y, 0.0, 1.0);\n"
2655 " v_color = outputColor;\n"
2658 " gl_Position = vec4(dstArea.x, dstArea.w, 0.0, 1.0);\n"
2659 " v_color = outputColor;\n"
2662 " gl_Position = vec4(dstArea.z, dstArea.y, 0.0, 1.0);\n"
2663 " v_color = outputColor;\n"
2666 " gl_Position = vec4(dstArea.z, dstArea.w, 0.0, 1.0);\n"
2667 " v_color = outputColor;\n"
2669 " EndPrimitive();\n"
2672 else if (m_flags & FLAG_GEOMETRY_SCATTER_LAYERS)
2674 // Number of subrectangle instances = num layers
2675 DE_ASSERT(m_numLayers == numInstances * 2);
2677 buf << " // Draw grid cells, send each primitive to a separate layer\n"
2678 " int baseLayer = gl_InvocationID * 2 + ((isBottomTriangle) ? (1) : (0));\n"
2679 " for (int ndx = 0; ndx < " << numPrimitives << "; ++ndx)\n"
2681 " ivec2 dstGridSize = ivec2(" << tessLevel << " * " << numPrimitives << ", " << tessLevel << ");\n"
2682 " ivec2 dstGridNdx = ivec2((gridPosition.x * " << numPrimitives << " * 7 + ndx)*13, (gridPosition.y * 127 + ndx) * 19) % dstGridSize;\n"
2684 " dstArea.x = float(dstGridNdx.x) / float(dstGridSize.x) * 2.0 - 1.0 - gapOffset;\n"
2685 " dstArea.y = float(dstGridNdx.y) / float(dstGridSize.y) * 2.0 - 1.0 - gapOffset;\n"
2686 " dstArea.z = float(dstGridNdx.x+1) / float(dstGridSize.x) * 2.0 - 1.0 + gapOffset;\n"
2687 " dstArea.w = float(dstGridNdx.y+1) / float(dstGridSize.y) * 2.0 - 1.0 + gapOffset;\n"
2689 " vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
2690 " vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
2691 " vec4 outputColor = (((dstGridNdx.y + dstGridNdx.x) % 2) == 0) ? (green) : (yellow);\n"
2693 " gl_Position = vec4(dstArea.x, dstArea.y, 0.0, 1.0);\n"
2694 " v_color = outputColor;\n"
2695 " gl_Layer = ((baseLayer + ndx) * 11) % " << m_numLayers << ";\n"
2698 " gl_Position = vec4(dstArea.x, dstArea.w, 0.0, 1.0);\n"
2699 " v_color = outputColor;\n"
2700 " gl_Layer = ((baseLayer + ndx) * 11) % " << m_numLayers << ";\n"
2703 " gl_Position = vec4(dstArea.z, dstArea.y, 0.0, 1.0);\n"
2704 " v_color = outputColor;\n"
2705 " gl_Layer = ((baseLayer + ndx) * 11) % " << m_numLayers << ";\n"
2708 " gl_Position = vec4(dstArea.z, dstArea.w, 0.0, 1.0);\n"
2709 " v_color = outputColor;\n"
2710 " gl_Layer = ((baseLayer + ndx) * 11) % " << m_numLayers << ";\n"
2712 " EndPrimitive();\n"
2717 if (m_flags & FLAG_GEOMETRY_SCATTER_INSTANCES)
2719 buf << " // Scatter slices\n"
2720 " int inputTriangleNdx = gl_InvocationID * 2 + ((isBottomTriangle) ? (1) : (0));\n"
2721 " ivec2 srcSliceNdx = ivec2(gridPosition.x, gridPosition.y * " << (numInstances*2) << " + inputTriangleNdx);\n"
2722 " ivec2 dstSliceNdx = ivec2(7 * srcSliceNdx.x, 127 * srcSliceNdx.y) % ivec2(" << tessLevel << ", " << tessLevel << " * " << (numInstances*2) << ");\n"
2724 " // Draw slice to the dstSlice slot\n"
2725 " vec4 outputSliceArea;\n"
2726 " outputSliceArea.x = float(dstSliceNdx.x) / float(" << tessLevel << ") * 2.0 - 1.0 - gapOffset;\n"
2727 " outputSliceArea.y = float(dstSliceNdx.y) / float(" << (tessLevel * numInstances * 2) << ") * 2.0 - 1.0 - gapOffset;\n"
2728 " outputSliceArea.z = float(dstSliceNdx.x+1) / float(" << tessLevel << ") * 2.0 - 1.0 + gapOffset;\n"
2729 " outputSliceArea.w = float(dstSliceNdx.y+1) / float(" << (tessLevel * numInstances * 2) << ") * 2.0 - 1.0 + gapOffset;\n";
2733 buf << " // Fill the input area with slices\n"
2734 " // Upper triangle produces slices only to the upper half of the quad and vice-versa\n"
2735 " float triangleOffset = (isBottomTriangle) ? ((aabb.w + aabb.y) / 2.0) : (aabb.y);\n"
2736 " // Each slice is a invocation\n"
2737 " float sliceHeight = (aabb.w - aabb.y) / float(2 * " << numInstances << ");\n"
2738 " float invocationOffset = float(gl_InvocationID) * sliceHeight;\n"
2740 " vec4 outputSliceArea;\n"
2741 " outputSliceArea.x = aabb.x - gapOffset;\n"
2742 " outputSliceArea.y = triangleOffset + invocationOffset - gapOffset;\n"
2743 " outputSliceArea.z = aabb.z + gapOffset;\n"
2744 " outputSliceArea.w = triangleOffset + invocationOffset + sliceHeight + gapOffset;\n";
2749 " for (int ndx = 0; ndx < " << ((numPrimitives+2)/2) << "; ++ndx)\n"
2751 " vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
2752 " vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
2753 " vec4 outputColor = (((gl_InvocationID + ndx) % 2) == 0) ? (green) : (yellow);\n"
2754 " float xpos = mix(outputSliceArea.x, outputSliceArea.z, float(ndx) / float(" << (numPrimitives/2) << "));\n"
2756 " gl_Position = vec4(xpos, outputSliceArea.y, 0.0, 1.0);\n"
2757 " v_color = outputColor;\n"
2760 " gl_Position = vec4(xpos, outputSliceArea.w, 0.0, 1.0);\n"
2761 " v_color = outputColor;\n"
2771 class FeedbackRecordVariableSelectionCase : public TestCase
2774 FeedbackRecordVariableSelectionCase (Context& context, const char* name, const char* description);
2775 ~FeedbackRecordVariableSelectionCase (void);
2780 IterateResult iterate (void);
2782 const char* getVertexSource (void);
2783 const char* getFragmentSource (void);
2784 const char* getTessellationControlSource (void);
2785 const char* getTessellationEvaluationSource (void);
2786 const char* getGeometrySource (void);
2788 glu::ShaderProgram* m_program;
2792 FeedbackRecordVariableSelectionCase::FeedbackRecordVariableSelectionCase (Context& context, const char* name, const char* description)
2793 : TestCase (context, name, description)
2794 , m_program (DE_NULL)
2799 FeedbackRecordVariableSelectionCase::~FeedbackRecordVariableSelectionCase (void)
2804 void FeedbackRecordVariableSelectionCase::init (void)
2806 if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader") ||
2807 !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
2808 throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader and GL_EXT_geometry_shader extensions");
2810 m_testCtx.getLog() << tcu::TestLog::Message << "Declaring multiple output variables with the same name in multiple shader stages. Capturing the value of the varying using transform feedback." << tcu::TestLog::EndMessage;
2812 // gen feedback buffer fit for 1 triangle (4 components)
2814 static const tcu::Vec4 initialData[3] =
2816 tcu::Vec4(-1.0f, -1.0f, -1.0f, -1.0f),
2817 tcu::Vec4(-1.0f, -1.0f, -1.0f, -1.0f),
2818 tcu::Vec4(-1.0f, -1.0f, -1.0f, -1.0f),
2821 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2823 m_testCtx.getLog() << tcu::TestLog::Message << "Creating buffer for transform feedback. Allocating storage for one triangle. Filling with -1.0" << tcu::TestLog::EndMessage;
2825 gl.genBuffers(1, &m_xfbBuf);
2826 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_xfbBuf);
2827 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, (int)(sizeof(tcu::Vec4[3])), initialData, GL_DYNAMIC_READ);
2828 GLU_EXPECT_NO_ERROR(gl.getError(), "gen xfb buf");
2832 m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
2833 << glu::VertexSource(getVertexSource())
2834 << glu::FragmentSource(getFragmentSource())
2835 << glu::TessellationControlSource(getTessellationControlSource())
2836 << glu::TessellationEvaluationSource(getTessellationEvaluationSource())
2837 << glu::GeometrySource(getGeometrySource())
2838 << glu::TransformFeedbackMode(GL_INTERLEAVED_ATTRIBS)
2839 << glu::TransformFeedbackVarying("tf_feedback"));
2840 m_testCtx.getLog() << *m_program;
2842 if (!m_program->isOk())
2843 throw tcu::TestError("could not build program");
2846 void FeedbackRecordVariableSelectionCase::deinit (void)
2849 m_program = DE_NULL;
2853 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_xfbBuf);
2858 FeedbackRecordVariableSelectionCase::IterateResult FeedbackRecordVariableSelectionCase::iterate (void)
2860 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2861 const int posLoc = gl.getAttribLocation(m_program->getProgram(), "a_position");
2862 const glu::VertexArray vao (m_context.getRenderContext());
2865 throw tcu::TestError("a_position attribute location was -1");
2867 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2869 m_testCtx.getLog() << tcu::TestLog::Message << "Rendering a patch of size 3." << tcu::TestLog::EndMessage;
2871 // Render and feed back
2873 gl.viewport(0, 0, 1, 1);
2874 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
2875 gl.clear(GL_COLOR_BUFFER_BIT);
2876 GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
2878 gl.bindVertexArray(*vao);
2879 GLU_EXPECT_NO_ERROR(gl.getError(), "bindVertexArray");
2881 gl.vertexAttrib4f(posLoc, 0.0f, 0.0f, 0.0f, 1.0f);
2882 GLU_EXPECT_NO_ERROR(gl.getError(), "vertexAttrib4f");
2884 gl.useProgram(m_program->getProgram());
2885 GLU_EXPECT_NO_ERROR(gl.getError(), "use program");
2887 gl.patchParameteri(GL_PATCH_VERTICES, 3);
2888 GLU_EXPECT_NO_ERROR(gl.getError(), "set patch param");
2890 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_xfbBuf);
2891 GLU_EXPECT_NO_ERROR(gl.getError(), "bind xfb buf");
2893 gl.beginTransformFeedback(GL_TRIANGLES);
2894 GLU_EXPECT_NO_ERROR(gl.getError(), "beginTransformFeedback");
2896 gl.drawArrays(GL_PATCHES, 0, 3);
2897 GLU_EXPECT_NO_ERROR(gl.getError(), "drawArrays");
2899 gl.endTransformFeedback();
2900 GLU_EXPECT_NO_ERROR(gl.getError(), "beginTransformFeedback");
2902 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying the value of tf_feedback using transform feedback, expecting (3.0, 3.0, 3.0, 3.0)." << tcu::TestLog::EndMessage;
2904 // Read back result (one triangle)
2906 tcu::Vec4 feedbackValues[3];
2907 const void* mapPtr = gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, (int)sizeof(feedbackValues), GL_MAP_READ_BIT);
2908 GLU_EXPECT_NO_ERROR(gl.getError(), "mapBufferRange");
2910 if (mapPtr == DE_NULL)
2911 throw tcu::TestError("mapBufferRange returned null");
2913 deMemcpy(feedbackValues, mapPtr, sizeof(feedbackValues));
2915 if (gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER) != GL_TRUE)
2916 throw tcu::TestError("unmapBuffer did not return TRUE");
2918 for (int ndx = 0; ndx < 3; ++ndx)
2920 if (!tcu::boolAll(tcu::lessThan(tcu::abs(feedbackValues[ndx] - tcu::Vec4(3.0f)), tcu::Vec4(0.001f))))
2922 m_testCtx.getLog() << tcu::TestLog::Message << "Feedback vertex " << ndx << ": expected (3.0, 3.0, 3.0, 3.0), got " << feedbackValues[ndx] << tcu::TestLog::EndMessage;
2923 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got unexpected feedback results");
2931 const char* FeedbackRecordVariableSelectionCase::getVertexSource (void)
2933 return "#version 310 es\n"
2934 "in highp vec4 a_position;\n"
2935 "out highp vec4 tf_feedback;\n"
2938 " gl_Position = a_position;\n"
2939 " tf_feedback = vec4(1.0, 1.0, 1.0, 1.0);\n"
2943 const char* FeedbackRecordVariableSelectionCase::getFragmentSource (void)
2945 return s_whiteOutputFragmentShader;
2948 const char* FeedbackRecordVariableSelectionCase::getTessellationControlSource (void)
2950 return "#version 310 es\n"
2951 "#extension GL_EXT_tessellation_shader : require\n"
2952 "layout(vertices=3) out;\n"
2955 " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
2956 " gl_TessLevelOuter[0] = 1.0;\n"
2957 " gl_TessLevelOuter[1] = 1.0;\n"
2958 " gl_TessLevelOuter[2] = 1.0;\n"
2959 " gl_TessLevelInner[0] = 1.0;\n"
2963 const char* FeedbackRecordVariableSelectionCase::getTessellationEvaluationSource (void)
2965 return "#version 310 es\n"
2966 "#extension GL_EXT_tessellation_shader : require\n"
2967 "layout(triangles) in;\n"
2968 "out highp vec4 tf_feedback;\n"
2971 " gl_Position = gl_in[0].gl_Position * gl_TessCoord.x + gl_in[1].gl_Position * gl_TessCoord.y + gl_in[2].gl_Position * gl_TessCoord.z;\n"
2972 " tf_feedback = vec4(2.0, 2.0, 2.0, 2.0);\n"
2976 const char* FeedbackRecordVariableSelectionCase::getGeometrySource (void)
2978 return "#version 310 es\n"
2979 "#extension GL_EXT_geometry_shader : require\n"
2980 "layout (triangles) in;\n"
2981 "layout (triangle_strip, max_vertices=3) out;\n"
2982 "out highp vec4 tf_feedback;\n"
2985 " for (int ndx = 0; ndx < 3; ++ndx)\n"
2987 " gl_Position = gl_in[ndx].gl_Position + vec4(float(ndx), float(ndx)*float(ndx), 0.0, 0.0);\n"
2988 " tf_feedback = vec4(3.0, 3.0, 3.0, 3.0);\n"
2991 " EndPrimitive();\n"
2997 TessellationGeometryInteractionTests::TessellationGeometryInteractionTests (Context& context)
2998 : TestCaseGroup(context, "tessellation_geometry_interaction", "Tessellation and geometry shader interaction tests")
3002 TessellationGeometryInteractionTests::~TessellationGeometryInteractionTests (void)
3006 void TessellationGeometryInteractionTests::init (void)
3008 tcu::TestCaseGroup* const renderGroup = new tcu::TestCaseGroup(m_testCtx, "render", "Various render tests");
3009 tcu::TestCaseGroup* const feedbackGroup = new tcu::TestCaseGroup(m_testCtx, "feedback", "Test transform feedback");
3010 tcu::TestCaseGroup* const pointSizeGroup = new tcu::TestCaseGroup(m_testCtx, "point_size", "Test point size");
3012 addChild(renderGroup);
3013 addChild(feedbackGroup);
3014 addChild(pointSizeGroup);
3018 tcu::TestCaseGroup* const passthroughGroup = new tcu::TestCaseGroup(m_testCtx, "passthrough", "Render various types with either passthrough geometry or tessellation shader");
3019 tcu::TestCaseGroup* const limitGroup = new tcu::TestCaseGroup(m_testCtx, "limits", "Render with properties near their limits");
3020 tcu::TestCaseGroup* const scatterGroup = new tcu::TestCaseGroup(m_testCtx, "scatter", "Scatter output primitives");
3022 renderGroup->addChild(passthroughGroup);
3023 renderGroup->addChild(limitGroup);
3024 renderGroup->addChild(scatterGroup);
3028 // tessellate_tris_passthrough_geometry_no_change
3029 // tessellate_quads_passthrough_geometry_no_change
3030 // tessellate_isolines_passthrough_geometry_no_change
3031 passthroughGroup->addChild(new IdentityGeometryShaderCase(m_context, "tessellate_tris_passthrough_geometry_no_change", "Passthrough geometry shader has no effect", IdentityGeometryShaderCase::CASE_TRIANGLES));
3032 passthroughGroup->addChild(new IdentityGeometryShaderCase(m_context, "tessellate_quads_passthrough_geometry_no_change", "Passthrough geometry shader has no effect", IdentityGeometryShaderCase::CASE_QUADS));
3033 passthroughGroup->addChild(new IdentityGeometryShaderCase(m_context, "tessellate_isolines_passthrough_geometry_no_change", "Passthrough geometry shader has no effect", IdentityGeometryShaderCase::CASE_ISOLINES));
3035 // passthrough_tessellation_geometry_shade_triangles_no_change
3036 // passthrough_tessellation_geometry_shade_lines_no_change
3037 passthroughGroup->addChild(new IdentityTessellationShaderCase(m_context, "passthrough_tessellation_geometry_shade_triangles_no_change", "Passthrough tessellation shader has no effect", IdentityTessellationShaderCase::CASE_TRIANGLES));
3038 passthroughGroup->addChild(new IdentityTessellationShaderCase(m_context, "passthrough_tessellation_geometry_shade_lines_no_change", "Passthrough tessellation shader has no effect", IdentityTessellationShaderCase::CASE_ISOLINES));
3043 static const struct LimitCaseDef
3050 // Test single limit
3052 "output_required_max_tessellation",
3053 "Minimum maximum tessellation level",
3054 GridRenderCase::FLAG_TESSELLATION_MAX_SPEC
3057 "output_implementation_max_tessellation",
3058 "Maximum tessellation level supported by the implementation",
3059 GridRenderCase::FLAG_TESSELLATION_MAX_IMPLEMENTATION
3062 "output_required_max_geometry",
3063 "Output minimum maximum number of vertices the geometry shader",
3064 GridRenderCase::FLAG_GEOMETRY_MAX_SPEC
3067 "output_implementation_max_geometry",
3068 "Output maximum number of vertices in the geometry shader supported by the implementation",
3069 GridRenderCase::FLAG_GEOMETRY_MAX_IMPLEMENTATION
3072 "output_required_max_invocations",
3073 "Minimum maximum number of geometry shader invocations",
3074 GridRenderCase::FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC
3077 "output_implementation_max_invocations",
3078 "Maximum number of geometry shader invocations supported by the implementation",
3079 GridRenderCase::FLAG_GEOMETRY_INVOCATIONS_MAX_IMPLEMENTATION
3083 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cases); ++ndx)
3084 limitGroup->addChild(new GridRenderCase(m_context, cases[ndx].name, cases[ndx].desc, cases[ndx].flags));
3089 scatterGroup->addChild(new GridRenderCase(m_context,
3090 "geometry_scatter_instances",
3091 "Each geometry shader instance outputs its primitives far from other instances of the same execution",
3092 GridRenderCase::FLAG_GEOMETRY_SCATTER_INSTANCES));
3093 scatterGroup->addChild(new GridRenderCase(m_context,
3094 "geometry_scatter_primitives",
3095 "Each geometry shader instance outputs its primitives far from other primitives of the same instance",
3096 GridRenderCase::FLAG_GEOMETRY_SCATTER_PRIMITIVES | GridRenderCase::FLAG_GEOMETRY_SEPARATE_PRIMITIVES));
3097 scatterGroup->addChild(new GridRenderCase(m_context,
3098 "geometry_scatter_layers",
3099 "Each geometry shader instance outputs its primitives to multiple layers and far from other primitives of the same instance",
3100 GridRenderCase::FLAG_GEOMETRY_SCATTER_LAYERS | GridRenderCase::FLAG_GEOMETRY_SEPARATE_PRIMITIVES));
3106 static const struct PrimitiveCaseConfig
3109 const char* description;
3110 FeedbackPrimitiveTypeCase::TessellationOutputType tessellationOutput;
3111 FeedbackPrimitiveTypeCase::TessellationPointMode tessellationPointMode;
3112 FeedbackPrimitiveTypeCase::GeometryOutputType geometryOutputType;
3115 // tess output triangles -> geo input triangles, output points
3117 "tessellation_output_triangles_geometry_output_points",
3118 "Tessellation outputs triangles, geometry outputs points",
3119 FeedbackPrimitiveTypeCase::TESSELLATION_OUT_TRIANGLES,
3120 FeedbackPrimitiveTypeCase::TESSELLATION_POINTMODE_OFF,
3121 FeedbackPrimitiveTypeCase::GEOMETRY_OUTPUT_POINTS
3124 // tess output quads <-> geo input triangles, output points
3126 "tessellation_output_quads_geometry_output_points",
3127 "Tessellation outputs quads, geometry outputs points",
3128 FeedbackPrimitiveTypeCase::TESSELLATION_OUT_QUADS,
3129 FeedbackPrimitiveTypeCase::TESSELLATION_POINTMODE_OFF,
3130 FeedbackPrimitiveTypeCase::GEOMETRY_OUTPUT_POINTS
3133 // tess output isolines <-> geo input lines, output points
3135 "tessellation_output_isolines_geometry_output_points",
3136 "Tessellation outputs isolines, geometry outputs points",
3137 FeedbackPrimitiveTypeCase::TESSELLATION_OUT_ISOLINES,
3138 FeedbackPrimitiveTypeCase::TESSELLATION_POINTMODE_OFF,
3139 FeedbackPrimitiveTypeCase::GEOMETRY_OUTPUT_POINTS
3142 // tess output triangles, point_mode <-> geo input points, output lines
3144 "tessellation_output_triangles_point_mode_geometry_output_lines",
3145 "Tessellation outputs triangles in point mode, geometry outputs lines",
3146 FeedbackPrimitiveTypeCase::TESSELLATION_OUT_TRIANGLES,
3147 FeedbackPrimitiveTypeCase::TESSELLATION_POINTMODE_ON,
3148 FeedbackPrimitiveTypeCase::GEOMETRY_OUTPUT_LINES
3151 // tess output quads, point_mode <-> geo input points, output lines
3153 "tessellation_output_quads_point_mode_geometry_output_lines",
3154 "Tessellation outputs quads in point mode, geometry outputs lines",
3155 FeedbackPrimitiveTypeCase::TESSELLATION_OUT_QUADS,
3156 FeedbackPrimitiveTypeCase::TESSELLATION_POINTMODE_ON,
3157 FeedbackPrimitiveTypeCase::GEOMETRY_OUTPUT_LINES
3160 // tess output isolines, point_mode <-> geo input points, output triangles
3162 "tessellation_output_isolines_point_mode_geometry_output_triangles",
3163 "Tessellation outputs isolines in point mode, geometry outputs triangles",
3164 FeedbackPrimitiveTypeCase::TESSELLATION_OUT_ISOLINES,
3165 FeedbackPrimitiveTypeCase::TESSELLATION_POINTMODE_ON,
3166 FeedbackPrimitiveTypeCase::GEOMETRY_OUTPUT_TRIANGLES
3170 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(caseConfigs); ++ndx)
3172 feedbackGroup->addChild(new FeedbackPrimitiveTypeCase(m_context,
3173 caseConfigs[ndx].name,
3174 caseConfigs[ndx].description,
3175 caseConfigs[ndx].tessellationOutput,
3176 caseConfigs[ndx].tessellationPointMode,
3177 caseConfigs[ndx].geometryOutputType));
3180 feedbackGroup->addChild(new FeedbackRecordVariableSelectionCase(m_context, "record_variable_selection", "Record a variable that has been declared as an output variable in multiple shader stages"));
3185 static const int caseFlags[] =
3187 PointSizeCase::FLAG_VERTEX_SET,
3188 PointSizeCase::FLAG_TESSELLATION_EVALUATION_SET,
3189 PointSizeCase::FLAG_GEOMETRY_SET,
3190 PointSizeCase::FLAG_VERTEX_SET | PointSizeCase::FLAG_TESSELLATION_CONTROL_SET,
3191 PointSizeCase::FLAG_VERTEX_SET | PointSizeCase::FLAG_TESSELLATION_EVALUATION_SET,
3192 PointSizeCase::FLAG_VERTEX_SET | PointSizeCase::FLAG_TESSELLATION_DONT_SET,
3193 PointSizeCase::FLAG_VERTEX_SET | PointSizeCase::FLAG_GEOMETRY_SET,
3194 PointSizeCase::FLAG_VERTEX_SET | PointSizeCase::FLAG_TESSELLATION_EVALUATION_SET | PointSizeCase::FLAG_GEOMETRY_SET,
3195 PointSizeCase::FLAG_VERTEX_SET | PointSizeCase::FLAG_TESSELLATION_ADD | PointSizeCase::FLAG_GEOMETRY_ADD,
3196 PointSizeCase::FLAG_VERTEX_SET | PointSizeCase::FLAG_TESSELLATION_EVALUATION_SET | PointSizeCase::FLAG_GEOMETRY_DONT_SET,
3199 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(caseFlags); ++ndx)
3201 const std::string name = PointSizeCase::genTestCaseName(caseFlags[ndx]);
3202 const std::string desc = PointSizeCase::genTestCaseDescription(caseFlags[ndx]);
3204 pointSizeGroup->addChild(new PointSizeCase(m_context, name.c_str(), desc.c_str(), caseFlags[ndx]));