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:
ColorClearCase(Context & context,const char * name,int numIters,int numClearsMin,int numClearsMax,bool testAlpha,bool testScissoring,bool testColorMasks,bool firstClearFull)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
~ColorClearCase(void)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:
ClearInfo(const tcu::IVec4 & rect,deUint8 colorMask,tcu::RGBA color)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
iterate(void)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
ColorClearTest(Context & context)297 ColorClearTest::ColorClearTest (Context& context) : TestCaseGroup(context, "color_clear", "Color Clear Tests")
298 {
299 }
300
~ColorClearTest(void)301 ColorClearTest::~ColorClearTest (void)
302 {
303 }
304
init(void)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