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
SSBOArrayLengthCase(Context & context,const char * name,const char * desc,ArrayAccess access,bool sized)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
~SSBOArrayLengthCase(void)85 SSBOArrayLengthCase::~SSBOArrayLengthCase (void)
86 {
87 deinit();
88 }
89
init(void)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
deinit(void)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
iterate(void)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
genComputeSource(void) const235 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
SSBOArrayLengthTests(Context & context)275 SSBOArrayLengthTests::SSBOArrayLengthTests (Context& context)
276 : TestCaseGroup(context, "array_length", "Test array.length()")
277 {
278 }
279
~SSBOArrayLengthTests(void)280 SSBOArrayLengthTests::~SSBOArrayLengthTests (void)
281 {
282 }
283
init(void)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
313