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.
2396 lines
82 KiB
2396 lines
82 KiB
/*-------------------------------------------------------------------------
|
|
* drawElements Quality Program OpenGL ES 3.1 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 Sample variable tests
|
|
*//*--------------------------------------------------------------------*/
|
|
|
|
#include "es31fSampleVariableTests.hpp"
|
|
#include "es31fMultisampleShaderRenderCase.hpp"
|
|
#include "tcuSurface.hpp"
|
|
#include "tcuTestLog.hpp"
|
|
#include "tcuRenderTarget.hpp"
|
|
#include "tcuTextureUtil.hpp"
|
|
#include "tcuVectorUtil.hpp"
|
|
#include "tcuFormatUtil.hpp"
|
|
#include "tcuStringTemplate.hpp"
|
|
#include "gluContextInfo.hpp"
|
|
#include "gluShaderProgram.hpp"
|
|
#include "gluRenderContext.hpp"
|
|
#include "glwFunctions.hpp"
|
|
#include "glwEnums.hpp"
|
|
#include "deStringUtil.hpp"
|
|
|
|
namespace deqp
|
|
{
|
|
|
|
using std::map;
|
|
using std::string;
|
|
|
|
namespace gles31
|
|
{
|
|
namespace Functional
|
|
{
|
|
namespace
|
|
{
|
|
|
|
class Verifier
|
|
{
|
|
public:
|
|
virtual bool verify (const tcu::RGBA& testColor, const tcu::IVec2& position) const = 0;
|
|
virtual void logInfo (tcu::TestLog& log) const = 0;
|
|
};
|
|
|
|
class ColorVerifier : public Verifier
|
|
{
|
|
public:
|
|
ColorVerifier (const tcu::Vec3& _color, int _threshold = 8)
|
|
: m_color (tcu::Vec4(_color.x(), _color.y(), _color.z(), 1.0f))
|
|
, m_threshold (tcu::IVec3(_threshold))
|
|
{
|
|
}
|
|
|
|
ColorVerifier (const tcu::Vec3& _color, tcu::IVec3 _threshold)
|
|
: m_color (tcu::Vec4(_color.x(), _color.y(), _color.z(), 1.0f))
|
|
, m_threshold (_threshold)
|
|
{
|
|
}
|
|
|
|
bool verify (const tcu::RGBA& testColor, const tcu::IVec2& position) const
|
|
{
|
|
DE_UNREF(position);
|
|
return !tcu::boolAny(tcu::greaterThan(tcu::abs(m_color.toIVec().swizzle(0, 1, 2) - testColor.toIVec().swizzle(0, 1, 2)), tcu::IVec3(m_threshold)));
|
|
}
|
|
|
|
void logInfo (tcu::TestLog& log) const
|
|
{
|
|
// full threshold? print * for clarity
|
|
log << tcu::TestLog::Message
|
|
<< "Expecting unicolored image, color = RGB("
|
|
<< ((m_threshold[0] >= 255) ? ("*") : (de::toString(m_color.getRed()))) << ", "
|
|
<< ((m_threshold[1] >= 255) ? ("*") : (de::toString(m_color.getGreen()))) << ", "
|
|
<< ((m_threshold[2] >= 255) ? ("*") : (de::toString(m_color.getBlue()))) << ")"
|
|
<< tcu::TestLog::EndMessage;
|
|
}
|
|
|
|
const tcu::RGBA m_color;
|
|
const tcu::IVec3 m_threshold;
|
|
};
|
|
|
|
class FullBlueSomeGreenVerifier : public Verifier
|
|
{
|
|
public:
|
|
FullBlueSomeGreenVerifier (void)
|
|
{
|
|
}
|
|
|
|
bool verify (const tcu::RGBA& testColor, const tcu::IVec2& position) const
|
|
{
|
|
DE_UNREF(position);
|
|
|
|
// Values from 0.0 and 1.0 are accurate
|
|
|
|
if (testColor.getRed() != 0)
|
|
return false;
|
|
if (testColor.getGreen() == 0)
|
|
return false;
|
|
if (testColor.getBlue() != 255)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
void logInfo (tcu::TestLog& log) const
|
|
{
|
|
log << tcu::TestLog::Message << "Expecting color c = (0.0, x, 1.0), x > 0.0" << tcu::TestLog::EndMessage;
|
|
}
|
|
};
|
|
|
|
class NoRedVerifier : public Verifier
|
|
{
|
|
public:
|
|
NoRedVerifier (void)
|
|
{
|
|
}
|
|
|
|
bool verify (const tcu::RGBA& testColor, const tcu::IVec2& position) const
|
|
{
|
|
DE_UNREF(position);
|
|
return testColor.getRed() == 0;
|
|
}
|
|
|
|
void logInfo (tcu::TestLog& log) const
|
|
{
|
|
log << tcu::TestLog::Message << "Expecting zero-valued red channel." << tcu::TestLog::EndMessage;
|
|
}
|
|
};
|
|
|
|
class SampleAverageVerifier : public Verifier
|
|
{
|
|
public:
|
|
SampleAverageVerifier (int _numSamples);
|
|
|
|
bool verify (const tcu::RGBA& testColor, const tcu::IVec2& position) const;
|
|
void logInfo (tcu::TestLog& log) const;
|
|
|
|
const int m_numSamples;
|
|
const bool m_isStatisticallySignificant;
|
|
float m_distanceThreshold;
|
|
};
|
|
|
|
SampleAverageVerifier::SampleAverageVerifier (int _numSamples)
|
|
: m_numSamples (_numSamples)
|
|
, m_isStatisticallySignificant (_numSamples >= 4)
|
|
, m_distanceThreshold (0.0f)
|
|
{
|
|
// approximate Bates distribution as normal
|
|
const float variance = (1.0f / (12.0f * (float)m_numSamples));
|
|
const float standardDeviation = deFloatSqrt(variance);
|
|
|
|
// 95% of means of sample positions are within 2 standard deviations if
|
|
// they were randomly assigned. Sample patterns are expected to be more
|
|
// uniform than a random pattern.
|
|
m_distanceThreshold = 2 * standardDeviation;
|
|
}
|
|
|
|
bool SampleAverageVerifier::verify (const tcu::RGBA& testColor, const tcu::IVec2& position) const
|
|
{
|
|
DE_UNREF(position);
|
|
DE_ASSERT(m_isStatisticallySignificant);
|
|
|
|
const tcu::Vec2 avgPosition ((float)testColor.getGreen() / 255.0f, (float)testColor.getBlue() / 255.0f);
|
|
const tcu::Vec2 distanceFromCenter = tcu::abs(avgPosition - tcu::Vec2(0.5f, 0.5f));
|
|
|
|
return distanceFromCenter.x() < m_distanceThreshold && distanceFromCenter.y() < m_distanceThreshold;
|
|
}
|
|
|
|
void SampleAverageVerifier::logInfo (tcu::TestLog& log) const
|
|
{
|
|
log << tcu::TestLog::Message << "Expecting average sample position to be near the pixel center. Maximum per-axis distance " << m_distanceThreshold << tcu::TestLog::EndMessage;
|
|
}
|
|
|
|
class PartialDiscardVerifier : public Verifier
|
|
{
|
|
public:
|
|
PartialDiscardVerifier (void)
|
|
{
|
|
}
|
|
|
|
bool verify (const tcu::RGBA& testColor, const tcu::IVec2& position) const
|
|
{
|
|
DE_UNREF(position);
|
|
|
|
return (testColor.getGreen() != 0) && (testColor.getGreen() != 255);
|
|
}
|
|
|
|
void logInfo (tcu::TestLog& log) const
|
|
{
|
|
log << tcu::TestLog::Message << "Expecting color non-zero and non-saturated green channel" << tcu::TestLog::EndMessage;
|
|
}
|
|
};
|
|
|
|
static bool verifyImageWithVerifier (const tcu::Surface& resultImage, tcu::TestLog& log, const Verifier& verifier, bool logOnSuccess = true)
|
|
{
|
|
tcu::Surface errorMask (resultImage.getWidth(), resultImage.getHeight());
|
|
bool error = false;
|
|
|
|
tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
|
|
|
|
if (logOnSuccess)
|
|
{
|
|
log << tcu::TestLog::Message << "Verifying image." << tcu::TestLog::EndMessage;
|
|
verifier.logInfo(log);
|
|
}
|
|
|
|
for (int y = 0; y < resultImage.getHeight(); ++y)
|
|
for (int x = 0; x < resultImage.getWidth(); ++x)
|
|
{
|
|
const tcu::RGBA color = resultImage.getPixel(x, y);
|
|
|
|
// verify color value is valid for this pixel position
|
|
if (!verifier.verify(color, tcu::IVec2(x,y)))
|
|
{
|
|
error = true;
|
|
errorMask.setPixel(x, y, tcu::RGBA::red());
|
|
}
|
|
}
|
|
|
|
if (error)
|
|
{
|
|
// describe the verification logic if we haven't already
|
|
if (!logOnSuccess)
|
|
verifier.logInfo(log);
|
|
|
|
log << tcu::TestLog::Message << "Image verification failed." << tcu::TestLog::EndMessage
|
|
<< tcu::TestLog::ImageSet("Verification", "Image Verification")
|
|
<< tcu::TestLog::Image("Result", "Result image", resultImage.getAccess())
|
|
<< tcu::TestLog::Image("ErrorMask", "Error Mask", errorMask.getAccess())
|
|
<< tcu::TestLog::EndImageSet;
|
|
}
|
|
else if (logOnSuccess)
|
|
{
|
|
log << tcu::TestLog::Message << "Image verification passed." << tcu::TestLog::EndMessage
|
|
<< tcu::TestLog::ImageSet("Verification", "Image Verification")
|
|
<< tcu::TestLog::Image("Result", "Result image", resultImage.getAccess())
|
|
<< tcu::TestLog::EndImageSet;
|
|
}
|
|
|
|
return !error;
|
|
}
|
|
|
|
class MultisampleRenderCase : public MultisampleShaderRenderUtil::MultisampleRenderCase
|
|
{
|
|
public:
|
|
MultisampleRenderCase (Context& context, const char* name, const char* desc, int numSamples, RenderTarget target, int renderSize, int flags = 0);
|
|
virtual ~MultisampleRenderCase (void);
|
|
|
|
virtual void init (void);
|
|
|
|
};
|
|
|
|
MultisampleRenderCase::MultisampleRenderCase (Context& context, const char* name, const char* desc, int numSamples, RenderTarget target, int renderSize, int flags)
|
|
: MultisampleShaderRenderUtil::MultisampleRenderCase(context, name, desc, numSamples, target, renderSize, flags)
|
|
{
|
|
DE_ASSERT(target < TARGET_LAST);
|
|
}
|
|
|
|
MultisampleRenderCase::~MultisampleRenderCase (void)
|
|
{
|
|
MultisampleRenderCase::deinit();
|
|
}
|
|
|
|
void MultisampleRenderCase::init (void)
|
|
{
|
|
const bool supportsES32orGL45 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
|
|
contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
|
|
if (!supportsES32orGL45 && !m_context.getContextInfo().isExtensionSupported("GL_OES_sample_variables"))
|
|
TCU_THROW(NotSupportedError, "Test requires GL_OES_sample_variables extension or a context version 3.2 or higher.");
|
|
|
|
MultisampleShaderRenderUtil::MultisampleRenderCase::init();
|
|
}
|
|
|
|
class NumSamplesCase : public MultisampleRenderCase
|
|
{
|
|
public:
|
|
NumSamplesCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target);
|
|
~NumSamplesCase (void);
|
|
|
|
std::string genFragmentSource (int numTargetSamples) const;
|
|
bool verifyImage (const tcu::Surface& resultImage);
|
|
|
|
private:
|
|
enum
|
|
{
|
|
RENDER_SIZE = 64
|
|
};
|
|
};
|
|
|
|
NumSamplesCase::NumSamplesCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target)
|
|
: MultisampleRenderCase(context, name, desc, sampleCount, target, RENDER_SIZE)
|
|
{
|
|
}
|
|
|
|
NumSamplesCase::~NumSamplesCase (void)
|
|
{
|
|
}
|
|
|
|
std::string NumSamplesCase::genFragmentSource (int numTargetSamples) const
|
|
{
|
|
std::ostringstream buf;
|
|
const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
|
|
map<string, string> args;
|
|
args["GLSL_VERSION_DECL"] = supportsES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
|
|
args["GLSL_EXTENSION"] = supportsES32 ? "" : "#extension GL_OES_sample_variables : require";
|
|
|
|
buf << "${GLSL_VERSION_DECL}\n"
|
|
"${GLSL_EXTENSION}\n"
|
|
"layout(location = 0) out mediump vec4 fragColor;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
|
|
" if (gl_NumSamples == " << numTargetSamples << ")\n"
|
|
" fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
|
|
"}\n";
|
|
|
|
return tcu::StringTemplate(buf.str()).specialize(args);
|
|
}
|
|
|
|
bool NumSamplesCase::verifyImage (const tcu::Surface& resultImage)
|
|
{
|
|
return verifyImageWithVerifier(resultImage, m_testCtx.getLog(), NoRedVerifier());
|
|
}
|
|
|
|
class MaxSamplesCase : public MultisampleRenderCase
|
|
{
|
|
public:
|
|
MaxSamplesCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target);
|
|
~MaxSamplesCase (void);
|
|
|
|
private:
|
|
void preDraw (void);
|
|
std::string genFragmentSource (int numTargetSamples) const;
|
|
bool verifyImage (const tcu::Surface& resultImage);
|
|
|
|
enum
|
|
{
|
|
RENDER_SIZE = 64
|
|
};
|
|
};
|
|
|
|
MaxSamplesCase::MaxSamplesCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target)
|
|
: MultisampleRenderCase(context, name, desc, sampleCount, target, RENDER_SIZE)
|
|
{
|
|
}
|
|
|
|
MaxSamplesCase::~MaxSamplesCase (void)
|
|
{
|
|
}
|
|
|
|
void MaxSamplesCase::preDraw (void)
|
|
{
|
|
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
|
|
deInt32 maxSamples = -1;
|
|
|
|
// query samples
|
|
{
|
|
gl.getIntegerv(GL_MAX_SAMPLES, &maxSamples);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "query GL_MAX_SAMPLES");
|
|
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_SAMPLES = " << maxSamples << tcu::TestLog::EndMessage;
|
|
}
|
|
|
|
// set samples
|
|
{
|
|
const int maxSampleLoc = gl.getUniformLocation(m_program->getProgram(), "u_maxSamples");
|
|
if (maxSampleLoc == -1)
|
|
throw tcu::TestError("Location of u_maxSamples was -1");
|
|
|
|
gl.uniform1i(maxSampleLoc, maxSamples);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "set u_maxSamples uniform");
|
|
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Set u_maxSamples = " << maxSamples << tcu::TestLog::EndMessage;
|
|
}
|
|
}
|
|
|
|
std::string MaxSamplesCase::genFragmentSource (int numTargetSamples) const
|
|
{
|
|
DE_UNREF(numTargetSamples);
|
|
|
|
std::ostringstream buf;
|
|
const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
|
|
map<string, string> args;
|
|
args["GLSL_VERSION_DECL"] = supportsES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
|
|
args["GLSL_EXTENSION"] = supportsES32 ? "" : "#extension GL_OES_sample_variables : require";
|
|
|
|
buf << "${GLSL_VERSION_DECL}\n"
|
|
"${GLSL_EXTENSION}\n"
|
|
"layout(location = 0) out mediump vec4 fragColor;\n"
|
|
"uniform mediump int u_maxSamples;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
|
|
" if (gl_MaxSamples == u_maxSamples)\n"
|
|
" fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
|
|
"}\n";
|
|
|
|
return tcu::StringTemplate(buf.str()).specialize(args);
|
|
}
|
|
|
|
bool MaxSamplesCase::verifyImage (const tcu::Surface& resultImage)
|
|
{
|
|
return verifyImageWithVerifier(resultImage, m_testCtx.getLog(), NoRedVerifier());
|
|
}
|
|
|
|
class SampleIDCase : public MultisampleRenderCase
|
|
{
|
|
public:
|
|
SampleIDCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target);
|
|
~SampleIDCase (void);
|
|
|
|
void init (void);
|
|
|
|
private:
|
|
std::string genFragmentSource (int numTargetSamples) const;
|
|
bool verifyImage (const tcu::Surface& resultImage);
|
|
bool verifySampleBuffers (const std::vector<tcu::Surface>& resultBuffers);
|
|
|
|
enum
|
|
{
|
|
RENDER_SIZE = 64
|
|
};
|
|
enum VerificationMode
|
|
{
|
|
VERIFY_USING_SAMPLES,
|
|
VERIFY_USING_SELECTION,
|
|
};
|
|
|
|
const VerificationMode m_vericationMode;
|
|
};
|
|
|
|
SampleIDCase::SampleIDCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target)
|
|
: MultisampleRenderCase (context, name, desc, sampleCount, target, RENDER_SIZE, MultisampleShaderRenderUtil::MultisampleRenderCase::FLAG_VERIFY_MSAA_TEXTURE_SAMPLE_BUFFERS)
|
|
, m_vericationMode ((target == TARGET_TEXTURE) ? (VERIFY_USING_SAMPLES) : (VERIFY_USING_SELECTION))
|
|
{
|
|
}
|
|
|
|
SampleIDCase::~SampleIDCase (void)
|
|
{
|
|
}
|
|
|
|
void SampleIDCase::init (void)
|
|
{
|
|
// log the test method and expectations
|
|
if (m_vericationMode == VERIFY_USING_SAMPLES)
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message
|
|
<< "Writing gl_SampleID to the green channel of the texture and verifying texture values, expecting:\n"
|
|
<< " 1) 0 with non-multisample targets.\n"
|
|
<< " 2) value N at sample index N of a multisample texture\n"
|
|
<< tcu::TestLog::EndMessage;
|
|
else if (m_vericationMode == VERIFY_USING_SELECTION)
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message
|
|
<< "Selecting a single sample id for each pixel and writing color only if gl_SampleID == selected.\n"
|
|
<< "Expecting all output pixels to be partially (multisample) or fully (singlesample) colored.\n"
|
|
<< tcu::TestLog::EndMessage;
|
|
else
|
|
DE_ASSERT(false);
|
|
|
|
MultisampleRenderCase::init();
|
|
}
|
|
|
|
std::string SampleIDCase::genFragmentSource (int numTargetSamples) const
|
|
{
|
|
DE_ASSERT(numTargetSamples != 0);
|
|
|
|
std::ostringstream buf;
|
|
const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
|
|
map<string, string> args;
|
|
args["GLSL_VERSION_DECL"] = supportsES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
|
|
args["GLSL_EXTENSION"] = supportsES32 ? "" : "#extension GL_OES_sample_variables : require";
|
|
|
|
if (m_vericationMode == VERIFY_USING_SAMPLES)
|
|
{
|
|
// encode the id to the output, and then verify it during sampling
|
|
buf << "${GLSL_VERSION_DECL}\n"
|
|
"${GLSL_EXTENSION}\n"
|
|
"layout(location = 0) out mediump vec4 fragColor;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" highp float normalizedSample = float(gl_SampleID) / float(" << numTargetSamples << ");\n"
|
|
" fragColor = vec4(0.0, normalizedSample, 1.0, 1.0);\n"
|
|
"}\n";
|
|
}
|
|
else if (m_vericationMode == VERIFY_USING_SELECTION)
|
|
{
|
|
if (numTargetSamples == 1)
|
|
{
|
|
// single sample, just verify value is 0
|
|
buf << "${GLSL_VERSION_DECL}\n"
|
|
"${GLSL_EXTENSION}\n"
|
|
"layout(location = 0) out mediump vec4 fragColor;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" if (gl_SampleID == 0)\n"
|
|
" fragColor = vec4(0.0, 1.0, 1.0, 1.0);\n"
|
|
" else\n"
|
|
" fragColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
|
|
"}\n";
|
|
}
|
|
else
|
|
{
|
|
// select only one sample per PIXEL
|
|
buf << "${GLSL_VERSION_DECL}\n"
|
|
"${GLSL_EXTENSION}\n"
|
|
"in highp vec4 v_position;\n"
|
|
"layout(location = 0) out mediump vec4 fragColor;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" highp vec2 relPosition = (v_position.xy + vec2(1.0, 1.0)) / 2.0;\n"
|
|
" highp ivec2 pixelPos = ivec2(floor(relPosition * " << (int)RENDER_SIZE << ".0));\n"
|
|
" highp int selectedID = abs(pixelPos.x + 17 * pixelPos.y) % " << numTargetSamples << ";\n"
|
|
"\n"
|
|
" if (gl_SampleID == selectedID)\n"
|
|
" fragColor = vec4(0.0, 1.0, 1.0, 1.0);\n"
|
|
" else\n"
|
|
" fragColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
|
|
"}\n";
|
|
}
|
|
}
|
|
else
|
|
DE_ASSERT(false);
|
|
|
|
return tcu::StringTemplate(buf.str()).specialize(args);
|
|
}
|
|
|
|
bool SampleIDCase::verifyImage (const tcu::Surface& resultImage)
|
|
{
|
|
if (m_vericationMode == VERIFY_USING_SAMPLES)
|
|
{
|
|
// never happens
|
|
DE_ASSERT(false);
|
|
return false;
|
|
}
|
|
else if (m_vericationMode == VERIFY_USING_SELECTION)
|
|
{
|
|
// should result in full blue and some green everywhere
|
|
return verifyImageWithVerifier(resultImage, m_testCtx.getLog(), FullBlueSomeGreenVerifier());
|
|
}
|
|
else
|
|
{
|
|
DE_ASSERT(false);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool SampleIDCase::verifySampleBuffers (const std::vector<tcu::Surface>& resultBuffers)
|
|
{
|
|
// Verify all sample buffers
|
|
bool allOk = true;
|
|
|
|
// Log layers
|
|
{
|
|
m_testCtx.getLog() << tcu::TestLog::ImageSet("SampleBuffers", "Image sample buffers");
|
|
for (int sampleNdx = 0; sampleNdx < (int)resultBuffers.size(); ++sampleNdx)
|
|
m_testCtx.getLog() << tcu::TestLog::Image("Buffer" + de::toString(sampleNdx), "Sample " + de::toString(sampleNdx), resultBuffers[sampleNdx].getAccess());
|
|
m_testCtx.getLog() << tcu::TestLog::EndImageSet;
|
|
}
|
|
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Verifying sample buffers" << tcu::TestLog::EndMessage;
|
|
for (int sampleNdx = 0; sampleNdx < (int)resultBuffers.size(); ++sampleNdx)
|
|
{
|
|
// sample id should be sample index
|
|
const int threshold = 255 / 4 / m_numTargetSamples + 1;
|
|
const float sampleIdColor = (float)sampleNdx / (float)m_numTargetSamples;
|
|
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Verifying sample " << (sampleNdx+1) << "/" << (int)resultBuffers.size() << tcu::TestLog::EndMessage;
|
|
allOk &= verifyImageWithVerifier(resultBuffers[sampleNdx], m_testCtx.getLog(), ColorVerifier(tcu::Vec3(0.0f, sampleIdColor, 1.0f), tcu::IVec3(1, threshold, 1)), false);
|
|
}
|
|
|
|
if (!allOk)
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Sample buffer verification failed" << tcu::TestLog::EndMessage;
|
|
|
|
return allOk;
|
|
}
|
|
|
|
class SamplePosDistributionCase : public MultisampleRenderCase
|
|
{
|
|
public:
|
|
SamplePosDistributionCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target);
|
|
~SamplePosDistributionCase (void);
|
|
|
|
void init (void);
|
|
private:
|
|
enum
|
|
{
|
|
RENDER_SIZE = 64
|
|
};
|
|
|
|
std::string genFragmentSource (int numTargetSamples) const;
|
|
bool verifyImage (const tcu::Surface& resultImage);
|
|
bool verifySampleBuffers (const std::vector<tcu::Surface>& resultBuffers);
|
|
};
|
|
|
|
SamplePosDistributionCase::SamplePosDistributionCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target)
|
|
: MultisampleRenderCase(context, name, desc, sampleCount, target, RENDER_SIZE, MultisampleShaderRenderUtil::MultisampleRenderCase::FLAG_VERIFY_MSAA_TEXTURE_SAMPLE_BUFFERS)
|
|
{
|
|
}
|
|
|
|
SamplePosDistributionCase::~SamplePosDistributionCase (void)
|
|
{
|
|
}
|
|
|
|
void SamplePosDistributionCase::init (void)
|
|
{
|
|
// log the test method and expectations
|
|
if (m_renderTarget == TARGET_TEXTURE)
|
|
{
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message
|
|
<< "Verifying gl_SamplePosition value:\n"
|
|
<< " 1) With non-multisample targets: Expect the center of the pixel.\n"
|
|
<< " 2) With multisample targets:\n"
|
|
<< " a) Expect legal sample position.\n"
|
|
<< " b) Sample position is unique within the set of all sample positions of a pixel.\n"
|
|
<< " c) Sample position distribution is uniform or almost uniform.\n"
|
|
<< tcu::TestLog::EndMessage;
|
|
}
|
|
else
|
|
{
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message
|
|
<< "Verifying gl_SamplePosition value:\n"
|
|
<< " 1) With non-multisample targets: Expect the center of the pixel.\n"
|
|
<< " 2) With multisample targets:\n"
|
|
<< " a) Expect legal sample position.\n"
|
|
<< " b) Sample position distribution is uniform or almost uniform.\n"
|
|
<< tcu::TestLog::EndMessage;
|
|
}
|
|
|
|
MultisampleRenderCase::init();
|
|
}
|
|
|
|
std::string SamplePosDistributionCase::genFragmentSource (int numTargetSamples) const
|
|
{
|
|
DE_ASSERT(numTargetSamples != 0);
|
|
DE_UNREF(numTargetSamples);
|
|
|
|
const bool multisampleTarget = (m_numRequestedSamples > 0) || (m_renderTarget == TARGET_DEFAULT && m_context.getRenderTarget().getNumSamples() > 1);
|
|
std::ostringstream buf;
|
|
const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
|
|
map<string, string> args;
|
|
args["GLSL_VERSION_DECL"] = supportsES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
|
|
args["GLSL_EXTENSION"] = supportsES32 ? "\n" : "#extension GL_OES_sample_variables : require\n";
|
|
|
|
if (multisampleTarget)
|
|
{
|
|
// encode the position to the output, use red channel as error channel
|
|
buf << "${GLSL_VERSION_DECL}\n"
|
|
"${GLSL_EXTENSION}\n"
|
|
"layout(location = 0) out mediump vec4 fragColor;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" if (gl_SamplePosition.x < 0.0 || gl_SamplePosition.x > 1.0 || gl_SamplePosition.y < 0.0 || gl_SamplePosition.y > 1.0)\n"
|
|
" fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
|
|
" else\n"
|
|
" fragColor = vec4(0.0, gl_SamplePosition.x, gl_SamplePosition.y, 1.0);\n"
|
|
"}\n";
|
|
}
|
|
else
|
|
{
|
|
// verify value is ok
|
|
buf << "${GLSL_VERSION_DECL}\n"
|
|
"${GLSL_EXTENSION}\n"
|
|
"layout(location = 0) out mediump vec4 fragColor;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" if (gl_SamplePosition.x != 0.5 || gl_SamplePosition.y != 0.5)\n"
|
|
" fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
|
|
" else\n"
|
|
" fragColor = vec4(0.0, gl_SamplePosition.x, gl_SamplePosition.y, 1.0);\n"
|
|
"}\n";
|
|
}
|
|
|
|
return tcu::StringTemplate(buf.str()).specialize(args);
|
|
}
|
|
|
|
bool SamplePosDistributionCase::verifyImage (const tcu::Surface& resultImage)
|
|
{
|
|
const int sampleCount = (m_renderTarget == TARGET_DEFAULT) ? (m_context.getRenderTarget().getNumSamples()) : (m_numRequestedSamples);
|
|
SampleAverageVerifier verifier (sampleCount);
|
|
|
|
// check there is nothing in the error channel
|
|
if (!verifyImageWithVerifier(resultImage, m_testCtx.getLog(), NoRedVerifier()))
|
|
return false;
|
|
|
|
// position average should be around 0.5, 0.5
|
|
if (verifier.m_isStatisticallySignificant && !verifyImageWithVerifier(resultImage, m_testCtx.getLog(), verifier))
|
|
throw MultisampleShaderRenderUtil::QualityWarning("Bias detected, sample positions are not uniformly distributed within the pixel");
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SamplePosDistributionCase::verifySampleBuffers (const std::vector<tcu::Surface>& resultBuffers)
|
|
{
|
|
const int width = resultBuffers[0].getWidth();
|
|
const int height = resultBuffers[0].getHeight();
|
|
bool allOk = true;
|
|
bool distibutionError = false;
|
|
|
|
// Check sample range, uniqueness, and distribution, log layers
|
|
{
|
|
m_testCtx.getLog() << tcu::TestLog::ImageSet("SampleBuffers", "Image sample buffers");
|
|
for (int sampleNdx = 0; sampleNdx < (int)resultBuffers.size(); ++sampleNdx)
|
|
m_testCtx.getLog() << tcu::TestLog::Image("Buffer" + de::toString(sampleNdx), "Sample " + de::toString(sampleNdx), resultBuffers[sampleNdx].getAccess());
|
|
m_testCtx.getLog() << tcu::TestLog::EndImageSet;
|
|
}
|
|
|
|
// verify range
|
|
{
|
|
bool rangeOk = true;
|
|
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Verifying sample position range" << tcu::TestLog::EndMessage;
|
|
for (int sampleNdx = 0; sampleNdx < (int)resultBuffers.size(); ++sampleNdx)
|
|
{
|
|
// shader does the check, just check the shader error output (red)
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Verifying sample " << (sampleNdx+1) << "/" << (int)resultBuffers.size() << tcu::TestLog::EndMessage;
|
|
rangeOk &= verifyImageWithVerifier(resultBuffers[sampleNdx], m_testCtx.getLog(), NoRedVerifier(), false);
|
|
}
|
|
|
|
if (!rangeOk)
|
|
{
|
|
allOk = false;
|
|
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Sample position verification failed." << tcu::TestLog::EndMessage;
|
|
}
|
|
}
|
|
|
|
// Verify uniqueness
|
|
{
|
|
bool uniquenessOk = true;
|
|
tcu::Surface errorMask (width, height);
|
|
std::vector<tcu::Vec2> samplePositions (resultBuffers.size());
|
|
int printCount = 0;
|
|
const int printFloodLimit = 5;
|
|
|
|
tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
|
|
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Verifying sample position uniqueness." << tcu::TestLog::EndMessage;
|
|
|
|
for (int y = 0; y < height; ++y)
|
|
for (int x = 0; x < width; ++x)
|
|
{
|
|
bool samplePosNotUnique = false;
|
|
|
|
for (int sampleNdx = 0; sampleNdx < (int)resultBuffers.size(); ++sampleNdx)
|
|
{
|
|
const tcu::RGBA color = resultBuffers[sampleNdx].getPixel(x, y);
|
|
samplePositions[sampleNdx] = tcu::Vec2((float)color.getGreen() / 255.0f, (float)color.getBlue() / 255.0f);
|
|
}
|
|
|
|
// Just check there are no two samples with same positions
|
|
for (int sampleNdxA = 0; sampleNdxA < (int)resultBuffers.size() && (!samplePosNotUnique || printCount < printFloodLimit); ++sampleNdxA)
|
|
for (int sampleNdxB = sampleNdxA+1; sampleNdxB < (int)resultBuffers.size() && (!samplePosNotUnique || printCount < printFloodLimit); ++sampleNdxB)
|
|
{
|
|
if (samplePositions[sampleNdxA] == samplePositions[sampleNdxB])
|
|
{
|
|
if (++printCount <= printFloodLimit)
|
|
{
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message
|
|
<< "Pixel (" << x << ", " << y << "): Samples " << sampleNdxA << " and " << sampleNdxB << " have the same position."
|
|
<< tcu::TestLog::EndMessage;
|
|
}
|
|
|
|
samplePosNotUnique = true;
|
|
uniquenessOk = false;
|
|
errorMask.setPixel(x, y, tcu::RGBA::red());
|
|
}
|
|
}
|
|
}
|
|
|
|
// end result
|
|
if (!uniquenessOk)
|
|
{
|
|
if (printCount > printFloodLimit)
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message
|
|
<< "...\n"
|
|
<< "Omitted " << (printCount-printFloodLimit) << " error descriptions."
|
|
<< tcu::TestLog::EndMessage;
|
|
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message << "Image verification failed." << tcu::TestLog::EndMessage
|
|
<< tcu::TestLog::ImageSet("Verification", "Image Verification")
|
|
<< tcu::TestLog::Image("ErrorMask", "Error Mask", errorMask.getAccess())
|
|
<< tcu::TestLog::EndImageSet;
|
|
|
|
allOk = false;
|
|
}
|
|
}
|
|
|
|
// check distribution
|
|
{
|
|
const SampleAverageVerifier verifier (m_numTargetSamples);
|
|
tcu::Surface errorMask (width, height);
|
|
int printCount = 0;
|
|
const int printFloodLimit = 5;
|
|
|
|
tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
|
|
|
|
// don't bother with small sample counts
|
|
if (verifier.m_isStatisticallySignificant)
|
|
{
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Verifying sample position distribution is (nearly) unbiased." << tcu::TestLog::EndMessage;
|
|
verifier.logInfo(m_testCtx.getLog());
|
|
|
|
for (int y = 0; y < height; ++y)
|
|
for (int x = 0; x < width; ++x)
|
|
{
|
|
tcu::IVec3 colorSum(0, 0, 0);
|
|
|
|
// color average
|
|
|
|
for (int sampleNdx = 0; sampleNdx < (int)resultBuffers.size(); ++sampleNdx)
|
|
{
|
|
const tcu::RGBA color = resultBuffers[sampleNdx].getPixel(x, y);
|
|
colorSum.x() += color.getRed();
|
|
colorSum.y() += color.getBlue();
|
|
colorSum.z() += color.getGreen();
|
|
}
|
|
|
|
colorSum.x() /= m_numTargetSamples;
|
|
colorSum.y() /= m_numTargetSamples;
|
|
colorSum.z() /= m_numTargetSamples;
|
|
|
|
// verify average sample position
|
|
|
|
if (!verifier.verify(tcu::RGBA(colorSum.x(), colorSum.y(), colorSum.z(), 0), tcu::IVec2(x, y)))
|
|
{
|
|
if (++printCount <= printFloodLimit)
|
|
{
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message
|
|
<< "Pixel (" << x << ", " << y << "): Sample distribution is biased."
|
|
<< tcu::TestLog::EndMessage;
|
|
}
|
|
|
|
distibutionError = true;
|
|
errorMask.setPixel(x, y, tcu::RGBA::red());
|
|
}
|
|
}
|
|
|
|
// sub-verification result
|
|
if (distibutionError)
|
|
{
|
|
if (printCount > printFloodLimit)
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message
|
|
<< "...\n"
|
|
<< "Omitted " << (printCount-printFloodLimit) << " error descriptions."
|
|
<< tcu::TestLog::EndMessage;
|
|
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message << "Image verification failed." << tcu::TestLog::EndMessage
|
|
<< tcu::TestLog::ImageSet("Verification", "Image Verification")
|
|
<< tcu::TestLog::Image("ErrorMask", "Error Mask", errorMask.getAccess())
|
|
<< tcu::TestLog::EndImageSet;
|
|
}
|
|
}
|
|
}
|
|
|
|
// results
|
|
if (!allOk)
|
|
return false;
|
|
else if (distibutionError)
|
|
throw MultisampleShaderRenderUtil::QualityWarning("Bias detected, sample positions are not uniformly distributed within the pixel");
|
|
else
|
|
{
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Verification ok." << tcu::TestLog::EndMessage;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
class SamplePosCorrectnessCase : public MultisampleRenderCase
|
|
{
|
|
public:
|
|
SamplePosCorrectnessCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target);
|
|
~SamplePosCorrectnessCase (void);
|
|
|
|
void init (void);
|
|
private:
|
|
enum
|
|
{
|
|
RENDER_SIZE = 32
|
|
};
|
|
|
|
void preDraw (void);
|
|
void postDraw (void);
|
|
|
|
std::string genVertexSource (int numTargetSamples) const;
|
|
std::string genFragmentSource (int numTargetSamples) const;
|
|
bool verifyImage (const tcu::Surface& resultImage);
|
|
|
|
bool m_useSampleQualifier;
|
|
};
|
|
|
|
SamplePosCorrectnessCase::SamplePosCorrectnessCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target)
|
|
: MultisampleRenderCase (context, name, desc, sampleCount, target, RENDER_SIZE)
|
|
, m_useSampleQualifier (false)
|
|
{
|
|
}
|
|
|
|
SamplePosCorrectnessCase::~SamplePosCorrectnessCase (void)
|
|
{
|
|
}
|
|
|
|
void SamplePosCorrectnessCase::init (void)
|
|
{
|
|
auto ctxType = m_context.getRenderContext().getType();
|
|
const bool isES32orGL45 = glu::contextSupports(ctxType, glu::ApiType::es(3, 2)) ||
|
|
glu::contextSupports(ctxType, glu::ApiType::core(4, 5));
|
|
|
|
// requirements: per-invocation interpolation required
|
|
if (!isES32orGL45 && !m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation") &&
|
|
!m_context.getContextInfo().isExtensionSupported("GL_OES_sample_shading"))
|
|
TCU_THROW(NotSupportedError, "Test requires GL_OES_shader_multisample_interpolation or GL_OES_sample_shading extension or a context version 3.2 or higher.");
|
|
|
|
// prefer to use the sample qualifier path
|
|
m_useSampleQualifier = m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation");
|
|
|
|
// log the test method and expectations
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message
|
|
<< "Verifying gl_SamplePosition correctness:\n"
|
|
<< " 1) Varying values should be sampled at the sample position.\n"
|
|
<< " => fract(screenSpacePosition) == gl_SamplePosition\n"
|
|
<< tcu::TestLog::EndMessage;
|
|
|
|
MultisampleRenderCase::init();
|
|
}
|
|
|
|
void SamplePosCorrectnessCase::preDraw (void)
|
|
{
|
|
if (!m_useSampleQualifier)
|
|
{
|
|
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
|
|
|
|
// use GL_OES_sample_shading to set per fragment sample invocation interpolation
|
|
gl.enable(GL_SAMPLE_SHADING);
|
|
gl.minSampleShading(1.0f);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "set ratio");
|
|
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Enabling per-sample interpolation with GL_SAMPLE_SHADING." << tcu::TestLog::EndMessage;
|
|
}
|
|
}
|
|
|
|
void SamplePosCorrectnessCase::postDraw (void)
|
|
{
|
|
if (!m_useSampleQualifier)
|
|
{
|
|
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
|
|
|
|
gl.disable(GL_SAMPLE_SHADING);
|
|
gl.minSampleShading(1.0f);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "set ratio");
|
|
}
|
|
}
|
|
|
|
std::string SamplePosCorrectnessCase::genVertexSource (int numTargetSamples) const
|
|
{
|
|
DE_UNREF(numTargetSamples);
|
|
|
|
auto ctxType = m_context.getRenderContext().getType();
|
|
const bool isES32 = glu::contextSupports(ctxType, glu::ApiType::es(3, 2));
|
|
const bool isGL45 = glu::contextSupports(ctxType, glu::ApiType::core(4, 5));
|
|
|
|
std::ostringstream buf;
|
|
map<string, string> args;
|
|
args["GLSL_VERSION_DECL"] = isES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
|
|
args["GLSL_EXTENSION"] = (isES32 || isGL45) ? "" : m_useSampleQualifier ? "#extension GL_OES_shader_multisample_interpolation : require" : "";
|
|
|
|
buf << "${GLSL_VERSION_DECL}\n"
|
|
"${GLSL_EXTENSION}\n"
|
|
<< "in highp vec4 a_position;\n"
|
|
<< ((m_useSampleQualifier) ? ("sample ") : ("")) << "out highp vec4 v_position;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" gl_Position = a_position;\n"
|
|
" v_position = a_position;\n"
|
|
"}\n";
|
|
|
|
return tcu::StringTemplate(buf.str()).specialize(args);
|
|
}
|
|
|
|
std::string SamplePosCorrectnessCase::genFragmentSource (int numTargetSamples) const
|
|
{
|
|
DE_UNREF(numTargetSamples);
|
|
|
|
std::ostringstream buf;
|
|
const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
|
|
map<string, string> args;
|
|
args["GLSL_VERSION_DECL"] = supportsES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
|
|
args["GLSL_SAMPLE_EXTENSION"] = supportsES32 ? "" : "#extension GL_OES_sample_variables : require";
|
|
args["GLSL_MULTISAMPLE_EXTENSION"] = supportsES32 ? "" : m_useSampleQualifier ? "#extension GL_OES_shader_multisample_interpolation : require" : "";
|
|
|
|
// encode the position to the output, use red channel as error channel
|
|
buf << "${GLSL_VERSION_DECL}\n"
|
|
"${GLSL_SAMPLE_EXTENSION}\n"
|
|
"${GLSL_MULTISAMPLE_EXTENSION}\n"
|
|
<< ((m_useSampleQualifier) ? ("sample ") : ("")) << "in highp vec4 v_position;\n"
|
|
"layout(location = 0) out mediump vec4 fragColor;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" const highp float maxDistance = 0.15625; // 4 subpixel bits. Assume 3 accurate bits + 0.03125 for other errors\n" // 0.03125 = mediump epsilon when value = 32 (RENDER_SIZE)
|
|
"\n"
|
|
" highp vec2 screenSpacePosition = (v_position.xy + vec2(1.0, 1.0)) / 2.0 * " << (int)RENDER_SIZE << ".0;\n"
|
|
" highp ivec2 nearbyPixel = ivec2(floor(screenSpacePosition));\n"
|
|
" bool allOk = false;\n"
|
|
"\n"
|
|
" // sample at edge + inaccuaries may cause us to round to any neighboring pixel\n"
|
|
" // check all neighbors for any match\n"
|
|
" for (highp int dy = -1; dy <= 1; ++dy)\n"
|
|
" for (highp int dx = -1; dx <= 1; ++dx)\n"
|
|
" {\n"
|
|
" highp ivec2 currentPixel = nearbyPixel + ivec2(dx, dy);\n"
|
|
" highp vec2 candidateSamplingPos = vec2(currentPixel) + gl_SamplePosition.xy;\n"
|
|
" highp vec2 positionDiff = abs(candidateSamplingPos - screenSpacePosition);\n"
|
|
" if (positionDiff.x < maxDistance && positionDiff.y < maxDistance)\n"
|
|
" allOk = true;\n"
|
|
" }\n"
|
|
"\n"
|
|
" if (allOk)\n"
|
|
" fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
|
|
" else\n"
|
|
" fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
|
|
"}\n";
|
|
|
|
return tcu::StringTemplate(buf.str()).specialize(args);
|
|
}
|
|
|
|
bool SamplePosCorrectnessCase::verifyImage (const tcu::Surface& resultImage)
|
|
{
|
|
return verifyImageWithVerifier(resultImage, m_testCtx.getLog(), NoRedVerifier());
|
|
}
|
|
|
|
class SampleMaskBaseCase : public MultisampleRenderCase
|
|
{
|
|
public:
|
|
enum ShaderRunMode
|
|
{
|
|
RUN_PER_PIXEL = 0,
|
|
RUN_PER_SAMPLE,
|
|
RUN_PER_TWO_SAMPLES,
|
|
|
|
RUN_LAST
|
|
};
|
|
|
|
SampleMaskBaseCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target, int renderSize, ShaderRunMode runMode, int flags = 0);
|
|
virtual ~SampleMaskBaseCase (void);
|
|
|
|
protected:
|
|
virtual void init (void);
|
|
virtual void preDraw (void);
|
|
virtual void postDraw (void);
|
|
virtual bool verifyImage (const tcu::Surface& resultImage);
|
|
|
|
const ShaderRunMode m_runMode;
|
|
};
|
|
|
|
SampleMaskBaseCase::SampleMaskBaseCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target, int renderSize, ShaderRunMode runMode, int flags)
|
|
: MultisampleRenderCase (context, name, desc, sampleCount, target, renderSize, flags)
|
|
, m_runMode (runMode)
|
|
{
|
|
DE_ASSERT(runMode < RUN_LAST);
|
|
}
|
|
|
|
SampleMaskBaseCase::~SampleMaskBaseCase (void)
|
|
{
|
|
}
|
|
|
|
void SampleMaskBaseCase::init (void)
|
|
{
|
|
const bool supportsES32orGL45 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
|
|
contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
|
|
// required extra extension
|
|
if (m_runMode == RUN_PER_TWO_SAMPLES && !supportsES32orGL45 && !m_context.getContextInfo().isExtensionSupported("GL_OES_sample_shading"))
|
|
TCU_THROW(NotSupportedError, "Test requires GL_OES_sample_shading extension or a context version 3.2 or higher.");
|
|
|
|
MultisampleRenderCase::init();
|
|
}
|
|
|
|
void SampleMaskBaseCase::preDraw (void)
|
|
{
|
|
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
|
|
|
|
if (m_runMode == RUN_PER_TWO_SAMPLES)
|
|
{
|
|
gl.enable(GL_SAMPLE_SHADING);
|
|
gl.minSampleShading(0.5f);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "enable sample shading");
|
|
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Enabled GL_SAMPLE_SHADING, value = 0.5" << tcu::TestLog::EndMessage;
|
|
}
|
|
}
|
|
|
|
void SampleMaskBaseCase::postDraw (void)
|
|
{
|
|
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
|
|
|
|
if (m_runMode == RUN_PER_TWO_SAMPLES)
|
|
{
|
|
gl.disable(GL_SAMPLE_SHADING);
|
|
gl.minSampleShading(1.0f);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "disable sample shading");
|
|
}
|
|
}
|
|
|
|
bool SampleMaskBaseCase::verifyImage (const tcu::Surface& resultImage)
|
|
{
|
|
// shader does the verification
|
|
return verifyImageWithVerifier(resultImage, m_testCtx.getLog(), NoRedVerifier());
|
|
}
|
|
|
|
class SampleMaskCase : public SampleMaskBaseCase
|
|
{
|
|
public:
|
|
SampleMaskCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target);
|
|
~SampleMaskCase (void);
|
|
|
|
void init (void);
|
|
void preDraw (void);
|
|
void postDraw (void);
|
|
|
|
private:
|
|
enum
|
|
{
|
|
RENDER_SIZE = 64
|
|
};
|
|
|
|
std::string genFragmentSource (int numTargetSamples) const;
|
|
};
|
|
|
|
SampleMaskCase::SampleMaskCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target)
|
|
: SampleMaskBaseCase(context, name, desc, sampleCount, target, RENDER_SIZE, RUN_PER_PIXEL)
|
|
{
|
|
}
|
|
|
|
SampleMaskCase::~SampleMaskCase (void)
|
|
{
|
|
}
|
|
|
|
void SampleMaskCase::init (void)
|
|
{
|
|
// log the test method and expectations
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message
|
|
<< "Verifying gl_SampleMaskIn value with SAMPLE_MASK state. gl_SampleMaskIn does not contain any bits set that are have been killed by SAMPLE_MASK state. Expecting:\n"
|
|
<< " 1) With multisample targets: gl_SampleMaskIn AND ~(SAMPLE_MASK) should be zero.\n"
|
|
<< " 2) With non-multisample targets: SAMPLE_MASK state is only ANDed as a multisample operation. gl_SampleMaskIn should only have its last bit set regardless of SAMPLE_MASK state.\n"
|
|
<< tcu::TestLog::EndMessage;
|
|
|
|
SampleMaskBaseCase::init();
|
|
}
|
|
|
|
void SampleMaskCase::preDraw (void)
|
|
{
|
|
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
|
|
const bool multisampleTarget = (m_numRequestedSamples > 0) || (m_renderTarget == TARGET_DEFAULT && m_context.getRenderTarget().getNumSamples() > 1);
|
|
const deUint32 fullMask = (deUint32)0xAAAAAAAAUL;
|
|
const deUint32 maskMask = (1U << m_numTargetSamples) - 1;
|
|
const deUint32 effectiveMask = fullMask & maskMask;
|
|
|
|
// set test mask
|
|
gl.enable(GL_SAMPLE_MASK);
|
|
gl.sampleMaski(0, effectiveMask);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "set mask");
|
|
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Setting sample mask " << tcu::Format::Hex<4>(effectiveMask) << tcu::TestLog::EndMessage;
|
|
|
|
// set multisample case uniforms
|
|
if (multisampleTarget)
|
|
{
|
|
const int maskLoc = gl.getUniformLocation(m_program->getProgram(), "u_sampleMask");
|
|
if (maskLoc == -1)
|
|
throw tcu::TestError("Location of u_mask was -1");
|
|
|
|
gl.uniform1ui(maskLoc, effectiveMask);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "set mask uniform");
|
|
}
|
|
|
|
// base class logic
|
|
SampleMaskBaseCase::preDraw();
|
|
}
|
|
|
|
void SampleMaskCase::postDraw (void)
|
|
{
|
|
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
|
|
const deUint32 fullMask = (1U << m_numTargetSamples) - 1;
|
|
|
|
gl.disable(GL_SAMPLE_MASK);
|
|
gl.sampleMaski(0, fullMask);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "set mask");
|
|
|
|
// base class logic
|
|
SampleMaskBaseCase::postDraw();
|
|
}
|
|
|
|
std::string SampleMaskCase::genFragmentSource (int numTargetSamples) const
|
|
{
|
|
DE_ASSERT(numTargetSamples != 0);
|
|
|
|
const bool multisampleTarget = (m_numRequestedSamples > 0) || (m_renderTarget == TARGET_DEFAULT && m_context.getRenderTarget().getNumSamples() > 1);
|
|
std::ostringstream buf;
|
|
const bool supportsES32orGL45 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
|
|
contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
|
|
map<string, string> args;
|
|
args["GLSL_VERSION_DECL"] = supportsES32orGL45 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
|
|
args["GLSL_EXTENSION"] = supportsES32orGL45 ? "" : "#extension GL_OES_sample_variables : require";
|
|
|
|
// test supports only one sample mask word
|
|
if (numTargetSamples > 32)
|
|
TCU_THROW(NotSupportedError, "Sample count larger than 32 is not supported.");
|
|
|
|
if (multisampleTarget)
|
|
{
|
|
buf << "${GLSL_VERSION_DECL}\n"
|
|
"${GLSL_EXTENSION}\n"
|
|
"layout(location = 0) out mediump vec4 fragColor;\n"
|
|
"uniform highp uint u_sampleMask;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" if ((uint(gl_SampleMaskIn[0]) & (~u_sampleMask)) != 0u)\n"
|
|
" fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
|
|
" else\n"
|
|
" fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
|
|
"}\n";
|
|
}
|
|
else
|
|
{
|
|
// non-multisample targets don't get multisample operations like ANDing with mask
|
|
|
|
buf << "${GLSL_VERSION_DECL}\n"
|
|
"${GLSL_EXTENSION}\n"
|
|
"layout(location = 0) out mediump vec4 fragColor;\n"
|
|
"uniform highp uint u_sampleMask;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" if (gl_SampleMaskIn[0] != 1)\n"
|
|
" fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
|
|
" else\n"
|
|
" fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
|
|
"}\n";
|
|
}
|
|
|
|
return tcu::StringTemplate(buf.str()).specialize(args);
|
|
}
|
|
|
|
class SampleMaskCountCase : public SampleMaskBaseCase
|
|
{
|
|
public:
|
|
SampleMaskCountCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target, ShaderRunMode runMode);
|
|
~SampleMaskCountCase (void);
|
|
|
|
void init (void);
|
|
void preDraw (void);
|
|
void postDraw (void);
|
|
|
|
private:
|
|
enum
|
|
{
|
|
RENDER_SIZE = 64
|
|
};
|
|
|
|
std::string genFragmentSource (int numTargetSamples) const;
|
|
};
|
|
|
|
SampleMaskCountCase::SampleMaskCountCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target, ShaderRunMode runMode)
|
|
: SampleMaskBaseCase(context, name, desc, sampleCount, target, RENDER_SIZE, runMode)
|
|
{
|
|
DE_ASSERT(runMode < RUN_LAST);
|
|
}
|
|
|
|
SampleMaskCountCase::~SampleMaskCountCase (void)
|
|
{
|
|
}
|
|
|
|
void SampleMaskCountCase::init (void)
|
|
{
|
|
// log the test method and expectations
|
|
if (m_runMode == RUN_PER_PIXEL)
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message
|
|
<< "Verifying gl_SampleMaskIn.\n"
|
|
<< " Fragment shader may be invoked [1, numSamples] times.\n"
|
|
<< " => gl_SampleMaskIn should have the number of bits set in range [1, numSamples]\n"
|
|
<< tcu::TestLog::EndMessage;
|
|
else if (m_runMode == RUN_PER_SAMPLE)
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message
|
|
<< "Verifying gl_SampleMaskIn.\n"
|
|
<< " Fragment will be invoked numSamples times.\n"
|
|
<< " => gl_SampleMaskIn should have only one bit set.\n"
|
|
<< tcu::TestLog::EndMessage;
|
|
else if (m_runMode == RUN_PER_TWO_SAMPLES)
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message
|
|
<< "Verifying gl_SampleMaskIn.\n"
|
|
<< " Fragment shader may be invoked [ceil(numSamples/2), numSamples] times.\n"
|
|
<< " => gl_SampleMaskIn should have the number of bits set in range [1, numSamples - ceil(numSamples/2) + 1]:\n"
|
|
<< tcu::TestLog::EndMessage;
|
|
else
|
|
DE_ASSERT(false);
|
|
|
|
SampleMaskBaseCase::init();
|
|
}
|
|
|
|
void SampleMaskCountCase::preDraw (void)
|
|
{
|
|
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
|
|
|
|
if (m_runMode == RUN_PER_PIXEL)
|
|
{
|
|
const int maxLoc = gl.getUniformLocation(m_program->getProgram(), "u_maxBitCount");
|
|
const int minLoc = gl.getUniformLocation(m_program->getProgram(), "u_minBitCount");
|
|
const int minBitCount = 1;
|
|
const int maxBitCount = m_numTargetSamples;
|
|
|
|
if (maxLoc == -1)
|
|
throw tcu::TestError("Location of u_maxBitCount was -1");
|
|
if (minLoc == -1)
|
|
throw tcu::TestError("Location of u_minBitCount was -1");
|
|
|
|
gl.uniform1i(minLoc, minBitCount);
|
|
gl.uniform1i(maxLoc, maxBitCount);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "set limits");
|
|
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Setting minBitCount = " << minBitCount << ", maxBitCount = " << maxBitCount << tcu::TestLog::EndMessage;
|
|
}
|
|
else if (m_runMode == RUN_PER_TWO_SAMPLES)
|
|
{
|
|
const int maxLoc = gl.getUniformLocation(m_program->getProgram(), "u_maxBitCount");
|
|
const int minLoc = gl.getUniformLocation(m_program->getProgram(), "u_minBitCount");
|
|
|
|
// Worst case: all but one shader invocations get one sample, one shader invocation the rest of the samples
|
|
const int minInvocationCount = ((m_numTargetSamples + 1) / 2);
|
|
const int minBitCount = 1;
|
|
const int maxBitCount = m_numTargetSamples - ((minInvocationCount-1) * minBitCount);
|
|
|
|
if (maxLoc == -1)
|
|
throw tcu::TestError("Location of u_maxBitCount was -1");
|
|
if (minLoc == -1)
|
|
throw tcu::TestError("Location of u_minBitCount was -1");
|
|
|
|
gl.uniform1i(minLoc, minBitCount);
|
|
gl.uniform1i(maxLoc, maxBitCount);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "set limits");
|
|
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Setting minBitCount = " << minBitCount << ", maxBitCount = " << maxBitCount << tcu::TestLog::EndMessage;
|
|
}
|
|
|
|
SampleMaskBaseCase::preDraw();
|
|
}
|
|
|
|
void SampleMaskCountCase::postDraw (void)
|
|
{
|
|
SampleMaskBaseCase::postDraw();
|
|
}
|
|
|
|
std::string SampleMaskCountCase::genFragmentSource (int numTargetSamples) const
|
|
{
|
|
DE_ASSERT(numTargetSamples != 0);
|
|
|
|
std::ostringstream buf;
|
|
const bool supportsES32orGL45 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
|
|
contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
|
|
map<string, string> args;
|
|
args["GLSL_VERSION_DECL"] = supportsES32orGL45 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
|
|
args["GLSL_EXTENSION"] = supportsES32orGL45 ? "" : "#extension GL_OES_sample_variables : require";
|
|
|
|
// test supports only one sample mask word
|
|
if (numTargetSamples > 32)
|
|
TCU_THROW(NotSupportedError, "Sample count larger than 32 is not supported.");
|
|
|
|
// count the number of the bits in gl_SampleMask
|
|
|
|
buf << "${GLSL_VERSION_DECL}\n"
|
|
"${GLSL_EXTENSION}\n"
|
|
"layout(location = 0) out mediump vec4 fragColor;\n";
|
|
|
|
if (m_runMode != RUN_PER_SAMPLE)
|
|
buf << "uniform highp int u_minBitCount;\n"
|
|
"uniform highp int u_maxBitCount;\n";
|
|
|
|
buf << "void main (void)\n"
|
|
"{\n"
|
|
" mediump int maskBitCount = 0;\n"
|
|
" for (int i = 0; i < 32; ++i)\n"
|
|
" if (((gl_SampleMaskIn[0] >> i) & 0x01) == 0x01)\n"
|
|
" ++maskBitCount;\n"
|
|
"\n";
|
|
|
|
if (m_runMode == RUN_PER_SAMPLE)
|
|
{
|
|
// check the validity here
|
|
buf << " // force per-sample shading\n"
|
|
" highp float blue = float(gl_SampleID);\n"
|
|
"\n"
|
|
" if (maskBitCount != 1)\n"
|
|
" fragColor = vec4(1.0, 0.0, blue, 1.0);\n"
|
|
" else\n"
|
|
" fragColor = vec4(0.0, 1.0, blue, 1.0);\n"
|
|
"}\n";
|
|
}
|
|
else
|
|
{
|
|
// check the validity here
|
|
buf << " if (maskBitCount < u_minBitCount || maskBitCount > u_maxBitCount)\n"
|
|
" fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
|
|
" else\n"
|
|
" fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
|
|
"}\n";
|
|
}
|
|
|
|
return tcu::StringTemplate(buf.str()).specialize(args);
|
|
}
|
|
|
|
class SampleMaskUniqueCase : public SampleMaskBaseCase
|
|
{
|
|
public:
|
|
SampleMaskUniqueCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target, ShaderRunMode runMode);
|
|
~SampleMaskUniqueCase (void);
|
|
|
|
void init (void);
|
|
|
|
private:
|
|
enum
|
|
{
|
|
RENDER_SIZE = 64
|
|
};
|
|
|
|
std::string genFragmentSource (int numTargetSamples) const;
|
|
bool verifySampleBuffers (const std::vector<tcu::Surface>& resultBuffers);
|
|
};
|
|
|
|
SampleMaskUniqueCase::SampleMaskUniqueCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target, ShaderRunMode runMode)
|
|
: SampleMaskBaseCase(context, name, desc, sampleCount, target, RENDER_SIZE, runMode, MultisampleShaderRenderUtil::MultisampleRenderCase::FLAG_VERIFY_MSAA_TEXTURE_SAMPLE_BUFFERS)
|
|
{
|
|
DE_ASSERT(runMode == RUN_PER_SAMPLE);
|
|
DE_ASSERT(target == TARGET_TEXTURE);
|
|
}
|
|
|
|
SampleMaskUniqueCase::~SampleMaskUniqueCase (void)
|
|
{
|
|
}
|
|
|
|
void SampleMaskUniqueCase::init (void)
|
|
{
|
|
// log the test method and expectations
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message
|
|
<< "Verifying gl_SampleMaskIn.\n"
|
|
<< " Fragment will be invoked numSamples times.\n"
|
|
<< " => gl_SampleMaskIn should have only one bit set\n"
|
|
<< " => and that bit index should be unique within other fragment shader invocations of that pixel.\n"
|
|
<< " Writing sampleMask bit index to green channel in render shader. Verifying uniqueness in sampler shader.\n"
|
|
<< tcu::TestLog::EndMessage;
|
|
|
|
SampleMaskBaseCase::init();
|
|
}
|
|
|
|
std::string SampleMaskUniqueCase::genFragmentSource (int numTargetSamples) const
|
|
{
|
|
DE_ASSERT(numTargetSamples != 0);
|
|
|
|
std::ostringstream buf;
|
|
const bool supportsES32orGL45 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
|
|
contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
|
|
map<string, string> args;
|
|
args["GLSL_VERSION_DECL"] = supportsES32orGL45 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
|
|
args["GLSL_EXTENSION"] = supportsES32orGL45 ? "" : "#extension GL_OES_sample_variables : require";
|
|
|
|
// test supports only one sample mask word
|
|
if (numTargetSamples > 32)
|
|
TCU_THROW(NotSupportedError, "Sample count larger than 32 is not supported.");
|
|
|
|
// find our sampleID by searching for unique bit.
|
|
buf << "${GLSL_VERSION_DECL}\n"
|
|
"${GLSL_EXTENSION}\n"
|
|
"layout(location = 0) out mediump vec4 fragColor;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" mediump int firstIndex = -1;\n"
|
|
" for (int i = 0; i < 32; ++i)\n"
|
|
" {\n"
|
|
" if (((gl_SampleMaskIn[0] >> i) & 0x01) == 0x01)\n"
|
|
" {\n"
|
|
" firstIndex = i;\n"
|
|
" break;\n"
|
|
" }\n"
|
|
" }\n"
|
|
"\n"
|
|
" bool notUniqueError = false;\n"
|
|
" for (int i = firstIndex + 1; i < 32; ++i)\n"
|
|
" if (((gl_SampleMaskIn[0] >> i) & 0x01) == 0x01)\n"
|
|
" notUniqueError = true;\n"
|
|
"\n"
|
|
" highp float encodedSampleId = float(firstIndex) / " << numTargetSamples <<".0;\n"
|
|
"\n"
|
|
" // force per-sample shading\n"
|
|
" highp float blue = float(gl_SampleID);\n"
|
|
"\n"
|
|
" if (notUniqueError)\n"
|
|
" fragColor = vec4(1.0, 0.0, blue, 1.0);\n"
|
|
" else\n"
|
|
" fragColor = vec4(0.0, encodedSampleId, blue, 1.0);\n"
|
|
"}\n";
|
|
|
|
return tcu::StringTemplate(buf.str()).specialize(args);
|
|
}
|
|
|
|
bool SampleMaskUniqueCase::verifySampleBuffers (const std::vector<tcu::Surface>& resultBuffers)
|
|
{
|
|
const int width = resultBuffers[0].getWidth();
|
|
const int height = resultBuffers[0].getHeight();
|
|
bool allOk = true;
|
|
|
|
// Log samples
|
|
{
|
|
m_testCtx.getLog() << tcu::TestLog::ImageSet("SampleBuffers", "Image sample buffers");
|
|
for (int sampleNdx = 0; sampleNdx < (int)resultBuffers.size(); ++sampleNdx)
|
|
m_testCtx.getLog() << tcu::TestLog::Image("Buffer" + de::toString(sampleNdx), "Sample " + de::toString(sampleNdx), resultBuffers[sampleNdx].getAccess());
|
|
m_testCtx.getLog() << tcu::TestLog::EndImageSet;
|
|
}
|
|
|
|
// check for earlier errors (in fragment shader)
|
|
{
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Verifying fragment shader invocation found only one set sample mask bit." << tcu::TestLog::EndMessage;
|
|
|
|
for (int sampleNdx = 0; sampleNdx < (int)resultBuffers.size(); ++sampleNdx)
|
|
{
|
|
// shader does the check, just check the shader error output (red)
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Verifying sample " << (sampleNdx+1) << "/" << (int)resultBuffers.size() << tcu::TestLog::EndMessage;
|
|
allOk &= verifyImageWithVerifier(resultBuffers[sampleNdx], m_testCtx.getLog(), NoRedVerifier(), false);
|
|
}
|
|
|
|
if (!allOk)
|
|
{
|
|
// can't check the uniqueness if the masks don't work at all
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Could not get mask information from the rendered image, cannot continue verification." << tcu::TestLog::EndMessage;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// verify index / index ranges
|
|
|
|
if (m_numRequestedSamples == 0)
|
|
{
|
|
// single sample target, expect index=0
|
|
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Verifying sample mask bit index is 0." << tcu::TestLog::EndMessage;
|
|
|
|
// only check the mask index
|
|
allOk &= verifyImageWithVerifier(resultBuffers[0], m_testCtx.getLog(), ColorVerifier(tcu::Vec3(0.0f, 0.0f, 0.0f), tcu::IVec3(255, 8, 255)), false);
|
|
}
|
|
else
|
|
{
|
|
// check uniqueness
|
|
|
|
tcu::Surface errorMask (width, height);
|
|
bool uniquenessOk = true;
|
|
int printCount = 0;
|
|
const int printFloodLimit = 5;
|
|
std::vector<int> maskBitIndices (resultBuffers.size());
|
|
|
|
tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
|
|
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Verifying per-invocation sample mask bit is unique." << tcu::TestLog::EndMessage;
|
|
|
|
for (int y = 0; y < height; ++y)
|
|
for (int x = 0; x < width; ++x)
|
|
{
|
|
bool maskNdxNotUnique = false;
|
|
|
|
// decode index
|
|
for (int sampleNdx = 0; sampleNdx < (int)resultBuffers.size(); ++sampleNdx)
|
|
{
|
|
const tcu::RGBA color = resultBuffers[sampleNdx].getPixel(x, y);
|
|
maskBitIndices[sampleNdx] = (int)deFloatRound((float)color.getGreen() / 255.0f * (float)m_numTargetSamples);
|
|
}
|
|
|
|
// just check there are no two invocations with the same bit index
|
|
for (int sampleNdxA = 0; sampleNdxA < (int)resultBuffers.size() && (!maskNdxNotUnique || printCount < printFloodLimit); ++sampleNdxA)
|
|
for (int sampleNdxB = sampleNdxA+1; sampleNdxB < (int)resultBuffers.size() && (!maskNdxNotUnique || printCount < printFloodLimit); ++sampleNdxB)
|
|
{
|
|
if (maskBitIndices[sampleNdxA] == maskBitIndices[sampleNdxB])
|
|
{
|
|
if (++printCount <= printFloodLimit)
|
|
{
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message
|
|
<< "Pixel (" << x << ", " << y << "): Samples " << sampleNdxA << " and " << sampleNdxB << " have the same sample mask. (Single bit at index " << maskBitIndices[sampleNdxA] << ")"
|
|
<< tcu::TestLog::EndMessage;
|
|
}
|
|
|
|
maskNdxNotUnique = true;
|
|
uniquenessOk = false;
|
|
errorMask.setPixel(x, y, tcu::RGBA::red());
|
|
}
|
|
}
|
|
}
|
|
|
|
// end result
|
|
if (!uniquenessOk)
|
|
{
|
|
if (printCount > printFloodLimit)
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message
|
|
<< "...\n"
|
|
<< "Omitted " << (printCount-printFloodLimit) << " error descriptions."
|
|
<< tcu::TestLog::EndMessage;
|
|
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message << "Image verification failed." << tcu::TestLog::EndMessage
|
|
<< tcu::TestLog::ImageSet("Verification", "Image Verification")
|
|
<< tcu::TestLog::Image("ErrorMask", "Error Mask", errorMask.getAccess())
|
|
<< tcu::TestLog::EndImageSet;
|
|
|
|
allOk = false;
|
|
}
|
|
}
|
|
|
|
return allOk;
|
|
}
|
|
|
|
class SampleMaskUniqueSetCase : public SampleMaskBaseCase
|
|
{
|
|
public:
|
|
SampleMaskUniqueSetCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target, ShaderRunMode runMode);
|
|
~SampleMaskUniqueSetCase (void);
|
|
|
|
void init (void);
|
|
void deinit (void);
|
|
|
|
private:
|
|
enum
|
|
{
|
|
RENDER_SIZE = 64
|
|
};
|
|
|
|
void preDraw (void);
|
|
void postDraw (void);
|
|
std::string genFragmentSource (int numTargetSamples) const;
|
|
bool verifySampleBuffers (const std::vector<tcu::Surface>& resultBuffers);
|
|
std::string getIterationDescription (int iteration) const;
|
|
|
|
void preTest (void);
|
|
void postTest (void);
|
|
|
|
std::vector<tcu::Surface> m_iterationSampleBuffers;
|
|
};
|
|
|
|
SampleMaskUniqueSetCase::SampleMaskUniqueSetCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target, ShaderRunMode runMode)
|
|
: SampleMaskBaseCase(context, name, desc, sampleCount, target, RENDER_SIZE, runMode, MultisampleShaderRenderUtil::MultisampleRenderCase::FLAG_VERIFY_MSAA_TEXTURE_SAMPLE_BUFFERS)
|
|
{
|
|
DE_ASSERT(runMode == RUN_PER_TWO_SAMPLES);
|
|
DE_ASSERT(target == TARGET_TEXTURE);
|
|
|
|
// high and low bits
|
|
m_numIterations = 2;
|
|
}
|
|
|
|
SampleMaskUniqueSetCase::~SampleMaskUniqueSetCase (void)
|
|
{
|
|
}
|
|
|
|
void SampleMaskUniqueSetCase::init (void)
|
|
{
|
|
// log the test method and expectations
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message
|
|
<< "Verifying gl_SampleMaskIn.\n"
|
|
<< " Fragment shader may be invoked [ceil(numSamples/2), numSamples] times.\n"
|
|
<< " => Each invocation should have unique bit set\n"
|
|
<< " Writing highest and lowest bit index to color channels in render shader. Verifying:\n"
|
|
<< " 1) no other invocation contains these bits in sampler shader.\n"
|
|
<< " 2) number of invocations is at least ceil(numSamples/2).\n"
|
|
<< tcu::TestLog::EndMessage;
|
|
|
|
SampleMaskBaseCase::init();
|
|
}
|
|
|
|
void SampleMaskUniqueSetCase::deinit (void)
|
|
{
|
|
m_iterationSampleBuffers.clear();
|
|
}
|
|
|
|
void SampleMaskUniqueSetCase::preDraw (void)
|
|
{
|
|
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
|
|
const int selectorLoc = gl.getUniformLocation(m_program->getProgram(), "u_bitSelector");
|
|
|
|
gl.uniform1ui(selectorLoc, (deUint32)m_iteration);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "set u_bitSelector");
|
|
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Setting u_bitSelector = " << m_iteration << tcu::TestLog::EndMessage;
|
|
|
|
SampleMaskBaseCase::preDraw();
|
|
}
|
|
|
|
void SampleMaskUniqueSetCase::postDraw (void)
|
|
{
|
|
SampleMaskBaseCase::postDraw();
|
|
}
|
|
|
|
std::string SampleMaskUniqueSetCase::genFragmentSource (int numTargetSamples) const
|
|
{
|
|
DE_ASSERT(numTargetSamples != 0);
|
|
|
|
std::ostringstream buf;
|
|
const bool supportsES32orGL45 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
|
|
contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
|
|
map<string, string> args;
|
|
args["GLSL_VERSION_DECL"] = supportsES32orGL45 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
|
|
args["GLSL_EXTENSION"] = supportsES32orGL45 ? "" : "#extension GL_OES_sample_variables : require";
|
|
|
|
// test supports only one sample mask word
|
|
if (numTargetSamples > 32)
|
|
TCU_THROW(NotSupportedError, "Sample count larger than 32 is not supported.");
|
|
|
|
// output min and max sample id
|
|
buf << "${GLSL_VERSION_DECL}\n"
|
|
"${GLSL_EXTENSION}\n"
|
|
"uniform highp uint u_bitSelector;\n"
|
|
"layout(location = 0) out mediump vec4 fragColor;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" highp int selectedBits;\n"
|
|
" if (u_bitSelector == 0u)\n"
|
|
" selectedBits = (gl_SampleMaskIn[0] & 0xFFFF);\n"
|
|
" else\n"
|
|
" selectedBits = ((gl_SampleMaskIn[0] >> 16) & 0xFFFF);\n"
|
|
"\n"
|
|
" // encode bits to color\n"
|
|
" highp int redBits = selectedBits & 31;\n"
|
|
" highp int greenBits = (selectedBits >> 5) & 63;\n"
|
|
" highp int blueBits = (selectedBits >> 11) & 31;\n"
|
|
"\n"
|
|
" fragColor = vec4(float(redBits) / float(31), float(greenBits) / float(63), float(blueBits) / float(31), 1.0);\n"
|
|
"}\n";
|
|
|
|
return tcu::StringTemplate(buf.str()).specialize(args);
|
|
}
|
|
|
|
bool SampleMaskUniqueSetCase::verifySampleBuffers (const std::vector<tcu::Surface>& resultBuffers)
|
|
{
|
|
// we need results from all passes to do verification. Store results and verify later (at postTest).
|
|
|
|
DE_ASSERT(m_numTargetSamples == (int)resultBuffers.size());
|
|
for (int ndx = 0; ndx < m_numTargetSamples; ++ndx)
|
|
m_iterationSampleBuffers[m_iteration * m_numTargetSamples + ndx] = resultBuffers[ndx];
|
|
|
|
return true;
|
|
}
|
|
|
|
std::string SampleMaskUniqueSetCase::getIterationDescription (int iteration) const
|
|
{
|
|
if (iteration == 0)
|
|
return "Reading low bits";
|
|
else if (iteration == 1)
|
|
return "Reading high bits";
|
|
else
|
|
DE_ASSERT(false);
|
|
return "";
|
|
}
|
|
|
|
void SampleMaskUniqueSetCase::preTest (void)
|
|
{
|
|
m_iterationSampleBuffers.resize(m_numTargetSamples * 2);
|
|
}
|
|
|
|
void SampleMaskUniqueSetCase::postTest (void)
|
|
{
|
|
DE_ASSERT((m_iterationSampleBuffers.size() % 2) == 0);
|
|
DE_ASSERT((int)m_iterationSampleBuffers.size() / 2 == m_numTargetSamples);
|
|
|
|
const int width = m_iterationSampleBuffers[0].getWidth();
|
|
const int height = m_iterationSampleBuffers[0].getHeight();
|
|
bool allOk = true;
|
|
std::vector<tcu::TextureLevel> sampleCoverage (m_numTargetSamples);
|
|
const tcu::ScopedLogSection section (m_testCtx.getLog(), "Verify", "Verify masks");
|
|
|
|
// convert color layers to 32 bit coverage masks, 2 passes per coverage
|
|
|
|
for (int sampleNdx = 0; sampleNdx < (int)sampleCoverage.size(); ++sampleNdx)
|
|
{
|
|
sampleCoverage[sampleNdx].setStorage(tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::UNSIGNED_INT32), width, height);
|
|
|
|
for (int y = 0; y < height; ++y)
|
|
for (int x = 0; x < width; ++x)
|
|
{
|
|
const tcu::RGBA lowColor = m_iterationSampleBuffers[sampleNdx].getPixel(x, y);
|
|
const tcu::RGBA highColor = m_iterationSampleBuffers[sampleNdx + (int)sampleCoverage.size()].getPixel(x, y);
|
|
deUint16 low;
|
|
deUint16 high;
|
|
|
|
{
|
|
int redBits = (int)deFloatRound((float)lowColor.getRed() / 255.0f * 31);
|
|
int greenBits = (int)deFloatRound((float)lowColor.getGreen() / 255.0f * 63);
|
|
int blueBits = (int)deFloatRound((float)lowColor.getBlue() / 255.0f * 31);
|
|
|
|
low = (deUint16)(redBits | (greenBits << 5) | (blueBits << 11));
|
|
}
|
|
{
|
|
int redBits = (int)deFloatRound((float)highColor.getRed() / 255.0f * 31);
|
|
int greenBits = (int)deFloatRound((float)highColor.getGreen() / 255.0f * 63);
|
|
int blueBits = (int)deFloatRound((float)highColor.getBlue() / 255.0f * 31);
|
|
|
|
high = (deUint16)(redBits | (greenBits << 5) | (blueBits << 11));
|
|
}
|
|
|
|
sampleCoverage[sampleNdx].getAccess().setPixel(tcu::UVec4((((deUint32)high) << 16) | low, 0, 0, 0), x, y);
|
|
}
|
|
}
|
|
|
|
// verify masks
|
|
|
|
if (m_numRequestedSamples == 0)
|
|
{
|
|
// single sample target, expect mask = 0x01
|
|
const int printFloodLimit = 5;
|
|
int printCount = 0;
|
|
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Verifying sample mask is 0x00000001." << tcu::TestLog::EndMessage;
|
|
|
|
for (int y = 0; y < height; ++y)
|
|
for (int x = 0; x < width; ++x)
|
|
{
|
|
deUint32 mask = sampleCoverage[0].getAccess().getPixelUint(x, y).x();
|
|
if (mask != 0x01)
|
|
{
|
|
allOk = false;
|
|
|
|
if (++printCount <= printFloodLimit)
|
|
{
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message
|
|
<< "Pixel (" << x << ", " << y << "): Invalid mask, got " << tcu::Format::Hex<8>(mask) << ", expected " << tcu::Format::Hex<8>(0x01) << "\n"
|
|
<< tcu::TestLog::EndMessage;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!allOk && printCount > printFloodLimit)
|
|
{
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message
|
|
<< "...\n"
|
|
<< "Omitted " << (printCount-printFloodLimit) << " error descriptions."
|
|
<< tcu::TestLog::EndMessage;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// check uniqueness
|
|
{
|
|
bool uniquenessOk = true;
|
|
int printCount = 0;
|
|
const int printFloodLimit = 5;
|
|
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Verifying invocation sample masks do not share bits." << tcu::TestLog::EndMessage;
|
|
|
|
for (int y = 0; y < height; ++y)
|
|
for (int x = 0; x < width; ++x)
|
|
{
|
|
bool maskBitsNotUnique = false;
|
|
|
|
for (int sampleNdxA = 0; sampleNdxA < m_numTargetSamples && (!maskBitsNotUnique || printCount < printFloodLimit); ++sampleNdxA)
|
|
for (int sampleNdxB = sampleNdxA+1; sampleNdxB < m_numTargetSamples && (!maskBitsNotUnique || printCount < printFloodLimit); ++sampleNdxB)
|
|
{
|
|
const deUint32 maskA = sampleCoverage[sampleNdxA].getAccess().getPixelUint(x, y).x();
|
|
const deUint32 maskB = sampleCoverage[sampleNdxB].getAccess().getPixelUint(x, y).x();
|
|
|
|
// equal mask == emitted by the same invocation
|
|
if (maskA != maskB)
|
|
{
|
|
// shares samples?
|
|
if (maskA & maskB)
|
|
{
|
|
maskBitsNotUnique = true;
|
|
uniquenessOk = false;
|
|
|
|
if (++printCount <= printFloodLimit)
|
|
{
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message
|
|
<< "Pixel (" << x << ", " << y << "):\n"
|
|
<< "\tSamples " << sampleNdxA << " and " << sampleNdxB << " share mask bits\n"
|
|
<< "\tMask" << sampleNdxA << " = " << tcu::Format::Hex<8>(maskA) << "\n"
|
|
<< "\tMask" << sampleNdxB << " = " << tcu::Format::Hex<8>(maskB) << "\n"
|
|
<< tcu::TestLog::EndMessage;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!uniquenessOk)
|
|
{
|
|
allOk = false;
|
|
|
|
if (printCount > printFloodLimit)
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message
|
|
<< "...\n"
|
|
<< "Omitted " << (printCount-printFloodLimit) << " error descriptions."
|
|
<< tcu::TestLog::EndMessage;
|
|
}
|
|
}
|
|
|
|
// check number of sample mask bit groups is valid ( == number of invocations )
|
|
{
|
|
const deUint32 minNumInvocations = (deUint32)de::max(1, (m_numTargetSamples+1)/2);
|
|
bool countOk = true;
|
|
int printCount = 0;
|
|
const int printFloodLimit = 5;
|
|
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Verifying cardinality of separate sample mask bit sets. Expecting equal to the number of invocations, (greater or equal to " << minNumInvocations << ")" << tcu::TestLog::EndMessage;
|
|
|
|
for (int y = 0; y < height; ++y)
|
|
for (int x = 0; x < width; ++x)
|
|
{
|
|
std::set<deUint32> masks;
|
|
|
|
for (int maskNdx = 0; maskNdx < m_numTargetSamples; ++maskNdx)
|
|
{
|
|
const deUint32 mask = sampleCoverage[maskNdx].getAccess().getPixelUint(x, y).x();
|
|
masks.insert(mask);
|
|
}
|
|
|
|
if ((int)masks.size() < (int)minNumInvocations)
|
|
{
|
|
if (++printCount <= printFloodLimit)
|
|
{
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message
|
|
<< "Pixel (" << x << ", " << y << "): Pixel invocations had only " << (int)masks.size() << " separate mask sets. Expected " << minNumInvocations << " or more. Found masks:"
|
|
<< tcu::TestLog::EndMessage;
|
|
|
|
for (std::set<deUint32>::iterator it = masks.begin(); it != masks.end(); ++it)
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message
|
|
<< "\tMask: " << tcu::Format::Hex<8>(*it) << "\n"
|
|
<< tcu::TestLog::EndMessage;
|
|
}
|
|
|
|
countOk = false;
|
|
}
|
|
}
|
|
|
|
if (!countOk)
|
|
{
|
|
allOk = false;
|
|
|
|
if (printCount > printFloodLimit)
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message
|
|
<< "...\n"
|
|
<< "Omitted " << (printCount-printFloodLimit) << " error descriptions."
|
|
<< tcu::TestLog::EndMessage;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!allOk)
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
|
|
}
|
|
|
|
class SampleMaskWriteCase : public SampleMaskBaseCase
|
|
{
|
|
public:
|
|
enum TestMode
|
|
{
|
|
TEST_DISCARD = 0,
|
|
TEST_INVERSE,
|
|
|
|
TEST_LAST
|
|
};
|
|
SampleMaskWriteCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target, ShaderRunMode runMode, TestMode testMode);
|
|
~SampleMaskWriteCase (void);
|
|
|
|
void init (void);
|
|
void preDraw (void);
|
|
void postDraw (void);
|
|
|
|
private:
|
|
enum
|
|
{
|
|
RENDER_SIZE = 64
|
|
};
|
|
|
|
std::string genFragmentSource (int numTargetSamples) const;
|
|
bool verifyImage (const tcu::Surface& resultImage);
|
|
|
|
const TestMode m_testMode;
|
|
};
|
|
|
|
SampleMaskWriteCase::SampleMaskWriteCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target, ShaderRunMode runMode, TestMode testMode)
|
|
: SampleMaskBaseCase (context, name, desc, sampleCount, target, RENDER_SIZE, runMode)
|
|
, m_testMode (testMode)
|
|
{
|
|
DE_ASSERT(testMode < TEST_LAST);
|
|
}
|
|
|
|
SampleMaskWriteCase::~SampleMaskWriteCase (void)
|
|
{
|
|
}
|
|
|
|
void SampleMaskWriteCase::init (void)
|
|
{
|
|
// log the test method and expectations
|
|
if (m_testMode == TEST_DISCARD)
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message
|
|
<< "Discarding half of the samples using gl_SampleMask, expecting:\n"
|
|
<< " 1) half intensity on multisample targets (numSamples > 1)\n"
|
|
<< " 2) full discard on multisample targets (numSamples == 1)\n"
|
|
<< " 3) full intensity (no discard) on singlesample targets. (Mask is only applied as a multisample operation.)\n"
|
|
<< tcu::TestLog::EndMessage;
|
|
else if (m_testMode == TEST_INVERSE)
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message
|
|
<< "Discarding half of the samples using GL_SAMPLE_MASK, setting inverse mask in fragment shader using gl_SampleMask, expecting:\n"
|
|
<< " 1) full discard on multisample targets (mask & modifiedCoverge == 0)\n"
|
|
<< " 2) full intensity (no discard) on singlesample targets. (Mask and coverage is only applied as a multisample operation.)\n"
|
|
<< tcu::TestLog::EndMessage;
|
|
else
|
|
DE_ASSERT(false);
|
|
|
|
SampleMaskBaseCase::init();
|
|
}
|
|
|
|
void SampleMaskWriteCase::preDraw (void)
|
|
{
|
|
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
|
|
|
|
if (m_testMode == TEST_INVERSE)
|
|
{
|
|
// set mask to 0xAAAA.., set inverse mask bit coverage in shader
|
|
|
|
const int maskLoc = gl.getUniformLocation(m_program->getProgram(), "u_mask");
|
|
const deUint32 mask = (deUint32)0xAAAAAAAAUL;
|
|
|
|
if (maskLoc == -1)
|
|
throw tcu::TestError("Location of u_mask was -1");
|
|
|
|
gl.enable(GL_SAMPLE_MASK);
|
|
gl.sampleMaski(0, mask);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "set mask");
|
|
|
|
gl.uniform1ui(maskLoc, mask);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "set mask uniform");
|
|
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Setting sample mask " << tcu::Format::Hex<4>(mask) << tcu::TestLog::EndMessage;
|
|
}
|
|
|
|
SampleMaskBaseCase::preDraw();
|
|
}
|
|
|
|
void SampleMaskWriteCase::postDraw (void)
|
|
{
|
|
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
|
|
|
|
if (m_testMode == TEST_INVERSE)
|
|
{
|
|
const deUint32 fullMask = (1U << m_numTargetSamples) - 1;
|
|
|
|
gl.disable(GL_SAMPLE_MASK);
|
|
gl.sampleMaski(0, fullMask);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "set mask");
|
|
}
|
|
|
|
SampleMaskBaseCase::postDraw();
|
|
}
|
|
|
|
std::string SampleMaskWriteCase::genFragmentSource (int numTargetSamples) const
|
|
{
|
|
DE_ASSERT(numTargetSamples != 0);
|
|
DE_UNREF(numTargetSamples);
|
|
|
|
std::ostringstream buf;
|
|
const bool supportsES32orGL45 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
|
|
contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
|
|
map<string, string> args;
|
|
args["GLSL_VERSION_DECL"] = supportsES32orGL45 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
|
|
args["GLSL_EXTENSION"] = supportsES32orGL45 ? "" : "#extension GL_OES_sample_variables : require";
|
|
|
|
if (m_testMode == TEST_DISCARD)
|
|
{
|
|
// mask out every other coverage bit
|
|
|
|
buf << "${GLSL_VERSION_DECL}\n"
|
|
"${GLSL_EXTENSION}\n"
|
|
"layout(location = 0) out mediump vec4 fragColor;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" for (int i = 0; i < gl_SampleMask.length(); ++i)\n"
|
|
" gl_SampleMask[i] = int(0xAAAAAAAA);\n"
|
|
"\n";
|
|
|
|
if (m_runMode == RUN_PER_SAMPLE)
|
|
buf << " // force per-sample shading\n"
|
|
" highp float blue = float(gl_SampleID);\n"
|
|
"\n"
|
|
" fragColor = vec4(0.0, 1.0, blue, 1.0);\n"
|
|
"}\n";
|
|
else
|
|
buf << " fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
|
|
"}\n";
|
|
}
|
|
else if (m_testMode == TEST_INVERSE)
|
|
{
|
|
// inverse every coverage bit
|
|
|
|
buf << "${GLSL_VERSION_DECL}\n"
|
|
"${GLSL_EXTENSION}\n"
|
|
"layout(location = 0) out mediump vec4 fragColor;\n"
|
|
"uniform highp uint u_mask;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" gl_SampleMask[0] = int(~u_mask);\n"
|
|
"\n";
|
|
|
|
if (m_runMode == RUN_PER_SAMPLE)
|
|
buf << " // force per-sample shading\n"
|
|
" highp float blue = float(gl_SampleID);\n"
|
|
"\n"
|
|
" fragColor = vec4(0.0, 1.0, blue, 1.0);\n"
|
|
"}\n";
|
|
else
|
|
buf << " fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
|
|
"}\n";
|
|
}
|
|
else
|
|
DE_ASSERT(false);
|
|
|
|
return tcu::StringTemplate(buf.str()).specialize(args);
|
|
}
|
|
|
|
bool SampleMaskWriteCase::verifyImage (const tcu::Surface& resultImage)
|
|
{
|
|
const bool singleSampleTarget = m_numRequestedSamples == 0 && !(m_renderTarget == TARGET_DEFAULT && m_context.getRenderTarget().getNumSamples() > 1);
|
|
|
|
if (m_testMode == TEST_DISCARD)
|
|
{
|
|
if (singleSampleTarget)
|
|
{
|
|
// single sample case => multisample operations are not effective => don't discard anything
|
|
// expect green
|
|
return verifyImageWithVerifier(resultImage, m_testCtx.getLog(), ColorVerifier(tcu::Vec3(0.0f, 1.0f, 0.0f)));
|
|
}
|
|
else if (m_numTargetSamples == 1)
|
|
{
|
|
// total discard, expect black
|
|
return verifyImageWithVerifier(resultImage, m_testCtx.getLog(), ColorVerifier(tcu::Vec3(0.0f, 0.0f, 0.0f)));
|
|
}
|
|
else
|
|
{
|
|
// partial discard, expect something between black and green
|
|
return verifyImageWithVerifier(resultImage, m_testCtx.getLog(), PartialDiscardVerifier());
|
|
}
|
|
}
|
|
else if (m_testMode == TEST_INVERSE)
|
|
{
|
|
if (singleSampleTarget)
|
|
{
|
|
// single sample case => multisample operations are not effective => don't discard anything
|
|
// expect green
|
|
return verifyImageWithVerifier(resultImage, m_testCtx.getLog(), ColorVerifier(tcu::Vec3(0.0f, 1.0f, 0.0f)));
|
|
}
|
|
else
|
|
{
|
|
// total discard, expect black
|
|
return verifyImageWithVerifier(resultImage, m_testCtx.getLog(), ColorVerifier(tcu::Vec3(0.0f, 0.0f, 0.0f)));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DE_ASSERT(false);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
} // anonymous
|
|
|
|
SampleVariableTests::SampleVariableTests (Context& context)
|
|
: TestCaseGroup(context, "sample_variables", "Test sample variables")
|
|
{
|
|
}
|
|
|
|
SampleVariableTests::~SampleVariableTests (void)
|
|
{
|
|
}
|
|
|
|
void SampleVariableTests::init (void)
|
|
{
|
|
tcu::TestCaseGroup* const numSampleGroup = new tcu::TestCaseGroup(m_testCtx, "num_samples", "Test NumSamples");
|
|
tcu::TestCaseGroup* const maxSampleGroup = new tcu::TestCaseGroup(m_testCtx, "max_samples", "Test MaxSamples");
|
|
tcu::TestCaseGroup* const sampleIDGroup = new tcu::TestCaseGroup(m_testCtx, "sample_id", "Test SampleID");
|
|
tcu::TestCaseGroup* const samplePosGroup = new tcu::TestCaseGroup(m_testCtx, "sample_pos", "Test SamplePosition");
|
|
tcu::TestCaseGroup* const sampleMaskInGroup = new tcu::TestCaseGroup(m_testCtx, "sample_mask_in", "Test SampleMaskIn");
|
|
tcu::TestCaseGroup* const sampleMaskGroup = new tcu::TestCaseGroup(m_testCtx, "sample_mask", "Test SampleMask");
|
|
|
|
addChild(numSampleGroup);
|
|
addChild(maxSampleGroup);
|
|
addChild(sampleIDGroup);
|
|
addChild(samplePosGroup);
|
|
addChild(sampleMaskInGroup);
|
|
addChild(sampleMaskGroup);
|
|
|
|
static const struct RenderTarget
|
|
{
|
|
const char* name;
|
|
const char* desc;
|
|
int numSamples;
|
|
MultisampleRenderCase::RenderTarget target;
|
|
} targets[] =
|
|
{
|
|
{ "default_framebuffer", "Test with default framebuffer", 0, MultisampleRenderCase::TARGET_DEFAULT },
|
|
{ "singlesample_texture", "Test with singlesample texture", 0, MultisampleRenderCase::TARGET_TEXTURE },
|
|
{ "multisample_texture_1", "Test with multisample texture", 1, MultisampleRenderCase::TARGET_TEXTURE },
|
|
{ "multisample_texture_2", "Test with multisample texture", 2, MultisampleRenderCase::TARGET_TEXTURE },
|
|
{ "multisample_texture_4", "Test with multisample texture", 4, MultisampleRenderCase::TARGET_TEXTURE },
|
|
{ "multisample_texture_8", "Test with multisample texture", 8, MultisampleRenderCase::TARGET_TEXTURE },
|
|
{ "multisample_texture_16", "Test with multisample texture", 16, MultisampleRenderCase::TARGET_TEXTURE },
|
|
{ "singlesample_rbo", "Test with singlesample rbo", 0, MultisampleRenderCase::TARGET_RENDERBUFFER },
|
|
{ "multisample_rbo_1", "Test with multisample rbo", 1, MultisampleRenderCase::TARGET_RENDERBUFFER },
|
|
{ "multisample_rbo_2", "Test with multisample rbo", 2, MultisampleRenderCase::TARGET_RENDERBUFFER },
|
|
{ "multisample_rbo_4", "Test with multisample rbo", 4, MultisampleRenderCase::TARGET_RENDERBUFFER },
|
|
{ "multisample_rbo_8", "Test with multisample rbo", 8, MultisampleRenderCase::TARGET_RENDERBUFFER },
|
|
{ "multisample_rbo_16", "Test with multisample rbo", 16, MultisampleRenderCase::TARGET_RENDERBUFFER },
|
|
};
|
|
|
|
// .num_samples
|
|
{
|
|
for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
|
|
numSampleGroup->addChild(new NumSamplesCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target));
|
|
}
|
|
|
|
// .max_samples
|
|
{
|
|
for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
|
|
maxSampleGroup->addChild(new MaxSamplesCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target));
|
|
}
|
|
|
|
// .sample_ID
|
|
{
|
|
for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
|
|
sampleIDGroup->addChild(new SampleIDCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target));
|
|
}
|
|
|
|
// .sample_pos
|
|
{
|
|
{
|
|
tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "correctness", "Test SamplePos correctness");
|
|
samplePosGroup->addChild(group);
|
|
|
|
for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
|
|
group->addChild(new SamplePosCorrectnessCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target));
|
|
}
|
|
|
|
{
|
|
tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "distribution", "Test SamplePos distribution");
|
|
samplePosGroup->addChild(group);
|
|
|
|
for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
|
|
group->addChild(new SamplePosDistributionCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target));
|
|
}
|
|
}
|
|
|
|
// .sample_mask_in
|
|
{
|
|
// .sample_mask
|
|
{
|
|
tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "sample_mask", "Test with GL_SAMPLE_MASK");
|
|
sampleMaskInGroup->addChild(group);
|
|
|
|
for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
|
|
group->addChild(new SampleMaskCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target));
|
|
}
|
|
// .bit_count_per_pixel
|
|
{
|
|
tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "bit_count_per_pixel", "Test number of coverage bits");
|
|
sampleMaskInGroup->addChild(group);
|
|
|
|
for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
|
|
group->addChild(new SampleMaskCountCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskCountCase::RUN_PER_PIXEL));
|
|
}
|
|
// .bit_count_per_sample
|
|
{
|
|
tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "bit_count_per_sample", "Test number of coverage bits");
|
|
sampleMaskInGroup->addChild(group);
|
|
|
|
for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
|
|
group->addChild(new SampleMaskCountCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskCountCase::RUN_PER_SAMPLE));
|
|
}
|
|
// .bit_count_per_two_samples
|
|
{
|
|
tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "bit_count_per_two_samples", "Test number of coverage bits");
|
|
sampleMaskInGroup->addChild(group);
|
|
|
|
for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
|
|
group->addChild(new SampleMaskCountCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskCountCase::RUN_PER_TWO_SAMPLES));
|
|
}
|
|
// .bits_unique_per_sample
|
|
{
|
|
tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "bits_unique_per_sample", "Test coverage bits");
|
|
sampleMaskInGroup->addChild(group);
|
|
|
|
for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
|
|
if (targets[targetNdx].target == MultisampleRenderCase::TARGET_TEXTURE)
|
|
group->addChild(new SampleMaskUniqueCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskUniqueCase::RUN_PER_SAMPLE));
|
|
}
|
|
// .bits_unique_per_two_samples
|
|
{
|
|
tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "bits_unique_per_two_samples", "Test coverage bits");
|
|
sampleMaskInGroup->addChild(group);
|
|
|
|
for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
|
|
if (targets[targetNdx].target == MultisampleRenderCase::TARGET_TEXTURE)
|
|
group->addChild(new SampleMaskUniqueSetCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskUniqueCase::RUN_PER_TWO_SAMPLES));
|
|
}
|
|
}
|
|
|
|
// .sample_mask
|
|
{
|
|
// .discard_half_per_pixel
|
|
{
|
|
tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "discard_half_per_pixel", "Test coverage bits");
|
|
sampleMaskGroup->addChild(group);
|
|
|
|
for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
|
|
group->addChild(new SampleMaskWriteCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskWriteCase::RUN_PER_PIXEL, SampleMaskWriteCase::TEST_DISCARD));
|
|
}
|
|
// .discard_half_per_sample
|
|
{
|
|
tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "discard_half_per_sample", "Test coverage bits");
|
|
sampleMaskGroup->addChild(group);
|
|
|
|
for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
|
|
group->addChild(new SampleMaskWriteCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskWriteCase::RUN_PER_SAMPLE, SampleMaskWriteCase::TEST_DISCARD));
|
|
}
|
|
// .discard_half_per_two_samples
|
|
{
|
|
tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "discard_half_per_two_samples", "Test coverage bits");
|
|
sampleMaskGroup->addChild(group);
|
|
|
|
for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
|
|
group->addChild(new SampleMaskWriteCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskWriteCase::RUN_PER_TWO_SAMPLES, SampleMaskWriteCase::TEST_DISCARD));
|
|
}
|
|
|
|
// .discard_half_per_two_samples
|
|
{
|
|
tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "inverse_per_pixel", "Test coverage bits");
|
|
sampleMaskGroup->addChild(group);
|
|
|
|
for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
|
|
group->addChild(new SampleMaskWriteCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskWriteCase::RUN_PER_PIXEL, SampleMaskWriteCase::TEST_INVERSE));
|
|
}
|
|
// .inverse_per_sample
|
|
{
|
|
tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "inverse_per_sample", "Test coverage bits");
|
|
sampleMaskGroup->addChild(group);
|
|
|
|
for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
|
|
group->addChild(new SampleMaskWriteCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskWriteCase::RUN_PER_SAMPLE, SampleMaskWriteCase::TEST_INVERSE));
|
|
}
|
|
// .inverse_per_two_samples
|
|
{
|
|
tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "inverse_per_two_samples", "Test coverage bits");
|
|
sampleMaskGroup->addChild(group);
|
|
|
|
for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
|
|
group->addChild(new SampleMaskWriteCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskWriteCase::RUN_PER_TWO_SAMPLES, SampleMaskWriteCase::TEST_INVERSE));
|
|
}
|
|
}
|
|
}
|
|
|
|
} // Functional
|
|
} // gles31
|
|
} // deqp
|