#ifndef _GLCSHADERRENDERCASE_HPP #define _GLCSHADERRENDERCASE_HPP /*------------------------------------------------------------------------- * OpenGL Conformance Test Suite * ----------------------------- * * Copyright (c) 2016 Google Inc. * Copyright (c) 2016 The Khronos Group Inc. * * 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 "glcTestCase.hpp" #include "gluContextInfo.hpp" #include "gluRenderContext.hpp" #include "gluShaderProgram.hpp" #include "tcuDefs.hpp" #include "tcuMatrix.hpp" #include "tcuSurface.hpp" #include "tcuTexture.hpp" #include "tcuVector.hpp" #include #include namespace glu { class RenderContext; class Texture2D; class TextureCube; class Texture2DArray; class Texture3D; class TextureCubeArray; } // glu namespace deqp { // LineStream 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_CUBE_MAP_ARRAY, 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(const glu::TextureCubeArray* texCubeArray, 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); void setTexture(const glu::TextureCubeArray* texCubeArray); 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; } const glu::TextureCubeArray* getCubeArray(void) const { DE_ASSERT(getType() == TYPE_CUBE_MAP_ARRAY); return m_binding.texCubeArray; } 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; const glu::TextureCubeArray* texCubeArray; } 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; const tcu::TextureCubeArray* texCubeArray; inline ShaderSampler(void) : tex2D(DE_NULL), texCube(DE_NULL), tex2DArray(DE_NULL), tex3D(DE_NULL), texCubeArray(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 setup(deUint32 programID); virtual void setupUniforms(deUint32 programID, const tcu::Vec4& constCoords); tcu::IVec2 getViewportSize(void) const; 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 m_userAttribTransforms; std::vector 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); } // deqp #endif // _GLCSHADERRENDERCASE_HPP