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), ¶ms, 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), ¶ms, 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