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.
1152 lines
40 KiB
1152 lines
40 KiB
/*------------------------------------------------------------------------- |
|
* drawElements Quality Program OpenGL ES 2.0 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 texture tests. |
|
*//*--------------------------------------------------------------------*/ |
|
|
|
#include "es2fVertexTextureTests.hpp" |
|
#include "glsTextureTestUtil.hpp" |
|
#include "gluTexture.hpp" |
|
#include "gluPixelTransfer.hpp" |
|
#include "gluTextureUtil.hpp" |
|
#include "tcuVector.hpp" |
|
#include "tcuMatrix.hpp" |
|
#include "tcuTextureUtil.hpp" |
|
#include "tcuTexVerifierUtil.hpp" |
|
#include "tcuImageCompare.hpp" |
|
#include "deRandom.hpp" |
|
#include "deString.h" |
|
#include "deMath.h" |
|
|
|
#include <string> |
|
#include <vector> |
|
|
|
#include <limits> |
|
|
|
#include "glw.h" |
|
|
|
using tcu::TestLog; |
|
using tcu::Vec2; |
|
using tcu::Vec3; |
|
using tcu::Vec4; |
|
using tcu::IVec2; |
|
using tcu::IVec3; |
|
using tcu::IVec4; |
|
using tcu::Mat3; |
|
using std::string; |
|
using std::vector; |
|
|
|
namespace deqp |
|
{ |
|
|
|
using namespace gls::TextureTestUtil; |
|
using namespace glu::TextureTestUtil; |
|
|
|
using glu::TextureTestUtil::TEXTURETYPE_2D; |
|
using glu::TextureTestUtil::TEXTURETYPE_CUBE; |
|
|
|
namespace gles2 |
|
{ |
|
namespace Functional |
|
{ |
|
|
|
// The 2D case draws four images. |
|
static const int MAX_2D_RENDER_WIDTH = 128*2; |
|
static const int MAX_2D_RENDER_HEIGHT = 128*2; |
|
|
|
// The cube map case draws four 3-by-2 image groups. |
|
static const int MAX_CUBE_RENDER_WIDTH = 28*2*3; |
|
static const int MAX_CUBE_RENDER_HEIGHT = 28*2*2; |
|
|
|
static const int GRID_SIZE_2D = 127; |
|
static const int GRID_SIZE_CUBE = 63; |
|
|
|
// Helpers for making texture coordinates "safe", i.e. move them further from coordinate bounary. |
|
|
|
// Moves x towards the closest K+targetFraction, where K is an integer. |
|
// E.g. moveTowardsFraction(x, 0.5f) moves x away from integer boundaries. |
|
static inline float moveTowardsFraction (float x, float targetFraction) |
|
{ |
|
const float strictness = 0.5f; |
|
DE_ASSERT(0.0f < strictness && strictness <= 1.0f); |
|
DE_ASSERT(de::inBounds(targetFraction, 0.0f, 1.0f)); |
|
const float y = x + 0.5f - targetFraction; |
|
return deFloatFloor(y) + deFloatFrac(y)*(1.0f-strictness) + strictness*0.5f - 0.5f + targetFraction; |
|
} |
|
|
|
static inline float safeCoord (float raw, int scale, float fraction) |
|
{ |
|
const float scaleFloat = (float)scale; |
|
return moveTowardsFraction(raw*scaleFloat, fraction) / scaleFloat; |
|
} |
|
|
|
template <int Size> |
|
static inline tcu::Vector<float, Size> safeCoords (const tcu::Vector<float, Size>& raw, const tcu::Vector<int, Size>& scale, const tcu::Vector<float, Size>& fraction) |
|
{ |
|
tcu::Vector<float, Size> result; |
|
for (int i = 0; i < Size; i++) |
|
result[i] = safeCoord(raw[i], scale[i], fraction[i]); |
|
return result; |
|
} |
|
|
|
static inline Vec2 safe2DTexCoords (const Vec2& raw, const IVec2& textureSize) |
|
{ |
|
return safeCoords(raw, textureSize, Vec2(0.5f)); |
|
} |
|
|
|
namespace |
|
{ |
|
|
|
struct Rect |
|
{ |
|
Rect (int x_, int y_, int w_, int h_) : x(x_), y(y_), w(w_), h(h_) {} |
|
IVec2 pos (void) const { return IVec2(x, y); } |
|
IVec2 size (void) const { return IVec2(w, h); } |
|
|
|
int x; |
|
int y; |
|
int w; |
|
int h; |
|
}; |
|
|
|
template <TextureType> struct TexTypeTcuClass; |
|
template <> struct TexTypeTcuClass<TEXTURETYPE_2D> { typedef tcu::Texture2D t; }; |
|
template <> struct TexTypeTcuClass<TEXTURETYPE_CUBE> { typedef tcu::TextureCube t; }; |
|
|
|
template <TextureType> struct TexTypeSizeDims; |
|
template <> struct TexTypeSizeDims<TEXTURETYPE_2D> { enum { V = 2 }; }; |
|
template <> struct TexTypeSizeDims<TEXTURETYPE_CUBE> { enum { V = 2 }; }; |
|
|
|
template <TextureType> struct TexTypeCoordDims; |
|
template <> struct TexTypeCoordDims<TEXTURETYPE_2D> { enum { V = 2 }; }; |
|
template <> struct TexTypeCoordDims<TEXTURETYPE_CUBE> { enum { V = 3 }; }; |
|
|
|
template <TextureType TexType> struct TexTypeSizeIVec { typedef tcu::Vector<int, TexTypeSizeDims<TexType>::V> t; }; |
|
template <TextureType TexType> struct TexTypeCoordVec { typedef tcu::Vector<float, TexTypeCoordDims<TexType>::V> t; }; |
|
|
|
template <TextureType> struct TexTypeCoordParams; |
|
|
|
template <> struct |
|
TexTypeCoordParams<TEXTURETYPE_2D> |
|
{ |
|
Vec2 scale; |
|
Vec2 bias; |
|
|
|
TexTypeCoordParams (const Vec2& scale_, const Vec2& bias_) : scale(scale_), bias(bias_) {} |
|
}; |
|
|
|
template <> struct |
|
TexTypeCoordParams<TEXTURETYPE_CUBE> |
|
{ |
|
Vec2 scale; |
|
Vec2 bias; |
|
tcu::CubeFace face; |
|
|
|
TexTypeCoordParams (const Vec2& scale_, const Vec2& bias_, tcu::CubeFace face_) : scale(scale_), bias(bias_), face(face_) {} |
|
}; |
|
|
|
/*--------------------------------------------------------------------*//*! |
|
* \brief Quad grid class containing position and texture coordinate data. |
|
* |
|
* A quad grid of size S means a grid consisting of S*S quads (S rows and |
|
* S columns). The quads are rectangles with main axis aligned sides, and |
|
* each consists of two triangles. Note that although there are only |
|
* (S+1)*(S+1) distinct vertex positions, there are S*S*4 distinct vertices |
|
* because we want texture coordinates to be constant across the vertices |
|
* of a quad (to avoid interpolation issues), and thus each quad needs its |
|
* own 4 vertices. |
|
* |
|
* Pointers returned by get*Ptr() are suitable for gl calls such as |
|
* glVertexAttribPointer() (for position and tex coord) or glDrawElements() |
|
* (for indices). |
|
*//*--------------------------------------------------------------------*/ |
|
template <TextureType TexType> |
|
class PosTexCoordQuadGrid |
|
{ |
|
private: |
|
enum { TEX_COORD_DIMS = TexTypeCoordDims <TexType>::V }; |
|
typedef typename TexTypeCoordVec<TexType>::t TexCoordVec; |
|
typedef typename TexTypeSizeIVec<TexType>::t TexSizeIVec; |
|
typedef TexTypeCoordParams<TexType> TexCoordParams; |
|
|
|
public: |
|
PosTexCoordQuadGrid (int gridSize, const IVec2& renderSize, const TexSizeIVec& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords); |
|
|
|
int getSize (void) const { return m_gridSize; } |
|
Vec4 getQuadLDRU (int col, int row) const; //!< Vec4(leftX, downY, rightX, upY) |
|
const TexCoordVec& getQuadTexCoord (int col, int row) const; |
|
|
|
int getNumIndices (void) const { return m_gridSize*m_gridSize*3*2; } |
|
const float* getPositionPtr (void) const { DE_STATIC_ASSERT(sizeof(Vec2) == 2*sizeof(float)); return (float*)&m_positions[0]; } |
|
const float* getTexCoordPtr (void) const { DE_STATIC_ASSERT(sizeof(TexCoordVec) == TEX_COORD_DIMS*(int)sizeof(float)); return (float*)&m_texCoords[0]; } |
|
const deUint16* getIndexPtr (void) const { return &m_indices[0]; } |
|
|
|
private: |
|
void initializeTexCoords (const TexSizeIVec& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords); |
|
|
|
const int m_gridSize; |
|
vector<Vec2> m_positions; |
|
vector<TexCoordVec> m_texCoords; |
|
vector<deUint16> m_indices; |
|
}; |
|
|
|
template <TextureType TexType> |
|
Vec4 PosTexCoordQuadGrid<TexType>::getQuadLDRU (int col, int row) const |
|
{ |
|
int ndx00 = (row*m_gridSize + col) * 4; |
|
int ndx11 = ndx00 + 3; |
|
|
|
return Vec4(m_positions[ndx00].x(), |
|
m_positions[ndx00].y(), |
|
m_positions[ndx11].x(), |
|
m_positions[ndx11].y()); |
|
} |
|
|
|
template <TextureType TexType> |
|
const typename TexTypeCoordVec<TexType>::t& PosTexCoordQuadGrid<TexType>::getQuadTexCoord (int col, int row) const |
|
{ |
|
return m_texCoords[(row*m_gridSize + col) * 4]; |
|
} |
|
|
|
template <TextureType TexType> |
|
PosTexCoordQuadGrid<TexType>::PosTexCoordQuadGrid (int gridSize, const IVec2& renderSize, const TexSizeIVec& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords) |
|
: m_gridSize(gridSize) |
|
{ |
|
DE_ASSERT(m_gridSize > 0 && m_gridSize*m_gridSize <= (int)std::numeric_limits<deUint16>::max() + 1); |
|
|
|
const float gridSizeFloat = (float)m_gridSize; |
|
|
|
m_positions.reserve(m_gridSize*m_gridSize*4); |
|
m_indices.reserve(m_gridSize*m_gridSize*3*2); |
|
|
|
for (int y = 0; y < m_gridSize; y++) |
|
for (int x = 0; x < m_gridSize; x++) |
|
{ |
|
float fx0 = (float)(x+0) / gridSizeFloat; |
|
float fx1 = (float)(x+1) / gridSizeFloat; |
|
float fy0 = (float)(y+0) / gridSizeFloat; |
|
float fy1 = (float)(y+1) / gridSizeFloat; |
|
|
|
Vec2 quadVertices[4] = { Vec2(fx0, fy0), Vec2(fx1, fy0), Vec2(fx0, fy1), Vec2(fx1, fy1) }; |
|
|
|
int firstNdx = (int)m_positions.size(); |
|
|
|
for (int i = 0; i < DE_LENGTH_OF_ARRAY(quadVertices); i++) |
|
m_positions.push_back(safeCoords(quadVertices[i], renderSize, Vec2(0.0f)) * 2.0f - 1.0f); |
|
|
|
m_indices.push_back(deUint16(firstNdx + 0)); |
|
m_indices.push_back(deUint16(firstNdx + 1)); |
|
m_indices.push_back(deUint16(firstNdx + 2)); |
|
|
|
m_indices.push_back(deUint16(firstNdx + 1)); |
|
m_indices.push_back(deUint16(firstNdx + 3)); |
|
m_indices.push_back(deUint16(firstNdx + 2)); |
|
} |
|
|
|
m_texCoords.reserve(m_gridSize*m_gridSize*4); |
|
initializeTexCoords(textureSize, texCoordParams, useSafeTexCoords); |
|
|
|
DE_ASSERT((int)m_positions.size() == m_gridSize*m_gridSize*4); |
|
DE_ASSERT((int)m_indices.size() == m_gridSize*m_gridSize*3*2); |
|
DE_ASSERT((int)m_texCoords.size() == m_gridSize*m_gridSize*4); |
|
} |
|
|
|
template <> |
|
void PosTexCoordQuadGrid<TEXTURETYPE_2D>::initializeTexCoords (const IVec2& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords) |
|
{ |
|
DE_ASSERT(m_texCoords.empty()); |
|
|
|
const float gridSizeFloat = (float)m_gridSize; |
|
|
|
for (int y = 0; y < m_gridSize; y++) |
|
for (int x = 0; x < m_gridSize; x++) |
|
{ |
|
Vec2 rawCoord = Vec2((float)x / gridSizeFloat, (float)y / gridSizeFloat) * texCoordParams.scale + texCoordParams.bias; |
|
|
|
for (int i = 0; i < 4; i++) |
|
m_texCoords.push_back(useSafeTexCoords ? safe2DTexCoords(rawCoord, textureSize) : rawCoord); |
|
} |
|
} |
|
|
|
template <> |
|
void PosTexCoordQuadGrid<TEXTURETYPE_CUBE>::initializeTexCoords (const IVec2& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords) |
|
{ |
|
DE_ASSERT(m_texCoords.empty()); |
|
|
|
const float gridSizeFloat = (float)m_gridSize; |
|
vector<float> texBoundaries; |
|
computeQuadTexCoordCube(texBoundaries, texCoordParams.face); |
|
const Vec3 coordA = Vec3(texBoundaries[0], texBoundaries[1], texBoundaries[2]); |
|
const Vec3 coordB = Vec3(texBoundaries[3], texBoundaries[4], texBoundaries[5]); |
|
const Vec3 coordC = Vec3(texBoundaries[6], texBoundaries[7], texBoundaries[8]); |
|
const Vec3 coordAB = coordB - coordA; |
|
const Vec3 coordAC = coordC - coordA; |
|
|
|
for (int y = 0; y < m_gridSize; y++) |
|
for (int x = 0; x < m_gridSize; x++) |
|
{ |
|
const Vec2 rawFaceCoord = texCoordParams.scale * Vec2((float)x / gridSizeFloat, (float)y / gridSizeFloat) + texCoordParams.bias; |
|
const Vec2 safeFaceCoord = useSafeTexCoords ? safe2DTexCoords(rawFaceCoord, textureSize) : rawFaceCoord; |
|
const Vec3 texCoord = coordA + coordAC*safeFaceCoord.x() + coordAB*safeFaceCoord.y(); |
|
|
|
for (int i = 0; i < 4; i++) |
|
m_texCoords.push_back(texCoord); |
|
} |
|
} |
|
|
|
} // anonymous |
|
|
|
static inline bool isLevelNearest (deUint32 filter) |
|
{ |
|
return filter == GL_NEAREST || filter == GL_NEAREST_MIPMAP_NEAREST || filter == GL_NEAREST_MIPMAP_LINEAR; |
|
} |
|
|
|
static inline IVec2 getTextureSize (const glu::Texture2D& tex) |
|
{ |
|
const tcu::Texture2D& ref = tex.getRefTexture(); |
|
return IVec2(ref.getWidth(), ref.getHeight()); |
|
} |
|
|
|
static inline IVec2 getTextureSize (const glu::TextureCube& tex) |
|
{ |
|
const tcu::TextureCube& ref = tex.getRefTexture(); |
|
return IVec2(ref.getSize(), ref.getSize()); |
|
} |
|
|
|
template <TextureType TexType> |
|
static void setPixelColors (const vector<Vec4>& quadColors, const Rect& region, const PosTexCoordQuadGrid<TexType>& grid, tcu::Surface& dst) |
|
{ |
|
const int gridSize = grid.getSize(); |
|
|
|
for (int y = 0; y < gridSize; y++) |
|
for (int x = 0; x < gridSize; x++) |
|
{ |
|
const Vec4 color = quadColors[y*gridSize + x]; |
|
const Vec4 ldru = grid.getQuadLDRU(x, y) * 0.5f + 0.5f; // [-1, 1] -> [0, 1] |
|
const int ix0 = deCeilFloatToInt32(ldru.x() * (float)region.w - 0.5f); |
|
const int ix1 = deCeilFloatToInt32(ldru.z() * (float)region.w - 0.5f); |
|
const int iy0 = deCeilFloatToInt32(ldru.y() * (float)region.h - 0.5f); |
|
const int iy1 = deCeilFloatToInt32(ldru.w() * (float)region.h - 0.5f); |
|
|
|
for (int iy = iy0; iy < iy1; iy++) |
|
for (int ix = ix0; ix < ix1; ix++) |
|
{ |
|
DE_ASSERT(deInBounds32(ix + region.x, 0, dst.getWidth())); |
|
DE_ASSERT(deInBounds32(iy + region.y, 0, dst.getHeight())); |
|
|
|
dst.setPixel(ix + region.x, iy + region.y, tcu::RGBA(color)); |
|
} |
|
} |
|
} |
|
|
|
static inline Vec4 sample (const tcu::Texture2D& tex, const Vec2& coord, float lod, const tcu::Sampler& sam) { return tex.sample(sam, coord.x(), coord.y(), lod); } |
|
static inline Vec4 sample (const tcu::TextureCube& tex, const Vec3& coord, float lod, const tcu::Sampler& sam) { return tex.sample(sam, coord.x(), coord.y(), coord.z(), lod); } |
|
|
|
template <TextureType TexType> |
|
void computeReference (const typename TexTypeTcuClass<TexType>::t& texture, float lod, const tcu::Sampler& sampler, const PosTexCoordQuadGrid<TexType>& grid, tcu::Surface& dst, const Rect& dstRegion) |
|
{ |
|
const int gridSize = grid.getSize(); |
|
vector<Vec4> quadColors (gridSize*gridSize); |
|
|
|
for (int y = 0; y < gridSize; y++) |
|
for (int x = 0; x < gridSize; x++) |
|
{ |
|
const int ndx = y*gridSize + x; |
|
const typename TexTypeCoordVec<TexType>::t& coord = grid.getQuadTexCoord(x, y); |
|
|
|
quadColors[ndx] = sample(texture, coord, lod, sampler); |
|
} |
|
|
|
setPixelColors(quadColors, dstRegion, grid, dst); |
|
} |
|
|
|
static bool compareImages (const glu::RenderContext& renderCtx, tcu::TestLog& log, const tcu::Surface& ref, const tcu::Surface& res) |
|
{ |
|
DE_ASSERT(renderCtx.getRenderTarget().getNumSamples() == 0); |
|
|
|
const tcu::RGBA threshold = renderCtx.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(15,15,15,15); |
|
return tcu::pixelThresholdCompare(log, "Result", "Image compare result", ref, res, threshold, tcu::COMPARE_LOG_RESULT); |
|
} |
|
|
|
class Vertex2DTextureCase : public TestCase |
|
{ |
|
public: |
|
Vertex2DTextureCase (Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT); |
|
~Vertex2DTextureCase (void); |
|
|
|
void init (void); |
|
void deinit (void); |
|
IterateResult iterate (void); |
|
|
|
private: |
|
typedef PosTexCoordQuadGrid<TEXTURETYPE_2D> Grid; |
|
|
|
Vertex2DTextureCase (const Vertex2DTextureCase& other); |
|
Vertex2DTextureCase& operator= (const Vertex2DTextureCase& other); |
|
|
|
float calculateLod (const Vec2& texScale, const Vec2& dstSize, int textureNdx) const; |
|
void setupShaderInputs (int textureNdx, float lod, const Grid& grid) const; |
|
void renderCell (int textureNdx, float lod, const Grid& grid) const; |
|
void computeReferenceCell (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const; |
|
|
|
const deUint32 m_minFilter; |
|
const deUint32 m_magFilter; |
|
const deUint32 m_wrapS; |
|
const deUint32 m_wrapT; |
|
|
|
const glu::ShaderProgram* m_program; |
|
glu::Texture2D* m_textures[2]; // 2 textures, a gradient texture and a grid texture. |
|
}; |
|
|
|
Vertex2DTextureCase::Vertex2DTextureCase (Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT) |
|
: TestCase (testCtx, tcu::NODETYPE_SELF_VALIDATE, name, desc) |
|
, m_minFilter (minFilter) |
|
, m_magFilter (magFilter) |
|
, m_wrapS (wrapS) |
|
, m_wrapT (wrapT) |
|
, m_program (DE_NULL) |
|
{ |
|
m_textures[0] = DE_NULL; |
|
m_textures[1] = DE_NULL; |
|
} |
|
|
|
Vertex2DTextureCase::~Vertex2DTextureCase(void) |
|
{ |
|
Vertex2DTextureCase::deinit(); |
|
} |
|
|
|
void Vertex2DTextureCase::init (void) |
|
{ |
|
const char* const vertexShader = |
|
"attribute highp vec2 a_position;\n" |
|
"attribute highp vec2 a_texCoord;\n" |
|
"uniform highp sampler2D u_texture;\n" |
|
"uniform highp float u_lod;\n" |
|
"varying mediump vec4 v_color;\n" |
|
"\n" |
|
"void main()\n" |
|
"{\n" |
|
" gl_Position = vec4(a_position, 0.0, 1.0);\n" |
|
" v_color = texture2DLod(u_texture, a_texCoord, u_lod);\n" |
|
"}\n"; |
|
|
|
const char* const fragmentShader = |
|
"varying mediump vec4 v_color;\n" |
|
"\n" |
|
"void main()\n" |
|
"{\n" |
|
" gl_FragColor = v_color;\n" |
|
"}\n"; |
|
|
|
if (m_context.getRenderTarget().getNumSamples() != 0) |
|
throw tcu::NotSupportedError("MSAA config not supported by this test"); |
|
|
|
DE_ASSERT(!m_program); |
|
m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertexShader, fragmentShader)); |
|
|
|
if(!m_program->isOk()) |
|
{ |
|
m_testCtx.getLog() << *m_program; |
|
|
|
GLint maxVertexTextures; |
|
glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxVertexTextures); |
|
|
|
if (maxVertexTextures < 1) |
|
throw tcu::NotSupportedError("Vertex texture image units not supported", "", __FILE__, __LINE__); |
|
else |
|
TCU_FAIL("Failed to compile shader"); |
|
} |
|
|
|
// Make the textures. |
|
try |
|
{ |
|
// Compute suitable power-of-two sizes (for mipmaps). |
|
const int texWidth = 1 << deLog2Ceil32(MAX_2D_RENDER_WIDTH / 2); |
|
const int texHeight = 1 << deLog2Ceil32(MAX_2D_RENDER_HEIGHT / 2); |
|
|
|
for (int i = 0; i < 2; i++) |
|
{ |
|
DE_ASSERT(!m_textures[i]); |
|
m_textures[i] = new glu::Texture2D(m_context.getRenderContext(), GL_RGB, GL_UNSIGNED_BYTE, texWidth, texHeight); |
|
} |
|
|
|
const bool mipmaps = (deIsPowerOfTwo32(texWidth) && deIsPowerOfTwo32(texHeight)); |
|
const int numLevels = mipmaps ? deLog2Floor32(de::max(texWidth, texHeight))+1 : 1; |
|
const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat()); |
|
const Vec4 cBias = fmtInfo.valueMin; |
|
const Vec4 cScale = fmtInfo.valueMax-fmtInfo.valueMin; |
|
|
|
// Fill first with gradient texture. |
|
for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) |
|
{ |
|
const Vec4 gMin = Vec4(-0.5f, -0.5f, -0.5f, 2.0f)*cScale + cBias; |
|
const Vec4 gMax = Vec4( 1.0f, 1.0f, 1.0f, 0.0f)*cScale + cBias; |
|
|
|
m_textures[0]->getRefTexture().allocLevel(levelNdx); |
|
tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevel(levelNdx), gMin, gMax); |
|
} |
|
|
|
// Fill second with grid texture. |
|
for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) |
|
{ |
|
const deUint32 step = 0x00ffffff / numLevels; |
|
const deUint32 rgb = step*levelNdx; |
|
const deUint32 colorA = 0xff000000 | rgb; |
|
const deUint32 colorB = 0xff000000 | ~rgb; |
|
|
|
m_textures[1]->getRefTexture().allocLevel(levelNdx); |
|
tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevel(levelNdx), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias); |
|
} |
|
|
|
// Upload. |
|
for (int i = 0; i < 2; i++) |
|
m_textures[i]->upload(); |
|
} |
|
catch (const std::exception&) |
|
{ |
|
// Clean up to save memory. |
|
Vertex2DTextureCase::deinit(); |
|
throw; |
|
} |
|
} |
|
|
|
void Vertex2DTextureCase::deinit (void) |
|
{ |
|
for (int i = 0; i < 2; i++) |
|
{ |
|
delete m_textures[i]; |
|
m_textures[i] = DE_NULL; |
|
} |
|
|
|
delete m_program; |
|
m_program = DE_NULL; |
|
} |
|
|
|
float Vertex2DTextureCase::calculateLod (const Vec2& texScale, const Vec2& dstSize, int textureNdx) const |
|
{ |
|
const tcu::Texture2D& refTexture = m_textures[textureNdx]->getRefTexture(); |
|
const Vec2 srcSize = Vec2((float)refTexture.getWidth(), (float)refTexture.getHeight()); |
|
const Vec2 sizeRatio = texScale*srcSize / dstSize; |
|
|
|
// \note In this particular case dv/dx and du/dy are zero, simplifying the expression. |
|
return deFloatLog2(de::max(sizeRatio.x(), sizeRatio.y())); |
|
} |
|
|
|
Vertex2DTextureCase::IterateResult Vertex2DTextureCase::iterate (void) |
|
{ |
|
const int viewportWidth = deMin32(m_context.getRenderTarget().getWidth(), MAX_2D_RENDER_WIDTH); |
|
const int viewportHeight = deMin32(m_context.getRenderTarget().getHeight(), MAX_2D_RENDER_HEIGHT); |
|
|
|
const int viewportXOffsetMax = m_context.getRenderTarget().getWidth() - viewportWidth; |
|
const int viewportYOffsetMax = m_context.getRenderTarget().getHeight() - viewportHeight; |
|
|
|
de::Random rnd (deStringHash(getName())); |
|
|
|
const int viewportXOffset = rnd.getInt(0, viewportXOffsetMax); |
|
const int viewportYOffset = rnd.getInt(0, viewportYOffsetMax); |
|
|
|
glUseProgram(m_program->getProgram()); |
|
|
|
// Divide viewport into 4 cells. |
|
const int leftWidth = viewportWidth / 2; |
|
const int rightWidth = viewportWidth - leftWidth; |
|
const int bottomHeight = viewportHeight / 2; |
|
const int topHeight = viewportHeight - bottomHeight; |
|
|
|
// Clear. |
|
glClearColor(0.125f, 0.25f, 0.5f, 1.0f); |
|
glClear(GL_COLOR_BUFFER_BIT); |
|
|
|
// Texture scaling and offsetting vectors. |
|
const Vec2 texMinScale (+1.8f, +1.8f); |
|
const Vec2 texMinOffset (-0.3f, -0.2f); |
|
const Vec2 texMagScale (+0.3f, +0.3f); |
|
const Vec2 texMagOffset (+0.9f, +0.8f); |
|
|
|
// Surface for the reference image. |
|
tcu::Surface refImage(viewportWidth, viewportHeight); |
|
|
|
{ |
|
const struct Render |
|
{ |
|
const Rect region; |
|
int textureNdx; |
|
const Vec2 texCoordScale; |
|
const Vec2 texCoordOffset; |
|
Render (const Rect& r, int tN, const Vec2& tS, const Vec2& tO) : region(r), textureNdx(tN), texCoordScale(tS), texCoordOffset(tO) {} |
|
} renders[] = |
|
{ |
|
Render(Rect(0, 0, leftWidth, bottomHeight), 0, texMinScale, texMinOffset), |
|
Render(Rect(leftWidth, 0, rightWidth, bottomHeight), 0, texMagScale, texMagOffset), |
|
Render(Rect(0, bottomHeight, leftWidth, topHeight), 1, texMinScale, texMinOffset), |
|
Render(Rect(leftWidth, bottomHeight, rightWidth, topHeight), 1, texMagScale, texMagOffset) |
|
}; |
|
|
|
for (int renderNdx = 0; renderNdx < DE_LENGTH_OF_ARRAY(renders); renderNdx++) |
|
{ |
|
const Render& rend = renders[renderNdx]; |
|
const float lod = calculateLod(rend.texCoordScale, rend.region.size().asFloat(), rend.textureNdx); |
|
const bool useSafeTexCoords = isLevelNearest(lod > 0.0f ? m_minFilter : m_magFilter); |
|
const Grid grid (GRID_SIZE_2D, rend.region.size(), getTextureSize(*m_textures[rend.textureNdx]), |
|
TexTypeCoordParams<TEXTURETYPE_2D>(rend.texCoordScale, rend.texCoordOffset), useSafeTexCoords); |
|
|
|
glViewport(viewportXOffset + rend.region.x, viewportYOffset + rend.region.y, rend.region.w, rend.region.h); |
|
renderCell (rend.textureNdx, lod, grid); |
|
computeReferenceCell (rend.textureNdx, lod, grid, refImage, rend.region); |
|
} |
|
} |
|
|
|
// Read back rendered results. |
|
tcu::Surface resImage(viewportWidth, viewportHeight); |
|
glu::readPixels(m_context.getRenderContext(), viewportXOffset, viewportYOffset, resImage.getAccess()); |
|
|
|
glUseProgram(0); |
|
|
|
// Compare and log. |
|
{ |
|
const bool isOk = compareImages(m_context.getRenderContext(), m_testCtx.getLog(), refImage, resImage); |
|
|
|
m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, |
|
isOk ? "Pass" : "Image comparison failed"); |
|
} |
|
|
|
return STOP; |
|
} |
|
|
|
void Vertex2DTextureCase::setupShaderInputs (int textureNdx, float lod, const Grid& grid) const |
|
{ |
|
const deUint32 programID = m_program->getProgram(); |
|
|
|
// SETUP ATTRIBUTES. |
|
|
|
{ |
|
const int positionLoc = glGetAttribLocation(programID, "a_position"); |
|
if (positionLoc != -1) |
|
{ |
|
glEnableVertexAttribArray(positionLoc); |
|
glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, grid.getPositionPtr()); |
|
} |
|
} |
|
|
|
{ |
|
const int texCoordLoc = glGetAttribLocation(programID, "a_texCoord"); |
|
if (texCoordLoc != -1) |
|
{ |
|
glEnableVertexAttribArray(texCoordLoc); |
|
glVertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, grid.getTexCoordPtr()); |
|
} |
|
} |
|
|
|
// SETUP UNIFORMS. |
|
|
|
{ |
|
const int lodLoc = glGetUniformLocation(programID, "u_lod"); |
|
if (lodLoc != -1) |
|
glUniform1f(lodLoc, lod); |
|
} |
|
|
|
glActiveTexture(GL_TEXTURE0); |
|
glBindTexture(GL_TEXTURE_2D, m_textures[textureNdx]->getGLTexture()); |
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_wrapS); |
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_wrapT); |
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_minFilter); |
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_magFilter); |
|
|
|
{ |
|
const int texLoc = glGetUniformLocation(programID, "u_texture"); |
|
if (texLoc != -1) |
|
glUniform1i(texLoc, 0); |
|
} |
|
} |
|
|
|
// Renders one sub-image with given parameters. |
|
void Vertex2DTextureCase::renderCell (int textureNdx, float lod, const Grid& grid) const |
|
{ |
|
setupShaderInputs(textureNdx, lod, grid); |
|
glDrawElements(GL_TRIANGLES, grid.getNumIndices(), GL_UNSIGNED_SHORT, grid.getIndexPtr()); |
|
} |
|
|
|
void Vertex2DTextureCase::computeReferenceCell (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const |
|
{ |
|
computeReference(m_textures[textureNdx]->getRefTexture(), lod, glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter), grid, dst, dstRegion); |
|
} |
|
|
|
class VertexCubeTextureCase : public TestCase |
|
{ |
|
public: |
|
VertexCubeTextureCase (Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT); |
|
~VertexCubeTextureCase (void); |
|
|
|
void init (void); |
|
void deinit (void); |
|
IterateResult iterate (void); |
|
|
|
private: |
|
typedef PosTexCoordQuadGrid<TEXTURETYPE_CUBE> Grid; |
|
|
|
VertexCubeTextureCase (const VertexCubeTextureCase& other); |
|
VertexCubeTextureCase& operator= (const VertexCubeTextureCase& other); |
|
|
|
float calculateLod (const Vec2& texScale, const Vec2& dstSize, int textureNdx) const; |
|
void setupShaderInputs (int textureNdx, float lod, const Grid& grid) const; |
|
void renderCell (int textureNdx, float lod, const Grid& grid) const; |
|
void computeReferenceCell (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const; |
|
|
|
const deUint32 m_minFilter; |
|
const deUint32 m_magFilter; |
|
const deUint32 m_wrapS; |
|
const deUint32 m_wrapT; |
|
|
|
const glu::ShaderProgram* m_program; |
|
glu::TextureCube* m_textures[2]; // 2 textures, a gradient texture and a grid texture. |
|
}; |
|
|
|
VertexCubeTextureCase::VertexCubeTextureCase (Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT) |
|
: TestCase (testCtx, tcu::NODETYPE_SELF_VALIDATE, name, desc) |
|
, m_minFilter (minFilter) |
|
, m_magFilter (magFilter) |
|
, m_wrapS (wrapS) |
|
, m_wrapT (wrapT) |
|
, m_program (DE_NULL) |
|
{ |
|
m_textures[0] = DE_NULL; |
|
m_textures[1] = DE_NULL; |
|
} |
|
|
|
VertexCubeTextureCase::~VertexCubeTextureCase(void) |
|
{ |
|
VertexCubeTextureCase::deinit(); |
|
} |
|
|
|
void VertexCubeTextureCase::init (void) |
|
{ |
|
const char* const vertexShader = |
|
"attribute highp vec2 a_position;\n" |
|
"attribute highp vec3 a_texCoord;\n" |
|
"uniform highp samplerCube u_texture;\n" |
|
"uniform highp float u_lod;\n" |
|
"varying mediump vec4 v_color;\n" |
|
"\n" |
|
"void main()\n" |
|
"{\n" |
|
" gl_Position = vec4(a_position, 0.0, 1.0);\n" |
|
" v_color = textureCubeLod(u_texture, a_texCoord, u_lod);\n" |
|
"}\n"; |
|
|
|
const char* const fragmentShader = |
|
"varying mediump vec4 v_color;\n" |
|
"\n" |
|
"void main()\n" |
|
"{\n" |
|
" gl_FragColor = v_color;\n" |
|
"}\n"; |
|
|
|
if (m_context.getRenderTarget().getNumSamples() != 0) |
|
throw tcu::NotSupportedError("MSAA config not supported by this test"); |
|
|
|
DE_ASSERT(!m_program); |
|
m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertexShader, fragmentShader)); |
|
|
|
if(!m_program->isOk()) |
|
{ |
|
m_testCtx.getLog() << *m_program; |
|
|
|
GLint maxVertexTextures; |
|
glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxVertexTextures); |
|
|
|
if (maxVertexTextures < 1) |
|
throw tcu::NotSupportedError("Vertex texture image units not supported", "", __FILE__, __LINE__); |
|
else |
|
TCU_FAIL("Failed to compile shader"); |
|
} |
|
|
|
// Make the textures. |
|
try |
|
{ |
|
// Compute suitable power-of-two sizes (for mipmaps). |
|
const int texWidth = 1 << deLog2Ceil32(MAX_CUBE_RENDER_WIDTH / 3 / 2); |
|
const int texHeight = 1 << deLog2Ceil32(MAX_CUBE_RENDER_HEIGHT / 2 / 2); |
|
|
|
DE_ASSERT(texWidth == texHeight); |
|
DE_UNREF(texHeight); |
|
|
|
for (int i = 0; i < 2; i++) |
|
{ |
|
DE_ASSERT(!m_textures[i]); |
|
m_textures[i] = new glu::TextureCube(m_context.getRenderContext(), GL_RGB, GL_UNSIGNED_BYTE, texWidth); |
|
} |
|
|
|
const bool mipmaps = deIsPowerOfTwo32(texWidth) != DE_FALSE; |
|
const int numLevels = mipmaps ? deLog2Floor32(texWidth)+1 : 1; |
|
const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat()); |
|
const Vec4 cBias = fmtInfo.valueMin; |
|
const Vec4 cScale = fmtInfo.valueMax-fmtInfo.valueMin; |
|
|
|
// Fill first with gradient texture. |
|
static const Vec4 gradients[tcu::CUBEFACE_LAST][2] = |
|
{ |
|
{ Vec4(-1.0f, -1.0f, -1.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative x |
|
{ Vec4( 0.0f, -1.0f, -1.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive x |
|
{ Vec4(-1.0f, 0.0f, -1.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative y |
|
{ Vec4(-1.0f, -1.0f, 0.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive y |
|
{ Vec4(-1.0f, -1.0f, -1.0f, 0.0f), Vec4(1.0f, 1.0f, 1.0f, 1.0f) }, // negative z |
|
{ Vec4( 0.0f, 0.0f, 0.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) } // positive z |
|
}; |
|
for (int face = 0; face < tcu::CUBEFACE_LAST; face++) |
|
{ |
|
for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) |
|
{ |
|
m_textures[0]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx); |
|
tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), gradients[face][0]*cScale + cBias, gradients[face][1]*cScale + cBias); |
|
} |
|
} |
|
|
|
// Fill second with grid texture. |
|
for (int face = 0; face < tcu::CUBEFACE_LAST; face++) |
|
{ |
|
for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) |
|
{ |
|
const deUint32 step = 0x00ffffff / (numLevels*tcu::CUBEFACE_LAST); |
|
const deUint32 rgb = step*levelNdx*face; |
|
const deUint32 colorA = 0xff000000 | rgb; |
|
const deUint32 colorB = 0xff000000 | ~rgb; |
|
|
|
m_textures[1]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx); |
|
tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias); |
|
} |
|
} |
|
|
|
// Upload. |
|
for (int i = 0; i < 2; i++) |
|
m_textures[i]->upload(); |
|
} |
|
catch (const std::exception&) |
|
{ |
|
// Clean up to save memory. |
|
VertexCubeTextureCase::deinit(); |
|
throw; |
|
} |
|
} |
|
|
|
void VertexCubeTextureCase::deinit (void) |
|
{ |
|
for (int i = 0; i < 2; i++) |
|
{ |
|
delete m_textures[i]; |
|
m_textures[i] = DE_NULL; |
|
} |
|
|
|
delete m_program; |
|
m_program = DE_NULL; |
|
} |
|
|
|
float VertexCubeTextureCase::calculateLod (const Vec2& texScale, const Vec2& dstSize, int textureNdx) const |
|
{ |
|
const tcu::TextureCube& refTexture = m_textures[textureNdx]->getRefTexture(); |
|
const Vec2 srcSize = Vec2((float)refTexture.getSize(), (float)refTexture.getSize()); |
|
const Vec2 sizeRatio = texScale*srcSize / dstSize; |
|
|
|
// \note In this particular case, dv/dx and du/dy are zero, simplifying the expression. |
|
return deFloatLog2(de::max(sizeRatio.x(), sizeRatio.y())); |
|
} |
|
|
|
VertexCubeTextureCase::IterateResult VertexCubeTextureCase::iterate (void) |
|
{ |
|
const int viewportWidth = deMin32(m_context.getRenderTarget().getWidth(), MAX_CUBE_RENDER_WIDTH); |
|
const int viewportHeight = deMin32(m_context.getRenderTarget().getHeight(), MAX_CUBE_RENDER_HEIGHT); |
|
|
|
const int viewportXOffsetMax = m_context.getRenderTarget().getWidth() - viewportWidth; |
|
const int viewportYOffsetMax = m_context.getRenderTarget().getHeight() - viewportHeight; |
|
|
|
de::Random rnd (deStringHash(getName())); |
|
|
|
const int viewportXOffset = rnd.getInt(0, viewportXOffsetMax); |
|
const int viewportYOffset = rnd.getInt(0, viewportYOffsetMax); |
|
|
|
glUseProgram(m_program->getProgram()); |
|
|
|
// Divide viewport into 4 areas. |
|
const int leftWidth = viewportWidth / 2; |
|
const int rightWidth = viewportWidth - leftWidth; |
|
const int bottomHeight = viewportHeight / 2; |
|
const int topHeight = viewportHeight - bottomHeight; |
|
|
|
// Clear. |
|
glClearColor(0.125f, 0.25f, 0.5f, 1.0f); |
|
glClear(GL_COLOR_BUFFER_BIT); |
|
|
|
// Texture scaling and offsetting vectors. |
|
const Vec2 texMinScale (1.0f, 1.0f); |
|
const Vec2 texMinOffset (0.0f, 0.0f); |
|
const Vec2 texMagScale (0.3f, 0.3f); |
|
const Vec2 texMagOffset (0.5f, 0.3f); |
|
|
|
// Surface for the reference image. |
|
tcu::Surface refImage(viewportWidth, viewportHeight); |
|
|
|
// Each of the four areas is divided into 6 cells. |
|
const int defCellWidth = viewportWidth / 2 / 3; |
|
const int defCellHeight = viewportHeight / 2 / 2; |
|
|
|
for (int i = 0; i < tcu::CUBEFACE_LAST; i++) |
|
{ |
|
const int cellOffsetX = defCellWidth * (i % 3); |
|
const int cellOffsetY = defCellHeight * (i / 3); |
|
const bool isRightmostCell = i == 2 || i == 5; |
|
const bool isTopCell = i >= 3; |
|
const int leftCellWidth = isRightmostCell ? leftWidth - cellOffsetX : defCellWidth; |
|
const int rightCellWidth = isRightmostCell ? rightWidth - cellOffsetX : defCellWidth; |
|
const int bottomCellHeight = isTopCell ? bottomHeight - cellOffsetY : defCellHeight; |
|
const int topCellHeight = isTopCell ? topHeight - cellOffsetY : defCellHeight; |
|
|
|
const struct Render |
|
{ |
|
const Rect region; |
|
int textureNdx; |
|
const Vec2 texCoordScale; |
|
const Vec2 texCoordOffset; |
|
Render (const Rect& r, int tN, const Vec2& tS, const Vec2& tO) : region(r), textureNdx(tN), texCoordScale(tS), texCoordOffset(tO) {} |
|
} renders[] = |
|
{ |
|
Render(Rect(cellOffsetX + 0, cellOffsetY + 0, leftCellWidth, bottomCellHeight), 0, texMinScale, texMinOffset), |
|
Render(Rect(cellOffsetX + leftWidth, cellOffsetY + 0, rightCellWidth, bottomCellHeight), 0, texMagScale, texMagOffset), |
|
Render(Rect(cellOffsetX + 0, cellOffsetY + bottomHeight, leftCellWidth, topCellHeight), 1, texMinScale, texMinOffset), |
|
Render(Rect(cellOffsetX + leftWidth, cellOffsetY + bottomHeight, rightCellWidth, topCellHeight), 1, texMagScale, texMagOffset) |
|
}; |
|
|
|
for (int renderNdx = 0; renderNdx < DE_LENGTH_OF_ARRAY(renders); renderNdx++) |
|
{ |
|
const Render& rend = renders[renderNdx]; |
|
const float lod = calculateLod(rend.texCoordScale, rend.region.size().asFloat(), rend.textureNdx); |
|
const bool useSafeTexCoords = isLevelNearest(lod > 0.0f ? m_minFilter : m_magFilter); |
|
const Grid grid (GRID_SIZE_CUBE, rend.region.size(), getTextureSize(*m_textures[rend.textureNdx]), |
|
TexTypeCoordParams<TEXTURETYPE_CUBE>(rend.texCoordScale, rend.texCoordOffset, (tcu::CubeFace)i), useSafeTexCoords); |
|
|
|
glViewport(viewportXOffset + rend.region.x, viewportYOffset + rend.region.y, rend.region.w, rend.region.h); |
|
renderCell (rend.textureNdx, lod, grid); |
|
computeReferenceCell (rend.textureNdx, lod, grid, refImage, rend.region); |
|
} |
|
} |
|
|
|
// Read back rendered results. |
|
tcu::Surface resImage(viewportWidth, viewportHeight); |
|
glu::readPixels(m_context.getRenderContext(), viewportXOffset, viewportYOffset, resImage.getAccess()); |
|
|
|
glUseProgram(0); |
|
|
|
// Compare and log. |
|
{ |
|
const bool isOk = compareImages(m_context.getRenderContext(), m_testCtx.getLog(), refImage, resImage); |
|
|
|
m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, |
|
isOk ? "Pass" : "Image comparison failed"); |
|
} |
|
|
|
return STOP; |
|
} |
|
|
|
void VertexCubeTextureCase::setupShaderInputs (int textureNdx, float lod, const Grid& grid) const |
|
{ |
|
const deUint32 programID = m_program->getProgram(); |
|
|
|
// SETUP ATTRIBUTES. |
|
|
|
{ |
|
const int positionLoc = glGetAttribLocation(programID, "a_position"); |
|
if (positionLoc != -1) |
|
{ |
|
glEnableVertexAttribArray(positionLoc); |
|
glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, grid.getPositionPtr()); |
|
} |
|
} |
|
|
|
{ |
|
const int texCoordLoc = glGetAttribLocation(programID, "a_texCoord"); |
|
if (texCoordLoc != -1) |
|
{ |
|
glEnableVertexAttribArray(texCoordLoc); |
|
glVertexAttribPointer(texCoordLoc, 3, GL_FLOAT, GL_FALSE, 0, grid.getTexCoordPtr()); |
|
} |
|
} |
|
|
|
// SETUP UNIFORMS. |
|
|
|
{ |
|
const int lodLoc = glGetUniformLocation(programID, "u_lod"); |
|
if (lodLoc != -1) |
|
glUniform1f(lodLoc, lod); |
|
} |
|
|
|
glActiveTexture(GL_TEXTURE0); |
|
glBindTexture(GL_TEXTURE_CUBE_MAP, m_textures[textureNdx]->getGLTexture()); |
|
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, m_wrapS); |
|
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, m_wrapT); |
|
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, m_minFilter); |
|
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, m_magFilter); |
|
|
|
{ |
|
const int texLoc = glGetUniformLocation(programID, "u_texture"); |
|
if (texLoc != -1) |
|
glUniform1i(texLoc, 0); |
|
} |
|
} |
|
|
|
// Renders one cube face with given parameters. |
|
void VertexCubeTextureCase::renderCell (int textureNdx, float lod, const Grid& grid) const |
|
{ |
|
setupShaderInputs(textureNdx, lod, grid); |
|
glDrawElements(GL_TRIANGLES, grid.getNumIndices(), GL_UNSIGNED_SHORT, grid.getIndexPtr()); |
|
} |
|
|
|
// Computes reference for one cube face with given parameters. |
|
void VertexCubeTextureCase::computeReferenceCell (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const |
|
{ |
|
tcu::Sampler sampler = glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter); |
|
computeReference(m_textures[textureNdx]->getRefTexture(), lod, sampler, grid, dst, dstRegion); |
|
} |
|
|
|
VertexTextureTests::VertexTextureTests (Context& context) |
|
: TestCaseGroup(context, "vertex", "Vertex Texture Tests") |
|
{ |
|
} |
|
|
|
VertexTextureTests::~VertexTextureTests(void) |
|
{ |
|
} |
|
|
|
void VertexTextureTests::init (void) |
|
{ |
|
// 2D and cube map groups, and their filtering and wrap sub-groups. |
|
TestCaseGroup* const group2D = new TestCaseGroup(m_context, "2d", "2D Vertex Texture Tests"); |
|
TestCaseGroup* const groupCube = new TestCaseGroup(m_context, "cube", "Cube Map Vertex Texture Tests"); |
|
TestCaseGroup* const filteringGroup2D = new TestCaseGroup(m_context, "filtering", "2D Vertex Texture Filtering Tests"); |
|
TestCaseGroup* const wrapGroup2D = new TestCaseGroup(m_context, "wrap", "2D Vertex Texture Wrap Tests"); |
|
TestCaseGroup* const filteringGroupCube = new TestCaseGroup(m_context, "filtering", "Cube Map Vertex Texture Filtering Tests"); |
|
TestCaseGroup* const wrapGroupCube = new TestCaseGroup(m_context, "wrap", "Cube Map Vertex Texture Wrap Tests"); |
|
|
|
group2D->addChild(filteringGroup2D); |
|
group2D->addChild(wrapGroup2D); |
|
groupCube->addChild(filteringGroupCube); |
|
groupCube->addChild(wrapGroupCube); |
|
|
|
addChild(group2D); |
|
addChild(groupCube); |
|
|
|
static const struct |
|
{ |
|
const char* name; |
|
GLenum mode; |
|
} wrapModes[] = |
|
{ |
|
{ "clamp", GL_CLAMP_TO_EDGE }, |
|
{ "repeat", GL_REPEAT }, |
|
{ "mirror", GL_MIRRORED_REPEAT } |
|
}; |
|
|
|
static const struct |
|
{ |
|
const char* name; |
|
GLenum mode; |
|
} minFilterModes[] = |
|
{ |
|
{ "nearest", GL_NEAREST }, |
|
{ "linear", GL_LINEAR }, |
|
{ "nearest_mipmap_nearest", GL_NEAREST_MIPMAP_NEAREST }, |
|
{ "linear_mipmap_nearest", GL_LINEAR_MIPMAP_NEAREST }, |
|
{ "nearest_mipmap_linear", GL_NEAREST_MIPMAP_LINEAR }, |
|
{ "linear_mipmap_linear", GL_LINEAR_MIPMAP_LINEAR } |
|
}; |
|
|
|
static const struct |
|
{ |
|
const char* name; |
|
GLenum mode; |
|
} magFilterModes[] = |
|
{ |
|
{ "nearest", GL_NEAREST }, |
|
{ "linear", GL_LINEAR } |
|
}; |
|
|
|
#define FOR_EACH(ITERATOR, ARRAY, BODY) \ |
|
for (int (ITERATOR) = 0; (ITERATOR) < DE_LENGTH_OF_ARRAY(ARRAY); (ITERATOR)++) \ |
|
BODY |
|
|
|
// 2D cases. |
|
|
|
FOR_EACH(minFilter, minFilterModes, |
|
FOR_EACH(magFilter, magFilterModes, |
|
FOR_EACH(wrapMode, wrapModes, |
|
{ |
|
const string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name; |
|
|
|
filteringGroup2D->addChild(new Vertex2DTextureCase(m_context, |
|
name.c_str(), "", |
|
minFilterModes[minFilter].mode, |
|
magFilterModes[magFilter].mode, |
|
wrapModes[wrapMode].mode, |
|
wrapModes[wrapMode].mode)); |
|
}))); |
|
|
|
FOR_EACH(wrapSMode, wrapModes, |
|
FOR_EACH(wrapTMode, wrapModes, |
|
{ |
|
const string name = string("") + wrapModes[wrapSMode].name + "_" + wrapModes[wrapTMode].name; |
|
|
|
wrapGroup2D->addChild(new Vertex2DTextureCase(m_context, |
|
name.c_str(), "", |
|
GL_LINEAR_MIPMAP_LINEAR, |
|
GL_LINEAR, |
|
wrapModes[wrapSMode].mode, |
|
wrapModes[wrapTMode].mode)); |
|
})); |
|
|
|
// Cube map cases. |
|
|
|
FOR_EACH(minFilter, minFilterModes, |
|
FOR_EACH(magFilter, magFilterModes, |
|
FOR_EACH(wrapMode, wrapModes, |
|
{ |
|
const string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name; |
|
|
|
filteringGroupCube->addChild(new VertexCubeTextureCase(m_context, |
|
name.c_str(), "", |
|
minFilterModes[minFilter].mode, |
|
magFilterModes[magFilter].mode, |
|
wrapModes[wrapMode].mode, |
|
wrapModes[wrapMode].mode)); |
|
}))); |
|
|
|
FOR_EACH(wrapSMode, wrapModes, |
|
FOR_EACH(wrapTMode, wrapModes, |
|
{ |
|
const string name = string("") + wrapModes[wrapSMode].name + "_" + wrapModes[wrapTMode].name; |
|
|
|
wrapGroupCube->addChild(new VertexCubeTextureCase(m_context, |
|
name.c_str(), "", |
|
GL_LINEAR_MIPMAP_LINEAR, |
|
GL_LINEAR, |
|
wrapModes[wrapSMode].mode, |
|
wrapModes[wrapTMode].mode)); |
|
})); |
|
} |
|
|
|
} // Functional |
|
} // gles2 |
|
} // deqp
|
|
|