xref: /aosp_15_r20/external/deqp/modules/gles31/functional/es31fSSBOArrayLengthTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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