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