#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