1 /*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
4 *
5 * Copyright (c) 2017 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 gl4cShaderAtomicCounterOpsTests.cpp
21 * \brief Conformance tests for the ARB_shader_atomic_counter_ops functionality.
22 */ /*-------------------------------------------------------------------*/
23
24 #include "gl4cShaderAtomicCounterOpsTests.hpp"
25 #include "gluContextInfo.hpp"
26 #include "gluDefs.hpp"
27 #include "gluDrawUtil.hpp"
28 #include "gluObjectWrapper.hpp"
29 #include "gluShaderProgram.hpp"
30 #include "glwEnums.hpp"
31 #include "glwFunctions.hpp"
32 #include "tcuRenderTarget.hpp"
33
34 #include <algorithm>
35 #include <sstream>
36 #include <string>
37
38 using namespace glw;
39
40 namespace gl4cts
41 {
42
ShaderPipeline(glu::ShaderType testedShader,AtomicOperation * newOp,bool contextGL46)43 ShaderAtomicCounterOpsTestBase::ShaderPipeline::ShaderPipeline(glu::ShaderType testedShader, AtomicOperation *newOp,
44 bool contextGL46)
45 : m_program(NULL)
46 , m_programCompute(NULL)
47 , m_testedShader(testedShader)
48 , m_atomicOp(newOp)
49 {
50 m_shaders[glu::SHADERTYPE_VERTEX] = "<version>\n"
51 "<head>"
52 "in highp vec2 inPosition;\n"
53 "out highp vec3 vsPosition;\n"
54 "out highp vec4 vsColor;\n"
55 "void main()\n"
56 "{\n"
57 " gl_Position = vec4(inPosition, 0.0, 1.0);\n"
58 " vsPosition = vec3(inPosition, 0.0);\n"
59 " vec4 outColor = vec4(1.0);\n"
60 "<atomic_operation>"
61 " vsColor = outColor;\n"
62 "}\n";
63
64 m_shaders[glu::SHADERTYPE_FRAGMENT] = "<version>\n"
65 "<head>"
66 "in highp vec4 gsColor;\n"
67 "out highp vec4 fsColor;\n"
68 "void main()\n"
69 "{\n"
70 " vec4 outColor = gsColor; \n"
71 "<atomic_operation>"
72 " fsColor = outColor;\n"
73 "}\n";
74
75 m_shaders[glu::SHADERTYPE_TESSELLATION_CONTROL] =
76 "<version>\n"
77 "<head>"
78 "layout(vertices = 3) out;\n"
79 "in highp vec4 vsColor[];\n"
80 "in highp vec3 vsPosition[];\n"
81 "out highp vec3 tcsPosition[];\n"
82 "out highp vec4 tcsColor[];\n"
83 "void main()\n"
84 "{\n"
85 " tcsPosition[gl_InvocationID] = vsPosition[gl_InvocationID];\n"
86 " vec4 outColor = vsColor[gl_InvocationID];\n"
87 "<atomic_operation>"
88 " tcsColor[gl_InvocationID] = outColor;\n"
89 " gl_TessLevelInner[0] = 3;\n"
90 " gl_TessLevelOuter[0] = 3;\n"
91 " gl_TessLevelOuter[1] = 3;\n"
92 " gl_TessLevelOuter[2] = 3;\n"
93 "}\n";
94
95 m_shaders[glu::SHADERTYPE_TESSELLATION_EVALUATION] = "<version>\n"
96 "<head>"
97 "layout(triangles, equal_spacing, cw) in;\n"
98 "in highp vec3 tcsPosition[];\n"
99 "in highp vec4 tcsColor[];\n"
100 "out highp vec4 tesColor;\n"
101 "void main()\n"
102 "{\n"
103 " vec3 p0 = gl_TessCoord.x * tcsPosition[0];\n"
104 " vec3 p1 = gl_TessCoord.y * tcsPosition[1];\n"
105 " vec3 p2 = gl_TessCoord.z * tcsPosition[2];\n"
106 " vec4 outColor = tcsColor[0];\n"
107 "<atomic_operation>"
108 " tesColor = outColor;\n"
109 " gl_Position = vec4(normalize(p0 + p1 + p2), 1.0);\n"
110 "}\n";
111
112 m_shaders[glu::SHADERTYPE_GEOMETRY] = "<version>\n"
113 "<head>"
114 "layout(triangles) in;\n"
115 "layout(triangle_strip, max_vertices = 3) out;\n"
116 "in highp vec4 tesColor[];\n"
117 "out highp vec4 gsColor;\n"
118 "void main()\n"
119 "{\n"
120 " for (int i = 0; i<3; i++)\n"
121 " {\n"
122 " gl_Position = gl_in[i].gl_Position;\n"
123 " vec4 outColor = tesColor[i];\n"
124 "<atomic_operation>"
125 " gsColor = outColor;\n"
126 " EmitVertex();\n"
127 " }\n"
128 " EndPrimitive();\n"
129 "}\n";
130
131 m_shaders[glu::SHADERTYPE_COMPUTE] = "<version>\n"
132 "<head>"
133 "layout(rgba32f, binding = 2) writeonly uniform highp image2D destImage;\n"
134 "layout (local_size_x = 16, local_size_y = 16) in;\n"
135 "void main (void)\n"
136 "{\n"
137 " vec4 outColor = vec4(1.0);\n"
138 "<atomic_operation>"
139 " imageStore(destImage, ivec2(gl_GlobalInvocationID.xy), outColor);\n"
140 "}\n";
141
142 // prepare shaders
143
144 std::string postfix(contextGL46 ? "" : "ARB");
145 std::stringstream atomicOperationStream;
146 atomicOperationStream << "uint returned = " << m_atomicOp->getFunction() + postfix + "(counter, ";
147 if (m_atomicOp->getCompareValue() != 0)
148 {
149 atomicOperationStream << m_atomicOp->getCompareValue();
150 atomicOperationStream << "u, ";
151 }
152 atomicOperationStream << m_atomicOp->getParamValue();
153 atomicOperationStream << "u);\n";
154 atomicOperationStream << "uint after = atomicCounter(counter);\n";
155
156 if (m_atomicOp->shouldTestReturnValue())
157 {
158 atomicOperationStream << "if(after == returned) outColor = vec4(0.0f);\n";
159 }
160
161 atomicOperationStream << "atomicCounterIncrement(calls);\n";
162
163 std::string versionString;
164 std::string headString;
165 if (contextGL46)
166 {
167 versionString = "#version 460 core";
168 headString = "layout (binding=0) uniform atomic_uint counter;\n"
169 "layout (binding=1) uniform atomic_uint calls;\n";
170 }
171 else
172 {
173 versionString = "#version 450 core";
174 headString = "#extension GL_ARB_shader_atomic_counters: enable\n"
175 "#extension GL_ARB_shader_atomic_counter_ops: enable\n"
176 "layout (binding=0) uniform atomic_uint counter;\n"
177 "layout (binding=1) uniform atomic_uint calls;\n";
178 }
179
180 for (unsigned int i = 0; i <= glu::SHADERTYPE_COMPUTE; ++i)
181 {
182 prepareShader(m_shaders[i], "<version>", versionString);
183 prepareShader(m_shaders[i], "<head>", i == testedShader ? headString : "");
184 prepareShader(m_shaders[i], "<atomic_operation>", i == testedShader ? atomicOperationStream.str() : "");
185 }
186 }
187
~ShaderPipeline()188 ShaderAtomicCounterOpsTestBase::ShaderPipeline::~ShaderPipeline()
189 {
190 if (m_program)
191 {
192 delete m_program;
193 }
194
195 if (m_programCompute)
196 {
197 delete m_programCompute;
198 }
199 }
200
prepareShader(std::string & shader,const std::string & tag,const std::string & value)201 void ShaderAtomicCounterOpsTestBase::ShaderPipeline::prepareShader(std::string &shader, const std::string &tag,
202 const std::string &value)
203 {
204 size_t tagPos = shader.find(tag);
205
206 if (tagPos != std::string::npos)
207 shader.replace(tagPos, tag.length(), value);
208 }
209
create(deqp::Context & context)210 void ShaderAtomicCounterOpsTestBase::ShaderPipeline::create(deqp::Context &context)
211 {
212 glu::ProgramSources sources;
213 for (unsigned int i = 0; i < glu::SHADERTYPE_COMPUTE; ++i)
214 {
215 if (!m_shaders[i].empty())
216 {
217 sources.sources[i].push_back(m_shaders[i]);
218 }
219 }
220 m_program = new glu::ShaderProgram(context.getRenderContext(), sources);
221
222 if (!m_program->isOk())
223 {
224 TCU_FAIL("Shader compilation failed");
225 }
226
227 glu::ProgramSources sourcesCompute;
228 sourcesCompute.sources[glu::SHADERTYPE_COMPUTE].push_back(m_shaders[glu::SHADERTYPE_COMPUTE]);
229 m_programCompute = new glu::ShaderProgram(context.getRenderContext(), sourcesCompute);
230
231 if (!m_programCompute->isOk())
232 {
233 TCU_FAIL("Shader compilation failed");
234 }
235 }
236
use(deqp::Context & context)237 void ShaderAtomicCounterOpsTestBase::ShaderPipeline::use(deqp::Context &context)
238 {
239 const glw::Functions &gl = context.getRenderContext().getFunctions();
240 gl.useProgram(m_program->getProgram());
241 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram failed");
242 }
243
test(deqp::Context & context)244 void ShaderAtomicCounterOpsTestBase::ShaderPipeline::test(deqp::Context &context)
245 {
246 const glw::Functions &gl = context.getRenderContext().getFunctions();
247
248 gl.clearColor(0.5f, 0.5f, 0.5f, 1.0f);
249 gl.clear(GL_COLOR_BUFFER_BIT);
250
251 if (m_testedShader == glu::SHADERTYPE_COMPUTE)
252 {
253 executeComputeShader(context);
254 }
255 else
256 {
257 renderQuad(context);
258 }
259
260 gl.flush();
261 }
262
renderQuad(deqp::Context & context)263 void ShaderAtomicCounterOpsTestBase::ShaderPipeline::renderQuad(deqp::Context &context)
264 {
265 const glw::Functions &gl = context.getRenderContext().getFunctions();
266
267 uint16_t const quadIndices[] = {0, 1, 2, 2, 1, 3};
268
269 float const position[] = {-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f};
270
271 glu::VertexArrayBinding vertexArrays[] = {glu::va::Float("inPosition", 2, 4, 0, position)};
272
273 this->use(context);
274
275 glu::PrimitiveList primitiveList = glu::pr::Patches(DE_LENGTH_OF_ARRAY(quadIndices), quadIndices);
276
277 glu::draw(context.getRenderContext(), this->getShaderProgram()->getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays),
278 vertexArrays, primitiveList);
279
280 GLU_EXPECT_NO_ERROR(gl.getError(), "glu::draw error");
281
282 gl.memoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
283 GLU_EXPECT_NO_ERROR(gl.getError(), "glMemoryBarrier() error");
284 }
285
executeComputeShader(deqp::Context & context)286 void ShaderAtomicCounterOpsTestBase::ShaderPipeline::executeComputeShader(deqp::Context &context)
287 {
288 const glw::Functions &gl = context.getRenderContext().getFunctions();
289
290 const glu::Texture outputTexture(context.getRenderContext());
291
292 gl.useProgram(m_programCompute->getProgram());
293
294 // output image
295 gl.bindTexture(GL_TEXTURE_2D, *outputTexture);
296 gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, 16, 16);
297 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
298 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
299 GLU_EXPECT_NO_ERROR(gl.getError(), "Uploading image data failed");
300
301 // bind image
302 gl.bindImageTexture(2, *outputTexture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);
303 GLU_EXPECT_NO_ERROR(gl.getError(), "Image setup failed");
304
305 // dispatch compute
306 gl.dispatchCompute(1, 1, 1);
307 GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute() error");
308 gl.memoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
309 GLU_EXPECT_NO_ERROR(gl.getError(), "glMemoryBarrier() error");
310
311 // render output texture
312
313 std::string vs = "#version 450 core\n"
314 "in highp vec2 position;\n"
315 "in vec2 inTexcoord;\n"
316 "out vec2 texcoord;\n"
317 "void main()\n"
318 "{\n"
319 " texcoord = inTexcoord;\n"
320 " gl_Position = vec4(position, 0.0, 1.0);\n"
321 "}\n";
322
323 std::string fs = "#version 450 core\n"
324 "uniform sampler2D sampler;\n"
325 "in vec2 texcoord;\n"
326 "out vec4 color;\n"
327 "void main()\n"
328 "{\n"
329 " color = texture(sampler, texcoord);\n"
330 "}\n";
331
332 glu::ProgramSources sources;
333 sources.sources[glu::SHADERTYPE_VERTEX].push_back(vs);
334 sources.sources[glu::SHADERTYPE_FRAGMENT].push_back(fs);
335 glu::ShaderProgram renderShader(context.getRenderContext(), sources);
336
337 if (!m_program->isOk())
338 {
339 TCU_FAIL("Shader compilation failed");
340 }
341
342 gl.bindTexture(GL_TEXTURE_2D, *outputTexture);
343 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed.");
344
345 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
346 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
347 GLU_EXPECT_NO_ERROR(gl.getError(), "texParameteri failed");
348
349 gl.useProgram(renderShader.getProgram());
350 GLU_EXPECT_NO_ERROR(gl.getError(), "useProgram failed");
351
352 gl.uniform1i(gl.getUniformLocation(renderShader.getProgram(), "sampler"), 0);
353 GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i failed");
354
355 uint16_t const quadIndices[] = {0, 1, 2, 2, 1, 3};
356
357 float const position[] = {-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f};
358
359 float const texCoord[] = {0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f};
360
361 glu::VertexArrayBinding vertexArrays[] = {glu::va::Float("position", 2, 4, 0, position),
362 glu::va::Float("inTexcoord", 2, 4, 0, texCoord)};
363
364 glu::draw(context.getRenderContext(), renderShader.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), vertexArrays,
365 glu::pr::TriangleStrip(DE_LENGTH_OF_ARRAY(quadIndices), quadIndices));
366
367 GLU_EXPECT_NO_ERROR(gl.getError(), "glu::draw error");
368 }
369
fillAtomicCounterBuffer(AtomicOperation * atomicOp)370 void ShaderAtomicCounterOpsTestBase::fillAtomicCounterBuffer(AtomicOperation *atomicOp)
371 {
372 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
373
374 GLuint *dataPtr;
375
376 // fill values buffer
377
378 GLuint inputValue = atomicOp->getInputValue();
379
380 gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_atomicCounterBuffer);
381 GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer() call failed.");
382
383 dataPtr = (GLuint *)gl.mapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint),
384 GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
385 GLU_EXPECT_NO_ERROR(gl.getError(), "mapBufferRange() call failed.");
386
387 *dataPtr = inputValue;
388
389 gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
390 GLU_EXPECT_NO_ERROR(gl.getError(), "unmapBuffer() call failed.");
391
392 // fill calls buffer
393
394 gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_atomicCounterCallsBuffer);
395 GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer() call failed.");
396
397 dataPtr = (GLuint *)gl.mapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint),
398 GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
399 GLU_EXPECT_NO_ERROR(gl.getError(), "mapBufferRange() call failed.");
400
401 *dataPtr = 0;
402
403 gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
404 GLU_EXPECT_NO_ERROR(gl.getError(), "unmapBuffer() call failed.");
405 }
406
checkAtomicCounterBuffer(AtomicOperation * atomicOp)407 bool ShaderAtomicCounterOpsTestBase::checkAtomicCounterBuffer(AtomicOperation *atomicOp)
408 {
409 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
410
411 GLuint *dataPtr;
412
413 // get value
414
415 gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_atomicCounterBuffer);
416 GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer() call failed.");
417
418 dataPtr = (GLuint *)gl.mapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), GL_MAP_READ_BIT);
419 GLU_EXPECT_NO_ERROR(gl.getError(), "mapBufferRange() call failed.");
420
421 GLuint finalValue = *dataPtr;
422
423 gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
424 GLU_EXPECT_NO_ERROR(gl.getError(), "unmapBuffer() call failed.");
425
426 // get calls
427
428 gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_atomicCounterCallsBuffer);
429 GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer() call failed.");
430
431 dataPtr = (GLuint *)gl.mapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), GL_MAP_READ_BIT);
432 GLU_EXPECT_NO_ERROR(gl.getError(), "mapBufferRange() call failed.");
433
434 GLuint numberOfCalls = *dataPtr;
435
436 gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
437 GLU_EXPECT_NO_ERROR(gl.getError(), "unmapBuffer() call failed.");
438
439 // validate
440
441 GLuint expectedValue = atomicOp->getResult(numberOfCalls);
442
443 return finalValue == expectedValue;
444 }
445
bindBuffers()446 void ShaderAtomicCounterOpsTestBase::bindBuffers()
447 {
448 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
449
450 gl.bindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, m_atomicCounterBuffer);
451 GLU_EXPECT_NO_ERROR(gl.getError(), "bindBufferBase() call failed.");
452
453 gl.bindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 1, m_atomicCounterCallsBuffer);
454 GLU_EXPECT_NO_ERROR(gl.getError(), "bindBufferBase() call failed.");
455 }
456
validateColor(tcu::Vec4 testedColor,tcu::Vec4 desiredColor)457 bool ShaderAtomicCounterOpsTestBase::validateColor(tcu::Vec4 testedColor, tcu::Vec4 desiredColor)
458 {
459 const float epsilon = 1.1f / 31.0f; // Accommodate framebuffers with 5-bit channels.
460 return de::abs(testedColor.x() - desiredColor.x()) < epsilon &&
461 de::abs(testedColor.y() - desiredColor.y()) < epsilon &&
462 de::abs(testedColor.z() - desiredColor.z()) < epsilon;
463 }
464
validateScreenPixels(tcu::Vec4 desiredColor,tcu::Vec4 ignoredColor)465 bool ShaderAtomicCounterOpsTestBase::validateScreenPixels(tcu::Vec4 desiredColor, tcu::Vec4 ignoredColor)
466 {
467 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
468 const tcu::RenderTarget renderTarget = m_context.getRenderContext().getRenderTarget();
469 tcu::IVec2 size(renderTarget.getWidth(), renderTarget.getHeight());
470
471 glw::GLfloat *pixels = new glw::GLfloat[size.x() * size.y() * 4];
472
473 // clear buffer
474 for (int x = 0; x < size.x(); ++x)
475 {
476 for (int y = 0; y < size.y(); ++y)
477 {
478 int mappedPixelPosition = y * size.x() + x;
479
480 pixels[mappedPixelPosition * 4 + 0] = -1.0f;
481 pixels[mappedPixelPosition * 4 + 1] = -1.0f;
482 pixels[mappedPixelPosition * 4 + 2] = -1.0f;
483 pixels[mappedPixelPosition * 4 + 3] = -1.0f;
484 }
485 }
486
487 // read pixels
488 gl.readPixels(0, 0, size.x(), size.y(), GL_RGBA, GL_FLOAT, pixels);
489
490 // validate pixels
491 bool rendered = false;
492 for (int x = 0; x < size.x(); ++x)
493 {
494 for (int y = 0; y < size.y(); ++y)
495 {
496 int mappedPixelPosition = y * size.x() + x;
497
498 tcu::Vec4 color(pixels[mappedPixelPosition * 4 + 0], pixels[mappedPixelPosition * 4 + 1],
499 pixels[mappedPixelPosition * 4 + 2], pixels[mappedPixelPosition * 4 + 3]);
500
501 if (!validateColor(color, ignoredColor))
502 {
503 rendered = true;
504 if (!validateColor(color, desiredColor))
505 {
506 delete[] pixels;
507 return false;
508 }
509 }
510 }
511 }
512
513 delete[] pixels;
514
515 return rendered;
516 }
517
ShaderAtomicCounterOpsTestBase(deqp::Context & context,const char * name,const char * description)518 ShaderAtomicCounterOpsTestBase::ShaderAtomicCounterOpsTestBase(deqp::Context &context, const char *name,
519 const char *description)
520 : TestCase(context, name, description)
521 , m_atomicCounterBuffer(0)
522 , m_atomicCounterCallsBuffer(0)
523 {
524 glu::ContextType contextType = m_context.getRenderContext().getType();
525 m_contextSupportsGL46 = glu::contextSupports(contextType, glu::ApiType::core(4, 6));
526 }
527
init()528 void ShaderAtomicCounterOpsTestBase::init()
529 {
530 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
531
532 // generate atomic counter buffer
533
534 gl.genBuffers(1, &m_atomicCounterBuffer);
535 GLU_EXPECT_NO_ERROR(gl.getError(), "genBuffers() call failed.");
536
537 gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_atomicCounterBuffer);
538 GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer() call failed.");
539
540 gl.bufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint), NULL, GL_DYNAMIC_DRAW);
541 GLU_EXPECT_NO_ERROR(gl.getError(), "bufferData() call failed.");
542
543 // generate atomic counter calls buffer
544
545 gl.genBuffers(1, &m_atomicCounterCallsBuffer);
546 GLU_EXPECT_NO_ERROR(gl.getError(), "genBuffers() call failed.");
547
548 gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_atomicCounterCallsBuffer);
549 GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer() call failed.");
550
551 gl.bufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint), NULL, GL_DYNAMIC_DRAW);
552 GLU_EXPECT_NO_ERROR(gl.getError(), "bufferData() call failed.");
553
554 // setup tested atomic operations
555
556 setOperations();
557
558 // setup shaders
559
560 for (ShaderPipelineIter iter = m_shaderPipelines.begin(); iter != m_shaderPipelines.end(); ++iter)
561 {
562 iter->create(m_context);
563 }
564 }
565
deinit()566 void ShaderAtomicCounterOpsTestBase::deinit()
567 {
568 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
569
570 // delete atomic counter buffer
571
572 gl.deleteBuffers(1, &m_atomicCounterBuffer);
573 GLU_EXPECT_NO_ERROR(gl.getError(), "deleteBuffers() call failed.");
574
575 // delete atomic counter calls buffer
576
577 gl.deleteBuffers(1, &m_atomicCounterCallsBuffer);
578 GLU_EXPECT_NO_ERROR(gl.getError(), "deleteBuffers() call failed.");
579
580 // delete operations
581
582 for (AtomicOperationIter iter = m_operations.begin(); iter != m_operations.end(); ++iter)
583 {
584 delete *iter;
585 }
586 }
587
iterate()588 tcu::TestNode::IterateResult ShaderAtomicCounterOpsTestBase::iterate()
589 {
590 if (!m_contextSupportsGL46)
591 {
592 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_atomic_counters") ||
593 !m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_atomic_counter_ops"))
594 {
595 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not supported");
596 return STOP;
597 }
598 }
599
600 for (ShaderPipelineIter iter = m_shaderPipelines.begin(); iter != m_shaderPipelines.end(); ++iter)
601 {
602 fillAtomicCounterBuffer(iter->getAtomicOperation());
603 bindBuffers();
604 iter->test(m_context);
605
606 bool operationValueValid = checkAtomicCounterBuffer(iter->getAtomicOperation());
607 std::string operationFailMsg = "Result of atomic operation was different than expected (" +
608 iter->getAtomicOperation()->getFunction() + ").";
609 TCU_CHECK_MSG(operationValueValid, operationFailMsg.c_str());
610
611 bool returnValueValid = validateScreenPixels(tcu::Vec4(1.0f), tcu::Vec4(0.5f));
612 std::string returnFailMsg = "Result of atomic operation return value was different than expected (" +
613 iter->getAtomicOperation()->getFunction() + ").";
614 TCU_CHECK_MSG(returnValueValid, returnFailMsg.c_str());
615 }
616
617 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
618 return STOP;
619 }
620
621 /** Constructor.
622 *
623 * @param context Rendering context
624 */
ShaderAtomicCounterOpsAdditionSubstractionTestCase(deqp::Context & context)625 ShaderAtomicCounterOpsAdditionSubstractionTestCase::ShaderAtomicCounterOpsAdditionSubstractionTestCase(
626 deqp::Context &context)
627 : ShaderAtomicCounterOpsTestBase(
628 context, "ShaderAtomicCounterOpsAdditionSubstractionTestCase",
629 "Implements verification of new built-in addition and substraction atomic counter operations")
630 {
631 }
632
setOperations()633 void ShaderAtomicCounterOpsAdditionSubstractionTestCase::setOperations()
634 {
635 glw::GLuint input = 12;
636 glw::GLuint param = 4;
637
638 addOperation(new AtomicOperationAdd(input, param));
639 addOperation(new AtomicOperationSubtract(input, param));
640 }
641
642 /** Constructor.
643 *
644 * @param context Rendering context
645 */
ShaderAtomicCounterOpsMinMaxTestCase(deqp::Context & context)646 ShaderAtomicCounterOpsMinMaxTestCase::ShaderAtomicCounterOpsMinMaxTestCase(deqp::Context &context)
647 : ShaderAtomicCounterOpsTestBase(
648 context, "ShaderAtomicCounterOpsMinMaxTestCase",
649 "Implements verification of new built-in minimum and maximum atomic counter operations")
650 {
651 }
652
setOperations()653 void ShaderAtomicCounterOpsMinMaxTestCase::setOperations()
654 {
655 glw::GLuint input = 12;
656 glw::GLuint params[] = {4, 16};
657
658 addOperation(new AtomicOperationMin(input, params[0]));
659 addOperation(new AtomicOperationMin(input, params[1]));
660 addOperation(new AtomicOperationMax(input, params[0]));
661 addOperation(new AtomicOperationMax(input, params[1]));
662 }
663
664 /** Constructor.
665 *
666 * @param context Rendering context
667 */
ShaderAtomicCounterOpsBitwiseTestCase(deqp::Context & context)668 ShaderAtomicCounterOpsBitwiseTestCase::ShaderAtomicCounterOpsBitwiseTestCase(deqp::Context &context)
669 : ShaderAtomicCounterOpsTestBase(context, "ShaderAtomicCounterOpsBitwiseTestCase",
670 "Implements verification of new built-in bitwise atomic counter operations")
671 {
672 }
673
setOperations()674 void ShaderAtomicCounterOpsBitwiseTestCase::setOperations()
675 {
676 glw::GLuint input = 0x2ED; // 0b1011101101;
677 glw::GLuint param = 0x3A9; // 0b1110101001;
678
679 addOperation(new AtomicOperationAnd(input, param));
680 addOperation(new AtomicOperationOr(input, param));
681 addOperation(new AtomicOperationXor(input, param));
682 }
683
684 /** Constructor.
685 *
686 * @param context Rendering context
687 */
ShaderAtomicCounterOpsExchangeTestCase(deqp::Context & context)688 ShaderAtomicCounterOpsExchangeTestCase::ShaderAtomicCounterOpsExchangeTestCase(deqp::Context &context)
689 : ShaderAtomicCounterOpsTestBase(
690 context, "ShaderAtomicCounterOpsExchangeTestCase",
691 "Implements verification of new built-in exchange and swap atomic counter operations")
692 {
693 }
694
setOperations()695 void ShaderAtomicCounterOpsExchangeTestCase::setOperations()
696 {
697 glw::GLuint input = 5;
698 glw::GLuint param = 10;
699 glw::GLuint compare[] = {5, 20};
700
701 addOperation(new AtomicOperationExchange(input, param));
702 addOperation(new AtomicOperationCompSwap(input, param, compare[0]));
703 addOperation(new AtomicOperationCompSwap(input, param, compare[1]));
704 }
705
706 /** Constructor.
707 *
708 * @param context Rendering context.
709 */
ShaderAtomicCounterOps(deqp::Context & context)710 ShaderAtomicCounterOps::ShaderAtomicCounterOps(deqp::Context &context)
711 : TestCaseGroup(context, "shader_atomic_counter_ops_tests",
712 "Verify conformance of CTS_ARB_shader_atomic_counter_ops implementation")
713 {
714 }
715
716 /** Initializes the test group contents. */
init()717 void ShaderAtomicCounterOps::init()
718 {
719 addChild(new ShaderAtomicCounterOpsAdditionSubstractionTestCase(m_context));
720 addChild(new ShaderAtomicCounterOpsMinMaxTestCase(m_context));
721 addChild(new ShaderAtomicCounterOpsBitwiseTestCase(m_context));
722 addChild(new ShaderAtomicCounterOpsExchangeTestCase(m_context));
723 }
724 } // namespace gl4cts
725