1 /*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
4 *
5 * Copyright (c) 2015-2016 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 */ /*!
20 * \file
21 * \brief
22 */ /*-------------------------------------------------------------------*/
23
24 /**
25 */ /*!
26 * \file gl3cCullDistanceTests.cpp
27 * \brief Cull Distance Test Suite Implementation
28 */ /*-------------------------------------------------------------------*/
29
30 #include "gl3cCullDistanceTests.hpp"
31 #include "gluContextInfo.hpp"
32 #include "gluDefs.hpp"
33 #include "gluStrUtil.hpp"
34 #include "glwEnums.hpp"
35 #include "glwFunctions.hpp"
36 #include "tcuRenderTarget.hpp"
37 #include "tcuTestLog.hpp"
38
39 #include <cmath>
40 #include <sstream>
41 #include <string>
42 #include <vector>
43
44 #ifndef GL_MAX_CULL_DISTANCES
45 #define GL_MAX_CULL_DISTANCES (0x82F9)
46 #endif
47 #ifndef GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES
48 #define GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES (0x82FA)
49 #endif
50
51 namespace glcts
52 {
53 /** @brief Build OpenGL program
54 *
55 * @param [in] gl OpenGL function bindings
56 * @param [in] testCtx Context
57 * @param [in] cs_body Compute shader source code
58 * @param [in] fs_body Fragment shader source code
59 * @param [in] gs_body Geometric shader source code
60 * @param [in] tc_body Tessellation control shader source code
61 * @param [in] te_body Tessellation evaluation shader source code
62 * @param [in] vs_body Vertex shader source code
63 * @param [in] n_tf_varyings Number of transform feedback varyings
64 * @param [in] tf_varyings Transform feedback varyings names
65 *
66 * @param [out] out_program If succeeded output program GL handle, 0 otherwise.
67 */
buildProgram(const glw::Functions & gl,tcu::TestContext & testCtx,const glw::GLchar * cs_body,const glw::GLchar * fs_body,const glw::GLchar * gs_body,const glw::GLchar * tc_body,const glw::GLchar * te_body,const glw::GLchar * vs_body,const glw::GLuint & n_tf_varyings,const glw::GLchar ** tf_varyings,glw::GLuint * out_program)68 void CullDistance::Utilities::buildProgram(const glw::Functions &gl, tcu::TestContext &testCtx,
69 const glw::GLchar *cs_body, const glw::GLchar *fs_body,
70 const glw::GLchar *gs_body, const glw::GLchar *tc_body,
71 const glw::GLchar *te_body, const glw::GLchar *vs_body,
72 const glw::GLuint &n_tf_varyings, const glw::GLchar **tf_varyings,
73 glw::GLuint *out_program)
74 {
75 glw::GLuint po_id = 0;
76
77 struct _shaders_configuration
78 {
79 glw::GLenum type;
80 const glw::GLchar *body;
81 glw::GLuint id;
82 } shaders_configuration[] = {{GL_COMPUTE_SHADER, cs_body, 0}, {GL_FRAGMENT_SHADER, fs_body, 0},
83 {GL_GEOMETRY_SHADER, gs_body, 0}, {GL_TESS_CONTROL_SHADER, tc_body, 0},
84 {GL_TESS_EVALUATION_SHADER, te_body, 0}, {GL_VERTEX_SHADER, vs_body, 0}};
85
86 const glw::GLuint n_shaders_configuration = sizeof(shaders_configuration) / sizeof(shaders_configuration[0]);
87
88 /* Guard allocated OpenGL resources */
89 try
90 {
91 /* Create needed programs */
92 po_id = gl.createProgram();
93 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed.");
94
95 for (glw::GLuint n_shader_index = 0; n_shader_index < n_shaders_configuration; n_shader_index++)
96 {
97 if (shaders_configuration[n_shader_index].body != DE_NULL)
98 {
99 /* Generate shader object */
100 shaders_configuration[n_shader_index].id = gl.createShader(shaders_configuration[n_shader_index].type);
101 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed");
102
103 glw::GLint compile_status = GL_FALSE;
104 const glw::GLuint so_id = shaders_configuration[n_shader_index].id;
105
106 /* Assign shader source code */
107 gl.shaderSource(shaders_configuration[n_shader_index].id, 1, /* count */
108 &shaders_configuration[n_shader_index].body, DE_NULL); /* length */
109 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed");
110
111 gl.compileShader(so_id);
112 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
113
114 gl.getShaderiv(so_id, GL_COMPILE_STATUS, &compile_status);
115 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
116
117 if (compile_status == GL_FALSE)
118 {
119 std::vector<glw::GLchar> log_array(1);
120 glw::GLint log_length = 0;
121 std::string log_string("Failed to retrieve log");
122
123 /* Retrive compilation log length */
124 gl.getShaderiv(so_id, GL_INFO_LOG_LENGTH, &log_length);
125 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
126
127 log_array.resize(log_length + 1, 0);
128
129 gl.getShaderInfoLog(so_id, log_length, DE_NULL, &log_array[0]);
130 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderInfoLog() call failed.");
131
132 log_string = std::string(&log_array[0]);
133
134 testCtx.getLog() << tcu::TestLog::Message << "Shader compilation has failed.\n"
135 << "Shader type: " << shaders_configuration[n_shader_index].type << "\n"
136 << "Shader compilation error log:\n"
137 << log_string << "\n"
138 << "Shader source code:\n"
139 << shaders_configuration[n_shader_index].body << "\n"
140 << tcu::TestLog::EndMessage;
141
142 TCU_FAIL("Shader compilation has failed.");
143 }
144
145 /* Also attach the shader to the corresponding program object */
146 gl.attachShader(po_id, so_id);
147
148 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed");
149 } /* if (shaders_configuration[n_shader_index].body != DE_NULL) */
150 } /* for (all shader object IDs) */
151
152 /* Set transform feedback if requested */
153 if (n_tf_varyings > 0)
154 {
155 gl.transformFeedbackVaryings(po_id, n_tf_varyings, tf_varyings, GL_INTERLEAVED_ATTRIBS);
156 GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed");
157 }
158
159 /* Try to link the program objects */
160 if (po_id != 0)
161 {
162 glw::GLint link_status = GL_FALSE;
163
164 gl.linkProgram(po_id);
165 GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed");
166
167 gl.getProgramiv(po_id, GL_LINK_STATUS, &link_status);
168 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed");
169
170 if (link_status == GL_FALSE)
171 {
172 std::vector<glw::GLchar> log_array(1);
173 glw::GLsizei log_length = 0;
174 std::string log_string;
175
176 /* Retreive compilation log length */
177 gl.getProgramiv(po_id, GL_INFO_LOG_LENGTH, &log_length);
178 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
179
180 log_array.resize(log_length + 1, 0);
181
182 /* Retreive compilation log */
183 gl.getProgramInfoLog(po_id, log_length, DE_NULL, &log_array[0]);
184 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInfoLog() call failed.");
185
186 log_string = std::string(&log_array[0]);
187
188 /* Log linking error message */
189 testCtx.getLog() << tcu::TestLog::Message << "Program linking has failed.\n"
190 << "Linking error log:\n"
191 << log_string << "\n"
192 << tcu::TestLog::EndMessage;
193
194 /* Log shader source code of shaders involved */
195 for (glw::GLuint n_shader_index = 0; n_shader_index < n_shaders_configuration; n_shader_index++)
196 {
197 if (shaders_configuration[n_shader_index].body != DE_NULL)
198 {
199 testCtx.getLog() << tcu::TestLog::Message << "Shader source code of type "
200 << shaders_configuration[n_shader_index].type << " follows:\n"
201 << shaders_configuration[n_shader_index].body << "\n"
202 << tcu::TestLog::EndMessage;
203 }
204 }
205
206 TCU_FAIL("Program linking failed");
207 }
208 } /* if (po_id != 0) */
209
210 /* Delete all shaders we've created */
211 for (glw::GLuint n_shader_index = 0; n_shader_index < n_shaders_configuration; n_shader_index++)
212 {
213 const glw::GLuint so_id = shaders_configuration[n_shader_index].id;
214
215 if (so_id != 0)
216 {
217 gl.deleteShader(so_id);
218
219 shaders_configuration[n_shader_index].id = 0;
220
221 GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteShader() call failed.");
222 }
223 }
224
225 /* Store the result progrtam IDs */
226 *out_program = po_id;
227 }
228 catch (...)
229 {
230 /* Delete all shaders we've created */
231 for (glw::GLuint n_shader_index = 0; n_shader_index < n_shaders_configuration; n_shader_index++)
232 {
233 const glw::GLuint so_id = shaders_configuration[n_shader_index].id;
234
235 if (so_id != 0)
236 {
237 gl.deleteShader(so_id);
238
239 shaders_configuration[n_shader_index].id = 0;
240 }
241 }
242
243 /* Delete the program object */
244 if (po_id != 0)
245 {
246 gl.deleteProgram(po_id);
247
248 po_id = 0;
249 }
250
251 /* Rethrow */
252 throw;
253 }
254 }
255
256 /** @brief Replace all occurences of a substring in a string by a substring
257 *
258 * @param [in,out] str string to be edited
259 * @param [in] from substring to be replaced
260 * @param [out] to new substring
261 */
replaceAll(std::string & str,const std::string & from,const std::string & to)262 void CullDistance::Utilities::replaceAll(std::string &str, const std::string &from, const std::string &to)
263 {
264 for (size_t start_pos = str.find(from, 0); start_pos != std::string::npos; start_pos = str.find(from, start_pos))
265 {
266 str.replace(start_pos, from.length(), to);
267
268 start_pos += to.length();
269 }
270
271 return;
272 }
273
274 /** @brief Convert integer to string representation
275 *
276 * @param [in] integer input integer to be converted
277 *
278 * @return String representation of integer
279 */
intToString(glw::GLint integer)280 std::string CullDistance::Utilities::intToString(glw::GLint integer)
281 {
282 std::stringstream temp_sstream;
283
284 temp_sstream << integer;
285
286 return temp_sstream.str();
287 }
288
289 /** Constructor.
290 *
291 * @param context Rendering context handle.
292 **/
APICoverageTest(deqp::Context & context)293 CullDistance::APICoverageTest::APICoverageTest(deqp::Context &context)
294 : TestCase(context, "coverage", "Cull Distance API Coverage Test")
295 , m_bo_id(0)
296 , m_cs_id(0)
297 , m_cs_to_id(0)
298 , m_fbo_draw_id(0)
299 , m_fbo_draw_to_id(0)
300 , m_fbo_read_id(0)
301 , m_fs_id(0)
302 , m_gs_id(0)
303 , m_po_id(0)
304 , m_tc_id(0)
305 , m_te_id(0)
306 , m_vao_id(0)
307 , m_vs_id(0)
308 {
309 /* Left blank on purpose */
310 }
311
312 /** @brief Cull Distance API Coverage Test deinitialization */
deinit()313 void CullDistance::APICoverageTest::deinit()
314 {
315 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
316
317 if (m_bo_id != 0)
318 {
319 gl.deleteBuffers(1, &m_bo_id);
320
321 m_bo_id = 0;
322 }
323
324 if (m_cs_id != 0)
325 {
326 gl.deleteShader(m_cs_id);
327
328 m_cs_id = 0;
329 }
330
331 if (m_cs_to_id != 0)
332 {
333 gl.deleteTextures(1, &m_cs_to_id);
334
335 m_cs_to_id = 0;
336 }
337
338 if (m_fbo_draw_id != 0)
339 {
340 gl.deleteFramebuffers(1, &m_fbo_draw_id);
341
342 m_fbo_draw_id = 0;
343 }
344
345 if (m_fbo_draw_to_id != 0)
346 {
347 gl.deleteTextures(1, &m_fbo_draw_to_id);
348
349 m_fbo_draw_to_id = 0;
350 }
351
352 if (m_fbo_read_id != 0)
353 {
354 gl.deleteFramebuffers(1, &m_fbo_read_id);
355
356 m_fbo_read_id = 0;
357 }
358
359 if (m_fs_id != 0)
360 {
361 gl.deleteShader(m_fs_id);
362
363 m_fs_id = 0;
364 }
365
366 if (m_gs_id != 0)
367 {
368 gl.deleteShader(m_gs_id);
369
370 m_gs_id = 0;
371 }
372
373 if (m_po_id != 0)
374 {
375 gl.deleteProgram(m_po_id);
376
377 m_po_id = 0;
378 }
379
380 if (m_tc_id != 0)
381 {
382 gl.deleteShader(m_tc_id);
383
384 m_tc_id = 0;
385 }
386
387 if (m_te_id != 0)
388 {
389 gl.deleteShader(m_te_id);
390
391 m_te_id = 0;
392 }
393
394 if (m_vao_id != 0)
395 {
396 gl.deleteVertexArrays(1, &m_vao_id);
397
398 m_vao_id = 0;
399 }
400
401 if (m_vs_id != 0)
402 {
403 gl.deleteShader(m_vs_id);
404
405 m_vs_id = 0;
406 }
407
408 /* Restore default pack alignment value */
409 gl.pixelStorei(GL_PACK_ALIGNMENT, 4);
410 }
411
412 /** Executes test iteration.
413 *
414 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
415 */
iterate()416 tcu::TestNode::IterateResult CullDistance::APICoverageTest::iterate()
417 {
418 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
419
420 /* This test should only be executed if ARB_cull_distance is supported, or if
421 * we're running a GL4.5 context
422 */
423 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_cull_distance") &&
424 !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)))
425 {
426 throw tcu::NotSupportedError("GL_ARB_cull_distance is not supported");
427 }
428
429 /* Check that calling GetIntegerv with MAX_CULL_DISTANCES doesn't generate
430 * any errors and returns a value at least 8.
431 *
432 * Check that calling GetIntegerv with MAX_COMBINED_CLIP_AND_CULL_DISTANCES
433 * doesn't generate any errors and returns a value at least 8.
434 *
435 */
436 glw::GLint error_code = GL_NO_ERROR;
437 glw::GLint gl_max_cull_distances_value = 0;
438 glw::GLint gl_max_combined_clip_and_cull_distances_value = 0;
439
440 gl.getIntegerv(GL_MAX_CULL_DISTANCES, &gl_max_cull_distances_value);
441
442 error_code = gl.getError();
443 if (error_code != GL_NO_ERROR)
444 {
445 m_testCtx.getLog() << tcu::TestLog::Message << "glGetIntegerv() returned error code "
446 << "[" << glu::getErrorStr(error_code)
447 << "] for GL_MAX_CULL_DISTANCES"
448 " query instead of GL_NO_ERROR"
449 << tcu::TestLog::EndMessage;
450
451 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
452
453 return STOP;
454 }
455
456 gl.getIntegerv(GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES, &gl_max_combined_clip_and_cull_distances_value);
457
458 error_code = gl.getError();
459 if (error_code != GL_NO_ERROR)
460 {
461 m_testCtx.getLog() << tcu::TestLog::Message << "glGetIntegerv() returned error code "
462 << "[" << glu::getErrorStr(error_code)
463 << "] for "
464 "GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES query "
465 "instead of GL_NO_ERROR"
466 << tcu::TestLog::EndMessage;
467
468 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
469
470 return STOP;
471 }
472
473 /* Before we proceed with the two other tests, initialize a buffer & a texture
474 * object we will need to capture data from the programs */
475 static const glw::GLuint bo_size = sizeof(int) * 4 /* components */ * 4 /* result points */;
476
477 gl.genBuffers(1, &m_bo_id);
478 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
479
480 gl.genFramebuffers(1, &m_fbo_draw_id);
481 gl.genFramebuffers(1, &m_fbo_read_id);
482 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() call(s) failed.");
483
484 gl.genTextures(1, &m_cs_to_id);
485 gl.genTextures(1, &m_fbo_draw_to_id);
486 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed.");
487
488 gl.genVertexArrays(1, &m_vao_id);
489 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
490
491 gl.bindVertexArray(m_vao_id);
492 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
493
494 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
495 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */
496 m_bo_id);
497 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() or glBindBufferBase() call(s) failed.");
498
499 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bo_size, DE_NULL, GL_STATIC_DRAW);
500 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
501
502 for (glw::GLuint n_to_id = 0; n_to_id < 2; /* CS, FBO */ ++n_to_id)
503 {
504 gl.bindTexture(GL_TEXTURE_2D, (n_to_id == 0) ? m_cs_to_id : m_fbo_draw_to_id);
505 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed.");
506
507 gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */
508 GL_R32I, 1, /* width */
509 1); /* height */
510 GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed.");
511 }
512
513 if (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 3)) ||
514 m_context.getContextInfo().isExtensionSupported("GL_ARB_compute_shader"))
515 {
516 gl.bindImageTexture(0, /* unit */
517 m_cs_to_id, 0, /* level */
518 GL_FALSE, /* layered */
519 0, /* layer */
520 GL_WRITE_ONLY, GL_R32I);
521 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindImageTexture() call failed.");
522 }
523
524 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo_draw_id);
525 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed.");
526
527 gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_fbo_draw_to_id, 0); /* level */
528 GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed.");
529
530 gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_read_id);
531 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed.");
532
533 gl.viewport(0, /* x */
534 0, /* y */
535 1, /* width */
536 1); /* height */
537 GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() call failed.");
538
539 gl.pixelStorei(GL_PACK_ALIGNMENT, 1);
540 GLU_EXPECT_NO_ERROR(gl.getError(), "glPixelStorei() call failed.");
541
542 /* There are two new GL constants, where value we need to verify */
543 struct _run
544 {
545 const glw::GLchar *essl_token_value;
546 glw::GLenum gl_enum;
547 glw::GLint gl_value;
548 glw::GLint min_value;
549 const glw::GLchar *name;
550 } runs[] = {{"gl_MaxCullDistances", GL_MAX_CULL_DISTANCES, gl_max_cull_distances_value, 8 /*minimum required */,
551 "GL_MAX_CULL_DISTANCES"},
552 {"gl_MaxCombinedClipAndCullDistances", GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES,
553 gl_max_combined_clip_and_cull_distances_value, 8 /*minimum required */,
554 "GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES"}};
555
556 static const glw::GLuint n_runs = sizeof(runs) / sizeof(runs[0]);
557
558 for (glw::GLuint n_run = 0; n_run < n_runs; ++n_run)
559 {
560 _run ¤t_run = runs[n_run];
561
562 static const struct _stage
563 {
564 bool use_cs;
565 bool use_fs;
566 bool use_gs;
567 bool use_tc;
568 bool use_te;
569 bool use_vs;
570
571 const glw::GLchar *fs_input;
572 const glw::GLchar *gs_input;
573 const glw::GLchar *tc_input;
574 const glw::GLchar *te_input;
575
576 const glw::GLchar *tf_output_name;
577 const glw::GLenum tf_mode;
578
579 glw::GLenum draw_call_mode;
580 glw::GLuint n_draw_call_vertices;
581 } stages[] = {/* CS only test */
582 {
583 /* use_cs|use_fs|use_gs|use_tc|use_te|use_vs */
584 true, false, false, false, false, false,
585
586 NULL, /* fs_input */
587 NULL, /* gs_input */
588 NULL, /* tc_input */
589 NULL, /* te_input */
590 NULL, /* tf_output_name */
591 GL_NONE, /* tf_mode */
592 GL_NONE, /* draw_call_mode */
593 0, /* n_draw_call_vertices */
594 },
595 /* VS+GS+TC+TE+FS test */
596 {
597 /* use_cs|use_fs|use_gs|use_tc|use_te|use_vs */
598 false, true, true, true, true, true,
599
600 "out_gs", /* fs_input */
601 "out_te", /* gs_input */
602 "out_vs", /* tc_input */
603 "out_tc", /* te_input */
604 "out_gs", /* tf_output_name */
605 GL_TRIANGLES, /* tf_mode */
606 GL_PATCHES, /* draw_call_mode */
607 3, /* n_draw_call_vertices */
608 },
609 /* VS+GS+FS test */
610 {
611 /* use_cs|use_fs|use_gs|use_tc|use_te|use_vs */
612 false, true, true, false, false, true,
613
614 "out_gs", /* fs_input */
615 "out_vs", /* gs_input */
616 NULL, /* tc_input */
617 NULL, /* te_input */
618 "out_gs", /* tf_output_name */
619 GL_TRIANGLES, /* tf_mode */
620 GL_POINTS, /* draw_call_mode */
621 1, /* n_draw_call_vertices */
622 },
623 /* VS+TC+TE+FS test */
624 {
625 /* use_cs|use_fs|use_gs|use_tc|use_te|use_vs */
626 false, true, false, true, true, true,
627
628 "out_te", /* fs_input */
629 NULL, /* gs_input */
630 "out_vs", /* tc_input */
631 "out_tc", /* te_input */
632 "out_te", /* tf_output_name */
633 GL_POINTS, /* tf_mode */
634 GL_PATCHES, /* draw_call_mode */
635 3 /* n_draw_call_vertices */
636 },
637 /* VS test */
638 {
639 /* use_cs|use_fs|use_gs|use_tc|use_te|use_vs */
640 false, false, false, false, false, true,
641
642 "out_vs", /* fs_input */
643 NULL, /* gs_input */
644 NULL, /* tc_input */
645 NULL, /* te_input */
646 "out_vs", /* tf_output_name */
647 GL_POINTS, /* tf_mode */
648 GL_POINTS, /* draw_call_mode */
649 1 /* n_draw_call_vertices */
650 }};
651 const glw::GLuint n_stages = sizeof(stages) / sizeof(stages[0]);
652
653 /* Run through all test stages */
654 for (glw::GLuint n_stage = 0; n_stage < n_stages; ++n_stage)
655 {
656 /* Check for OpenGL feature support */
657 if (stages[n_stage].use_cs)
658 {
659 if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 3)) &&
660 !m_context.getContextInfo().isExtensionSupported("GL_ARB_compute_shader"))
661 {
662 continue; // no compute shader support
663 }
664 }
665 if (stages[n_stage].use_tc || stages[n_stage].use_te)
666 {
667 if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 0)) &&
668 !m_context.getContextInfo().isExtensionSupported("GL_ARB_tessellation_shader"))
669 {
670 continue; // no tessellation shader support
671 }
672 }
673
674 /* Check that use of the GLSL built-in constant gl_MaxCullDistance in any
675 * shader stage (including compute shader) does not affect the shader
676 * compilation & program linking process.
677 */
678 static const glw::GLchar *cs_body_template =
679 "#version 420 core\n"
680 "\n"
681 "#extension GL_ARB_compute_shader : require\n"
682 "#extension GL_ARB_cull_distance : require\n"
683 "#extension GL_ARB_shader_image_load_store : require\n"
684 "\n"
685 "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
686 "\n"
687 "layout(r32i) uniform writeonly iimage2D result;\n"
688 "\n"
689 "void main()\n"
690 "{\n"
691 " imageStore(result, ivec2(0),ivec4(TOKEN) );\n"
692 "}\n";
693 std::string cs_body = cs_body_template;
694
695 static const glw::GLchar *fs_body_template = "#version 150\n"
696 "\n"
697 "#extension GL_ARB_cull_distance : require\n"
698 "\n"
699 "flat in int INPUT_FS_NAME;\n"
700 "out int out_fs;\n"
701 "\n"
702 "void main()\n"
703 "{\n"
704 " if (INPUT_FS_NAME == TOKEN)\n"
705 " {\n"
706 " out_fs = TOKEN;\n"
707 " }\n"
708 " else\n"
709 " {\n"
710 " out_fs = -1;\n"
711 " }\n"
712 "}\n";
713 std::string fs_body = fs_body_template;
714
715 static const glw::GLchar *gs_body_template =
716 "#version 150\n"
717 "\n"
718 "#extension GL_ARB_cull_distance : require\n"
719 "\n"
720 "flat in int INPUT_GS_NAME[];\n"
721 "flat out int out_gs;\n"
722 "\n"
723 "layout(points) in;\n"
724 "layout(triangle_strip, max_vertices = 4) out;\n"
725 "\n"
726 "void main()\n"
727 "{\n"
728 " int result_value = (INPUT_GS_NAME[0] == TOKEN) ? TOKEN : -1;\n"
729 "\n"
730 /* Draw a full-screen quad */
731 " gl_Position = vec4(-1.0, 1.0, 0.0, 1.0);\n"
732 " out_gs = result_value;\n"
733 " EmitVertex();\n"
734 "\n"
735 " gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
736 " out_gs = result_value;\n"
737 " EmitVertex();\n"
738 "\n"
739 " gl_Position = vec4(1.0, 1.0, 0.0, 1.0);\n"
740 " out_gs = result_value;\n"
741 " EmitVertex();\n"
742 "\n"
743 " gl_Position = vec4(1.0, -1.0, 0.0, 1.0);\n"
744 " out_gs = result_value;\n"
745 " EmitVertex();\n"
746 " EndPrimitive();\n"
747 "}\n";
748 std::string gs_body = gs_body_template;
749
750 static const glw::GLchar *tc_body_template =
751 "#version 150\n"
752 "\n"
753 "#extension GL_ARB_cull_distance : require\n"
754 "#extension GL_ARB_tessellation_shader : require\n"
755 "\n"
756 "layout(vertices = 1) out;\n"
757 "\n"
758 "flat in int INPUT_TC_NAME[];\n"
759 "flat out int out_tc [];\n"
760 "\n"
761 "void main()\n"
762 "{\n"
763 " int result_value = (INPUT_TC_NAME[0] == TOKEN) ? TOKEN : -1;\n"
764 "\n"
765 " out_tc[gl_InvocationID] = result_value;\n"
766 " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
767 " gl_TessLevelInner[0] = 1.0;\n"
768 " gl_TessLevelInner[1] = 1.0;\n"
769 " gl_TessLevelOuter[0] = 1.0;\n"
770 " gl_TessLevelOuter[1] = 1.0;\n"
771 " gl_TessLevelOuter[2] = 1.0;\n"
772 " gl_TessLevelOuter[3] = 1.0;\n"
773 "}\n";
774 std::string tc_body = tc_body_template;
775
776 static const glw::GLchar *te_body_template =
777 "#version 150\n"
778 "\n"
779 "#extension GL_ARB_cull_distance : require\n"
780 "#extension GL_ARB_tessellation_shader : require\n"
781 "\n"
782 "flat in int INPUT_TE_NAME[];\n"
783 "flat out int out_te;\n"
784 "\n"
785 "layout(isolines, point_mode) in;\n"
786 "\n"
787 "void main()\n"
788 "{\n"
789 " int result_value = (INPUT_TE_NAME[0] == TOKEN) ? TOKEN : 0;\n"
790 "\n"
791 " out_te = result_value;\n"
792 "\n"
793 " gl_Position = vec4(0.0, 0.0, 0.0, 1.);\n"
794 "}\n";
795 std::string te_body = te_body_template;
796
797 static const glw::GLchar *vs_body_template = "#version 150\n"
798 "\n"
799 "#extension GL_ARB_cull_distance : require\n"
800 "\n"
801 "flat out int out_vs;\n"
802 "\n"
803 "void main()\n"
804 "{\n"
805 " gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
806 " out_vs = TOKEN;\n"
807 "}\n";
808 std::string vs_body = vs_body_template;
809
810 const _stage ¤t_stage = stages[n_stage];
811
812 /* Build shader bodies */
813 struct _shader_body
814 {
815 std::string *body_ptr;
816 glw::GLenum gl_type;
817 } shader_bodies[] = {{&cs_body, GL_COMPUTE_SHADER}, {&fs_body, GL_FRAGMENT_SHADER},
818 {&gs_body, GL_GEOMETRY_SHADER}, {&tc_body, GL_TESS_CONTROL_SHADER},
819 {&te_body, GL_TESS_EVALUATION_SHADER}, {&vs_body, GL_VERTEX_SHADER}};
820 static const glw::GLchar *input_fs_token_string = "INPUT_FS_NAME";
821 static const glw::GLchar *input_gs_token_string = "INPUT_GS_NAME";
822 static const glw::GLchar *input_te_token_string = "INPUT_TE_NAME";
823 static const glw::GLchar *input_tc_token_string = "INPUT_TC_NAME";
824 static const glw::GLuint n_shader_bodies = sizeof(shader_bodies) / sizeof(shader_bodies[0]);
825
826 std::size_t token_position = std::string::npos;
827 static const glw::GLchar *token_string = "TOKEN";
828
829 for (glw::GLuint n_shader_body = 0; n_shader_body < n_shader_bodies; ++n_shader_body)
830 {
831 _shader_body ¤t_body = shader_bodies[n_shader_body];
832
833 /* Is this stage actually used? */
834 if (((current_body.gl_type == GL_COMPUTE_SHADER) && (!current_stage.use_cs)) ||
835 ((current_body.gl_type == GL_FRAGMENT_SHADER) && (!current_stage.use_fs)) ||
836 ((current_body.gl_type == GL_TESS_CONTROL_SHADER) && (!current_stage.use_tc)) ||
837 ((current_body.gl_type == GL_TESS_EVALUATION_SHADER) && (!current_stage.use_te)) ||
838 ((current_body.gl_type == GL_VERTEX_SHADER) && (!current_stage.use_vs)))
839 {
840 /* Skip the iteration. */
841 continue;
842 }
843
844 /* Iterate over all token and replace them with stage-specific values */
845 struct _token_value_pair
846 {
847 const glw::GLchar *token;
848 const glw::GLchar *value;
849 } token_value_pairs[] = {
850 /* NOTE: The last entry is filled by the switch() block below */
851 {token_string, current_run.essl_token_value},
852 {NULL, NULL},
853 };
854
855 const size_t n_token_value_pairs = sizeof(token_value_pairs) / sizeof(token_value_pairs[0]);
856
857 switch (current_body.gl_type)
858 {
859 case GL_COMPUTE_SHADER:
860 case GL_VERTEX_SHADER:
861 break;
862
863 case GL_FRAGMENT_SHADER:
864 {
865 token_value_pairs[1].token = input_fs_token_string;
866 token_value_pairs[1].value = current_stage.fs_input;
867
868 break;
869 }
870
871 case GL_GEOMETRY_SHADER:
872 {
873 token_value_pairs[1].token = input_gs_token_string;
874 token_value_pairs[1].value = current_stage.gs_input;
875
876 break;
877 }
878
879 case GL_TESS_CONTROL_SHADER:
880 {
881 token_value_pairs[1].token = input_tc_token_string;
882 token_value_pairs[1].value = current_stage.tc_input;
883
884 break;
885 }
886
887 case GL_TESS_EVALUATION_SHADER:
888 {
889 token_value_pairs[1].token = input_te_token_string;
890 token_value_pairs[1].value = current_stage.te_input;
891
892 break;
893 }
894
895 default:
896 TCU_FAIL("Unrecognized shader body type");
897 }
898
899 for (glw::GLuint n_pair = 0; n_pair < n_token_value_pairs; ++n_pair)
900 {
901 const _token_value_pair ¤t_pair = token_value_pairs[n_pair];
902
903 if (current_pair.token == NULL || current_pair.value == NULL)
904 {
905 continue;
906 }
907
908 while ((token_position = current_body.body_ptr->find(current_pair.token)) != std::string::npos)
909 {
910 current_body.body_ptr->replace(token_position, strlen(current_pair.token), current_pair.value);
911 }
912 } /* for (all token+value pairs) */
913 } /* for (all sader bodies) */
914
915 /* Build the test program */
916 CullDistance::Utilities::buildProgram(
917 gl, m_testCtx, current_stage.use_cs ? cs_body.c_str() : DE_NULL,
918 current_stage.use_fs ? fs_body.c_str() : DE_NULL, current_stage.use_gs ? gs_body.c_str() : DE_NULL,
919 current_stage.use_tc ? tc_body.c_str() : DE_NULL, current_stage.use_te ? te_body.c_str() : DE_NULL,
920 current_stage.use_vs ? vs_body.c_str() : DE_NULL, (current_stage.tf_output_name != NULL) ? 1 : 0,
921 (const glw::GLchar **)¤t_stage.tf_output_name, &m_po_id);
922
923 /* Bind the test program */
924 DE_ASSERT(m_po_id != 0);
925
926 gl.useProgram(m_po_id);
927 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
928
929 /* Execute the draw call. Transform Feed-back should be enabled for all iterations
930 * par the CS one, since we use a different tool to capture the result data in the
931 * latter case.
932 */
933 if (!current_stage.use_cs)
934 {
935 gl.beginTransformFeedback(current_stage.tf_mode);
936 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed.");
937
938 gl.drawArrays(current_stage.draw_call_mode, 0, /* first */
939 current_stage.n_draw_call_vertices); /* count */
940 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed.");
941
942 gl.endTransformFeedback();
943 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed.");
944 } /* if (uses_tf) */
945 else
946 {
947 gl.dispatchCompute(1, /* num_groups_x */
948 1, /* num_groups_y */
949 1); /* num_groups_z */
950 GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute() call failed.");
951 }
952
953 /* Verify the result values */
954 if (!current_stage.use_cs)
955 {
956 glw::GLint *result_data_ptr = DE_NULL;
957
958 /* Retrieve the data captured by Transform Feedback */
959 result_data_ptr = (glw::GLint *)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
960 sizeof(unsigned int) * 1, GL_MAP_READ_BIT);
961 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed.");
962
963 if (*result_data_ptr != current_run.gl_value)
964 {
965 m_testCtx.getLog() << tcu::TestLog::Message << current_run.name
966 << " value "
967 "["
968 << *result_data_ptr
969 << "]"
970 " does not match the one reported by glGetIntegerv() "
971 "["
972 << current_run.gl_value << "]" << tcu::TestLog::EndMessage;
973
974 TCU_FAIL("GL constant value does not match the ES SL equivalent");
975 }
976
977 if (*result_data_ptr < current_run.min_value)
978 {
979 m_testCtx.getLog() << tcu::TestLog::Message << current_run.name
980 << " value "
981 "["
982 << *result_data_ptr
983 << "]"
984 " does not meet the minimum specification requirements "
985 "["
986 << current_run.min_value << "]" << tcu::TestLog::EndMessage;
987
988 TCU_FAIL("GL constant value does not meet minimum specification requirements");
989 }
990
991 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
992 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed.");
993 }
994
995 for (glw::GLuint n_stage_internal = 0; n_stage_internal < 2; /* CS, FS write to separate textures */
996 ++n_stage_internal)
997 {
998 glw::GLuint to_id = (n_stage_internal == 0) ? m_cs_to_id : m_fbo_draw_to_id;
999
1000 if (((n_stage_internal == 0) && (!current_stage.use_cs)) ||
1001 ((n_stage_internal == 1) && (!current_stage.use_fs)))
1002 {
1003 /* Skip the iteration */
1004 continue;
1005 }
1006
1007 /* Check the image data the test CS / FS should have written */
1008 glw::GLint result_value = 0;
1009
1010 gl.framebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, to_id, 0); /* level */
1011 GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed.");
1012
1013 /* NOTE: We're using our custom read framebuffer here, so we'll be reading
1014 * from the texture, that the writes have been issued to earlier. */
1015 gl.finish();
1016 GLU_EXPECT_NO_ERROR(gl.getError(), "glMemoryBarrier() call failed.");
1017
1018 gl.readPixels(0, /* x */
1019 0, /* y */
1020 1, /* width */
1021 1, /* height */
1022 GL_RED_INTEGER, GL_INT, &result_value);
1023 GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() call failed.");
1024
1025 if (result_value != current_run.gl_value)
1026 {
1027 m_testCtx.getLog() << tcu::TestLog::Message << current_run.name
1028 << " value accessible to the compute / fragment shader "
1029 "["
1030 << result_value
1031 << "]"
1032 " does not match the one reported by glGetIntegerv() "
1033 "["
1034 << current_run.gl_value << "]" << tcu::TestLog::EndMessage;
1035
1036 TCU_FAIL("GL constant value does not match the ES SL equivalent");
1037 }
1038
1039 if (result_value < current_run.min_value)
1040 {
1041 m_testCtx.getLog() << tcu::TestLog::Message << current_run.name
1042 << " value accessible to the compute / fragment shader "
1043 "["
1044 << result_value
1045 << "]"
1046 " does not meet the minimum specification requirements "
1047 "["
1048 << current_run.min_value << "]" << tcu::TestLog::EndMessage;
1049
1050 TCU_FAIL("GL constant value does not meet minimum specification requirements");
1051 }
1052 }
1053
1054 /* Clear the data buffer before we continue */
1055 static const glw::GLubyte bo_clear_data[bo_size] = {0};
1056
1057 gl.bufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
1058 bo_size, bo_clear_data);
1059 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferSubData() call failed.");
1060
1061 /* Clear the texture mip-map before we continue */
1062 glw::GLint clear_values[4] = {0, 0, 0, 0};
1063
1064 gl.clearBufferiv(GL_COLOR, 0, /* drawbuffer */
1065 clear_values);
1066 GLU_EXPECT_NO_ERROR(gl.getError(), "glClearBufferiv() call failed.");
1067
1068 /* Release program before we move on to the next iteration */
1069 if (m_po_id != 0)
1070 {
1071 gl.deleteProgram(m_po_id);
1072
1073 m_po_id = 0;
1074 }
1075 } /* for (all stages) */
1076 } /* for (both runs) */
1077
1078 /* All done */
1079 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1080
1081 return STOP;
1082 }
1083
1084 /** Constructor.
1085 *
1086 * @param context Rendering context handle.
1087 **/
FunctionalTest(deqp::Context & context)1088 CullDistance::FunctionalTest::FunctionalTest(deqp::Context &context)
1089 : TestCase(context, "functional", "Cull Distance Functional Test")
1090 , m_bo_data()
1091 , m_bo_id(0)
1092 , m_fbo_id(0)
1093 , m_po_id(0)
1094 , m_render_primitives(0)
1095 , m_render_vertices(0)
1096 , m_sub_grid_cell_size(0)
1097 , m_to_id(0)
1098 , m_vao_id(0)
1099 , m_to_height(512)
1100 , m_to_width(512)
1101 , m_to_pixel_data_cache()
1102 {
1103 /* Left blank on purpose */
1104 }
1105
1106 /** @brief Build OpenGL program for functional tests
1107 *
1108 * @param [in] clipdistances_array_size use size of gl_ClipDistance array
1109 * @param [in] culldistances_array_size use size of gl_CullDistance array
1110 * @param [in] dynamic_index_writes use dunamic indexing for setting the gl_ClipDistance and gl_CullDistance arrays
1111 * @param [in] primitive_mode primitive_mode will be used for rendering
1112 * @param [in] redeclare_clipdistances redeclare gl_ClipDistance
1113 * @param [in] redeclare_culldistances redeclare gl_CullDistance
1114 * @param [in] use_core_functionality use core OpenGL functionality
1115 * @param [in] use_gs use geometry shader
1116 * @param [in] use_ts use tessellation shader
1117 * @param [in] fetch_culldistance_from_fs fetch check sum of gl_ClipDistance and gl_CullDistance from fragment shader
1118 */
buildPO(glw::GLuint clipdistances_array_size,glw::GLuint culldistances_array_size,bool dynamic_index_writes,_primitive_mode primitive_mode,bool redeclare_clipdistances,bool redeclare_culldistances,bool use_core_functionality,bool use_gs,bool use_ts,bool fetch_culldistance_from_fs)1119 void CullDistance::FunctionalTest::buildPO(glw::GLuint clipdistances_array_size, glw::GLuint culldistances_array_size,
1120 bool dynamic_index_writes, _primitive_mode primitive_mode,
1121 bool redeclare_clipdistances, bool redeclare_culldistances,
1122 bool use_core_functionality, bool use_gs, bool use_ts,
1123 bool fetch_culldistance_from_fs)
1124 {
1125 deinitPO();
1126
1127 /* Form the vertex shader */
1128 glw::GLuint clipdistances_input_size =
1129 clipdistances_array_size > 0 ? clipdistances_array_size : 1; /* Avoid zero-sized array compilation error */
1130 glw::GLuint culldistances_input_size =
1131 culldistances_array_size > 0 ? culldistances_array_size : 1; /* Avoid zero-sized array compilation error */
1132 static const glw::GLchar *dynamic_array_setters =
1133 "\n"
1134 "#if TEMPLATE_N_GL_CLIPDISTANCE_ENTRIES\n"
1135 " for (int n_clipdistance_entry = 0;\n"
1136 " n_clipdistance_entry < TEMPLATE_N_GL_CLIPDISTANCE_ENTRIES;\n"
1137 " ++n_clipdistance_entry)\n"
1138 " {\n"
1139 " ASSIGN_CLIP_DISTANCE(n_clipdistance_entry);\n"
1140 " }\n"
1141 "#endif"
1142 "\n"
1143 "#if TEMPLATE_N_GL_CULLDISTANCE_ENTRIES \n"
1144 " for (int n_culldistance_entry = 0;\n"
1145 " n_culldistance_entry < TEMPLATE_N_GL_CULLDISTANCE_ENTRIES;\n"
1146 " ++n_culldistance_entry)\n"
1147 " {\n"
1148 " ASSIGN_CULL_DISTANCE(n_culldistance_entry);\n"
1149 " }\n"
1150 "#endif\n";
1151
1152 static const glw::GLchar *core_functionality = "#version 450\n";
1153
1154 static const glw::GLchar *extention_functionality = "#version 150\n"
1155 "\n"
1156 "#extension GL_ARB_cull_distance : require\n"
1157 "TEMPLATE_EXTENSIONS\n"
1158 "\n"
1159 "#ifndef GL_ARB_cull_distance\n"
1160 " #error GL_ARB_cull_distance is undefined\n"
1161 "#endif\n";
1162
1163 static const glw::GLchar *fetch_function = "highp float fetch()\n"
1164 "{\n"
1165 " highp float sum = 0.0;\n"
1166 "\n"
1167 "TEMPLATE_SUM_SETTER"
1168 "\n"
1169 " return sum / TEMPLATE_SUM_DIVIDER;\n"
1170 "}\n"
1171 "\n"
1172 "#define ASSIGN_RETURN_VALUE fetch()";
1173
1174 static const glw::GLchar *fs_template = "TEMPLATE_HEADER_DECLARATION\n"
1175 "\n"
1176 "TEMPLATE_REDECLARE_CLIPDISTANCE\n"
1177 "TEMPLATE_REDECLARE_CULLDISTANCE\n"
1178 "\n"
1179 "TEMPLATE_ASSIGN_RETURN_VALUE\n"
1180 "\n"
1181 "out vec4 out_fs;\n"
1182 "\n"
1183 "/* Fragment shader main function */\n"
1184 "void main()\n"
1185 "{\n"
1186 " out_fs = vec4(ASSIGN_RETURN_VALUE, 1.0, 1.0, 1.0);\n"
1187 "}\n";
1188
1189 static const glw::GLchar *gs_template = "TEMPLATE_HEADER_DECLARATION\n"
1190 "\n"
1191 "TEMPLATE_LAYOUT_IN\n"
1192 "TEMPLATE_LAYOUT_OUT\n"
1193 "\n"
1194 "TEMPLATE_REDECLARE_CLIPDISTANCE\n"
1195 "TEMPLATE_REDECLARE_CULLDISTANCE\n"
1196 "\n"
1197 "#define ASSIGN_CLIP_DISTANCE(IDX) TEMPLATE_ASSIGN_CLIP_DISTANCE\n"
1198 "#define ASSIGN_CULL_DISTANCE(IDX) TEMPLATE_ASSIGN_CULL_DISTANCE\n"
1199 "\n"
1200 "/* Geometry shader (passthrough) main function */\n"
1201 "void main()\n"
1202 "{\n"
1203 " for (int n_vertex_index = 0;\n"
1204 " n_vertex_index < gl_in.length();\n"
1205 " n_vertex_index ++)\n"
1206 " {\n"
1207 " gl_Position = gl_in[n_vertex_index].gl_Position;\n"
1208 "\n"
1209 " TEMPLATE_ARRAY_SETTERS\n"
1210 "\n"
1211 " EmitVertex();\n"
1212 " }\n"
1213 "\n"
1214 " EndPrimitive();\n"
1215 "}\n";
1216
1217 static const glw::GLchar *tc_template =
1218 "TEMPLATE_HEADER_DECLARATION\n"
1219 "\n"
1220 "TEMPLATE_LAYOUT_OUT\n"
1221 "\n"
1222 "out gl_PerVertex {\n"
1223 "TEMPLATE_REDECLARE_CLIPDISTANCE\n"
1224 "TEMPLATE_REDECLARE_CULLDISTANCE\n"
1225 "vec4 gl_Position;\n"
1226 "} gl_out[];\n"
1227 "\n"
1228 "#define ASSIGN_CLIP_DISTANCE(IDX) TEMPLATE_ASSIGN_CLIP_DISTANCE\n"
1229 "#define ASSIGN_CULL_DISTANCE(IDX) TEMPLATE_ASSIGN_CULL_DISTANCE\n"
1230 "\n"
1231 "/* Tesselation control shader main function */\n"
1232 "void main()\n"
1233 "{\n"
1234 " gl_TessLevelInner[0] = 1.0;\n"
1235 " gl_TessLevelInner[1] = 1.0;\n"
1236 " gl_TessLevelOuter[0] = 1.0;\n"
1237 " gl_TessLevelOuter[1] = 1.0;\n"
1238 " gl_TessLevelOuter[2] = 1.0;\n"
1239 " gl_TessLevelOuter[3] = 1.0;\n"
1240 " /* Clipdistance and culldistance array setters */\n"
1241 " {\n"
1242 " TEMPLATE_ARRAY_SETTERS\n"
1243 " }\n"
1244 " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
1245 "}\n";
1246
1247 static const glw::GLchar *te_template = "TEMPLATE_HEADER_DECLARATION\n"
1248 "\n"
1249 "TEMPLATE_LAYOUT_IN\n"
1250 "\n"
1251 "in gl_PerVertex {\n"
1252 "TEMPLATE_REDECLARE_IN_CLIPDISTANCE\n"
1253 "TEMPLATE_REDECLARE_IN_CULLDISTANCE\n"
1254 "vec4 gl_Position;\n"
1255 "} gl_in[];\n"
1256 "\n"
1257 "TEMPLATE_REDECLARE_CLIPDISTANCE\n"
1258 "TEMPLATE_REDECLARE_CULLDISTANCE\n"
1259 "\n"
1260 "#define ASSIGN_CLIP_DISTANCE(IDX) TEMPLATE_ASSIGN_CLIP_DISTANCE\n"
1261 "#define ASSIGN_CULL_DISTANCE(IDX) TEMPLATE_ASSIGN_CULL_DISTANCE\n"
1262 "\n"
1263 "/* Tesselation evaluation shader main function */\n"
1264 "void main()\n"
1265 "{\n"
1266 " /* Clipdistance and culldistance array setters */\n"
1267 " {\n"
1268 " TEMPLATE_ARRAY_SETTERS\n"
1269 " }\n"
1270 " gl_Position = TEMPLATE_OUT_FORMULA;\n"
1271 "}\n";
1272
1273 static const glw::GLchar *vs_template =
1274 "TEMPLATE_HEADER_DECLARATION\n"
1275 "\n"
1276 "in float clipdistance_data[TEMPLATE_CLIPDISTANCE_INPUT_SIZE];\n"
1277 "in float culldistance_data[TEMPLATE_CULLDISTANCE_INPUT_SIZE];\n"
1278 "in vec2 position;\n"
1279 "\n"
1280 "TEMPLATE_REDECLARE_CLIPDISTANCE\n"
1281 "TEMPLATE_REDECLARE_CULLDISTANCE\n"
1282 "\n"
1283 "#define ASSIGN_CLIP_DISTANCE(IDX) TEMPLATE_ASSIGN_CLIP_DISTANCE\n"
1284 "#define ASSIGN_CULL_DISTANCE(IDX) TEMPLATE_ASSIGN_CULL_DISTANCE\n"
1285 "\n"
1286 "/* Vertex shader main function */\n"
1287 "void main()\n"
1288 "{\n"
1289 " /* Clipdistance and culldistance array setters */\n"
1290 " {\n"
1291 " TEMPLATE_ARRAY_SETTERS\n"
1292 " }\n"
1293 " gl_Position = vec4(2.0 * position.x - 1.0, 2.0 * position.y - 1.0, 0.0, 1.0);\n"
1294 "}\n";
1295
1296 std::string *shader_body_string_fs = DE_NULL;
1297 std::string *shader_body_string_gs = DE_NULL;
1298 std::string *shader_body_string_tc = DE_NULL;
1299 std::string *shader_body_string_te = DE_NULL;
1300 std::string *shader_body_string_vs = DE_NULL;
1301 std::string shader_header_declaration = use_core_functionality ? core_functionality : extention_functionality;
1302
1303 struct _shaders_configuration
1304 {
1305 glw::GLenum type;
1306 const glw::GLchar *shader_template;
1307 std::string body;
1308 const bool use;
1309 } shaders_configuration[] = {{
1310 GL_FRAGMENT_SHADER,
1311 fs_template,
1312 std::string(),
1313 true,
1314 },
1315 {
1316 GL_GEOMETRY_SHADER,
1317 gs_template,
1318 std::string(),
1319 use_gs,
1320 },
1321 {
1322 GL_TESS_CONTROL_SHADER,
1323 tc_template,
1324 std::string(),
1325 use_ts,
1326 },
1327 {
1328 GL_TESS_EVALUATION_SHADER,
1329 te_template,
1330 std::string(),
1331 use_ts,
1332 },
1333 {
1334 GL_VERTEX_SHADER,
1335 vs_template,
1336 std::string(),
1337 true,
1338 }};
1339
1340 const glw::GLuint n_shaders_configuration = sizeof(shaders_configuration) / sizeof(shaders_configuration[0]);
1341
1342 /* Construct shader bodies out of templates */
1343 for (glw::GLuint n_shader_index = 0; n_shader_index < n_shaders_configuration; n_shader_index++)
1344 {
1345 if (shaders_configuration[n_shader_index].use)
1346 {
1347 std::string array_setters;
1348 std::string clipdistance_array_declaration;
1349 std::string culldistance_array_declaration;
1350 std::string clipdistance_in_array_declaration;
1351 std::string culldistance_in_array_declaration;
1352 std::string &shader_source = shaders_configuration[n_shader_index].body;
1353
1354 /* Copy template into shader body source */
1355 shader_source = shaders_configuration[n_shader_index].shader_template;
1356
1357 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_HEADER_DECLARATION"),
1358 shader_header_declaration);
1359
1360 /* Shader-specific actions */
1361 switch (shaders_configuration[n_shader_index].type)
1362 {
1363 case GL_FRAGMENT_SHADER:
1364 {
1365 shader_body_string_fs = &shaders_configuration[n_shader_index].body;
1366
1367 if (fetch_culldistance_from_fs)
1368 {
1369 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_ASSIGN_RETURN_VALUE"),
1370 std::string(fetch_function));
1371
1372 std::string fetch_sum_setters = "";
1373 for (glw::GLuint i = 0; i < clipdistances_array_size; ++i)
1374 {
1375 fetch_sum_setters.append(" sum += abs(gl_ClipDistance[");
1376 fetch_sum_setters.append(CullDistance::Utilities::intToString(i));
1377 fetch_sum_setters.append("]) * ");
1378 fetch_sum_setters.append(CullDistance::Utilities::intToString(i + 1));
1379 fetch_sum_setters.append(".0;\n");
1380 }
1381
1382 fetch_sum_setters.append("\n");
1383
1384 for (glw::GLuint i = 0; i < culldistances_array_size; ++i)
1385 {
1386 fetch_sum_setters.append(" sum += abs(gl_CullDistance[");
1387 fetch_sum_setters.append(CullDistance::Utilities::intToString(i));
1388 fetch_sum_setters.append("]) * ");
1389 fetch_sum_setters.append(
1390 CullDistance::Utilities::intToString(i + 1 + clipdistances_array_size));
1391 fetch_sum_setters.append(".0;\n");
1392 }
1393
1394 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_SUM_SETTER"),
1395 std::string(fetch_sum_setters));
1396 CullDistance::Utilities::replaceAll(
1397 shader_source, std::string("TEMPLATE_SUM_DIVIDER"),
1398 std::string(CullDistance::Utilities::intToString(
1399 (clipdistances_array_size + culldistances_array_size) *
1400 ((clipdistances_array_size + culldistances_array_size + 1))))
1401 .append(".0"));
1402 }
1403 else
1404 {
1405 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_ASSIGN_RETURN_VALUE"),
1406 std::string("#define ASSIGN_RETURN_VALUE 1.0"));
1407 }
1408
1409 break;
1410 }
1411
1412 case GL_GEOMETRY_SHADER:
1413 {
1414 shader_body_string_gs = &shaders_configuration[n_shader_index].body;
1415
1416 CullDistance::Utilities::replaceAll(
1417 shader_source, std::string("TEMPLATE_ASSIGN_CLIP_DISTANCE"),
1418 std::string("gl_ClipDistance[IDX] = gl_in[n_vertex_index].gl_ClipDistance[IDX]"));
1419 CullDistance::Utilities::replaceAll(
1420 shader_source, std::string("TEMPLATE_ASSIGN_CULL_DISTANCE"),
1421 std::string("gl_CullDistance[IDX] = gl_in[n_vertex_index].gl_CullDistance[IDX]"));
1422
1423 switch (primitive_mode)
1424 {
1425 case PRIMITIVE_MODE_LINES:
1426 {
1427 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_IN"),
1428 std::string("layout(lines) in;"));
1429 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_OUT"),
1430 std::string("layout(line_strip, max_vertices = 2) out;"));
1431
1432 break;
1433 }
1434 case PRIMITIVE_MODE_POINTS:
1435 {
1436 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_IN"),
1437 std::string("layout(points) in;"));
1438 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_OUT"),
1439 std::string("layout(points, max_vertices = 1) out;"));
1440
1441 break;
1442 }
1443 case PRIMITIVE_MODE_TRIANGLES:
1444 {
1445 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_IN"),
1446 std::string("layout(triangles) in;"));
1447 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_OUT"),
1448 std::string("layout(triangle_strip, max_vertices = 3) out;"));
1449
1450 break;
1451 }
1452 default:
1453 TCU_FAIL("Unknown primitive mode");
1454 }
1455
1456 break;
1457 }
1458
1459 case GL_TESS_CONTROL_SHADER:
1460 {
1461 shader_body_string_tc = &shaders_configuration[n_shader_index].body;
1462
1463 CullDistance::Utilities::replaceAll(
1464 shader_source, std::string("TEMPLATE_ASSIGN_CLIP_DISTANCE"),
1465 std::string(
1466 "gl_out[gl_InvocationID].gl_ClipDistance[IDX] = gl_in[gl_InvocationID].gl_ClipDistance[IDX]"));
1467 CullDistance::Utilities::replaceAll(
1468 shader_source, std::string("TEMPLATE_ASSIGN_CULL_DISTANCE"),
1469 std::string(
1470 "gl_out[gl_InvocationID].gl_CullDistance[IDX] = gl_in[gl_InvocationID].gl_CullDistance[IDX]"));
1471
1472 switch (primitive_mode)
1473 {
1474 case PRIMITIVE_MODE_LINES:
1475 {
1476 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_OUT"),
1477 std::string("layout(vertices = 2) out;"));
1478
1479 break;
1480 }
1481 case PRIMITIVE_MODE_POINTS:
1482 {
1483 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_OUT"),
1484 std::string("layout(vertices = 1) out;"));
1485
1486 break;
1487 }
1488 case PRIMITIVE_MODE_TRIANGLES:
1489 {
1490 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_OUT"),
1491 std::string("layout(vertices = 3) out;"));
1492
1493 break;
1494 }
1495 default:
1496 TCU_FAIL("Unknown primitive mode");
1497 }
1498
1499 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_EXTENSIONS"),
1500 std::string("#extension GL_ARB_tessellation_shader: require"));
1501 break;
1502 }
1503
1504 case GL_TESS_EVALUATION_SHADER:
1505 {
1506 shader_body_string_te = &shaders_configuration[n_shader_index].body;
1507
1508 switch (primitive_mode)
1509 {
1510 case PRIMITIVE_MODE_LINES:
1511 {
1512 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_IN"),
1513 std::string("layout(isolines) in;"));
1514 CullDistance::Utilities::replaceAll(
1515 shader_source, std::string("TEMPLATE_OUT_FORMULA"),
1516 std::string("mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x)"));
1517 CullDistance::Utilities::replaceAll(
1518 shader_source, std::string("TEMPLATE_ASSIGN_CLIP_DISTANCE"),
1519 std::string("gl_ClipDistance[IDX] = mix(gl_in[0].gl_ClipDistance[IDX], "
1520 "gl_in[1].gl_ClipDistance[IDX], gl_TessCoord.x)"));
1521 CullDistance::Utilities::replaceAll(
1522 shader_source, std::string("TEMPLATE_ASSIGN_CULL_DISTANCE"),
1523 std::string("gl_CullDistance[IDX] = mix(gl_in[0].gl_CullDistance[IDX], "
1524 "gl_in[1].gl_CullDistance[IDX], gl_TessCoord.x)"));
1525
1526 break;
1527 }
1528 case PRIMITIVE_MODE_POINTS:
1529 {
1530 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_IN"),
1531 std::string("layout(isolines, point_mode) in;"));
1532 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_OUT_FORMULA"),
1533 std::string("gl_in[0].gl_Position"));
1534 CullDistance::Utilities::replaceAll(
1535 shader_source, std::string("TEMPLATE_ASSIGN_CLIP_DISTANCE"),
1536 std::string("gl_ClipDistance[IDX] = gl_in[0].gl_ClipDistance[IDX]"));
1537 CullDistance::Utilities::replaceAll(
1538 shader_source, std::string("TEMPLATE_ASSIGN_CULL_DISTANCE"),
1539 std::string("gl_CullDistance[IDX] = gl_in[0].gl_CullDistance[IDX]"));
1540
1541 break;
1542 }
1543 case PRIMITIVE_MODE_TRIANGLES:
1544 {
1545 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_IN"),
1546 std::string("layout(triangles) in;"));
1547 CullDistance::Utilities::replaceAll(
1548 shader_source, std::string("TEMPLATE_OUT_FORMULA"),
1549 std::string("vec4(mat3(gl_in[0].gl_Position.xyz, gl_in[1].gl_Position.xyz, "
1550 "gl_in[2].gl_Position.xyz) * gl_TessCoord, 1.0)"));
1551 CullDistance::Utilities::replaceAll(
1552 shader_source, std::string("TEMPLATE_ASSIGN_CLIP_DISTANCE"),
1553 std::string("gl_ClipDistance[IDX] = dot(vec3(gl_in[0].gl_ClipDistance[IDX], "
1554 "gl_in[1].gl_ClipDistance[IDX], gl_in[2].gl_ClipDistance[IDX]), gl_TessCoord)"));
1555 CullDistance::Utilities::replaceAll(
1556 shader_source, std::string("TEMPLATE_ASSIGN_CULL_DISTANCE"),
1557 std::string("gl_CullDistance[IDX] = dot(vec3(gl_in[0].gl_CullDistance[IDX], "
1558 "gl_in[1].gl_CullDistance[IDX], gl_in[2].gl_CullDistance[IDX]), gl_TessCoord)"));
1559
1560 break;
1561 }
1562 default:
1563 TCU_FAIL("Unknown primitive mode");
1564 }
1565
1566 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_EXTENSIONS"),
1567 std::string("#extension GL_ARB_tessellation_shader: require"));
1568 break;
1569 }
1570
1571 case GL_VERTEX_SHADER:
1572 {
1573 shader_body_string_vs = &shaders_configuration[n_shader_index].body;
1574
1575 /* Specify input data size for clipdistances data */
1576 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_CLIPDISTANCE_INPUT_SIZE"),
1577 CullDistance::Utilities::intToString(clipdistances_input_size));
1578
1579 /* Specify input data size for culldistances data */
1580 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_CULLDISTANCE_INPUT_SIZE"),
1581 CullDistance::Utilities::intToString(culldistances_input_size));
1582
1583 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_ASSIGN_CLIP_DISTANCE"),
1584 std::string("gl_ClipDistance[IDX] = clipdistance_data[IDX]"));
1585 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_ASSIGN_CULL_DISTANCE"),
1586 std::string("gl_CullDistance[IDX] = culldistance_data[IDX]"));
1587
1588 break;
1589 }
1590
1591 default:
1592 TCU_FAIL("Unknown shader type");
1593 }
1594
1595 /* Clear out in case no specific exts were needed */
1596 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_EXTENSIONS"), std::string(""));
1597
1598 /* Adjust clipdistances declaration */
1599 if (redeclare_clipdistances && clipdistances_array_size > 0)
1600 {
1601 if (shaders_configuration[n_shader_index].type == GL_FRAGMENT_SHADER)
1602 {
1603 if (fetch_culldistance_from_fs)
1604 {
1605 clipdistance_array_declaration =
1606 std::string("in float gl_ClipDistance[") +
1607 CullDistance::Utilities::intToString(clipdistances_array_size) + std::string("];");
1608 }
1609 }
1610 else if (shaders_configuration[n_shader_index].type == GL_TESS_CONTROL_SHADER)
1611 {
1612 clipdistance_array_declaration = std::string("float gl_ClipDistance[") +
1613 CullDistance::Utilities::intToString(clipdistances_array_size) +
1614 std::string("];");
1615 }
1616 else
1617 {
1618 clipdistance_array_declaration = std::string("out float gl_ClipDistance[") +
1619 CullDistance::Utilities::intToString(clipdistances_array_size) +
1620 std::string("];");
1621 clipdistance_in_array_declaration = std::string("in float gl_ClipDistance[") +
1622 CullDistance::Utilities::intToString(clipdistances_array_size) +
1623 std::string("];");
1624 }
1625 }
1626 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_REDECLARE_CLIPDISTANCE"),
1627 clipdistance_array_declaration);
1628 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_REDECLARE_IN_CLIPDISTANCE"),
1629 clipdistance_in_array_declaration);
1630
1631 /* Adjust culldistances declaration */
1632 if (redeclare_culldistances && culldistances_array_size > 0)
1633 {
1634 if (shaders_configuration[n_shader_index].type == GL_FRAGMENT_SHADER)
1635 {
1636 if (fetch_culldistance_from_fs)
1637 {
1638 culldistance_array_declaration =
1639 std::string("in float gl_CullDistance[") +
1640 CullDistance::Utilities::intToString(culldistances_array_size) + std::string("];");
1641 }
1642 }
1643 else if (shaders_configuration[n_shader_index].type == GL_TESS_CONTROL_SHADER)
1644 {
1645 culldistance_array_declaration = std::string("float gl_CullDistance[") +
1646 CullDistance::Utilities::intToString(culldistances_array_size) +
1647 std::string("];");
1648 }
1649 else
1650 {
1651 culldistance_array_declaration = std::string("out float gl_CullDistance[") +
1652 CullDistance::Utilities::intToString(culldistances_array_size) +
1653 std::string("];");
1654 culldistance_in_array_declaration = std::string("in float gl_CullDistance[") +
1655 CullDistance::Utilities::intToString(culldistances_array_size) +
1656 std::string("];");
1657 }
1658 }
1659 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_REDECLARE_CULLDISTANCE"),
1660 culldistance_array_declaration);
1661 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_REDECLARE_IN_CULLDISTANCE"),
1662 culldistance_in_array_declaration);
1663
1664 /* Adjust clip/cull distances setters */
1665 if (dynamic_index_writes)
1666 {
1667 array_setters = dynamic_array_setters;
1668
1669 CullDistance::Utilities::replaceAll(array_setters, std::string("TEMPLATE_N_GL_CLIPDISTANCE_ENTRIES"),
1670 CullDistance::Utilities::intToString(clipdistances_array_size));
1671 CullDistance::Utilities::replaceAll(array_setters, std::string("TEMPLATE_N_GL_CULLDISTANCE_ENTRIES"),
1672 CullDistance::Utilities::intToString(culldistances_array_size));
1673 }
1674 else
1675 {
1676 std::stringstream static_array_setters_sstream;
1677
1678 static_array_setters_sstream << "\n";
1679
1680 for (glw::GLuint clipdistances_array_entry = 0; clipdistances_array_entry < clipdistances_array_size;
1681 ++clipdistances_array_entry)
1682 {
1683 static_array_setters_sstream << " ASSIGN_CLIP_DISTANCE(" << clipdistances_array_entry
1684 << ");\n";
1685 }
1686
1687 static_array_setters_sstream << "\n";
1688
1689 for (glw::GLuint culldistances_array_entry = 0; culldistances_array_entry < culldistances_array_size;
1690 ++culldistances_array_entry)
1691 {
1692 static_array_setters_sstream << " ASSIGN_CULL_DISTANCE(" << culldistances_array_entry
1693 << ");\n";
1694 }
1695
1696 array_setters = static_array_setters_sstream.str();
1697 }
1698
1699 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_ARRAY_SETTERS"), array_setters);
1700 }
1701 }
1702
1703 /* Build the geometry shader */
1704 CullDistance::Utilities::buildProgram(
1705 m_context.getRenderContext().getFunctions(), m_testCtx, DE_NULL, /* Compute shader */
1706 shader_body_string_fs != DE_NULL ? shader_body_string_fs->c_str() :
1707 DE_NULL, /* Fragment shader */
1708 shader_body_string_gs != DE_NULL ? shader_body_string_gs->c_str() :
1709 DE_NULL, /* Geometry shader */
1710 shader_body_string_tc != DE_NULL ? shader_body_string_tc->c_str() :
1711 DE_NULL, /* Tesselation control shader */
1712 shader_body_string_te != DE_NULL ? shader_body_string_te->c_str() :
1713 DE_NULL, /* Tesselation evaluation shader */
1714 shader_body_string_vs != DE_NULL ? shader_body_string_vs->c_str() :
1715 DE_NULL, /* Vertex shader */
1716 0, /* Transform feedback varyings count */
1717 DE_NULL, /* Transform feedback varyings */
1718 &m_po_id /* Program object id */
1719 );
1720 }
1721
1722 /** Generates primitive data required to test a case with specified
1723 * gl_ClipDistance and glCullDistance array sizes for specified
1724 * primitive mode. Generated primitive data is stored in m_bo_data
1725 * as well uploaded into buffer specified in m_bo_id buffer.
1726 * Also the procedure binds vertex attribute locations to
1727 * program object m_po_id.
1728 *
1729 * @param clipdistances_array_size gl_ClipDistance array size. Can be 0.
1730 * @param culldistances_array_size gl_CullDistance array size. Can be 0.
1731 * @param _primitive_mode Primitives to be generated. Can be:
1732 * PRIMITIVE_MODE_POINTS,
1733 * PRIMITIVE_MODE_LINES,
1734 * PRIMITIVE_MODE_TRIANGLES.
1735 */
configureVAO(glw::GLuint clipdistances_array_size,glw::GLuint culldistances_array_size,_primitive_mode primitive_mode)1736 void CullDistance::FunctionalTest::configureVAO(glw::GLuint clipdistances_array_size,
1737 glw::GLuint culldistances_array_size, _primitive_mode primitive_mode)
1738 {
1739 /* Detailed test description.
1740 *
1741 * configureVAO() generates primitives layouted in grid. Primitve
1742 * consists of up to 3 vertices and each vertex is accompanied by:
1743 * - array of clipdistances (clipdistances_array_size floats);
1744 * - array of culldistances (culldistances_array_size floats);
1745 * - rendering position coordinates (x and y);
1746 * - check position coordinates (x and y).
1747 *
1748 * The grid has following layout:
1749 *
1750 * Grid | gl_CullDistance[x] |
1751 * | 0 .. culldistances_array_size - 1 |
1752 * | 0th | 1st | 2nd | .......... |
1753 * ---------------------------+-------+-------+-------+------------+
1754 * 0th gl_ClipDistance |Subgrid|Subgrid|Subgrid| .......... |
1755 * 1st gl_ClipDistance |Subgrid|Subgrid|Subgrid| .......... |
1756 * ... | ... | ... | ... | .......... |
1757 * y-th gl_ClipDistance |Subgrid|Subgrid|Subgrid| .......... |
1758 * ... | ... | ... | ... | .......... |
1759 * clipdistances_array_size-1 |Subgrid|Subgrid|Subgrid| .......... |
1760 *
1761 * Each grid cell contains subgrid of 3*3 items in size with following
1762 * structure:
1763 *
1764 * Subgrid | x-th gl_CullDistance test |
1765 * | |
1766 * y-th | all vertices | 0th vertex | all vertices |
1767 * gl_ClipDistance| in primitive | in primitive | in primitive |
1768 * tests | dist[x] > 0 | dist[x] < 0 | dist[x] < 0 |
1769 * ---------------+--------------+--------------+--------------+
1770 * all vertices| primitive #0 | primitive #1 | primitive #2 |
1771 * in primitive| | | |
1772 * dist[y] > 0 | visible | visible | culled |
1773 * ---------------+--------------+--------------+--------------+
1774 * 0th vertex | primitive #3 | primitive #4 | primitive #5 |
1775 * in primitive| 0th vertex | 0th vertex | |
1776 * dist[y] < 0 | clipped | clipped | culled |
1777 * ---------------+--------------+--------------+--------------+
1778 * all vertices| primitive #6 | primitive #7 | primitive #8 |
1779 * in primitive| | | |
1780 * dist[y] < 0 | clipped | clipped | culled |
1781 * ---------------+--------------+--------------+--------------+
1782 *
1783 * Expected rendering result is specified in cell bottom.
1784 * It can be one of the following:
1785 * - "visible" means the primitive is not affected neither by gl_CullDistance
1786 * nor by gl_ClipDistance and rendered as a whole;
1787 * - "clipped" for the vertex means the vertex is not rendered, while other
1788 * primitive vertices and some filling fragments are rendered;
1789 * - "clipped" for primitive means none of primitive vertices and fragments
1790 * are rendered and thus primitive is not rendered and is invisible;
1791 * - "culled" means, that neither primitive vertices, nor primitive filling
1792 * fragments are rendered (primitive is invisible).
1793 *
1794 * All subgrid items contain same primitive rendered. Depending on
1795 * test case running it would be either triangle, or line, or point:
1796 *
1797 * triangle line point
1798 * 8x8 box 8x8 box 3x3 box
1799 * ........ ........ ...
1800 * .0----2. .0...... .0.
1801 * ..\@@@|. ..\..... ...
1802 * ...\@@|. ...\....
1803 * ....\@|. ....\...
1804 * .....\|. .....\..
1805 * ......1. ......1.
1806 * ........ ........
1807 *
1808 * where 0 - is a 0th vertex primitive
1809 * 1 - is a 1st vertex primitive
1810 * 2 - is a 2nd vertex primitive
1811 *
1812 * The culldistances_array_size can be 0. In that case, grid height
1813 * is assumed equal to 1, but 0 glCullDistances is specified.
1814 * Similar handled clipdistances_array_size.
1815 *
1816 * The data generated is used and checked in executeRenderTest().
1817 * After rendering each primitive vertex is tested:
1818 * - if it is rendered, if it have to be rendered (according distance);
1819 * - if it is not rendered, if it have to be not rendered (according distance).
1820 * Due to "top-left" rasterization rule check position is
1821 * different from rendering vertex position.
1822 *
1823 * Also one pixel width guarding box is checked to be clear.
1824 */
1825
1826 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1827 const glw::GLuint n_sub_grid_cells = 3; /* Tested distance is positive for all vertices in the primitive;
1828 * Tested distance is negative for 0th vertex in the primitive;
1829 * Tested distance is negative for all vertices in the primitive;
1830 */
1831 const glw::GLuint sub_grid_cell_size = ((primitive_mode == PRIMITIVE_MODE_LINES) ? 8 :
1832 (primitive_mode == PRIMITIVE_MODE_POINTS) ? 3 :
1833 8);
1834
1835 const glw::GLuint grid_cell_size = n_sub_grid_cells * sub_grid_cell_size;
1836 const glw::GLuint n_primitive_vertices = ((primitive_mode == PRIMITIVE_MODE_LINES) ? 2 :
1837 (primitive_mode == PRIMITIVE_MODE_POINTS) ? 1 :
1838 3);
1839
1840 const glw::GLuint n_grid_cells_x = culldistances_array_size != 0 ? culldistances_array_size : 1;
1841 const glw::GLuint n_grid_cells_y = clipdistances_array_size != 0 ? clipdistances_array_size : 1;
1842 const glw::GLuint n_pervertex_float_attributes = clipdistances_array_size + culldistances_array_size +
1843 2 /* vertex' draw x, y */ + 2 /* vertex' checkpoint x, y */;
1844 const glw::GLuint n_primitives_total = n_grid_cells_x * n_sub_grid_cells * n_grid_cells_y * n_sub_grid_cells;
1845 const glw::GLuint n_vertices_total = n_primitives_total * n_primitive_vertices;
1846 const glw::GLuint offsets_line_draw_x[2] = {
1847 1, sub_grid_cell_size - 1}; /* vertex x offsets to subgrid cell origin for line primitive */
1848 const glw::GLuint offsets_line_draw_y[2] = {
1849 1, sub_grid_cell_size - 1}; /* vertex y offsets to subgrid cell origin for line primitive */
1850 const glw::GLuint offsets_line_checkpoint_x[2] = {
1851 1, sub_grid_cell_size - 2}; /* pixel x offsets to subgrid cell origin for line primitive */
1852 const glw::GLuint offsets_line_checkpoint_y[2] = {
1853 1, sub_grid_cell_size - 2}; /* pixel y offsets to subgrid cell origin for line primitive */
1854 const glw::GLuint offsets_point_draw_x[1] = {
1855 1}; /* vertex x offsets to subgrid cell origin for point primitive */
1856 const glw::GLuint offsets_point_draw_y[1] = {
1857 1}; /* vertex y offsets to subgrid cell origin for point primitive */
1858 const glw::GLuint offsets_point_checkpoint_x[1] = {
1859 1}; /* pixel x offsets to subgrid cell origin for point primitive */
1860 const glw::GLuint offsets_point_checkpoint_y[1] = {
1861 1}; /* pixel y offsets to subgrid cell origin for point primitive */
1862 const glw::GLuint offsets_triangle_draw_x[3] = {
1863 1, sub_grid_cell_size - 1,
1864 sub_grid_cell_size - 1}; /* vertex x offsets to subgrid cell origin for triangle primitive */
1865 const glw::GLuint offsets_triangle_draw_y[3] = {
1866 1, sub_grid_cell_size - 1, 1}; /* vertex y offsets to subgrid cell origin for triangle primitive */
1867 const glw::GLuint offsets_triangle_checkpoint_x[3] = {
1868 1, sub_grid_cell_size - 2,
1869 sub_grid_cell_size - 2}; /* pixel x offsets to subgrid cell origin for triangle primitive */
1870 const glw::GLuint offsets_triangle_checkpoint_y[3] = {
1871 1, sub_grid_cell_size - 2, 1}; /* pixel y offsets to subgrid cell origin for triangle primitive */
1872 const glw::GLfloat offsets_pixel_center_x = (primitive_mode == PRIMITIVE_MODE_POINTS) ? 0.5f : 0;
1873 const glw::GLfloat offsets_pixel_center_y = (primitive_mode == PRIMITIVE_MODE_POINTS) ? 0.5f : 0;
1874 /* Clear data left from previous tests. */
1875 m_bo_data.clear();
1876
1877 /* No data to render */
1878 m_render_primitives = 0;
1879 m_render_vertices = 0;
1880
1881 /* Preallocate space for bo_points_count */
1882 m_bo_data.reserve(n_vertices_total * n_pervertex_float_attributes);
1883
1884 /* Generate test data for cell_y-th clip distance */
1885 for (glw::GLuint cell_y = 0; cell_y < n_grid_cells_y; cell_y++)
1886 {
1887 /* Generate test data for cell_x-th cull distance */
1888 for (glw::GLuint cell_x = 0; cell_x < n_grid_cells_x; cell_x++)
1889 {
1890 /* Check clip distance sub cases:
1891 * 0. Tested distance is positive for all vertices in the primitive;
1892 * 1. Tested distance is negative for 0th vertex in the primitive;
1893 * 2. Tested distance is negative for all vertices in the primitive;
1894 */
1895 for (glw::GLuint n_sub_cell_y = 0; n_sub_cell_y < n_sub_grid_cells; n_sub_cell_y++)
1896 {
1897 /* Check cull distance sub cases:
1898 * 0. Tested distance is positive for all vertices in the primitive;
1899 * 1. Tested distance is negative for 0th vertex in the primitive;
1900 * 2. Tested distance is negative for all vertices in the primitive;
1901 */
1902 for (glw::GLuint n_sub_cell_x = 0; n_sub_cell_x < n_sub_grid_cells; n_sub_cell_x++)
1903 {
1904 /* Generate vertices in primitive */
1905 for (glw::GLuint n_primitive_vertex = 0; n_primitive_vertex < n_primitive_vertices;
1906 n_primitive_vertex++)
1907 {
1908 /* Fill in clipdistance array for the n_primitive_vertex vertex in primitive */
1909 for (glw::GLuint n_clipdistance_entry = 0; n_clipdistance_entry < clipdistances_array_size;
1910 n_clipdistance_entry++)
1911 {
1912 glw::GLfloat distance_value = 0.0f;
1913 bool negative = true;
1914
1915 /* Special approach to tested clipdistance entry. */
1916 if (n_clipdistance_entry == cell_y)
1917 {
1918 /* The primitive vertex should be affected by the clip distance */
1919 switch (n_sub_cell_y)
1920 {
1921 case 0:
1922 {
1923 /* subgrid row 0: all primitive vertices have tested distance value positive */
1924 negative = false;
1925
1926 break;
1927 }
1928 case 1:
1929 {
1930 /* subgrid row 1: tested distance value for 0th primitive vertex is negative,
1931 all other primitive vertices have tested distance value positive */
1932 negative = (n_primitive_vertex == 0) ? true : false;
1933
1934 break;
1935 }
1936 case 2:
1937 {
1938 /* subgrid row 2: tested distance value is negative for all primitive vertices */
1939 negative = true;
1940
1941 break;
1942 }
1943 default:
1944 TCU_FAIL("Invalid subgrid cell index");
1945 }
1946
1947 distance_value = (negative ? -1.0f : 1.0f) * glw::GLfloat(n_clipdistance_entry + 1);
1948 }
1949 else
1950 {
1951 /* For clip distances other than tested: assign positive value to avoid its influence. */
1952 distance_value = glw::GLfloat(clipdistances_array_size + n_clipdistance_entry + 1);
1953 }
1954
1955 m_bo_data.push_back(distance_value / glw::GLfloat(clipdistances_array_size));
1956 } /* for (all gl_ClipDistance[] array values) */
1957
1958 /* Fill in culldistance array for the n_primitive_vertex vertex in primitive */
1959 for (glw::GLuint n_culldistance_entry = 0; n_culldistance_entry < culldistances_array_size;
1960 n_culldistance_entry++)
1961 {
1962 glw::GLfloat distance_value = 0.0f;
1963 bool negative = true;
1964
1965 /* Special approach to tested culldistance entry. */
1966 if (n_culldistance_entry == cell_x)
1967 {
1968 /* The primitive vertex should be affected by the cull distance */
1969 switch (n_sub_cell_x)
1970 {
1971 case 0:
1972 {
1973 /* subgrid column 0: all primitive vertices have tested distance value positive */
1974 negative = false;
1975
1976 break;
1977 }
1978 case 1:
1979 {
1980 /* subgrid column 1: tested distance value for 0th primitive vertex is negative,
1981 all other primitive vertices have tested distance value positive */
1982 negative = (n_primitive_vertex == 0) ? true : false;
1983
1984 break;
1985 }
1986 case 2:
1987 {
1988 /* subgrid column 2: tested distance value is negative for all primitive vertices */
1989 negative = true;
1990
1991 break;
1992 }
1993 default:
1994 TCU_FAIL("Invalid subgrid cell index");
1995 }
1996
1997 distance_value = (negative ? -1.0f : 1.0f) * glw::GLfloat(n_culldistance_entry + 1);
1998 }
1999 else
2000 {
2001 /* For cull distances other than tested: assign 0th vertex negative value,
2002 to check absence of between-distances influence. */
2003 if (n_primitive_vertices > 1 && n_primitive_vertex == 0)
2004 {
2005 distance_value = -glw::GLfloat(culldistances_array_size + n_culldistance_entry + 1);
2006 }
2007 else
2008 {
2009 /* This culldistance is out of interest: assign positive value. */
2010 distance_value = glw::GLfloat(culldistances_array_size + n_culldistance_entry + 1);
2011 }
2012 }
2013
2014 m_bo_data.push_back(distance_value / glw::GLfloat(culldistances_array_size));
2015 } /* for (all gl_CullDistance[] array values) */
2016
2017 /* Generate primitve vertex draw and checkpoint coordinates */
2018 glw::GLint vertex_draw_pixel_offset_x = 0;
2019 glw::GLint vertex_draw_pixel_offset_y = 0;
2020 glw::GLint vertex_checkpoint_pixel_offset_x = 0;
2021 glw::GLint vertex_checkpoint_pixel_offset_y = 0;
2022
2023 switch (primitive_mode)
2024 {
2025 case PRIMITIVE_MODE_LINES:
2026 {
2027 vertex_draw_pixel_offset_x = offsets_line_draw_x[n_primitive_vertex];
2028 vertex_draw_pixel_offset_y = offsets_line_draw_y[n_primitive_vertex];
2029 vertex_checkpoint_pixel_offset_x = offsets_line_checkpoint_x[n_primitive_vertex];
2030 vertex_checkpoint_pixel_offset_y = offsets_line_checkpoint_y[n_primitive_vertex];
2031
2032 break;
2033 }
2034
2035 case PRIMITIVE_MODE_POINTS:
2036 {
2037 vertex_draw_pixel_offset_x = offsets_point_draw_x[n_primitive_vertex];
2038 vertex_draw_pixel_offset_y = offsets_point_draw_y[n_primitive_vertex];
2039 vertex_checkpoint_pixel_offset_x = offsets_point_checkpoint_x[n_primitive_vertex];
2040 vertex_checkpoint_pixel_offset_y = offsets_point_checkpoint_y[n_primitive_vertex];
2041
2042 break;
2043 }
2044
2045 case PRIMITIVE_MODE_TRIANGLES:
2046 {
2047 vertex_draw_pixel_offset_x = offsets_triangle_draw_x[n_primitive_vertex];
2048 vertex_draw_pixel_offset_y = offsets_triangle_draw_y[n_primitive_vertex];
2049 vertex_checkpoint_pixel_offset_x = offsets_triangle_checkpoint_x[n_primitive_vertex];
2050 vertex_checkpoint_pixel_offset_y = offsets_triangle_checkpoint_y[n_primitive_vertex];
2051
2052 break;
2053 }
2054
2055 default:
2056 TCU_FAIL("Unknown primitive mode");
2057 }
2058
2059 /* Origin of sub_cell */
2060 glw::GLint sub_cell_origin_x = cell_x * grid_cell_size + n_sub_cell_x * sub_grid_cell_size;
2061 glw::GLint sub_cell_origin_y = cell_y * grid_cell_size + n_sub_cell_y * sub_grid_cell_size;
2062 /* Normalized texture coordinates of vertex draw position. */
2063 glw::GLfloat x =
2064 (glw::GLfloat(sub_cell_origin_x + vertex_draw_pixel_offset_x) + offsets_pixel_center_x) /
2065 glw::GLfloat(m_to_width);
2066 glw::GLfloat y =
2067 (glw::GLfloat(sub_cell_origin_y + vertex_draw_pixel_offset_y) + offsets_pixel_center_y) /
2068 glw::GLfloat(m_to_height);
2069 /* Normalized texture coordinates of vertex checkpoint position. */
2070 glw::GLfloat checkpoint_x = glw::GLfloat(sub_cell_origin_x + vertex_checkpoint_pixel_offset_x) /
2071 glw::GLfloat(m_to_width);
2072 glw::GLfloat checkpoint_y = glw::GLfloat(sub_cell_origin_y + vertex_checkpoint_pixel_offset_y) /
2073 glw::GLfloat(m_to_height);
2074
2075 /* Add vertex draw coordinates into buffer. */
2076 m_bo_data.push_back(x);
2077 m_bo_data.push_back(y);
2078
2079 /* Add vertex checkpoint coordinates into buffer. */
2080 m_bo_data.push_back(checkpoint_x);
2081 m_bo_data.push_back(checkpoint_y);
2082 } /* for (all vertices in primitive) */
2083 } /* for (all horizontal sub cells) */
2084 } /* for (all vertical sub cells) */
2085 } /* for (all horizontal cells) */
2086 } /* for (all vertical cells) */
2087
2088 /* Quick check: make sure we pushed required amount of data */
2089 DE_ASSERT(m_bo_data.size() == n_vertices_total * n_pervertex_float_attributes);
2090
2091 /* Save number of primitives to render */
2092 m_render_primitives = n_primitives_total;
2093 m_render_vertices = n_vertices_total;
2094 m_sub_grid_cell_size = sub_grid_cell_size;
2095
2096 /* Copy the data to the buffer object */
2097 gl.bindBuffer(GL_ARRAY_BUFFER, m_bo_id);
2098 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
2099
2100 gl.bufferData(GL_ARRAY_BUFFER, m_bo_data.size() * sizeof(glw::GLfloat), &m_bo_data[0], GL_STATIC_DRAW);
2101 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
2102
2103 DE_ASSERT(m_po_id != 0);
2104
2105 /* Bind VAO data to program */
2106 glw::GLint po_clipdistance_array_location = -1;
2107 glw::GLint po_culldistance_array_location = -1;
2108 glw::GLint po_position_location = -1;
2109
2110 /* Retrieve clipdistance and culldistance attribute locations */
2111 gl.bindVertexArray(m_vao_id);
2112 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
2113
2114 po_clipdistance_array_location = gl.getAttribLocation(m_po_id, "clipdistance_data[0]");
2115 po_culldistance_array_location = gl.getAttribLocation(m_po_id, "culldistance_data[0]");
2116 po_position_location = gl.getAttribLocation(m_po_id, "position");
2117
2118 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetAttribLocation() call(s) failed.");
2119
2120 if (clipdistances_array_size > 0)
2121 {
2122 DE_ASSERT(po_clipdistance_array_location != -1);
2123 }
2124
2125 if (culldistances_array_size > 0)
2126 {
2127 DE_ASSERT(po_culldistance_array_location != -1);
2128 }
2129
2130 DE_ASSERT(po_position_location != -1);
2131
2132 glw::GLintptr current_offset = 0;
2133 const glw::GLint stride = static_cast<glw::GLint>(n_pervertex_float_attributes * sizeof(glw::GLfloat));
2134
2135 gl.bindVertexArray(m_vao_id);
2136 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
2137
2138 for (glw::GLuint n_clipdistance_entry = 0; n_clipdistance_entry < clipdistances_array_size; ++n_clipdistance_entry)
2139 {
2140 gl.vertexAttribPointer(po_clipdistance_array_location + n_clipdistance_entry, 1, /* size */
2141 GL_FLOAT, GL_FALSE, /* normalized */
2142 stride, (const glw::GLvoid *)current_offset);
2143 GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer() call failed.");
2144
2145 gl.enableVertexAttribArray(po_clipdistance_array_location + n_clipdistance_entry);
2146 GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray() call failed.");
2147
2148 current_offset += sizeof(glw::GLfloat);
2149 } /* for (all clip distance array value attributes) */
2150
2151 for (glw::GLuint n_culldistance_entry = 0; n_culldistance_entry < culldistances_array_size; ++n_culldistance_entry)
2152 {
2153 gl.vertexAttribPointer(po_culldistance_array_location + n_culldistance_entry, 1, /* size */
2154 GL_FLOAT, GL_FALSE, /* normalized */
2155 stride, (const glw::GLvoid *)current_offset);
2156 GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer() call failed.");
2157
2158 gl.enableVertexAttribArray(po_culldistance_array_location + n_culldistance_entry);
2159 GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray() call failed.");
2160
2161 current_offset += sizeof(glw::GLfloat);
2162 } /* for (all cull distance array value attributes) */
2163
2164 gl.vertexAttribPointer(po_position_location, 2, /* size */
2165 GL_FLOAT, GL_FALSE, /* normalized */
2166 stride, (const glw::GLvoid *)current_offset);
2167 GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer() call failed");
2168
2169 gl.enableVertexAttribArray(po_position_location);
2170 GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray() call failed");
2171 }
2172
2173 /** @brief Cull Distance Functional Test deinitialization */
deinit()2174 void CullDistance::FunctionalTest::deinit()
2175 {
2176 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2177
2178 if (m_fbo_id != 0)
2179 {
2180 gl.deleteFramebuffers(1, &m_fbo_id);
2181
2182 m_fbo_id = 0;
2183 }
2184
2185 if (m_to_id != 0)
2186 {
2187 gl.deleteTextures(1, &m_to_id);
2188
2189 m_to_id = 0;
2190 }
2191
2192 if (m_vao_id != 0)
2193 {
2194 gl.deleteVertexArrays(1, &m_vao_id);
2195
2196 m_vao_id = 0;
2197 }
2198
2199 deinitPO();
2200 }
2201
2202 /** @brief Cull Distance Functional Test deinitialization of OpenGL programs */
deinitPO()2203 void CullDistance::FunctionalTest::deinitPO()
2204 {
2205 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2206
2207 if (m_po_id != 0)
2208 {
2209 gl.deleteProgram(m_po_id);
2210
2211 m_po_id = 0;
2212 }
2213 }
2214
2215 /** @brief Executes single render test case
2216 *
2217 * @param [in] clipdistances_array_size Size of gl_ClipDistance[] array
2218 * @param [in] culldistances_array_size Size of gl_CullDistance[] array
2219 * @param [in] primitive_mode Type of primitives to be rendered (see enum _primitive_mode)
2220 * @param [in] use_tesselation Indicate whether to use tessellation shader
2221 * @param [in] fetch_culldistance_from_fs Indicate whether to fetch gl_CullDistance and gl_ClipDistance values from the fragment shader
2222 */
executeRenderTest(glw::GLuint clipdistances_array_size,glw::GLuint culldistances_array_size,_primitive_mode primitive_mode,bool use_tesselation,bool fetch_culldistance_from_fs)2223 void CullDistance::FunctionalTest::executeRenderTest(glw::GLuint clipdistances_array_size,
2224 glw::GLuint culldistances_array_size,
2225 _primitive_mode primitive_mode, bool use_tesselation,
2226 bool fetch_culldistance_from_fs)
2227 {
2228 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2229 glw::GLenum mode = GL_NONE;
2230 glw::GLuint n_clipped_vertices_real = 0;
2231 glw::GLuint n_culled_primitives_real = 0;
2232 const glw::GLuint primitive_vertices_count = ((primitive_mode == PRIMITIVE_MODE_LINES) ? 2 :
2233 (primitive_mode == PRIMITIVE_MODE_POINTS) ? 1 :
2234 3);
2235 const glw::GLuint stride_in_floats =
2236 clipdistances_array_size + culldistances_array_size + 2 /* position's x, y*/ + 2 /* checkpoint x,y */;
2237
2238 // Release build does not use them
2239 DE_UNREF(n_clipped_vertices_real);
2240 DE_UNREF(n_culled_primitives_real);
2241
2242 switch (primitive_mode)
2243 {
2244 case PRIMITIVE_MODE_LINES:
2245 {
2246 mode = GL_LINES;
2247
2248 break;
2249 }
2250 case PRIMITIVE_MODE_POINTS:
2251 {
2252 mode = GL_POINTS;
2253
2254 break;
2255 }
2256 case PRIMITIVE_MODE_TRIANGLES:
2257 {
2258 mode = GL_TRIANGLES;
2259
2260 break;
2261 }
2262 default:
2263 TCU_FAIL("Unknown primitive mode");
2264 }
2265
2266 if (use_tesselation)
2267 {
2268 mode = GL_PATCHES;
2269
2270 gl.patchParameteri(GL_PATCH_VERTICES, primitive_vertices_count);
2271 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteri() call failed.");
2272 }
2273
2274 gl.clear(GL_COLOR_BUFFER_BIT);
2275 GLU_EXPECT_NO_ERROR(gl.getError(), "glClear() call failed.");
2276
2277 gl.useProgram(m_po_id);
2278 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
2279
2280 for (glw::GLuint n_clipdistance_entry = 0; n_clipdistance_entry < clipdistances_array_size; n_clipdistance_entry++)
2281 {
2282 gl.enable(GL_CLIP_DISTANCE0 + n_clipdistance_entry);
2283 GLU_EXPECT_NO_ERROR(gl.getError(), "gl.enable(GL_CLIP_DISTANCE)() call failed.");
2284 } /* for (all clip distance array value attributes) */
2285
2286 gl.drawArrays(mode, 0, m_render_vertices);
2287 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArray() call(s) failed.");
2288
2289 for (glw::GLuint n_clipdistance_entry = 0; n_clipdistance_entry < clipdistances_array_size; n_clipdistance_entry++)
2290 {
2291 gl.disable(GL_CLIP_DISTANCE0 + n_clipdistance_entry);
2292 GLU_EXPECT_NO_ERROR(gl.getError(), "gl.disable(GL_CLIP_DISTANCE)() call failed.");
2293 } /* for (all clip distance array value attributes) */
2294
2295 gl.useProgram(0);
2296 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
2297
2298 /* Read generated texture into m_to_pixel_data_cache */
2299 readTexturePixels();
2300
2301 for (glw::GLint n_primitive_index = 0; n_primitive_index < m_render_primitives; n_primitive_index++)
2302 {
2303 glw::GLuint base_index_of_primitive = n_primitive_index * primitive_vertices_count * stride_in_floats;
2304 bool primitive_culled = false;
2305 glw::GLint primitive_culled_by_distance = -1;
2306
2307 /* Check the bounding box is clear */
2308 glw::GLuint base_index_of_vertex = base_index_of_primitive;
2309 glw::GLuint checkpoint_position_index = base_index_of_vertex + clipdistances_array_size +
2310 culldistances_array_size + 2 /* ignore vertex coordinates */;
2311 glw::GLint checkpoint_x = glw::GLint(glw::GLfloat(m_to_width) * m_bo_data[checkpoint_position_index]);
2312 glw::GLint checkpoint_y = glw::GLint(glw::GLfloat(m_to_height) * m_bo_data[checkpoint_position_index + 1]);
2313 glw::GLint origin_x = checkpoint_x - 1;
2314 glw::GLint origin_y = checkpoint_y - 1;
2315 for (glw::GLint pixel_offset = 0; pixel_offset < m_sub_grid_cell_size; pixel_offset++)
2316 {
2317 if (readRedPixelValue(origin_x + pixel_offset, origin_y) != 0)
2318 {
2319 TCU_FAIL("Top edge of bounding box is overwritten");
2320 }
2321
2322 if (readRedPixelValue(origin_x + m_sub_grid_cell_size - 1, origin_y + pixel_offset) != 0)
2323 {
2324 TCU_FAIL("Right edge of bounding box is overwritten");
2325 }
2326
2327 if (readRedPixelValue(origin_x + m_sub_grid_cell_size - 1 - pixel_offset,
2328 origin_y + m_sub_grid_cell_size - 1) != 0)
2329 {
2330 TCU_FAIL("Bottom edge of bounding box is overwritten");
2331 }
2332
2333 if (readRedPixelValue(origin_x, origin_y + m_sub_grid_cell_size - 1 - pixel_offset) != 0)
2334 {
2335 TCU_FAIL("Left edge of bounding box is overwritten");
2336 }
2337 }
2338
2339 /* Determine if primitive has been culled */
2340 for (glw::GLuint n_culldistance_entry = 0; n_culldistance_entry < culldistances_array_size;
2341 n_culldistance_entry++)
2342 {
2343 bool distance_negative_in_all_primitive_vertices = true;
2344
2345 for (glw::GLuint n_primitive_vertex = 0; n_primitive_vertex < primitive_vertices_count;
2346 n_primitive_vertex++)
2347 {
2348 glw::GLint base_index_of_vertex_internal =
2349 base_index_of_primitive + n_primitive_vertex * stride_in_floats;
2350 glw::GLint culldistance_array_offset = base_index_of_vertex_internal + clipdistances_array_size;
2351 glw::GLfloat *vertex_culldistance_array = &m_bo_data[culldistance_array_offset];
2352
2353 if (vertex_culldistance_array[n_culldistance_entry] >= 0)
2354 {
2355 /* Primitive is not culled, due to one of its distances is not negative */
2356 distance_negative_in_all_primitive_vertices = false;
2357
2358 /* Skip left vertices for this distance */
2359 break;
2360 }
2361 }
2362
2363 /* The distance is negative in all primitive vertices, so this distance culls the primitive */
2364 if (distance_negative_in_all_primitive_vertices)
2365 {
2366 primitive_culled = true;
2367 primitive_culled_by_distance = n_culldistance_entry;
2368
2369 n_culled_primitives_real++;
2370
2371 /* Skip left distances from check */
2372 break;
2373 }
2374 }
2375
2376 /* Validate culling */
2377 if (primitive_culled)
2378 {
2379 /* Check whether primitive was culled and all its vertices are invisible */
2380 for (glw::GLuint n_primitive_vertex = 0; n_primitive_vertex < primitive_vertices_count;
2381 n_primitive_vertex++)
2382 {
2383 glw::GLint base_index_of_vertex_internal =
2384 base_index_of_primitive + n_primitive_vertex * stride_in_floats;
2385 glw::GLint checkpoint_position_index_internal = base_index_of_vertex_internal +
2386 clipdistances_array_size + culldistances_array_size +
2387 2 /* ignore vertex coordinates */;
2388 glw::GLint checkpoint_x_internal =
2389 glw::GLint(glw::GLfloat(m_to_width) * m_bo_data[checkpoint_position_index_internal]);
2390 glw::GLint checkpoint_y_internal =
2391 glw::GLint(glw::GLfloat(m_to_height) * m_bo_data[checkpoint_position_index_internal + 1]);
2392 glw::GLint vertex_color_red_value = readRedPixelValue(checkpoint_x_internal, checkpoint_y_internal);
2393
2394 /* Make sure vertex is invisible */
2395 if (vertex_color_red_value != 0)
2396 {
2397 m_testCtx.getLog() << tcu::TestLog::Message << "Primitive number [" << n_primitive_index << "] "
2398 << "should be culled by distance [" << primitive_culled_by_distance << "]"
2399 << "but primitive vertex at (" << checkpoint_x << "," << checkpoint_y
2400 << ") is visible." << tcu::TestLog::EndMessage;
2401
2402 TCU_FAIL("Primitive is expected to be culled, but one of its vertices is visible.");
2403 }
2404 }
2405
2406 /* Primitive is culled, no reason to check clipping */
2407 continue;
2408 }
2409
2410 bool all_vertices_are_clipped = true;
2411
2412 for (glw::GLuint n_primitive_vertex = 0; n_primitive_vertex < primitive_vertices_count; n_primitive_vertex++)
2413 {
2414 glw::GLuint base_index_of_vertex_internal = base_index_of_primitive + n_primitive_vertex * stride_in_floats;
2415 glw::GLuint clipdistance_array_index = base_index_of_vertex_internal;
2416 glw::GLuint checkpoint_position_index_internal = base_index_of_vertex_internal + clipdistances_array_size +
2417 culldistances_array_size +
2418 2 /* ignore vertex coordinates */;
2419 glw::GLint checkpoint_x_internal =
2420 glw::GLint(glw::GLfloat(m_to_width) * m_bo_data[checkpoint_position_index_internal]);
2421 glw::GLint checkpoint_y_internal =
2422 glw::GLint(glw::GLfloat(m_to_height) * m_bo_data[checkpoint_position_index_internal + 1]);
2423 glw::GLfloat *vertex_clipdistance_array = &m_bo_data[clipdistance_array_index];
2424 bool vertex_clipped = false;
2425 glw::GLint vertex_clipped_by_distance = 0;
2426 glw::GLint vertex_color_red_value = readRedPixelValue(checkpoint_x_internal, checkpoint_y_internal);
2427
2428 /* Check whether pixel should be clipped */
2429 for (glw::GLuint n_clipdistance_entry = 0; n_clipdistance_entry < clipdistances_array_size;
2430 n_clipdistance_entry++)
2431 {
2432 if (vertex_clipdistance_array[n_clipdistance_entry] < 0)
2433 {
2434 vertex_clipped = true;
2435 vertex_clipped_by_distance = n_clipdistance_entry;
2436
2437 break;
2438 }
2439 }
2440
2441 all_vertices_are_clipped &= vertex_clipped;
2442
2443 /* Validate whether real data same as expected */
2444 if (vertex_clipped)
2445 {
2446 if (vertex_color_red_value != 0)
2447 {
2448 m_testCtx.getLog() << tcu::TestLog::Message << "In primitive number [" << n_primitive_index << "] "
2449 << "vertex at (" << checkpoint_x << "," << checkpoint_y << ") "
2450 << "should be clipped by distance [" << vertex_clipped_by_distance << "] "
2451 << "(distance value [" << vertex_clipdistance_array[vertex_clipped_by_distance]
2452 << "])" << tcu::TestLog::EndMessage;
2453
2454 TCU_FAIL("Vertex is expected to be clipped and invisible, while it is visible.");
2455 }
2456 else
2457 {
2458 n_clipped_vertices_real++;
2459 }
2460 }
2461 else
2462 {
2463 if (vertex_color_red_value == 0)
2464 {
2465 m_testCtx.getLog() << tcu::TestLog::Message << "In primitive number [" << n_primitive_index << "] "
2466 << "vertex at (" << checkpoint_x << "," << checkpoint_y << ") "
2467 << "should not be clipped." << tcu::TestLog::EndMessage;
2468
2469 TCU_FAIL("Vertex is unexpectedly clipped or invisible");
2470 }
2471 }
2472 }
2473
2474 if (!all_vertices_are_clipped)
2475 {
2476 /* Check fetched values from the shader (Point 2 of Basic Outline : "Use program that...") */
2477 if (fetch_culldistance_from_fs)
2478 {
2479 for (glw::GLuint n_primitive_vertex = 0; n_primitive_vertex < primitive_vertices_count;
2480 n_primitive_vertex++)
2481 {
2482 /* Get shader output value */
2483 glw::GLuint base_index_of_vertex_internal =
2484 base_index_of_primitive + n_primitive_vertex * stride_in_floats;
2485 glw::GLuint checkpoint_position_index_internal =
2486 base_index_of_vertex_internal + clipdistances_array_size + culldistances_array_size +
2487 2 /* ignore vertex coordinates */;
2488 glw::GLuint culldistances_index = base_index_of_vertex_internal + clipdistances_array_size;
2489 glw::GLint checkpoint_x_internal =
2490 glw::GLint(glw::GLfloat(m_to_width) * m_bo_data[checkpoint_position_index_internal]);
2491 glw::GLint checkpoint_y_internal =
2492 glw::GLint(glw::GLfloat(m_to_height) * m_bo_data[checkpoint_position_index_internal + 1]);
2493 glw::GLint vertex_color_red_value = readRedPixelValue(checkpoint_x_internal, checkpoint_y_internal);
2494
2495 /* Calculate culldistances check sum hash */
2496 float sum = 0.f;
2497
2498 for (glw::GLuint n_clipdistance_entry = 0; n_clipdistance_entry < clipdistances_array_size;
2499 ++n_clipdistance_entry)
2500 {
2501 sum += de::abs(m_bo_data[base_index_of_vertex_internal + n_clipdistance_entry]) *
2502 float(n_clipdistance_entry + 1);
2503 }
2504
2505 for (glw::GLuint n_culldistance_entry = 0; n_culldistance_entry < culldistances_array_size;
2506 ++n_culldistance_entry)
2507 {
2508 sum += de::abs(m_bo_data[culldistances_index + n_culldistance_entry]) *
2509 float(n_culldistance_entry + 1 + clipdistances_array_size);
2510 }
2511
2512 /* limit sum and return */
2513 glw::GLint sum_hash =
2514 glw::GLint(sum /
2515 glw::GLfloat((clipdistances_array_size + culldistances_array_size) *
2516 (clipdistances_array_size + culldistances_array_size + 1)) *
2517 65535.f /* normalizing to short */);
2518 sum_hash = (sum_hash < 65536) ? sum_hash : 65535; /* clamping to short */
2519
2520 /* Compare against setup value */
2521 if (std::abs(vertex_color_red_value - sum_hash) > 4 /* precision 4/65536 */)
2522 {
2523 m_testCtx.getLog()
2524 << tcu::TestLog::Message << "Primitive number [" << n_primitive_index << "] "
2525 << "should have culldistance hash sum " << sum_hash << "but primitive vertex at ("
2526 << checkpoint_x << "," << checkpoint_y << ") has sum hash equal to "
2527 << vertex_color_red_value << tcu::TestLog::EndMessage;
2528
2529 TCU_FAIL("Culled distances returned from fragment shader dose not match expected values.");
2530 }
2531 }
2532 }
2533 }
2534 }
2535
2536 /* sub_grid cell size is 3*3 */
2537 DE_ASSERT(m_render_primitives % 9 == 0);
2538
2539 /* Quick check */
2540 switch (primitive_mode)
2541 {
2542 case PRIMITIVE_MODE_LINES:
2543 case PRIMITIVE_MODE_TRIANGLES:
2544 {
2545 /* Validate culled primitives */
2546 if (culldistances_array_size == 0)
2547 {
2548 DE_ASSERT(n_culled_primitives_real == 0);
2549 }
2550 else
2551 {
2552 /* Each 3rd line or triangle should be culled by test design */
2553 DE_ASSERT(glw::GLsizei(n_culled_primitives_real) == m_render_primitives / 3);
2554 }
2555
2556 /* Validate clipped vertices */
2557 if (clipdistances_array_size == 0)
2558 {
2559 DE_ASSERT(n_clipped_vertices_real == 0);
2560 }
2561 else
2562 {
2563 #if defined(DE_DEBUG) && !defined(DE_COVERAGE_BUILD)
2564 glw::GLint one_third_of_rendered_primitives = (m_render_primitives - n_culled_primitives_real) / 3;
2565 glw::GLint n_clipped_vertices_expected = /* One third of primitives has 0th vertex clipped */
2566 one_third_of_rendered_primitives +
2567 /* One third of primitives clipped completely */
2568 one_third_of_rendered_primitives * primitive_vertices_count;
2569
2570 DE_ASSERT(glw::GLint(n_clipped_vertices_real) == n_clipped_vertices_expected);
2571 #endif
2572 }
2573 break;
2574 }
2575
2576 case PRIMITIVE_MODE_POINTS:
2577 {
2578 /* Validate culled primitives */
2579 if (culldistances_array_size == 0)
2580 {
2581 DE_ASSERT(n_culled_primitives_real == 0);
2582 }
2583 else
2584 {
2585 /* 2/3 points should be culled by test design */
2586 DE_ASSERT(glw::GLsizei(n_culled_primitives_real) == m_render_primitives * 2 / 3);
2587 }
2588
2589 /* Validate clipped vertices */
2590 if (clipdistances_array_size == 0)
2591 {
2592 DE_ASSERT(n_clipped_vertices_real == 0);
2593 }
2594 else
2595 {
2596 #if defined(DE_DEBUG) && !defined(DE_COVERAGE_BUILD)
2597 glw::GLint one_third_of_rendered_primitives = (m_render_primitives - n_culled_primitives_real) / 3;
2598
2599 /* 2/3 of rendered points should be clipped by test design */
2600 DE_ASSERT(glw::GLint(n_clipped_vertices_real) == 2 * one_third_of_rendered_primitives);
2601 #endif
2602 }
2603
2604 break;
2605 }
2606 default:
2607 TCU_FAIL("Unknown primitive mode");
2608 }
2609 }
2610
2611 /** Executes test iteration.
2612 *
2613 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
2614 */
iterate()2615 tcu::TestNode::IterateResult CullDistance::FunctionalTest::iterate()
2616 {
2617 /* This test should only be executed if ARB_cull_distance is supported, or if
2618 * we're running a GL4.5 context
2619 */
2620 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_cull_distance") &&
2621 !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)))
2622 {
2623 throw tcu::NotSupportedError("GL_ARB_cull_distance is not supported");
2624 }
2625
2626 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2627 bool has_succeeded = true;
2628 bool is_core = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
2629
2630 /* Retrieve important GL constant values */
2631 glw::GLint gl_max_clip_distances_value = 0;
2632 glw::GLint gl_max_combined_clip_and_cull_distances_value = 0;
2633 glw::GLint gl_max_cull_distances_value = 0;
2634
2635 gl.getIntegerv(GL_MAX_CLIP_DISTANCES, &gl_max_clip_distances_value);
2636 gl.getIntegerv(GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES, &gl_max_combined_clip_and_cull_distances_value);
2637 gl.getIntegerv(GL_MAX_CULL_DISTANCES, &gl_max_cull_distances_value);
2638 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call(s) failed.");
2639
2640 gl.genTextures(1, &m_to_id);
2641 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed.");
2642
2643 gl.bindTexture(GL_TEXTURE_2D, m_to_id);
2644 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed.");
2645
2646 gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */
2647 GL_R32F, m_to_width, m_to_height);
2648 GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed.");
2649
2650 /* Set up the draw/read FBO */
2651 gl.genFramebuffers(1, &m_fbo_id);
2652 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() call failed.");
2653
2654 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id);
2655 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed.");
2656
2657 gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to_id, 0); /* level */
2658 GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed.");
2659
2660 /* Prepare a buffer object */
2661 gl.genBuffers(1, &m_bo_id);
2662 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
2663
2664 /* Prepare a VAO. We will configure separately for each iteration. */
2665 gl.genVertexArrays(1, &m_vao_id);
2666 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
2667
2668 /* Iterate over all functional tests */
2669 struct _test_item
2670 {
2671 bool redeclare_clipdistances_array;
2672 bool redeclare_culldistances_array;
2673 bool dynamic_index_writes;
2674 bool use_passthrough_gs;
2675 bool use_passthrough_ts;
2676 bool use_core_functionality;
2677 bool fetch_culldistances;
2678 } test_items[] = {/* Use the basic outline to test the basic functionality of cull distances. */
2679 {
2680 true, /* redeclare_clipdistances_array */
2681 true, /* redeclare_culldistances_array */
2682 false, /* dynamic_index_writes */
2683 false, /* use_passthrough_gs */
2684 false, /* use_passthrough_ts */
2685 is_core, /* use_core_functionality */
2686 false /* fetch_culldistances */
2687 },
2688 /* Use the basic outline but don't redeclare gl_ClipDistance with a size. */
2689 {
2690 false, /* redeclare_clipdistances_array */
2691 true, /* redeclare_culldistances_array */
2692 false, /* dynamic_index_writes */
2693 false, /* use_passthrough_gs */
2694 false, /* use_passthrough_ts */
2695 is_core, /* use_core_functionality */
2696 false /* fetch_culldistances */
2697 },
2698 /* Use the basic outline but don't redeclare gl_CullDistance with a size. */
2699 {
2700 true, /* redeclare_clipdistances_array */
2701 false, /* redeclare_culldistances_array */
2702 false, /* dynamic_index_writes */
2703 false, /* use_passthrough_gs */
2704 false, /* use_passthrough_ts */
2705 is_core, /* use_core_functionality */
2706 false /* fetch_culldistances */
2707 },
2708 /* Use the basic outline but don't redeclare either gl_ClipDistance or
2709 * gl_CullDistance with a size.
2710 */
2711 {
2712 false, /* redeclare_clipdistances_array */
2713 false, /* redeclare_culldistances_array */
2714 false, /* dynamic_index_writes */
2715 false, /* use_passthrough_gs */
2716 false, /* use_passthrough_ts */
2717 is_core, /* use_core_functionality */
2718 false /* fetch_culldistances */
2719 },
2720 /* Use the basic outline but use dynamic indexing when writing the elements
2721 * of the gl_ClipDistance and gl_CullDistance arrays.
2722 */
2723 {
2724 true, /* redeclare_clipdistances_array */
2725 true, /* redeclare_culldistances_array */
2726 true, /* dynamic_index_writes */
2727 false, /* use_passthrough_gs */
2728 false, /* use_passthrough_ts */
2729 is_core, /* use_core_functionality */
2730 false /* fetch_culldistances */
2731 },
2732 /* Use the basic outline but add a geometry shader to the program that
2733 * simply passes through all written clip and cull distances.
2734 */
2735 {
2736 true, /* redeclare_clipdistances_array */
2737 true, /* redeclare_culldistances_array */
2738 false, /* dynamic_index_writes */
2739 true, /* use_passthrough_gs */
2740 false, /* use_passthrough_ts */
2741 is_core, /* use_core_functionality */
2742 false /* fetch_culldistances */
2743 },
2744 /* Use the basic outline but add a tessellation control and tessellation
2745 * evaluation shader to the program which simply pass through all written
2746 * clip and cull distances.
2747 */
2748 {
2749 true, /* redeclare_clipdistances_array */
2750 true, /* redeclare_culldistances_array */
2751 false, /* dynamic_index_writes */
2752 false, /* use_passthrough_gs */
2753 true, /* use_passthrough_ts */
2754 is_core, /* use_core_functionality */
2755 false /* fetch_culldistances */
2756 },
2757 /* Test that using #extension with GL_ARB_cull_distance allows using the
2758 * feature even with an earlier version of GLSL. Also test that the
2759 * extension name is available as preprocessor #define.
2760 */
2761 {
2762 true, /* redeclare_clipdistances_array */
2763 true, /* redeclare_culldistances_array */
2764 false, /* dynamic_index_writes */
2765 false, /* use_passthrough_gs */
2766 false, /* use_passthrough_ts */
2767 false, /* use_core_functionality */
2768 false /* fetch_culldistances */
2769 },
2770 /* Use a program that has only a vertex shader and a fragment shader.
2771 * The vertex shader should redeclare gl_ClipDistance with a size that
2772 * fits all enabled cull distances. Also redeclare gl_CullDistance with a
2773 * size. The sum of the two sizes should not be more than MAX_COMBINED_-
2774 * CLIP_AND_CULL_DISTANCES. The fragment shader should output the cull
2775 * distances written by the vertex shader by reading them from the built-in
2776 * array gl_CullDistance.
2777 */
2778 {
2779 true, /* redeclare_clipdistances_array */
2780 true, /* redeclare_culldistances_array */
2781 false, /* dynamic_index_writes */
2782 false, /* use_passthrough_gs */
2783 false, /* use_passthrough_ts */
2784 false, /* use_core_functionality */
2785 true /* fetch_culldistances */
2786 }};
2787 const glw::GLuint n_test_items = sizeof(test_items) / sizeof(test_items[0]);
2788
2789 gl.viewport(0, 0, m_to_width, m_to_height);
2790 GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() call failed.");
2791
2792 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
2793 GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor() call failed.");
2794
2795 for (glw::GLuint n_test_item = 0; n_test_item < n_test_items; ++n_test_item)
2796 {
2797 /* Check for OpenGL feature support */
2798 if (test_items[n_test_item].use_passthrough_ts)
2799 {
2800 if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 0)) &&
2801 !m_context.getContextInfo().isExtensionSupported("GL_ARB_tessellation_shader"))
2802 {
2803 continue; // no tessellation shader support
2804 }
2805 }
2806
2807 const _test_item ¤t_test_item = test_items[n_test_item];
2808 const _primitive_mode primitive_modes[PRIMITIVE_MODE_COUNT] = {PRIMITIVE_MODE_LINES, PRIMITIVE_MODE_POINTS,
2809 PRIMITIVE_MODE_TRIANGLES};
2810
2811 for (glw::GLuint primitive_mode_index = 0; primitive_mode_index < PRIMITIVE_MODE_COUNT; ++primitive_mode_index)
2812 {
2813 _primitive_mode primitive_mode = primitive_modes[primitive_mode_index];
2814
2815 /* Iterate over a set of gl_ClipDistances[] and gl_CullDistances[] array sizes */
2816 for (glw::GLint n_iteration = 0; n_iteration <= gl_max_combined_clip_and_cull_distances_value;
2817 ++n_iteration)
2818 {
2819 glw::GLuint clipdistances_array_size = 0;
2820 glw::GLuint culldistances_array_size = 0;
2821
2822 if (n_iteration != 0 && n_iteration <= gl_max_clip_distances_value)
2823 {
2824 clipdistances_array_size = n_iteration;
2825 }
2826
2827 if ((gl_max_combined_clip_and_cull_distances_value - n_iteration) < gl_max_cull_distances_value)
2828 {
2829 culldistances_array_size = gl_max_combined_clip_and_cull_distances_value - n_iteration;
2830 }
2831 else
2832 {
2833 culldistances_array_size = gl_max_cull_distances_value;
2834 }
2835
2836 if (clipdistances_array_size == 0 && culldistances_array_size == 0)
2837 {
2838 /* Skip the empty iteration */
2839 continue;
2840 }
2841
2842 if (current_test_item.fetch_culldistances && (primitive_mode != PRIMITIVE_MODE_POINTS))
2843 {
2844 continue;
2845 }
2846
2847 /* Create a program to run */
2848 buildPO(clipdistances_array_size, culldistances_array_size, current_test_item.dynamic_index_writes,
2849 primitive_mode, current_test_item.redeclare_clipdistances_array,
2850 current_test_item.redeclare_culldistances_array, current_test_item.use_core_functionality,
2851 current_test_item.use_passthrough_gs, current_test_item.use_passthrough_ts,
2852 current_test_item.fetch_culldistances);
2853
2854 /* Initialize VAO data */
2855 configureVAO(clipdistances_array_size, culldistances_array_size, primitive_mode);
2856
2857 /* Run GLSL program and check results */
2858 executeRenderTest(clipdistances_array_size, culldistances_array_size, primitive_mode,
2859 current_test_item.use_passthrough_ts, current_test_item.fetch_culldistances);
2860
2861 } /* for (all iterations) */
2862 } /* for (all test modes) */
2863 } /* for (all test items) */
2864
2865 /* All done */
2866 if (has_succeeded)
2867 {
2868 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2869 }
2870 else
2871 {
2872 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
2873 }
2874
2875 return STOP;
2876 }
2877
2878 /** Returns pixel red component read from texture at position x, y.
2879 *
2880 * @param x x-coordinate to read pixel color component from
2881 * @param y y-coordinate to read pixel color component from
2882 **/
readRedPixelValue(glw::GLint x,glw::GLint y)2883 glw::GLint CullDistance::FunctionalTest::readRedPixelValue(glw::GLint x, glw::GLint y)
2884 {
2885 glw::GLint result = -1;
2886
2887 DE_ASSERT(x >= 0 && (glw::GLuint)x < m_to_width);
2888 DE_ASSERT(y >= 0 && (glw::GLuint)y < m_to_height);
2889
2890 result = m_to_pixel_data_cache[(m_to_width * y + x) * m_to_pixel_data_cache_color_components];
2891
2892 return result;
2893 }
2894
2895 /** Reads texture into m_to_pixel_data_cache.
2896 * Texture size determined by fields m_to_width, m_to_height
2897 **/
readTexturePixels()2898 void CullDistance::FunctionalTest::readTexturePixels()
2899 {
2900 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2901
2902 m_to_pixel_data_cache.clear();
2903
2904 m_to_pixel_data_cache.resize(m_to_width * m_to_height * m_to_pixel_data_cache_color_components);
2905
2906 /* Read vertex from texture */
2907 gl.readPixels(0, /* x */
2908 0, /* y */
2909 m_to_width, /* width */
2910 m_to_height, /* height */
2911 GL_RGBA, GL_UNSIGNED_SHORT, &m_to_pixel_data_cache[0]);
2912 GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() call failed.");
2913 }
2914
2915 /** Constructor.
2916 *
2917 * @param context Rendering context handle.
2918 **/
NegativeTest(deqp::Context & context)2919 CullDistance::NegativeTest::NegativeTest(deqp::Context &context)
2920 : TestCase(context, "negative", "Cull Distance Negative Test")
2921 , m_fs_id(0)
2922 , m_po_id(0)
2923 , m_temp_buffer(DE_NULL)
2924 , m_vs_id(0)
2925 {
2926 /* Left blank on purpose */
2927 }
2928
2929 /** @brief Cull Distance Negative Test deinitialization */
deinit()2930 void CullDistance::NegativeTest::deinit()
2931 {
2932 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2933
2934 if (m_fs_id != 0)
2935 {
2936 gl.deleteShader(m_fs_id);
2937
2938 m_fs_id = 0;
2939 }
2940
2941 if (m_po_id != 0)
2942 {
2943 gl.deleteProgram(m_po_id);
2944
2945 m_po_id = 0;
2946 }
2947
2948 if (m_vs_id != 0)
2949 {
2950 gl.deleteShader(m_vs_id);
2951
2952 m_vs_id = 0;
2953 }
2954
2955 if (m_temp_buffer != DE_NULL)
2956 {
2957 delete[] m_temp_buffer;
2958
2959 m_temp_buffer = DE_NULL;
2960 }
2961 }
2962
2963 /** @brief Get string description of test with given parameters
2964 *
2965 * @param [in] n_test_iteration Test iteration number
2966 * @param [in] should_redeclare_output_variables Indicate whether test redeclared gl_ClipDistance and gl_CullDistance
2967 * @param [in] use_dynamic_index_based_writes Indicate whether test used dynamic index-based setters
2968 *
2969 * @return String containing description.
2970 */
getTestDescription(int n_test_iteration,bool should_redeclare_output_variables,bool use_dynamic_index_based_writes)2971 std::string CullDistance::NegativeTest::getTestDescription(int n_test_iteration, bool should_redeclare_output_variables,
2972 bool use_dynamic_index_based_writes)
2973 {
2974 std::stringstream stream;
2975
2976 stream << "Test iteration [" << n_test_iteration << "] which uses a vertex shader that:\n\n"
2977 << ((should_redeclare_output_variables) ?
2978 "* redeclares gl_ClipDistance and gl_CullDistance arrays\n" :
2979 "* does not redeclare gl_ClipDistance and gl_CullDistance arrays\n")
2980 << ((use_dynamic_index_based_writes) ? "* uses dynamic index-based writes\n" : "* uses static writes\n");
2981
2982 return stream.str();
2983 }
2984
2985 /** Executes test iteration.
2986 *
2987 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
2988 */
iterate()2989 tcu::TestNode::IterateResult CullDistance::NegativeTest::iterate()
2990 {
2991 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2992
2993 /* Build the test shaders. */
2994 const glw::GLchar *token_dynamic_index_based_writes = "DYNAMIC_INDEX_BASED_WRITES";
2995 const glw::GLchar *token_insert_static_writes = "INSERT_STATIC_WRITES";
2996 const glw::GLchar *token_n_gl_clipdistance_entries = "N_GL_CLIPDISTANCE_ENTRIES";
2997 const glw::GLchar *token_n_gl_culldistance_entries = "N_GL_CULLDISTANCE_ENTRIES";
2998 const glw::GLchar *token_redeclare_output_variables = "REDECLARE_OUTPUT_VARIABLES";
2999
3000 const glw::GLchar *fs_body = "#version 130\n"
3001 "\n"
3002 "void main()\n"
3003 "{\n"
3004 "}\n";
3005
3006 const glw::GLchar *vs_body_preamble = "#version 130\n"
3007 "\n"
3008 " #extension GL_ARB_cull_distance : require\n"
3009 "\n";
3010
3011 const glw::GLchar *vs_body_main = "#ifdef REDECLARE_OUTPUT_VARIABLES\n"
3012 " out float gl_ClipDistance[N_GL_CLIPDISTANCE_ENTRIES];\n"
3013 " out float gl_CullDistance[N_GL_CULLDISTANCE_ENTRIES];\n"
3014 "#endif\n"
3015 "\n"
3016 "void main()\n"
3017 "{\n"
3018 "#ifdef DYNAMIC_INDEX_BASED_WRITES\n"
3019 " for (int n_clipdistance_entry = 0;\n"
3020 " n_clipdistance_entry < N_GL_CLIPDISTANCE_ENTRIES;\n"
3021 " ++n_clipdistance_entry)\n"
3022 " {\n"
3023 " gl_ClipDistance[n_clipdistance_entry] = float(n_clipdistance_entry) / "
3024 "float(N_GL_CLIPDISTANCE_ENTRIES);\n"
3025 " }\n"
3026 "\n"
3027 " for (int n_culldistance_entry = 0;\n"
3028 " n_culldistance_entry < N_GL_CULLDISTANCE_ENTRIES;\n"
3029 " ++n_culldistance_entry)\n"
3030 " {\n"
3031 " gl_CullDistance[n_culldistance_entry] = float(n_culldistance_entry) / "
3032 "float(N_GL_CULLDISTANCE_ENTRIES);\n"
3033 " }\n"
3034 "#else\n"
3035 " INSERT_STATIC_WRITES\n"
3036 "#endif\n"
3037 "}\n";
3038
3039 /* This test should only be executed if ARB_cull_distance is supported, or if
3040 * we're running a GL4.5 context
3041 */
3042 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_cull_distance") &&
3043 !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)))
3044 {
3045 throw tcu::NotSupportedError("GL_ARB_cull_distance is not supported");
3046 }
3047
3048 /* It only makes sense to run this test if GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES
3049 * is lower than a sum of GL_MAX_CLIP_DISTANCES and GL_MAX_CLIP_CULL_DISTANCES.
3050 */
3051 glw::GLint gl_max_clip_distances_value = 0;
3052 glw::GLint gl_max_combined_clip_and_cull_distances_value = 0;
3053 glw::GLint gl_max_cull_distances_value = 0;
3054 glw::GLuint n_gl_clipdistance_array_items = 0;
3055 std::string n_gl_clipdistance_array_items_string;
3056 glw::GLuint n_gl_culldistance_array_items = 0;
3057 std::string n_gl_culldistance_array_items_string;
3058 std::string static_write_shader_body_part;
3059
3060 gl.getIntegerv(GL_MAX_CLIP_DISTANCES, &gl_max_clip_distances_value);
3061 gl.getIntegerv(GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES, &gl_max_combined_clip_and_cull_distances_value);
3062 gl.getIntegerv(GL_MAX_CULL_DISTANCES, &gl_max_cull_distances_value);
3063
3064 if (gl_max_clip_distances_value + gl_max_cull_distances_value < gl_max_combined_clip_and_cull_distances_value)
3065 {
3066 m_testCtx.getLog() << tcu::TestLog::Message
3067 << "GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES is larger than or equal to "
3068 "the sum of GL_MAX_CLIP_DISTANCES and GL_MAX_CULL_DISTANCES. Skipping."
3069 << tcu::TestLog::EndMessage;
3070
3071 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3072
3073 return STOP;
3074 }
3075
3076 n_gl_clipdistance_array_items = gl_max_clip_distances_value;
3077 n_gl_culldistance_array_items = gl_max_combined_clip_and_cull_distances_value - gl_max_clip_distances_value + 1;
3078
3079 /* Determine the number of items we will want the gl_ClipDistance and gl_CullDistance arrays
3080 * to hold for test iterations that will re-declare the built-in output variables.
3081 */
3082 {
3083 std::stringstream temp_sstream;
3084
3085 temp_sstream << n_gl_clipdistance_array_items;
3086
3087 n_gl_clipdistance_array_items_string = temp_sstream.str();
3088 }
3089
3090 {
3091 std::stringstream temp_sstream;
3092
3093 temp_sstream << n_gl_culldistance_array_items;
3094
3095 n_gl_culldistance_array_items_string = temp_sstream.str();
3096 }
3097
3098 /* Form the "static write" shader body part. */
3099 {
3100 std::stringstream temp_sstream;
3101
3102 temp_sstream << "gl_ClipDistance[" << n_gl_clipdistance_array_items_string.c_str() << "] = 0.0f;\n"
3103 << "gl_CullDistance[" << n_gl_culldistance_array_items_string.c_str() << "] = 0.0f;\n";
3104
3105 static_write_shader_body_part = temp_sstream.str();
3106 }
3107
3108 /* Prepare GL objects before we continue */
3109 glw::GLint compile_status = GL_FALSE;
3110
3111 m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
3112 m_po_id = gl.createProgram();
3113 m_vs_id = gl.createShader(GL_VERTEX_SHADER);
3114
3115 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() / glCreateShader() calls failed.");
3116
3117 gl.attachShader(m_po_id, m_fs_id);
3118 gl.attachShader(m_po_id, m_vs_id);
3119
3120 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed.");
3121
3122 gl.shaderSource(m_fs_id, 1, /* count */
3123 &fs_body, DE_NULL); /* length */
3124 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
3125
3126 gl.compileShader(m_fs_id);
3127 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
3128
3129 gl.getShaderiv(m_fs_id, GL_COMPILE_STATUS, &compile_status);
3130 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
3131
3132 if (compile_status == GL_FALSE)
3133 {
3134 TCU_FAIL("Fragment shader failed to compile.");
3135 }
3136
3137 /* Run three separate test iterations. */
3138 struct _test_item
3139 {
3140 bool should_redeclare_output_variables;
3141 bool use_dynamic_index_based_writes;
3142 } test_items[] = {/* Negative Test 1 */
3143 {true, false},
3144
3145 /* Negative Test 2 */
3146 {false, false},
3147
3148 /* Negative Test 3 */
3149 {false, true}};
3150 const unsigned int n_test_items = sizeof(test_items) / sizeof(test_items[0]);
3151
3152 for (unsigned int n_test_item = 0; n_test_item < n_test_items; ++n_test_item)
3153 {
3154 const _test_item ¤t_test_item = test_items[n_test_item];
3155
3156 /* Prepare vertex shader body */
3157 std::size_t token_position = std::string::npos;
3158 std::stringstream vs_body_sstream;
3159 std::string vs_body_string;
3160
3161 vs_body_sstream << vs_body_preamble << "\n";
3162
3163 if (current_test_item.should_redeclare_output_variables)
3164 {
3165 vs_body_sstream << "#define " << token_redeclare_output_variables << "\n";
3166 }
3167
3168 if (current_test_item.use_dynamic_index_based_writes)
3169 {
3170 vs_body_sstream << "#define " << token_dynamic_index_based_writes << "\n";
3171 }
3172
3173 vs_body_sstream << vs_body_main;
3174
3175 /* Replace tokens with meaningful values */
3176 vs_body_string = vs_body_sstream.str();
3177
3178 while ((token_position = vs_body_string.find(token_n_gl_clipdistance_entries)) != std::string::npos)
3179 {
3180 vs_body_string = vs_body_string.replace(token_position, strlen(token_n_gl_clipdistance_entries),
3181 n_gl_clipdistance_array_items_string);
3182 }
3183
3184 while ((token_position = vs_body_string.find(token_n_gl_culldistance_entries)) != std::string::npos)
3185 {
3186 vs_body_string = vs_body_string.replace(token_position, strlen(token_n_gl_clipdistance_entries),
3187 n_gl_culldistance_array_items_string);
3188 }
3189
3190 while ((token_position = vs_body_string.find(token_insert_static_writes)) != std::string::npos)
3191 {
3192 vs_body_string = vs_body_string.replace(token_position, strlen(token_insert_static_writes),
3193 static_write_shader_body_part);
3194 }
3195
3196 /* Try to compile the vertex shader */
3197 glw::GLint compile_status_internal = GL_FALSE;
3198 const char *vs_body_raw_ptr = vs_body_string.c_str();
3199
3200 gl.shaderSource(m_vs_id, 1, /* count */
3201 &vs_body_raw_ptr, DE_NULL); /* length */
3202 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
3203
3204 gl.compileShader(m_vs_id);
3205 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
3206
3207 gl.getShaderiv(m_vs_id, GL_COMPILE_STATUS, &compile_status_internal);
3208 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
3209
3210 if (compile_status_internal == GL_FALSE)
3211 {
3212 glw::GLint buffer_size = 0;
3213
3214 /* Log the compilation error */
3215 m_testCtx.getLog() << tcu::TestLog::Message
3216 << getTestDescription(n_test_item, current_test_item.should_redeclare_output_variables,
3217 current_test_item.use_dynamic_index_based_writes)
3218 << "has failed (as expected) to compile with the following info log:\n\n"
3219 << tcu::TestLog::EndMessage;
3220
3221 gl.getShaderiv(m_vs_id, GL_INFO_LOG_LENGTH, &buffer_size);
3222 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
3223
3224 m_temp_buffer = new glw::GLchar[buffer_size + 1];
3225
3226 memset(m_temp_buffer, 0, buffer_size + 1);
3227
3228 gl.getShaderInfoLog(m_vs_id, buffer_size, DE_NULL, /* length */
3229 m_temp_buffer);
3230 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderInfoLog() call failed.");
3231
3232 m_testCtx.getLog() << tcu::TestLog::Message << m_temp_buffer << tcu::TestLog::EndMessage;
3233
3234 delete[] m_temp_buffer;
3235 m_temp_buffer = DE_NULL;
3236
3237 /* Move on to the next iteration */
3238 continue;
3239 }
3240
3241 /* Try to link the program object */
3242 glw::GLint link_status = GL_FALSE;
3243
3244 gl.linkProgram(m_po_id);
3245 GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
3246
3247 gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status);
3248 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
3249
3250 if (link_status == GL_TRUE)
3251 {
3252 m_testCtx.getLog() << tcu::TestLog::Message
3253 << getTestDescription(n_test_item, current_test_item.should_redeclare_output_variables,
3254 current_test_item.use_dynamic_index_based_writes)
3255 << "has linked successfully which is invalid!" << tcu::TestLog::EndMessage;
3256
3257 TCU_FAIL("Program object has linked successfully, even though the process should have failed.");
3258 }
3259 else
3260 {
3261 glw::GLint buffer_size = 0;
3262
3263 m_testCtx.getLog() << tcu::TestLog::Message
3264 << getTestDescription(n_test_item, current_test_item.should_redeclare_output_variables,
3265 current_test_item.use_dynamic_index_based_writes)
3266 << "has failed (as expected) to link with the following info log:\n\n"
3267 << tcu::TestLog::EndMessage;
3268
3269 gl.getProgramiv(m_po_id, GL_INFO_LOG_LENGTH, &buffer_size);
3270 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
3271
3272 m_temp_buffer = new glw::GLchar[buffer_size + 1];
3273
3274 memset(m_temp_buffer, 0, buffer_size + 1);
3275
3276 gl.getProgramInfoLog(m_po_id, buffer_size, DE_NULL, /* length */
3277 m_temp_buffer);
3278 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInfoLog() call failed.");
3279
3280 m_testCtx.getLog() << tcu::TestLog::Message << m_temp_buffer << tcu::TestLog::EndMessage;
3281
3282 delete[] m_temp_buffer;
3283 m_temp_buffer = DE_NULL;
3284 }
3285 } /* for (all test items) */
3286
3287 /* All done */
3288 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3289
3290 return STOP;
3291 }
3292
3293 /** Constructor.
3294 *
3295 * @param context Rendering context.
3296 */
Tests(deqp::Context & context)3297 CullDistance::Tests::Tests(deqp::Context &context) : TestCaseGroup(context, "cull_distance", "Cull Distance Test Suite")
3298 {
3299 }
3300
3301 /** Initializes the test group contents. */
init()3302 void CullDistance::Tests::init()
3303 {
3304 addChild(new CullDistance::APICoverageTest(m_context));
3305 addChild(new CullDistance::FunctionalTest(m_context));
3306 addChild(new CullDistance::NegativeTest(m_context));
3307 }
3308 } // namespace glcts
3309