blob: 3fd9fa9ccefa8d56028046c1018a447381c60290 [file] [log] [blame]
#ifndef _GLSVERTEXARRAYTESTS_HPP
#define _GLSVERTEXARRAYTESTS_HPP
/*-------------------------------------------------------------------------
* drawElements Quality Program OpenGL (ES) Module
* -----------------------------------------------
*
* Copyright 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file
* \brief Vertex array and buffer tests
*//*--------------------------------------------------------------------*/
#include "tcuTestCase.hpp"
#include "tcuVector.hpp"
#include "tcuSurface.hpp"
#include "gluRenderContext.hpp"
#include "gluCallLogWrapper.hpp"
#include "tcuTestLog.hpp"
#include "gluShaderProgram.hpp"
#include "deFloat16.h"
#include "deMath.h"
#include "tcuFloat.hpp"
#include "tcuPixelFormat.hpp"
#include "sglrContext.hpp"
namespace sglr
{
class ReferenceContextBuffers;
class ReferenceContext;
class Context;
} // sglr
namespace deqp
{
namespace gls
{
class Array
{
public:
enum Target
{
// \note [mika] Are these actualy used somewhere?
TARGET_ELEMENT_ARRAY = 0,
TARGET_ARRAY,
TARGET_LAST
};
enum InputType
{
INPUTTYPE_FLOAT = 0,
INPUTTYPE_FIXED,
INPUTTYPE_DOUBLE,
INPUTTYPE_BYTE,
INPUTTYPE_SHORT,
INPUTTYPE_UNSIGNED_BYTE,
INPUTTYPE_UNSIGNED_SHORT,
INPUTTYPE_INT,
INPUTTYPE_UNSIGNED_INT,
INPUTTYPE_HALF,
INPUTTYPE_UNSIGNED_INT_2_10_10_10,
INPUTTYPE_INT_2_10_10_10,
INPUTTYPE_LAST
};
enum OutputType
{
OUTPUTTYPE_FLOAT = 0,
OUTPUTTYPE_VEC2,
OUTPUTTYPE_VEC3,
OUTPUTTYPE_VEC4,
OUTPUTTYPE_INT,
OUTPUTTYPE_UINT,
OUTPUTTYPE_IVEC2,
OUTPUTTYPE_IVEC3,
OUTPUTTYPE_IVEC4,
OUTPUTTYPE_UVEC2,
OUTPUTTYPE_UVEC3,
OUTPUTTYPE_UVEC4,
OUTPUTTYPE_LAST
};
enum Usage
{
USAGE_DYNAMIC_DRAW = 0,
USAGE_STATIC_DRAW,
USAGE_STREAM_DRAW,
USAGE_STREAM_READ,
USAGE_STREAM_COPY,
USAGE_STATIC_READ,
USAGE_STATIC_COPY,
USAGE_DYNAMIC_READ,
USAGE_DYNAMIC_COPY,
USAGE_LAST
};
enum Storage
{
STORAGE_USER = 0,
STORAGE_BUFFER,
STORAGE_LAST
};
enum Primitive
{
PRIMITIVE_POINTS = 0,
PRIMITIVE_TRIANGLES,
PRIMITIVE_TRIANGLE_FAN,
PRIMITIVE_TRIANGLE_STRIP,
PRIMITIVE_LAST
};
static std::string targetToString (Target target);
static std::string inputTypeToString (InputType type);
static std::string outputTypeToString (OutputType type);
static std::string usageTypeToString (Usage usage);
static std::string storageToString (Storage storage);
static std::string primitiveToString (Primitive primitive);
static int inputTypeSize (InputType type);
virtual ~Array (void) {}
virtual void data (Target target, int size, const char* data, Usage usage) = 0;
virtual void subdata (Target target, int offset, int size, const char* data) = 0;
virtual void bind (int attribNdx, int offset, int size, InputType inType, OutputType outType, bool normalized, int stride) = 0;
virtual void unBind (void) = 0;
virtual bool isBound (void) const = 0;
virtual int getComponentCount (void) const = 0;
virtual Target getTarget (void) const = 0;
virtual InputType getInputType (void) const = 0;
virtual OutputType getOutputType (void) const = 0;
virtual Storage getStorageType (void) const = 0;
virtual bool getNormalized (void) const = 0;
virtual int getStride (void) const = 0;
virtual int getAttribNdx (void) const = 0;
virtual void setAttribNdx (int attribNdx) = 0;
};
class ContextArray : public Array
{
public:
ContextArray (Storage storage, sglr::Context& context);
virtual ~ContextArray (void);
virtual void data (Target target, int size, const char* data, Usage usage);
virtual void subdata (Target target, int offset, int size, const char* data);
virtual void bind (int attribNdx, int offset, int size, InputType inType, OutputType outType, bool normalized, int stride);
virtual void bindIndexArray (Array::Target storage);
virtual void unBind (void) { m_bound = false; }
virtual bool isBound (void) const { return m_bound; }
virtual int getComponentCount (void) const { return m_componentCount; }
virtual Array::Target getTarget (void) const { return m_target; }
virtual Array::InputType getInputType (void) const { return m_inputType; }
virtual Array::OutputType getOutputType (void) const { return m_outputType; }
virtual Array::Storage getStorageType (void) const { return m_storage; }
virtual bool getNormalized (void) const { return m_normalize; }
virtual int getStride (void) const { return m_stride; }
virtual int getAttribNdx (void) const { return m_attribNdx; }
virtual void setAttribNdx (int attribNdx) { m_attribNdx = attribNdx; }
void glBind (deUint32 loc);
static deUint32 targetToGL (Array::Target target);
static deUint32 usageToGL (Array::Usage usage);
static deUint32 inputTypeToGL (Array::InputType type);
static std::string outputTypeToGLType (Array::OutputType type);
static deUint32 primitiveToGL (Array::Primitive primitive);
private:
Storage m_storage;
sglr::Context& m_ctx;
deUint32 m_glBuffer;
bool m_bound;
int m_attribNdx;
int m_size;
char* m_data;
int m_componentCount;
Array::Target m_target;
Array::InputType m_inputType;
Array::OutputType m_outputType;
bool m_normalize;
int m_stride;
int m_offset;
};
class ContextArrayPack
{
public:
ContextArrayPack (glu::RenderContext& renderCtx, sglr::Context& drawContext);
virtual ~ContextArrayPack (void);
virtual Array* getArray (int i);
virtual int getArrayCount (void);
virtual void newArray (Array::Storage storage);
virtual void render (Array::Primitive primitive, int firstVertex, int vertexCount, bool useVao, float coordScale, float colorScale);
const tcu::Surface& getSurface (void) const { return m_screen; }
private:
void updateProgram (void);
glu::RenderContext& m_renderCtx;
sglr::Context& m_ctx;
std::vector<ContextArray*> m_arrays;
sglr::ShaderProgram* m_program;
tcu::Surface m_screen;
};
class GLValue
{
public:
template<class Type>
class WrappedType
{
public:
static WrappedType<Type> create (Type value) { WrappedType<Type> v; v.m_value = value; return v; }
static WrappedType<Type> fromFloat (float value) { WrappedType<Type> v; v.m_value = (Type)value; return v; }
inline Type getValue (void) const { return m_value; }
inline WrappedType<Type> operator+ (const WrappedType<Type>& other) const { return WrappedType<Type>::create((Type)(m_value + other.getValue())); }
inline WrappedType<Type> operator* (const WrappedType<Type>& other) const { return WrappedType<Type>::create((Type)(m_value * other.getValue())); }
inline WrappedType<Type> operator/ (const WrappedType<Type>& other) const { return WrappedType<Type>::create((Type)(m_value / other.getValue())); }
inline WrappedType<Type> operator% (const WrappedType<Type>& other) const { return WrappedType<Type>::create((Type)(m_value % other.getValue())); }
inline WrappedType<Type> operator- (const WrappedType<Type>& other) const { return WrappedType<Type>::create((Type)(m_value - other.getValue())); }
inline WrappedType<Type>& operator+= (const WrappedType<Type>& other) { m_value += other.getValue(); return *this; }
inline WrappedType<Type>& operator*= (const WrappedType<Type>& other) { m_value *= other.getValue(); return *this; }
inline WrappedType<Type>& operator/= (const WrappedType<Type>& other) { m_value /= other.getValue(); return *this; }
inline WrappedType<Type>& operator-= (const WrappedType<Type>& other) { m_value -= other.getValue(); return *this; }
inline bool operator== (const WrappedType<Type>& other) const { return m_value == other.m_value; }
inline bool operator!= (const WrappedType<Type>& other) const { return m_value != other.m_value; }
inline bool operator< (const WrappedType<Type>& other) const { return m_value < other.m_value; }
inline bool operator> (const WrappedType<Type>& other) const { return m_value > other.m_value; }
inline bool operator<= (const WrappedType<Type>& other) const { return m_value <= other.m_value; }
inline bool operator>= (const WrappedType<Type>& other) const { return m_value >= other.m_value; }
inline operator Type (void) const { return m_value; }
template<class T>
inline T to (void) const { return (T)m_value; }
private:
Type m_value;
};
template<class Type>
class WrappedFloatType
{
public:
static WrappedFloatType<Type> create (Type value) { WrappedFloatType<Type> v; v.m_value = value; return v; }
static WrappedFloatType<Type> fromFloat (float value) { WrappedFloatType<Type> v; v.m_value = (Type)value; return v; }
inline Type getValue (void) const { return m_value; }
inline WrappedFloatType<Type> operator+ (const WrappedFloatType<Type>& other) const { return WrappedFloatType<Type>::create((Type)(m_value + other.getValue())); }
inline WrappedFloatType<Type> operator* (const WrappedFloatType<Type>& other) const { return WrappedFloatType<Type>::create((Type)(m_value * other.getValue())); }
inline WrappedFloatType<Type> operator/ (const WrappedFloatType<Type>& other) const { return WrappedFloatType<Type>::create((Type)(m_value / other.getValue())); }
inline WrappedFloatType<Type> operator% (const WrappedFloatType<Type>& other) const { return WrappedFloatType<Type>::create((Type)(deMod(m_value, other.getValue()))); }
inline WrappedFloatType<Type> operator- (const WrappedFloatType<Type>& other) const { return WrappedFloatType<Type>::create((Type)(m_value - other.getValue())); }
inline WrappedFloatType<Type>& operator+= (const WrappedFloatType<Type>& other) { m_value += other.getValue(); return *this; }
inline WrappedFloatType<Type>& operator*= (const WrappedFloatType<Type>& other) { m_value *= other.getValue(); return *this; }
inline WrappedFloatType<Type>& operator/= (const WrappedFloatType<Type>& other) { m_value /= other.getValue(); return *this; }
inline WrappedFloatType<Type>& operator-= (const WrappedFloatType<Type>& other) { m_value -= other.getValue(); return *this; }
inline bool operator== (const WrappedFloatType<Type>& other) const { return m_value == other.m_value; }
inline bool operator!= (const WrappedFloatType<Type>& other) const { return m_value != other.m_value; }
inline bool operator< (const WrappedFloatType<Type>& other) const { return m_value < other.m_value; }
inline bool operator> (const WrappedFloatType<Type>& other) const { return m_value > other.m_value; }
inline bool operator<= (const WrappedFloatType<Type>& other) const { return m_value <= other.m_value; }
inline bool operator>= (const WrappedFloatType<Type>& other) const { return m_value >= other.m_value; }
inline operator Type (void) const { return m_value; }
template<class T>
inline T to (void) const { return (T)m_value; }
private:
Type m_value;
};
typedef WrappedType<deInt16> Short;
typedef WrappedType<deUint16> Ushort;
typedef WrappedType<deInt8> Byte;
typedef WrappedType<deUint8> Ubyte;
typedef WrappedFloatType<float> Float;
typedef WrappedFloatType<double> Double;
typedef WrappedType<deInt32> Int;
typedef WrappedType<deUint32> Uint;
class Half
{
public:
static Half create (float value) { Half h; h.m_value = floatToHalf(value); return h; }
static Half fromFloat (float value) { Half h; h.m_value = floatToHalf(value); return h; }
inline deFloat16 getValue (void) const { return m_value; }
inline Half operator+ (const Half& other) const { return create(halfToFloat(m_value) + halfToFloat(other.getValue())); }
inline Half operator* (const Half& other) const { return create(halfToFloat(m_value) * halfToFloat(other.getValue())); }
inline Half operator/ (const Half& other) const { return create(halfToFloat(m_value) / halfToFloat(other.getValue())); }
inline Half operator% (const Half& other) const { return create(deFloatMod(halfToFloat(m_value), halfToFloat(other.getValue()))); }
inline Half operator- (const Half& other) const { return create(halfToFloat(m_value) - halfToFloat(other.getValue())); }
inline Half& operator+= (const Half& other) { m_value = floatToHalf(halfToFloat(other.getValue()) + halfToFloat(m_value)); return *this; }
inline Half& operator*= (const Half& other) { m_value = floatToHalf(halfToFloat(other.getValue()) * halfToFloat(m_value)); return *this; }
inline Half& operator/= (const Half& other) { m_value = floatToHalf(halfToFloat(other.getValue()) / halfToFloat(m_value)); return *this; }
inline Half& operator-= (const Half& other) { m_value = floatToHalf(halfToFloat(other.getValue()) - halfToFloat(m_value)); return *this; }
inline bool operator== (const Half& other) const { return m_value == other.m_value; }
inline bool operator!= (const Half& other) const { return m_value != other.m_value; }
inline bool operator< (const Half& other) const { return halfToFloat(m_value) < halfToFloat(other.m_value); }
inline bool operator> (const Half& other) const { return halfToFloat(m_value) > halfToFloat(other.m_value); }
inline bool operator<= (const Half& other) const { return halfToFloat(m_value) <= halfToFloat(other.m_value); }
inline bool operator>= (const Half& other) const { return halfToFloat(m_value) >= halfToFloat(other.m_value); }
template<class T>
inline T to (void) const { return (T)halfToFloat(m_value); }
inline static deFloat16 floatToHalf (float f);
inline static float halfToFloat (deFloat16 h);
private:
deFloat16 m_value;
};
class Fixed
{
public:
static Fixed create (deInt32 value) { Fixed v; v.m_value = value; return v; }
static Fixed fromFloat (float value) { Fixed v; v.m_value = (deInt32)(value * 32768.0f); return v; }
inline deInt32 getValue (void) const { return m_value; }
inline Fixed operator+ (const Fixed& other) const { return create(m_value + other.getValue()); }
inline Fixed operator* (const Fixed& other) const { return create(m_value * other.getValue()); }
inline Fixed operator/ (const Fixed& other) const { return create(m_value / other.getValue()); }
inline Fixed operator% (const Fixed& other) const { return create(m_value % other.getValue()); }
inline Fixed operator- (const Fixed& other) const { return create(m_value - other.getValue()); }
inline Fixed& operator+= (const Fixed& other) { m_value += other.getValue(); return *this; }
inline Fixed& operator*= (const Fixed& other) { m_value *= other.getValue(); return *this; }
inline Fixed& operator/= (const Fixed& other) { m_value /= other.getValue(); return *this; }
inline Fixed& operator-= (const Fixed& other) { m_value -= other.getValue(); return *this; }
inline bool operator== (const Fixed& other) const { return m_value == other.m_value; }
inline bool operator!= (const Fixed& other) const { return m_value != other.m_value; }
inline bool operator< (const Fixed& other) const { return m_value < other.m_value; }
inline bool operator> (const Fixed& other) const { return m_value > other.m_value; }
inline bool operator<= (const Fixed& other) const { return m_value <= other.m_value; }
inline bool operator>= (const Fixed& other) const { return m_value >= other.m_value; }
inline operator deInt32 (void) const { return m_value; }
template<class T>
inline T to (void) const { return (T)m_value; }
private:
deInt32 m_value;
};
// \todo [mika] This is pretty messy
GLValue (void) : type(Array::INPUTTYPE_LAST) {}
explicit GLValue (Float value) : type(Array::INPUTTYPE_FLOAT), fl(value) {}
explicit GLValue (Fixed value) : type(Array::INPUTTYPE_FIXED), fi(value) {}
explicit GLValue (Byte value) : type(Array::INPUTTYPE_BYTE), b(value) {}
explicit GLValue (Ubyte value) : type(Array::INPUTTYPE_UNSIGNED_BYTE), ub(value) {}
explicit GLValue (Short value) : type(Array::INPUTTYPE_SHORT), s(value) {}
explicit GLValue (Ushort value) : type(Array::INPUTTYPE_UNSIGNED_SHORT), us(value) {}
explicit GLValue (Int value) : type(Array::INPUTTYPE_INT), i(value) {}
explicit GLValue (Uint value) : type(Array::INPUTTYPE_UNSIGNED_INT), ui(value) {}
explicit GLValue (Half value) : type(Array::INPUTTYPE_HALF), h(value) {}
explicit GLValue (Double value) : type(Array::INPUTTYPE_DOUBLE), d(value) {}
float toFloat (void) const;
static GLValue getMaxValue (Array::InputType type);
static GLValue getMinValue (Array::InputType type);
Array::InputType type;
union
{
Float fl;
Fixed fi;
Double d;
Byte b;
Ubyte ub;
Short s;
Ushort us;
Int i;
Uint ui;
Half h;
};
};
class VertexArrayTest : public tcu::TestCase
{
public:
VertexArrayTest (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name ,const char* desc);
virtual ~VertexArrayTest (void);
virtual void init (void);
virtual void deinit (void);
protected:
VertexArrayTest (const VertexArrayTest& other);
VertexArrayTest& operator= (const VertexArrayTest& other);
void compare (void);
glu::RenderContext& m_renderCtx;
sglr::ReferenceContextBuffers* m_refBuffers;
sglr::ReferenceContext* m_refContext;
sglr::Context* m_glesContext;
ContextArrayPack* m_glArrayPack;
ContextArrayPack* m_rrArrayPack;
bool m_isOk;
int m_maxDiffRed;
int m_maxDiffGreen;
int m_maxDiffBlue;
};
class MultiVertexArrayTest : public VertexArrayTest
{
public:
class Spec
{
public:
class ArraySpec
{
public:
ArraySpec (Array::InputType inputType, Array::OutputType outputType, Array::Storage storage, Array::Usage usage, int componetCount, int offset, int stride, bool normalize, GLValue min, GLValue max);
Array::InputType inputType;
Array::OutputType outputType;
Array::Storage storage;
Array::Usage usage;
int componentCount;
int offset;
int stride;
bool normalize;
GLValue min;
GLValue max;
};
std::string getName (void) const;
std::string getDesc (void) const;
Array::Primitive primitive;
int drawCount; //!<Number of primitives to draw
int first;
std::vector<ArraySpec> arrays;
};
MultiVertexArrayTest (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const Spec& spec, const char* name, const char* desc);
virtual ~MultiVertexArrayTest (void);
virtual IterateResult iterate (void);
private:
bool isUnalignedBufferOffsetTest (void) const;
bool isUnalignedBufferStrideTest (void) const;
Spec m_spec;
int m_iteration;
};
inline deFloat16 GLValue::Half::floatToHalf (float f)
{
// No denorm support.
tcu::Float<deUint16, 5, 10, 15, tcu::FLOAT_HAS_SIGN> v(f);
DE_ASSERT(!v.isNaN() && !v.isInf());
return v.bits();
}
inline float GLValue::Half::halfToFloat (deFloat16 h)
{
return tcu::Float16((deUint16)h).asFloat();
}
} // gls
} // deqp
#endif // _GLSVERTEXARRAYTESTS_HPP