1/*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
4 *
5 * Copyright (c) 2014-2016 The Khronos Group Inc.
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
22 */ /*-------------------------------------------------------------------*/
23
24#include "glcBlendEquationAdvancedTests.hpp"
25// de
26#include "deRandom.hpp"
27#include "deString.h"
28// tcu
29#include "tcuRGBA.hpp"
30#include "tcuRenderTarget.hpp"
31#include "tcuStringTemplate.hpp"
32#include "tcuSurface.hpp"
33#include "tcuTestLog.hpp"
34#include "tcuVectorType.hpp"
35#include "tcuVectorUtil.hpp"
36// glu
37#include "gluContextInfo.hpp"
38#include "gluDrawUtil.hpp"
39#include "gluPixelTransfer.hpp"
40#include "gluShaderProgram.hpp"
41// glw
42#include "glwEnums.hpp"
43#include "glwFunctions.hpp"
44// de
45#include "deMath.h"
46// stl
47#include <algorithm>
48#include <map>
49#include <memory>
50#include <sstream>
51#include <string>
52#include <vector>
53
54namespace glcts
55{
56using tcu::TestLog;
57
58static const float	s_pos[]	 = { -1.0f, -1.0f, -1.0f, +1.0f, +1.0f, -1.0f, +1.0f, +1.0f };
59static const deUint16 s_indices[] = { 0, 1, 2, 2, 1, 3 };
60
61// Lists all modes introduced by the extension.
62static const glw::GLenum s_modes[] = { GL_MULTIPLY_KHR,		  GL_SCREEN_KHR,	 GL_OVERLAY_KHR,	   GL_DARKEN_KHR,
63									   GL_LIGHTEN_KHR,		  GL_COLORDODGE_KHR, GL_COLORBURN_KHR,	 GL_HARDLIGHT_KHR,
64									   GL_SOFTLIGHT_KHR,	  GL_DIFFERENCE_KHR, GL_EXCLUSION_KHR,	 GL_HSL_HUE_KHR,
65									   GL_HSL_SATURATION_KHR, GL_HSL_COLOR_KHR,  GL_HSL_LUMINOSITY_KHR };
66
67static const char* GetModeStr(glw::GLenum mode)
68{
69	switch (mode)
70	{
71	case GL_MULTIPLY_KHR:
72		return "GL_MULTIPLY_KHR";
73	case GL_SCREEN_KHR:
74		return "GL_SCREEN_KHR";
75	case GL_OVERLAY_KHR:
76		return "GL_OVERLAY_KHR";
77	case GL_DARKEN_KHR:
78		return "GL_DARKEN_KHR";
79	case GL_LIGHTEN_KHR:
80		return "GL_LIGHTEN_KHR";
81	case GL_COLORDODGE_KHR:
82		return "GL_COLORDODGE_KHR";
83	case GL_COLORBURN_KHR:
84		return "GL_COLORBURN_KHR";
85	case GL_HARDLIGHT_KHR:
86		return "GL_HARDLIGHT_KHR";
87	case GL_SOFTLIGHT_KHR:
88		return "GL_SOFTLIGHT_KHR";
89	case GL_DIFFERENCE_KHR:
90		return "GL_DIFFERENCE_KHR";
91	case GL_EXCLUSION_KHR:
92		return "GL_EXCLUSION_KHR";
93	case GL_HSL_HUE_KHR:
94		return "GL_HSL_HUE_KHR";
95	case GL_HSL_SATURATION_KHR:
96		return "GL_HSL_SATURATION_KHR";
97	case GL_HSL_COLOR_KHR:
98		return "GL_HSL_COLOR_KHR";
99	case GL_HSL_LUMINOSITY_KHR:
100		return "GL_HSL_LUMINOSITY_KHR";
101	default:
102		DE_ASSERT(DE_FALSE && "Blend mode not from GL_KHR_blend_equation_advanced.");
103		return "Blend mode not from GL_KHR_blend_equation_advanced.";
104	}
105}
106
107static const char* GetLayoutQualifierStr(glw::GLenum mode)
108{
109	switch (mode)
110	{
111	case GL_MULTIPLY_KHR:
112		return "blend_support_multiply";
113	case GL_SCREEN_KHR:
114		return "blend_support_screen";
115	case GL_OVERLAY_KHR:
116		return "blend_support_overlay";
117	case GL_DARKEN_KHR:
118		return "blend_support_darken";
119	case GL_LIGHTEN_KHR:
120		return "blend_support_lighten";
121	case GL_COLORDODGE_KHR:
122		return "blend_support_colordodge";
123	case GL_COLORBURN_KHR:
124		return "blend_support_colorburn";
125	case GL_HARDLIGHT_KHR:
126		return "blend_support_hardlight";
127	case GL_SOFTLIGHT_KHR:
128		return "blend_support_softlight";
129	case GL_DIFFERENCE_KHR:
130		return "blend_support_difference";
131	case GL_EXCLUSION_KHR:
132		return "blend_support_exclusion";
133	case GL_HSL_HUE_KHR:
134		return "blend_support_hsl_hue";
135	case GL_HSL_SATURATION_KHR:
136		return "blend_support_hsl_saturation";
137	case GL_HSL_COLOR_KHR:
138		return "blend_support_hsl_color";
139	case GL_HSL_LUMINOSITY_KHR:
140		return "blend_support_hsl_luminosity";
141	default:
142		DE_ASSERT(DE_FALSE && "Blend mode not from GL_KHR_blend_equation_advanced.");
143		return "Blend mode not from GL_KHR_blend_equation_advanced.";
144	}
145}
146
147static bool IsExtensionSupported(deqp::Context& context, const char* extension)
148{
149	const std::vector<std::string>& v = context.getContextInfo().getExtensions();
150	return std::find(v.begin(), v.end(), extension) != v.end();
151}
152
153static float GetP0(const tcu::Vec4& src, const tcu::Vec4& dst)
154{
155	return src[3] * dst[3];
156}
157static float GetP1(const tcu::Vec4& src, const tcu::Vec4& dst)
158{
159	return src[3] * (1.f - dst[3]);
160}
161static float GetP2(const tcu::Vec4& src, const tcu::Vec4& dst)
162{
163	return dst[3] * (1.f - src[3]);
164}
165
166static tcu::Vec4 Blend(const tcu::Vec4& rgb, const tcu::Vec4& src, const tcu::Vec4& dst)
167{
168	float	 p[3]   = { GetP0(src, dst), GetP1(src, dst), GetP2(src, dst) };
169	float	 alpha  = p[0] + p[1] + p[2];
170	tcu::Vec4 rgbOut = (p[0] * rgb) + (p[1] * src) + (p[2] * dst);
171	return tcu::Vec4(rgbOut[0], rgbOut[1], rgbOut[2], alpha);
172}
173
174static tcu::Vec4 BlendMultiply(const tcu::Vec4& src, const tcu::Vec4& dst)
175{
176	tcu::Vec4 rgb = src * dst;
177
178	return Blend(rgb, src, dst);
179}
180
181static tcu::Vec4 BlendScreen(const tcu::Vec4& src, const tcu::Vec4& dst)
182{
183	tcu::Vec4 rgb = src + dst - src * dst;
184
185	return Blend(rgb, src, dst);
186}
187
188static float Overlay(float s, float d)
189{
190	if (d <= 0.5f)
191		return 2.f * s * d;
192	else
193		return 1.f - 2.f * (1.f - s) * (1.f - d);
194}
195
196static tcu::Vec4 BlendOverlay(const tcu::Vec4& src, const tcu::Vec4& dst)
197{
198	tcu::Vec4 rgb(Overlay(src[0], dst[0]), Overlay(src[1], dst[1]), Overlay(src[2], dst[2]), 0.f);
199
200	return Blend(rgb, src, dst);
201}
202
203static tcu::Vec4 BlendDarken(const tcu::Vec4& src, const tcu::Vec4& dst)
204{
205	tcu::Vec4 rgb(de::min(src[0], dst[0]), de::min(src[1], dst[1]), de::min(src[2], dst[2]), 0.f);
206
207	return Blend(rgb, src, dst);
208}
209
210static tcu::Vec4 BlendLighten(const tcu::Vec4& src, const tcu::Vec4& dst)
211{
212	tcu::Vec4 rgb(de::max(src[0], dst[0]), de::max(src[1], dst[1]), de::max(src[2], dst[2]), 0.f);
213
214	return Blend(rgb, src, dst);
215}
216
217static float ColorDodge(float s, float d)
218{
219	if (d <= 0.f)
220		return 0.f;
221	else if (d > 0.f && s < 1.f)
222		return de::min(1.f, d / (1.f - s));
223	else
224		return 1.f;
225}
226
227static tcu::Vec4 BlendColorDodge(const tcu::Vec4& src, const tcu::Vec4& dst)
228{
229	tcu::Vec4 rgb(ColorDodge(src[0], dst[0]), ColorDodge(src[1], dst[1]), ColorDodge(src[2], dst[2]), 0.f);
230
231	return Blend(rgb, src, dst);
232}
233
234static float ColorBurn(float s, float d)
235{
236	if (d >= 1.f)
237		return 1.f;
238	else if (d < 1.f && s > 0.f)
239		return 1.f - de::min(1.f, (1.f - d) / s);
240	else
241	{
242		DE_ASSERT(d < 1.f && s <= 0.f);
243		return 0.f;
244	}
245}
246
247static tcu::Vec4 BlendColorBurn(const tcu::Vec4& src, const tcu::Vec4& dst)
248{
249	tcu::Vec4 rgb(ColorBurn(src[0], dst[0]), ColorBurn(src[1], dst[1]), ColorBurn(src[2], dst[2]), 0.f);
250
251	return Blend(rgb, src, dst);
252}
253
254static float HardLight(float s, float d)
255{
256	if (s <= 0.5f)
257		return 2.f * s * d;
258	else
259		return 1.f - 2.f * (1.f - s) * (1.f - d);
260}
261
262static tcu::Vec4 BlendHardLight(const tcu::Vec4& src, const tcu::Vec4& dst)
263{
264	tcu::Vec4 rgb(HardLight(src[0], dst[0]), HardLight(src[1], dst[1]), HardLight(src[2], dst[2]), 0.f);
265
266	return Blend(rgb, src, dst);
267}
268
269static float SoftLight(float s, float d)
270{
271	if (s <= 0.5f)
272		return d - (1.f - 2.f * s) * d * (1.f - d);
273	else if (d <= 0.25f)
274	{
275		DE_ASSERT(s > 0.5f && d <= 0.25f);
276		return d + (2.f * s - 1.f) * d * ((16.f * d - 12.f) * d + 3.f);
277	}
278	else
279	{
280		DE_ASSERT(s > 0.5f && d > 0.25f);
281		return d + (2.f * s - 1.f) * (deFloatSqrt(d) - d);
282	}
283}
284
285static tcu::Vec4 BlendSoftLight(const tcu::Vec4& src, const tcu::Vec4& dst)
286{
287	tcu::Vec4 rgb(SoftLight(src[0], dst[0]), SoftLight(src[1], dst[1]), SoftLight(src[2], dst[2]), 0.f);
288
289	return Blend(rgb, src, dst);
290}
291
292static tcu::Vec4 BlendDifference(const tcu::Vec4& src, const tcu::Vec4& dst)
293{
294	tcu::Vec4 rgb(deFloatAbs(src[0] - dst[0]), deFloatAbs(src[1] - dst[1]), deFloatAbs(src[2] - dst[2]), 0.f);
295
296	return Blend(rgb, src, dst);
297}
298
299static float Exclusion(float s, float d)
300{
301	return s + d - 2.f * s * d;
302}
303
304static tcu::Vec4 BlendExclusion(const tcu::Vec4& src, const tcu::Vec4& dst)
305{
306	tcu::Vec4 rgb(Exclusion(src[0], dst[0]), Exclusion(src[1], dst[1]), Exclusion(src[2], dst[2]), 0.f);
307	return Blend(rgb, src, dst);
308}
309
310static float Luminance(const tcu::Vec4& rgba)
311{
312	// Coefficients from the KHR_GL_blend_equation_advanced test spec.
313	return 0.30f * rgba[0] + 0.59f * rgba[1] + 0.11f * rgba[2];
314}
315
316// Minimum of R, G and B components.
317static float MinRGB(const tcu::Vec4& rgba)
318{
319	return deFloatMin(deFloatMin(rgba[0], rgba[1]), rgba[2]);
320}
321
322// Maximum of R, G and B components.
323static float MaxRGB(const tcu::Vec4& rgba)
324{
325	return deFloatMax(deFloatMax(rgba[0], rgba[1]), rgba[2]);
326}
327
328static float Saturation(const tcu::Vec4& rgba)
329{
330	return MaxRGB(rgba) - MinRGB(rgba);
331}
332
333// Take the base RGB color <cbase> and override its luminosity
334// with that of the RGB color <clum>.
335static tcu::Vec4 SetLum(const tcu::Vec4& cbase, const tcu::Vec4& clum)
336{
337	float	 lbase = Luminance(cbase);
338	float	 llum  = Luminance(clum);
339	float	 ldiff = llum - lbase;
340	tcu::Vec4 color = cbase + tcu::Vec4(ldiff);
341	tcu::Vec4 vllum = tcu::Vec4(llum);
342	if (MinRGB(color) < 0.0f)
343	{
344		return vllum + ((color - vllum) * llum) / (llum - MinRGB(color));
345	}
346	else if (MaxRGB(color) > 1.0f)
347	{
348		return vllum + ((color - vllum) * (1.f - llum)) / (MaxRGB(color) - llum);
349	}
350	else
351	{
352		return color;
353	}
354}
355
356// Take the base RGB color <cbase> and override its saturation with
357// that of the RGB color <csat>.  The override the luminosity of the
358// result with that of the RGB color <clum>.
359static tcu::Vec4 SetLumSat(const tcu::Vec4& cbase, const tcu::Vec4& csat, const tcu::Vec4& clum)
360{
361	float	 minbase = MinRGB(cbase);
362	float	 sbase   = Saturation(cbase);
363	float	 ssat	= Saturation(csat);
364	tcu::Vec4 color;
365	if (sbase > 0)
366	{
367		// From the extension spec:
368		// Equivalent (modulo rounding errors) to setting the
369		// smallest (R,G,B) component to 0, the largest to <ssat>,
370		// and interpolating the "middle" component based on its
371		// original value relative to the smallest/largest.
372		color = (cbase - tcu::Vec4(minbase)) * ssat / sbase;
373	}
374	else
375	{
376		color = tcu::Vec4(0.0f);
377	}
378	return SetLum(color, clum);
379}
380
381static tcu::Vec4 BlendHSLHue(const tcu::Vec4& src, const tcu::Vec4& dst)
382{
383	tcu::Vec4 rgb = SetLumSat(src, dst, dst);
384	return Blend(rgb, src, dst);
385}
386
387static tcu::Vec4 BlendHSLSaturation(const tcu::Vec4& src, const tcu::Vec4& dst)
388{
389	tcu::Vec4 rgb = SetLumSat(dst, src, dst);
390	return Blend(rgb, src, dst);
391}
392
393static tcu::Vec4 BlendHSLColor(const tcu::Vec4& src, const tcu::Vec4& dst)
394{
395	tcu::Vec4 rgb = SetLum(src, dst);
396	return Blend(rgb, src, dst);
397}
398
399static tcu::Vec4 BlendHSLuminosity(const tcu::Vec4& src, const tcu::Vec4& dst)
400{
401	tcu::Vec4 rgb = SetLum(dst, src);
402	return Blend(rgb, src, dst);
403}
404
405typedef tcu::Vec4 (*BlendFunc)(const tcu::Vec4& src, const tcu::Vec4& dst);
406
407static BlendFunc GetBlendFunc(glw::GLenum mode)
408{
409	switch (mode)
410	{
411	case GL_MULTIPLY_KHR:
412		return BlendMultiply;
413	case GL_SCREEN_KHR:
414		return BlendScreen;
415	case GL_OVERLAY_KHR:
416		return BlendOverlay;
417	case GL_DARKEN_KHR:
418		return BlendDarken;
419	case GL_LIGHTEN_KHR:
420		return BlendLighten;
421	case GL_COLORDODGE_KHR:
422		return BlendColorDodge;
423	case GL_COLORBURN_KHR:
424		return BlendColorBurn;
425	case GL_HARDLIGHT_KHR:
426		return BlendHardLight;
427	case GL_SOFTLIGHT_KHR:
428		return BlendSoftLight;
429	case GL_DIFFERENCE_KHR:
430		return BlendDifference;
431	case GL_EXCLUSION_KHR:
432		return BlendExclusion;
433	case GL_HSL_HUE_KHR:
434		return BlendHSLHue;
435	case GL_HSL_SATURATION_KHR:
436		return BlendHSLSaturation;
437	case GL_HSL_COLOR_KHR:
438		return BlendHSLColor;
439	case GL_HSL_LUMINOSITY_KHR:
440		return BlendHSLuminosity;
441	default:
442		DE_ASSERT(DE_FALSE && "Blend mode not from GL_KHR_blend_equation_advanced.");
443		return NULL;
444	}
445}
446
447static tcu::Vec4 ToNormal(const tcu::Vec4& v)
448{
449	float a = v[3];
450	if (a == 0)
451		return tcu::Vec4(0.f, 0.f, 0.f, 0.f);
452	return tcu::Vec4(v[0] / a, v[1] / a, v[2] / a, a);
453}
454
455// Blend premultiplied src and dst with given blend mode.
456static tcu::Vec4 Blend(glw::GLenum mode, const tcu::Vec4& src, const tcu::Vec4& dst)
457{
458	BlendFunc blend   = GetBlendFunc(mode);
459	tcu::Vec4 srcNorm = ToNormal(src);
460	tcu::Vec4 dstNorm = ToNormal(dst);
461
462	return blend(srcNorm, dstNorm);
463}
464
465static std::string GetDef2DVtxSrc(glu::GLSLVersion glslVersion)
466{
467	std::stringstream str;
468
469	DE_ASSERT(glslVersion == glu::GLSL_VERSION_310_ES || glslVersion >= glu::GLSL_VERSION_430);
470
471	str << glu::getGLSLVersionDeclaration(glslVersion) << "\n"
472		<< "in highp vec2 aPos;\n"
473		   "void main() {\n"
474		   "   gl_Position = vec4(aPos, 0.0, 1.0);\n"
475		   "}\n";
476	return str.str();
477}
478
479static std::string GetSolidShader(
480	const char* layoutQualifier, const char* glslVersion,
481	const char* extensionDirective = "#extension GL_KHR_blend_equation_advanced : require")
482{
483	static const char* frgSrcTemplate = "${VERSION_DIRECTIVE}\n"
484										"${EXTENSION_DIRECTIVE}\n"
485										"\n"
486										"precision highp float;\n"
487										"\n"
488										"${LAYOUT_QUALIFIER}\n"
489										"layout (location = 0) out vec4 oCol;\n"
490										"\n"
491										"uniform vec4 uSrcCol;\n"
492										"\n"
493										"void main (void) {\n"
494										"   oCol = uSrcCol;\n"
495										"}\n";
496
497	std::map<std::string, std::string> args;
498	args["VERSION_DIRECTIVE"]   = glslVersion;
499	args["EXTENSION_DIRECTIVE"] = extensionDirective;
500	if (layoutQualifier)
501		args["LAYOUT_QUALIFIER"] = std::string("layout (") + layoutQualifier + std::string(") out;");
502	else
503		args["LAYOUT_QUALIFIER"] = ""; // none
504
505	return tcu::StringTemplate(frgSrcTemplate).specialize(args);
506}
507
508/*
509 * Framebuffer helper.
510 * Creates and binds FBO and either one or two renderbuffer color attachments (fmt0, fmt1) with
511 * given size (width, height).
512 *
513 * Note: Does not restore previous 1) fbo binding, 2) scissor or 3) viewport upon exit.
514 */
515class FBOSentry
516{
517public:
518	FBOSentry(const glw::Functions& gl, int width, int height, glw::GLenum fmt0);
519	FBOSentry(const glw::Functions& gl, int width, int height, glw::GLenum fmt0, glw::GLenum fmt1);
520	~FBOSentry();
521
522private:
523	void init(int width, int height, glw::GLenum fmt0, glw::GLenum fmt1);
524	const glw::Functions& m_gl;
525	glw::GLuint			  m_fbo;
526	glw::GLuint			  m_rbo[2];
527};
528
529FBOSentry::FBOSentry(const glw::Functions& gl, int width, int height, glw::GLenum fmt0) : m_gl(gl)
530{
531	init(width, height, fmt0, GL_NONE);
532}
533
534FBOSentry::FBOSentry(const glw::Functions& gl, int width, int height, glw::GLenum fmt0, glw::GLenum fmt1) : m_gl(gl)
535{
536	init(width, height, fmt0, fmt1);
537}
538
539FBOSentry::~FBOSentry()
540{
541	m_gl.deleteFramebuffers(1, &m_fbo);
542	m_gl.deleteRenderbuffers(2, m_rbo);
543}
544
545void FBOSentry::init(int width, int height, glw::GLenum fmt0, glw::GLenum fmt1)
546{
547	m_gl.genFramebuffers(1, &m_fbo);
548	m_gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
549
550	m_gl.genRenderbuffers(2, m_rbo);
551	m_gl.bindRenderbuffer(GL_RENDERBUFFER, m_rbo[0]);
552	m_gl.renderbufferStorage(GL_RENDERBUFFER, fmt0, width, height);
553	m_gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_rbo[0]);
554
555	if (fmt1 != GL_NONE)
556	{
557		m_gl.bindRenderbuffer(GL_RENDERBUFFER, m_rbo[1]);
558		m_gl.renderbufferStorage(GL_RENDERBUFFER, fmt1, width, height);
559		m_gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, m_rbo[1]);
560	}
561
562	glw::GLenum status = m_gl.checkFramebufferStatus(GL_FRAMEBUFFER);
563	if (m_gl.getError() != GL_NO_ERROR || status != GL_FRAMEBUFFER_COMPLETE)
564	{
565		TCU_FAIL("Framebuffer failed");
566	}
567
568	m_gl.viewport(0, 0, width, height);
569	m_gl.scissor(0, 0, width, height);
570}
571
572class CoherentBlendTestCaseGroup : public deqp::TestCaseGroup
573{
574public:
575	CoherentBlendTestCaseGroup(deqp::Context& context, glu::GLSLVersion glslVersion)
576		: TestCaseGroup(context, "test_coherency", ""), m_glslVersion(glslVersion)
577	{
578	}
579
580	void init(void)
581	{
582		addChild(
583			new CoherentBlendTest(m_context, "mixedSequence", m_glslVersion, 4, DE_LENGTH_OF_ARRAY(s_mixed), s_mixed));
584		addChild(new CoherentBlendTest(m_context, "multiplySequence", m_glslVersion, 1, DE_LENGTH_OF_ARRAY(s_multiply),
585									   s_multiply));
586	}
587
588private:
589	struct BlendStep;
590
591	class CoherentBlendTest : public deqp::TestCase
592	{
593	public:
594		CoherentBlendTest(deqp::Context& context, const char* name, glu::GLSLVersion glslVersion, int repeatCount,
595						  int numSteps, const BlendStep* steps)
596			: TestCase(context, name, "")
597			, m_glslVersion(glslVersion)
598			, m_repeatCount(repeatCount)
599			, m_numSteps(numSteps)
600			, m_steps(steps)
601		{
602			DE_ASSERT(repeatCount > 0 && numSteps > 0 && steps);
603		}
604
605		IterateResult iterate(void);
606
607	private:
608		glu::GLSLVersion m_glslVersion;
609		int				 m_repeatCount;
610		int				 m_numSteps;
611		const BlendStep* m_steps;
612	};
613
614	struct BlendStep
615	{
616		glw::GLenum  mode;
617		glw::GLfloat src[4]; // rgba
618	};
619
620	// Blend sequences.
621	static const BlendStep s_mixed[11];
622	static const BlendStep s_multiply[7];
623
624	glu::GLSLVersion m_glslVersion;
625};
626
627const CoherentBlendTestCaseGroup::BlendStep CoherentBlendTestCaseGroup::s_mixed[] = {
628	{ GL_LIGHTEN_KHR, { 0.250f, 0.375f, 1.000f, 1.000f } },	// =>  (0.250, 0.375, 1.000, 1.000) (from src)
629	{ GL_OVERLAY_KHR, { 1.000f, 1.000f, 1.000f, 1.000f } },	// => ~(0.500, 0.750, 1.000, 1.000)
630	{ GL_HARDLIGHT_KHR, { 0.750f, 0.750f, 0.250f, 1.000f } },  // => ~(0.750, 1.000, 0.500, 1.000)
631	{ GL_DARKEN_KHR, { 0.250f, 0.250f, 0.250f, 1.000f } },	 // =>  (0.250, 0.250, 0.250, 1.000) (from src)
632	{ GL_COLORDODGE_KHR, { 0.750f, 0.875f, 1.000f, 1.000f } }, // => ~(1.000, 1.000, 1.000, 1.000)
633	{ GL_MULTIPLY_KHR, { 0.500f, 0.500f, 0.500f, 1.000f } },   // => ~(0.500, 0.500, 0.500, 1.000)
634	{ GL_SCREEN_KHR, { 0.500f, 0.500f, 0.500f, 1.000f } },	 // => ~(0.750, 0.750, 0.750, 1.000)
635	{ GL_DARKEN_KHR, { 0.250f, 0.500f, 0.500f, 1.000f } },	 // =>  (0.250, 0.500, 0.500, 1.000) (from src)
636	{ GL_DIFFERENCE_KHR, { 0.000f, 0.875f, 0.125f, 1.000f } }, // => ~(0.250, 0.375, 0.375, 1.000)
637	{ GL_EXCLUSION_KHR, { 1.000f, 0.500f, 0.750f, 1.000f } },  // => ~(0.750, 0.500, 0.563, 1.000)
638	{ GL_DARKEN_KHR, { 0.125f, 0.125f, 0.125f, 1.000f } },	 // =>  (0.125, 0.125, 0.125, 1.000) (from src)
639	// Last row is unique and "accurate" since it comes from the source.
640	// That means so that it can be easily tested for correctness.
641};
642
643const CoherentBlendTestCaseGroup::BlendStep CoherentBlendTestCaseGroup::s_multiply[] = {
644	{ GL_LIGHTEN_KHR, { 1.000f, 1.000f, 1.000f, 1.000f } },  { GL_MULTIPLY_KHR, { 0.500f, 0.500f, 0.500f, 1.000f } },
645	{ GL_MULTIPLY_KHR, { 0.500f, 0.500f, 0.500f, 1.000f } }, { GL_MULTIPLY_KHR, { 0.500f, 0.500f, 0.500f, 1.000f } },
646	{ GL_MULTIPLY_KHR, { 0.500f, 0.500f, 0.500f, 1.000f } }, { GL_MULTIPLY_KHR, { 0.500f, 0.500f, 0.500f, 1.000f } },
647	{ GL_MULTIPLY_KHR, { 0.500f, 0.500f, 0.500f, 1.000f } }, // ~4 in 8bits
648};
649
650CoherentBlendTestCaseGroup::CoherentBlendTest::IterateResult CoherentBlendTestCaseGroup::CoherentBlendTest::iterate(
651	void)
652{
653	static const int		 dim = 1024;
654	const tcu::RenderTarget& rt  = m_context.getRenderContext().getRenderTarget();
655	const tcu::PixelFormat&  pf  = rt.getPixelFormat();
656	const glw::Functions&	gl  = m_context.getRenderContext().getFunctions();
657	TestLog&				 log = m_testCtx.getLog();
658
659	// Check that extension is supported.
660	if (!IsExtensionSupported(m_context, "GL_KHR_blend_equation_advanced"))
661	{
662		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_KHR_blend_equation_advanced");
663		return STOP;
664	}
665
666	bool needBarrier = !IsExtensionSupported(m_context, "GL_KHR_blend_equation_advanced_coherent");
667
668	tcu::Vec4 dstCol(0.f, 0.f, 0.f, 0.f);
669
670	FBOSentry fbo(gl, dim, dim, GL_RGBA8);
671
672	// Setup progra
673	std::string frgSrc = GetSolidShader("blend_support_all_equations", glu::getGLSLVersionDeclaration(m_glslVersion));
674	glu::ShaderProgram p(m_context.getRenderContext(),
675						 glu::makeVtxFragSources(GetDef2DVtxSrc(m_glslVersion).c_str(), frgSrc.c_str()));
676	if (!p.isOk())
677	{
678		log << p;
679		TCU_FAIL("Compile failed");
680	}
681	gl.useProgram(p.getProgram());
682	GLU_EXPECT_NO_ERROR(gl.getError(), "Program failed");
683
684	glu::VertexArrayBinding posBinding = glu::va::Float("aPos", 2, 4, 0, &s_pos[0]);
685
686	// Enable blending.
687	gl.disable(GL_DITHER);
688	gl.enable(GL_BLEND);
689
690	// Clear.
691	gl.clearColor(dstCol[0], dstCol[1], dstCol[2], dstCol[3]);
692	gl.clear(GL_COLOR_BUFFER_BIT);
693
694	// Blend barrier.
695	if (needBarrier)
696		gl.blendBarrier();
697
698	// Repeat block.
699	for (int i = 0; i < m_repeatCount; i++)
700		// Loop blending steps.
701		for (int j = 0; j < m_numSteps; j++)
702		{
703			const BlendStep& s = m_steps[j];
704			tcu::Vec4		 srcCol(s.src[0], s.src[1], s.src[2], s.src[3]);
705			tcu::Vec4		 refCol = Blend(s.mode, srcCol, dstCol);
706			dstCol					= refCol;
707
708			// Set blend equation.
709			gl.blendEquation(s.mode);
710			GLU_EXPECT_NO_ERROR(gl.getError(), "BlendEquation failed");
711
712			// Set source color.
713			gl.uniform4f(gl.getUniformLocation(p.getProgram(), "uSrcCol"), srcCol[0], srcCol[1], srcCol[2], srcCol[3]);
714			GLU_EXPECT_NO_ERROR(gl.getError(), "Uniforms failed");
715
716			// Draw.
717			glu::draw(m_context.getRenderContext(), p.getProgram(), 1, &posBinding,
718					  glu::pr::Triangles(DE_LENGTH_OF_ARRAY(s_indices), &s_indices[0]));
719			GLU_EXPECT_NO_ERROR(gl.getError(), "Draw failed");
720
721			// Blend barrier.
722			if (needBarrier)
723				gl.blendBarrier();
724		}
725
726	// Read the results.
727	glw::GLubyte* result = new glw::GLubyte[4 * dim * dim];
728	gl.readPixels(0, 0, dim, dim, GL_RGBA, GL_UNSIGNED_BYTE, result);
729	GLU_EXPECT_NO_ERROR(gl.getError(), "Read pixels failed");
730
731	// Check that first pixel is ok.
732	tcu::RGBA res		= tcu::RGBA::fromBytes(result);
733	tcu::RGBA ref		= pf.convertColor(tcu::RGBA(dstCol));
734	tcu::RGBA threshold = pf.getColorThreshold() + pf.getColorThreshold();
735	bool	  firstOk   = tcu::compareThreshold(ref, res, threshold);
736
737	// Check that all pixels are the same as the first one.
738	bool allSame = true;
739	for (int i = 0; i < dim * (dim - 1); i++)
740		allSame = allSame && (0 == memcmp(result, result + (i * 4), 4));
741
742	bool pass = firstOk && allSame;
743	if (!pass)
744	{
745		log << TestLog::Message << "Exceeds: " << threshold << " diff:" << tcu::computeAbsDiff(ref, res)
746			<< "  res:" << res << "  ref:" << tcu::RGBA(dstCol) << TestLog::EndMessage;
747	}
748
749	delete[] result;
750
751	m_testCtx.setTestResult(pass ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, pass ? "" : "results differ");
752	return STOP;
753}
754
755class BlendTestCaseGroup : public deqp::TestCaseGroup
756{
757public:
758	enum QualifierType
759	{
760		MATCHING_QUALIFIER, // Use single qualifier that matches used blending mode.
761		ALL_QUALIFIER		// Use "all_equations" qualifier.
762	};
763
764	BlendTestCaseGroup(deqp::Context& context, glu::GLSLVersion glslVersion, QualifierType qualifierType)
765		: TestCaseGroup(context, (qualifierType == ALL_QUALIFIER) ? "blend_all" : "blend_specific",
766						"Test all added blends.")
767		, m_glslVersion(glslVersion)
768		, m_useAllQualifier(qualifierType == ALL_QUALIFIER)
769	{
770		DE_ASSERT(qualifierType == MATCHING_QUALIFIER || qualifierType == ALL_QUALIFIER);
771	}
772
773	void init(void)
774	{
775		// Pump individual modes.
776		for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_modes); i++)
777		{
778			addChild(new BlendTest(m_context, m_glslVersion, s_modes[i], m_useAllQualifier,
779								   DE_LENGTH_OF_ARRAY(s_common) / 8, s_common, DE_LENGTH_OF_ARRAY(s_rgb10a2) / 8, s_rgb10a2));
780		}
781	}
782
783private:
784	glu::GLSLVersion m_glslVersion;
785	bool			 m_useAllQualifier;
786
787	class BlendTest : public deqp::TestCase
788	{
789	public:
790		BlendTest(deqp::Context& context, glu::GLSLVersion glslVersion, glw::GLenum mode, bool useAllQualifier,
791				  int numColors, const glw::GLfloat* colors, int numSpecificColors, const glw::GLfloat* specificColors)
792			: TestCase(context, (std::string(GetModeStr(mode)) + (useAllQualifier ? "_all_qualifier" : "")).c_str(),
793					   "Test new blend modes for correctness.")
794			, m_glslVersion(glslVersion)
795			, m_mode(mode)
796			, m_useAllQualifier(useAllQualifier)
797			, m_numColors(numColors)
798			, m_colors(colors)
799			, m_numSpecificColors(numSpecificColors)
800			, m_specificColors(specificColors)
801			, m_useRGB10A2Data(GL_FALSE)
802		{
803		}
804
805		IterateResult iterate(void);
806
807	private:
808		void getTestColors(int index, tcu::Vec4& src, tcu::Vec4& dst) const;
809		void getCoordinates(int index, int& x, int& y) const;
810
811		glu::GLSLVersion	m_glslVersion;
812		glw::GLenum			m_mode;
813		bool				m_useAllQualifier;
814		int					m_numColors;
815		const glw::GLfloat* m_colors;
816		int					m_numSpecificColors;
817		const glw::GLfloat*	m_specificColors;
818		bool				m_useRGB10A2Data;
819	};
820
821	static const glw::GLfloat s_common[46 * 8];
822	static const glw::GLfloat s_rgb10a2[42 * 8];
823};
824
825// Alpha values for pre-multiplied colors.
826static const float A1 = 0.750f; // Between 1    and 0.5
827static const float A2 = 0.375f; // Between 0.5  and 0.25
828static const float A3 = 0.125f; // Between 0.25 and 0.0
829
830const glw::GLfloat BlendTestCaseGroup::s_common[] = {
831	// Test that pre-multiplied is converted correctly.
832	// Should not test invalid premultiplied colours (1, 1, 1, 0).
833	1.000f, 0.750f, 0.500f, 1.00f, 0.000f, 0.000f, 0.000f, 0.00f, 0.250f, 0.125f, 0.000f, 1.00f, 0.000f, 0.000f, 0.000f,
834	0.00f,
835
836	// Test clamping.
837	1.000f, 0.750f, 0.500f, 1.00f, -0.125f, -0.125f, -0.125f, 1.00f, 0.250f, 0.125f, 0.000f, 1.00f, -0.125f, -0.125f,
838	-0.125f, 1.00f, 1.000f, 0.750f, 0.500f, 1.00f, 1.125f, 1.125f, 1.125f, 1.00f, 0.250f, 0.125f, 0.000f, 1.00f, 1.125f,
839	1.125f, 1.125f, 1.00f,
840
841	// Cobinations that test other branches of blend equations.
842	1.000f, 0.750f, 0.500f, 1.00f, 1.000f, 1.000f, 1.000f, 1.00f, 0.250f, 0.125f, 0.000f, 1.00f, 1.000f, 1.000f, 1.000f,
843	1.00f, 1.000f, 0.750f, 0.500f, 1.00f, 0.500f, 0.500f, 0.500f, 1.00f, 0.250f, 0.125f, 0.000f, 1.00f, 0.500f, 0.500f,
844	0.500f, 1.00f, 1.000f, 0.750f, 0.500f, 1.00f, 0.250f, 0.250f, 0.250f, 1.00f, 0.250f, 0.125f, 0.000f, 1.00f, 0.250f,
845	0.250f, 0.250f, 1.00f, 1.000f, 0.750f, 0.500f, 1.00f, 0.125f, 0.125f, 0.125f, 1.00f, 0.250f, 0.125f, 0.000f, 1.00f,
846	0.125f, 0.125f, 0.125f, 1.00f, 1.000f, 0.750f, 0.500f, 1.00f, 0.000f, 0.000f, 0.000f, 1.00f, 0.250f, 0.125f, 0.000f,
847	1.00f, 0.000f, 0.000f, 0.000f, 1.00f,
848
849	// Above block with few different pre-multiplied alpha values.
850	A1 * 1.000f, A1 * 0.750f, A1 * 0.500f, A1 * 1.00f, A1 * 1.000f, A1 * 1.000f, A1 * 1.000f, A1 * 1.00f, A1 * 0.250f,
851	A1 * 0.125f, A1 * 0.000f, A1 * 1.00f, A1 * 1.000f, A1 * 1.000f, A1 * 1.000f, A1 * 1.00f, A1 * 1.000f, A1 * 0.750f,
852	A1 * 0.500f, A1 * 1.00f, A1 * 0.500f, A1 * 0.500f, A1 * 0.500f, A1 * 1.00f, A1 * 0.250f, A1 * 0.125f, A1 * 0.000f,
853	A1 * 1.00f, A1 * 0.500f, A1 * 0.500f, A1 * 0.500f, A1 * 1.00f, A1 * 1.000f, A1 * 0.750f, A1 * 0.500f, A1 * 1.00f,
854	A1 * 0.250f, A1 * 0.250f, A1 * 0.250f, A1 * 1.00f, A1 * 0.250f, A1 * 0.125f, A1 * 0.000f, A1 * 1.00f, A1 * 0.250f,
855	A1 * 0.250f, A1 * 0.250f, A1 * 1.00f, A1 * 1.000f, A1 * 0.750f, A1 * 0.500f, A1 * 1.00f, A1 * 0.125f, A1 * 0.125f,
856	A1 * 0.125f, A1 * 1.00f, A1 * 0.250f, A1 * 0.125f, A1 * 0.000f, A1 * 1.00f, A1 * 0.125f, A1 * 0.125f, A1 * 0.125f,
857	A1 * 1.00f, A1 * 1.000f, A1 * 0.750f, A1 * 0.500f, A1 * 1.00f, A1 * 0.000f, A1 * 0.000f, A1 * 0.000f, A1 * 1.00f,
858	A1 * 0.250f, A1 * 0.125f, A1 * 0.000f, A1 * 1.00f, A1 * 0.000f, A1 * 0.000f, A1 * 0.000f, A1 * 1.00f,
859
860	A2 * 1.000f, A2 * 0.750f, A2 * 0.500f, A2 * 1.00f, A2 * 1.000f, A2 * 1.000f, A2 * 1.000f, A2 * 1.00f, A2 * 0.250f,
861	A2 * 0.125f, A2 * 0.000f, A2 * 1.00f, A2 * 1.000f, A2 * 1.000f, A2 * 1.000f, A2 * 1.00f, A2 * 1.000f, A2 * 0.750f,
862	A2 * 0.500f, A2 * 1.00f, A2 * 0.500f, A2 * 0.500f, A2 * 0.500f, A2 * 1.00f, A2 * 0.250f, A2 * 0.125f, A2 * 0.000f,
863	A2 * 1.00f, A2 * 0.500f, A2 * 0.500f, A2 * 0.500f, A2 * 1.00f, A2 * 1.000f, A2 * 0.750f, A2 * 0.500f, A2 * 1.00f,
864	A2 * 0.250f, A2 * 0.250f, A2 * 0.250f, A2 * 1.00f, A2 * 0.250f, A2 * 0.125f, A2 * 0.000f, A2 * 1.00f, A2 * 0.250f,
865	A2 * 0.250f, A2 * 0.250f, A2 * 1.00f, A2 * 1.000f, A2 * 0.750f, A2 * 0.500f, A2 * 1.00f, A2 * 0.125f, A2 * 0.125f,
866	A2 * 0.125f, A2 * 1.00f, A2 * 0.250f, A2 * 0.125f, A2 * 0.000f, A2 * 1.00f, A2 * 0.125f, A2 * 0.125f, A2 * 0.125f,
867	A2 * 1.00f, A2 * 1.000f, A2 * 0.750f, A2 * 0.500f, A2 * 1.00f, A2 * 0.000f, A2 * 0.000f, A2 * 0.000f, A2 * 1.00f,
868	A2 * 0.250f, A2 * 0.125f, A2 * 0.000f, A2 * 1.00f, A2 * 0.000f, A2 * 0.000f, A2 * 0.000f, A2 * 1.00f,
869
870	A3 * 1.000f, A3 * 0.750f, A3 * 0.500f, A3 * 1.00f, A3 * 1.000f, A3 * 1.000f, A3 * 1.000f, A3 * 1.00f, A3 * 0.250f,
871	A3 * 0.125f, A3 * 0.000f, A3 * 1.00f, A3 * 1.000f, A3 * 1.000f, A3 * 1.000f, A3 * 1.00f, A3 * 1.000f, A3 * 0.750f,
872	A3 * 0.500f, A3 * 1.00f, A3 * 0.500f, A3 * 0.500f, A3 * 0.500f, A3 * 1.00f, A3 * 0.250f, A3 * 0.125f, A3 * 0.000f,
873	A3 * 1.00f, A3 * 0.500f, A3 * 0.500f, A3 * 0.500f, A3 * 1.00f, A3 * 1.000f, A3 * 0.750f, A3 * 0.500f, A3 * 1.00f,
874	A3 * 0.250f, A3 * 0.250f, A3 * 0.250f, A3 * 1.00f, A3 * 0.250f, A3 * 0.125f, A3 * 0.000f, A3 * 1.00f, A3 * 0.250f,
875	A3 * 0.250f, A3 * 0.250f, A3 * 1.00f, A3 * 1.000f, A3 * 0.750f, A3 * 0.500f, A3 * 1.00f, A3 * 0.125f, A3 * 0.125f,
876	A3 * 0.125f, A3 * 1.00f, A3 * 0.250f, A3 * 0.125f, A3 * 0.000f, A3 * 1.00f, A3 * 0.125f, A3 * 0.125f, A3 * 0.125f,
877	A3 * 1.00f, A3 * 1.000f, A3 * 0.750f, A3 * 0.500f, A3 * 1.00f, A3 * 0.000f, A3 * 0.000f, A3 * 0.000f, A3 * 1.00f,
878	A3 * 0.250f, A3 * 0.125f, A3 * 0.000f, A3 * 1.00f, A3 * 0.000f, A3 * 0.000f, A3 * 0.000f, A3 * 1.00f,
879};
880
881// Some data in the s_common array are invalid for BlendHSLHue and BlendHSLSaturation function when the render target
882// format is GL_RGB10A2. These data will lead to undefine behavior(divide 0). Remove those data and create a new array
883// to test this format and the blend functions.
884const glw::GLfloat BlendTestCaseGroup::s_rgb10a2[] = {
885	// Test that pre-multiplied is converted correctly.
886	// Should not test invalid premultiplied colours (1, 1, 1, 0).
887	1.000f, 0.750f, 0.500f, 1.00f, 0.000f, 0.000f, 0.000f, 0.00f, 0.250f, 0.125f, 0.000f, 1.00f, 0.000f, 0.000f, 0.000f,
888	0.00f,
889
890	// Test clamping.
891	1.000f, 0.750f, 0.500f, 1.00f, -0.125f, -0.125f, -0.125f, 1.00f, 0.250f, 0.125f, 0.000f, 1.00f, -0.125f, -0.125f,
892	-0.125f, 1.00f, 1.000f, 0.750f, 0.500f, 1.00f, 1.125f, 1.125f, 1.125f, 1.00f, 0.250f, 0.125f, 0.000f, 1.00f, 1.125f,
893	1.125f, 1.125f, 1.00f,
894
895	// Cobinations that test other branches of blend equations.
896	1.000f, 0.750f, 0.500f, 1.00f, 1.000f, 1.000f, 1.000f, 1.00f, 0.250f, 0.125f, 0.000f, 1.00f, 1.000f, 1.000f, 1.000f,
897	1.00f, 1.000f, 0.750f, 0.500f, 1.00f, 0.500f, 0.500f, 0.500f, 1.00f, 0.250f, 0.125f, 0.000f, 1.00f, 0.500f, 0.500f,
898	0.500f, 1.00f, 1.000f, 0.750f, 0.500f, 1.00f, 0.250f, 0.250f, 0.250f, 1.00f, 0.250f, 0.125f, 0.000f, 1.00f, 0.250f,
899	0.250f, 0.250f, 1.00f, 1.000f, 0.750f, 0.500f, 1.00f, 0.125f, 0.125f, 0.125f, 1.00f, 0.250f, 0.125f, 0.000f, 1.00f,
900	0.125f, 0.125f, 0.125f, 1.00f, 1.000f, 0.750f, 0.500f, 1.00f, 0.000f, 0.000f, 0.000f, 1.00f, 0.250f, 0.125f, 0.000f,
901	1.00f, 0.000f, 0.000f, 0.000f, 1.00f,
902
903	// Above block with few different pre-multiplied alpha values.
904	A1 * 1.000f, A1 * 0.750f, A1 * 0.500f, A1 * 1.00f, A1 * 0.500f, A1 * 0.500f, A1 * 0.500f, A1 * 1.00f, A1 * 0.250f,
905	A1 * 0.125f, A1 * 0.000f, A1 * 1.00f, A1 * 0.500f, A1 * 0.500f, A1 * 0.500f, A1 * 1.00f, A1 * 1.000f, A1 * 0.750f,
906	A1 * 0.500f, A1 * 1.00f, A1 * 0.250f, A1 * 0.250f, A1 * 0.250f, A1 * 1.00f, A1 * 0.250f, A1 * 0.125f, A1 * 0.000f,
907	A1 * 1.00f, A1 * 0.250f, A1 * 0.250f, A1 * 0.250f, A1 * 1.00f, A1 * 1.000f, A1 * 0.750f, A1 * 0.500f, A1 * 1.00f,
908	A1 * 0.125f, A1 * 0.125f, A1 * 0.125f, A1 * 1.00f, A1 * 0.250f, A1 * 0.125f, A1 * 0.000f, A1 * 1.00f, A1 * 0.125f,
909	A1 * 0.125f, A1 * 0.125f, A1 * 1.00f, A1 * 1.000f, A1 * 0.750f, A1 * 0.500f, A1 * 1.00f, A1 * 0.000f, A1 * 0.000f,
910	A1 * 0.000f, A1 * 1.00f, A1 * 0.250f, A1 * 0.125f, A1 * 0.000f, A1 * 1.00f, A1 * 0.000f, A1 * 0.000f, A1 * 0.000f,
911	A1 * 1.00f,
912
913	A2 * 1.000f, A2 * 0.750f, A2 * 0.500f, A2 * 1.00f, A2 * 0.500f, A2 * 0.500f, A2 * 0.500f, A2 * 1.00f, A2 * 0.250f,
914	A2 * 0.125f, A2 * 0.000f, A2 * 1.00f, A2 * 0.500f, A2 * 0.500f, A2 * 0.500f, A2 * 1.00f, A2 * 1.000f, A2 * 0.750f,
915	A2 * 0.500f, A2 * 1.00f, A2 * 0.250f, A2 * 0.250f, A2 * 0.250f, A2 * 1.00f, A2 * 0.250f, A2 * 0.125f, A2 * 0.000f,
916	A2 * 1.00f, A2 * 0.250f, A2 * 0.250f, A2 * 0.250f, A2 * 1.00f, A2 * 1.000f, A2 * 0.750f, A2 * 0.500f, A2 * 1.00f,
917	A2 * 0.125f, A2 * 0.125f, A2 * 0.125f, A2 * 1.00f, A2 * 0.250f, A2 * 0.125f, A2 * 0.000f, A2 * 1.00f, A2 * 0.125f,
918	A2 * 0.125f, A2 * 0.125f, A2 * 1.00f, A2 * 1.000f, A2 * 0.750f, A2 * 0.500f, A2 * 1.00f, A2 * 0.000f, A2 * 0.000f,
919	A2 * 0.000f, A2 * 1.00f, A2 * 0.250f, A2 * 0.125f, A2 * 0.000f, A2 * 1.00f, A2 * 0.000f, A2 * 0.000f, A2 * 0.000f,
920	A2 * 1.00f,
921
922	A3 * 1.000f, A3 * 0.750f, A3 * 0.500f, A3 * 1.00f, A3 * 1.000f, A3 * 1.000f, A3 * 1.000f, A3 * 1.00f, A3 * 0.250f,
923	A3 * 0.125f, A3 * 0.000f, A3 * 1.00f, A3 * 1.000f, A3 * 1.000f, A3 * 1.000f, A3 * 1.00f, A3 * 1.000f, A3 * 0.750f,
924	A3 * 0.500f, A3 * 1.00f, A3 * 0.500f, A3 * 0.500f, A3 * 0.500f, A3 * 1.00f, A3 * 0.250f, A3 * 0.125f, A3 * 0.000f,
925	A3 * 1.00f, A3 * 0.500f, A3 * 0.500f, A3 * 0.500f, A3 * 1.00f, A3 * 1.000f, A3 * 0.750f, A3 * 0.500f, A3 * 1.00f,
926	A3 * 0.250f, A3 * 0.250f, A3 * 0.250f, A3 * 1.00f, A3 * 0.250f, A3 * 0.125f, A3 * 0.000f, A3 * 1.00f, A3 * 0.250f,
927	A3 * 0.250f, A3 * 0.250f, A3 * 1.00f, A3 * 1.000f, A3 * 0.750f, A3 * 0.500f, A3 * 1.00f, A3 * 0.125f, A3 * 0.125f,
928	A3 * 0.125f, A3 * 1.00f, A3 * 0.250f, A3 * 0.125f, A3 * 0.000f, A3 * 1.00f, A3 * 0.125f, A3 * 0.125f, A3 * 0.125f,
929	A3 * 1.00f, A3 * 1.000f, A3 * 0.750f, A3 * 0.500f, A3 * 1.00f, A3 * 0.000f, A3 * 0.000f, A3 * 0.000f, A3 * 1.00f,
930	A3 * 0.250f, A3 * 0.125f, A3 * 0.000f, A3 * 1.00f, A3 * 0.000f, A3 * 0.000f, A3 * 0.000f, A3 * 1.00f,
931};
932
933static tcu::Vec4 MaskChannels(const tcu::PixelFormat& pf, const tcu::Vec4& v)
934{
935	return tcu::Vec4(pf.redBits > 0 ? v[0] : 0.f, pf.greenBits > 0 ? v[1] : 0.f, pf.blueBits > 0 ? v[2] : 0.f,
936					 pf.alphaBits > 0 ? v[3] : 1.f);
937}
938
939//
940// Quantize the input colour by the colour bit depth for each channel.
941//
942static tcu::Vec4 QuantizeChannels(const tcu::PixelFormat& pf, const tcu::Vec4& v)
943{
944	float maxChanel[4] = { static_cast<float>(1 << pf.redBits) - 1.0f, static_cast<float>(1 << pf.greenBits) - 1.0f,
945						   static_cast<float>(1 << pf.blueBits) - 1.0f, static_cast<float>(1 << pf.alphaBits) - 1.0f };
946
947	return tcu::Vec4(static_cast<float>((unsigned int)(v[0] * maxChanel[0])) / maxChanel[0],
948					 static_cast<float>((unsigned int)(v[1] * maxChanel[1])) / maxChanel[1],
949					 static_cast<float>((unsigned int)(v[2] * maxChanel[2])) / maxChanel[2],
950					 pf.alphaBits ? static_cast<float>((unsigned int)(v[3] * maxChanel[3])) / maxChanel[3] : 1.0f);
951}
952
953void BlendTestCaseGroup::BlendTest::getTestColors(int index, tcu::Vec4& src, tcu::Vec4& dst) const
954{
955	DE_ASSERT(0 <= index && index < (m_useRGB10A2Data ? m_numSpecificColors : m_numColors));
956
957	const tcu::RenderTarget&	rt = m_context.getRenderContext().getRenderTarget();
958	const tcu::PixelFormat&		pf = rt.getPixelFormat();
959	const glw::GLfloat*			s  = (m_useRGB10A2Data ? m_specificColors : m_colors) + 8 * index;
960
961	src = MaskChannels(pf, tcu::Vec4(s[0], s[1], s[2], s[3]));
962	dst = MaskChannels(pf, tcu::Vec4(s[4], s[5], s[6], s[7]));
963	src = tcu::clamp(src, tcu::Vec4(0.f), tcu::Vec4(1.f));
964	dst = tcu::clamp(dst, tcu::Vec4(0.f), tcu::Vec4(1.f));
965
966	// Quantize the destination channels
967	// this matches what implementation does on render target write
968	dst = QuantizeChannels(pf, dst);
969}
970
971void BlendTestCaseGroup::BlendTest::getCoordinates(int index, int& x, int& y) const
972{
973	const tcu::RenderTarget& rt = m_context.getRenderContext().getRenderTarget();
974	y							= index / rt.getWidth();
975	x							= index % rt.getWidth();
976}
977
978BlendTestCaseGroup::BlendTest::IterateResult BlendTestCaseGroup::BlendTest::iterate(void)
979{
980	const tcu::RenderTarget& rt  = m_context.getRenderContext().getRenderTarget();
981	const tcu::PixelFormat&  pf  = rt.getPixelFormat();
982	const glw::Functions&	gl  = m_context.getRenderContext().getFunctions();
983	TestLog&				 log = m_testCtx.getLog();
984
985	// Check that extension is supported.
986	if (!IsExtensionSupported(m_context, "GL_KHR_blend_equation_advanced"))
987	{
988		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_KHR_blend_equation_advanced");
989		return STOP;
990	}
991
992	if ((GetBlendFunc(m_mode) == BlendHSLHue || GetBlendFunc(m_mode) == BlendHSLSaturation)
993		&& (pf.redBits == 10 && pf.greenBits == 10 && pf.blueBits == 10 && pf.alphaBits == 2))
994	{
995		m_useRGB10A2Data = GL_TRUE;
996	}
997
998	// Setup program.
999	std::string frgSrc =
1000		GetSolidShader(m_useAllQualifier ? "blend_support_all_equations" : GetLayoutQualifierStr(m_mode),
1001					   glu::getGLSLVersionDeclaration(m_glslVersion));
1002	glu::ShaderProgram p(m_context.getRenderContext(),
1003						 glu::makeVtxFragSources(GetDef2DVtxSrc(m_glslVersion).c_str(), frgSrc.c_str()));
1004	if (!p.isOk())
1005	{
1006		log << p;
1007		TCU_FAIL("Compile failed");
1008	}
1009	gl.useProgram(p.getProgram());
1010	GLU_EXPECT_NO_ERROR(gl.getError(), "Program failed");
1011
1012	glu::VertexArrayBinding posBinding = glu::va::Float("aPos", 2, 4, 0, &s_pos[0]);
1013
1014	// Enable blending and set blend equation.
1015	gl.disable(GL_DITHER);
1016	gl.enable(GL_SCISSOR_TEST);
1017	gl.enable(GL_BLEND);
1018	gl.blendEquation(m_mode);
1019	GLU_EXPECT_NO_ERROR(gl.getError(), "BlendEquation failed");
1020
1021	bool needBarrier = !IsExtensionSupported(m_context, "GL_KHR_blend_equation_advanced_coherent");
1022
1023	// Render loop.
1024	for (int colorIndex = 0; colorIndex < (m_useRGB10A2Data ? m_numSpecificColors : m_numColors); colorIndex++)
1025	{
1026		tcu::Vec4 srcCol, dstCol;
1027		getTestColors(colorIndex, srcCol, dstCol);
1028
1029		// Get pixel to blend.
1030		int x, y;
1031		getCoordinates(colorIndex, x, y);
1032		gl.scissor(x, y, 1, 1);
1033
1034		// Clear to destination color.
1035		gl.clearColor(dstCol[0], dstCol[1], dstCol[2], dstCol[3]);
1036		gl.clear(GL_COLOR_BUFFER_BIT);
1037		if (needBarrier)
1038			gl.blendBarrier();
1039
1040		// Set source color.
1041		gl.uniform4f(gl.getUniformLocation(p.getProgram(), "uSrcCol"), srcCol[0], srcCol[1], srcCol[2], srcCol[3]);
1042		GLU_EXPECT_NO_ERROR(gl.getError(), "Uniforms failed");
1043
1044		// Draw.
1045		glu::draw(m_context.getRenderContext(), p.getProgram(), 1, &posBinding,
1046				  glu::pr::Triangles(DE_LENGTH_OF_ARRAY(s_indices), &s_indices[0]));
1047		GLU_EXPECT_NO_ERROR(gl.getError(), "Draw failed");
1048		if (needBarrier)
1049			gl.blendBarrier();
1050	}
1051
1052	// Read the results.
1053	const int	 w			  = rt.getWidth();
1054	const int	 h			  = rt.getHeight();
1055	glw::GLubyte* resultBytes = new glw::GLubyte[4 * w * h];
1056	gl.pixelStorei(GL_PACK_ALIGNMENT, 1);
1057	gl.readPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, resultBytes);
1058	GLU_EXPECT_NO_ERROR(gl.getError(), "Read pixels failed");
1059
1060	bool pass = true;
1061	for (int colorIndex = 0; colorIndex < (m_useRGB10A2Data ? m_numSpecificColors : m_numColors); colorIndex++)
1062	{
1063		tcu::Vec4 srcCol, dstCol;
1064		getTestColors(colorIndex, srcCol, dstCol);
1065
1066		// Get result and calculate reference.
1067		int x, y;
1068		getCoordinates(colorIndex, x, y);
1069
1070		tcu::Vec4 refCol	= Blend(m_mode, srcCol, dstCol);
1071		tcu::RGBA ref		= pf.convertColor(tcu::RGBA(refCol));
1072		tcu::RGBA res		= tcu::RGBA::fromBytes(resultBytes + 4 * (x + w * y));
1073		tcu::RGBA tmp		= pf.getColorThreshold();
1074		tcu::RGBA threshold = tcu::RGBA(std::min(2 + 2 * tmp.getRed(), 255), std::min(2 + 2 * tmp.getGreen(), 255),
1075										std::min(2 + 2 * tmp.getBlue(), 255), std::min(2 + 2 * tmp.getAlpha(), 255));
1076		bool pixelOk = tcu::compareThreshold(ref, res, threshold);
1077		pass		 = pass && pixelOk;
1078		if (!pixelOk)
1079		{
1080			log << TestLog::Message << "(" << x << "," << y << ")  "
1081				<< "(" << colorIndex << ") "
1082				<< "Exceeds: " << threshold << " diff:" << tcu::computeAbsDiff(ref, res) << "  res:" << res
1083				<< "  ref:" << ref << "  dst:" << tcu::RGBA(dstCol) << "  src:" << tcu::RGBA(srcCol)
1084				<< TestLog::EndMessage;
1085		}
1086	}
1087
1088	m_testCtx.setTestResult(pass ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, pass ? "" : "results differ");
1089	delete[] resultBytes;
1090	return STOP;
1091}
1092
1093/*
1094 * From 'Other' part of the spec:
1095 *    "Test different behaviors for GLSL #extension
1096 *     GL_XXX_blend_equation_advanced"
1097 *
1098 * - require : Covered by "Blend" tests.
1099 * - enable  : Use layout modifier from GL_KHR_blend_equation_advanced and
1100 *             expect compile to succeed. (warn if not supported)
1101 * - warn    : Use layout modifier from GL_KHR_blend_equation_advanced and
1102 *             expect compile to succeed. (work, but issue warning)
1103 * - disable : Use layout modifier from GL_KHR_blend_equation_advanced and
1104 *             expect compile to fail with error.
1105 *
1106 */
1107class ExtensionDirectiveTestCaseGroup : public deqp::TestCaseGroup
1108{
1109public:
1110	ExtensionDirectiveTestCaseGroup(deqp::Context& context, glu::GLSLVersion glslVersion)
1111		: TestCaseGroup(context, "extension_directive", "Test #extension directive."), m_glslVersion(glslVersion)
1112	{
1113	}
1114
1115	void init(void)
1116	{
1117		addChild(new ExtensionDirectiveTestCase(m_context, m_glslVersion, "disable"));
1118		addChild(new ExtensionDirectiveTestCase(m_context, m_glslVersion, "enable"));
1119		addChild(new ExtensionDirectiveTestCase(m_context, m_glslVersion, "warn"));
1120	}
1121
1122private:
1123	class ExtensionDirectiveTestCase : public deqp::TestCase
1124	{
1125	public:
1126		ExtensionDirectiveTestCase(deqp::Context& context, glu::GLSLVersion glslVersion, const char* behaviour)
1127			: TestCase(context, (std::string("extension_directive_") + behaviour).c_str(), "Test #extension directive.")
1128			, m_glslVersion(glslVersion)
1129			, m_behaviourStr(behaviour)
1130		{
1131			// Initialize expected compiler behaviour.
1132			std::string b(behaviour);
1133			if (b == "disable")
1134			{
1135				m_requireInfoLog = true;
1136				m_requireCompile = false;
1137			}
1138			else if (b == "enable")
1139			{
1140				m_requireInfoLog = false;
1141				m_requireCompile = true;
1142			}
1143			else
1144			{
1145				DE_ASSERT(b == "warn");
1146				m_requireInfoLog = false;
1147				m_requireCompile = true;
1148			}
1149		}
1150
1151		IterateResult iterate(void)
1152		{
1153			const glw::Functions& gl  = m_context.getRenderContext().getFunctions();
1154			TestLog&			  log = m_testCtx.getLog();
1155			const int			  dim = 4;
1156
1157			// Check that extension is supported.
1158			if (!IsExtensionSupported(m_context, "GL_KHR_blend_equation_advanced"))
1159			{
1160				m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_KHR_blend_equation_advanced");
1161				return STOP;
1162			}
1163
1164			FBOSentry fbo(gl, dim, dim, GL_RGBA8);
1165
1166			tcu::Vec4 dstCol(1.f, 1.f, 1.f, 1.f);
1167			tcu::Vec4 srcCol(0.f, 0.f, 0.f, 1.f);
1168
1169			// Clear to destination color.
1170			gl.clearColor(dstCol.x(), dstCol.y(), dstCol.z(), dstCol.w());
1171			gl.clear(GL_COLOR_BUFFER_BIT);
1172
1173			// Setup program.
1174			std::string directive = "#extension GL_KHR_blend_equation_advanced : " + m_behaviourStr;
1175			std::string frgSrc = GetSolidShader("blend_support_multiply", glu::getGLSLVersionDeclaration(m_glslVersion),
1176												directive.c_str());
1177			glu::ShaderProgram p(m_context.getRenderContext(),
1178								 glu::makeVtxFragSources(GetDef2DVtxSrc(m_glslVersion).c_str(), frgSrc.c_str()));
1179			// If check that there is some info log if it is expected.
1180			const bool infoLogOk =
1181				m_requireInfoLog ? p.getShaderInfo(glu::SHADERTYPE_FRAGMENT).infoLog.size() > 0 : true;
1182			if (!p.isOk())
1183			{
1184				if (m_requireCompile)
1185				{
1186					log << p;
1187					TCU_FAIL("Compile failed");
1188				}
1189				else
1190				{
1191					// If shader was expected to fail, so assume info log has something.
1192					bool pass = infoLogOk;
1193					m_testCtx.setTestResult(pass ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
1194											pass ? "Pass" : "Fail. Expected info log.");
1195				}
1196				return STOP;
1197			}
1198			gl.useProgram(p.getProgram());
1199			GLU_EXPECT_NO_ERROR(gl.getError(), "Program failed");
1200
1201			// Program ok, check whether info log was as expected.
1202			if (!infoLogOk)
1203			{
1204				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail. No warnings were generated.");
1205				return STOP;
1206			}
1207
1208			// Enable blending and set blend equation.
1209			gl.disable(GL_DITHER);
1210			gl.enable(GL_BLEND);
1211			gl.blendEquation(GL_MULTIPLY_KHR);
1212			GLU_EXPECT_NO_ERROR(gl.getError(), "BlendEquation failed");
1213
1214			// Setup source color.
1215			gl.uniform4f(gl.getUniformLocation(p.getProgram(), "uSrcCol"), srcCol.x(), srcCol.y(), srcCol.z(),
1216						 srcCol.w());
1217			GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform failed");
1218
1219			glu::VertexArrayBinding posBinding = glu::va::Float("aPos", 2, 4, 0, &s_pos[0]);
1220			GLU_EXPECT_NO_ERROR(gl.getError(), "Attributes failed");
1221
1222			glu::draw(m_context.getRenderContext(), p.getProgram(), 1, &posBinding,
1223					  glu::pr::Triangles(DE_LENGTH_OF_ARRAY(s_indices), &s_indices[0]));
1224			GLU_EXPECT_NO_ERROR(gl.getError(), "Draw failed");
1225
1226			// Check the result to see that extension was actually enabled.
1227			glw::GLubyte result[4] = { 1, 2, 3, 4 };
1228			gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, result);
1229			GLU_EXPECT_NO_ERROR(gl.getError(), "Read pixels failed");
1230			bool pass = tcu::RGBA::fromBytes(result) == tcu::RGBA(0, 0, 0, 0xFF);
1231			m_testCtx.setTestResult(pass ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, pass ? "Pass" : "Fail");
1232
1233			return STOP;
1234		}
1235
1236	private:
1237		glu::GLSLVersion m_glslVersion;
1238		std::string		 m_behaviourStr;
1239		bool			 m_requireInfoLog;
1240		bool			 m_requireCompile;
1241	};
1242
1243	glu::GLSLVersion m_glslVersion;
1244};
1245
1246/*
1247 * From 'Other' part of the spec:
1248 *    "If XXX_blend_equation_advanced_coherent is supported, test
1249 *     Each blending mode needs to be tested without specifying the proper
1250 *     blend_support_[mode] or blend_support_all layout qualifier in the
1251 *     fragment shader. Expect INVALID_OPERATION GL error after calling
1252 *     DrawElements/Arrays."
1253 */
1254class MissingQualifierTestGroup : public deqp::TestCaseGroup
1255{
1256public:
1257	enum MissingType
1258	{
1259		MISMATCH, // wrong qualifier in the shader.
1260		MISSING,  // no qualifier at all.
1261	};
1262
1263	MissingQualifierTestGroup(deqp::Context& context, glu::GLSLVersion glslVersion, MissingType missingType)
1264		: TestCaseGroup(context, missingType == MISMATCH ? "mismatching_qualifier" : "missing_qualifier", "")
1265		, m_glslVersion(glslVersion)
1266		, m_missingType(missingType)
1267	{
1268	}
1269
1270	void init(void)
1271	{
1272		// Pump individual modes.
1273		for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_modes); i++)
1274		{
1275			const char* qualifier = m_missingType == MISSING ?
1276										DE_NULL :
1277										GetLayoutQualifierStr(s_modes[(i + 1) % DE_LENGTH_OF_ARRAY(s_modes)]);
1278			addChild(new MissingCase(m_context, m_glslVersion, s_modes[i], qualifier));
1279		}
1280	}
1281
1282private:
1283	class MissingCase : public deqp::TestCase
1284	{
1285	public:
1286		MissingCase(deqp::Context& context, glu::GLSLVersion glslVersion, glw::GLenum mode, const char* layoutQualifier)
1287			: TestCase(context, GetModeStr(mode), "")
1288			, m_glslVersion(glslVersion)
1289			, m_mode(mode)
1290			, m_layoutQualifier(layoutQualifier)
1291		{
1292		}
1293
1294		IterateResult iterate(void);
1295
1296	private:
1297		glu::GLSLVersion m_glslVersion;
1298		glw::GLenum		 m_mode;
1299		const char*		 m_layoutQualifier; // NULL => no qualifier at all.
1300	};
1301
1302	glu::GLSLVersion m_glslVersion;
1303	MissingType		 m_missingType;
1304};
1305
1306MissingQualifierTestGroup::MissingCase::IterateResult MissingQualifierTestGroup::MissingCase::iterate(void)
1307{
1308	const int			  dim = 4;
1309	const glw::Functions& gl  = m_context.getRenderContext().getFunctions();
1310	TestLog&			  log = m_testCtx.getLog();
1311
1312	// Check that extension is supported.
1313	if (!IsExtensionSupported(m_context, "GL_KHR_blend_equation_advanced"))
1314	{
1315		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_KHR_blend_equation_advanced");
1316		return STOP;
1317	}
1318
1319	FBOSentry fbo(gl, dim, dim, GL_RGBA8);
1320
1321	tcu::Vec4 dstCol(1.f, 1.f, 1.f, 1.f);
1322	tcu::Vec4 srcCol(0.f, 0.f, 0.f, 1.f);
1323
1324	// Clear to destination color.
1325	gl.clearColor(dstCol.x(), dstCol.y(), dstCol.z(), dstCol.w());
1326	gl.clear(GL_COLOR_BUFFER_BIT);
1327
1328	// Setup program.
1329	glu::ShaderProgram p(m_context.getRenderContext(),
1330						 glu::makeVtxFragSources(
1331							 GetDef2DVtxSrc(m_glslVersion).c_str(),
1332							 GetSolidShader(m_layoutQualifier, glu::getGLSLVersionDeclaration(m_glslVersion)).c_str()));
1333	if (!p.isOk())
1334	{
1335		log << p;
1336		TCU_FAIL("Compile failed");
1337	}
1338
1339	gl.useProgram(p.getProgram());
1340	GLU_EXPECT_NO_ERROR(gl.getError(), "Program failed");
1341
1342	// Enable blending and set blend equation.
1343	gl.disable(GL_DITHER);
1344	gl.enable(GL_BLEND);
1345	gl.blendEquation(m_mode);
1346	GLU_EXPECT_NO_ERROR(gl.getError(), "BlendEquation failed");
1347
1348	// Setup source color.
1349	gl.uniform4f(gl.getUniformLocation(p.getProgram(), "uSrcCol"), srcCol.x(), srcCol.y(), srcCol.z(), srcCol.w());
1350	GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform failed");
1351
1352	glu::VertexArrayBinding posBinding = glu::va::Float("aPos", 2, 4, 0, &s_pos[0]);
1353	GLU_EXPECT_NO_ERROR(gl.getError(), "Attributes failed");
1354
1355	glu::draw(m_context.getRenderContext(), p.getProgram(), 1, &posBinding,
1356			  glu::pr::Triangles(DE_LENGTH_OF_ARRAY(s_indices), &s_indices[0]));
1357
1358	glw::GLenum error = gl.getError();
1359	bool		pass  = (error == GL_INVALID_OPERATION);
1360
1361	m_testCtx.setTestResult(pass ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, pass ? "Pass" : "Fail");
1362
1363	return STOP;
1364}
1365
1366/*
1367 * From 'Other' part of the spec:
1368 *    "If XXX_blend_equation_advanced_coherent is supported, test
1369 *     BLEND_ADVANCED_COHERENT_XXX setting:
1370 *     - The setting should work with Enable, Disable and IsEnable without producing errors
1371 *     - Default value should be TRUE"
1372 *
1373 *  1. Test that coherent is enabled by default.
1374 *  2. Disable and check the state.
1375 *  3. Enable and check the state and test that rendering does not produce errors.
1376 */
1377
1378class CoherentEnableCaseGroup : public deqp::TestCaseGroup
1379{
1380public:
1381	CoherentEnableCaseGroup(deqp::Context& context) : TestCaseGroup(context, "coherent", "")
1382	{
1383	}
1384
1385	void init(void)
1386	{
1387		addChild(new CoherentEnableCase(m_context));
1388	}
1389
1390private:
1391	class CoherentEnableCase : public deqp::TestCase
1392	{
1393	public:
1394		CoherentEnableCase(deqp::Context& context) : TestCase(context, "enableDisable", "")
1395		{
1396		}
1397		IterateResult iterate(void);
1398	};
1399};
1400
1401CoherentEnableCaseGroup::CoherentEnableCase::IterateResult CoherentEnableCaseGroup::CoherentEnableCase::iterate(void)
1402{
1403	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1404
1405	// Check that extension is supported.
1406	if (!IsExtensionSupported(m_context, "GL_KHR_blend_equation_advanced"))
1407	{
1408		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_KHR_blend_equation_advanced");
1409		return STOP;
1410	}
1411	if (!IsExtensionSupported(m_context, "GL_KHR_blend_equation_advanced_coherent"))
1412	{
1413		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_KHR_blend_equation_advanced_coherent");
1414		return STOP;
1415	}
1416
1417	std::vector<bool> res;
1418	// Enabled by default.
1419	res.push_back(gl.isEnabled(GL_BLEND_ADVANCED_COHERENT_KHR) == GL_TRUE);
1420	res.push_back(gl.getError() == GL_NO_ERROR);
1421
1422	// Check disabling.
1423	gl.disable(GL_BLEND_ADVANCED_COHERENT_KHR);
1424	res.push_back(gl.getError() == GL_NO_ERROR);
1425	res.push_back(gl.isEnabled(GL_BLEND_ADVANCED_COHERENT_KHR) == GL_FALSE);
1426	res.push_back(gl.getError() == GL_NO_ERROR);
1427
1428	// Check enabling.
1429	gl.enable(GL_BLEND_ADVANCED_COHERENT_KHR);
1430	res.push_back(gl.getError() == GL_NO_ERROR);
1431	res.push_back(gl.isEnabled(GL_BLEND_ADVANCED_COHERENT_KHR) == GL_TRUE);
1432	res.push_back(gl.getError() == GL_NO_ERROR);
1433
1434	// Pass if no failures found.
1435	bool pass = std::find(res.begin(), res.end(), false) == res.end();
1436
1437	m_testCtx.setTestResult(pass ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, pass ? "Pass" : "Fail");
1438
1439	return STOP;
1440}
1441/*
1442 * From 'Other' part of the spec:
1443 *    "Test that rendering into more than one color buffers at once produces
1444 *     INVALID_OPERATION error when calling drawArrays/drawElements"
1445 */
1446class MRTCaseGroup : public deqp::TestCaseGroup
1447{
1448public:
1449	MRTCaseGroup(deqp::Context& context, glu::GLSLVersion glslVersion)
1450		: TestCaseGroup(context, "MRT", "GL_KHR_blend_equation_advanced"), m_glslVersion(glslVersion)
1451	{
1452	}
1453
1454	void init(void)
1455	{
1456		addChild(new MRTCase(m_context, m_glslVersion, MRTCase::ARRAY));
1457		addChild(new MRTCase(m_context, m_glslVersion, MRTCase::SEPARATE));
1458	}
1459
1460private:
1461	class MRTCase : public deqp::TestCase
1462	{
1463	public:
1464		enum DeclarationType
1465		{
1466			ARRAY,
1467			SEPARATE
1468		};
1469
1470		MRTCase(deqp::Context& context, glu::GLSLVersion glslVersion, DeclarationType declType)
1471			: TestCase(context, (declType == ARRAY ? "MRT_array" : "MRT_separate"), "GL_KHR_blend_equation_advanced")
1472			, m_glslVersion(glslVersion)
1473			, m_declarationType(declType)
1474		{
1475			DE_ASSERT(m_declarationType == ARRAY || m_declarationType == SEPARATE);
1476		}
1477
1478		IterateResult iterate(void);
1479
1480	private:
1481		glu::GLSLVersion m_glslVersion;
1482		DeclarationType  m_declarationType;
1483	};
1484
1485	glu::GLSLVersion m_glslVersion;
1486};
1487
1488MRTCaseGroup::MRTCase::IterateResult MRTCaseGroup::MRTCase::iterate(void)
1489{
1490	TestLog&			  log = m_testCtx.getLog();
1491	const glw::Functions& gl  = m_context.getRenderContext().getFunctions();
1492
1493	if (!IsExtensionSupported(m_context, "GL_KHR_blend_equation_advanced"))
1494	{
1495		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_KHR_blend_equation_advanced");
1496		return STOP;
1497	}
1498
1499	static const char* frgSrcTemplateArray = "${VERSION_DIRECTIVE}\n"
1500											 "#extension GL_KHR_blend_equation_advanced : require\n"
1501											 "\n"
1502											 "precision highp float;\n"
1503											 "layout (blend_support_multiply) out;\n"
1504											 "layout (location = 0) out vec4 oCol[2];\n"
1505											 "\n"
1506											 "uniform vec4 uMultCol;\n"
1507											 "\n"
1508											 "void main (void) {\n"
1509											 "   oCol[0] = uMultCol;\n"
1510											 "   oCol[1] = uMultCol;\n"
1511											 "}\n";
1512
1513	static const char* frgSrcTemplateSeparate = "${VERSION_DIRECTIVE}\n"
1514												"#extension GL_KHR_blend_equation_advanced : require\n"
1515												"\n"
1516												"precision highp float;\n"
1517												"layout (blend_support_multiply) out;\n"
1518												"layout (location = 0) out vec4 oCol0;\n"
1519												"layout (location = 1) out vec4 oCol1;\n"
1520												"\n"
1521												"uniform vec4 uMultCol;\n"
1522												"\n"
1523												"void main (void) {\n"
1524												"   oCol0 = uMultCol;\n"
1525												"   oCol1 = uMultCol;\n"
1526												"}\n";
1527
1528	static const char* frgSrcTemplate = m_declarationType == ARRAY ? frgSrcTemplateArray : frgSrcTemplateSeparate;
1529
1530	std::map<std::string, std::string> args;
1531	args["VERSION_DIRECTIVE"] = glu::getGLSLVersionDeclaration(m_glslVersion);
1532	std::string frgSrc		  = tcu::StringTemplate(frgSrcTemplate).specialize(args);
1533
1534	FBOSentry fbo(gl, 4, 4, GL_RGBA8, GL_RGBA8);
1535
1536	static const glw::GLenum bufs[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
1537	gl.drawBuffers(2, bufs);
1538
1539	// Clear buffers to white.
1540	gl.clearColor(1.f, 1.f, 1.f, 1.f);
1541	gl.clear(GL_COLOR_BUFFER_BIT);
1542
1543	// Setup program.
1544	glu::ShaderProgram p(m_context.getRenderContext(),
1545						 glu::makeVtxFragSources(GetDef2DVtxSrc(m_glslVersion).c_str(), frgSrc.c_str()));
1546	if (!p.isOk())
1547	{
1548		log << p;
1549		TCU_FAIL("Compile failed");
1550	}
1551
1552	gl.useProgram(p.getProgram());
1553	GLU_EXPECT_NO_ERROR(gl.getError(), "Program failed");
1554
1555	// Enable blending and set blend equation.
1556	gl.disable(GL_DITHER);
1557	gl.enable(GL_BLEND);
1558	gl.blendEquation(GL_DARKEN_KHR);
1559	GLU_EXPECT_NO_ERROR(gl.getError(), "BlendEquation failed");
1560
1561	// Multiply with zero.
1562	gl.uniform4f(gl.getUniformLocation(p.getProgram(), "uMultCol"), 0.f, 0.f, 0.f, 1.00f);
1563	GLU_EXPECT_NO_ERROR(gl.getError(), "Uniforms failed");
1564
1565	// Set vertex buffer
1566	glw::GLuint vbo;
1567	gl.genBuffers(1, &vbo);
1568	gl.bindBuffer(GL_ARRAY_BUFFER, vbo);
1569	gl.bufferData(GL_ARRAY_BUFFER, sizeof(s_pos), s_pos, GL_STATIC_DRAW);
1570
1571	// Set vertices.
1572	glw::GLuint vao;
1573	gl.genVertexArrays(1, &vao);
1574	gl.bindVertexArray(vao);
1575	glw::GLint loc = gl.getAttribLocation(p.getProgram(), "aPos");
1576	gl.enableVertexAttribArray(loc);
1577	gl.vertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, 8, DE_NULL);
1578	GLU_EXPECT_NO_ERROR(gl.getError(), "Attributes failed");
1579
1580	gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
1581	bool errorOk = (gl.getError() == GL_INVALID_OPERATION);
1582
1583	gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, s_indices);
1584	errorOk = errorOk && (gl.getError() == GL_INVALID_OPERATION);
1585
1586	if (!errorOk)
1587		log << TestLog::Message << "DrawArrays/DrawElements didn't produce error." << TestLog::EndMessage;
1588
1589	// Expect unaltered destination pixels.
1590	bool contentsOk = true;
1591	for (int i = 0; i < 2; i++)
1592	{
1593		glw::GLubyte result[4] = { 1, 2, 3, 4 };
1594		gl.readBuffer(bufs[0]);
1595		gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, result);
1596		GLU_EXPECT_NO_ERROR(gl.getError(), "Read pixels failed");
1597		if (tcu::RGBA::fromBytes(result) != tcu::RGBA::white())
1598		{
1599			contentsOk = false;
1600			log << TestLog::Message << "Buffer " << i << " "
1601				<< "contents changed: " << tcu::RGBA::fromBytes(result) << " expected:" << tcu::RGBA::white()
1602				<< TestLog::EndMessage;
1603		}
1604	}
1605
1606	gl.deleteVertexArrays(1, &vao);
1607	gl.deleteBuffers(1, &vbo);
1608
1609	bool pass = errorOk && contentsOk;
1610	m_testCtx.setTestResult(pass ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, pass ? "Pass" : "Fail");
1611	return STOP;
1612}
1613
1614/*
1615 * From "Other" part of the spec:
1616 *    "Test that the new blending modes cannot be used with
1617 *     BlendEquationSeparate(i). Expect INVALID_ENUM GL error"
1618 *
1619 * Tests that BlendEquationSeparate does not accept extension's blending modes
1620 * either in rgb or alpha parameter.
1621 */
1622class BlendEquationSeparateCase : public deqp::TestCaseGroup
1623{
1624public:
1625	BlendEquationSeparateCase(deqp::Context& context)
1626		: TestCaseGroup(context, "BlendEquationSeparate",
1627						"Test that advanced blend modes are correctly rejected from glBlendEquationSeparate.")
1628	{
1629	}
1630
1631	void init(void)
1632	{
1633		// Pump individual modes.
1634		for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_modes); i++)
1635			addChild(new ModeCase(m_context, s_modes[i]));
1636	}
1637
1638private:
1639	class ModeCase : public deqp::TestCase
1640	{
1641	public:
1642		ModeCase(deqp::Context& context, glw::GLenum mode)
1643			: TestCase(context, GetModeStr(mode), "Test one mode"), m_mode(mode)
1644		{
1645		}
1646
1647		IterateResult iterate(void)
1648		{
1649			// Check that extension is supported.
1650			if (!IsExtensionSupported(m_context, "GL_KHR_blend_equation_advanced"))
1651			{
1652				m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_KHR_blend_equation_advanced");
1653				return STOP;
1654			}
1655
1656			const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1657
1658			// Set separate blend equations.
1659			// Expect error and that default value (FUNC_ADD) is not changed.
1660
1661			// RGB.
1662			gl.blendEquationSeparate(m_mode, GL_FUNC_ADD);
1663			bool	   rgbOk = gl.getError() == GL_INVALID_ENUM;
1664			glw::GLint rgbEq = GL_NONE;
1665			gl.getIntegerv(GL_BLEND_EQUATION_RGB, &rgbEq);
1666			rgbOk = rgbOk && (rgbEq == GL_FUNC_ADD);
1667
1668			// Alpha.
1669			gl.blendEquationSeparate(GL_FUNC_ADD, m_mode);
1670			bool	   alphaOk = gl.getError() == GL_INVALID_ENUM;
1671			glw::GLint alphaEq = GL_NONE;
1672			gl.getIntegerv(GL_BLEND_EQUATION_ALPHA, &alphaEq);
1673			alphaOk = alphaOk && (alphaEq == GL_FUNC_ADD);
1674
1675			bool pass = rgbOk && alphaOk;
1676			m_testCtx.setTestResult(pass ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, pass ? "Pass" : "Fail");
1677			return STOP;
1678		}
1679
1680	private:
1681		glw::GLenum m_mode;
1682	};
1683};
1684
1685/*
1686 *  From "Other" part of the spec:
1687 *     "Check that GLSL GL_KHR_blend_equation_advanced #define exists and is 1"
1688 *
1689 *  Test that regardless of extension directive the definition exists and has value 1.
1690 */
1691
1692class PreprocessorCaseGroup : public deqp::TestCaseGroup
1693{
1694public:
1695	PreprocessorCaseGroup(deqp::Context& context, glu::GLSLVersion glslVersion)
1696		: TestCaseGroup(context, "preprocessor", "GL_KHR_blend_equation_advanced"), m_glslVersion(glslVersion)
1697	{
1698	}
1699
1700	void init(void)
1701	{
1702		addChild(new PreprocessorCase(m_context, m_glslVersion, DE_NULL));
1703		addChild(new PreprocessorCase(m_context, m_glslVersion, "require"));
1704		addChild(new PreprocessorCase(m_context, m_glslVersion, "enable"));
1705		addChild(new PreprocessorCase(m_context, m_glslVersion, "warn"));
1706		addChild(new PreprocessorCase(m_context, m_glslVersion, "disable"));
1707	}
1708
1709private:
1710	class PreprocessorCase : public deqp::TestCase
1711	{
1712	public:
1713		PreprocessorCase(deqp::Context& context, glu::GLSLVersion glslVersion, const char* behaviour)
1714			: TestCase(context, behaviour ? behaviour : "none", "GL_KHR_blend_equation_advanced")
1715			, m_glslVersion(glslVersion)
1716			, m_behaviour(behaviour)
1717		{
1718		}
1719
1720		IterateResult iterate(void);
1721
1722	private:
1723		glu::GLSLVersion m_glslVersion;
1724		const char*		 m_behaviour;
1725	};
1726
1727	glu::GLSLVersion m_glslVersion;
1728};
1729
1730PreprocessorCaseGroup::PreprocessorCase::IterateResult PreprocessorCaseGroup::PreprocessorCase::iterate(void)
1731{
1732	TestLog&			  log = m_testCtx.getLog();
1733	const glw::Functions& gl  = m_context.getRenderContext().getFunctions();
1734	const int			  dim = 4;
1735
1736	if (!IsExtensionSupported(m_context, "GL_KHR_blend_equation_advanced"))
1737	{
1738		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_KHR_blend_equation_advanced");
1739		return STOP;
1740	}
1741
1742	FBOSentry fbo(gl, dim, dim, GL_RGBA8);
1743	gl.clearColor(0.125f, 0.125f, 0.125f, 1.f);
1744	gl.clear(GL_COLOR_BUFFER_BIT);
1745
1746	// Test that GL_KHR_blend_equation_advanced is defined and it has value 1.
1747	// Renders green pixels if above is true, red pixels otherwise.
1748	static const char* frgSrcTemplate = "${VERSION_DIRECTIVE}\n"
1749										"${EXTENSION_DIRECTIVE}\n"
1750										"precision highp float;\n"
1751										"\n"
1752										"uniform vec4 uDefined;\n"
1753										"uniform vec4 uNonDefined;\n"
1754										"\n"
1755										"uniform int  uValue;\n"
1756										"\n"
1757										"layout(location = 0) out vec4 oCol;\n"
1758										"\n"
1759										"void main (void) {\n"
1760										"    vec4 col = uNonDefined;\n"
1761										"#if defined(GL_KHR_blend_equation_advanced)\n"
1762										"    int val = GL_KHR_blend_equation_advanced;\n"
1763										"    if (uValue == val) {\n"
1764										"        col = uDefined;\n"
1765										"    }\n"
1766										"#endif\n"
1767										"    oCol = col;\n"
1768										"}\n";
1769
1770	std::map<std::string, std::string> args;
1771	args["VERSION_DIRECTIVE"] = glu::getGLSLVersionDeclaration(m_glslVersion);
1772	if (m_behaviour)
1773		args["EXTENSION_DIRECTIVE"] = std::string("#extension GL_KHR_blend_equation_advanced : ") + m_behaviour;
1774	else
1775		args["EXTENSION_DIRECTIVE"] = "";
1776	std::string frgSrc				= tcu::StringTemplate(frgSrcTemplate).specialize(args);
1777
1778	glu::ShaderProgram p(m_context.getRenderContext(),
1779						 glu::makeVtxFragSources(GetDef2DVtxSrc(m_glslVersion).c_str(), frgSrc.c_str()));
1780	if (!p.isOk())
1781	{
1782		log << p;
1783		TCU_FAIL("Compile failed");
1784	}
1785	gl.useProgram(p.getProgram());
1786	GLU_EXPECT_NO_ERROR(gl.getError(), "Program failed");
1787
1788	gl.uniform1i(gl.getUniformLocation(p.getProgram(), "uValue"), 1);
1789	gl.uniform4f(gl.getUniformLocation(p.getProgram(), "uDefined"), 0.f, 1.f, 0.f, 1.f);
1790	gl.uniform4f(gl.getUniformLocation(p.getProgram(), "uNonDefined"), 1.f, 0.f, 1.f, 1.f);
1791	GLU_EXPECT_NO_ERROR(gl.getError(), "Uniforms failed");
1792
1793	glu::VertexArrayBinding posBinding = glu::va::Float("aPos", 2, 4, 0, &s_pos[0]);
1794	glu::draw(m_context.getRenderContext(), p.getProgram(), 1, &posBinding,
1795			  glu::pr::Triangles(DE_LENGTH_OF_ARRAY(s_indices), &s_indices[0]));
1796	GLU_EXPECT_NO_ERROR(gl.getError(), "Draw failed");
1797
1798	// Check the results.
1799	tcu::Surface resultSurface(dim, dim);
1800	glu::readPixels(m_context.getRenderContext(), 0, 0, resultSurface.getAccess());
1801	GLU_EXPECT_NO_ERROR(gl.getError(), "Read pixels failed");
1802	bool pass = tcu::RGBA::green() == resultSurface.getPixel(0, 0);
1803
1804	m_testCtx.setTestResult(pass ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, pass ? "Pass" : "Fail");
1805
1806	return STOP;
1807}
1808
1809BlendEquationAdvancedTests::BlendEquationAdvancedTests(deqp::Context& context, glu::GLSLVersion glslVersion)
1810	: TestCaseGroup(context, "blend_equation_advanced", "KHR_blend_equation_advanced tests"), m_glslVersion(glslVersion)
1811{
1812}
1813
1814BlendEquationAdvancedTests::~BlendEquationAdvancedTests(void)
1815{
1816}
1817
1818void BlendEquationAdvancedTests::init(void)
1819{
1820	// Test that enable/disable and getting status works.
1821	addChild(new CoherentEnableCaseGroup(m_context));
1822
1823	// Test that preprocessor macro GL_KHR_blend_equation_advanced
1824	// is always defined and its value is 1.
1825	addChild(new PreprocessorCaseGroup(m_context, m_glslVersion));
1826
1827	// Test that BlendEquationSeparate rejects advanced blend modes.
1828	addChild(new BlendEquationSeparateCase(m_context));
1829
1830	// Test that advanced blend equations cannot be used with multiple render targets.
1831	addChild(new MRTCaseGroup(m_context, m_glslVersion));
1832
1833	// Test that using new blend modes produce errors if appropriate qualifier
1834	// is not in the shader (test without any blend qualifier and with mismatching qualifier).
1835	addChild(new MissingQualifierTestGroup(m_context, m_glslVersion, MissingQualifierTestGroup::MISMATCH));
1836	addChild(new MissingQualifierTestGroup(m_context, m_glslVersion, MissingQualifierTestGroup::MISSING));
1837
1838	// Test #extension directive behaviour.
1839	// Case "require" is tested indirectly by blending tests.
1840	addChild(new ExtensionDirectiveTestCaseGroup(m_context, m_glslVersion));
1841
1842	// Test that each blend mode produces correct results.
1843	addChild(new BlendTestCaseGroup(m_context, m_glslVersion, BlendTestCaseGroup::ALL_QUALIFIER));
1844	addChild(new BlendTestCaseGroup(m_context, m_glslVersion, BlendTestCaseGroup::MATCHING_QUALIFIER));
1845
1846	// Test that coherent blending or barrier works.
1847	addChild(new CoherentBlendTestCaseGroup(m_context, m_glslVersion));
1848}
1849
1850} // glcts
1851