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.
827 lines
27 KiB
827 lines
27 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 Multisample shader render case
|
|
*//*--------------------------------------------------------------------*/
|
|
|
|
#include "es31fMultisampleShaderRenderCase.hpp"
|
|
#include "tcuRenderTarget.hpp"
|
|
#include "tcuSurface.hpp"
|
|
#include "tcuTestLog.hpp"
|
|
#include "tcuStringTemplate.hpp"
|
|
#include "gluContextInfo.hpp"
|
|
#include "gluShaderProgram.hpp"
|
|
#include "gluRenderContext.hpp"
|
|
#include "gluPixelTransfer.hpp"
|
|
#include "glwFunctions.hpp"
|
|
#include "glwEnums.hpp"
|
|
#include "deStringUtil.hpp"
|
|
|
|
namespace deqp
|
|
{
|
|
namespace gles31
|
|
{
|
|
namespace Functional
|
|
{
|
|
namespace MultisampleShaderRenderUtil
|
|
{
|
|
using std::map;
|
|
using std::string;
|
|
namespace
|
|
{
|
|
|
|
static const char* const s_vertexSource = "${GLSL_VERSION_DECL}\n"
|
|
"in highp vec4 a_position;\n"
|
|
"out highp vec4 v_position;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" gl_Position = a_position;\n"
|
|
" v_position = a_position;\n"
|
|
"}";
|
|
|
|
} // anonymous
|
|
|
|
QualityWarning::QualityWarning (const std::string& message)
|
|
: tcu::Exception(message)
|
|
{
|
|
}
|
|
|
|
MultisampleRenderCase::MultisampleRenderCase (Context& context, const char* name, const char* desc, int numSamples, RenderTarget target, int renderSize, int flags)
|
|
: TestCase (context, name, desc)
|
|
, m_numRequestedSamples (numSamples)
|
|
, m_renderTarget (target)
|
|
, m_renderSize (renderSize)
|
|
, m_perIterationShader ((flags & FLAG_PER_ITERATION_SHADER) != 0)
|
|
, m_verifyTextureSampleBuffers ((flags & FLAG_VERIFY_MSAA_TEXTURE_SAMPLE_BUFFERS) != 0 && target == TARGET_TEXTURE)
|
|
, m_numTargetSamples (-1)
|
|
, m_buffer (0)
|
|
, m_resolveBuffer (0)
|
|
, m_program (DE_NULL)
|
|
, m_fbo (0)
|
|
, m_fboTexture (0)
|
|
, m_textureSamplerProgram (DE_NULL)
|
|
, m_fboRbo (0)
|
|
, m_resolveFbo (0)
|
|
, m_resolveFboTexture (0)
|
|
, m_iteration (0)
|
|
, m_numIterations (1)
|
|
, m_renderMode (0)
|
|
, m_renderCount (0)
|
|
, m_renderVao (0)
|
|
, m_resolveVao (0)
|
|
{
|
|
DE_ASSERT(target < TARGET_LAST);
|
|
}
|
|
|
|
MultisampleRenderCase::~MultisampleRenderCase (void)
|
|
{
|
|
MultisampleRenderCase::deinit();
|
|
}
|
|
|
|
void MultisampleRenderCase::init (void)
|
|
{
|
|
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
|
|
deInt32 queriedSampleCount = -1;
|
|
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);
|
|
|
|
// requirements
|
|
|
|
switch (m_renderTarget)
|
|
{
|
|
case TARGET_DEFAULT:
|
|
{
|
|
if (m_context.getRenderTarget().getWidth() < m_renderSize || m_context.getRenderTarget().getHeight() < m_renderSize)
|
|
throw tcu::NotSupportedError("Test requires render target with size " + de::toString(m_renderSize) + "x" + de::toString(m_renderSize) + " or greater");
|
|
break;
|
|
}
|
|
|
|
case TARGET_TEXTURE:
|
|
{
|
|
deInt32 maxTextureSamples = getMaxConformantSampleCount(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8);
|
|
if (m_numRequestedSamples > maxTextureSamples)
|
|
throw tcu::NotSupportedError("Sample count not supported");
|
|
break;
|
|
}
|
|
|
|
case TARGET_RENDERBUFFER:
|
|
{
|
|
deInt32 maxRboSamples = getMaxConformantSampleCount(GL_RENDERBUFFER, GL_RGBA8);
|
|
if (m_numRequestedSamples > maxRboSamples)
|
|
throw tcu::NotSupportedError("Sample count not supported");
|
|
break;
|
|
}
|
|
|
|
default:
|
|
DE_ASSERT(false);
|
|
}
|
|
|
|
// resources
|
|
|
|
{
|
|
gl.genBuffers(1, &m_buffer);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "gen buf");
|
|
|
|
setupRenderData();
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "setup data");
|
|
|
|
gl.genVertexArrays(1, &m_renderVao);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "gen vao");
|
|
|
|
// buffer for MSAA texture resolving
|
|
{
|
|
static const tcu::Vec4 fullscreenQuad[] =
|
|
{
|
|
tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
|
|
tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f),
|
|
tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
|
|
tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
|
|
};
|
|
|
|
gl.genBuffers(1, &m_resolveBuffer);
|
|
gl.bindBuffer(GL_ARRAY_BUFFER, m_resolveBuffer);
|
|
gl.bufferData(GL_ARRAY_BUFFER, (int)sizeof(fullscreenQuad), fullscreenQuad, GL_STATIC_DRAW);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "setup data");
|
|
}
|
|
}
|
|
|
|
// msaa targets
|
|
|
|
if (m_renderTarget == TARGET_TEXTURE)
|
|
{
|
|
const deUint32 textureTarget = (m_numRequestedSamples == 0) ? (GL_TEXTURE_2D) : (GL_TEXTURE_2D_MULTISAMPLE);
|
|
|
|
gl.genVertexArrays(1, &m_resolveVao);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "gen vao");
|
|
|
|
gl.genTextures(1, &m_fboTexture);
|
|
gl.bindTexture(textureTarget, m_fboTexture);
|
|
if (m_numRequestedSamples == 0)
|
|
{
|
|
gl.texStorage2D(textureTarget, 1, GL_RGBA8, m_renderSize, m_renderSize);
|
|
gl.texParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
gl.texParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
}
|
|
else
|
|
gl.texStorage2DMultisample(textureTarget, m_numRequestedSamples, GL_RGBA8, m_renderSize, m_renderSize, GL_FALSE);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "gen tex");
|
|
|
|
gl.genFramebuffers(1, &m_fbo);
|
|
gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
|
|
gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureTarget, m_fboTexture, 0);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "gen fbo");
|
|
|
|
if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
|
throw tcu::TestError("fbo not complete");
|
|
|
|
if (m_numRequestedSamples != 0)
|
|
{
|
|
// for shader
|
|
gl.getTexLevelParameteriv(GL_TEXTURE_2D_MULTISAMPLE, 0, GL_TEXTURE_SAMPLES, &queriedSampleCount);
|
|
|
|
// logging
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Asked for " << m_numRequestedSamples << " samples, got " << queriedSampleCount << " samples." << tcu::TestLog::EndMessage;
|
|
|
|
// sanity
|
|
if (queriedSampleCount < m_numRequestedSamples)
|
|
throw tcu::TestError("Got less texture samples than asked for");
|
|
}
|
|
|
|
// texture sampler shader
|
|
m_textureSamplerProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
|
|
<< glu::VertexSource(tcu::StringTemplate(s_vertexSource).specialize(args))
|
|
<< glu::FragmentSource(genMSSamplerSource(queriedSampleCount)));
|
|
if (!m_textureSamplerProgram->isOk())
|
|
{
|
|
m_testCtx.getLog() << tcu::TestLog::Section("SamplerShader", "Sampler shader") << *m_textureSamplerProgram << tcu::TestLog::EndSection;
|
|
throw tcu::TestError("could not build program");
|
|
}
|
|
}
|
|
else if (m_renderTarget == TARGET_RENDERBUFFER)
|
|
{
|
|
gl.genRenderbuffers(1, &m_fboRbo);
|
|
gl.bindRenderbuffer(GL_RENDERBUFFER, m_fboRbo);
|
|
gl.renderbufferStorageMultisample(GL_RENDERBUFFER, m_numRequestedSamples, GL_RGBA8, m_renderSize, m_renderSize);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "gen rbo");
|
|
|
|
gl.genFramebuffers(1, &m_fbo);
|
|
gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
|
|
gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_fboRbo);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "gen fbo");
|
|
|
|
if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
|
throw tcu::TestError("fbo not complete");
|
|
|
|
// logging
|
|
gl.getRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &queriedSampleCount);
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Asked for " << m_numRequestedSamples << " samples, got " << queriedSampleCount << " samples." << tcu::TestLog::EndMessage;
|
|
|
|
// sanity
|
|
if (queriedSampleCount < m_numRequestedSamples)
|
|
throw tcu::TestError("Got less renderbuffer samples samples than asked for");
|
|
}
|
|
|
|
// fbo for resolving the multisample fbo
|
|
if (m_renderTarget != TARGET_DEFAULT)
|
|
{
|
|
gl.genTextures(1, &m_resolveFboTexture);
|
|
gl.bindTexture(GL_TEXTURE_2D, m_resolveFboTexture);
|
|
gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, m_renderSize, m_renderSize);
|
|
gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "gen tex");
|
|
|
|
gl.genFramebuffers(1, &m_resolveFbo);
|
|
gl.bindFramebuffer(GL_FRAMEBUFFER, m_resolveFbo);
|
|
gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_resolveFboTexture, 0);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "gen fbo");
|
|
|
|
if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
|
throw tcu::TestError("resolve fbo not complete");
|
|
}
|
|
|
|
// create verifier shader and set targetSampleCount
|
|
|
|
{
|
|
int realSampleCount = -1;
|
|
|
|
if (m_renderTarget == TARGET_TEXTURE)
|
|
{
|
|
if (m_numRequestedSamples == 0)
|
|
realSampleCount = 1; // non msaa texture
|
|
else
|
|
realSampleCount = de::max(1, queriedSampleCount); // msaa texture
|
|
}
|
|
else if (m_renderTarget == TARGET_RENDERBUFFER)
|
|
{
|
|
realSampleCount = de::max(1, queriedSampleCount); // msaa rbo
|
|
}
|
|
else if (m_renderTarget == TARGET_DEFAULT)
|
|
{
|
|
realSampleCount = de::max(1, m_context.getRenderTarget().getNumSamples());
|
|
}
|
|
else
|
|
DE_ASSERT(DE_FALSE);
|
|
|
|
// is set and is valid
|
|
DE_ASSERT(realSampleCount != -1);
|
|
DE_ASSERT(realSampleCount != 0);
|
|
m_numTargetSamples = realSampleCount;
|
|
}
|
|
|
|
if (!m_perIterationShader)
|
|
{
|
|
m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(genVertexSource(m_numTargetSamples)) << glu::FragmentSource(genFragmentSource(m_numTargetSamples)));
|
|
m_testCtx.getLog() << tcu::TestLog::Section("RenderShader", "Render shader") << *m_program << tcu::TestLog::EndSection;
|
|
if (!m_program->isOk())
|
|
throw tcu::TestError("could not build program");
|
|
|
|
}
|
|
}
|
|
|
|
void MultisampleRenderCase::deinit (void)
|
|
{
|
|
if (m_buffer)
|
|
{
|
|
m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_buffer);
|
|
m_buffer = 0;
|
|
}
|
|
|
|
if (m_resolveBuffer)
|
|
{
|
|
m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_resolveBuffer);
|
|
m_resolveBuffer = 0;
|
|
}
|
|
|
|
delete m_program;
|
|
m_program = DE_NULL;
|
|
|
|
if (m_fbo)
|
|
{
|
|
m_context.getRenderContext().getFunctions().deleteFramebuffers(1, &m_fbo);
|
|
m_fbo = 0;
|
|
}
|
|
|
|
if (m_fboTexture)
|
|
{
|
|
m_context.getRenderContext().getFunctions().deleteTextures(1, &m_fboTexture);
|
|
m_fboTexture = 0;
|
|
}
|
|
|
|
delete m_textureSamplerProgram;
|
|
m_textureSamplerProgram = DE_NULL;
|
|
|
|
if (m_fboRbo)
|
|
{
|
|
m_context.getRenderContext().getFunctions().deleteRenderbuffers(1, &m_fboRbo);
|
|
m_fboRbo = 0;
|
|
}
|
|
|
|
if (m_resolveFbo)
|
|
{
|
|
m_context.getRenderContext().getFunctions().deleteFramebuffers(1, &m_resolveFbo);
|
|
m_resolveFbo = 0;
|
|
}
|
|
|
|
if (m_resolveFboTexture)
|
|
{
|
|
m_context.getRenderContext().getFunctions().deleteTextures(1, &m_resolveFboTexture);
|
|
m_resolveFboTexture = 0;
|
|
}
|
|
|
|
if (m_renderVao)
|
|
{
|
|
m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_renderVao);
|
|
m_renderVao = 0;
|
|
}
|
|
|
|
if (m_resolveVao)
|
|
{
|
|
m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_resolveVao);
|
|
m_resolveVao = 0;
|
|
}
|
|
}
|
|
|
|
MultisampleRenderCase::IterateResult MultisampleRenderCase::iterate (void)
|
|
{
|
|
// default value
|
|
if (m_iteration == 0)
|
|
{
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
|
|
preTest();
|
|
}
|
|
|
|
drawOneIteration();
|
|
|
|
// next iteration
|
|
++m_iteration;
|
|
if (m_iteration < m_numIterations)
|
|
return CONTINUE;
|
|
else
|
|
{
|
|
postTest();
|
|
return STOP;
|
|
}
|
|
}
|
|
|
|
void MultisampleRenderCase::preDraw (void)
|
|
{
|
|
}
|
|
|
|
void MultisampleRenderCase::postDraw (void)
|
|
{
|
|
}
|
|
|
|
void MultisampleRenderCase::preTest (void)
|
|
{
|
|
}
|
|
|
|
void MultisampleRenderCase::postTest (void)
|
|
{
|
|
}
|
|
|
|
void MultisampleRenderCase::verifyResultImageAndSetResult (const tcu::Surface& resultImage)
|
|
{
|
|
// verify using case-specific verification
|
|
|
|
try
|
|
{
|
|
if (!verifyImage(resultImage))
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
|
|
}
|
|
catch (const QualityWarning& ex)
|
|
{
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Quality warning, error = " << ex.what() << tcu::TestLog::EndMessage;
|
|
|
|
// Failures are more important than warnings
|
|
if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, ex.what());
|
|
}
|
|
}
|
|
|
|
void MultisampleRenderCase::verifyResultBuffersAndSetResult (const std::vector<tcu::Surface>& resultBuffers)
|
|
{
|
|
// verify using case-specific verification
|
|
|
|
try
|
|
{
|
|
if (!verifySampleBuffers(resultBuffers))
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
|
|
}
|
|
catch (const QualityWarning& ex)
|
|
{
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Quality warning, error = " << ex.what() << tcu::TestLog::EndMessage;
|
|
|
|
// Failures are more important than warnings
|
|
if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, ex.what());
|
|
}
|
|
}
|
|
|
|
std::string MultisampleRenderCase::getIterationDescription (int iteration) const
|
|
{
|
|
DE_UNREF(iteration);
|
|
DE_ASSERT(false);
|
|
return "";
|
|
}
|
|
|
|
void MultisampleRenderCase::drawOneIteration (void)
|
|
{
|
|
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
|
|
const std::string sectionDescription = (m_numIterations > 1) ? ("Iteration " + de::toString(m_iteration+1) + "/" + de::toString(m_numIterations) + ": " + getIterationDescription(m_iteration)) : ("Test");
|
|
const tcu::ScopedLogSection section (m_testCtx.getLog(), "Iteration" + de::toString(m_iteration), sectionDescription);
|
|
|
|
// Per iteration shader?
|
|
if (m_perIterationShader)
|
|
{
|
|
delete m_program;
|
|
m_program = DE_NULL;
|
|
|
|
m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
|
|
<< glu::VertexSource(genVertexSource(m_numTargetSamples))
|
|
<< glu::FragmentSource(genFragmentSource(m_numTargetSamples)));
|
|
m_testCtx.getLog() << tcu::TestLog::Section("RenderShader", "Render shader") << *m_program << tcu::TestLog::EndSection;
|
|
if (!m_program->isOk())
|
|
throw tcu::TestError("could not build program");
|
|
|
|
}
|
|
|
|
// render
|
|
{
|
|
if (m_renderTarget == TARGET_TEXTURE || m_renderTarget == TARGET_RENDERBUFFER)
|
|
{
|
|
gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "bind fbo");
|
|
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Rendering " << m_renderSceneDescription << " with render shader to fbo." << tcu::TestLog::EndMessage;
|
|
}
|
|
else
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Rendering " << m_renderSceneDescription << " with render shader to default framebuffer." << tcu::TestLog::EndMessage;
|
|
|
|
gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
|
gl.clear(GL_COLOR_BUFFER_BIT);
|
|
gl.viewport(0, 0, m_renderSize, m_renderSize);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
|
|
|
|
gl.bindVertexArray(m_renderVao);
|
|
gl.bindBuffer(GL_ARRAY_BUFFER, m_buffer);
|
|
|
|
// set attribs
|
|
DE_ASSERT(!m_renderAttribs.empty());
|
|
for (std::map<std::string, Attrib>::const_iterator it = m_renderAttribs.begin(); it != m_renderAttribs.end(); ++it)
|
|
{
|
|
const deInt32 location = gl.getAttribLocation(m_program->getProgram(), it->first.c_str());
|
|
|
|
if (location != -1)
|
|
{
|
|
gl.vertexAttribPointer(location, 4, GL_FLOAT, GL_FALSE, it->second.stride, glu::BufferOffsetAsPointer(it->second.offset));
|
|
gl.enableVertexAttribArray(location);
|
|
}
|
|
}
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "set attrib");
|
|
|
|
gl.useProgram(m_program->getProgram());
|
|
preDraw();
|
|
gl.drawArrays(m_renderMode, 0, m_renderCount);
|
|
postDraw();
|
|
gl.useProgram(0);
|
|
gl.bindVertexArray(0);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
|
|
|
|
if (m_renderTarget == TARGET_TEXTURE || m_renderTarget == TARGET_RENDERBUFFER)
|
|
gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
}
|
|
|
|
// read
|
|
{
|
|
if (m_renderTarget == TARGET_DEFAULT)
|
|
{
|
|
tcu::Surface resultImage(m_renderSize, m_renderSize);
|
|
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Reading pixels from default framebuffer." << tcu::TestLog::EndMessage;
|
|
|
|
// default directly
|
|
glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels");
|
|
|
|
// set test result
|
|
verifyResultImageAndSetResult(resultImage);
|
|
}
|
|
else if (m_renderTarget == TARGET_RENDERBUFFER)
|
|
{
|
|
tcu::Surface resultImage(m_renderSize, m_renderSize);
|
|
|
|
// rbo by blitting to non-multisample fbo
|
|
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Blitting result from fbo to single sample fbo. (Resolve multisample)" << tcu::TestLog::EndMessage;
|
|
|
|
gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo);
|
|
gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_resolveFbo);
|
|
gl.blitFramebuffer(0, 0, m_renderSize, m_renderSize, 0, 0, m_renderSize, m_renderSize, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "blit resolve");
|
|
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Reading pixels from single sample framebuffer." << tcu::TestLog::EndMessage;
|
|
|
|
gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_resolveFbo);
|
|
glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels");
|
|
|
|
gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
|
|
// set test result
|
|
verifyResultImageAndSetResult(resultImage);
|
|
}
|
|
else if (m_renderTarget == TARGET_TEXTURE && !m_verifyTextureSampleBuffers)
|
|
{
|
|
const deInt32 posLocation = gl.getAttribLocation(m_textureSamplerProgram->getProgram(), "a_position");
|
|
const deInt32 samplerLocation = gl.getUniformLocation(m_textureSamplerProgram->getProgram(), "u_sampler");
|
|
const deUint32 textureTarget = (m_numRequestedSamples == 0) ? (GL_TEXTURE_2D) : (GL_TEXTURE_2D_MULTISAMPLE);
|
|
tcu::Surface resultImage (m_renderSize, m_renderSize);
|
|
|
|
if (m_numRequestedSamples)
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Using sampler shader to sample the multisample texture to single sample framebuffer." << tcu::TestLog::EndMessage;
|
|
else
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Drawing texture to single sample framebuffer. Using sampler shader." << tcu::TestLog::EndMessage;
|
|
|
|
if (samplerLocation == -1)
|
|
throw tcu::TestError("Location u_sampler was -1.");
|
|
|
|
// resolve multisample texture by averaging
|
|
gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
|
gl.clear(GL_COLOR_BUFFER_BIT);
|
|
gl.viewport(0, 0, m_renderSize, m_renderSize);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
|
|
|
|
gl.bindVertexArray(m_resolveVao);
|
|
gl.bindBuffer(GL_ARRAY_BUFFER, m_resolveBuffer);
|
|
gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
|
|
gl.enableVertexAttribArray(posLocation);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "set attrib");
|
|
|
|
gl.activeTexture(GL_TEXTURE0);
|
|
gl.bindTexture(textureTarget, m_fboTexture);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "bind tex");
|
|
|
|
gl.useProgram(m_textureSamplerProgram->getProgram());
|
|
gl.uniform1i(samplerLocation, 0);
|
|
|
|
gl.bindFramebuffer(GL_FRAMEBUFFER, m_resolveFbo);
|
|
gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
|
|
|
gl.useProgram(0);
|
|
gl.bindVertexArray(0);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
|
|
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Reading pixels from single sample framebuffer." << tcu::TestLog::EndMessage;
|
|
|
|
glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels");
|
|
|
|
gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
|
|
// set test result
|
|
verifyResultImageAndSetResult(resultImage);
|
|
}
|
|
else if (m_renderTarget == TARGET_TEXTURE && m_verifyTextureSampleBuffers)
|
|
{
|
|
const deInt32 posLocation = gl.getAttribLocation(m_textureSamplerProgram->getProgram(), "a_position");
|
|
const deInt32 samplerLocation = gl.getUniformLocation(m_textureSamplerProgram->getProgram(), "u_sampler");
|
|
const deInt32 sampleLocation = gl.getUniformLocation(m_textureSamplerProgram->getProgram(), "u_sampleNdx");
|
|
const deUint32 textureTarget = (m_numRequestedSamples == 0) ? (GL_TEXTURE_2D) : (GL_TEXTURE_2D_MULTISAMPLE);
|
|
std::vector<tcu::Surface> resultBuffers (m_numTargetSamples);
|
|
|
|
if (m_numRequestedSamples)
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Reading multisample texture sample buffers." << tcu::TestLog::EndMessage;
|
|
else
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Reading texture." << tcu::TestLog::EndMessage;
|
|
|
|
if (samplerLocation == -1)
|
|
throw tcu::TestError("Location u_sampler was -1.");
|
|
if (sampleLocation == -1)
|
|
throw tcu::TestError("Location u_sampleNdx was -1.");
|
|
|
|
for (int sampleNdx = 0; sampleNdx < m_numTargetSamples; ++sampleNdx)
|
|
resultBuffers[sampleNdx].setSize(m_renderSize, m_renderSize);
|
|
|
|
// read sample buffers to different surfaces
|
|
gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
|
gl.clear(GL_COLOR_BUFFER_BIT);
|
|
gl.viewport(0, 0, m_renderSize, m_renderSize);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
|
|
|
|
gl.bindVertexArray(m_resolveVao);
|
|
gl.bindBuffer(GL_ARRAY_BUFFER, m_resolveBuffer);
|
|
gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
|
|
gl.enableVertexAttribArray(posLocation);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "set attrib");
|
|
|
|
gl.activeTexture(GL_TEXTURE0);
|
|
gl.bindTexture(textureTarget, m_fboTexture);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "bind tex");
|
|
|
|
gl.bindFramebuffer(GL_FRAMEBUFFER, m_resolveFbo);
|
|
gl.useProgram(m_textureSamplerProgram->getProgram());
|
|
gl.uniform1i(samplerLocation, 0);
|
|
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Reading sample buffers" << tcu::TestLog::EndMessage;
|
|
|
|
for (int sampleNdx = 0; sampleNdx < m_numTargetSamples; ++sampleNdx)
|
|
{
|
|
gl.uniform1i(sampleLocation, sampleNdx);
|
|
gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
|
|
|
|
glu::readPixels(m_context.getRenderContext(), 0, 0, resultBuffers[sampleNdx].getAccess());
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels");
|
|
}
|
|
|
|
gl.useProgram(0);
|
|
gl.bindVertexArray(0);
|
|
gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
|
|
// verify sample buffers
|
|
verifyResultBuffersAndSetResult(resultBuffers);
|
|
}
|
|
else
|
|
DE_ASSERT(false);
|
|
}
|
|
}
|
|
|
|
std::string MultisampleRenderCase::genVertexSource (int numTargetSamples) const
|
|
{
|
|
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);
|
|
|
|
DE_UNREF(numTargetSamples);
|
|
return std::string(tcu::StringTemplate(s_vertexSource).specialize(args));
|
|
}
|
|
|
|
std::string MultisampleRenderCase::genMSSamplerSource (int numTargetSamples) const
|
|
{
|
|
if (m_verifyTextureSampleBuffers)
|
|
return genMSTextureLayerFetchSource(numTargetSamples);
|
|
else
|
|
return genMSTextureResolverSource(numTargetSamples);
|
|
}
|
|
|
|
std::string MultisampleRenderCase::genMSTextureResolverSource (int numTargetSamples) const
|
|
{
|
|
// default behavior: average
|
|
|
|
const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
|
|
map<string, string> args;
|
|
const bool isSingleSampleTarget = (m_numRequestedSamples == 0);
|
|
std::ostringstream buf;
|
|
|
|
args["GLSL_VERSION_DECL"] = supportsES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
|
|
|
|
buf << "${GLSL_VERSION_DECL}\n"
|
|
"in mediump vec4 v_position;\n"
|
|
"layout(location = 0) out mediump vec4 fragColor;\n"
|
|
"uniform mediump " << ((isSingleSampleTarget) ? ("sampler2D") : ("sampler2DMS")) << " u_sampler;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" mediump vec2 relPosition = (v_position.xy + vec2(1.0, 1.0)) / 2.0;\n"
|
|
" mediump ivec2 fetchPos = ivec2(floor(relPosition * " << m_renderSize << ".0));\n"
|
|
" mediump vec4 colorSum = vec4(0.0, 0.0, 0.0, 0.0);\n"
|
|
"\n";
|
|
|
|
if (isSingleSampleTarget)
|
|
buf << " colorSum = texelFetch(u_sampler, fetchPos, 0);\n"
|
|
"\n";
|
|
else
|
|
buf << " for (int sampleNdx = 0; sampleNdx < " << numTargetSamples << "; ++sampleNdx)\n"
|
|
" colorSum += texelFetch(u_sampler, fetchPos, sampleNdx);\n"
|
|
" colorSum /= " << numTargetSamples << ".0;\n"
|
|
"\n";
|
|
|
|
buf << " fragColor = vec4(colorSum.xyz, 1.0);\n"
|
|
"}\n";
|
|
|
|
return tcu::StringTemplate(buf.str()).specialize(args);
|
|
}
|
|
|
|
std::string MultisampleRenderCase::genMSTextureLayerFetchSource (int numTargetSamples) const
|
|
{
|
|
DE_UNREF(numTargetSamples);
|
|
|
|
const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
|
|
map<string, string> args;
|
|
const bool isSingleSampleTarget = (m_numRequestedSamples == 0);
|
|
std::ostringstream buf;
|
|
|
|
args["GLSL_VERSION_DECL"] = supportsES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
|
|
|
|
buf << "${GLSL_VERSION_DECL}\n"
|
|
"in mediump vec4 v_position;\n"
|
|
"layout(location = 0) out mediump vec4 fragColor;\n"
|
|
"uniform mediump " << ((isSingleSampleTarget) ? ("sampler2D") : ("sampler2DMS")) << " u_sampler;\n"
|
|
"uniform mediump int u_sampleNdx;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" mediump vec2 relPosition = (v_position.xy + vec2(1.0, 1.0)) / 2.0;\n"
|
|
" mediump ivec2 fetchPos = ivec2(floor(relPosition * " << m_renderSize << ".0));\n"
|
|
"\n"
|
|
" mediump vec4 color = texelFetch(u_sampler, fetchPos, u_sampleNdx);\n"
|
|
" fragColor = vec4(color.rgb, 1.0);\n"
|
|
"}\n";
|
|
|
|
return tcu::StringTemplate(buf.str()).specialize(args);
|
|
}
|
|
|
|
bool MultisampleRenderCase::verifySampleBuffers (const std::vector<tcu::Surface>& resultBuffers)
|
|
{
|
|
DE_UNREF(resultBuffers);
|
|
DE_ASSERT(false);
|
|
return false;
|
|
}
|
|
|
|
void MultisampleRenderCase::setupRenderData (void)
|
|
{
|
|
static const tcu::Vec4 fullscreenQuad[] =
|
|
{
|
|
tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
|
|
tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f),
|
|
tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
|
|
tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
|
|
};
|
|
|
|
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
|
|
|
|
m_renderMode = GL_TRIANGLE_STRIP;
|
|
m_renderCount = 4;
|
|
m_renderSceneDescription = "quad";
|
|
|
|
m_renderAttribs["a_position"].offset = 0;
|
|
m_renderAttribs["a_position"].stride = sizeof(float[4]);
|
|
|
|
gl.bindBuffer(GL_ARRAY_BUFFER, m_buffer);
|
|
gl.bufferData(GL_ARRAY_BUFFER, (int)sizeof(fullscreenQuad), fullscreenQuad, GL_STATIC_DRAW);
|
|
}
|
|
|
|
glw::GLint MultisampleRenderCase::getMaxConformantSampleCount(glw::GLenum target, glw::GLenum internalFormat)
|
|
{
|
|
deInt32 maxTextureSamples = 0;
|
|
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
|
|
|
|
if (m_context.getContextInfo().isExtensionSupported("GL_NV_internalformat_sample_query"))
|
|
{
|
|
glw::GLint gl_sample_counts = 0;
|
|
gl.getInternalformativ(target, internalFormat, GL_NUM_SAMPLE_COUNTS, 1, &gl_sample_counts);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInternalformativ() failed for GL_NUM_SAMPLE_COUNTS pname");
|
|
|
|
/* Check and return the first conformant sample count */
|
|
glw::GLint* gl_supported_samples = new glw::GLint[gl_sample_counts];
|
|
if (gl_supported_samples)
|
|
{
|
|
gl.getInternalformativ(target, internalFormat, GL_SAMPLES, gl_sample_counts, gl_supported_samples);
|
|
|
|
for (glw::GLint i = 0; i < gl_sample_counts; i++)
|
|
{
|
|
glw::GLint isConformant = 0;
|
|
gl.getInternalformatSampleivNV(target, internalFormat, gl_supported_samples[i], GL_CONFORMANT_NV, 1,
|
|
&isConformant);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInternalformatSampleivNV() call(s) failed");
|
|
|
|
if (isConformant && gl_supported_samples[i] > maxTextureSamples)
|
|
{
|
|
maxTextureSamples = gl_supported_samples[i];
|
|
}
|
|
}
|
|
delete[] gl_supported_samples;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gl.getInternalformativ(target, internalFormat, GL_SAMPLES, 1, &maxTextureSamples);
|
|
}
|
|
|
|
return maxTextureSamples;
|
|
}
|
|
|
|
} // MultisampleShaderRenderUtil
|
|
} // Functional
|
|
} // gles31
|
|
} // deqp
|