xref: /aosp_15_r20/external/deqp/modules/gles3/functional/es3fColorClearTest.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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