xref: /aosp_15_r20/external/deqp/modules/gles2/functional/es2fBlendTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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 Blend tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es2fBlendTests.hpp"
25 #include "glsFragmentOpUtil.hpp"
26 #include "gluPixelTransfer.hpp"
27 #include "gluStrUtil.hpp"
28 #include "tcuSurface.hpp"
29 #include "tcuImageCompare.hpp"
30 #include "tcuRenderTarget.hpp"
31 #include "tcuTestLog.hpp"
32 #include "tcuTextureUtil.hpp"
33 #include "deRandom.hpp"
34 #include "rrFragmentOperations.hpp"
35 #include "sglrReferenceUtils.hpp"
36 
37 #include "glw.h"
38 
39 #include <string>
40 #include <vector>
41 
42 namespace deqp
43 {
44 
45 using gls::FragmentOpUtil::IntegerQuad;
46 using gls::FragmentOpUtil::Quad;
47 using gls::FragmentOpUtil::QuadRenderer;
48 using gls::FragmentOpUtil::ReferenceQuadRenderer;
49 using glu::getBlendEquationName;
50 using glu::getBlendFactorName;
51 using std::string;
52 using std::vector;
53 using tcu::Surface;
54 using tcu::TestLog;
55 using tcu::TextureFormat;
56 using tcu::TextureLevel;
57 using tcu::UVec4;
58 using tcu::Vec4;
59 
60 namespace gles2
61 {
62 namespace Functional
63 {
64 
65 static const int MAX_VIEWPORT_WIDTH  = 64;
66 static const int MAX_VIEWPORT_HEIGHT = 64;
67 
68 struct BlendParams
69 {
70     GLenum equationRGB;
71     GLenum srcFuncRGB;
72     GLenum dstFuncRGB;
73     GLenum equationAlpha;
74     GLenum srcFuncAlpha;
75     GLenum dstFuncAlpha;
76     Vec4 blendColor;
77 
BlendParamsdeqp::gles2::Functional::BlendParams78     BlendParams(GLenum equationRGB_, GLenum srcFuncRGB_, GLenum dstFuncRGB_, GLenum equationAlpha_,
79                 GLenum srcFuncAlpha_, GLenum dstFuncAlpha_, Vec4 blendColor_)
80         : equationRGB(equationRGB_)
81         , srcFuncRGB(srcFuncRGB_)
82         , dstFuncRGB(dstFuncRGB_)
83         , equationAlpha(equationAlpha_)
84         , srcFuncAlpha(srcFuncAlpha_)
85         , dstFuncAlpha(dstFuncAlpha_)
86         , blendColor(blendColor_)
87     {
88     }
89 };
90 
91 class BlendCase : public TestCase
92 {
93 public:
94     BlendCase(Context &context, const char *name, const char *desc, const vector<BlendParams> &paramSets);
95 
96     ~BlendCase(void);
97 
98     void init(void);
99     void deinit(void);
100 
101     IterateResult iterate(void);
102 
103 private:
104     BlendCase(const BlendCase &other);
105     BlendCase &operator=(const BlendCase &other);
106 
107     vector<BlendParams> m_paramSets;
108     int m_curParamSetNdx;
109 
110     QuadRenderer *m_renderer;
111     ReferenceQuadRenderer *m_referenceRenderer;
112     TextureLevel *m_refColorBuffer;
113     Quad m_firstQuad;
114     Quad m_secondQuad;
115     IntegerQuad m_firstQuadInt;
116     IntegerQuad m_secondQuadInt;
117 
118     int m_viewportW;
119     int m_viewportH;
120 };
121 
BlendCase(Context & context,const char * name,const char * desc,const vector<BlendParams> & paramSets)122 BlendCase::BlendCase(Context &context, const char *name, const char *desc, const vector<BlendParams> &paramSets)
123     : TestCase(context, name, desc)
124     , m_paramSets(paramSets)
125     , m_curParamSetNdx(0)
126     , m_renderer(DE_NULL)
127     , m_referenceRenderer(DE_NULL)
128     , m_refColorBuffer(DE_NULL)
129     , m_viewportW(0)
130     , m_viewportH(0)
131 {
132     DE_ASSERT(!m_paramSets.empty());
133     for (int i = 0; i < (int)m_paramSets.size(); i++)
134         DE_ASSERT(m_paramSets[i].dstFuncRGB != GL_SRC_ALPHA_SATURATE &&
135                   m_paramSets[i].dstFuncAlpha != GL_SRC_ALPHA_SATURATE);
136 }
137 
init(void)138 void BlendCase::init(void)
139 {
140     bool useRGB = m_context.getRenderTarget().getPixelFormat().alphaBits == 0;
141 
142     static const Vec4 baseGradientColors[4] = {Vec4(0.0f, 0.5f, 1.0f, 0.5f), Vec4(0.5f, 0.0f, 0.5f, 1.0f),
143                                                Vec4(0.5f, 1.0f, 0.5f, 0.0f), Vec4(1.0f, 0.5f, 0.0f, 0.5f)};
144 
145     DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(m_firstQuad.color) == DE_LENGTH_OF_ARRAY(m_firstQuadInt.color));
146     for (int i = 0; i < DE_LENGTH_OF_ARRAY(m_firstQuad.color); i++)
147     {
148         m_firstQuad.color[i]    = (baseGradientColors[i] - 0.5f) * 0.2f + 0.5f;
149         m_firstQuadInt.color[i] = m_firstQuad.color[i];
150 
151         m_secondQuad.color[i]    = (Vec4(1.0f) - baseGradientColors[i] - 0.5f) * 1.0f + 0.5f;
152         m_secondQuadInt.color[i] = m_secondQuad.color[i];
153     }
154 
155     m_viewportW = de::min<int>(m_context.getRenderTarget().getWidth(), MAX_VIEWPORT_WIDTH);
156     m_viewportH = de::min<int>(m_context.getRenderTarget().getHeight(), MAX_VIEWPORT_HEIGHT);
157 
158     m_firstQuadInt.posA  = tcu::IVec2(0, 0);
159     m_secondQuadInt.posA = tcu::IVec2(0, 0);
160     m_firstQuadInt.posB  = tcu::IVec2(m_viewportW - 1, m_viewportH - 1);
161     m_secondQuadInt.posB = tcu::IVec2(m_viewportW - 1, m_viewportH - 1);
162 
163     DE_ASSERT(!m_renderer);
164     DE_ASSERT(!m_referenceRenderer);
165     DE_ASSERT(!m_refColorBuffer);
166 
167     m_renderer          = new QuadRenderer(m_context.getRenderContext(), glu::GLSL_VERSION_100_ES);
168     m_referenceRenderer = new ReferenceQuadRenderer;
169     m_refColorBuffer =
170         new TextureLevel(TextureFormat(useRGB ? TextureFormat::RGB : TextureFormat::RGBA, TextureFormat::UNORM_INT8),
171                          m_viewportW, m_viewportH);
172 
173     m_curParamSetNdx = 0;
174 }
175 
~BlendCase(void)176 BlendCase::~BlendCase(void)
177 {
178     delete m_renderer;
179     delete m_referenceRenderer;
180     delete m_refColorBuffer;
181 }
182 
deinit(void)183 void BlendCase::deinit(void)
184 {
185     delete m_renderer;
186     delete m_referenceRenderer;
187     delete m_refColorBuffer;
188 
189     m_renderer          = DE_NULL;
190     m_referenceRenderer = DE_NULL;
191     m_refColorBuffer    = DE_NULL;
192 }
193 
iterate(void)194 BlendCase::IterateResult BlendCase::iterate(void)
195 {
196     de::Random rnd(deStringHash(getName()) ^ deInt32Hash(m_curParamSetNdx));
197     int viewportX = rnd.getInt(0, m_context.getRenderTarget().getWidth() - m_viewportW);
198     int viewportY = rnd.getInt(0, m_context.getRenderTarget().getHeight() - m_viewportH);
199     tcu::Surface renderedImg(m_viewportW, m_viewportH);
200     tcu::Surface referenceImg(m_viewportH, m_viewportH);
201     TestLog &log(m_testCtx.getLog());
202     const BlendParams &paramSet = m_paramSets[m_curParamSetNdx];
203     rr::FragmentOperationState referenceState;
204 
205     // Log the blend parameters.
206 
207     log << TestLog::Message << "RGB equation = " << getBlendEquationName(paramSet.equationRGB) << TestLog::EndMessage;
208     log << TestLog::Message << "RGB src func = " << getBlendFactorName(paramSet.srcFuncRGB) << TestLog::EndMessage;
209     log << TestLog::Message << "RGB dst func = " << getBlendFactorName(paramSet.dstFuncRGB) << TestLog::EndMessage;
210     log << TestLog::Message << "Alpha equation = " << getBlendEquationName(paramSet.equationAlpha)
211         << TestLog::EndMessage;
212     log << TestLog::Message << "Alpha src func = " << getBlendFactorName(paramSet.srcFuncAlpha) << TestLog::EndMessage;
213     log << TestLog::Message << "Alpha dst func = " << getBlendFactorName(paramSet.dstFuncAlpha) << TestLog::EndMessage;
214     log << TestLog::Message << "Blend color = (" << paramSet.blendColor.x() << ", " << paramSet.blendColor.y() << ", "
215         << paramSet.blendColor.z() << ", " << paramSet.blendColor.w() << ")" << TestLog::EndMessage;
216 
217     // Set GL state.
218 
219     GLU_CHECK_CALL(glBlendEquationSeparate(paramSet.equationRGB, paramSet.equationAlpha));
220     GLU_CHECK_CALL(
221         glBlendFuncSeparate(paramSet.srcFuncRGB, paramSet.dstFuncRGB, paramSet.srcFuncAlpha, paramSet.dstFuncAlpha));
222     GLU_CHECK_CALL(glBlendColor(paramSet.blendColor.x(), paramSet.blendColor.y(), paramSet.blendColor.z(),
223                                 paramSet.blendColor.w()));
224 
225     // Set reference state.
226 
227     referenceState.blendRGBState.equation = sglr::rr_util::mapGLBlendEquation(paramSet.equationRGB);
228     referenceState.blendRGBState.srcFunc  = sglr::rr_util::mapGLBlendFunc(paramSet.srcFuncRGB);
229     referenceState.blendRGBState.dstFunc  = sglr::rr_util::mapGLBlendFunc(paramSet.dstFuncRGB);
230     referenceState.blendAState.equation   = sglr::rr_util::mapGLBlendEquation(paramSet.equationAlpha);
231     referenceState.blendAState.srcFunc    = sglr::rr_util::mapGLBlendFunc(paramSet.srcFuncAlpha);
232     referenceState.blendAState.dstFunc    = sglr::rr_util::mapGLBlendFunc(paramSet.dstFuncAlpha);
233     referenceState.blendColor             = paramSet.blendColor;
234 
235     // Render with GL.
236 
237     glDisable(GL_BLEND);
238     glViewport(viewportX, viewportY, m_viewportW, m_viewportH);
239     m_renderer->render(m_firstQuad);
240     glEnable(GL_BLEND);
241     m_renderer->render(m_secondQuad);
242     glFlush();
243 
244     // Render reference.
245 
246     const tcu::PixelBufferAccess nullAccess = tcu::PixelBufferAccess();
247 
248     referenceState.blendMode = rr::BLENDMODE_NONE;
249     m_referenceRenderer->render(gls::FragmentOpUtil::getMultisampleAccess(m_refColorBuffer->getAccess()),
250                                 nullAccess /* no depth */, nullAccess /* no stencil */, m_firstQuadInt, referenceState);
251     referenceState.blendMode = rr::BLENDMODE_STANDARD;
252     m_referenceRenderer->render(gls::FragmentOpUtil::getMultisampleAccess(m_refColorBuffer->getAccess()),
253                                 nullAccess /* no depth */, nullAccess /* no stencil */, m_secondQuadInt,
254                                 referenceState);
255 
256     // Expand reference color buffer to RGBA8
257     copy(referenceImg.getAccess(), m_refColorBuffer->getAccess());
258 
259     // Read GL image.
260 
261     glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, renderedImg.getAccess());
262 
263     // Compare images.
264 
265     UVec4 compareThreshold =
266         m_context.getRenderTarget().getPixelFormat().getColorThreshold().toIVec().asUint() * UVec4(5) / UVec4(2) +
267         UVec4(
268             3); // \note Non-scientific ad hoc formula. Need big threshold when few color bits; blending brings extra inaccuracy.
269 
270     bool comparePass = tcu::intThresholdCompare(m_testCtx.getLog(), "CompareResult", "Image Comparison Result",
271                                                 referenceImg.getAccess(), renderedImg.getAccess(), compareThreshold,
272                                                 tcu::COMPARE_LOG_RESULT);
273 
274     // Fail now if images don't match.
275 
276     if (!comparePass)
277     {
278         m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Image compare failed");
279         return STOP;
280     }
281 
282     // Continue if param sets still remain in m_paramSets; otherwise stop.
283 
284     m_curParamSetNdx++;
285 
286     if (m_curParamSetNdx < (int)m_paramSets.size())
287         return CONTINUE;
288     else
289     {
290         m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Passed");
291         return STOP;
292     }
293 }
294 
BlendTests(Context & context)295 BlendTests::BlendTests(Context &context) : TestCaseGroup(context, "blend", "Blend tests")
296 {
297 }
298 
~BlendTests(void)299 BlendTests::~BlendTests(void)
300 {
301 }
302 
init(void)303 void BlendTests::init(void)
304 {
305     struct EnumGL
306     {
307         GLenum glValue;
308         const char *nameStr;
309     };
310 
311     static const EnumGL blendEquations[] = {
312         {GL_FUNC_ADD, "add"}, {GL_FUNC_SUBTRACT, "subtract"}, {GL_FUNC_REVERSE_SUBTRACT, "reverse_subtract"}};
313 
314     static const EnumGL blendFunctions[] = {{GL_ZERO, "zero"},
315                                             {GL_ONE, "one"},
316                                             {GL_SRC_COLOR, "src_color"},
317                                             {GL_ONE_MINUS_SRC_COLOR, "one_minus_src_color"},
318                                             {GL_DST_COLOR, "dst_color"},
319                                             {GL_ONE_MINUS_DST_COLOR, "one_minus_dst_color"},
320                                             {GL_SRC_ALPHA, "src_alpha"},
321                                             {GL_ONE_MINUS_SRC_ALPHA, "one_minus_src_alpha"},
322                                             {GL_DST_ALPHA, "dst_alpha"},
323                                             {GL_ONE_MINUS_DST_ALPHA, "one_minus_dst_alpha"},
324                                             {GL_CONSTANT_COLOR, "constant_color"},
325                                             {GL_ONE_MINUS_CONSTANT_COLOR, "one_minus_constant_color"},
326                                             {GL_CONSTANT_ALPHA, "constant_alpha"},
327                                             {GL_ONE_MINUS_CONSTANT_ALPHA, "one_minus_constant_alpha"},
328                                             {GL_SRC_ALPHA_SATURATE, "src_alpha_saturate"}};
329 
330     const Vec4 defaultBlendColor(0.2f, 0.4f, 0.6f, 0.8f);
331 
332     // Test all blend equation, src blend function, dst blend function combinations. RGB and alpha modes are the same.
333 
334     {
335         TestCaseGroup *group =
336             new TestCaseGroup(m_context, "equation_src_func_dst_func", "Combinations of Blend Equations and Functions");
337         addChild(group);
338 
339         for (int equationNdx = 0; equationNdx < DE_LENGTH_OF_ARRAY(blendEquations); equationNdx++)
340             for (int srcFuncNdx = 0; srcFuncNdx < DE_LENGTH_OF_ARRAY(blendFunctions); srcFuncNdx++)
341                 for (int dstFuncNdx = 0; dstFuncNdx < DE_LENGTH_OF_ARRAY(blendFunctions); dstFuncNdx++)
342                 {
343                     const EnumGL &eq  = blendEquations[equationNdx];
344                     const EnumGL &src = blendFunctions[srcFuncNdx];
345                     const EnumGL &dst = blendFunctions[dstFuncNdx];
346 
347                     if (dst.glValue == GL_SRC_ALPHA_SATURATE) // SRC_ALPHA_SATURATE is only valid for src func.
348                         continue;
349 
350                     string name        = string("") + eq.nameStr + "_" + src.nameStr + "_" + dst.nameStr;
351                     string description = string("") + "Equations " + getBlendEquationName(eq.glValue) + ", src funcs " +
352                                          getBlendFactorName(src.glValue) + ", dst funcs " +
353                                          getBlendFactorName(dst.glValue);
354 
355                     vector<BlendParams> paramSets;
356                     paramSets.push_back(BlendParams(eq.glValue, src.glValue, dst.glValue, eq.glValue, src.glValue,
357                                                     dst.glValue, defaultBlendColor));
358 
359                     group->addChild(new BlendCase(m_context, name.c_str(), description.c_str(), paramSets));
360                 }
361     }
362 
363     // Test all RGB src, alpha src and RGB dst, alpha dst combinations. Equations are ADD.
364     // \note For all RGB src, alpha src combinations, also test a couple of different RGBA dst functions, and vice versa.
365 
366     {
367         TestCaseGroup *mainGroup =
368             new TestCaseGroup(m_context, "rgb_func_alpha_func", "Combinations of RGB and Alpha Functions");
369         addChild(mainGroup);
370         TestCaseGroup *srcGroup = new TestCaseGroup(m_context, "src", "Source functions");
371         TestCaseGroup *dstGroup = new TestCaseGroup(m_context, "dst", "Destination functions");
372         mainGroup->addChild(srcGroup);
373         mainGroup->addChild(dstGroup);
374 
375         for (int isDstI = 0; isDstI <= 1; isDstI++)
376             for (int rgbFuncNdx = 0; rgbFuncNdx < DE_LENGTH_OF_ARRAY(blendFunctions); rgbFuncNdx++)
377                 for (int alphaFuncNdx = 0; alphaFuncNdx < DE_LENGTH_OF_ARRAY(blendFunctions); alphaFuncNdx++)
378                 {
379                     bool isSrc              = isDstI == 0;
380                     TestCaseGroup *curGroup = isSrc ? srcGroup : dstGroup;
381                     const EnumGL &funcRGB   = blendFunctions[rgbFuncNdx];
382                     const EnumGL &funcAlpha = blendFunctions[alphaFuncNdx];
383                     const char *dstOrSrcStr = isSrc ? "src" : "dst";
384 
385                     if (!isSrc &&
386                         (funcRGB.glValue == GL_SRC_ALPHA_SATURATE ||
387                          funcAlpha.glValue == GL_SRC_ALPHA_SATURATE)) // SRC_ALPHA_SATURATE is only valid for src func.
388                         continue;
389 
390                     string name        = string("") + funcRGB.nameStr + "_" + funcAlpha.nameStr;
391                     string description = string("") + "RGB " + dstOrSrcStr + " func " +
392                                          getBlendFactorName(funcRGB.glValue) + ", alpha " + dstOrSrcStr + " func " +
393                                          getBlendFactorName(funcAlpha.glValue);
394 
395                     // First, make param sets as if this was a src case.
396 
397                     vector<BlendParams> paramSets;
398                     paramSets.push_back(BlendParams(GL_FUNC_ADD, funcRGB.glValue, GL_ONE, GL_FUNC_ADD,
399                                                     funcAlpha.glValue, GL_ONE, defaultBlendColor));
400                     paramSets.push_back(BlendParams(GL_FUNC_ADD, funcRGB.glValue, GL_ZERO, GL_FUNC_ADD,
401                                                     funcAlpha.glValue, GL_ZERO, defaultBlendColor));
402                     paramSets.push_back(BlendParams(GL_FUNC_ADD, funcRGB.glValue, GL_SRC_COLOR, GL_FUNC_ADD,
403                                                     funcAlpha.glValue, GL_SRC_COLOR, defaultBlendColor));
404                     paramSets.push_back(BlendParams(GL_FUNC_ADD, funcRGB.glValue, GL_DST_COLOR, GL_FUNC_ADD,
405                                                     funcAlpha.glValue, GL_DST_COLOR, defaultBlendColor));
406 
407                     // Swap src and dst params if this is a dst case.
408 
409                     if (!isSrc)
410                     {
411                         for (int i = 0; i < (int)paramSets.size(); i++)
412                         {
413                             std::swap(paramSets[i].srcFuncRGB, paramSets[i].dstFuncRGB);
414                             std::swap(paramSets[i].srcFuncAlpha, paramSets[i].dstFuncAlpha);
415                         }
416                     }
417 
418                     curGroup->addChild(new BlendCase(m_context, name.c_str(), description.c_str(), paramSets));
419                 }
420     }
421 
422     // Test all RGB and alpha equation combinations. Src and dst funcs are ONE for both.
423 
424     {
425         TestCaseGroup *group = new TestCaseGroup(m_context, "rgb_equation_alpha_equation",
426                                                  "Combinations of RGB and Alpha Equation Combinations");
427         addChild(group);
428 
429         for (int equationRGBNdx = 0; equationRGBNdx < DE_LENGTH_OF_ARRAY(blendEquations); equationRGBNdx++)
430             for (int equationAlphaNdx = 0; equationAlphaNdx < DE_LENGTH_OF_ARRAY(blendEquations); equationAlphaNdx++)
431             {
432                 const EnumGL &eqRGB   = blendEquations[equationRGBNdx];
433                 const EnumGL &eqAlpha = blendEquations[equationAlphaNdx];
434 
435                 string name        = string("") + eqRGB.nameStr + "_" + eqAlpha.nameStr;
436                 string description = string("") + "RGB equation " + getBlendEquationName(eqRGB.glValue) +
437                                      ", alpha equation " + getBlendEquationName(eqAlpha.glValue);
438 
439                 vector<BlendParams> paramSets;
440                 paramSets.push_back(
441                     BlendParams(eqRGB.glValue, GL_ONE, GL_ONE, eqAlpha.glValue, GL_ONE, GL_ONE, defaultBlendColor));
442 
443                 group->addChild(new BlendCase(m_context, name.c_str(), description.c_str(), paramSets));
444             }
445     }
446 }
447 
448 } // namespace Functional
449 } // namespace gles2
450 } // namespace deqp
451