#ifndef _GLSLONGSTRESSCASE_HPP #define _GLSLONGSTRESSCASE_HPP /*------------------------------------------------------------------------- * drawElements Quality Program OpenGL (ES) 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 Parametrized, long-running stress case. *//*--------------------------------------------------------------------*/ #include "tcuDefs.hpp" #include "tcuTestCase.hpp" #include "tcuTexture.hpp" #include "tcuMatrix.hpp" #include "gluRenderContext.hpp" #include "gluShaderUtil.hpp" #include "glsTextureTestUtil.hpp" #include "deRandom.hpp" #include "deSharedPtr.hpp" #include <string> #include <vector> #include <map> namespace deqp { namespace gls { namespace LongStressCaseInternal { template <typename T> class GLObjectManager; class Program; class Buffer; class Texture; class DebugInfoRenderer; } struct VarSpec { union Value { float f[4*4]; // \note Matrices are stored in column major order. int i[4]; }; std::string name; glu::DataType type; Value minValue; Value maxValue; template <typename T> VarSpec (const std::string& name_, const T& minValue_, const T& maxValue_) : name(name_) { set(minValue_, maxValue_); } template <typename T> VarSpec (const std::string& name_, const T& value) : name(name_) { set(value, value); } void set (float minValue_, float maxValue_) { type = glu::TYPE_FLOAT; minValue.f[0] = minValue_; maxValue.f[0] = maxValue_; } template <int ValSize> void set (const tcu::Vector<float, ValSize>& minValue_, const tcu::Vector<float, ValSize>& maxValue_) { type = glu::getDataTypeFloatVec(ValSize); vecToArr(minValue_, minValue.f); vecToArr(maxValue_, maxValue.f); } template <int ValRows, int ValCols> void set (const tcu::Matrix<float, ValRows, ValCols>& minValue_, const tcu::Matrix<float, ValRows, ValCols>& maxValue_) { type = glu::getDataTypeMatrix(ValCols, ValRows); matToArr(minValue_, minValue.f); matToArr(maxValue_, maxValue.f); } void set (int minValue_, int maxValue_) { type = glu::TYPE_INT; minValue.i[0] = minValue_; maxValue.i[0] = maxValue_; } template <int ValSize> void set (const tcu::Vector<int, ValSize>& minValue_, const tcu::Vector<int, ValSize>& maxValue_) { type = glu::getDataTypeVector(glu::TYPE_INT, ValSize); vecToArr(minValue_, minValue.i); vecToArr(maxValue_, maxValue.i); } private: template <typename T, int SrcSize, int DstSize> static inline void vecToArr (const tcu::Vector<T, SrcSize>& src, T (&dst)[DstSize]) { DE_STATIC_ASSERT(DstSize >= SrcSize); for (int i = 0; i < SrcSize; i++) dst[i] = src[i]; } template <int ValRows, int ValCols, int DstSize> static inline void matToArr (const tcu::Matrix<float, ValRows, ValCols>& src, float (&dst)[DstSize]) { DE_STATIC_ASSERT(DstSize >= ValRows*ValCols); tcu::Array<float, ValRows*ValCols> data = src.getColumnMajorData(); for (int i = 0; i < ValRows*ValCols; i++) dst[i] = data[i]; } }; struct TextureSpec { gls::TextureTestUtil::TextureType textureType; deUint32 textureUnit; int width; int height; deUint32 format; deUint32 dataType; deUint32 internalFormat; bool useMipmap; deUint32 minFilter; deUint32 magFilter; deUint32 sWrap; deUint32 tWrap; tcu::Vec4 minValue; tcu::Vec4 maxValue; TextureSpec (const gls::TextureTestUtil::TextureType texType, const deUint32 unit, const int width_, const int height_, const deUint32 format_, const deUint32 dataType_, const deUint32 internalFormat_, const bool useMipmap_, const deUint32 minFilter_, const deUint32 magFilter_, const deUint32 sWrap_, const deUint32 tWrap_, const tcu::Vec4& minValue_, const tcu::Vec4& maxValue_) : textureType (texType) , textureUnit (unit) , width (width_) , height (height_) , format (format_) , dataType (dataType_) , internalFormat (internalFormat_) , useMipmap (useMipmap_) , minFilter (minFilter_) , magFilter (magFilter_) , sWrap (sWrap_) , tWrap (tWrap_) , minValue (minValue_) , maxValue (maxValue_) { } }; /*--------------------------------------------------------------------*//*! * \brief Struct for a shader program sources and related data * * A ProgramContext holds a program's vertex and fragment shader sources * as well as specifications of its attributes, uniforms, and textures. * When given to a StressCase, the string ${NS} is replaced by a magic * number that varies between different compilations of the same program; * the same replacement is done in attributes' and uniforms' names. This * can be used to avoid shader caching by the GL, by e.g. suffixing each * attribute, uniform and varying name with ${NS} in the shader source. *//*--------------------------------------------------------------------*/ struct ProgramContext { std::string vertexSource; std::string fragmentSource; std::vector<VarSpec> attributes; std::vector<VarSpec> uniforms; std::vector<TextureSpec> textureSpecs; //!< \note If multiple textures have same unit, one of them is picked randomly. std::string positionAttrName; //!< \note Position attribute may get a bit more careful handling than just complete random. ProgramContext (const char* const vtxShaderSource_, const char* const fragShaderSource_, const char* const positionAttrName_) : vertexSource (vtxShaderSource_) , fragmentSource (fragShaderSource_) , positionAttrName (positionAttrName_) { } }; class LongStressCase : public tcu::TestCase { public: //! Probabilities for actions that may be taken on each iteration. \note The texture and buffer specific actions are randomized per texture or buffer. struct FeatureProbabilities { float rebuildProgram; //!< Rebuild program, with variable name-mangling. float reuploadTexture; //!< Reupload texture, even if it already exists and has been uploaded. float reuploadBuffer; //!< Reupload buffer, even if it already exists and has been uploaded. float reuploadWithTexImage; //!< Use glTexImage*() when re-uploading texture, not glTexSubImage*(). float reuploadWithBufferData; //!< Use glBufferData() when re-uploading buffer, not glBufferSubData(). float deleteTexture; //!< Delete texture at end of iteration, even if we could re-use it. float deleteBuffer; //!< Delete buffer at end of iteration, even if we could re-use it. float wastefulTextureMemoryUsage; //!< Don't re-use a texture, and don't delete it until given memory limit is hit. float wastefulBufferMemoryUsage; //!< Don't re-use a buffer, and don't delete it until given memory limit is hit. float clientMemoryAttributeData; //!< Use client memory for vertex attribute data when drawing (instead of GL buffers). float clientMemoryIndexData; //!< Use client memory for vertex indices when drawing (instead of GL buffers). float randomBufferUploadTarget; //!< Use a random target when setting buffer data (i.e. not necessarily the one it'll be ultimately bound to). float randomBufferUsage; //!< Use a random buffer usage parameter with glBufferData(), instead of the ones specified as params for the case. float useDrawArrays; //!< Use glDrawArrays() instead of glDrawElements(). float separateAttributeBuffers; //!< Give each vertex attribute its own buffer. // Named parameter idiom: helpers that can be used when making temporaries, e.g. FeatureProbabilities().pReuploadTexture(1.0f).pReuploadWithTexImage(1.0f) FeatureProbabilities& pRebuildProgram (const float prob) { rebuildProgram = prob; return *this; } FeatureProbabilities& pReuploadTexture (const float prob) { reuploadTexture = prob; return *this; } FeatureProbabilities& pReuploadBuffer (const float prob) { reuploadBuffer = prob; return *this; } FeatureProbabilities& pReuploadWithTexImage (const float prob) { reuploadWithTexImage = prob; return *this; } FeatureProbabilities& pReuploadWithBufferData (const float prob) { reuploadWithBufferData = prob; return *this; } FeatureProbabilities& pDeleteTexture (const float prob) { deleteTexture = prob; return *this; } FeatureProbabilities& pDeleteBuffer (const float prob) { deleteBuffer = prob; return *this; } FeatureProbabilities& pWastefulTextureMemoryUsage (const float prob) { wastefulTextureMemoryUsage = prob; return *this; } FeatureProbabilities& pWastefulBufferMemoryUsage (const float prob) { wastefulBufferMemoryUsage = prob; return *this; } FeatureProbabilities& pClientMemoryAttributeData (const float prob) { clientMemoryAttributeData = prob; return *this; } FeatureProbabilities& pClientMemoryIndexData (const float prob) { clientMemoryIndexData = prob; return *this; } FeatureProbabilities& pRandomBufferUploadTarget (const float prob) { randomBufferUploadTarget = prob; return *this; } FeatureProbabilities& pRandomBufferUsage (const float prob) { randomBufferUsage = prob; return *this; } FeatureProbabilities& pUseDrawArrays (const float prob) { useDrawArrays = prob; return *this; } FeatureProbabilities& pSeparateAttribBuffers (const float prob) { separateAttributeBuffers = prob; return *this; } FeatureProbabilities (void) : rebuildProgram (0.0f) , reuploadTexture (0.0f) , reuploadBuffer (0.0f) , reuploadWithTexImage (0.0f) , reuploadWithBufferData (0.0f) , deleteTexture (0.0f) , deleteBuffer (0.0f) , wastefulTextureMemoryUsage (0.0f) , wastefulBufferMemoryUsage (0.0f) , clientMemoryAttributeData (0.0f) , clientMemoryIndexData (0.0f) , randomBufferUploadTarget (0.0f) , randomBufferUsage (0.0f) , useDrawArrays (0.0f) , separateAttributeBuffers (0.0f) { } }; LongStressCase (tcu::TestContext& testCtx, const glu::RenderContext& renderCtx, const char* name, const char* desc, int maxTexMemoryUsageBytes, //!< Approximate upper bound on GL texture memory usage. int maxBufMemoryUsageBytes, //!< Approximate upper bound on GL buffer memory usage. int numDrawCallsPerIteration, int numTrianglesPerDrawCall, const std::vector<ProgramContext>& programContexts, const FeatureProbabilities& probabilities, deUint32 indexBufferUsage, deUint32 attrBufferUsage, int redundantBufferFactor = 1, bool showDebugInfo = false); ~LongStressCase (void); void init (void); void deinit (void); IterateResult iterate (void); private: LongStressCase (const LongStressCase&); LongStressCase& operator= (const LongStressCase&); const glu::RenderContext& m_renderCtx; const int m_maxTexMemoryUsageBytes; const int m_maxBufMemoryUsageBytes; const int m_numDrawCallsPerIteration; const int m_numTrianglesPerDrawCall; const int m_numVerticesPerDrawCall; const std::vector<ProgramContext> m_programContexts; const FeatureProbabilities m_probabilities; const deUint32 m_indexBufferUsage; const deUint32 m_attrBufferUsage; const int m_redundantBufferFactor; //!< By what factor we allocate redundant buffers. Default is 1, i.e. no redundancy. const bool m_showDebugInfo; const int m_numIterations; const bool m_isGLES3; int m_currentIteration; deUint64 m_startTimeSeconds; //!< Set at beginning of first iteration. deUint64 m_lastLogTime; int m_lastLogIteration; int m_currentLogEntryNdx; de::Random m_rnd; LongStressCaseInternal::GLObjectManager< LongStressCaseInternal::Program>* m_programs; LongStressCaseInternal::GLObjectManager< LongStressCaseInternal::Buffer>* m_buffers; LongStressCaseInternal::GLObjectManager< LongStressCaseInternal::Texture>* m_textures; std::vector<deUint16> m_vertexIndices; struct ProgramResources { std::vector<deUint8> attrDataBuf; std::vector<int> attrDataOffsets; std::vector<int> attrDataSizes; std::vector<de::SharedPtr<tcu::TextureLevel> > dummyTextures; std::string shaderNameManglingSuffix; }; std::vector<ProgramResources> m_programResources; LongStressCaseInternal::DebugInfoRenderer* m_debugInfoRenderer; }; } // gls } // deqp #endif // _GLSLONGSTRESSCASE_HPP