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