blob: c2d74601c01cbfb2fc11874c74b31a8512dd1809 [file] [log] [blame] [edit]
#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;
} // namespace LongStressCaseInternal
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
{
glu::TextureTestUtil::TextureType textureType;
uint32_t textureUnit;
int width;
int height;
uint32_t format;
uint32_t dataType;
uint32_t internalFormat;
bool useMipmap;
uint32_t minFilter;
uint32_t magFilter;
uint32_t sWrap;
uint32_t tWrap;
tcu::Vec4 minValue;
tcu::Vec4 maxValue;
TextureSpec(const glu::TextureTestUtil::TextureType texType, const uint32_t unit, const int width_,
const int height_, const uint32_t format_, const uint32_t dataType_, const uint32_t internalFormat_,
const bool useMipmap_, const uint32_t minFilter_, const uint32_t magFilter_, const uint32_t sWrap_,
const uint32_t 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,
uint32_t indexBufferUsage, uint32_t 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 uint32_t m_indexBufferUsage;
const uint32_t 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;
uint64_t m_startTimeSeconds; //!< Set at beginning of first iteration.
uint64_t 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<uint16_t> m_vertexIndices;
struct ProgramResources
{
std::vector<uint8_t> attrDataBuf;
std::vector<int> attrDataOffsets;
std::vector<int> attrDataSizes;
std::vector<de::SharedPtr<tcu::TextureLevel>> unusedTextures;
std::string shaderNameManglingSuffix;
};
std::vector<ProgramResources> m_programResources;
LongStressCaseInternal::DebugInfoRenderer *m_debugInfoRenderer;
};
} // namespace gls
} // namespace deqp
#endif // _GLSLONGSTRESSCASE_HPP