blob: 14754ebea8178498a430c94ebde5d2e431f60008 [file] [log] [blame]
#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 <sstream>
#include <string>
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<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);
} // deqp
#endif // _GLCSHADERRENDERCASE_HPP