/*------------------------------------------------------------------------- * 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 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& 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::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 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 supportsES32orGL45 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) || glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)); map args; args["GLSL_VERSION_DECL"] = supportsES32orGL45 ? 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 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 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& 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