#ifndef _GLSSHADERRENDERCASE_HPP #define _GLSSHADERRENDERCASE_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 Shader execute test. *//*--------------------------------------------------------------------*/ #include "tcuDefs.hpp" #include "tcuTestCase.hpp" #include "tcuVector.hpp" #include "tcuMatrix.hpp" #include "tcuTexture.hpp" #include "tcuSurface.hpp" #include "gluRenderContext.hpp" #include "gluContextInfo.hpp" #include "gluShaderProgram.hpp" #include <sstream> #include <string> namespace glu { class RenderContext; class Texture2D; class TextureCube; class Texture2DArray; class Texture3D; } // glu namespace deqp { namespace gls { // LineStream \todo [2011-10-17 pyry] Move to proper place! class LineStream { public: LineStream (int indent = 0) { m_indent = indent; } ~LineStream (void) {} const char* str (void) const { m_string = m_stream.str(); return m_string.c_str(); } LineStream& operator<< (const char* line) { for (int i = 0; i < m_indent; i++) { m_stream << "\t"; } m_stream << line << "\n"; return *this; } private: int m_indent; std::ostringstream m_stream; mutable std::string m_string; }; class QuadGrid; // TextureBinding class TextureBinding { public: enum Type { TYPE_NONE = 0, TYPE_2D, TYPE_CUBE_MAP, TYPE_2D_ARRAY, TYPE_3D, TYPE_LAST }; TextureBinding (const glu::Texture2D* tex2D, const tcu::Sampler& sampler); TextureBinding (const glu::TextureCube* texCube, const tcu::Sampler& sampler); TextureBinding (const glu::Texture2DArray* tex2DArray, const tcu::Sampler& sampler); TextureBinding (const glu::Texture3D* tex3D, const tcu::Sampler& sampler); TextureBinding (void); void setSampler (const tcu::Sampler& sampler); void setTexture (const glu::Texture2D* tex2D); void setTexture (const glu::TextureCube* texCube); void setTexture (const glu::Texture2DArray* tex2DArray); void setTexture (const glu::Texture3D* tex3D); Type getType (void) const { return m_type; } const tcu::Sampler& getSampler (void) const { return m_sampler; } const glu::Texture2D* get2D (void) const { DE_ASSERT(getType() == TYPE_2D); return m_binding.tex2D; } const glu::TextureCube* getCube (void) const { DE_ASSERT(getType() == TYPE_CUBE_MAP); return m_binding.texCube; } const glu::Texture2DArray* get2DArray (void) const { DE_ASSERT(getType() == TYPE_2D_ARRAY); return m_binding.tex2DArray;} const glu::Texture3D* get3D (void) const { DE_ASSERT(getType() == TYPE_3D); return m_binding.tex3D; } private: Type m_type; tcu::Sampler m_sampler; union { const glu::Texture2D* tex2D; const glu::TextureCube* texCube; const glu::Texture2DArray* tex2DArray; const glu::Texture3D* tex3D; } m_binding; }; // ShaderEvalContext. class ShaderEvalContext { public: // Limits. enum { MAX_USER_ATTRIBS = 4, MAX_TEXTURES = 4, }; struct ShaderSampler { tcu::Sampler sampler; const tcu::Texture2D* tex2D; const tcu::TextureCube* texCube; const tcu::Texture2DArray* tex2DArray; const tcu::Texture3D* tex3D; inline ShaderSampler (void) : tex2D (DE_NULL) , texCube (DE_NULL) , tex2DArray(DE_NULL) , tex3D (DE_NULL) { } }; ShaderEvalContext (const QuadGrid& quadGrid); ~ShaderEvalContext (void); void reset (float sx, float sy); // Inputs. tcu::Vec4 coords; tcu::Vec4 unitCoords; tcu::Vec4 constCoords; tcu::Vec4 in[MAX_USER_ATTRIBS]; ShaderSampler textures[MAX_TEXTURES]; // Output. tcu::Vec4 color; bool isDiscarded; // Functions. inline void discard (void) { isDiscarded = true; } tcu::Vec4 texture2D (int unitNdx, const tcu::Vec2& coords); private: const QuadGrid& quadGrid; }; // ShaderEvalFunc. typedef void (*ShaderEvalFunc) (ShaderEvalContext& c); inline void evalCoordsPassthroughX (ShaderEvalContext& c) { c.color.x() = c.coords.x(); } inline void evalCoordsPassthroughXY (ShaderEvalContext& c) { c.color.xy() = c.coords.swizzle(0,1); } inline void evalCoordsPassthroughXYZ (ShaderEvalContext& c) { c.color.xyz() = c.coords.swizzle(0,1,2); } inline void evalCoordsPassthrough (ShaderEvalContext& c) { c.color = c.coords; } inline void evalCoordsSwizzleWZYX (ShaderEvalContext& c) { c.color = c.coords.swizzle(3,2,1,0); } // ShaderEvaluator // Either inherit a class with overridden evaluate() or just pass in an evalFunc. class ShaderEvaluator { public: ShaderEvaluator (void); ShaderEvaluator (ShaderEvalFunc evalFunc); virtual ~ShaderEvaluator (void); virtual void evaluate (ShaderEvalContext& ctx); private: ShaderEvaluator (const ShaderEvaluator&); // not allowed! ShaderEvaluator& operator= (const ShaderEvaluator&); // not allowed! ShaderEvalFunc m_evalFunc; }; // ShaderRenderCase. class ShaderRenderCase : public tcu::TestCase { public: ShaderRenderCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo, const char* name, const char* description, bool isVertexCase, ShaderEvalFunc evalFunc); ShaderRenderCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo, const char* name, const char* description, bool isVertexCase, ShaderEvaluator& evaluator); virtual ~ShaderRenderCase (void); void init (void); void deinit (void); IterateResult iterate (void); protected: virtual void setupShaderData (void); virtual void setup (int programID); virtual void setupUniforms (int programID, const tcu::Vec4& constCoords); tcu::IVec2 getViewportSize (void) const; class CompileFailed : public tcu::TestError { public: inline CompileFailed (const char* file, int line) : tcu::TestError("Failed to compile shader program", DE_NULL, file, line) {} }; private: ShaderRenderCase (const ShaderRenderCase&); // not allowed! ShaderRenderCase& operator= (const ShaderRenderCase&); // not allowed! void setupDefaultInputs (int programID); void render (tcu::Surface& result, int programID, const QuadGrid& quadGrid); void computeVertexReference (tcu::Surface& result, const QuadGrid& quadGrid); void computeFragmentReference(tcu::Surface& result, const QuadGrid& quadGrid); bool compareImages (const tcu::Surface& resImage, const tcu::Surface& refImage, float errorThreshold); protected: glu::RenderContext& m_renderCtx; const glu::ContextInfo& m_ctxInfo; bool m_isVertexCase; ShaderEvaluator m_defaultEvaluator; ShaderEvaluator& m_evaluator; std::string m_vertShaderSource; std::string m_fragShaderSource; tcu::Vec4 m_clearColor; std::vector<tcu::Mat4> m_userAttribTransforms; std::vector<TextureBinding> m_textures; glu::ShaderProgram* m_program; }; // Helpers. // \todo [2012-04-10 pyry] Move these to separate utility? const char* getIntUniformName (int number); const char* getFloatUniformName (int number); const char* getFloatFractionUniformName (int number); void setupDefaultUniforms (const glu::RenderContext& context, deUint32 programID); } // gls } // deqp #endif // _GLSSHADERRENDERCASE_HPP