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.
946 lines
24 KiB
946 lines
24 KiB
/*-------------------------------------------------------------------------
|
|
* 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 Memory object stress test
|
|
*//*--------------------------------------------------------------------*/
|
|
|
|
#include "glsMemoryStressCase.hpp"
|
|
#include "gluShaderProgram.hpp"
|
|
#include "tcuTestLog.hpp"
|
|
#include "tcuCommandLine.hpp"
|
|
#include "deRandom.hpp"
|
|
#include "deClock.h"
|
|
#include "deString.h"
|
|
|
|
#include "glw.h"
|
|
|
|
#include <vector>
|
|
#include <iostream>
|
|
|
|
using std::vector;
|
|
using tcu::TestLog;
|
|
|
|
namespace deqp
|
|
{
|
|
namespace gls
|
|
{
|
|
|
|
static const char* glErrorToString (deUint32 error)
|
|
{
|
|
switch (error)
|
|
{
|
|
case GL_OUT_OF_MEMORY:
|
|
return "GL_OUT_OF_MEMORY";
|
|
break;
|
|
|
|
case GL_INVALID_ENUM:
|
|
return "GL_INVALID_ENUM";
|
|
break;
|
|
|
|
case GL_INVALID_FRAMEBUFFER_OPERATION:
|
|
return "GL_INVALID_FRAMEBUFFER_OPERATION";
|
|
break;
|
|
|
|
case GL_INVALID_OPERATION:
|
|
return "GL_INVALID_OPERATION";
|
|
break;
|
|
|
|
case GL_INVALID_VALUE:
|
|
return "GL_INVALID_VALUE";
|
|
break;
|
|
|
|
case 0:
|
|
return "<none>";
|
|
break;
|
|
|
|
default:
|
|
// \todo [mika] Handle uknown errors?
|
|
DE_ASSERT(false);
|
|
return NULL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static const float s_quadCoords[] =
|
|
{
|
|
-1.0f, -1.0f,
|
|
1.0f, -1.0f,
|
|
1.0f, 1.0f,
|
|
-1.0f, 1.0f
|
|
};
|
|
|
|
static const GLubyte s_quadIndices[] =
|
|
{
|
|
0, 1, 2,
|
|
2, 3, 0
|
|
};
|
|
|
|
class TextureRenderer
|
|
{
|
|
public:
|
|
TextureRenderer (tcu::TestLog& log, glu::RenderContext& renderContext);
|
|
~TextureRenderer (void);
|
|
void render (deUint32 texture);
|
|
|
|
private:
|
|
glu::ShaderProgram* m_program;
|
|
glu::RenderContext& m_renderCtx;
|
|
|
|
deUint32 m_coordBuffer;
|
|
deUint32 m_indexBuffer;
|
|
deUint32 m_vao;
|
|
|
|
static const char* s_vertexShaderGLES2;
|
|
static const char* s_fragmentShaderGLES2;
|
|
|
|
static const char* s_vertexShaderGLES3;
|
|
static const char* s_fragmentShaderGLES3;
|
|
|
|
static const char* s_vertexShaderGL3;
|
|
static const char* s_fragmentShaderGL3;
|
|
};
|
|
|
|
const char* TextureRenderer::s_vertexShaderGLES2 =
|
|
"attribute mediump vec2 a_coord;\n"
|
|
"varying mediump vec2 v_texCoord;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
"\tv_texCoord = 0.5 * (a_coord + vec2(1.0));\n"
|
|
"\tgl_Position = vec4(a_coord, 0.0, 1.0);\n"
|
|
"}\n";
|
|
|
|
const char* TextureRenderer::s_fragmentShaderGLES2 =
|
|
"varying mediump vec2 v_texCoord;\n"
|
|
"uniform sampler2D u_texture;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
"\tgl_FragColor = texture2D(u_texture, v_texCoord);\n"
|
|
"}\n";
|
|
|
|
const char* TextureRenderer::s_vertexShaderGLES3 =
|
|
"#version 300 es\n"
|
|
"in mediump vec2 a_coord;\n"
|
|
"out mediump vec2 v_texCoord;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
"\tv_texCoord = 0.5 * (a_coord + vec2(1.0));\n"
|
|
"\tgl_Position = vec4(a_coord, 0.0, 1.0);\n"
|
|
"}\n";
|
|
|
|
const char* TextureRenderer::s_fragmentShaderGLES3 =
|
|
"#version 300 es\n"
|
|
"in mediump vec2 v_texCoord;\n"
|
|
"uniform sampler2D u_texture;\n"
|
|
"layout(location = 0) out mediump vec4 dEQP_FragColor;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
"\tdEQP_FragColor = texture(u_texture, v_texCoord);\n"
|
|
"}\n";
|
|
|
|
const char* TextureRenderer::s_vertexShaderGL3 =
|
|
"#version 330\n"
|
|
"in mediump vec2 a_coord;\n"
|
|
"out mediump vec2 v_texCoord;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
"\tv_texCoord = 0.5 * (a_coord + vec2(1.0));\n"
|
|
"\tgl_Position = vec4(a_coord, 0.0, 1.0);\n"
|
|
"}\n";
|
|
|
|
const char* TextureRenderer::s_fragmentShaderGL3 =
|
|
"#version 330\n"
|
|
"in mediump vec2 v_texCoord;\n"
|
|
"uniform sampler2D u_texture;\n"
|
|
"layout(location = 0) out mediump vec4 dEQP_FragColor;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
"\tdEQP_FragColor = texture(u_texture, v_texCoord);\n"
|
|
"}\n";
|
|
|
|
TextureRenderer::TextureRenderer (tcu::TestLog& log, glu::RenderContext& renderContext)
|
|
: m_program (NULL)
|
|
, m_renderCtx (renderContext)
|
|
, m_coordBuffer (0)
|
|
, m_indexBuffer (0)
|
|
, m_vao (0)
|
|
{
|
|
const glu::ContextType ctxType = renderContext.getType();
|
|
|
|
if (glu::isGLSLVersionSupported(ctxType, glu::GLSL_VERSION_300_ES))
|
|
m_program = new glu::ShaderProgram(m_renderCtx, glu::makeVtxFragSources(s_vertexShaderGLES3, s_fragmentShaderGLES3));
|
|
else if (glu::isGLSLVersionSupported(ctxType, glu::GLSL_VERSION_100_ES))
|
|
m_program = new glu::ShaderProgram(m_renderCtx, glu::makeVtxFragSources(s_vertexShaderGLES2, s_fragmentShaderGLES2));
|
|
else if (glu::isGLSLVersionSupported(ctxType, glu::GLSL_VERSION_330))
|
|
m_program = new glu::ShaderProgram(m_renderCtx, glu::makeVtxFragSources(s_vertexShaderGL3, s_fragmentShaderGL3));
|
|
else
|
|
DE_ASSERT(false);
|
|
|
|
if (ctxType.getProfile() == glu::PROFILE_CORE)
|
|
GLU_CHECK_CALL(glGenVertexArrays(1, &m_vao));
|
|
|
|
GLU_CHECK_CALL(glGenBuffers(1, &m_coordBuffer));
|
|
GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, m_coordBuffer));
|
|
GLU_CHECK_CALL(glBufferData(GL_ARRAY_BUFFER, sizeof(s_quadCoords), s_quadCoords, GL_STATIC_DRAW));
|
|
|
|
GLU_CHECK_CALL(glGenBuffers(1, &m_indexBuffer));
|
|
GLU_CHECK_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBuffer));
|
|
GLU_CHECK_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(s_quadIndices), s_quadIndices, GL_STATIC_DRAW));
|
|
|
|
if (!m_program->isOk())
|
|
{
|
|
log << *m_program;
|
|
TCU_CHECK_MSG(m_program->isOk(), "Shader compilation failed");
|
|
}
|
|
}
|
|
|
|
TextureRenderer::~TextureRenderer (void)
|
|
{
|
|
delete m_program;
|
|
glDeleteBuffers(1, &m_coordBuffer);
|
|
glDeleteBuffers(1, &m_indexBuffer);
|
|
}
|
|
|
|
void TextureRenderer::render (deUint32 texture)
|
|
{
|
|
deUint32 coordLoc = -1;
|
|
deUint32 texLoc = -1;
|
|
|
|
GLU_CHECK_CALL(glUseProgram(m_program->getProgram()));
|
|
|
|
coordLoc = glGetAttribLocation(m_program->getProgram(), "a_coord");
|
|
GLU_CHECK();
|
|
TCU_CHECK(coordLoc != (deUint32)-1);
|
|
|
|
if (m_vao != 0)
|
|
GLU_CHECK_CALL(glBindVertexArray(m_vao));
|
|
|
|
GLU_CHECK_CALL(glEnableVertexAttribArray(coordLoc));
|
|
|
|
GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, m_coordBuffer));
|
|
GLU_CHECK_CALL(glVertexAttribPointer(coordLoc, 2, GL_FLOAT, GL_FALSE, 0, NULL));
|
|
|
|
GLU_CHECK_CALL(glActiveTexture(GL_TEXTURE0));
|
|
GLU_CHECK_CALL(glBindTexture(GL_TEXTURE_2D, texture));
|
|
|
|
texLoc = glGetUniformLocation(m_program->getProgram(), "u_texture");
|
|
GLU_CHECK();
|
|
TCU_CHECK(texLoc != (deUint32)-1);
|
|
|
|
GLU_CHECK_CALL(glUniform1i(texLoc, 0));
|
|
|
|
GLU_CHECK_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBuffer));
|
|
GLU_CHECK_CALL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, NULL));
|
|
|
|
GLU_CHECK_CALL(glDisableVertexAttribArray(coordLoc));
|
|
|
|
if (m_vao != 0)
|
|
GLU_CHECK_CALL(glBindVertexArray(0));
|
|
}
|
|
|
|
class BufferRenderer
|
|
{
|
|
public:
|
|
BufferRenderer (tcu::TestLog& log, glu::RenderContext& renderContext);
|
|
~BufferRenderer (void);
|
|
void render (deUint32 buffer, int size);
|
|
|
|
private:
|
|
glu::ShaderProgram* m_program;
|
|
glu::RenderContext& m_renderCtx;
|
|
|
|
deUint32 m_coordBuffer;
|
|
deUint32 m_indexBuffer;
|
|
deUint32 m_vao;
|
|
|
|
static const char* s_vertexShaderGLES2;
|
|
static const char* s_fragmentShaderGLES2;
|
|
|
|
static const char* s_vertexShaderGLES3;
|
|
static const char* s_fragmentShaderGLES3;
|
|
|
|
static const char* s_vertexShaderGL3;
|
|
static const char* s_fragmentShaderGL3;
|
|
};
|
|
|
|
const char* BufferRenderer::s_vertexShaderGLES2 =
|
|
"attribute mediump vec2 a_coord;\n"
|
|
"attribute mediump vec4 a_buffer;\n"
|
|
"varying mediump vec4 v_buffer;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
"\tv_buffer = a_buffer;\n"
|
|
"\tgl_Position = vec4(a_coord, 0.0, 1.0);\n"
|
|
"}\n";
|
|
|
|
const char* BufferRenderer::s_fragmentShaderGLES2 =
|
|
"varying mediump vec4 v_buffer;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
"\tgl_FragColor = v_buffer;\n"
|
|
"}\n";
|
|
|
|
const char* BufferRenderer::s_vertexShaderGLES3 =
|
|
"#version 300 es\n"
|
|
"in mediump vec2 a_coord;\n"
|
|
"in mediump vec4 a_buffer;\n"
|
|
"out mediump vec4 v_buffer;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
"\tv_buffer = a_buffer;\n"
|
|
"\tgl_Position = vec4(a_coord, 0.0, 1.0);\n"
|
|
"}\n";
|
|
|
|
const char* BufferRenderer::s_fragmentShaderGLES3 =
|
|
"#version 300 es\n"
|
|
"in mediump vec4 v_buffer;\n"
|
|
"layout(location = 0) out mediump vec4 dEQP_FragColor;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
"\tdEQP_FragColor = v_buffer;\n"
|
|
"}\n";
|
|
|
|
const char* BufferRenderer::s_vertexShaderGL3 =
|
|
"#version 330\n"
|
|
"in mediump vec2 a_coord;\n"
|
|
"in mediump vec4 a_buffer;\n"
|
|
"out mediump vec4 v_buffer;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
"\tv_buffer = a_buffer;\n"
|
|
"\tgl_Position = vec4(a_coord, 0.0, 1.0);\n"
|
|
"}\n";
|
|
|
|
const char* BufferRenderer::s_fragmentShaderGL3 =
|
|
"#version 330\n"
|
|
"in mediump vec4 v_buffer;\n"
|
|
"layout(location = 0) out mediump vec4 dEQP_FragColor;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
"\tdEQP_FragColor = v_buffer;\n"
|
|
"}\n";
|
|
|
|
BufferRenderer::BufferRenderer (tcu::TestLog& log, glu::RenderContext& renderContext)
|
|
: m_program (NULL)
|
|
, m_renderCtx (renderContext)
|
|
, m_coordBuffer (0)
|
|
, m_indexBuffer (0)
|
|
, m_vao (0)
|
|
{
|
|
const glu::ContextType ctxType = renderContext.getType();
|
|
|
|
if (glu::isGLSLVersionSupported(ctxType, glu::GLSL_VERSION_300_ES))
|
|
m_program = new glu::ShaderProgram(m_renderCtx, glu::makeVtxFragSources(s_vertexShaderGLES3, s_fragmentShaderGLES3));
|
|
else if (glu::isGLSLVersionSupported(ctxType, glu::GLSL_VERSION_100_ES))
|
|
m_program = new glu::ShaderProgram(m_renderCtx, glu::makeVtxFragSources(s_vertexShaderGLES2, s_fragmentShaderGLES2));
|
|
else if (glu::isGLSLVersionSupported(ctxType, glu::GLSL_VERSION_330))
|
|
m_program = new glu::ShaderProgram(m_renderCtx, glu::makeVtxFragSources(s_vertexShaderGL3, s_fragmentShaderGL3));
|
|
else
|
|
DE_ASSERT(false);
|
|
|
|
if (ctxType.getProfile() == glu::PROFILE_CORE)
|
|
GLU_CHECK_CALL(glGenVertexArrays(1, &m_vao));
|
|
|
|
GLU_CHECK_CALL(glGenBuffers(1, &m_coordBuffer));
|
|
GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, m_coordBuffer));
|
|
GLU_CHECK_CALL(glBufferData(GL_ARRAY_BUFFER, sizeof(s_quadCoords), s_quadCoords, GL_STATIC_DRAW));
|
|
|
|
GLU_CHECK_CALL(glGenBuffers(1, &m_indexBuffer));
|
|
GLU_CHECK_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBuffer));
|
|
GLU_CHECK_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(s_quadIndices), s_quadIndices, GL_STATIC_DRAW));
|
|
|
|
if (!m_program->isOk())
|
|
{
|
|
log << *m_program;
|
|
TCU_CHECK_MSG(m_program->isOk(), "Shader compilation failed");
|
|
}
|
|
}
|
|
|
|
BufferRenderer::~BufferRenderer (void)
|
|
{
|
|
delete m_program;
|
|
glDeleteBuffers(1, &m_coordBuffer);
|
|
glDeleteBuffers(1, &m_indexBuffer);
|
|
}
|
|
|
|
void BufferRenderer::render (deUint32 buffer, int size)
|
|
{
|
|
DE_UNREF(size);
|
|
DE_ASSERT((size_t)size >= sizeof(GLubyte) * 4 * 6);
|
|
GLU_CHECK_CALL(glUseProgram(m_program->getProgram()));
|
|
|
|
deUint32 bufferLoc = glGetAttribLocation(m_program->getProgram(), "a_buffer");
|
|
TCU_CHECK(bufferLoc != (deUint32)-1);
|
|
|
|
deUint32 coordLoc = glGetAttribLocation(m_program->getProgram(), "a_coord");
|
|
TCU_CHECK(coordLoc != (deUint32)-1);
|
|
|
|
if (m_vao != 0)
|
|
GLU_CHECK_CALL(glBindVertexArray(m_vao));
|
|
|
|
GLU_CHECK_CALL(glEnableVertexAttribArray(bufferLoc));
|
|
GLU_CHECK_CALL(glEnableVertexAttribArray(coordLoc));
|
|
|
|
GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, m_coordBuffer));
|
|
GLU_CHECK_CALL(glVertexAttribPointer(coordLoc, 2, GL_FLOAT, GL_FALSE, 0, NULL));
|
|
|
|
GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, buffer));
|
|
GLU_CHECK_CALL(glVertexAttribPointer(bufferLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0));
|
|
GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, 0));
|
|
|
|
GLU_CHECK_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBuffer));
|
|
GLU_CHECK_CALL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, NULL));
|
|
|
|
GLU_CHECK_CALL(glDisableVertexAttribArray(bufferLoc));
|
|
GLU_CHECK_CALL(glDisableVertexAttribArray(coordLoc));
|
|
|
|
if (m_vao != 0)
|
|
GLU_CHECK_CALL(glBindVertexArray(0));
|
|
}
|
|
|
|
class MemObjectAllocator
|
|
{
|
|
public:
|
|
enum Result
|
|
{
|
|
RESULT_GOT_BAD_ALLOC = 0,
|
|
RESULT_GEN_TEXTURES_FAILED,
|
|
RESULT_GEN_BUFFERS_FAILED,
|
|
RESULT_BUFFER_DATA_FAILED,
|
|
RESULT_BUFFER_SUB_DATA_FAILED,
|
|
RESULT_TEXTURE_IMAGE_FAILED,
|
|
RESULT_TEXTURE_SUB_IMAGE_FAILED,
|
|
RESULT_BIND_TEXTURE_FAILED,
|
|
RESULT_BIND_BUFFER_FAILED,
|
|
RESULT_DELETE_TEXTURES_FAILED,
|
|
RESULT_DELETE_BUFFERS_FAILED,
|
|
RESULT_RENDER_FAILED,
|
|
|
|
RESULT_LAST
|
|
};
|
|
|
|
MemObjectAllocator (tcu::TestLog& log, glu::RenderContext& renderContext, MemObjectType objectTypes, const MemObjectConfig& config, int seed);
|
|
~MemObjectAllocator (void);
|
|
bool allocUntilFailure (void);
|
|
void clearObjects (void);
|
|
Result getResult (void) const { return m_result; }
|
|
deUint32 getGLError (void) const { return m_glError; }
|
|
int getObjectCount (void) const { return m_objectCount; }
|
|
deUint32 getBytes (void) const { return m_bytesRequired; }
|
|
|
|
static const char* resultToString (Result result);
|
|
|
|
private:
|
|
|
|
void allocateTexture (de::Random& rnd);
|
|
void allocateBuffer (de::Random& rnd);
|
|
|
|
vector<deUint32> m_buffers;
|
|
vector<deUint32> m_textures;
|
|
int m_seed;
|
|
int m_objectCount;
|
|
deUint32 m_bytesRequired;
|
|
MemObjectType m_objectTypes;
|
|
Result m_result;
|
|
MemObjectConfig m_config;
|
|
deUint32 m_glError;
|
|
vector<deUint8> m_dummyData;
|
|
BufferRenderer m_bufferRenderer;
|
|
TextureRenderer m_textureRenderer;
|
|
};
|
|
|
|
MemObjectAllocator::MemObjectAllocator (tcu::TestLog& log, glu::RenderContext& renderContext, MemObjectType objectTypes, const MemObjectConfig& config, int seed)
|
|
: m_seed (seed)
|
|
, m_objectCount (0)
|
|
, m_bytesRequired (0)
|
|
, m_objectTypes (objectTypes)
|
|
, m_result (RESULT_LAST)
|
|
, m_config (config)
|
|
, m_glError (0)
|
|
, m_bufferRenderer (log, renderContext)
|
|
, m_textureRenderer (log, renderContext)
|
|
{
|
|
DE_UNREF(renderContext);
|
|
|
|
if (m_config.useDummyData)
|
|
{
|
|
int dummySize = deMax32(m_config.maxBufferSize, m_config.maxTextureSize*m_config.maxTextureSize*4);
|
|
m_dummyData = vector<deUint8>(dummySize);
|
|
}
|
|
else if (m_config.write)
|
|
m_dummyData = vector<deUint8>(128);
|
|
}
|
|
|
|
MemObjectAllocator::~MemObjectAllocator (void)
|
|
{
|
|
}
|
|
|
|
bool MemObjectAllocator::allocUntilFailure (void)
|
|
{
|
|
de::Random rnd(m_seed);
|
|
GLU_CHECK_MSG("Error in init");
|
|
try
|
|
{
|
|
const deUint64 timeoutUs = 10000000; // 10s
|
|
deUint64 beginTimeUs = deGetMicroseconds();
|
|
deUint64 currentTimeUs;
|
|
|
|
do
|
|
{
|
|
GLU_CHECK_MSG("Unkown Error");
|
|
switch (m_objectTypes)
|
|
{
|
|
case MEMOBJECTTYPE_TEXTURE:
|
|
allocateTexture(rnd);
|
|
break;
|
|
|
|
case MEMOBJECTTYPE_BUFFER:
|
|
allocateBuffer(rnd);
|
|
break;
|
|
|
|
default:
|
|
{
|
|
if (rnd.getBool())
|
|
allocateBuffer(rnd);
|
|
else
|
|
allocateTexture(rnd);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (m_result != RESULT_LAST)
|
|
{
|
|
glFinish();
|
|
return true;
|
|
}
|
|
|
|
currentTimeUs = deGetMicroseconds();
|
|
} while (currentTimeUs - beginTimeUs < timeoutUs);
|
|
|
|
// Timeout
|
|
if (currentTimeUs - beginTimeUs >= timeoutUs)
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
catch (const std::bad_alloc&)
|
|
{
|
|
m_result = RESULT_GOT_BAD_ALLOC;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
void MemObjectAllocator::clearObjects (void)
|
|
{
|
|
deUint32 error = 0;
|
|
|
|
if (!m_textures.empty())
|
|
{
|
|
glDeleteTextures((GLsizei)m_textures.size(), &(m_textures[0]));
|
|
error = glGetError();
|
|
if (error != 0)
|
|
{
|
|
m_result = RESULT_DELETE_TEXTURES_FAILED;
|
|
m_glError = error;
|
|
}
|
|
|
|
m_textures.clear();
|
|
}
|
|
|
|
if (!m_buffers.empty())
|
|
{
|
|
glDeleteBuffers((GLsizei)m_buffers.size(), &(m_buffers[0]));
|
|
error = glGetError();
|
|
if (error != 0)
|
|
{
|
|
m_result = RESULT_DELETE_BUFFERS_FAILED;
|
|
m_glError = error;
|
|
}
|
|
|
|
m_buffers.clear();
|
|
}
|
|
}
|
|
|
|
void MemObjectAllocator::allocateTexture (de::Random& rnd)
|
|
{
|
|
const int vectorBlockSize = 128;
|
|
deUint32 tex = 0;
|
|
deUint32 error = 0;
|
|
int width = rnd.getInt(m_config.minTextureSize, m_config.maxTextureSize);
|
|
int height = rnd.getInt(m_config.minTextureSize, m_config.maxTextureSize);
|
|
|
|
glGenTextures(1, &tex);
|
|
error = glGetError();
|
|
if (error != 0)
|
|
{
|
|
m_result = RESULT_GEN_TEXTURES_FAILED;
|
|
m_glError = error;
|
|
return;
|
|
}
|
|
|
|
if (m_textures.size() % vectorBlockSize == 0)
|
|
m_textures.reserve(m_textures.size() + vectorBlockSize);
|
|
|
|
m_textures.push_back(tex);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, tex);
|
|
error = glGetError();
|
|
if (error != 0)
|
|
{
|
|
m_result = RESULT_BIND_TEXTURE_FAILED;
|
|
m_glError = error;
|
|
return;
|
|
}
|
|
|
|
if (m_config.useDummyData)
|
|
{
|
|
DE_ASSERT((int)m_dummyData.size() >= width*height*4);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &(m_dummyData[0]));
|
|
}
|
|
else
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
|
|
|
error = glGetError();
|
|
if (error != 0)
|
|
{
|
|
m_result = RESULT_TEXTURE_IMAGE_FAILED;
|
|
m_glError = error;
|
|
return;
|
|
}
|
|
|
|
if (m_config.write)
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &(m_dummyData[0]));
|
|
|
|
error = glGetError();
|
|
if (error != 0)
|
|
{
|
|
m_result = RESULT_TEXTURE_SUB_IMAGE_FAILED;
|
|
m_glError = error;
|
|
return;
|
|
}
|
|
|
|
if (m_config.use)
|
|
{
|
|
try
|
|
{
|
|
m_textureRenderer.render(tex);
|
|
}
|
|
catch (const glu::Error& err)
|
|
{
|
|
m_result = RESULT_RENDER_FAILED;
|
|
m_glError = err.getError();
|
|
return;
|
|
}
|
|
catch (const glu::OutOfMemoryError&)
|
|
{
|
|
m_result = RESULT_RENDER_FAILED;
|
|
m_glError = GL_OUT_OF_MEMORY;
|
|
return;
|
|
}
|
|
}
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
error = glGetError();
|
|
if (error != 0)
|
|
{
|
|
m_result = RESULT_BIND_TEXTURE_FAILED;
|
|
m_glError = error;
|
|
return;
|
|
}
|
|
|
|
m_objectCount++;
|
|
m_bytesRequired += width*height*4;
|
|
}
|
|
|
|
void MemObjectAllocator::allocateBuffer (de::Random& rnd)
|
|
{
|
|
const int vectorBlockSize = 128;
|
|
deUint32 buffer = 0;
|
|
deUint32 error = 0;
|
|
int size = rnd.getInt(m_config.minBufferSize, m_config.maxBufferSize);
|
|
|
|
glGenBuffers(1, &buffer);
|
|
error = glGetError();
|
|
if (error != 0)
|
|
{
|
|
m_result = RESULT_GEN_BUFFERS_FAILED;
|
|
m_glError = error;
|
|
return;
|
|
}
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, buffer);
|
|
error = glGetError();
|
|
if (error != 0)
|
|
{
|
|
m_result = RESULT_BIND_BUFFER_FAILED;
|
|
m_glError = error;
|
|
return;
|
|
}
|
|
|
|
if (m_buffers.size() % vectorBlockSize == 0)
|
|
m_buffers.reserve(m_buffers.size() + vectorBlockSize);
|
|
|
|
m_buffers.push_back(buffer);
|
|
|
|
if (m_config.useDummyData)
|
|
{
|
|
DE_ASSERT((int)m_dummyData.size() >= size);
|
|
glBufferData(GL_ARRAY_BUFFER, size, &(m_dummyData[0]), GL_DYNAMIC_DRAW);
|
|
}
|
|
else
|
|
glBufferData(GL_ARRAY_BUFFER, size, NULL, GL_DYNAMIC_DRAW);
|
|
|
|
error = glGetError();
|
|
if (error != 0)
|
|
{
|
|
m_result = RESULT_BUFFER_DATA_FAILED;
|
|
m_glError = error;
|
|
return;
|
|
}
|
|
|
|
if (m_config.write)
|
|
glBufferSubData(GL_ARRAY_BUFFER, 0, 1, &(m_dummyData[0]));
|
|
|
|
error = glGetError();
|
|
if (error != 0)
|
|
{
|
|
m_result = RESULT_BUFFER_SUB_DATA_FAILED;
|
|
m_glError = error;
|
|
return;
|
|
}
|
|
|
|
if (m_config.use)
|
|
{
|
|
try
|
|
{
|
|
m_bufferRenderer.render(buffer, size);
|
|
}
|
|
catch (const glu::Error& err)
|
|
{
|
|
m_result = RESULT_RENDER_FAILED;
|
|
m_glError = err.getError();
|
|
return;
|
|
}
|
|
catch (const glu::OutOfMemoryError&)
|
|
{
|
|
m_result = RESULT_RENDER_FAILED;
|
|
m_glError = GL_OUT_OF_MEMORY;
|
|
return;
|
|
}
|
|
}
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
error = glGetError();
|
|
if (error != 0)
|
|
{
|
|
m_result = RESULT_BIND_BUFFER_FAILED;
|
|
m_glError = error;
|
|
return;
|
|
}
|
|
|
|
m_objectCount++;
|
|
m_bytesRequired += size;
|
|
}
|
|
|
|
const char* MemObjectAllocator::resultToString (Result result)
|
|
{
|
|
switch (result)
|
|
{
|
|
case RESULT_GOT_BAD_ALLOC:
|
|
return "Caught std::bad_alloc";
|
|
break;
|
|
|
|
case RESULT_GEN_TEXTURES_FAILED:
|
|
return "glGenTextures failed";
|
|
break;
|
|
|
|
case RESULT_GEN_BUFFERS_FAILED:
|
|
return "glGenBuffers failed";
|
|
break;
|
|
|
|
case RESULT_BUFFER_DATA_FAILED:
|
|
return "glBufferData failed";
|
|
break;
|
|
|
|
case RESULT_BUFFER_SUB_DATA_FAILED:
|
|
return "glBufferSubData failed";
|
|
break;
|
|
|
|
case RESULT_TEXTURE_IMAGE_FAILED:
|
|
return "glTexImage2D failed";
|
|
break;
|
|
|
|
case RESULT_TEXTURE_SUB_IMAGE_FAILED:
|
|
return "glTexSubImage2D failed";
|
|
break;
|
|
|
|
case RESULT_BIND_TEXTURE_FAILED:
|
|
return "glBindTexture failed";
|
|
break;
|
|
|
|
case RESULT_BIND_BUFFER_FAILED:
|
|
return "glBindBuffer failed";
|
|
break;
|
|
|
|
case RESULT_DELETE_TEXTURES_FAILED:
|
|
return "glDeleteTextures failed";
|
|
break;
|
|
|
|
case RESULT_DELETE_BUFFERS_FAILED:
|
|
return "glDeleteBuffers failed";
|
|
break;
|
|
|
|
case RESULT_RENDER_FAILED:
|
|
return "Rendering result failed";
|
|
break;
|
|
|
|
default:
|
|
DE_ASSERT(false);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
MemoryStressCase::MemoryStressCase (tcu::TestContext& ctx, glu::RenderContext& renderContext, deUint32 objectTypes, int minTextureSize, int maxTextureSize, int minBufferSize, int maxBufferSize, bool write, bool use, bool useDummyData, bool clearAfterOOM, const char* name, const char* desc)
|
|
: tcu::TestCase (ctx, name, desc)
|
|
, m_iteration (0)
|
|
, m_iterationCount (5)
|
|
, m_objectTypes ((MemObjectType)objectTypes)
|
|
, m_zeroAlloc (false)
|
|
, m_clearAfterOOM (clearAfterOOM)
|
|
, m_renderCtx (renderContext)
|
|
{
|
|
m_allocated.reserve(m_iterationCount);
|
|
m_config.maxTextureSize = maxTextureSize;
|
|
m_config.minTextureSize = minTextureSize;
|
|
m_config.maxBufferSize = maxBufferSize;
|
|
m_config.minBufferSize = minBufferSize;
|
|
m_config.useDummyData = useDummyData;
|
|
m_config.write = write;
|
|
m_config.use = use;
|
|
}
|
|
|
|
MemoryStressCase::~MemoryStressCase (void)
|
|
{
|
|
}
|
|
|
|
void MemoryStressCase::init (void)
|
|
{
|
|
if (!m_testCtx.getCommandLine().isOutOfMemoryTestEnabled())
|
|
{
|
|
m_testCtx.getLog() << TestLog::Message << "Tests that exhaust memory are disabled, use --deqp-test-oom=enable command line option to enable." << TestLog::EndMessage;
|
|
throw tcu::NotSupportedError("OOM tests disabled");
|
|
}
|
|
}
|
|
|
|
void MemoryStressCase::deinit (void)
|
|
{
|
|
TCU_CHECK(!m_zeroAlloc);
|
|
}
|
|
|
|
tcu::TestCase::IterateResult MemoryStressCase::iterate (void)
|
|
{
|
|
bool end = false;
|
|
tcu::TestLog& log = m_testCtx.getLog();
|
|
|
|
MemObjectAllocator allocator(log, m_renderCtx, m_objectTypes, m_config, deStringHash(getName()));
|
|
|
|
if (!allocator.allocUntilFailure())
|
|
{
|
|
// Allocation timed out
|
|
allocator.clearObjects();
|
|
|
|
log << TestLog::Message << "Timeout. Couldn't exhaust memory in timelimit. Allocated " << allocator.getObjectCount() << " objects." << TestLog::EndMessage;
|
|
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
|
|
return STOP;
|
|
}
|
|
|
|
// Try to cancel rendering operations
|
|
if (m_clearAfterOOM)
|
|
GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT));
|
|
|
|
allocator.clearObjects();
|
|
|
|
m_allocated.push_back(allocator.getObjectCount());
|
|
|
|
if (m_iteration != 0 && allocator.getObjectCount() == 0)
|
|
m_zeroAlloc = true;
|
|
|
|
log << TestLog::Message << "Got error when allocation object count: " << allocator.getObjectCount() << " bytes: " << allocator.getBytes() << TestLog::EndMessage;
|
|
|
|
if ((allocator.getGLError() == 0) && (allocator.getResult() == MemObjectAllocator::RESULT_GOT_BAD_ALLOC))
|
|
{
|
|
log << TestLog::Message << "std::bad_alloc" << TestLog::EndMessage;
|
|
end = true;
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_RESOURCE_ERROR, "Memory allocation failed");
|
|
}
|
|
else if (allocator.getGLError() != GL_OUT_OF_MEMORY)
|
|
{
|
|
log << TestLog::Message << "Invalid Error " << MemObjectAllocator::resultToString(allocator.getResult())
|
|
<< " GLError: " << glErrorToString(allocator.getGLError()) <<
|
|
TestLog::EndMessage;
|
|
|
|
end = true;
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
|
|
}
|
|
|
|
if ((m_iteration+1) == m_iterationCount)
|
|
{
|
|
int min = m_allocated[0];
|
|
int max = m_allocated[0];
|
|
|
|
float threshold = 50.0f;
|
|
|
|
for (int allocNdx = 0; allocNdx < (int)m_allocated.size(); allocNdx++)
|
|
{
|
|
min = deMin32(m_allocated[allocNdx], min);
|
|
max = deMax32(m_allocated[allocNdx], max);
|
|
}
|
|
|
|
if (min == 0 && max != 0)
|
|
{
|
|
log << TestLog::Message << "Allocation count zero" << TestLog::EndMessage;
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
|
|
}
|
|
else
|
|
{
|
|
const float change = (float)(min - max) / (float)(max);
|
|
if (change > threshold)
|
|
{
|
|
log << TestLog::Message << "Allocated objects max: " << max << ", min: " << min << ", difference: " << change << "% threshold: " << threshold << "%" << TestLog::EndMessage;
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Allocation count variation");
|
|
}
|
|
else
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
|
|
}
|
|
end = true;
|
|
}
|
|
|
|
GLU_CHECK_CALL(glFinish());
|
|
|
|
m_iteration++;
|
|
if (end)
|
|
return STOP;
|
|
else
|
|
return CONTINUE;
|
|
}
|
|
|
|
} // gls
|
|
} // deqp
|