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 esextcGPUShader5SSBOArrayIndexing.cpp
26  * \brief GPUShader5 SSBO Array Indexing (Test 5)
27  */ /*-------------------------------------------------------------------*/
28 
29 #include "esextcGPUShader5SSBOArrayIndexing.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 
40 /* Compute shader code */
41 const char *GPUShader5SSBOArrayIndexing::m_compute_shader_code =
42     "${VERSION}\n"
43     "\n"
44     "${GPU_SHADER5_REQUIRE}\n"
45     "\n"
46     "#define LOCAL_SIZE_X 3u\n"
47     "#define LOCAL_SIZE_Y 3u\n"
48     "\n"
49     "layout (local_size_x = LOCAL_SIZE_X, local_size_y = LOCAL_SIZE_Y) in;\n"
50     "\n"
51     "layout(binding = 0) buffer ComputeSSBO\n"
52     "{\n"
53     "    uint value;\n"
54     "} computeSSBO[4];\n"
55     "\n"
56     "uniform uint index;\n"
57     "\n"
58     "void main(void)\n"
59     "{\n"
60     "    uint id = gl_LocalInvocationID.x * LOCAL_SIZE_Y + gl_LocalInvocationID.y;\n"
61     "\n"
62     "    for (uint i = 0u; i < LOCAL_SIZE_X * LOCAL_SIZE_Y; ++i)\n"
63     "    {\n"
64     "        if (id == i)\n"
65     "        {\n"
66     "            computeSSBO[index].value += id;\n"
67     "        }\n"
68     "\n"
69     "        memoryBarrier();\n"
70     "    }\n"
71     "}\n";
72 
73 /* Size of the ssbo array */
74 const glw::GLuint GPUShader5SSBOArrayIndexing::m_n_arrays = 4;
75 
76 /** Constructor
77  *
78  *  @param context       Test context
79  *  @param name          Test case's name
80  *  @param description   Test case's description
81  **/
GPUShader5SSBOArrayIndexing(Context & context,const ExtParameters & extParams,const char * name,const char * description)82 GPUShader5SSBOArrayIndexing::GPUShader5SSBOArrayIndexing(Context &context, const ExtParameters &extParams,
83                                                          const char *name, const char *description)
84     : TestCaseBase(context, extParams, name, description)
85     , m_compute_shader_id(0)
86     , m_program_id(0)
87     , m_ssbo_buffer_ids(DE_NULL)
88 {
89     /* Nothing to be done here */
90 }
91 
92 /** Initializes GLES objects used during the test.
93  *
94  */
initTest(void)95 void GPUShader5SSBOArrayIndexing::initTest(void)
96 {
97     /* Check if gpu_shader5 extension is supported */
98     if (!m_is_gpu_shader5_supported)
99     {
100         throw tcu::NotSupportedError(GPU_SHADER5_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
101     }
102 
103     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
104 
105     m_program_id = gl.createProgram();
106     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create program object!");
107 
108     m_compute_shader_id = gl.createShader(GL_COMPUTE_SHADER);
109     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create shader object!");
110 
111     if (!buildProgram(m_program_id, m_compute_shader_id, 1, &m_compute_shader_code))
112     {
113         TCU_FAIL("Could not build program from valid compute shader!");
114     }
115 
116     m_ssbo_buffer_ids = new glw::GLuint[m_n_arrays];
117     memset(m_ssbo_buffer_ids, 0, m_n_arrays * sizeof(glw::GLuint));
118 
119     gl.genBuffers(m_n_arrays, m_ssbo_buffer_ids);
120     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed");
121 
122     for (glw::GLuint index = 0; index < m_n_arrays; ++index)
123     {
124         gl.bindBuffer(GL_ARRAY_BUFFER, m_ssbo_buffer_ids[index]);
125         GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind buffer object!");
126 
127         const glw::GLuint ssbo_data = 0;
128 
129         gl.bufferData(GL_ARRAY_BUFFER, sizeof(glw::GLuint), &ssbo_data, GL_DYNAMIC_COPY);
130         GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set buffer object data!");
131 
132         gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, index, m_ssbo_buffer_ids[index]);
133         GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind buffer object to shader storage binding point!");
134     }
135 }
136 
137 /** Executes the test.
138  *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
139  *
140  *  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
141  *
142  *  Note the function throws exception should an error occur!
143  **/
iterate(void)144 tcu::TestNode::IterateResult GPUShader5SSBOArrayIndexing::iterate(void)
145 {
146     initTest();
147 
148     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
149 
150     /* Activate the program object and retrieve index uniform location */
151     gl.useProgram(m_program_id);
152     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not use program!");
153 
154     glw::GLint index_location = gl.getUniformLocation(m_program_id, "index");
155     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformLocation() call failed!");
156 
157     if (index_location == -1)
158     {
159         TCU_FAIL("Index uniform location is inactive which is invalid!");
160     }
161 
162     /* Issue a few compute operations */
163     gl.uniform1ui(index_location, 1);
164     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set value of index uniform variable!");
165 
166     gl.dispatchCompute(1,  /* num_groups_x */
167                        1,  /* num_groups_y */
168                        1); /* num_groups_z */
169     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not dispatch compute!");
170 
171     gl.memoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
172     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set memory barrier!");
173 
174     gl.uniform1ui(index_location, 3);
175     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set value to index uniform variable!");
176 
177     gl.dispatchCompute(1,  /* num_groups_x */
178                        1,  /* num_groups_y */
179                        1); /* num_groups_z */
180     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not dispatch compute!");
181 
182     gl.memoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
183     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set memory barrier!");
184 
185     /* Validate the results */
186     glw::GLuint expected_result[m_n_arrays] = {0, 36, 0, 36};
187     bool test_failed                        = false;
188 
189     for (glw::GLuint index = 0; index < m_n_arrays; ++index)
190     {
191         gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo_buffer_ids[index]);
192         GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind a buffer object!");
193 
194         const glw::GLuint *compute_SSBO =
195             (const glw::GLuint *)gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(glw::GLuint), GL_MAP_READ_BIT);
196 
197         GLU_EXPECT_NO_ERROR(gl.getError(), "Could not map buffer data to client memory");
198 
199         if (compute_SSBO[0] != expected_result[index])
200         {
201             m_testCtx.getLog() << tcu::TestLog::Message << "Expected Data (" << expected_result[index] << ") "
202                                << "Result Data (" << compute_SSBO[0] << ")" << tcu::TestLog::EndMessage;
203 
204             test_failed = true;
205         }
206 
207         gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
208         GLU_EXPECT_NO_ERROR(gl.getError(), "Could not unmap buffer");
209     }
210 
211     if (test_failed)
212     {
213         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
214     }
215     else
216     {
217         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
218     }
219 
220     return STOP;
221 }
222 
223 /** Deinitializes GLES objects created during the test.
224  *
225  */
deinit(void)226 void GPUShader5SSBOArrayIndexing::deinit(void)
227 {
228     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
229 
230     /* Reset OpenGL ES state */
231     gl.useProgram(0);
232     gl.bindBuffer(GL_ARRAY_BUFFER, 0);
233     gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
234 
235     /* Delete program object and shaders */
236     if (m_program_id != 0)
237     {
238         gl.deleteProgram(m_program_id);
239 
240         m_program_id = 0;
241     }
242 
243     if (m_compute_shader_id != 0)
244     {
245         gl.deleteShader(m_compute_shader_id);
246 
247         m_compute_shader_id = 0;
248     }
249 
250     if (m_ssbo_buffer_ids != DE_NULL)
251     {
252         gl.deleteBuffers(m_n_arrays, m_ssbo_buffer_ids);
253 
254         delete[] m_ssbo_buffer_ids;
255         m_ssbo_buffer_ids = DE_NULL;
256     }
257 
258     /* Call base class' deinit() */
259     TestCaseBase::deinit();
260 }
261 
262 } // namespace glcts
263