1 /*-------------------------------------------------------------------------
2  * OpenGL Conformance Test Suite
3  * -----------------------------
4  *
5  * Copyright (c) 2014-2016 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  */ /*!
20  * \file
21  * \brief
22  */ /*-------------------------------------------------------------------*/
23 
24 /*!
25  * \file esextcGPUShader5AtomicCountersArrayIndexing.cpp
26  * \brief GPUShader5 Atomic Counters Array Indexing (Test 3)
27  */ /*-------------------------------------------------------------------*/
28 
29 #include "esextcGPUShader5AtomicCountersArrayIndexing.hpp"
30 #include "gluContextInfo.hpp"
31 #include "gluDefs.hpp"
32 #include "glwEnums.hpp"
33 #include "glwFunctions.hpp"
34 #include "tcuTestLog.hpp"
35 #include <cstring>
36 
37 namespace glcts
38 {
39 const glw::GLuint GPUShader5AtomicCountersArrayIndexing::m_atomic_counters_array_size = 4;
40 
41 /* Compute Shader code */
42 const char *GPUShader5AtomicCountersArrayIndexing::m_compute_shader_code =
43     "${VERSION}\n"
44     "\n"
45     "${GPU_SHADER5_REQUIRE}\n"
46     "\n"
47     "layout (local_size_x = 2, local_size_y = 2) in;\n"
48     "layout (binding      = 0, offset       = 0) uniform atomic_uint counters[4];\n"
49     "\n"
50     "void main(void)\n"
51     "{\n"
52     "    for (uint index = 0u; index <= 3u; ++index)\n"
53     "    {\n"
54     "        for (uint iteration = 0u; iteration <= gl_LocalInvocationID.x * 2u + gl_LocalInvocationID.y; "
55     "++iteration)\n"
56     "        {\n"
57     "            atomicCounterIncrement( counters[index] );\n"
58     "        }\n"
59     "    }\n"
60     "}\n";
61 
62 /** Constructor
63  *
64  *  @param context     Test context
65  *  @param name        Test case's name
66  *  @param description Test case's description
67  **/
GPUShader5AtomicCountersArrayIndexing(Context & context,const ExtParameters & extParams,const char * name,const char * description)68 GPUShader5AtomicCountersArrayIndexing::GPUShader5AtomicCountersArrayIndexing(Context &context,
69                                                                              const ExtParameters &extParams,
70                                                                              const char *name, const char *description)
71     : TestCaseBase(context, extParams, name, description)
72     , m_buffer_id(0)
73     , m_compute_shader_id(0)
74     , m_program_id(0)
75 {
76     /* Nothing to be done here */
77 }
78 
79 /** Initializes GLES objects used during the test.
80  *
81  */
initTest(void)82 void GPUShader5AtomicCountersArrayIndexing::initTest(void)
83 {
84     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
85 
86     /* Check if gpu_shader5 extension is supported */
87     if (!m_is_gpu_shader5_supported)
88     {
89         throw tcu::NotSupportedError(GPU_SHADER5_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
90     }
91 
92     /* Create program object from the supplied compute shader code */
93     m_program_id = gl.createProgram();
94     GLU_EXPECT_NO_ERROR(gl.getError(), "Creating program object failed");
95 
96     m_compute_shader_id = gl.createShader(GL_COMPUTE_SHADER);
97     GLU_EXPECT_NO_ERROR(gl.getError(), "Creating compute shader object failed");
98 
99     if (!buildProgram(m_program_id, m_compute_shader_id, 1, &m_compute_shader_code))
100     {
101         TCU_FAIL("Could not create program object!");
102     }
103 
104     glw::GLuint bufferData[m_atomic_counters_array_size];
105     for (glw::GLuint index = 0; index < m_atomic_counters_array_size; ++index)
106     {
107         bufferData[index] = index;
108     }
109 
110     gl.genBuffers(1, &m_buffer_id);
111     gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_buffer_id);
112     gl.bufferData(GL_ATOMIC_COUNTER_BUFFER, m_atomic_counters_array_size * sizeof(glw::GLuint), bufferData,
113                   GL_DYNAMIC_COPY);
114     gl.bindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, m_buffer_id);
115 
116     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not setup buffer object!");
117 }
118 
119 /** Executes the test.
120  *
121  *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
122  *
123  *  Note the function throws exception should an error occur!
124  *
125  *  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
126  **/
iterate(void)127 tcu::TestNode::IterateResult GPUShader5AtomicCountersArrayIndexing::iterate(void)
128 {
129     initTest();
130 
131     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
132 
133     /* Do the computations */
134     gl.useProgram(m_program_id);
135     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not use program object!");
136 
137     gl.dispatchCompute(10, /* num_groups_x */
138                        10, /* num_groups_y */
139                        1); /* num_groups_z */
140     GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to dispatch compute operation!");
141 
142     /* Map the buffer object storage into user space */
143     glw::GLuint *bufferData =
144         (glw::GLuint *)gl.mapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, /* offset */
145                                          m_atomic_counters_array_size * sizeof(glw::GLuint), GL_MAP_READ_BIT);
146     GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to map buffer range to client space!");
147 
148     /* Compare the result values with reference value */
149     const glw::GLuint expectedResult = 1000;
150 
151     if (expectedResult != bufferData[0] || expectedResult + 1 != bufferData[1] || expectedResult + 2 != bufferData[2] ||
152         expectedResult + 3 != bufferData[3])
153     {
154         m_testCtx.getLog() << tcu::TestLog::Message << "Invalid data rendered. Expected Data"
155                            << " (" << expectedResult << ", " << expectedResult << ", " << expectedResult << ", "
156                            << expectedResult << ") Result Data"
157                            << " (" << bufferData[0] << " ," << bufferData[1] << " ," << bufferData[2] << " ,"
158                            << bufferData[3] << ")" << tcu::TestLog::EndMessage;
159 
160         gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
161         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to unmap buffer!");
162 
163         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
164         return STOP;
165     }
166 
167     gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
168     GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to unmap buffer!");
169 
170     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
171     return STOP;
172 }
173 
174 /** Deinitializes GLES objects created during the test.
175  *
176  */
deinit(void)177 void GPUShader5AtomicCountersArrayIndexing::deinit(void)
178 {
179     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
180 
181     /* Reset OpenGL ES state */
182     gl.useProgram(0);
183     gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
184 
185     if (m_program_id != 0)
186     {
187         gl.deleteProgram(m_program_id);
188         m_program_id = 0;
189     }
190 
191     if (m_compute_shader_id != 0)
192     {
193         gl.deleteShader(m_compute_shader_id);
194         m_compute_shader_id = 0;
195     }
196 
197     if (m_buffer_id != 0)
198     {
199         gl.deleteBuffers(1, &m_buffer_id);
200         m_buffer_id = 0;
201     }
202 
203     /* Release base class */
204     TestCaseBase::deinit();
205 }
206 
207 } // namespace glcts
208