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