| /*------------------------------------------------------------------------- |
| * drawElements Quality Program OpenGL ES 3.0 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 Vertex array and buffer unaligned access stress tests |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "es3sVertexArrayTests.hpp" |
| #include "glsVertexArrayTests.hpp" |
| |
| #include <sstream> |
| |
| using namespace deqp::gls; |
| |
| namespace deqp |
| { |
| namespace gles3 |
| { |
| namespace Stress |
| { |
| namespace |
| { |
| |
| |
| class SingleVertexArrayUsageGroup : public TestCaseGroup |
| { |
| public: |
| SingleVertexArrayUsageGroup (Context& context, Array::Usage usage); |
| virtual ~SingleVertexArrayUsageGroup (void); |
| |
| virtual void init (void); |
| |
| private: |
| SingleVertexArrayUsageGroup (const SingleVertexArrayUsageGroup& other); |
| SingleVertexArrayUsageGroup& operator= (const SingleVertexArrayUsageGroup& other); |
| |
| Array::Usage m_usage; |
| }; |
| |
| SingleVertexArrayUsageGroup::SingleVertexArrayUsageGroup (Context& context, Array::Usage usage) |
| : TestCaseGroup (context, Array::usageTypeToString(usage).c_str(), Array::usageTypeToString(usage).c_str()) |
| , m_usage (usage) |
| { |
| } |
| |
| SingleVertexArrayUsageGroup::~SingleVertexArrayUsageGroup (void) |
| { |
| } |
| |
| template<class T> |
| static std::string typeToString (T t) |
| { |
| std::stringstream strm; |
| strm << t; |
| return strm.str(); |
| } |
| |
| void SingleVertexArrayUsageGroup::init (void) |
| { |
| int counts[] = {1, 256}; |
| int strides[] = {0, -1, 17, 32}; // Tread negative value as sizeof input. Same as 0, but done outside of GL. |
| Array::InputType inputTypes[] = {Array::INPUTTYPE_FLOAT, Array::INPUTTYPE_FIXED, Array::INPUTTYPE_SHORT, Array::INPUTTYPE_BYTE}; |
| |
| for (int inputTypeNdx = 0; inputTypeNdx < DE_LENGTH_OF_ARRAY(inputTypes); inputTypeNdx++) |
| { |
| for (int countNdx = 0; countNdx < DE_LENGTH_OF_ARRAY(counts); countNdx++) |
| { |
| for (int strideNdx = 0; strideNdx < DE_LENGTH_OF_ARRAY(strides); strideNdx++) |
| { |
| const int stride = (strides[strideNdx] < 0 ? Array::inputTypeSize(inputTypes[inputTypeNdx]) * 2 : strides[strideNdx]); |
| const bool aligned = (stride % Array::inputTypeSize(inputTypes[inputTypeNdx])) == 0; |
| const std::string name = "stride" + typeToString(stride) + "_" + Array::inputTypeToString(inputTypes[inputTypeNdx]) + "_quads" + typeToString(counts[countNdx]); |
| |
| MultiVertexArrayTest::Spec::ArraySpec arraySpec(inputTypes[inputTypeNdx], |
| Array::OUTPUTTYPE_VEC2, |
| Array::STORAGE_BUFFER, |
| m_usage, |
| 2, |
| 0, |
| stride, |
| false, |
| GLValue::getMinValue(inputTypes[inputTypeNdx]), |
| GLValue::getMaxValue(inputTypes[inputTypeNdx])); |
| |
| MultiVertexArrayTest::Spec spec; |
| spec.primitive = Array::PRIMITIVE_TRIANGLES; |
| spec.drawCount = counts[countNdx]; |
| spec.first = 0; |
| spec.arrays.push_back(arraySpec); |
| |
| if (!aligned) |
| addChild(new MultiVertexArrayTest(m_testCtx, m_context.getRenderContext(), spec, name.c_str(), name.c_str())); |
| } |
| } |
| } |
| } |
| |
| class SingleVertexArrayUsageTests : public TestCaseGroup |
| { |
| public: |
| SingleVertexArrayUsageTests (Context& context); |
| virtual ~SingleVertexArrayUsageTests (void); |
| |
| virtual void init (void); |
| |
| private: |
| SingleVertexArrayUsageTests (const SingleVertexArrayUsageTests& other); |
| SingleVertexArrayUsageTests& operator= (const SingleVertexArrayUsageTests& other); |
| }; |
| |
| SingleVertexArrayUsageTests::SingleVertexArrayUsageTests (Context& context) |
| : TestCaseGroup(context, "usages", "Single vertex atribute, usage") |
| { |
| } |
| |
| SingleVertexArrayUsageTests::~SingleVertexArrayUsageTests (void) |
| { |
| } |
| |
| void SingleVertexArrayUsageTests::init (void) |
| { |
| // Test usage |
| Array::Usage usages[] = { Array::USAGE_STATIC_DRAW, Array::USAGE_STREAM_DRAW, Array::USAGE_DYNAMIC_DRAW, Array::USAGE_STATIC_COPY, Array::USAGE_STREAM_COPY, Array::USAGE_DYNAMIC_COPY, Array::USAGE_STATIC_READ, Array::USAGE_STREAM_READ, Array::USAGE_DYNAMIC_READ }; |
| for (int usageNdx = 0; usageNdx < DE_LENGTH_OF_ARRAY(usages); usageNdx++) |
| { |
| addChild(new SingleVertexArrayUsageGroup(m_context, usages[usageNdx])); |
| } |
| } |
| |
| class SingleVertexArrayStrideGroup : public TestCaseGroup |
| { |
| public: |
| SingleVertexArrayStrideGroup (Context& context, Array::InputType type); |
| virtual ~SingleVertexArrayStrideGroup (void); |
| |
| virtual void init (void); |
| |
| private: |
| SingleVertexArrayStrideGroup (const SingleVertexArrayStrideGroup& other); |
| SingleVertexArrayStrideGroup& operator= (const SingleVertexArrayStrideGroup& other); |
| |
| Array::InputType m_type; |
| }; |
| |
| SingleVertexArrayStrideGroup::SingleVertexArrayStrideGroup (Context& context, Array::InputType type) |
| : TestCaseGroup (context, Array::inputTypeToString(type).c_str(), Array::inputTypeToString(type).c_str()) |
| , m_type (type) |
| { |
| } |
| |
| SingleVertexArrayStrideGroup::~SingleVertexArrayStrideGroup (void) |
| { |
| } |
| |
| void SingleVertexArrayStrideGroup::init (void) |
| { |
| Array::Storage storages[] = {Array::STORAGE_USER, Array::STORAGE_BUFFER}; |
| int counts[] = {1, 256}; |
| int strides[] = {/*0,*/ -1, 17, 32}; // Tread negative value as sizeof input. Same as 0, but done outside of GL. |
| |
| for (int storageNdx = 0; storageNdx < DE_LENGTH_OF_ARRAY(storages); storageNdx++) |
| { |
| for (int componentCount = 2; componentCount < 5; componentCount++) |
| { |
| for (int countNdx = 0; countNdx < DE_LENGTH_OF_ARRAY(counts); countNdx++) |
| { |
| for (int strideNdx = 0; strideNdx < DE_LENGTH_OF_ARRAY(strides); strideNdx++) |
| { |
| const bool packed = m_type == Array::INPUTTYPE_UNSIGNED_INT_2_10_10_10 || m_type == Array::INPUTTYPE_INT_2_10_10_10; |
| const int stride = (strides[strideNdx] < 0) ? ((packed) ? (16) : (Array::inputTypeSize(m_type) * componentCount)) : (strides[strideNdx]); |
| const int alignment = (packed) ? (Array::inputTypeSize(m_type) * componentCount) : (Array::inputTypeSize(m_type)); |
| const bool bufferUnaligned = (storages[storageNdx] == Array::STORAGE_BUFFER) && (stride % alignment) != 0; |
| |
| std::string name = Array::storageToString(storages[storageNdx]) + "_stride" + typeToString(stride) + "_components" + typeToString(componentCount) + "_quads" + typeToString(counts[countNdx]); |
| |
| if((m_type == Array::INPUTTYPE_UNSIGNED_INT_2_10_10_10 || m_type == Array::INPUTTYPE_INT_2_10_10_10) && componentCount != 4) |
| continue; |
| |
| MultiVertexArrayTest::Spec::ArraySpec arraySpec(m_type, |
| Array::OUTPUTTYPE_VEC4, |
| storages[storageNdx], |
| Array::USAGE_DYNAMIC_DRAW, |
| componentCount, |
| 0, |
| stride, |
| false, |
| GLValue::getMinValue(m_type), |
| GLValue::getMaxValue(m_type)); |
| |
| MultiVertexArrayTest::Spec spec; |
| spec.primitive = Array::PRIMITIVE_TRIANGLES; |
| spec.drawCount = counts[countNdx]; |
| spec.first = 0; |
| spec.arrays.push_back(arraySpec); |
| |
| if (bufferUnaligned) |
| addChild(new MultiVertexArrayTest(m_testCtx, m_context.getRenderContext(), spec, name.c_str(), name.c_str())); |
| } |
| } |
| } |
| } |
| } |
| |
| class SingleVertexArrayStrideTests : public TestCaseGroup |
| { |
| public: |
| SingleVertexArrayStrideTests (Context& context); |
| virtual ~SingleVertexArrayStrideTests (void); |
| |
| virtual void init (void); |
| |
| private: |
| SingleVertexArrayStrideTests (const SingleVertexArrayStrideTests& other); |
| SingleVertexArrayStrideTests& operator= (const SingleVertexArrayStrideTests& other); |
| }; |
| |
| SingleVertexArrayStrideTests::SingleVertexArrayStrideTests (Context& context) |
| : TestCaseGroup(context, "strides", "Single stride vertex atribute") |
| { |
| } |
| |
| SingleVertexArrayStrideTests::~SingleVertexArrayStrideTests (void) |
| { |
| } |
| |
| void SingleVertexArrayStrideTests::init (void) |
| { |
| Array::InputType inputTypes[] = {Array::INPUTTYPE_FLOAT, Array::INPUTTYPE_SHORT, /*Array::INPUTTYPE_UNSIGNED_SHORT, Array::INPUTTYPE_UNSIGNED_BYTE,*/ Array::INPUTTYPE_FIXED, Array::INPUTTYPE_INT_2_10_10_10 }; |
| |
| for (int inputTypeNdx = 0; inputTypeNdx < DE_LENGTH_OF_ARRAY(inputTypes); inputTypeNdx++) |
| { |
| addChild(new SingleVertexArrayStrideGroup(m_context, inputTypes[inputTypeNdx])); |
| } |
| } |
| |
| class SingleVertexArrayFirstGroup : public TestCaseGroup |
| { |
| public: |
| SingleVertexArrayFirstGroup (Context& context, Array::InputType type); |
| virtual ~SingleVertexArrayFirstGroup (void); |
| |
| virtual void init (void); |
| |
| private: |
| SingleVertexArrayFirstGroup (const SingleVertexArrayFirstGroup& other); |
| SingleVertexArrayFirstGroup& operator= (const SingleVertexArrayFirstGroup& other); |
| Array::InputType m_type; |
| }; |
| |
| SingleVertexArrayFirstGroup::SingleVertexArrayFirstGroup (Context& context, Array::InputType type) |
| : TestCaseGroup (context, Array::inputTypeToString(type).c_str(), Array::inputTypeToString(type).c_str()) |
| , m_type (type) |
| { |
| } |
| |
| SingleVertexArrayFirstGroup::~SingleVertexArrayFirstGroup (void) |
| { |
| } |
| |
| void SingleVertexArrayFirstGroup::init (void) |
| { |
| int counts[] = {5, 256}; |
| int firsts[] = {6, 24}; |
| int offsets[] = {1, 17}; |
| int strides[] = {/*0,*/ -1, 17, 32}; // Tread negative value as sizeof input. Same as 0, but done outside of GL. |
| |
| for (int offsetNdx = 0; offsetNdx < DE_LENGTH_OF_ARRAY(offsets); offsetNdx++) |
| { |
| for (int countNdx = 0; countNdx < DE_LENGTH_OF_ARRAY(counts); countNdx++) |
| { |
| for (int strideNdx = 0; strideNdx < DE_LENGTH_OF_ARRAY(strides); strideNdx++) |
| { |
| for (int firstNdx = 0; firstNdx < DE_LENGTH_OF_ARRAY(firsts); firstNdx++) |
| { |
| const bool packed = m_type == Array::INPUTTYPE_UNSIGNED_INT_2_10_10_10 || m_type == Array::INPUTTYPE_INT_2_10_10_10; |
| const int componentCount = (packed) ? (4) : (2); |
| const int stride = (strides[strideNdx] < 0) ? ((packed) ? (8) : (Array::inputTypeSize(m_type) * componentCount)) : (strides[strideNdx]); |
| const int alignment = (packed) ? (Array::inputTypeSize(m_type) * componentCount) : (Array::inputTypeSize(m_type)); |
| const bool aligned = ((stride % alignment) == 0) && ((offsets[offsetNdx] % alignment) == 0); |
| std::string name = "first" + typeToString(firsts[firstNdx]) + "_offset" + typeToString(offsets[offsetNdx]) + "_stride" + typeToString(stride) + "_quads" + typeToString(counts[countNdx]); |
| |
| MultiVertexArrayTest::Spec::ArraySpec arraySpec(m_type, |
| Array::OUTPUTTYPE_VEC2, |
| Array::STORAGE_BUFFER, |
| Array::USAGE_DYNAMIC_DRAW, |
| componentCount, |
| offsets[offsetNdx], |
| stride, |
| false, |
| GLValue::getMinValue(m_type), |
| GLValue::getMaxValue(m_type)); |
| |
| MultiVertexArrayTest::Spec spec; |
| spec.primitive = Array::PRIMITIVE_TRIANGLES; |
| spec.drawCount = counts[countNdx]; |
| spec.first = firsts[firstNdx]; |
| spec.arrays.push_back(arraySpec); |
| |
| if (!aligned) |
| addChild(new MultiVertexArrayTest(m_testCtx, m_context.getRenderContext(), spec, name.c_str(), name.c_str())); |
| } |
| } |
| } |
| } |
| } |
| |
| class SingleVertexArrayFirstTests : public TestCaseGroup |
| { |
| public: |
| SingleVertexArrayFirstTests (Context& context); |
| virtual ~SingleVertexArrayFirstTests (void); |
| |
| virtual void init (void); |
| |
| private: |
| SingleVertexArrayFirstTests (const SingleVertexArrayFirstTests& other); |
| SingleVertexArrayFirstTests& operator= (const SingleVertexArrayFirstTests& other); |
| }; |
| |
| SingleVertexArrayFirstTests::SingleVertexArrayFirstTests (Context& context) |
| : TestCaseGroup(context, "first", "Single vertex attribute, different first values to drawArrays") |
| { |
| } |
| |
| SingleVertexArrayFirstTests::~SingleVertexArrayFirstTests (void) |
| { |
| } |
| |
| void SingleVertexArrayFirstTests::init (void) |
| { |
| // Test offset with different input types, component counts and storage, Usage(?) |
| Array::InputType inputTypes[] = {Array::INPUTTYPE_FLOAT, Array::INPUTTYPE_INT_2_10_10_10 }; |
| |
| for (int inputTypeNdx = 0; inputTypeNdx < DE_LENGTH_OF_ARRAY(inputTypes); inputTypeNdx++) |
| { |
| addChild(new SingleVertexArrayFirstGroup(m_context, inputTypes[inputTypeNdx])); |
| } |
| } |
| |
| class SingleVertexArrayOffsetGroup : public TestCaseGroup |
| { |
| public: |
| SingleVertexArrayOffsetGroup (Context& context, Array::InputType type); |
| virtual ~SingleVertexArrayOffsetGroup (void); |
| |
| virtual void init (void); |
| |
| private: |
| SingleVertexArrayOffsetGroup (const SingleVertexArrayOffsetGroup& other); |
| SingleVertexArrayOffsetGroup& operator= (const SingleVertexArrayOffsetGroup& other); |
| Array::InputType m_type; |
| }; |
| |
| SingleVertexArrayOffsetGroup::SingleVertexArrayOffsetGroup (Context& context, Array::InputType type) |
| : TestCaseGroup (context, Array::inputTypeToString(type).c_str(), Array::inputTypeToString(type).c_str()) |
| , m_type (type) |
| { |
| } |
| |
| SingleVertexArrayOffsetGroup::~SingleVertexArrayOffsetGroup (void) |
| { |
| } |
| |
| void SingleVertexArrayOffsetGroup::init (void) |
| { |
| int counts[] = {1, 256}; |
| int offsets[] = {1, 4, 17, 32}; |
| int strides[] = {/*0,*/ -1, 17, 32}; // Tread negative value as sizeof input. Same as 0, but done outside of GL. |
| |
| for (int offsetNdx = 0; offsetNdx < DE_LENGTH_OF_ARRAY(offsets); offsetNdx++) |
| { |
| for (int countNdx = 0; countNdx < DE_LENGTH_OF_ARRAY(counts); countNdx++) |
| { |
| for (int strideNdx = 0; strideNdx < DE_LENGTH_OF_ARRAY(strides); strideNdx++) |
| { |
| const bool packed = m_type == Array::INPUTTYPE_UNSIGNED_INT_2_10_10_10 || m_type == Array::INPUTTYPE_INT_2_10_10_10; |
| const int componentCount = (packed) ? (4) : (2); |
| const int stride = (strides[strideNdx] < 0 ? Array::inputTypeSize(m_type) * componentCount : strides[strideNdx]); |
| const int alignment = (packed) ? (Array::inputTypeSize(m_type) * componentCount) : (Array::inputTypeSize(m_type)); |
| const bool aligned = ((stride % alignment) == 0) && ((offsets[offsetNdx] % alignment) == 0); |
| const std::string name = "offset" + typeToString(offsets[offsetNdx]) + "_stride" + typeToString(strides[strideNdx]) + "_quads" + typeToString(counts[countNdx]); |
| |
| MultiVertexArrayTest::Spec::ArraySpec arraySpec(m_type, |
| Array::OUTPUTTYPE_VEC2, |
| Array::STORAGE_BUFFER, |
| Array::USAGE_DYNAMIC_DRAW, |
| componentCount, |
| offsets[offsetNdx], |
| stride, |
| false, |
| GLValue::getMinValue(m_type), |
| GLValue::getMaxValue(m_type)); |
| |
| MultiVertexArrayTest::Spec spec; |
| spec.primitive = Array::PRIMITIVE_TRIANGLES; |
| spec.drawCount = counts[countNdx]; |
| spec.first = 0; |
| spec.arrays.push_back(arraySpec); |
| |
| if (!aligned) |
| addChild(new MultiVertexArrayTest(m_testCtx, m_context.getRenderContext(), spec, name.c_str(), name.c_str())); |
| } |
| } |
| } |
| } |
| |
| class SingleVertexArrayOffsetTests : public TestCaseGroup |
| { |
| public: |
| SingleVertexArrayOffsetTests (Context& context); |
| virtual ~SingleVertexArrayOffsetTests (void); |
| |
| virtual void init (void); |
| |
| private: |
| SingleVertexArrayOffsetTests (const SingleVertexArrayOffsetTests& other); |
| SingleVertexArrayOffsetTests& operator= (const SingleVertexArrayOffsetTests& other); |
| }; |
| |
| SingleVertexArrayOffsetTests::SingleVertexArrayOffsetTests (Context& context) |
| : TestCaseGroup(context, "offset", "Single vertex atribute offset element") |
| { |
| } |
| |
| SingleVertexArrayOffsetTests::~SingleVertexArrayOffsetTests (void) |
| { |
| } |
| |
| void SingleVertexArrayOffsetTests::init (void) |
| { |
| // Test offset with different input types, component counts and storage, Usage(?) |
| Array::InputType inputTypes[] = {Array::INPUTTYPE_FLOAT, Array::INPUTTYPE_INT_2_10_10_10 }; |
| |
| for (int inputTypeNdx = 0; inputTypeNdx < DE_LENGTH_OF_ARRAY(inputTypes); inputTypeNdx++) |
| { |
| addChild(new SingleVertexArrayOffsetGroup(m_context, inputTypes[inputTypeNdx])); |
| } |
| } |
| |
| } // anonymous |
| |
| VertexArrayTests::VertexArrayTests (Context& context) |
| : TestCaseGroup(context, "vertex_arrays", "Vertex array and array tests") |
| { |
| } |
| |
| VertexArrayTests::~VertexArrayTests (void) |
| { |
| } |
| |
| void VertexArrayTests::init (void) |
| { |
| tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "single_attribute", "Single attribute"); |
| addChild(group); |
| |
| // .single_attribute |
| { |
| group->addChild(new SingleVertexArrayStrideTests(m_context)); |
| group->addChild(new SingleVertexArrayUsageTests(m_context)); |
| group->addChild(new SingleVertexArrayOffsetTests(m_context)); |
| group->addChild(new SingleVertexArrayFirstTests(m_context)); |
| } |
| } |
| |
| } // Stress |
| } // gles3 |
| } // deqp |