You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
313 lines
9.1 KiB
313 lines
9.1 KiB
/*-------------------------------------------------------------------------
|
|
* drawElements Quality Program OpenGL ES 3.1 Module
|
|
* -------------------------------------------------
|
|
*
|
|
* Copyright 2014 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*//*!
|
|
* \file
|
|
* \brief SSBO array length tests.
|
|
*//*--------------------------------------------------------------------*/
|
|
|
|
#include "es31fSSBOArrayLengthTests.hpp"
|
|
#include "gluShaderProgram.hpp"
|
|
#include "gluRenderContext.hpp"
|
|
#include "tcuTestLog.hpp"
|
|
#include "glwFunctions.hpp"
|
|
#include "glwEnums.hpp"
|
|
#include "deStringUtil.hpp"
|
|
|
|
#include <sstream>
|
|
|
|
namespace deqp
|
|
{
|
|
namespace gles31
|
|
{
|
|
namespace Functional
|
|
{
|
|
namespace
|
|
{
|
|
|
|
class SSBOArrayLengthCase : public TestCase
|
|
{
|
|
public:
|
|
enum ArrayAccess
|
|
{
|
|
ACCESS_DEFAULT = 0,
|
|
ACCESS_WRITEONLY,
|
|
ACCESS_READONLY,
|
|
|
|
ACCESS_LAST
|
|
};
|
|
|
|
SSBOArrayLengthCase (Context& context, const char* name, const char* desc, ArrayAccess access, bool sized);
|
|
~SSBOArrayLengthCase (void);
|
|
|
|
void init (void);
|
|
void deinit (void);
|
|
IterateResult iterate (void);
|
|
|
|
private:
|
|
std::string genComputeSource (void) const;
|
|
|
|
const ArrayAccess m_access;
|
|
const bool m_sized;
|
|
|
|
glu::ShaderProgram* m_shader;
|
|
deUint32 m_targetBufferID;
|
|
deUint32 m_outputBufferID;
|
|
|
|
static const int s_fixedBufferSize = 16;
|
|
};
|
|
|
|
SSBOArrayLengthCase::SSBOArrayLengthCase (Context& context, const char* name, const char* desc, ArrayAccess access, bool sized)
|
|
: TestCase (context, name, desc)
|
|
, m_access (access)
|
|
, m_sized (sized)
|
|
, m_shader (DE_NULL)
|
|
, m_targetBufferID (0)
|
|
, m_outputBufferID (0)
|
|
{
|
|
}
|
|
|
|
SSBOArrayLengthCase::~SSBOArrayLengthCase (void)
|
|
{
|
|
deinit();
|
|
}
|
|
|
|
void SSBOArrayLengthCase::init (void)
|
|
{
|
|
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
|
|
const deUint32 invalidValue = 0xFFFFFFFFUL;
|
|
|
|
// program
|
|
m_shader = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::ComputeSource(genComputeSource()));
|
|
m_testCtx.getLog() << *m_shader;
|
|
|
|
if (!m_shader->isOk())
|
|
throw tcu::TestError("Failed to build shader");
|
|
|
|
// gen and attach buffers
|
|
gl.genBuffers(1, &m_outputBufferID);
|
|
gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, m_outputBufferID);
|
|
gl.bufferData(GL_SHADER_STORAGE_BUFFER, 2 * (int)sizeof(deUint32), &invalidValue, GL_DYNAMIC_COPY);
|
|
|
|
gl.genBuffers(1, &m_targetBufferID);
|
|
gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, m_targetBufferID);
|
|
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "create buffers");
|
|
|
|
gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_outputBufferID);
|
|
gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_targetBufferID);
|
|
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "bind buffers");
|
|
|
|
// check the ssbo has expected layout
|
|
{
|
|
const deUint32 index = gl.getProgramResourceIndex(m_shader->getProgram(), GL_BUFFER_VARIABLE, "Out.outLength");
|
|
const glw::GLenum prop = GL_OFFSET;
|
|
glw::GLint result = 0;
|
|
|
|
if (index == GL_INVALID_INDEX)
|
|
throw tcu::TestError("Failed to find outLength variable");
|
|
|
|
gl.getProgramResourceiv(m_shader->getProgram(), GL_BUFFER_VARIABLE, index, 1, &prop, 1, DE_NULL, &result);
|
|
|
|
if (result != 0)
|
|
throw tcu::TestError("Unexpected outLength location");
|
|
}
|
|
{
|
|
const deUint32 index = gl.getProgramResourceIndex(m_shader->getProgram(), GL_BUFFER_VARIABLE, "Out.unused");
|
|
const glw::GLenum prop = GL_OFFSET;
|
|
glw::GLint result = 0;
|
|
|
|
if (index == GL_INVALID_INDEX)
|
|
throw tcu::TestError("Failed to find unused variable");
|
|
|
|
gl.getProgramResourceiv(m_shader->getProgram(), GL_BUFFER_VARIABLE, index, 1, &prop, 1, DE_NULL, &result);
|
|
|
|
if (result != 4)
|
|
throw tcu::TestError("Unexpected unused location");
|
|
}
|
|
{
|
|
const deUint32 index = gl.getProgramResourceIndex(m_shader->getProgram(), GL_BUFFER_VARIABLE, "Target.array");
|
|
const glw::GLenum prop = GL_ARRAY_STRIDE;
|
|
glw::GLint result = 0;
|
|
|
|
if (index == GL_INVALID_INDEX)
|
|
throw tcu::TestError("Failed to find array variable");
|
|
|
|
gl.getProgramResourceiv(m_shader->getProgram(), GL_BUFFER_VARIABLE, index, 1, &prop, 1, DE_NULL, &result);
|
|
|
|
if (result != 4)
|
|
throw tcu::TestError("Unexpected array stride");
|
|
}
|
|
}
|
|
|
|
void SSBOArrayLengthCase::deinit (void)
|
|
{
|
|
if (m_shader)
|
|
{
|
|
delete m_shader;
|
|
m_shader = DE_NULL;
|
|
}
|
|
|
|
if (m_targetBufferID)
|
|
{
|
|
m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_targetBufferID);
|
|
m_targetBufferID = 0;
|
|
}
|
|
|
|
if (m_outputBufferID)
|
|
{
|
|
m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_outputBufferID);
|
|
m_outputBufferID = 0;
|
|
}
|
|
}
|
|
|
|
SSBOArrayLengthCase::IterateResult SSBOArrayLengthCase::iterate (void)
|
|
{
|
|
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
|
|
bool error = false;
|
|
|
|
// Update buffer size
|
|
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Allocating float memory buffer with " << static_cast<int>(s_fixedBufferSize) << " elements." << tcu::TestLog::EndMessage;
|
|
|
|
gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, m_targetBufferID);
|
|
gl.bufferData(GL_SHADER_STORAGE_BUFFER, s_fixedBufferSize * (int)sizeof(float), DE_NULL, GL_DYNAMIC_COPY);
|
|
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "update buffer");
|
|
|
|
// Run compute
|
|
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Running compute shader." << tcu::TestLog::EndMessage;
|
|
|
|
gl.useProgram(m_shader->getProgram());
|
|
gl.dispatchCompute(1, 1, 1);
|
|
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "dispatch");
|
|
|
|
// Verify
|
|
{
|
|
const void* ptr;
|
|
|
|
gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, m_outputBufferID);
|
|
ptr = gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, (int)sizeof(deUint32), GL_MAP_READ_BIT);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "map");
|
|
|
|
if (!ptr)
|
|
throw tcu::TestError("mapBufferRange returned NULL");
|
|
|
|
if (*(const deUint32*)ptr != (deUint32)s_fixedBufferSize)
|
|
{
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: Length returned was " << *(const deUint32*)ptr << ", expected " << static_cast<int>(s_fixedBufferSize) << tcu::TestLog::EndMessage;
|
|
error = true;
|
|
}
|
|
else
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Length returned was correct." << tcu::TestLog::EndMessage;
|
|
|
|
if (gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER) == GL_FALSE)
|
|
throw tcu::TestError("unmapBuffer returned false");
|
|
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "unmap");
|
|
}
|
|
|
|
if (!error)
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
|
|
else
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
|
|
return STOP;
|
|
}
|
|
|
|
std::string SSBOArrayLengthCase::genComputeSource (void) const
|
|
{
|
|
const std::string qualifierStr = (m_access == ACCESS_READONLY) ? ("readonly ") : (m_access == ACCESS_WRITEONLY) ? ("writeonly ") : ("");
|
|
const std::string sizeStr = (m_sized) ? (de::toString(static_cast<int>(s_fixedBufferSize))) : ("");
|
|
|
|
std::ostringstream buf;
|
|
buf << "#version 310 es\n"
|
|
<< "layout(local_size_x = 1, local_size_y = 1) in;\n"
|
|
<< "layout(std430) buffer;\n"
|
|
<< "\n"
|
|
<< "layout(binding = 0) buffer Out\n"
|
|
<< "{\n"
|
|
<< " int outLength;\n"
|
|
<< " uint unused;\n"
|
|
<< "} sb_out;\n"
|
|
<< "layout(binding = 1) " << qualifierStr << "buffer Target\n"
|
|
<< "{\n"
|
|
<< " float array[" << sizeStr << "];\n"
|
|
<< "} sb_target;\n\n"
|
|
<< "void main (void)\n"
|
|
<< "{\n";
|
|
|
|
// read
|
|
if (m_access == ACCESS_READONLY || m_access == ACCESS_DEFAULT)
|
|
buf << " sb_out.unused = uint(sb_target.array[1]);\n";
|
|
|
|
// write
|
|
if (m_access == ACCESS_WRITEONLY || m_access == ACCESS_DEFAULT)
|
|
buf << " sb_target.array[2] = float(sb_out.unused);\n";
|
|
|
|
// actual test
|
|
buf << "\n"
|
|
<< " sb_out.outLength = sb_target.array.length();\n"
|
|
<< "}\n";
|
|
|
|
return buf.str();
|
|
}
|
|
|
|
} // anonymous
|
|
|
|
SSBOArrayLengthTests::SSBOArrayLengthTests (Context& context)
|
|
: TestCaseGroup(context, "array_length", "Test array.length()")
|
|
{
|
|
}
|
|
|
|
SSBOArrayLengthTests::~SSBOArrayLengthTests (void)
|
|
{
|
|
}
|
|
|
|
void SSBOArrayLengthTests::init (void)
|
|
{
|
|
static const struct Qualifier
|
|
{
|
|
SSBOArrayLengthCase::ArrayAccess access;
|
|
const char* name;
|
|
const char* desc;
|
|
} qualifiers[] =
|
|
{
|
|
{ SSBOArrayLengthCase::ACCESS_DEFAULT, "", "" },
|
|
{ SSBOArrayLengthCase::ACCESS_WRITEONLY, "writeonly_", "writeonly" },
|
|
{ SSBOArrayLengthCase::ACCESS_READONLY, "readonly_", "readonly" },
|
|
};
|
|
|
|
static const bool arraysSized[] = { true, false };
|
|
|
|
for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(arraysSized); ++sizeNdx)
|
|
for (int qualifierNdx = 0; qualifierNdx < DE_LENGTH_OF_ARRAY(qualifiers); ++qualifierNdx)
|
|
{
|
|
const std::string name = std::string() + ((arraysSized[sizeNdx]) ? ("sized_") : ("unsized_")) + qualifiers[qualifierNdx].name + "array";
|
|
const std::string desc = std::string("Test length() of ") + ((arraysSized[sizeNdx]) ? ("sized ") : ("unsized ")) + qualifiers[qualifierNdx].name + " array";
|
|
|
|
this->addChild(new SSBOArrayLengthCase(m_context, name.c_str(), desc.c_str(), qualifiers[qualifierNdx].access, arraysSized[sizeNdx]));
|
|
}
|
|
}
|
|
|
|
} // Functional
|
|
} // gles31
|
|
} // deqp
|