1/*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 3.1 Module 3 * ------------------------------------------------- 4 * 5 * Copyright 2014 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file 21 * \brief Multisample shader render case 22 *//*--------------------------------------------------------------------*/ 23 24#include "es31fMultisampleShaderRenderCase.hpp" 25#include "tcuRenderTarget.hpp" 26#include "tcuSurface.hpp" 27#include "tcuTestLog.hpp" 28#include "tcuStringTemplate.hpp" 29#include "gluContextInfo.hpp" 30#include "gluShaderProgram.hpp" 31#include "gluRenderContext.hpp" 32#include "gluPixelTransfer.hpp" 33#include "glwFunctions.hpp" 34#include "glwEnums.hpp" 35#include "deStringUtil.hpp" 36 37namespace deqp 38{ 39namespace gles31 40{ 41namespace Functional 42{ 43namespace MultisampleShaderRenderUtil 44{ 45using std::map; 46using std::string; 47namespace 48{ 49 50static const char* const s_vertexSource = "${GLSL_VERSION_DECL}\n" 51 "in highp vec4 a_position;\n" 52 "out highp vec4 v_position;\n" 53 "void main (void)\n" 54 "{\n" 55 " gl_Position = a_position;\n" 56 " v_position = a_position;\n" 57 "}"; 58 59} // anonymous 60 61QualityWarning::QualityWarning (const std::string& message) 62 : tcu::Exception(message) 63{ 64} 65 66MultisampleRenderCase::MultisampleRenderCase (Context& context, const char* name, const char* desc, int numSamples, RenderTarget target, int renderSize, int flags) 67 : TestCase (context, name, desc) 68 , m_numRequestedSamples (numSamples) 69 , m_renderTarget (target) 70 , m_renderSize (renderSize) 71 , m_perIterationShader ((flags & FLAG_PER_ITERATION_SHADER) != 0) 72 , m_verifyTextureSampleBuffers ((flags & FLAG_VERIFY_MSAA_TEXTURE_SAMPLE_BUFFERS) != 0 && target == TARGET_TEXTURE) 73 , m_numTargetSamples (-1) 74 , m_buffer (0) 75 , m_resolveBuffer (0) 76 , m_program (DE_NULL) 77 , m_fbo (0) 78 , m_fboTexture (0) 79 , m_textureSamplerProgram (DE_NULL) 80 , m_fboRbo (0) 81 , m_resolveFbo (0) 82 , m_resolveFboTexture (0) 83 , m_iteration (0) 84 , m_numIterations (1) 85 , m_renderMode (0) 86 , m_renderCount (0) 87 , m_renderVao (0) 88 , m_resolveVao (0) 89{ 90 DE_ASSERT(target < TARGET_LAST); 91} 92 93MultisampleRenderCase::~MultisampleRenderCase (void) 94{ 95 MultisampleRenderCase::deinit(); 96} 97 98void MultisampleRenderCase::init (void) 99{ 100 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 101 deInt32 queriedSampleCount = -1; 102 const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)); 103 map<string, string> args; 104 105 args["GLSL_VERSION_DECL"] = supportsES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES); 106 107 // requirements 108 109 switch (m_renderTarget) 110 { 111 case TARGET_DEFAULT: 112 { 113 if (m_context.getRenderTarget().getWidth() < m_renderSize || m_context.getRenderTarget().getHeight() < m_renderSize) 114 throw tcu::NotSupportedError("Test requires render target with size " + de::toString(m_renderSize) + "x" + de::toString(m_renderSize) + " or greater"); 115 break; 116 } 117 118 case TARGET_TEXTURE: 119 { 120 deInt32 maxTextureSamples = getMaxConformantSampleCount(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8); 121 if (m_numRequestedSamples > maxTextureSamples) 122 throw tcu::NotSupportedError("Sample count not supported"); 123 break; 124 } 125 126 case TARGET_RENDERBUFFER: 127 { 128 deInt32 maxRboSamples = getMaxConformantSampleCount(GL_RENDERBUFFER, GL_RGBA8); 129 if (m_numRequestedSamples > maxRboSamples) 130 throw tcu::NotSupportedError("Sample count not supported"); 131 break; 132 } 133 134 default: 135 DE_ASSERT(false); 136 } 137 138 // resources 139 140 { 141 gl.genBuffers(1, &m_buffer); 142 GLU_EXPECT_NO_ERROR(gl.getError(), "gen buf"); 143 144 setupRenderData(); 145 GLU_EXPECT_NO_ERROR(gl.getError(), "setup data"); 146 147 gl.genVertexArrays(1, &m_renderVao); 148 GLU_EXPECT_NO_ERROR(gl.getError(), "gen vao"); 149 150 // buffer for MSAA texture resolving 151 { 152 static const tcu::Vec4 fullscreenQuad[] = 153 { 154 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f), 155 tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f), 156 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), 157 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), 158 }; 159 160 gl.genBuffers(1, &m_resolveBuffer); 161 gl.bindBuffer(GL_ARRAY_BUFFER, m_resolveBuffer); 162 gl.bufferData(GL_ARRAY_BUFFER, (int)sizeof(fullscreenQuad), fullscreenQuad, GL_STATIC_DRAW); 163 GLU_EXPECT_NO_ERROR(gl.getError(), "setup data"); 164 } 165 } 166 167 // msaa targets 168 169 if (m_renderTarget == TARGET_TEXTURE) 170 { 171 const deUint32 textureTarget = (m_numRequestedSamples == 0) ? (GL_TEXTURE_2D) : (GL_TEXTURE_2D_MULTISAMPLE); 172 173 gl.genVertexArrays(1, &m_resolveVao); 174 GLU_EXPECT_NO_ERROR(gl.getError(), "gen vao"); 175 176 gl.genTextures(1, &m_fboTexture); 177 gl.bindTexture(textureTarget, m_fboTexture); 178 if (m_numRequestedSamples == 0) 179 { 180 gl.texStorage2D(textureTarget, 1, GL_RGBA8, m_renderSize, m_renderSize); 181 gl.texParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 182 gl.texParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 183 } 184 else 185 gl.texStorage2DMultisample(textureTarget, m_numRequestedSamples, GL_RGBA8, m_renderSize, m_renderSize, GL_FALSE); 186 GLU_EXPECT_NO_ERROR(gl.getError(), "gen tex"); 187 188 gl.genFramebuffers(1, &m_fbo); 189 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo); 190 gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureTarget, m_fboTexture, 0); 191 GLU_EXPECT_NO_ERROR(gl.getError(), "gen fbo"); 192 193 if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) 194 throw tcu::TestError("fbo not complete"); 195 196 if (m_numRequestedSamples != 0) 197 { 198 // for shader 199 gl.getTexLevelParameteriv(GL_TEXTURE_2D_MULTISAMPLE, 0, GL_TEXTURE_SAMPLES, &queriedSampleCount); 200 201 // logging 202 m_testCtx.getLog() << tcu::TestLog::Message << "Asked for " << m_numRequestedSamples << " samples, got " << queriedSampleCount << " samples." << tcu::TestLog::EndMessage; 203 204 // sanity 205 if (queriedSampleCount < m_numRequestedSamples) 206 throw tcu::TestError("Got less texture samples than asked for"); 207 } 208 209 // texture sampler shader 210 m_textureSamplerProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() 211 << glu::VertexSource(tcu::StringTemplate(s_vertexSource).specialize(args)) 212 << glu::FragmentSource(genMSSamplerSource(queriedSampleCount))); 213 if (!m_textureSamplerProgram->isOk()) 214 { 215 m_testCtx.getLog() << tcu::TestLog::Section("SamplerShader", "Sampler shader") << *m_textureSamplerProgram << tcu::TestLog::EndSection; 216 throw tcu::TestError("could not build program"); 217 } 218 } 219 else if (m_renderTarget == TARGET_RENDERBUFFER) 220 { 221 gl.genRenderbuffers(1, &m_fboRbo); 222 gl.bindRenderbuffer(GL_RENDERBUFFER, m_fboRbo); 223 gl.renderbufferStorageMultisample(GL_RENDERBUFFER, m_numRequestedSamples, GL_RGBA8, m_renderSize, m_renderSize); 224 GLU_EXPECT_NO_ERROR(gl.getError(), "gen rbo"); 225 226 gl.genFramebuffers(1, &m_fbo); 227 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo); 228 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_fboRbo); 229 GLU_EXPECT_NO_ERROR(gl.getError(), "gen fbo"); 230 231 if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) 232 throw tcu::TestError("fbo not complete"); 233 234 // logging 235 gl.getRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &queriedSampleCount); 236 m_testCtx.getLog() << tcu::TestLog::Message << "Asked for " << m_numRequestedSamples << " samples, got " << queriedSampleCount << " samples." << tcu::TestLog::EndMessage; 237 238 // sanity 239 if (queriedSampleCount < m_numRequestedSamples) 240 throw tcu::TestError("Got less renderbuffer samples samples than asked for"); 241 } 242 243 // fbo for resolving the multisample fbo 244 if (m_renderTarget != TARGET_DEFAULT) 245 { 246 gl.genTextures(1, &m_resolveFboTexture); 247 gl.bindTexture(GL_TEXTURE_2D, m_resolveFboTexture); 248 gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, m_renderSize, m_renderSize); 249 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 250 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 251 GLU_EXPECT_NO_ERROR(gl.getError(), "gen tex"); 252 253 gl.genFramebuffers(1, &m_resolveFbo); 254 gl.bindFramebuffer(GL_FRAMEBUFFER, m_resolveFbo); 255 gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_resolveFboTexture, 0); 256 GLU_EXPECT_NO_ERROR(gl.getError(), "gen fbo"); 257 258 if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) 259 throw tcu::TestError("resolve fbo not complete"); 260 } 261 262 // create verifier shader and set targetSampleCount 263 264 { 265 int realSampleCount = -1; 266 267 if (m_renderTarget == TARGET_TEXTURE) 268 { 269 if (m_numRequestedSamples == 0) 270 realSampleCount = 1; // non msaa texture 271 else 272 realSampleCount = de::max(1, queriedSampleCount); // msaa texture 273 } 274 else if (m_renderTarget == TARGET_RENDERBUFFER) 275 { 276 realSampleCount = de::max(1, queriedSampleCount); // msaa rbo 277 } 278 else if (m_renderTarget == TARGET_DEFAULT) 279 { 280 realSampleCount = de::max(1, m_context.getRenderTarget().getNumSamples()); 281 } 282 else 283 DE_ASSERT(DE_FALSE); 284 285 // is set and is valid 286 DE_ASSERT(realSampleCount != -1); 287 DE_ASSERT(realSampleCount != 0); 288 m_numTargetSamples = realSampleCount; 289 } 290 291 if (!m_perIterationShader) 292 { 293 m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(genVertexSource(m_numTargetSamples)) << glu::FragmentSource(genFragmentSource(m_numTargetSamples))); 294 m_testCtx.getLog() << tcu::TestLog::Section("RenderShader", "Render shader") << *m_program << tcu::TestLog::EndSection; 295 if (!m_program->isOk()) 296 throw tcu::TestError("could not build program"); 297 298 } 299} 300 301void MultisampleRenderCase::deinit (void) 302{ 303 if (m_buffer) 304 { 305 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_buffer); 306 m_buffer = 0; 307 } 308 309 if (m_resolveBuffer) 310 { 311 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_resolveBuffer); 312 m_resolveBuffer = 0; 313 } 314 315 delete m_program; 316 m_program = DE_NULL; 317 318 if (m_fbo) 319 { 320 m_context.getRenderContext().getFunctions().deleteFramebuffers(1, &m_fbo); 321 m_fbo = 0; 322 } 323 324 if (m_fboTexture) 325 { 326 m_context.getRenderContext().getFunctions().deleteTextures(1, &m_fboTexture); 327 m_fboTexture = 0; 328 } 329 330 delete m_textureSamplerProgram; 331 m_textureSamplerProgram = DE_NULL; 332 333 if (m_fboRbo) 334 { 335 m_context.getRenderContext().getFunctions().deleteRenderbuffers(1, &m_fboRbo); 336 m_fboRbo = 0; 337 } 338 339 if (m_resolveFbo) 340 { 341 m_context.getRenderContext().getFunctions().deleteFramebuffers(1, &m_resolveFbo); 342 m_resolveFbo = 0; 343 } 344 345 if (m_resolveFboTexture) 346 { 347 m_context.getRenderContext().getFunctions().deleteTextures(1, &m_resolveFboTexture); 348 m_resolveFboTexture = 0; 349 } 350 351 if (m_renderVao) 352 { 353 m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_renderVao); 354 m_renderVao = 0; 355 } 356 357 if (m_resolveVao) 358 { 359 m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_resolveVao); 360 m_resolveVao = 0; 361 } 362} 363 364MultisampleRenderCase::IterateResult MultisampleRenderCase::iterate (void) 365{ 366 // default value 367 if (m_iteration == 0) 368 { 369 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 370 preTest(); 371 } 372 373 drawOneIteration(); 374 375 // next iteration 376 ++m_iteration; 377 if (m_iteration < m_numIterations) 378 return CONTINUE; 379 else 380 { 381 postTest(); 382 return STOP; 383 } 384} 385 386void MultisampleRenderCase::preDraw (void) 387{ 388} 389 390void MultisampleRenderCase::postDraw (void) 391{ 392} 393 394void MultisampleRenderCase::preTest (void) 395{ 396} 397 398void MultisampleRenderCase::postTest (void) 399{ 400} 401 402void MultisampleRenderCase::verifyResultImageAndSetResult (const tcu::Surface& resultImage) 403{ 404 // verify using case-specific verification 405 406 try 407 { 408 if (!verifyImage(resultImage)) 409 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed"); 410 } 411 catch (const QualityWarning& ex) 412 { 413 m_testCtx.getLog() << tcu::TestLog::Message << "Quality warning, error = " << ex.what() << tcu::TestLog::EndMessage; 414 415 // Failures are more important than warnings 416 if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) 417 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, ex.what()); 418 } 419} 420 421void MultisampleRenderCase::verifyResultBuffersAndSetResult (const std::vector<tcu::Surface>& resultBuffers) 422{ 423 // verify using case-specific verification 424 425 try 426 { 427 if (!verifySampleBuffers(resultBuffers)) 428 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed"); 429 } 430 catch (const QualityWarning& ex) 431 { 432 m_testCtx.getLog() << tcu::TestLog::Message << "Quality warning, error = " << ex.what() << tcu::TestLog::EndMessage; 433 434 // Failures are more important than warnings 435 if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) 436 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, ex.what()); 437 } 438} 439 440std::string MultisampleRenderCase::getIterationDescription (int iteration) const 441{ 442 DE_UNREF(iteration); 443 DE_ASSERT(false); 444 return ""; 445} 446 447void MultisampleRenderCase::drawOneIteration (void) 448{ 449 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 450 const std::string sectionDescription = (m_numIterations > 1) ? ("Iteration " + de::toString(m_iteration+1) + "/" + de::toString(m_numIterations) + ": " + getIterationDescription(m_iteration)) : ("Test"); 451 const tcu::ScopedLogSection section (m_testCtx.getLog(), "Iteration" + de::toString(m_iteration), sectionDescription); 452 453 // Per iteration shader? 454 if (m_perIterationShader) 455 { 456 delete m_program; 457 m_program = DE_NULL; 458 459 m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() 460 << glu::VertexSource(genVertexSource(m_numTargetSamples)) 461 << glu::FragmentSource(genFragmentSource(m_numTargetSamples))); 462 m_testCtx.getLog() << tcu::TestLog::Section("RenderShader", "Render shader") << *m_program << tcu::TestLog::EndSection; 463 if (!m_program->isOk()) 464 throw tcu::TestError("could not build program"); 465 466 } 467 468 // render 469 { 470 if (m_renderTarget == TARGET_TEXTURE || m_renderTarget == TARGET_RENDERBUFFER) 471 { 472 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo); 473 GLU_EXPECT_NO_ERROR(gl.getError(), "bind fbo"); 474 475 m_testCtx.getLog() << tcu::TestLog::Message << "Rendering " << m_renderSceneDescription << " with render shader to fbo." << tcu::TestLog::EndMessage; 476 } 477 else 478 m_testCtx.getLog() << tcu::TestLog::Message << "Rendering " << m_renderSceneDescription << " with render shader to default framebuffer." << tcu::TestLog::EndMessage; 479 480 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); 481 gl.clear(GL_COLOR_BUFFER_BIT); 482 gl.viewport(0, 0, m_renderSize, m_renderSize); 483 GLU_EXPECT_NO_ERROR(gl.getError(), "clear"); 484 485 gl.bindVertexArray(m_renderVao); 486 gl.bindBuffer(GL_ARRAY_BUFFER, m_buffer); 487 488 // set attribs 489 DE_ASSERT(!m_renderAttribs.empty()); 490 for (std::map<std::string, Attrib>::const_iterator it = m_renderAttribs.begin(); it != m_renderAttribs.end(); ++it) 491 { 492 const deInt32 location = gl.getAttribLocation(m_program->getProgram(), it->first.c_str()); 493 494 if (location != -1) 495 { 496 gl.vertexAttribPointer(location, 4, GL_FLOAT, GL_FALSE, it->second.stride, glu::BufferOffsetAsPointer(it->second.offset)); 497 gl.enableVertexAttribArray(location); 498 } 499 } 500 GLU_EXPECT_NO_ERROR(gl.getError(), "set attrib"); 501 502 gl.useProgram(m_program->getProgram()); 503 preDraw(); 504 gl.drawArrays(m_renderMode, 0, m_renderCount); 505 postDraw(); 506 gl.useProgram(0); 507 gl.bindVertexArray(0); 508 GLU_EXPECT_NO_ERROR(gl.getError(), "draw"); 509 510 if (m_renderTarget == TARGET_TEXTURE || m_renderTarget == TARGET_RENDERBUFFER) 511 gl.bindFramebuffer(GL_FRAMEBUFFER, 0); 512 } 513 514 // read 515 { 516 if (m_renderTarget == TARGET_DEFAULT) 517 { 518 tcu::Surface resultImage(m_renderSize, m_renderSize); 519 520 m_testCtx.getLog() << tcu::TestLog::Message << "Reading pixels from default framebuffer." << tcu::TestLog::EndMessage; 521 522 // default directly 523 glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess()); 524 GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels"); 525 526 // set test result 527 verifyResultImageAndSetResult(resultImage); 528 } 529 else if (m_renderTarget == TARGET_RENDERBUFFER) 530 { 531 tcu::Surface resultImage(m_renderSize, m_renderSize); 532 533 // rbo by blitting to non-multisample fbo 534 535 m_testCtx.getLog() << tcu::TestLog::Message << "Blitting result from fbo to single sample fbo. (Resolve multisample)" << tcu::TestLog::EndMessage; 536 537 gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo); 538 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_resolveFbo); 539 gl.blitFramebuffer(0, 0, m_renderSize, m_renderSize, 0, 0, m_renderSize, m_renderSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); 540 GLU_EXPECT_NO_ERROR(gl.getError(), "blit resolve"); 541 542 m_testCtx.getLog() << tcu::TestLog::Message << "Reading pixels from single sample framebuffer." << tcu::TestLog::EndMessage; 543 544 gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_resolveFbo); 545 glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess()); 546 GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels"); 547 548 gl.bindFramebuffer(GL_FRAMEBUFFER, 0); 549 550 // set test result 551 verifyResultImageAndSetResult(resultImage); 552 } 553 else if (m_renderTarget == TARGET_TEXTURE && !m_verifyTextureSampleBuffers) 554 { 555 const deInt32 posLocation = gl.getAttribLocation(m_textureSamplerProgram->getProgram(), "a_position"); 556 const deInt32 samplerLocation = gl.getUniformLocation(m_textureSamplerProgram->getProgram(), "u_sampler"); 557 const deUint32 textureTarget = (m_numRequestedSamples == 0) ? (GL_TEXTURE_2D) : (GL_TEXTURE_2D_MULTISAMPLE); 558 tcu::Surface resultImage (m_renderSize, m_renderSize); 559 560 if (m_numRequestedSamples) 561 m_testCtx.getLog() << tcu::TestLog::Message << "Using sampler shader to sample the multisample texture to single sample framebuffer." << tcu::TestLog::EndMessage; 562 else 563 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing texture to single sample framebuffer. Using sampler shader." << tcu::TestLog::EndMessage; 564 565 if (samplerLocation == -1) 566 throw tcu::TestError("Location u_sampler was -1."); 567 568 // resolve multisample texture by averaging 569 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); 570 gl.clear(GL_COLOR_BUFFER_BIT); 571 gl.viewport(0, 0, m_renderSize, m_renderSize); 572 GLU_EXPECT_NO_ERROR(gl.getError(), "clear"); 573 574 gl.bindVertexArray(m_resolveVao); 575 gl.bindBuffer(GL_ARRAY_BUFFER, m_resolveBuffer); 576 gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); 577 gl.enableVertexAttribArray(posLocation); 578 GLU_EXPECT_NO_ERROR(gl.getError(), "set attrib"); 579 580 gl.activeTexture(GL_TEXTURE0); 581 gl.bindTexture(textureTarget, m_fboTexture); 582 GLU_EXPECT_NO_ERROR(gl.getError(), "bind tex"); 583 584 gl.useProgram(m_textureSamplerProgram->getProgram()); 585 gl.uniform1i(samplerLocation, 0); 586 587 gl.bindFramebuffer(GL_FRAMEBUFFER, m_resolveFbo); 588 gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4); 589 590 gl.useProgram(0); 591 gl.bindVertexArray(0); 592 GLU_EXPECT_NO_ERROR(gl.getError(), "draw"); 593 594 m_testCtx.getLog() << tcu::TestLog::Message << "Reading pixels from single sample framebuffer." << tcu::TestLog::EndMessage; 595 596 glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess()); 597 GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels"); 598 599 gl.bindFramebuffer(GL_FRAMEBUFFER, 0); 600 601 // set test result 602 verifyResultImageAndSetResult(resultImage); 603 } 604 else if (m_renderTarget == TARGET_TEXTURE && m_verifyTextureSampleBuffers) 605 { 606 const deInt32 posLocation = gl.getAttribLocation(m_textureSamplerProgram->getProgram(), "a_position"); 607 const deInt32 samplerLocation = gl.getUniformLocation(m_textureSamplerProgram->getProgram(), "u_sampler"); 608 const deInt32 sampleLocation = gl.getUniformLocation(m_textureSamplerProgram->getProgram(), "u_sampleNdx"); 609 const deUint32 textureTarget = (m_numRequestedSamples == 0) ? (GL_TEXTURE_2D) : (GL_TEXTURE_2D_MULTISAMPLE); 610 std::vector<tcu::Surface> resultBuffers (m_numTargetSamples); 611 612 if (m_numRequestedSamples) 613 m_testCtx.getLog() << tcu::TestLog::Message << "Reading multisample texture sample buffers." << tcu::TestLog::EndMessage; 614 else 615 m_testCtx.getLog() << tcu::TestLog::Message << "Reading texture." << tcu::TestLog::EndMessage; 616 617 if (samplerLocation == -1) 618 throw tcu::TestError("Location u_sampler was -1."); 619 if (sampleLocation == -1) 620 throw tcu::TestError("Location u_sampleNdx was -1."); 621 622 for (int sampleNdx = 0; sampleNdx < m_numTargetSamples; ++sampleNdx) 623 resultBuffers[sampleNdx].setSize(m_renderSize, m_renderSize); 624 625 // read sample buffers to different surfaces 626 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); 627 gl.clear(GL_COLOR_BUFFER_BIT); 628 gl.viewport(0, 0, m_renderSize, m_renderSize); 629 GLU_EXPECT_NO_ERROR(gl.getError(), "clear"); 630 631 gl.bindVertexArray(m_resolveVao); 632 gl.bindBuffer(GL_ARRAY_BUFFER, m_resolveBuffer); 633 gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); 634 gl.enableVertexAttribArray(posLocation); 635 GLU_EXPECT_NO_ERROR(gl.getError(), "set attrib"); 636 637 gl.activeTexture(GL_TEXTURE0); 638 gl.bindTexture(textureTarget, m_fboTexture); 639 GLU_EXPECT_NO_ERROR(gl.getError(), "bind tex"); 640 641 gl.bindFramebuffer(GL_FRAMEBUFFER, m_resolveFbo); 642 gl.useProgram(m_textureSamplerProgram->getProgram()); 643 gl.uniform1i(samplerLocation, 0); 644 645 m_testCtx.getLog() << tcu::TestLog::Message << "Reading sample buffers" << tcu::TestLog::EndMessage; 646 647 for (int sampleNdx = 0; sampleNdx < m_numTargetSamples; ++sampleNdx) 648 { 649 gl.uniform1i(sampleLocation, sampleNdx); 650 gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4); 651 GLU_EXPECT_NO_ERROR(gl.getError(), "draw"); 652 653 glu::readPixels(m_context.getRenderContext(), 0, 0, resultBuffers[sampleNdx].getAccess()); 654 GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels"); 655 } 656 657 gl.useProgram(0); 658 gl.bindVertexArray(0); 659 gl.bindFramebuffer(GL_FRAMEBUFFER, 0); 660 661 // verify sample buffers 662 verifyResultBuffersAndSetResult(resultBuffers); 663 } 664 else 665 DE_ASSERT(false); 666 } 667} 668 669std::string MultisampleRenderCase::genVertexSource (int numTargetSamples) const 670{ 671 const bool supportsES32orGL45 = 672 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) || 673 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)); 674 675 map<string, string> args; 676 677 args["GLSL_VERSION_DECL"] = supportsES32orGL45 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES); 678 679 DE_UNREF(numTargetSamples); 680 return std::string(tcu::StringTemplate(s_vertexSource).specialize(args)); 681} 682 683std::string MultisampleRenderCase::genMSSamplerSource (int numTargetSamples) const 684{ 685 if (m_verifyTextureSampleBuffers) 686 return genMSTextureLayerFetchSource(numTargetSamples); 687 else 688 return genMSTextureResolverSource(numTargetSamples); 689} 690 691std::string MultisampleRenderCase::genMSTextureResolverSource (int numTargetSamples) const 692{ 693 // default behavior: average 694 695 const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)); 696 map<string, string> args; 697 const bool isSingleSampleTarget = (m_numRequestedSamples == 0); 698 std::ostringstream buf; 699 700 args["GLSL_VERSION_DECL"] = supportsES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES); 701 702 buf << "${GLSL_VERSION_DECL}\n" 703 "in mediump vec4 v_position;\n" 704 "layout(location = 0) out mediump vec4 fragColor;\n" 705 "uniform mediump " << ((isSingleSampleTarget) ? ("sampler2D") : ("sampler2DMS")) << " u_sampler;\n" 706 "void main (void)\n" 707 "{\n" 708 " mediump vec2 relPosition = (v_position.xy + vec2(1.0, 1.0)) / 2.0;\n" 709 " mediump ivec2 fetchPos = ivec2(floor(relPosition * " << m_renderSize << ".0));\n" 710 " mediump vec4 colorSum = vec4(0.0, 0.0, 0.0, 0.0);\n" 711 "\n"; 712 713 if (isSingleSampleTarget) 714 buf << " colorSum = texelFetch(u_sampler, fetchPos, 0);\n" 715 "\n"; 716 else 717 buf << " for (int sampleNdx = 0; sampleNdx < " << numTargetSamples << "; ++sampleNdx)\n" 718 " colorSum += texelFetch(u_sampler, fetchPos, sampleNdx);\n" 719 " colorSum /= " << numTargetSamples << ".0;\n" 720 "\n"; 721 722 buf << " fragColor = vec4(colorSum.xyz, 1.0);\n" 723 "}\n"; 724 725 return tcu::StringTemplate(buf.str()).specialize(args); 726} 727 728std::string MultisampleRenderCase::genMSTextureLayerFetchSource (int numTargetSamples) const 729{ 730 DE_UNREF(numTargetSamples); 731 732 const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)); 733 map<string, string> args; 734 const bool isSingleSampleTarget = (m_numRequestedSamples == 0); 735 std::ostringstream buf; 736 737 args["GLSL_VERSION_DECL"] = supportsES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES); 738 739 buf << "${GLSL_VERSION_DECL}\n" 740 "in mediump vec4 v_position;\n" 741 "layout(location = 0) out mediump vec4 fragColor;\n" 742 "uniform mediump " << ((isSingleSampleTarget) ? ("sampler2D") : ("sampler2DMS")) << " u_sampler;\n" 743 "uniform mediump int u_sampleNdx;\n" 744 "void main (void)\n" 745 "{\n" 746 " mediump vec2 relPosition = (v_position.xy + vec2(1.0, 1.0)) / 2.0;\n" 747 " mediump ivec2 fetchPos = ivec2(floor(relPosition * " << m_renderSize << ".0));\n" 748 "\n" 749 " mediump vec4 color = texelFetch(u_sampler, fetchPos, u_sampleNdx);\n" 750 " fragColor = vec4(color.rgb, 1.0);\n" 751 "}\n"; 752 753 return tcu::StringTemplate(buf.str()).specialize(args); 754} 755 756bool MultisampleRenderCase::verifySampleBuffers (const std::vector<tcu::Surface>& resultBuffers) 757{ 758 DE_UNREF(resultBuffers); 759 DE_ASSERT(false); 760 return false; 761} 762 763void MultisampleRenderCase::setupRenderData (void) 764{ 765 static const tcu::Vec4 fullscreenQuad[] = 766 { 767 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f), 768 tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f), 769 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), 770 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), 771 }; 772 773 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 774 775 m_renderMode = GL_TRIANGLE_STRIP; 776 m_renderCount = 4; 777 m_renderSceneDescription = "quad"; 778 779 m_renderAttribs["a_position"].offset = 0; 780 m_renderAttribs["a_position"].stride = sizeof(float[4]); 781 782 gl.bindBuffer(GL_ARRAY_BUFFER, m_buffer); 783 gl.bufferData(GL_ARRAY_BUFFER, (int)sizeof(fullscreenQuad), fullscreenQuad, GL_STATIC_DRAW); 784} 785 786glw::GLint MultisampleRenderCase::getMaxConformantSampleCount(glw::GLenum target, glw::GLenum internalFormat) 787{ 788 deInt32 maxTextureSamples = 0; 789 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 790 791 if (m_context.getContextInfo().isExtensionSupported("GL_NV_internalformat_sample_query")) 792 { 793 glw::GLint gl_sample_counts = 0; 794 gl.getInternalformativ(target, internalFormat, GL_NUM_SAMPLE_COUNTS, 1, &gl_sample_counts); 795 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInternalformativ() failed for GL_NUM_SAMPLE_COUNTS pname"); 796 797 /* Check and return the first conformant sample count */ 798 glw::GLint* gl_supported_samples = new glw::GLint[gl_sample_counts]; 799 if (gl_supported_samples) 800 { 801 gl.getInternalformativ(target, internalFormat, GL_SAMPLES, gl_sample_counts, gl_supported_samples); 802 803 for (glw::GLint i = 0; i < gl_sample_counts; i++) 804 { 805 glw::GLint isConformant = 0; 806 gl.getInternalformatSampleivNV(target, internalFormat, gl_supported_samples[i], GL_CONFORMANT_NV, 1, 807 &isConformant); 808 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInternalformatSampleivNV() call(s) failed"); 809 810 if (isConformant && gl_supported_samples[i] > maxTextureSamples) 811 { 812 maxTextureSamples = gl_supported_samples[i]; 813 } 814 } 815 delete[] gl_supported_samples; 816 } 817 } 818 else 819 { 820 gl.getInternalformativ(target, internalFormat, GL_SAMPLES, 1, &maxTextureSamples); 821 } 822 823 return maxTextureSamples; 824} 825 826} // MultisampleShaderRenderUtil 827} // Functional 828} // gles31 829} // deqp 830