xref: /aosp_15_r20/external/deqp/modules/gles31/functional/es31fGeometryShaderTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.1 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Geometry shader tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es31fGeometryShaderTests.hpp"
25 
26 #include "gluRenderContext.hpp"
27 #include "gluTextureUtil.hpp"
28 #include "gluObjectWrapper.hpp"
29 #include "gluPixelTransfer.hpp"
30 #include "gluContextInfo.hpp"
31 #include "gluCallLogWrapper.hpp"
32 #include "tcuRenderTarget.hpp"
33 #include "tcuTestLog.hpp"
34 #include "tcuVectorUtil.hpp"
35 #include "tcuImageCompare.hpp"
36 #include "tcuTextureUtil.hpp"
37 #include "tcuStringTemplate.hpp"
38 #include "glsStateQueryUtil.hpp"
39 
40 #include "gluStrUtil.hpp"
41 #include "deStringUtil.hpp"
42 #include "deUniquePtr.hpp"
43 #include "deMemory.h"
44 
45 #include "sglrContext.hpp"
46 #include "sglrReferenceContext.hpp"
47 #include "sglrGLContext.hpp"
48 #include "sglrReferenceUtils.hpp"
49 
50 #include "glwDefs.hpp"
51 #include "glwEnums.hpp"
52 #include "glwFunctions.hpp"
53 
54 #include <algorithm>
55 
56 using namespace glw;
57 
58 namespace deqp
59 {
60 namespace gles31
61 {
62 namespace Functional
63 {
64 namespace
65 {
66 
67 using namespace gls::StateQueryUtil;
68 
69 const int TEST_CANVAS_SIZE = 256;
70 
71 static const char *const s_commonShaderSourceVertex   = "${GLSL_VERSION_DECL}\n"
72                                                         "in highp vec4 a_position;\n"
73                                                         "in highp vec4 a_color;\n"
74                                                         "out highp vec4 v_geom_FragColor;\n"
75                                                         "void main (void)\n"
76                                                         "{\n"
77                                                         "    gl_Position = a_position;\n"
78                                                         "    gl_PointSize = 1.0;\n"
79                                                         "    v_geom_FragColor = a_color;\n"
80                                                         "}\n";
81 static const char *const s_commonShaderSourceFragment = "${GLSL_VERSION_DECL}\n"
82                                                         "layout(location = 0) out mediump vec4 fragColor;\n"
83                                                         "in mediump vec4 v_frag_FragColor;\n"
84                                                         "void main (void)\n"
85                                                         "{\n"
86                                                         "    fragColor = v_frag_FragColor;\n"
87                                                         "}\n";
88 static const char *const s_expandShaderSourceGeometryBody =
89     "in highp vec4 v_geom_FragColor[];\n"
90     "out highp vec4 v_frag_FragColor;\n"
91     "\n"
92     "void main (void)\n"
93     "{\n"
94     "    const highp vec4 offset0 = vec4(-0.07, -0.01, 0.0, 0.0);\n"
95     "    const highp vec4 offset1 = vec4( 0.03, -0.03, 0.0, 0.0);\n"
96     "    const highp vec4 offset2 = vec4(-0.01,  0.08, 0.0, 0.0);\n"
97     "          highp vec4 yoffset = float(gl_PrimitiveIDIn) * vec4(0.02, 0.1, 0.0, 0.0);\n"
98     "\n"
99     "    for (highp int ndx = 0; ndx < gl_in.length(); ndx++)\n"
100     "    {\n"
101     "        gl_Position = gl_in[ndx].gl_Position + offset0 + yoffset;\n"
102     "        gl_PrimitiveID = gl_PrimitiveIDIn;\n"
103     "        v_frag_FragColor = v_geom_FragColor[ndx];\n"
104     "        EmitVertex();\n"
105     "\n"
106     "        gl_Position = gl_in[ndx].gl_Position + offset1 + yoffset;\n"
107     "        gl_PrimitiveID = gl_PrimitiveIDIn;\n"
108     "        v_frag_FragColor = v_geom_FragColor[ndx];\n"
109     "        EmitVertex();\n"
110     "\n"
111     "        gl_Position = gl_in[ndx].gl_Position + offset2 + yoffset;\n"
112     "        gl_PrimitiveID = gl_PrimitiveIDIn;\n"
113     "        v_frag_FragColor = v_geom_FragColor[ndx];\n"
114     "        EmitVertex();\n"
115     "        EndPrimitive();\n"
116     "    }\n"
117     "}\n";
118 
specializeShader(const std::string & shaderSource,const glu::ContextType & contextType)119 static std::string specializeShader(const std::string &shaderSource, const glu::ContextType &contextType)
120 {
121     const bool supportsES32orGL45 = glu::contextSupports(contextType, glu::ApiType::es(3, 2)) ||
122                                     glu::contextSupports(contextType, glu::ApiType::core(4, 5));
123     std::map<std::string, std::string> args;
124     args["GLSL_VERSION_DECL"]        = glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(contextType));
125     args["GLSL_EXT_GEOMETRY_SHADER"] = supportsES32orGL45 ? "" : "#extension GL_EXT_geometry_shader : require\n";
126     args["GLSL_OES_TEXTURE_STORAGE_MULTISAMPLE"] =
127         supportsES32orGL45 ? "" : "#extension GL_OES_texture_storage_multisample_2d_array : require\n";
128 
129     return tcu::StringTemplate(shaderSource).specialize(args);
130 }
131 
checkSupport(Context & ctx)132 static bool checkSupport(Context &ctx)
133 {
134     auto contextType = ctx.getRenderContext().getType();
135     return contextSupports(contextType, glu::ApiType::es(3, 2)) ||
136            contextSupports(contextType, glu::ApiType::core(4, 5)) ||
137            ctx.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader");
138 }
139 
inputTypeToGLString(rr::GeometryShaderInputType inputType)140 std::string inputTypeToGLString(rr::GeometryShaderInputType inputType)
141 {
142     switch (inputType)
143     {
144     case rr::GEOMETRYSHADERINPUTTYPE_POINTS:
145         return "points";
146     case rr::GEOMETRYSHADERINPUTTYPE_LINES:
147         return "lines";
148     case rr::GEOMETRYSHADERINPUTTYPE_LINES_ADJACENCY:
149         return "lines_adjacency";
150     case rr::GEOMETRYSHADERINPUTTYPE_TRIANGLES:
151         return "triangles";
152     case rr::GEOMETRYSHADERINPUTTYPE_TRIANGLES_ADJACENCY:
153         return "triangles_adjacency";
154     default:
155         DE_ASSERT(false);
156         return "error";
157     }
158 }
159 
outputTypeToGLString(rr::GeometryShaderOutputType outputType)160 std::string outputTypeToGLString(rr::GeometryShaderOutputType outputType)
161 {
162     switch (outputType)
163     {
164     case rr::GEOMETRYSHADEROUTPUTTYPE_POINTS:
165         return "points";
166     case rr::GEOMETRYSHADEROUTPUTTYPE_LINE_STRIP:
167         return "line_strip";
168     case rr::GEOMETRYSHADEROUTPUTTYPE_TRIANGLE_STRIP:
169         return "triangle_strip";
170     default:
171         DE_ASSERT(false);
172         return "error";
173     }
174 }
175 
primitiveTypeToString(GLenum primitive)176 std::string primitiveTypeToString(GLenum primitive)
177 {
178     switch (primitive)
179     {
180     case GL_POINTS:
181         return "points";
182     case GL_LINES:
183         return "lines";
184     case GL_LINE_LOOP:
185         return "line_loop";
186     case GL_LINE_STRIP:
187         return "line_strip";
188     case GL_LINES_ADJACENCY:
189         return "lines_adjacency";
190     case GL_LINE_STRIP_ADJACENCY:
191         return "line_strip_adjacency";
192     case GL_TRIANGLES:
193         return "triangles";
194     case GL_TRIANGLE_STRIP:
195         return "triangle_strip";
196     case GL_TRIANGLE_FAN:
197         return "triangle_fan";
198     case GL_TRIANGLES_ADJACENCY:
199         return "triangles_adjacency";
200     case GL_TRIANGLE_STRIP_ADJACENCY:
201         return "triangle_strip_adjacency";
202     default:
203         DE_ASSERT(false);
204         return "error";
205     }
206 }
207 
208 struct OutputCountPatternSpec
209 {
210     OutputCountPatternSpec(int count);
211     OutputCountPatternSpec(int count0, int count1);
212 
213     std::vector<int> pattern;
214 };
215 
OutputCountPatternSpec(int count)216 OutputCountPatternSpec::OutputCountPatternSpec(int count)
217 {
218     pattern.push_back(count);
219 }
220 
OutputCountPatternSpec(int count0,int count1)221 OutputCountPatternSpec::OutputCountPatternSpec(int count0, int count1)
222 {
223     pattern.push_back(count0);
224     pattern.push_back(count1);
225 }
226 
227 class VertexExpanderShader : public sglr::ShaderProgram
228 {
229 public:
230     VertexExpanderShader(const glu::ContextType &contextType, rr::GeometryShaderInputType inputType,
231                          rr::GeometryShaderOutputType outputType);
232 
233     void shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets, const int numPackets) const;
234     void shadeFragments(rr::FragmentPacket *packets, const int numPackets,
235                         const rr::FragmentShadingContext &context) const;
236     void shadePrimitives(rr::GeometryEmitter &output, int verticesIn, const rr::PrimitivePacket *packets,
237                          const int numPackets, int invocationID) const;
238 
239 private:
240     size_t calcOutputVertices(rr::GeometryShaderInputType inputType) const;
241     std::string genGeometrySource(const glu::ContextType &contextType, rr::GeometryShaderInputType inputType,
242                                   rr::GeometryShaderOutputType outputType) const;
243 };
244 
VertexExpanderShader(const glu::ContextType & contextType,rr::GeometryShaderInputType inputType,rr::GeometryShaderOutputType outputType)245 VertexExpanderShader::VertexExpanderShader(const glu::ContextType &contextType, rr::GeometryShaderInputType inputType,
246                                            rr::GeometryShaderOutputType outputType)
247     : sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
248                           << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
249                           << sglr::pdec::VertexAttribute("a_color", rr::GENERICVECTYPE_FLOAT)
250                           << sglr::pdec::VertexToGeometryVarying(rr::GENERICVECTYPE_FLOAT)
251                           << sglr::pdec::GeometryToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
252                           << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
253                           << sglr::pdec::VertexSource(specializeShader(s_commonShaderSourceVertex, contextType))
254                           << sglr::pdec::FragmentSource(specializeShader(s_commonShaderSourceFragment, contextType))
255                           << sglr::pdec::GeometryShaderDeclaration(inputType, outputType, calcOutputVertices(inputType))
256                           << sglr::pdec::GeometrySource(genGeometrySource(contextType, inputType, outputType)))
257 {
258 }
259 
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const260 void VertexExpanderShader::shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets,
261                                          const int numPackets) const
262 {
263     for (int ndx = 0; ndx < numPackets; ++ndx)
264     {
265         packets[ndx]->position =
266             rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
267         packets[ndx]->pointSize = 1.0f;
268         packets[ndx]->outputs[0] =
269             rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
270     }
271 }
272 
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const273 void VertexExpanderShader::shadeFragments(rr::FragmentPacket *packets, const int numPackets,
274                                           const rr::FragmentShadingContext &context) const
275 {
276     for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
277         for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
278             rr::writeFragmentOutput(context, packetNdx, fragNdx, 0,
279                                     rr::readVarying<float>(packets[packetNdx], context, 0, fragNdx));
280 }
281 
shadePrimitives(rr::GeometryEmitter & output,int verticesIn,const rr::PrimitivePacket * packets,const int numPackets,int invocationID) const282 void VertexExpanderShader::shadePrimitives(rr::GeometryEmitter &output, int verticesIn,
283                                            const rr::PrimitivePacket *packets, const int numPackets,
284                                            int invocationID) const
285 {
286     DE_UNREF(invocationID);
287 
288     for (int ndx = 0; ndx < numPackets; ++ndx)
289         for (int verticeNdx = 0; verticeNdx < verticesIn; ++verticeNdx)
290         {
291             const tcu::Vec4 offsets[] = {tcu::Vec4(-0.07f, -0.01f, 0.0f, 0.0f), tcu::Vec4(0.03f, -0.03f, 0.0f, 0.0f),
292                                          tcu::Vec4(-0.01f, 0.08f, 0.0f, 0.0f)};
293             const tcu::Vec4 yoffset   = float(packets[ndx].primitiveIDIn) * tcu::Vec4(0.02f, 0.1f, 0, 0);
294 
295             // Create new primitive at every input vertice
296             const rr::VertexPacket *vertex = packets[ndx].vertices[verticeNdx];
297 
298             output.EmitVertex(vertex->position + offsets[0] + yoffset, vertex->pointSize, vertex->outputs,
299                               packets[ndx].primitiveIDIn);
300             output.EmitVertex(vertex->position + offsets[1] + yoffset, vertex->pointSize, vertex->outputs,
301                               packets[ndx].primitiveIDIn);
302             output.EmitVertex(vertex->position + offsets[2] + yoffset, vertex->pointSize, vertex->outputs,
303                               packets[ndx].primitiveIDIn);
304             output.EndPrimitive();
305         }
306 }
307 
calcOutputVertices(rr::GeometryShaderInputType inputType) const308 size_t VertexExpanderShader::calcOutputVertices(rr::GeometryShaderInputType inputType) const
309 {
310     switch (inputType)
311     {
312     case rr::GEOMETRYSHADERINPUTTYPE_POINTS:
313         return 1 * 3;
314     case rr::GEOMETRYSHADERINPUTTYPE_LINES:
315         return 2 * 3;
316     case rr::GEOMETRYSHADERINPUTTYPE_LINES_ADJACENCY:
317         return 4 * 3;
318     case rr::GEOMETRYSHADERINPUTTYPE_TRIANGLES:
319         return 3 * 3;
320     case rr::GEOMETRYSHADERINPUTTYPE_TRIANGLES_ADJACENCY:
321         return 6 * 3;
322     default:
323         DE_ASSERT(false);
324         return 0;
325     }
326 }
327 
genGeometrySource(const glu::ContextType & contextType,rr::GeometryShaderInputType inputType,rr::GeometryShaderOutputType outputType) const328 std::string VertexExpanderShader::genGeometrySource(const glu::ContextType &contextType,
329                                                     rr::GeometryShaderInputType inputType,
330                                                     rr::GeometryShaderOutputType outputType) const
331 {
332     std::ostringstream str;
333 
334     str << "${GLSL_VERSION_DECL}\n";
335     str << "${GLSL_EXT_GEOMETRY_SHADER}";
336     str << "layout(" << inputTypeToGLString(inputType) << ") in;\n";
337     str << "layout(" << outputTypeToGLString(outputType) << ", max_vertices = " << calcOutputVertices(inputType)
338         << ") out;";
339     str << "\n";
340     str << s_expandShaderSourceGeometryBody;
341 
342     return specializeShader(str.str(), contextType);
343 }
344 
345 class VertexEmitterShader : public sglr::ShaderProgram
346 {
347 public:
348     VertexEmitterShader(const glu::ContextType &contextType, int emitCountA, int endCountA, int emitCountB,
349                         int endCountB, rr::GeometryShaderOutputType outputType);
350 
351     void shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets, const int numPackets) const;
352     void shadeFragments(rr::FragmentPacket *packets, const int numPackets,
353                         const rr::FragmentShadingContext &context) const;
354     void shadePrimitives(rr::GeometryEmitter &output, int verticesIn, const rr::PrimitivePacket *packets,
355                          const int numPackets, int invocationID) const;
356 
357 private:
358     std::string genGeometrySource(const glu::ContextType &contextType, int emitCountA, int endCountA, int emitCountB,
359                                   int endCountB, rr::GeometryShaderOutputType outputType) const;
360 
361     int m_emitCountA;
362     int m_endCountA;
363     int m_emitCountB;
364     int m_endCountB;
365 };
366 
VertexEmitterShader(const glu::ContextType & contextType,int emitCountA,int endCountA,int emitCountB,int endCountB,rr::GeometryShaderOutputType outputType)367 VertexEmitterShader::VertexEmitterShader(const glu::ContextType &contextType, int emitCountA, int endCountA,
368                                          int emitCountB, int endCountB, rr::GeometryShaderOutputType outputType)
369     : sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
370                           << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
371                           << sglr::pdec::VertexAttribute("a_color", rr::GENERICVECTYPE_FLOAT)
372                           << sglr::pdec::VertexToGeometryVarying(rr::GENERICVECTYPE_FLOAT)
373                           << sglr::pdec::GeometryToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
374                           << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
375                           << sglr::pdec::VertexSource(specializeShader(s_commonShaderSourceVertex, contextType))
376                           << sglr::pdec::FragmentSource(specializeShader(s_commonShaderSourceFragment, contextType))
377                           << sglr::pdec::GeometryShaderDeclaration(rr::GEOMETRYSHADERINPUTTYPE_POINTS, outputType,
378                                                                    emitCountA + emitCountB)
379                           << sglr::pdec::GeometrySource(genGeometrySource(contextType, emitCountA, endCountA,
380                                                                           emitCountB, endCountB, outputType)))
381     , m_emitCountA(emitCountA)
382     , m_endCountA(endCountA)
383     , m_emitCountB(emitCountB)
384     , m_endCountB(endCountB)
385 {
386 }
387 
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const388 void VertexEmitterShader::shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets,
389                                         const int numPackets) const
390 {
391     for (int ndx = 0; ndx < numPackets; ++ndx)
392     {
393         packets[ndx]->position =
394             rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
395         packets[ndx]->pointSize = 1.0f;
396         packets[ndx]->outputs[0] =
397             rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
398     }
399 }
400 
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const401 void VertexEmitterShader::shadeFragments(rr::FragmentPacket *packets, const int numPackets,
402                                          const rr::FragmentShadingContext &context) const
403 {
404     for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
405         for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
406             rr::writeFragmentOutput(context, packetNdx, fragNdx, 0,
407                                     rr::readVarying<float>(packets[packetNdx], context, 0, fragNdx));
408 }
409 
shadePrimitives(rr::GeometryEmitter & output,int verticesIn,const rr::PrimitivePacket * packets,const int numPackets,int invocationID) const410 void VertexEmitterShader::shadePrimitives(rr::GeometryEmitter &output, int verticesIn,
411                                           const rr::PrimitivePacket *packets, const int numPackets,
412                                           int invocationID) const
413 {
414     DE_UNREF(verticesIn);
415     DE_UNREF(invocationID);
416 
417     for (int ndx = 0; ndx < numPackets; ++ndx)
418     {
419         const tcu::Vec4 positions[] = {
420             tcu::Vec4(-0.5f, 0.5f, 0.0f, 0.0f), tcu::Vec4(0.0f, 0.1f, 0.0f, 0.0f), tcu::Vec4(0.5f, 0.5f, 0.0f, 0.0f),
421             tcu::Vec4(0.7f, -0.2f, 0.0f, 0.0f), tcu::Vec4(0.2f, 0.2f, 0.0f, 0.0f), tcu::Vec4(0.4f, -0.3f, 0.0f, 0.0f),
422         };
423 
424         // Create new primitive at this point
425         const rr::VertexPacket *vertex = packets[ndx].vertices[0];
426 
427         for (int i = 0; i < m_emitCountA; ++i)
428             output.EmitVertex(vertex->position + positions[i], vertex->pointSize, vertex->outputs,
429                               packets[ndx].primitiveIDIn);
430 
431         for (int i = 0; i < m_endCountA; ++i)
432             output.EndPrimitive();
433 
434         for (int i = 0; i < m_emitCountB; ++i)
435             output.EmitVertex(vertex->position + positions[m_emitCountA + i], vertex->pointSize, vertex->outputs,
436                               packets[ndx].primitiveIDIn);
437 
438         for (int i = 0; i < m_endCountB; ++i)
439             output.EndPrimitive();
440     }
441 }
442 
genGeometrySource(const glu::ContextType & contextType,int emitCountA,int endCountA,int emitCountB,int endCountB,rr::GeometryShaderOutputType outputType) const443 std::string VertexEmitterShader::genGeometrySource(const glu::ContextType &contextType, int emitCountA, int endCountA,
444                                                    int emitCountB, int endCountB,
445                                                    rr::GeometryShaderOutputType outputType) const
446 {
447     std::ostringstream str;
448 
449     str << "${GLSL_VERSION_DECL}\n";
450     str << "${GLSL_EXT_GEOMETRY_SHADER}";
451     str << "layout(points) in;\n";
452     str << "layout(" << outputTypeToGLString(outputType) << ", max_vertices = " << (emitCountA + emitCountB)
453         << ") out;";
454     str << "\n";
455 
456     str << "in highp vec4 v_geom_FragColor[];\n"
457            "out highp vec4 v_frag_FragColor;\n"
458            "\n"
459            "void main (void)\n"
460            "{\n"
461            "    const highp vec4 position0 = vec4(-0.5,  0.5, 0.0, 0.0);\n"
462            "    const highp vec4 position1 = vec4( 0.0,  0.1, 0.0, 0.0);\n"
463            "    const highp vec4 position2 = vec4( 0.5,  0.5, 0.0, 0.0);\n"
464            "    const highp vec4 position3 = vec4( 0.7, -0.2, 0.0, 0.0);\n"
465            "    const highp vec4 position4 = vec4( 0.2,  0.2, 0.0, 0.0);\n"
466            "    const highp vec4 position5 = vec4( 0.4, -0.3, 0.0, 0.0);\n"
467            "\n";
468 
469     for (int i = 0; i < emitCountA; ++i)
470         str << "    gl_Position = gl_in[0].gl_Position + position" << i
471             << ";\n"
472                "    gl_PrimitiveID = gl_PrimitiveIDIn;\n"
473                "    v_frag_FragColor = v_geom_FragColor[0];\n"
474                "    EmitVertex();\n"
475                "\n";
476 
477     for (int i = 0; i < endCountA; ++i)
478         str << "    EndPrimitive();\n";
479 
480     for (int i = 0; i < emitCountB; ++i)
481         str << "    gl_Position = gl_in[0].gl_Position + position" << (emitCountA + i)
482             << ";\n"
483                "    gl_PrimitiveID = gl_PrimitiveIDIn;\n"
484                "    v_frag_FragColor = v_geom_FragColor[0];\n"
485                "    EmitVertex();\n"
486                "\n";
487 
488     for (int i = 0; i < endCountB; ++i)
489         str << "    EndPrimitive();\n";
490 
491     str << "}\n";
492 
493     return specializeShader(str.str(), contextType);
494 }
495 
496 class VertexVaryingShader : public sglr::ShaderProgram
497 {
498 public:
499     VertexVaryingShader(const glu::ContextType &contextType, int vertexOut, int geometryOut);
500 
501     void shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets, const int numPackets) const;
502     void shadeFragments(rr::FragmentPacket *packets, const int numPackets,
503                         const rr::FragmentShadingContext &context) const;
504     void shadePrimitives(rr::GeometryEmitter &output, int verticesIn, const rr::PrimitivePacket *packets,
505                          const int numPackets, int invocationID) const;
506 
507 private:
508     static sglr::pdec::ShaderProgramDeclaration genProgramDeclaration(const glu::ContextType &contextType,
509                                                                       int vertexOut, int geometryOut);
510 
511     const int m_vertexOut;
512     const int m_geometryOut;
513 };
514 
VertexVaryingShader(const glu::ContextType & contextType,int vertexOut,int geometryOut)515 VertexVaryingShader::VertexVaryingShader(const glu::ContextType &contextType, int vertexOut, int geometryOut)
516     : sglr::ShaderProgram(genProgramDeclaration(contextType, vertexOut, geometryOut))
517     , m_vertexOut(vertexOut)
518     , m_geometryOut(geometryOut)
519 {
520 }
521 
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const522 void VertexVaryingShader::shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets,
523                                         const int numPackets) const
524 {
525     // vertex shader is no-op
526     if (m_vertexOut == -1)
527         return;
528 
529     for (int ndx = 0; ndx < numPackets; ++ndx)
530     {
531         const tcu::Vec4 color =
532             rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
533 
534         packets[ndx]->position =
535             rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
536         packets[ndx]->pointSize = 1.0f;
537 
538         switch (m_vertexOut)
539         {
540         case 0:
541             break;
542 
543         case 1:
544             packets[ndx]->outputs[0] = color;
545             break;
546 
547         case 2:
548             packets[ndx]->outputs[0] = color * 0.5f;
549             packets[ndx]->outputs[1] = color.swizzle(2, 1, 0, 3) * 0.5f;
550             break;
551 
552         default:
553             DE_ASSERT(false);
554         }
555     }
556 }
557 
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const558 void VertexVaryingShader::shadeFragments(rr::FragmentPacket *packets, const int numPackets,
559                                          const rr::FragmentShadingContext &context) const
560 {
561     for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
562     {
563         switch (m_geometryOut)
564         {
565         case 0:
566             for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
567                 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f));
568             break;
569 
570         case 1:
571             for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
572                 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0,
573                                         rr::readTriangleVarying<float>(packets[packetNdx], context, 0, fragNdx));
574             break;
575 
576         case 2:
577             for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
578                 rr::writeFragmentOutput(
579                     context, packetNdx, fragNdx, 0,
580                     rr::readTriangleVarying<float>(packets[packetNdx], context, 0, fragNdx) +
581                         rr::readTriangleVarying<float>(packets[packetNdx], context, 1, fragNdx).swizzle(1, 0, 2, 3));
582             break;
583 
584         default:
585             DE_ASSERT(false);
586         }
587     }
588 }
589 
shadePrimitives(rr::GeometryEmitter & output,int verticesIn,const rr::PrimitivePacket * packets,const int numPackets,int invocationID) const590 void VertexVaryingShader::shadePrimitives(rr::GeometryEmitter &output, int verticesIn,
591                                           const rr::PrimitivePacket *packets, const int numPackets,
592                                           int invocationID) const
593 {
594     DE_UNREF(invocationID);
595 
596     const tcu::Vec4 vertexOffset(-0.2f, -0.2f, 0, 0);
597 
598     if (m_vertexOut == -1)
599     {
600         // vertex is a no-op
601         const tcu::Vec4 inputColor = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
602         rr::GenericVec4 outputs[2];
603 
604         // output color
605         switch (m_geometryOut)
606         {
607         case 0:
608             break;
609 
610         case 1:
611             outputs[0] = inputColor;
612             break;
613 
614         case 2:
615             outputs[0] = inputColor * 0.5f;
616             outputs[1] = inputColor.swizzle(1, 0, 2, 3) * 0.5f;
617             break;
618 
619         default:
620             DE_ASSERT(false);
621         }
622 
623         for (int ndx = 0; ndx < numPackets; ++ndx)
624         {
625             output.EmitVertex(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f) + vertexOffset, 1.0f, outputs,
626                               packets[ndx].primitiveIDIn);
627             output.EmitVertex(tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f) + vertexOffset, 1.0f, outputs,
628                               packets[ndx].primitiveIDIn);
629             output.EmitVertex(tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f) + vertexOffset, 1.0f, outputs,
630                               packets[ndx].primitiveIDIn);
631             output.EndPrimitive();
632         }
633     }
634     else
635     {
636         // vertex is not a no-op
637         for (int ndx = 0; ndx < numPackets; ++ndx)
638         {
639             for (int verticeNdx = 0; verticeNdx < verticesIn; ++verticeNdx)
640             {
641                 tcu::Vec4 inputColor;
642                 rr::GenericVec4 outputs[2];
643 
644                 // input color
645                 switch (m_vertexOut)
646                 {
647                 case 0:
648                     inputColor = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
649                     break;
650 
651                 case 1:
652                     inputColor = packets[ndx].vertices[verticeNdx]->outputs[0].get<float>();
653                     break;
654 
655                 case 2:
656                     inputColor =
657                         (packets[ndx].vertices[verticeNdx]->outputs[0].get<float>() * 0.5f) +
658                         (packets[ndx].vertices[verticeNdx]->outputs[1].get<float>().swizzle(2, 1, 0, 3) * 0.5f);
659                     break;
660 
661                 default:
662                     DE_ASSERT(false);
663                 }
664 
665                 // output color
666                 switch (m_geometryOut)
667                 {
668                 case 0:
669                     break;
670 
671                 case 1:
672                     outputs[0] = inputColor;
673                     break;
674 
675                 case 2:
676                     outputs[0] = inputColor * 0.5f;
677                     outputs[1] = inputColor.swizzle(1, 0, 2, 3) * 0.5f;
678                     break;
679 
680                 default:
681                     DE_ASSERT(false);
682                 }
683 
684                 output.EmitVertex(packets[ndx].vertices[verticeNdx]->position + vertexOffset,
685                                   packets[ndx].vertices[verticeNdx]->pointSize, outputs, packets[ndx].primitiveIDIn);
686             }
687             output.EndPrimitive();
688         }
689     }
690 }
691 
genProgramDeclaration(const glu::ContextType & contextType,int vertexOut,int geometryOut)692 sglr::pdec::ShaderProgramDeclaration VertexVaryingShader::genProgramDeclaration(const glu::ContextType &contextType,
693                                                                                 int vertexOut, int geometryOut)
694 {
695     sglr::pdec::ShaderProgramDeclaration decl;
696     std::ostringstream vertexSource;
697     std::ostringstream fragmentSource;
698     std::ostringstream geometrySource;
699 
700     decl << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
701          << sglr::pdec::VertexAttribute("a_color", rr::GENERICVECTYPE_FLOAT);
702 
703     for (int i = 0; i < vertexOut; ++i)
704         decl << sglr::pdec::VertexToGeometryVarying(rr::GENERICVECTYPE_FLOAT);
705     for (int i = 0; i < geometryOut; ++i)
706         decl << sglr::pdec::GeometryToFragmentVarying(rr::GENERICVECTYPE_FLOAT);
707 
708     decl << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
709          << sglr::pdec::GeometryShaderDeclaration(rr::GEOMETRYSHADERINPUTTYPE_TRIANGLES,
710                                                   rr::GEOMETRYSHADEROUTPUTTYPE_TRIANGLE_STRIP, 3);
711 
712     // vertexSource
713 
714     vertexSource << "${GLSL_VERSION_DECL}\n"
715                     "in highp vec4 a_position;\n"
716                     "in highp vec4 a_color;\n";
717 
718     // no-op case?
719     if (vertexOut == -1)
720     {
721         vertexSource << "void main (void)\n"
722                         "{\n"
723                         "}\n";
724     }
725     else
726     {
727         for (int i = 0; i < vertexOut; ++i)
728             vertexSource << "out highp vec4 v_geom_" << i << ";\n";
729 
730         vertexSource << "void main (void)\n"
731                         "{\n"
732                         "\tgl_Position = a_position;\n"
733                         "\tgl_PointSize = 1.0;\n";
734         switch (vertexOut)
735         {
736         case 0:
737             break;
738 
739         case 1:
740             vertexSource << "\tv_geom_0 = a_color;\n";
741             break;
742 
743         case 2:
744             vertexSource << "\tv_geom_0 = a_color * 0.5;\n";
745             vertexSource << "\tv_geom_1 = a_color.zyxw * 0.5;\n";
746             break;
747 
748         default:
749             DE_ASSERT(false);
750         }
751         vertexSource << "}\n";
752     }
753 
754     // fragmentSource
755 
756     fragmentSource << "${GLSL_VERSION_DECL}\n"
757                       "layout(location = 0) out mediump vec4 fragColor;\n";
758 
759     for (int i = 0; i < geometryOut; ++i)
760         fragmentSource << "in mediump vec4 v_frag_" << i << ";\n";
761 
762     fragmentSource << "void main (void)\n"
763                       "{\n";
764     switch (geometryOut)
765     {
766     case 0:
767         fragmentSource << "\tfragColor = vec4(1.0, 0.0, 0.0, 1.0);\n";
768         break;
769 
770     case 1:
771         fragmentSource << "\tfragColor = v_frag_0;\n";
772         break;
773 
774     case 2:
775         fragmentSource << "\tfragColor = v_frag_0 + v_frag_1.yxzw;\n";
776         break;
777 
778     default:
779         DE_ASSERT(false);
780     }
781     fragmentSource << "}\n";
782 
783     // geometrySource
784 
785     geometrySource << "${GLSL_VERSION_DECL}\n"
786                       "${GLSL_EXT_GEOMETRY_SHADER}"
787                       "layout(triangles) in;\n"
788                       "layout(triangle_strip, max_vertices = 3) out;\n";
789 
790     for (int i = 0; i < vertexOut; ++i)
791         geometrySource << "in highp vec4 v_geom_" << i << "[];\n";
792     for (int i = 0; i < geometryOut; ++i)
793         geometrySource << "out highp vec4 v_frag_" << i << ";\n";
794 
795     geometrySource << "void main (void)\n"
796                       "{\n"
797                       "\thighp vec4 offset = vec4(-0.2, -0.2, 0.0, 0.0);\n"
798                       "\thighp vec4 inputColor;\n\n";
799 
800     for (int vertexNdx = 0; vertexNdx < 3; ++vertexNdx)
801     {
802         if (vertexOut == -1)
803         {
804             // vertex is a no-op
805             geometrySource << "\tinputColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
806                               "\tgl_Position = vec4("
807                            << ((vertexNdx == 0) ? ("0.0, 0.0") : ((vertexNdx == 1) ? ("1.0, 0.0") : ("1.0, 1.0")))
808                            << ", 0.0, 1.0) + offset;\n"
809                               "\tgl_PrimitiveID = gl_PrimitiveIDIn;\n";
810         }
811         else
812         {
813             switch (vertexOut)
814             {
815             case 0:
816                 geometrySource << "\tinputColor = vec4(1.0, 0.0, 0.0, 1.0);\n";
817                 break;
818 
819             case 1:
820                 geometrySource << "\tinputColor = v_geom_0[" << vertexNdx << "];\n";
821                 break;
822 
823             case 2:
824                 geometrySource << "\tinputColor = v_geom_0[" << vertexNdx << "] * 0.5 + v_geom_1[" << vertexNdx
825                                << "].zyxw * 0.5;\n";
826                 break;
827 
828             default:
829                 DE_ASSERT(false);
830             }
831             geometrySource << "\tgl_Position = gl_in[" << vertexNdx
832                            << "].gl_Position + offset;\n"
833                               "\tgl_PrimitiveID = gl_PrimitiveIDIn;\n";
834         }
835 
836         switch (geometryOut)
837         {
838         case 0:
839             break;
840 
841         case 1:
842             geometrySource << "\tv_frag_0 = inputColor;\n";
843             break;
844 
845         case 2:
846             geometrySource << "\tv_frag_0 = inputColor * 0.5;\n";
847             geometrySource << "\tv_frag_1 = inputColor.yxzw * 0.5;\n";
848             break;
849 
850         default:
851             DE_ASSERT(false);
852         }
853 
854         geometrySource << "\tEmitVertex();\n\n";
855     }
856 
857     geometrySource << "\tEndPrimitive();\n"
858                       "}\n";
859 
860     decl << sglr::pdec::VertexSource(specializeShader(vertexSource.str(), contextType))
861          << sglr::pdec::FragmentSource(specializeShader(fragmentSource.str(), contextType))
862          << sglr::pdec::GeometrySource(specializeShader(geometrySource.str(), contextType));
863     return decl;
864 }
865 
866 class OutputCountShader : public sglr::ShaderProgram
867 {
868 public:
869     OutputCountShader(const glu::ContextType &contextType, const OutputCountPatternSpec &spec);
870 
871     void shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets, const int numPackets) const;
872     void shadeFragments(rr::FragmentPacket *packets, const int numPackets,
873                         const rr::FragmentShadingContext &context) const;
874     void shadePrimitives(rr::GeometryEmitter &output, int verticesIn, const rr::PrimitivePacket *packets,
875                          const int numPackets, int invocationID) const;
876 
877 private:
878     std::string genGeometrySource(const glu::ContextType &contextType, const OutputCountPatternSpec &spec) const;
879     size_t getPatternEmitCount(const OutputCountPatternSpec &spec) const;
880 
881     const int m_patternLength;
882     const int m_patternMaxEmitCount;
883     const OutputCountPatternSpec m_spec;
884 };
885 
OutputCountShader(const glu::ContextType & contextType,const OutputCountPatternSpec & spec)886 OutputCountShader::OutputCountShader(const glu::ContextType &contextType, const OutputCountPatternSpec &spec)
887     : sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
888                           << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
889                           << sglr::pdec::VertexAttribute("a_color", rr::GENERICVECTYPE_FLOAT)
890                           << sglr::pdec::VertexToGeometryVarying(rr::GENERICVECTYPE_FLOAT)
891                           << sglr::pdec::GeometryToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
892                           << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
893                           << sglr::pdec::VertexSource(specializeShader(s_commonShaderSourceVertex, contextType))
894                           << sglr::pdec::FragmentSource(specializeShader(s_commonShaderSourceFragment, contextType))
895                           << sglr::pdec::GeometryShaderDeclaration(rr::GEOMETRYSHADERINPUTTYPE_POINTS,
896                                                                    rr::GEOMETRYSHADEROUTPUTTYPE_TRIANGLE_STRIP,
897                                                                    getPatternEmitCount(spec))
898                           << sglr::pdec::GeometrySource(genGeometrySource(contextType, spec)))
899     , m_patternLength((int)spec.pattern.size())
900     , m_patternMaxEmitCount((int)getPatternEmitCount(spec))
901     , m_spec(spec)
902 {
903 }
904 
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const905 void OutputCountShader::shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets,
906                                       const int numPackets) const
907 {
908     for (int ndx = 0; ndx < numPackets; ++ndx)
909     {
910         packets[ndx]->position =
911             rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
912         packets[ndx]->pointSize = 1.0f;
913         packets[ndx]->outputs[0] =
914             rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
915     }
916 }
917 
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const918 void OutputCountShader::shadeFragments(rr::FragmentPacket *packets, const int numPackets,
919                                        const rr::FragmentShadingContext &context) const
920 {
921     for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
922         for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
923             rr::writeFragmentOutput(context, packetNdx, fragNdx, 0,
924                                     rr::readVarying<float>(packets[packetNdx], context, 0, fragNdx));
925 }
926 
shadePrimitives(rr::GeometryEmitter & output,int verticesIn,const rr::PrimitivePacket * packets,const int numPackets,int invocationID) const927 void OutputCountShader::shadePrimitives(rr::GeometryEmitter &output, int verticesIn, const rr::PrimitivePacket *packets,
928                                         const int numPackets, int invocationID) const
929 {
930     DE_UNREF(verticesIn);
931     DE_UNREF(invocationID);
932 
933     const float rowHeight = 2.0f / (float)m_patternLength;
934     const float colWidth  = 2.0f / (float)m_patternMaxEmitCount;
935 
936     for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
937     {
938         // Create triangle strip at this point
939         const rr::VertexPacket *vertex = packets[packetNdx].vertices[0];
940         const int emitCount            = m_spec.pattern[packets[packetNdx].primitiveIDIn];
941 
942         for (int ndx = 0; ndx < emitCount / 2; ++ndx)
943         {
944             output.EmitVertex(vertex->position + tcu::Vec4(2 * (float)ndx * colWidth, 0.0, 0.0, 0.0), vertex->pointSize,
945                               vertex->outputs, packets[packetNdx].primitiveIDIn);
946             output.EmitVertex(vertex->position + tcu::Vec4(2 * (float)ndx * colWidth, rowHeight, 0.0, 0.0),
947                               vertex->pointSize, vertex->outputs, packets[packetNdx].primitiveIDIn);
948         }
949         output.EndPrimitive();
950     }
951 }
952 
genGeometrySource(const glu::ContextType & contextType,const OutputCountPatternSpec & spec) const953 std::string OutputCountShader::genGeometrySource(const glu::ContextType &contextType,
954                                                  const OutputCountPatternSpec &spec) const
955 {
956     std::ostringstream str;
957 
958     // draw row with a triangle strip, always make rectangles
959     for (int ndx = 0; ndx < (int)spec.pattern.size(); ++ndx)
960         DE_ASSERT(spec.pattern[ndx] % 2 == 0);
961 
962     str << "${GLSL_VERSION_DECL}\n";
963     str << "${GLSL_EXT_GEOMETRY_SHADER}";
964     str << "layout(points) in;\n";
965     str << "layout(triangle_strip, max_vertices = " << getPatternEmitCount(spec) << ") out;";
966     str << "\n";
967 
968     str << "in highp vec4 v_geom_FragColor[];\n"
969            "out highp vec4 v_frag_FragColor;\n"
970            "\n"
971            "void main (void)\n"
972            "{\n"
973            "    const highp float rowHeight = 2.0 / float("
974         << spec.pattern.size()
975         << ");\n"
976            "    const highp float colWidth = 2.0 / float("
977         << getPatternEmitCount(spec)
978         << ");\n"
979            "\n";
980 
981     str << "    highp int emitCount = ";
982     for (int ndx = 0; ndx < (int)spec.pattern.size() - 1; ++ndx)
983         str << "(gl_PrimitiveIDIn == " << ndx << ") ? (" << spec.pattern[ndx] << ") : (";
984     str << spec.pattern[(int)spec.pattern.size() - 1] << ((spec.pattern.size() == 1) ? ("") : (")")) << ";\n";
985 
986     str << "    for (highp int ndx = 0; ndx < emitCount / 2; ndx++)\n"
987            "    {\n"
988            "        gl_Position = gl_in[0].gl_Position + vec4(float(ndx) * 2.0 * colWidth, 0.0, 0.0, 0.0);\n"
989            "        v_frag_FragColor = v_geom_FragColor[0];\n"
990            "        EmitVertex();\n"
991            "\n"
992            "        gl_Position = gl_in[0].gl_Position + vec4(float(ndx) * 2.0 * colWidth, rowHeight, 0.0, 0.0);\n"
993            "        v_frag_FragColor = v_geom_FragColor[0];\n"
994            "        EmitVertex();\n"
995            "    }\n"
996            "}\n";
997 
998     return specializeShader(str.str(), contextType);
999 }
1000 
getPatternEmitCount(const OutputCountPatternSpec & spec) const1001 size_t OutputCountShader::getPatternEmitCount(const OutputCountPatternSpec &spec) const
1002 {
1003     return *std::max_element(spec.pattern.begin(), spec.pattern.end());
1004 }
1005 
1006 class BuiltinVariableShader : public sglr::ShaderProgram
1007 {
1008 public:
1009     enum VariableTest
1010     {
1011         TEST_POINT_SIZE = 0,
1012         TEST_PRIMITIVE_ID_IN,
1013         TEST_PRIMITIVE_ID,
1014 
1015         TEST_LAST
1016     };
1017 
1018     BuiltinVariableShader(const glu::ContextType &contextType, VariableTest test);
1019 
1020     void shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets, const int numPackets) const;
1021     void shadeFragments(rr::FragmentPacket *packets, const int numPackets,
1022                         const rr::FragmentShadingContext &context) const;
1023     void shadePrimitives(rr::GeometryEmitter &output, int verticesIn, const rr::PrimitivePacket *packets,
1024                          const int numPackets, int invocationID) const;
1025 
1026     static const char *getTestAttributeName(VariableTest test);
1027 
1028 private:
1029     std::string genGeometrySource(const glu::ContextType &contextType, VariableTest test) const;
1030     std::string genVertexSource(const glu::ContextType &contextType, VariableTest test) const;
1031     std::string genFragmentSource(const glu::ContextType &contextType, VariableTest test) const;
1032 
1033     const VariableTest m_test;
1034 };
1035 
BuiltinVariableShader(const glu::ContextType & contextType,VariableTest test)1036 BuiltinVariableShader::BuiltinVariableShader(const glu::ContextType &contextType, VariableTest test)
1037     : sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
1038                           << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
1039                           << sglr::pdec::VertexAttribute(getTestAttributeName(test), rr::GENERICVECTYPE_FLOAT)
1040                           << sglr::pdec::VertexToGeometryVarying(rr::GENERICVECTYPE_FLOAT)
1041                           << sglr::pdec::GeometryToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
1042                           << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
1043                           << sglr::pdec::VertexSource(genVertexSource(contextType, test))
1044                           << sglr::pdec::FragmentSource(genFragmentSource(contextType, test))
1045                           << sglr::pdec::GeometryShaderDeclaration(rr::GEOMETRYSHADERINPUTTYPE_POINTS,
1046                                                                    ((test == TEST_POINT_SIZE) ?
1047                                                                         (rr::GEOMETRYSHADEROUTPUTTYPE_POINTS) :
1048                                                                         (rr::GEOMETRYSHADEROUTPUTTYPE_TRIANGLE_STRIP)),
1049                                                                    ((test == TEST_POINT_SIZE) ? (1) : (3)))
1050                           << sglr::pdec::GeometrySource(genGeometrySource(contextType, test)))
1051     , m_test(test)
1052 {
1053 }
1054 
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const1055 void BuiltinVariableShader::shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets,
1056                                           const int numPackets) const
1057 {
1058     for (int ndx = 0; ndx < numPackets; ++ndx)
1059     {
1060         packets[ndx]->position =
1061             rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
1062         packets[ndx]->pointSize = 1.0f;
1063         packets[ndx]->outputs[0] =
1064             rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
1065     }
1066 }
1067 
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const1068 void BuiltinVariableShader::shadeFragments(rr::FragmentPacket *packets, const int numPackets,
1069                                            const rr::FragmentShadingContext &context) const
1070 {
1071     const tcu::Vec4 red       = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
1072     const tcu::Vec4 green     = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
1073     const tcu::Vec4 blue      = tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
1074     const tcu::Vec4 yellow    = tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f);
1075     const tcu::Vec4 colors[4] = {yellow, red, green, blue};
1076 
1077     if (m_test == TEST_POINT_SIZE || m_test == TEST_PRIMITIVE_ID_IN)
1078     {
1079         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
1080             for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
1081                 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0,
1082                                         rr::readVarying<float>(packets[packetNdx], context, 0, fragNdx));
1083     }
1084     else if (m_test == TEST_PRIMITIVE_ID)
1085     {
1086         const tcu::Vec4 color = colors[context.primitiveID % 4];
1087 
1088         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
1089             for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
1090                 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
1091     }
1092     else
1093         DE_ASSERT(false);
1094 }
1095 
shadePrimitives(rr::GeometryEmitter & output,int verticesIn,const rr::PrimitivePacket * packets,const int numPackets,int invocationID) const1096 void BuiltinVariableShader::shadePrimitives(rr::GeometryEmitter &output, int verticesIn,
1097                                             const rr::PrimitivePacket *packets, const int numPackets,
1098                                             int invocationID) const
1099 {
1100     DE_UNREF(verticesIn);
1101     DE_UNREF(invocationID);
1102 
1103     const tcu::Vec4 red       = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
1104     const tcu::Vec4 green     = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
1105     const tcu::Vec4 blue      = tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
1106     const tcu::Vec4 yellow    = tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f);
1107     const tcu::Vec4 colors[4] = {red, green, blue, yellow};
1108 
1109     for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
1110     {
1111         const rr::VertexPacket *vertex = packets[packetNdx].vertices[0];
1112 
1113         if (m_test == TEST_POINT_SIZE)
1114         {
1115             rr::GenericVec4 fragColor;
1116             const float pointSize = vertex->outputs[0].get<float>().x() + 1.0f;
1117 
1118             fragColor = tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
1119             output.EmitVertex(vertex->position, pointSize, &fragColor, packets[packetNdx].primitiveIDIn);
1120         }
1121         else if (m_test == TEST_PRIMITIVE_ID_IN)
1122         {
1123             rr::GenericVec4 fragColor;
1124             fragColor = colors[packets[packetNdx].primitiveIDIn % 4];
1125 
1126             output.EmitVertex(vertex->position + tcu::Vec4(0.05f, 0.0f, 0.0f, 0.0f), 1.0f, &fragColor,
1127                               packets[packetNdx].primitiveIDIn);
1128             output.EmitVertex(vertex->position - tcu::Vec4(0.05f, 0.0f, 0.0f, 0.0f), 1.0f, &fragColor,
1129                               packets[packetNdx].primitiveIDIn);
1130             output.EmitVertex(vertex->position + tcu::Vec4(0.0f, 0.05f, 0.0f, 0.0f), 1.0f, &fragColor,
1131                               packets[packetNdx].primitiveIDIn);
1132         }
1133         else if (m_test == TEST_PRIMITIVE_ID)
1134         {
1135             const int primitiveID = (int)deFloatFloor(vertex->outputs[0].get<float>().x()) + 3;
1136 
1137             output.EmitVertex(vertex->position + tcu::Vec4(0.05f, 0.0f, 0.0f, 0.0f), 1.0f, vertex->outputs,
1138                               primitiveID);
1139             output.EmitVertex(vertex->position - tcu::Vec4(0.05f, 0.0f, 0.0f, 0.0f), 1.0f, vertex->outputs,
1140                               primitiveID);
1141             output.EmitVertex(vertex->position + tcu::Vec4(0.0f, 0.05f, 0.0f, 0.0f), 1.0f, vertex->outputs,
1142                               primitiveID);
1143         }
1144         else
1145             DE_ASSERT(false);
1146 
1147         output.EndPrimitive();
1148     }
1149 }
1150 
getTestAttributeName(VariableTest test)1151 const char *BuiltinVariableShader::getTestAttributeName(VariableTest test)
1152 {
1153     switch (test)
1154     {
1155     case TEST_POINT_SIZE:
1156         return "a_pointSize";
1157     case TEST_PRIMITIVE_ID_IN:
1158         return "";
1159     case TEST_PRIMITIVE_ID:
1160         return "a_primitiveID";
1161     default:
1162         DE_ASSERT(false);
1163         return "";
1164     }
1165 }
1166 
genGeometrySource(const glu::ContextType & contextType,VariableTest test) const1167 std::string BuiltinVariableShader::genGeometrySource(const glu::ContextType &contextType, VariableTest test) const
1168 {
1169     std::ostringstream buf;
1170 
1171     buf << "${GLSL_VERSION_DECL}\n"
1172            "${GLSL_EXT_GEOMETRY_SHADER}";
1173 
1174     const bool supportsGL45 = glu::contextSupports(contextType, glu::ApiType::core(4, 5));
1175 
1176     /* GL_EXT_geometry_point_size not available on desktop GLSL. */
1177     if (!supportsGL45 && test == TEST_POINT_SIZE)
1178         buf << "#extension GL_EXT_geometry_point_size : require\n";
1179 
1180     buf << "layout(points) in;\n";
1181 
1182     if (test == TEST_POINT_SIZE)
1183         buf << "layout(points, max_vertices = 1) out;\n";
1184     else
1185         buf << "layout(triangle_strip, max_vertices = 3) out;\n";
1186 
1187     if (test == TEST_POINT_SIZE)
1188         buf << "in highp vec4 v_geom_pointSize[];\n";
1189     else if (test == TEST_PRIMITIVE_ID)
1190         buf << "in highp vec4 v_geom_primitiveID[];\n";
1191 
1192     if (test != TEST_PRIMITIVE_ID)
1193         buf << "out highp vec4 v_frag_FragColor;\n";
1194 
1195     buf << "\n"
1196            "void main (void)\n"
1197            "{\n";
1198 
1199     if (test == TEST_POINT_SIZE)
1200     {
1201         buf << "    gl_Position = gl_in[0].gl_Position;\n"
1202                "    gl_PointSize = v_geom_pointSize[0].x + 1.0;\n"
1203                "    v_frag_FragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
1204                "    EmitVertex();\n";
1205     }
1206     else if (test == TEST_PRIMITIVE_ID_IN)
1207     {
1208         buf << "    const highp vec4 red = vec4(1.0, 0.0, 0.0, 1.0);\n"
1209                "    const highp vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
1210                "    const highp vec4 blue = vec4(0.0, 0.0, 1.0, 1.0);\n"
1211                "    const highp vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
1212                "    const highp vec4 colors[4] = vec4[4](red, green, blue, yellow);\n"
1213                "\n"
1214                "    gl_Position = gl_in[0].gl_Position + vec4(0.05, 0.0, 0.0, 0.0);\n"
1215                "    v_frag_FragColor = colors[gl_PrimitiveIDIn % 4];\n"
1216                "    EmitVertex();\n"
1217                "\n"
1218                "    gl_Position = gl_in[0].gl_Position - vec4(0.05, 0.0, 0.0, 0.0);\n"
1219                "    v_frag_FragColor = colors[gl_PrimitiveIDIn % 4];\n"
1220                "    EmitVertex();\n"
1221                "\n"
1222                "    gl_Position = gl_in[0].gl_Position + vec4(0.0, 0.05, 0.0, 0.0);\n"
1223                "    v_frag_FragColor = colors[gl_PrimitiveIDIn % 4];\n"
1224                "    EmitVertex();\n";
1225     }
1226     else if (test == TEST_PRIMITIVE_ID)
1227     {
1228         buf << "    gl_Position = gl_in[0].gl_Position + vec4(0.05, 0.0, 0.0, 0.0);\n"
1229                "    gl_PrimitiveID = int(floor(v_geom_primitiveID[0].x)) + 3;\n"
1230                "    EmitVertex();\n"
1231                "\n"
1232                "    gl_Position = gl_in[0].gl_Position - vec4(0.05, 0.0, 0.0, 0.0);\n"
1233                "    gl_PrimitiveID = int(floor(v_geom_primitiveID[0].x)) + 3;\n"
1234                "    EmitVertex();\n"
1235                "\n"
1236                "    gl_Position = gl_in[0].gl_Position + vec4(0.0, 0.05, 0.0, 0.0);\n"
1237                "    gl_PrimitiveID = int(floor(v_geom_primitiveID[0].x)) + 3;\n"
1238                "    EmitVertex();\n"
1239                "\n";
1240     }
1241     else
1242         DE_ASSERT(false);
1243 
1244     buf << "}\n";
1245 
1246     return specializeShader(buf.str(), contextType);
1247 }
1248 
genVertexSource(const glu::ContextType & contextType,VariableTest test) const1249 std::string BuiltinVariableShader::genVertexSource(const glu::ContextType &contextType, VariableTest test) const
1250 {
1251     std::ostringstream buf;
1252 
1253     buf << "${GLSL_VERSION_DECL}\n"
1254            "in highp vec4 a_position;\n";
1255 
1256     if (test == TEST_POINT_SIZE)
1257         buf << "in highp vec4 a_pointSize;\n";
1258     else if (test == TEST_PRIMITIVE_ID)
1259         buf << "in highp vec4 a_primitiveID;\n";
1260 
1261     if (test == TEST_POINT_SIZE)
1262         buf << "out highp vec4 v_geom_pointSize;\n";
1263     else if (test == TEST_PRIMITIVE_ID)
1264         buf << "out highp vec4 v_geom_primitiveID;\n";
1265 
1266     buf << "void main (void)\n"
1267            "{\n"
1268            "    gl_Position = a_position;\n"
1269            "    gl_PointSize = 1.0;\n";
1270 
1271     if (test == TEST_POINT_SIZE)
1272         buf << "    v_geom_pointSize = a_pointSize;\n";
1273     else if (test == TEST_PRIMITIVE_ID)
1274         buf << "    v_geom_primitiveID = a_primitiveID;\n";
1275 
1276     buf << "}\n";
1277 
1278     return specializeShader(buf.str(), contextType);
1279 }
1280 
genFragmentSource(const glu::ContextType & contextType,VariableTest test) const1281 std::string BuiltinVariableShader::genFragmentSource(const glu::ContextType &contextType, VariableTest test) const
1282 {
1283     std::ostringstream buf;
1284 
1285     if (test == TEST_POINT_SIZE || test == TEST_PRIMITIVE_ID_IN)
1286         return specializeShader(s_commonShaderSourceFragment, contextType);
1287     else if (test == TEST_PRIMITIVE_ID)
1288     {
1289         buf << "${GLSL_VERSION_DECL}\n"
1290                "${GLSL_EXT_GEOMETRY_SHADER}"
1291                "layout(location = 0) out mediump vec4 fragColor;\n"
1292                "void main (void)\n"
1293                "{\n"
1294                "    const mediump vec4 red = vec4(1.0, 0.0, 0.0, 1.0);\n"
1295                "    const mediump vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
1296                "    const mediump vec4 blue = vec4(0.0, 0.0, 1.0, 1.0);\n"
1297                "    const mediump vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
1298                "    const mediump vec4 colors[4] = vec4[4](yellow, red, green, blue);\n"
1299                "    fragColor = colors[gl_PrimitiveID % 4];\n"
1300                "}\n";
1301 
1302         return specializeShader(buf.str(), contextType);
1303     }
1304     else
1305     {
1306         DE_ASSERT(false);
1307         return "";
1308     }
1309 }
1310 
1311 class VaryingOutputCountShader : public sglr::ShaderProgram
1312 {
1313 public:
1314     enum VaryingSource
1315     {
1316         READ_ATTRIBUTE = 0,
1317         READ_UNIFORM,
1318         READ_TEXTURE,
1319 
1320         READ_LAST
1321     };
1322 
1323     enum
1324     {
1325         EMIT_COUNT_VERTEX_0 = 6,
1326         EMIT_COUNT_VERTEX_1 = 0,
1327         EMIT_COUNT_VERTEX_2 = -1,
1328         EMIT_COUNT_VERTEX_3 = 10,
1329     };
1330 
1331     VaryingOutputCountShader(const glu::ContextType &contextType, VaryingSource source, int maxEmitCount,
1332                              bool instanced);
1333 
1334     void shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets, const int numPackets) const;
1335     void shadeFragments(rr::FragmentPacket *packets, const int numPackets,
1336                         const rr::FragmentShadingContext &context) const;
1337     void shadePrimitives(rr::GeometryEmitter &output, int verticesIn, const rr::PrimitivePacket *packets,
1338                          const int numPackets, int invocationID) const;
1339 
1340     static const char *getAttributeName(VaryingSource test);
1341 
1342 private:
1343     static std::string genGeometrySource(const glu::ContextType &contextType, VaryingSource test, int maxEmitCount,
1344                                          bool instanced);
1345     static std::string genVertexSource(const glu::ContextType &contextType, VaryingSource test);
1346 
1347     const VaryingSource m_test;
1348     const sglr::UniformSlot &m_sampler;
1349     const sglr::UniformSlot &m_emitCount;
1350     const int m_maxEmitCount;
1351     const bool m_instanced;
1352 };
1353 
VaryingOutputCountShader(const glu::ContextType & contextType,VaryingSource source,int maxEmitCount,bool instanced)1354 VaryingOutputCountShader::VaryingOutputCountShader(const glu::ContextType &contextType, VaryingSource source,
1355                                                    int maxEmitCount, bool instanced)
1356     : sglr::ShaderProgram(
1357           sglr::pdec::ShaderProgramDeclaration()
1358           << sglr::pdec::Uniform("u_sampler", glu::TYPE_SAMPLER_2D)
1359           << sglr::pdec::Uniform("u_emitCount", glu::TYPE_INT_VEC4)
1360           << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
1361           << sglr::pdec::VertexAttribute(getAttributeName(source), rr::GENERICVECTYPE_FLOAT)
1362           << sglr::pdec::VertexToGeometryVarying(rr::GENERICVECTYPE_FLOAT)
1363           << sglr::pdec::GeometryToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
1364           << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
1365           << sglr::pdec::VertexSource(genVertexSource(contextType, source))
1366           << sglr::pdec::FragmentSource(specializeShader(s_commonShaderSourceFragment, contextType))
1367           << sglr::pdec::GeometryShaderDeclaration(rr::GEOMETRYSHADERINPUTTYPE_POINTS,
1368                                                    rr::GEOMETRYSHADEROUTPUTTYPE_TRIANGLE_STRIP, maxEmitCount,
1369                                                    (instanced) ? (4) : (1))
1370           << sglr::pdec::GeometrySource(genGeometrySource(contextType, source, maxEmitCount, instanced)))
1371     , m_test(source)
1372     , m_sampler(getUniformByName("u_sampler"))
1373     , m_emitCount(getUniformByName("u_emitCount"))
1374     , m_maxEmitCount(maxEmitCount)
1375     , m_instanced(instanced)
1376 {
1377 }
1378 
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const1379 void VaryingOutputCountShader::shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets,
1380                                              const int numPackets) const
1381 {
1382     for (int ndx = 0; ndx < numPackets; ++ndx)
1383     {
1384         packets[ndx]->position =
1385             rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
1386         packets[ndx]->outputs[0] =
1387             rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
1388     }
1389 }
1390 
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const1391 void VaryingOutputCountShader::shadeFragments(rr::FragmentPacket *packets, const int numPackets,
1392                                               const rr::FragmentShadingContext &context) const
1393 {
1394     for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
1395         for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
1396             rr::writeFragmentOutput(context, packetNdx, fragNdx, 0,
1397                                     rr::readVarying<float>(packets[packetNdx], context, 0, fragNdx));
1398 }
1399 
shadePrimitives(rr::GeometryEmitter & output,int verticesIn,const rr::PrimitivePacket * packets,const int numPackets,int invocationID) const1400 void VaryingOutputCountShader::shadePrimitives(rr::GeometryEmitter &output, int verticesIn,
1401                                                const rr::PrimitivePacket *packets, const int numPackets,
1402                                                int invocationID) const
1403 {
1404     DE_UNREF(verticesIn);
1405 
1406     const tcu::Vec4 red       = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
1407     const tcu::Vec4 green     = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
1408     const tcu::Vec4 blue      = tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
1409     const tcu::Vec4 yellow    = tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f);
1410     const tcu::Vec4 colors[4] = {red, green, blue, yellow};
1411 
1412     for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
1413     {
1414         const rr::VertexPacket *vertex = packets[packetNdx].vertices[0];
1415         int emitCount                  = 0;
1416         tcu::Vec4 color                = tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
1417 
1418         if (m_test == READ_ATTRIBUTE)
1419         {
1420             emitCount = (int)vertex->outputs[0].get<float>()[(m_instanced) ? (invocationID) : (0)];
1421             color     = tcu::Vec4((emitCount < 10) ? (0.0f) : (1.0f), (emitCount > 10) ? (0.0f) : (1.0f), 1.0f, 1.0f);
1422         }
1423         else if (m_test == READ_UNIFORM)
1424         {
1425             const int primitiveNdx = (m_instanced) ? (invocationID) : ((int)vertex->outputs[0].get<float>().x());
1426 
1427             DE_ASSERT(primitiveNdx >= 0);
1428             DE_ASSERT(primitiveNdx < 4);
1429 
1430             emitCount = m_emitCount.value.i4[primitiveNdx];
1431             color     = colors[primitiveNdx];
1432         }
1433         else if (m_test == READ_TEXTURE)
1434         {
1435             const int primitiveNdx   = (m_instanced) ? (invocationID) : ((int)vertex->outputs[0].get<float>().x());
1436             const tcu::Vec2 texCoord = tcu::Vec2(1.0f / 8.0f + (float)primitiveNdx / 4.0f, 0.5f);
1437             const tcu::Vec4 texColor = m_sampler.sampler.tex2D->sample(texCoord.x(), texCoord.y(), 0.0f);
1438 
1439             DE_ASSERT(primitiveNdx >= 0);
1440             DE_ASSERT(primitiveNdx < 4);
1441 
1442             color     = colors[primitiveNdx];
1443             emitCount = 0;
1444 
1445             if (texColor.x() > 0.0f)
1446                 emitCount += (EMIT_COUNT_VERTEX_0 == -1) ? (m_maxEmitCount) : (EMIT_COUNT_VERTEX_0);
1447             if (texColor.y() > 0.0f)
1448                 emitCount += (EMIT_COUNT_VERTEX_1 == -1) ? (m_maxEmitCount) : (EMIT_COUNT_VERTEX_1);
1449             if (texColor.z() > 0.0f)
1450                 emitCount += (EMIT_COUNT_VERTEX_2 == -1) ? (m_maxEmitCount) : (EMIT_COUNT_VERTEX_2);
1451             if (texColor.w() > 0.0f)
1452                 emitCount += (EMIT_COUNT_VERTEX_3 == -1) ? (m_maxEmitCount) : (EMIT_COUNT_VERTEX_3);
1453         }
1454         else
1455             DE_ASSERT(false);
1456 
1457         for (int ndx = 0; ndx < (int)emitCount / 2; ++ndx)
1458         {
1459             const float angle = (float(ndx) + 0.5f) / float(emitCount / 2) * 3.142f;
1460             const tcu::Vec4 basePosition =
1461                 (m_instanced) ?
1462                     (vertex->position +
1463                      tcu::Vec4(deFloatCos(float(invocationID)), deFloatSin(float(invocationID)), 0.0f, 0.0f) * 0.5f) :
1464                     (vertex->position);
1465             const tcu::Vec4 position0 =
1466                 basePosition + tcu::Vec4(deFloatCos(angle), deFloatSin(angle), 0.0f, 0.0f) * 0.15f;
1467             const tcu::Vec4 position1 =
1468                 basePosition + tcu::Vec4(deFloatCos(angle), -deFloatSin(angle), 0.0f, 0.0f) * 0.15f;
1469             rr::GenericVec4 fragColor;
1470 
1471             fragColor = color;
1472 
1473             output.EmitVertex(position0, 0.0f, &fragColor, packets[packetNdx].primitiveIDIn);
1474             output.EmitVertex(position1, 0.0f, &fragColor, packets[packetNdx].primitiveIDIn);
1475         }
1476 
1477         output.EndPrimitive();
1478     }
1479 }
1480 
getAttributeName(VaryingSource test)1481 const char *VaryingOutputCountShader::getAttributeName(VaryingSource test)
1482 {
1483     switch (test)
1484     {
1485     case READ_ATTRIBUTE:
1486         return "a_emitCount";
1487     case READ_UNIFORM:
1488         return "a_vertexNdx";
1489     case READ_TEXTURE:
1490         return "a_vertexNdx";
1491     default:
1492         DE_ASSERT(false);
1493         return "";
1494     }
1495 }
1496 
genGeometrySource(const glu::ContextType & contextType,VaryingSource test,int maxEmitCount,bool instanced)1497 std::string VaryingOutputCountShader::genGeometrySource(const glu::ContextType &contextType, VaryingSource test,
1498                                                         int maxEmitCount, bool instanced)
1499 {
1500     std::ostringstream buf;
1501 
1502     buf << "${GLSL_VERSION_DECL}\n"
1503            "${GLSL_EXT_GEOMETRY_SHADER}"
1504            "layout(points"
1505         << ((instanced) ? (",invocations=4") : (""))
1506         << ") in;\n"
1507            "layout(triangle_strip, max_vertices = "
1508         << maxEmitCount << ") out;\n";
1509 
1510     if (test == READ_ATTRIBUTE)
1511         buf << "in highp vec4 v_geom_emitCount[];\n";
1512     else if (test == READ_UNIFORM)
1513         buf << "in highp vec4 v_geom_vertexNdx[];\n"
1514                "uniform highp ivec4 u_emitCount;\n";
1515     else
1516         buf << "in highp vec4 v_geom_vertexNdx[];\n"
1517                "uniform highp sampler2D u_sampler;\n";
1518 
1519     buf << "out highp vec4 v_frag_FragColor;\n"
1520            "\n"
1521            "void main (void)\n"
1522            "{\n";
1523 
1524     // emit count
1525 
1526     if (test == READ_ATTRIBUTE)
1527     {
1528         buf << "    highp vec4 attrEmitCounts = v_geom_emitCount[0];\n"
1529                "    mediump int emitCount = int(attrEmitCounts["
1530             << ((instanced) ? ("gl_InvocationID") : ("0")) << "]);\n";
1531     }
1532     else if (test == READ_UNIFORM)
1533     {
1534         buf << "    mediump int primitiveNdx = " << ((instanced) ? ("gl_InvocationID") : ("int(v_geom_vertexNdx[0].x)"))
1535             << ";\n"
1536                "    mediump int emitCount = u_emitCount[primitiveNdx];\n";
1537     }
1538     else if (test == READ_TEXTURE)
1539     {
1540         buf << "    highp float primitiveNdx = "
1541             << ((instanced) ? ("float(gl_InvocationID)") : ("v_geom_vertexNdx[0].x"))
1542             << ";\n"
1543                "    highp vec2 texCoord = vec2(1.0 / 8.0 + primitiveNdx / 4.0, 0.5);\n"
1544                "    highp vec4 texColor = texture(u_sampler, texCoord);\n"
1545                "    mediump int emitCount = 0;\n"
1546                "    if (texColor.x > 0.0)\n"
1547                "        emitCount += "
1548             << ((EMIT_COUNT_VERTEX_0 == -1) ? (maxEmitCount) : (EMIT_COUNT_VERTEX_0))
1549             << ";\n"
1550                "    if (texColor.y > 0.0)\n"
1551                "        emitCount += "
1552             << ((EMIT_COUNT_VERTEX_1 == -1) ? (maxEmitCount) : (EMIT_COUNT_VERTEX_1))
1553             << ";\n"
1554                "    if (texColor.z > 0.0)\n"
1555                "        emitCount += "
1556             << ((EMIT_COUNT_VERTEX_2 == -1) ? (maxEmitCount) : (EMIT_COUNT_VERTEX_2))
1557             << ";\n"
1558                "    if (texColor.w > 0.0)\n"
1559                "        emitCount += "
1560             << ((EMIT_COUNT_VERTEX_3 == -1) ? (maxEmitCount) : (EMIT_COUNT_VERTEX_3)) << ";\n";
1561     }
1562     else
1563         DE_ASSERT(false);
1564 
1565     // color
1566 
1567     if (test == READ_ATTRIBUTE)
1568     {
1569         // We don't want color to be compile time constant
1570         buf << "    highp vec4 color = vec4((emitCount < 10) ? (0.0) : (1.0), (emitCount > 10) ? (0.0) : (1.0), 1.0, "
1571                "1.0);\n";
1572     }
1573     else if (test == READ_UNIFORM || test == READ_TEXTURE)
1574     {
1575         buf << "\n"
1576                "    const highp vec4 red = vec4(1.0, 0.0, 0.0, 1.0);\n"
1577                "    const highp vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
1578                "    const highp vec4 blue = vec4(0.0, 0.0, 1.0, 1.0);\n"
1579                "    const highp vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
1580                "    const highp vec4 colors[4] = vec4[4](red, green, blue, yellow);\n"
1581                "    highp vec4 color = colors[int(primitiveNdx)];\n";
1582     }
1583     else
1584         DE_ASSERT(false);
1585 
1586     buf << "\n"
1587            "    highp vec4 basePos = "
1588         << ((instanced) ? ("gl_in[0].gl_Position + 0.5 * vec4(cos(float(gl_InvocationID)), "
1589                            "sin(float(gl_InvocationID)), 0.0, 0.0)") :
1590                           ("gl_in[0].gl_Position"))
1591         << ";\n"
1592            "    for (mediump int i = 0; i < emitCount / 2; i++)\n"
1593            "    {\n"
1594            "        highp float angle = (float(i) + 0.5) / float(emitCount / 2) * 3.142;\n"
1595            "        gl_Position = basePos + vec4(cos(angle),  sin(angle), 0.0, 0.0) * 0.15;\n"
1596            "        v_frag_FragColor = color;\n"
1597            "        EmitVertex();\n"
1598            "        gl_Position = basePos + vec4(cos(angle), -sin(angle), 0.0, 0.0) * 0.15;\n"
1599            "        v_frag_FragColor = color;\n"
1600            "        EmitVertex();\n"
1601            "    }"
1602            "}\n";
1603 
1604     return specializeShader(buf.str(), contextType);
1605 }
1606 
genVertexSource(const glu::ContextType & contextType,VaryingSource test)1607 std::string VaryingOutputCountShader::genVertexSource(const glu::ContextType &contextType, VaryingSource test)
1608 {
1609     std::ostringstream buf;
1610 
1611     buf << "${GLSL_VERSION_DECL}\n"
1612            "in highp vec4 a_position;\n";
1613 
1614     if (test == READ_ATTRIBUTE)
1615     {
1616         buf << "in highp vec4 a_emitCount;\n";
1617         buf << "out highp vec4 v_geom_emitCount;\n";
1618     }
1619     else if (test == READ_UNIFORM || test == READ_TEXTURE)
1620     {
1621         buf << "in highp vec4 a_vertexNdx;\n";
1622         buf << "out highp vec4 v_geom_vertexNdx;\n";
1623     }
1624 
1625     buf << "void main (void)\n"
1626            "{\n"
1627            "    gl_Position = a_position;\n";
1628 
1629     if (test == READ_ATTRIBUTE)
1630         buf << "    v_geom_emitCount = a_emitCount;\n";
1631     else if (test == READ_UNIFORM || test == READ_TEXTURE)
1632         buf << "    v_geom_vertexNdx = a_vertexNdx;\n";
1633 
1634     buf << "}\n";
1635 
1636     return specializeShader(buf.str(), contextType);
1637 }
1638 
1639 class InvocationCountShader : public sglr::ShaderProgram
1640 {
1641 public:
1642     enum OutputCase
1643     {
1644         CASE_FIXED_OUTPUT_COUNTS = 0,
1645         CASE_DIFFERENT_OUTPUT_COUNTS,
1646 
1647         CASE_LAST
1648     };
1649 
1650     InvocationCountShader(const glu::ContextType &contextType, int numInvocations, OutputCase testCase);
1651 
1652 private:
1653     void shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets, const int numPackets) const;
1654     void shadeFragments(rr::FragmentPacket *packets, const int numPackets,
1655                         const rr::FragmentShadingContext &context) const;
1656     void shadePrimitives(rr::GeometryEmitter &output, int verticesIn, const rr::PrimitivePacket *packets,
1657                          const int numPackets, int invocationID) const;
1658 
1659     static std::string genGeometrySource(const glu::ContextType &contextType, int numInvocations, OutputCase testCase);
1660     static size_t getNumVertices(int numInvocations, OutputCase testCase);
1661 
1662     const int m_numInvocations;
1663     const OutputCase m_testCase;
1664 };
1665 
InvocationCountShader(const glu::ContextType & contextType,int numInvocations,OutputCase testCase)1666 InvocationCountShader::InvocationCountShader(const glu::ContextType &contextType, int numInvocations,
1667                                              OutputCase testCase)
1668     : sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
1669                           << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
1670                           << sglr::pdec::VertexAttribute("a_color", rr::GENERICVECTYPE_FLOAT)
1671                           << sglr::pdec::VertexToGeometryVarying(rr::GENERICVECTYPE_FLOAT)
1672                           << sglr::pdec::GeometryToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
1673                           << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
1674                           << sglr::pdec::VertexSource(specializeShader(s_commonShaderSourceVertex, contextType))
1675                           << sglr::pdec::FragmentSource(specializeShader(s_commonShaderSourceFragment, contextType))
1676                           << sglr::pdec::GeometryShaderDeclaration(
1677                                  rr::GEOMETRYSHADERINPUTTYPE_POINTS, rr::GEOMETRYSHADEROUTPUTTYPE_TRIANGLE_STRIP,
1678                                  getNumVertices(numInvocations, testCase), numInvocations)
1679                           << sglr::pdec::GeometrySource(genGeometrySource(contextType, numInvocations, testCase)))
1680     , m_numInvocations(numInvocations)
1681     , m_testCase(testCase)
1682 {
1683 }
1684 
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const1685 void InvocationCountShader::shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets,
1686                                           const int numPackets) const
1687 {
1688     for (int ndx = 0; ndx < numPackets; ++ndx)
1689     {
1690         packets[ndx]->position =
1691             rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
1692         packets[ndx]->outputs[0] =
1693             rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
1694     }
1695 }
1696 
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const1697 void InvocationCountShader::shadeFragments(rr::FragmentPacket *packets, const int numPackets,
1698                                            const rr::FragmentShadingContext &context) const
1699 {
1700     for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
1701         for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
1702             rr::writeFragmentOutput(context, packetNdx, fragNdx, 0,
1703                                     rr::readVarying<float>(packets[packetNdx], context, 0, fragNdx));
1704 }
1705 
shadePrimitives(rr::GeometryEmitter & output,int verticesIn,const rr::PrimitivePacket * packets,const int numPackets,int invocationID) const1706 void InvocationCountShader::shadePrimitives(rr::GeometryEmitter &output, int verticesIn,
1707                                             const rr::PrimitivePacket *packets, const int numPackets,
1708                                             int invocationID) const
1709 {
1710     DE_UNREF(verticesIn);
1711 
1712     for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
1713     {
1714         const float l_angle  = float(invocationID) / float(m_numInvocations) * 5.5f;
1715         const float l_radius = 0.6f;
1716 
1717         const rr::VertexPacket *vertex = packets[packetNdx].vertices[0];
1718 
1719         if (m_testCase == CASE_FIXED_OUTPUT_COUNTS)
1720         {
1721             const tcu::Vec4 position0 =
1722                 vertex->position +
1723                 tcu::Vec4(deFloatCos(l_angle) * (l_radius - 0.1f), deFloatSin(l_angle) * (l_radius - 0.1f), 0.0f, 0.0f);
1724             const tcu::Vec4 position1 = vertex->position + tcu::Vec4(deFloatCos(l_angle + 0.1f) * l_radius,
1725                                                                      deFloatSin(l_angle + 0.1f) * l_radius, 0.0f, 0.0f);
1726             const tcu::Vec4 position2 = vertex->position + tcu::Vec4(deFloatCos(l_angle - 0.1f) * l_radius,
1727                                                                      deFloatSin(l_angle - 0.1f) * l_radius, 0.0f, 0.0f);
1728 
1729             rr::GenericVec4 tipColor;
1730             rr::GenericVec4 baseColor;
1731 
1732             tipColor  = tcu::Vec4(1.0, 1.0, 0.0, 1.0) * packets[packetNdx].vertices[0]->outputs[0].get<float>();
1733             baseColor = tcu::Vec4(1.0, 0.0, 0.0, 1.0) * packets[packetNdx].vertices[0]->outputs[0].get<float>();
1734 
1735             output.EmitVertex(position0, 0.0f, &tipColor, packets[packetNdx].primitiveIDIn);
1736             output.EmitVertex(position1, 0.0f, &baseColor, packets[packetNdx].primitiveIDIn);
1737             output.EmitVertex(position2, 0.0f, &baseColor, packets[packetNdx].primitiveIDIn);
1738             output.EndPrimitive();
1739         }
1740         else if (m_testCase == CASE_DIFFERENT_OUTPUT_COUNTS)
1741         {
1742             const tcu::Vec4 color =
1743                 tcu::Vec4(float(invocationID % 2), (((invocationID / 2) % 2) == 0) ? (1.0f) : (0.0f), 1.0f, 1.0f);
1744             const tcu::Vec4 basePosition = vertex->position + tcu::Vec4(deFloatCos(l_angle) * l_radius,
1745                                                                         deFloatSin(l_angle) * l_radius, 0.0f, 0.0f);
1746             const int numNgonVtx         = invocationID + 3;
1747 
1748             rr::GenericVec4 outColor;
1749             outColor = color;
1750 
1751             for (int ndx = 0; ndx + 1 < numNgonVtx; ndx += 2)
1752             {
1753                 const float subAngle = (float(ndx) + 1.0f) / float(numNgonVtx) * 3.141f;
1754 
1755                 output.EmitVertex(basePosition +
1756                                       tcu::Vec4(deFloatCos(subAngle) * 0.1f, deFloatSin(subAngle) * 0.1f, 0.0f, 0.0f),
1757                                   0.0f, &outColor, packets[packetNdx].primitiveIDIn);
1758                 output.EmitVertex(basePosition +
1759                                       tcu::Vec4(deFloatCos(subAngle) * 0.1f, deFloatSin(subAngle) * -0.1f, 0.0f, 0.0f),
1760                                   0.0f, &outColor, packets[packetNdx].primitiveIDIn);
1761             }
1762 
1763             if ((numNgonVtx % 2) == 1)
1764                 output.EmitVertex(basePosition + tcu::Vec4(-0.1f, 0.0f, 0.0f, 0.0f), 0.0f, &outColor,
1765                                   packets[packetNdx].primitiveIDIn);
1766 
1767             output.EndPrimitive();
1768         }
1769     }
1770 }
1771 
genGeometrySource(const glu::ContextType & contextType,int numInvocations,OutputCase testCase)1772 std::string InvocationCountShader::genGeometrySource(const glu::ContextType &contextType, int numInvocations,
1773                                                      OutputCase testCase)
1774 {
1775     const int maxVertices = (int)getNumVertices(numInvocations, testCase);
1776     std::ostringstream buf;
1777 
1778     buf << "${GLSL_VERSION_DECL}\n"
1779            "${GLSL_EXT_GEOMETRY_SHADER}"
1780            "layout(points, invocations = "
1781         << numInvocations
1782         << ") in;\n"
1783            "layout(triangle_strip, max_vertices = "
1784         << maxVertices
1785         << ") out;\n"
1786            "\n"
1787            "in highp vec4 v_geom_FragColor[];\n"
1788            "out highp vec4 v_frag_FragColor;\n"
1789            "\n"
1790            "void main ()\n"
1791            "{\n"
1792            "    highp float l_angle = float(gl_InvocationID) / float("
1793         << numInvocations
1794         << ") * 5.5;\n"
1795            "    highp float l_radius = 0.6;\n"
1796            "\n";
1797 
1798     if (testCase == CASE_FIXED_OUTPUT_COUNTS)
1799     {
1800         buf << "    v_frag_FragColor = vec4(1.0, 1.0, 0.0, 1.0) * v_geom_FragColor[0];\n"
1801                "    gl_Position = gl_in[0].gl_Position + vec4(cos(l_angle) * (l_radius - 0.1), sin(l_angle) * "
1802                "(l_radius - 0.1), 0.0, 0.0);\n"
1803                "    EmitVertex();\n"
1804                "\n"
1805                "    v_frag_FragColor = vec4(1.0, 0.0, 0.0, 1.0) * v_geom_FragColor[0];\n"
1806                "    gl_Position = gl_in[0].gl_Position + vec4(cos(l_angle+0.1) * l_radius, sin(l_angle+0.1) * "
1807                "l_radius, 0.0, 0.0);\n"
1808                "    EmitVertex();\n"
1809                "\n"
1810                "    v_frag_FragColor = vec4(1.0, 0.0, 0.0, 1.0) * v_geom_FragColor[0];\n"
1811                "    gl_Position = gl_in[0].gl_Position + vec4(cos(l_angle-0.1) * l_radius, sin(l_angle-0.1) * "
1812                "l_radius, 0.0, 0.0);\n"
1813                "    EmitVertex();\n";
1814     }
1815     else if (testCase == CASE_DIFFERENT_OUTPUT_COUNTS)
1816     {
1817         buf << "    highp vec4 l_color = vec4(float(gl_InvocationID % 2), (((gl_InvocationID / 2) % 2) == 0) ? (1.0) : "
1818                "(0.0), 1.0, 1.0);\n"
1819                "    highp vec4 basePosition = gl_in[0].gl_Position + vec4(cos(l_angle) * l_radius, sin(l_angle) * "
1820                "l_radius, 0.0, 0.0);\n"
1821                "    mediump int numNgonVtx = gl_InvocationID + 3;\n"
1822                "\n"
1823                "    for (int ndx = 0; ndx + 1 < numNgonVtx; ndx += 2)\n"
1824                "    {\n"
1825                "        highp float sub_angle = (float(ndx) + 1.0) / float(numNgonVtx) * 3.141;\n"
1826                "\n"
1827                "        v_frag_FragColor = l_color;\n"
1828                "        gl_Position = basePosition + vec4(cos(sub_angle) * 0.1, sin(sub_angle) * 0.1, 0.0, 0.0);\n"
1829                "        EmitVertex();\n"
1830                "\n"
1831                "        v_frag_FragColor = l_color;\n"
1832                "        gl_Position = basePosition + vec4(cos(sub_angle) * 0.1, sin(sub_angle) * -0.1, 0.0, 0.0);\n"
1833                "        EmitVertex();\n"
1834                "    }\n"
1835                "    if ((numNgonVtx % 2) == 1)\n"
1836                "    {\n"
1837                "        v_frag_FragColor = l_color;\n"
1838                "        gl_Position = basePosition + vec4(-0.1, 0.0, 0.0, 0.0);\n"
1839                "        EmitVertex();\n"
1840                "    }\n";
1841     }
1842     else
1843         DE_ASSERT(false);
1844 
1845     buf << "}\n";
1846 
1847     return specializeShader(buf.str(), contextType);
1848 }
1849 
getNumVertices(int numInvocations,OutputCase testCase)1850 size_t InvocationCountShader::getNumVertices(int numInvocations, OutputCase testCase)
1851 {
1852     switch (testCase)
1853     {
1854     case CASE_FIXED_OUTPUT_COUNTS:
1855         return 3;
1856     case CASE_DIFFERENT_OUTPUT_COUNTS:
1857         return (size_t)(2 + numInvocations);
1858     default:
1859         DE_ASSERT(false);
1860         return 0;
1861     }
1862 }
1863 
1864 class InstancedExpansionShader : public sglr::ShaderProgram
1865 {
1866 public:
1867     InstancedExpansionShader(const glu::ContextType &contextType, int numInvocations);
1868 
1869 private:
1870     void shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets, const int numPackets) const;
1871     void shadeFragments(rr::FragmentPacket *packets, const int numPackets,
1872                         const rr::FragmentShadingContext &context) const;
1873     void shadePrimitives(rr::GeometryEmitter &output, int verticesIn, const rr::PrimitivePacket *packets,
1874                          const int numPackets, int invocationID) const;
1875 
1876     static std::string genVertexSource(const glu::ContextType &contextType);
1877     static std::string genFragmentSource(const glu::ContextType &contextType);
1878     static std::string genGeometrySource(const glu::ContextType &contextType, int numInvocations);
1879 
1880     const int m_numInvocations;
1881 };
1882 
InstancedExpansionShader(const glu::ContextType & contextType,int numInvocations)1883 InstancedExpansionShader::InstancedExpansionShader(const glu::ContextType &contextType, int numInvocations)
1884     : sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
1885                           << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
1886                           << sglr::pdec::VertexAttribute("a_offset", rr::GENERICVECTYPE_FLOAT)
1887                           << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
1888                           << sglr::pdec::VertexSource(genVertexSource(contextType))
1889                           << sglr::pdec::FragmentSource(genFragmentSource(contextType))
1890                           << sglr::pdec::GeometryShaderDeclaration(rr::GEOMETRYSHADERINPUTTYPE_POINTS,
1891                                                                    rr::GEOMETRYSHADEROUTPUTTYPE_TRIANGLE_STRIP, 4,
1892                                                                    numInvocations)
1893                           << sglr::pdec::GeometrySource(genGeometrySource(contextType, numInvocations)))
1894     , m_numInvocations(numInvocations)
1895 {
1896 }
1897 
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const1898 void InstancedExpansionShader::shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets,
1899                                              const int numPackets) const
1900 {
1901     for (int ndx = 0; ndx < numPackets; ++ndx)
1902     {
1903         packets[ndx]->position =
1904             rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx) +
1905             rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
1906     }
1907 }
1908 
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const1909 void InstancedExpansionShader::shadeFragments(rr::FragmentPacket *packets, const int numPackets,
1910                                               const rr::FragmentShadingContext &context) const
1911 {
1912     DE_UNREF(packets);
1913 
1914     for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
1915         for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
1916             rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
1917 }
1918 
shadePrimitives(rr::GeometryEmitter & output,int verticesIn,const rr::PrimitivePacket * packets,const int numPackets,int invocationID) const1919 void InstancedExpansionShader::shadePrimitives(rr::GeometryEmitter &output, int verticesIn,
1920                                                const rr::PrimitivePacket *packets, const int numPackets,
1921                                                int invocationID) const
1922 {
1923     DE_UNREF(verticesIn);
1924 
1925     for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
1926     {
1927         const rr::VertexPacket *vertex = packets[packetNdx].vertices[0];
1928         const tcu::Vec4 basePosition   = vertex->position;
1929         const float phase              = float(invocationID) / float(m_numInvocations) * 6.3f;
1930         const tcu::Vec4 centerPosition =
1931             basePosition + tcu::Vec4(deFloatCos(phase), deFloatSin(phase), 0.0f, 0.0f) * 0.1f;
1932 
1933         output.EmitVertex(centerPosition + tcu::Vec4(0.0f, -0.1f, 0.0f, 0.0f), 0.0f, DE_NULL,
1934                           packets[packetNdx].primitiveIDIn);
1935         output.EmitVertex(centerPosition + tcu::Vec4(-0.05f, 0.0f, 0.0f, 0.0f), 0.0f, DE_NULL,
1936                           packets[packetNdx].primitiveIDIn);
1937         output.EmitVertex(centerPosition + tcu::Vec4(0.05f, 0.0f, 0.0f, 0.0f), 0.0f, DE_NULL,
1938                           packets[packetNdx].primitiveIDIn);
1939         output.EndPrimitive();
1940     }
1941 }
1942 
genVertexSource(const glu::ContextType & contextType)1943 std::string InstancedExpansionShader::genVertexSource(const glu::ContextType &contextType)
1944 {
1945     std::ostringstream buf;
1946 
1947     buf << "${GLSL_VERSION_DECL}\n"
1948            "in highp vec4 a_position;\n"
1949            "in highp vec4 a_offset;\n"
1950            "void main (void)\n"
1951            "{\n"
1952            "    gl_Position = a_position + a_offset;\n"
1953            "}\n";
1954 
1955     return specializeShader(buf.str(), contextType);
1956 }
1957 
genFragmentSource(const glu::ContextType & contextType)1958 std::string InstancedExpansionShader::genFragmentSource(const glu::ContextType &contextType)
1959 {
1960     std::ostringstream buf;
1961 
1962     buf << "${GLSL_VERSION_DECL}\n"
1963            "layout(location = 0) out mediump vec4 fragColor;\n"
1964            "void main (void)\n"
1965            "{\n"
1966            "    fragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
1967            "}\n";
1968 
1969     return specializeShader(buf.str(), contextType);
1970 }
1971 
genGeometrySource(const glu::ContextType & contextType,int numInvocations)1972 std::string InstancedExpansionShader::genGeometrySource(const glu::ContextType &contextType, int numInvocations)
1973 {
1974     std::ostringstream buf;
1975 
1976     buf << "${GLSL_VERSION_DECL}\n"
1977            "${GLSL_EXT_GEOMETRY_SHADER}"
1978            "layout(points,invocations="
1979         << numInvocations
1980         << ") in;\n"
1981            "layout(triangle_strip, max_vertices = 3) out;\n"
1982            "\n"
1983            "void main (void)\n"
1984            "{\n"
1985            "    highp vec4 basePosition = gl_in[0].gl_Position;\n"
1986            "    highp float phase = float(gl_InvocationID) / float("
1987         << numInvocations
1988         << ") * 6.3;\n"
1989            "    highp vec4 centerPosition = basePosition + 0.1 * vec4(cos(phase), sin(phase), 0.0, 0.0);\n"
1990            "\n"
1991            "    gl_Position = centerPosition + vec4( 0.00, -0.1, 0.0, 0.0);\n"
1992            "    EmitVertex();\n"
1993            "    gl_Position = centerPosition + vec4(-0.05,  0.0, 0.0, 0.0);\n"
1994            "    EmitVertex();\n"
1995            "    gl_Position = centerPosition + vec4( 0.05,  0.0, 0.0, 0.0);\n"
1996            "    EmitVertex();\n"
1997            "}\n";
1998 
1999     return specializeShader(buf.str(), contextType);
2000 }
2001 
2002 class GeometryShaderRenderTest : public TestCase
2003 {
2004 public:
2005     enum Flag
2006     {
2007         FLAG_DRAW_INSTANCED    = 1,
2008         FLAG_USE_INDICES       = 2,
2009         FLAG_USE_RESTART_INDEX = 4,
2010     };
2011 
2012     GeometryShaderRenderTest(Context &context, const char *name, const char *desc, GLenum inputPrimitives,
2013                              GLenum outputPrimitives, const char *dataAttributeName, int flags = 0);
2014     virtual ~GeometryShaderRenderTest(void);
2015 
2016     void init(void);
2017     void deinit(void);
2018 
2019     IterateResult iterate(void);
2020     bool compare(void);
2021 
2022     virtual sglr::ShaderProgram &getProgram(void) = 0;
2023 
2024 protected:
2025     virtual void genVertexAttribData(void);
2026     void renderWithContext(sglr::Context &ctx, sglr::ShaderProgram &program, tcu::Surface &dstSurface);
2027     virtual void preRender(sglr::Context &ctx, GLuint programID);
2028     virtual void postRender(sglr::Context &ctx, GLuint programID);
2029 
2030     int m_numDrawVertices;
2031     int m_numDrawInstances;
2032     int m_vertexAttrDivisor;
2033 
2034     const GLenum m_inputPrimitives;
2035     const GLenum m_outputPrimitives;
2036     const char *const m_dataAttributeName;
2037     const int m_flags;
2038 
2039     tcu::IVec2 m_viewportSize;
2040     int m_interationCount;
2041 
2042     tcu::Surface *m_glResult;
2043     tcu::Surface *m_refResult;
2044 
2045     sglr::ReferenceContextBuffers *m_refBuffers;
2046     sglr::ReferenceContext *m_refContext;
2047     sglr::Context *m_glContext;
2048 
2049     std::vector<tcu::Vec4> m_vertexPosData;
2050     std::vector<tcu::Vec4> m_vertexAttrData;
2051     std::vector<uint16_t> m_indices;
2052 };
2053 
GeometryShaderRenderTest(Context & context,const char * name,const char * desc,GLenum inputPrimitives,GLenum outputPrimitives,const char * dataAttributeName,int flags)2054 GeometryShaderRenderTest::GeometryShaderRenderTest(Context &context, const char *name, const char *desc,
2055                                                    GLenum inputPrimitives, GLenum outputPrimitives,
2056                                                    const char *dataAttributeName, int flags)
2057     : TestCase(context, name, desc)
2058     , m_numDrawVertices(0)
2059     , m_numDrawInstances(0)
2060     , m_vertexAttrDivisor(0)
2061     , m_inputPrimitives(inputPrimitives)
2062     , m_outputPrimitives(outputPrimitives)
2063     , m_dataAttributeName(dataAttributeName)
2064     , m_flags(flags)
2065     , m_viewportSize(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE)
2066     , m_interationCount(0)
2067     , m_glResult(DE_NULL)
2068     , m_refResult(DE_NULL)
2069     , m_refBuffers(DE_NULL)
2070     , m_refContext(DE_NULL)
2071     , m_glContext(DE_NULL)
2072 {
2073     // Disallow instanced drawElements
2074     DE_ASSERT(((m_flags & FLAG_DRAW_INSTANCED) == 0) || ((m_flags & FLAG_USE_INDICES) == 0));
2075     // Disallow restart without indices
2076     DE_ASSERT(!(((m_flags & FLAG_USE_RESTART_INDEX) != 0) && ((m_flags & FLAG_USE_INDICES) == 0)));
2077 }
2078 
~GeometryShaderRenderTest(void)2079 GeometryShaderRenderTest::~GeometryShaderRenderTest(void)
2080 {
2081     deinit();
2082 }
2083 
init(void)2084 void GeometryShaderRenderTest::init(void)
2085 {
2086     // requirements
2087     if (!checkSupport(m_context))
2088         TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
2089 
2090     // gen resources
2091     {
2092         sglr::ReferenceContextLimits limits;
2093 
2094         m_glResult  = new tcu::Surface(m_viewportSize.x(), m_viewportSize.y());
2095         m_refResult = new tcu::Surface(m_viewportSize.x(), m_viewportSize.y());
2096 
2097         m_refBuffers = new sglr::ReferenceContextBuffers(m_context.getRenderTarget().getPixelFormat(),
2098                                                          m_context.getRenderTarget().getDepthBits(), 0,
2099                                                          m_viewportSize.x(), m_viewportSize.y());
2100         m_refContext = new sglr::ReferenceContext(limits, m_refBuffers->getColorbuffer(),
2101                                                   m_refBuffers->getDepthbuffer(), m_refBuffers->getStencilbuffer());
2102         m_glContext  = new sglr::GLContext(m_context.getRenderContext(), m_testCtx.getLog(),
2103                                            sglr::GLCONTEXT_LOG_CALLS | sglr::GLCONTEXT_LOG_PROGRAMS,
2104                                            tcu::IVec4(0, 0, m_viewportSize.x(), m_viewportSize.y()));
2105     }
2106 }
2107 
deinit(void)2108 void GeometryShaderRenderTest::deinit(void)
2109 {
2110     delete m_glResult;
2111     delete m_refResult;
2112 
2113     m_glResult  = DE_NULL;
2114     m_refResult = DE_NULL;
2115 
2116     delete m_refContext;
2117     delete m_glContext;
2118     delete m_refBuffers;
2119 
2120     m_refBuffers = DE_NULL;
2121     m_refContext = DE_NULL;
2122     m_glContext  = DE_NULL;
2123 }
2124 
iterate(void)2125 tcu::TestCase::IterateResult GeometryShaderRenderTest::iterate(void)
2126 {
2127     // init() must be called
2128     DE_ASSERT(m_glContext);
2129     DE_ASSERT(m_refContext);
2130 
2131     const int iteration = m_interationCount++;
2132 
2133     if (iteration == 0)
2134     {
2135         // Check requirements
2136         const int width  = m_context.getRenderTarget().getWidth();
2137         const int height = m_context.getRenderTarget().getHeight();
2138 
2139         if (width < m_viewportSize.x() || height < m_viewportSize.y())
2140             throw tcu::NotSupportedError(std::string("Render target size must be at least ") +
2141                                          de::toString(m_viewportSize.x()) + "x" + de::toString(m_viewportSize.y()));
2142 
2143         // Gen data
2144         genVertexAttribData();
2145 
2146         return CONTINUE;
2147     }
2148     else if (iteration == 1)
2149     {
2150         // Render
2151         sglr::ShaderProgram &program = getProgram();
2152 
2153         renderWithContext(*m_glContext, program, *m_glResult);
2154         renderWithContext(*m_refContext, program, *m_refResult);
2155 
2156         return CONTINUE;
2157     }
2158     else
2159     {
2160         if (compare())
2161             m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2162         else
2163             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
2164 
2165         return STOP;
2166     }
2167 }
2168 
compare(void)2169 bool GeometryShaderRenderTest::compare(void)
2170 {
2171     using tcu::TestLog;
2172 
2173     if (m_context.getRenderTarget().getNumSamples() > 1)
2174     {
2175         return tcu::fuzzyCompare(m_testCtx.getLog(), "Compare Results", "Compare Results", m_refResult->getAccess(),
2176                                  m_glResult->getAccess(), 0.02f, tcu::COMPARE_LOG_RESULT);
2177     }
2178     else
2179     {
2180         tcu::Surface errorMask(m_viewportSize.x(), m_viewportSize.y());
2181         const tcu::RGBA green(0, 255, 0, 255);
2182         const tcu::RGBA red(255, 0, 0, 255);
2183         const int colorComponentThreshold = 20;
2184         bool testResult                   = true;
2185 
2186         for (int x = 0; x < m_viewportSize.x(); ++x)
2187             for (int y = 0; y < m_viewportSize.y(); ++y)
2188             {
2189                 if (x == 0 || y == 0 || x + 1 == m_viewportSize.x() || y + 1 == m_viewportSize.y())
2190                 {
2191                     // Mark edge pixels as correct since their neighbourhood is undefined
2192                     errorMask.setPixel(x, y, green);
2193                 }
2194                 else
2195                 {
2196                     const tcu::RGBA refcolor = m_refResult->getPixel(x, y);
2197                     bool found               = false;
2198 
2199                     // Got to find similar pixel near this pixel (3x3 kernel)
2200                     for (int dx = -1; dx <= 1; ++dx)
2201                         for (int dy = -1; dy <= 1; ++dy)
2202                         {
2203                             const tcu::RGBA testColor = m_glResult->getPixel(x + dx, y + dy);
2204                             const tcu::IVec4 colDiff  = tcu::abs(testColor.toIVec() - refcolor.toIVec());
2205 
2206                             const int maxColDiff =
2207                                 de::max(de::max(colDiff.x(), colDiff.y()), colDiff.z()); // check RGB channels
2208 
2209                             if (maxColDiff <= colorComponentThreshold)
2210                                 found = true;
2211                         }
2212 
2213                     if (!found)
2214                         testResult = false;
2215 
2216                     errorMask.setPixel(x, y, (found) ? (green) : (red));
2217                 }
2218             }
2219 
2220         if (testResult)
2221         {
2222             m_testCtx.getLog() << TestLog::ImageSet("Compare result", "Result of rendering")
2223                                << TestLog::Image("Result", "Result", *m_glResult) << TestLog::EndImageSet;
2224             m_testCtx.getLog() << TestLog::Message << "Image compare ok." << TestLog::EndMessage;
2225         }
2226         else
2227         {
2228             m_testCtx.getLog() << TestLog::ImageSet("Compare result", "Result of rendering")
2229                                << TestLog::Image("Result", "Result", *m_glResult)
2230                                << TestLog::Image("Reference", "Reference", *m_refResult)
2231                                << TestLog::Image("ErrorMask", "Error mask", errorMask) << TestLog::EndImageSet;
2232             m_testCtx.getLog() << TestLog::Message << "Image compare failed." << TestLog::EndMessage;
2233         }
2234 
2235         return testResult;
2236     }
2237 }
2238 
genVertexAttribData(void)2239 void GeometryShaderRenderTest::genVertexAttribData(void)
2240 {
2241     // Create 1 X 2 grid in triangle strip adjacent - order
2242     const float scale = 0.3f;
2243     const tcu::Vec4 offset(-0.5f, -0.2f, 0.0f, 1.0f);
2244 
2245     m_vertexPosData.resize(12);
2246     m_vertexPosData[0]  = tcu::Vec4(0, 0, 0.0f, 0.0f) * scale + offset;
2247     m_vertexPosData[1]  = tcu::Vec4(-1, -1, 0.0f, 0.0f) * scale + offset;
2248     m_vertexPosData[2]  = tcu::Vec4(0, -1, 0.0f, 0.0f) * scale + offset;
2249     m_vertexPosData[3]  = tcu::Vec4(1, 1, 0.0f, 0.0f) * scale + offset;
2250     m_vertexPosData[4]  = tcu::Vec4(1, 0, 0.0f, 0.0f) * scale + offset;
2251     m_vertexPosData[5]  = tcu::Vec4(0, -2, 0.0f, 0.0f) * scale + offset;
2252     m_vertexPosData[6]  = tcu::Vec4(1, -1, 0.0f, 0.0f) * scale + offset;
2253     m_vertexPosData[7]  = tcu::Vec4(2, 1, 0.0f, 0.0f) * scale + offset;
2254     m_vertexPosData[8]  = tcu::Vec4(2, 0, 0.0f, 0.0f) * scale + offset;
2255     m_vertexPosData[9]  = tcu::Vec4(1, -2, 0.0f, 0.0f) * scale + offset;
2256     m_vertexPosData[10] = tcu::Vec4(2, -1, 0.0f, 0.0f) * scale + offset;
2257     m_vertexPosData[11] = tcu::Vec4(3, 0, 0.0f, 0.0f) * scale + offset;
2258 
2259     // Red and white
2260     m_vertexAttrData.resize(12);
2261     for (int i = 0; i < 12; ++i)
2262         m_vertexAttrData[i] = (i % 2 == 0) ? tcu::Vec4(1, 1, 1, 1) : tcu::Vec4(1, 0, 0, 1);
2263 
2264     m_numDrawVertices = 12;
2265 }
2266 
renderWithContext(sglr::Context & ctx,sglr::ShaderProgram & program,tcu::Surface & dstSurface)2267 void GeometryShaderRenderTest::renderWithContext(sglr::Context &ctx, sglr::ShaderProgram &program,
2268                                                  tcu::Surface &dstSurface)
2269 {
2270 #define CHECK_GL_CTX_ERRORS() glu::checkError(ctx.getError(), DE_NULL, __FILE__, __LINE__)
2271 
2272     const GLuint programId = ctx.createProgram(&program);
2273     const GLint attrPosLoc = ctx.getAttribLocation(programId, "a_position");
2274     const GLint attrColLoc = ctx.getAttribLocation(programId, m_dataAttributeName);
2275     GLuint vaoId           = 0;
2276     GLuint vertexPosBuf    = 0;
2277     GLuint vertexAttrBuf   = 0;
2278     GLuint elementArrayBuf = 0;
2279 
2280     ctx.genVertexArrays(1, &vaoId);
2281     ctx.bindVertexArray(vaoId);
2282 
2283     if (attrPosLoc != -1)
2284     {
2285         ctx.genBuffers(1, &vertexPosBuf);
2286         ctx.bindBuffer(GL_ARRAY_BUFFER, vertexPosBuf);
2287         ctx.bufferData(GL_ARRAY_BUFFER, m_vertexPosData.size() * sizeof(tcu::Vec4), &m_vertexPosData[0],
2288                        GL_STATIC_DRAW);
2289         ctx.vertexAttribPointer(attrPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
2290         ctx.enableVertexAttribArray(attrPosLoc);
2291     }
2292 
2293     if (attrColLoc != -1)
2294     {
2295         ctx.genBuffers(1, &vertexAttrBuf);
2296         ctx.bindBuffer(GL_ARRAY_BUFFER, vertexAttrBuf);
2297         ctx.bufferData(GL_ARRAY_BUFFER, m_vertexAttrData.size() * sizeof(tcu::Vec4), &m_vertexAttrData[0],
2298                        GL_STATIC_DRAW);
2299         ctx.vertexAttribPointer(attrColLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
2300         ctx.enableVertexAttribArray(attrColLoc);
2301 
2302         if (m_vertexAttrDivisor)
2303             ctx.vertexAttribDivisor(attrColLoc, m_vertexAttrDivisor);
2304     }
2305 
2306     if (m_flags & FLAG_USE_INDICES)
2307     {
2308         ctx.genBuffers(1, &elementArrayBuf);
2309         ctx.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementArrayBuf);
2310         ctx.bufferData(GL_ELEMENT_ARRAY_BUFFER, m_indices.size() * sizeof(uint16_t), &m_indices[0], GL_STATIC_DRAW);
2311     }
2312 
2313     ctx.clearColor(0, 0, 0, 1);
2314     ctx.clear(GL_COLOR_BUFFER_BIT);
2315 
2316     ctx.viewport(0, 0, m_viewportSize.x(), m_viewportSize.y());
2317     CHECK_GL_CTX_ERRORS();
2318 
2319     ctx.useProgram(programId);
2320     CHECK_GL_CTX_ERRORS();
2321 
2322     preRender(ctx, programId);
2323     CHECK_GL_CTX_ERRORS();
2324 
2325     if (m_flags & FLAG_USE_RESTART_INDEX)
2326     {
2327         ctx.enable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
2328         CHECK_GL_CTX_ERRORS();
2329     }
2330 
2331     if (m_flags & FLAG_USE_INDICES)
2332         ctx.drawElements(m_inputPrimitives, m_numDrawVertices, GL_UNSIGNED_SHORT, DE_NULL);
2333     else if (m_flags & FLAG_DRAW_INSTANCED)
2334         ctx.drawArraysInstanced(m_inputPrimitives, 0, m_numDrawVertices, m_numDrawInstances);
2335     else
2336         ctx.drawArrays(m_inputPrimitives, 0, m_numDrawVertices);
2337 
2338     CHECK_GL_CTX_ERRORS();
2339 
2340     if (m_flags & FLAG_USE_RESTART_INDEX)
2341     {
2342         ctx.disable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
2343         CHECK_GL_CTX_ERRORS();
2344     }
2345 
2346     postRender(ctx, programId);
2347     CHECK_GL_CTX_ERRORS();
2348 
2349     ctx.useProgram(0);
2350 
2351     if (attrPosLoc != -1)
2352         ctx.disableVertexAttribArray(attrPosLoc);
2353     if (attrColLoc != -1)
2354         ctx.disableVertexAttribArray(attrColLoc);
2355 
2356     if (vertexPosBuf)
2357         ctx.deleteBuffers(1, &vertexPosBuf);
2358     if (vertexAttrBuf)
2359         ctx.deleteBuffers(1, &vertexAttrBuf);
2360     if (elementArrayBuf)
2361         ctx.deleteBuffers(1, &elementArrayBuf);
2362 
2363     ctx.deleteVertexArrays(1, &vaoId);
2364 
2365     CHECK_GL_CTX_ERRORS();
2366 
2367     ctx.finish();
2368     ctx.readPixels(dstSurface, 0, 0, m_viewportSize.x(), m_viewportSize.y());
2369 
2370 #undef CHECK_GL_CTX_ERRORS
2371 }
2372 
preRender(sglr::Context & ctx,GLuint programID)2373 void GeometryShaderRenderTest::preRender(sglr::Context &ctx, GLuint programID)
2374 {
2375     DE_UNREF(ctx);
2376     DE_UNREF(programID);
2377 }
2378 
postRender(sglr::Context & ctx,GLuint programID)2379 void GeometryShaderRenderTest::postRender(sglr::Context &ctx, GLuint programID)
2380 {
2381     DE_UNREF(ctx);
2382     DE_UNREF(programID);
2383 }
2384 
2385 class GeometryExpanderRenderTest : public GeometryShaderRenderTest
2386 {
2387 public:
2388     GeometryExpanderRenderTest(Context &context, const char *name, const char *desc, GLenum inputPrimitives,
2389                                GLenum outputPrimitives);
2390     virtual ~GeometryExpanderRenderTest(void);
2391 
2392     sglr::ShaderProgram &getProgram(void);
2393 
2394 private:
2395     void init(void);
2396     void deinit(void);
2397     VertexExpanderShader *m_program;
2398 };
2399 
GeometryExpanderRenderTest(Context & context,const char * name,const char * desc,GLenum inputPrimitives,GLenum outputPrimitives)2400 GeometryExpanderRenderTest::GeometryExpanderRenderTest(Context &context, const char *name, const char *desc,
2401                                                        GLenum inputPrimitives, GLenum outputPrimitives)
2402     : GeometryShaderRenderTest(context, name, desc, inputPrimitives, outputPrimitives, "a_color")
2403     , m_program(DE_NULL)
2404 {
2405 }
2406 
~GeometryExpanderRenderTest(void)2407 GeometryExpanderRenderTest::~GeometryExpanderRenderTest(void)
2408 {
2409 }
2410 
init(void)2411 void GeometryExpanderRenderTest::init(void)
2412 {
2413     m_program = new VertexExpanderShader(m_context.getRenderContext().getType(),
2414                                          sglr::rr_util::mapGLGeometryShaderInputType(m_inputPrimitives),
2415                                          sglr::rr_util::mapGLGeometryShaderOutputType(m_outputPrimitives));
2416 
2417     GeometryShaderRenderTest::init();
2418 }
2419 
deinit(void)2420 void GeometryExpanderRenderTest::deinit(void)
2421 {
2422     if (m_program)
2423     {
2424         delete m_program;
2425         m_program = DE_NULL;
2426     }
2427 
2428     GeometryShaderRenderTest::deinit();
2429 }
2430 
getProgram(void)2431 sglr::ShaderProgram &GeometryExpanderRenderTest::getProgram(void)
2432 {
2433     return *m_program;
2434 }
2435 
2436 class EmitTest : public GeometryShaderRenderTest
2437 {
2438 public:
2439     EmitTest(Context &context, const char *name, const char *desc, int emitCountA, int endCountA, int emitCountB,
2440              int endCountB, GLenum outputType);
2441 
2442     sglr::ShaderProgram &getProgram(void);
2443 
2444 private:
2445     void init(void);
2446     void deinit(void);
2447     void genVertexAttribData(void);
2448 
2449     VertexEmitterShader *m_program;
2450     int m_emitCountA;
2451     int m_endCountA;
2452     int m_emitCountB;
2453     int m_endCountB;
2454     GLenum m_outputType;
2455 };
2456 
EmitTest(Context & context,const char * name,const char * desc,int emitCountA,int endCountA,int emitCountB,int endCountB,GLenum outputType)2457 EmitTest::EmitTest(Context &context, const char *name, const char *desc, int emitCountA, int endCountA, int emitCountB,
2458                    int endCountB, GLenum outputType)
2459     : GeometryShaderRenderTest(context, name, desc, GL_POINTS, outputType, "a_color")
2460     , m_program(DE_NULL)
2461     , m_emitCountA(emitCountA)
2462     , m_endCountA(endCountA)
2463     , m_emitCountB(emitCountB)
2464     , m_endCountB(endCountB)
2465     , m_outputType(outputType)
2466 {
2467 }
2468 
init(void)2469 void EmitTest::init(void)
2470 {
2471     m_program = new VertexEmitterShader(m_context.getRenderContext().getType(), m_emitCountA, m_endCountA, m_emitCountB,
2472                                         m_endCountB, sglr::rr_util::mapGLGeometryShaderOutputType(m_outputType));
2473 
2474     GeometryShaderRenderTest::init();
2475 }
2476 
deinit(void)2477 void EmitTest::deinit(void)
2478 {
2479     if (m_program)
2480     {
2481         delete m_program;
2482         m_program = DE_NULL;
2483     }
2484 
2485     GeometryShaderRenderTest::deinit();
2486 }
2487 
getProgram(void)2488 sglr::ShaderProgram &EmitTest::getProgram(void)
2489 {
2490     return *m_program;
2491 }
2492 
genVertexAttribData(void)2493 void EmitTest::genVertexAttribData(void)
2494 {
2495     m_vertexPosData.resize(1);
2496     m_vertexPosData[0] = tcu::Vec4(0, 0, 0, 1);
2497 
2498     m_vertexAttrData.resize(1);
2499     m_vertexAttrData[0] = tcu::Vec4(1, 1, 1, 1);
2500 
2501     m_numDrawVertices = 1;
2502 }
2503 
2504 class VaryingTest : public GeometryShaderRenderTest
2505 {
2506 public:
2507     VaryingTest(Context &context, const char *name, const char *desc, int vertexOut, int geometryOut);
2508 
2509     sglr::ShaderProgram &getProgram(void);
2510 
2511 private:
2512     void init(void);
2513     void deinit(void);
2514     void genVertexAttribData(void);
2515 
2516     VertexVaryingShader *m_program;
2517     int m_vertexOut;
2518     int m_geometryOut;
2519 };
2520 
VaryingTest(Context & context,const char * name,const char * desc,int vertexOut,int geometryOut)2521 VaryingTest::VaryingTest(Context &context, const char *name, const char *desc, int vertexOut, int geometryOut)
2522     : GeometryShaderRenderTest(context, name, desc, GL_TRIANGLES, GL_TRIANGLE_STRIP, "a_color")
2523     , m_program(DE_NULL)
2524     , m_vertexOut(vertexOut)
2525     , m_geometryOut(geometryOut)
2526 {
2527 }
2528 
init(void)2529 void VaryingTest::init(void)
2530 {
2531     m_program = new VertexVaryingShader(m_context.getRenderContext().getType(), m_vertexOut, m_geometryOut);
2532 
2533     GeometryShaderRenderTest::init();
2534 }
2535 
deinit(void)2536 void VaryingTest::deinit(void)
2537 {
2538     if (m_program)
2539     {
2540         delete m_program;
2541         m_program = DE_NULL;
2542     }
2543 
2544     GeometryShaderRenderTest::deinit();
2545 }
2546 
getProgram(void)2547 sglr::ShaderProgram &VaryingTest::getProgram(void)
2548 {
2549     return *m_program;
2550 }
2551 
genVertexAttribData(void)2552 void VaryingTest::genVertexAttribData(void)
2553 {
2554     m_vertexPosData.resize(3);
2555     m_vertexPosData[0] = tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f);
2556     m_vertexPosData[1] = tcu::Vec4(0.0f, 0.5f, 0.0f, 1.0f);
2557     m_vertexPosData[2] = tcu::Vec4(0.1f, 0.0f, 0.0f, 1.0f);
2558 
2559     m_vertexAttrData.resize(3);
2560     m_vertexAttrData[0] = tcu::Vec4(0.7f, 0.4f, 0.6f, 1.0f);
2561     m_vertexAttrData[1] = tcu::Vec4(0.9f, 0.2f, 0.5f, 1.0f);
2562     m_vertexAttrData[2] = tcu::Vec4(0.1f, 0.8f, 0.3f, 1.0f);
2563 
2564     m_numDrawVertices = 3;
2565 }
2566 
2567 class TriangleStripAdjacencyVertexCountTest : public GeometryExpanderRenderTest
2568 {
2569 public:
2570     TriangleStripAdjacencyVertexCountTest(Context &context, const char *name, const char *desc, int numInputVertices);
2571 
2572 private:
2573     void genVertexAttribData(void);
2574 
2575     int m_numInputVertices;
2576 };
2577 
TriangleStripAdjacencyVertexCountTest(Context & context,const char * name,const char * desc,int numInputVertices)2578 TriangleStripAdjacencyVertexCountTest::TriangleStripAdjacencyVertexCountTest(Context &context, const char *name,
2579                                                                              const char *desc, int numInputVertices)
2580     : GeometryExpanderRenderTest(context, name, desc, GL_TRIANGLE_STRIP_ADJACENCY, GL_TRIANGLE_STRIP)
2581     , m_numInputVertices(numInputVertices)
2582 {
2583 }
2584 
genVertexAttribData(void)2585 void TriangleStripAdjacencyVertexCountTest::genVertexAttribData(void)
2586 {
2587     this->GeometryShaderRenderTest::genVertexAttribData();
2588     m_numDrawVertices = m_numInputVertices;
2589 }
2590 
2591 class NegativeDrawCase : public TestCase
2592 {
2593 public:
2594     NegativeDrawCase(Context &context, const char *name, const char *desc, GLenum inputType, GLenum inputPrimitives);
2595     ~NegativeDrawCase(void);
2596 
2597     void init(void);
2598     void deinit(void);
2599 
2600     IterateResult iterate(void);
2601 
2602 private:
2603     sglr::Context *m_ctx;
2604     VertexExpanderShader *m_program;
2605     GLenum m_inputType;
2606     GLenum m_inputPrimitives;
2607 };
2608 
NegativeDrawCase(Context & context,const char * name,const char * desc,GLenum inputType,GLenum inputPrimitives)2609 NegativeDrawCase::NegativeDrawCase(Context &context, const char *name, const char *desc, GLenum inputType,
2610                                    GLenum inputPrimitives)
2611     : TestCase(context, name, desc)
2612     , m_ctx(DE_NULL)
2613     , m_program(DE_NULL)
2614     , m_inputType(inputType)
2615     , m_inputPrimitives(inputPrimitives)
2616 {
2617 }
2618 
~NegativeDrawCase(void)2619 NegativeDrawCase::~NegativeDrawCase(void)
2620 {
2621     deinit();
2622 }
2623 
init(void)2624 void NegativeDrawCase::init(void)
2625 {
2626     if (!checkSupport(m_context))
2627         TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
2628 
2629     m_ctx     = new sglr::GLContext(m_context.getRenderContext(), m_testCtx.getLog(),
2630                                     sglr::GLCONTEXT_LOG_CALLS | sglr::GLCONTEXT_LOG_PROGRAMS, tcu::IVec4(0, 0, 1, 1));
2631     m_program = new VertexExpanderShader(m_context.getRenderContext().getType(),
2632                                          sglr::rr_util::mapGLGeometryShaderInputType(m_inputType),
2633                                          rr::GEOMETRYSHADEROUTPUTTYPE_POINTS);
2634 }
2635 
deinit(void)2636 void NegativeDrawCase::deinit(void)
2637 {
2638     delete m_ctx;
2639     delete m_program;
2640 
2641     m_ctx     = NULL;
2642     m_program = DE_NULL;
2643 }
2644 
iterate(void)2645 NegativeDrawCase::IterateResult NegativeDrawCase::iterate(void)
2646 {
2647     const GLuint programId = m_ctx->createProgram(m_program);
2648     const GLint attrPosLoc = m_ctx->getAttribLocation(programId, "a_position");
2649     const tcu::Vec4 vertexPosData(0, 0, 0, 1);
2650 
2651     GLuint vaoId        = 0;
2652     GLuint vertexPosBuf = 0;
2653     GLenum errorCode    = 0;
2654 
2655     m_ctx->genVertexArrays(1, &vaoId);
2656     m_ctx->bindVertexArray(vaoId);
2657 
2658     m_ctx->genBuffers(1, &vertexPosBuf);
2659     m_ctx->bindBuffer(GL_ARRAY_BUFFER, vertexPosBuf);
2660     m_ctx->bufferData(GL_ARRAY_BUFFER, sizeof(tcu::Vec4), vertexPosData.m_data, GL_STATIC_DRAW);
2661     m_ctx->vertexAttribPointer(attrPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
2662     m_ctx->enableVertexAttribArray(attrPosLoc);
2663 
2664     m_ctx->clearColor(0, 0, 0, 1);
2665     m_ctx->clear(GL_COLOR_BUFFER_BIT);
2666 
2667     m_ctx->viewport(0, 0, 1, 1);
2668 
2669     m_ctx->useProgram(programId);
2670 
2671     // no errors before
2672     glu::checkError(m_ctx->getError(), "", __FILE__, __LINE__);
2673 
2674     m_ctx->drawArrays(m_inputPrimitives, 0, 1);
2675 
2676     errorCode = m_ctx->getError();
2677     if (errorCode != GL_INVALID_OPERATION)
2678     {
2679         m_testCtx.getLog() << tcu::TestLog::Message << "Expected GL_INVALID_OPERATION, got "
2680                            << glu::getErrorStr(errorCode) << tcu::TestLog::EndMessage;
2681         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong error code");
2682     }
2683     else
2684     {
2685         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2686     }
2687 
2688     m_ctx->useProgram(0);
2689 
2690     m_ctx->disableVertexAttribArray(attrPosLoc);
2691     m_ctx->deleteBuffers(1, &vertexPosBuf);
2692 
2693     m_ctx->deleteVertexArrays(1, &vaoId);
2694 
2695     return STOP;
2696 }
2697 
2698 class OutputCountCase : public GeometryShaderRenderTest
2699 {
2700 public:
2701     OutputCountCase(Context &context, const char *name, const char *desc, const OutputCountPatternSpec &);
2702 
2703 private:
2704     void init(void);
2705     void deinit(void);
2706 
2707     sglr::ShaderProgram &getProgram(void);
2708     void genVertexAttribData(void);
2709 
2710     const int m_primitiveCount;
2711     OutputCountShader *m_program;
2712     OutputCountPatternSpec m_spec;
2713 };
2714 
OutputCountCase(Context & context,const char * name,const char * desc,const OutputCountPatternSpec & spec)2715 OutputCountCase::OutputCountCase(Context &context, const char *name, const char *desc,
2716                                  const OutputCountPatternSpec &spec)
2717     : GeometryShaderRenderTest(context, name, desc, GL_POINTS, GL_TRIANGLE_STRIP, "a_color")
2718     , m_primitiveCount((int)spec.pattern.size())
2719     , m_program(DE_NULL)
2720     , m_spec(spec)
2721 {
2722 }
2723 
init(void)2724 void OutputCountCase::init(void)
2725 {
2726     // Check requirements and adapt to them
2727     {
2728         const int componentsPerVertex = 4 + 4; // vec4 pos, vec4 color
2729         const int testVertices        = *std::max_element(m_spec.pattern.begin(), m_spec.pattern.end());
2730         glw::GLint maxVertices        = 0;
2731         glw::GLint maxComponents      = 0;
2732 
2733         // check the extension before querying anything
2734         if (!checkSupport(m_context))
2735             TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
2736 
2737         m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, &maxVertices);
2738         m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS,
2739                                                                 &maxComponents);
2740 
2741         m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_OUTPUT_VERTICES = " << maxVertices
2742                            << tcu::TestLog::EndMessage;
2743         m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS = " << maxComponents
2744                            << tcu::TestLog::EndMessage;
2745         m_testCtx.getLog() << tcu::TestLog::Message << "Components per vertex = " << componentsPerVertex
2746                            << tcu::TestLog::EndMessage;
2747 
2748         if (testVertices == -1)
2749         {
2750             // "max vertices"-case
2751             DE_ASSERT((int)m_spec.pattern.size() == 1);
2752             m_spec.pattern[0] = de::min(maxVertices, maxComponents / componentsPerVertex);
2753 
2754             // make sure size is dividable by 2, as OutputShader requires
2755             m_spec.pattern[0] = m_spec.pattern[0] & ~0x00000001;
2756 
2757             if (m_spec.pattern[0] == 0)
2758                 throw tcu::InternalError("Pattern size is invalid.");
2759         }
2760         else
2761         {
2762             // normal case
2763             if (testVertices > maxVertices)
2764                 throw tcu::NotSupportedError(de::toString(testVertices) + " output vertices required.");
2765             if (testVertices * componentsPerVertex > maxComponents)
2766                 throw tcu::NotSupportedError(de::toString(testVertices * componentsPerVertex) +
2767                                              " output components required.");
2768         }
2769     }
2770 
2771     // Log what the test tries to do
2772 
2773     m_testCtx.getLog() << tcu::TestLog::Message << "Rendering " << (int)m_spec.pattern.size()
2774                        << " row(s).\nOne geometry shader invocation generates one row.\nRow sizes:"
2775                        << tcu::TestLog::EndMessage;
2776     for (int ndx = 0; ndx < (int)m_spec.pattern.size(); ++ndx)
2777         m_testCtx.getLog() << tcu::TestLog::Message << "Row " << ndx << ": " << m_spec.pattern[ndx] << " vertices."
2778                            << tcu::TestLog::EndMessage;
2779 
2780     // Gen shader
2781     DE_ASSERT(!m_program);
2782     m_program = new OutputCountShader(m_context.getRenderContext().getType(), m_spec);
2783 
2784     // Case init
2785     GeometryShaderRenderTest::init();
2786 }
2787 
deinit(void)2788 void OutputCountCase::deinit(void)
2789 {
2790     if (m_program)
2791     {
2792         delete m_program;
2793         m_program = DE_NULL;
2794     }
2795 
2796     GeometryShaderRenderTest::deinit();
2797 }
2798 
getProgram(void)2799 sglr::ShaderProgram &OutputCountCase::getProgram(void)
2800 {
2801     return *m_program;
2802 }
2803 
genVertexAttribData(void)2804 void OutputCountCase::genVertexAttribData(void)
2805 {
2806     m_vertexPosData.resize(m_primitiveCount);
2807     m_vertexAttrData.resize(m_primitiveCount);
2808 
2809     for (int ndx = 0; ndx < m_primitiveCount; ++ndx)
2810     {
2811         m_vertexPosData[ndx]  = tcu::Vec4(-1.0f, ((float)ndx) / (float)m_primitiveCount * 2.0f - 1.0f, 0.0f, 1.0f);
2812         m_vertexAttrData[ndx] = (ndx % 2 == 0) ? tcu::Vec4(1, 1, 1, 1) : tcu::Vec4(1, 0, 0, 1);
2813     }
2814 
2815     m_numDrawVertices = m_primitiveCount;
2816 }
2817 
2818 class BuiltinVariableRenderTest : public GeometryShaderRenderTest
2819 {
2820 public:
2821     BuiltinVariableRenderTest(Context &context, const char *name, const char *desc,
2822                               BuiltinVariableShader::VariableTest test, int flags = 0);
2823 
2824 private:
2825     void init(void);
2826     void deinit(void);
2827 
2828     sglr::ShaderProgram &getProgram(void);
2829     void genVertexAttribData(void);
2830 
2831     BuiltinVariableShader *m_program;
2832     const BuiltinVariableShader::VariableTest m_test;
2833 };
2834 
BuiltinVariableRenderTest(Context & context,const char * name,const char * desc,BuiltinVariableShader::VariableTest test,int flags)2835 BuiltinVariableRenderTest::BuiltinVariableRenderTest(Context &context, const char *name, const char *desc,
2836                                                      BuiltinVariableShader::VariableTest test, int flags)
2837     : GeometryShaderRenderTest(context, name, desc, GL_POINTS, GL_POINTS,
2838                                BuiltinVariableShader::getTestAttributeName(test), flags)
2839     , m_program(DE_NULL)
2840     , m_test(test)
2841 {
2842 }
2843 
init(void)2844 void BuiltinVariableRenderTest::init(void)
2845 {
2846     // Requirements
2847     if (m_test == BuiltinVariableShader::TEST_POINT_SIZE)
2848     {
2849         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2850 
2851         const float requiredPointSize = 5.0f;
2852 
2853         tcu::Vec2 range = tcu::Vec2(1.0f, 1.0f);
2854 
2855         if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 4)) &&
2856             !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_point_size"))
2857             TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_point_size extension.");
2858 
2859         gl.getFloatv(GL_ALIASED_POINT_SIZE_RANGE, range.getPtr());
2860         if (range.y() < requiredPointSize)
2861             throw tcu::NotSupportedError("Test case requires point size " + de::toString(requiredPointSize));
2862 
2863         if (glu::isContextTypeGLCore(m_context.getRenderContext().getType()))
2864             gl.enable(GL_PROGRAM_POINT_SIZE);
2865     }
2866 
2867     m_program = new BuiltinVariableShader(m_context.getRenderContext().getType(), m_test);
2868 
2869     // Shader init
2870     GeometryShaderRenderTest::init();
2871 }
2872 
deinit(void)2873 void BuiltinVariableRenderTest::deinit(void)
2874 {
2875     if (BuiltinVariableShader::TEST_POINT_SIZE == m_test &&
2876         glu::isContextTypeGLCore(m_context.getRenderContext().getType()))
2877     {
2878         m_context.getRenderContext().getFunctions().disable(GL_PROGRAM_POINT_SIZE);
2879     }
2880 
2881     if (m_program)
2882     {
2883         delete m_program;
2884         m_program = DE_NULL;
2885     }
2886 
2887     GeometryShaderRenderTest::deinit();
2888 }
2889 
getProgram(void)2890 sglr::ShaderProgram &BuiltinVariableRenderTest::getProgram(void)
2891 {
2892     return *m_program;
2893 }
2894 
genVertexAttribData(void)2895 void BuiltinVariableRenderTest::genVertexAttribData(void)
2896 {
2897     m_vertexPosData.resize(4);
2898     m_vertexPosData[0] = tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f);
2899     m_vertexPosData[1] = tcu::Vec4(0.0f, 0.5f, 0.0f, 1.0f);
2900     m_vertexPosData[2] = tcu::Vec4(-0.7f, -0.1f, 0.0f, 1.0f);
2901     m_vertexPosData[3] = tcu::Vec4(-0.1f, -0.7f, 0.0f, 1.0f);
2902 
2903     m_vertexAttrData.resize(4);
2904     m_vertexAttrData[0] = tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
2905     m_vertexAttrData[1] = tcu::Vec4(1.0f, 0.0f, 0.0f, 0.0f);
2906     m_vertexAttrData[2] = tcu::Vec4(2.0f, 0.0f, 0.0f, 0.0f);
2907     m_vertexAttrData[3] = tcu::Vec4(3.0f, 0.0f, 0.0f, 0.0f);
2908 
2909     // Only used by primitive ID restart test
2910     m_indices.resize(4);
2911     m_indices[0] = 3;
2912     m_indices[1] = 2;
2913     m_indices[2] = 0xFFFF; // restart
2914     m_indices[3] = 1;
2915 
2916     m_numDrawVertices = 4;
2917 }
2918 
2919 class LayeredRenderCase : public TestCase
2920 {
2921 public:
2922     enum LayeredRenderTargetType
2923     {
2924         TARGET_CUBE = 0,
2925         TARGET_3D,
2926         TARGET_1D_ARRAY,
2927         TARGET_2D_ARRAY,
2928         TARGET_2D_MS_ARRAY,
2929 
2930         TARGET_LAST
2931     };
2932     enum TestType
2933     {
2934         TEST_DEFAULT_LAYER,                  // !< draw to default layer
2935         TEST_SINGLE_LAYER,                   // !< draw to single layer
2936         TEST_ALL_LAYERS,                     // !< draw all layers
2937         TEST_DIFFERENT_LAYERS,               // !< draw different content to different layers
2938         TEST_INVOCATION_PER_LAYER,           // !< draw to all layers, one invocation per layer
2939         TEST_MULTIPLE_LAYERS_PER_INVOCATION, // !< draw to all layers, multiple invocations write to multiple layers
2940         TEST_LAYER_ID,                       // !< draw to all layers, verify gl_Layer fragment input
2941         TEST_LAYER_PROVOKING_VERTEX, // !< draw primitive with vertices in different layers, check which layer it was drawn to
2942 
2943         TEST_LAST
2944     };
2945     LayeredRenderCase(Context &context, const char *name, const char *desc, LayeredRenderTargetType target,
2946                       TestType test);
2947     ~LayeredRenderCase(void);
2948 
2949     void init(void);
2950     void deinit(void);
2951     IterateResult iterate(void);
2952 
2953 private:
2954     void initTexture(void);
2955     void initFbo(void);
2956     void initRenderShader(void);
2957     void initSamplerShader(void);
2958 
2959     std::string genFragmentSource(const glu::ContextType &contextType) const;
2960     std::string genGeometrySource(const glu::ContextType &contextType) const;
2961     std::string genSamplerFragmentSource(const glu::ContextType &contextType) const;
2962 
2963     void renderToTexture(void);
2964     void sampleTextureLayer(tcu::Surface &dst, int layer);
2965     bool verifyLayerContent(const tcu::Surface &layer, int layerNdx);
2966     bool verifyImageSingleColoredRow(const tcu::Surface &layer, float rowWidthRatio, const tcu::Vec4 &color,
2967                                      bool logging = true);
2968     bool verifyEmptyImage(const tcu::Surface &layer, bool logging = true);
2969     bool verifyProvokingVertexLayers(const tcu::Surface &layer0, const tcu::Surface &layer1);
2970 
2971     static int getTargetLayers(LayeredRenderTargetType target);
2972     static glw::GLenum getTargetTextureTarget(LayeredRenderTargetType target);
2973     static tcu::IVec3 getTargetDimensions(LayeredRenderTargetType target);
2974     static tcu::IVec2 getResolveDimensions(LayeredRenderTargetType target);
2975 
2976     const LayeredRenderTargetType m_target;
2977     const TestType m_test;
2978     const int m_numLayers;
2979     const int m_targetLayer;
2980     const tcu::IVec2 m_resolveDimensions;
2981 
2982     int m_iteration;
2983     bool m_allLayersOk;
2984 
2985     glw::GLuint m_texture;
2986     glw::GLuint m_fbo;
2987     glu::ShaderProgram *m_renderShader;
2988     glu::ShaderProgram *m_samplerShader;
2989 
2990     glw::GLint m_samplerSamplerLoc;
2991     glw::GLint m_samplerLayerLoc;
2992 
2993     glw::GLenum m_provokingVertex;
2994 };
2995 
LayeredRenderCase(Context & context,const char * name,const char * desc,LayeredRenderTargetType target,TestType test)2996 LayeredRenderCase::LayeredRenderCase(Context &context, const char *name, const char *desc,
2997                                      LayeredRenderTargetType target, TestType test)
2998     : TestCase(context, name, desc)
2999     , m_target(target)
3000     , m_test(test)
3001     , m_numLayers(getTargetLayers(target))
3002     , m_targetLayer(m_numLayers / 2)
3003     , m_resolveDimensions(getResolveDimensions(target))
3004     , m_iteration(0)
3005     , m_allLayersOk(true)
3006     , m_texture(0)
3007     , m_fbo(0)
3008     , m_renderShader(DE_NULL)
3009     , m_samplerShader(DE_NULL)
3010     , m_samplerSamplerLoc(-1)
3011     , m_samplerLayerLoc(-1)
3012     , m_provokingVertex(0)
3013 {
3014 }
3015 
~LayeredRenderCase(void)3016 LayeredRenderCase::~LayeredRenderCase(void)
3017 {
3018     deinit();
3019 }
3020 
init(void)3021 void LayeredRenderCase::init(void)
3022 {
3023     // Requirements
3024 
3025     const bool supportES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
3026     const bool supportGL45 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
3027 
3028     if (!checkSupport(m_context))
3029         TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
3030 
3031     if (m_target == TARGET_2D_MS_ARRAY &&
3032         !(supportGL45 || (supportES32 && m_context.getContextInfo().isExtensionSupported(
3033                                              "GL_OES_texture_storage_multisample_2d_array"))))
3034         TCU_THROW(NotSupportedError,
3035                   "Test requires OES_texture_storage_multisample_2d_array extension or higher context version.");
3036 
3037     if (m_context.getRenderTarget().getWidth() < m_resolveDimensions.x() ||
3038         m_context.getRenderTarget().getHeight() < m_resolveDimensions.y())
3039         throw tcu::NotSupportedError("Render target size must be at least " + de::toString(m_resolveDimensions.x()) +
3040                                      "x" + de::toString(m_resolveDimensions.y()));
3041 
3042     // log what the test tries to do
3043 
3044     if (m_test == TEST_DEFAULT_LAYER)
3045         m_testCtx.getLog() << tcu::TestLog::Message << "Rendering to the default layer." << tcu::TestLog::EndMessage;
3046     else if (m_test == TEST_SINGLE_LAYER)
3047         m_testCtx.getLog() << tcu::TestLog::Message << "Rendering to a single layer." << tcu::TestLog::EndMessage;
3048     else if (m_test == TEST_ALL_LAYERS)
3049         m_testCtx.getLog() << tcu::TestLog::Message << "Rendering to all layers." << tcu::TestLog::EndMessage;
3050     else if (m_test == TEST_DIFFERENT_LAYERS)
3051         m_testCtx.getLog() << tcu::TestLog::Message << "Outputting different number of vertices to each layer."
3052                            << tcu::TestLog::EndMessage;
3053     else if (m_test == TEST_INVOCATION_PER_LAYER)
3054         m_testCtx.getLog() << tcu::TestLog::Message << "Using a different invocation to output to each layer."
3055                            << tcu::TestLog::EndMessage;
3056     else if (m_test == TEST_MULTIPLE_LAYERS_PER_INVOCATION)
3057         m_testCtx.getLog() << tcu::TestLog::Message << "Outputting to each layer from multiple invocations."
3058                            << tcu::TestLog::EndMessage;
3059     else if (m_test == TEST_LAYER_ID)
3060         m_testCtx.getLog() << tcu::TestLog::Message << "Using gl_Layer in fragment shader." << tcu::TestLog::EndMessage;
3061     else if (m_test == TEST_LAYER_PROVOKING_VERTEX)
3062         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying LAYER_PROVOKING_VERTEX." << tcu::TestLog::EndMessage;
3063     else
3064         DE_ASSERT(false);
3065 
3066     // init resources
3067 
3068     initTexture();
3069     initFbo();
3070     initRenderShader();
3071     initSamplerShader();
3072 }
3073 
deinit(void)3074 void LayeredRenderCase::deinit(void)
3075 {
3076     if (m_texture)
3077     {
3078         m_context.getRenderContext().getFunctions().deleteTextures(1, &m_texture);
3079         m_texture = 0;
3080     }
3081 
3082     if (m_fbo)
3083     {
3084         m_context.getRenderContext().getFunctions().deleteFramebuffers(1, &m_fbo);
3085         m_fbo = 0;
3086     }
3087 
3088     delete m_renderShader;
3089     delete m_samplerShader;
3090 
3091     m_renderShader  = DE_NULL;
3092     m_samplerShader = DE_NULL;
3093 }
3094 
iterate(void)3095 LayeredRenderCase::IterateResult LayeredRenderCase::iterate(void)
3096 {
3097     ++m_iteration;
3098 
3099     if (m_iteration == 1)
3100     {
3101         if (m_test == TEST_LAYER_PROVOKING_VERTEX)
3102         {
3103             // which layer the implementation claims to render to
3104 
3105             gls::StateQueryUtil::StateQueryMemoryWriteGuard<glw::GLint> state;
3106 
3107             const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3108 
3109             gl.getIntegerv(GL_LAYER_PROVOKING_VERTEX, &state);
3110             GLU_EXPECT_NO_ERROR(gl.getError(), "getInteger(GL_LAYER_PROVOKING_VERTEX)");
3111 
3112             if (!state.verifyValidity(m_testCtx))
3113                 return STOP;
3114 
3115             m_testCtx.getLog() << tcu::TestLog::Message
3116                                << "GL_LAYER_PROVOKING_VERTEX = " << glu::getProvokingVertexStr(state)
3117                                << tcu::TestLog::EndMessage;
3118 
3119             bool ok = false;
3120             if (contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(3, 2)))
3121             {
3122                 ok = state == GL_FIRST_VERTEX_CONVENTION || state == GL_LAST_VERTEX_CONVENTION ||
3123                      state == GL_PROVOKING_VERTEX || state == GL_UNDEFINED_VERTEX;
3124                 m_provokingVertex = (glw::GLenum)state;
3125 
3126                 if (state == GL_PROVOKING_VERTEX)
3127                 {
3128                     gl.getIntegerv(GL_PROVOKING_VERTEX, reinterpret_cast<glw::GLint *>(&m_provokingVertex));
3129                     GLU_EXPECT_NO_ERROR(gl.getError(), "getInteger(GL_PROVOKING_VERTEX)");
3130                 }
3131             }
3132             else
3133             {
3134                 ok = state == GL_FIRST_VERTEX_CONVENTION || state == GL_LAST_VERTEX_CONVENTION ||
3135                      state == GL_UNDEFINED_VERTEX;
3136                 m_provokingVertex = (glw::GLenum)state;
3137             }
3138             if (!ok)
3139             {
3140                 m_testCtx.getLog() << tcu::TestLog::Message
3141                                    << "getInteger(GL_LAYER_PROVOKING_VERTEX) returned illegal value. Got " << state
3142                                    << tcu::TestLog::EndMessage;
3143                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got unexpected provoking vertex value");
3144                 return STOP;
3145             }
3146         }
3147 
3148         // render to texture
3149         {
3150             const tcu::ScopedLogSection section(m_testCtx.getLog(), "RenderToTexture", "Render to layered texture");
3151 
3152             // render to layered texture with the geometry shader
3153             renderToTexture();
3154         }
3155 
3156         return CONTINUE;
3157     }
3158     else if (m_test == TEST_LAYER_PROVOKING_VERTEX && m_provokingVertex == GL_UNDEFINED_VERTEX)
3159     {
3160         // Verification requires information from another layers, layers not independent
3161         {
3162             const tcu::ScopedLogSection section(m_testCtx.getLog(), "VerifyLayers", "Verify layers 0 and 1");
3163             tcu::Surface layer0(m_resolveDimensions.x(), m_resolveDimensions.y());
3164             tcu::Surface layer1(m_resolveDimensions.x(), m_resolveDimensions.y());
3165 
3166             // sample layer to frame buffer
3167             sampleTextureLayer(layer0, 0);
3168             sampleTextureLayer(layer1, 1);
3169 
3170             m_allLayersOk &= verifyProvokingVertexLayers(layer0, layer1);
3171         }
3172 
3173         // Other layers empty
3174         for (int layerNdx = 2; layerNdx < m_numLayers; ++layerNdx)
3175         {
3176             const tcu::ScopedLogSection section(m_testCtx.getLog(), "VerifyLayer",
3177                                                 "Verify layer " + de::toString(layerNdx));
3178             tcu::Surface layer(m_resolveDimensions.x(), m_resolveDimensions.y());
3179 
3180             // sample layer to frame buffer
3181             sampleTextureLayer(layer, layerNdx);
3182 
3183             // verify
3184             m_allLayersOk &= verifyEmptyImage(layer);
3185         }
3186     }
3187     else
3188     {
3189         // Layers independent
3190 
3191         const int layerNdx = m_iteration - 2;
3192         const tcu::ScopedLogSection section(m_testCtx.getLog(), "VerifyLayer",
3193                                             "Verify layer " + de::toString(layerNdx));
3194         tcu::Surface layer(m_resolveDimensions.x(), m_resolveDimensions.y());
3195 
3196         // sample layer to frame buffer
3197         sampleTextureLayer(layer, layerNdx);
3198 
3199         // verify
3200         m_allLayersOk &= verifyLayerContent(layer, layerNdx);
3201 
3202         if (layerNdx < m_numLayers - 1)
3203             return CONTINUE;
3204     }
3205 
3206     // last iteration
3207     if (m_allLayersOk)
3208         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3209     else
3210         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Detected invalid layer content");
3211 
3212     return STOP;
3213 }
3214 
initTexture(void)3215 void LayeredRenderCase::initTexture(void)
3216 {
3217     DE_ASSERT(!m_texture);
3218 
3219     const glw::Functions &gl                 = m_context.getRenderContext().getFunctions();
3220     const tcu::IVec3 texSize                 = getTargetDimensions(m_target);
3221     const tcu::TextureFormat texFormat       = glu::mapGLInternalFormat(GL_RGBA8);
3222     const glu::TransferFormat transferFormat = glu::getTransferFormat(texFormat);
3223 
3224     gl.genTextures(1, &m_texture);
3225     GLU_EXPECT_NO_ERROR(gl.getError(), "gen texture");
3226 
3227     switch (m_target)
3228     {
3229     case TARGET_CUBE:
3230         m_testCtx.getLog() << tcu::TestLog::Message << "Creating cubemap texture, size = " << texSize.x() << "x"
3231                            << texSize.y() << tcu::TestLog::EndMessage;
3232         gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_texture);
3233         gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA8, texSize.x(), texSize.y(), 0, transferFormat.format,
3234                       transferFormat.dataType, DE_NULL);
3235         gl.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA8, texSize.x(), texSize.y(), 0, transferFormat.format,
3236                       transferFormat.dataType, DE_NULL);
3237         gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA8, texSize.x(), texSize.y(), 0, transferFormat.format,
3238                       transferFormat.dataType, DE_NULL);
3239         gl.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA8, texSize.x(), texSize.y(), 0, transferFormat.format,
3240                       transferFormat.dataType, DE_NULL);
3241         gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGBA8, texSize.x(), texSize.y(), 0, transferFormat.format,
3242                       transferFormat.dataType, DE_NULL);
3243         gl.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA8, texSize.x(), texSize.y(), 0, transferFormat.format,
3244                       transferFormat.dataType, DE_NULL);
3245         break;
3246 
3247     case TARGET_3D:
3248         m_testCtx.getLog() << tcu::TestLog::Message << "Creating 3d texture, size = " << texSize.x() << "x"
3249                            << texSize.y() << "x" << texSize.z() << tcu::TestLog::EndMessage;
3250         gl.bindTexture(GL_TEXTURE_3D, m_texture);
3251         gl.texImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, texSize.x(), texSize.y(), texSize.z(), 0, transferFormat.format,
3252                       transferFormat.dataType, DE_NULL);
3253         break;
3254 
3255     case TARGET_1D_ARRAY:
3256         m_testCtx.getLog() << tcu::TestLog::Message << "Creating 1d texture array, size = " << texSize.x()
3257                            << ", layers = " << texSize.y() << tcu::TestLog::EndMessage;
3258         gl.bindTexture(GL_TEXTURE_1D_ARRAY, m_texture);
3259         gl.texImage2D(GL_TEXTURE_1D_ARRAY, 0, GL_RGBA8, texSize.x(), texSize.y(), 0, transferFormat.format,
3260                       transferFormat.dataType, DE_NULL);
3261         break;
3262 
3263     case TARGET_2D_ARRAY:
3264         m_testCtx.getLog() << tcu::TestLog::Message << "Creating 2d texture array, size = " << texSize.x() << "x"
3265                            << texSize.y() << ", layers = " << texSize.z() << tcu::TestLog::EndMessage;
3266         gl.bindTexture(GL_TEXTURE_2D_ARRAY, m_texture);
3267         gl.texImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, texSize.x(), texSize.y(), texSize.z(), 0, transferFormat.format,
3268                       transferFormat.dataType, DE_NULL);
3269         break;
3270 
3271     case TARGET_2D_MS_ARRAY:
3272     {
3273         const int numSamples = 2;
3274 
3275         int maxSamples = 0;
3276         gl.getIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &maxSamples);
3277 
3278         m_testCtx.getLog() << tcu::TestLog::Message << "Creating 2d multisample texture array, size = " << texSize.x()
3279                            << "x" << texSize.y() << ", layers = " << texSize.z() << ", samples = " << numSamples
3280                            << tcu::TestLog::EndMessage;
3281 
3282         if (numSamples > maxSamples)
3283             throw tcu::NotSupportedError("Test requires " + de::toString(numSamples) + " color texture samples.");
3284 
3285         gl.bindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, m_texture);
3286         gl.texStorage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, numSamples, GL_RGBA8, texSize.x(), texSize.y(),
3287                                    texSize.z(), GL_TRUE);
3288         break;
3289     }
3290 
3291     default:
3292         DE_ASSERT(false);
3293     }
3294     GLU_EXPECT_NO_ERROR(gl.getError(), "tex image");
3295 
3296     // Multisample textures don't use filters
3297     if (getTargetTextureTarget(m_target) != GL_TEXTURE_2D_MULTISAMPLE_ARRAY)
3298     {
3299         gl.texParameteri(getTargetTextureTarget(m_target), GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3300         gl.texParameteri(getTargetTextureTarget(m_target), GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3301         gl.texParameteri(getTargetTextureTarget(m_target), GL_TEXTURE_WRAP_S, GL_REPEAT);
3302         gl.texParameteri(getTargetTextureTarget(m_target), GL_TEXTURE_WRAP_T, GL_REPEAT);
3303         gl.texParameteri(getTargetTextureTarget(m_target), GL_TEXTURE_WRAP_R, GL_REPEAT);
3304         GLU_EXPECT_NO_ERROR(gl.getError(), "tex filter");
3305     }
3306 }
3307 
initFbo(void)3308 void LayeredRenderCase::initFbo(void)
3309 {
3310     DE_ASSERT(!m_fbo);
3311 
3312     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3313 
3314     m_testCtx.getLog() << tcu::TestLog::Message << "Creating FBO" << tcu::TestLog::EndMessage;
3315 
3316     gl.genFramebuffers(1, &m_fbo);
3317     gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
3318     gl.framebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture, 0);
3319     gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
3320 
3321     GLU_EXPECT_NO_ERROR(gl.getError(), "setup fbo");
3322 }
3323 
initRenderShader(void)3324 void LayeredRenderCase::initRenderShader(void)
3325 {
3326     const tcu::ScopedLogSection section(m_testCtx.getLog(), "RenderToTextureShader",
3327                                         "Create layered rendering shader program");
3328 
3329     static const char *const positionVertex = "${GLSL_VERSION_DECL}\n"
3330                                               "void main (void)\n"
3331                                               "{\n"
3332                                               "    gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
3333                                               "}\n";
3334 
3335     m_renderShader = new glu::ShaderProgram(
3336         m_context.getRenderContext(),
3337         glu::ProgramSources() << glu::VertexSource(
3338                                      specializeShader(positionVertex, m_context.getRenderContext().getType()))
3339                               << glu::FragmentSource(genFragmentSource(m_context.getRenderContext().getType()))
3340                               << glu::GeometrySource(genGeometrySource(m_context.getRenderContext().getType())));
3341     m_testCtx.getLog() << *m_renderShader;
3342 
3343     if (!m_renderShader->isOk())
3344         throw tcu::TestError("failed to build render shader");
3345 }
3346 
initSamplerShader(void)3347 void LayeredRenderCase::initSamplerShader(void)
3348 {
3349     const tcu::ScopedLogSection section(m_testCtx.getLog(), "TextureSamplerShader", "Create shader sampler program");
3350 
3351     static const char *const positionVertex = "${GLSL_VERSION_DECL}\n"
3352                                               "in highp vec4 a_position;\n"
3353                                               "void main (void)\n"
3354                                               "{\n"
3355                                               "    gl_Position = a_position;\n"
3356                                               "}\n";
3357 
3358     m_samplerShader = new glu::ShaderProgram(
3359         m_context.getRenderContext(),
3360         glu::ProgramSources() << glu::VertexSource(
3361                                      specializeShader(positionVertex, m_context.getRenderContext().getType()))
3362                               << glu::FragmentSource(genSamplerFragmentSource(m_context.getRenderContext().getType())));
3363 
3364     m_testCtx.getLog() << *m_samplerShader;
3365 
3366     if (!m_samplerShader->isOk())
3367         throw tcu::TestError("failed to build sampler shader");
3368 
3369     m_samplerSamplerLoc =
3370         m_context.getRenderContext().getFunctions().getUniformLocation(m_samplerShader->getProgram(), "u_sampler");
3371     if (m_samplerSamplerLoc == -1)
3372         throw tcu::TestError("u_sampler uniform location = -1");
3373 
3374     m_samplerLayerLoc =
3375         m_context.getRenderContext().getFunctions().getUniformLocation(m_samplerShader->getProgram(), "u_layer");
3376     if (m_samplerLayerLoc == -1)
3377         throw tcu::TestError("u_layer uniform location = -1");
3378 }
3379 
genFragmentSource(const glu::ContextType & contextType) const3380 std::string LayeredRenderCase::genFragmentSource(const glu::ContextType &contextType) const
3381 {
3382     static const char *const fragmentLayerIdShader = "${GLSL_VERSION_DECL}\n"
3383                                                      "${GLSL_EXT_GEOMETRY_SHADER}"
3384                                                      "layout(location = 0) out mediump vec4 fragColor;\n"
3385                                                      "void main (void)\n"
3386                                                      "{\n"
3387                                                      "    fragColor = vec4(((gl_Layer % 2) == 1) ? 1.0 : 0.5,\n"
3388                                                      "                     (((gl_Layer / 2) % 2) == 1) ? 1.0 : 0.5,\n"
3389                                                      "                     (gl_Layer == 0) ? 1.0 : 0.0,\n"
3390                                                      "                     1.0);\n"
3391                                                      "}\n";
3392 
3393     if (m_test != TEST_LAYER_ID)
3394         return specializeShader(s_commonShaderSourceFragment, contextType);
3395     else
3396         return specializeShader(fragmentLayerIdShader, contextType);
3397 }
3398 
genGeometrySource(const glu::ContextType & contextType) const3399 std::string LayeredRenderCase::genGeometrySource(const glu::ContextType &contextType) const
3400 {
3401     // TEST_DIFFERENT_LAYERS: draw 0 quad to first layer, 1 to second, etc.
3402     // TEST_ALL_LAYERS: draw 1 quad to all layers
3403     // TEST_MULTIPLE_LAYERS_PER_INVOCATION: draw 1 triangle to "current layer" and 1 triangle to another layer
3404     // else: draw 1 quad to some single layer
3405     const int maxVertices = (m_test == TEST_DIFFERENT_LAYERS) ? ((2 + m_numLayers - 1) * m_numLayers) :
3406                             (m_test == TEST_ALL_LAYERS || m_test == TEST_LAYER_ID) ? (m_numLayers * 4) :
3407                             (m_test == TEST_MULTIPLE_LAYERS_PER_INVOCATION)        ? (6) :
3408                             (m_test == TEST_LAYER_PROVOKING_VERTEX)                ? (6) :
3409                                                                                      (4);
3410     std::ostringstream buf;
3411 
3412     buf << "${GLSL_VERSION_DECL}\n"
3413            "${GLSL_EXT_GEOMETRY_SHADER}";
3414 
3415     if (m_test == TEST_INVOCATION_PER_LAYER || m_test == TEST_MULTIPLE_LAYERS_PER_INVOCATION)
3416         buf << "layout(points, invocations=" << m_numLayers << ") in;\n";
3417     else
3418         buf << "layout(points) in;\n";
3419 
3420     buf << "layout(triangle_strip, max_vertices = " << maxVertices
3421         << ") out;\n"
3422            "out highp vec4 v_frag_FragColor;\n"
3423            "\n"
3424            "void main (void)\n"
3425            "{\n";
3426 
3427     if (m_test == TEST_DEFAULT_LAYER)
3428     {
3429         buf << "    const highp vec4 white = vec4(1.0, 1.0, 1.0, 1.0);\n\n"
3430                "    gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
3431                "    v_frag_FragColor = white;\n"
3432                "    EmitVertex();\n\n"
3433                "    gl_Position = vec4(-1.0,  1.0, 0.0, 1.0);\n"
3434                "    v_frag_FragColor = white;\n"
3435                "    EmitVertex();\n\n"
3436                "    gl_Position = vec4( 0.0, -1.0, 0.0, 1.0);\n"
3437                "    v_frag_FragColor = white;\n"
3438                "    EmitVertex();\n\n"
3439                "    gl_Position = vec4( 0.0,  1.0, 0.0, 1.0);\n"
3440                "    v_frag_FragColor = white;\n"
3441                "    EmitVertex();\n";
3442     }
3443     else if (m_test == TEST_SINGLE_LAYER)
3444     {
3445         buf << "    const highp vec4 white = vec4(1.0, 1.0, 1.0, 1.0);\n\n"
3446                "    gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
3447                "    gl_Layer = "
3448             << m_targetLayer
3449             << ";\n"
3450                "    v_frag_FragColor = white;\n"
3451                "    EmitVertex();\n\n"
3452                "    gl_Position = vec4(-1.0,  1.0, 0.0, 1.0);\n"
3453                "    gl_Layer = "
3454             << m_targetLayer
3455             << ";\n"
3456                "    v_frag_FragColor = white;\n"
3457                "    EmitVertex();\n\n"
3458                "    gl_Position = vec4( 0.0, -1.0, 0.0, 1.0);\n"
3459                "    gl_Layer = "
3460             << m_targetLayer
3461             << ";\n"
3462                "    v_frag_FragColor = white;\n"
3463                "    EmitVertex();\n\n"
3464                "    gl_Position = vec4( 0.0,  1.0, 0.0, 1.0);\n"
3465                "    gl_Layer = "
3466             << m_targetLayer
3467             << ";\n"
3468                "    v_frag_FragColor = white;\n"
3469                "    EmitVertex();\n";
3470     }
3471     else if (m_test == TEST_ALL_LAYERS || m_test == TEST_LAYER_ID)
3472     {
3473         DE_ASSERT(m_numLayers <= 6);
3474 
3475         buf << "    const highp vec4 white   = vec4(1.0, 1.0, 1.0, 1.0);\n"
3476                "    const highp vec4 red     = vec4(1.0, 0.0, 0.0, 1.0);\n"
3477                "    const highp vec4 green   = vec4(0.0, 1.0, 0.0, 1.0);\n"
3478                "    const highp vec4 blue    = vec4(0.0, 0.0, 1.0, 1.0);\n"
3479                "    const highp vec4 yellow  = vec4(1.0, 1.0, 0.0, 1.0);\n"
3480                "    const highp vec4 magenta = vec4(1.0, 0.0, 1.0, 1.0);\n"
3481                "    const highp vec4 colors[6] = vec4[6](white, red, green, blue, yellow, magenta);\n\n"
3482                "    for (mediump int layerNdx = 0; layerNdx < "
3483             << m_numLayers
3484             << "; ++layerNdx)\n"
3485                "    {\n"
3486                "        gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
3487                "        gl_Layer = layerNdx;\n"
3488                "        v_frag_FragColor = colors[layerNdx];\n"
3489                "        EmitVertex();\n\n"
3490                "        gl_Position = vec4(-1.0,  1.0, 0.0, 1.0);\n"
3491                "        gl_Layer = layerNdx;\n"
3492                "        v_frag_FragColor = colors[layerNdx];\n"
3493                "        EmitVertex();\n\n"
3494                "        gl_Position = vec4( 0.0, -1.0, 0.0, 1.0);\n"
3495                "        gl_Layer = layerNdx;\n"
3496                "        v_frag_FragColor = colors[layerNdx];\n"
3497                "        EmitVertex();\n\n"
3498                "        gl_Position = vec4( 0.0,  1.0, 0.0, 1.0);\n"
3499                "        gl_Layer = layerNdx;\n"
3500                "        v_frag_FragColor = colors[layerNdx];\n"
3501                "        EmitVertex();\n"
3502                "        EndPrimitive();\n"
3503                "    }\n";
3504     }
3505     else if (m_test == TEST_DIFFERENT_LAYERS)
3506     {
3507         DE_ASSERT(m_numLayers <= 6);
3508 
3509         buf << "    const highp vec4 white = vec4(1.0, 1.0, 1.0, 1.0);\n\n"
3510                "    for (mediump int layerNdx = 0; layerNdx < "
3511             << m_numLayers
3512             << "; ++layerNdx)\n"
3513                "    {\n"
3514                "        for (mediump int colNdx = 0; colNdx <= layerNdx; ++colNdx)\n"
3515                "        {\n"
3516                "            highp float posX = float(colNdx) / float("
3517             << m_numLayers
3518             << ") * 2.0 - 1.0;\n\n"
3519                "            gl_Position = vec4(posX,  1.0, 0.0, 1.0);\n"
3520                "            gl_Layer = layerNdx;\n"
3521                "            v_frag_FragColor = white;\n"
3522                "            EmitVertex();\n\n"
3523                "            gl_Position = vec4(posX, -1.0, 0.0, 1.0);\n"
3524                "            gl_Layer = layerNdx;\n"
3525                "            v_frag_FragColor = white;\n"
3526                "            EmitVertex();\n"
3527                "        }\n"
3528                "        EndPrimitive();\n"
3529                "    }\n";
3530     }
3531     else if (m_test == TEST_INVOCATION_PER_LAYER)
3532     {
3533         buf << "    const highp vec4 white   = vec4(1.0, 1.0, 1.0, 1.0);\n"
3534                "    const highp vec4 red     = vec4(1.0, 0.0, 0.0, 1.0);\n"
3535                "    const highp vec4 green   = vec4(0.0, 1.0, 0.0, 1.0);\n"
3536                "    const highp vec4 blue    = vec4(0.0, 0.0, 1.0, 1.0);\n"
3537                "    const highp vec4 yellow  = vec4(1.0, 1.0, 0.0, 1.0);\n"
3538                "    const highp vec4 magenta = vec4(1.0, 0.0, 1.0, 1.0);\n"
3539                "    const highp vec4 colors[6] = vec4[6](white, red, green, blue, yellow, magenta);\n"
3540                "\n"
3541                "    gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
3542                "    gl_Layer = gl_InvocationID;\n"
3543                "    v_frag_FragColor = colors[gl_InvocationID];\n"
3544                "    EmitVertex();\n\n"
3545                "    gl_Position = vec4(-1.0,  1.0, 0.0, 1.0);\n"
3546                "    gl_Layer = gl_InvocationID;\n"
3547                "    v_frag_FragColor = colors[gl_InvocationID];\n"
3548                "    EmitVertex();\n\n"
3549                "    gl_Position = vec4( 0.0, -1.0, 0.0, 1.0);\n"
3550                "    gl_Layer = gl_InvocationID;\n"
3551                "    v_frag_FragColor = colors[gl_InvocationID];\n"
3552                "    EmitVertex();\n\n"
3553                "    gl_Position = vec4( 0.0,  1.0, 0.0, 1.0);\n"
3554                "    gl_Layer = gl_InvocationID;\n"
3555                "    v_frag_FragColor = colors[gl_InvocationID];\n"
3556                "    EmitVertex();\n"
3557                "    EndPrimitive();\n";
3558     }
3559     else if (m_test == TEST_MULTIPLE_LAYERS_PER_INVOCATION)
3560     {
3561         buf << "    const highp vec4 white = vec4(1.0, 1.0, 1.0, 1.0);\n"
3562                "\n"
3563                "    mediump int layerA = gl_InvocationID;\n"
3564                "    mediump int layerB = (gl_InvocationID + 1) % "
3565             << m_numLayers
3566             << ";\n"
3567                "    highp float aEnd = float(layerA) / float("
3568             << m_numLayers
3569             << ") * 2.0 - 1.0;\n"
3570                "    highp float bEnd = float(layerB) / float("
3571             << m_numLayers
3572             << ") * 2.0 - 1.0;\n"
3573                "\n"
3574                "    gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
3575                "    gl_Layer = layerA;\n"
3576                "    v_frag_FragColor = white;\n"
3577                "    EmitVertex();\n\n"
3578                "    gl_Position = vec4(-1.0,  1.0, 0.0, 1.0);\n"
3579                "    gl_Layer = layerA;\n"
3580                "    v_frag_FragColor = white;\n"
3581                "    EmitVertex();\n\n"
3582                "    gl_Position = vec4(aEnd, -1.0, 0.0, 1.0);\n"
3583                "    gl_Layer = layerA;\n"
3584                "    v_frag_FragColor = white;\n"
3585                "    EmitVertex();\n\n"
3586                "    EndPrimitive();\n"
3587                "\n"
3588                "    gl_Position = vec4(-1.0,  1.0, 0.0, 1.0);\n"
3589                "    gl_Layer = layerB;\n"
3590                "    v_frag_FragColor = white;\n"
3591                "    EmitVertex();\n\n"
3592                "    gl_Position = vec4(bEnd,  1.0, 0.0, 1.0);\n"
3593                "    gl_Layer = layerB;\n"
3594                "    v_frag_FragColor = white;\n"
3595                "    EmitVertex();\n\n"
3596                "    gl_Position = vec4(bEnd, -1.0, 0.0, 1.0);\n"
3597                "    gl_Layer = layerB;\n"
3598                "    v_frag_FragColor = white;\n"
3599                "    EmitVertex();\n\n"
3600                "    EndPrimitive();\n";
3601     }
3602     else if (m_test == TEST_LAYER_PROVOKING_VERTEX)
3603     {
3604         buf << "    const highp vec4 white = vec4(1.0, 1.0, 1.0, 1.0);\n\n"
3605                "    gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
3606                "    gl_Layer = 0;\n"
3607                "    v_frag_FragColor = white;\n"
3608                "    EmitVertex();\n\n"
3609                "    gl_Position = vec4(-1.0,  1.0, 0.0, 1.0);\n"
3610                "    gl_Layer = 1;\n"
3611                "    v_frag_FragColor = white;\n"
3612                "    EmitVertex();\n\n"
3613                "    gl_Position = vec4( 0.0, -1.0, 0.0, 1.0);\n"
3614                "    gl_Layer = 1;\n"
3615                "    v_frag_FragColor = white;\n"
3616                "    EmitVertex();\n\n"
3617                "    EndPrimitive();\n\n"
3618                "    gl_Position = vec4(-1.0,  1.0, 0.0, 1.0);\n"
3619                "    gl_Layer = 0;\n"
3620                "    v_frag_FragColor = white;\n"
3621                "    EmitVertex();\n\n"
3622                "    gl_Position = vec4( 0.0, -1.0, 0.0, 1.0);\n"
3623                "    gl_Layer = 1;\n"
3624                "    v_frag_FragColor = white;\n"
3625                "    EmitVertex();\n\n"
3626                "    gl_Position = vec4( 0.0,  1.0, 0.0, 1.0);\n"
3627                "    gl_Layer = 1;\n"
3628                "    v_frag_FragColor = white;\n"
3629                "    EmitVertex();\n";
3630     }
3631     else
3632         DE_ASSERT(false);
3633 
3634     buf << "}\n";
3635 
3636     return specializeShader(buf.str(), contextType);
3637 }
3638 
genSamplerFragmentSource(const glu::ContextType & contextType) const3639 std::string LayeredRenderCase::genSamplerFragmentSource(const glu::ContextType &contextType) const
3640 {
3641     std::ostringstream buf;
3642 
3643     buf << "${GLSL_VERSION_DECL}\n";
3644     if (m_target == TARGET_2D_MS_ARRAY)
3645         buf << "${GLSL_OES_TEXTURE_STORAGE_MULTISAMPLE}";
3646     buf << "layout(location = 0) out mediump vec4 fragColor;\n";
3647 
3648     switch (m_target)
3649     {
3650     case TARGET_CUBE:
3651         buf << "uniform highp samplerCube u_sampler;\n";
3652         break;
3653     case TARGET_3D:
3654         buf << "uniform highp sampler3D u_sampler;\n";
3655         break;
3656     case TARGET_2D_ARRAY:
3657         buf << "uniform highp sampler2DArray u_sampler;\n";
3658         break;
3659     case TARGET_1D_ARRAY:
3660         buf << "uniform highp sampler1DArray u_sampler;\n";
3661         break;
3662     case TARGET_2D_MS_ARRAY:
3663         buf << "uniform highp sampler2DMSArray u_sampler;\n";
3664         break;
3665     default:
3666         DE_ASSERT(false);
3667     }
3668 
3669     buf << "uniform highp int u_layer;\n"
3670            "void main (void)\n"
3671            "{\n";
3672 
3673     switch (m_target)
3674     {
3675     case TARGET_CUBE:
3676         buf << "    highp vec2 facepos = 2.0 * gl_FragCoord.xy / vec2(ivec2(" << m_resolveDimensions.x() << ", "
3677             << m_resolveDimensions.y()
3678             << ")) - vec2(1.0, 1.0);\n"
3679                "    if (u_layer == 0)\n"
3680                "        fragColor = textureLod(u_sampler, vec3(1.0, -facepos.y, -facepos.x), 0.0);\n"
3681                "    else if (u_layer == 1)\n"
3682                "        fragColor = textureLod(u_sampler, vec3(-1.0, -facepos.y, facepos.x), 0.0);\n"
3683                "    else if (u_layer == 2)\n"
3684                "        fragColor = textureLod(u_sampler, vec3(facepos.x, 1.0, facepos.y), 0.0);\n"
3685                "    else if (u_layer == 3)\n"
3686                "        fragColor = textureLod(u_sampler, vec3(facepos.x, -1.0, -facepos.y), 0.0);\n"
3687                "    else if (u_layer == 4)\n"
3688                "        fragColor = textureLod(u_sampler, vec3(facepos.x, -facepos.y, 1.0), 0.0);\n"
3689                "    else if (u_layer == 5)\n"
3690                "        fragColor = textureLod(u_sampler, vec3(-facepos.x, -facepos.y, -1.0), 0.0);\n"
3691                "    else\n"
3692                "        fragColor = vec4(1.0, 0.0, 1.0, 1.0);\n";
3693         break;
3694 
3695     case TARGET_3D:
3696     case TARGET_2D_ARRAY:
3697     case TARGET_2D_MS_ARRAY:
3698         buf << "    highp ivec2 screenpos = ivec2(floor(gl_FragCoord.xy));\n"
3699                "    fragColor = texelFetch(u_sampler, ivec3(screenpos, u_layer), 0);\n";
3700         break;
3701 
3702     case TARGET_1D_ARRAY:
3703         buf << "    highp ivec2 screenpos = ivec2(floor(gl_FragCoord.xy));\n"
3704                "    fragColor = texelFetch(u_sampler, ivec2(screenpos.x, u_layer), 0);\n";
3705         break;
3706 
3707     default:
3708         DE_ASSERT(false);
3709     }
3710     buf << "}\n";
3711     return specializeShader(buf.str(), contextType);
3712 }
3713 
renderToTexture(void)3714 void LayeredRenderCase::renderToTexture(void)
3715 {
3716     const tcu::IVec3 texSize = getTargetDimensions(m_target);
3717     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3718     glu::VertexArray vao(m_context.getRenderContext());
3719 
3720     m_testCtx.getLog() << tcu::TestLog::Message << "Rendering to texture" << tcu::TestLog::EndMessage;
3721 
3722     gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
3723     gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
3724     gl.clear(GL_COLOR_BUFFER_BIT);
3725     gl.viewport(0, 0, texSize.x(), texSize.y());
3726     gl.clear(GL_COLOR_BUFFER_BIT);
3727 
3728     gl.bindVertexArray(*vao);
3729     gl.useProgram(m_renderShader->getProgram());
3730     gl.drawArrays(GL_POINTS, 0, 1);
3731     gl.useProgram(0);
3732     gl.bindVertexArray(0);
3733     gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
3734 
3735     GLU_EXPECT_NO_ERROR(gl.getError(), "render");
3736 }
3737 
sampleTextureLayer(tcu::Surface & dst,int layer)3738 void LayeredRenderCase::sampleTextureLayer(tcu::Surface &dst, int layer)
3739 {
3740     DE_ASSERT(dst.getWidth() == m_resolveDimensions.x());
3741     DE_ASSERT(dst.getHeight() == m_resolveDimensions.y());
3742 
3743     static const tcu::Vec4 fullscreenQuad[4] = {
3744         tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
3745         tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
3746         tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f),
3747         tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f),
3748     };
3749 
3750     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3751     const int positionLoc    = gl.getAttribLocation(m_samplerShader->getProgram(), "a_position");
3752     glu::VertexArray vao(m_context.getRenderContext());
3753     glu::Buffer buf(m_context.getRenderContext());
3754 
3755     m_testCtx.getLog() << tcu::TestLog::Message << "Sampling from texture layer " << layer << tcu::TestLog::EndMessage;
3756 
3757     gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
3758     gl.clear(GL_COLOR_BUFFER_BIT);
3759     gl.viewport(0, 0, m_resolveDimensions.x(), m_resolveDimensions.y());
3760     GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
3761 
3762     gl.bindBuffer(GL_ARRAY_BUFFER, *buf);
3763     gl.bufferData(GL_ARRAY_BUFFER, sizeof(fullscreenQuad), fullscreenQuad, GL_STATIC_DRAW);
3764     GLU_EXPECT_NO_ERROR(gl.getError(), "buf");
3765 
3766     gl.bindVertexArray(*vao);
3767     gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
3768     gl.enableVertexAttribArray(positionLoc);
3769     GLU_EXPECT_NO_ERROR(gl.getError(), "setup attribs");
3770 
3771     gl.activeTexture(GL_TEXTURE0);
3772     gl.bindTexture(getTargetTextureTarget(m_target), m_texture);
3773     GLU_EXPECT_NO_ERROR(gl.getError(), "bind texture");
3774 
3775     gl.useProgram(m_samplerShader->getProgram());
3776     gl.uniform1i(m_samplerLayerLoc, layer);
3777     gl.uniform1i(m_samplerSamplerLoc, 0);
3778     GLU_EXPECT_NO_ERROR(gl.getError(), "setup program");
3779 
3780     gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
3781     GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
3782 
3783     gl.useProgram(0);
3784     gl.bindVertexArray(0);
3785     GLU_EXPECT_NO_ERROR(gl.getError(), "clean");
3786 
3787     glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
3788 }
3789 
verifyLayerContent(const tcu::Surface & layer,int layerNdx)3790 bool LayeredRenderCase::verifyLayerContent(const tcu::Surface &layer, int layerNdx)
3791 {
3792     const tcu::Vec4 white     = tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
3793     const tcu::Vec4 red       = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
3794     const tcu::Vec4 green     = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
3795     const tcu::Vec4 blue      = tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
3796     const tcu::Vec4 yellow    = tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f);
3797     const tcu::Vec4 magenta   = tcu::Vec4(1.0f, 0.0f, 1.0f, 1.0f);
3798     const tcu::Vec4 colors[6] = {white, red, green, blue, yellow, magenta};
3799 
3800     m_testCtx.getLog() << tcu::TestLog::Message << "Verifying layer contents" << tcu::TestLog::EndMessage;
3801 
3802     switch (m_test)
3803     {
3804     case TEST_DEFAULT_LAYER:
3805         if (layerNdx == 0)
3806             return verifyImageSingleColoredRow(layer, 0.5f, white);
3807         else
3808             return verifyEmptyImage(layer);
3809 
3810     case TEST_SINGLE_LAYER:
3811         if (layerNdx == m_targetLayer)
3812             return verifyImageSingleColoredRow(layer, 0.5f, white);
3813         else
3814             return verifyEmptyImage(layer);
3815 
3816     case TEST_ALL_LAYERS:
3817     case TEST_INVOCATION_PER_LAYER:
3818         return verifyImageSingleColoredRow(layer, 0.5f, colors[layerNdx]);
3819 
3820     case TEST_DIFFERENT_LAYERS:
3821     case TEST_MULTIPLE_LAYERS_PER_INVOCATION:
3822         if (layerNdx == 0)
3823             return verifyEmptyImage(layer);
3824         else
3825             return verifyImageSingleColoredRow(layer, (float)layerNdx / (float)m_numLayers, white);
3826 
3827     case TEST_LAYER_ID:
3828     {
3829         const tcu::Vec4 layerColor((layerNdx % 2 == 1) ? (1.0f) : (0.5f), ((layerNdx / 2) % 2 == 1) ? (1.0f) : (0.5f),
3830                                    (layerNdx == 0) ? (1.0f) : (0.0f), 1.0f);
3831         return verifyImageSingleColoredRow(layer, 0.5f, layerColor);
3832     }
3833 
3834     case TEST_LAYER_PROVOKING_VERTEX:
3835         if (m_provokingVertex == GL_FIRST_VERTEX_CONVENTION)
3836         {
3837             if (layerNdx == 0)
3838                 return verifyImageSingleColoredRow(layer, 0.5f, white);
3839             else
3840                 return verifyEmptyImage(layer);
3841         }
3842         else if (m_provokingVertex == GL_LAST_VERTEX_CONVENTION)
3843         {
3844             if (layerNdx == 1)
3845                 return verifyImageSingleColoredRow(layer, 0.5f, white);
3846             else
3847                 return verifyEmptyImage(layer);
3848         }
3849         else
3850         {
3851             DE_ASSERT(false);
3852             return false;
3853         }
3854 
3855     default:
3856         DE_ASSERT(false);
3857         return false;
3858     }
3859 }
3860 
verifyImageSingleColoredRow(const tcu::Surface & layer,float rowWidthRatio,const tcu::Vec4 & barColor,bool logging)3861 bool LayeredRenderCase::verifyImageSingleColoredRow(const tcu::Surface &layer, float rowWidthRatio,
3862                                                     const tcu::Vec4 &barColor, bool logging)
3863 {
3864     DE_ASSERT(rowWidthRatio > 0.0f);
3865 
3866     const int barLength          = (int)(rowWidthRatio * (float)layer.getWidth());
3867     const int barLengthThreshold = 1;
3868     tcu::Surface errorMask(layer.getWidth(), layer.getHeight());
3869     bool allPixelsOk = true;
3870 
3871     if (logging)
3872         m_testCtx.getLog() << tcu::TestLog::Message << "Expecting all pixels with distance less or equal to (about) "
3873                            << barLength << " pixels from left border to be of color " << barColor.swizzle(0, 1, 2)
3874                            << "." << tcu::TestLog::EndMessage;
3875 
3876     tcu::clear(errorMask.getAccess(), tcu::RGBA::green().toIVec());
3877 
3878     for (int y = 0; y < layer.getHeight(); ++y)
3879         for (int x = 0; x < layer.getWidth(); ++x)
3880         {
3881             const tcu::RGBA color    = layer.getPixel(x, y);
3882             const tcu::RGBA refColor = tcu::RGBA(barColor);
3883             const int threshold      = 8;
3884             const bool isBlack =
3885                 color.getRed() <= threshold || color.getGreen() <= threshold || color.getBlue() <= threshold;
3886             const bool isColor = tcu::allEqual(
3887                 tcu::lessThan(tcu::abs(color.toIVec().swizzle(0, 1, 2) - refColor.toIVec().swizzle(0, 1, 2)),
3888                               tcu::IVec3(threshold, threshold, threshold)),
3889                 tcu::BVec3(true, true, true));
3890 
3891             bool isOk;
3892 
3893             if (x <= barLength - barLengthThreshold)
3894                 isOk = isColor;
3895             else if (x >= barLength + barLengthThreshold)
3896                 isOk = isBlack;
3897             else
3898                 isOk = isColor || isBlack;
3899 
3900             allPixelsOk &= isOk;
3901 
3902             if (!isOk)
3903                 errorMask.setPixel(x, y, tcu::RGBA::red());
3904         }
3905 
3906     if (allPixelsOk)
3907     {
3908         if (logging)
3909             m_testCtx.getLog() << tcu::TestLog::Message << "Image is valid." << tcu::TestLog::EndMessage
3910                                << tcu::TestLog::ImageSet("LayerContent", "Layer content")
3911                                << tcu::TestLog::Image("Layer", "Layer", layer) << tcu::TestLog::EndImageSet;
3912         return true;
3913     }
3914     else
3915     {
3916         if (logging)
3917             m_testCtx.getLog() << tcu::TestLog::Message << "Image verification failed. Got unexpected pixels."
3918                                << tcu::TestLog::EndMessage << tcu::TestLog::ImageSet("LayerContent", "Layer content")
3919                                << tcu::TestLog::Image("Layer", "Layer", layer)
3920                                << tcu::TestLog::Image("ErrorMask", "Errors", errorMask) << tcu::TestLog::EndImageSet;
3921         return false;
3922     }
3923 
3924     // Note: never reached
3925     if (logging)
3926         m_testCtx.getLog() << tcu::TestLog::Image("LayerContent", "Layer content", layer);
3927 
3928     return allPixelsOk;
3929 }
3930 
verifyEmptyImage(const tcu::Surface & layer,bool logging)3931 bool LayeredRenderCase::verifyEmptyImage(const tcu::Surface &layer, bool logging)
3932 {
3933     // Expect black
3934     if (logging)
3935         m_testCtx.getLog() << tcu::TestLog::Message << "Expecting empty image" << tcu::TestLog::EndMessage;
3936 
3937     for (int y = 0; y < layer.getHeight(); ++y)
3938         for (int x = 0; x < layer.getWidth(); ++x)
3939         {
3940             const tcu::RGBA color = layer.getPixel(x, y);
3941             const int threshold   = 8;
3942             const bool isBlack =
3943                 color.getRed() <= threshold || color.getGreen() <= threshold || color.getBlue() <= threshold;
3944 
3945             if (!isBlack)
3946             {
3947                 if (logging)
3948                     m_testCtx.getLog() << tcu::TestLog::Message << "Found (at least) one bad pixel at " << x << "," << y
3949                                        << ". Pixel color is not background color." << tcu::TestLog::EndMessage
3950                                        << tcu::TestLog::ImageSet("LayerContent", "Layer content")
3951                                        << tcu::TestLog::Image("Layer", "Layer", layer) << tcu::TestLog::EndImageSet;
3952                 return false;
3953             }
3954         }
3955 
3956     if (logging)
3957         m_testCtx.getLog() << tcu::TestLog::Message << "Image is valid" << tcu::TestLog::EndMessage;
3958 
3959     return true;
3960 }
3961 
verifyProvokingVertexLayers(const tcu::Surface & layer0,const tcu::Surface & layer1)3962 bool LayeredRenderCase::verifyProvokingVertexLayers(const tcu::Surface &layer0, const tcu::Surface &layer1)
3963 {
3964     const bool layer0Empty = verifyEmptyImage(layer0, false);
3965     const bool layer1Empty = verifyEmptyImage(layer1, false);
3966     bool error             = false;
3967 
3968     // Both images could contain something if the quad triangles get assigned to different layers
3969     m_testCtx.getLog() << tcu::TestLog::Message << "Expecting non-empty layers, or non-empty layer."
3970                        << tcu::TestLog::EndMessage;
3971 
3972     if (layer0Empty == true && layer1Empty == true)
3973     {
3974         m_testCtx.getLog() << tcu::TestLog::Message << "Got empty images." << tcu::TestLog::EndMessage;
3975         error = true;
3976     }
3977 
3978     // log images always
3979     m_testCtx.getLog() << tcu::TestLog::ImageSet("LayerContent", "Layer content")
3980                        << tcu::TestLog::Image("Layer", "Layer0", layer0)
3981                        << tcu::TestLog::Image("Layer", "Layer1", layer1) << tcu::TestLog::EndImageSet;
3982 
3983     if (error)
3984         m_testCtx.getLog() << tcu::TestLog::Message << "Image verification failed." << tcu::TestLog::EndMessage;
3985     else
3986         m_testCtx.getLog() << tcu::TestLog::Message << "Image is valid." << tcu::TestLog::EndMessage;
3987 
3988     return !error;
3989 }
3990 
getTargetLayers(LayeredRenderTargetType target)3991 int LayeredRenderCase::getTargetLayers(LayeredRenderTargetType target)
3992 {
3993     switch (target)
3994     {
3995     case TARGET_CUBE:
3996         return 6;
3997     case TARGET_3D:
3998         return 4;
3999     case TARGET_1D_ARRAY:
4000         return 4;
4001     case TARGET_2D_ARRAY:
4002         return 4;
4003     case TARGET_2D_MS_ARRAY:
4004         return 2;
4005     default:
4006         DE_ASSERT(false);
4007         return 0;
4008     }
4009 }
4010 
getTargetTextureTarget(LayeredRenderTargetType target)4011 glw::GLenum LayeredRenderCase::getTargetTextureTarget(LayeredRenderTargetType target)
4012 {
4013     switch (target)
4014     {
4015     case TARGET_CUBE:
4016         return GL_TEXTURE_CUBE_MAP;
4017     case TARGET_3D:
4018         return GL_TEXTURE_3D;
4019     case TARGET_1D_ARRAY:
4020         return GL_TEXTURE_1D_ARRAY;
4021     case TARGET_2D_ARRAY:
4022         return GL_TEXTURE_2D_ARRAY;
4023     case TARGET_2D_MS_ARRAY:
4024         return GL_TEXTURE_2D_MULTISAMPLE_ARRAY;
4025     default:
4026         DE_ASSERT(false);
4027         return 0;
4028     }
4029 }
4030 
getTargetDimensions(LayeredRenderTargetType target)4031 tcu::IVec3 LayeredRenderCase::getTargetDimensions(LayeredRenderTargetType target)
4032 {
4033     switch (target)
4034     {
4035     case TARGET_CUBE:
4036         return tcu::IVec3(64, 64, 0);
4037     case TARGET_3D:
4038         return tcu::IVec3(64, 64, 4);
4039     case TARGET_1D_ARRAY:
4040         return tcu::IVec3(64, 4, 0);
4041     case TARGET_2D_ARRAY:
4042         return tcu::IVec3(64, 64, 4);
4043     case TARGET_2D_MS_ARRAY:
4044         return tcu::IVec3(64, 64, 2);
4045     default:
4046         DE_ASSERT(false);
4047         return tcu::IVec3(0, 0, 0);
4048     }
4049 }
4050 
getResolveDimensions(LayeredRenderTargetType target)4051 tcu::IVec2 LayeredRenderCase::getResolveDimensions(LayeredRenderTargetType target)
4052 {
4053     switch (target)
4054     {
4055     case TARGET_CUBE:
4056         return tcu::IVec2(64, 64);
4057     case TARGET_3D:
4058         return tcu::IVec2(64, 64);
4059     case TARGET_1D_ARRAY:
4060         return tcu::IVec2(64, 1);
4061     case TARGET_2D_ARRAY:
4062         return tcu::IVec2(64, 64);
4063     case TARGET_2D_MS_ARRAY:
4064         return tcu::IVec2(64, 64);
4065     default:
4066         DE_ASSERT(false);
4067         return tcu::IVec2(0, 0);
4068     }
4069 }
4070 
4071 class VaryingOutputCountCase : public GeometryShaderRenderTest
4072 {
4073 public:
4074     enum ShaderInstancingMode
4075     {
4076         MODE_WITHOUT_INSTANCING = 0,
4077         MODE_WITH_INSTANCING,
4078 
4079         MODE_LAST
4080     };
4081     VaryingOutputCountCase(Context &context, const char *name, const char *desc,
4082                            VaryingOutputCountShader::VaryingSource test, ShaderInstancingMode mode);
4083 
4084 private:
4085     void init(void);
4086     void deinit(void);
4087     void preRender(sglr::Context &ctx, GLuint programID);
4088 
4089     sglr::ShaderProgram &getProgram(void);
4090     void genVertexAttribData(void);
4091     void genVertexDataWithoutInstancing(void);
4092     void genVertexDataWithInstancing(void);
4093 
4094     VaryingOutputCountShader *m_program;
4095     const VaryingOutputCountShader::VaryingSource m_test;
4096     const ShaderInstancingMode m_mode;
4097     int m_maxEmitCount;
4098 };
4099 
VaryingOutputCountCase(Context & context,const char * name,const char * desc,VaryingOutputCountShader::VaryingSource test,ShaderInstancingMode mode)4100 VaryingOutputCountCase::VaryingOutputCountCase(Context &context, const char *name, const char *desc,
4101                                                VaryingOutputCountShader::VaryingSource test, ShaderInstancingMode mode)
4102     : GeometryShaderRenderTest(context, name, desc, GL_POINTS, GL_TRIANGLE_STRIP,
4103                                VaryingOutputCountShader::getAttributeName(test))
4104     , m_program(DE_NULL)
4105     , m_test(test)
4106     , m_mode(mode)
4107     , m_maxEmitCount(0)
4108 {
4109     DE_ASSERT(mode < MODE_LAST);
4110 }
4111 
init(void)4112 void VaryingOutputCountCase::init(void)
4113 {
4114     // Check requirements
4115 
4116     if (!checkSupport(m_context))
4117         TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
4118 
4119     if (m_test == VaryingOutputCountShader::READ_TEXTURE)
4120     {
4121         glw::GLint maxTextures = 0;
4122 
4123         m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS, &maxTextures);
4124 
4125         m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS = " << maxTextures
4126                            << tcu::TestLog::EndMessage;
4127 
4128         if (maxTextures < 1)
4129             throw tcu::NotSupportedError("Geometry shader texture units required");
4130     }
4131 
4132     // Get max emit count
4133     {
4134         const int componentsPerVertex = 4 + 4; // vec4 pos, vec4 color
4135         glw::GLint maxVertices        = 0;
4136         glw::GLint maxComponents      = 0;
4137 
4138         m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, &maxVertices);
4139         m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS,
4140                                                                 &maxComponents);
4141 
4142         m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_OUTPUT_VERTICES = " << maxVertices
4143                            << tcu::TestLog::EndMessage;
4144         m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS = " << maxComponents
4145                            << tcu::TestLog::EndMessage;
4146         m_testCtx.getLog() << tcu::TestLog::Message << "Components per vertex = " << componentsPerVertex
4147                            << tcu::TestLog::EndMessage;
4148 
4149         if (maxVertices < 256)
4150             throw tcu::TestError("MAX_GEOMETRY_OUTPUT_VERTICES was less than minimum required (256)");
4151         if (maxComponents < 1024)
4152             throw tcu::TestError("MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS was less than minimum required (1024)");
4153 
4154         m_maxEmitCount = de::min(maxVertices, maxComponents / componentsPerVertex);
4155     }
4156 
4157     // Log what the test tries to do
4158 
4159     m_testCtx.getLog() << tcu::TestLog::Message << "Rendering 4 n-gons with n = "
4160                        << ((VaryingOutputCountShader::EMIT_COUNT_VERTEX_0 == -1) ?
4161                                (m_maxEmitCount) :
4162                                (VaryingOutputCountShader::EMIT_COUNT_VERTEX_0))
4163                        << ", "
4164                        << ((VaryingOutputCountShader::EMIT_COUNT_VERTEX_1 == -1) ?
4165                                (m_maxEmitCount) :
4166                                (VaryingOutputCountShader::EMIT_COUNT_VERTEX_1))
4167                        << ", "
4168                        << ((VaryingOutputCountShader::EMIT_COUNT_VERTEX_2 == -1) ?
4169                                (m_maxEmitCount) :
4170                                (VaryingOutputCountShader::EMIT_COUNT_VERTEX_2))
4171                        << ", and "
4172                        << ((VaryingOutputCountShader::EMIT_COUNT_VERTEX_3 == -1) ?
4173                                (m_maxEmitCount) :
4174                                (VaryingOutputCountShader::EMIT_COUNT_VERTEX_3))
4175                        << ".\n"
4176                        << "N is supplied to the geomery shader with "
4177                        << ((m_test == VaryingOutputCountShader::READ_ATTRIBUTE) ? ("attribute") :
4178                            (m_test == VaryingOutputCountShader::READ_UNIFORM)   ? ("uniform") :
4179                                                                                   ("texture"))
4180                        << tcu::TestLog::EndMessage;
4181 
4182     // Gen shader
4183     {
4184         const bool instanced = (m_mode == MODE_WITH_INSTANCING);
4185 
4186         DE_ASSERT(!m_program);
4187         m_program =
4188             new VaryingOutputCountShader(m_context.getRenderContext().getType(), m_test, m_maxEmitCount, instanced);
4189     }
4190 
4191     // Case init
4192     GeometryShaderRenderTest::init();
4193 }
4194 
deinit(void)4195 void VaryingOutputCountCase::deinit(void)
4196 {
4197     if (m_program)
4198     {
4199         delete m_program;
4200         m_program = DE_NULL;
4201     }
4202 
4203     GeometryShaderRenderTest::deinit();
4204 }
4205 
preRender(sglr::Context & ctx,GLuint programID)4206 void VaryingOutputCountCase::preRender(sglr::Context &ctx, GLuint programID)
4207 {
4208     if (m_test == VaryingOutputCountShader::READ_UNIFORM)
4209     {
4210         const int location         = ctx.getUniformLocation(programID, "u_emitCount");
4211         const int32_t emitCount[4] = {6, 0, m_maxEmitCount, 10};
4212 
4213         if (location == -1)
4214             throw tcu::TestError("uniform location of u_emitCount was -1.");
4215 
4216         ctx.uniform4iv(location, 1, emitCount);
4217     }
4218     else if (m_test == VaryingOutputCountShader::READ_TEXTURE)
4219     {
4220         const uint8_t data[4 * 4] = {
4221             255, 0, 0, 0, 0, 255, 0, 0, 0, 0, 255, 0, 0, 0, 0, 255,
4222         };
4223         const int location = ctx.getUniformLocation(programID, "u_sampler");
4224         GLuint texID       = 0;
4225 
4226         if (location == -1)
4227             throw tcu::TestError("uniform location of u_sampler was -1.");
4228         ctx.uniform1i(location, 0);
4229 
4230         // \note we don't need to explicitly delete the texture, the sglr context will delete it
4231         ctx.genTextures(1, &texID);
4232         ctx.bindTexture(GL_TEXTURE_2D, texID);
4233         ctx.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
4234         ctx.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
4235         ctx.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
4236     }
4237 }
4238 
getProgram(void)4239 sglr::ShaderProgram &VaryingOutputCountCase::getProgram(void)
4240 {
4241     return *m_program;
4242 }
4243 
genVertexAttribData(void)4244 void VaryingOutputCountCase::genVertexAttribData(void)
4245 {
4246     if (m_mode == MODE_WITHOUT_INSTANCING)
4247         genVertexDataWithoutInstancing();
4248     else if (m_mode == MODE_WITH_INSTANCING)
4249         genVertexDataWithInstancing();
4250     else
4251         DE_ASSERT(false);
4252 }
4253 
genVertexDataWithoutInstancing(void)4254 void VaryingOutputCountCase::genVertexDataWithoutInstancing(void)
4255 {
4256     m_numDrawVertices = 4;
4257 
4258     m_vertexPosData.resize(4);
4259     m_vertexAttrData.resize(4);
4260 
4261     m_vertexPosData[0] = tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f);
4262     m_vertexPosData[1] = tcu::Vec4(0.0f, 0.5f, 0.0f, 1.0f);
4263     m_vertexPosData[2] = tcu::Vec4(-0.7f, -0.1f, 0.0f, 1.0f);
4264     m_vertexPosData[3] = tcu::Vec4(-0.1f, -0.7f, 0.0f, 1.0f);
4265 
4266     if (m_test == VaryingOutputCountShader::READ_ATTRIBUTE)
4267     {
4268         m_vertexAttrData[0] = tcu::Vec4(((VaryingOutputCountShader::EMIT_COUNT_VERTEX_0 == -1) ?
4269                                              ((float)m_maxEmitCount) :
4270                                              ((float)VaryingOutputCountShader::EMIT_COUNT_VERTEX_0)),
4271                                         0.0f, 0.0f, 0.0f);
4272         m_vertexAttrData[1] = tcu::Vec4(((VaryingOutputCountShader::EMIT_COUNT_VERTEX_1 == -1) ?
4273                                              ((float)m_maxEmitCount) :
4274                                              ((float)VaryingOutputCountShader::EMIT_COUNT_VERTEX_1)),
4275                                         0.0f, 0.0f, 0.0f);
4276         m_vertexAttrData[2] = tcu::Vec4(((VaryingOutputCountShader::EMIT_COUNT_VERTEX_2 == -1) ?
4277                                              ((float)m_maxEmitCount) :
4278                                              ((float)VaryingOutputCountShader::EMIT_COUNT_VERTEX_2)),
4279                                         0.0f, 0.0f, 0.0f);
4280         m_vertexAttrData[3] = tcu::Vec4(((VaryingOutputCountShader::EMIT_COUNT_VERTEX_3 == -1) ?
4281                                              ((float)m_maxEmitCount) :
4282                                              ((float)VaryingOutputCountShader::EMIT_COUNT_VERTEX_3)),
4283                                         0.0f, 0.0f, 0.0f);
4284     }
4285     else
4286     {
4287         m_vertexAttrData[0] = tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
4288         m_vertexAttrData[1] = tcu::Vec4(1.0f, 0.0f, 0.0f, 0.0f);
4289         m_vertexAttrData[2] = tcu::Vec4(2.0f, 0.0f, 0.0f, 0.0f);
4290         m_vertexAttrData[3] = tcu::Vec4(3.0f, 0.0f, 0.0f, 0.0f);
4291     }
4292 }
4293 
genVertexDataWithInstancing(void)4294 void VaryingOutputCountCase::genVertexDataWithInstancing(void)
4295 {
4296     m_numDrawVertices = 1;
4297 
4298     m_vertexPosData.resize(1);
4299     m_vertexAttrData.resize(1);
4300 
4301     m_vertexPosData[0] = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
4302 
4303     if (m_test == VaryingOutputCountShader::READ_ATTRIBUTE)
4304     {
4305         const int emitCounts[] = {
4306             (VaryingOutputCountShader::EMIT_COUNT_VERTEX_0 == -1) ? (m_maxEmitCount) :
4307                                                                     (VaryingOutputCountShader::EMIT_COUNT_VERTEX_0),
4308             (VaryingOutputCountShader::EMIT_COUNT_VERTEX_1 == -1) ? (m_maxEmitCount) :
4309                                                                     (VaryingOutputCountShader::EMIT_COUNT_VERTEX_1),
4310             (VaryingOutputCountShader::EMIT_COUNT_VERTEX_2 == -1) ? (m_maxEmitCount) :
4311                                                                     (VaryingOutputCountShader::EMIT_COUNT_VERTEX_2),
4312             (VaryingOutputCountShader::EMIT_COUNT_VERTEX_3 == -1) ? (m_maxEmitCount) :
4313                                                                     (VaryingOutputCountShader::EMIT_COUNT_VERTEX_3),
4314         };
4315 
4316         m_vertexAttrData[0] =
4317             tcu::Vec4((float)emitCounts[0], (float)emitCounts[1], (float)emitCounts[2], (float)emitCounts[3]);
4318     }
4319     else
4320     {
4321         // not used
4322         m_vertexAttrData[0] = tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
4323     }
4324 }
4325 
4326 class GeometryProgramQueryCase : public TestCase
4327 {
4328 public:
4329     struct ProgramCase
4330     {
4331         const char *description;
4332         const char *header;
4333         int value;
4334     };
4335 
4336     GeometryProgramQueryCase(Context &context, const char *name, const char *description, glw::GLenum target);
4337 
4338     void init(void);
4339     IterateResult iterate(void);
4340 
4341 private:
4342     void expectProgramValue(uint32_t program, int value);
4343     void expectQueryError(uint32_t program);
4344 
4345     const glw::GLenum m_target;
4346 
4347 protected:
4348     std::vector<ProgramCase> m_cases;
4349 };
4350 
GeometryProgramQueryCase(Context & context,const char * name,const char * description,glw::GLenum target)4351 GeometryProgramQueryCase::GeometryProgramQueryCase(Context &context, const char *name, const char *description,
4352                                                    glw::GLenum target)
4353     : TestCase(context, name, description)
4354     , m_target(target)
4355 {
4356 }
4357 
init(void)4358 void GeometryProgramQueryCase::init(void)
4359 {
4360     if (!checkSupport(m_context))
4361         TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
4362 }
4363 
iterate(void)4364 GeometryProgramQueryCase::IterateResult GeometryProgramQueryCase::iterate(void)
4365 {
4366     const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
4367 
4368     const std::string vertexSource = std::string(glu::getGLSLVersionDeclaration(
4369                                          glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType()))) +
4370                                      "\n"
4371                                      "void main ()\n"
4372                                      "{\n"
4373                                      "    gl_Position = vec4(0.0, 0.0, 0.0, 0.0);\n"
4374                                      "}\n";
4375     const std::string fragmentSource = std::string(glu::getGLSLVersionDeclaration(
4376                                            glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType()))) +
4377                                        "\n"
4378                                        "layout(location = 0) out mediump vec4 fragColor;\n"
4379                                        "void main ()\n"
4380                                        "{\n"
4381                                        "    fragColor = vec4(0.0, 0.0, 0.0, 0.0);\n"
4382                                        "}\n";
4383     static const char *s_geometryBody = "void main ()\n"
4384                                         "{\n"
4385                                         "    gl_Position = vec4(0.0, 0.0, 0.0, 0.0);\n"
4386                                         "    EmitVertex();\n"
4387                                         "}\n";
4388 
4389     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4390 
4391     // default cases
4392     for (int ndx = 0; ndx < (int)m_cases.size(); ++ndx)
4393     {
4394         const tcu::ScopedLogSection section(m_testCtx.getLog(), "Case", m_cases[ndx].description);
4395         const std::string geometrySource = m_cases[ndx].header + std::string(s_geometryBody);
4396         const glu::ShaderProgram program(m_context.getRenderContext(),
4397                                          glu::ProgramSources()
4398                                              << glu::VertexSource(vertexSource) << glu::FragmentSource(fragmentSource)
4399                                              << glu::GeometrySource(specializeShader(
4400                                                     geometrySource, m_context.getRenderContext().getType())));
4401 
4402         m_testCtx.getLog() << program;
4403         expectProgramValue(program.getProgram(), m_cases[ndx].value);
4404     }
4405 
4406     // no geometry shader -case (INVALID OP)
4407     {
4408         const tcu::ScopedLogSection section(m_testCtx.getLog(), "NoGeometryShader", "No geometry shader");
4409         const glu::ShaderProgram program(m_context.getRenderContext(), glu::ProgramSources()
4410                                                                            << glu::VertexSource(vertexSource)
4411                                                                            << glu::FragmentSource(fragmentSource));
4412 
4413         m_testCtx.getLog() << program;
4414         expectQueryError(program.getProgram());
4415     }
4416 
4417     // not linked -case (INVALID OP)
4418     {
4419         const tcu::ScopedLogSection section(m_testCtx.getLog(), "NotLinkedProgram", "Shader program not linked");
4420         const std::string geometrySource =
4421             std::string(glu::getGLSLVersionDeclaration(
4422                 glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType()))) +
4423             "\n" + std::string(supportsES32 ? "" : "#extension GL_EXT_geometry_shader : require\n") +
4424             "layout (triangles) in;\n"
4425             "layout (points, max_vertices = 3) out;\n" +
4426             std::string(s_geometryBody);
4427 
4428         const char *const vtxSourcePtr  = vertexSource.c_str();
4429         const char *const fragSourcePtr = fragmentSource.c_str();
4430         const char *const geomSourcePtr = geometrySource.c_str();
4431 
4432         glu::Shader vertexShader(m_context.getRenderContext(), glu::SHADERTYPE_VERTEX);
4433         glu::Shader fragmentShader(m_context.getRenderContext(), glu::SHADERTYPE_FRAGMENT);
4434         glu::Shader geometryShader(m_context.getRenderContext(), glu::SHADERTYPE_GEOMETRY);
4435         glu::Program program(m_context.getRenderContext());
4436 
4437         vertexShader.setSources(1, &vtxSourcePtr, DE_NULL);
4438         fragmentShader.setSources(1, &fragSourcePtr, DE_NULL);
4439         geometryShader.setSources(1, &geomSourcePtr, DE_NULL);
4440 
4441         vertexShader.compile();
4442         fragmentShader.compile();
4443         geometryShader.compile();
4444 
4445         if (!vertexShader.getCompileStatus() || !fragmentShader.getCompileStatus() ||
4446             !geometryShader.getCompileStatus())
4447             throw tcu::TestError("Failed to compile shader");
4448 
4449         program.attachShader(vertexShader.getShader());
4450         program.attachShader(fragmentShader.getShader());
4451         program.attachShader(geometryShader.getShader());
4452 
4453         m_testCtx.getLog() << tcu::TestLog::Message << "Creating a program with geometry shader, but not linking it"
4454                            << tcu::TestLog::EndMessage;
4455 
4456         expectQueryError(program.getProgram());
4457     }
4458 
4459     return STOP;
4460 }
4461 
expectProgramValue(uint32_t program,int value)4462 void GeometryProgramQueryCase::expectProgramValue(uint32_t program, int value)
4463 {
4464     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
4465     gls::StateQueryUtil::StateQueryMemoryWriteGuard<glw::GLint> state;
4466 
4467     gl.getProgramiv(program, m_target, &state);
4468     GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramiv");
4469 
4470     m_testCtx.getLog() << tcu::TestLog::Message << glu::getProgramParamStr(m_target) << " = " << state
4471                        << tcu::TestLog::EndMessage;
4472 
4473     if (state != value)
4474     {
4475         m_testCtx.getLog() << tcu::TestLog::Message << "// ERROR: Expected " << value << ", got " << state
4476                            << tcu::TestLog::EndMessage;
4477 
4478         // don't overwrite error
4479         if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
4480             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid value");
4481     }
4482 }
4483 
expectQueryError(uint32_t program)4484 void GeometryProgramQueryCase::expectQueryError(uint32_t program)
4485 {
4486     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
4487     glw::GLint unused;
4488     glw::GLenum errorCode;
4489 
4490     m_testCtx.getLog() << tcu::TestLog::Message << "Querying " << glu::getProgramParamStr(m_target)
4491                        << ", expecting INVALID_OPERATION" << tcu::TestLog::EndMessage;
4492     gl.getProgramiv(program, m_target, &unused);
4493 
4494     errorCode = gl.getError();
4495 
4496     if (errorCode != GL_INVALID_OPERATION)
4497     {
4498         m_testCtx.getLog() << tcu::TestLog::Message << "// ERROR: Expected INVALID_OPERATION, got "
4499                            << glu::getErrorStr(errorCode) << tcu::TestLog::EndMessage;
4500 
4501         // don't overwrite error
4502         if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
4503             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got unexpected error code");
4504     }
4505 }
4506 
4507 class GeometryShaderInvocationsQueryCase : public GeometryProgramQueryCase
4508 {
4509 public:
4510     GeometryShaderInvocationsQueryCase(Context &context, const char *name, const char *description);
4511 };
4512 
GeometryShaderInvocationsQueryCase(Context & context,const char * name,const char * description)4513 GeometryShaderInvocationsQueryCase::GeometryShaderInvocationsQueryCase(Context &context, const char *name,
4514                                                                        const char *description)
4515     : GeometryProgramQueryCase(context, name, description, GL_GEOMETRY_SHADER_INVOCATIONS)
4516 {
4517     // 2 normal cases
4518     m_cases.resize(2);
4519 
4520     m_cases[0].description = "Default value";
4521     m_cases[0].header      = "${GLSL_VERSION_DECL}\n${GLSL_EXT_GEOMETRY_SHADER}layout (triangles) in;\nlayout (points, "
4522                              "max_vertices = 3) out;\n";
4523     m_cases[0].value       = 1;
4524 
4525     m_cases[1].description = "Value declared";
4526     m_cases[1].header      = "${GLSL_VERSION_DECL}\n${GLSL_EXT_GEOMETRY_SHADER}layout (triangles, invocations=2) "
4527                              "in;\nlayout (points, max_vertices = 3) out;\n";
4528     m_cases[1].value       = 2;
4529 }
4530 
4531 class GeometryShaderVerticesQueryCase : public GeometryProgramQueryCase
4532 {
4533 public:
4534     GeometryShaderVerticesQueryCase(Context &context, const char *name, const char *description);
4535 };
4536 
GeometryShaderVerticesQueryCase(Context & context,const char * name,const char * description)4537 GeometryShaderVerticesQueryCase::GeometryShaderVerticesQueryCase(Context &context, const char *name,
4538                                                                  const char *description)
4539     : GeometryProgramQueryCase(context, name, description, GL_GEOMETRY_LINKED_VERTICES_OUT_EXT)
4540 {
4541     m_cases.resize(1);
4542 
4543     m_cases[0].description = "max_vertices = 1";
4544     m_cases[0].header      = "${GLSL_VERSION_DECL}\n${GLSL_EXT_GEOMETRY_SHADER}layout (triangles) in;\nlayout (points, "
4545                              "max_vertices = 1) out;\n";
4546     m_cases[0].value       = 1;
4547 }
4548 
4549 class GeometryShaderInputQueryCase : public GeometryProgramQueryCase
4550 {
4551 public:
4552     GeometryShaderInputQueryCase(Context &context, const char *name, const char *description);
4553 };
4554 
GeometryShaderInputQueryCase(Context & context,const char * name,const char * description)4555 GeometryShaderInputQueryCase::GeometryShaderInputQueryCase(Context &context, const char *name, const char *description)
4556     : GeometryProgramQueryCase(context, name, description, GL_GEOMETRY_LINKED_INPUT_TYPE_EXT)
4557 {
4558     m_cases.resize(3);
4559 
4560     m_cases[0].description = "Triangles";
4561     m_cases[0].header      = "${GLSL_VERSION_DECL}\n${GLSL_EXT_GEOMETRY_SHADER}layout (triangles) in;\nlayout (points, "
4562                              "max_vertices = 3) out;\n";
4563     m_cases[0].value       = GL_TRIANGLES;
4564 
4565     m_cases[1].description = "Lines";
4566     m_cases[1].header =
4567         "${GLSL_VERSION_DECL}\n${GLSL_EXT_GEOMETRY_SHADER}layout (lines) in;\nlayout (points, max_vertices = 3) out;\n";
4568     m_cases[1].value = GL_LINES;
4569 
4570     m_cases[2].description = "Points";
4571     m_cases[2].header      = "${GLSL_VERSION_DECL}\n${GLSL_EXT_GEOMETRY_SHADER}layout (points) in;\nlayout (points, "
4572                              "max_vertices = 3) out;\n";
4573     m_cases[2].value       = GL_POINTS;
4574 }
4575 
4576 class GeometryShaderOutputQueryCase : public GeometryProgramQueryCase
4577 {
4578 public:
4579     GeometryShaderOutputQueryCase(Context &context, const char *name, const char *description);
4580 };
4581 
GeometryShaderOutputQueryCase(Context & context,const char * name,const char * description)4582 GeometryShaderOutputQueryCase::GeometryShaderOutputQueryCase(Context &context, const char *name,
4583                                                              const char *description)
4584     : GeometryProgramQueryCase(context, name, description, GL_GEOMETRY_LINKED_OUTPUT_TYPE_EXT)
4585 {
4586     m_cases.resize(3);
4587 
4588     m_cases[0].description = "Triangle strip";
4589     m_cases[0].header      = "${GLSL_VERSION_DECL}\n${GLSL_EXT_GEOMETRY_SHADER}layout (triangles) in;\nlayout "
4590                              "(triangle_strip, max_vertices = 3) out;\n";
4591     m_cases[0].value       = GL_TRIANGLE_STRIP;
4592 
4593     m_cases[1].description = "Lines";
4594     m_cases[1].header = "${GLSL_VERSION_DECL}\n${GLSL_EXT_GEOMETRY_SHADER}layout (triangles) in;\nlayout (line_strip, "
4595                         "max_vertices = 3) out;\n";
4596     m_cases[1].value  = GL_LINE_STRIP;
4597 
4598     m_cases[2].description = "Points";
4599     m_cases[2].header      = "${GLSL_VERSION_DECL}\n${GLSL_EXT_GEOMETRY_SHADER}layout (triangles) in;\nlayout (points, "
4600                              "max_vertices = 3) out;\n";
4601     m_cases[2].value       = GL_POINTS;
4602 }
4603 
4604 class ImplementationLimitCase : public TestCase
4605 {
4606 public:
4607     ImplementationLimitCase(Context &context, const char *name, const char *description, glw::GLenum target,
4608                             int minValue);
4609 
4610     void init(void);
4611     IterateResult iterate(void);
4612 
4613     const glw::GLenum m_target;
4614     const int m_minValue;
4615 };
4616 
ImplementationLimitCase(Context & context,const char * name,const char * description,glw::GLenum target,int minValue)4617 ImplementationLimitCase::ImplementationLimitCase(Context &context, const char *name, const char *description,
4618                                                  glw::GLenum target, int minValue)
4619     : TestCase(context, name, description)
4620     , m_target(target)
4621     , m_minValue(minValue)
4622 {
4623 }
4624 
init(void)4625 void ImplementationLimitCase::init(void)
4626 {
4627     if (!checkSupport(m_context))
4628         TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
4629 }
4630 
iterate(void)4631 ImplementationLimitCase::IterateResult ImplementationLimitCase::iterate(void)
4632 {
4633     glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
4634     tcu::ResultCollector result(m_testCtx.getLog(), " // ERROR: ");
4635 
4636     gl.enableLogging(true);
4637     verifyStateIntegerMin(result, gl, m_target, m_minValue, QUERY_INTEGER);
4638 
4639     {
4640         const tcu::ScopedLogSection section(m_testCtx.getLog(), "Types", "Alternative queries");
4641         verifyStateIntegerMin(result, gl, m_target, m_minValue, QUERY_BOOLEAN);
4642         verifyStateIntegerMin(result, gl, m_target, m_minValue, QUERY_INTEGER64);
4643         verifyStateIntegerMin(result, gl, m_target, m_minValue, QUERY_FLOAT);
4644     }
4645 
4646     result.setTestContextResult(m_testCtx);
4647     return STOP;
4648 }
4649 
4650 class LayerProvokingVertexQueryCase : public TestCase
4651 {
4652 public:
4653     LayerProvokingVertexQueryCase(Context &context, const char *name, const char *description);
4654 
4655     void init(void);
4656     IterateResult iterate(void);
4657 };
4658 
LayerProvokingVertexQueryCase(Context & context,const char * name,const char * description)4659 LayerProvokingVertexQueryCase::LayerProvokingVertexQueryCase(Context &context, const char *name,
4660                                                              const char *description)
4661     : TestCase(context, name, description)
4662 {
4663 }
4664 
init(void)4665 void LayerProvokingVertexQueryCase::init(void)
4666 {
4667     if (!checkSupport(m_context))
4668         TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
4669 }
4670 
iterate(void)4671 LayerProvokingVertexQueryCase::IterateResult LayerProvokingVertexQueryCase::iterate(void)
4672 {
4673     glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
4674     tcu::ResultCollector result(m_testCtx.getLog(), " // ERROR: ");
4675     QueriedState state;
4676 
4677     gl.enableLogging(true);
4678     queryState(result, gl, QUERY_INTEGER, GL_LAYER_PROVOKING_VERTEX, state);
4679 
4680     if (!state.isUndefined())
4681     {
4682         m_testCtx.getLog() << tcu::TestLog::Message
4683                            << "LAYER_PROVOKING_VERTEX = " << glu::getProvokingVertexStr(state.getIntAccess())
4684                            << tcu::TestLog::EndMessage;
4685 
4686         bool ok = true;
4687         std::string expectedValue;
4688 
4689         if (contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(3, 2)))
4690         {
4691             if (state.getIntAccess() != GL_FIRST_VERTEX_CONVENTION &&
4692                 state.getIntAccess() != GL_LAST_VERTEX_CONVENTION && state.getIntAccess() != GL_PROVOKING_VERTEX &&
4693                 state.getIntAccess() != GL_UNDEFINED_VERTEX)
4694             {
4695                 ok = false;
4696                 expectedValue =
4697                     "any of {FIRST_VERTEX_CONVENTION, LAST_VERTEX_CONVENTION, GL_PROVOKING_VERTEX, UNDEFINED_VERTEX}";
4698             }
4699         }
4700         else if (state.getIntAccess() != GL_FIRST_VERTEX_CONVENTION &&
4701                  state.getIntAccess() != GL_LAST_VERTEX_CONVENTION && state.getIntAccess() != GL_UNDEFINED_VERTEX)
4702         {
4703             ok            = false;
4704             expectedValue = "any of {FIRST_VERTEX_CONVENTION, LAST_VERTEX_CONVENTION, UNDEFINED_VERTEX}";
4705         }
4706 
4707         if (!ok)
4708         {
4709             m_testCtx.getLog() << tcu::TestLog::Message
4710                                << "getInteger(GL_LAYER_PROVOKING_VERTEX) returned illegal value. Got "
4711                                << state.getIntAccess() << "\n"
4712                                << "Expected " << expectedValue << "." << tcu::TestLog::EndMessage;
4713 
4714             result.fail("got unexpected provoking vertex value");
4715         }
4716 
4717         {
4718             const tcu::ScopedLogSection section(m_testCtx.getLog(), "Types", "Alternative queries");
4719             verifyStateInteger(result, gl, GL_LAYER_PROVOKING_VERTEX, state.getIntAccess(), QUERY_BOOLEAN);
4720             verifyStateInteger(result, gl, GL_LAYER_PROVOKING_VERTEX, state.getIntAccess(), QUERY_INTEGER64);
4721             verifyStateInteger(result, gl, GL_LAYER_PROVOKING_VERTEX, state.getIntAccess(), QUERY_FLOAT);
4722         }
4723     }
4724 
4725     result.setTestContextResult(m_testCtx);
4726     return STOP;
4727 }
4728 
4729 class GeometryInvocationCase : public GeometryShaderRenderTest
4730 {
4731 public:
4732     enum OutputCase
4733     {
4734         CASE_FIXED_OUTPUT_COUNTS = 0,
4735         CASE_DIFFERENT_OUTPUT_COUNTS,
4736 
4737         CASE_LAST
4738     };
4739 
4740     GeometryInvocationCase(Context &context, const char *name, const char *description, int numInvocations,
4741                            OutputCase testCase);
4742     ~GeometryInvocationCase(void);
4743 
4744     void init(void);
4745     void deinit(void);
4746 
4747 private:
4748     sglr::ShaderProgram &getProgram(void);
4749     void genVertexAttribData(void);
4750 
4751     static InvocationCountShader::OutputCase mapToShaderCaseType(OutputCase testCase);
4752 
4753     const OutputCase m_testCase;
4754     int m_numInvocations;
4755     InvocationCountShader *m_program;
4756 };
4757 
GeometryInvocationCase(Context & context,const char * name,const char * description,int numInvocations,OutputCase testCase)4758 GeometryInvocationCase::GeometryInvocationCase(Context &context, const char *name, const char *description,
4759                                                int numInvocations, OutputCase testCase)
4760     : GeometryShaderRenderTest(context, name, description, GL_POINTS, GL_TRIANGLE_STRIP, "a_color")
4761     , m_testCase(testCase)
4762     , m_numInvocations(numInvocations)
4763     , m_program(DE_NULL)
4764 {
4765     DE_ASSERT(m_testCase < CASE_LAST);
4766 }
4767 
~GeometryInvocationCase(void)4768 GeometryInvocationCase::~GeometryInvocationCase(void)
4769 {
4770     deinit();
4771 }
4772 
init(void)4773 void GeometryInvocationCase::init(void)
4774 {
4775     const glw::Functions &gl         = m_context.getRenderContext().getFunctions();
4776     int maxGeometryShaderInvocations = 0;
4777     int maxComponents                = 0;
4778 
4779     // requirements
4780 
4781     if (!checkSupport(m_context))
4782         TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
4783 
4784     gl.getIntegerv(GL_MAX_GEOMETRY_SHADER_INVOCATIONS, &maxGeometryShaderInvocations);
4785     GLU_EXPECT_NO_ERROR(gl.getError(), "getIntegerv(GL_MAX_GEOMETRY_SHADER_INVOCATIONS)");
4786 
4787     gl.getIntegerv(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS, &maxComponents);
4788     GLU_EXPECT_NO_ERROR(gl.getError(), "getIntegerv(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS)");
4789 
4790     m_testCtx.getLog() << tcu::TestLog::Message
4791                        << "GL_MAX_GEOMETRY_SHADER_INVOCATIONS = " << maxGeometryShaderInvocations
4792                        << tcu::TestLog::EndMessage;
4793 
4794     // set target num invocations
4795 
4796     if (m_numInvocations == -1)
4797         m_numInvocations = maxGeometryShaderInvocations;
4798     else if (maxGeometryShaderInvocations < m_numInvocations)
4799         throw tcu::NotSupportedError("Test requires larger GL_MAX_GEOMETRY_SHADER_INVOCATIONS");
4800 
4801     if (m_testCase == CASE_DIFFERENT_OUTPUT_COUNTS)
4802     {
4803         const int maxEmitCount  = m_numInvocations + 2;
4804         const int numComponents = 8; // pos + color
4805         if (maxEmitCount * numComponents > maxComponents)
4806             throw tcu::NotSupportedError("Test requires larger GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS");
4807     }
4808 
4809     // Log what the test tries to do
4810 
4811     if (m_testCase == CASE_FIXED_OUTPUT_COUNTS)
4812     {
4813         m_testCtx.getLog() << tcu::TestLog::Message
4814                            << "Rendering triangles in a partial circle formation with a geometry shader. Each triangle "
4815                               "is generated by a separate invocation.\n"
4816                            << "Drawing 2 points, each generating " << m_numInvocations << " triangles."
4817                            << tcu::TestLog::EndMessage;
4818     }
4819     else if (m_testCase == CASE_DIFFERENT_OUTPUT_COUNTS)
4820     {
4821         m_testCtx.getLog() << tcu::TestLog::Message
4822                            << "Rendering n-gons in a partial circle formation with a geometry shader. Each n-gon is "
4823                               "generated by a separate invocation.\n"
4824                            << "Drawing 2 points, each generating " << m_numInvocations << " n-gons."
4825                            << tcu::TestLog::EndMessage;
4826     }
4827     else
4828         DE_ASSERT(false);
4829 
4830     // resources
4831 
4832     m_program = new InvocationCountShader(m_context.getRenderContext().getType(), m_numInvocations,
4833                                           mapToShaderCaseType(m_testCase));
4834 
4835     GeometryShaderRenderTest::init();
4836 }
4837 
deinit(void)4838 void GeometryInvocationCase::deinit(void)
4839 {
4840     if (m_program)
4841     {
4842         delete m_program;
4843         m_program = DE_NULL;
4844     }
4845 
4846     GeometryShaderRenderTest::deinit();
4847 }
4848 
getProgram(void)4849 sglr::ShaderProgram &GeometryInvocationCase::getProgram(void)
4850 {
4851     return *m_program;
4852 }
4853 
genVertexAttribData(void)4854 void GeometryInvocationCase::genVertexAttribData(void)
4855 {
4856     m_vertexPosData.resize(2);
4857     m_vertexPosData[0] = tcu::Vec4(0.0f, -0.3f, 0.0f, 1.0f);
4858     m_vertexPosData[1] = tcu::Vec4(0.2f, 0.3f, 0.0f, 1.0f);
4859 
4860     m_vertexAttrData.resize(2);
4861     m_vertexAttrData[0] = tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
4862     m_vertexAttrData[1] = tcu::Vec4(0.8f, 0.8f, 0.8f, 1.0f);
4863     m_numDrawVertices   = 2;
4864 }
4865 
mapToShaderCaseType(OutputCase testCase)4866 InvocationCountShader::OutputCase GeometryInvocationCase::mapToShaderCaseType(OutputCase testCase)
4867 {
4868     switch (testCase)
4869     {
4870     case CASE_FIXED_OUTPUT_COUNTS:
4871         return InvocationCountShader::CASE_FIXED_OUTPUT_COUNTS;
4872     case CASE_DIFFERENT_OUTPUT_COUNTS:
4873         return InvocationCountShader::CASE_DIFFERENT_OUTPUT_COUNTS;
4874     default:
4875         DE_ASSERT(false);
4876         return InvocationCountShader::CASE_LAST;
4877     }
4878 }
4879 
4880 class DrawInstancedGeometryInstancedCase : public GeometryShaderRenderTest
4881 {
4882 public:
4883     DrawInstancedGeometryInstancedCase(Context &context, const char *name, const char *description, int numInstances,
4884                                        int numInvocations);
4885     ~DrawInstancedGeometryInstancedCase(void);
4886 
4887 private:
4888     void init(void);
4889     void deinit(void);
4890     sglr::ShaderProgram &getProgram(void);
4891     void genVertexAttribData(void);
4892 
4893     const int m_numInstances;
4894     const int m_numInvocations;
4895     InstancedExpansionShader *m_program;
4896 };
4897 
DrawInstancedGeometryInstancedCase(Context & context,const char * name,const char * description,int numInstances,int numInvocations)4898 DrawInstancedGeometryInstancedCase::DrawInstancedGeometryInstancedCase(Context &context, const char *name,
4899                                                                        const char *description, int numInstances,
4900                                                                        int numInvocations)
4901     : GeometryShaderRenderTest(context, name, description, GL_POINTS, GL_TRIANGLE_STRIP, "a_offset",
4902                                FLAG_DRAW_INSTANCED)
4903     , m_numInstances(numInstances)
4904     , m_numInvocations(numInvocations)
4905     , m_program(DE_NULL)
4906 {
4907 }
4908 
~DrawInstancedGeometryInstancedCase(void)4909 DrawInstancedGeometryInstancedCase::~DrawInstancedGeometryInstancedCase(void)
4910 {
4911 }
4912 
init(void)4913 void DrawInstancedGeometryInstancedCase::init(void)
4914 {
4915     m_program = new InstancedExpansionShader(m_context.getRenderContext().getType(), m_numInvocations);
4916 
4917     m_testCtx.getLog() << tcu::TestLog::Message << "Rendering a single point with " << m_numInstances << " instances. "
4918                        << "Each geometry shader is invoked " << m_numInvocations << " times for each primitive. "
4919                        << tcu::TestLog::EndMessage;
4920 
4921     GeometryShaderRenderTest::init();
4922 }
4923 
deinit(void)4924 void DrawInstancedGeometryInstancedCase::deinit(void)
4925 {
4926     if (m_program)
4927     {
4928         delete m_program;
4929         m_program = DE_NULL;
4930     }
4931 
4932     GeometryShaderRenderTest::deinit();
4933 }
4934 
getProgram(void)4935 sglr::ShaderProgram &DrawInstancedGeometryInstancedCase::getProgram(void)
4936 {
4937     return *m_program;
4938 }
4939 
genVertexAttribData(void)4940 void DrawInstancedGeometryInstancedCase::genVertexAttribData(void)
4941 {
4942     m_numDrawVertices   = 1;
4943     m_numDrawInstances  = m_numInstances;
4944     m_vertexAttrDivisor = 1;
4945 
4946     m_vertexPosData.resize(1);
4947     m_vertexAttrData.resize(8);
4948 
4949     m_vertexPosData[0] = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
4950 
4951     m_vertexAttrData[0] = tcu::Vec4(0.5f, 0.0f, 0.0f, 0.0f);
4952     m_vertexAttrData[1] = tcu::Vec4(0.0f, 0.5f, 0.0f, 0.0f);
4953     m_vertexAttrData[2] = tcu::Vec4(-0.7f, -0.1f, 0.0f, 0.0f);
4954     m_vertexAttrData[3] = tcu::Vec4(-0.1f, -0.7f, 0.0f, 0.0f);
4955     m_vertexAttrData[4] = tcu::Vec4(-0.8f, -0.7f, 0.0f, 0.0f);
4956     m_vertexAttrData[5] = tcu::Vec4(-0.9f, 0.6f, 0.0f, 0.0f);
4957     m_vertexAttrData[6] = tcu::Vec4(-0.8f, 0.3f, 0.0f, 0.0f);
4958     m_vertexAttrData[7] = tcu::Vec4(-0.1f, 0.1f, 0.0f, 0.0f);
4959 
4960     DE_ASSERT(m_numInstances <= (int)m_vertexAttrData.size());
4961 }
4962 
4963 class GeometryProgramLimitCase : public TestCase
4964 {
4965 public:
4966     GeometryProgramLimitCase(Context &context, const char *name, const char *description, glw::GLenum apiName,
4967                              const std::string &glslName, int limit);
4968 
4969 private:
4970     void init(void);
4971     IterateResult iterate(void);
4972 
4973     const glw::GLenum m_apiName;
4974     const std::string m_glslName;
4975     const int m_limit;
4976 };
4977 
GeometryProgramLimitCase(Context & context,const char * name,const char * description,glw::GLenum apiName,const std::string & glslName,int limit)4978 GeometryProgramLimitCase::GeometryProgramLimitCase(Context &context, const char *name, const char *description,
4979                                                    glw::GLenum apiName, const std::string &glslName, int limit)
4980     : TestCase(context, name, description)
4981     , m_apiName(apiName)
4982     , m_glslName(glslName)
4983     , m_limit(limit)
4984 {
4985 }
4986 
init(void)4987 void GeometryProgramLimitCase::init(void)
4988 {
4989     if (!checkSupport(m_context))
4990         TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
4991 }
4992 
iterate(void)4993 GeometryProgramLimitCase::IterateResult GeometryProgramLimitCase::iterate(void)
4994 {
4995     tcu::ResultCollector result(m_testCtx.getLog(), " // ERROR: ");
4996     int limit;
4997 
4998     // query limit
4999     {
5000         gls::StateQueryUtil::StateQueryMemoryWriteGuard<glw::GLint> state;
5001         glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
5002 
5003         gl.enableLogging(true);
5004         gl.glGetIntegerv(m_apiName, &state);
5005         GLU_EXPECT_NO_ERROR(gl.glGetError(), "getIntegerv()");
5006 
5007         m_testCtx.getLog() << tcu::TestLog::Message << glu::getGettableStateStr(m_apiName) << " = " << state
5008                            << tcu::TestLog::EndMessage;
5009 
5010         if (!state.verifyValidity(result))
5011         {
5012             result.setTestContextResult(m_testCtx);
5013             return STOP;
5014         }
5015 
5016         if (state < m_limit)
5017         {
5018             result.fail("Minimum value = " + de::toString(m_limit) + ", got " + de::toString(state.get()));
5019             result.setTestContextResult(m_testCtx);
5020             return STOP;
5021         }
5022 
5023         limit = state;
5024 
5025         // verify other getters
5026         {
5027             const tcu::ScopedLogSection section(m_testCtx.getLog(), "Types", "Alternative queries");
5028             verifyStateInteger(result, gl, m_apiName, limit, QUERY_BOOLEAN);
5029             verifyStateInteger(result, gl, m_apiName, limit, QUERY_INTEGER64);
5030             verifyStateInteger(result, gl, m_apiName, limit, QUERY_FLOAT);
5031         }
5032     }
5033 
5034     // verify limit is the same in GLSL
5035     {
5036         static const char *const vertexSource   = "${GLSL_VERSION_DECL}\n"
5037                                                   "void main ()\n"
5038                                                   "{\n"
5039                                                   "    gl_Position = vec4(0.0, 0.0, 0.0, 0.0);\n"
5040                                                   "}\n";
5041         static const char *const fragmentSource = "${GLSL_VERSION_DECL}\n"
5042                                                   "layout(location = 0) out mediump vec4 fragColor;\n"
5043                                                   "void main ()\n"
5044                                                   "{\n"
5045                                                   "    fragColor = vec4(0.0, 0.0, 0.0, 0.0);\n"
5046                                                   "}\n";
5047         const std::string geometrySource =
5048             "${GLSL_VERSION_DECL}\n"
5049             "${GLSL_EXT_GEOMETRY_SHADER}"
5050             "layout(points) in;\n"
5051             "layout(points, max_vertices = 1) out;\n"
5052             "void main ()\n"
5053             "{\n"
5054             "    // Building the shader will fail if the constant value is not the expected\n"
5055             "    const mediump int cArraySize = (gl_" +
5056             m_glslName + " == " + de::toString(limit) +
5057             ") ? (1) : (-1);\n"
5058             "    float[cArraySize] fArray;\n"
5059             "    fArray[0] = 0.0f;\n"
5060             "    gl_Position = vec4(0.0, 0.0, 0.0, fArray[0]);\n"
5061             "    EmitVertex();\n"
5062             "}\n";
5063 
5064         const de::UniquePtr<glu::ShaderProgram> program(new glu::ShaderProgram(
5065             m_context.getRenderContext(),
5066             glu::ProgramSources() << glu::VertexSource(
5067                                          specializeShader(vertexSource, m_context.getRenderContext().getType()))
5068                                   << glu::FragmentSource(
5069                                          specializeShader(fragmentSource, m_context.getRenderContext().getType()))
5070                                   << glu::GeometrySource(
5071                                          specializeShader(geometrySource, m_context.getRenderContext().getType()))));
5072 
5073         m_testCtx.getLog() << tcu::TestLog::Message << "Building a test shader to verify GLSL constant " << m_glslName
5074                            << " value." << tcu::TestLog::EndMessage;
5075         m_testCtx.getLog() << *program;
5076 
5077         if (!program->isOk())
5078         {
5079             // compile failed, assume static assert failed
5080             result.fail("Shader build failed");
5081             result.setTestContextResult(m_testCtx);
5082             return STOP;
5083         }
5084 
5085         m_testCtx.getLog() << tcu::TestLog::Message << "Build ok" << tcu::TestLog::EndMessage;
5086     }
5087 
5088     result.setTestContextResult(m_testCtx);
5089     return STOP;
5090 }
5091 
5092 class PrimitivesGeneratedQueryCase : public TestCase
5093 {
5094 public:
5095     enum QueryTest
5096     {
5097         TEST_NO_GEOMETRY = 0,
5098         TEST_NO_AMPLIFICATION,
5099         TEST_AMPLIFICATION,
5100         TEST_PARTIAL_PRIMITIVES,
5101         TEST_INSTANCED,
5102 
5103         TEST_LAST
5104     };
5105 
5106     PrimitivesGeneratedQueryCase(Context &context, const char *name, const char *description, QueryTest test);
5107     ~PrimitivesGeneratedQueryCase(void);
5108 
5109 private:
5110     void init(void);
5111     void deinit(void);
5112     IterateResult iterate(void);
5113 
5114     glu::ShaderProgram *genProgram(void);
5115 
5116     const QueryTest m_test;
5117     glu::ShaderProgram *m_program;
5118 };
5119 
PrimitivesGeneratedQueryCase(Context & context,const char * name,const char * description,QueryTest test)5120 PrimitivesGeneratedQueryCase::PrimitivesGeneratedQueryCase(Context &context, const char *name, const char *description,
5121                                                            QueryTest test)
5122     : TestCase(context, name, description)
5123     , m_test(test)
5124     , m_program(DE_NULL)
5125 {
5126     DE_ASSERT(m_test < TEST_LAST);
5127 }
5128 
~PrimitivesGeneratedQueryCase(void)5129 PrimitivesGeneratedQueryCase::~PrimitivesGeneratedQueryCase(void)
5130 {
5131     deinit();
5132 }
5133 
init(void)5134 void PrimitivesGeneratedQueryCase::init(void)
5135 {
5136     // requirements
5137 
5138     if (!checkSupport(m_context))
5139         TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
5140 
5141     // log what test tries to do
5142 
5143     if (m_test == TEST_NO_GEOMETRY)
5144         m_testCtx.getLog() << tcu::TestLog::Message
5145                            << "Querying PRIMITIVES_GENERATED while rendering without a geometry shader."
5146                            << tcu::TestLog::EndMessage;
5147     else if (m_test == TEST_NO_AMPLIFICATION)
5148         m_testCtx.getLog() << tcu::TestLog::Message
5149                            << "Querying PRIMITIVES_GENERATED while rendering with a non-amplifying geometry shader."
5150                            << tcu::TestLog::EndMessage;
5151     else if (m_test == TEST_AMPLIFICATION)
5152         m_testCtx.getLog() << tcu::TestLog::Message
5153                            << "Querying PRIMITIVES_GENERATED while rendering with a (3x) amplifying geometry shader."
5154                            << tcu::TestLog::EndMessage;
5155     else if (m_test == TEST_PARTIAL_PRIMITIVES)
5156         m_testCtx.getLog() << tcu::TestLog::Message
5157                            << "Querying PRIMITIVES_GENERATED while rendering with a geometry shader that emits also "
5158                               "partial primitives."
5159                            << tcu::TestLog::EndMessage;
5160     else if (m_test == TEST_INSTANCED)
5161         m_testCtx.getLog() << tcu::TestLog::Message
5162                            << "Querying PRIMITIVES_GENERATED while rendering with a instanced geometry shader."
5163                            << tcu::TestLog::EndMessage;
5164     else
5165         DE_ASSERT(false);
5166 
5167     // resources
5168 
5169     m_program = genProgram();
5170     m_testCtx.getLog() << *m_program;
5171 
5172     if (!m_program->isOk())
5173         throw tcu::TestError("could not build program");
5174 }
5175 
deinit(void)5176 void PrimitivesGeneratedQueryCase::deinit(void)
5177 {
5178     delete m_program;
5179     m_program = DE_NULL;
5180 }
5181 
iterate(void)5182 PrimitivesGeneratedQueryCase::IterateResult PrimitivesGeneratedQueryCase::iterate(void)
5183 {
5184     glw::GLuint primitivesGenerated = 0xDEBADBAD;
5185 
5186     m_testCtx.getLog() << tcu::TestLog::Message
5187                        << "Drawing 8 points, setting a_one for each to value (1.0, 1.0, 1.0, 1.0)"
5188                        << tcu::TestLog::EndMessage;
5189 
5190     {
5191         static const tcu::Vec4 vertexData[8 * 2] = {
5192             tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f), tcu::Vec4(0.1f, 0.0f, 0.0f, 1.0f),
5193             tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f), tcu::Vec4(0.2f, 0.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
5194             tcu::Vec4(0.3f, 0.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f), tcu::Vec4(0.4f, 0.0f, 0.0f, 1.0f),
5195             tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f), tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
5196             tcu::Vec4(0.6f, 0.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f), tcu::Vec4(0.7f, 0.0f, 0.0f, 1.0f),
5197             tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
5198         };
5199 
5200         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
5201         const glu::VertexArray vao(m_context.getRenderContext());
5202         const glu::Buffer buffer(m_context.getRenderContext());
5203         const glu::Query query(m_context.getRenderContext());
5204         const int positionLocation = gl.getAttribLocation(m_program->getProgram(), "a_position");
5205         const int oneLocation      = gl.getAttribLocation(m_program->getProgram(), "a_one");
5206 
5207         gl.bindVertexArray(*vao);
5208 
5209         gl.bindBuffer(GL_ARRAY_BUFFER, *buffer);
5210         gl.bufferData(GL_ARRAY_BUFFER, (int)sizeof(vertexData), vertexData, GL_STATIC_DRAW);
5211 
5212         gl.vertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 2 * (int)sizeof(tcu::Vec4), DE_NULL);
5213         gl.enableVertexAttribArray(positionLocation);
5214 
5215         if (oneLocation != -1)
5216         {
5217             gl.vertexAttribPointer(oneLocation, 4, GL_FLOAT, GL_FALSE, 2 * (int)sizeof(tcu::Vec4),
5218                                    glu::BufferOffsetAsPointer(1 * sizeof(tcu::Vec4)));
5219             gl.enableVertexAttribArray(oneLocation);
5220         }
5221 
5222         gl.useProgram(m_program->getProgram());
5223 
5224         GLU_EXPECT_NO_ERROR(gl.getError(), "setup render");
5225 
5226         gl.beginQuery(GL_PRIMITIVES_GENERATED, *query);
5227         gl.drawArrays(GL_POINTS, 0, 8);
5228         gl.endQuery(GL_PRIMITIVES_GENERATED);
5229 
5230         GLU_EXPECT_NO_ERROR(gl.getError(), "render and query");
5231 
5232         gl.getQueryObjectuiv(*query, GL_QUERY_RESULT, &primitivesGenerated);
5233         GLU_EXPECT_NO_ERROR(gl.getError(), "get query result");
5234     }
5235 
5236     m_testCtx.getLog() << tcu::TestLog::Message << "GL_PRIMITIVES_GENERATED = " << primitivesGenerated
5237                        << tcu::TestLog::EndMessage;
5238 
5239     {
5240         const uint32_t expectedGenerated = (m_test == TEST_AMPLIFICATION) ? (3 * 8) :
5241                                            (m_test == TEST_INSTANCED)     ? (8 * (3 + 1)) :
5242                                                                             (8);
5243 
5244         if (expectedGenerated == primitivesGenerated)
5245             m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5246         else
5247         {
5248             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got wrong result for GL_PRIMITIVES_GENERATED");
5249             m_testCtx.getLog() << tcu::TestLog::Message
5250                                << "Got unexpected result for GL_PRIMITIVES_GENERATED. Expected " << expectedGenerated
5251                                << ", got " << primitivesGenerated << tcu::TestLog::EndMessage;
5252         }
5253     }
5254 
5255     return STOP;
5256 }
5257 
genProgram(void)5258 glu::ShaderProgram *PrimitivesGeneratedQueryCase::genProgram(void)
5259 {
5260     static const char *const vertexSource   = "${GLSL_VERSION_DECL}\n"
5261                                               "in highp vec4 a_position;\n"
5262                                               "in highp vec4 a_one;\n"
5263                                               "out highp vec4 v_one;\n"
5264                                               "void main (void)\n"
5265                                               "{\n"
5266                                               "    gl_Position = a_position;\n"
5267                                               "    v_one = a_one;\n"
5268                                               "}\n";
5269     static const char *const fragmentSource = "${GLSL_VERSION_DECL}\n"
5270                                               "layout(location = 0) out mediump vec4 fragColor;\n"
5271                                               "void main (void)\n"
5272                                               "{\n"
5273                                               "    fragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
5274                                               "}\n";
5275     std::ostringstream geometrySource;
5276     glu::ProgramSources sources;
5277 
5278     if (m_test != TEST_NO_GEOMETRY)
5279     {
5280         geometrySource << "${GLSL_VERSION_DECL}\n"
5281                           "${GLSL_EXT_GEOMETRY_SHADER}"
5282                           "layout(points"
5283                        << ((m_test == TEST_INSTANCED) ? (", invocations = 3") : (""))
5284                        << ") in;\n"
5285                           "layout(triangle_strip, max_vertices = 7) out;\n"
5286                           "in highp vec4 v_one[];\n"
5287                           "void main (void)\n"
5288                           "{\n"
5289                           "    // always taken\n"
5290                           "    if (v_one[0].x != 0.0)\n"
5291                           "    {\n"
5292                           "        gl_Position = gl_in[0].gl_Position + vec4(0.0, 0.1, 0.0, 0.0);\n"
5293                           "        EmitVertex();\n"
5294                           "        gl_Position = gl_in[0].gl_Position + vec4(0.1, 0.0, 0.0, 0.0);\n"
5295                           "        EmitVertex();\n"
5296                           "        gl_Position = gl_in[0].gl_Position - vec4(0.1, 0.0, 0.0, 0.0);\n"
5297                           "        EmitVertex();\n"
5298                           "        EndPrimitive();\n"
5299                           "    }\n";
5300 
5301         if (m_test == TEST_AMPLIFICATION)
5302         {
5303             geometrySource << "\n"
5304                               "    // always taken\n"
5305                               "    if (v_one[0].y != 0.0)\n"
5306                               "    {\n"
5307                               "        gl_Position = gl_in[0].gl_Position + vec4(0.0, 0.1, 0.0, 0.0);\n"
5308                               "        EmitVertex();\n"
5309                               "        gl_Position = gl_in[0].gl_Position + vec4(0.1, 0.0, 0.0, 0.0);\n"
5310                               "        EmitVertex();\n"
5311                               "        gl_Position = gl_in[0].gl_Position - vec4(0.0, 0.1, 0.0, 0.0);\n"
5312                               "        EmitVertex();\n"
5313                               "        gl_Position = gl_in[0].gl_Position - vec4(0.1, 0.0, 0.0, 0.0);\n"
5314                               "        EmitVertex();\n"
5315                               "    }\n";
5316         }
5317         else if (m_test == TEST_PARTIAL_PRIMITIVES)
5318         {
5319             geometrySource << "\n"
5320                               "    // always taken\n"
5321                               "    if (v_one[0].y != 0.0)\n"
5322                               "    {\n"
5323                               "        gl_Position = gl_in[0].gl_Position + vec4(0.0, 0.1, 0.0, 0.0);\n"
5324                               "        EmitVertex();\n"
5325                               "        gl_Position = gl_in[0].gl_Position + vec4(0.1, 0.0, 0.0, 0.0);\n"
5326                               "        EmitVertex();\n"
5327                               "\n"
5328                               "        // never taken\n"
5329                               "        if (v_one[0].z < 0.0)\n"
5330                               "        {\n"
5331                               "            gl_Position = gl_in[0].gl_Position - vec4(0.1, 0.0, 0.0, 0.0);\n"
5332                               "            EmitVertex();\n"
5333                               "        }\n"
5334                               "    }\n";
5335         }
5336         else if (m_test == TEST_INSTANCED)
5337         {
5338             geometrySource << "\n"
5339                               "    // taken once\n"
5340                               "    if (v_one[0].y > float(gl_InvocationID) + 0.5)\n"
5341                               "    {\n"
5342                               "        gl_Position = gl_in[0].gl_Position + vec4(0.0, 0.1, 0.0, 0.0);\n"
5343                               "        EmitVertex();\n"
5344                               "        gl_Position = gl_in[0].gl_Position + vec4(0.1, 0.0, 0.0, 0.0);\n"
5345                               "        EmitVertex();\n"
5346                               "        gl_Position = gl_in[0].gl_Position - vec4(0.1, 0.0, 0.0, 0.0);\n"
5347                               "        EmitVertex();\n"
5348                               "    }\n";
5349         }
5350 
5351         geometrySource << "}\n";
5352     }
5353 
5354     sources << glu::VertexSource(specializeShader(vertexSource, m_context.getRenderContext().getType()));
5355     sources << glu::FragmentSource(specializeShader(fragmentSource, m_context.getRenderContext().getType()));
5356 
5357     if (!geometrySource.str().empty())
5358         sources << glu::GeometrySource(specializeShader(geometrySource.str(), m_context.getRenderContext().getType()));
5359 
5360     return new glu::ShaderProgram(m_context.getRenderContext(), sources);
5361 }
5362 
5363 class PrimitivesGeneratedQueryObjectQueryCase : public TestCase
5364 {
5365 public:
5366     PrimitivesGeneratedQueryObjectQueryCase(Context &context, const char *name, const char *description);
5367 
5368     void init(void);
5369     IterateResult iterate(void);
5370 };
5371 
PrimitivesGeneratedQueryObjectQueryCase(Context & context,const char * name,const char * description)5372 PrimitivesGeneratedQueryObjectQueryCase::PrimitivesGeneratedQueryObjectQueryCase(Context &context, const char *name,
5373                                                                                  const char *description)
5374     : TestCase(context, name, description)
5375 {
5376 }
5377 
init(void)5378 void PrimitivesGeneratedQueryObjectQueryCase::init(void)
5379 {
5380     if (!checkSupport(m_context))
5381         TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
5382 }
5383 
iterate(void)5384 PrimitivesGeneratedQueryObjectQueryCase::IterateResult PrimitivesGeneratedQueryObjectQueryCase::iterate(void)
5385 {
5386     glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
5387     tcu::ResultCollector result(m_testCtx.getLog(), " // ERROR: ");
5388 
5389     gl.enableLogging(true);
5390 
5391     {
5392         glw::GLuint query = 0;
5393 
5394         verifyStateQueryInteger(result, gl, GL_PRIMITIVES_GENERATED, GL_CURRENT_QUERY, 0, QUERY_QUERY);
5395 
5396         gl.glGenQueries(1, &query);
5397         GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "glGenQueries");
5398 
5399         gl.glBeginQuery(GL_PRIMITIVES_GENERATED, query);
5400         GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "beginQuery");
5401 
5402         verifyStateQueryInteger(result, gl, GL_PRIMITIVES_GENERATED, GL_CURRENT_QUERY, (int)query, QUERY_QUERY);
5403 
5404         gl.glEndQuery(GL_PRIMITIVES_GENERATED);
5405         GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "endQuery");
5406     }
5407 
5408     result.setTestContextResult(m_testCtx);
5409     return STOP;
5410 }
5411 
5412 class GeometryShaderFeartureTestCase : public TestCase
5413 {
5414 public:
5415     GeometryShaderFeartureTestCase(Context &context, const char *name, const char *description);
5416 
5417     void init(void);
5418 };
5419 
GeometryShaderFeartureTestCase(Context & context,const char * name,const char * description)5420 GeometryShaderFeartureTestCase::GeometryShaderFeartureTestCase(Context &context, const char *name,
5421                                                                const char *description)
5422     : TestCase(context, name, description)
5423 {
5424 }
5425 
init(void)5426 void GeometryShaderFeartureTestCase::init(void)
5427 {
5428     if (!checkSupport(m_context))
5429         TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
5430 }
5431 
5432 class FramebufferDefaultLayersCase : public GeometryShaderFeartureTestCase
5433 {
5434 public:
5435     FramebufferDefaultLayersCase(Context &context, const char *name, const char *description);
5436     IterateResult iterate(void);
5437 };
5438 
FramebufferDefaultLayersCase(Context & context,const char * name,const char * description)5439 FramebufferDefaultLayersCase::FramebufferDefaultLayersCase(Context &context, const char *name, const char *description)
5440     : GeometryShaderFeartureTestCase(context, name, description)
5441 {
5442 }
5443 
iterate(void)5444 FramebufferDefaultLayersCase::IterateResult FramebufferDefaultLayersCase::iterate(void)
5445 {
5446     glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
5447 
5448     gl.enableLogging(true);
5449 
5450     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5451 
5452     {
5453         const tcu::ScopedLogSection section(m_testCtx.getLog(), "Default", "Default value");
5454         const glu::Framebuffer fbo(m_context.getRenderContext());
5455         glw::GLint defaultLayers = -1;
5456 
5457         gl.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, *fbo);
5458         gl.glGetFramebufferParameteriv(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_LAYERS, &defaultLayers);
5459         GLU_EXPECT_NO_ERROR(gl.glGetError(), "getFramebufferParameteriv");
5460 
5461         m_testCtx.getLog() << tcu::TestLog::Message << "GL_FRAMEBUFFER_DEFAULT_LAYERS = " << defaultLayers
5462                            << tcu::TestLog::EndMessage;
5463 
5464         if (defaultLayers != 0)
5465         {
5466             m_testCtx.getLog() << tcu::TestLog::Message << "Error, expected 0, got " << defaultLayers
5467                                << tcu::TestLog::EndMessage;
5468             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "invalid layer count");
5469         }
5470     }
5471 
5472     {
5473         const tcu::ScopedLogSection section(m_testCtx.getLog(), "SetTo12", "Set default layers to 12");
5474         const glu::Framebuffer fbo(m_context.getRenderContext());
5475         glw::GLint defaultLayers = -1;
5476 
5477         gl.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, *fbo);
5478         gl.glFramebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_LAYERS, 12);
5479         gl.glGetFramebufferParameteriv(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_LAYERS, &defaultLayers);
5480         GLU_EXPECT_NO_ERROR(gl.glGetError(), "getFramebufferParameteriv");
5481 
5482         m_testCtx.getLog() << tcu::TestLog::Message << "GL_FRAMEBUFFER_DEFAULT_LAYERS = " << defaultLayers
5483                            << tcu::TestLog::EndMessage;
5484 
5485         if (defaultLayers != 12)
5486         {
5487             m_testCtx.getLog() << tcu::TestLog::Message << "Error, expected 12, got " << defaultLayers
5488                                << tcu::TestLog::EndMessage;
5489             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "invalid layer count");
5490         }
5491     }
5492 
5493     return STOP;
5494 }
5495 
5496 class FramebufferAttachmentLayeredCase : public GeometryShaderFeartureTestCase
5497 {
5498 public:
5499     FramebufferAttachmentLayeredCase(Context &context, const char *name, const char *description);
5500     IterateResult iterate(void);
5501 };
5502 
FramebufferAttachmentLayeredCase(Context & context,const char * name,const char * description)5503 FramebufferAttachmentLayeredCase::FramebufferAttachmentLayeredCase(Context &context, const char *name,
5504                                                                    const char *description)
5505     : GeometryShaderFeartureTestCase(context, name, description)
5506 {
5507 }
5508 
iterate(void)5509 FramebufferAttachmentLayeredCase::IterateResult FramebufferAttachmentLayeredCase::iterate(void)
5510 {
5511     enum CaseType
5512     {
5513         TEXTURE_3D,
5514         TEXTURE_2D_ARRAY,
5515         TEXTURE_CUBE,
5516         TEXTURE_2D_MS_ARRAY,
5517         TEXTURE_3D_LAYER,
5518         TEXTURE_2D_ARRAY_LAYER,
5519     };
5520 
5521     static const struct TextureType
5522     {
5523         const char *name;
5524         const char *description;
5525         bool layered;
5526         CaseType type;
5527     } textureTypes[] = {
5528         {"3D", "3D texture", true, TEXTURE_3D},
5529         {"2DArray", "2D array", true, TEXTURE_2D_ARRAY},
5530         {"Cube", "Cube map", true, TEXTURE_CUBE},
5531         {"2DMSArray", "2D multisample array", true, TEXTURE_2D_MS_ARRAY},
5532         {"3DLayer", "3D texture layer ", false, TEXTURE_3D_LAYER},
5533         {"2DArrayLayer", "2D array layer ", false, TEXTURE_2D_ARRAY_LAYER},
5534     };
5535 
5536     glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
5537     gl.enableLogging(true);
5538 
5539     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5540 
5541     for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(textureTypes); ++ndx)
5542     {
5543         const tcu::ScopedLogSection section(m_testCtx.getLog(), textureTypes[ndx].name, textureTypes[ndx].description);
5544         const glu::Framebuffer fbo(m_context.getRenderContext());
5545         const glu::Texture texture(m_context.getRenderContext());
5546         glw::GLint layered = -1;
5547 
5548         gl.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, *fbo);
5549 
5550         if (textureTypes[ndx].type == TEXTURE_3D || textureTypes[ndx].type == TEXTURE_3D_LAYER)
5551         {
5552             gl.glBindTexture(GL_TEXTURE_3D, *texture);
5553             gl.glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 32, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, DE_NULL);
5554             gl.glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5555             gl.glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5556 
5557             if (textureTypes[ndx].type == TEXTURE_3D)
5558                 gl.glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, *texture, 0);
5559             else
5560                 gl.glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, *texture, 0, 2);
5561         }
5562         else if (textureTypes[ndx].type == TEXTURE_2D_ARRAY || textureTypes[ndx].type == TEXTURE_2D_ARRAY_LAYER)
5563         {
5564             gl.glBindTexture(GL_TEXTURE_2D_ARRAY, *texture);
5565             gl.glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 32, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, DE_NULL);
5566             gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5567             gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5568 
5569             if (textureTypes[ndx].type == TEXTURE_2D_ARRAY)
5570                 gl.glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, *texture, 0);
5571             else
5572                 gl.glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, *texture, 0, 3);
5573         }
5574         else if (textureTypes[ndx].type == TEXTURE_CUBE)
5575         {
5576             gl.glBindTexture(GL_TEXTURE_CUBE_MAP, *texture);
5577             for (int face = 0; face < 6; ++face)
5578                 gl.glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, GL_RGBA8, 32, 32, 0, GL_RGBA,
5579                                 GL_UNSIGNED_BYTE, DE_NULL);
5580             gl.glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5581             gl.glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5582             gl.glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, *texture, 0);
5583         }
5584         else if (textureTypes[ndx].type == TEXTURE_2D_MS_ARRAY)
5585         {
5586             const bool supportES32 =
5587                 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
5588             const bool supportGL45 =
5589                 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
5590 
5591             // check extension
5592             if (!(supportGL45 || (supportES32 && m_context.getContextInfo().isExtensionSupported(
5593                                                      "GL_OES_texture_storage_multisample_2d_array"))))
5594             {
5595                 m_testCtx.getLog() << tcu::TestLog::Message
5596                                    << "Context is not equal or greather than 3.2 and "
5597                                       "GL_OES_texture_storage_multisample_2d_array not supported, skipping."
5598                                    << tcu::TestLog::EndMessage;
5599                 continue;
5600             }
5601 
5602             gl.glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, *texture);
5603             gl.glTexStorage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, 1, GL_RGBA8, 32, 32, 32, GL_FALSE);
5604             gl.glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, *texture, 0);
5605         }
5606 
5607         GLU_EXPECT_NO_ERROR(gl.glGetError(), "setup attachment");
5608 
5609         gl.glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
5610                                                  GL_FRAMEBUFFER_ATTACHMENT_LAYERED, &layered);
5611         GLU_EXPECT_NO_ERROR(gl.glGetError(), "getFramebufferParameteriv");
5612 
5613         m_testCtx.getLog() << tcu::TestLog::Message
5614                            << "GL_FRAMEBUFFER_ATTACHMENT_LAYERED = " << glu::getBooleanStr(layered)
5615                            << tcu::TestLog::EndMessage;
5616 
5617         if (layered != GL_TRUE && layered != GL_FALSE)
5618         {
5619             m_testCtx.getLog() << tcu::TestLog::Message << "Error, expected boolean, got " << layered
5620                                << tcu::TestLog::EndMessage;
5621             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "invalid boolean");
5622         }
5623         else if ((layered == GL_TRUE) != textureTypes[ndx].layered)
5624         {
5625             m_testCtx.getLog() << tcu::TestLog::Message << "Error, expected "
5626                                << ((textureTypes[ndx].layered) ? ("GL_TRUE") : ("GL_FALSE")) << ", got "
5627                                << glu::getBooleanStr(layered) << tcu::TestLog::EndMessage;
5628             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "invalid layer count");
5629         }
5630     }
5631 
5632     return STOP;
5633 }
5634 
5635 class FramebufferIncompleteLayereTargetsCase : public GeometryShaderFeartureTestCase
5636 {
5637 public:
5638     FramebufferIncompleteLayereTargetsCase(Context &context, const char *name, const char *description);
5639     IterateResult iterate(void);
5640 };
5641 
FramebufferIncompleteLayereTargetsCase(Context & context,const char * name,const char * description)5642 FramebufferIncompleteLayereTargetsCase::FramebufferIncompleteLayereTargetsCase(Context &context, const char *name,
5643                                                                                const char *description)
5644     : GeometryShaderFeartureTestCase(context, name, description)
5645 {
5646 }
5647 
iterate(void)5648 FramebufferIncompleteLayereTargetsCase::IterateResult FramebufferIncompleteLayereTargetsCase::iterate(void)
5649 {
5650     glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
5651     gl.enableLogging(true);
5652 
5653     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5654 
5655     {
5656         const tcu::ScopedLogSection section(m_testCtx.getLog(), "LayerAndNonLayer", "Layered and non-layered");
5657         const glu::Framebuffer fbo(m_context.getRenderContext());
5658         const glu::Texture texture0(m_context.getRenderContext());
5659         const glu::Texture texture1(m_context.getRenderContext());
5660 
5661         glw::GLint fboStatus;
5662 
5663         gl.glBindTexture(GL_TEXTURE_2D_ARRAY, *texture0);
5664         gl.glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 32, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, DE_NULL);
5665         gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5666         gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5667 
5668         gl.glBindTexture(GL_TEXTURE_2D_ARRAY, *texture1);
5669         gl.glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 32, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, DE_NULL);
5670         gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5671         gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5672 
5673         gl.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, *fbo);
5674         gl.glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, *texture0, 0);
5675         gl.glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, *texture1, 0, 0);
5676 
5677         GLU_EXPECT_NO_ERROR(gl.glGetError(), "setup fbo");
5678 
5679         fboStatus = gl.glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
5680         m_testCtx.getLog() << tcu::TestLog::Message << "Framebuffer status: " << glu::getFramebufferStatusStr(fboStatus)
5681                            << tcu::TestLog::EndMessage;
5682 
5683         if (fboStatus != GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS)
5684         {
5685             m_testCtx.getLog() << tcu::TestLog::Message
5686                                << "Error, expected GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS, got "
5687                                << glu::getFramebufferStatusStr(fboStatus) << tcu::TestLog::EndMessage;
5688             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "invalid layer count");
5689         }
5690     }
5691 
5692     {
5693         const tcu::ScopedLogSection section(m_testCtx.getLog(), "DifferentTarget", "Different target");
5694         const glu::Framebuffer fbo(m_context.getRenderContext());
5695         const glu::Texture texture0(m_context.getRenderContext());
5696         const glu::Texture texture1(m_context.getRenderContext());
5697 
5698         glw::GLint fboStatus;
5699 
5700         gl.glBindTexture(GL_TEXTURE_2D_ARRAY, *texture0);
5701         gl.glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 32, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, DE_NULL);
5702         gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5703         gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5704 
5705         gl.glBindTexture(GL_TEXTURE_3D, *texture1);
5706         gl.glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 32, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, DE_NULL);
5707         gl.glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5708         gl.glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5709 
5710         gl.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, *fbo);
5711         gl.glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, *texture0, 0);
5712         gl.glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, *texture1, 0);
5713 
5714         GLU_EXPECT_NO_ERROR(gl.glGetError(), "setup fbo");
5715 
5716         fboStatus = gl.glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
5717         m_testCtx.getLog() << tcu::TestLog::Message << "Framebuffer status: " << glu::getFramebufferStatusStr(fboStatus)
5718                            << tcu::TestLog::EndMessage;
5719 
5720         if (fboStatus != GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS)
5721         {
5722             m_testCtx.getLog() << tcu::TestLog::Message
5723                                << "Error, expected GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS, got "
5724                                << glu::getFramebufferStatusStr(fboStatus) << tcu::TestLog::EndMessage;
5725             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "invalid layer count");
5726         }
5727     }
5728 
5729     return STOP;
5730 }
5731 
5732 class ReferencedByGeometryShaderCase : public GeometryShaderFeartureTestCase
5733 {
5734 public:
5735     ReferencedByGeometryShaderCase(Context &context, const char *name, const char *description);
5736     IterateResult iterate(void);
5737 };
5738 
ReferencedByGeometryShaderCase(Context & context,const char * name,const char * description)5739 ReferencedByGeometryShaderCase::ReferencedByGeometryShaderCase(Context &context, const char *name,
5740                                                                const char *description)
5741     : GeometryShaderFeartureTestCase(context, name, description)
5742 {
5743 }
5744 
iterate(void)5745 ReferencedByGeometryShaderCase::IterateResult ReferencedByGeometryShaderCase::iterate(void)
5746 {
5747     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5748 
5749     {
5750         static const char *const vertexSource   = "${GLSL_VERSION_DECL}\n"
5751                                                   "uniform highp vec4 u_position;\n"
5752                                                   "void main (void)\n"
5753                                                   "{\n"
5754                                                   "    gl_Position = u_position;\n"
5755                                                   "}\n";
5756         static const char *const fragmentSource = "${GLSL_VERSION_DECL}\n"
5757                                                   "layout(location = 0) out mediump vec4 fragColor;\n"
5758                                                   "void main (void)\n"
5759                                                   "{\n"
5760                                                   "    fragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
5761                                                   "}\n";
5762         static const char *const geometrySource = "${GLSL_VERSION_DECL}\n"
5763                                                   "${GLSL_EXT_GEOMETRY_SHADER}"
5764                                                   "layout(points) in;\n"
5765                                                   "layout(points, max_vertices=1) out;\n"
5766                                                   "uniform highp vec4 u_offset;\n"
5767                                                   "void main (void)\n"
5768                                                   "{\n"
5769                                                   "    gl_Position = gl_in[0].gl_Position + u_offset;\n"
5770                                                   "    EmitVertex();\n"
5771                                                   "}\n";
5772 
5773         const glu::ShaderProgram program(
5774             m_context.getRenderContext(),
5775             glu::ProgramSources() << glu::VertexSource(
5776                                          specializeShader(vertexSource, m_context.getRenderContext().getType()))
5777                                   << glu::FragmentSource(
5778                                          specializeShader(fragmentSource, m_context.getRenderContext().getType()))
5779                                   << glu::GeometrySource(
5780                                          specializeShader(geometrySource, m_context.getRenderContext().getType())));
5781         m_testCtx.getLog() << program;
5782 
5783         {
5784             const tcu::ScopedLogSection section(m_testCtx.getLog(), "ReferencedUniform", "Referenced uniform u_offset");
5785             glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
5786             const uint32_t props[1] = {GL_REFERENCED_BY_GEOMETRY_SHADER};
5787             uint32_t resourcePos;
5788             glw::GLsizei length   = 0;
5789             glw::GLint referenced = 0;
5790 
5791             gl.enableLogging(true);
5792 
5793             resourcePos = gl.glGetProgramResourceIndex(program.getProgram(), GL_UNIFORM, "u_offset");
5794             m_testCtx.getLog() << tcu::TestLog::Message << "u_offset resource index: " << resourcePos
5795                                << tcu::TestLog::EndMessage;
5796 
5797             gl.glGetProgramResourceiv(program.getProgram(), GL_UNIFORM, resourcePos, 1, props, 1, &length, &referenced);
5798             m_testCtx.getLog() << tcu::TestLog::Message << "Query GL_REFERENCED_BY_GEOMETRY_SHADER, got " << length
5799                                << " value(s), value[0] = " << glu::getBooleanStr(referenced)
5800                                << tcu::TestLog::EndMessage;
5801 
5802             GLU_EXPECT_NO_ERROR(gl.glGetError(), "query resource");
5803 
5804             if (length == 0 || referenced != GL_TRUE)
5805             {
5806                 m_testCtx.getLog() << tcu::TestLog::Message << "Error, expected GL_TRUE." << tcu::TestLog::EndMessage;
5807                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got unexpected value");
5808             }
5809         }
5810     }
5811 
5812     return STOP;
5813 }
5814 
5815 class CombinedGeometryUniformLimitCase : public GeometryShaderFeartureTestCase
5816 {
5817 public:
5818     CombinedGeometryUniformLimitCase(Context &context, const char *name, const char *desc);
5819 
5820 private:
5821     IterateResult iterate(void);
5822 };
5823 
CombinedGeometryUniformLimitCase(Context & context,const char * name,const char * desc)5824 CombinedGeometryUniformLimitCase::CombinedGeometryUniformLimitCase(Context &context, const char *name, const char *desc)
5825     : GeometryShaderFeartureTestCase(context, name, desc)
5826 {
5827 }
5828 
iterate(void)5829 CombinedGeometryUniformLimitCase::IterateResult CombinedGeometryUniformLimitCase::iterate(void)
5830 {
5831     glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
5832     tcu::ResultCollector result(m_testCtx.getLog(), " // ERROR: ");
5833 
5834     gl.enableLogging(true);
5835 
5836     m_testCtx.getLog() << tcu::TestLog::Message
5837                        << "The minimum value of MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS is "
5838                           "MAX_GEOMETRY_UNIFORM_BLOCKS x MAX_UNIFORM_BLOCK_SIZE / 4 + MAX_GEOMETRY_UNIFORM_COMPONENTS"
5839                        << tcu::TestLog::EndMessage;
5840 
5841     StateQueryMemoryWriteGuard<glw::GLint> maxUniformBlocks;
5842     gl.glGetIntegerv(GL_MAX_GEOMETRY_UNIFORM_BLOCKS, &maxUniformBlocks);
5843     GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "glGetIntegerv");
5844 
5845     StateQueryMemoryWriteGuard<glw::GLint> maxUniformBlockSize;
5846     gl.glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUniformBlockSize);
5847     GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "glGetIntegerv");
5848 
5849     StateQueryMemoryWriteGuard<glw::GLint> maxUniformComponents;
5850     gl.glGetIntegerv(GL_MAX_GEOMETRY_UNIFORM_COMPONENTS, &maxUniformComponents);
5851     GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "glGetIntegerv");
5852 
5853     if (maxUniformBlocks.verifyValidity(result) && maxUniformBlockSize.verifyValidity(result) &&
5854         maxUniformComponents.verifyValidity(result))
5855     {
5856         const int limit = ((int)maxUniformBlocks) * ((int)maxUniformBlockSize) / 4 + (int)maxUniformComponents;
5857         verifyStateIntegerMin(result, gl, GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS, limit, QUERY_INTEGER);
5858 
5859         {
5860             const tcu::ScopedLogSection section(m_testCtx.getLog(), "Types", "Alternative queries");
5861             verifyStateIntegerMin(result, gl, GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS, limit, QUERY_BOOLEAN);
5862             verifyStateIntegerMin(result, gl, GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS, limit, QUERY_INTEGER64);
5863             verifyStateIntegerMin(result, gl, GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS, limit, QUERY_FLOAT);
5864         }
5865     }
5866 
5867     result.setTestContextResult(m_testCtx);
5868     return STOP;
5869 }
5870 
5871 class VertexFeedbackCase : public TestCase
5872 {
5873 public:
5874     enum DrawMethod
5875     {
5876         METHOD_DRAW_ARRAYS = 0,
5877         METHOD_DRAW_ARRAYS_INSTANCED,
5878         METHOD_DRAW_ARRAYS_INDIRECT,
5879         METHOD_DRAW_ELEMENTS,
5880         METHOD_DRAW_ELEMENTS_INSTANCED,
5881         METHOD_DRAW_ELEMENTS_INDIRECT,
5882 
5883         METHOD_LAST
5884     };
5885     enum PrimitiveType
5886     {
5887         PRIMITIVE_LINE_LOOP = 0,
5888         PRIMITIVE_LINE_STRIP,
5889         PRIMITIVE_TRIANGLE_STRIP,
5890         PRIMITIVE_TRIANGLE_FAN,
5891         PRIMITIVE_POINTS,
5892 
5893         PRIMITIVE_LAST
5894     };
5895 
5896     VertexFeedbackCase(Context &context, const char *name, const char *description, DrawMethod method,
5897                        PrimitiveType output);
5898     ~VertexFeedbackCase(void);
5899 
5900 private:
5901     void init(void);
5902     void deinit(void);
5903     IterateResult iterate(void);
5904 
5905     glu::ShaderProgram *genProgram(void);
5906     uint32_t getOutputPrimitive(void);
5907     uint32_t getBasePrimitive(void);
5908 
5909     const DrawMethod m_method;
5910     const PrimitiveType m_output;
5911 
5912     uint32_t m_elementBuf;
5913     uint32_t m_arrayBuf;
5914     uint32_t m_offsetBuf;
5915     uint32_t m_feedbackBuf;
5916     uint32_t m_indirectBuffer;
5917     glu::ShaderProgram *m_program;
5918     glu::VertexArray *m_vao;
5919 };
5920 
VertexFeedbackCase(Context & context,const char * name,const char * description,DrawMethod method,PrimitiveType output)5921 VertexFeedbackCase::VertexFeedbackCase(Context &context, const char *name, const char *description, DrawMethod method,
5922                                        PrimitiveType output)
5923     : TestCase(context, name, description)
5924     , m_method(method)
5925     , m_output(output)
5926     , m_elementBuf(0)
5927     , m_arrayBuf(0)
5928     , m_offsetBuf(0)
5929     , m_feedbackBuf(0)
5930     , m_indirectBuffer(0)
5931     , m_program(DE_NULL)
5932     , m_vao(DE_NULL)
5933 {
5934     DE_ASSERT(method < METHOD_LAST);
5935     DE_ASSERT(output < PRIMITIVE_LAST);
5936 }
5937 
~VertexFeedbackCase(void)5938 VertexFeedbackCase::~VertexFeedbackCase(void)
5939 {
5940     deinit();
5941 }
5942 
init(void)5943 void VertexFeedbackCase::init(void)
5944 {
5945     // requirements
5946 
5947     if (!checkSupport(m_context))
5948         TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
5949 
5950     // log what test tries to do
5951 
5952     m_testCtx.getLog() << tcu::TestLog::Message << "Testing GL_EXT_geometry_shader transform feedback relaxations.\n"
5953                        << "Capturing vertex shader varying, no geometry shader. Invoke with:"
5954                        << tcu::TestLog::EndMessage;
5955 
5956     switch (m_method)
5957     {
5958     case METHOD_DRAW_ARRAYS:
5959         m_testCtx.getLog() << tcu::TestLog::Message << "Draw method: drawArrays" << tcu::TestLog::EndMessage;
5960         break;
5961     case METHOD_DRAW_ARRAYS_INSTANCED:
5962         m_testCtx.getLog() << tcu::TestLog::Message << "Draw method: drawArraysInstanced" << tcu::TestLog::EndMessage;
5963         break;
5964     case METHOD_DRAW_ARRAYS_INDIRECT:
5965         m_testCtx.getLog() << tcu::TestLog::Message << "Draw method: drawArraysIndirect" << tcu::TestLog::EndMessage;
5966         break;
5967     case METHOD_DRAW_ELEMENTS:
5968         m_testCtx.getLog() << tcu::TestLog::Message << "Draw method: drawElements" << tcu::TestLog::EndMessage;
5969         break;
5970     case METHOD_DRAW_ELEMENTS_INSTANCED:
5971         m_testCtx.getLog() << tcu::TestLog::Message << "Draw method: drawElementsInstanced" << tcu::TestLog::EndMessage;
5972         break;
5973     case METHOD_DRAW_ELEMENTS_INDIRECT:
5974         m_testCtx.getLog() << tcu::TestLog::Message << "Draw method: drawElementsIndirect" << tcu::TestLog::EndMessage;
5975         break;
5976     default:
5977         DE_ASSERT(false);
5978     }
5979     switch (m_output)
5980     {
5981     case PRIMITIVE_LINE_LOOP:
5982         m_testCtx.getLog() << tcu::TestLog::Message << "Draw primitive: line loop" << tcu::TestLog::EndMessage;
5983         break;
5984     case PRIMITIVE_LINE_STRIP:
5985         m_testCtx.getLog() << tcu::TestLog::Message << "Draw primitive: line strip" << tcu::TestLog::EndMessage;
5986         break;
5987     case PRIMITIVE_TRIANGLE_STRIP:
5988         m_testCtx.getLog() << tcu::TestLog::Message << "Draw primitive: triangle strip" << tcu::TestLog::EndMessage;
5989         break;
5990     case PRIMITIVE_TRIANGLE_FAN:
5991         m_testCtx.getLog() << tcu::TestLog::Message << "Draw primitive: triangle fan" << tcu::TestLog::EndMessage;
5992         break;
5993     case PRIMITIVE_POINTS:
5994         m_testCtx.getLog() << tcu::TestLog::Message << "Draw primitive: points" << tcu::TestLog::EndMessage;
5995         break;
5996     default:
5997         DE_ASSERT(false);
5998     }
5999 
6000     // resources
6001 
6002     {
6003         static const uint16_t elementData[] = {
6004             0,
6005             1,
6006             2,
6007             3,
6008         };
6009         static const tcu::Vec4 arrayData[] = {
6010             tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f),
6011             tcu::Vec4(1.0f, 0.0f, 0.0f, 0.0f),
6012             tcu::Vec4(2.0f, 0.0f, 0.0f, 0.0f),
6013             tcu::Vec4(3.0f, 0.0f, 0.0f, 0.0f),
6014         };
6015         static const tcu::Vec4 offsetData[] = {
6016             tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f),
6017             tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f),
6018             tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f),
6019             tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f),
6020         };
6021 
6022         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
6023         const int feedbackSize   = 8 * (int)sizeof(float[4]);
6024 
6025         m_vao = new glu::VertexArray(m_context.getRenderContext());
6026         gl.bindVertexArray(**m_vao);
6027         GLU_EXPECT_NO_ERROR(gl.getError(), "set up vao");
6028 
6029         gl.genBuffers(1, &m_elementBuf);
6030         gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementBuf);
6031         gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elementData), &elementData[0], GL_STATIC_DRAW);
6032         GLU_EXPECT_NO_ERROR(gl.getError(), "gen buf");
6033 
6034         gl.genBuffers(1, &m_arrayBuf);
6035         gl.bindBuffer(GL_ARRAY_BUFFER, m_arrayBuf);
6036         gl.bufferData(GL_ARRAY_BUFFER, sizeof(arrayData), &arrayData[0], GL_STATIC_DRAW);
6037         GLU_EXPECT_NO_ERROR(gl.getError(), "gen buf");
6038 
6039         gl.genBuffers(1, &m_offsetBuf);
6040         gl.bindBuffer(GL_ARRAY_BUFFER, m_offsetBuf);
6041         gl.bufferData(GL_ARRAY_BUFFER, sizeof(offsetData), &offsetData[0], GL_STATIC_DRAW);
6042         GLU_EXPECT_NO_ERROR(gl.getError(), "gen buf");
6043 
6044         gl.genBuffers(1, &m_feedbackBuf);
6045         gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_feedbackBuf);
6046         gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, feedbackSize, DE_NULL, GL_DYNAMIC_COPY);
6047         GLU_EXPECT_NO_ERROR(gl.getError(), "gen buf");
6048 
6049         m_program = genProgram();
6050 
6051         if (!m_program->isOk())
6052         {
6053             m_testCtx.getLog() << *m_program;
6054             throw tcu::TestError("could not build program");
6055         }
6056     }
6057 }
6058 
deinit(void)6059 void VertexFeedbackCase::deinit(void)
6060 {
6061     if (m_elementBuf)
6062     {
6063         m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_elementBuf);
6064         m_elementBuf = 0;
6065     }
6066 
6067     if (m_arrayBuf)
6068     {
6069         m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_arrayBuf);
6070         m_arrayBuf = 0;
6071     }
6072 
6073     if (m_offsetBuf)
6074     {
6075         m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_offsetBuf);
6076         m_offsetBuf = 0;
6077     }
6078 
6079     if (m_feedbackBuf)
6080     {
6081         m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_feedbackBuf);
6082         m_feedbackBuf = 0;
6083     }
6084 
6085     if (m_indirectBuffer)
6086     {
6087         m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_indirectBuffer);
6088         m_indirectBuffer = 0;
6089     }
6090 
6091     delete m_program;
6092     m_program = DE_NULL;
6093 
6094     delete m_vao;
6095     m_vao = DE_NULL;
6096 }
6097 
iterate(void)6098 VertexFeedbackCase::IterateResult VertexFeedbackCase::iterate(void)
6099 {
6100     const glw::Functions &gl       = m_context.getRenderContext().getFunctions();
6101     const uint32_t outputPrimitive = getOutputPrimitive();
6102     const uint32_t basePrimitive   = getBasePrimitive();
6103 
6104     const int posLocation    = gl.getAttribLocation(m_program->getProgram(), "a_position");
6105     const int offsetLocation = gl.getAttribLocation(m_program->getProgram(), "a_offset");
6106 
6107     if (posLocation == -1)
6108         throw tcu::TestError("a_position location was -1");
6109     if (offsetLocation == -1)
6110         throw tcu::TestError("a_offset location was -1");
6111 
6112     gl.useProgram(m_program->getProgram());
6113 
6114     gl.bindBuffer(GL_ARRAY_BUFFER, m_arrayBuf);
6115     gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
6116     gl.enableVertexAttribArray(posLocation);
6117 
6118     gl.bindBuffer(GL_ARRAY_BUFFER, m_offsetBuf);
6119     gl.vertexAttribPointer(offsetLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
6120     gl.enableVertexAttribArray(offsetLocation);
6121 
6122     gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_feedbackBuf);
6123     GLU_EXPECT_NO_ERROR(gl.getError(), "bind buffer base");
6124 
6125     m_testCtx.getLog() << tcu::TestLog::Message << "Calling BeginTransformFeedback("
6126                        << glu::getPrimitiveTypeStr(basePrimitive) << ")" << tcu::TestLog::EndMessage;
6127     gl.beginTransformFeedback(basePrimitive);
6128     GLU_EXPECT_NO_ERROR(gl.getError(), "beginTransformFeedback");
6129 
6130     switch (m_method)
6131     {
6132     case METHOD_DRAW_ARRAYS:
6133     {
6134         m_testCtx.getLog() << tcu::TestLog::Message << "Calling DrawArrays("
6135                            << glu::getPrimitiveTypeStr(outputPrimitive) << ", ...)" << tcu::TestLog::EndMessage;
6136         gl.drawArrays(outputPrimitive, 0, 4);
6137         break;
6138     }
6139 
6140     case METHOD_DRAW_ARRAYS_INSTANCED:
6141     {
6142         m_testCtx.getLog() << tcu::TestLog::Message << "Calling DrawArraysInstanced("
6143                            << glu::getPrimitiveTypeStr(outputPrimitive) << ", ...)" << tcu::TestLog::EndMessage;
6144         gl.vertexAttribDivisor(offsetLocation, 2);
6145         gl.drawArraysInstanced(outputPrimitive, 0, 3, 2);
6146         break;
6147     }
6148 
6149     case METHOD_DRAW_ELEMENTS:
6150     {
6151         m_testCtx.getLog() << tcu::TestLog::Message << "Calling DrawElements("
6152                            << glu::getPrimitiveTypeStr(outputPrimitive) << ", ...)" << tcu::TestLog::EndMessage;
6153         gl.drawElements(outputPrimitive, 4, GL_UNSIGNED_SHORT, DE_NULL);
6154         break;
6155     }
6156 
6157     case METHOD_DRAW_ELEMENTS_INSTANCED:
6158     {
6159         m_testCtx.getLog() << tcu::TestLog::Message << "Calling DrawElementsInstanced("
6160                            << glu::getPrimitiveTypeStr(outputPrimitive) << ", ...)" << tcu::TestLog::EndMessage;
6161         gl.drawElementsInstanced(outputPrimitive, 3, GL_UNSIGNED_SHORT, DE_NULL, 2);
6162         break;
6163     }
6164 
6165     case METHOD_DRAW_ARRAYS_INDIRECT:
6166     {
6167         struct DrawArraysIndirectCommand
6168         {
6169             uint32_t count;
6170             uint32_t instanceCount;
6171             uint32_t first;
6172             uint32_t reservedMustBeZero;
6173         } params;
6174 
6175         DE_STATIC_ASSERT(sizeof(DrawArraysIndirectCommand) == sizeof(uint32_t[4]));
6176 
6177         params.count              = 4;
6178         params.instanceCount      = 1;
6179         params.first              = 0;
6180         params.reservedMustBeZero = 0;
6181 
6182         gl.genBuffers(1, &m_indirectBuffer);
6183         gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, m_indirectBuffer);
6184         gl.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(params), &params, GL_STATIC_DRAW);
6185 
6186         m_testCtx.getLog() << tcu::TestLog::Message << "Calling DrawElementsIndirect("
6187                            << glu::getPrimitiveTypeStr(outputPrimitive) << ", ...)" << tcu::TestLog::EndMessage;
6188         gl.drawArraysIndirect(outputPrimitive, DE_NULL);
6189         break;
6190     }
6191 
6192     case METHOD_DRAW_ELEMENTS_INDIRECT:
6193     {
6194         struct DrawElementsIndirectCommand
6195         {
6196             uint32_t count;
6197             uint32_t instanceCount;
6198             uint32_t firstIndex;
6199             int32_t baseVertex;
6200             uint32_t reservedMustBeZero;
6201         } params;
6202 
6203         DE_STATIC_ASSERT(sizeof(DrawElementsIndirectCommand) == sizeof(uint32_t[5]));
6204 
6205         params.count              = 4;
6206         params.instanceCount      = 1;
6207         params.firstIndex         = 0;
6208         params.baseVertex         = 0;
6209         params.reservedMustBeZero = 0;
6210 
6211         gl.genBuffers(1, &m_indirectBuffer);
6212         gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, m_indirectBuffer);
6213         gl.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(params), &params, GL_STATIC_DRAW);
6214 
6215         m_testCtx.getLog() << tcu::TestLog::Message << "Calling DrawElementsIndirect("
6216                            << glu::getPrimitiveTypeStr(outputPrimitive) << ", ...)" << tcu::TestLog::EndMessage;
6217         gl.drawElementsIndirect(outputPrimitive, GL_UNSIGNED_SHORT, DE_NULL);
6218         break;
6219     }
6220 
6221     default:
6222         DE_ASSERT(false);
6223     }
6224     GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
6225 
6226     gl.endTransformFeedback();
6227     GLU_EXPECT_NO_ERROR(gl.getError(), "endTransformFeedback");
6228 
6229     m_testCtx.getLog() << tcu::TestLog::Message << "No errors." << tcu::TestLog::EndMessage;
6230     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
6231 
6232     return STOP;
6233 }
6234 
genProgram(void)6235 glu::ShaderProgram *VertexFeedbackCase::genProgram(void)
6236 {
6237     static const char *const vertexSource   = "${GLSL_VERSION_DECL}\n"
6238                                               "in highp vec4 a_position;\n"
6239                                               "in highp vec4 a_offset;\n"
6240                                               "out highp vec4 tf_value;\n"
6241                                               "void main (void)\n"
6242                                               "{\n"
6243                                               "    gl_Position = a_position;\n"
6244                                               "    tf_value = a_position + a_offset;\n"
6245                                               "}\n";
6246     static const char *const fragmentSource = "${GLSL_VERSION_DECL}\n"
6247                                               "layout(location = 0) out mediump vec4 fragColor;\n"
6248                                               "void main (void)\n"
6249                                               "{\n"
6250                                               "    fragColor = vec4(1.0);\n"
6251                                               "}\n";
6252 
6253     return new glu::ShaderProgram(m_context.getRenderContext(),
6254                                   glu::ProgramSources() << glu::VertexSource(specializeShader(
6255                                                                vertexSource, m_context.getRenderContext().getType()))
6256                                                         << glu::FragmentSource(specializeShader(
6257                                                                fragmentSource, m_context.getRenderContext().getType()))
6258                                                         << glu::TransformFeedbackVarying("tf_value")
6259                                                         << glu::TransformFeedbackMode(GL_INTERLEAVED_ATTRIBS));
6260 }
6261 
getOutputPrimitive(void)6262 uint32_t VertexFeedbackCase::getOutputPrimitive(void)
6263 {
6264     switch (m_output)
6265     {
6266     case PRIMITIVE_LINE_LOOP:
6267         return GL_LINE_LOOP;
6268     case PRIMITIVE_LINE_STRIP:
6269         return GL_LINE_STRIP;
6270     case PRIMITIVE_TRIANGLE_STRIP:
6271         return GL_TRIANGLE_STRIP;
6272     case PRIMITIVE_TRIANGLE_FAN:
6273         return GL_TRIANGLE_FAN;
6274     case PRIMITIVE_POINTS:
6275         return GL_POINTS;
6276     default:
6277         DE_ASSERT(false);
6278         return 0;
6279     }
6280 }
6281 
getBasePrimitive(void)6282 uint32_t VertexFeedbackCase::getBasePrimitive(void)
6283 {
6284     switch (m_output)
6285     {
6286     case PRIMITIVE_LINE_LOOP:
6287         return GL_LINES;
6288     case PRIMITIVE_LINE_STRIP:
6289         return GL_LINES;
6290     case PRIMITIVE_TRIANGLE_STRIP:
6291         return GL_TRIANGLES;
6292     case PRIMITIVE_TRIANGLE_FAN:
6293         return GL_TRIANGLES;
6294     case PRIMITIVE_POINTS:
6295         return GL_POINTS;
6296     default:
6297         DE_ASSERT(false);
6298         return 0;
6299     }
6300 }
6301 
6302 class VertexFeedbackOverflowCase : public TestCase
6303 {
6304 public:
6305     enum Method
6306     {
6307         METHOD_DRAW_ARRAYS = 0,
6308         METHOD_DRAW_ELEMENTS,
6309     };
6310 
6311     VertexFeedbackOverflowCase(Context &context, const char *name, const char *description, Method method);
6312     ~VertexFeedbackOverflowCase(void);
6313 
6314 private:
6315     void init(void);
6316     void deinit(void);
6317     IterateResult iterate(void);
6318     glu::ShaderProgram *genProgram(void);
6319 
6320     const Method m_method;
6321 
6322     uint32_t m_elementBuf;
6323     uint32_t m_arrayBuf;
6324     uint32_t m_feedbackBuf;
6325     glu::ShaderProgram *m_program;
6326     glu::VertexArray *m_vao;
6327 };
6328 
VertexFeedbackOverflowCase(Context & context,const char * name,const char * description,Method method)6329 VertexFeedbackOverflowCase::VertexFeedbackOverflowCase(Context &context, const char *name, const char *description,
6330                                                        Method method)
6331     : TestCase(context, name, description)
6332     , m_method(method)
6333     , m_elementBuf(0)
6334     , m_arrayBuf(0)
6335     , m_feedbackBuf(0)
6336     , m_program(DE_NULL)
6337     , m_vao(DE_NULL)
6338 {
6339 }
6340 
~VertexFeedbackOverflowCase(void)6341 VertexFeedbackOverflowCase::~VertexFeedbackOverflowCase(void)
6342 {
6343     deinit();
6344 }
6345 
init(void)6346 void VertexFeedbackOverflowCase::init(void)
6347 {
6348     // requirements
6349 
6350     if (!checkSupport(m_context))
6351         TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
6352 
6353     // log what test tries to do
6354 
6355     m_testCtx.getLog()
6356         << tcu::TestLog::Message << "Testing GL_EXT_geometry_shader transform feedback overflow behavior.\n"
6357         << "Capturing vertex shader varying, rendering 2 triangles. Allocating feedback buffer for 5 vertices."
6358         << tcu::TestLog::EndMessage;
6359 
6360     // resources
6361 
6362     {
6363         static const uint16_t elementData[] = {
6364             0, 1, 2, 0, 1, 2,
6365         };
6366         static const tcu::Vec4 arrayData[] = {
6367             tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
6368             tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
6369             tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
6370             tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
6371         };
6372 
6373         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
6374 
6375         m_vao = new glu::VertexArray(m_context.getRenderContext());
6376         gl.bindVertexArray(**m_vao);
6377         GLU_EXPECT_NO_ERROR(gl.getError(), "set up vao");
6378 
6379         if (m_method == METHOD_DRAW_ELEMENTS)
6380         {
6381             gl.genBuffers(1, &m_elementBuf);
6382             gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementBuf);
6383             gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elementData), &elementData[0], GL_STATIC_DRAW);
6384             GLU_EXPECT_NO_ERROR(gl.getError(), "gen buf");
6385         }
6386 
6387         gl.genBuffers(1, &m_arrayBuf);
6388         gl.bindBuffer(GL_ARRAY_BUFFER, m_arrayBuf);
6389         gl.bufferData(GL_ARRAY_BUFFER, sizeof(arrayData), &arrayData[0], GL_STATIC_DRAW);
6390         GLU_EXPECT_NO_ERROR(gl.getError(), "gen buf");
6391 
6392         {
6393             const int feedbackCount = 5 * 4; // 5x vec4
6394             const std::vector<float> initialBufferContents(feedbackCount, -1.0f);
6395 
6396             m_testCtx.getLog() << tcu::TestLog::Message << "Filling feeback buffer with unused value (-1.0)."
6397                                << tcu::TestLog::EndMessage;
6398 
6399             gl.genBuffers(1, &m_feedbackBuf);
6400             gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_feedbackBuf);
6401             gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, (int)(sizeof(float) * initialBufferContents.size()),
6402                           &initialBufferContents[0], GL_DYNAMIC_COPY);
6403             GLU_EXPECT_NO_ERROR(gl.getError(), "gen buf");
6404         }
6405 
6406         m_program = genProgram();
6407 
6408         if (!m_program->isOk())
6409         {
6410             m_testCtx.getLog() << *m_program;
6411             throw tcu::TestError("could not build program");
6412         }
6413     }
6414 }
6415 
deinit(void)6416 void VertexFeedbackOverflowCase::deinit(void)
6417 {
6418     if (m_elementBuf)
6419     {
6420         m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_elementBuf);
6421         m_elementBuf = 0;
6422     }
6423 
6424     if (m_arrayBuf)
6425     {
6426         m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_arrayBuf);
6427         m_arrayBuf = 0;
6428     }
6429 
6430     if (m_feedbackBuf)
6431     {
6432         m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_feedbackBuf);
6433         m_feedbackBuf = 0;
6434     }
6435 
6436     delete m_program;
6437     m_program = DE_NULL;
6438 
6439     delete m_vao;
6440     m_vao = DE_NULL;
6441 }
6442 
iterate(void)6443 VertexFeedbackOverflowCase::IterateResult VertexFeedbackOverflowCase::iterate(void)
6444 {
6445     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
6446     const int posLocation    = gl.getAttribLocation(m_program->getProgram(), "a_position");
6447 
6448     if (posLocation == -1)
6449         throw tcu::TestError("a_position location was -1");
6450 
6451     gl.useProgram(m_program->getProgram());
6452 
6453     gl.bindBuffer(GL_ARRAY_BUFFER, m_arrayBuf);
6454     gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
6455     gl.enableVertexAttribArray(posLocation);
6456 
6457     if (m_method == METHOD_DRAW_ELEMENTS)
6458     {
6459         gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementBuf);
6460         GLU_EXPECT_NO_ERROR(gl.getError(), "bind buffers");
6461     }
6462 
6463     gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_feedbackBuf);
6464     GLU_EXPECT_NO_ERROR(gl.getError(), "bind buffer base");
6465 
6466     m_testCtx.getLog() << tcu::TestLog::Message << "Capturing 2 triangles." << tcu::TestLog::EndMessage;
6467 
6468     gl.beginTransformFeedback(GL_TRIANGLES);
6469 
6470     if (m_method == METHOD_DRAW_ELEMENTS)
6471         gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, DE_NULL);
6472     else if (m_method == METHOD_DRAW_ARRAYS)
6473         gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
6474     else
6475         DE_ASSERT(false);
6476 
6477     gl.endTransformFeedback();
6478     GLU_EXPECT_NO_ERROR(gl.getError(), "capture");
6479 
6480     m_testCtx.getLog() << tcu::TestLog::Message
6481                        << "Verifying final triangle was not partially written to the feedback buffer."
6482                        << tcu::TestLog::EndMessage;
6483 
6484     {
6485         const void *ptr = gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(float[4]) * 5, GL_MAP_READ_BIT);
6486         std::vector<float> feedback;
6487         bool error = false;
6488 
6489         GLU_EXPECT_NO_ERROR(gl.getError(), "mapBufferRange");
6490         if (!ptr)
6491             throw tcu::TestError("mapBufferRange returned null");
6492 
6493         feedback.resize(5 * 4);
6494         deMemcpy(&feedback[0], ptr, sizeof(float[4]) * 5);
6495 
6496         if (gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER) != GL_TRUE)
6497             throw tcu::TestError("unmapBuffer returned false");
6498 
6499         // Verify vertices 0 - 2
6500         for (int vertex = 0; vertex < 3; ++vertex)
6501         {
6502             for (int component = 0; component < 4; ++component)
6503             {
6504                 if (feedback[vertex * 4 + component] != 1.0f)
6505                 {
6506                     m_testCtx.getLog() << tcu::TestLog::Message << "Feedback buffer vertex " << vertex << ", component "
6507                                        << component << ": unexpected value, expected 1.0, got "
6508                                        << feedback[vertex * 4 + component] << tcu::TestLog::EndMessage;
6509                     error = true;
6510                 }
6511             }
6512         }
6513 
6514         // Verify vertices 3 - 4
6515         for (int vertex = 3; vertex < 5; ++vertex)
6516         {
6517             for (int component = 0; component < 4; ++component)
6518             {
6519                 if (feedback[vertex * 4 + component] != -1.0f)
6520                 {
6521                     m_testCtx.getLog() << tcu::TestLog::Message << "Feedback buffer vertex " << vertex << ", component "
6522                                        << component << ": unexpected value, expected -1.0, got "
6523                                        << feedback[vertex * 4 + component] << tcu::TestLog::EndMessage;
6524                     error = true;
6525                 }
6526             }
6527         }
6528 
6529         if (error)
6530             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Feedback result validation failed");
6531         else
6532             m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
6533     }
6534 
6535     return STOP;
6536 }
6537 
genProgram(void)6538 glu::ShaderProgram *VertexFeedbackOverflowCase::genProgram(void)
6539 {
6540     static const char *const vertexSource   = "${GLSL_VERSION_DECL}\n"
6541                                               "in highp vec4 a_position;\n"
6542                                               "void main (void)\n"
6543                                               "{\n"
6544                                               "    gl_Position = a_position;\n"
6545                                               "}\n";
6546     static const char *const fragmentSource = "${GLSL_VERSION_DECL}\n"
6547                                               "layout(location = 0) out mediump vec4 fragColor;\n"
6548                                               "void main (void)\n"
6549                                               "{\n"
6550                                               "    fragColor = vec4(1.0);\n"
6551                                               "}\n";
6552 
6553     return new glu::ShaderProgram(m_context.getRenderContext(),
6554                                   glu::ProgramSources() << glu::VertexSource(specializeShader(
6555                                                                vertexSource, m_context.getRenderContext().getType()))
6556                                                         << glu::FragmentSource(specializeShader(
6557                                                                fragmentSource, m_context.getRenderContext().getType()))
6558                                                         << glu::TransformFeedbackVarying("gl_Position")
6559                                                         << glu::TransformFeedbackMode(GL_INTERLEAVED_ATTRIBS));
6560 }
6561 
6562 } // namespace
6563 
GeometryShaderTests(Context & context,bool isGL45)6564 GeometryShaderTests::GeometryShaderTests(Context &context, bool isGL45)
6565     : TestCaseGroup(context, "geometry_shading", "Geometry shader tests")
6566     , m_isGL45(isGL45)
6567 {
6568 }
6569 
~GeometryShaderTests(void)6570 GeometryShaderTests::~GeometryShaderTests(void)
6571 {
6572 }
6573 
init(void)6574 void GeometryShaderTests::init(void)
6575 {
6576     struct PrimitiveTestSpec
6577     {
6578         uint32_t primitiveType;
6579         const char *name;
6580         uint32_t outputType;
6581     };
6582 
6583     struct EmitTestSpec
6584     {
6585         uint32_t outputType;
6586         int emitCountA; //!< primitive A emit count
6587         int endCountA;  //!< primitive A end count
6588         int emitCountB; //!<
6589         int endCountB;  //!<
6590         const char *name;
6591     };
6592 
6593     static const struct LayeredTarget
6594     {
6595         LayeredRenderCase::LayeredRenderTargetType target;
6596         const char *name;
6597         const char *desc;
6598     } layerTargets[] = {
6599         {LayeredRenderCase::TARGET_CUBE, "cubemap", "cubemap"},
6600         {LayeredRenderCase::TARGET_3D, "3d", "3D texture"},
6601         {LayeredRenderCase::TARGET_2D_ARRAY, "2d_array", "2D array texture"},
6602         {LayeredRenderCase::TARGET_2D_MS_ARRAY, "2d_multisample_array", "2D multisample array texture"},
6603     };
6604 
6605     tcu::TestCaseGroup *const queryGroup = new tcu::TestCaseGroup(m_testCtx, "query", "Query tests.");
6606     tcu::TestCaseGroup *const basicGroup = new tcu::TestCaseGroup(m_testCtx, "basic", "Basic tests.");
6607     tcu::TestCaseGroup *const inputPrimitiveGroup =
6608         new tcu::TestCaseGroup(m_testCtx, "input", "Different input primitives.");
6609     tcu::TestCaseGroup *const conversionPrimitiveGroup =
6610         new tcu::TestCaseGroup(m_testCtx, "conversion", "Different input and output primitives.");
6611     tcu::TestCaseGroup *const emitGroup      = new tcu::TestCaseGroup(m_testCtx, "emit", "Different emit counts.");
6612     tcu::TestCaseGroup *const varyingGroup   = new tcu::TestCaseGroup(m_testCtx, "varying", "Test varyings.");
6613     tcu::TestCaseGroup *const layeredGroup   = new tcu::TestCaseGroup(m_testCtx, "layered", "Layered rendering.");
6614     tcu::TestCaseGroup *const instancedGroup = new tcu::TestCaseGroup(m_testCtx, "instanced", "Instanced rendering.");
6615     tcu::TestCaseGroup *const negativeGroup  = new tcu::TestCaseGroup(m_testCtx, "negative", "Negative tests.");
6616     tcu::TestCaseGroup *const feedbackGroup =
6617         new tcu::TestCaseGroup(m_testCtx, "vertex_transform_feedback", "Transform feedback.");
6618 
6619     this->addChild(queryGroup);
6620     this->addChild(basicGroup);
6621     this->addChild(inputPrimitiveGroup);
6622     this->addChild(conversionPrimitiveGroup);
6623     this->addChild(emitGroup);
6624     this->addChild(varyingGroup);
6625     this->addChild(layeredGroup);
6626     this->addChild(instancedGroup);
6627     this->addChild(negativeGroup);
6628     this->addChild(feedbackGroup);
6629 
6630     // query test
6631     {
6632         // limits with a corresponding glsl constant
6633         queryGroup->addChild(new GeometryProgramLimitCase(m_context, "max_geometry_input_components", "",
6634                                                           GL_MAX_GEOMETRY_INPUT_COMPONENTS,
6635                                                           "MaxGeometryInputComponents", 64));
6636         queryGroup->addChild(new GeometryProgramLimitCase(m_context, "max_geometry_output_components", "",
6637                                                           GL_MAX_GEOMETRY_OUTPUT_COMPONENTS,
6638                                                           "MaxGeometryOutputComponents", 64));
6639         queryGroup->addChild(new GeometryProgramLimitCase(m_context, "max_geometry_image_uniforms", "",
6640                                                           GL_MAX_GEOMETRY_IMAGE_UNIFORMS, "MaxGeometryImageUniforms",
6641                                                           0));
6642         queryGroup->addChild(new GeometryProgramLimitCase(m_context, "max_geometry_texture_image_units", "",
6643                                                           GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS,
6644                                                           "MaxGeometryTextureImageUnits", 16));
6645         queryGroup->addChild(new GeometryProgramLimitCase(m_context, "max_geometry_output_vertices", "",
6646                                                           GL_MAX_GEOMETRY_OUTPUT_VERTICES, "MaxGeometryOutputVertices",
6647                                                           256));
6648         queryGroup->addChild(new GeometryProgramLimitCase(m_context, "max_geometry_total_output_components", "",
6649                                                           GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS,
6650                                                           "MaxGeometryTotalOutputComponents", 1024));
6651         queryGroup->addChild(new GeometryProgramLimitCase(m_context, "max_geometry_uniform_components", "",
6652                                                           GL_MAX_GEOMETRY_UNIFORM_COMPONENTS,
6653                                                           "MaxGeometryUniformComponents", 1024));
6654         queryGroup->addChild(new GeometryProgramLimitCase(m_context, "max_geometry_atomic_counters", "",
6655                                                           GL_MAX_GEOMETRY_ATOMIC_COUNTERS, "MaxGeometryAtomicCounters",
6656                                                           0));
6657         queryGroup->addChild(new GeometryProgramLimitCase(m_context, "max_geometry_atomic_counter_buffers", "",
6658                                                           GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS,
6659                                                           "MaxGeometryAtomicCounterBuffers", 0));
6660 
6661         // program queries
6662         // ES only
6663         if (!m_isGL45)
6664         {
6665             queryGroup->addChild(new GeometryShaderVerticesQueryCase(m_context, "geometry_linked_vertices_out",
6666                                                                      "GL_GEOMETRY_LINKED_VERTICES_OUT"));
6667             queryGroup->addChild(new GeometryShaderInputQueryCase(m_context, "geometry_linked_input_type",
6668                                                                   "GL_GEOMETRY_LINKED_INPUT_TYPE"));
6669             queryGroup->addChild(new GeometryShaderOutputQueryCase(m_context, "geometry_linked_output_type",
6670                                                                    "GL_GEOMETRY_LINKED_OUTPUT_TYPE"));
6671             queryGroup->addChild(new GeometryShaderInvocationsQueryCase(m_context, "geometry_shader_invocations",
6672                                                                         "GL_GEOMETRY_SHADER_INVOCATIONS"));
6673         }
6674 
6675         // limits
6676         queryGroup->addChild(new ImplementationLimitCase(m_context, "max_geometry_shader_invocations", "",
6677                                                          GL_MAX_GEOMETRY_SHADER_INVOCATIONS, 32));
6678         queryGroup->addChild(new ImplementationLimitCase(m_context, "max_geometry_uniform_blocks", "",
6679                                                          GL_MAX_GEOMETRY_UNIFORM_BLOCKS, 12));
6680         queryGroup->addChild(new ImplementationLimitCase(m_context, "max_geometry_shader_storage_blocks", "",
6681                                                          GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS, 0));
6682 
6683         // layer_provoking_vertex_ext
6684         queryGroup->addChild(
6685             new LayerProvokingVertexQueryCase(m_context, "layer_provoking_vertex", "GL_LAYER_PROVOKING_VERTEX"));
6686 
6687         // primitives_generated
6688         queryGroup->addChild(new PrimitivesGeneratedQueryCase(m_context, "primitives_generated_no_geometry",
6689                                                               "PRIMITIVES_GENERATED query with no geometry shader",
6690                                                               PrimitivesGeneratedQueryCase::TEST_NO_GEOMETRY));
6691         queryGroup->addChild(
6692             new PrimitivesGeneratedQueryCase(m_context, "primitives_generated_no_amplification",
6693                                              "PRIMITIVES_GENERATED query with non amplifying geometry shader",
6694                                              PrimitivesGeneratedQueryCase::TEST_NO_AMPLIFICATION));
6695         queryGroup->addChild(
6696             new PrimitivesGeneratedQueryCase(m_context, "primitives_generated_amplification",
6697                                              "PRIMITIVES_GENERATED query with amplifying geometry shader",
6698                                              PrimitivesGeneratedQueryCase::TEST_AMPLIFICATION));
6699         queryGroup->addChild(new PrimitivesGeneratedQueryCase(
6700             m_context, "primitives_generated_partial_primitives",
6701             "PRIMITIVES_GENERATED query with geometry shader emitting partial primitives",
6702             PrimitivesGeneratedQueryCase::TEST_PARTIAL_PRIMITIVES));
6703         queryGroup->addChild(new PrimitivesGeneratedQueryCase(
6704             m_context, "primitives_generated_instanced", "PRIMITIVES_GENERATED query with instanced geometry shader",
6705             PrimitivesGeneratedQueryCase::TEST_INSTANCED));
6706 
6707         queryGroup->addChild(new PrimitivesGeneratedQueryObjectQueryCase(m_context, "primitives_generated",
6708                                                                          "Query bound PRIMITIVES_GENERATED query"));
6709 
6710         // fbo
6711         queryGroup->addChild(
6712             new ImplementationLimitCase(m_context, "max_framebuffer_layers", "", GL_MAX_FRAMEBUFFER_LAYERS, 256));
6713         queryGroup->addChild(new FramebufferDefaultLayersCase(m_context, "framebuffer_default_layers", ""));
6714         queryGroup->addChild(new FramebufferAttachmentLayeredCase(m_context, "framebuffer_attachment_layered", ""));
6715         queryGroup->addChild(
6716             new FramebufferIncompleteLayereTargetsCase(m_context, "framebuffer_incomplete_layer_targets", ""));
6717 
6718         // resource query
6719         queryGroup->addChild(new ReferencedByGeometryShaderCase(m_context, "referenced_by_geometry_shader", ""));
6720 
6721         // combined limits
6722         queryGroup->addChild(new CombinedGeometryUniformLimitCase(m_context, "max_combined_geometry_uniform_components",
6723                                                                   "MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS"));
6724     }
6725 
6726     // basic tests
6727     {
6728         basicGroup->addChild(
6729             new OutputCountCase(m_context, "output_10", "Output 10 vertices", OutputCountPatternSpec(10)));
6730         basicGroup->addChild(
6731             new OutputCountCase(m_context, "output_128", "Output 128 vertices", OutputCountPatternSpec(128)));
6732         basicGroup->addChild(
6733             new OutputCountCase(m_context, "output_256", "Output 256 vertices", OutputCountPatternSpec(256)));
6734         basicGroup->addChild(
6735             new OutputCountCase(m_context, "output_max", "Output max vertices", OutputCountPatternSpec(-1)));
6736         basicGroup->addChild(new OutputCountCase(m_context, "output_10_and_100",
6737                                                  "Output 10 and 100 vertices in two invocations",
6738                                                  OutputCountPatternSpec(10, 100)));
6739         basicGroup->addChild(new OutputCountCase(m_context, "output_100_and_10",
6740                                                  "Output 100 and 10 vertices in two invocations",
6741                                                  OutputCountPatternSpec(100, 10)));
6742         basicGroup->addChild(new OutputCountCase(m_context, "output_0_and_128",
6743                                                  "Output 0 and 128 vertices in two invocations",
6744                                                  OutputCountPatternSpec(0, 128)));
6745         basicGroup->addChild(new OutputCountCase(m_context, "output_128_and_0",
6746                                                  "Output 128 and 0 vertices in two invocations",
6747                                                  OutputCountPatternSpec(128, 0)));
6748 
6749         basicGroup->addChild(new VaryingOutputCountCase(
6750             m_context, "output_vary_by_attribute", "Output varying number of vertices",
6751             VaryingOutputCountShader::READ_ATTRIBUTE, VaryingOutputCountCase::MODE_WITHOUT_INSTANCING));
6752         basicGroup->addChild(new VaryingOutputCountCase(
6753             m_context, "output_vary_by_uniform", "Output varying number of vertices",
6754             VaryingOutputCountShader::READ_UNIFORM, VaryingOutputCountCase::MODE_WITHOUT_INSTANCING));
6755         basicGroup->addChild(new VaryingOutputCountCase(
6756             m_context, "output_vary_by_texture", "Output varying number of vertices",
6757             VaryingOutputCountShader::READ_TEXTURE, VaryingOutputCountCase::MODE_WITHOUT_INSTANCING));
6758 
6759         basicGroup->addChild(new BuiltinVariableRenderTest(m_context, "point_size", "test gl_PointSize",
6760                                                            BuiltinVariableShader::TEST_POINT_SIZE));
6761         basicGroup->addChild(new BuiltinVariableRenderTest(m_context, "primitive_id_in", "test gl_PrimitiveIDIn",
6762                                                            BuiltinVariableShader::TEST_PRIMITIVE_ID_IN));
6763         basicGroup->addChild(new BuiltinVariableRenderTest(
6764             m_context, "primitive_id_in_restarted", "test gl_PrimitiveIDIn with primitive restart",
6765             BuiltinVariableShader::TEST_PRIMITIVE_ID_IN,
6766             GeometryShaderRenderTest::FLAG_USE_RESTART_INDEX | GeometryShaderRenderTest::FLAG_USE_INDICES));
6767         basicGroup->addChild(new BuiltinVariableRenderTest(m_context, "primitive_id", "test gl_PrimitiveID",
6768                                                            BuiltinVariableShader::TEST_PRIMITIVE_ID));
6769     }
6770 
6771     // input primitives
6772     {
6773         static const PrimitiveTestSpec inputPrimitives[] = {
6774             {GL_POINTS, "points", GL_POINTS},
6775             {GL_LINES, "lines", GL_LINE_STRIP},
6776             {GL_LINE_LOOP, "line_loop", GL_LINE_STRIP},
6777             {GL_LINE_STRIP, "line_strip", GL_LINE_STRIP},
6778             {GL_TRIANGLES, "triangles", GL_TRIANGLE_STRIP},
6779             {GL_TRIANGLE_STRIP, "triangle_strip", GL_TRIANGLE_STRIP},
6780             {GL_TRIANGLE_FAN, "triangle_fan", GL_TRIANGLE_STRIP},
6781             {GL_LINES_ADJACENCY, "lines_adjacency", GL_LINE_STRIP},
6782             {GL_LINE_STRIP_ADJACENCY, "line_strip_adjacency", GL_LINE_STRIP},
6783             {GL_TRIANGLES_ADJACENCY, "triangles_adjacency", GL_TRIANGLE_STRIP}};
6784 
6785         tcu::TestCaseGroup *const basicPrimitiveGroup =
6786             new tcu::TestCaseGroup(m_testCtx, "basic_primitive", "Different input and output primitives.");
6787         tcu::TestCaseGroup *const triStripAdjacencyGroup = new tcu::TestCaseGroup(
6788             m_testCtx, "triangle_strip_adjacency", "Different triangle_strip_adjacency vertex counts.");
6789 
6790         // more basic types
6791         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(inputPrimitives); ++ndx)
6792             basicPrimitiveGroup->addChild(
6793                 new GeometryExpanderRenderTest(m_context, inputPrimitives[ndx].name, inputPrimitives[ndx].name,
6794                                                inputPrimitives[ndx].primitiveType, inputPrimitives[ndx].outputType));
6795 
6796         // triangle strip adjacency with different vtx counts
6797         for (int vtxCount = 0; vtxCount <= 12; ++vtxCount)
6798         {
6799             const std::string name = "vertex_count_" + de::toString(vtxCount);
6800             const std::string desc = "Vertex count is " + de::toString(vtxCount);
6801 
6802             triStripAdjacencyGroup->addChild(
6803                 new TriangleStripAdjacencyVertexCountTest(m_context, name.c_str(), desc.c_str(), vtxCount));
6804         }
6805 
6806         inputPrimitiveGroup->addChild(basicPrimitiveGroup);
6807         inputPrimitiveGroup->addChild(triStripAdjacencyGroup);
6808     }
6809 
6810     // different type conversions
6811     {
6812         static const PrimitiveTestSpec conversionPrimitives[] = {
6813             {GL_TRIANGLES, "triangles_to_points", GL_POINTS},      {GL_LINES, "lines_to_points", GL_POINTS},
6814             {GL_POINTS, "points_to_lines", GL_LINE_STRIP},         {GL_TRIANGLES, "triangles_to_lines", GL_LINE_STRIP},
6815             {GL_POINTS, "points_to_triangles", GL_TRIANGLE_STRIP}, {GL_LINES, "lines_to_triangles", GL_TRIANGLE_STRIP}};
6816 
6817         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(conversionPrimitives); ++ndx)
6818             conversionPrimitiveGroup->addChild(new GeometryExpanderRenderTest(
6819                 m_context, conversionPrimitives[ndx].name, conversionPrimitives[ndx].name,
6820                 conversionPrimitives[ndx].primitiveType, conversionPrimitives[ndx].outputType));
6821     }
6822 
6823     // emit different amounts
6824     {
6825         static const EmitTestSpec emitTests[] = {
6826             {GL_POINTS, 0, 0, 0, 0, "points"},
6827             {GL_POINTS, 0, 1, 0, 0, "points"},
6828             {GL_POINTS, 1, 1, 0, 0, "points"},
6829             {GL_POINTS, 0, 2, 0, 0, "points"},
6830             {GL_POINTS, 1, 2, 0, 0, "points"},
6831             {GL_LINE_STRIP, 0, 0, 0, 0, "line_strip"},
6832             {GL_LINE_STRIP, 0, 1, 0, 0, "line_strip"},
6833             {GL_LINE_STRIP, 1, 1, 0, 0, "line_strip"},
6834             {GL_LINE_STRIP, 2, 1, 0, 0, "line_strip"},
6835             {GL_LINE_STRIP, 0, 2, 0, 0, "line_strip"},
6836             {GL_LINE_STRIP, 1, 2, 0, 0, "line_strip"},
6837             {GL_LINE_STRIP, 2, 2, 0, 0, "line_strip"},
6838             {GL_LINE_STRIP, 2, 2, 2, 0, "line_strip"},
6839             {GL_TRIANGLE_STRIP, 0, 0, 0, 0, "triangle_strip"},
6840             {GL_TRIANGLE_STRIP, 0, 1, 0, 0, "triangle_strip"},
6841             {GL_TRIANGLE_STRIP, 1, 1, 0, 0, "triangle_strip"},
6842             {GL_TRIANGLE_STRIP, 2, 1, 0, 0, "triangle_strip"},
6843             {GL_TRIANGLE_STRIP, 3, 1, 0, 0, "triangle_strip"},
6844             {GL_TRIANGLE_STRIP, 0, 2, 0, 0, "triangle_strip"},
6845             {GL_TRIANGLE_STRIP, 1, 2, 0, 0, "triangle_strip"},
6846             {GL_TRIANGLE_STRIP, 2, 2, 0, 0, "triangle_strip"},
6847             {GL_TRIANGLE_STRIP, 3, 2, 0, 0, "triangle_strip"},
6848             {GL_TRIANGLE_STRIP, 3, 2, 3, 0, "triangle_strip"},
6849         };
6850 
6851         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(emitTests); ++ndx)
6852         {
6853             std::string name = std::string(emitTests[ndx].name) + "_emit_" + de::toString(emitTests[ndx].emitCountA) +
6854                                "_end_" + de::toString(emitTests[ndx].endCountA);
6855             std::string desc = std::string(emitTests[ndx].name) + " output, emit " +
6856                                de::toString(emitTests[ndx].emitCountA) + " vertices, call EndPrimitive " +
6857                                de::toString(emitTests[ndx].endCountA) + " times";
6858 
6859             if (emitTests[ndx].emitCountB)
6860             {
6861                 name += "_emit_" + de::toString(emitTests[ndx].emitCountB) + "_end_" +
6862                         de::toString(emitTests[ndx].endCountB);
6863                 desc += ", emit " + de::toString(emitTests[ndx].emitCountB) + " vertices, call EndPrimitive " +
6864                         de::toString(emitTests[ndx].endCountB) + " times";
6865             }
6866 
6867             emitGroup->addChild(new EmitTest(m_context, name.c_str(), desc.c_str(), emitTests[ndx].emitCountA,
6868                                              emitTests[ndx].endCountA, emitTests[ndx].emitCountB,
6869                                              emitTests[ndx].endCountB, emitTests[ndx].outputType));
6870         }
6871     }
6872 
6873     // varying
6874     {
6875         struct VaryingTestSpec
6876         {
6877             int vertexOutputs;
6878             int geometryOutputs;
6879             const char *name;
6880             const char *desc;
6881         };
6882 
6883         static const VaryingTestSpec varyingTests[] = {
6884             {-1, 1, "vertex_no_op_geometry_out_1", "vertex_no_op_geometry_out_1"},
6885             {0, 1, "vertex_out_0_geometry_out_1", "vertex_out_0_geometry_out_1"},
6886             {0, 2, "vertex_out_0_geometry_out_2", "vertex_out_0_geometry_out_2"},
6887             {1, 0, "vertex_out_1_geometry_out_0", "vertex_out_1_geometry_out_0"},
6888             {1, 2, "vertex_out_1_geometry_out_2", "vertex_out_1_geometry_out_2"},
6889         };
6890 
6891         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(varyingTests); ++ndx)
6892             varyingGroup->addChild(new VaryingTest(m_context, varyingTests[ndx].name, varyingTests[ndx].desc,
6893                                                    varyingTests[ndx].vertexOutputs, varyingTests[ndx].geometryOutputs));
6894     }
6895 
6896     // layered
6897     {
6898         static const struct TestType
6899         {
6900             LayeredRenderCase::TestType test;
6901             const char *testPrefix;
6902             const char *descPrefix;
6903         } tests[] = {
6904             {LayeredRenderCase::TEST_DEFAULT_LAYER, "render_with_default_layer_", "Render to all layers of "},
6905             {LayeredRenderCase::TEST_SINGLE_LAYER, "render_to_one_", "Render to one layer of "},
6906             {LayeredRenderCase::TEST_ALL_LAYERS, "render_to_all_", "Render to all layers of "},
6907             {LayeredRenderCase::TEST_DIFFERENT_LAYERS, "render_different_to_",
6908              "Render different data to different layers"},
6909             {LayeredRenderCase::TEST_LAYER_ID, "fragment_layer_", "Read gl_Layer in fragment shader"},
6910             {LayeredRenderCase::TEST_LAYER_PROVOKING_VERTEX, "layer_provoking_vertex_",
6911              "Verify LAYER_PROVOKING_VERTEX"},
6912         };
6913 
6914         for (int testNdx = 0; testNdx < DE_LENGTH_OF_ARRAY(tests); ++testNdx)
6915             for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(layerTargets); ++targetNdx)
6916             {
6917                 const std::string name = std::string(tests[testNdx].testPrefix) + layerTargets[targetNdx].name;
6918                 const std::string desc = std::string(tests[testNdx].descPrefix) + layerTargets[targetNdx].desc;
6919 
6920                 layeredGroup->addChild(new LayeredRenderCase(m_context, name.c_str(), desc.c_str(),
6921                                                              layerTargets[targetNdx].target, tests[testNdx].test));
6922             }
6923     }
6924 
6925     // instanced
6926     {
6927         static const struct InvocationCase
6928         {
6929             const char *name;
6930             int numInvocations;
6931         } invocationCases[] = {
6932             {"1", 1}, {"2", 2}, {"8", 8}, {"32", 32}, {"max", -1},
6933         };
6934         static const int numDrawInstances[]   = {2, 4, 8};
6935         static const int numDrawInvocations[] = {2, 8};
6936 
6937         // same amount of content to all invocations
6938         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(invocationCases); ++ndx)
6939             instancedGroup->addChild(new GeometryInvocationCase(
6940                 m_context, (std::string("geometry_") + invocationCases[ndx].name + "_invocations").c_str(),
6941                 (std::string("Geometry shader with ") + invocationCases[ndx].name + " invocation(s)").c_str(),
6942                 invocationCases[ndx].numInvocations, GeometryInvocationCase::CASE_FIXED_OUTPUT_COUNTS));
6943 
6944         // different amount of content to each invocation
6945         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(invocationCases); ++ndx)
6946             if (invocationCases[ndx].numInvocations != 1)
6947                 instancedGroup->addChild(new GeometryInvocationCase(
6948                     m_context,
6949                     (std::string("geometry_output_different_") + invocationCases[ndx].name + "_invocations").c_str(),
6950                     "Geometry shader invocation(s) with different emit counts", invocationCases[ndx].numInvocations,
6951                     GeometryInvocationCase::CASE_DIFFERENT_OUTPUT_COUNTS));
6952 
6953         // invocation per layer
6954         for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(layerTargets); ++targetNdx)
6955         {
6956             const std::string name = std::string("invocation_per_layer_") + layerTargets[targetNdx].name;
6957             const std::string desc =
6958                 std::string("Render to multiple layers with multiple invocations, one invocation per layer, target ") +
6959                 layerTargets[targetNdx].desc;
6960 
6961             instancedGroup->addChild(new LayeredRenderCase(m_context, name.c_str(), desc.c_str(),
6962                                                            layerTargets[targetNdx].target,
6963                                                            LayeredRenderCase::TEST_INVOCATION_PER_LAYER));
6964         }
6965 
6966         // multiple layers per invocation
6967         for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(layerTargets); ++targetNdx)
6968         {
6969             const std::string name = std::string("multiple_layers_per_invocation_") + layerTargets[targetNdx].name;
6970             const std::string desc =
6971                 std::string(
6972                     "Render to multiple layers with multiple invocations, multiple layers per invocation, target ") +
6973                 layerTargets[targetNdx].desc;
6974 
6975             instancedGroup->addChild(new LayeredRenderCase(m_context, name.c_str(), desc.c_str(),
6976                                                            layerTargets[targetNdx].target,
6977                                                            LayeredRenderCase::TEST_MULTIPLE_LAYERS_PER_INVOCATION));
6978         }
6979 
6980         // different invocation output counts depending on {uniform, attrib, texture}
6981         instancedGroup->addChild(new VaryingOutputCountCase(
6982             m_context, "invocation_output_vary_by_attribute", "Output varying number of vertices",
6983             VaryingOutputCountShader::READ_ATTRIBUTE, VaryingOutputCountCase::MODE_WITH_INSTANCING));
6984         instancedGroup->addChild(new VaryingOutputCountCase(
6985             m_context, "invocation_output_vary_by_uniform", "Output varying number of vertices",
6986             VaryingOutputCountShader::READ_UNIFORM, VaryingOutputCountCase::MODE_WITH_INSTANCING));
6987         instancedGroup->addChild(new VaryingOutputCountCase(
6988             m_context, "invocation_output_vary_by_texture", "Output varying number of vertices",
6989             VaryingOutputCountShader::READ_TEXTURE, VaryingOutputCountCase::MODE_WITH_INSTANCING));
6990 
6991         // with drawInstanced
6992         for (int instanceNdx = 0; instanceNdx < DE_LENGTH_OF_ARRAY(numDrawInstances); ++instanceNdx)
6993             for (int invocationNdx = 0; invocationNdx < DE_LENGTH_OF_ARRAY(numDrawInvocations); ++invocationNdx)
6994             {
6995                 const std::string name = std::string("draw_") + de::toString(numDrawInstances[instanceNdx]) +
6996                                          "_instances_geometry_" + de::toString(numDrawInvocations[invocationNdx]) +
6997                                          "_invocations";
6998                 const std::string desc = std::string("Draw ") + de::toString(numDrawInstances[instanceNdx]) +
6999                                          " instances, with " + de::toString(numDrawInvocations[invocationNdx]) +
7000                                          " geometry shader invocations.";
7001 
7002                 instancedGroup->addChild(new DrawInstancedGeometryInstancedCase(m_context, name.c_str(), desc.c_str(),
7003                                                                                 numDrawInstances[instanceNdx],
7004                                                                                 numDrawInvocations[invocationNdx]));
7005             }
7006     }
7007 
7008     // negative (wrong types)
7009     {
7010         struct PrimitiveToInputTypeConversion
7011         {
7012             GLenum inputType;
7013             GLenum primitiveType;
7014         };
7015 
7016         static const PrimitiveToInputTypeConversion legalConversions[] = {
7017             {GL_POINTS, GL_POINTS},
7018             {GL_LINES, GL_LINES},
7019             {GL_LINES, GL_LINE_LOOP},
7020             {GL_LINES, GL_LINE_STRIP},
7021             {GL_LINES_ADJACENCY, GL_LINES_ADJACENCY},
7022             {GL_LINES_ADJACENCY, GL_LINE_STRIP_ADJACENCY},
7023             {GL_TRIANGLES, GL_TRIANGLES},
7024             {GL_TRIANGLES, GL_TRIANGLE_STRIP},
7025             {GL_TRIANGLES, GL_TRIANGLE_FAN},
7026             {GL_TRIANGLES_ADJACENCY, GL_TRIANGLES_ADJACENCY},
7027             {GL_TRIANGLES_ADJACENCY, GL_TRIANGLE_STRIP_ADJACENCY},
7028         };
7029 
7030         static const GLenum inputTypes[] = {GL_POINTS, GL_LINES, GL_LINES_ADJACENCY, GL_TRIANGLES,
7031                                             GL_TRIANGLES_ADJACENCY};
7032 
7033         static const GLenum primitiveTypes[] = {GL_POINTS,
7034                                                 GL_LINES,
7035                                                 GL_LINE_LOOP,
7036                                                 GL_LINE_STRIP,
7037                                                 GL_LINES_ADJACENCY,
7038                                                 GL_LINE_STRIP_ADJACENCY,
7039                                                 GL_TRIANGLES,
7040                                                 GL_TRIANGLE_STRIP,
7041                                                 GL_TRIANGLE_FAN,
7042                                                 GL_TRIANGLES_ADJACENCY,
7043                                                 GL_TRIANGLE_STRIP_ADJACENCY};
7044 
7045         for (int inputTypeNdx = 0; inputTypeNdx < DE_LENGTH_OF_ARRAY(inputTypes); ++inputTypeNdx)
7046             for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); ++primitiveTypeNdx)
7047             {
7048                 const GLenum inputType     = inputTypes[inputTypeNdx];
7049                 const GLenum primitiveType = primitiveTypes[primitiveTypeNdx];
7050                 const std::string name     = std::string("type_") +
7051                                          inputTypeToGLString(sglr::rr_util::mapGLGeometryShaderInputType(inputType)) +
7052                                          "_primitive_" + primitiveTypeToString(primitiveType);
7053                 const std::string desc = std::string("Shader input type ") +
7054                                          inputTypeToGLString(sglr::rr_util::mapGLGeometryShaderInputType(inputType)) +
7055                                          ", draw primitive type " + primitiveTypeToString(primitiveType);
7056 
7057                 bool isLegal = false;
7058 
7059                 for (int legalNdx = 0; legalNdx < DE_LENGTH_OF_ARRAY(legalConversions); ++legalNdx)
7060                     if (legalConversions[legalNdx].inputType == inputType &&
7061                         legalConversions[legalNdx].primitiveType == primitiveType)
7062                         isLegal = true;
7063 
7064                 // only illegal
7065                 if (!isLegal)
7066                     negativeGroup->addChild(
7067                         new NegativeDrawCase(m_context, name.c_str(), desc.c_str(), inputType, primitiveType));
7068             }
7069     }
7070 
7071     // vertex transform feedback
7072     {
7073         feedbackGroup->addChild(new VertexFeedbackCase(m_context, "capture_vertex_line_loop", "Capture line loop lines",
7074                                                        VertexFeedbackCase::METHOD_DRAW_ARRAYS,
7075                                                        VertexFeedbackCase::PRIMITIVE_LINE_LOOP));
7076         feedbackGroup->addChild(
7077             new VertexFeedbackCase(m_context, "capture_vertex_line_strip", "Capture line strip lines",
7078                                    VertexFeedbackCase::METHOD_DRAW_ARRAYS, VertexFeedbackCase::PRIMITIVE_LINE_STRIP));
7079         feedbackGroup->addChild(new VertexFeedbackCase(
7080             m_context, "capture_vertex_triangle_strip", "Capture triangle strip triangles",
7081             VertexFeedbackCase::METHOD_DRAW_ARRAYS, VertexFeedbackCase::PRIMITIVE_TRIANGLE_STRIP));
7082         feedbackGroup->addChild(
7083             new VertexFeedbackCase(m_context, "capture_vertex_triangle_fan", "Capture triangle fan triangles",
7084                                    VertexFeedbackCase::METHOD_DRAW_ARRAYS, VertexFeedbackCase::PRIMITIVE_TRIANGLE_FAN));
7085         feedbackGroup->addChild(new VertexFeedbackCase(
7086             m_context, "capture_vertex_draw_arrays", "Capture primitives generated with drawArrays",
7087             VertexFeedbackCase::METHOD_DRAW_ARRAYS, VertexFeedbackCase::PRIMITIVE_POINTS));
7088         feedbackGroup->addChild(new VertexFeedbackCase(
7089             m_context, "capture_vertex_draw_arrays_instanced", "Capture primitives generated with drawArraysInstanced",
7090             VertexFeedbackCase::METHOD_DRAW_ARRAYS_INSTANCED, VertexFeedbackCase::PRIMITIVE_POINTS));
7091         feedbackGroup->addChild(new VertexFeedbackCase(
7092             m_context, "capture_vertex_draw_arrays_indirect", "Capture primitives generated with drawArraysIndirect",
7093             VertexFeedbackCase::METHOD_DRAW_ARRAYS_INDIRECT, VertexFeedbackCase::PRIMITIVE_POINTS));
7094         feedbackGroup->addChild(new VertexFeedbackCase(
7095             m_context, "capture_vertex_draw_elements", "Capture primitives generated with drawElements",
7096             VertexFeedbackCase::METHOD_DRAW_ELEMENTS, VertexFeedbackCase::PRIMITIVE_POINTS));
7097         feedbackGroup->addChild(new VertexFeedbackCase(m_context, "capture_vertex_draw_elements_instanced",
7098                                                        "Capture primitives generated with drawElementsInstanced",
7099                                                        VertexFeedbackCase::METHOD_DRAW_ELEMENTS_INSTANCED,
7100                                                        VertexFeedbackCase::PRIMITIVE_POINTS));
7101         feedbackGroup->addChild(new VertexFeedbackCase(m_context, "capture_vertex_draw_elements_indirect",
7102                                                        "Capture primitives generated with drawElementsIndirect",
7103                                                        VertexFeedbackCase::METHOD_DRAW_ELEMENTS_INDIRECT,
7104                                                        VertexFeedbackCase::PRIMITIVE_POINTS));
7105 
7106         feedbackGroup->addChild(new VertexFeedbackOverflowCase(
7107             m_context, "capture_vertex_draw_arrays_overflow_single_buffer", "Capture triangles to too small a buffer",
7108             VertexFeedbackOverflowCase::METHOD_DRAW_ARRAYS));
7109         feedbackGroup->addChild(new VertexFeedbackOverflowCase(
7110             m_context, "capture_vertex_draw_elements_overflow_single_buffer", "Capture triangles to too small a buffer",
7111             VertexFeedbackOverflowCase::METHOD_DRAW_ELEMENTS));
7112     }
7113 }
7114 
7115 } // namespace Functional
7116 } // namespace gles31
7117 } // namespace deqp
7118