xref: /aosp_15_r20/external/deqp/external/openglcts/modules/gl/gl4cShaderAtomicCounterOpsTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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