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 uint32_t m_targetBufferID;
70 uint32_t 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,
76 bool sized)
77 : TestCase(context, name, desc)
78 , m_access(access)
79 , m_sized(sized)
80 , m_shader(DE_NULL)
81 , m_targetBufferID(0)
82 , m_outputBufferID(0)
83 {
84 }
85
~SSBOArrayLengthCase(void)86 SSBOArrayLengthCase::~SSBOArrayLengthCase(void)
87 {
88 deinit();
89 }
90
init(void)91 void SSBOArrayLengthCase::init(void)
92 {
93 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
94 const uint32_t invalidValues[] = {0xFFFFFFFFUL, 0xAAAAAAAAUL};
95
96 // program
97 m_shader = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
98 << glu::ComputeSource(genComputeSource()));
99 m_testCtx.getLog() << *m_shader;
100
101 if (!m_shader->isOk())
102 throw tcu::TestError("Failed to build shader");
103
104 // gen and attach buffers
105 gl.genBuffers(1, &m_outputBufferID);
106 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, m_outputBufferID);
107 gl.bufferData(GL_SHADER_STORAGE_BUFFER, 2 * (int)sizeof(uint32_t), invalidValues, GL_DYNAMIC_COPY);
108
109 gl.genBuffers(1, &m_targetBufferID);
110 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, m_targetBufferID);
111
112 GLU_EXPECT_NO_ERROR(gl.getError(), "create buffers");
113
114 gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_outputBufferID);
115 gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_targetBufferID);
116
117 GLU_EXPECT_NO_ERROR(gl.getError(), "bind buffers");
118
119 // check the ssbo has expected layout
120 {
121 const uint32_t index = gl.getProgramResourceIndex(m_shader->getProgram(), GL_BUFFER_VARIABLE, "Out.outLength");
122 const glw::GLenum prop = GL_OFFSET;
123 glw::GLint result = 0;
124
125 if (index == GL_INVALID_INDEX)
126 throw tcu::TestError("Failed to find outLength variable");
127
128 gl.getProgramResourceiv(m_shader->getProgram(), GL_BUFFER_VARIABLE, index, 1, &prop, 1, DE_NULL, &result);
129
130 if (result != 0)
131 throw tcu::TestError("Unexpected outLength location");
132 }
133 {
134 const uint32_t index = gl.getProgramResourceIndex(m_shader->getProgram(), GL_BUFFER_VARIABLE, "Out.unused");
135 const glw::GLenum prop = GL_OFFSET;
136 glw::GLint result = 0;
137
138 if (index == GL_INVALID_INDEX)
139 throw tcu::TestError("Failed to find unused variable");
140
141 gl.getProgramResourceiv(m_shader->getProgram(), GL_BUFFER_VARIABLE, index, 1, &prop, 1, DE_NULL, &result);
142
143 if (result != 4)
144 throw tcu::TestError("Unexpected unused location");
145 }
146 {
147 const uint32_t index = gl.getProgramResourceIndex(m_shader->getProgram(), GL_BUFFER_VARIABLE, "Target.array");
148 const glw::GLenum prop = GL_ARRAY_STRIDE;
149 glw::GLint result = 0;
150
151 if (index == GL_INVALID_INDEX)
152 throw tcu::TestError("Failed to find array variable");
153
154 gl.getProgramResourceiv(m_shader->getProgram(), GL_BUFFER_VARIABLE, index, 1, &prop, 1, DE_NULL, &result);
155
156 if (result != 4)
157 throw tcu::TestError("Unexpected array stride");
158 }
159 }
160
deinit(void)161 void SSBOArrayLengthCase::deinit(void)
162 {
163 if (m_shader)
164 {
165 delete m_shader;
166 m_shader = DE_NULL;
167 }
168
169 if (m_targetBufferID)
170 {
171 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_targetBufferID);
172 m_targetBufferID = 0;
173 }
174
175 if (m_outputBufferID)
176 {
177 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_outputBufferID);
178 m_outputBufferID = 0;
179 }
180 }
181
iterate(void)182 SSBOArrayLengthCase::IterateResult SSBOArrayLengthCase::iterate(void)
183 {
184 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
185 bool error = false;
186
187 // Update buffer size
188
189 m_testCtx.getLog() << tcu::TestLog::Message << "Allocating float memory buffer with "
190 << static_cast<int>(s_fixedBufferSize) << " elements." << tcu::TestLog::EndMessage;
191
192 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, m_targetBufferID);
193 gl.bufferData(GL_SHADER_STORAGE_BUFFER, s_fixedBufferSize * (int)sizeof(float), DE_NULL, GL_DYNAMIC_COPY);
194
195 GLU_EXPECT_NO_ERROR(gl.getError(), "update buffer");
196
197 // Run compute
198
199 m_testCtx.getLog() << tcu::TestLog::Message << "Running compute shader." << tcu::TestLog::EndMessage;
200
201 gl.useProgram(m_shader->getProgram());
202 gl.dispatchCompute(1, 1, 1);
203
204 GLU_EXPECT_NO_ERROR(gl.getError(), "dispatch");
205
206 // Verify
207 {
208 const void *ptr;
209
210 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, m_outputBufferID);
211 ptr = gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, (int)sizeof(uint32_t), GL_MAP_READ_BIT);
212 GLU_EXPECT_NO_ERROR(gl.getError(), "map");
213
214 if (!ptr)
215 throw tcu::TestError("mapBufferRange returned NULL");
216
217 if (*(const uint32_t *)ptr != (uint32_t)s_fixedBufferSize)
218 {
219 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: Length returned was " << *(const uint32_t *)ptr
220 << ", expected " << static_cast<int>(s_fixedBufferSize) << tcu::TestLog::EndMessage;
221 error = true;
222 }
223 else
224 m_testCtx.getLog() << tcu::TestLog::Message << "Length returned was correct." << tcu::TestLog::EndMessage;
225
226 if (gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER) == GL_FALSE)
227 throw tcu::TestError("unmapBuffer returned false");
228
229 GLU_EXPECT_NO_ERROR(gl.getError(), "unmap");
230 }
231
232 if (!error)
233 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
234 else
235 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
236 return STOP;
237 }
238
genComputeSource(void) const239 std::string SSBOArrayLengthCase::genComputeSource(void) const
240 {
241 const std::string qualifierStr = (m_access == ACCESS_READONLY) ? ("readonly ") :
242 (m_access == ACCESS_WRITEONLY) ? ("writeonly ") :
243 ("");
244 const std::string sizeStr = (m_sized) ? (de::toString(static_cast<int>(s_fixedBufferSize))) : ("");
245
246 std::ostringstream buf;
247 buf << "#version 310 es\n"
248 << "layout(local_size_x = 1, local_size_y = 1) in;\n"
249 << "layout(std430) buffer;\n"
250 << "\n"
251 << "layout(binding = 0) buffer Out\n"
252 << "{\n"
253 << " int outLength;\n"
254 << " uint unused;\n"
255 << "} sb_out;\n"
256 << "layout(binding = 1) " << qualifierStr << "buffer Target\n"
257 << "{\n"
258 << " float array[" << sizeStr << "];\n"
259 << "} sb_target;\n\n"
260 << "void main (void)\n"
261 << "{\n";
262
263 // read
264 if (m_access == ACCESS_READONLY || m_access == ACCESS_DEFAULT)
265 buf << " sb_out.unused = uint(sb_target.array[1]);\n";
266
267 // write
268 if (m_access == ACCESS_WRITEONLY || m_access == ACCESS_DEFAULT)
269 buf << " sb_target.array[2] = float(sb_out.unused);\n";
270
271 // actual test
272 buf << "\n"
273 << " sb_out.outLength = sb_target.array.length();\n"
274 << "}\n";
275
276 return buf.str();
277 }
278
279 } // namespace
280
SSBOArrayLengthTests(Context & context)281 SSBOArrayLengthTests::SSBOArrayLengthTests(Context &context)
282 : TestCaseGroup(context, "array_length", "Test array.length()")
283 {
284 }
285
~SSBOArrayLengthTests(void)286 SSBOArrayLengthTests::~SSBOArrayLengthTests(void)
287 {
288 }
289
init(void)290 void SSBOArrayLengthTests::init(void)
291 {
292 static const struct Qualifier
293 {
294 SSBOArrayLengthCase::ArrayAccess access;
295 const char *name;
296 const char *desc;
297 } qualifiers[] = {
298 {SSBOArrayLengthCase::ACCESS_DEFAULT, "", ""},
299 {SSBOArrayLengthCase::ACCESS_WRITEONLY, "writeonly_", "writeonly"},
300 {SSBOArrayLengthCase::ACCESS_READONLY, "readonly_", "readonly"},
301 };
302
303 static const bool arraysSized[] = {true, false};
304
305 for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(arraysSized); ++sizeNdx)
306 for (int qualifierNdx = 0; qualifierNdx < DE_LENGTH_OF_ARRAY(qualifiers); ++qualifierNdx)
307 {
308 const std::string name = std::string() + ((arraysSized[sizeNdx]) ? ("sized_") : ("unsized_")) +
309 qualifiers[qualifierNdx].name + "array";
310 const std::string desc = std::string("Test length() of ") +
311 ((arraysSized[sizeNdx]) ? ("sized ") : ("unsized ")) +
312 qualifiers[qualifierNdx].name + " array";
313
314 this->addChild(new SSBOArrayLengthCase(m_context, name.c_str(), desc.c_str(),
315 qualifiers[qualifierNdx].access, arraysSized[sizeNdx]));
316 }
317 }
318
319 } // namespace Functional
320 } // namespace gles31
321 } // namespace deqp
322