blob: 9650f50306a8cda5d74b36ae510abf2c2b9da6b2 [file] [log] [blame]
/*------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2016 The Khronos Group Inc.
* Copyright (c) 2016 Samsung Electronics Co., Ltd.
* 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 Mipmapping tests.
*//*--------------------------------------------------------------------*/
#include "vktTextureMipmapTests.hpp"
#include "deRandom.hpp"
#include "deString.h"
#include "gluShaderUtil.hpp"
#include "gluTextureTestUtil.hpp"
#include "tcuMatrix.hpp"
#include "tcuMatrixUtil.hpp"
#include "tcuPixelFormat.hpp"
#include "tcuTexLookupVerifier.hpp"
#include "tcuTextureUtil.hpp"
#include "tcuVectorUtil.hpp"
#include "tcuCommandLine.hpp"
#include "vkImageUtil.hpp"
#include "vkQueryUtil.hpp"
#include "vkImageWithMemory.hpp"
#include "vkBufferWithMemory.hpp"
#include "vkObjUtil.hpp"
#include "vkCmdUtil.hpp"
#include "vkBarrierUtil.hpp"
#include "vkBuilderUtil.hpp"
#include "vktTestGroupUtil.hpp"
#include "vktTextureTestUtil.hpp"
#include "vktCustomInstancesDevices.hpp"
#include <memory>
using namespace vk;
namespace vkt
{
namespace texture
{
namespace
{
using std::string;
using std::vector;
using tcu::TestLog;
using tcu::Vec2;
using tcu::Vec3;
using tcu::Vec4;
using tcu::IVec3;
using tcu::IVec4;
using tcu::Sampler;
using tcu::TextureFormat;
using namespace texture::util;
using namespace glu::TextureTestUtil;
float getMinLodForCell (int cellNdx)
{
static const float s_values[] =
{
1.0f,
3.5f,
2.0f,
-2.0f,
0.0f,
3.0f,
10.0f,
4.8f,
5.8f,
5.7f,
-1.9f,
4.0f,
6.5f,
7.1f,
-1e10,
1000.f
};
return s_values[cellNdx % DE_LENGTH_OF_ARRAY(s_values)];
}
float getMaxLodForCell (int cellNdx)
{
static const float s_values[] =
{
0.0f,
0.2f,
0.7f,
0.4f,
1.3f,
0.0f,
0.5f,
1.2f,
-2.0f,
1.0f,
0.1f,
0.3f,
2.7f,
1.2f,
10.0f,
-1000.f,
1e10f
};
return s_values[cellNdx % DE_LENGTH_OF_ARRAY(s_values)];
}
enum CoordType
{
COORDTYPE_BASIC, //!< texCoord = translateScale(position).
COORDTYPE_BASIC_BIAS, //!< Like basic, but with bias values.
COORDTYPE_AFFINE, //!< texCoord = translateScaleRotateShear(position).
COORDTYPE_PROJECTED, //!< Projected coordinates, w != 1
COORDTYPE_LAST
};
struct TextureMipmapCommonTestCaseParameters
{
TextureMipmapCommonTestCaseParameters (void);
CoordType coordType;
const char* minFilterName;
};
TextureMipmapCommonTestCaseParameters::TextureMipmapCommonTestCaseParameters (void)
: coordType (COORDTYPE_BASIC)
, minFilterName (NULL)
{
}
struct Texture2DMipmapTestCaseParameters : public Texture2DTestCaseParameters, public TextureMipmapCommonTestCaseParameters
{
};
struct TextureCubeMipmapTestCaseParameters : public TextureCubeTestCaseParameters, public TextureMipmapCommonTestCaseParameters
{
};
struct Texture3DMipmapTestCaseParameters : public Texture3DTestCaseParameters, public TextureMipmapCommonTestCaseParameters
{
};
// Texture2DMipmapTestInstance
class Texture2DMipmapTestInstance : public TestInstance
{
public:
typedef Texture2DMipmapTestCaseParameters ParameterType;
Texture2DMipmapTestInstance (Context& context, const ParameterType& testParameters);
~Texture2DMipmapTestInstance (void);
virtual tcu::TestStatus iterate (void);
private:
Texture2DMipmapTestInstance (const Texture2DMipmapTestInstance& other);
Texture2DMipmapTestInstance& operator= (const Texture2DMipmapTestInstance& other);
const ParameterType m_testParameters;
TestTexture2DSp m_texture;
TextureRenderer m_renderer;
};
Texture2DMipmapTestInstance::Texture2DMipmapTestInstance (Context& context, const Texture2DMipmapTestCaseParameters& testParameters)
: TestInstance (context)
, m_testParameters (testParameters)
, m_renderer (context, testParameters.sampleCount, testParameters.width*4, testParameters.height*4)
{
TCU_CHECK_INTERNAL(!(m_testParameters.coordType == COORDTYPE_PROJECTED && m_testParameters.sampleCount != VK_SAMPLE_COUNT_1_BIT));
m_texture = TestTexture2DSp(new pipeline::TestTexture2D(vk::mapVkFormat(m_testParameters.format), m_testParameters.width, m_testParameters.height));
const int numLevels = deLog2Floor32(de::max(m_testParameters.width, m_testParameters.height))+1;
// Fill texture with colored grid.
for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
{
const deUint32 step = 0xff / (numLevels-1);
const deUint32 inc = deClamp32(step*levelNdx, 0x00, 0xff);
const deUint32 dec = 0xff - inc;
const deUint32 rgb = (inc << 16) | (dec << 8) | 0xff;
const deUint32 color = 0xff000000 | rgb;
tcu::clear(m_texture->getLevel(levelNdx, 0), tcu::RGBA(color).toVec());
}
// Upload texture data.
m_renderer.add2DTexture(m_texture, testParameters.aspectMask);
}
Texture2DMipmapTestInstance::~Texture2DMipmapTestInstance (void)
{
}
static void getBasicTexCoord2D (std::vector<float>& dst, int cellNdx)
{
static const struct
{
const Vec2 bottomLeft;
const Vec2 topRight;
} s_basicCoords[] =
{
{ Vec2(-0.1f, 0.1f), Vec2( 0.8f, 1.0f) },
{ Vec2(-0.3f, -0.6f), Vec2( 0.7f, 0.4f) },
{ Vec2(-0.3f, 0.6f), Vec2( 0.7f, -0.9f) },
{ Vec2(-0.8f, 0.6f), Vec2( 0.7f, -0.9f) },
{ Vec2(-0.5f, -0.5f), Vec2( 1.5f, 1.5f) },
{ Vec2( 1.0f, -1.0f), Vec2(-1.3f, 1.0f) },
{ Vec2( 1.2f, -1.0f), Vec2(-1.3f, 1.6f) },
{ Vec2( 2.2f, -1.1f), Vec2(-1.3f, 0.8f) },
{ Vec2(-1.5f, 1.6f), Vec2( 1.7f, -1.4f) },
{ Vec2( 2.0f, 1.6f), Vec2( 2.3f, -1.4f) },
{ Vec2( 1.3f, -2.6f), Vec2(-2.7f, 2.9f) },
{ Vec2(-0.8f, -6.6f), Vec2( 6.0f, -0.9f) },
{ Vec2( -8.0f, 9.0f), Vec2( 8.3f, -7.0f) },
{ Vec2(-16.0f, 10.0f), Vec2( 18.3f, 24.0f) },
{ Vec2( 30.2f, 55.0f), Vec2(-24.3f, -1.6f) },
{ Vec2(-33.2f, 64.1f), Vec2( 32.1f, -64.1f) },
};
DE_ASSERT(de::inBounds(cellNdx, 0, DE_LENGTH_OF_ARRAY(s_basicCoords)));
const Vec2& bottomLeft = s_basicCoords[cellNdx].bottomLeft;
const Vec2& topRight = s_basicCoords[cellNdx].topRight;
computeQuadTexCoord2D(dst, bottomLeft, topRight);
}
static void getBasicTexCoord2DImageViewMinLodIntTexCoord (std::vector<float>& dst)
{
computeQuadTexCoord2D(dst, Vec2(0.0f), Vec2(1.0f));
}
static void getAffineTexCoord2D (std::vector<float>& dst, int cellNdx)
{
// Use basic coords as base.
getBasicTexCoord2D(dst, cellNdx);
// Rotate based on cell index.
const float angle = 2.0f*DE_PI * ((float)cellNdx / 16.0f);
const tcu::Mat2 rotMatrix = tcu::rotationMatrix(angle);
// Second and third row are sheared.
const float shearX = de::inRange(cellNdx, 4, 11) ? (float)(15-cellNdx) / 16.0f : 0.0f;
const tcu::Mat2 shearMatrix = tcu::shearMatrix(tcu::Vec2(shearX, 0.0f));
const tcu::Mat2 transform = rotMatrix * shearMatrix;
const Vec2 p0 = transform * Vec2(dst[0], dst[1]);
const Vec2 p1 = transform * Vec2(dst[2], dst[3]);
const Vec2 p2 = transform * Vec2(dst[4], dst[5]);
const Vec2 p3 = transform * Vec2(dst[6], dst[7]);
dst[0] = p0.x(); dst[1] = p0.y();
dst[2] = p1.x(); dst[3] = p1.y();
dst[4] = p2.x(); dst[5] = p2.y();
dst[6] = p3.x(); dst[7] = p3.y();
}
tcu::TestStatus Texture2DMipmapTestInstance::iterate (void)
{
const Sampler::FilterMode magFilter = Sampler::NEAREST;
const int viewportWidth = m_renderer.getRenderWidth();
const int viewportHeight = m_renderer.getRenderHeight();
ReferenceParams refParams (TEXTURETYPE_2D);
vector<float> texCoord;
const bool isProjected = m_testParameters.coordType == COORDTYPE_PROJECTED;
const bool useLodBias = m_testParameters.coordType == COORDTYPE_BASIC_BIAS;
tcu::Surface renderedFrame (viewportWidth, viewportHeight);
// Viewport is divided into 4x4 grid.
const int gridWidth = 4;
const int gridHeight = 4;
const int cellWidth = viewportWidth / gridWidth;
const int cellHeight = viewportHeight / gridHeight;
// Sampling parameters.
refParams.sampler = util::createSampler(m_testParameters.wrapS, m_testParameters.wrapT, m_testParameters.minFilter, magFilter);
refParams.samplerType = getSamplerType(vk::mapVkFormat(m_testParameters.format));
refParams.flags = (isProjected ? ReferenceParams::PROJECTED : 0) | (useLodBias ? ReferenceParams::USE_BIAS : 0);
refParams.lodMode = LODMODE_EXACT; // Use ideal lod.
// Bias values.
static const float s_bias[] = { 1.0f, -2.0f, 0.8f, -0.5f, 1.5f, 0.9f, 2.0f, 4.0f };
// Projection values.
static const Vec4 s_projections[] =
{
Vec4(1.2f, 1.0f, 0.7f, 1.0f),
Vec4(1.3f, 0.8f, 0.6f, 2.0f),
Vec4(0.8f, 1.0f, 1.7f, 0.6f),
Vec4(1.2f, 1.0f, 1.7f, 1.5f)
};
// Render cells.
for (int gridY = 0; gridY < gridHeight; gridY++)
{
for (int gridX = 0; gridX < gridWidth; gridX++)
{
const int curX = cellWidth*gridX;
const int curY = cellHeight*gridY;
const int curW = gridX+1 == gridWidth ? (viewportWidth-curX) : cellWidth;
const int curH = gridY+1 == gridHeight ? (viewportHeight-curY) : cellHeight;
const int cellNdx = gridY*gridWidth + gridX;
// Compute texcoord.
switch (m_testParameters.coordType)
{
case COORDTYPE_BASIC_BIAS: // Fall-through.
case COORDTYPE_PROJECTED:
case COORDTYPE_BASIC: getBasicTexCoord2D (texCoord, cellNdx); break;
case COORDTYPE_AFFINE: getAffineTexCoord2D (texCoord, cellNdx); break;
default: DE_ASSERT(DE_FALSE);
}
if (isProjected)
refParams.w = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
if (useLodBias)
refParams.bias = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
m_renderer.setViewport((float)curX, (float)curY, (float)curW, (float)curH);
m_renderer.renderQuad(renderedFrame, 0, &texCoord[0], refParams);
}
}
// Compare and log.
{
const tcu::IVec4 formatBitDepth = getTextureFormatBitDepth(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
const tcu::PixelFormat pixelFormat (formatBitDepth[0], formatBitDepth[1], formatBitDepth[2], formatBitDepth[3]);
const bool isTrilinear = m_testParameters.minFilter == Sampler::NEAREST_MIPMAP_LINEAR || m_testParameters.minFilter == Sampler::LINEAR_MIPMAP_LINEAR;
tcu::Surface referenceFrame (viewportWidth, viewportHeight);
tcu::Surface errorMask (viewportWidth, viewportHeight);
tcu::LookupPrecision lookupPrec;
tcu::LodPrecision lodPrec;
int numFailedPixels = 0;
lookupPrec.coordBits = tcu::IVec3(20, 20, 0);
lookupPrec.uvwBits = tcu::IVec3(16, 16, 0); // Doesn't really matter since pixels are unicolored.
lookupPrec.colorThreshold = tcu::computeFixedPointThreshold(max(getBitsVec(pixelFormat) - (isTrilinear ? 2 : 1), tcu::IVec4(0)));
lookupPrec.colorMask = getCompareMask(pixelFormat);
lodPrec.derivateBits = 10;
lodPrec.lodBits = isProjected ? 6 : 8;
for (int gridY = 0; gridY < gridHeight; gridY++)
{
for (int gridX = 0; gridX < gridWidth; gridX++)
{
const int curX = cellWidth*gridX;
const int curY = cellHeight*gridY;
const int curW = gridX+1 == gridWidth ? (viewportWidth-curX) : cellWidth;
const int curH = gridY+1 == gridHeight ? (viewportHeight-curY) : cellHeight;
const int cellNdx = gridY*gridWidth + gridX;
// Compute texcoord.
switch (m_testParameters.coordType)
{
case COORDTYPE_BASIC_BIAS: // Fall-through.
case COORDTYPE_PROJECTED:
case COORDTYPE_BASIC: getBasicTexCoord2D (texCoord, cellNdx); break;
case COORDTYPE_AFFINE: getAffineTexCoord2D (texCoord, cellNdx); break;
default: DE_ASSERT(DE_FALSE);
}
if (isProjected)
refParams.w = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
if (useLodBias)
refParams.bias = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
// Render ideal result
sampleTexture(tcu::SurfaceAccess(referenceFrame, pixelFormat, curX, curY, curW, curH),
m_texture->getTexture(), &texCoord[0], refParams);
// Compare this cell
numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
m_texture->getTexture(), &texCoord[0], refParams,
lookupPrec, lodPrec, m_context.getTestContext().getWatchDog());
}
}
if (numFailedPixels > 0)
m_context.getTestContext().getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
m_context.getTestContext().getLog() << TestLog::ImageSet("Result", "Verification result")
<< TestLog::Image("Rendered", "Rendered image", renderedFrame);
if (numFailedPixels > 0)
{
m_context.getTestContext().getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
<< TestLog::Image("ErrorMask", "Error mask", errorMask);
}
m_context.getTestContext().getLog() << TestLog::EndImageSet;
{
const bool isOk = numFailedPixels == 0;
return isOk ? tcu::TestStatus::pass("pass") : tcu::TestStatus::fail("fail");
}
}
}
// TextureCubeMipmapTestInstance
class TextureCubeMipmapTestInstance : public TestInstance
{
public:
typedef TextureCubeMipmapTestCaseParameters ParameterType;
TextureCubeMipmapTestInstance (Context& context, const ParameterType& testParameters);
~TextureCubeMipmapTestInstance (void);
virtual tcu::TestStatus iterate (void);
private:
TextureCubeMipmapTestInstance (const TextureCubeMipmapTestInstance& other);
TextureCubeMipmapTestInstance& operator= (const TextureCubeMipmapTestInstance& other);
const ParameterType m_testParameters;
TestTextureCubeSp m_texture;
TextureRenderer m_renderer;
};
TextureCubeMipmapTestInstance::TextureCubeMipmapTestInstance (Context& context, const TextureCubeMipmapTestCaseParameters& testParameters)
: TestInstance (context)
, m_testParameters (testParameters)
, m_renderer (context, m_testParameters.sampleCount, m_testParameters.size*2, m_testParameters.size*2)
{
TCU_CHECK_INTERNAL(!(m_testParameters.coordType == COORDTYPE_PROJECTED && m_testParameters.sampleCount != VK_SAMPLE_COUNT_1_BIT));
m_texture = TestTextureCubeSp(new pipeline::TestTextureCube(vk::mapVkFormat(m_testParameters.format), m_testParameters.size));
const int numLevels = deLog2Floor32(m_testParameters.size)+1;
// Fill texture with colored grid.
for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
{
for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
{
const deUint32 step = 0xff / (numLevels-1);
const deUint32 inc = deClamp32(step*levelNdx, 0x00, 0xff);
const deUint32 dec = 0xff - inc;
deUint32 rgb = 0;
switch (faceNdx)
{
case 0: rgb = (inc << 16) | (dec << 8) | 255; break;
case 1: rgb = (255 << 16) | (inc << 8) | dec; break;
case 2: rgb = (dec << 16) | (255 << 8) | inc; break;
case 3: rgb = (dec << 16) | (inc << 8) | 255; break;
case 4: rgb = (255 << 16) | (dec << 8) | inc; break;
case 5: rgb = (inc << 16) | (255 << 8) | dec; break;
}
const deUint32 color = 0xff000000 | rgb;
tcu::clear(m_texture->getLevel(levelNdx, (tcu::CubeFace)faceNdx), tcu::RGBA(color).toVec());
}
}
m_renderer.addCubeTexture(m_texture, testParameters.aspectMask);
}
TextureCubeMipmapTestInstance::~TextureCubeMipmapTestInstance (void)
{
}
static void randomPartition (vector<IVec4>& dst, de::Random& rnd, int x, int y, int width, int height)
{
const int minWidth = 8;
const int minHeight = 8;
const bool partition = rnd.getFloat() > 0.4f;
const bool partitionX = partition && width > minWidth && rnd.getBool();
const bool partitionY = partition && height > minHeight && !partitionX;
if (partitionX)
{
const int split = width/2 + rnd.getInt(-width/4, +width/4);
randomPartition(dst, rnd, x, y, split, height);
randomPartition(dst, rnd, x+split, y, width-split, height);
}
else if (partitionY)
{
const int split = height/2 + rnd.getInt(-height/4, +height/4);
randomPartition(dst, rnd, x, y, width, split);
randomPartition(dst, rnd, x, y+split, width, height-split);
}
else
dst.push_back(IVec4(x, y, width, height));
}
static void computeGridLayout (vector<IVec4>& dst, int width, int height)
{
de::Random rnd(7);
randomPartition(dst, rnd, 0, 0, width, height);
}
tcu::TestStatus TextureCubeMipmapTestInstance::iterate (void)
{
const int viewportWidth = m_renderer.getRenderWidth();
const int viewportHeight = m_renderer.getRenderHeight();
const bool isProjected = m_testParameters.coordType == COORDTYPE_PROJECTED;
const bool useLodBias = m_testParameters.coordType == COORDTYPE_BASIC_BIAS;
ReferenceParams refParams (TEXTURETYPE_CUBE);
vector<float> texCoord;
tcu::Surface renderedFrame (viewportWidth, viewportHeight);
refParams.sampler = util::createSampler(m_testParameters.wrapS, m_testParameters.wrapT, m_testParameters.minFilter, m_testParameters.magFilter);
refParams.samplerType = getSamplerType(vk::mapVkFormat(m_testParameters.format));
refParams.flags = (isProjected ? ReferenceParams::PROJECTED : 0) | (useLodBias ? ReferenceParams::USE_BIAS : 0);
refParams.lodMode = LODMODE_EXACT; // Use ideal lod.
// Compute grid.
vector<IVec4> gridLayout;
computeGridLayout(gridLayout, viewportWidth, viewportHeight);
// Bias values.
static const float s_bias[] = { 1.0f, -2.0f, 0.8f, -0.5f, 1.5f, 0.9f, 2.0f, 4.0f };
// Projection values \note Less agressive than in 2D case due to smaller quads.
static const Vec4 s_projections[] =
{
Vec4(1.2f, 1.0f, 0.7f, 1.0f),
Vec4(1.3f, 0.8f, 0.6f, 1.1f),
Vec4(0.8f, 1.0f, 1.2f, 0.8f),
Vec4(1.2f, 1.0f, 1.3f, 0.9f)
};
// Render with GL
for (int cellNdx = 0; cellNdx < (int)gridLayout.size(); cellNdx++)
{
const float curX = (float)gridLayout[cellNdx].x();
const float curY = (float)gridLayout[cellNdx].y();
const float curW = (float)gridLayout[cellNdx].z();
const float curH = (float)gridLayout[cellNdx].w();
const tcu::CubeFace cubeFace = (tcu::CubeFace)(cellNdx % tcu::CUBEFACE_LAST);
DE_ASSERT(m_testParameters.coordType != COORDTYPE_AFFINE); // Not supported.
computeQuadTexCoordCube(texCoord, cubeFace);
if (isProjected)
{
refParams.flags |= ReferenceParams::PROJECTED;
refParams.w = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
}
if (useLodBias)
{
refParams.flags |= ReferenceParams::USE_BIAS;
refParams.bias = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
}
// Render
m_renderer.setViewport(curX, curY, curW, curH);
m_renderer.renderQuad(renderedFrame, 0, &texCoord[0], refParams);
}
// Render reference and compare
{
const tcu::IVec4 formatBitDepth = getTextureFormatBitDepth(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
const tcu::PixelFormat pixelFormat (formatBitDepth[0], formatBitDepth[1], formatBitDepth[2], formatBitDepth[3]);
tcu::Surface referenceFrame (viewportWidth, viewportHeight);
tcu::Surface errorMask (viewportWidth, viewportHeight);
int numFailedPixels = 0;
tcu::LookupPrecision lookupPrec;
tcu::LodPrecision lodPrec;
// Params for rendering reference
refParams.sampler = util::createSampler(m_testParameters.wrapS, m_testParameters.wrapT, m_testParameters.minFilter, m_testParameters.magFilter);
refParams.sampler.seamlessCubeMap = true;
refParams.lodMode = LODMODE_EXACT;
// Comparison parameters
lookupPrec.colorMask = getCompareMask(pixelFormat);
lookupPrec.colorThreshold = tcu::computeFixedPointThreshold(max(getBitsVec(pixelFormat)-2, tcu::IVec4(0)));
lookupPrec.coordBits = isProjected ? tcu::IVec3(8) : tcu::IVec3(10);
lookupPrec.uvwBits = tcu::IVec3(5,5,0);
lodPrec.derivateBits = 10;
lodPrec.lodBits = isProjected ? 3 : 6;
for (int cellNdx = 0; cellNdx < (int)gridLayout.size(); cellNdx++)
{
const int curX = gridLayout[cellNdx].x();
const int curY = gridLayout[cellNdx].y();
const int curW = gridLayout[cellNdx].z();
const int curH = gridLayout[cellNdx].w();
const tcu::CubeFace cubeFace = (tcu::CubeFace)(cellNdx % tcu::CUBEFACE_LAST);
DE_ASSERT(m_testParameters.coordType != COORDTYPE_AFFINE); // Not supported.
computeQuadTexCoordCube(texCoord, cubeFace);
if (isProjected)
{
refParams.flags |= ReferenceParams::PROJECTED;
refParams.w = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
}
if (useLodBias)
{
refParams.flags |= ReferenceParams::USE_BIAS;
refParams.bias = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
}
// Render ideal reference.
{
tcu::SurfaceAccess idealDst(referenceFrame, pixelFormat, curX, curY, curW, curH);
sampleTexture(idealDst, m_texture->getTexture(), &texCoord[0], refParams);
}
// Compare this cell
numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
m_texture->getTexture(), &texCoord[0], refParams,
lookupPrec, lodPrec, m_context.getTestContext().getWatchDog());
}
if (numFailedPixels > 0)
{
m_context.getTestContext().getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
}
m_context.getTestContext().getLog() << TestLog::ImageSet("Result", "Verification result")
<< TestLog::Image("Rendered", "Rendered image", renderedFrame);
if (numFailedPixels > 0)
{
m_context.getTestContext().getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
<< TestLog::Image("ErrorMask", "Error mask", errorMask);
}
m_context.getTestContext().getLog() << TestLog::EndImageSet;
{
const bool isOk = numFailedPixels == 0;
return isOk ? tcu::TestStatus::pass("pass") : tcu::TestStatus::fail("fail");
}
}
}
// Texture3DMipmapTestInstance
class Texture3DMipmapTestInstance : public TestInstance
{
public:
typedef Texture3DMipmapTestCaseParameters ParameterType;
Texture3DMipmapTestInstance (Context& context, const ParameterType& testParameters);
~Texture3DMipmapTestInstance (void);
virtual tcu::TestStatus iterate (void);
private:
Texture3DMipmapTestInstance (const Texture3DMipmapTestInstance& other);
Texture3DMipmapTestInstance& operator= (const Texture3DMipmapTestInstance& other);
const ParameterType m_testParameters;
TestTexture3DSp m_texture;
TextureRenderer m_renderer;
};
Texture3DMipmapTestInstance::Texture3DMipmapTestInstance (Context& context, const Texture3DMipmapTestCaseParameters& testParameters)
: TestInstance (context)
, m_testParameters (testParameters)
, m_renderer (context, testParameters.sampleCount, testParameters.width*4, testParameters.height*4)
{
TCU_CHECK_INTERNAL(!(m_testParameters.coordType == COORDTYPE_PROJECTED && m_testParameters.sampleCount != VK_SAMPLE_COUNT_1_BIT));
const tcu::TextureFormat& texFmt = mapVkFormat(testParameters.format);
tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt);
const tcu::Vec4& cScale = fmtInfo.lookupScale;
const tcu::Vec4& cBias = fmtInfo.lookupBias;
const int numLevels = deLog2Floor32(de::max(de::max(testParameters.width, testParameters.height), testParameters.depth))+1;
m_texture = TestTexture3DSp(new pipeline::TestTexture3D(vk::mapVkFormat(m_testParameters.format), m_testParameters.width, m_testParameters.height, m_testParameters.depth));
// Fill texture with colored grid.
for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
{
const deUint32 step = 0xff / (numLevels-1);
const deUint32 inc = deClamp32(step*levelNdx, 0x00, 0xff);
const deUint32 dec = 0xff - inc;
const deUint32 rgb = (0xff << 16) | (dec << 8) | inc;
const deUint32 color = 0xff000000 | rgb;
tcu::clear(m_texture->getLevel(levelNdx, 0), tcu::RGBA(color).toVec()*cScale + cBias);
}
m_renderer.add3DTexture(m_texture, testParameters.aspectMask);
}
Texture3DMipmapTestInstance::~Texture3DMipmapTestInstance (void)
{
}
static void getBasicTexCoord3D (std::vector<float>& dst, int cellNdx)
{
static const struct
{
const float sScale;
const float sBias;
const float tScale;
const float tBias;
const float rScale;
const float rBias;
} s_params[] =
{
// sScale sBias tScale tBias rScale rBias
{ 0.9f, -0.1f, 0.7f, 0.3f, 0.8f, 0.9f },
{ 1.2f, -0.1f, 1.1f, 0.3f, 1.0f, 0.9f },
{ 1.5f, 0.7f, 0.9f, -0.3f, 1.1f, 0.1f },
{ 1.2f, 0.7f, -2.3f, -0.3f, 1.1f, 0.2f },
{ 1.1f, 0.8f, -1.3f, -0.3f, 2.9f, 0.9f },
{ 3.4f, 0.8f, 4.0f, 0.0f, -3.3f, -1.0f },
{ -3.4f, -0.1f, -4.0f, 0.0f, -5.1f, 1.0f },
{ -4.0f, -0.1f, 3.4f, 0.1f, 5.7f, 0.0f },
{ -5.6f, 0.0f, 0.5f, 1.2f, 3.9f, 4.0f },
{ 5.0f, -2.0f, 3.1f, 1.2f, 5.1f, 0.2f },
{ 2.5f, -2.0f, 6.3f, 3.0f, 5.1f, 0.2f },
{ -8.3f, 0.0f, 7.1f, 3.0f, 2.0f, 0.2f },
{ 3.8f, 0.0f, 9.7f, 1.0f, 7.0f, 0.7f },
{ 13.3f, 0.0f, 7.1f, 3.0f, 2.0f, 0.2f },
{ 16.0f, 8.0f, 12.7f, 1.0f, 17.1f, 0.7f },
{ 15.3f, 0.0f, 20.1f, 3.0f, 33.0f, 3.2f }
};
const float sScale = s_params[cellNdx%DE_LENGTH_OF_ARRAY(s_params)].sScale;
const float sBias = s_params[cellNdx%DE_LENGTH_OF_ARRAY(s_params)].sBias;
const float tScale = s_params[cellNdx%DE_LENGTH_OF_ARRAY(s_params)].tScale;
const float tBias = s_params[cellNdx%DE_LENGTH_OF_ARRAY(s_params)].tBias;
const float rScale = s_params[cellNdx%DE_LENGTH_OF_ARRAY(s_params)].rScale;
const float rBias = s_params[cellNdx%DE_LENGTH_OF_ARRAY(s_params)].rBias;
dst.resize(3*4);
dst[0] = sBias; dst[ 1] = tBias; dst[ 2] = rBias;
dst[3] = sBias; dst[ 4] = tBias+tScale; dst[ 5] = rBias+rScale*0.5f;
dst[6] = sBias+sScale; dst[ 7] = tBias; dst[ 8] = rBias+rScale*0.5f;
dst[9] = sBias+sScale; dst[10] = tBias+tScale; dst[11] = rBias+rScale;
}
static void getBasicTexCoord3DImageViewMinlodIntTexCoord (std::vector<float>& dst)
{
const float sScale = 1.0f;
const float sBias = 0.0f;
const float tScale = 1.0f;
const float tBias = 0.0f;
const float rScale = 1.0f;
const float rBias = 0.0f;
dst.resize(3*4);
dst[0] = sBias; dst[ 1] = tBias; dst[ 2] = rBias;
dst[3] = sBias; dst[ 4] = tBias+tScale; dst[ 5] = rBias+rScale*0.5f;
dst[6] = sBias+sScale; dst[ 7] = tBias; dst[ 8] = rBias+rScale*0.5f;
dst[9] = sBias+sScale; dst[10] = tBias+tScale; dst[11] = rBias+rScale;
}
static void getAffineTexCoord3D (std::vector<float>& dst, int cellNdx)
{
// Use basic coords as base.
getBasicTexCoord3D(dst, cellNdx);
// Rotate based on cell index.
const float angleX = 0.0f + 2.0f*DE_PI * ((float)cellNdx / 16.0f);
const float angleY = 1.0f + 2.0f*DE_PI * ((float)cellNdx / 32.0f);
const tcu::Mat3 rotMatrix = tcu::rotationMatrixX(angleX) * tcu::rotationMatrixY(angleY);
const Vec3 p0 = rotMatrix * Vec3(dst[0], dst[ 1], dst[ 2]);
const Vec3 p1 = rotMatrix * Vec3(dst[3], dst[ 4], dst[ 5]);
const Vec3 p2 = rotMatrix * Vec3(dst[6], dst[ 7], dst[ 8]);
const Vec3 p3 = rotMatrix * Vec3(dst[9], dst[10], dst[11]);
dst[0] = p0.x(); dst[ 1] = p0.y(); dst[ 2] = p0.z();
dst[3] = p1.x(); dst[ 4] = p1.y(); dst[ 5] = p1.z();
dst[6] = p2.x(); dst[ 7] = p2.y(); dst[ 8] = p2.z();
dst[9] = p3.x(); dst[10] = p3.y(); dst[11] = p3.z();
}
tcu::TestStatus Texture3DMipmapTestInstance::iterate (void)
{
const tcu::TextureFormat& texFmt = m_texture->getTextureFormat();
const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt);
const Sampler::FilterMode magFilter = Sampler::NEAREST;
const int viewportWidth = m_renderer.getRenderWidth();
const int viewportHeight = m_renderer.getRenderHeight();
const bool isProjected = m_testParameters.coordType == COORDTYPE_PROJECTED;
const bool useLodBias = m_testParameters.coordType == COORDTYPE_BASIC_BIAS;
// Viewport is divided into 4x4 grid.
const int gridWidth = 4;
const int gridHeight = 4;
const int cellWidth = viewportWidth / gridWidth;
const int cellHeight = viewportHeight / gridHeight;
ReferenceParams refParams (TEXTURETYPE_3D);
tcu::Surface renderedFrame (viewportWidth, viewportHeight);
vector<float> texCoord;
// Sampling parameters.
refParams.sampler = util::createSampler(m_testParameters.wrapS, m_testParameters.wrapT, m_testParameters.minFilter, magFilter);
refParams.samplerType = getSamplerType(texFmt);
refParams.colorBias = fmtInfo.lookupBias;
refParams.colorScale = fmtInfo.lookupScale;
refParams.flags = (isProjected ? ReferenceParams::PROJECTED : 0) | (useLodBias ? ReferenceParams::USE_BIAS : 0);
// Bias values.
static const float s_bias[] = { 1.0f, -2.0f, 0.8f, -0.5f, 1.5f, 0.9f, 2.0f, 4.0f };
// Projection values.
static const Vec4 s_projections[] =
{
Vec4(1.2f, 1.0f, 0.7f, 1.0f),
Vec4(1.3f, 0.8f, 0.6f, 2.0f),
Vec4(0.8f, 1.0f, 1.7f, 0.6f),
Vec4(1.2f, 1.0f, 1.7f, 1.5f)
};
// Render cells.
for (int gridY = 0; gridY < gridHeight; gridY++)
{
for (int gridX = 0; gridX < gridWidth; gridX++)
{
const int curX = cellWidth*gridX;
const int curY = cellHeight*gridY;
const int curW = gridX+1 == gridWidth ? (viewportWidth-curX) : cellWidth;
const int curH = gridY+1 == gridHeight ? (viewportHeight-curY) : cellHeight;
const int cellNdx = gridY*gridWidth + gridX;
// Compute texcoord.
switch (m_testParameters.coordType)
{
case COORDTYPE_BASIC_BIAS: // Fall-through.
case COORDTYPE_PROJECTED:
case COORDTYPE_BASIC: getBasicTexCoord3D (texCoord, cellNdx); break;
case COORDTYPE_AFFINE: getAffineTexCoord3D (texCoord, cellNdx); break;
default: DE_ASSERT(DE_FALSE);
}
// Set projection.
if (isProjected)
refParams.w = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
// Set LOD bias.
if (useLodBias)
refParams.bias = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
m_renderer.setViewport((float)curX, (float)curY, (float)curW, (float)curH);
m_renderer.renderQuad(renderedFrame, 0, &texCoord[0], refParams);
}
}
// Compare and log
{
const tcu::IVec4 formatBitDepth = getTextureFormatBitDepth(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
const tcu::PixelFormat pixelFormat (formatBitDepth[0], formatBitDepth[1], formatBitDepth[2], formatBitDepth[3]);
const bool isTrilinear = m_testParameters.minFilter == Sampler::NEAREST_MIPMAP_LINEAR || m_testParameters.minFilter == Sampler::LINEAR_MIPMAP_LINEAR;
tcu::Surface referenceFrame (viewportWidth, viewportHeight);
tcu::Surface errorMask (viewportWidth, viewportHeight);
tcu::LookupPrecision lookupPrec;
tcu::LodPrecision lodPrec;
int numFailedPixels = 0;
lookupPrec.coordBits = tcu::IVec3(20, 20, 20);
lookupPrec.uvwBits = tcu::IVec3(16, 16, 16); // Doesn't really matter since pixels are unicolored.
lookupPrec.colorThreshold = tcu::computeFixedPointThreshold(max(getBitsVec(pixelFormat) - (isTrilinear ? 2 : 1), tcu::IVec4(0)));
lookupPrec.colorMask = getCompareMask(pixelFormat);
lodPrec.derivateBits = 10;
lodPrec.lodBits = isProjected ? 6 : 8;
for (int gridY = 0; gridY < gridHeight; gridY++)
{
for (int gridX = 0; gridX < gridWidth; gridX++)
{
const int curX = cellWidth*gridX;
const int curY = cellHeight*gridY;
const int curW = gridX+1 == gridWidth ? (viewportWidth-curX) : cellWidth;
const int curH = gridY+1 == gridHeight ? (viewportHeight-curY) : cellHeight;
const int cellNdx = gridY*gridWidth + gridX;
switch (m_testParameters.coordType)
{
case COORDTYPE_BASIC_BIAS: // Fall-through.
case COORDTYPE_PROJECTED:
case COORDTYPE_BASIC: getBasicTexCoord3D (texCoord, cellNdx); break;
case COORDTYPE_AFFINE: getAffineTexCoord3D (texCoord, cellNdx); break;
default: DE_ASSERT(DE_FALSE);
}
if (isProjected)
refParams.w = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
if (useLodBias)
refParams.bias = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
// Render ideal result
sampleTexture(tcu::SurfaceAccess(referenceFrame, pixelFormat, curX, curY, curW, curH),
m_texture->getTexture(), &texCoord[0], refParams);
// Compare this cell
numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
m_texture->getTexture(), &texCoord[0], refParams,
lookupPrec, lodPrec, m_context.getTestContext().getWatchDog());
}
}
if (numFailedPixels > 0)
m_context.getTestContext().getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
m_context.getTestContext().getLog() << TestLog::ImageSet("Result", "Verification result")
<< TestLog::Image("Rendered", "Rendered image", renderedFrame);
if (numFailedPixels > 0)
{
m_context.getTestContext().getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
<< TestLog::Image("ErrorMask", "Error mask", errorMask);
}
m_context.getTestContext().getLog() << TestLog::EndImageSet;
{
const bool isOk = numFailedPixels == 0;
return isOk ? tcu::TestStatus::pass("pass") : tcu::TestStatus::fail("fail");
}
}
}
// Texture2DLodControlTestInstance
class Texture2DLodControlTestInstance : public TestInstance
{
public:
typedef Texture2DMipmapTestCaseParameters ParameterType;
Texture2DLodControlTestInstance (Context& context, const ParameterType& testParameters);
~Texture2DLodControlTestInstance (void);
virtual tcu::TestStatus iterate (void);
protected:
virtual void getReferenceParams (ReferenceParams& params, int cellNdx) = 0;
const int m_texWidth;
const int m_texHeight;
private:
Texture2DLodControlTestInstance (const Texture2DLodControlTestInstance& other);
Texture2DLodControlTestInstance& operator= (const Texture2DLodControlTestInstance& other);
const ParameterType m_testParameters;
tcu::Sampler::FilterMode m_minFilter;
TestTexture2DSp m_texture;
TextureRenderer m_renderer;
};
Texture2DLodControlTestInstance::Texture2DLodControlTestInstance (Context& context, const Texture2DMipmapTestCaseParameters& testParameters)
: TestInstance (context)
, m_texWidth (64) //64
, m_texHeight (64)//64
, m_testParameters (testParameters)
, m_minFilter (testParameters.minFilter)
, m_texture (DE_NULL)
, m_renderer (context, testParameters.sampleCount, m_texWidth*4, m_texHeight*4, vk::makeComponentMappingRGBA(), testParameters.testType > util::TextureCommonTestCaseParameters::TEST_IMAGE_VIEW_MINLOD)
{
const VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
const int numLevels = deLog2Floor32(de::max(m_texWidth, m_texHeight))+1;
m_texture = TestTexture2DSp(new pipeline::TestTexture2D(vk::mapVkFormat(format), m_texWidth, m_texHeight));
// Fill texture with colored grid.
for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
{
const deUint32 step = 0xff / (numLevels-1);
const deUint32 inc = deClamp32(step*levelNdx, 0x00, 0xff);
const deUint32 dec = 0xff - inc;
const deUint32 rgb = (inc << 16) | (dec << 8) | 0xff;
const deUint32 color = 0xff000000 | rgb;
tcu::clear(m_texture->getLevel(levelNdx, 0), tcu::RGBA(color).toVec());
}
m_renderer.add2DTexture(m_texture, testParameters.aspectMask);
}
Texture2DLodControlTestInstance::~Texture2DLodControlTestInstance (void)
{
}
tcu::TestStatus Texture2DLodControlTestInstance::iterate (void)
{
const tcu::Sampler::WrapMode wrapS = Sampler::REPEAT_GL;
const tcu::Sampler::WrapMode wrapT = Sampler::REPEAT_GL;
const tcu::Sampler::FilterMode magFilter = Sampler::NEAREST;
const tcu::Texture2D& refTexture = m_texture->getTexture();
const int viewportWidth = m_renderer.getRenderWidth();
const int viewportHeight = m_renderer.getRenderHeight();
tcu::Sampler sampler = util::createSampler(wrapS, wrapT, m_minFilter, magFilter);
ReferenceParams refParams (TEXTURETYPE_2D, sampler);
vector<float> texCoord;
tcu::Surface renderedFrame (viewportWidth, viewportHeight);
// Viewport is divided into 4x4 grid.
const int gridWidth = 4;
const int gridHeight = 4;
const int cellWidth = viewportWidth / gridWidth;
const int cellHeight = viewportHeight / gridHeight;
refParams.maxLevel = deLog2Floor32(de::max(m_texWidth, m_texHeight));
// Render cells.
for (int gridY = 0; gridY < gridHeight; gridY++)
{
for (int gridX = 0; gridX < gridWidth; gridX++)
{
const int curX = cellWidth*gridX;
const int curY = cellHeight*gridY;
const int curW = gridX+1 == gridWidth ? (viewportWidth-curX) : cellWidth;
const int curH = gridY+1 == gridHeight ? (viewportHeight-curY) : cellHeight;
const int cellNdx = gridY*gridWidth + gridX;
getReferenceParams(refParams,cellNdx);
// Compute texcoord.
getBasicTexCoord2D(texCoord, cellNdx);
// Render
m_renderer.setViewport((float)curX, (float)curY, (float)curW, (float)curH);
m_renderer.getTextureBinding(0)->updateTextureViewMipLevels(refParams.baseLevel, refParams.maxLevel, refParams.imageViewMinLod);
m_renderer.renderQuad(renderedFrame, 0, &texCoord[0], refParams);
}
}
// Compare and log.
{
const tcu::IVec4 formatBitDepth = getTextureFormatBitDepth(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
const tcu::PixelFormat pixelFormat (formatBitDepth[0], formatBitDepth[1], formatBitDepth[2], formatBitDepth[3]);
const bool isTrilinear = m_minFilter == Sampler::NEAREST_MIPMAP_LINEAR || m_minFilter == Sampler::LINEAR_MIPMAP_LINEAR;
tcu::LookupPrecision lookupPrec;
tcu::LodPrecision lodPrec;
lookupPrec.coordBits = tcu::IVec3(20, 20, 0);
lookupPrec.uvwBits = tcu::IVec3(16, 16, 0); // Doesn't really matter since pixels are unicolored.
lookupPrec.colorThreshold = tcu::computeFixedPointThreshold(max(getBitsVec(pixelFormat) - (isTrilinear ? 2 : 1), tcu::IVec4(0)));
lookupPrec.colorMask = getCompareMask(pixelFormat);
lodPrec.derivateBits = 10;
lodPrec.lodBits = 8;
auto compareAndLogImages = [&] (tcu::ImageViewMinLodMode imageViewLodMode = tcu::IMAGEVIEWMINLODMODE_PREFERRED)
{
tcu::Surface referenceFrame (viewportWidth, viewportHeight);
tcu::Surface errorMask (viewportWidth, viewportHeight);
int numFailedPixels = 0;
for (int gridY = 0; gridY < gridHeight; gridY++)
{
for (int gridX = 0; gridX < gridWidth; gridX++)
{
const int curX = cellWidth*gridX;
const int curY = cellHeight*gridY;
const int curW = gridX+1 == gridWidth ? (viewportWidth-curX) : cellWidth;
const int curH = gridY+1 == gridHeight ? (viewportHeight-curY) : cellHeight;
const int cellNdx = gridY*gridWidth + gridX;
getReferenceParams(refParams,cellNdx);
refParams.imageViewMinLodMode = imageViewLodMode;
// Compute texcoord.
if (refParams.samplerType == glu::TextureTestUtil::SAMPLERTYPE_FETCH_FLOAT)
getBasicTexCoord2DImageViewMinLodIntTexCoord(texCoord);
else
getBasicTexCoord2D(texCoord, cellNdx);
// Render ideal result
sampleTexture(tcu::SurfaceAccess(referenceFrame, pixelFormat, curX, curY, curW, curH),
refTexture, &texCoord[0], refParams);
// Compare this cell
numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
m_texture->getTexture(), &texCoord[0], refParams,
lookupPrec, lodPrec, m_context.getTestContext().getWatchDog());
}
}
if (numFailedPixels > 0)
{
m_context.getTestContext().getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
<< TestLog::Image("ErrorMask", "Error mask", errorMask);
}
return numFailedPixels;
};
m_context.getTestContext().getLog() << TestLog::ImageSet("Result", "Verification result")
<< TestLog::Image("Rendered", "Rendered image", renderedFrame);
int numFailedPixels = compareAndLogImages();
if (numFailedPixels > 0 && refParams.imageViewMinLod > 0.0f)
{
numFailedPixels = compareAndLogImages(tcu::IMAGEVIEWMINLODMODE_ALTERNATIVE);
}
m_context.getTestContext().getLog() << TestLog::EndImageSet;
if (numFailedPixels > 0)
m_context.getTestContext().getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
{
const bool isOk = numFailedPixels == 0;
return isOk ? tcu::TestStatus::pass("pass") : tcu::TestStatus::fail("fail");
}
}
}
class Texture2DMinLodTestInstance : public Texture2DLodControlTestInstance
{
public:
Texture2DMinLodTestInstance (Context& context, const Texture2DMipmapTestCaseParameters& testParameters)
: Texture2DLodControlTestInstance(context, testParameters)
{
}
protected:
void getReferenceParams (ReferenceParams& params, int cellNdx)
{
params.minLod = getMinLodForCell(cellNdx);
}
};
class Texture2DMaxLodTestInstance : public Texture2DLodControlTestInstance
{
public:
Texture2DMaxLodTestInstance (Context& context, const Texture2DMipmapTestCaseParameters& testParameters)
: Texture2DLodControlTestInstance(context, testParameters)
{
}
protected:
void getReferenceParams (ReferenceParams& params, int cellNdx)
{
params.maxLod = getMaxLodForCell(cellNdx);
}
};
class Texture2DBaseLevelTestInstance : public Texture2DLodControlTestInstance
{
public:
Texture2DBaseLevelTestInstance (Context& context, const Texture2DMipmapTestCaseParameters& testParameters)
: Texture2DLodControlTestInstance(context, testParameters)
, m_testParam (testParameters)
{
}
protected:
const Texture2DMipmapTestCaseParameters m_testParam;
int getBaseLevel (int cellNdx) const
{
const int numLevels = deLog2Floor32(de::max(m_texWidth, m_texHeight))+1;
const int baseLevel = (deInt32Hash(cellNdx) ^ deStringHash(m_testParam.minFilterName) ^ 0xac2f274a) % numLevels;
return baseLevel;
}
void getReferenceParams (ReferenceParams& params, int cellNdx)
{
params.baseLevel = getBaseLevel(cellNdx);
}
};
class Texture2DMaxLevelTestInstance : public Texture2DLodControlTestInstance
{
public:
Texture2DMaxLevelTestInstance (Context& context, const Texture2DMipmapTestCaseParameters& testParameters)
: Texture2DLodControlTestInstance(context, testParameters)
, m_testParam (testParameters)
{
}
protected:
const Texture2DMipmapTestCaseParameters m_testParam;
int getMaxLevel (int cellNdx) const
{
const int numLevels = deLog2Floor32(de::max(m_texWidth, m_texHeight))+1;
const int maxLevel = (deInt32Hash(cellNdx) ^ deStringHash(m_testParam.minFilterName) ^ 0x82cfa4e) % numLevels;
return maxLevel;
}
void getReferenceParams (ReferenceParams& params, int cellNdx)
{
params.maxLevel = getMaxLevel(cellNdx);
}
};
// TextureCubeLodControlTestInstance
class TextureCubeLodControlTestInstance : public TestInstance
{
public:
typedef TextureCubeMipmapTestCaseParameters ParameterType;
TextureCubeLodControlTestInstance (Context& context, const ParameterType& testParameters);
~TextureCubeLodControlTestInstance (void);
virtual tcu::TestStatus iterate (void);
protected:
virtual void getReferenceParams (ReferenceParams& params, int cellNdx) = DE_NULL;
const int m_texSize;
private:
TextureCubeLodControlTestInstance (const TextureCubeLodControlTestInstance& other);
TextureCubeLodControlTestInstance& operator= (const TextureCubeLodControlTestInstance& other);
const ParameterType m_testParameters;
tcu::Sampler::FilterMode m_minFilter;
TestTextureCubeSp m_texture;
TextureRenderer m_renderer;
};
TextureCubeLodControlTestInstance::TextureCubeLodControlTestInstance (Context& context, const TextureCubeMipmapTestCaseParameters& testParameters)
: TestInstance (context)
, m_texSize (64)
, m_testParameters (testParameters)
, m_minFilter (testParameters.minFilter)
, m_texture (DE_NULL)
, m_renderer (context, testParameters.sampleCount, m_texSize*2, m_texSize*2)
{
const VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
const int numLevels = deLog2Floor32(m_texSize)+1;
m_texture = TestTextureCubeSp(new pipeline::TestTextureCube(vk::mapVkFormat(format), m_texSize));
// Fill texture with colored grid.
for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
{
for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
{
const deUint32 step = 0xff / (numLevels-1);
const deUint32 inc = deClamp32(step*levelNdx, 0x00, 0xff);
const deUint32 dec = 0xff - inc;
deUint32 rgb = 0;
switch (faceNdx)
{
case 0: rgb = (inc << 16) | (dec << 8) | 255; break;
case 1: rgb = (255 << 16) | (inc << 8) | dec; break;
case 2: rgb = (dec << 16) | (255 << 8) | inc; break;
case 3: rgb = (dec << 16) | (inc << 8) | 255; break;
case 4: rgb = (255 << 16) | (dec << 8) | inc; break;
case 5: rgb = (inc << 16) | (255 << 8) | dec; break;
}
const deUint32 color = 0xff000000 | rgb;
tcu::clear(m_texture->getLevel(levelNdx, (tcu::CubeFace)faceNdx), tcu::RGBA(color).toVec());
}
}
m_renderer.addCubeTexture(m_texture, testParameters.aspectMask);
}
TextureCubeLodControlTestInstance::~TextureCubeLodControlTestInstance (void)
{
}
tcu::TestStatus TextureCubeLodControlTestInstance::iterate (void)
{
const tcu::Sampler::WrapMode wrapS = Sampler::CLAMP_TO_EDGE;
const tcu::Sampler::WrapMode wrapT = Sampler::CLAMP_TO_EDGE;
const tcu::Sampler::FilterMode magFilter = Sampler::NEAREST;
const tcu::TextureCube& refTexture = m_texture->getTexture();
const int viewportWidth = m_renderer.getRenderWidth();
const int viewportHeight = m_renderer.getRenderHeight();
tcu::Sampler sampler = util::createSampler(wrapS, wrapT, m_minFilter, magFilter);
ReferenceParams refParams (TEXTURETYPE_CUBE, sampler);
vector<float> texCoord;
tcu::Surface renderedFrame (viewportWidth, viewportHeight);
refParams.maxLevel = deLog2Floor32(m_texSize);
// Compute grid.
vector<tcu::IVec4> gridLayout;
computeGridLayout(gridLayout, viewportWidth, viewportHeight);
for (int cellNdx = 0; cellNdx < (int)gridLayout.size(); cellNdx++)
{
const int curX = gridLayout[cellNdx].x();
const int curY = gridLayout[cellNdx].y();
const int curW = gridLayout[cellNdx].z();
const int curH = gridLayout[cellNdx].w();
const tcu::CubeFace cubeFace = (tcu::CubeFace)(cellNdx % tcu::CUBEFACE_LAST);
computeQuadTexCoordCube(texCoord, cubeFace);
getReferenceParams(refParams, cellNdx);
// Render with GL.
m_renderer.setViewport((float)curX, (float)curY, (float)curW, (float)curH);
m_renderer.getTextureBinding(0)->updateTextureViewMipLevels(refParams.baseLevel, refParams.maxLevel, refParams.imageViewMinLod);
m_renderer.renderQuad(renderedFrame, 0, &texCoord[0], refParams);
}
// Render reference and compare
{
const tcu::IVec4 formatBitDepth = getTextureFormatBitDepth(mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
const tcu::PixelFormat pixelFormat (formatBitDepth[0], formatBitDepth[1], formatBitDepth[2], formatBitDepth[3]);
tcu::LookupPrecision lookupPrec;
tcu::LodPrecision lodPrec;
// Params for rendering reference
refParams.sampler = util::createSampler(wrapS, wrapT, m_testParameters.minFilter, magFilter);
refParams.sampler.seamlessCubeMap = true;
refParams.lodMode = LODMODE_EXACT;
// Comparison parameters
lookupPrec.colorMask = getCompareMask(pixelFormat);
lookupPrec.colorThreshold = tcu::computeFixedPointThreshold(max(getBitsVec(pixelFormat)-2, IVec4(0)));
lookupPrec.coordBits = tcu::IVec3(10);
lookupPrec.uvwBits = tcu::IVec3(5,5,0);
lodPrec.derivateBits = 10;
lodPrec.lodBits = 6;
auto compareAndLogImages = [&](tcu::ImageViewMinLodMode imageViewLodMode = tcu::IMAGEVIEWMINLODMODE_PREFERRED)
{
tcu::Surface referenceFrame(viewportWidth, viewportHeight);
tcu::Surface errorMask(viewportWidth, viewportHeight);
int numFailedPixels = 0;
for (int cellNdx = 0; cellNdx < (int)gridLayout.size(); cellNdx++)
{
const int curX = gridLayout[cellNdx].x();
const int curY = gridLayout[cellNdx].y();
const int curW = gridLayout[cellNdx].z();
const int curH = gridLayout[cellNdx].w();
const tcu::CubeFace cubeFace = (tcu::CubeFace)(cellNdx % tcu::CUBEFACE_LAST);
computeQuadTexCoordCube(texCoord, cubeFace);
getReferenceParams(refParams, cellNdx);
refParams.imageViewMinLodMode = imageViewLodMode;
// Render ideal reference.
{
tcu::SurfaceAccess idealDst(referenceFrame, pixelFormat, curX, curY, curW, curH);
sampleTexture(idealDst, refTexture, &texCoord[0], refParams);
}
// Compare this cell
numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
m_texture->getTexture(), &texCoord[0], refParams,
lookupPrec, lodPrec, m_context.getTestContext().getWatchDog());
}
if (numFailedPixels > 0)
{
m_context.getTestContext().getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
<< TestLog::Image("ErrorMask", "Error mask", errorMask);
}
return numFailedPixels;
};
m_context.getTestContext().getLog() << TestLog::ImageSet("Result", "Verification result")
<< TestLog::Image("Rendered", "Rendered image", renderedFrame);
int numFailedPixels = compareAndLogImages();
if (numFailedPixels > 0 && refParams.imageViewMinLod > 0.0f)
{
numFailedPixels = compareAndLogImages(tcu::IMAGEVIEWMINLODMODE_ALTERNATIVE);
}
m_context.getTestContext().getLog() << TestLog::EndImageSet;
if (numFailedPixels > 0)
m_context.getTestContext().getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
{
const bool isOk = numFailedPixels == 0;
return isOk ? tcu::TestStatus::pass("pass") : tcu::TestStatus::fail("fail");
}
}
}
class TextureCubeMinLodTestInstance : public TextureCubeLodControlTestInstance
{
public:
TextureCubeMinLodTestInstance (Context& context, const TextureCubeMipmapTestCaseParameters& testParameters)
: TextureCubeLodControlTestInstance(context, testParameters)
{
}
protected:
void getReferenceParams (ReferenceParams& params, int cellNdx)
{
params.minLod = getMinLodForCell(cellNdx);
}
};
class TextureCubeMaxLodTestInstance : public TextureCubeLodControlTestInstance
{
public:
TextureCubeMaxLodTestInstance (Context& context, const TextureCubeMipmapTestCaseParameters& testParameters)
: TextureCubeLodControlTestInstance(context, testParameters)
{
}
protected:
void getReferenceParams (ReferenceParams& params, int cellNdx)
{
params.maxLod = getMaxLodForCell(cellNdx);
}
};
class TextureCubeBaseLevelTestInstance : public TextureCubeLodControlTestInstance
{
public:
TextureCubeBaseLevelTestInstance (Context& context, const TextureCubeMipmapTestCaseParameters& testParameters)
: TextureCubeLodControlTestInstance(context, testParameters)
, m_testParam (testParameters)
{
}
protected:
const TextureCubeMipmapTestCaseParameters m_testParam;
int getBaseLevel (int cellNdx) const
{
const int numLevels = deLog2Floor32(m_texSize)+1;
const int baseLevel = (deInt32Hash(cellNdx) ^ deStringHash(m_testParam.minFilterName) ^ 0x23fae13) % numLevels;
return baseLevel;
}
void getReferenceParams (ReferenceParams& params, int cellNdx)
{
params.baseLevel = getBaseLevel(cellNdx);
}
};
class TextureCubeMaxLevelTestInstance : public TextureCubeLodControlTestInstance
{
public:
TextureCubeMaxLevelTestInstance (Context& context, const TextureCubeMipmapTestCaseParameters& testParameters)
: TextureCubeLodControlTestInstance(context, testParameters)
, m_testParam (testParameters)
{
}
protected:
const TextureCubeMipmapTestCaseParameters m_testParam;
int getMaxLevel (int cellNdx) const
{
const int numLevels = deLog2Floor32(m_texSize)+1;
const int maxLevel = (deInt32Hash(cellNdx) ^ deStringHash(m_testParam.minFilterName) ^ 0x974e21) % numLevels;
return maxLevel;
}
void getReferenceParams (ReferenceParams& params, int cellNdx)
{
params.maxLevel = getMaxLevel(cellNdx);
}
};
// Texture3DLodControlTestInstance
class Texture3DLodControlTestInstance : public TestInstance
{
public:
typedef Texture3DMipmapTestCaseParameters ParameterType;
Texture3DLodControlTestInstance (Context& context, const ParameterType& testParameters);
~Texture3DLodControlTestInstance (void);
virtual tcu::TestStatus iterate (void);
protected:
virtual void getReferenceParams (ReferenceParams& params, int cellNdx) = DE_NULL;
const int m_texWidth;
const int m_texHeight;
const int m_texDepth;
private:
Texture3DLodControlTestInstance (const Texture3DLodControlTestInstance& other);
Texture3DLodControlTestInstance& operator= (const Texture3DLodControlTestInstance& other);
const ParameterType m_testParameters;
tcu::Sampler::FilterMode m_minFilter;
TestTexture3DSp m_texture;
TextureRenderer m_renderer;
};
Texture3DLodControlTestInstance::Texture3DLodControlTestInstance (Context& context, const Texture3DMipmapTestCaseParameters& testParameters)
: TestInstance (context)
, m_texWidth (32)
, m_texHeight (32)
, m_texDepth (32)
, m_testParameters (testParameters)
, m_minFilter (testParameters.minFilter)
, m_texture (DE_NULL)
, m_renderer (context, testParameters.sampleCount, m_texWidth*4, m_texHeight*4, vk::makeComponentMappingRGBA(), testParameters.testType > util::TextureCommonTestCaseParameters::TEST_IMAGE_VIEW_MINLOD)
{
const VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(mapVkFormat(format));
const tcu::Vec4& cScale = fmtInfo.lookupScale;
const tcu::Vec4& cBias = fmtInfo.lookupBias;
const int numLevels = deLog2Floor32(de::max(de::max(m_texWidth, m_texHeight), m_texDepth))+1;
m_texture = TestTexture3DSp(new pipeline::TestTexture3D(vk::mapVkFormat(format), m_texWidth, m_texHeight, m_texDepth));
// Fill texture with colored grid.
for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
{
const deUint32 step = 0xff / (numLevels-1);
const deUint32 inc = deClamp32(step*levelNdx, 0x00, 0xff);
const deUint32 dec = 0xff - inc;
const deUint32 rgb = (inc << 16) | (dec << 8) | 0xff;
const deUint32 color = 0xff000000 | rgb;
tcu::clear(m_texture->getLevel(levelNdx, 0), tcu::RGBA(color).toVec()*cScale + cBias);
}
m_renderer.add3DTexture(m_texture, testParameters.aspectMask);
}
Texture3DLodControlTestInstance::~Texture3DLodControlTestInstance (void)
{
}
tcu::TestStatus Texture3DLodControlTestInstance::iterate (void)
{
const tcu::Sampler::WrapMode wrapS = Sampler::CLAMP_TO_EDGE;
const tcu::Sampler::WrapMode wrapT = Sampler::CLAMP_TO_EDGE;
const tcu::Sampler::WrapMode wrapR = Sampler::CLAMP_TO_EDGE;
const tcu::Sampler::FilterMode magFilter = Sampler::NEAREST;
const tcu::Texture3D& refTexture = m_texture->getTexture();
const tcu::TextureFormat& texFmt = refTexture.getFormat();
const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt);
const int viewportWidth = m_renderer.getRenderWidth();
const int viewportHeight = m_renderer.getRenderHeight();
tcu::Sampler sampler = util::createSampler(wrapS, wrapT, m_minFilter, magFilter);
ReferenceParams refParams (TEXTURETYPE_3D, sampler);
vector<float> texCoord;
tcu::Surface renderedFrame (viewportWidth, viewportHeight);
// Viewport is divided into 4x4 grid.
const int gridWidth = 4;
const int gridHeight = 4;
const int cellWidth = viewportWidth / gridWidth;
const int cellHeight = viewportHeight / gridHeight;
// Sampling parameters.
refParams.sampler = util::createSampler(wrapS, wrapT, wrapR, m_testParameters.minFilter, magFilter);
refParams.samplerType = getSamplerType(texFmt);
refParams.colorBias = fmtInfo.lookupBias;
refParams.colorScale = fmtInfo.lookupScale;
refParams.maxLevel = deLog2Floor32(de::max(de::max(m_texWidth, m_texHeight), m_texDepth));
// Render cells.
for (int gridY = 0; gridY < gridHeight; gridY++)
{
for (int gridX = 0; gridX < gridWidth; gridX++)
{
const int curX = cellWidth*gridX;
const int curY = cellHeight*gridY;
const int curW = gridX+1 == gridWidth ? (viewportWidth-curX) : cellWidth;
const int curH = gridY+1 == gridHeight ? (viewportHeight-curY) : cellHeight;
const int cellNdx = gridY*gridWidth + gridX;
// Compute texcoord.
getBasicTexCoord3D(texCoord, cellNdx);
getReferenceParams(refParams,cellNdx);
//Render
m_renderer.setViewport((float)curX, (float)curY, (float)curW, (float)curH);
m_renderer.getTextureBinding(0)->updateTextureViewMipLevels(refParams.baseLevel, refParams.maxLevel, refParams.imageViewMinLod);
m_renderer.renderQuad(renderedFrame, 0, &texCoord[0], refParams);
}
}
// Compare and log
{
const tcu::IVec4 formatBitDepth = getTextureFormatBitDepth(mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
const tcu::PixelFormat pixelFormat (formatBitDepth[0], formatBitDepth[1], formatBitDepth[2], formatBitDepth[3]);
const bool isTrilinear = m_minFilter == Sampler::NEAREST_MIPMAP_LINEAR || m_minFilter == Sampler::LINEAR_MIPMAP_LINEAR;
tcu::LookupPrecision lookupPrec;
tcu::LodPrecision lodPrec;
lookupPrec.coordBits = tcu::IVec3(20, 20, 20);
lookupPrec.uvwBits = tcu::IVec3(16, 16, 16); // Doesn't really matter since pixels are unicolored.
lookupPrec.colorThreshold = tcu::computeFixedPointThreshold(max(getBitsVec(pixelFormat) - (isTrilinear ? 2 : 1), tcu::IVec4(0)));
lookupPrec.colorMask = getCompareMask(pixelFormat);
lodPrec.derivateBits = 10;
lodPrec.lodBits = 8;
auto compareAndLogImages = [&](tcu::ImageViewMinLodMode imageViewLodMode = tcu::IMAGEVIEWMINLODMODE_PREFERRED)
{
tcu::Surface referenceFrame (viewportWidth, viewportHeight);
tcu::Surface errorMask (viewportWidth, viewportHeight);
int numFailedPixels = 0;
for (int gridY = 0; gridY < gridHeight; gridY++)
{
for (int gridX = 0; gridX < gridWidth; gridX++)
{
const int curX = cellWidth*gridX;
const int curY = cellHeight*gridY;
const int curW = gridX+1 == gridWidth ? (viewportWidth-curX) : cellWidth;
const int curH = gridY+1 == gridHeight ? (viewportHeight-curY) : cellHeight;
const int cellNdx = gridY*gridWidth + gridX;
getReferenceParams(refParams, cellNdx);
refParams.imageViewMinLodMode = imageViewLodMode;
// Compute texcoord.
if (refParams.samplerType == glu::TextureTestUtil::SAMPLERTYPE_FETCH_FLOAT)
getBasicTexCoord3DImageViewMinlodIntTexCoord(texCoord);
else
getBasicTexCoord3D(texCoord, cellNdx);
// Render ideal result
sampleTexture(tcu::SurfaceAccess(referenceFrame, pixelFormat, curX, curY, curW, curH),
refTexture, &texCoord[0], refParams);
// Compare this cell
numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
m_texture->getTexture(), &texCoord[0], refParams,
lookupPrec, lodPrec, m_context.getTestContext().getWatchDog());
}
}
if (numFailedPixels > 0)
{
m_context.getTestContext().getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
<< TestLog::Image("ErrorMask", "Error mask", errorMask);
}
return numFailedPixels;
};
m_context.getTestContext().getLog() << TestLog::ImageSet("Result", "Verification result")
<< TestLog::Image("Rendered", "Rendered image", renderedFrame);
int numFailedPixels = compareAndLogImages();
if (numFailedPixels > 0 && refParams.imageViewMinLod > 0.0f)
{
numFailedPixels = compareAndLogImages(tcu::IMAGEVIEWMINLODMODE_ALTERNATIVE);
}
m_context.getTestContext().getLog() << TestLog::EndImageSet;
if (numFailedPixels > 0)
m_context.getTestContext().getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
{
const bool isOk = numFailedPixels == 0;
return isOk ? tcu::TestStatus::pass("pass") : tcu::TestStatus::fail("fail");
}
}
}
class Texture3DMinLodTestInstance : public Texture3DLodControlTestInstance
{
public:
Texture3DMinLodTestInstance (Context& context, const Texture3DMipmapTestCaseParameters& testParameters)
: Texture3DLodControlTestInstance(context, testParameters)
{
}
protected:
void getReferenceParams (ReferenceParams& params, int cellNdx)
{
params.minLod = getMinLodForCell(cellNdx);
}
};
class Texture3DMaxLodTestInstance : public Texture3DLodControlTestInstance
{
public:
Texture3DMaxLodTestInstance (Context& context, const Texture3DMipmapTestCaseParameters& testParameters)
: Texture3DLodControlTestInstance(context, testParameters)
{
}
protected:
void getReferenceParams (ReferenceParams& params, int cellNdx)
{
params.maxLod = getMaxLodForCell(cellNdx);
}
};
class Texture3DBaseLevelTestInstance : public Texture3DLodControlTestInstance
{
public:
Texture3DBaseLevelTestInstance (Context& context, const Texture3DMipmapTestCaseParameters& testParameters)
: Texture3DLodControlTestInstance(context, testParameters)
,m_testParam (testParameters)
{
}
protected:
const Texture3DMipmapTestCaseParameters m_testParam;
int getBaseLevel (int cellNdx) const
{
const int numLevels = deLog2Floor32(de::max(m_texWidth, de::max(m_texHeight, m_texDepth)))+1;
const int baseLevel = (deInt32Hash(cellNdx) ^ deStringHash(m_testParam.minFilterName) ^ 0x7347e9) % numLevels;
return baseLevel;
}
void getReferenceParams (ReferenceParams& params, int cellNdx)
{
params.baseLevel = getBaseLevel(cellNdx);
}
};
class Texture3DMaxLevelTestInstance : public Texture3DLodControlTestInstance
{
public:
Texture3DMaxLevelTestInstance (Context& context, const Texture3DMipmapTestCaseParameters& testParameters)
: Texture3DLodControlTestInstance(context, testParameters)
,m_testParam (testParameters)
{
}
protected:
const Texture3DMipmapTestCaseParameters m_testParam;
int getMaxLevel (int cellNdx) const
{
const int numLevels = deLog2Floor32(de::max(m_texWidth, de::max(m_texHeight, m_texDepth)))+1;
const int maxLevel = (deInt32Hash(cellNdx) ^ deStringHash(m_testParam.minFilterName) ^ 0x9111e7) % numLevels;
return maxLevel;
}
void getReferenceParams (ReferenceParams& params, int cellNdx)
{
params.maxLevel = getMaxLevel(cellNdx);
}
};
#ifndef CTS_USES_VULKANSC
class Texture2DImageViewMinLodTestInstance : public Texture2DLodControlTestInstance
{
public:
Texture2DImageViewMinLodTestInstance (Context& context, const Texture2DMipmapTestCaseParameters& testParameters)
: Texture2DLodControlTestInstance(context, testParameters)
{
}
protected:
float getImageViewMinLod (int cellNdx, int baseLevel, int maxLevel) const
{
de::Random rnd(cellNdx + 1);
// baselevel + 1.0 as minimum, to test that minLod is working. If we go over the maximum, use that instead.
float minBaseLevel = de::min((float)baseLevel + 1.0f, (float)maxLevel);
return rnd.getFloat(minBaseLevel, (float)maxLevel);
}
void getReferenceParams (ReferenceParams& params, int cellNdx)
{
params.minLod = getMinLodForCell(cellNdx);
params.imageViewMinLod = getImageViewMinLod(cellNdx, params.baseLevel, params.maxLevel);
}
};
class Texture2DImageViewMinLodBaseLevelTestInstance : public Texture2DLodControlTestInstance
{
public:
Texture2DImageViewMinLodBaseLevelTestInstance (Context& context, const Texture2DMipmapTestCaseParameters& testParameters)
: Texture2DLodControlTestInstance(context, testParameters)
, m_testParam (testParameters)
{
}
protected:
const Texture2DMipmapTestCaseParameters m_testParam;
int getBaseLevel (int cellNdx) const
{
const int numLevels = deLog2Floor32(de::max(m_texWidth, m_texHeight))+1;
const int baseLevel = (deInt32Hash(cellNdx) ^ deStringHash(m_testParam.minFilterName) ^ 0xac2f274a) % numLevels;
return baseLevel;
}
float getImageViewMinLod (int cellNdx, int baseLevel, int maxLevel) const
{
de::Random rnd(cellNdx + 1);
// baselevel + 1.0 as minimum, to test that minLod is working. If we go over the maximum, use that instead.
float minValue = de::min((float)baseLevel + 1.0f, (float)maxLevel);
return rnd.getFloat(minValue, (float)maxLevel);
}
void getReferenceParams (ReferenceParams& params, int cellNdx)
{
params.baseLevel = getBaseLevel(cellNdx);
params.imageViewMinLod = getImageViewMinLod(cellNdx, params.baseLevel, params.maxLevel);
}
};
class Texture3DImageViewMinLodTestInstance : public Texture3DLodControlTestInstance
{
public:
Texture3DImageViewMinLodTestInstance (Context& context, const Texture3DMipmapTestCaseParameters& testParameters)
: Texture3DLodControlTestInstance(context, testParameters)
{
}
protected:
float getImageViewMinLod (int cellNdx, int baseLevel, int maxLevel) const
{
de::Random rnd(cellNdx + 1);
// baselevel + 1.0 as minimum, to test that minLod is working. If we go over the maximum, use that instead.
float minValue = de::min((float)baseLevel + 1.0f, (float)maxLevel);
return rnd.getFloat(minValue, (float)maxLevel);
}
void getReferenceParams (ReferenceParams& params, int cellNdx)
{
params.minLod = getMinLodForCell(cellNdx);
params.imageViewMinLod = getImageViewMinLod(cellNdx, params.baseLevel, params.maxLevel);
}
};
class Texture3DImageViewMinLodBaseLevelTestInstance : public Texture3DLodControlTestInstance
{
public:
Texture3DImageViewMinLodBaseLevelTestInstance (Context& context, const Texture3DMipmapTestCaseParameters& testParameters)
: Texture3DLodControlTestInstance(context, testParameters)
, m_testParam (testParameters)
{
}
protected:
const Texture3DMipmapTestCaseParameters m_testParam;
int getBaseLevel (int cellNdx) const
{
const int numLevels = deLog2Floor32(de::max(m_texWidth, de::max(m_texHeight, m_texDepth)))+1;
const int baseLevel = (deInt32Hash(cellNdx) ^ deStringHash(m_testParam.minFilterName) ^ 0x7347e9) % numLevels;
return baseLevel;
}
float getImageViewMinLod (int cellNdx, int baseLevel, int maxLevel) const
{
de::Random rnd(cellNdx + 1);
// baselevel + 1.0 as minimum, to test that minLod is working. If we go over the maximum, use that instead.
float minValue = de::min((float)baseLevel + 1.0f, (float)maxLevel);
return rnd.getFloat(minValue, (float)maxLevel);
}
void getReferenceParams (ReferenceParams& params, int cellNdx)
{
params.baseLevel = getBaseLevel(cellNdx);
params.imageViewMinLod = getImageViewMinLod(cellNdx, params.baseLevel, params.maxLevel);
}
};
class TextureCubeImageViewMinLodTestInstance : public TextureCubeLodControlTestInstance
{
public:
TextureCubeImageViewMinLodTestInstance (Context& context, const TextureCubeMipmapTestCaseParameters& testParameters)
: TextureCubeLodControlTestInstance(context, testParameters)
{
}
protected:
float getImageViewMinLod (int cellNdx, int baseLevel, int maxLevel) const
{
de::Random rnd(cellNdx + 1);
// baselevel + 1.0 as minimum, to test that minLod is working. If we go over the maximum, use that instead.
float minValue = de::min((float)baseLevel + 1.0f, (float)maxLevel);
return rnd.getFloat(minValue, (float)maxLevel);
}
void getReferenceParams (ReferenceParams& params, int cellNdx)
{
params.minLod = getMinLodForCell(cellNdx);
params.imageViewMinLod = getImageViewMinLod(cellNdx, params.baseLevel, params.maxLevel);
}
};
class TextureCubeImageViewMinLodBaseLevelTestInstance : public TextureCubeLodControlTestInstance
{
public:
TextureCubeImageViewMinLodBaseLevelTestInstance (Context& context, const TextureCubeMipmapTestCaseParameters& testParameters)
: TextureCubeLodControlTestInstance(context, testParameters)
, m_testParam (testParameters)
{
}
protected:
const TextureCubeMipmapTestCaseParameters m_testParam;
int getBaseLevel (int cellNdx) const
{
const int numLevels = deLog2Floor32(m_texSize)+1;
const int baseLevel = (deInt32Hash(cellNdx) ^ deStringHash(m_testParam.minFilterName) ^ 0x23fae13) % numLevels;
return baseLevel;
}
float getImageViewMinLod (int cellNdx, int baseLevel, int maxLevel) const
{
de::Random rnd(cellNdx + 1);
// baselevel + 1.0 as minimum, to test that minLod is working. If we go over the maximum, use that instead.
float minValue = de::min((float)baseLevel + 1.0f, (float)maxLevel);
return rnd.getFloat(minValue, (float)maxLevel);
}
void getReferenceParams (ReferenceParams& params, int cellNdx)
{
params.baseLevel = getBaseLevel(cellNdx);
params.imageViewMinLod = getImageViewMinLod(cellNdx, params.baseLevel, params.maxLevel);
}
};
class Texture2DImageViewMinLodIntTexCoordTestInstance : public Texture2DLodControlTestInstance
{
public:
Texture2DImageViewMinLodIntTexCoordTestInstance (Context& context, const Texture2DMipmapTestCaseParameters& testParameters)
: Texture2DLodControlTestInstance(context, testParameters)
, m_testParam (testParameters)
{
}
protected:
const Texture2DMipmapTestCaseParameters m_testParam;
float getImageViewMinLod (int cellNdx, int baseLevel, int maxLevel) const
{
de::Random rnd(cellNdx + 1);
// baselevel + 1.0 as minimum, to test that minLod is working. If we go over the maximum, use that instead.
float minValue = de::min((float)baseLevel + 1.0f, (float)maxLevel);
return rnd.getFloat(minValue, (float)maxLevel);
}
int getLodTexelFetch (int cellNdx, int baseLevel, int maxLevel) const
{
de::Random rnd(cellNdx + 1);
return rnd.getInt(baseLevel, maxLevel) - baseLevel;
}
void getReferenceParams (ReferenceParams& params, int cellNdx)
{
params.imageViewMinLod = getImageViewMinLod(cellNdx, params.baseLevel, params.maxLevel);
params.samplerType = glu::TextureTestUtil::SAMPLERTYPE_FETCH_FLOAT;
params.lodTexelFetch = getLodTexelFetch(cellNdx, params.baseLevel, params.maxLevel);
}
};
class Texture2DImageViewMinLodBaseLevelIntTexCoordTestInstance : public Texture2DLodControlTestInstance
{
public:
Texture2DImageViewMinLodBaseLevelIntTexCoordTestInstance (Context& context, const Texture2DMipmapTestCaseParameters& testParameters)
: Texture2DLodControlTestInstance(context, testParameters)
, m_testParam (testParameters)
{
}
protected:
const Texture2DMipmapTestCaseParameters m_testParam;
int getBaseLevel (int cellNdx) const
{
const int numLevels = deLog2Floor32(de::max(m_texWidth, m_texHeight))+1;
const int baseLevel = (deInt32Hash(cellNdx) ^ deStringHash(m_testParam.minFilterName) ^ 0xac2f274a) % numLevels;
return baseLevel;
}
float getImageViewMinLod (int cellNdx, int baseLevel, int maxLevel) const
{
de::Random rnd(cellNdx + 1);
// baselevel + 1.0 as minimum, to test that minLod is working. If we go over the maximum, use that instead.
float minValue = de::min((float)baseLevel + 1.0f, (float)maxLevel);
return rnd.getFloat(minValue, (float)maxLevel);
}
int getLodTexelFetch (int cellNdx, int baseLevel, int maxLevel) const
{
de::Random rnd(cellNdx + 1);
return rnd.getInt(baseLevel, maxLevel) - baseLevel;
}
void getReferenceParams (ReferenceParams& params, int cellNdx)
{
params.baseLevel = getBaseLevel(cellNdx);
params.imageViewMinLod = getImageViewMinLod(cellNdx, params.baseLevel, params.maxLevel);
params.samplerType = glu::TextureTestUtil::SAMPLERTYPE_FETCH_FLOAT;
params.lodTexelFetch = getLodTexelFetch(cellNdx, params.baseLevel, params.maxLevel);
}
};
class Texture2DImageViewMinLodIntTexCoordTest : public vkt::TestCase
{
public:
Texture2DImageViewMinLodIntTexCoordTest (tcu::TestContext& testContext,
const string& name,
const string& description,
const Texture2DMipmapTestCaseParameters& params);
~Texture2DImageViewMinLodIntTexCoordTest (void);
void initPrograms (SourceCollections& sourceCollections) const;
TestInstance* createInstance (Context& context) const;
void checkSupport (Context& context) const;
protected:
const Texture2DMipmapTestCaseParameters m_params;
};
Texture2DImageViewMinLodIntTexCoordTest::Texture2DImageViewMinLodIntTexCoordTest (tcu::TestContext& testContext,
const string& name,
const string& description,
const Texture2DMipmapTestCaseParameters& params)
: vkt::TestCase (testContext, name, description)
, m_params (params)
{
}
Texture2DImageViewMinLodIntTexCoordTest::~Texture2DImageViewMinLodIntTexCoordTest (void)
{
}
void Texture2DImageViewMinLodIntTexCoordTest::initPrograms(SourceCollections& sourceCollections) const
{
static const char* vertShader =
"#version 450\n"
"layout(location = 0) in vec4 a_position;\n"
"layout(location = 1) in vec2 a_texCoord;\n"
"out gl_PerVertex { vec4 gl_Position; };\n"
"\n"
"void main (void)\n"
"{\n"
" gl_Position = a_position;\n"
"}\n";
static const char* fragShader =
"#version 450\n"
"layout(location = 0) out vec4 outColor;\n"
"layout (set=0, binding=0, std140) uniform Block \n"
"{\n"
" float u_bias;\n"
" float u_ref;\n"
" vec4 u_colorScale;\n"
" vec4 u_colorBias;\n"
" int u_lod;\n"
"};\n\n"
"layout (set=1, binding=0) uniform sampler2D u_sampler;\n"
"void main (void)\n"
"{\n"
" ivec2 texCoord = ivec2(0,0);\n" // Sampling always from the same coord, we are only interested on the lod.
" outColor = texelFetch(u_sampler, texCoord, u_lod) * u_colorScale + u_colorBias;\n"
"}\n";
sourceCollections.glslSources.add("vertex_2D_FETCH_LOD") << glu::VertexSource(vertShader);
sourceCollections.glslSources.add("fragment_2D_FETCH_LOD") << glu::FragmentSource(fragShader);
}
void Texture2DImageViewMinLodIntTexCoordTest::checkSupport(Context& context) const
{
DE_ASSERT(m_params.testType > util::TextureCommonTestCaseParameters::TEST_IMAGE_VIEW_MINLOD);
context.requireDeviceFunctionality("VK_EXT_image_view_min_lod");
context.requireDeviceFunctionality("VK_EXT_robustness2");
vk::VkPhysicalDeviceImageViewMinLodFeaturesEXT imageViewMinLodFeatures;
imageViewMinLodFeatures.sType = vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_MIN_LOD_FEATURES_EXT;
imageViewMinLodFeatures.pNext = DE_NULL;
VkPhysicalDeviceRobustness2FeaturesEXT robustness2Features;
robustness2Features.sType = vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT;
robustness2Features.pNext = &imageViewMinLodFeatures;
vk::VkPhysicalDeviceFeatures2 features2;
features2.sType = vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
features2.pNext = &robustness2Features;
context.getInstanceInterface().getPhysicalDeviceFeatures2(context.getPhysicalDevice(), &features2);
if (imageViewMinLodFeatures.minLod == DE_FALSE)
TCU_THROW(NotSupportedError, "VK_EXT_image_view_min_lod minLod feature not supported");
if (robustness2Features.robustImageAccess2 == DE_FALSE)
TCU_THROW(NotSupportedError, "VK_EXT_robustness2 robustImageAccess2 feature not supported");
}
TestInstance* Texture2DImageViewMinLodIntTexCoordTest::createInstance(Context& context) const
{
if (m_params.testType == util::TextureCommonTestCaseParameters::TEST_IMAGE_VIEW_MINLOD_INT_TEX_COORD)
return new Texture2DImageViewMinLodIntTexCoordTestInstance(context, m_params);
else
return new Texture2DImageViewMinLodBaseLevelIntTexCoordTestInstance(context, m_params);
}
class Texture3DImageViewMinLodIntTexCoordTestInstance : public Texture3DLodControlTestInstance
{
public:
Texture3DImageViewMinLodIntTexCoordTestInstance (Context& context, const Texture3DMipmapTestCaseParameters& testParameters)
: Texture3DLodControlTestInstance(context, testParameters)
, m_testParam (testParameters)
{
}
protected:
const Texture3DMipmapTestCaseParameters m_testParam;
float getImageViewMinLod (int cellNdx, int baseLevel, int maxLevel) const
{
de::Random rnd(cellNdx + 1);
// baselevel + 1.0 as minimum, to test that minLod is working. If we go over the maximum, use that instead.
float minValue = de::min((float)baseLevel + 1.0f, (float)maxLevel);
return rnd.getFloat(minValue, (float)maxLevel);
}
int getLodTexelFetch (int cellNdx, int baseLevel, int maxLevel) const
{
de::Random rnd(cellNdx + 1);
return rnd.getInt(baseLevel, maxLevel) - baseLevel;
}
void getReferenceParams (ReferenceParams& params, int cellNdx)
{
params.imageViewMinLod = getImageViewMinLod(cellNdx, params.baseLevel, params.maxLevel);
params.samplerType = glu::TextureTestUtil::SAMPLERTYPE_FETCH_FLOAT;
params.lodTexelFetch = getLodTexelFetch(cellNdx, params.baseLevel, params.maxLevel);
}
};
class Texture3DImageViewMinLodBaseLevelIntTexCoordTestInstance : public Texture3DLodControlTestInstance
{
public:
Texture3DImageViewMinLodBaseLevelIntTexCoordTestInstance (Context& context, const Texture3DMipmapTestCaseParameters& testParameters)
: Texture3DLodControlTestInstance(context, testParameters)
, m_testParam (testParameters)
{
}
protected:
const Texture3DMipmapTestCaseParameters m_testParam;
int getBaseLevel (int cellNdx) const
{
const int numLevels = deLog2Floor32(de::max(m_texWidth, de::max(m_texHeight, m_texDepth)))+1;
const int baseLevel = (deInt32Hash(cellNdx) ^ deStringHash(m_testParam.minFilterName) ^ 0x7347e9) % numLevels;
return baseLevel;
}
float getImageViewMinLod (int cellNdx, int baseLevel, int maxLevel) const
{
de::Random rnd(cellNdx + 1);
// baselevel + 1.0 as minimum, to test that minLod is working. If we go over the maximum, use that instead.
float minValue = de::min((float)baseLevel + 1.0f, (float)maxLevel);
return rnd.getFloat(minValue, (float)maxLevel);
}
int getLodTexelFetch (int cellNdx, int baseLevel, int maxLevel) const
{
de::Random rnd(cellNdx + 1);
return rnd.getInt(baseLevel, maxLevel) - baseLevel;
}
void getReferenceParams (ReferenceParams& params, int cellNdx)
{
params.baseLevel = getBaseLevel(cellNdx);
params.imageViewMinLod = getImageViewMinLod(cellNdx, params.baseLevel, params.maxLevel);
params.samplerType = glu::TextureTestUtil::SAMPLERTYPE_FETCH_FLOAT;
params.lodTexelFetch = getLodTexelFetch(cellNdx, params.baseLevel, params.maxLevel);
}
};
class Texture3DImageViewMinLodIntTexCoordTest : public vkt::TestCase
{
public:
Texture3DImageViewMinLodIntTexCoordTest (tcu::TestContext& testContext,
const string& name,
const string& description,
const Texture3DMipmapTestCaseParameters& params);
~Texture3DImageViewMinLodIntTexCoordTest (void);
void initPrograms (SourceCollections& sourceCollections) const;
TestInstance* createInstance (Context& context) const;
void checkSupport (Context& context) const;
protected:
const Texture3DMipmapTestCaseParameters m_params;
};
Texture3DImageViewMinLodIntTexCoordTest::Texture3DImageViewMinLodIntTexCoordTest (tcu::TestContext& testContext,
const string& name,
const string& description,
const Texture3DMipmapTestCaseParameters& params)
: vkt::TestCase (testContext, name, description)
, m_params (params)
{
}
Texture3DImageViewMinLodIntTexCoordTest::~Texture3DImageViewMinLodIntTexCoordTest (void)
{
}
void Texture3DImageViewMinLodIntTexCoordTest::initPrograms(SourceCollections& sourceCollections) const
{
static const char* vertShader =
"#version 450\n"
"layout(location = 0) in vec4 a_position;\n"
"layout(location = 1) in vec3 a_texCoord;\n"
"out gl_PerVertex { vec4 gl_Position; };\n"
"\n"
"void main (void)\n"
"{\n"
" gl_Position = a_position;\n"
"}\n";
static const char* fragShader =
"#version 450\n"
"layout(location = 0) out vec4 outColor;\n"
"layout (set=0, binding=0, std140) uniform Block \n"
"{\n"
" float u_bias;\n"
" float u_ref;\n"
" vec4 u_colorScale;\n"
" vec4 u_colorBias;\n"
" int u_lod;\n"
"};\n\n"
"layout (set=1, binding=0) uniform sampler3D u_sampler;\n"
"void main (void)\n"
"{\n"
" ivec3 texCoord = ivec3(0,0,0);\n" // Sampling always from the same coord, we are only interested on the lod.
" outColor = texelFetch(u_sampler, texCoord, u_lod) * u_colorScale + u_colorBias;\n"
"}\n";
sourceCollections.glslSources.add("vertex_3D_FETCH_LOD") << glu::VertexSource(vertShader);
sourceCollections.glslSources.add("fragment_3D_FETCH_LOD") << glu::FragmentSource(fragShader);
}
void Texture3DImageViewMinLodIntTexCoordTest::checkSupport(Context& context) const
{
DE_ASSERT(m_params.testType > util::TextureCommonTestCaseParameters::TEST_IMAGE_VIEW_MINLOD);
context.requireDeviceFunctionality("VK_EXT_image_view_min_lod");
context.requireDeviceFunctionality("VK_EXT_robustness2");
vk::VkPhysicalDeviceImageViewMinLodFeaturesEXT imageViewMinLodFeatures;
imageViewMinLodFeatures.sType = vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_MIN_LOD_FEATURES_EXT;
imageViewMinLodFeatures.pNext = DE_NULL;
VkPhysicalDeviceRobustness2FeaturesEXT robustness2Features;
robustness2Features.sType = vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT;
robustness2Features.pNext = &imageViewMinLodFeatures;
vk::VkPhysicalDeviceFeatures2 features2;
features2.sType = vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
features2.pNext = &robustness2Features;
context.getInstanceInterface().getPhysicalDeviceFeatures2(context.getPhysicalDevice(), &features2);
if (imageViewMinLodFeatures.minLod == DE_FALSE)
TCU_THROW(NotSupportedError, "VK_EXT_image_view_min_lod minLod feature not supported");
if (robustness2Features.robustImageAccess2 == DE_FALSE)
TCU_THROW(NotSupportedError, "VK_EXT_robustness2 robustImageAccess2 feature not supported");
}
TestInstance* Texture3DImageViewMinLodIntTexCoordTest::createInstance(Context& context) const
{
if (m_params.testType == util::TextureCommonTestCaseParameters::TEST_IMAGE_VIEW_MINLOD_INT_TEX_COORD)
return new Texture3DImageViewMinLodIntTexCoordTestInstance(context, m_params);
else
return new Texture3DImageViewMinLodBaseLevelIntTexCoordTestInstance(context, m_params);
}
// Texture gather tests.
enum class GatherMinLod
{
MINLOD_0_1, // 0.1
MINLOD_1_1, // 1.1
};
struct GatherParams
{
uint32_t randomSeed; // Seed for the pseudorandom number generator.
GatherMinLod minLod; // Idea: make it 0.1 or 1.1
int component; // 0, 1, 2, 3 for the gather operation.
float getNumericMinLod (void) const
{
float lod = 0.0f;
switch (minLod)
{
case GatherMinLod::MINLOD_0_1: lod = 0.1f; break;
case GatherMinLod::MINLOD_1_1: lod = 1.1f; break;
default: DE_ASSERT(false); break;
}
return lod;
}
uint32_t getMinLodInteger (void) const
{
uint32_t lod = 0u;
switch (minLod)
{
case GatherMinLod::MINLOD_0_1: lod = 0u; break;
case GatherMinLod::MINLOD_1_1: lod = 1u; break;
default: DE_ASSERT(false); break;
}
return lod;
}
bool needsRobustness2 (void) const
{
return (getNumericMinLod() >= 1.0f);
}
};
class TextureGatherMinLodTest : public vkt::TestCase