1/*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 3.0 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 FBO multisample tests. 22 *//*--------------------------------------------------------------------*/ 23 24#include "es3fApiCase.hpp" 25#include "es3fFboMultisampleTests.hpp" 26#include "es3fFboTestCase.hpp" 27#include "es3fFboTestUtil.hpp" 28#include "gluTextureUtil.hpp" 29#include "tcuImageCompare.hpp" 30#include "tcuTextureUtil.hpp" 31#include "tcuTestLog.hpp" 32#include "deStringUtil.hpp" 33#include "deRandom.hpp" 34#include "sglrContextUtil.hpp" 35#include "glwEnums.hpp" 36 37namespace deqp 38{ 39namespace gles3 40{ 41namespace Functional 42{ 43 44using std::string; 45using tcu::TestLog; 46using tcu::Vec2; 47using tcu::Vec3; 48using tcu::Vec4; 49using tcu::IVec2; 50using tcu::IVec3; 51using tcu::IVec4; 52using tcu::UVec4; 53using namespace FboTestUtil; 54 55class BasicFboMultisampleCase : public FboTestCase 56{ 57public: 58 BasicFboMultisampleCase (Context& context, const char* name, const char* desc, deUint32 colorFormat, deUint32 depthStencilFormat, const IVec2& size, int numSamples) 59 : FboTestCase (context, name, desc) 60 , m_colorFormat (colorFormat) 61 , m_depthStencilFormat (depthStencilFormat) 62 , m_size (size) 63 , m_numSamples (numSamples) 64 { 65 } 66 67protected: 68 void preCheck (void) 69 { 70 checkFormatSupport (m_colorFormat); 71 checkSampleCount (m_colorFormat, m_numSamples); 72 73 if (m_depthStencilFormat != GL_NONE) 74 { 75 checkFormatSupport (m_depthStencilFormat); 76 checkSampleCount (m_depthStencilFormat, m_numSamples); 77 } 78 } 79 80 void render (tcu::Surface& dst) 81 { 82 tcu::TextureFormat colorFmt = glu::mapGLInternalFormat(m_colorFormat); 83 tcu::TextureFormat depthStencilFmt = m_depthStencilFormat != GL_NONE ? glu::mapGLInternalFormat(m_depthStencilFormat) : tcu::TextureFormat(); 84 tcu::TextureFormatInfo colorFmtInfo = tcu::getTextureFormatInfo(colorFmt); 85 bool depth = depthStencilFmt.order == tcu::TextureFormat::D || depthStencilFmt.order == tcu::TextureFormat::DS; 86 bool stencil = depthStencilFmt.order == tcu::TextureFormat::S || depthStencilFmt.order == tcu::TextureFormat::DS; 87 GradientShader gradShader (getFragmentOutputType(colorFmt)); 88 FlatColorShader flatShader (getFragmentOutputType(colorFmt)); 89 deUint32 gradShaderID = getCurrentContext()->createProgram(&gradShader); 90 deUint32 flatShaderID = getCurrentContext()->createProgram(&flatShader); 91 deUint32 msaaFbo = 0; 92 deUint32 resolveFbo = 0; 93 deUint32 msaaColorRbo = 0; 94 deUint32 resolveColorRbo = 0; 95 deUint32 msaaDepthStencilRbo = 0; 96 deUint32 resolveDepthStencilRbo = 0; 97 98 // Create framebuffers. 99 for (int ndx = 0; ndx < 2; ndx++) 100 { 101 deUint32& fbo = ndx ? resolveFbo : msaaFbo; 102 deUint32& colorRbo = ndx ? resolveColorRbo : msaaColorRbo; 103 deUint32& depthStencilRbo = ndx ? resolveDepthStencilRbo : msaaDepthStencilRbo; 104 int samples = ndx ? 0 : m_numSamples; 105 106 glGenRenderbuffers(1, &colorRbo); 107 glBindRenderbuffer(GL_RENDERBUFFER, colorRbo); 108 glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, m_colorFormat, m_size.x(), m_size.y()); 109 110 if (depth || stencil) 111 { 112 glGenRenderbuffers(1, &depthStencilRbo); 113 glBindRenderbuffer(GL_RENDERBUFFER, depthStencilRbo); 114 glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, m_depthStencilFormat, m_size.x(), m_size.y()); 115 } 116 117 glGenFramebuffers(1, &fbo); 118 glBindFramebuffer(GL_FRAMEBUFFER, fbo); 119 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRbo); 120 if (depth) 121 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthStencilRbo); 122 if (stencil) 123 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthStencilRbo); 124 125 checkError(); 126 checkFramebufferStatus(GL_FRAMEBUFFER); 127 } 128 129 glBindFramebuffer(GL_FRAMEBUFFER, msaaFbo); 130 glViewport(0, 0, m_size.x(), m_size.y()); 131 132 // Clear depth and stencil buffers. 133 glClearBufferfi(GL_DEPTH_STENCIL, 0, 1.0f, 0); 134 135 // Fill MSAA fbo with gradient, depth = [-1..1] 136 glEnable(GL_DEPTH_TEST); 137 gradShader.setGradient(*getCurrentContext(), gradShaderID, colorFmtInfo.valueMin, colorFmtInfo.valueMax); 138 sglr::drawQuad(*getCurrentContext(), gradShaderID, Vec3(-1.0f, -1.0f, -1.0f), Vec3(1.0f, 1.0f, 1.0f)); 139 140 // Render random-colored quads. 141 { 142 const int numQuads = 8; 143 de::Random rnd (9); 144 145 glDepthFunc(GL_ALWAYS); 146 glEnable(GL_STENCIL_TEST); 147 glStencilFunc(GL_ALWAYS, 0, 0xffu); 148 glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); 149 150 for (int ndx = 0; ndx < numQuads; ndx++) 151 { 152 float r = rnd.getFloat(); 153 float g = rnd.getFloat(); 154 float b = rnd.getFloat(); 155 float a = rnd.getFloat(); 156 float x0 = rnd.getFloat(-1.0f, 1.0f); 157 float y0 = rnd.getFloat(-1.0f, 1.0f); 158 float z0 = rnd.getFloat(-1.0f, 1.0f); 159 float x1 = rnd.getFloat(-1.0f, 1.0f); 160 float y1 = rnd.getFloat(-1.0f, 1.0f); 161 float z1 = rnd.getFloat(-1.0f, 1.0f); 162 163 flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(r,g,b,a) * (colorFmtInfo.valueMax-colorFmtInfo.valueMin) + colorFmtInfo.valueMin); 164 sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(x0, y0, z0), Vec3(x1, y1, z1)); 165 } 166 } 167 168 glDisable(GL_DEPTH_TEST); 169 glDisable(GL_STENCIL_TEST); 170 checkError(); 171 172 // Resolve using glBlitFramebuffer(). 173 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFbo); 174 glBlitFramebuffer(0, 0, m_size.x(), m_size.y(), 0, 0, m_size.x(), m_size.y(), GL_COLOR_BUFFER_BIT | (depth ? GL_DEPTH_BUFFER_BIT : 0) | (stencil ? GL_STENCIL_BUFFER_BIT : 0), GL_NEAREST); 175 176 glBindFramebuffer(GL_READ_FRAMEBUFFER, resolveFbo); 177 178 if (depth) 179 { 180 // Visualize depth. 181 const int numSteps = 8; 182 const float step = 2.0f / (float)numSteps; 183 184 glEnable(GL_DEPTH_TEST); 185 glDepthFunc(GL_LESS); 186 glDepthMask(GL_FALSE); 187 glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE); 188 189 for (int ndx = 0; ndx < numSteps; ndx++) 190 { 191 float d = -1.0f + step*(float)ndx; 192 float c = (float)ndx / (float)(numSteps-1); 193 194 flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(0.0f, 0.0f, c, 1.0f) * (colorFmtInfo.valueMax-colorFmtInfo.valueMin) + colorFmtInfo.valueMin); 195 sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-1.0f, -1.0f, d), Vec3(1.0f, 1.0f, d)); 196 } 197 198 glDisable(GL_DEPTH_TEST); 199 } 200 201 if (stencil) 202 { 203 // Visualize stencil. 204 const int numSteps = 4; 205 const int step = 1; 206 207 glEnable(GL_STENCIL_TEST); 208 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); 209 glColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_FALSE); 210 211 for (int ndx = 0; ndx < numSteps; ndx++) 212 { 213 int s = step*ndx; 214 float c = (float)ndx / (float)(numSteps-1); 215 216 glStencilFunc(GL_EQUAL, s, 0xffu); 217 218 flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(0.0f, c, 0.0f, 1.0f) * (colorFmtInfo.valueMax-colorFmtInfo.valueMin) + colorFmtInfo.valueMin); 219 sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); 220 } 221 222 glDisable(GL_STENCIL_TEST); 223 } 224 225 readPixels(dst, 0, 0, m_size.x(), m_size.y(), colorFmt, colorFmtInfo.lookupScale, colorFmtInfo.lookupBias); 226 } 227 228 bool colorCompare (const tcu::Surface& reference, const tcu::Surface& result) 229 { 230 const tcu::RGBA threshold (tcu::max(getFormatThreshold(m_colorFormat), tcu::RGBA(12, 12, 12, 12))); 231 232 return tcu::bilinearCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference.getAccess(), result.getAccess(), threshold, tcu::COMPARE_LOG_RESULT); 233 } 234 235 bool compare (const tcu::Surface& reference, const tcu::Surface& result) 236 { 237 if (m_depthStencilFormat != GL_NONE) 238 return FboTestCase::compare(reference, result); 239 else 240 return colorCompare(reference, result); 241 } 242 243private: 244 deUint32 m_colorFormat; 245 deUint32 m_depthStencilFormat; 246 IVec2 m_size; 247 int m_numSamples; 248}; 249 250// Ported from WebGL [1], originally written to test a Qualcomm driver bug [2]. 251// [1] https://github.com/KhronosGroup/WebGL/blob/master/sdk/tests/conformance2/renderbuffers/multisampled-renderbuffer-initialization.html 252// [2] http://crbug.com/696126 253class RenderbufferResizeCase : public ApiCase 254{ 255public: 256 RenderbufferResizeCase (Context& context, const char* name, const char* desc, bool multisampled1, bool multisampled2) 257 : ApiCase (context, name, desc) 258 , m_multisampled1(multisampled1) 259 , m_multisampled2(multisampled2) 260 { 261 } 262 263protected: 264 void test () 265 { 266 glDisable(GL_DEPTH_TEST); 267 268 int maxSamples = 0; 269 glGetInternalformativ(GL_RENDERBUFFER, GL_RGBA8, GL_SAMPLES, 1, &maxSamples); 270 deUint32 samp1 = m_multisampled1 ? maxSamples : 0; 271 deUint32 samp2 = m_multisampled2 ? maxSamples : 0; 272 273 static const deUint32 W1 = 10, H1 = 10; 274 static const deUint32 W2 = 40, H2 = 40; 275 276 // Set up non-multisampled buffer to blit to and read back from. 277 deUint32 fboResolve = 0; 278 deUint32 rboResolve = 0; 279 { 280 glGenFramebuffers(1, &fboResolve); 281 glBindFramebuffer(GL_FRAMEBUFFER, fboResolve); 282 glGenRenderbuffers(1, &rboResolve); 283 glBindRenderbuffer(GL_RENDERBUFFER, rboResolve); 284 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, W2, H2); 285 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rboResolve); 286 TCU_CHECK(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); 287 glClearBufferfv(GL_COLOR, 0, Vec4(1.0f, 0.0f, 0.0f, 1.0f).getPtr()); 288 } 289 expectError(GL_NO_ERROR); 290 291 // Set up multisampled buffer to test. 292 deUint32 fboMultisampled = 0; 293 deUint32 rboMultisampled = 0; 294 { 295 glGenFramebuffers(1, &fboMultisampled); 296 glBindFramebuffer(GL_FRAMEBUFFER, fboMultisampled); 297 glGenRenderbuffers(1, &rboMultisampled); 298 glBindRenderbuffer(GL_RENDERBUFFER, rboMultisampled); 299 // Allocate, 300 glRenderbufferStorageMultisample(GL_RENDERBUFFER, samp1, GL_RGBA8, W1, H1); 301 // attach, 302 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rboMultisampled); 303 TCU_CHECK(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); 304 glClearBufferfv(GL_COLOR, 0, Vec4(0.0f, 0.0f, 1.0f, 1.0f).getPtr()); 305 // and allocate again with different parameters. 306 glRenderbufferStorageMultisample(GL_RENDERBUFFER, samp2, GL_RGBA8, W2, H2); 307 TCU_CHECK(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); 308 glClearBufferfv(GL_COLOR, 0, Vec4(0.0f, 1.0f, 0.0f, 1.0f).getPtr()); 309 } 310 expectError(GL_NO_ERROR); 311 312 // This is a blit from the multisampled buffer to the non-multisampled buffer. 313 glBindFramebuffer(GL_READ_FRAMEBUFFER, fboMultisampled); 314 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboResolve); 315 // Blit color from fboMultisampled (should be green) to fboResolve (should currently be red). 316 glBlitFramebuffer(0, 0, W2, H2, 0, 0, W2, H2, GL_COLOR_BUFFER_BIT, GL_NEAREST); 317 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); 318 expectError(GL_NO_ERROR); 319 320 // fboResolve should now be green. 321 glBindFramebuffer(GL_READ_FRAMEBUFFER, fboResolve); 322 deUint32 pixels[W2 * H2] = {}; 323 glReadPixels(0, 0, W2, H2, GL_RGBA, GL_UNSIGNED_BYTE, pixels); 324 expectError(GL_NO_ERROR); 325 326 const tcu::RGBA threshold (tcu::max(getFormatThreshold(GL_RGBA8), tcu::RGBA(12, 12, 12, 12))); 327 for (deUint32 y = 0; y < H2; ++y) 328 { 329 for (deUint32 x = 0; x < W2; ++x) 330 { 331 tcu::RGBA color(pixels[y * W2 + x]); 332 TCU_CHECK(compareThreshold(color, tcu::RGBA::green(), threshold)); 333 } 334 } 335 } 336 337private: 338 bool m_multisampled1; 339 bool m_multisampled2; 340}; 341 342FboMultisampleTests::FboMultisampleTests (Context& context) 343 : TestCaseGroup(context, "msaa", "Multisample FBO tests") 344{ 345} 346 347FboMultisampleTests::~FboMultisampleTests (void) 348{ 349} 350 351void FboMultisampleTests::init (void) 352{ 353 static const deUint32 colorFormats[] = 354 { 355 // RGBA formats 356 GL_RGBA8, 357 GL_SRGB8_ALPHA8, 358 GL_RGB10_A2, 359 GL_RGBA4, 360 GL_RGB5_A1, 361 362 // RGB formats 363 GL_RGB8, 364 GL_RGB565, 365 366 // RG formats 367 GL_RG8, 368 369 // R formats 370 GL_R8, 371 372 // GL_EXT_color_buffer_float 373 GL_RGBA32F, 374 GL_RGBA16F, 375 GL_R11F_G11F_B10F, 376 GL_RG32F, 377 GL_RG16F, 378 GL_R32F, 379 GL_R16F 380 }; 381 382 static const deUint32 depthStencilFormats[] = 383 { 384 GL_DEPTH_COMPONENT32F, 385 GL_DEPTH_COMPONENT24, 386 GL_DEPTH_COMPONENT16, 387 GL_DEPTH32F_STENCIL8, 388 GL_DEPTH24_STENCIL8, 389 GL_STENCIL_INDEX8 390 }; 391 392 static const int sampleCounts[] = { 2, 4, 8 }; 393 394 for (int sampleCntNdx = 0; sampleCntNdx < DE_LENGTH_OF_ARRAY(sampleCounts); sampleCntNdx++) 395 { 396 int samples = sampleCounts[sampleCntNdx]; 397 tcu::TestCaseGroup* sampleCountGroup = new tcu::TestCaseGroup(m_testCtx, (de::toString(samples) + "_samples").c_str(), ""); 398 addChild(sampleCountGroup); 399 400 // Color formats. 401 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++) 402 sampleCountGroup->addChild(new BasicFboMultisampleCase(m_context, getFormatName(colorFormats[fmtNdx]), "", colorFormats[fmtNdx], GL_NONE, IVec2(119, 131), samples)); 403 404 // Depth/stencil formats. 405 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(depthStencilFormats); fmtNdx++) 406 sampleCountGroup->addChild(new BasicFboMultisampleCase(m_context, getFormatName(depthStencilFormats[fmtNdx]), "", GL_RGBA8, depthStencilFormats[fmtNdx], IVec2(119, 131), samples)); 407 } 408 409 // .renderbuffer_resize 410 { 411 tcu::TestCaseGroup* group = new tcu::TestCaseGroup(m_testCtx, "renderbuffer_resize", "Multisample renderbuffer resize"); 412 addChild(group); 413 414 { 415 group->addChild(new RenderbufferResizeCase(m_context, "nonms_to_nonms", "", false, false)); 416 group->addChild(new RenderbufferResizeCase(m_context, "nonms_to_ms", "", false, true)); 417 group->addChild(new RenderbufferResizeCase(m_context, "ms_to_nonms", "", true, false)); 418 group->addChild(new RenderbufferResizeCase(m_context, "ms_to_ms", "", true, true)); 419 } 420 } 421} 422 423} // Functional 424} // gles3 425} // deqp 426