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 #include "gl4cStencilTexturingTests.hpp"
25
26 #include "gluContextInfo.hpp"
27 #include "gluDefs.hpp"
28 #include "gluStrUtil.hpp"
29 #include "glwEnums.hpp"
30 #include "glwFunctions.hpp"
31 #include "tcuTestLog.hpp"
32
33 #include <algorithm>
34 #include <string>
35 #include <vector>
36
37 #define DEBUG_REPLACE_TOKEN 0
38
39 using namespace glw;
40
41 namespace gl4cts
42 {
43 namespace StencilTexturing
44 {
45 class Utils
46 {
47 public:
48 static GLuint createAndBuildProgram(deqp::Context& context, const GLchar* cs_code, const GLchar* fs_code,
49 const GLchar* gs_code, const GLchar* tcs_code, const GLchar* tes_code,
50 const GLchar* vs_code);
51
52 static GLuint createAndCompileShader(deqp::Context& context, const GLenum type, const GLchar* code);
53
54 static GLuint createAndFill2DTexture(deqp::Context& context, GLuint width, GLuint height, GLenum internal_format,
55 GLenum format, GLenum type, const GLvoid* data);
56
57 static void deleteProgram(deqp::Context& context, const GLuint id);
58 static void deleteShader(deqp::Context& context, const GLuint id);
59 static void deleteTexture(deqp::Context& context, const GLuint id);
60 static bool isExtensionSupported(deqp::Context& context, const GLchar* extension_name);
61
62 static void replaceToken(const GLchar* token, size_t& search_position, const GLchar* text, std::string& string);
63 };
64
65 /** Create and build program from provided sources
66 *
67 * @param context Test context
68 * @param cs_code Source code for compute shader stage
69 * @param fs_code Source code for fragment shader stage
70 * @param gs_code Source code for geometry shader stage
71 * @param tcs_code Source code for tesselation control shader stage
72 * @param tes_code Source code for tesselation evaluation shader stage
73 * @param vs_code Source code for vertex shader stage
74 *
75 * @return ID of program object
76 **/
createAndBuildProgram(deqp::Context & context,const GLchar * cs_code,const GLchar * fs_code,const GLchar * gs_code,const GLchar * tcs_code,const GLchar * tes_code,const GLchar * vs_code)77 GLuint Utils::createAndBuildProgram(deqp::Context& context, const GLchar* cs_code, const GLchar* fs_code,
78 const GLchar* gs_code, const GLchar* tcs_code, const GLchar* tes_code,
79 const GLchar* vs_code)
80 {
81 #define N_SHADER_STAGES 6
82
83 const Functions& gl = context.getRenderContext().getFunctions();
84 GLuint id = 0;
85 GLuint shader_ids[N_SHADER_STAGES] = { 0 };
86
87 const GLchar* shader_sources[N_SHADER_STAGES] = { cs_code, fs_code, gs_code, tcs_code, tes_code, vs_code };
88
89 const GLenum shader_types[N_SHADER_STAGES] = { GL_COMPUTE_SHADER, GL_FRAGMENT_SHADER,
90 GL_GEOMETRY_SHADER, GL_TESS_CONTROL_SHADER,
91 GL_TESS_EVALUATION_SHADER, GL_VERTEX_SHADER };
92 GLint status = GL_FALSE;
93
94 /* Compile all shaders */
95 try
96 {
97 for (GLuint i = 0; i < N_SHADER_STAGES; ++i)
98 {
99 if (0 != shader_sources[i])
100 {
101 shader_ids[i] = createAndCompileShader(context, shader_types[i], shader_sources[i]);
102 }
103 }
104
105 /* Check compilation */
106 for (GLuint i = 0; i < N_SHADER_STAGES; ++i)
107 {
108 if ((0 != shader_sources[i]) && (0 == shader_ids[i]))
109 {
110 context.getTestContext().getLog() << tcu::TestLog::Message
111 << "Failed to build program due to compilation problems"
112 << tcu::TestLog::EndMessage;
113
114 /* Delete shaders */
115 for (GLuint j = 0; j < N_SHADER_STAGES; ++j)
116 {
117 deleteShader(context, shader_ids[j]);
118 }
119
120 /* Done */
121 return 0;
122 }
123 }
124
125 /* Create program */
126 id = gl.createProgram();
127 GLU_EXPECT_NO_ERROR(gl.getError(), "CreateProgram");
128
129 /* Attach shaders */
130 for (GLuint i = 0; i < N_SHADER_STAGES; ++i)
131 {
132 if (0 != shader_ids[i])
133 {
134 gl.attachShader(id, shader_ids[i]);
135 GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
136 }
137 }
138
139 /* Link program */
140 gl.linkProgram(id);
141 GLU_EXPECT_NO_ERROR(gl.getError(), "LinkProgram");
142
143 /* Clean shaders */
144 for (GLuint j = 0; j < N_SHADER_STAGES; ++j)
145 {
146 deleteShader(context, shader_ids[j]);
147 }
148
149 /* Get link status */
150 gl.getProgramiv(id, GL_LINK_STATUS, &status);
151 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv");
152
153 /* Log link error */
154 if (GL_TRUE != status)
155 {
156 glw::GLint length = 0;
157 std::string message;
158
159 /* Get error log length */
160 gl.getProgramiv(id, GL_INFO_LOG_LENGTH, &length);
161 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv");
162
163 message.resize(length, 0);
164
165 /* Get error log */
166 gl.getProgramInfoLog(id, length, 0, &message[0]);
167 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramInfoLog");
168
169 context.getTestContext().getLog() << tcu::TestLog::Message << "Program linking failed: " << message
170 << tcu::TestLog::EndMessage;
171
172 /* Clean program */
173 deleteProgram(context, id);
174
175 /* Done */
176 return 0;
177 }
178 }
179 catch (std::exception& exc)
180 {
181 /* Delete shaders */
182 for (GLuint j = 0; j < N_SHADER_STAGES; ++j)
183 {
184 deleteShader(context, shader_ids[j]);
185 }
186
187 throw exc;
188 }
189
190 return id;
191 }
192
193 /** Create and compile shader
194 *
195 * @param context Test context
196 * @param type Type of shader
197 * @param code Source code for shader
198 *
199 * @return ID of shader object
200 **/
createAndCompileShader(deqp::Context & context,const GLenum type,const GLchar * code)201 GLuint Utils::createAndCompileShader(deqp::Context& context, const GLenum type, const GLchar* code)
202 {
203 const Functions& gl = context.getRenderContext().getFunctions();
204 GLuint id = gl.createShader(type);
205 GLint status = GL_FALSE;
206
207 GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
208
209 try
210 {
211 gl.shaderSource(id, 1 /* count */, &code, 0 /* lengths */);
212 GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderSource");
213
214 /* Compile */
215 gl.compileShader(id);
216 GLU_EXPECT_NO_ERROR(gl.getError(), "CompileShader");
217
218 /* Get compilation status */
219 gl.getShaderiv(id, GL_COMPILE_STATUS, &status);
220 GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv");
221
222 /* Log compilation error */
223 if (GL_TRUE != status)
224 {
225 glw::GLint length = 0;
226 std::string message;
227
228 /* Error log length */
229 gl.getShaderiv(id, GL_INFO_LOG_LENGTH, &length);
230 GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv");
231
232 /* Prepare storage */
233 message.resize(length, 0);
234
235 /* Get error log */
236 gl.getShaderInfoLog(id, length, 0, &message[0]);
237 GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderInfoLog");
238
239 context.getTestContext().getLog() << tcu::TestLog::Message << "Shader (" << glu::getShaderTypeStr(type)
240 << ") compilation failed: " << message << tcu::TestLog::EndMessage;
241
242 deleteShader(context, id);
243 id = 0;
244 }
245 }
246 catch (std::exception& exc)
247 {
248 deleteShader(context, id);
249 throw exc;
250 }
251
252 return id;
253 }
254
255 /** Generate and fill 2d texture
256 *
257 * @param context Test context
258 * @param width Width of texture
259 * @param height Height of texture
260 * @param internal_format Internal format of texture
261 * @param format Format of data
262 * @param type Type of data
263 * @param data Data
264 *
265 * @return ID of texture object
266 **/
createAndFill2DTexture(deqp::Context & context,GLuint width,GLuint height,GLenum internal_format,GLenum format,GLenum type,const GLvoid * data)267 GLuint Utils::createAndFill2DTexture(deqp::Context& context, GLuint width, GLuint height, GLenum internal_format,
268 GLenum format, GLenum type, const GLvoid* data)
269 {
270 const Functions& gl = context.getRenderContext().getFunctions();
271 GLuint id = 0;
272
273 gl.genTextures(1, &id);
274 GLU_EXPECT_NO_ERROR(gl.getError(), "GenTextures");
275
276 try
277 {
278 gl.bindTexture(GL_TEXTURE_2D, id);
279 GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
280
281 gl.texImage2D(GL_TEXTURE_2D, 0 /* level */, internal_format, width, height, 0 /* border */, format, type, data);
282 GLU_EXPECT_NO_ERROR(gl.getError(), "TexImage2D");
283
284 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
285 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
286 GLU_EXPECT_NO_ERROR(gl.getError(), "TexParameteri");
287
288 gl.bindTexture(GL_TEXTURE_2D, 0);
289 GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
290 }
291 catch (std::exception& exc)
292 {
293 gl.deleteTextures(1, &id);
294 id = 0;
295
296 throw exc;
297 }
298
299 return id;
300 }
301
302 /** Delete program
303 *
304 * @param context Test context
305 * @param id ID of program
306 **/
deleteProgram(deqp::Context & context,const GLuint id)307 void Utils::deleteProgram(deqp::Context& context, const GLuint id)
308 {
309 const glw::Functions& gl = context.getRenderContext().getFunctions();
310
311 if (0 != id)
312 {
313 gl.deleteProgram(id);
314 }
315 }
316
317 /** Delete shader
318 *
319 * @param context Test context
320 * @param id ID of shader
321 **/
deleteShader(deqp::Context & context,const GLuint id)322 void Utils::deleteShader(deqp::Context& context, const GLuint id)
323 {
324 const glw::Functions& gl = context.getRenderContext().getFunctions();
325
326 if (0 != id)
327 {
328 gl.deleteShader(id);
329 }
330 }
331
332 /** Delete texture
333 *
334 * @param context Test context
335 * @param id ID of texture
336 **/
deleteTexture(deqp::Context & context,const GLuint id)337 void Utils::deleteTexture(deqp::Context& context, const GLuint id)
338 {
339 const glw::Functions& gl = context.getRenderContext().getFunctions();
340
341 if (0 != id)
342 {
343 gl.deleteTextures(1, &id);
344 }
345 }
346
347 /** Checks if extensions is not available.
348 *
349 * @param context Test context
350 * @param extension_name Name of extension
351 *
352 * @return true if extension is reported as available, false otherwise
353 **/
isExtensionSupported(deqp::Context & context,const GLchar * extension_name)354 bool Utils::isExtensionSupported(deqp::Context& context, const GLchar* extension_name)
355 {
356 const std::vector<std::string>& extensions = context.getContextInfo().getExtensions();
357
358 if (std::find(extensions.begin(), extensions.end(), extension_name) == extensions.end())
359 {
360 std::string message = "Required extension is not supported: ";
361 message.append(extension_name);
362
363 return false;
364 }
365
366 return true;
367 }
368
369 /** Replace first occurance of <token> with <text> in <string> starting at <search_posistion>
370 *
371 * @param token Token string
372 * @param search_position Position at which find will start, it is updated to position at which replaced text ends
373 * @param text String that will be used as replacement for <token>
374 * @param string String to work on
375 **/
replaceToken(const GLchar * token,size_t & search_position,const GLchar * text,std::string & string)376 void Utils::replaceToken(const GLchar* token, size_t& search_position, const GLchar* text, std::string& string)
377 {
378 const size_t text_length = strlen(text);
379 const size_t token_length = strlen(token);
380 const size_t token_position = string.find(token, search_position);
381
382 #if DEBUG_REPLACE_TOKEN
383 if (std::string::npos == token_position)
384 {
385 string.append("\n\nInvalid token: ");
386 string.append(token);
387
388 TCU_FAIL(string.c_str());
389 }
390 #endif /* DEBUG_REPLACE_TOKEN */
391
392 string.replace(token_position, token_length, text, text_length);
393
394 search_position = token_position + text_length;
395 }
396
397 /* FunctionalTest */
398 /* Shader sources */
399 const GLchar* FunctionalTest::m_compute_shader_code =
400 "#version 430 core\n"
401 "\n"
402 "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
403 "\n"
404 "IMAGE_DEFINITION;\n"
405 "SAMPLER_DEFINITION;\n"
406 "\n"
407 "void main()\n"
408 "{\n"
409 " vec2 tex_coord = vec2(gl_GlobalInvocationID.xy) / 8.0;\n"
410 "\n"
411 " imageStore(uni_image,\n"
412 " ivec2(gl_GlobalInvocationID.xy),\n"
413 " TYPE(texture(uni_sampler, tex_coord).r, 0, 0, 0));\n"
414 "}\n"
415 "\n";
416
417 const GLchar* FunctionalTest::m_fragment_shader_code =
418 "#version 430 core\n"
419 "\n"
420 " in vec2 gs_fs_tex_coord;\n"
421 "flat in uint gs_fs_result;\n"
422 " out TYPE fs_out_result;\n"
423 "\n"
424 "SAMPLER_DEFINITION;\n"
425 "\n"
426 "void main()\n"
427 "{\n"
428 " if (1 != gs_fs_result)\n"
429 " {\n"
430 " fs_out_result = texture(uni_sampler, vec2(0.9375, 0.9375));\n"
431 " }\n"
432 " else\n"
433 " {\n"
434 " fs_out_result = texture(uni_sampler, gs_fs_tex_coord);\n"
435 " }\n"
436 "}\n"
437 "\n";
438
439 const GLchar* FunctionalTest::m_geometry_shader_code =
440 "#version 430 core\n"
441 "\n"
442 "layout(points) in;\n"
443 "layout(triangle_strip, max_vertices = 4) out;\n"
444 "\n"
445 " in uint tes_gs_result[];\n"
446 "flat out uint gs_fs_result;\n"
447 " out vec2 gs_fs_tex_coord;\n"
448 "\n"
449 "SAMPLER_DEFINITION;\n"
450 "\n"
451 "void main()\n"
452 "{\n"
453 " uint result = 1u;\n"
454 "\n"
455 " if (1 != tes_gs_result[0])\n"
456 " {\n"
457 " result = 0u;\n"
458 " }\n"
459 "\n"
460 " if (EXPECTED_VALUE != texture(uni_sampler, vec2(0.9375, 0.9375)).r)\n"
461 " {\n"
462 " result = 0u;\n"
463 " }\n"
464 "\n"
465 " gs_fs_result = result;\n"
466 " gs_fs_tex_coord = vec2(0, 0);\n"
467 " gl_Position = vec4(-1, -1, 0, 1);\n"
468 " EmitVertex();\n"
469 " gs_fs_result = result;\n"
470 " gs_fs_tex_coord = vec2(0, 1);\n"
471 " gl_Position = vec4(-1, 1, 0, 1);\n"
472 " EmitVertex();\n"
473 " gs_fs_result = result;\n"
474 " gs_fs_tex_coord = vec2(1, 0);\n"
475 " gl_Position = vec4(1, -1, 0, 1);\n"
476 " EmitVertex();\n"
477 " gs_fs_result = result;\n"
478 " gs_fs_tex_coord = vec2(1, 1);\n"
479 " gl_Position = vec4(1, 1, 0, 1);\n"
480 " EmitVertex();\n"
481 "}\n"
482 "\n";
483
484 const GLchar* FunctionalTest::m_tesselation_control_shader_code =
485 "#version 430 core\n"
486 "\n"
487 "layout(vertices = 1) out;\n"
488 "\n"
489 "in uint vs_tcs_result[];\n"
490 "out uint tcs_tes_result[];\n"
491 "\n"
492 "SAMPLER_DEFINITION;\n"
493 "\n"
494 "void main()\n"
495 "{\n"
496 " uint result = 1u;\n"
497 "\n"
498 " if (1u != vs_tcs_result[gl_InvocationID])\n"
499 " {\n"
500 " result = 0u;\n"
501 " }\n"
502 "\n"
503 " if (EXPECTED_VALUE != texture(uni_sampler, vec2(0.9375, 0.9375)).r)\n"
504 " {\n"
505 " result = 0u;\n"
506 " }\n"
507 "\n"
508 " tcs_tes_result[gl_InvocationID] = result;\n"
509 "\n"
510 " gl_TessLevelOuter[0] = 1.0;\n"
511 " gl_TessLevelOuter[1] = 1.0;\n"
512 " gl_TessLevelOuter[2] = 1.0;\n"
513 " gl_TessLevelOuter[3] = 1.0;\n"
514 " gl_TessLevelInner[0] = 1.0;\n"
515 " gl_TessLevelInner[1] = 1.0;\n"
516 "}\n"
517 "\n";
518
519 const GLchar* FunctionalTest::m_tesselation_evaluation_shader_code =
520 "#version 430 core\n"
521 "\n"
522 "layout(isolines, point_mode) in;\n"
523 "\n"
524 "in uint tcs_tes_result[];\n"
525 "out uint tes_gs_result;\n"
526 "\n"
527 "SAMPLER_DEFINITION;\n"
528 "\n"
529 "void main()\n"
530 "{\n"
531 " uint result = 1u;\n"
532 "\n"
533 " if (1u != tcs_tes_result[0])\n"
534 " {\n"
535 " result = 0u;\n"
536 " }\n"
537 "\n"
538 " if (EXPECTED_VALUE != texture(uni_sampler, vec2(0.9375, 0.9375)).r)\n"
539 " {\n"
540 " result = 0u;\n"
541 " }\n"
542 "\n"
543 " tes_gs_result = result;\n"
544 "}\n"
545 "\n";
546
547 const GLchar* FunctionalTest::m_vertex_shader_code =
548 "#version 430 core\n"
549 "\n"
550 "out uint vs_tcs_result;\n"
551 "\n"
552 "SAMPLER_DEFINITION;\n"
553 "\n"
554 "void main()\n"
555 "{\n"
556 " uint result = 1u;\n"
557 "\n"
558 " if (EXPECTED_VALUE != texture(uni_sampler, vec2(0.9375, 0.9375)).r)\n"
559 " {\n"
560 " result = 0u;\n"
561 " }\n"
562 "\n"
563 " vs_tcs_result = result;\n"
564 "}\n"
565 "\n";
566
567 const GLchar* FunctionalTest::m_expected_value_depth = "0.0";
568
569 const GLchar* FunctionalTest::m_expected_value_stencil = "15u";
570
571 const GLchar* FunctionalTest::m_image_definition_depth = "writeonly uniform image2D uni_image";
572
573 const GLchar* FunctionalTest::m_image_definition_stencil = "writeonly uniform uimage2D uni_image";
574
575 const GLchar* FunctionalTest::m_output_type_depth = "vec4";
576
577 const GLchar* FunctionalTest::m_output_type_stencil = "uvec4";
578
579 const GLchar* FunctionalTest::m_sampler_definition_depth = "uniform sampler2D uni_sampler";
580
581 const GLchar* FunctionalTest::m_sampler_definition_stencil = "uniform usampler2D uni_sampler";
582
583 /* Constants */
584 const GLuint FunctionalTest::m_height = 8;
585 const GLint FunctionalTest::m_image_unit = 1;
586 const GLint FunctionalTest::m_texture_unit = 1;
587 const GLuint FunctionalTest::m_width = 8;
588
589 /** Constructor
590 *
591 * @param context Test context
592 **/
FunctionalTest(deqp::Context & context)593 FunctionalTest::FunctionalTest(deqp::Context& context)
594 : TestCase(context, "functional", "Checks if sampling stencil texture gives expected results")
595 {
596 /* Nothing to be done here */
597 }
598
599 /** Execute test
600 *
601 * @return tcu::TestNode::STOP
602 **/
iterate()603 tcu::TestNode::IterateResult FunctionalTest::iterate()
604 {
605 bool test_result = true;
606
607 if (false == test(GL_DEPTH24_STENCIL8, true))
608 {
609 m_context.getTestContext().getLog() << tcu::TestLog::Message
610 << "Test failed. Case format: GL_DEPTH24_STENCIL8, channel: S"
611 << tcu::TestLog::EndMessage;
612 test_result = false;
613 }
614
615 if (false == test(GL_DEPTH24_STENCIL8, false))
616 {
617 m_context.getTestContext().getLog() << tcu::TestLog::Message
618 << "Test failed. Case format: GL_DEPTH24_STENCIL8, channel: D"
619 << tcu::TestLog::EndMessage;
620 test_result = false;
621 }
622
623 if (false == test(GL_DEPTH32F_STENCIL8, true))
624 {
625 m_context.getTestContext().getLog() << tcu::TestLog::Message
626 << "Test failed. Case format: GL_DEPTH32F_STENCIL8, channel: S"
627 << tcu::TestLog::EndMessage;
628 test_result = false;
629 }
630
631 if (false == test(GL_DEPTH32F_STENCIL8, false))
632 {
633 m_context.getTestContext().getLog() << tcu::TestLog::Message
634 << "Test failed. Case format: GL_DEPTH32F_STENCIL8, channel: D"
635 << tcu::TestLog::EndMessage;
636 test_result = false;
637 }
638
639 /* Set result */
640 if (true == test_result)
641 {
642 m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
643 }
644 else
645 {
646 m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
647 }
648
649 /* Done */
650 return tcu::TestNode::STOP;
651 }
652
653 /** Execute compute program
654 *
655 * @param program_id ID of program
656 * @param is_stencil Selects if stencil or depth channel is sampled
657 * @param dst_texture_id ID of destination texture
658 * @param src_texture_id ID of source texture
659 **/
dispatch(GLuint program_id,bool is_stencil,GLuint dst_texture_id,GLuint src_texture_id)660 void FunctionalTest::dispatch(GLuint program_id, bool is_stencil, GLuint dst_texture_id, GLuint src_texture_id)
661 {
662 const Functions& gl = m_context.getRenderContext().getFunctions();
663 GLenum internal_format = GL_R8UI;
664 GLint uni_image_loc = -1;
665 GLint uni_sampler_loc = -1;
666
667 if (false == is_stencil)
668 {
669 internal_format = GL_R32F;
670 }
671
672 /* Set program */
673 gl.useProgram(program_id);
674 GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgram");
675
676 /* Get uniform location and bind texture to proper image unit */
677 uni_image_loc = gl.getUniformLocation(program_id, "uni_image");
678 GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformLocation");
679
680 gl.bindImageTexture(m_image_unit, dst_texture_id, 0 /* level */, GL_FALSE /* layered */, 0 /* Layer */,
681 GL_WRITE_ONLY, internal_format);
682 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
683
684 gl.uniform1i(uni_image_loc, m_image_unit);
685 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
686
687 /* Get uniform location and bind texture to proper texture unit */
688 uni_sampler_loc = gl.getUniformLocation(program_id, "uni_sampler");
689 GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformLocation");
690
691 gl.activeTexture(GL_TEXTURE0 + m_texture_unit);
692 GLU_EXPECT_NO_ERROR(gl.getError(), "ActiveTexture");
693
694 gl.bindTexture(GL_TEXTURE_2D, src_texture_id);
695 GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
696
697 gl.uniform1i(uni_sampler_loc, m_texture_unit);
698 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
699
700 /* Dispatch program */
701 gl.dispatchCompute(m_width, m_height, 1);
702 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
703
704 /* Sync */
705 gl.memoryBarrier(GL_ALL_BARRIER_BITS);
706 GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier");
707 }
708
709 /** Execute draw program
710 *
711 * @param program_id ID of program
712 * @param dst_texture_id ID of destination texture
713 * @param src_texture_id ID of source texture
714 **/
draw(GLuint program_id,GLuint dst_texture_id,GLuint src_texture_id)715 void FunctionalTest::draw(GLuint program_id, GLuint dst_texture_id, GLuint src_texture_id)
716 {
717 GLuint fb_id = 0;
718 const Functions& gl = m_context.getRenderContext().getFunctions();
719 GLint uni_sampler_loc = -1;
720 GLuint vao_id = 0;
721
722 try
723 {
724 /* Tesselation patch set up */
725 gl.patchParameteri(GL_PATCH_VERTICES, 1);
726 GLU_EXPECT_NO_ERROR(gl.getError(), "PatchParameteri");
727
728 /* Prepare VAO */
729 gl.genVertexArrays(1, &vao_id);
730 GLU_EXPECT_NO_ERROR(gl.getError(), "GenVertexArrays");
731
732 gl.bindVertexArray(vao_id);
733 GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexArray");
734
735 /* Prepare FBO */
736 gl.genFramebuffers(1, &fb_id);
737 GLU_EXPECT_NO_ERROR(gl.getError(), "GenFramebuffers");
738
739 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, fb_id);
740 GLU_EXPECT_NO_ERROR(gl.getError(), "BindFramebuffer");
741
742 gl.framebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dst_texture_id, 0 /* level */);
743 GLU_EXPECT_NO_ERROR(gl.getError(), "FramebufferTexture");
744
745 gl.viewport(0 /* x */, 0 /* y */, m_width, m_height);
746 GLU_EXPECT_NO_ERROR(gl.getError(), "Viewport");
747
748 /* Set program */
749 gl.useProgram(program_id);
750 GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgram");
751
752 /* Get uniform location and bind texture to proper texture unit */
753 uni_sampler_loc = gl.getUniformLocation(program_id, "uni_sampler");
754 GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformLocation");
755
756 gl.activeTexture(GL_TEXTURE0 + m_texture_unit);
757 GLU_EXPECT_NO_ERROR(gl.getError(), "ActiveTexture");
758
759 gl.bindTexture(GL_TEXTURE_2D, src_texture_id);
760 GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
761
762 gl.uniform1i(uni_sampler_loc, m_texture_unit);
763 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
764
765 /* Draw */
766 gl.drawArrays(GL_PATCHES, 0 /* first */, 1 /* count */);
767 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
768
769 /* Sync */
770 gl.memoryBarrier(GL_ALL_BARRIER_BITS);
771 GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier");
772 }
773 catch (std::exception& exc)
774 {
775 gl.bindVertexArray(0);
776 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
777 gl.bindTexture(GL_TEXTURE_2D, 0);
778
779 if (0 != vao_id)
780 {
781 gl.deleteVertexArrays(1, &vao_id);
782 }
783
784 if (0 != fb_id)
785 {
786 gl.deleteFramebuffers(1, &fb_id);
787 }
788
789 throw exc;
790 }
791
792 gl.bindVertexArray(0);
793 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
794 gl.bindTexture(GL_TEXTURE_2D, 0);
795
796 if (0 != vao_id)
797 {
798 gl.deleteVertexArrays(1, &vao_id);
799 }
800
801 if (0 != fb_id)
802 {
803 gl.deleteFramebuffers(1, &fb_id);
804 }
805 }
806
807 /** Prepare destination texture
808 *
809 * @param is_stencil Selects if stencil or depth channel is sampled
810 *
811 * @return ID of texture
812 **/
prepareDestinationTexture(bool is_stencil)813 GLuint FunctionalTest::prepareDestinationTexture(bool is_stencil)
814 {
815 static const GLuint n_pixels = m_width * m_height;
816 GLenum format = 0;
817 GLenum internal_format = 0;
818 GLuint pixel_size = 0;
819 std::vector<GLubyte> texture_data;
820 GLuint texture_id = 0;
821 GLuint texture_size = 0;
822 GLenum type = 0;
823
824 /* Select size of pixel */
825 if (true == is_stencil)
826 {
827 format = GL_RED_INTEGER;
828 internal_format = GL_R8UI;
829 pixel_size = 1;
830 type = GL_UNSIGNED_BYTE;
831 }
832 else
833 {
834 format = GL_RED;
835 internal_format = GL_R32F;
836 pixel_size = 4;
837 type = GL_FLOAT;
838 }
839
840 /* Allocate storage */
841 texture_size = pixel_size * n_pixels;
842 texture_data.resize(texture_size);
843
844 /* Fill texture data */
845 memset(&texture_data[0], 0, texture_size);
846
847 /* Create texture */
848 texture_id =
849 Utils::createAndFill2DTexture(m_context, m_width, m_height, internal_format, format, type, &texture_data[0]);
850
851 /* Done */
852 return texture_id;
853 }
854
855 /** Prepare program
856 *
857 * @param is_draw Selects if draw or compute program is prepared
858 * @param is_stencil Selects if stencil or depth channel is sampled
859 *
860 * @return ID of texture
861 **/
prepareProgram(bool is_draw,bool is_stencil)862 GLuint FunctionalTest::prepareProgram(bool is_draw, bool is_stencil)
863 {
864 GLuint program_id = 0;
865
866 if (true != is_draw)
867 {
868 std::string cs_code = m_compute_shader_code;
869 const GLchar* image_definition = m_image_definition_stencil;
870 size_t position = 0;
871 const GLchar* sampler_definition = m_sampler_definition_stencil;
872 const GLchar* type = m_output_type_stencil;
873
874 if (false == is_stencil)
875 {
876 image_definition = m_image_definition_depth;
877 sampler_definition = m_sampler_definition_depth;
878 type = m_output_type_depth;
879 }
880
881 Utils::replaceToken("IMAGE_DEFINITION", position, image_definition, cs_code);
882 Utils::replaceToken("SAMPLER_DEFINITION", position, sampler_definition, cs_code);
883 Utils::replaceToken("TYPE", position, type, cs_code);
884
885 program_id = Utils::createAndBuildProgram(m_context, cs_code.c_str(), 0 /* fs_code */, 0 /* gs_code */,
886 0 /* tcs_code */, 0 /* tes_code */, 0 /* vs_code */);
887 }
888 else
889 {
890 #define N_FUNCTIONAL_TEST_SHADER_STAGES 5
891
892 const GLchar* expected_value = m_expected_value_stencil;
893 const GLchar* sampler_definition = m_sampler_definition_stencil;
894 std::string shader_code[N_FUNCTIONAL_TEST_SHADER_STAGES];
895 const GLchar* shader_templates[N_FUNCTIONAL_TEST_SHADER_STAGES] = {
896 m_fragment_shader_code, m_geometry_shader_code, m_tesselation_control_shader_code,
897 m_tesselation_evaluation_shader_code, m_vertex_shader_code
898 };
899 const GLchar* type = m_output_type_stencil;
900
901 if (false == is_stencil)
902 {
903 expected_value = m_expected_value_depth;
904 sampler_definition = m_sampler_definition_depth;
905 type = m_output_type_depth;
906 }
907
908 for (GLuint i = 0; i < N_FUNCTIONAL_TEST_SHADER_STAGES; ++i)
909 {
910 size_t position = 0;
911
912 shader_code[i] = shader_templates[i];
913
914 if (0 == i)
915 {
916 Utils::replaceToken("TYPE", position, type, shader_code[i]);
917 Utils::replaceToken("SAMPLER_DEFINITION", position, sampler_definition, shader_code[i]);
918 //Utils::replaceToken("TYPE", position, type, shader_code[i]);
919 }
920 else
921 {
922 Utils::replaceToken("SAMPLER_DEFINITION", position, sampler_definition, shader_code[i]);
923 Utils::replaceToken("EXPECTED_VALUE", position, expected_value, shader_code[i]);
924 }
925 }
926
927 program_id =
928 Utils::createAndBuildProgram(m_context, 0 /* cs_code */, shader_code[0].c_str() /* fs_code */,
929 shader_code[1].c_str() /* gs_code */, shader_code[2].c_str() /* tcs_code */,
930 shader_code[3].c_str() /* tes_code */, shader_code[4].c_str() /* vs_code */);
931 }
932
933 /* Done */
934 return program_id;
935 }
936
937 /** Prepare source texture
938 *
939 * @param internal_format Internal format of texture
940 * @param is_stencil Selects if stencil or depth channel is sampled
941 * @param texture_data Texture contents
942 *
943 * @return ID of texture
944 **/
prepareSourceTexture(GLenum internal_format,bool is_stencil,const std::vector<glw::GLubyte> & texture_data)945 GLuint FunctionalTest::prepareSourceTexture(GLenum internal_format, bool is_stencil,
946 const std::vector<glw::GLubyte>& texture_data)
947 {
948 const Functions& gl = m_context.getRenderContext().getFunctions();
949 GLuint texture_id = 0;
950 GLenum type = 0;
951
952 /* Select size of pixel */
953 switch (internal_format)
954 {
955 case GL_DEPTH24_STENCIL8:
956 type = GL_UNSIGNED_INT_24_8;
957 break;
958 case GL_DEPTH32F_STENCIL8:
959 type = GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
960 break;
961 default:
962 TCU_FAIL("Invalid enum");
963 }
964
965 /* Create texture */
966 texture_id = Utils::createAndFill2DTexture(m_context, m_width, m_height, internal_format, GL_DEPTH_STENCIL, type,
967 &texture_data[0]);
968
969 /* Set DS texture mode */
970 gl.bindTexture(GL_TEXTURE_2D, texture_id);
971 GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
972
973 if (true == is_stencil)
974 {
975 gl.texParameteri(GL_TEXTURE_2D, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX);
976 GLU_EXPECT_NO_ERROR(gl.getError(), "TexParameteri");
977 }
978 else
979 {
980 gl.texParameteri(GL_TEXTURE_2D, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_DEPTH_COMPONENT);
981 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
982 GLU_EXPECT_NO_ERROR(gl.getError(), "TexParameteri");
983 }
984
985 /* Set nearest filtering */
986 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
987 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
988 GLU_EXPECT_NO_ERROR(gl.getError(), "TexParameteri");
989
990 /* Unbind */
991 gl.bindTexture(GL_TEXTURE_2D, 0);
992 GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
993
994 /* Done */
995 return texture_id;
996 }
997
998 /** Prepare data for source texture
999 *
1000 * @param internal_format Internal format of texture
1001 * @param texture_data Texture contents
1002 *
1003 * @return ID of texture
1004 **/
prepareSourceTextureData(GLenum internal_format,std::vector<GLubyte> & texture_data)1005 void FunctionalTest::prepareSourceTextureData(GLenum internal_format, std::vector<GLubyte>& texture_data)
1006 {
1007 static const GLfloat depth_step_h = -0.5f / ((GLfloat)(m_width - 1));
1008 static const GLfloat depth_step_v = -0.5f / ((GLfloat)(m_height - 1));
1009 static const GLuint stencil_step_h = 1;
1010 static const GLuint stencil_step_v = 1;
1011 static const GLuint n_pixels = m_width * m_height;
1012 GLuint pixel_size = 0;
1013 GLuint line_size = 0;
1014 GLuint texture_size = 0;
1015
1016 /* Select size of pixel */
1017 switch (internal_format)
1018 {
1019 case GL_DEPTH24_STENCIL8:
1020 pixel_size = 4;
1021 break;
1022 case GL_DEPTH32F_STENCIL8:
1023 pixel_size = 8;
1024 break;
1025 default:
1026 TCU_FAIL("Invalid enum");
1027 }
1028
1029 line_size = pixel_size * m_width;
1030 texture_size = pixel_size * n_pixels;
1031
1032 /* Allocate storage */
1033 texture_data.resize(texture_size);
1034
1035 /* Fill texture data */
1036 for (GLuint y = 0; y < m_height; ++y)
1037 {
1038 const GLfloat depth_v = depth_step_v * (GLfloat)y;
1039 const GLuint line_offset = line_size * y;
1040 const GLuint stencil_v = stencil_step_v * y;
1041
1042 for (GLuint x = 0; x < m_width; ++x)
1043 {
1044 const GLfloat depth_h = depth_step_h * (GLfloat)x;
1045 const GLfloat depth_f = 1 + depth_h + depth_v;
1046 const GLuint depth_i = (GLuint)(((GLfloat)0xffffff) * depth_f);
1047 const GLuint pixel_offset = pixel_size * x;
1048 const GLuint stencil_h = stencil_step_h * x;
1049 const GLuint stencil = 1 + stencil_h + stencil_v;
1050
1051 GLubyte* depth_f_data = (GLubyte*)&depth_f;
1052 GLubyte* depth_i_data = (GLubyte*)&depth_i;
1053 GLubyte* pixel_data = &texture_data[0] + line_offset + pixel_offset;
1054 GLubyte* stencil_data = (GLubyte*)&stencil;
1055
1056 switch (pixel_size)
1057 {
1058 case 4:
1059 memcpy(pixel_data, stencil_data, 1);
1060 memcpy(pixel_data + 1, depth_i_data, 3);
1061 break;
1062 case 8:
1063 memcpy(pixel_data, depth_f_data, 4);
1064 memcpy(pixel_data + 4, stencil_data, 1);
1065 break;
1066 default:
1067 TCU_FAIL("Invalid value");
1068 }
1069 }
1070 }
1071 }
1072
1073 /** Verifies that destination texture contents match expectations
1074 *
1075 * @param id ID of destination texture
1076 * @param source_internal_format Internal format of source texture
1077 * @param is_stencil Selects if stencil of depth channel is sampled
1078 * @param src_texture_data Contents of source texture
1079 *
1080 * @return true if everything is fine, false otherwise
1081 **/
verifyTexture(GLuint id,GLenum source_internal_format,bool is_stencil,const std::vector<GLubyte> & src_texture_data)1082 bool FunctionalTest::verifyTexture(GLuint id, GLenum source_internal_format, bool is_stencil,
1083 const std::vector<GLubyte>& src_texture_data)
1084 {
1085 static const GLuint n_pixels = m_width * m_height;
1086 const Functions& gl = m_context.getRenderContext().getFunctions();
1087 GLuint dst_pixel_size = 0;
1088 std::vector<GLubyte> dst_texture_data;
1089 GLuint dst_texture_size = 0;
1090 GLenum format = 0;
1091 GLuint src_pixel_size = 0;
1092 GLuint src_stencil_off = 0;
1093 GLenum type = 0;
1094
1095 /* Select size of pixel */
1096 if (true == is_stencil)
1097 {
1098 format = GL_RED_INTEGER;
1099 dst_pixel_size = 1;
1100 type = GL_UNSIGNED_BYTE;
1101 }
1102 else
1103 {
1104 format = GL_RED;
1105 dst_pixel_size = 4;
1106 type = GL_FLOAT;
1107 }
1108
1109 if (GL_DEPTH24_STENCIL8 == source_internal_format)
1110 {
1111 src_pixel_size = 4;
1112 }
1113 else
1114 {
1115 src_pixel_size = 8;
1116 src_stencil_off = 4;
1117 }
1118
1119 /* Allocate storage */
1120 dst_texture_size = dst_pixel_size * n_pixels;
1121 dst_texture_data.resize(dst_texture_size);
1122
1123 /* Get texture contents */
1124 gl.bindTexture(GL_TEXTURE_2D, id);
1125 GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
1126
1127 gl.getTexImage(GL_TEXTURE_2D, 0 /* level */, format, type, &dst_texture_data[0]);
1128 GLU_EXPECT_NO_ERROR(gl.getError(), "GetTexImage");
1129
1130 gl.bindTexture(GL_TEXTURE_2D, 0);
1131 GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
1132
1133 /* For each pixel */
1134 for (GLuint i = 0; i < n_pixels; ++i)
1135 {
1136 const GLuint dst_pixel_offset = dst_pixel_size * i;
1137 const GLuint src_pixel_offset = src_pixel_size * i;
1138
1139 const GLubyte* dst_pixel_data = &dst_texture_data[0] + dst_pixel_offset;
1140 const GLubyte* src_pixel_data = &src_texture_data[0] + src_pixel_offset;
1141
1142 if (true == is_stencil) /* Stencil channel */
1143 {
1144 const GLubyte dst_stencil = dst_pixel_data[0];
1145 const GLubyte src_stencil = src_pixel_data[src_stencil_off];
1146
1147 if (src_stencil != dst_stencil)
1148 {
1149 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid pixel [" << i
1150 << "], got: " << (GLuint)dst_stencil
1151 << " expected: " << (GLuint)src_stencil << tcu::TestLog::EndMessage;
1152
1153 return false;
1154 }
1155 }
1156 else /* Depth channel */
1157 {
1158 if (GL_DEPTH24_STENCIL8 == source_internal_format) /* DEPTH24 */
1159 {
1160 GLfloat dst_depth = 0.0f;
1161 GLuint src_depth_i = 0;
1162 GLfloat src_depth_f = 0.0f;
1163
1164 memcpy(&dst_depth, dst_pixel_data, 4);
1165 memcpy(&src_depth_i, src_pixel_data + 1, 3);
1166
1167 src_depth_f = ((GLfloat)src_depth_i) / ((GLfloat)0xffffff);
1168
1169 if (de::abs(src_depth_f - dst_depth) > 0.0001f)
1170 {
1171 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid pixel [" << i
1172 << "], got: " << dst_depth << " expected: " << src_depth_f
1173 << tcu::TestLog::EndMessage;
1174
1175 return false;
1176 }
1177 }
1178 else /* DEPTH32F */
1179 {
1180 GLfloat dst_depth = 0.0f;
1181 GLfloat src_depth = 0.0f;
1182
1183 memcpy(&dst_depth, dst_pixel_data, 4);
1184 memcpy(&src_depth, src_pixel_data, 4);
1185
1186 if (de::abs(src_depth - dst_depth) > 0.0001f)
1187 {
1188 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid pixel [" << i
1189 << "], got: " << dst_depth << " expected: " << src_depth
1190 << tcu::TestLog::EndMessage;
1191
1192 return false;
1193 }
1194 }
1195 }
1196 }
1197
1198 return true;
1199 }
1200
1201 /** Test given internal format and channel
1202 *
1203 * @param internal_format Internal fromat of source texture
1204 * @param is_stencil Selects if stencil or depth channel is sampled
1205 *
1206 * @return true if results from compute and draw programs are positive, false otherwise
1207 **/
test(GLenum internal_format,bool is_stencil)1208 bool FunctionalTest::test(GLenum internal_format, bool is_stencil)
1209 {
1210 GLuint compute_dst_tex_id = 0;
1211 GLuint compute_program_id = 0;
1212 GLuint compute_src_tex_id = 0;
1213 GLuint draw_dst_tex_id = 0;
1214 GLuint draw_program_id = 0;
1215 GLuint draw_src_tex_id = 0;
1216 const Functions& gl = m_context.getRenderContext().getFunctions();
1217 bool test_result = true;
1218 std::vector<GLubyte> texture_data;
1219
1220 prepareSourceTextureData(internal_format, texture_data);
1221
1222 try
1223 {
1224 if (true == Utils::isExtensionSupported(m_context, "GL_ARB_compute_shader"))
1225 {
1226 compute_dst_tex_id = prepareDestinationTexture(is_stencil);
1227 compute_program_id = prepareProgram(false, is_stencil);
1228 compute_src_tex_id = prepareSourceTexture(internal_format, is_stencil, texture_data);
1229
1230 dispatch(compute_program_id, is_stencil, compute_dst_tex_id, compute_src_tex_id);
1231
1232 if (false == verifyTexture(compute_dst_tex_id, internal_format, is_stencil, texture_data))
1233 {
1234 test_result = false;
1235 }
1236 }
1237
1238 {
1239 draw_dst_tex_id = prepareDestinationTexture(is_stencil);
1240 draw_program_id = prepareProgram(true, is_stencil);
1241 draw_src_tex_id = prepareSourceTexture(internal_format, is_stencil, texture_data);
1242
1243 draw(draw_program_id, draw_dst_tex_id, draw_src_tex_id);
1244
1245 if (false == verifyTexture(draw_dst_tex_id, internal_format, is_stencil, texture_data))
1246 {
1247 test_result = false;
1248 }
1249 }
1250 }
1251 catch (std::exception& exc)
1252 {
1253 gl.bindVertexArray(0);
1254 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1255 gl.useProgram(0);
1256
1257 Utils::deleteProgram(m_context, compute_program_id);
1258 Utils::deleteProgram(m_context, draw_program_id);
1259
1260 Utils::deleteTexture(m_context, compute_dst_tex_id);
1261 Utils::deleteTexture(m_context, compute_src_tex_id);
1262 Utils::deleteTexture(m_context, draw_dst_tex_id);
1263 Utils::deleteTexture(m_context, draw_src_tex_id);
1264
1265 TCU_FAIL(exc.what());
1266 }
1267
1268 gl.bindVertexArray(0);
1269 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1270 gl.useProgram(0);
1271
1272 Utils::deleteProgram(m_context, compute_program_id);
1273 Utils::deleteProgram(m_context, draw_program_id);
1274
1275 Utils::deleteTexture(m_context, compute_dst_tex_id);
1276 Utils::deleteTexture(m_context, compute_src_tex_id);
1277 Utils::deleteTexture(m_context, draw_dst_tex_id);
1278 Utils::deleteTexture(m_context, draw_src_tex_id);
1279
1280 /* Done */
1281 return test_result;
1282 }
1283 } /* namespace StencilTexturing */
1284
StencilTexturingTests(deqp::Context & context)1285 StencilTexturingTests::StencilTexturingTests(deqp::Context& context) : TestCaseGroup(context, "stencil_texturing", "")
1286 {
1287 }
1288
~StencilTexturingTests(void)1289 StencilTexturingTests::~StencilTexturingTests(void)
1290 {
1291 }
1292
init()1293 void StencilTexturingTests::init()
1294 {
1295 addChild(new StencilTexturing::FunctionalTest(m_context));
1296 }
1297 } /* namespace gl4cts */
1298