You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

270 lines
7.9 KiB

#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