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