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.
2224 lines
66 KiB
2224 lines
66 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 Vertex array and buffer tests
|
|
*//*--------------------------------------------------------------------*/
|
|
|
|
#include "glsVertexArrayTests.hpp"
|
|
|
|
#include "deRandom.h"
|
|
|
|
#include "tcuTestLog.hpp"
|
|
#include "tcuPixelFormat.hpp"
|
|
#include "tcuRGBA.hpp"
|
|
#include "tcuSurface.hpp"
|
|
#include "tcuVector.hpp"
|
|
#include "tcuTestLog.hpp"
|
|
#include "tcuRenderTarget.hpp"
|
|
#include "tcuStringTemplate.hpp"
|
|
#include "tcuImageCompare.hpp"
|
|
|
|
#include "gluPixelTransfer.hpp"
|
|
#include "gluCallLogWrapper.hpp"
|
|
|
|
#include "sglrContext.hpp"
|
|
#include "sglrReferenceContext.hpp"
|
|
#include "sglrGLContext.hpp"
|
|
|
|
#include "deMath.h"
|
|
#include "deStringUtil.hpp"
|
|
#include "deArrayUtil.hpp"
|
|
|
|
#include <cstring>
|
|
#include <cmath>
|
|
#include <vector>
|
|
#include <sstream>
|
|
#include <limits>
|
|
#include <algorithm>
|
|
|
|
#include "glwDefs.hpp"
|
|
#include "glwEnums.hpp"
|
|
|
|
namespace deqp
|
|
{
|
|
namespace gls
|
|
{
|
|
|
|
using tcu::TestLog;
|
|
using namespace glw; // GL types
|
|
|
|
std::string Array::targetToString(Target target)
|
|
{
|
|
static const char* targets[] =
|
|
{
|
|
"element_array", // TARGET_ELEMENT_ARRAY = 0,
|
|
"array" // TARGET_ARRAY,
|
|
};
|
|
|
|
return de::getSizedArrayElement<Array::TARGET_LAST>(targets, (int)target);
|
|
}
|
|
|
|
std::string Array::inputTypeToString(InputType type)
|
|
{
|
|
static const char* types[] =
|
|
{
|
|
"float", // INPUTTYPE_FLOAT = 0,
|
|
"fixed", // INPUTTYPE_FIXED,
|
|
"double", // INPUTTYPE_DOUBLE
|
|
|
|
"byte", // INPUTTYPE_BYTE,
|
|
"short", // INPUTTYPE_SHORT,
|
|
|
|
"unsigned_byte", // INPUTTYPE_UNSIGNED_BYTE,
|
|
"unsigned_short", // INPUTTYPE_UNSIGNED_SHORT,
|
|
|
|
"int", // INPUTTYPE_INT,
|
|
"unsigned_int", // INPUTTYPE_UNSIGNED_INT,
|
|
"half", // INPUTTYPE_HALF,
|
|
"usigned_int2_10_10_10", // INPUTTYPE_UNSIGNED_INT_2_10_10_10,
|
|
"int2_10_10_10" // INPUTTYPE_INT_2_10_10_10,
|
|
};
|
|
|
|
return de::getSizedArrayElement<Array::INPUTTYPE_LAST>(types, (int)type);
|
|
}
|
|
|
|
std::string Array::outputTypeToString(OutputType type)
|
|
{
|
|
static const char* types[] =
|
|
{
|
|
"float", // OUTPUTTYPE_FLOAT = 0,
|
|
"vec2", // OUTPUTTYPE_VEC2,
|
|
"vec3", // OUTPUTTYPE_VEC3,
|
|
"vec4", // OUTPUTTYPE_VEC4,
|
|
|
|
"int", // OUTPUTTYPE_INT,
|
|
"uint", // OUTPUTTYPE_UINT,
|
|
|
|
"ivec2", // OUTPUTTYPE_IVEC2,
|
|
"ivec3", // OUTPUTTYPE_IVEC3,
|
|
"ivec4", // OUTPUTTYPE_IVEC4,
|
|
|
|
"uvec2", // OUTPUTTYPE_UVEC2,
|
|
"uvec3", // OUTPUTTYPE_UVEC3,
|
|
"uvec4", // OUTPUTTYPE_UVEC4,
|
|
};
|
|
|
|
return de::getSizedArrayElement<Array::OUTPUTTYPE_LAST>(types, (int)type);
|
|
}
|
|
|
|
std::string Array::usageTypeToString(Usage usage)
|
|
{
|
|
static const char* usages[] =
|
|
{
|
|
"dynamic_draw", // USAGE_DYNAMIC_DRAW = 0,
|
|
"static_draw", // USAGE_STATIC_DRAW,
|
|
"stream_draw", // USAGE_STREAM_DRAW,
|
|
|
|
"stream_read", // USAGE_STREAM_READ,
|
|
"stream_copy", // USAGE_STREAM_COPY,
|
|
|
|
"static_read", // USAGE_STATIC_READ,
|
|
"static_copy", // USAGE_STATIC_COPY,
|
|
|
|
"dynamic_read", // USAGE_DYNAMIC_READ,
|
|
"dynamic_copy", // USAGE_DYNAMIC_COPY,
|
|
};
|
|
|
|
return de::getSizedArrayElement<Array::USAGE_LAST>(usages, (int)usage);
|
|
}
|
|
|
|
std::string Array::storageToString (Storage storage)
|
|
{
|
|
static const char* storages[] =
|
|
{
|
|
"user_ptr", // STORAGE_USER = 0,
|
|
"buffer" // STORAGE_BUFFER,
|
|
};
|
|
|
|
return de::getSizedArrayElement<Array::STORAGE_LAST>(storages, (int)storage);
|
|
}
|
|
|
|
std::string Array::primitiveToString (Primitive primitive)
|
|
{
|
|
static const char* primitives[] =
|
|
{
|
|
"points", // PRIMITIVE_POINTS ,
|
|
"triangles", // PRIMITIVE_TRIANGLES,
|
|
"triangle_fan", // PRIMITIVE_TRIANGLE_FAN,
|
|
"triangle_strip" // PRIMITIVE_TRIANGLE_STRIP,
|
|
};
|
|
|
|
return de::getSizedArrayElement<Array::PRIMITIVE_LAST>(primitives, (int)primitive);
|
|
}
|
|
|
|
int Array::inputTypeSize (InputType type)
|
|
{
|
|
static const int size[] =
|
|
{
|
|
(int)sizeof(float), // INPUTTYPE_FLOAT = 0,
|
|
(int)sizeof(deInt32), // INPUTTYPE_FIXED,
|
|
(int)sizeof(double), // INPUTTYPE_DOUBLE
|
|
|
|
(int)sizeof(deInt8), // INPUTTYPE_BYTE,
|
|
(int)sizeof(deInt16), // INPUTTYPE_SHORT,
|
|
|
|
(int)sizeof(deUint8), // INPUTTYPE_UNSIGNED_BYTE,
|
|
(int)sizeof(deUint16), // INPUTTYPE_UNSIGNED_SHORT,
|
|
|
|
(int)sizeof(deInt32), // INPUTTYPE_INT,
|
|
(int)sizeof(deUint32), // INPUTTYPE_UNSIGNED_INT,
|
|
(int)sizeof(deFloat16), // INPUTTYPE_HALF,
|
|
(int)sizeof(deUint32) / 4, // INPUTTYPE_UNSIGNED_INT_2_10_10_10,
|
|
(int)sizeof(deUint32) / 4 // INPUTTYPE_INT_2_10_10_10,
|
|
};
|
|
|
|
return de::getSizedArrayElement<Array::INPUTTYPE_LAST>(size, (int)type);
|
|
}
|
|
|
|
static bool inputTypeIsFloatType (Array::InputType type)
|
|
{
|
|
if (type == Array::INPUTTYPE_FLOAT)
|
|
return true;
|
|
if (type == Array::INPUTTYPE_FIXED)
|
|
return true;
|
|
if (type == Array::INPUTTYPE_DOUBLE)
|
|
return true;
|
|
if (type == Array::INPUTTYPE_HALF)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
static bool outputTypeIsFloatType (Array::OutputType type)
|
|
{
|
|
if (type == Array::OUTPUTTYPE_FLOAT
|
|
|| type == Array::OUTPUTTYPE_VEC2
|
|
|| type == Array::OUTPUTTYPE_VEC3
|
|
|| type == Array::OUTPUTTYPE_VEC4)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
template<class T>
|
|
inline T getRandom (deRandom& rnd, T min, T max);
|
|
|
|
template<>
|
|
inline GLValue::Float getRandom (deRandom& rnd, GLValue::Float min, GLValue::Float max)
|
|
{
|
|
if (max < min)
|
|
return min;
|
|
|
|
return GLValue::Float::create(min + deRandom_getFloat(&rnd) * (max.to<float>() - min.to<float>()));
|
|
}
|
|
|
|
template<>
|
|
inline GLValue::Short getRandom (deRandom& rnd, GLValue::Short min, GLValue::Short max)
|
|
{
|
|
if (max < min)
|
|
return min;
|
|
|
|
return GLValue::Short::create((min == max ? min : (deInt16)(min + (deRandom_getUint32(&rnd) % (max.to<int>() - min.to<int>())))));
|
|
}
|
|
|
|
template<>
|
|
inline GLValue::Ushort getRandom (deRandom& rnd, GLValue::Ushort min, GLValue::Ushort max)
|
|
{
|
|
if (max < min)
|
|
return min;
|
|
|
|
return GLValue::Ushort::create((min == max ? min : (deUint16)(min + (deRandom_getUint32(&rnd) % (max.to<int>() - min.to<int>())))));
|
|
}
|
|
|
|
template<>
|
|
inline GLValue::Byte getRandom (deRandom& rnd, GLValue::Byte min, GLValue::Byte max)
|
|
{
|
|
if (max < min)
|
|
return min;
|
|
|
|
return GLValue::Byte::create((min == max ? min : (deInt8)(min + (deRandom_getUint32(&rnd) % (max.to<int>() - min.to<int>())))));
|
|
}
|
|
|
|
template<>
|
|
inline GLValue::Ubyte getRandom (deRandom& rnd, GLValue::Ubyte min, GLValue::Ubyte max)
|
|
{
|
|
if (max < min)
|
|
return min;
|
|
|
|
return GLValue::Ubyte::create((min == max ? min : (deUint8)(min + (deRandom_getUint32(&rnd) % (max.to<int>() - min.to<int>())))));
|
|
}
|
|
|
|
template<>
|
|
inline GLValue::Fixed getRandom (deRandom& rnd, GLValue::Fixed min, GLValue::Fixed max)
|
|
{
|
|
if (max < min)
|
|
return min;
|
|
|
|
return GLValue::Fixed::create((min == max ? min : min + (deRandom_getUint32(&rnd) % (max.to<deUint32>() - min.to<deUint32>()))));
|
|
}
|
|
|
|
template<>
|
|
inline GLValue::Half getRandom (deRandom& rnd, GLValue::Half min, GLValue::Half max)
|
|
{
|
|
if (max < min)
|
|
return min;
|
|
|
|
float fMax = max.to<float>();
|
|
float fMin = min.to<float>();
|
|
GLValue::Half h = GLValue::Half::create(fMin + deRandom_getFloat(&rnd) * (fMax - fMin));
|
|
return h;
|
|
}
|
|
|
|
template<>
|
|
inline GLValue::Int getRandom (deRandom& rnd, GLValue::Int min, GLValue::Int max)
|
|
{
|
|
if (max < min)
|
|
return min;
|
|
|
|
return GLValue::Int::create((min == max ? min : min + (deRandom_getUint32(&rnd) % (max.to<deUint32>() - min.to<deUint32>()))));
|
|
}
|
|
|
|
template<>
|
|
inline GLValue::Uint getRandom (deRandom& rnd, GLValue::Uint min, GLValue::Uint max)
|
|
{
|
|
if (max < min)
|
|
return min;
|
|
|
|
return GLValue::Uint::create((min == max ? min : min + (deRandom_getUint32(&rnd) % (max.to<deUint32>() - min.to<deUint32>()))));
|
|
}
|
|
|
|
template<>
|
|
inline GLValue::Double getRandom (deRandom& rnd, GLValue::Double min, GLValue::Double max)
|
|
{
|
|
if (max < min)
|
|
return min;
|
|
|
|
return GLValue::Double::create(min + deRandom_getFloat(&rnd) * (max.to<float>() - min.to<float>()));
|
|
}
|
|
|
|
// Minimum difference required between coordinates
|
|
template<class T>
|
|
inline T minValue (void);
|
|
|
|
template<>
|
|
inline GLValue::Float minValue (void)
|
|
{
|
|
return GLValue::Float::create(4 * 1.0f);
|
|
}
|
|
|
|
template<>
|
|
inline GLValue::Short minValue (void)
|
|
{
|
|
return GLValue::Short::create(4 * 256);
|
|
}
|
|
|
|
template<>
|
|
inline GLValue::Ushort minValue (void)
|
|
{
|
|
return GLValue::Ushort::create(4 * 256);
|
|
}
|
|
|
|
template<>
|
|
inline GLValue::Byte minValue (void)
|
|
{
|
|
return GLValue::Byte::create(4 * 1);
|
|
}
|
|
|
|
template<>
|
|
inline GLValue::Ubyte minValue (void)
|
|
{
|
|
return GLValue::Ubyte::create(4 * 2);
|
|
}
|
|
|
|
template<>
|
|
inline GLValue::Fixed minValue (void)
|
|
{
|
|
return GLValue::Fixed::create(4 * 512);
|
|
}
|
|
|
|
template<>
|
|
inline GLValue::Int minValue (void)
|
|
{
|
|
return GLValue::Int::create(4 * 16777216);
|
|
}
|
|
|
|
template<>
|
|
inline GLValue::Uint minValue (void)
|
|
{
|
|
return GLValue::Uint::create(4 * 16777216);
|
|
}
|
|
|
|
template<>
|
|
inline GLValue::Half minValue (void)
|
|
{
|
|
return GLValue::Half::create(4 * 1.0f);
|
|
}
|
|
|
|
template<>
|
|
inline GLValue::Double minValue (void)
|
|
{
|
|
return GLValue::Double::create(4 * 1.0f);
|
|
}
|
|
|
|
template<class T>
|
|
inline T abs (T val);
|
|
|
|
template<>
|
|
inline GLValue::Fixed abs (GLValue::Fixed val)
|
|
{
|
|
return GLValue::Fixed::create(0x7FFFu & val.getValue());
|
|
}
|
|
|
|
template<>
|
|
inline GLValue::Ubyte abs (GLValue::Ubyte val)
|
|
{
|
|
return val;
|
|
}
|
|
|
|
template<>
|
|
inline GLValue::Byte abs (GLValue::Byte val)
|
|
{
|
|
return GLValue::Byte::create(0x7Fu & val.getValue());
|
|
}
|
|
|
|
template<>
|
|
inline GLValue::Ushort abs (GLValue::Ushort val)
|
|
{
|
|
return val;
|
|
}
|
|
|
|
template<>
|
|
inline GLValue::Short abs (GLValue::Short val)
|
|
{
|
|
return GLValue::Short::create(0x7FFFu & val.getValue());
|
|
}
|
|
|
|
template<>
|
|
inline GLValue::Float abs (GLValue::Float val)
|
|
{
|
|
return GLValue::Float::create(std::fabs(val.to<float>()));
|
|
}
|
|
|
|
template<>
|
|
inline GLValue::Uint abs (GLValue::Uint val)
|
|
{
|
|
return val;
|
|
}
|
|
|
|
template<>
|
|
inline GLValue::Int abs (GLValue::Int val)
|
|
{
|
|
return GLValue::Int::create(0x7FFFFFFFu & val.getValue());
|
|
}
|
|
|
|
template<>
|
|
inline GLValue::Half abs (GLValue::Half val)
|
|
{
|
|
return GLValue::Half::create(std::fabs(val.to<float>()));
|
|
}
|
|
|
|
template<>
|
|
inline GLValue::Double abs (GLValue::Double val)
|
|
{
|
|
return GLValue::Double::create(std::fabs(val.to<float>()));
|
|
}
|
|
|
|
template<class T>
|
|
static inline void alignmentSafeAssignment (char* dst, T val)
|
|
{
|
|
std::memcpy(dst, &val, sizeof(T));
|
|
}
|
|
|
|
ContextArray::ContextArray (Storage storage, sglr::Context& context)
|
|
: m_storage (storage)
|
|
, m_ctx (context)
|
|
, m_glBuffer (0)
|
|
, m_bound (false)
|
|
, m_attribNdx (0)
|
|
, m_size (0)
|
|
, m_data (DE_NULL)
|
|
, m_componentCount (1)
|
|
, m_target (Array::TARGET_ARRAY)
|
|
, m_inputType (Array::INPUTTYPE_FLOAT)
|
|
, m_outputType (Array::OUTPUTTYPE_VEC4)
|
|
, m_normalize (false)
|
|
, m_stride (0)
|
|
, m_offset (0)
|
|
{
|
|
if (m_storage == STORAGE_BUFFER)
|
|
{
|
|
m_ctx.genBuffers(1, &m_glBuffer);
|
|
GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glGenBuffers()");
|
|
}
|
|
}
|
|
|
|
ContextArray::~ContextArray (void)
|
|
{
|
|
if (m_storage == STORAGE_BUFFER)
|
|
{
|
|
m_ctx.deleteBuffers(1, &m_glBuffer);
|
|
GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDeleteBuffers()");
|
|
}
|
|
else if (m_storage == STORAGE_USER)
|
|
delete[] m_data;
|
|
else
|
|
DE_ASSERT(false);
|
|
}
|
|
|
|
Array* ContextArrayPack::getArray (int i)
|
|
{
|
|
return m_arrays.at(i);
|
|
}
|
|
|
|
void ContextArray::data (Target target, int size, const char* ptr, Usage usage)
|
|
{
|
|
m_size = size;
|
|
m_target = target;
|
|
|
|
if (m_storage == STORAGE_BUFFER)
|
|
{
|
|
m_ctx.bindBuffer(targetToGL(target), m_glBuffer);
|
|
GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()");
|
|
|
|
m_ctx.bufferData(targetToGL(target), size, ptr, usageToGL(usage));
|
|
GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBufferData()");
|
|
}
|
|
else if (m_storage == STORAGE_USER)
|
|
{
|
|
if (m_data)
|
|
delete[] m_data;
|
|
|
|
m_data = new char[size];
|
|
std::memcpy(m_data, ptr, size);
|
|
}
|
|
else
|
|
DE_ASSERT(false);
|
|
}
|
|
|
|
void ContextArray::subdata (Target target, int offset, int size, const char* ptr)
|
|
{
|
|
m_target = target;
|
|
|
|
if (m_storage == STORAGE_BUFFER)
|
|
{
|
|
m_ctx.bindBuffer(targetToGL(target), m_glBuffer);
|
|
GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()");
|
|
|
|
m_ctx.bufferSubData(targetToGL(target), offset, size, ptr);
|
|
GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBufferSubData()");
|
|
}
|
|
else if (m_storage == STORAGE_USER)
|
|
std::memcpy(m_data + offset, ptr, size);
|
|
else
|
|
DE_ASSERT(false);
|
|
}
|
|
|
|
void ContextArray::bind (int attribNdx, int offset, int size, InputType inputType, OutputType outType, bool normalized, int stride)
|
|
{
|
|
m_attribNdx = attribNdx;
|
|
m_bound = true;
|
|
m_componentCount = size;
|
|
m_inputType = inputType;
|
|
m_outputType = outType;
|
|
m_normalize = normalized;
|
|
m_stride = stride;
|
|
m_offset = offset;
|
|
}
|
|
|
|
void ContextArray::bindIndexArray (Array::Target target)
|
|
{
|
|
if (m_storage == STORAGE_USER)
|
|
{
|
|
}
|
|
else if (m_storage == STORAGE_BUFFER)
|
|
{
|
|
m_ctx.bindBuffer(targetToGL(target), m_glBuffer);
|
|
}
|
|
}
|
|
|
|
void ContextArray::glBind (deUint32 loc)
|
|
{
|
|
if (m_storage == STORAGE_BUFFER)
|
|
{
|
|
m_ctx.bindBuffer(targetToGL(m_target), m_glBuffer);
|
|
GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()");
|
|
|
|
if (!inputTypeIsFloatType(m_inputType))
|
|
{
|
|
// Input is not float type
|
|
|
|
if (outputTypeIsFloatType(m_outputType))
|
|
{
|
|
// Output type is float type
|
|
m_ctx.vertexAttribPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_normalize, m_stride, (GLvoid*)((GLintptr)m_offset));
|
|
GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribPointer()");
|
|
}
|
|
else
|
|
{
|
|
// Output type is int type
|
|
m_ctx.vertexAttribIPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_stride, (GLvoid*)((GLintptr)m_offset));
|
|
GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribIPointer()");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Input type is float type
|
|
|
|
// Output type must be float type
|
|
DE_ASSERT(m_outputType == OUTPUTTYPE_FLOAT || m_outputType == OUTPUTTYPE_VEC2 || m_outputType == OUTPUTTYPE_VEC3 || m_outputType == OUTPUTTYPE_VEC4);
|
|
|
|
m_ctx.vertexAttribPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_normalize, m_stride, (GLvoid*)((GLintptr)m_offset));
|
|
GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribPointer()");
|
|
}
|
|
|
|
m_ctx.bindBuffer(targetToGL(m_target), 0);
|
|
}
|
|
else if (m_storage == STORAGE_USER)
|
|
{
|
|
m_ctx.bindBuffer(targetToGL(m_target), 0);
|
|
GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()");
|
|
|
|
if (!inputTypeIsFloatType(m_inputType))
|
|
{
|
|
// Input is not float type
|
|
|
|
if (outputTypeIsFloatType(m_outputType))
|
|
{
|
|
// Output type is float type
|
|
m_ctx.vertexAttribPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_normalize, m_stride, m_data + m_offset);
|
|
GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribPointer()");
|
|
}
|
|
else
|
|
{
|
|
// Output type is int type
|
|
m_ctx.vertexAttribIPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_stride, m_data + m_offset);
|
|
GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribIPointer()");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Input type is float type
|
|
|
|
// Output type must be float type
|
|
DE_ASSERT(m_outputType == OUTPUTTYPE_FLOAT || m_outputType == OUTPUTTYPE_VEC2 || m_outputType == OUTPUTTYPE_VEC3 || m_outputType == OUTPUTTYPE_VEC4);
|
|
|
|
m_ctx.vertexAttribPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_normalize, m_stride, m_data + m_offset);
|
|
GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribPointer()");
|
|
}
|
|
}
|
|
else
|
|
DE_ASSERT(false);
|
|
}
|
|
|
|
GLenum ContextArray::targetToGL (Array::Target target)
|
|
{
|
|
static const GLenum targets[] =
|
|
{
|
|
GL_ELEMENT_ARRAY_BUFFER, // TARGET_ELEMENT_ARRAY = 0,
|
|
GL_ARRAY_BUFFER // TARGET_ARRAY,
|
|
};
|
|
|
|
return de::getSizedArrayElement<Array::TARGET_LAST>(targets, (int)target);
|
|
}
|
|
|
|
GLenum ContextArray::usageToGL (Array::Usage usage)
|
|
{
|
|
static const GLenum usages[] =
|
|
{
|
|
GL_DYNAMIC_DRAW, // USAGE_DYNAMIC_DRAW = 0,
|
|
GL_STATIC_DRAW, // USAGE_STATIC_DRAW,
|
|
GL_STREAM_DRAW, // USAGE_STREAM_DRAW,
|
|
|
|
GL_STREAM_READ, // USAGE_STREAM_READ,
|
|
GL_STREAM_COPY, // USAGE_STREAM_COPY,
|
|
|
|
GL_STATIC_READ, // USAGE_STATIC_READ,
|
|
GL_STATIC_COPY, // USAGE_STATIC_COPY,
|
|
|
|
GL_DYNAMIC_READ, // USAGE_DYNAMIC_READ,
|
|
GL_DYNAMIC_COPY // USAGE_DYNAMIC_COPY,
|
|
};
|
|
|
|
return de::getSizedArrayElement<Array::USAGE_LAST>(usages, (int)usage);
|
|
}
|
|
|
|
GLenum ContextArray::inputTypeToGL (Array::InputType type)
|
|
{
|
|
static const GLenum types[] =
|
|
{
|
|
GL_FLOAT, // INPUTTYPE_FLOAT = 0,
|
|
GL_FIXED, // INPUTTYPE_FIXED,
|
|
GL_DOUBLE, // INPUTTYPE_DOUBLE
|
|
GL_BYTE, // INPUTTYPE_BYTE,
|
|
GL_SHORT, // INPUTTYPE_SHORT,
|
|
GL_UNSIGNED_BYTE, // INPUTTYPE_UNSIGNED_BYTE,
|
|
GL_UNSIGNED_SHORT, // INPUTTYPE_UNSIGNED_SHORT,
|
|
|
|
GL_INT, // INPUTTYPE_INT,
|
|
GL_UNSIGNED_INT, // INPUTTYPE_UNSIGNED_INT,
|
|
GL_HALF_FLOAT, // INPUTTYPE_HALF,
|
|
GL_UNSIGNED_INT_2_10_10_10_REV, // INPUTTYPE_UNSIGNED_INT_2_10_10_10,
|
|
GL_INT_2_10_10_10_REV // INPUTTYPE_INT_2_10_10_10,
|
|
};
|
|
|
|
return de::getSizedArrayElement<Array::INPUTTYPE_LAST>(types, (int)type);
|
|
}
|
|
|
|
std::string ContextArray::outputTypeToGLType (Array::OutputType type)
|
|
{
|
|
static const char* types[] =
|
|
{
|
|
"float", // OUTPUTTYPE_FLOAT = 0,
|
|
"vec2", // OUTPUTTYPE_VEC2,
|
|
"vec3", // OUTPUTTYPE_VEC3,
|
|
"vec4", // OUTPUTTYPE_VEC4,
|
|
|
|
"int", // OUTPUTTYPE_INT,
|
|
"uint", // OUTPUTTYPE_UINT,
|
|
|
|
"ivec2", // OUTPUTTYPE_IVEC2,
|
|
"ivec3", // OUTPUTTYPE_IVEC3,
|
|
"ivec4", // OUTPUTTYPE_IVEC4,
|
|
|
|
"uvec2", // OUTPUTTYPE_UVEC2,
|
|
"uvec3", // OUTPUTTYPE_UVEC3,
|
|
"uvec4", // OUTPUTTYPE_UVEC4,
|
|
};
|
|
|
|
return de::getSizedArrayElement<Array::OUTPUTTYPE_LAST>(types, (int)type);
|
|
}
|
|
|
|
GLenum ContextArray::primitiveToGL (Array::Primitive primitive)
|
|
{
|
|
static const GLenum primitives[] =
|
|
{
|
|
GL_POINTS, // PRIMITIVE_POINTS = 0,
|
|
GL_TRIANGLES, // PRIMITIVE_TRIANGLES,
|
|
GL_TRIANGLE_FAN, // PRIMITIVE_TRIANGLE_FAN,
|
|
GL_TRIANGLE_STRIP // PRIMITIVE_TRIANGLE_STRIP,
|
|
};
|
|
|
|
return de::getSizedArrayElement<Array::PRIMITIVE_LAST>(primitives, (int)primitive);
|
|
}
|
|
|
|
ContextArrayPack::ContextArrayPack (glu::RenderContext& renderCtx, sglr::Context& drawContext)
|
|
: m_renderCtx (renderCtx)
|
|
, m_ctx (drawContext)
|
|
, m_program (DE_NULL)
|
|
, m_screen (std::min(512, renderCtx.getRenderTarget().getWidth()), std::min(512, renderCtx.getRenderTarget().getHeight()))
|
|
{
|
|
}
|
|
|
|
ContextArrayPack::~ContextArrayPack (void)
|
|
{
|
|
for (std::vector<ContextArray*>::iterator itr = m_arrays.begin(); itr != m_arrays.end(); itr++)
|
|
delete *itr;
|
|
|
|
delete m_program;
|
|
}
|
|
|
|
int ContextArrayPack::getArrayCount (void)
|
|
{
|
|
return (int)m_arrays.size();
|
|
}
|
|
|
|
void ContextArrayPack::newArray (Array::Storage storage)
|
|
{
|
|
m_arrays.push_back(new ContextArray(storage, m_ctx));
|
|
}
|
|
|
|
class ContextShaderProgram : public sglr::ShaderProgram
|
|
{
|
|
public:
|
|
ContextShaderProgram (const glu::RenderContext& ctx, const std::vector<ContextArray*>& arrays);
|
|
|
|
void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
|
|
void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
|
|
|
|
private:
|
|
static std::string genVertexSource (const glu::RenderContext& ctx, const std::vector<ContextArray*>& arrays);
|
|
static std::string genFragmentSource (const glu::RenderContext& ctx);
|
|
static rr::GenericVecType mapOutputType (const Array::OutputType& type);
|
|
static int getComponentCount (const Array::OutputType& type);
|
|
|
|
static sglr::pdec::ShaderProgramDeclaration createProgramDeclaration (const glu::RenderContext& ctx, const std::vector<ContextArray*>& arrays);
|
|
|
|
std::vector<int> m_componentCount;
|
|
std::vector<rr::GenericVecType> m_attrType;
|
|
};
|
|
|
|
ContextShaderProgram::ContextShaderProgram (const glu::RenderContext& ctx, const std::vector<ContextArray*>& arrays)
|
|
: sglr::ShaderProgram (createProgramDeclaration(ctx, arrays))
|
|
, m_componentCount (arrays.size())
|
|
, m_attrType (arrays.size())
|
|
{
|
|
for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
|
|
{
|
|
m_componentCount[arrayNdx] = getComponentCount(arrays[arrayNdx]->getOutputType());
|
|
m_attrType[arrayNdx] = mapOutputType(arrays[arrayNdx]->getOutputType());
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
void calcShaderColorCoord (tcu::Vec2& coord, tcu::Vec3& color, const tcu::Vector<T, 4>& attribValue, bool isCoordinate, int numComponents)
|
|
{
|
|
if (isCoordinate)
|
|
switch (numComponents)
|
|
{
|
|
case 1: coord = tcu::Vec2((float)attribValue.x(), (float)attribValue.x()); break;
|
|
case 2: coord = tcu::Vec2((float)attribValue.x(), (float)attribValue.y()); break;
|
|
case 3: coord = tcu::Vec2((float)attribValue.x() + (float)attribValue.z(), (float)attribValue.y()); break;
|
|
case 4: coord = tcu::Vec2((float)attribValue.x() + (float)attribValue.z(), (float)attribValue.y() + (float)attribValue.w()); break;
|
|
|
|
default:
|
|
DE_ASSERT(false);
|
|
}
|
|
else
|
|
{
|
|
switch (numComponents)
|
|
{
|
|
case 1:
|
|
color = color * (float)attribValue.x();
|
|
break;
|
|
|
|
case 2:
|
|
color.x() = color.x() * (float)attribValue.x();
|
|
color.y() = color.y() * (float)attribValue.y();
|
|
break;
|
|
|
|
case 3:
|
|
color.x() = color.x() * (float)attribValue.x();
|
|
color.y() = color.y() * (float)attribValue.y();
|
|
color.z() = color.z() * (float)attribValue.z();
|
|
break;
|
|
|
|
case 4:
|
|
color.x() = color.x() * (float)attribValue.x() * (float)attribValue.w();
|
|
color.y() = color.y() * (float)attribValue.y() * (float)attribValue.w();
|
|
color.z() = color.z() * (float)attribValue.z() * (float)attribValue.w();
|
|
break;
|
|
|
|
default:
|
|
DE_ASSERT(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ContextShaderProgram::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
|
|
{
|
|
const float u_coordScale = getUniformByName("u_coordScale").value.f;
|
|
const float u_colorScale = getUniformByName("u_colorScale").value.f;
|
|
|
|
for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
|
|
{
|
|
const size_t varyingLocColor = 0;
|
|
|
|
rr::VertexPacket& packet = *packets[packetNdx];
|
|
|
|
// Calc output color
|
|
tcu::Vec2 coord = tcu::Vec2(1.0, 1.0);
|
|
tcu::Vec3 color = tcu::Vec3(1.0, 1.0, 1.0);
|
|
|
|
for (int attribNdx = 0; attribNdx < (int)m_attrType.size(); attribNdx++)
|
|
{
|
|
const int numComponents = m_componentCount[attribNdx];
|
|
|
|
switch (m_attrType[attribNdx])
|
|
{
|
|
case rr::GENERICVECTYPE_FLOAT: calcShaderColorCoord(coord, color, rr::readVertexAttribFloat(inputs[attribNdx], packet.instanceNdx, packet.vertexNdx), attribNdx == 0, numComponents); break;
|
|
case rr::GENERICVECTYPE_INT32: calcShaderColorCoord(coord, color, rr::readVertexAttribInt (inputs[attribNdx], packet.instanceNdx, packet.vertexNdx), attribNdx == 0, numComponents); break;
|
|
case rr::GENERICVECTYPE_UINT32: calcShaderColorCoord(coord, color, rr::readVertexAttribUint (inputs[attribNdx], packet.instanceNdx, packet.vertexNdx), attribNdx == 0, numComponents); break;
|
|
default:
|
|
DE_ASSERT(false);
|
|
}
|
|
}
|
|
|
|
// Transform position
|
|
{
|
|
packet.position = tcu::Vec4(u_coordScale * coord.x(), u_coordScale * coord.y(), 1.0f, 1.0f);
|
|
}
|
|
|
|
// Pass color to FS
|
|
{
|
|
packet.outputs[varyingLocColor] = tcu::Vec4(u_colorScale * color.x(), u_colorScale * color.y(), u_colorScale * color.z(), 1.0f);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ContextShaderProgram::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
|
|
{
|
|
const size_t varyingLocColor = 0;
|
|
|
|
// Triangles are flashaded
|
|
tcu::Vec4 color = rr::readTriangleVarying<float>(packets[0], context, varyingLocColor, 0);
|
|
|
|
for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
|
|
for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
|
|
rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
|
|
}
|
|
|
|
std::string ContextShaderProgram::genVertexSource (const glu::RenderContext& ctx, const std::vector<ContextArray*>& arrays)
|
|
{
|
|
std::stringstream vertexShaderTmpl;
|
|
std::map<std::string, std::string> params;
|
|
|
|
if (glu::isGLSLVersionSupported(ctx.getType(), glu::GLSL_VERSION_300_ES))
|
|
{
|
|
params["VTX_IN"] = "in";
|
|
params["VTX_OUT"] = "out";
|
|
params["FRAG_IN"] = "in";
|
|
params["FRAG_COLOR"] = "dEQP_FragColor";
|
|
params["VTX_HDR"] = "#version 300 es\n";
|
|
params["FRAG_HDR"] = "#version 300 es\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n";
|
|
}
|
|
else if (glu::isGLSLVersionSupported(ctx.getType(), glu::GLSL_VERSION_100_ES))
|
|
{
|
|
params["VTX_IN"] = "attribute";
|
|
params["VTX_OUT"] = "varying";
|
|
params["FRAG_IN"] = "varying";
|
|
params["FRAG_COLOR"] = "gl_FragColor";
|
|
params["VTX_HDR"] = "";
|
|
params["FRAG_HDR"] = "";
|
|
}
|
|
else if (glu::isGLSLVersionSupported(ctx.getType(), glu::GLSL_VERSION_330))
|
|
{
|
|
params["VTX_IN"] = "in";
|
|
params["VTX_OUT"] = "out";
|
|
params["FRAG_IN"] = "in";
|
|
params["FRAG_COLOR"] = "dEQP_FragColor";
|
|
params["VTX_HDR"] = "#version 330\n";
|
|
params["FRAG_HDR"] = "#version 330\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n";
|
|
}
|
|
else
|
|
DE_ASSERT(DE_FALSE);
|
|
|
|
vertexShaderTmpl << "${VTX_HDR}";
|
|
|
|
for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
|
|
{
|
|
vertexShaderTmpl
|
|
<< "${VTX_IN} highp " << ContextArray::outputTypeToGLType(arrays[arrayNdx]->getOutputType()) << " a_" << arrays[arrayNdx]->getAttribNdx() << ";\n";
|
|
}
|
|
|
|
vertexShaderTmpl <<
|
|
"uniform highp float u_coordScale;\n"
|
|
"uniform highp float u_colorScale;\n"
|
|
"${VTX_OUT} mediump vec4 v_color;\n"
|
|
"void main(void)\n"
|
|
"{\n"
|
|
"\tgl_PointSize = 1.0;\n"
|
|
"\thighp vec2 coord = vec2(1.0, 1.0);\n"
|
|
"\thighp vec3 color = vec3(1.0, 1.0, 1.0);\n";
|
|
|
|
for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
|
|
{
|
|
if (arrays[arrayNdx]->getAttribNdx() == 0)
|
|
{
|
|
switch (arrays[arrayNdx]->getOutputType())
|
|
{
|
|
case (Array::OUTPUTTYPE_FLOAT):
|
|
vertexShaderTmpl <<
|
|
"\tcoord = vec2(a_0);\n";
|
|
break;
|
|
|
|
case (Array::OUTPUTTYPE_VEC2):
|
|
vertexShaderTmpl <<
|
|
"\tcoord = a_0.xy;\n";
|
|
break;
|
|
|
|
case (Array::OUTPUTTYPE_VEC3):
|
|
vertexShaderTmpl <<
|
|
"\tcoord = a_0.xy;\n"
|
|
"\tcoord.x = coord.x + a_0.z;\n";
|
|
break;
|
|
|
|
case (Array::OUTPUTTYPE_VEC4):
|
|
vertexShaderTmpl <<
|
|
"\tcoord = a_0.xy;\n"
|
|
"\tcoord += a_0.zw;\n";
|
|
break;
|
|
|
|
case (Array::OUTPUTTYPE_IVEC2):
|
|
case (Array::OUTPUTTYPE_UVEC2):
|
|
vertexShaderTmpl <<
|
|
"\tcoord = vec2(a_0.xy);\n";
|
|
break;
|
|
|
|
case (Array::OUTPUTTYPE_IVEC3):
|
|
case (Array::OUTPUTTYPE_UVEC3):
|
|
vertexShaderTmpl <<
|
|
"\tcoord = vec2(a_0.xy);\n"
|
|
"\tcoord.x = coord.x + float(a_0.z);\n";
|
|
break;
|
|
|
|
case (Array::OUTPUTTYPE_IVEC4):
|
|
case (Array::OUTPUTTYPE_UVEC4):
|
|
vertexShaderTmpl <<
|
|
"\tcoord = vec2(a_0.xy);\n"
|
|
"\tcoord += vec2(a_0.zw);\n";
|
|
break;
|
|
|
|
default:
|
|
DE_ASSERT(false);
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
switch (arrays[arrayNdx]->getOutputType())
|
|
{
|
|
case (Array::OUTPUTTYPE_FLOAT):
|
|
vertexShaderTmpl <<
|
|
"\tcolor = color * a_" << arrays[arrayNdx]->getAttribNdx() << ";\n";
|
|
break;
|
|
|
|
case (Array::OUTPUTTYPE_VEC2):
|
|
vertexShaderTmpl <<
|
|
"\tcolor.rg = color.rg * a_" << arrays[arrayNdx]->getAttribNdx() << ".xy;\n";
|
|
break;
|
|
|
|
case (Array::OUTPUTTYPE_VEC3):
|
|
vertexShaderTmpl <<
|
|
"\tcolor = color.rgb * a_" << arrays[arrayNdx]->getAttribNdx() << ".xyz;\n";
|
|
break;
|
|
|
|
case (Array::OUTPUTTYPE_VEC4):
|
|
vertexShaderTmpl <<
|
|
"\tcolor = color.rgb * a_" << arrays[arrayNdx]->getAttribNdx() << ".xyz * a_" << arrays[arrayNdx]->getAttribNdx() << ".w;\n";
|
|
break;
|
|
|
|
default:
|
|
DE_ASSERT(false);
|
|
break;
|
|
}
|
|
}
|
|
|
|
vertexShaderTmpl <<
|
|
"\tv_color = vec4(u_colorScale * color, 1.0);\n"
|
|
"\tgl_Position = vec4(u_coordScale * coord, 1.0, 1.0);\n"
|
|
"}\n";
|
|
|
|
return tcu::StringTemplate(vertexShaderTmpl.str().c_str()).specialize(params);
|
|
}
|
|
|
|
std::string ContextShaderProgram::genFragmentSource (const glu::RenderContext& ctx)
|
|
{
|
|
std::map<std::string, std::string> params;
|
|
|
|
if (glu::isGLSLVersionSupported(ctx.getType(), glu::GLSL_VERSION_300_ES))
|
|
{
|
|
params["VTX_IN"] = "in";
|
|
params["VTX_OUT"] = "out";
|
|
params["FRAG_IN"] = "in";
|
|
params["FRAG_COLOR"] = "dEQP_FragColor";
|
|
params["VTX_HDR"] = "#version 300 es\n";
|
|
params["FRAG_HDR"] = "#version 300 es\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n";
|
|
}
|
|
else if (glu::isGLSLVersionSupported(ctx.getType(), glu::GLSL_VERSION_100_ES))
|
|
{
|
|
params["VTX_IN"] = "attribute";
|
|
params["VTX_OUT"] = "varying";
|
|
params["FRAG_IN"] = "varying";
|
|
params["FRAG_COLOR"] = "gl_FragColor";
|
|
params["VTX_HDR"] = "";
|
|
params["FRAG_HDR"] = "";
|
|
}
|
|
else if (glu::isGLSLVersionSupported(ctx.getType(), glu::GLSL_VERSION_330))
|
|
{
|
|
params["VTX_IN"] = "in";
|
|
params["VTX_OUT"] = "out";
|
|
params["FRAG_IN"] = "in";
|
|
params["FRAG_COLOR"] = "dEQP_FragColor";
|
|
params["VTX_HDR"] = "#version 330\n";
|
|
params["FRAG_HDR"] = "#version 330\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n";
|
|
}
|
|
else
|
|
DE_ASSERT(DE_FALSE);
|
|
|
|
static const char* fragmentShaderTmpl =
|
|
"${FRAG_HDR}"
|
|
"${FRAG_IN} mediump vec4 v_color;\n"
|
|
"void main(void)\n"
|
|
"{\n"
|
|
"\t${FRAG_COLOR} = v_color;\n"
|
|
"}\n";
|
|
|
|
return tcu::StringTemplate(fragmentShaderTmpl).specialize(params);
|
|
}
|
|
|
|
rr::GenericVecType ContextShaderProgram::mapOutputType (const Array::OutputType& type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case (Array::OUTPUTTYPE_FLOAT):
|
|
case (Array::OUTPUTTYPE_VEC2):
|
|
case (Array::OUTPUTTYPE_VEC3):
|
|
case (Array::OUTPUTTYPE_VEC4):
|
|
return rr::GENERICVECTYPE_FLOAT;
|
|
|
|
case (Array::OUTPUTTYPE_INT):
|
|
case (Array::OUTPUTTYPE_IVEC2):
|
|
case (Array::OUTPUTTYPE_IVEC3):
|
|
case (Array::OUTPUTTYPE_IVEC4):
|
|
return rr::GENERICVECTYPE_INT32;
|
|
|
|
case (Array::OUTPUTTYPE_UINT):
|
|
case (Array::OUTPUTTYPE_UVEC2):
|
|
case (Array::OUTPUTTYPE_UVEC3):
|
|
case (Array::OUTPUTTYPE_UVEC4):
|
|
return rr::GENERICVECTYPE_UINT32;
|
|
|
|
default:
|
|
DE_ASSERT(false);
|
|
return rr::GENERICVECTYPE_LAST;
|
|
}
|
|
}
|
|
|
|
int ContextShaderProgram::getComponentCount (const Array::OutputType& type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case (Array::OUTPUTTYPE_FLOAT):
|
|
case (Array::OUTPUTTYPE_INT):
|
|
case (Array::OUTPUTTYPE_UINT):
|
|
return 1;
|
|
|
|
case (Array::OUTPUTTYPE_VEC2):
|
|
case (Array::OUTPUTTYPE_IVEC2):
|
|
case (Array::OUTPUTTYPE_UVEC2):
|
|
return 2;
|
|
|
|
case (Array::OUTPUTTYPE_VEC3):
|
|
case (Array::OUTPUTTYPE_IVEC3):
|
|
case (Array::OUTPUTTYPE_UVEC3):
|
|
return 3;
|
|
|
|
case (Array::OUTPUTTYPE_VEC4):
|
|
case (Array::OUTPUTTYPE_IVEC4):
|
|
case (Array::OUTPUTTYPE_UVEC4):
|
|
return 4;
|
|
|
|
default:
|
|
DE_ASSERT(false);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
sglr::pdec::ShaderProgramDeclaration ContextShaderProgram::createProgramDeclaration (const glu::RenderContext& ctx, const std::vector<ContextArray*>& arrays)
|
|
{
|
|
sglr::pdec::ShaderProgramDeclaration decl;
|
|
|
|
for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
|
|
decl << sglr::pdec::VertexAttribute(std::string("a_") + de::toString(arrayNdx), mapOutputType(arrays[arrayNdx]->getOutputType()));
|
|
|
|
decl << sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT);
|
|
decl << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT);
|
|
|
|
decl << sglr::pdec::VertexSource(genVertexSource(ctx, arrays));
|
|
decl << sglr::pdec::FragmentSource(genFragmentSource(ctx));
|
|
|
|
decl << sglr::pdec::Uniform("u_coordScale", glu::TYPE_FLOAT);
|
|
decl << sglr::pdec::Uniform("u_colorScale", glu::TYPE_FLOAT);
|
|
|
|
return decl;
|
|
}
|
|
|
|
void ContextArrayPack::updateProgram (void)
|
|
{
|
|
delete m_program;
|
|
m_program = new ContextShaderProgram(m_renderCtx, m_arrays);
|
|
}
|
|
|
|
void ContextArrayPack::render (Array::Primitive primitive, int firstVertex, int vertexCount, bool useVao, float coordScale, float colorScale)
|
|
{
|
|
deUint32 program = 0;
|
|
deUint32 vaoId = 0;
|
|
|
|
updateProgram();
|
|
|
|
m_ctx.viewport(0, 0, m_screen.getWidth(), m_screen.getHeight());
|
|
m_ctx.clearColor(0.0, 0.0, 0.0, 1.0);
|
|
m_ctx.clear(GL_COLOR_BUFFER_BIT);
|
|
|
|
program = m_ctx.createProgram(m_program);
|
|
|
|
m_ctx.useProgram(program);
|
|
GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glUseProgram()");
|
|
|
|
m_ctx.uniform1f(m_ctx.getUniformLocation(program, "u_coordScale"), coordScale);
|
|
m_ctx.uniform1f(m_ctx.getUniformLocation(program, "u_colorScale"), colorScale);
|
|
|
|
if (useVao)
|
|
{
|
|
m_ctx.genVertexArrays(1, &vaoId);
|
|
m_ctx.bindVertexArray(vaoId);
|
|
}
|
|
|
|
for (int arrayNdx = 0; arrayNdx < (int)m_arrays.size(); arrayNdx++)
|
|
{
|
|
if (m_arrays[arrayNdx]->isBound())
|
|
{
|
|
std::stringstream attribName;
|
|
attribName << "a_" << m_arrays[arrayNdx]->getAttribNdx();
|
|
|
|
deUint32 loc = m_ctx.getAttribLocation(program, attribName.str().c_str());
|
|
m_ctx.enableVertexAttribArray(loc);
|
|
GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glEnableVertexAttribArray()");
|
|
|
|
m_arrays[arrayNdx]->glBind(loc);
|
|
}
|
|
}
|
|
|
|
DE_ASSERT((firstVertex % 6) == 0);
|
|
m_ctx.drawArrays(ContextArray::primitiveToGL(primitive), firstVertex, vertexCount - firstVertex);
|
|
GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawArrays()");
|
|
|
|
for (int arrayNdx = 0; arrayNdx < (int)m_arrays.size(); arrayNdx++)
|
|
{
|
|
if (m_arrays[arrayNdx]->isBound())
|
|
{
|
|
std::stringstream attribName;
|
|
attribName << "a_" << m_arrays[arrayNdx]->getAttribNdx();
|
|
|
|
deUint32 loc = m_ctx.getAttribLocation(program, attribName.str().c_str());
|
|
|
|
m_ctx.disableVertexAttribArray(loc);
|
|
GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDisableVertexAttribArray()");
|
|
}
|
|
}
|
|
|
|
if (useVao)
|
|
m_ctx.deleteVertexArrays(1, &vaoId);
|
|
|
|
m_ctx.deleteProgram(program);
|
|
m_ctx.useProgram(0);
|
|
m_ctx.readPixels(m_screen, 0, 0, m_screen.getWidth(), m_screen.getHeight());
|
|
}
|
|
|
|
// GLValue
|
|
|
|
GLValue GLValue::getMaxValue (Array::InputType type)
|
|
{
|
|
GLValue rangesHi[(int)Array::INPUTTYPE_LAST];
|
|
|
|
rangesHi[(int)Array::INPUTTYPE_FLOAT] = GLValue(Float::create(127.0f));
|
|
rangesHi[(int)Array::INPUTTYPE_DOUBLE] = GLValue(Double::create(127.0f));
|
|
rangesHi[(int)Array::INPUTTYPE_BYTE] = GLValue(Byte::create(127));
|
|
rangesHi[(int)Array::INPUTTYPE_UNSIGNED_BYTE] = GLValue(Ubyte::create(255));
|
|
rangesHi[(int)Array::INPUTTYPE_UNSIGNED_SHORT] = GLValue(Ushort::create(65530));
|
|
rangesHi[(int)Array::INPUTTYPE_SHORT] = GLValue(Short::create(32760));
|
|
rangesHi[(int)Array::INPUTTYPE_FIXED] = GLValue(Fixed::create(32760));
|
|
rangesHi[(int)Array::INPUTTYPE_INT] = GLValue(Int::create(2147483647));
|
|
rangesHi[(int)Array::INPUTTYPE_UNSIGNED_INT] = GLValue(Uint::create(4294967295u));
|
|
rangesHi[(int)Array::INPUTTYPE_HALF] = GLValue(Half::create(256.0f));
|
|
|
|
return rangesHi[(int)type];
|
|
}
|
|
|
|
GLValue GLValue::getMinValue (Array::InputType type)
|
|
{
|
|
GLValue rangesLo[(int)Array::INPUTTYPE_LAST];
|
|
|
|
rangesLo[(int)Array::INPUTTYPE_FLOAT] = GLValue(Float::create(-127.0f));
|
|
rangesLo[(int)Array::INPUTTYPE_DOUBLE] = GLValue(Double::create(-127.0f));
|
|
rangesLo[(int)Array::INPUTTYPE_BYTE] = GLValue(Byte::create(-127));
|
|
rangesLo[(int)Array::INPUTTYPE_UNSIGNED_BYTE] = GLValue(Ubyte::create(0));
|
|
rangesLo[(int)Array::INPUTTYPE_UNSIGNED_SHORT] = GLValue(Ushort::create(0));
|
|
rangesLo[(int)Array::INPUTTYPE_SHORT] = GLValue(Short::create(-32760));
|
|
rangesLo[(int)Array::INPUTTYPE_FIXED] = GLValue(Fixed::create(-32760));
|
|
rangesLo[(int)Array::INPUTTYPE_INT] = GLValue(Int::create(-2147483647));
|
|
rangesLo[(int)Array::INPUTTYPE_UNSIGNED_INT] = GLValue(Uint::create(0));
|
|
rangesLo[(int)Array::INPUTTYPE_HALF] = GLValue(Half::create(-256.0f));
|
|
|
|
return rangesLo[(int)type];
|
|
}
|
|
|
|
float GLValue::toFloat (void) const
|
|
{
|
|
switch (type)
|
|
{
|
|
case Array::INPUTTYPE_FLOAT:
|
|
return fl.getValue();
|
|
break;
|
|
|
|
case Array::INPUTTYPE_BYTE:
|
|
return b.getValue();
|
|
break;
|
|
|
|
case Array::INPUTTYPE_UNSIGNED_BYTE:
|
|
return ub.getValue();
|
|
break;
|
|
|
|
case Array::INPUTTYPE_SHORT:
|
|
return s.getValue();
|
|
break;
|
|
|
|
case Array::INPUTTYPE_UNSIGNED_SHORT:
|
|
return us.getValue();
|
|
break;
|
|
|
|
case Array::INPUTTYPE_FIXED:
|
|
{
|
|
int maxValue = 65536;
|
|
return (float)(double(2 * fi.getValue() + 1) / (maxValue - 1));
|
|
|
|
break;
|
|
}
|
|
|
|
case Array::INPUTTYPE_UNSIGNED_INT:
|
|
return (float)ui.getValue();
|
|
break;
|
|
|
|
case Array::INPUTTYPE_INT:
|
|
return (float)i.getValue();
|
|
break;
|
|
|
|
case Array::INPUTTYPE_HALF:
|
|
return h.to<float>();
|
|
break;
|
|
|
|
case Array::INPUTTYPE_DOUBLE:
|
|
return (float)d.getValue();
|
|
break;
|
|
|
|
default:
|
|
DE_ASSERT(false);
|
|
return 0.0f;
|
|
break;
|
|
};
|
|
}
|
|
|
|
class RandomArrayGenerator
|
|
{
|
|
public:
|
|
static char* generateArray (int seed, GLValue min, GLValue max, int count, int componentCount, int stride, Array::InputType type);
|
|
static char* generateQuads (int seed, int count, int componentCount, int offset, int stride, Array::Primitive primitive, Array::InputType type, GLValue min, GLValue max, float gridSize);
|
|
static char* generatePerQuad (int seed, int count, int componentCount, int stride, Array::Primitive primitive, Array::InputType type, GLValue min, GLValue max);
|
|
|
|
private:
|
|
template<typename T>
|
|
static char* createQuads (int seed, int count, int componentCount, int offset, int stride, Array::Primitive primitive, T min, T max, float gridSize);
|
|
template<typename T>
|
|
static char* createPerQuads (int seed, int count, int componentCount, int stride, Array::Primitive primitive, T min, T max);
|
|
static char* createQuadsPacked (int seed, int count, int componentCount, int offset, int stride, Array::Primitive primitive);
|
|
static void setData (char* data, Array::InputType type, deRandom& rnd, GLValue min, GLValue max);
|
|
};
|
|
|
|
void RandomArrayGenerator::setData (char* data, Array::InputType type, deRandom& rnd, GLValue min, GLValue max)
|
|
{
|
|
switch (type)
|
|
{
|
|
case Array::INPUTTYPE_FLOAT:
|
|
{
|
|
alignmentSafeAssignment<float>(data, getRandom<GLValue::Float>(rnd, min.fl, max.fl));
|
|
break;
|
|
}
|
|
|
|
case Array::INPUTTYPE_DOUBLE:
|
|
{
|
|
alignmentSafeAssignment<double>(data, getRandom<GLValue::Float>(rnd, min.fl, max.fl));
|
|
break;
|
|
}
|
|
|
|
case Array::INPUTTYPE_SHORT:
|
|
{
|
|
alignmentSafeAssignment<deInt16>(data, getRandom<GLValue::Short>(rnd, min.s, max.s));
|
|
break;
|
|
}
|
|
|
|
case Array::INPUTTYPE_UNSIGNED_SHORT:
|
|
{
|
|
alignmentSafeAssignment<deUint16>(data, getRandom<GLValue::Ushort>(rnd, min.us, max.us));
|
|
break;
|
|
}
|
|
|
|
case Array::INPUTTYPE_BYTE:
|
|
{
|
|
alignmentSafeAssignment<deInt8>(data, getRandom<GLValue::Byte>(rnd, min.b, max.b));
|
|
break;
|
|
}
|
|
|
|
case Array::INPUTTYPE_UNSIGNED_BYTE:
|
|
{
|
|
alignmentSafeAssignment<deUint8>(data, getRandom<GLValue::Ubyte>(rnd, min.ub, max.ub));
|
|
break;
|
|
}
|
|
|
|
case Array::INPUTTYPE_FIXED:
|
|
{
|
|
alignmentSafeAssignment<deInt32>(data, getRandom<GLValue::Fixed>(rnd, min.fi, max.fi));
|
|
break;
|
|
}
|
|
|
|
case Array::INPUTTYPE_INT:
|
|
{
|
|
alignmentSafeAssignment<deInt32>(data, getRandom<GLValue::Int>(rnd, min.i, max.i));
|
|
break;
|
|
}
|
|
|
|
case Array::INPUTTYPE_UNSIGNED_INT:
|
|
{
|
|
alignmentSafeAssignment<deUint32>(data, getRandom<GLValue::Uint>(rnd, min.ui, max.ui));
|
|
break;
|
|
}
|
|
|
|
case Array::INPUTTYPE_HALF:
|
|
{
|
|
alignmentSafeAssignment<deFloat16>(data, getRandom<GLValue::Half>(rnd, min.h, max.h).getValue());
|
|
break;
|
|
}
|
|
|
|
default:
|
|
DE_ASSERT(false);
|
|
break;
|
|
}
|
|
}
|
|
|
|
char* RandomArrayGenerator::generateArray (int seed, GLValue min, GLValue max, int count, int componentCount, int stride, Array::InputType type)
|
|
{
|
|
char* data = NULL;
|
|
|
|
deRandom rnd;
|
|
deRandom_init(&rnd, seed);
|
|
|
|
if (stride == 0)
|
|
stride = componentCount * Array::inputTypeSize(type);
|
|
|
|
data = new char[stride * count];
|
|
|
|
for (int vertexNdx = 0; vertexNdx < count; vertexNdx++)
|
|
{
|
|
for (int componentNdx = 0; componentNdx < componentCount; componentNdx++)
|
|
{
|
|
setData(&(data[vertexNdx * stride + Array::inputTypeSize(type) * componentNdx]), type, rnd, min, max);
|
|
}
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
char* RandomArrayGenerator::generateQuads (int seed, int count, int componentCount, int offset, int stride, Array::Primitive primitive, Array::InputType type, GLValue min, GLValue max, float gridSize)
|
|
{
|
|
char* data = DE_NULL;
|
|
|
|
switch (type)
|
|
{
|
|
case Array::INPUTTYPE_FLOAT:
|
|
data = createQuads<GLValue::Float>(seed, count, componentCount, offset, stride, primitive, min.fl, max.fl, gridSize);
|
|
break;
|
|
|
|
case Array::INPUTTYPE_FIXED:
|
|
data = createQuads<GLValue::Fixed>(seed, count, componentCount, offset, stride, primitive, min.fi, max.fi, gridSize);
|
|
break;
|
|
|
|
case Array::INPUTTYPE_DOUBLE:
|
|
data = createQuads<GLValue::Double>(seed, count, componentCount, offset, stride, primitive, min.d, max.d, gridSize);
|
|
break;
|
|
|
|
case Array::INPUTTYPE_BYTE:
|
|
data = createQuads<GLValue::Byte>(seed, count, componentCount, offset, stride, primitive, min.b, max.b, gridSize);
|
|
break;
|
|
|
|
case Array::INPUTTYPE_SHORT:
|
|
data = createQuads<GLValue::Short>(seed, count, componentCount, offset, stride, primitive, min.s, max.s, gridSize);
|
|
break;
|
|
|
|
case Array::INPUTTYPE_UNSIGNED_BYTE:
|
|
data = createQuads<GLValue::Ubyte>(seed, count, componentCount, offset, stride, primitive, min.ub, max.ub, gridSize);
|
|
break;
|
|
|
|
case Array::INPUTTYPE_UNSIGNED_SHORT:
|
|
data = createQuads<GLValue::Ushort>(seed, count, componentCount, offset, stride, primitive, min.us, max.us, gridSize);
|
|
break;
|
|
|
|
case Array::INPUTTYPE_UNSIGNED_INT:
|
|
data = createQuads<GLValue::Uint>(seed, count, componentCount, offset, stride, primitive, min.ui, max.ui, gridSize);
|
|
break;
|
|
|
|
case Array::INPUTTYPE_INT:
|
|
data = createQuads<GLValue::Int>(seed, count, componentCount, offset, stride, primitive, min.i, max.i, gridSize);
|
|
break;
|
|
|
|
case Array::INPUTTYPE_HALF:
|
|
data = createQuads<GLValue::Half>(seed, count, componentCount, offset, stride, primitive, min.h, max.h, gridSize);
|
|
break;
|
|
|
|
case Array::INPUTTYPE_INT_2_10_10_10:
|
|
case Array::INPUTTYPE_UNSIGNED_INT_2_10_10_10:
|
|
data = createQuadsPacked(seed, count, componentCount, offset, stride, primitive);
|
|
break;
|
|
|
|
default:
|
|
DE_ASSERT(false);
|
|
break;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
char* RandomArrayGenerator::createQuadsPacked (int seed, int count, int componentCount, int offset, int stride, Array::Primitive primitive)
|
|
{
|
|
DE_ASSERT(componentCount == 4);
|
|
DE_UNREF(componentCount);
|
|
int quadStride = 0;
|
|
|
|
if (stride == 0)
|
|
stride = sizeof(deUint32);
|
|
|
|
switch (primitive)
|
|
{
|
|
case Array::PRIMITIVE_TRIANGLES:
|
|
quadStride = stride * 6;
|
|
break;
|
|
|
|
default:
|
|
DE_ASSERT(false);
|
|
break;
|
|
}
|
|
|
|
char* const _data = new char[offset + quadStride * (count - 1) + stride * 5 + componentCount * Array::inputTypeSize(Array::INPUTTYPE_INT_2_10_10_10)]; // last element must be fully in the array
|
|
char* const resultData = _data + offset;
|
|
|
|
const deUint32 max = 1024;
|
|
const deUint32 min = 10;
|
|
const deUint32 max2 = 4;
|
|
|
|
deRandom rnd;
|
|
deRandom_init(&rnd, seed);
|
|
|
|
switch (primitive)
|
|
{
|
|
case Array::PRIMITIVE_TRIANGLES:
|
|
{
|
|
for (int quadNdx = 0; quadNdx < count; quadNdx++)
|
|
{
|
|
deUint32 x1 = min + deRandom_getUint32(&rnd) % (max - min);
|
|
deUint32 x2 = min + deRandom_getUint32(&rnd) % (max - x1);
|
|
|
|
deUint32 y1 = min + deRandom_getUint32(&rnd) % (max - min);
|
|
deUint32 y2 = min + deRandom_getUint32(&rnd) % (max - y1);
|
|
|
|
deUint32 z = min + deRandom_getUint32(&rnd) % (max - min);
|
|
deUint32 w = deRandom_getUint32(&rnd) % max2;
|
|
|
|
deUint32 val1 = (w << 30) | (z << 20) | (y1 << 10) | x1;
|
|
deUint32 val2 = (w << 30) | (z << 20) | (y1 << 10) | x2;
|
|
deUint32 val3 = (w << 30) | (z << 20) | (y2 << 10) | x1;
|
|
|
|
deUint32 val4 = (w << 30) | (z << 20) | (y2 << 10) | x1;
|
|
deUint32 val5 = (w << 30) | (z << 20) | (y1 << 10) | x2;
|
|
deUint32 val6 = (w << 30) | (z << 20) | (y2 << 10) | x2;
|
|
|
|
alignmentSafeAssignment<deUint32>(&(resultData[quadNdx * quadStride + stride * 0]), val1);
|
|
alignmentSafeAssignment<deUint32>(&(resultData[quadNdx * quadStride + stride * 1]), val2);
|
|
alignmentSafeAssignment<deUint32>(&(resultData[quadNdx * quadStride + stride * 2]), val3);
|
|
alignmentSafeAssignment<deUint32>(&(resultData[quadNdx * quadStride + stride * 3]), val4);
|
|
alignmentSafeAssignment<deUint32>(&(resultData[quadNdx * quadStride + stride * 4]), val5);
|
|
alignmentSafeAssignment<deUint32>(&(resultData[quadNdx * quadStride + stride * 5]), val6);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
DE_ASSERT(false);
|
|
break;
|
|
}
|
|
|
|
return _data;
|
|
}
|
|
|
|
template<typename T>
|
|
T roundTo (const T& step, const T& value)
|
|
{
|
|
return value - (value % step);
|
|
}
|
|
|
|
template<typename T>
|
|
char* RandomArrayGenerator::createQuads (int seed, int count, int componentCount, int offset, int stride, Array::Primitive primitive, T min, T max, float gridSize)
|
|
{
|
|
int componentStride = sizeof(T);
|
|
int quadStride = 0;
|
|
|
|
if (stride == 0)
|
|
stride = componentCount * componentStride;
|
|
|
|
DE_ASSERT(stride >= componentCount * componentStride);
|
|
|
|
switch (primitive)
|
|
{
|
|
case Array::PRIMITIVE_TRIANGLES:
|
|
quadStride = stride * 6;
|
|
break;
|
|
|
|
default:
|
|
DE_ASSERT(false);
|
|
break;
|
|
}
|
|
|
|
char* resultData = new char[offset + quadStride * count];
|
|
char* _data = resultData;
|
|
resultData = resultData + offset;
|
|
|
|
deRandom rnd;
|
|
deRandom_init(&rnd, seed);
|
|
|
|
switch (primitive)
|
|
{
|
|
case Array::PRIMITIVE_TRIANGLES:
|
|
{
|
|
const T minQuadSize = T::fromFloat(deFloatAbs(max.template to<float>() - min.template to<float>()) * gridSize);
|
|
const T minDiff = minValue<T>() > minQuadSize
|
|
? minValue<T>()
|
|
: minQuadSize;
|
|
|
|
for (int quadNdx = 0; quadNdx < count; ++quadNdx)
|
|
{
|
|
T x1, x2;
|
|
T y1, y2;
|
|
T z, w;
|
|
|
|
// attempt to find a good (i.e not extremely small) quad
|
|
for (int attemptNdx = 0; attemptNdx < 4; ++attemptNdx)
|
|
{
|
|
x1 = roundTo(minDiff, getRandom<T>(rnd, min, max));
|
|
x2 = roundTo(minDiff, getRandom<T>(rnd, minDiff, abs<T>(max - x1)));
|
|
|
|
y1 = roundTo(minDiff, getRandom<T>(rnd, min, max));
|
|
y2 = roundTo(minDiff, getRandom<T>(rnd, minDiff, abs<T>(max - y1)));
|
|
|
|
z = (componentCount > 2) ? roundTo(minDiff, (getRandom<T>(rnd, min, max))) : (T::create(0));
|
|
w = (componentCount > 3) ? roundTo(minDiff, (getRandom<T>(rnd, min, max))) : (T::create(1));
|
|
|
|
// no additional components, all is good
|
|
if (componentCount <= 2)
|
|
break;
|
|
|
|
// The result quad is too thin?
|
|
if ((deFloatAbs(x2.template to<float>() + z.template to<float>()) < minDiff.template to<float>()) ||
|
|
(deFloatAbs(y2.template to<float>() + w.template to<float>()) < minDiff.template to<float>()))
|
|
continue;
|
|
|
|
// all ok
|
|
break;
|
|
}
|
|
|
|
alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride]), x1);
|
|
alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + componentStride]), y1);
|
|
|
|
alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride]), x1 + x2);
|
|
alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride + componentStride]), y1);
|
|
|
|
alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 2]), x1);
|
|
alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 2 + componentStride]), y1 + y2);
|
|
|
|
alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 3]), x1);
|
|
alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 3 + componentStride]), y1 + y2);
|
|
|
|
alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 4]), x1 + x2);
|
|
alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 4 + componentStride]), y1);
|
|
|
|
alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 5]), x1 + x2);
|
|
alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 5 + componentStride]), y1 + y2);
|
|
|
|
if (componentCount > 2)
|
|
{
|
|
for (int i = 0; i < 6; i++)
|
|
alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * i + componentStride * 2]), z);
|
|
}
|
|
|
|
if (componentCount > 3)
|
|
{
|
|
for (int i = 0; i < 6; i++)
|
|
alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * i + componentStride * 3]), w);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
DE_ASSERT(false);
|
|
break;
|
|
}
|
|
|
|
return _data;
|
|
}
|
|
|
|
char* RandomArrayGenerator::generatePerQuad (int seed, int count, int componentCount, int stride, Array::Primitive primitive, Array::InputType type, GLValue min, GLValue max)
|
|
{
|
|
char* data = DE_NULL;
|
|
|
|
switch (type)
|
|
{
|
|
case Array::INPUTTYPE_FLOAT:
|
|
data = createPerQuads<GLValue::Float>(seed, count, componentCount, stride, primitive, min.fl, max.fl);
|
|
break;
|
|
|
|
case Array::INPUTTYPE_FIXED:
|
|
data = createPerQuads<GLValue::Fixed>(seed, count, componentCount, stride, primitive, min.fi, max.fi);
|
|
break;
|
|
|
|
case Array::INPUTTYPE_DOUBLE:
|
|
data = createPerQuads<GLValue::Double>(seed, count, componentCount, stride, primitive, min.d, max.d);
|
|
break;
|
|
|
|
case Array::INPUTTYPE_BYTE:
|
|
data = createPerQuads<GLValue::Byte>(seed, count, componentCount, stride, primitive, min.b, max.b);
|
|
break;
|
|
|
|
case Array::INPUTTYPE_SHORT:
|
|
data = createPerQuads<GLValue::Short>(seed, count, componentCount, stride, primitive, min.s, max.s);
|
|
break;
|
|
|
|
case Array::INPUTTYPE_UNSIGNED_BYTE:
|
|
data = createPerQuads<GLValue::Ubyte>(seed, count, componentCount, stride, primitive, min.ub, max.ub);
|
|
break;
|
|
|
|
case Array::INPUTTYPE_UNSIGNED_SHORT:
|
|
data = createPerQuads<GLValue::Ushort>(seed, count, componentCount, stride, primitive, min.us, max.us);
|
|
break;
|
|
|
|
case Array::INPUTTYPE_UNSIGNED_INT:
|
|
data = createPerQuads<GLValue::Uint>(seed, count, componentCount, stride, primitive, min.ui, max.ui);
|
|
break;
|
|
|
|
case Array::INPUTTYPE_INT:
|
|
data = createPerQuads<GLValue::Int>(seed, count, componentCount, stride, primitive, min.i, max.i);
|
|
break;
|
|
|
|
case Array::INPUTTYPE_HALF:
|
|
data = createPerQuads<GLValue::Half>(seed, count, componentCount, stride, primitive, min.h, max.h);
|
|
break;
|
|
|
|
default:
|
|
DE_ASSERT(false);
|
|
break;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
template<typename T>
|
|
char* RandomArrayGenerator::createPerQuads (int seed, int count, int componentCount, int stride, Array::Primitive primitive, T min, T max)
|
|
{
|
|
deRandom rnd;
|
|
deRandom_init(&rnd, seed);
|
|
|
|
int componentStride = sizeof(T);
|
|
|
|
if (stride == 0)
|
|
stride = componentStride * componentCount;
|
|
|
|
int quadStride = 0;
|
|
|
|
switch (primitive)
|
|
{
|
|
case Array::PRIMITIVE_TRIANGLES:
|
|
quadStride = stride * 6;
|
|
break;
|
|
|
|
default:
|
|
DE_ASSERT(false);
|
|
break;
|
|
}
|
|
|
|
char* data = new char[count * quadStride];
|
|
|
|
for (int quadNdx = 0; quadNdx < count; quadNdx++)
|
|
{
|
|
for (int componentNdx = 0; componentNdx < componentCount; componentNdx++)
|
|
{
|
|
T val = getRandom<T>(rnd, min, max);
|
|
|
|
alignmentSafeAssignment<T>(data + quadNdx * quadStride + stride * 0 + componentStride * componentNdx, val);
|
|
alignmentSafeAssignment<T>(data + quadNdx * quadStride + stride * 1 + componentStride * componentNdx, val);
|
|
alignmentSafeAssignment<T>(data + quadNdx * quadStride + stride * 2 + componentStride * componentNdx, val);
|
|
alignmentSafeAssignment<T>(data + quadNdx * quadStride + stride * 3 + componentStride * componentNdx, val);
|
|
alignmentSafeAssignment<T>(data + quadNdx * quadStride + stride * 4 + componentStride * componentNdx, val);
|
|
alignmentSafeAssignment<T>(data + quadNdx * quadStride + stride * 5 + componentStride * componentNdx, val);
|
|
}
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
// VertexArrayTest
|
|
|
|
VertexArrayTest::VertexArrayTest (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name ,const char* desc)
|
|
: TestCase (testCtx, name, desc)
|
|
, m_renderCtx (renderCtx)
|
|
, m_refBuffers (DE_NULL)
|
|
, m_refContext (DE_NULL)
|
|
, m_glesContext (DE_NULL)
|
|
, m_glArrayPack (DE_NULL)
|
|
, m_rrArrayPack (DE_NULL)
|
|
, m_isOk (false)
|
|
, m_maxDiffRed (deCeilFloatToInt32(256.0f * (2.0f / (float)(1 << m_renderCtx.getRenderTarget().getPixelFormat().redBits))))
|
|
, m_maxDiffGreen (deCeilFloatToInt32(256.0f * (2.0f / (float)(1 << m_renderCtx.getRenderTarget().getPixelFormat().greenBits))))
|
|
, m_maxDiffBlue (deCeilFloatToInt32(256.0f * (2.0f / (float)(1 << m_renderCtx.getRenderTarget().getPixelFormat().blueBits))))
|
|
{
|
|
}
|
|
|
|
VertexArrayTest::~VertexArrayTest (void)
|
|
{
|
|
deinit();
|
|
}
|
|
|
|
void VertexArrayTest::init (void)
|
|
{
|
|
const int renderTargetWidth = de::min(512, m_renderCtx.getRenderTarget().getWidth());
|
|
const int renderTargetHeight = de::min(512, m_renderCtx.getRenderTarget().getHeight());
|
|
sglr::ReferenceContextLimits limits (m_renderCtx);
|
|
|
|
m_glesContext = new sglr::GLContext(m_renderCtx, m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS | sglr::GLCONTEXT_LOG_PROGRAMS, tcu::IVec4(0, 0, renderTargetWidth, renderTargetHeight));
|
|
|
|
m_refBuffers = new sglr::ReferenceContextBuffers(m_renderCtx.getRenderTarget().getPixelFormat(), 0, 0, renderTargetWidth, renderTargetHeight);
|
|
m_refContext = new sglr::ReferenceContext(limits, m_refBuffers->getColorbuffer(), m_refBuffers->getDepthbuffer(), m_refBuffers->getStencilbuffer());
|
|
|
|
m_glArrayPack = new ContextArrayPack(m_renderCtx, *m_glesContext);
|
|
m_rrArrayPack = new ContextArrayPack(m_renderCtx, *m_refContext);
|
|
}
|
|
|
|
void VertexArrayTest::deinit (void)
|
|
{
|
|
delete m_glArrayPack;
|
|
delete m_rrArrayPack;
|
|
delete m_refBuffers;
|
|
delete m_refContext;
|
|
delete m_glesContext;
|
|
|
|
m_glArrayPack = DE_NULL;
|
|
m_rrArrayPack = DE_NULL;
|
|
m_refBuffers = DE_NULL;
|
|
m_refContext = DE_NULL;
|
|
m_glesContext = DE_NULL;
|
|
}
|
|
|
|
void VertexArrayTest::compare (void)
|
|
{
|
|
const tcu::Surface& ref = m_rrArrayPack->getSurface();
|
|
const tcu::Surface& screen = m_glArrayPack->getSurface();
|
|
|
|
if (m_renderCtx.getRenderTarget().getNumSamples() > 1)
|
|
{
|
|
// \todo [mika] Improve compare when using multisampling
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Warning: Comparision of result from multisample render targets are not as stricts as without multisampling. Might produce false positives!" << tcu::TestLog::EndMessage;
|
|
m_isOk = tcu::fuzzyCompare(m_testCtx.getLog(), "Compare Results", "Compare Results", ref.getAccess(), screen.getAccess(), 1.5f, tcu::COMPARE_LOG_RESULT);
|
|
}
|
|
else
|
|
{
|
|
tcu::RGBA threshold (m_maxDiffRed, m_maxDiffGreen, m_maxDiffBlue, 255);
|
|
tcu::Surface error (ref.getWidth(), ref.getHeight());
|
|
|
|
m_isOk = true;
|
|
|
|
for (int y = 0; y < ref.getHeight(); y++)
|
|
{
|
|
for (int x = 0; x < ref.getWidth(); x++)
|
|
{
|
|
tcu::RGBA refPixel = ref.getPixel(x, y);
|
|
tcu::RGBA screenPixel = screen.getPixel(x, y);
|
|
bool isOkPixel = false;
|
|
|
|
if (y == 0 || y + 1 == ref.getHeight() || x == 0 || x + 1 == ref.getWidth())
|
|
{
|
|
// Don't check borders since the pixel neighborhood is undefined
|
|
error.setPixel(x, y, tcu::RGBA(screenPixel.getRed(), (screenPixel.getGreen() + 255) / 2, screenPixel.getBlue(), 255));
|
|
continue;
|
|
}
|
|
|
|
// Don't do comparisons for this pixel if it belongs to a one-pixel-thin part (i.e. it doesn't have similar-color neighbors in both x and y directions) in both result and reference.
|
|
// This fixes some false negatives.
|
|
bool refThin = (!tcu::compareThreshold(refPixel, ref.getPixel(x-1, y ), threshold) && !tcu::compareThreshold(refPixel, ref.getPixel(x+1, y ), threshold)) ||
|
|
(!tcu::compareThreshold(refPixel, ref.getPixel(x , y-1), threshold) && !tcu::compareThreshold(refPixel, ref.getPixel(x , y+1), threshold));
|
|
bool screenThin = (!tcu::compareThreshold(screenPixel, screen.getPixel(x-1, y ), threshold) && !tcu::compareThreshold(screenPixel, screen.getPixel(x+1, y ), threshold)) ||
|
|
(!tcu::compareThreshold(screenPixel, screen.getPixel(x , y-1), threshold) && !tcu::compareThreshold(screenPixel, screen.getPixel(x , y+1), threshold));
|
|
|
|
if (refThin && screenThin)
|
|
isOkPixel = true;
|
|
else
|
|
{
|
|
for (int dy = -1; dy < 2 && !isOkPixel; dy++)
|
|
{
|
|
for (int dx = -1; dx < 2 && !isOkPixel; dx++)
|
|
{
|
|
// Check reference pixel against screen pixel
|
|
{
|
|
tcu::RGBA screenCmpPixel = screen.getPixel(x+dx, y+dy);
|
|
deUint8 r = (deUint8)deAbs32(refPixel.getRed() - screenCmpPixel.getRed());
|
|
deUint8 g = (deUint8)deAbs32(refPixel.getGreen() - screenCmpPixel.getGreen());
|
|
deUint8 b = (deUint8)deAbs32(refPixel.getBlue() - screenCmpPixel.getBlue());
|
|
|
|
if (r <= m_maxDiffRed && g <= m_maxDiffGreen && b <= m_maxDiffBlue)
|
|
isOkPixel = true;
|
|
}
|
|
|
|
// Check screen pixels against reference pixel
|
|
{
|
|
tcu::RGBA refCmpPixel = ref.getPixel(x+dx, y+dy);
|
|
deUint8 r = (deUint8)deAbs32(refCmpPixel.getRed() - screenPixel.getRed());
|
|
deUint8 g = (deUint8)deAbs32(refCmpPixel.getGreen() - screenPixel.getGreen());
|
|
deUint8 b = (deUint8)deAbs32(refCmpPixel.getBlue() - screenPixel.getBlue());
|
|
|
|
if (r <= m_maxDiffRed && g <= m_maxDiffGreen && b <= m_maxDiffBlue)
|
|
isOkPixel = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isOkPixel)
|
|
error.setPixel(x, y, tcu::RGBA(screen.getPixel(x, y).getRed(), (screen.getPixel(x, y).getGreen() + 255) / 2, screen.getPixel(x, y).getBlue(), 255));
|
|
else
|
|
{
|
|
error.setPixel(x, y, tcu::RGBA(255, 0, 0, 255));
|
|
m_isOk = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
tcu::TestLog& log = m_testCtx.getLog();
|
|
if (!m_isOk)
|
|
{
|
|
log << TestLog::Message << "Image comparison failed, threshold = (" << m_maxDiffRed << ", " << m_maxDiffGreen << ", " << m_maxDiffBlue << ")" << TestLog::EndMessage;
|
|
log << TestLog::ImageSet("Compare result", "Result of rendering")
|
|
<< TestLog::Image("Result", "Result", screen)
|
|
<< TestLog::Image("Reference", "Reference", ref)
|
|
<< TestLog::Image("ErrorMask", "Error mask", error)
|
|
<< TestLog::EndImageSet;
|
|
}
|
|
else
|
|
{
|
|
log << TestLog::ImageSet("Compare result", "Result of rendering")
|
|
<< TestLog::Image("Result", "Result", screen)
|
|
<< TestLog::EndImageSet;
|
|
}
|
|
}
|
|
}
|
|
|
|
// MultiVertexArrayTest
|
|
|
|
MultiVertexArrayTest::Spec::ArraySpec::ArraySpec(Array::InputType inputType_, Array::OutputType outputType_, Array::Storage storage_, Array::Usage usage_, int componentCount_, int offset_, int stride_, bool normalize_, GLValue min_, GLValue max_)
|
|
: inputType (inputType_)
|
|
, outputType (outputType_)
|
|
, storage (storage_)
|
|
, usage (usage_)
|
|
, componentCount(componentCount_)
|
|
, offset (offset_)
|
|
, stride (stride_)
|
|
, normalize (normalize_)
|
|
, min (min_)
|
|
, max (max_)
|
|
{
|
|
}
|
|
|
|
std::string MultiVertexArrayTest::Spec::getName (void) const
|
|
{
|
|
std::stringstream name;
|
|
|
|
for (size_t ndx = 0; ndx < arrays.size(); ++ndx)
|
|
{
|
|
const ArraySpec& array = arrays[ndx];
|
|
|
|
if (arrays.size() > 1)
|
|
name << "array" << ndx << "_";
|
|
|
|
name
|
|
<< Array::storageToString(array.storage) << "_"
|
|
<< array.offset << "_"
|
|
<< array.stride << "_"
|
|
<< Array::inputTypeToString((Array::InputType)array.inputType);
|
|
if (array.inputType != Array::INPUTTYPE_UNSIGNED_INT_2_10_10_10 && array.inputType != Array::INPUTTYPE_INT_2_10_10_10)
|
|
name << array.componentCount;
|
|
name
|
|
<< "_"
|
|
<< (array.normalize ? "normalized_" : "")
|
|
<< Array::outputTypeToString(array.outputType) << "_"
|
|
<< Array::usageTypeToString(array.usage) << "_";
|
|
}
|
|
|
|
if (first)
|
|
name << "first" << first << "_";
|
|
|
|
switch (primitive)
|
|
{
|
|
case Array::PRIMITIVE_TRIANGLES:
|
|
name << "quads_";
|
|
break;
|
|
case Array::PRIMITIVE_POINTS:
|
|
name << "points_";
|
|
break;
|
|
|
|
default:
|
|
DE_ASSERT(false);
|
|
break;
|
|
}
|
|
|
|
name << drawCount;
|
|
|
|
return name.str();
|
|
}
|
|
|
|
std::string MultiVertexArrayTest::Spec::getDesc (void) const
|
|
{
|
|
std::stringstream desc;
|
|
|
|
for (size_t ndx = 0; ndx < arrays.size(); ++ndx)
|
|
{
|
|
const ArraySpec& array = arrays[ndx];
|
|
|
|
desc
|
|
<< "Array " << ndx << ": "
|
|
<< "Storage in " << Array::storageToString(array.storage) << ", "
|
|
<< "stride " << array.stride << ", "
|
|
<< "input datatype " << Array::inputTypeToString((Array::InputType)array.inputType) << ", "
|
|
<< "input component count " << array.componentCount << ", "
|
|
<< (array.normalize ? "normalized, " : "")
|
|
<< "used as " << Array::outputTypeToString(array.outputType) << ", ";
|
|
}
|
|
|
|
desc
|
|
<< "drawArrays(), "
|
|
<< "first " << first << ", "
|
|
<< drawCount;
|
|
|
|
switch (primitive)
|
|
{
|
|
case Array::PRIMITIVE_TRIANGLES:
|
|
desc << "quads ";
|
|
break;
|
|
case Array::PRIMITIVE_POINTS:
|
|
desc << "points";
|
|
break;
|
|
|
|
default:
|
|
DE_ASSERT(false);
|
|
break;
|
|
}
|
|
|
|
|
|
return desc.str();
|
|
}
|
|
|
|
MultiVertexArrayTest::MultiVertexArrayTest (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const Spec& spec, const char* name, const char* desc)
|
|
: VertexArrayTest (testCtx, renderCtx, name, desc)
|
|
, m_spec (spec)
|
|
, m_iteration (0)
|
|
{
|
|
}
|
|
|
|
MultiVertexArrayTest::~MultiVertexArrayTest (void)
|
|
{
|
|
}
|
|
|
|
MultiVertexArrayTest::IterateResult MultiVertexArrayTest::iterate (void)
|
|
{
|
|
if (m_iteration == 0)
|
|
{
|
|
const size_t primitiveSize = (m_spec.primitive == Array::PRIMITIVE_TRIANGLES) ? (6) : (1); // in non-indexed draw Triangles means rectangles
|
|
float coordScale = 1.0f;
|
|
float colorScale = 1.0f;
|
|
const bool useVao = m_renderCtx.getType().getProfile() == glu::PROFILE_CORE;
|
|
|
|
// Log info
|
|
m_testCtx.getLog() << TestLog::Message << m_spec.getDesc() << TestLog::EndMessage;
|
|
|
|
// Color and Coord scale
|
|
{
|
|
// First array is always position
|
|
{
|
|
Spec::ArraySpec arraySpec = m_spec.arrays[0];
|
|
if (arraySpec.inputType == Array::INPUTTYPE_UNSIGNED_INT_2_10_10_10)
|
|
{
|
|
if (arraySpec.normalize)
|
|
coordScale = 1.0f;
|
|
else
|
|
coordScale = 1.0 / 1024.0;
|
|
}
|
|
else if (arraySpec.inputType == Array::INPUTTYPE_INT_2_10_10_10)
|
|
{
|
|
if (arraySpec.normalize)
|
|
coordScale = 1.0f;
|
|
else
|
|
coordScale = 1.0 / 512.0;
|
|
}
|
|
else
|
|
coordScale = (arraySpec.normalize && !inputTypeIsFloatType(arraySpec.inputType) ? 1.0f : float(0.9 / double(arraySpec.max.toFloat())));
|
|
|
|
if (arraySpec.outputType == Array::OUTPUTTYPE_VEC3 || arraySpec.outputType == Array::OUTPUTTYPE_VEC4
|
|
|| arraySpec.outputType == Array::OUTPUTTYPE_IVEC3 || arraySpec.outputType == Array::OUTPUTTYPE_IVEC4
|
|
|| arraySpec.outputType == Array::OUTPUTTYPE_UVEC3 || arraySpec.outputType == Array::OUTPUTTYPE_UVEC4)
|
|
coordScale = coordScale * 0.5f;
|
|
}
|
|
|
|
// And other arrays are color-like
|
|
for (int arrayNdx = 1; arrayNdx < (int)m_spec.arrays.size(); arrayNdx++)
|
|
{
|
|
Spec::ArraySpec arraySpec = m_spec.arrays[arrayNdx];
|
|
|
|
colorScale *= (arraySpec.normalize && !inputTypeIsFloatType(arraySpec.inputType) ? 1.0f : float(1.0 / double(arraySpec.max.toFloat())));
|
|
if (arraySpec.outputType == Array::OUTPUTTYPE_VEC4)
|
|
colorScale *= (arraySpec.normalize && !inputTypeIsFloatType(arraySpec.inputType) ? 1.0f : float(1.0 / double(arraySpec.max.toFloat())));
|
|
}
|
|
}
|
|
|
|
// Data
|
|
for (int arrayNdx = 0; arrayNdx < (int)m_spec.arrays.size(); arrayNdx++)
|
|
{
|
|
Spec::ArraySpec arraySpec = m_spec.arrays[arrayNdx];
|
|
const int seed = int(arraySpec.inputType) + 10 * int(arraySpec.outputType) + 100 * int(arraySpec.storage) + 1000 * int(m_spec.primitive) + 10000 * int(arraySpec.usage) + int(m_spec.drawCount) + 12 * int(arraySpec.componentCount) + int(arraySpec.stride) + int(arraySpec.normalize);
|
|
const char* data = DE_NULL;
|
|
const size_t stride = (arraySpec.stride == 0) ? (arraySpec.componentCount * Array::inputTypeSize(arraySpec.inputType)) : (arraySpec.stride);
|
|
const size_t bufferSize = arraySpec.offset + stride * (m_spec.drawCount * primitiveSize - 1) + arraySpec.componentCount * Array::inputTypeSize(arraySpec.inputType);
|
|
// Snap values to at least 3x3 grid
|
|
const float gridSize = 3.0f / (float)(de::min(m_renderCtx.getRenderTarget().getWidth(), m_renderCtx.getRenderTarget().getHeight()) - 1);
|
|
|
|
switch (m_spec.primitive)
|
|
{
|
|
// case Array::PRIMITIVE_POINTS:
|
|
// data = RandomArrayGenerator::generateArray(seed, arraySpec.min, arraySpec.max, arraySpec.count, arraySpec.componentCount, arraySpec.stride, arraySpec.inputType);
|
|
// break;
|
|
case Array::PRIMITIVE_TRIANGLES:
|
|
if (arrayNdx == 0)
|
|
{
|
|
data = RandomArrayGenerator::generateQuads(seed, m_spec.drawCount, arraySpec.componentCount, arraySpec.offset, arraySpec.stride, m_spec.primitive, arraySpec.inputType, arraySpec.min, arraySpec.max, gridSize);
|
|
}
|
|
else
|
|
{
|
|
DE_ASSERT(arraySpec.offset == 0); // \note [jarkko] it just hasn't been implemented
|
|
data = RandomArrayGenerator::generatePerQuad(seed, m_spec.drawCount, arraySpec.componentCount, arraySpec.stride, m_spec.primitive, arraySpec.inputType, arraySpec.min, arraySpec.max);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
DE_ASSERT(false);
|
|
break;
|
|
}
|
|
|
|
m_glArrayPack->newArray(arraySpec.storage);
|
|
m_rrArrayPack->newArray(arraySpec.storage);
|
|
|
|
m_glArrayPack->getArray(arrayNdx)->data(Array::TARGET_ARRAY, (int)bufferSize, data, arraySpec.usage);
|
|
m_rrArrayPack->getArray(arrayNdx)->data(Array::TARGET_ARRAY, (int)bufferSize, data, arraySpec.usage);
|
|
|
|
m_glArrayPack->getArray(arrayNdx)->bind(arrayNdx, arraySpec.offset, arraySpec.componentCount, arraySpec.inputType, arraySpec.outputType, arraySpec.normalize, arraySpec.stride);
|
|
m_rrArrayPack->getArray(arrayNdx)->bind(arrayNdx, arraySpec.offset, arraySpec.componentCount, arraySpec.inputType, arraySpec.outputType, arraySpec.normalize, arraySpec.stride);
|
|
|
|
delete [] data;
|
|
}
|
|
|
|
try
|
|
{
|
|
m_glArrayPack->render(m_spec.primitive, m_spec.first, m_spec.drawCount * (int)primitiveSize, useVao, coordScale, colorScale);
|
|
m_testCtx.touchWatchdog();
|
|
m_rrArrayPack->render(m_spec.primitive, m_spec.first, m_spec.drawCount * (int)primitiveSize, useVao, coordScale, colorScale);
|
|
}
|
|
catch (glu::Error& err)
|
|
{
|
|
// GL Errors are ok if the mode is not properly aligned
|
|
|
|
m_testCtx.getLog() << TestLog::Message << "Got error: " << err.what() << TestLog::EndMessage;
|
|
|
|
if (isUnalignedBufferOffsetTest())
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned buffers.");
|
|
else if (isUnalignedBufferStrideTest())
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned stride.");
|
|
else
|
|
throw;
|
|
|
|
return STOP;
|
|
}
|
|
|
|
m_iteration++;
|
|
return CONTINUE;
|
|
}
|
|
else if (m_iteration == 1)
|
|
{
|
|
compare();
|
|
|
|
if (m_isOk)
|
|
{
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
|
|
}
|
|
else
|
|
{
|
|
if (isUnalignedBufferOffsetTest())
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned buffers.");
|
|
else if (isUnalignedBufferStrideTest())
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned stride.");
|
|
else
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed.");
|
|
}
|
|
|
|
m_iteration++;
|
|
return STOP;
|
|
}
|
|
else
|
|
{
|
|
DE_ASSERT(false);
|
|
return STOP;
|
|
}
|
|
}
|
|
|
|
bool MultiVertexArrayTest::isUnalignedBufferOffsetTest (void) const
|
|
{
|
|
// Buffer offsets should be data type size aligned
|
|
for (size_t i = 0; i < m_spec.arrays.size(); ++i)
|
|
{
|
|
if (m_spec.arrays[i].storage == Array::STORAGE_BUFFER)
|
|
{
|
|
const bool inputTypePacked = m_spec.arrays[i].inputType == Array::INPUTTYPE_UNSIGNED_INT_2_10_10_10 || m_spec.arrays[i].inputType == Array::INPUTTYPE_INT_2_10_10_10;
|
|
|
|
int dataTypeSize = Array::inputTypeSize(m_spec.arrays[i].inputType);
|
|
if (inputTypePacked)
|
|
dataTypeSize = 4;
|
|
|
|
if (m_spec.arrays[i].offset % dataTypeSize != 0)
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool MultiVertexArrayTest::isUnalignedBufferStrideTest (void) const
|
|
{
|
|
// Buffer strides should be data type size aligned
|
|
for (size_t i = 0; i < m_spec.arrays.size(); ++i)
|
|
{
|
|
if (m_spec.arrays[i].storage == Array::STORAGE_BUFFER)
|
|
{
|
|
const bool inputTypePacked = m_spec.arrays[i].inputType == Array::INPUTTYPE_UNSIGNED_INT_2_10_10_10 || m_spec.arrays[i].inputType == Array::INPUTTYPE_INT_2_10_10_10;
|
|
|
|
int dataTypeSize = Array::inputTypeSize(m_spec.arrays[i].inputType);
|
|
if (inputTypePacked)
|
|
dataTypeSize = 4;
|
|
|
|
if (m_spec.arrays[i].stride % dataTypeSize != 0)
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
} // gls
|
|
} // deqp
|