xref: /aosp_15_r20/external/deqp/modules/gles31/functional/es31fAdvancedBlendTests.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 Advanced blending (GL_KHR_blend_equation_advanced) tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es31fAdvancedBlendTests.hpp"
25 #include "gluStrUtil.hpp"
26 #include "glsFragmentOpUtil.hpp"
27 #include "glsStateQueryUtil.hpp"
28 #include "gluPixelTransfer.hpp"
29 #include "gluObjectWrapper.hpp"
30 #include "gluContextInfo.hpp"
31 #include "gluShaderProgram.hpp"
32 #include "gluCallLogWrapper.hpp"
33 #include "gluStrUtil.hpp"
34 #include "tcuPixelFormat.hpp"
35 #include "tcuTexture.hpp"
36 #include "tcuTextureUtil.hpp"
37 #include "tcuImageCompare.hpp"
38 #include "tcuRenderTarget.hpp"
39 #include "tcuTestLog.hpp"
40 #include "tcuStringTemplate.hpp"
41 #include "deRandom.hpp"
42 #include "deStringUtil.hpp"
43 #include "rrFragmentOperations.hpp"
44 #include "sglrReferenceUtils.hpp"
45 #include "glwEnums.hpp"
46 #include "glwFunctions.hpp"
47 
48 #include <string>
49 #include <vector>
50 
51 namespace deqp
52 {
53 
54 using gls::FragmentOpUtil::IntegerQuad;
55 using gls::FragmentOpUtil::ReferenceQuadRenderer;
56 using std::map;
57 using std::string;
58 using std::vector;
59 using tcu::TestLog;
60 using tcu::TextureFormat;
61 using tcu::TextureLevel;
62 using tcu::UVec4;
63 using tcu::Vec2;
64 using tcu::Vec4;
65 
66 namespace gles31
67 {
68 namespace Functional
69 {
70 
71 namespace
72 {
73 
74 enum
75 {
76     MAX_VIEWPORT_WIDTH  = 128,
77     MAX_VIEWPORT_HEIGHT = 128
78 };
79 
80 enum RenderTargetType
81 {
82     RENDERTARGETTYPE_DEFAULT = 0, //!< Default framebuffer
83     RENDERTARGETTYPE_SRGB_FBO,
84     RENDERTARGETTYPE_MSAA_FBO,
85 
86     RENDERTARGETTYPE_LAST
87 };
88 
getEquationName(glw::GLenum equation)89 static const char *getEquationName(glw::GLenum equation)
90 {
91     switch (equation)
92     {
93     case GL_MULTIPLY:
94         return "multiply";
95     case GL_SCREEN:
96         return "screen";
97     case GL_OVERLAY:
98         return "overlay";
99     case GL_DARKEN:
100         return "darken";
101     case GL_LIGHTEN:
102         return "lighten";
103     case GL_COLORDODGE:
104         return "colordodge";
105     case GL_COLORBURN:
106         return "colorburn";
107     case GL_HARDLIGHT:
108         return "hardlight";
109     case GL_SOFTLIGHT:
110         return "softlight";
111     case GL_DIFFERENCE:
112         return "difference";
113     case GL_EXCLUSION:
114         return "exclusion";
115     case GL_HSL_HUE:
116         return "hsl_hue";
117     case GL_HSL_SATURATION:
118         return "hsl_saturation";
119     case GL_HSL_COLOR:
120         return "hsl_color";
121     case GL_HSL_LUMINOSITY:
122         return "hsl_luminosity";
123     default:
124         DE_ASSERT(false);
125         return DE_NULL;
126     }
127 }
128 
129 class AdvancedBlendCase : public TestCase
130 {
131 public:
132     AdvancedBlendCase(Context &context, const char *name, const char *desc, uint32_t mode, int overdrawCount,
133                       bool coherent, RenderTargetType rtType);
134 
135     ~AdvancedBlendCase(void);
136 
137     void init(void);
138     void deinit(void);
139 
140     IterateResult iterate(void);
141 
142 private:
143     AdvancedBlendCase(const AdvancedBlendCase &);
144     AdvancedBlendCase &operator=(const AdvancedBlendCase &);
145 
146     const uint32_t m_blendMode;
147     const int m_overdrawCount;
148     const bool m_coherentBlending;
149     const RenderTargetType m_rtType;
150     const int m_numIters;
151 
152     bool m_coherentExtensionSupported;
153 
154     uint32_t m_colorRbo;
155     uint32_t m_fbo;
156 
157     uint32_t m_resolveColorRbo;
158     uint32_t m_resolveFbo;
159 
160     glu::ShaderProgram *m_program;
161 
162     ReferenceQuadRenderer *m_referenceRenderer;
163     TextureLevel *m_refColorBuffer;
164 
165     const int m_renderWidth;
166     const int m_renderHeight;
167     const int m_viewportWidth;
168     const int m_viewportHeight;
169 
170     int m_iterNdx;
171 };
172 
AdvancedBlendCase(Context & context,const char * name,const char * desc,uint32_t mode,int overdrawCount,bool coherent,RenderTargetType rtType)173 AdvancedBlendCase::AdvancedBlendCase(Context &context, const char *name, const char *desc, uint32_t mode,
174                                      int overdrawCount, bool coherent, RenderTargetType rtType)
175     : TestCase(context, name, desc)
176     , m_blendMode(mode)
177     , m_overdrawCount(overdrawCount)
178     , m_coherentBlending(coherent)
179     , m_rtType(rtType)
180     , m_numIters(5)
181     , m_coherentExtensionSupported(false)
182     , m_colorRbo(0)
183     , m_fbo(0)
184     , m_resolveColorRbo(0)
185     , m_resolveFbo(0)
186     , m_program(DE_NULL)
187     , m_referenceRenderer(DE_NULL)
188     , m_refColorBuffer(DE_NULL)
189     , m_renderWidth(rtType != RENDERTARGETTYPE_DEFAULT ? 2 * MAX_VIEWPORT_WIDTH :
190                                                          m_context.getRenderTarget().getWidth())
191     , m_renderHeight(rtType != RENDERTARGETTYPE_DEFAULT ? 2 * MAX_VIEWPORT_HEIGHT :
192                                                           m_context.getRenderTarget().getHeight())
193     , m_viewportWidth(de::min<int>(m_renderWidth, MAX_VIEWPORT_WIDTH))
194     , m_viewportHeight(de::min<int>(m_renderHeight, MAX_VIEWPORT_HEIGHT))
195     , m_iterNdx(0)
196 {
197 }
198 
getBlendLayoutQualifier(rr::BlendEquationAdvanced equation)199 const char *getBlendLayoutQualifier(rr::BlendEquationAdvanced equation)
200 {
201     static const char *s_qualifiers[] = {
202         "blend_support_multiply",       "blend_support_screen",    "blend_support_overlay",
203         "blend_support_darken",         "blend_support_lighten",   "blend_support_colordodge",
204         "blend_support_colorburn",      "blend_support_hardlight", "blend_support_softlight",
205         "blend_support_difference",     "blend_support_exclusion", "blend_support_hsl_hue",
206         "blend_support_hsl_saturation", "blend_support_hsl_color", "blend_support_hsl_luminosity",
207     };
208     DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_qualifiers) == rr::BLENDEQUATION_ADVANCED_LAST);
209     DE_ASSERT(de::inBounds<int>(equation, 0, rr::BLENDEQUATION_ADVANCED_LAST));
210     return s_qualifiers[equation];
211 }
212 
getBlendProgramSrc(rr::BlendEquationAdvanced equation,glu::RenderContext & renderContext)213 glu::ProgramSources getBlendProgramSrc(rr::BlendEquationAdvanced equation, glu::RenderContext &renderContext)
214 {
215     const bool supportsES32 = glu::contextSupports(renderContext.getType(), glu::ApiType::es(3, 2));
216 
217     static const char *s_vertSrc = "${GLSL_VERSION_DECL}\n"
218                                    "in highp vec4 a_position;\n"
219                                    "in mediump vec4 a_color;\n"
220                                    "out mediump vec4 v_color;\n"
221                                    "void main()\n"
222                                    "{\n"
223                                    "    gl_Position = a_position;\n"
224                                    "    v_color = a_color;\n"
225                                    "}\n";
226     static const char *s_fragSrc = "${GLSL_VERSION_DECL}\n"
227                                    "${EXTENSION}"
228                                    "in mediump vec4 v_color;\n"
229                                    "layout(${SUPPORT_QUALIFIER}) out;\n"
230                                    "layout(location = 0) out mediump vec4 o_color;\n"
231                                    "void main()\n"
232                                    "{\n"
233                                    "    o_color = v_color;\n"
234                                    "}\n";
235 
236     map<string, string> args;
237     args["GLSL_VERSION_DECL"] = supportsES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) :
238                                                getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
239     args["EXTENSION"]         = supportsES32 ? "\n" : "#extension GL_KHR_blend_equation_advanced : require\n";
240     args["SUPPORT_QUALIFIER"] = getBlendLayoutQualifier(equation);
241 
242     return glu::ProgramSources() << glu::VertexSource(tcu::StringTemplate(s_vertSrc).specialize(args))
243                                  << glu::FragmentSource(tcu::StringTemplate(s_fragSrc).specialize(args));
244 }
245 
init(void)246 void AdvancedBlendCase::init(void)
247 {
248     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
249     const bool useFbo        = m_rtType != RENDERTARGETTYPE_DEFAULT;
250     const bool useSRGB       = m_rtType == RENDERTARGETTYPE_SRGB_FBO;
251 
252     m_coherentExtensionSupported =
253         m_context.getContextInfo().isExtensionSupported("GL_KHR_blend_equation_advanced_coherent");
254 
255     if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)))
256         if (!m_context.getContextInfo().isExtensionSupported("GL_KHR_blend_equation_advanced"))
257             TCU_THROW(NotSupportedError, "GL_KHR_blend_equation_advanced is not supported");
258 
259     if (m_coherentBlending && !m_coherentExtensionSupported)
260         TCU_THROW(NotSupportedError, "GL_KHR_blend_equation_advanced_coherent is not supported");
261 
262     TCU_CHECK(gl.blendBarrier);
263 
264     DE_ASSERT(!m_program);
265     DE_ASSERT(!m_referenceRenderer);
266     DE_ASSERT(!m_refColorBuffer);
267 
268     m_program = new glu::ShaderProgram(
269         m_context.getRenderContext(),
270         getBlendProgramSrc(sglr::rr_util::mapGLBlendEquationAdvanced(m_blendMode), m_context.getRenderContext()));
271     m_testCtx.getLog() << *m_program;
272 
273     if (!m_program->isOk())
274     {
275         delete m_program;
276         m_program = DE_NULL;
277         TCU_FAIL("Compile failed");
278     }
279 
280     m_referenceRenderer = new ReferenceQuadRenderer;
281     m_refColorBuffer =
282         new TextureLevel(TextureFormat(useSRGB ? TextureFormat::sRGBA : TextureFormat::RGBA, TextureFormat::UNORM_INT8),
283                          m_viewportWidth, m_viewportHeight);
284 
285     if (useFbo)
286     {
287         const uint32_t format = useSRGB ? GL_SRGB8_ALPHA8 : GL_RGBA8;
288         const int numSamples  = m_rtType == RENDERTARGETTYPE_MSAA_FBO ? 4 : 0;
289 
290         m_testCtx.getLog() << TestLog::Message << "Using FBO of size (" << m_renderWidth << ", " << m_renderHeight
291                            << ") with format " << glu::getTextureFormatStr(format) << " and " << numSamples
292                            << " samples" << TestLog::EndMessage;
293 
294         gl.genRenderbuffers(1, &m_colorRbo);
295         gl.bindRenderbuffer(GL_RENDERBUFFER, m_colorRbo);
296         gl.renderbufferStorageMultisample(GL_RENDERBUFFER, numSamples, format, m_renderWidth, m_renderHeight);
297         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create color RBO");
298 
299         gl.genFramebuffers(1, &m_fbo);
300         gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
301         gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_colorRbo);
302         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create FBO");
303 
304         TCU_CHECK(gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
305 
306         if (numSamples > 0)
307         {
308             // Create resolve FBO
309             gl.genRenderbuffers(1, &m_resolveColorRbo);
310             gl.bindRenderbuffer(GL_RENDERBUFFER, m_resolveColorRbo);
311             gl.renderbufferStorageMultisample(GL_RENDERBUFFER, 0, format, m_renderWidth, m_renderHeight);
312             GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create resolve color RBO");
313 
314             gl.genFramebuffers(1, &m_resolveFbo);
315             gl.bindFramebuffer(GL_FRAMEBUFFER, m_resolveFbo);
316             gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_resolveColorRbo);
317             GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create FBO");
318 
319             TCU_CHECK(gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
320 
321             gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
322         }
323 
324         if (glu::isContextTypeGLCore(m_context.getRenderContext().getType()) && useSRGB)
325             gl.enable(GL_FRAMEBUFFER_SRGB);
326     }
327     else
328         DE_ASSERT(m_rtType == RENDERTARGETTYPE_DEFAULT);
329 
330     m_iterNdx = 0;
331 }
332 
~AdvancedBlendCase(void)333 AdvancedBlendCase::~AdvancedBlendCase(void)
334 {
335     AdvancedBlendCase::deinit();
336 }
337 
deinit(void)338 void AdvancedBlendCase::deinit(void)
339 {
340     delete m_program;
341     delete m_referenceRenderer;
342     delete m_refColorBuffer;
343 
344     m_program           = DE_NULL;
345     m_referenceRenderer = DE_NULL;
346     m_refColorBuffer    = DE_NULL;
347 
348     if (m_colorRbo || m_fbo)
349     {
350         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
351 
352         gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
353         gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
354 
355         if (m_colorRbo != 0)
356         {
357             gl.deleteRenderbuffers(1, &m_colorRbo);
358             m_colorRbo = 0;
359         }
360 
361         if (m_fbo != 0)
362         {
363             gl.deleteFramebuffers(1, &m_fbo);
364             m_fbo = 0;
365         }
366 
367         if (m_resolveColorRbo)
368         {
369             gl.deleteRenderbuffers(1, &m_resolveColorRbo);
370             m_resolveColorRbo = 0;
371         }
372 
373         if (m_resolveFbo)
374         {
375             gl.deleteRenderbuffers(1, &m_resolveFbo);
376             m_resolveFbo = 0;
377         }
378 
379         if (glu::isContextTypeGLCore(m_context.getRenderContext().getType()) && RENDERTARGETTYPE_SRGB_FBO == m_rtType)
380             gl.disable(GL_FRAMEBUFFER_SRGB);
381     }
382 }
383 
randomColor(de::Random * rnd)384 static tcu::Vec4 randomColor(de::Random *rnd)
385 {
386     const float rgbValues[]   = {0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f};
387     const float alphaValues[] = {0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f};
388 
389     // \note Spec assumes premultiplied inputs.
390     const float a = rnd->choose<float>(DE_ARRAY_BEGIN(alphaValues), DE_ARRAY_END(alphaValues));
391     const float r = a * rnd->choose<float>(DE_ARRAY_BEGIN(rgbValues), DE_ARRAY_END(rgbValues));
392     const float g = a * rnd->choose<float>(DE_ARRAY_BEGIN(rgbValues), DE_ARRAY_END(rgbValues));
393     const float b = a * rnd->choose<float>(DE_ARRAY_BEGIN(rgbValues), DE_ARRAY_END(rgbValues));
394     return tcu::Vec4(r, g, b, a);
395 }
396 
getLinearAccess(const tcu::ConstPixelBufferAccess & access)397 static tcu::ConstPixelBufferAccess getLinearAccess(const tcu::ConstPixelBufferAccess &access)
398 {
399     if (access.getFormat().order == TextureFormat::sRGBA)
400         return tcu::ConstPixelBufferAccess(TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8),
401                                            access.getWidth(), access.getHeight(), access.getDepth(),
402                                            access.getRowPitch(), access.getSlicePitch(), access.getDataPtr());
403     else
404         return access;
405 }
406 
iterate(void)407 AdvancedBlendCase::IterateResult AdvancedBlendCase::iterate(void)
408 {
409     const glu::RenderContext &renderCtx = m_context.getRenderContext();
410     const glw::Functions &gl            = renderCtx.getFunctions();
411     de::Random rnd(deStringHash(getName()) ^ deInt32Hash(m_iterNdx));
412     const int viewportX        = rnd.getInt(0, m_renderWidth - m_viewportWidth);
413     const int viewportY        = rnd.getInt(0, m_renderHeight - m_viewportHeight);
414     const bool useFbo          = m_rtType != RENDERTARGETTYPE_DEFAULT;
415     const bool requiresResolve = m_rtType == RENDERTARGETTYPE_MSAA_FBO;
416     const int numQuads         = m_overdrawCount + 1;
417     TextureLevel renderedImg(TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8), m_viewportWidth,
418                              m_viewportHeight);
419     vector<Vec4> colors(numQuads * 4);
420 
421     for (vector<Vec4>::iterator col = colors.begin(); col != colors.end(); ++col)
422         *col = randomColor(&rnd);
423 
424     // Render with GL.
425     {
426         const uint32_t program = m_program->getProgram();
427         const int posLoc       = gl.getAttribLocation(program, "a_position");
428         const int colorLoc     = gl.getAttribLocation(program, "a_color");
429         uint32_t vao           = 0;
430         const glu::Buffer indexBuffer(renderCtx);
431         const glu::Buffer positionBuffer(renderCtx);
432         const glu::Buffer colorBuffer(renderCtx);
433         vector<Vec2> positions(numQuads * 4);
434         vector<uint16_t> indices(numQuads * 6);
435         const uint16_t singleQuadIndices[] = {0, 2, 1, 1, 2, 3};
436         const Vec2 singleQuadPos[]         = {
437             Vec2(-1.0f, -1.0f),
438             Vec2(-1.0f, +1.0f),
439             Vec2(+1.0f, -1.0f),
440             Vec2(+1.0f, +1.0f),
441         };
442 
443         TCU_CHECK(posLoc >= 0 && colorLoc >= 0);
444 
445         for (int quadNdx = 0; quadNdx < numQuads; quadNdx++)
446         {
447             std::copy(DE_ARRAY_BEGIN(singleQuadPos), DE_ARRAY_END(singleQuadPos), &positions[quadNdx * 4]);
448             for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(singleQuadIndices); ndx++)
449                 indices[quadNdx * 6 + ndx] = (uint16_t)(quadNdx * 4 + singleQuadIndices[ndx]);
450         }
451 
452         if (!glu::isContextTypeES(renderCtx.getType()))
453         {
454             gl.genVertexArrays(1, &vao);
455             gl.bindVertexArray(vao);
456         }
457 
458         gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, *indexBuffer);
459         gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (glw::GLsizeiptr)(indices.size() * sizeof(indices[0])), &indices[0],
460                       GL_STATIC_DRAW);
461 
462         gl.bindBuffer(GL_ARRAY_BUFFER, *positionBuffer);
463         gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(positions.size() * sizeof(positions[0])), &positions[0],
464                       GL_STATIC_DRAW);
465         gl.enableVertexAttribArray(posLoc);
466         gl.vertexAttribPointer(posLoc, 2, GL_FLOAT, GL_FALSE, 0, DE_NULL);
467 
468         gl.bindBuffer(GL_ARRAY_BUFFER, *colorBuffer);
469         gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(colors.size() * sizeof(colors[0])), &colors[0],
470                       GL_STATIC_DRAW);
471         gl.enableVertexAttribArray(colorLoc);
472         gl.vertexAttribPointer(colorLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
473         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create buffers");
474 
475         gl.useProgram(program);
476         gl.viewport(viewportX, viewportY, m_viewportWidth, m_viewportHeight);
477         gl.blendEquation(m_blendMode);
478 
479         // \note coherent extension enables GL_BLEND_ADVANCED_COHERENT_KHR by default
480         if (m_coherentBlending)
481             gl.enable(GL_BLEND_ADVANCED_COHERENT_KHR);
482         else if (m_coherentExtensionSupported)
483             gl.disable(GL_BLEND_ADVANCED_COHERENT_KHR);
484 
485         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to set render state");
486 
487         gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
488 
489         gl.disable(GL_BLEND);
490         gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, DE_NULL);
491         gl.enable(GL_BLEND);
492 
493         if (!m_coherentBlending)
494             gl.blendBarrier();
495 
496         if (m_coherentBlending)
497         {
498             gl.drawElements(GL_TRIANGLES, 6 * (numQuads - 1), GL_UNSIGNED_SHORT,
499                             (const void *)(uintptr_t)(6 * sizeof(uint16_t)));
500         }
501         else
502         {
503             for (int quadNdx = 1; quadNdx < numQuads; quadNdx++)
504             {
505                 gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT,
506                                 (const void *)(uintptr_t)(quadNdx * 6 * sizeof(uint16_t)));
507                 gl.blendBarrier();
508             }
509         }
510 
511         if (vao)
512             gl.deleteVertexArrays(1, &vao);
513 
514         gl.flush();
515         GLU_EXPECT_NO_ERROR(gl.getError(), "Render failed");
516     }
517 
518     // Render reference.
519     {
520         rr::FragmentOperationState referenceState;
521         const tcu::PixelBufferAccess colorAccess =
522             gls::FragmentOpUtil::getMultisampleAccess(m_refColorBuffer->getAccess());
523         const tcu::PixelBufferAccess nullAccess = tcu::PixelBufferAccess();
524         IntegerQuad quad;
525 
526         if (!useFbo && m_context.getRenderTarget().getPixelFormat().alphaBits == 0)
527         {
528             // Emulate lack of alpha by clearing to 1 and masking out alpha writes
529             tcu::clear(*m_refColorBuffer, tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
530             referenceState.colorMask = tcu::BVec4(true, true, true, false);
531         }
532 
533         referenceState.blendEquationAdvaced = sglr::rr_util::mapGLBlendEquationAdvanced(m_blendMode);
534 
535         quad.posA = tcu::IVec2(0, 0);
536         quad.posB = tcu::IVec2(m_viewportWidth - 1, m_viewportHeight - 1);
537 
538         for (int quadNdx = 0; quadNdx < numQuads; quadNdx++)
539         {
540             referenceState.blendMode = quadNdx == 0 ? rr::BLENDMODE_NONE : rr::BLENDMODE_ADVANCED;
541             std::copy(&colors[4 * quadNdx], &colors[4 * quadNdx] + 4, &quad.color[0]);
542             m_referenceRenderer->render(colorAccess, nullAccess /* no depth */, nullAccess /* no stencil */, quad,
543                                         referenceState);
544         }
545     }
546 
547     if (requiresResolve)
548     {
549         gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_resolveFbo);
550         gl.blitFramebuffer(0, 0, m_renderWidth, m_renderHeight, 0, 0, m_renderWidth, m_renderHeight,
551                            GL_COLOR_BUFFER_BIT, GL_NEAREST);
552         GLU_EXPECT_NO_ERROR(gl.getError(), "Resolve blit failed");
553 
554         gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_resolveFbo);
555     }
556 
557     glu::readPixels(renderCtx, viewportX, viewportY, renderedImg.getAccess());
558     GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels()");
559 
560     if (requiresResolve)
561         gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
562 
563     {
564         const bool isHSLMode = m_blendMode == GL_HSL_HUE || m_blendMode == GL_HSL_SATURATION ||
565                                m_blendMode == GL_HSL_COLOR || m_blendMode == GL_HSL_LUMINOSITY;
566         bool comparePass = false;
567 
568         if (isHSLMode)
569         {
570             // Compensate for more demanding HSL code by using fuzzy comparison.
571             const float threshold = 0.002f;
572             comparePass           = tcu::fuzzyCompare(m_testCtx.getLog(), "CompareResult", "Image Comparison Result",
573                                                       getLinearAccess(m_refColorBuffer->getAccess()), renderedImg.getAccess(),
574                                                       threshold, tcu::COMPARE_LOG_RESULT);
575         }
576         else
577         {
578             const UVec4 compareThreshold =
579                 (useFbo ? tcu::PixelFormat(8, 8, 8, 8) : m_context.getRenderTarget().getPixelFormat())
580                         .getColorThreshold()
581                         .toIVec()
582                         .asUint() *
583                     UVec4(5) / UVec4(2) +
584                 UVec4(3 * m_overdrawCount);
585 
586             comparePass = tcu::bilinearCompare(
587                 m_testCtx.getLog(), "CompareResult", "Image Comparison Result",
588                 getLinearAccess(m_refColorBuffer->getAccess()), renderedImg.getAccess(),
589                 tcu::RGBA(compareThreshold[0], compareThreshold[1], compareThreshold[2], compareThreshold[3]),
590                 tcu::COMPARE_LOG_RESULT);
591         }
592 
593         if (!comparePass)
594         {
595             m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
596             return STOP;
597         }
598     }
599 
600     m_iterNdx += 1;
601 
602     if (m_iterNdx < m_numIters)
603         return CONTINUE;
604     else
605     {
606         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
607         return STOP;
608     }
609 }
610 
611 class BlendAdvancedCoherentStateCase : public TestCase
612 {
613 public:
614     BlendAdvancedCoherentStateCase(Context &context, const char *name, const char *description,
615                                    gls::StateQueryUtil::QueryType type);
616 
617 private:
618     IterateResult iterate(void);
619 
620     const gls::StateQueryUtil::QueryType m_type;
621 };
622 
BlendAdvancedCoherentStateCase(Context & context,const char * name,const char * description,gls::StateQueryUtil::QueryType type)623 BlendAdvancedCoherentStateCase::BlendAdvancedCoherentStateCase(Context &context, const char *name,
624                                                                const char *description,
625                                                                gls::StateQueryUtil::QueryType type)
626     : TestCase(context, name, description)
627     , m_type(type)
628 {
629 }
630 
iterate(void)631 BlendAdvancedCoherentStateCase::IterateResult BlendAdvancedCoherentStateCase::iterate(void)
632 {
633     TCU_CHECK_AND_THROW(NotSupportedError,
634                         m_context.getContextInfo().isExtensionSupported("GL_KHR_blend_equation_advanced_coherent"),
635                         "GL_KHR_blend_equation_advanced_coherent is not supported");
636 
637     glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
638     tcu::ResultCollector result(m_testCtx.getLog(), " // ERROR: ");
639 
640     gl.enableLogging(true);
641 
642     // check inital value
643     {
644         const tcu::ScopedLogSection section(m_testCtx.getLog(), "Initial", "Initial");
645         gls::StateQueryUtil::verifyStateBoolean(result, gl, GL_BLEND_ADVANCED_COHERENT_KHR, true, m_type);
646     }
647 
648     // check toggle
649     {
650         const tcu::ScopedLogSection section(m_testCtx.getLog(), "Toggle", "Toggle");
651         gl.glDisable(GL_BLEND_ADVANCED_COHERENT_KHR);
652         GLU_EXPECT_NO_ERROR(gl.glGetError(), "glDisable");
653 
654         gls::StateQueryUtil::verifyStateBoolean(result, gl, GL_BLEND_ADVANCED_COHERENT_KHR, false, m_type);
655 
656         gl.glEnable(GL_BLEND_ADVANCED_COHERENT_KHR);
657         GLU_EXPECT_NO_ERROR(gl.glGetError(), "glEnable");
658 
659         gls::StateQueryUtil::verifyStateBoolean(result, gl, GL_BLEND_ADVANCED_COHERENT_KHR, true, m_type);
660     }
661 
662     result.setTestContextResult(m_testCtx);
663     return STOP;
664 }
665 
666 class BlendEquationStateCase : public TestCase
667 {
668 public:
669     BlendEquationStateCase(Context &context, const char *name, const char *description, const glw::GLenum *equations,
670                            int numEquations, gls::StateQueryUtil::QueryType type);
671 
672 private:
673     IterateResult iterate(void);
674 
675     const gls::StateQueryUtil::QueryType m_type;
676     const glw::GLenum *m_equations;
677     const int m_numEquations;
678 };
679 
BlendEquationStateCase(Context & context,const char * name,const char * description,const glw::GLenum * equations,int numEquations,gls::StateQueryUtil::QueryType type)680 BlendEquationStateCase::BlendEquationStateCase(Context &context, const char *name, const char *description,
681                                                const glw::GLenum *equations, int numEquations,
682                                                gls::StateQueryUtil::QueryType type)
683     : TestCase(context, name, description)
684     , m_type(type)
685     , m_equations(equations)
686     , m_numEquations(numEquations)
687 {
688 }
689 
iterate(void)690 BlendEquationStateCase::IterateResult BlendEquationStateCase::iterate(void)
691 {
692     if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)))
693         TCU_CHECK_AND_THROW(NotSupportedError,
694                             m_context.getContextInfo().isExtensionSupported("GL_KHR_blend_equation_advanced"),
695                             "GL_KHR_blend_equation_advanced is not supported");
696 
697     glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
698     tcu::ResultCollector result(m_testCtx.getLog(), " // ERROR: ");
699 
700     gl.enableLogging(true);
701 
702     for (int ndx = 0; ndx < m_numEquations; ++ndx)
703     {
704         const tcu::ScopedLogSection section(m_testCtx.getLog(), "Type",
705                                             "Test " + de::toString(glu::getBlendEquationStr(m_equations[ndx])));
706 
707         gl.glBlendEquation(m_equations[ndx]);
708         GLU_EXPECT_NO_ERROR(gl.glGetError(), "glBlendEquation");
709 
710         gls::StateQueryUtil::verifyStateInteger(result, gl, GL_BLEND_EQUATION, m_equations[ndx], m_type);
711     }
712 
713     result.setTestContextResult(m_testCtx);
714     return STOP;
715 }
716 
717 class BlendEquationIndexedStateCase : public TestCase
718 {
719 public:
720     BlendEquationIndexedStateCase(Context &context, const char *name, const char *description,
721                                   const glw::GLenum *equations, int numEquations, gls::StateQueryUtil::QueryType type);
722 
723 private:
724     IterateResult iterate(void);
725 
726     const gls::StateQueryUtil::QueryType m_type;
727     const glw::GLenum *m_equations;
728     const int m_numEquations;
729 };
730 
BlendEquationIndexedStateCase(Context & context,const char * name,const char * description,const glw::GLenum * equations,int numEquations,gls::StateQueryUtil::QueryType type)731 BlendEquationIndexedStateCase::BlendEquationIndexedStateCase(Context &context, const char *name,
732                                                              const char *description, const glw::GLenum *equations,
733                                                              int numEquations, gls::StateQueryUtil::QueryType type)
734     : TestCase(context, name, description)
735     , m_type(type)
736     , m_equations(equations)
737     , m_numEquations(numEquations)
738 {
739 }
740 
iterate(void)741 BlendEquationIndexedStateCase::IterateResult BlendEquationIndexedStateCase::iterate(void)
742 {
743     const auto &renderContext = m_context.getRenderContext();
744     if (!glu::contextSupports(renderContext.getType(), glu::ApiType::es(3, 2)) &&
745         !glu::contextSupports(renderContext.getType(), glu::ApiType::core(4, 5)))
746     {
747         TCU_CHECK_AND_THROW(NotSupportedError,
748                             m_context.getContextInfo().isExtensionSupported("GL_KHR_blend_equation_advanced"),
749                             "GL_KHR_blend_equation_advanced is not supported");
750         TCU_CHECK_AND_THROW(NotSupportedError,
751                             m_context.getContextInfo().isExtensionSupported("GL_EXT_draw_buffers_indexed"),
752                             "GL_EXT_draw_buffers_indexed is not supported");
753     }
754 
755     glu::CallLogWrapper gl(renderContext.getFunctions(), m_testCtx.getLog());
756     tcu::ResultCollector result(m_testCtx.getLog(), " // ERROR: ");
757 
758     gl.enableLogging(true);
759 
760     for (int ndx = 0; ndx < m_numEquations; ++ndx)
761     {
762         const tcu::ScopedLogSection section(m_testCtx.getLog(), "Type",
763                                             "Test " + de::toString(glu::getBlendEquationStr(m_equations[ndx])));
764 
765         gl.glBlendEquationi(2, m_equations[ndx]);
766         GLU_EXPECT_NO_ERROR(gl.glGetError(), "glBlendEquationi");
767 
768         gls::StateQueryUtil::verifyStateIndexedInteger(result, gl, GL_BLEND_EQUATION, 2, m_equations[ndx], m_type);
769     }
770 
771     result.setTestContextResult(m_testCtx);
772     return STOP;
773 }
774 
775 } // namespace
776 
AdvancedBlendTests(Context & context)777 AdvancedBlendTests::AdvancedBlendTests(Context &context)
778     : TestCaseGroup(context, "blend_equation_advanced", "GL_blend_equation_advanced Tests")
779 {
780 }
781 
~AdvancedBlendTests(void)782 AdvancedBlendTests::~AdvancedBlendTests(void)
783 {
784 }
785 
init(void)786 void AdvancedBlendTests::init(void)
787 {
788     static const glw::GLenum s_blendEquations[] = {
789         GL_MULTIPLY,   GL_SCREEN,    GL_OVERLAY,        GL_DARKEN,    GL_LIGHTEN,
790         GL_COLORDODGE, GL_COLORBURN, GL_HARDLIGHT,      GL_SOFTLIGHT, GL_DIFFERENCE,
791         GL_EXCLUSION,  GL_HSL_HUE,   GL_HSL_SATURATION, GL_HSL_COLOR, GL_HSL_LUMINOSITY,
792 
793     };
794 
795     tcu::TestCaseGroup *const stateQueryGroup = new tcu::TestCaseGroup(m_testCtx, "state_query", "State query tests");
796     tcu::TestCaseGroup *const basicGroup      = new tcu::TestCaseGroup(m_testCtx, "basic", "Single quad only");
797     tcu::TestCaseGroup *const srgbGroup = new tcu::TestCaseGroup(m_testCtx, "srgb", "Advanced blending with sRGB FBO");
798     tcu::TestCaseGroup *const msaaGroup = new tcu::TestCaseGroup(m_testCtx, "msaa", "Advanced blending with MSAA FBO");
799     tcu::TestCaseGroup *const barrierGroup =
800         new tcu::TestCaseGroup(m_testCtx, "barrier", "Multiple overlapping quads with blend barriers");
801     tcu::TestCaseGroup *const coherentGroup =
802         new tcu::TestCaseGroup(m_testCtx, "coherent", "Overlapping quads with coherent blending");
803     tcu::TestCaseGroup *const coherentMsaaGroup =
804         new tcu::TestCaseGroup(m_testCtx, "coherent_msaa", "Overlapping quads with coherent blending with MSAA FBO");
805 
806     addChild(stateQueryGroup);
807     addChild(basicGroup);
808     addChild(srgbGroup);
809     addChild(msaaGroup);
810     addChild(barrierGroup);
811     addChild(coherentGroup);
812     addChild(coherentMsaaGroup);
813 
814     // .state_query
815     {
816         using namespace gls::StateQueryUtil;
817 
818         stateQueryGroup->addChild(new BlendAdvancedCoherentStateCase(
819             m_context, "blend_advanced_coherent_getboolean", "Test BLEND_ADVANCED_COHERENT_KHR", QUERY_BOOLEAN));
820         stateQueryGroup->addChild(new BlendAdvancedCoherentStateCase(
821             m_context, "blend_advanced_coherent_isenabled", "Test BLEND_ADVANCED_COHERENT_KHR", QUERY_ISENABLED));
822         stateQueryGroup->addChild(new BlendAdvancedCoherentStateCase(
823             m_context, "blend_advanced_coherent_getinteger", "Test BLEND_ADVANCED_COHERENT_KHR", QUERY_INTEGER));
824         stateQueryGroup->addChild(new BlendAdvancedCoherentStateCase(
825             m_context, "blend_advanced_coherent_getinteger64", "Test BLEND_ADVANCED_COHERENT_KHR", QUERY_INTEGER64));
826         stateQueryGroup->addChild(new BlendAdvancedCoherentStateCase(m_context, "blend_advanced_coherent_getfloat",
827                                                                      "Test BLEND_ADVANCED_COHERENT_KHR", QUERY_FLOAT));
828 
829         stateQueryGroup->addChild(new BlendEquationStateCase(m_context, "blend_equation_getboolean",
830                                                              "Test BLEND_EQUATION", s_blendEquations,
831                                                              DE_LENGTH_OF_ARRAY(s_blendEquations), QUERY_BOOLEAN));
832         stateQueryGroup->addChild(new BlendEquationStateCase(m_context, "blend_equation_getinteger",
833                                                              "Test BLEND_EQUATION", s_blendEquations,
834                                                              DE_LENGTH_OF_ARRAY(s_blendEquations), QUERY_INTEGER));
835         stateQueryGroup->addChild(new BlendEquationStateCase(m_context, "blend_equation_getinteger64",
836                                                              "Test BLEND_EQUATION", s_blendEquations,
837                                                              DE_LENGTH_OF_ARRAY(s_blendEquations), QUERY_INTEGER64));
838         stateQueryGroup->addChild(new BlendEquationStateCase(m_context, "blend_equation_getfloat",
839                                                              "Test BLEND_EQUATION", s_blendEquations,
840                                                              DE_LENGTH_OF_ARRAY(s_blendEquations), QUERY_FLOAT));
841 
842         stateQueryGroup->addChild(new BlendEquationIndexedStateCase(
843             m_context, "blend_equation_getbooleani_v", "Test per-attchment BLEND_EQUATION", s_blendEquations,
844             DE_LENGTH_OF_ARRAY(s_blendEquations), QUERY_INDEXED_BOOLEAN));
845         stateQueryGroup->addChild(new BlendEquationIndexedStateCase(
846             m_context, "blend_equation_getintegeri_v", "Test per-attchment BLEND_EQUATION", s_blendEquations,
847             DE_LENGTH_OF_ARRAY(s_blendEquations), QUERY_INDEXED_INTEGER));
848         stateQueryGroup->addChild(new BlendEquationIndexedStateCase(
849             m_context, "blend_equation_getinteger64i_v", "Test per-attchment BLEND_EQUATION", s_blendEquations,
850             DE_LENGTH_OF_ARRAY(s_blendEquations), QUERY_INDEXED_INTEGER64));
851     }
852 
853     // others
854     for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(s_blendEquations); modeNdx++)
855     {
856         const char *const name = getEquationName(s_blendEquations[modeNdx]);
857         const char *const desc = "";
858         const uint32_t mode    = s_blendEquations[modeNdx];
859 
860         basicGroup->addChild(new AdvancedBlendCase(m_context, name, desc, mode, 1, false, RENDERTARGETTYPE_DEFAULT));
861         srgbGroup->addChild(new AdvancedBlendCase(m_context, name, desc, mode, 1, false, RENDERTARGETTYPE_SRGB_FBO));
862         msaaGroup->addChild(new AdvancedBlendCase(m_context, name, desc, mode, 1, false, RENDERTARGETTYPE_MSAA_FBO));
863         barrierGroup->addChild(new AdvancedBlendCase(m_context, name, desc, mode, 4, false, RENDERTARGETTYPE_DEFAULT));
864         coherentGroup->addChild(new AdvancedBlendCase(m_context, name, desc, mode, 4, true, RENDERTARGETTYPE_DEFAULT));
865         coherentMsaaGroup->addChild(
866             new AdvancedBlendCase(m_context, name, desc, mode, 4, true, RENDERTARGETTYPE_MSAA_FBO));
867     }
868 }
869 
870 } // namespace Functional
871 } // namespace gles31
872 } // namespace deqp
873