/*-------------------------------------------------------------------------
* 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 Interaction test utilities.
*//*--------------------------------------------------------------------*/
#include "glsInteractionTestUtil.hpp"
#include "tcuVector.hpp"
#include "deRandom.hpp"
#include "deMath.h"
#include "glwEnums.hpp"
namespace deqp
{
namespace gls
{
namespace InteractionTestUtil
{
using tcu::Vec4;
using tcu::IVec2;
using std::vector;
static Vec4 getRandomColor (de::Random& rnd)
{
static const float components[] = { 0.0f, 0.2f, 0.4f, 0.5f, 0.6f, 0.8f, 1.0f };
float r = rnd.choose<float>(DE_ARRAY_BEGIN(components), DE_ARRAY_END(components));
float g = rnd.choose<float>(DE_ARRAY_BEGIN(components), DE_ARRAY_END(components));
float b = rnd.choose<float>(DE_ARRAY_BEGIN(components), DE_ARRAY_END(components));
float a = rnd.choose<float>(DE_ARRAY_BEGIN(components), DE_ARRAY_END(components));
return Vec4(r, g, b, a);
}
void computeRandomRenderState (de::Random& rnd, RenderState& state, glu::ApiType apiType, int targetWidth, int targetHeight)
{
// Constants governing randomization.
const float scissorTestProbability = 0.2f;
const float stencilTestProbability = 0.4f;
const float depthTestProbability = 0.6f;
const float blendProbability = 0.4f;
const float ditherProbability = 0.5f;
const float depthWriteProbability = 0.7f;
const float colorWriteProbability = 0.7f;
const int minStencilVal = -3;
const int maxStencilVal = 260;
const int maxScissorOutOfBounds = 10;
const float minScissorSize = 0.7f;
static const deUint32 compareFuncs[] =
{
GL_NEVER,
GL_ALWAYS,
GL_LESS,
GL_LEQUAL,
GL_EQUAL,
GL_GEQUAL,
GL_GREATER,
GL_NOTEQUAL
};
static const deUint32 stencilOps[] =
{
GL_KEEP,
GL_ZERO,
GL_REPLACE,
GL_INCR,
GL_DECR,
GL_INVERT,
GL_INCR_WRAP,
GL_DECR_WRAP
};
static const deUint32 blendEquations[] =
{
GL_FUNC_ADD,
GL_FUNC_SUBTRACT,
GL_FUNC_REVERSE_SUBTRACT,
GL_MIN,
GL_MAX
};
static const deUint32 blendFuncs[] =
{
GL_ZERO,
GL_ONE,
GL_SRC_COLOR,
GL_ONE_MINUS_SRC_COLOR,
GL_DST_COLOR,
GL_ONE_MINUS_DST_COLOR,
GL_SRC_ALPHA,
GL_ONE_MINUS_SRC_ALPHA,
GL_DST_ALPHA,
GL_ONE_MINUS_DST_ALPHA,
GL_CONSTANT_COLOR,
GL_ONE_MINUS_CONSTANT_COLOR,
GL_CONSTANT_ALPHA,
GL_ONE_MINUS_CONSTANT_ALPHA,
GL_SRC_ALPHA_SATURATE
};
static const deUint32 blendEquationsES2[] =
{
GL_FUNC_ADD,
GL_FUNC_SUBTRACT,
GL_FUNC_REVERSE_SUBTRACT
};
static const deUint32 blendFuncsDstES2[] =
{
GL_ZERO,
GL_ONE,
GL_SRC_COLOR,
GL_ONE_MINUS_SRC_COLOR,
GL_DST_COLOR,
GL_ONE_MINUS_DST_COLOR,
GL_SRC_ALPHA,
GL_ONE_MINUS_SRC_ALPHA,
GL_DST_ALPHA,
GL_ONE_MINUS_DST_ALPHA,
GL_CONSTANT_COLOR,
GL_ONE_MINUS_CONSTANT_COLOR,
GL_CONSTANT_ALPHA,
GL_ONE_MINUS_CONSTANT_ALPHA
};
state.scissorTestEnabled = rnd.getFloat() < scissorTestProbability;
state.stencilTestEnabled = rnd.getFloat() < stencilTestProbability;
state.depthTestEnabled = rnd.getFloat() < depthTestProbability;
state.blendEnabled = rnd.getFloat() < blendProbability;
state.ditherEnabled = rnd.getFloat() < ditherProbability;
if (state.scissorTestEnabled)
{
int minScissorW = deCeilFloatToInt32(minScissorSize * (float)targetWidth);
int minScissorH = deCeilFloatToInt32(minScissorSize * (float)targetHeight);
int maxScissorW = targetWidth + 2*maxScissorOutOfBounds;
int maxScissorH = targetHeight + 2*maxScissorOutOfBounds;
int scissorW = rnd.getInt(minScissorW, maxScissorW);
int scissorH = rnd.getInt(minScissorH, maxScissorH);
int scissorX = rnd.getInt(-maxScissorOutOfBounds, targetWidth+maxScissorOutOfBounds-scissorW);
int scissorY = rnd.getInt(-maxScissorOutOfBounds, targetHeight+maxScissorOutOfBounds-scissorH);
state.scissorRectangle = rr::WindowRectangle(scissorX, scissorY, scissorW, scissorH);
}
if (state.stencilTestEnabled)
{
for (int ndx = 0; ndx < 2; ndx++)
{
state.stencil[ndx].function = rnd.choose<deUint32>(DE_ARRAY_BEGIN(compareFuncs), DE_ARRAY_END(compareFuncs));
state.stencil[ndx].reference = rnd.getInt(minStencilVal, maxStencilVal);
state.stencil[ndx].compareMask = rnd.getUint32();
state.stencil[ndx].stencilFailOp = rnd.choose<deUint32>(DE_ARRAY_BEGIN(stencilOps), DE_ARRAY_END(stencilOps));
state.stencil[ndx].depthFailOp = rnd.choose<deUint32>(DE_ARRAY_BEGIN(stencilOps), DE_ARRAY_END(stencilOps));
state.stencil[ndx].depthPassOp = rnd.choose<deUint32>(DE_ARRAY_BEGIN(stencilOps), DE_ARRAY_END(stencilOps));
state.stencil[ndx].writeMask = rnd.getUint32();
}
}
if (state.depthTestEnabled)
{
state.depthFunc = rnd.choose<deUint32>(DE_ARRAY_BEGIN(compareFuncs), DE_ARRAY_END(compareFuncs));
state.depthWriteMask = rnd.getFloat() < depthWriteProbability;
}
if (state.blendEnabled)
{
if (apiType == glu::ApiType::es(2,0))
{
state.blendRGBState.equation = rnd.choose<deUint32>(DE_ARRAY_BEGIN(blendEquationsES2), DE_ARRAY_END(blendEquationsES2));
state.blendRGBState.srcFunc = rnd.choose<deUint32>(DE_ARRAY_BEGIN(blendFuncs), DE_ARRAY_END(blendFuncs));
state.blendRGBState.dstFunc = rnd.choose<deUint32>(DE_ARRAY_BEGIN(blendFuncsDstES2), DE_ARRAY_END(blendFuncsDstES2));
state.blendAState.equation = rnd.choose<deUint32>(DE_ARRAY_BEGIN(blendEquationsES2), DE_ARRAY_END(blendEquationsES2));
state.blendAState.srcFunc = rnd.choose<deUint32>(DE_ARRAY_BEGIN(blendFuncs), DE_ARRAY_END(blendFuncs));
state.blendAState.dstFunc = rnd.choose<deUint32>(DE_ARRAY_BEGIN(blendFuncsDstES2), DE_ARRAY_END(blendFuncsDstES2));
}
else
{
state.blendRGBState.equation = rnd.choose<deUint32>(DE_ARRAY_BEGIN(blendEquations), DE_ARRAY_END(blendEquations));
state.blendRGBState.srcFunc = rnd.choose<deUint32>(DE_ARRAY_BEGIN(blendFuncs), DE_ARRAY_END(blendFuncs));
state.blendRGBState.dstFunc = rnd.choose<deUint32>(DE_ARRAY_BEGIN(blendFuncs), DE_ARRAY_END(blendFuncs));
state.blendAState.equation = rnd.choose<deUint32>(DE_ARRAY_BEGIN(blendEquations), DE_ARRAY_END(blendEquations));
state.blendAState.srcFunc = rnd.choose<deUint32>(DE_ARRAY_BEGIN(blendFuncs), DE_ARRAY_END(blendFuncs));
state.blendAState.dstFunc = rnd.choose<deUint32>(DE_ARRAY_BEGIN(blendFuncs), DE_ARRAY_END(blendFuncs));
}
state.blendColor = getRandomColor(rnd);
}
for (int ndx = 0; ndx < 4; ndx++)
state.colorMask[ndx] = rnd.getFloat() < colorWriteProbability;
}
void computeRandomQuad (de::Random& rnd, gls::FragmentOpUtil::IntegerQuad& quad, int targetWidth, int targetHeight)
{
// \note In viewport coordinates.
// \todo [2012-12-18 pyry] Out-of-bounds values.
// \note Not using depth 1.0 since clearing with 1.0 and rendering with 1.0 may not be same value.
static const float depthValues[] = { 0.0f, 0.2f, 0.4f, 0.5f, 0.51f, 0.6f, 0.8f, 0.95f };
const int maxOutOfBounds = 0;
const float minSize = 0.5f;
int minW = deCeilFloatToInt32(minSize * (float)targetWidth);
int minH = deCeilFloatToInt32(minSize * (float)targetHeight);
int maxW = targetWidth + 2*maxOutOfBounds;
int maxH = targetHeight + 2*maxOutOfBounds;
int width = rnd.getInt(minW, maxW);
int height = rnd.getInt(minH, maxH);
int x = rnd.getInt(-maxOutOfBounds, targetWidth+maxOutOfBounds-width);
int y = rnd.getInt(-maxOutOfBounds, targetHeight+maxOutOfBounds-height);
bool flipX = rnd.getBool();
bool flipY = rnd.getBool();
float depth = rnd.choose<float>(DE_ARRAY_BEGIN(depthValues), DE_ARRAY_END(depthValues));
quad.posA = IVec2(flipX ? (x+width-1) : x, flipY ? (y+height-1) : y);
quad.posB = IVec2(flipX ? x : (x+width-1), flipY ? y : (y+height-1));
for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(quad.color); ndx++)
quad.color[ndx] = getRandomColor(rnd);
std::fill(DE_ARRAY_BEGIN(quad.depth), DE_ARRAY_END(quad.depth), depth);
}
void computeRandomRenderCommands (de::Random& rnd, glu::ApiType apiType, int numCommands, int targetW, int targetH, vector<RenderCommand>& dst)
{
DE_ASSERT(dst.empty());
dst.resize(numCommands);
for (vector<RenderCommand>::iterator cmd = dst.begin(); cmd != dst.end(); cmd++)
{
computeRandomRenderState(rnd, cmd->state, apiType, targetW, targetH);
computeRandomQuad(rnd, cmd->quad, targetW, targetH);
}
}
} // InteractionTestUtil
} // gls
} // deqp