• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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