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