1b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org/*-------------------------------------------------------------------------
2b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * drawElements Quality Program Reference Renderer
3b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * -----------------------------------------------
4b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *
5b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * Copyright 2014 The Android Open Source Project
6b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *
7b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * Licensed under the Apache License, Version 2.0 (the "License");
8b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * you may not use this file except in compliance with the License.
9b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * You may obtain a copy of the License at
10b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *
11b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *      http://www.apache.org/licenses/LICENSE-2.0
12b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *
13b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * Unless required by applicable law or agreed to in writing, software
14a557f436b9d694d5a0a045e0295e1794f2df48eapbos@webrtc.org * distributed under the License is distributed on an "AS IS" BASIS,
15a557f436b9d694d5a0a045e0295e1794f2df48eapbos@webrtc.org * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * See the License for the specific language governing permissions and
17b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * limitations under the License.
18b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *
19b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *//*!
20b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * \file
21b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * \brief Reference implementation for per-fragment operations.
22b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *//*--------------------------------------------------------------------*/
23b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
24b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "rrFragmentOperations.hpp"
25b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "tcuVectorUtil.hpp"
26b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "tcuTextureUtil.hpp"
27b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
28b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgusing tcu::IVec2;
29b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgusing tcu::Vec3;
30b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgusing tcu::Vec4;
31b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgusing tcu::IVec4;
32b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgusing tcu::UVec4;
33b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgusing tcu::min;
34b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgusing tcu::max;
35b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgusing tcu::clamp;
36b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgusing de::min;
37b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgusing de::max;
38b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgusing de::clamp;
39b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
40b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgnamespace rr
41b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
42b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
43b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Return oldValue with the bits indicated by mask replaced by corresponding bits of newValue.
44b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgstatic inline int maskedBitReplace (int oldValue, int newValue, deUint32 mask)
45b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
46b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	return (oldValue & ~mask) | (newValue & mask);
47b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
48b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
49b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgstatic inline bool isInsideRect (const IVec2& point, const WindowRectangle& rect)
50b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
51b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	return de::inBounds(point.x(), rect.left,		rect.left + rect.width) &&
52b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		   de::inBounds(point.y(), rect.bottom,		rect.bottom + rect.height);
53b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
54b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
55b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgstatic inline Vec4 unpremultiply (const Vec4& v)
56b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
57b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	if (v.w() > 0.0f)
58b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		return Vec4(v.x()/v.w(), v.y()/v.w(), v.z()/v.w(), v.w());
59b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	else
60b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	{
61b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		DE_ASSERT(v.x() == 0.0f && v.y() == 0.0f && v.z() == 0.0f);
62b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		return Vec4(0.0f, 0.0f, 0.0f, 0.0f);
63b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	}
64b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
65b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
66b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid clearMultisampleColorBuffer	(const tcu::PixelBufferAccess& dst, const Vec4& v,	const WindowRectangle& r)	{ tcu::clear(tcu::getSubregion(dst, 0, r.left, r.bottom, dst.getWidth(), r.width, r.height), v);				}
67b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid clearMultisampleColorBuffer	(const tcu::PixelBufferAccess& dst, const IVec4& v,	const WindowRectangle& r)	{ tcu::clear(tcu::getSubregion(dst, 0, r.left, r.bottom, dst.getWidth(), r.width, r.height), v);				}
68b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid clearMultisampleColorBuffer	(const tcu::PixelBufferAccess& dst, const UVec4& v,	const WindowRectangle& r)	{ tcu::clear(tcu::getSubregion(dst, 0, r.left, r.bottom, dst.getWidth(), r.width, r.height), v.cast<int>());	}
69b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid clearMultisampleDepthBuffer	(const tcu::PixelBufferAccess& dst, float v,		const WindowRectangle& r)	{ tcu::clearDepth(tcu::getSubregion(dst, 0, r.left, r.bottom, dst.getWidth(), r.width, r.height), v);			}
70b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid clearMultisampleStencilBuffer	(const tcu::PixelBufferAccess& dst, int v,			const WindowRectangle& r)	{ tcu::clearStencil(tcu::getSubregion(dst, 0, r.left, r.bottom, dst.getWidth(), r.width, r.height), v);			}
71b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
72b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgFragmentProcessor::FragmentProcessor (void)
73b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	: m_sampleRegister()
74b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
75b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
76b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
77b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid FragmentProcessor::executeScissorTest (int fragNdxOffset, int numSamplesPerFragment, const Fragment* inputFragments, const WindowRectangle& scissorRect)
78b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
79b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	for (int regSampleNdx = 0; regSampleNdx < SAMPLE_REGISTER_SIZE; regSampleNdx++)
80b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	{
81b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		if (m_sampleRegister[regSampleNdx].isAlive)
82b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		{
83b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			int fragNdx = fragNdxOffset + regSampleNdx/numSamplesPerFragment;
84b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
85b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			if (!isInsideRect(inputFragments[fragNdx].pixelCoord, scissorRect))
86b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org				m_sampleRegister[regSampleNdx].isAlive = false;
87b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		}
88b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	}
89b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
90b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
91b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid FragmentProcessor::executeStencilCompare (int fragNdxOffset, int numSamplesPerFragment, const Fragment* inputFragments, const StencilState& stencilState, int numStencilBits, const tcu::ConstPixelBufferAccess& stencilBuffer)
92b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
93b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#define SAMPLE_REGISTER_STENCIL_COMPARE(COMPARE_EXPRESSION)																					\
94b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	for (int regSampleNdx = 0; regSampleNdx < SAMPLE_REGISTER_SIZE; regSampleNdx++)															\
95b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	{																																		\
96b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		if (m_sampleRegister[regSampleNdx].isAlive)																							\
97b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		{																																	\
98b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			int					fragSampleNdx		= regSampleNdx % numSamplesPerFragment;													\
99b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			const Fragment&		frag				= inputFragments[fragNdxOffset + regSampleNdx/numSamplesPerFragment];					\
100b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			int					stencilBufferValue	= stencilBuffer.getPixStencil(fragSampleNdx, frag.pixelCoord.x(), frag.pixelCoord.y());	\
101b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			int					maskedRef			= stencilState.compMask & clampedStencilRef;											\
102b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			int					maskedBuf			= stencilState.compMask & stencilBufferValue;											\
103b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			DE_UNREF(maskedRef);																											\
104b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			DE_UNREF(maskedBuf);																											\
105b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org																																			\
106b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			m_sampleRegister[regSampleNdx].stencilPassed = (COMPARE_EXPRESSION);															\
107b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		}																																	\
108b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	}
109b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
110b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	int clampedStencilRef = de::clamp(stencilState.ref, 0, (1<<numStencilBits)-1);
111b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
112b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	switch (stencilState.func)
113b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	{
114b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case TESTFUNC_NEVER:	SAMPLE_REGISTER_STENCIL_COMPARE(false)						break;
115b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case TESTFUNC_ALWAYS:	SAMPLE_REGISTER_STENCIL_COMPARE(true)						break;
116b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case TESTFUNC_LESS:		SAMPLE_REGISTER_STENCIL_COMPARE(maskedRef <  maskedBuf)		break;
117b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case TESTFUNC_LEQUAL:	SAMPLE_REGISTER_STENCIL_COMPARE(maskedRef <= maskedBuf)		break;
118b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case TESTFUNC_GREATER:	SAMPLE_REGISTER_STENCIL_COMPARE(maskedRef >  maskedBuf)		break;
119b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case TESTFUNC_GEQUAL:	SAMPLE_REGISTER_STENCIL_COMPARE(maskedRef >= maskedBuf)		break;
120b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case TESTFUNC_EQUAL:	SAMPLE_REGISTER_STENCIL_COMPARE(maskedRef == maskedBuf)		break;
121b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case TESTFUNC_NOTEQUAL:	SAMPLE_REGISTER_STENCIL_COMPARE(maskedRef != maskedBuf)		break;
122b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		default:
123b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			DE_ASSERT(false);
124b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	}
125b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
126b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#undef SAMPLE_REGISTER_STENCIL_COMPARE
127b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
128b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
129b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid FragmentProcessor::executeStencilSFail (int fragNdxOffset, int numSamplesPerFragment, const Fragment* inputFragments, const StencilState& stencilState, int numStencilBits, const tcu::PixelBufferAccess& stencilBuffer)
130b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
131b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#define SAMPLE_REGISTER_SFAIL(SFAIL_EXPRESSION)																																		\
132b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	for (int regSampleNdx = 0; regSampleNdx < SAMPLE_REGISTER_SIZE; regSampleNdx++)																									\
133b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	{																																												\
134b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		if (m_sampleRegister[regSampleNdx].isAlive && !m_sampleRegister[regSampleNdx].stencilPassed)																				\
135b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		{																																											\
136b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			int					fragSampleNdx		= regSampleNdx % numSamplesPerFragment;																							\
137b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			const Fragment&		frag				= inputFragments[fragNdxOffset + regSampleNdx/numSamplesPerFragment];															\
138b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			int					stencilBufferValue	= stencilBuffer.getPixStencil(fragSampleNdx, frag.pixelCoord.x(), frag.pixelCoord.y());											\
139b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org																																													\
140b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			stencilBuffer.setPixStencil(maskedBitReplace(stencilBufferValue, (SFAIL_EXPRESSION), stencilState.writeMask), fragSampleNdx, frag.pixelCoord.x(), frag.pixelCoord.y());	\
141b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			m_sampleRegister[regSampleNdx].isAlive = false;																															\
142b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		}																																											\
143b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	}
144b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
145b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	int clampedStencilRef = de::clamp(stencilState.ref, 0, (1<<numStencilBits)-1);
146b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
147b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	switch (stencilState.sFail)
148b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	{
149b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case STENCILOP_KEEP:		SAMPLE_REGISTER_SFAIL(stencilBufferValue)												break;
150b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case STENCILOP_ZERO:		SAMPLE_REGISTER_SFAIL(0)																break;
151b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case STENCILOP_REPLACE:		SAMPLE_REGISTER_SFAIL(clampedStencilRef)												break;
152b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case STENCILOP_INCR:		SAMPLE_REGISTER_SFAIL(de::clamp(stencilBufferValue+1, 0, (1<<numStencilBits) - 1))		break;
153b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case STENCILOP_DECR:		SAMPLE_REGISTER_SFAIL(de::clamp(stencilBufferValue-1, 0, (1<<numStencilBits) - 1))		break;
154b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case STENCILOP_INCR_WRAP:	SAMPLE_REGISTER_SFAIL((stencilBufferValue + 1) & ((1<<numStencilBits) - 1))				break;
155b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case STENCILOP_DECR_WRAP:	SAMPLE_REGISTER_SFAIL((stencilBufferValue - 1) & ((1<<numStencilBits) - 1))				break;
156b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case STENCILOP_INVERT:		SAMPLE_REGISTER_SFAIL((~stencilBufferValue) & ((1<<numStencilBits) - 1))				break;
157b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		default:
158b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			DE_ASSERT(false);
159b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	}
160b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
161b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#undef SAMPLE_REGISTER_SFAIL
162b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
163b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
164b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid FragmentProcessor::executeDepthCompare (int fragNdxOffset, int numSamplesPerFragment, const Fragment* inputFragments, TestFunc depthFunc, const tcu::ConstPixelBufferAccess& depthBuffer)
165b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
166b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#define SAMPLE_REGISTER_DEPTH_COMPARE_F(COMPARE_EXPRESSION)																						\
167b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	for (int regSampleNdx = 0; regSampleNdx < SAMPLE_REGISTER_SIZE; regSampleNdx++)																\
168b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	{																																			\
169b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		if (m_sampleRegister[regSampleNdx].isAlive)																								\
170b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		{																																		\
171b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			int					fragSampleNdx		= regSampleNdx % numSamplesPerFragment;														\
172b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			const Fragment&		frag				= inputFragments[fragNdxOffset + regSampleNdx/numSamplesPerFragment];						\
173b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			float				depthBufferValue	= depthBuffer.getPixDepth(fragSampleNdx, frag.pixelCoord.x(), frag.pixelCoord.y());			\
174b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			float				sampleDepthFloat	= frag.sampleDepths[fragSampleNdx];															\
175b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			float				sampleDepth			= de::clamp(sampleDepthFloat, 0.0f, 1.0f);													\
176b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org																																				\
177b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			m_sampleRegister[regSampleNdx].depthPassed = (COMPARE_EXPRESSION);																	\
178b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org																																				\
179b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			DE_UNREF(depthBufferValue);																											\
180b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			DE_UNREF(sampleDepth);																												\
181b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		}																																		\
182b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	}
183b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
184b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#define SAMPLE_REGISTER_DEPTH_COMPARE_UI(COMPARE_EXPRESSION)																					\
185b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	for (int regSampleNdx = 0; regSampleNdx < SAMPLE_REGISTER_SIZE; regSampleNdx++)																\
186b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	{																																			\
187b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		if (m_sampleRegister[regSampleNdx].isAlive)																								\
188b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		{																																		\
189b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			int					fragSampleNdx		= regSampleNdx % numSamplesPerFragment;														\
190b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			const Fragment&		frag				= inputFragments[fragNdxOffset + regSampleNdx/numSamplesPerFragment];						\
191b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			deUint32			depthBufferValue	= depthBuffer.getPixelUint(fragSampleNdx, frag.pixelCoord.x(), frag.pixelCoord.y()).x();	\
192b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			float				sampleDepthFloat	= frag.sampleDepths[fragSampleNdx];															\
193b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org																																				\
194b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			/* Convert input float to target buffer format for comparison */																	\
195b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org																																				\
196b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			deUint32 buffer[2];																													\
197b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org																																				\
198b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			DE_ASSERT(sizeof(buffer) >= (size_t)depthBuffer.getFormat().getPixelSize());														\
199b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org																																				\
200b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			tcu::PixelBufferAccess access(depthBuffer.getFormat(), 1, 1, 1, &buffer);															\
201b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			access.setPixDepth(sampleDepthFloat, 0, 0, 0);																						\
202b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			deUint32 sampleDepth = access.getPixelUint(0, 0, 0).x();																			\
203b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org																																				\
204b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			m_sampleRegister[regSampleNdx].depthPassed = (COMPARE_EXPRESSION);																	\
205b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org																																				\
206b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			DE_UNREF(depthBufferValue);																											\
207b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			DE_UNREF(sampleDepth);																												\
208b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		}																																		\
209b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	}
210b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
211b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	if (depthBuffer.getFormat().type == tcu::TextureFormat::FLOAT || depthBuffer.getFormat().type == tcu::TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV)
212b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	{
213b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
214b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		switch (depthFunc)
215b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		{
216b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			case TESTFUNC_NEVER:	SAMPLE_REGISTER_DEPTH_COMPARE_F(false)							break;
217b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			case TESTFUNC_ALWAYS:	SAMPLE_REGISTER_DEPTH_COMPARE_F(true)								break;
218b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			case TESTFUNC_LESS:		SAMPLE_REGISTER_DEPTH_COMPARE_F(sampleDepth <  depthBufferValue)	break;
219b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			case TESTFUNC_LEQUAL:	SAMPLE_REGISTER_DEPTH_COMPARE_F(sampleDepth <= depthBufferValue)	break;
220b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			case TESTFUNC_GREATER:	SAMPLE_REGISTER_DEPTH_COMPARE_F(sampleDepth >  depthBufferValue)	break;
221b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			case TESTFUNC_GEQUAL:	SAMPLE_REGISTER_DEPTH_COMPARE_F(sampleDepth >= depthBufferValue)	break;
222b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			case TESTFUNC_EQUAL:	SAMPLE_REGISTER_DEPTH_COMPARE_F(sampleDepth == depthBufferValue)	break;
223b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			case TESTFUNC_NOTEQUAL:	SAMPLE_REGISTER_DEPTH_COMPARE_F(sampleDepth != depthBufferValue)	break;
224b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			default:
225b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org				DE_ASSERT(false);
226b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		}
227b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
228b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	}
229b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	else
230b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	{
231b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		switch (depthFunc)
232b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		{
233b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			case TESTFUNC_NEVER:	SAMPLE_REGISTER_DEPTH_COMPARE_UI(false)							break;
234b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			case TESTFUNC_ALWAYS:	SAMPLE_REGISTER_DEPTH_COMPARE_UI(true)								break;
235b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			case TESTFUNC_LESS:		SAMPLE_REGISTER_DEPTH_COMPARE_UI(sampleDepth <  depthBufferValue)	break;
236b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			case TESTFUNC_LEQUAL:	SAMPLE_REGISTER_DEPTH_COMPARE_UI(sampleDepth <= depthBufferValue)	break;
237b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			case TESTFUNC_GREATER:	SAMPLE_REGISTER_DEPTH_COMPARE_UI(sampleDepth >  depthBufferValue)	break;
238b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			case TESTFUNC_GEQUAL:	SAMPLE_REGISTER_DEPTH_COMPARE_UI(sampleDepth >= depthBufferValue)	break;
239b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			case TESTFUNC_EQUAL:	SAMPLE_REGISTER_DEPTH_COMPARE_UI(sampleDepth == depthBufferValue)	break;
240b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			case TESTFUNC_NOTEQUAL:	SAMPLE_REGISTER_DEPTH_COMPARE_UI(sampleDepth != depthBufferValue)	break;
241b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			default:
242b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org				DE_ASSERT(false);
243b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		}
244b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	}
245b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
246b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#undef SAMPLE_REGISTER_DEPTH_COMPARE_F
247b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#undef SAMPLE_REGISTER_DEPTH_COMPARE_UI
248b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
249b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
250b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid FragmentProcessor::executeDepthWrite (int fragNdxOffset, int numSamplesPerFragment, const Fragment* inputFragments, const tcu::PixelBufferAccess& depthBuffer)
251b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
252b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	for (int regSampleNdx = 0; regSampleNdx < SAMPLE_REGISTER_SIZE; regSampleNdx++)
253b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	{
254b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		if (m_sampleRegister[regSampleNdx].isAlive && m_sampleRegister[regSampleNdx].depthPassed)
255b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		{
256b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			int					fragSampleNdx	= regSampleNdx % numSamplesPerFragment;
257b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			const Fragment&		frag			= inputFragments[fragNdxOffset + regSampleNdx/numSamplesPerFragment];
258b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			const float			clampedDepth	= de::clamp(frag.sampleDepths[fragSampleNdx], 0.0f, 1.0f);
259b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
260b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			depthBuffer.setPixDepth(clampedDepth, fragSampleNdx, frag.pixelCoord.x(), frag.pixelCoord.y());
261b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		}
262b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	}
263b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
264b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
265b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid FragmentProcessor::executeStencilDpFailAndPass (int fragNdxOffset, int numSamplesPerFragment, const Fragment* inputFragments, const StencilState& stencilState, int numStencilBits, const tcu::PixelBufferAccess& stencilBuffer)
266b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
267b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#define SAMPLE_REGISTER_DPFAIL_OR_DPPASS(CONDITION, EXPRESSION)																													\
268b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	for (int regSampleNdx = 0; regSampleNdx < SAMPLE_REGISTER_SIZE; regSampleNdx++)																								\
269b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	{																																											\
270b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		if (m_sampleRegister[regSampleNdx].isAlive && (CONDITION))																												\
271b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		{																																										\
272b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			int					fragSampleNdx		= regSampleNdx % numSamplesPerFragment;																						\
273b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			const Fragment&		frag				= inputFragments[fragNdxOffset + regSampleNdx/numSamplesPerFragment];														\
274b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			int					stencilBufferValue	= stencilBuffer.getPixStencil(fragSampleNdx, frag.pixelCoord.x(), frag.pixelCoord.y());										\
275b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org																																												\
276b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			stencilBuffer.setPixStencil(maskedBitReplace(stencilBufferValue, (EXPRESSION), stencilState.writeMask), fragSampleNdx, frag.pixelCoord.x(), frag.pixelCoord.y());	\
277b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		}																																										\
278b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	}
279b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
280b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#define SWITCH_DPFAIL_OR_DPPASS(OP_NAME, CONDITION)																											\
281b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		switch (stencilState.OP_NAME)																														\
282b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		{																																					\
283b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			case STENCILOP_KEEP:		SAMPLE_REGISTER_DPFAIL_OR_DPPASS(CONDITION, stencilBufferValue)												break;	\
284b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			case STENCILOP_ZERO:		SAMPLE_REGISTER_DPFAIL_OR_DPPASS(CONDITION, 0)																break;	\
285b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			case STENCILOP_REPLACE:		SAMPLE_REGISTER_DPFAIL_OR_DPPASS(CONDITION, clampedStencilRef)												break;	\
286b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			case STENCILOP_INCR:		SAMPLE_REGISTER_DPFAIL_OR_DPPASS(CONDITION, de::clamp(stencilBufferValue+1, 0, (1<<numStencilBits) - 1))	break;	\
287b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			case STENCILOP_DECR:		SAMPLE_REGISTER_DPFAIL_OR_DPPASS(CONDITION, de::clamp(stencilBufferValue-1, 0, (1<<numStencilBits) - 1))	break;	\
288b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			case STENCILOP_INCR_WRAP:	SAMPLE_REGISTER_DPFAIL_OR_DPPASS(CONDITION, (stencilBufferValue + 1) & ((1<<numStencilBits) - 1))			break;	\
289b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			case STENCILOP_DECR_WRAP:	SAMPLE_REGISTER_DPFAIL_OR_DPPASS(CONDITION, (stencilBufferValue - 1) & ((1<<numStencilBits) - 1))			break;	\
290b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			case STENCILOP_INVERT:		SAMPLE_REGISTER_DPFAIL_OR_DPPASS(CONDITION, (~stencilBufferValue) & ((1<<numStencilBits) - 1))				break;	\
291b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			default:																																		\
292b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org				DE_ASSERT(false);																															\
293b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		}
294b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
295b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	int clampedStencilRef = de::clamp(stencilState.ref, 0, (1<<numStencilBits)-1);
296b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
297b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	SWITCH_DPFAIL_OR_DPPASS(dpFail, !m_sampleRegister[regSampleNdx].depthPassed)
298b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	SWITCH_DPFAIL_OR_DPPASS(dpPass, m_sampleRegister[regSampleNdx].depthPassed)
299b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
300b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#undef SWITCH_DPFAIL_OR_DPPASS
301b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#undef SAMPLE_REGISTER_DPFAIL_OR_DPPASS
302b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
303b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
304b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid FragmentProcessor::executeBlendFactorComputeRGB (const Vec4& blendColor, const BlendState& blendRGBState)
305b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
306b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#define SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, FACTOR_EXPRESSION)											\
307b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	for (int regSampleNdx = 0; regSampleNdx < SAMPLE_REGISTER_SIZE; regSampleNdx++)								\
308b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	{																											\
309b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		if (m_sampleRegister[regSampleNdx].isAlive)																\
310b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		{																										\
311b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			const Vec4& src		= m_sampleRegister[regSampleNdx].clampedBlendSrcColor;							\
312b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			const Vec4& src1	= m_sampleRegister[regSampleNdx].clampedBlendSrc1Color;							\
313b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			const Vec4& dst		= m_sampleRegister[regSampleNdx].clampedBlendDstColor;							\
314b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			DE_UNREF(src);																						\
315b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			DE_UNREF(src1);																						\
316b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			DE_UNREF(dst);																						\
317b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org																												\
318b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			m_sampleRegister[regSampleNdx].FACTOR_NAME = clamp((FACTOR_EXPRESSION), Vec3(0.0f), Vec3(1.0f));	\
319b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		}																										\
320b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	}
321b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
322b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#define SWITCH_SRC_OR_DST_FACTOR_RGB(FUNC_NAME, FACTOR_NAME)																					\
323b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	switch (blendRGBState.FUNC_NAME)																											\
324b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	{																																			\
325b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case BLENDFUNC_ZERO:						SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, Vec3(0.0f))								break;	\
326b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case BLENDFUNC_ONE:							SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, Vec3(1.0f))								break;	\
327b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case BLENDFUNC_SRC_COLOR:					SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, src.swizzle(0,1,2))						break;	\
328b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case BLENDFUNC_ONE_MINUS_SRC_COLOR:			SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, Vec3(1.0f) - src.swizzle(0,1,2))			break;	\
329b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case BLENDFUNC_DST_COLOR:					SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, dst.swizzle(0,1,2))						break;	\
330b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case BLENDFUNC_ONE_MINUS_DST_COLOR:			SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, Vec3(1.0f) - dst.swizzle(0,1,2))			break;	\
331b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case BLENDFUNC_SRC_ALPHA:					SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, Vec3(src.w()))							break;	\
332b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case BLENDFUNC_ONE_MINUS_SRC_ALPHA:			SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, Vec3(1.0f - src.w()))						break;	\
333b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case BLENDFUNC_DST_ALPHA:					SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, Vec3(dst.w()))							break;	\
334b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case BLENDFUNC_ONE_MINUS_DST_ALPHA:			SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, Vec3(1.0f - dst.w()))						break;	\
335b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case BLENDFUNC_CONSTANT_COLOR:				SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, blendColor.swizzle(0,1,2))				break;	\
336b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case BLENDFUNC_ONE_MINUS_CONSTANT_COLOR:	SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, Vec3(1.0f) - blendColor.swizzle(0,1,2))	break;	\
337b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case BLENDFUNC_CONSTANT_ALPHA:				SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, Vec3(blendColor.w()))						break;	\
338b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case BLENDFUNC_ONE_MINUS_CONSTANT_ALPHA:	SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, Vec3(1.0f - blendColor.w()))				break;	\
339b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case BLENDFUNC_SRC_ALPHA_SATURATE:			SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, Vec3(de::min(src.w(), 1.0f - dst.w())))	break;	\
340b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case BLENDFUNC_SRC1_COLOR:					SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, src1.swizzle(0,1,2))						break;	\
341b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case BLENDFUNC_ONE_MINUS_SRC1_COLOR:		SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, Vec3(1.0f) - src1.swizzle(0,1,2))			break;	\
342b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case BLENDFUNC_SRC1_ALPHA:					SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, Vec3(src1.w()))							break;	\
343b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		case BLENDFUNC_ONE_MINUS_SRC1_ALPHA:		SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, Vec3(1.0f - src1.w()))					break;	\
344b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		default:																																\
345b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			DE_ASSERT(false);																													\
346b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	}
347b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
348b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	SWITCH_SRC_OR_DST_FACTOR_RGB(srcFunc, blendSrcFactorRGB)
349b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	SWITCH_SRC_OR_DST_FACTOR_RGB(dstFunc, blendDstFactorRGB)
350b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
351b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#undef SWITCH_SRC_OR_DST_FACTOR_RGB
352b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#undef SAMPLE_REGISTER_BLEND_FACTOR
353b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
354b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
355b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid FragmentProcessor::executeBlendFactorComputeA (const Vec4& blendColor, const BlendState& blendAState)
356b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
357b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#define SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, FACTOR_EXPRESSION)								\
358b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	for (int regSampleNdx = 0; regSampleNdx < SAMPLE_REGISTER_SIZE; regSampleNdx++)					\
359b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	{																								\
360b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		if (m_sampleRegister[regSampleNdx].isAlive)													\
361b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		{																							\
362b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			const Vec4& src		= m_sampleRegister[regSampleNdx].clampedBlendSrcColor;				\
363b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			const Vec4& src1	= m_sampleRegister[regSampleNdx].clampedBlendSrc1Color;				\
364b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			const Vec4& dst		= m_sampleRegister[regSampleNdx].clampedBlendDstColor;				\
365b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			DE_UNREF(src);																			\
366b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			DE_UNREF(src1);																			\
367b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			DE_UNREF(dst);																			\
368b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org																									\
369b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org			m_sampleRegister[regSampleNdx].FACTOR_NAME = clamp((FACTOR_EXPRESSION), 0.0f, 1.0f);	\
370b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org		}																							\
371b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	}
372b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
3733b89e10f31160da35b408fd00cb8f89d2b08862dpbos@webrtc.org#define SWITCH_SRC_OR_DST_FACTOR_A(FUNC_NAME, FACTOR_NAME)																		\
374b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org	switch (blendAState.FUNC_NAME)																								\
375	{																															\
376		case BLENDFUNC_ZERO:						SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, 0.0f)						break;	\
377		case BLENDFUNC_ONE:							SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, 1.0f)						break;	\
378		case BLENDFUNC_SRC_COLOR:					SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, src.w())					break;	\
379		case BLENDFUNC_ONE_MINUS_SRC_COLOR:			SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, 1.0f - src.w())			break;	\
380		case BLENDFUNC_DST_COLOR:					SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, dst.w())					break;	\
381		case BLENDFUNC_ONE_MINUS_DST_COLOR:			SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, 1.0f - dst.w())			break;	\
382		case BLENDFUNC_SRC_ALPHA:					SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, src.w())					break;	\
383		case BLENDFUNC_ONE_MINUS_SRC_ALPHA:			SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, 1.0f - src.w())			break;	\
384		case BLENDFUNC_DST_ALPHA:					SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, dst.w())					break;	\
385		case BLENDFUNC_ONE_MINUS_DST_ALPHA:			SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, 1.0f - dst.w())			break;	\
386		case BLENDFUNC_CONSTANT_COLOR:				SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, blendColor.w())			break;	\
387		case BLENDFUNC_ONE_MINUS_CONSTANT_COLOR:	SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, 1.0f - blendColor.w())	break;	\
388		case BLENDFUNC_CONSTANT_ALPHA:				SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, blendColor.w())			break;	\
389		case BLENDFUNC_ONE_MINUS_CONSTANT_ALPHA:	SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, 1.0f - blendColor.w())	break;	\
390		case BLENDFUNC_SRC_ALPHA_SATURATE:			SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, 1.0f)						break;	\
391		case BLENDFUNC_SRC1_COLOR:					SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, src1.w())					break;	\
392		case BLENDFUNC_ONE_MINUS_SRC1_COLOR:		SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, 1.0f - src1.w())			break;	\
393		case BLENDFUNC_SRC1_ALPHA:					SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, src1.w())					break;	\
394		case BLENDFUNC_ONE_MINUS_SRC1_ALPHA:		SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, 1.0f - src1.w())			break;	\
395		default:																												\
396			DE_ASSERT(false);																									\
397	}
398
399	SWITCH_SRC_OR_DST_FACTOR_A(srcFunc, blendSrcFactorA)
400	SWITCH_SRC_OR_DST_FACTOR_A(dstFunc, blendDstFactorA)
401
402#undef SWITCH_SRC_OR_DST_FACTOR_A
403#undef SAMPLE_REGISTER_BLEND_FACTOR
404}
405
406void FragmentProcessor::executeBlend (const BlendState& blendRGBState, const BlendState& blendAState)
407{
408#define SAMPLE_REGISTER_BLENDED_COLOR(COLOR_NAME, COLOR_EXPRESSION)						\
409	for (int regSampleNdx = 0; regSampleNdx < SAMPLE_REGISTER_SIZE; regSampleNdx++)		\
410	{																					\
411		if (m_sampleRegister[regSampleNdx].isAlive)										\
412		{																				\
413			SampleData& sample		= m_sampleRegister[regSampleNdx];					\
414			const Vec4& srcColor	= sample.clampedBlendSrcColor;						\
415			const Vec4& dstColor	= sample.clampedBlendDstColor;						\
416																						\
417			sample.COLOR_NAME = (COLOR_EXPRESSION);										\
418		}																				\
419	}
420
421	switch (blendRGBState.equation)
422	{
423		case BLENDEQUATION_ADD:					SAMPLE_REGISTER_BLENDED_COLOR(blendedRGB, srcColor.swizzle(0,1,2)*sample.blendSrcFactorRGB + dstColor.swizzle(0,1,2)*sample.blendDstFactorRGB)	break;
424		case BLENDEQUATION_SUBTRACT:			SAMPLE_REGISTER_BLENDED_COLOR(blendedRGB, srcColor.swizzle(0,1,2)*sample.blendSrcFactorRGB - dstColor.swizzle(0,1,2)*sample.blendDstFactorRGB)	break;
425		case BLENDEQUATION_REVERSE_SUBTRACT:	SAMPLE_REGISTER_BLENDED_COLOR(blendedRGB, dstColor.swizzle(0,1,2)*sample.blendDstFactorRGB - srcColor.swizzle(0,1,2)*sample.blendSrcFactorRGB)	break;
426		case BLENDEQUATION_MIN:					SAMPLE_REGISTER_BLENDED_COLOR(blendedRGB, min(srcColor.swizzle(0,1,2), dstColor.swizzle(0,1,2)))												break;
427		case BLENDEQUATION_MAX:					SAMPLE_REGISTER_BLENDED_COLOR(blendedRGB, max(srcColor.swizzle(0,1,2), dstColor.swizzle(0,1,2)))												break;
428		default:
429			DE_ASSERT(false);
430	}
431
432	switch (blendAState.equation)
433	{
434		case BLENDEQUATION_ADD:					SAMPLE_REGISTER_BLENDED_COLOR(blendedA, srcColor.w()*sample.blendSrcFactorA + dstColor.w()*sample.blendDstFactorA)	break;
435		case BLENDEQUATION_SUBTRACT:			SAMPLE_REGISTER_BLENDED_COLOR(blendedA, srcColor.w()*sample.blendSrcFactorA - dstColor.w()*sample.blendDstFactorA)	break;
436		case BLENDEQUATION_REVERSE_SUBTRACT:	SAMPLE_REGISTER_BLENDED_COLOR(blendedA, dstColor.w()*sample.blendDstFactorA - srcColor.w()*sample.blendSrcFactorA)	break;
437		case BLENDEQUATION_MIN:					SAMPLE_REGISTER_BLENDED_COLOR(blendedA, min(srcColor.w(), dstColor.w()))											break;
438		case BLENDEQUATION_MAX:					SAMPLE_REGISTER_BLENDED_COLOR(blendedA, max(srcColor.w(), dstColor.w()))											break;
439		default:
440			DE_ASSERT(false);
441	}
442#undef SAMPLE_REGISTER_BLENDED_COLOR
443}
444
445namespace advblend
446{
447
448inline float	multiply	(float src, float dst) { return src*dst;					}
449inline float	screen		(float src, float dst) { return src + dst - src*dst;		}
450inline float	darken		(float src, float dst) { return de::min(src, dst);			}
451inline float	lighten		(float src, float dst) { return de::max(src, dst);			}
452inline float	difference	(float src, float dst) { return de::abs(dst-src);			}
453inline float	exclusion	(float src, float dst) { return src + dst - 2.0f*src*dst;	}
454
455inline float overlay (float src, float dst)
456{
457	if (dst <= 0.5f)
458		return 2.0f*src*dst;
459	else
460		return 1.0f - 2.0f*(1.0f-src)*(1.0f-dst);
461}
462
463inline float colordodge (float src, float dst)
464{
465	if (dst <= 0.0f)
466		return 0.0f;
467	else if (src < 1.0f)
468		return de::min(1.0f, dst/(1.0f-src));
469	else
470		return 1.0f;
471}
472
473inline float colorburn (float src, float dst)
474{
475	if (dst >= 1.0f)
476		return 1.0f;
477	else if (src > 0.0f)
478		return 1.0f - de::min(1.0f, (1.0f-dst)/src);
479	else
480		return 0.0f;
481}
482
483inline float hardlight (float src, float dst)
484{
485	if (src <= 0.5f)
486		return 2.0f*src*dst;
487	else
488		return 1.0f - 2.0f*(1.0f-src)*(1.0f-dst);
489}
490
491inline float softlight (float src, float dst)
492{
493	if (src <= 0.5f)
494		return dst - (1.0f - 2.0f*src)*dst*(1.0f-dst);
495	else if (dst <= 0.25f)
496		return dst + (2.0f*src - 1.0f)*dst*((16.0f*dst - 12.0f)*dst + 3.0f);
497	else
498		return dst + (2.0f*src - 1.0f)*(deFloatSqrt(dst)-dst);
499}
500
501inline float minComp (const Vec3& v)
502{
503	return de::min(de::min(v.x(), v.y()), v.z());
504}
505
506inline float maxComp (const Vec3& v)
507{
508	return de::max(de::max(v.x(), v.y()), v.z());
509}
510
511inline float luminosity (const Vec3& rgb)
512{
513	return dot(rgb, Vec3(0.3f, 0.59f, 0.11f));
514}
515
516inline float saturation (const Vec3& rgb)
517{
518	return maxComp(rgb) - minComp(rgb);
519}
520
521Vec3 setLum (const Vec3& cbase, const Vec3& clum)
522{
523	const float		lbase	= luminosity(cbase);
524	const float		llum	= luminosity(clum);
525	const float		ldiff	= llum - lbase;
526	const Vec3		color	= cbase + Vec3(ldiff);
527	const float		minC	= minComp(color);
528	const float		maxC	= maxComp(color);
529
530	if (minC < 0.0f)
531		return llum + ((color-llum)*llum / (llum != minC ? (llum-minC) : 1.0f));
532	else if (maxC > 1.0f)
533		return llum + ((color-llum)*(1.0f-llum) / (llum != maxC ? (maxC-llum) : 1.0f));
534	else
535		return color;
536}
537
538Vec3 setLumSat (const Vec3& cbase, const Vec3& csat, const Vec3& clum)
539{
540	const float		minbase	= minComp(cbase);
541	const float		sbase	= saturation(cbase);
542	const float		ssat	= saturation(csat);
543	Vec3			color	= Vec3(0.0f);
544
545	if (sbase > 0.0f)
546		color = (cbase - minbase) * ssat / sbase;
547	else
548		color = color;
549
550	return setLum(color, clum);
551}
552
553} // advblend
554
555void FragmentProcessor::executeAdvancedBlend (BlendEquationAdvanced equation)
556{
557	using namespace advblend;
558
559#define SAMPLE_REGISTER_ADV_BLEND(FUNCTION_NAME)											\
560	for (int regSampleNdx = 0; regSampleNdx < SAMPLE_REGISTER_SIZE; regSampleNdx++)			\
561	{																						\
562		if (m_sampleRegister[regSampleNdx].isAlive)											\
563		{																					\
564			SampleData&	sample		= m_sampleRegister[regSampleNdx];						\
565			const Vec4&	srcColor	= sample.clampedBlendSrcColor;							\
566			const Vec4&	dstColor	= sample.clampedBlendDstColor;							\
567			const Vec3&	bias		= sample.blendSrcFactorRGB;								\
568			const float	p0			= sample.blendSrcFactorA;								\
569			const float	r			= FUNCTION_NAME(srcColor[0], dstColor[0])*p0 + bias[0];	\
570			const float	g			= FUNCTION_NAME(srcColor[1], dstColor[1])*p0 + bias[1];	\
571			const float	b			= FUNCTION_NAME(srcColor[2], dstColor[2])*p0 + bias[2];	\
572																							\
573			sample.blendedRGB = Vec3(r, g, b);												\
574		}																					\
575	}
576
577#define SAMPLE_REGISTER_ADV_BLEND_HSL(COLOR_EXPRESSION)										\
578	for (int regSampleNdx = 0; regSampleNdx < SAMPLE_REGISTER_SIZE; regSampleNdx++)			\
579	{																						\
580		if (m_sampleRegister[regSampleNdx].isAlive)											\
581		{																					\
582			SampleData&	sample		= m_sampleRegister[regSampleNdx];						\
583			const Vec3	srcColor	= sample.clampedBlendSrcColor.swizzle(0,1,2);			\
584			const Vec3	dstColor	= sample.clampedBlendDstColor.swizzle(0,1,2);			\
585			const Vec3&	bias		= sample.blendSrcFactorRGB;								\
586			const float	p0			= sample.blendSrcFactorA;								\
587																							\
588			sample.blendedRGB = (COLOR_EXPRESSION)*p0 + bias;								\
589		}																					\
590	}
591
592	// Pre-compute factors & compute alpha \todo [2014-03-18 pyry] Re-using variable names.
593	// \note clampedBlend*Color contains clamped & unpremultiplied colors
594	for (int regSampleNdx = 0; regSampleNdx < SAMPLE_REGISTER_SIZE; regSampleNdx++)
595	{
596		if (m_sampleRegister[regSampleNdx].isAlive)
597		{
598			SampleData&	sample		= m_sampleRegister[regSampleNdx];
599			const Vec4&	srcColor	= sample.clampedBlendSrcColor;
600			const Vec4&	dstColor	= sample.clampedBlendDstColor;
601			const float	srcA		= srcColor.w();
602			const float	dstA		= dstColor.w();
603			const float	p0			= srcA*dstA;
604			const float p1			= srcA*(1.0f-dstA);
605			const float p2			= dstA*(1.0f-srcA);
606			const Vec3	bias		(srcColor[0]*p1 + dstColor[0]*p2,
607									 srcColor[1]*p1 + dstColor[1]*p2,
608									 srcColor[2]*p1 + dstColor[2]*p2);
609
610			sample.blendSrcFactorRGB	= bias;
611			sample.blendSrcFactorA		= p0;
612			sample.blendedA				= p0 + p1 + p2;
613		}
614	}
615
616	switch (equation)
617	{
618		case BLENDEQUATION_ADVANCED_MULTIPLY:		SAMPLE_REGISTER_ADV_BLEND(multiply);									break;
619		case BLENDEQUATION_ADVANCED_SCREEN:			SAMPLE_REGISTER_ADV_BLEND(screen);										break;
620		case BLENDEQUATION_ADVANCED_OVERLAY:		SAMPLE_REGISTER_ADV_BLEND(overlay);										break;
621		case BLENDEQUATION_ADVANCED_DARKEN:			SAMPLE_REGISTER_ADV_BLEND(darken);										break;
622		case BLENDEQUATION_ADVANCED_LIGHTEN:		SAMPLE_REGISTER_ADV_BLEND(lighten);										break;
623		case BLENDEQUATION_ADVANCED_COLORDODGE:		SAMPLE_REGISTER_ADV_BLEND(colordodge);									break;
624		case BLENDEQUATION_ADVANCED_COLORBURN:		SAMPLE_REGISTER_ADV_BLEND(colorburn);									break;
625		case BLENDEQUATION_ADVANCED_HARDLIGHT:		SAMPLE_REGISTER_ADV_BLEND(hardlight);									break;
626		case BLENDEQUATION_ADVANCED_SOFTLIGHT:		SAMPLE_REGISTER_ADV_BLEND(softlight);									break;
627		case BLENDEQUATION_ADVANCED_DIFFERENCE:		SAMPLE_REGISTER_ADV_BLEND(difference);									break;
628		case BLENDEQUATION_ADVANCED_EXCLUSION:		SAMPLE_REGISTER_ADV_BLEND(exclusion);									break;
629		case BLENDEQUATION_ADVANCED_HSL_HUE:		SAMPLE_REGISTER_ADV_BLEND_HSL(setLumSat(srcColor, dstColor, dstColor));	break;
630		case BLENDEQUATION_ADVANCED_HSL_SATURATION:	SAMPLE_REGISTER_ADV_BLEND_HSL(setLumSat(dstColor, srcColor, dstColor));	break;
631		case BLENDEQUATION_ADVANCED_HSL_COLOR:		SAMPLE_REGISTER_ADV_BLEND_HSL(setLum(srcColor, dstColor));				break;
632		case BLENDEQUATION_ADVANCED_HSL_LUMINOSITY:	SAMPLE_REGISTER_ADV_BLEND_HSL(setLum(dstColor, srcColor));				break;
633		default:
634			DE_ASSERT(false);
635	}
636
637#undef SAMPLE_REGISTER_ADV_BLEND
638#undef SAMPLE_REGISTER_ADV_BLEND_HSL
639}
640
641void FragmentProcessor::executeColorWrite (int fragNdxOffset, int numSamplesPerFragment, const Fragment* inputFragments, bool isSRGB, const tcu::PixelBufferAccess& colorBuffer)
642{
643	for (int regSampleNdx = 0; regSampleNdx < SAMPLE_REGISTER_SIZE; regSampleNdx++)
644	{
645		if (m_sampleRegister[regSampleNdx].isAlive)
646		{
647			int					fragSampleNdx	= regSampleNdx % numSamplesPerFragment;
648			const Fragment&		frag			= inputFragments[fragNdxOffset + regSampleNdx/numSamplesPerFragment];
649			Vec4				combinedColor;
650
651			combinedColor.xyz()	= m_sampleRegister[regSampleNdx].blendedRGB;
652			combinedColor.w()	= m_sampleRegister[regSampleNdx].blendedA;
653
654			if (isSRGB)
655				combinedColor = tcu::linearToSRGB(combinedColor);
656
657			colorBuffer.setPixel(combinedColor, fragSampleNdx, frag.pixelCoord.x(), frag.pixelCoord.y());
658		}
659	}
660}
661
662void FragmentProcessor::executeRGBA8ColorWrite (int fragNdxOffset, int numSamplesPerFragment, const Fragment* inputFragments, const tcu::PixelBufferAccess& colorBuffer)
663{
664	const int		fragStride	= 4;
665	const int		xStride		= colorBuffer.getRowPitch();
666	const int		yStride		= colorBuffer.getSlicePitch();
667	deUint8* const	basePtr		= (deUint8*)colorBuffer.getDataPtr();
668
669	for (int regSampleNdx = 0; regSampleNdx < SAMPLE_REGISTER_SIZE; regSampleNdx++)
670	{
671		if (m_sampleRegister[regSampleNdx].isAlive)
672		{
673			const int			fragSampleNdx	= regSampleNdx % numSamplesPerFragment;
674			const Fragment&		frag			= inputFragments[fragNdxOffset + regSampleNdx/numSamplesPerFragment];
675			Vec4				combinedColor;
676			deUint8*			dstPtr			= basePtr + fragSampleNdx*fragStride + frag.pixelCoord.x()*xStride + frag.pixelCoord.y()*yStride;
677
678			dstPtr[0] = tcu::floatToU8(m_sampleRegister[regSampleNdx].blendedRGB.x());
679			dstPtr[1] = tcu::floatToU8(m_sampleRegister[regSampleNdx].blendedRGB.y());
680			dstPtr[2] = tcu::floatToU8(m_sampleRegister[regSampleNdx].blendedRGB.z());
681			dstPtr[3] = tcu::floatToU8(m_sampleRegister[regSampleNdx].blendedA);
682		}
683	}
684}
685
686void FragmentProcessor::executeMaskedColorWrite (int fragNdxOffset, int numSamplesPerFragment, const Fragment* inputFragments, const Vec4& colorMaskFactor, const Vec4& colorMaskNegationFactor, bool isSRGB, const tcu::PixelBufferAccess& colorBuffer)
687{
688	for (int regSampleNdx = 0; regSampleNdx < SAMPLE_REGISTER_SIZE; regSampleNdx++)
689	{
690		if (m_sampleRegister[regSampleNdx].isAlive)
691		{
692			int					fragSampleNdx	= regSampleNdx % numSamplesPerFragment;
693			const Fragment&		frag			= inputFragments[fragNdxOffset + regSampleNdx/numSamplesPerFragment];
694			Vec4				originalColor	= colorBuffer.getPixel(fragSampleNdx, frag.pixelCoord.x(), frag.pixelCoord.y());
695			Vec4				newColor;
696
697			newColor.xyz()	= m_sampleRegister[regSampleNdx].blendedRGB;
698			newColor.w()	= m_sampleRegister[regSampleNdx].blendedA;
699
700			if (isSRGB)
701				newColor = tcu::linearToSRGB(newColor);
702
703			newColor = colorMaskFactor*newColor + colorMaskNegationFactor*originalColor;
704
705			colorBuffer.setPixel(newColor, fragSampleNdx, frag.pixelCoord.x(), frag.pixelCoord.y());
706		}
707	}
708}
709
710void FragmentProcessor::executeSignedValueWrite (int fragNdxOffset, int numSamplesPerFragment, const Fragment* inputFragments, const tcu::BVec4& colorMask, const tcu::PixelBufferAccess& colorBuffer)
711{
712	for (int regSampleNdx = 0; regSampleNdx < SAMPLE_REGISTER_SIZE; regSampleNdx++)
713	{
714		if (m_sampleRegister[regSampleNdx].isAlive)
715		{
716			int					fragSampleNdx	= regSampleNdx % numSamplesPerFragment;
717			const Fragment&		frag			= inputFragments[fragNdxOffset + regSampleNdx/numSamplesPerFragment];
718			const IVec4			originalValue	= colorBuffer.getPixelInt(fragSampleNdx, frag.pixelCoord.x(), frag.pixelCoord.y());
719
720			colorBuffer.setPixel(tcu::select(m_sampleRegister[regSampleNdx].signedValue, originalValue, colorMask), fragSampleNdx, frag.pixelCoord.x(), frag.pixelCoord.y());
721		}
722	}
723}
724
725void FragmentProcessor::executeUnsignedValueWrite (int fragNdxOffset, int numSamplesPerFragment, const Fragment* inputFragments, const tcu::BVec4& colorMask, const tcu::PixelBufferAccess& colorBuffer)
726{
727	for (int regSampleNdx = 0; regSampleNdx < SAMPLE_REGISTER_SIZE; regSampleNdx++)
728	{
729		if (m_sampleRegister[regSampleNdx].isAlive)
730		{
731			int					fragSampleNdx	= regSampleNdx % numSamplesPerFragment;
732			const Fragment&		frag			= inputFragments[fragNdxOffset + regSampleNdx/numSamplesPerFragment];
733			const UVec4			originalValue	= colorBuffer.getPixelUint(fragSampleNdx, frag.pixelCoord.x(), frag.pixelCoord.y());
734
735			colorBuffer.setPixel(tcu::select(m_sampleRegister[regSampleNdx].unsignedValue, originalValue, colorMask), fragSampleNdx, frag.pixelCoord.x(), frag.pixelCoord.y());
736		}
737	}
738}
739
740void FragmentProcessor::render (const rr::MultisamplePixelBufferAccess&		msColorBuffer,
741								const rr::MultisamplePixelBufferAccess&		msDepthBuffer,
742								const rr::MultisamplePixelBufferAccess&		msStencilBuffer,
743								const Fragment*								inputFragments,
744								int											numFragments,
745								FaceType									fragmentFacing,
746								const FragmentOperationState&				state)
747{
748	DE_ASSERT(fragmentFacing < FACETYPE_LAST);
749
750	const tcu::PixelBufferAccess&	colorBuffer			= msColorBuffer.raw();
751	const tcu::PixelBufferAccess&	depthBuffer			= msDepthBuffer.raw();
752	const tcu::PixelBufferAccess&	stencilBuffer		= msStencilBuffer.raw();
753
754	bool							hasDepth			= depthBuffer.getWidth() > 0	&& depthBuffer.getHeight() > 0		&& depthBuffer.getDepth() > 0;
755	bool							hasStencil			= stencilBuffer.getWidth() > 0	&& stencilBuffer.getHeight() > 0	&& stencilBuffer.getDepth() > 0;
756	bool							doDepthTest			= hasDepth && state.depthTestEnabled;
757	bool							doStencilTest		= hasStencil && state.stencilTestEnabled;
758
759	tcu::TextureChannelClass		colorbufferClass	= tcu::getTextureChannelClass(msColorBuffer.raw().getFormat().type);
760	rr::GenericVecType				fragmentDataType	= (colorbufferClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER) ? (rr::GENERICVECTYPE_INT32) : ((colorbufferClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER) ? (rr::GENERICVECTYPE_UINT32) : (rr::GENERICVECTYPE_FLOAT));
761
762	DE_ASSERT((!hasDepth || colorBuffer.getWidth() == depthBuffer.getWidth())	&& (!hasStencil || colorBuffer.getWidth() == stencilBuffer.getWidth()));
763	DE_ASSERT((!hasDepth || colorBuffer.getHeight() == depthBuffer.getHeight())	&& (!hasStencil || colorBuffer.getHeight() == stencilBuffer.getHeight()));
764	DE_ASSERT((!hasDepth || colorBuffer.getDepth() == depthBuffer.getDepth())	&& (!hasStencil || colorBuffer.getDepth() == stencilBuffer.getDepth()));
765
766	int						numSamplesPerFragment		= colorBuffer.getWidth();
767	int						totalNumSamples				= numFragments*numSamplesPerFragment;
768	int						numSampleGroups				= (totalNumSamples - 1) / SAMPLE_REGISTER_SIZE + 1; // \note totalNumSamples/SAMPLE_REGISTER_SIZE rounded up.
769	const StencilState&		stencilState				= state.stencilStates[fragmentFacing];
770	Vec4					colorMaskFactor				(state.colorMask[0] ? 1.0f : 0.0f, state.colorMask[1] ? 1.0f : 0.0f, state.colorMask[2] ? 1.0f : 0.0f, state.colorMask[3] ? 1.0f : 0.0f);
771	Vec4					colorMaskNegationFactor		(state.colorMask[0] ? 0.0f : 1.0f, state.colorMask[1] ? 0.0f : 1.0f, state.colorMask[2] ? 0.0f : 1.0f, state.colorMask[3] ? 0.0f : 1.0f);
772	bool					sRGBTarget					= state.sRGBEnabled && (colorBuffer.getFormat().order == tcu::TextureFormat::sRGBA ||
773																				colorBuffer.getFormat().order == tcu::TextureFormat::sRGB);
774
775	DE_ASSERT(SAMPLE_REGISTER_SIZE % numSamplesPerFragment == 0);
776
777	// Divide the fragments' samples into groups of size SAMPLE_REGISTER_SIZE, and perform
778	// the per-sample operations for one group at a time.
779
780	for (int sampleGroupNdx = 0; sampleGroupNdx < numSampleGroups; sampleGroupNdx++)
781	{
782		// The index of the fragment of the sample at the beginning of m_sampleRegisters.
783		int groupFirstFragNdx = (sampleGroupNdx*SAMPLE_REGISTER_SIZE) / numSamplesPerFragment;
784
785		// Initialize sample data in the sample register.
786
787		for (int regSampleNdx = 0; regSampleNdx < SAMPLE_REGISTER_SIZE; regSampleNdx++)
788		{
789			int fragNdx			= groupFirstFragNdx + regSampleNdx/numSamplesPerFragment;
790			int fragSampleNdx	= regSampleNdx % numSamplesPerFragment;
791
792			if (fragNdx < numFragments)
793			{
794				m_sampleRegister[regSampleNdx].isAlive		= (inputFragments[fragNdx].coverage & (1u << fragSampleNdx)) != 0;
795				m_sampleRegister[regSampleNdx].depthPassed	= true; // \note This will stay true if depth test is disabled.
796			}
797			else
798				m_sampleRegister[regSampleNdx].isAlive = false;
799		}
800
801		// Scissor test.
802
803		if (state.scissorTestEnabled)
804			executeScissorTest(groupFirstFragNdx, numSamplesPerFragment, inputFragments, state.scissorRectangle);
805
806		// Stencil test.
807
808		if (doStencilTest)
809		{
810			executeStencilCompare(groupFirstFragNdx, numSamplesPerFragment, inputFragments, stencilState, state.numStencilBits, stencilBuffer);
811			executeStencilSFail(groupFirstFragNdx, numSamplesPerFragment, inputFragments, stencilState, state.numStencilBits, stencilBuffer);
812		}
813
814		// Depth test.
815		// \note Current value of isAlive is needed for dpPass and dpFail, so it's only updated after them and not right after depth test.
816
817		if (doDepthTest)
818		{
819			executeDepthCompare(groupFirstFragNdx, numSamplesPerFragment, inputFragments, state.depthFunc, depthBuffer);
820
821			if (state.depthMask)
822				executeDepthWrite(groupFirstFragNdx, numSamplesPerFragment, inputFragments, depthBuffer);
823		}
824
825		// Do dpFail and dpPass stencil writes.
826
827		if (doStencilTest)
828			executeStencilDpFailAndPass(groupFirstFragNdx, numSamplesPerFragment, inputFragments, stencilState, state.numStencilBits, stencilBuffer);
829
830		// Kill the samples that failed depth test.
831
832		if (doDepthTest)
833		{
834			for (int regSampleNdx = 0; regSampleNdx < SAMPLE_REGISTER_SIZE; regSampleNdx++)
835				m_sampleRegister[regSampleNdx].isAlive = m_sampleRegister[regSampleNdx].isAlive && m_sampleRegister[regSampleNdx].depthPassed;
836		}
837
838		// Paint fragments to target
839
840		switch (fragmentDataType)
841		{
842			case rr::GENERICVECTYPE_FLOAT:
843				// Blend calculation - only if using blend.
844				if (state.blendMode == BLENDMODE_STANDARD)
845				{
846					// Put dst color to register, doing srgb-to-linear conversion if needed.
847					for (int regSampleNdx = 0; regSampleNdx < SAMPLE_REGISTER_SIZE; regSampleNdx++)
848					{
849						if (m_sampleRegister[regSampleNdx].isAlive)
850						{
851							int					fragSampleNdx	= regSampleNdx % numSamplesPerFragment;
852							const Fragment&		frag			= inputFragments[groupFirstFragNdx + regSampleNdx/numSamplesPerFragment];
853							Vec4				dstColor		= colorBuffer.getPixel(fragSampleNdx, frag.pixelCoord.x(), frag.pixelCoord.y());
854
855							m_sampleRegister[regSampleNdx].clampedBlendSrcColor		= clamp(frag.value.get<float>(), Vec4(0.0f), Vec4(1.0f));
856							m_sampleRegister[regSampleNdx].clampedBlendSrc1Color	= clamp(frag.value1.get<float>(), Vec4(0.0f), Vec4(1.0f));
857							m_sampleRegister[regSampleNdx].clampedBlendDstColor		= clamp(sRGBTarget ? tcu::sRGBToLinear(dstColor) : dstColor, Vec4(0.0f), Vec4(1.0f));
858						}
859					}
860
861					// Calculate blend factors to register.
862					executeBlendFactorComputeRGB(state.blendColor, state.blendRGBState);
863					executeBlendFactorComputeA(state.blendColor, state.blendAState);
864
865					// Compute blended color.
866					executeBlend(state.blendRGBState, state.blendAState);
867				}
868				else if (state.blendMode == BLENDMODE_ADVANCED)
869				{
870					// Unpremultiply colors for blending, and do sRGB->linear if necessary
871					// \todo [2014-03-17 pyry] Re-consider clampedBlend*Color var names
872					for (int regSampleNdx = 0; regSampleNdx < SAMPLE_REGISTER_SIZE; regSampleNdx++)
873					{
874						if (m_sampleRegister[regSampleNdx].isAlive)
875						{
876							int					fragSampleNdx	= regSampleNdx % numSamplesPerFragment;
877							const Fragment&		frag			= inputFragments[groupFirstFragNdx + regSampleNdx/numSamplesPerFragment];
878							const Vec4			srcColor		= frag.value.get<float>();
879							const Vec4			dstColor		= colorBuffer.getPixel(fragSampleNdx, frag.pixelCoord.x(), frag.pixelCoord.y());
880
881							m_sampleRegister[regSampleNdx].clampedBlendSrcColor		= unpremultiply(clamp(srcColor, Vec4(0.0f), Vec4(1.0f)));
882							m_sampleRegister[regSampleNdx].clampedBlendDstColor		= unpremultiply(clamp(sRGBTarget ? tcu::sRGBToLinear(dstColor) : dstColor, Vec4(0.0f), Vec4(1.0f)));
883						}
884					}
885
886					executeAdvancedBlend(state.blendEquationAdvaced);
887				}
888				else
889				{
890					// Not using blend - just put values to register as-is.
891					DE_ASSERT(state.blendMode == BLENDMODE_NONE);
892
893					for (int regSampleNdx = 0; regSampleNdx < SAMPLE_REGISTER_SIZE; regSampleNdx++)
894					{
895						if (m_sampleRegister[regSampleNdx].isAlive)
896						{
897							const Fragment& frag = inputFragments[groupFirstFragNdx + regSampleNdx/numSamplesPerFragment];
898
899							m_sampleRegister[regSampleNdx].blendedRGB	= frag.value.get<float>().xyz();
900							m_sampleRegister[regSampleNdx].blendedA		= frag.value.get<float>().w();
901						}
902					}
903				}
904
905				// Finally, write the colors to the color buffer.
906
907				if (state.colorMask[0] && state.colorMask[1] && state.colorMask[2] && state.colorMask[3])
908				{
909					if (colorBuffer.getFormat() == tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8))
910						executeRGBA8ColorWrite(groupFirstFragNdx, numSamplesPerFragment, inputFragments, colorBuffer);
911					else
912						executeColorWrite(groupFirstFragNdx, numSamplesPerFragment, inputFragments, sRGBTarget, colorBuffer);
913				}
914				else if (state.colorMask[0] || state.colorMask[1] || state.colorMask[2] || state.colorMask[3])
915					executeMaskedColorWrite(groupFirstFragNdx, numSamplesPerFragment, inputFragments, colorMaskFactor, colorMaskNegationFactor, sRGBTarget, colorBuffer);
916				break;
917
918			case rr::GENERICVECTYPE_INT32:
919				// Write fragments
920				for (int regSampleNdx = 0; regSampleNdx < SAMPLE_REGISTER_SIZE; regSampleNdx++)
921				{
922					if (m_sampleRegister[regSampleNdx].isAlive)
923					{
924						const Fragment& frag = inputFragments[groupFirstFragNdx + regSampleNdx/numSamplesPerFragment];
925
926						m_sampleRegister[regSampleNdx].signedValue = frag.value.get<deInt32>();
927					}
928				}
929
930				if (state.colorMask[0] || state.colorMask[1] || state.colorMask[2] || state.colorMask[3])
931					executeSignedValueWrite(groupFirstFragNdx, numSamplesPerFragment, inputFragments, state.colorMask, colorBuffer);
932				break;
933
934			case rr::GENERICVECTYPE_UINT32:
935				// Write fragments
936				for (int regSampleNdx = 0; regSampleNdx < SAMPLE_REGISTER_SIZE; regSampleNdx++)
937				{
938					if (m_sampleRegister[regSampleNdx].isAlive)
939					{
940						const Fragment& frag = inputFragments[groupFirstFragNdx + regSampleNdx/numSamplesPerFragment];
941
942						m_sampleRegister[regSampleNdx].unsignedValue = frag.value.get<deUint32>();
943					}
944				}
945
946				if (state.colorMask[0] || state.colorMask[1] || state.colorMask[2] || state.colorMask[3])
947					executeUnsignedValueWrite(groupFirstFragNdx, numSamplesPerFragment, inputFragments, state.colorMask, colorBuffer);
948				break;
949
950			default:
951				DE_ASSERT(DE_FALSE);
952		}
953	}
954}
955
956} // rr
957