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