Home | History | Annotate | Download | only in functional
      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
    313