Fix PIPELINE_STAGE_TOP_OF_PIPE_BIT usage in api tests
[platform/upstream/VK-GL-CTS.git] / modules / gles31 / functional / es31fSSBOArrayLengthTests.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.1 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
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 SSBO array length tests.
22  *//*--------------------------------------------------------------------*/
23
24 #include "es31fSSBOArrayLengthTests.hpp"
25 #include "gluShaderProgram.hpp"
26 #include "gluRenderContext.hpp"
27 #include "tcuTestLog.hpp"
28 #include "glwFunctions.hpp"
29 #include "glwEnums.hpp"
30 #include "deStringUtil.hpp"
31
32 #include <sstream>
33
34 namespace deqp
35 {
36 namespace gles31
37 {
38 namespace Functional
39 {
40 namespace
41 {
42
43 class SSBOArrayLengthCase : public TestCase
44 {
45 public:
46         enum ArrayAccess
47         {
48                 ACCESS_DEFAULT = 0,
49                 ACCESS_WRITEONLY,
50                 ACCESS_READONLY,
51
52                 ACCESS_LAST
53         };
54
55                                                 SSBOArrayLengthCase             (Context& context, const char* name, const char* desc, ArrayAccess access, bool sized);
56                                                 ~SSBOArrayLengthCase    (void);
57
58         void                            init                                    (void);
59         void                            deinit                                  (void);
60         IterateResult           iterate                                 (void);
61
62 private:
63         std::string                     genComputeSource                (void) const;
64
65         const ArrayAccess       m_access;
66         const bool                      m_sized;
67
68         glu::ShaderProgram*     m_shader;
69         deUint32                        m_targetBufferID;
70         deUint32                        m_outputBufferID;
71
72         static const int        s_fixedBufferSize = 16;
73 };
74
75 SSBOArrayLengthCase::SSBOArrayLengthCase (Context& context, const char* name, const char* desc, ArrayAccess access, bool sized)
76         : TestCase                      (context, name, desc)
77         , m_access                      (access)
78         , m_sized                       (sized)
79         , m_shader                      (DE_NULL)
80         , m_targetBufferID      (0)
81         , m_outputBufferID      (0)
82 {
83 }
84
85 SSBOArrayLengthCase::~SSBOArrayLengthCase (void)
86 {
87         deinit();
88 }
89
90 void SSBOArrayLengthCase::init (void)
91 {
92         const glw::Functions&   gl                              = m_context.getRenderContext().getFunctions();
93         const deUint32                  invalidValue    = 0xFFFFFFFFUL;
94
95         // program
96         m_shader = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::ComputeSource(genComputeSource()));
97         m_testCtx.getLog() << *m_shader;
98
99         if (!m_shader->isOk())
100                 throw tcu::TestError("Failed to build shader");
101
102         // gen and attach buffers
103         gl.genBuffers(1, &m_outputBufferID);
104         gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, m_outputBufferID);
105         gl.bufferData(GL_SHADER_STORAGE_BUFFER, 2 * (int)sizeof(deUint32), &invalidValue, GL_DYNAMIC_COPY);
106
107         gl.genBuffers(1, &m_targetBufferID);
108         gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, m_targetBufferID);
109
110         GLU_EXPECT_NO_ERROR(gl.getError(), "create buffers");
111
112         gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_outputBufferID);
113         gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_targetBufferID);
114
115         GLU_EXPECT_NO_ERROR(gl.getError(), "bind buffers");
116
117         // check the ssbo has expected layout
118         {
119                 const deUint32          index   = gl.getProgramResourceIndex(m_shader->getProgram(), GL_BUFFER_VARIABLE, "Out.outLength");
120                 const glw::GLenum       prop    = GL_OFFSET;
121                 glw::GLint                      result  = 0;
122
123                 if (index == GL_INVALID_INDEX)
124                         throw tcu::TestError("Failed to find outLength variable");
125
126                 gl.getProgramResourceiv(m_shader->getProgram(), GL_BUFFER_VARIABLE, index, 1, &prop, 1, DE_NULL, &result);
127
128                 if (result != 0)
129                         throw tcu::TestError("Unexpected outLength location");
130         }
131         {
132                 const deUint32          index   = gl.getProgramResourceIndex(m_shader->getProgram(), GL_BUFFER_VARIABLE, "Out.unused");
133                 const glw::GLenum       prop    = GL_OFFSET;
134                 glw::GLint                      result  = 0;
135
136                 if (index == GL_INVALID_INDEX)
137                         throw tcu::TestError("Failed to find unused variable");
138
139                 gl.getProgramResourceiv(m_shader->getProgram(), GL_BUFFER_VARIABLE, index, 1, &prop, 1, DE_NULL, &result);
140
141                 if (result != 4)
142                         throw tcu::TestError("Unexpected unused location");
143         }
144         {
145                 const deUint32          index   = gl.getProgramResourceIndex(m_shader->getProgram(), GL_BUFFER_VARIABLE, "Target.array");
146                 const glw::GLenum       prop    = GL_ARRAY_STRIDE;
147                 glw::GLint                      result  = 0;
148
149                 if (index == GL_INVALID_INDEX)
150                         throw tcu::TestError("Failed to find array variable");
151
152                 gl.getProgramResourceiv(m_shader->getProgram(), GL_BUFFER_VARIABLE, index, 1, &prop, 1, DE_NULL, &result);
153
154                 if (result != 4)
155                         throw tcu::TestError("Unexpected array stride");
156         }
157 }
158
159 void SSBOArrayLengthCase::deinit (void)
160 {
161         if (m_shader)
162         {
163                 delete m_shader;
164                 m_shader = DE_NULL;
165         }
166
167         if (m_targetBufferID)
168         {
169                 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_targetBufferID);
170                 m_targetBufferID = 0;
171         }
172
173         if (m_outputBufferID)
174         {
175                 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_outputBufferID);
176                 m_outputBufferID = 0;
177         }
178 }
179
180 SSBOArrayLengthCase::IterateResult SSBOArrayLengthCase::iterate (void)
181 {
182         const glw::Functions&   gl              = m_context.getRenderContext().getFunctions();
183         bool                                    error   = false;
184
185         // Update buffer size
186
187         m_testCtx.getLog() << tcu::TestLog::Message << "Allocating float memory buffer with " << static_cast<int>(s_fixedBufferSize) << " elements." << tcu::TestLog::EndMessage;
188
189         gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, m_targetBufferID);
190         gl.bufferData(GL_SHADER_STORAGE_BUFFER, s_fixedBufferSize * (int)sizeof(float), DE_NULL, GL_DYNAMIC_COPY);
191
192         GLU_EXPECT_NO_ERROR(gl.getError(), "update buffer");
193
194         // Run compute
195
196         m_testCtx.getLog() << tcu::TestLog::Message << "Running compute shader." << tcu::TestLog::EndMessage;
197
198         gl.useProgram(m_shader->getProgram());
199         gl.dispatchCompute(1, 1, 1);
200
201         GLU_EXPECT_NO_ERROR(gl.getError(), "dispatch");
202
203         // Verify
204         {
205                 const void* ptr;
206
207                 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, m_outputBufferID);
208                 ptr = gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, (int)sizeof(deUint32), GL_MAP_READ_BIT);
209                 GLU_EXPECT_NO_ERROR(gl.getError(), "map");
210
211                 if (!ptr)
212                         throw tcu::TestError("mapBufferRange returned NULL");
213
214                 if (*(const deUint32*)ptr != (deUint32)s_fixedBufferSize)
215                 {
216                         m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: Length returned was " << *(const deUint32*)ptr << ", expected " << static_cast<int>(s_fixedBufferSize) << tcu::TestLog::EndMessage;
217                         error = true;
218                 }
219                 else
220                         m_testCtx.getLog() << tcu::TestLog::Message << "Length returned was correct." << tcu::TestLog::EndMessage;
221
222                 if (gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER) == GL_FALSE)
223                         throw tcu::TestError("unmapBuffer returned false");
224
225                 GLU_EXPECT_NO_ERROR(gl.getError(), "unmap");
226         }
227
228         if (!error)
229                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
230         else
231                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
232         return STOP;
233 }
234
235 std::string SSBOArrayLengthCase::genComputeSource (void) const
236 {
237         const std::string qualifierStr  = (m_access == ACCESS_READONLY) ? ("readonly ") : (m_access == ACCESS_WRITEONLY) ? ("writeonly ") : ("");
238         const std::string sizeStr               = (m_sized) ? (de::toString(static_cast<int>(s_fixedBufferSize))) : ("");
239
240         std::ostringstream buf;
241         buf << "#version 310 es\n"
242                 << "layout(local_size_x = 1, local_size_y = 1) in;\n"
243                 << "layout(std430) buffer;\n"
244                 << "\n"
245                 << "layout(binding = 0) buffer Out\n"
246                 << "{\n"
247                 << "    int outLength;\n"
248                 << "    uint unused;\n"
249                 << "} sb_out;\n"
250                 << "layout(binding = 1) " << qualifierStr << "buffer Target\n"
251                 << "{\n"
252                 << "    float array[" << sizeStr << "];\n"
253                 << "} sb_target;\n\n"
254                 << "void main (void)\n"
255                 << "{\n";
256
257         // read
258         if (m_access == ACCESS_READONLY || m_access == ACCESS_DEFAULT)
259                 buf << "    sb_out.unused = uint(sb_target.array[1]);\n";
260
261         // write
262         if (m_access == ACCESS_WRITEONLY || m_access == ACCESS_DEFAULT)
263                 buf << "    sb_target.array[2] = float(sb_out.unused);\n";
264
265         // actual test
266         buf << "\n"
267                 << "    sb_out.outLength = sb_target.array.length();\n"
268                 << "}\n";
269
270         return buf.str();
271 }
272
273 } // anonymous
274
275 SSBOArrayLengthTests::SSBOArrayLengthTests (Context& context)
276         : TestCaseGroup(context, "array_length", "Test array.length()")
277 {
278 }
279
280 SSBOArrayLengthTests::~SSBOArrayLengthTests (void)
281 {
282 }
283
284 void SSBOArrayLengthTests::init (void)
285 {
286         static const struct Qualifier
287         {
288                 SSBOArrayLengthCase::ArrayAccess        access;
289                 const char*                                                     name;
290                 const char*                                                     desc;
291         }  qualifiers[] =
292         {
293                 { SSBOArrayLengthCase::ACCESS_DEFAULT,          "",                             ""                      },
294                 { SSBOArrayLengthCase::ACCESS_WRITEONLY,        "writeonly_",   "writeonly"     },
295                 { SSBOArrayLengthCase::ACCESS_READONLY,         "readonly_",    "readonly"      },
296         };
297
298         static const bool arraysSized[] = { true, false };
299
300         for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(arraysSized); ++sizeNdx)
301         for (int qualifierNdx = 0; qualifierNdx < DE_LENGTH_OF_ARRAY(qualifiers); ++qualifierNdx)
302         {
303                 const std::string name = std::string() + ((arraysSized[sizeNdx]) ? ("sized_") : ("unsized_")) + qualifiers[qualifierNdx].name + "array";
304                 const std::string desc = std::string("Test length() of ") + ((arraysSized[sizeNdx]) ? ("sized ") : ("unsized ")) + qualifiers[qualifierNdx].name + " array";
305
306                 this->addChild(new SSBOArrayLengthCase(m_context, name.c_str(), desc.c_str(), qualifiers[qualifierNdx].access, arraysSized[sizeNdx]));
307         }
308 }
309
310 } // Functional
311 } // gles31
312 } // deqp