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  esextcTextureBufferAtomicFunctions.cpp
26  * \brief Texture Buffer Atomic Functions (Test 5)
27  */ /*-------------------------------------------------------------------*/
28 
29 #include "esextcTextureBufferAtomicFunctions.hpp"
30 #include "gluContextInfo.hpp"
31 #include "gluDefs.hpp"
32 #include "glwEnums.hpp"
33 #include "glwFunctions.hpp"
34 #include "tcuTestLog.hpp"
35 #include <vector>
36 
37 namespace glcts
38 {
39 
40 /** Constructor
41  *
42  *  @param context     Test context
43  *  @param name        Test case's name
44  *  @param description Test case's description
45  **/
TextureBufferAtomicFunctions(Context & context,const ExtParameters & extParams,const char * name,const char * description)46 TextureBufferAtomicFunctions::TextureBufferAtomicFunctions(Context &context, const ExtParameters &extParams,
47                                                            const char *name, const char *description)
48     : TestCaseBase(context, extParams, name, description)
49     , m_cs_id(0)
50     , m_po_id(0)
51     , m_tbo_id(0)
52     , m_tbo_tex_id(0)
53     , m_n_texels_in_texture_buffer(0)
54 {
55 }
56 
57 /** Initializes GLES objects used during the test */
initTest(void)58 void TextureBufferAtomicFunctions::initTest(void)
59 {
60     /* Check if required extensions are supported */
61     if (!m_is_texture_buffer_supported)
62     {
63         throw tcu::NotSupportedError(TEXTURE_BUFFER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
64     }
65 
66     if (!m_is_shader_image_atomic_supported)
67     {
68         throw tcu::NotSupportedError(SHADER_IMAGE_ATOMIC_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
69     }
70 
71     /* Get GL entry points */
72     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
73 
74     glw::GLint work_group_size = 0;
75     gl.getIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &work_group_size);
76     GLU_EXPECT_NO_ERROR(gl.getError(), "Error getting GL_MAX_COMPUTE_WORK_GROUP_SIZE parameter value!");
77 
78     m_n_texels_in_texture_buffer = (glw::GLuint)work_group_size + 1;
79     std::vector<glw::GLuint> data_buffer(m_n_texels_in_texture_buffer);
80 
81     for (glw::GLuint i = 0; i < m_n_texels_in_texture_buffer; ++i)
82     {
83         data_buffer[i] = i;
84     }
85 
86     /* Create buffer object */
87     gl.genBuffers(1, &m_tbo_id);
88     GLU_EXPECT_NO_ERROR(gl.getError(), "Error generating buffer object!");
89 
90     gl.bindBuffer(m_glExtTokens.TEXTURE_BUFFER, m_tbo_id);
91     GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding buffer object!");
92 
93     gl.bufferData(m_glExtTokens.TEXTURE_BUFFER, m_n_texels_in_texture_buffer * sizeof(glw::GLuint), &data_buffer[0],
94                   GL_DYNAMIC_DRAW);
95     GLU_EXPECT_NO_ERROR(gl.getError(), "Error allocating buffer object's data store!");
96 
97     /* Initialize texture buffer */
98     gl.genTextures(1, &m_tbo_tex_id);
99     GLU_EXPECT_NO_ERROR(gl.getError(), "Error generating texture object!");
100 
101     gl.activeTexture(GL_TEXTURE0);
102     GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting active texture unit!");
103 
104     gl.bindTexture(m_glExtTokens.TEXTURE_BUFFER, m_tbo_tex_id);
105     GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding texture object to GL_TEXTURE_BUFFER_EXT target!");
106 
107     gl.texBuffer(m_glExtTokens.TEXTURE_BUFFER, GL_R32UI, m_tbo_id);
108     GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting buffer object as texture buffer's data store!");
109 
110     /* Create program object */
111     m_po_id = gl.createProgram();
112     GLU_EXPECT_NO_ERROR(gl.getError(), "Error creating program object!");
113 
114     m_cs_id = gl.createShader(GL_COMPUTE_SHADER);
115     GLU_EXPECT_NO_ERROR(gl.getError(), "Error creating shader object!");
116 
117     std::string csSource = getComputeShaderCode(work_group_size);
118     const char *csCode   = csSource.c_str();
119 
120     if (!buildProgram(m_po_id, m_cs_id, 1, &csCode))
121     {
122         TCU_FAIL("Could not create a program object from valid compute shader object!");
123     }
124 }
125 
126 /** Returns Compute shader Code
127  *
128  * @return pointer to literal with Compute Shader Code
129  */
getComputeShaderCode(glw::GLint work_group_size) const130 std::string TextureBufferAtomicFunctions::getComputeShaderCode(glw::GLint work_group_size) const
131 {
132     std::stringstream strstream;
133 
134     strstream << "${VERSION}\n"
135                  "\n"
136                  "${TEXTURE_BUFFER_REQUIRE}\n"
137                  "${SHADER_IMAGE_ATOMIC_REQUIRE}\n"
138                  "\n"
139                  "precision highp float;\n"
140                  "\n"
141                  "layout (local_size_x = "
142               << work_group_size
143               << " ) in;\n"
144                  "\n"
145                  "layout(r32ui, binding = 0) coherent uniform highp uimageBuffer uimage_buffer;\n"
146                  "\n"
147                  "void main(void)\n"
148                  "{\n"
149                  "   uint value = imageLoad( uimage_buffer, int(gl_LocalInvocationID.x) + 1 ).x;\n"
150                  "   imageAtomicAdd( uimage_buffer, 0 , value );\n"
151                  "\n"
152                  "   memoryBarrier();\n"
153                  "   barrier();\n"
154                  "\n"
155                  "   value = imageLoad( uimage_buffer, 0 ).x;\n"
156                  "   imageAtomicCompSwap( uimage_buffer, int(gl_LocalInvocationID.x) + 1, "
157                  "gl_LocalInvocationID.x + 1u, value );\n"
158                  "}\n";
159 
160     return strstream.str();
161 }
162 
163 /** Executes the test.
164  *
165  *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
166  *
167  *  Note the function throws exception should an error occur!
168  *
169  *  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
170  **/
iterate(void)171 tcu::TestNode::IterateResult TextureBufferAtomicFunctions::iterate(void)
172 {
173     /* Initialize */
174     initTest();
175 
176     /* Get Gl entry points */
177     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
178 
179     bool test_result = true;
180 
181     gl.useProgram(m_po_id);
182     GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting active program object!");
183 
184     gl.bindImageTexture(0, m_tbo_tex_id, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32UI);
185     GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding texture object to image unit 0!");
186 
187     gl.dispatchCompute(1, 1, 1);
188     GLU_EXPECT_NO_ERROR(gl.getError(), "Error running compute shader!");
189 
190     gl.memoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
191     GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting memory barrier!");
192 
193     /* Get result data */
194     glw::GLuint *result = (glw::GLuint *)gl.mapBufferRange(
195         m_glExtTokens.TEXTURE_BUFFER, 0, m_n_texels_in_texture_buffer * sizeof(glw::GLuint), GL_MAP_READ_BIT);
196     GLU_EXPECT_NO_ERROR(gl.getError(), "Error mapping buffer object's data store to client address space!");
197 
198     glw::GLuint expected_value = (m_n_texels_in_texture_buffer * (m_n_texels_in_texture_buffer - 1)) / 2;
199 
200     for (glw::GLuint i = 0; i < m_n_texels_in_texture_buffer; ++i)
201     {
202         /* Log error if expected data and result data are not equal */
203         if (result[i] != expected_value)
204         {
205             m_testCtx.getLog() << tcu::TestLog::Message << "Result is different than expected at index: " << i << "\n"
206                                << "Expected value: " << expected_value << "\n"
207                                << "Result   value: " << result[i] << "\n"
208                                << tcu::TestLog::EndMessage;
209 
210             test_result = false;
211             break;
212         }
213     }
214 
215     gl.unmapBuffer(m_glExtTokens.TEXTURE_BUFFER);
216 
217     if (test_result)
218     {
219         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
220     }
221     else
222     {
223         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
224     }
225 
226     return STOP;
227 }
228 
229 /** Deinitializes GLES objects created during the test */
deinit(void)230 void TextureBufferAtomicFunctions::deinit(void)
231 {
232     /* Get Gl entry points */
233     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
234 
235     /* Reset GLES state */
236     gl.useProgram(0);
237     gl.bindBuffer(m_glExtTokens.TEXTURE_BUFFER, 0);
238     gl.bindTexture(m_glExtTokens.TEXTURE_BUFFER, 0);
239 
240     /* Delete GLES objects */
241     if (0 != m_po_id)
242     {
243         gl.deleteProgram(m_po_id);
244         m_po_id = 0;
245     }
246 
247     if (0 != m_cs_id)
248     {
249         gl.deleteShader(m_cs_id);
250         m_cs_id = 0;
251     }
252 
253     if (0 != m_tbo_tex_id)
254     {
255         gl.deleteTextures(1, &m_tbo_tex_id);
256         m_tbo_tex_id = 0;
257     }
258 
259     if (0 != m_tbo_id)
260     {
261         gl.deleteBuffers(1, &m_tbo_id);
262         m_tbo_id = 0;
263     }
264 
265     /* Deinitialize base class */
266     TestCaseBase::deinit();
267 }
268 
269 } // namespace glcts
270