1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 2.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 Screen clearing test. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es2fColorClearTest.hpp" 25 #include "tcuRGBA.hpp" 26 #include "tcuSurface.hpp" 27 #include "tcuTestLog.hpp" 28 #include "gluRenderContext.hpp" 29 #include "gluPixelTransfer.hpp" 30 #include "tcuVector.hpp" 31 #include "tcuRenderTarget.hpp" 32 #include "deRandom.hpp" 33 #include "deInt32.h" 34 35 #include "glwFunctions.hpp" 36 #include "glwEnums.hpp" 37 38 #include <vector> 39 40 using tcu::RGBA; 41 using tcu::Surface; 42 using tcu::TestLog; 43 44 using namespace std; 45 46 namespace deqp 47 { 48 namespace gles2 49 { 50 namespace Functional 51 { 52 53 class ColorClearCase : public TestCase 54 { 55 public: 56 ColorClearCase(Context& context, const char* name, int numIters, int numClearsMin, int numClearsMax, bool testAlpha, bool testScissoring, bool testColorMasks, bool firstClearFull) 57 : TestCase (context, name, name) 58 , m_numIters (numIters) 59 , m_numClearsMin (numClearsMin) 60 , m_numClearsMax (numClearsMax) 61 , m_testAlpha (testAlpha) 62 , m_testScissoring (testScissoring) 63 , m_testColorMasks (testColorMasks) 64 , m_firstClearFull (firstClearFull) 65 { 66 m_curIter = 0; 67 } 68 69 virtual ~ColorClearCase (void) 70 { 71 } 72 73 virtual IterateResult iterate (void); 74 75 private: 76 const int m_numIters; 77 const int m_numClearsMin; 78 const int m_numClearsMax; 79 const bool m_testAlpha; 80 const bool m_testScissoring; 81 const bool m_testColorMasks; 82 const bool m_firstClearFull; 83 84 int m_curIter; 85 }; 86 87 class ClearInfo 88 { 89 public: 90 ClearInfo (const tcu::IVec4& rect, deUint8 colorMask, tcu::RGBA color) 91 : m_rect(rect), m_colorMask(colorMask), m_color(color) 92 { 93 } 94 95 tcu::IVec4 m_rect; 96 deUint8 m_colorMask; 97 tcu::RGBA m_color; 98 }; 99 100 TestCase::IterateResult ColorClearCase::iterate (void) 101 { 102 TestLog& log = m_testCtx.getLog(); 103 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 104 const tcu::RenderTarget& renderTarget = m_context.getRenderTarget(); 105 const tcu::PixelFormat& pixelFormat = renderTarget.getPixelFormat(); 106 const int targetWidth = renderTarget.getWidth(); 107 const int targetHeight = renderTarget.getHeight(); 108 const int numPixels = targetWidth * targetHeight; 109 110 de::Random rnd (deInt32Hash(m_curIter)); 111 vector<deUint8> pixelKnownChannelMask (numPixels, 0); 112 Surface refImage (targetWidth, targetHeight); 113 Surface resImage (targetWidth, targetHeight); 114 Surface diffImage (targetWidth, targetHeight); 115 int numClears = rnd.getUint32() % (m_numClearsMax + 1 - m_numClearsMin) + m_numClearsMin; 116 std::vector<ClearInfo> clearOps; 117 118 if (m_testScissoring) 119 gl.enable(GL_SCISSOR_TEST); 120 121 for (int clearNdx = 0; clearNdx < numClears; clearNdx++) 122 { 123 // Rectangle. 124 int clearX; 125 int clearY; 126 int clearWidth; 127 int clearHeight; 128 if (!m_testScissoring || (clearNdx == 0 && m_firstClearFull)) 129 { 130 clearX = 0; 131 clearY = 0; 132 clearWidth = targetWidth; 133 clearHeight = targetHeight; 134 } 135 else 136 { 137 clearX = (rnd.getUint32() % (2*targetWidth)) - targetWidth; 138 clearY = (rnd.getUint32() % (2*targetHeight)) - targetHeight; 139 clearWidth = (rnd.getUint32() % targetWidth); 140 clearHeight = (rnd.getUint32() % targetHeight); 141 } 142 gl.scissor(clearX, clearY, clearWidth, clearHeight); 143 144 // Color. 145 int r = (int)(rnd.getUint32() & 0xFF); 146 int g = (int)(rnd.getUint32() & 0xFF); 147 int b = (int)(rnd.getUint32() & 0xFF); 148 int a = m_testAlpha ? (int)(rnd.getUint32() & 0xFF) : 0xFF; 149 RGBA clearCol(r, g, b, a); 150 gl.clearColor(float(r)/255.0f, float(g)/255.0f, float(b)/255.0f, float(a)/255.0f); 151 152 // Mask. 153 deUint8 clearMask; 154 if (!m_testColorMasks || (clearNdx == 0 && m_firstClearFull)) 155 clearMask = 0xF; 156 else 157 clearMask = (rnd.getUint32() & 0xF); 158 gl.colorMask((clearMask&0x1) != 0, (clearMask&0x2) != 0, (clearMask&0x4) != 0, (clearMask&0x8) != 0); 159 160 // Clear & store op. 161 gl.clear(GL_COLOR_BUFFER_BIT); 162 clearOps.push_back(ClearInfo(tcu::IVec4(clearX, clearY, clearWidth, clearHeight), clearMask, clearCol)); 163 164 // Let watchdog know we're alive. 165 m_testCtx.touchWatchdog(); 166 } 167 168 // Compute reference image. 169 { 170 for (int y = 0; y < targetHeight; y++) 171 { 172 std::vector<ClearInfo> scanlineClearOps; 173 174 // Find all rectangles affecting this scanline. 175 for (int opNdx = 0; opNdx < (int)clearOps.size(); opNdx++) 176 { 177 ClearInfo& op = clearOps[opNdx]; 178 if (de::inBounds(y, op.m_rect.y(), op.m_rect.y()+op.m_rect.w())) 179 scanlineClearOps.push_back(op); 180 } 181 182 // Compute reference for scanline. 183 int x = 0; 184 while (x < targetWidth) 185 { 186 tcu::RGBA spanColor; 187 deUint8 spanKnownMask = 0; 188 int spanLength = (targetWidth - x); 189 190 for (int opNdx = (int)scanlineClearOps.size() - 1; opNdx >= 0; opNdx--) 191 { 192 const ClearInfo& op = scanlineClearOps[opNdx]; 193 194 if (de::inBounds(x, op.m_rect.x(), op.m_rect.x()+op.m_rect.z()) && 195 de::inBounds(y, op.m_rect.y(), op.m_rect.y()+op.m_rect.w())) 196 { 197 // Compute span length until end of given rectangle. 198 spanLength = deMin32(spanLength, op.m_rect.x() + op.m_rect.z() - x); 199 200 tcu::RGBA clearCol = op.m_color; 201 deUint8 clearMask = op.m_colorMask; 202 if ((clearMask & 0x1) && !(spanKnownMask & 0x1)) spanColor.setRed(clearCol.getRed()); 203 if ((clearMask & 0x2) && !(spanKnownMask & 0x2)) spanColor.setGreen(clearCol.getGreen()); 204 if ((clearMask & 0x4) && !(spanKnownMask & 0x4)) spanColor.setBlue(clearCol.getBlue()); 205 if ((clearMask & 0x8) && !(spanKnownMask & 0x8)) spanColor.setAlpha(clearCol.getAlpha()); 206 spanKnownMask |= clearMask; 207 208 // Break if have all colors. 209 if (spanKnownMask == 0xF) 210 break; 211 } 212 else if (op.m_rect.x() > x) 213 spanLength = deMin32(spanLength, op.m_rect.x() - x); 214 } 215 216 // Set reference alpha channel to 0xFF, if no alpha in target. 217 if (pixelFormat.alphaBits == 0) 218 spanColor.setAlpha(0xFF); 219 220 // Fill the span. 221 for (int ndx = 0; ndx < spanLength; ndx++) 222 { 223 refImage.setPixel(x + ndx, y, spanColor); 224 pixelKnownChannelMask[y*targetWidth + x + ndx] |= spanKnownMask; 225 } 226 227 x += spanLength; 228 } 229 } 230 } 231 232 glu::readPixels(m_context.getRenderContext(), 0, 0, resImage.getAccess()); 233 GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels"); 234 235 // Compute difference image. 236 RGBA colorThreshold = pixelFormat.getColorThreshold(); 237 RGBA matchColor(0, 255, 0, 255); 238 RGBA diffColor(255, 0, 0, 255); 239 RGBA maxDiff(0, 0, 0, 0); 240 bool isImageOk = true; 241 242 if (gl.isEnabled(GL_DITHER)) 243 { 244 colorThreshold.setRed(colorThreshold.getRed() + 1); 245 colorThreshold.setGreen(colorThreshold.getGreen() + 1); 246 colorThreshold.setBlue(colorThreshold.getBlue() + 1); 247 colorThreshold.setAlpha(colorThreshold.getAlpha() + 1); 248 } 249 250 for (int y = 0; y < targetHeight; y++) 251 for (int x = 0; x < targetWidth; x++) 252 { 253 int offset = (y*targetWidth + x); 254 RGBA refRGBA = refImage.getPixel(x, y); 255 RGBA resRGBA = resImage.getPixel(x, y); 256 deUint8 colMask = pixelKnownChannelMask[offset]; 257 RGBA diff = computeAbsDiffMasked(refRGBA, resRGBA, colMask); 258 bool isPixelOk = diff.isBelowThreshold(colorThreshold); 259 260 diffImage.setPixel(x, y, isPixelOk ? matchColor : diffColor); 261 262 isImageOk = isImageOk && isPixelOk; 263 maxDiff = max(maxDiff, diff); 264 } 265 266 if (isImageOk) 267 { 268 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 269 } 270 else 271 { 272 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 273 274 m_testCtx.getLog() << tcu::TestLog::Message << "Image comparison failed, max diff = " << maxDiff << ", threshold = " << colorThreshold << tcu::TestLog::EndMessage; 275 276 log << TestLog::ImageSet("Result", "Resulting framebuffer") 277 << TestLog::Image("Result", "Resulting framebuffer", resImage) 278 << TestLog::Image("Reference", "Reference image", refImage) 279 << TestLog::Image("DiffMask", "Failing pixels", diffImage) 280 << TestLog::EndImageSet; 281 return TestCase::STOP; 282 } 283 284 bool isFinal = (++m_curIter == m_numIters); 285 286 // On final frame, dump images. 287 if (isFinal) 288 { 289 log << TestLog::ImageSet("Result", "Resulting framebuffer") 290 << TestLog::Image("Result", "Resulting framebuffer", resImage) 291 << TestLog::EndImageSet; 292 } 293 294 return isFinal ? TestCase::STOP : TestCase::CONTINUE; 295 } 296 297 ColorClearTest::ColorClearTest (Context& context) : TestCaseGroup(context, "color_clear", "Color Clear Tests") 298 { 299 } 300 301 ColorClearTest::~ColorClearTest (void) 302 { 303 } 304 305 void ColorClearTest::init (void) 306 { 307 // name iters, #..#, alpha?, scissor,masks, 1stfull? 308 addChild(new ColorClearCase(m_context, "single_rgb", 30, 1,3, false, false, false, true )); 309 addChild(new ColorClearCase(m_context, "single_rgba", 30, 1,3, true, false, false, true )); 310 addChild(new ColorClearCase(m_context, "multiple_rgb", 15, 4,20, false, false, false, true )); 311 addChild(new ColorClearCase(m_context, "multiple_rgba", 15, 4,20, true, false, false, true )); 312 addChild(new ColorClearCase(m_context, "long_rgb", 2, 100,500, false, false, false, true )); 313 addChild(new ColorClearCase(m_context, "long_rgba", 2, 100,500, true, false, false, true )); 314 addChild(new ColorClearCase(m_context, "subclears_rgb", 15, 4,30, false, false, false, false )); 315 addChild(new ColorClearCase(m_context, "subclears_rgba", 15, 4,30, true, false, false, false )); 316 addChild(new ColorClearCase(m_context, "short_scissored_rgb", 30, 2,4, false, true, false, true )); 317 addChild(new ColorClearCase(m_context, "scissored_rgb", 15, 4,30, false, true, false, true )); 318 addChild(new ColorClearCase(m_context, "scissored_rgba", 15, 4,30, true, true, false, true )); 319 addChild(new ColorClearCase(m_context, "masked_rgb", 15, 4,30, false, true, false, true )); 320 addChild(new ColorClearCase(m_context, "masked_rgba", 15, 4,30, true, true, false, true )); 321 addChild(new ColorClearCase(m_context, "masked_scissored_rgb", 15, 4,30, false, true, true, true )); 322 addChild(new ColorClearCase(m_context, "masked_scissored_rgba", 15, 4,30, true, true, true, true )); 323 addChild(new ColorClearCase(m_context, "complex_rgb", 15, 5,50, false, true, true, false )); 324 addChild(new ColorClearCase(m_context, "complex_rgba", 15, 5,50, true, true, true, false )); 325 addChild(new ColorClearCase(m_context, "long_masked_rgb", 2, 100,500, false, true, true, true )); 326 addChild(new ColorClearCase(m_context, "long_masked_rgba", 2, 100,500, true, true, true, true )); 327 } 328 329 } // Functional 330 } // gles2 331 } // deqp 332