1e5c31af7Sopenharmony_ci/*-------------------------------------------------------------------------
2e5c31af7Sopenharmony_ci * drawElements Quality Program Reference Renderer
3e5c31af7Sopenharmony_ci * -----------------------------------------------
4e5c31af7Sopenharmony_ci *
5e5c31af7Sopenharmony_ci * Copyright 2014 The Android Open Source Project
6e5c31af7Sopenharmony_ci *
7e5c31af7Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
8e5c31af7Sopenharmony_ci * you may not use this file except in compliance with the License.
9e5c31af7Sopenharmony_ci * You may obtain a copy of the License at
10e5c31af7Sopenharmony_ci *
11e5c31af7Sopenharmony_ci *      http://www.apache.org/licenses/LICENSE-2.0
12e5c31af7Sopenharmony_ci *
13e5c31af7Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
14e5c31af7Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
15e5c31af7Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16e5c31af7Sopenharmony_ci * See the License for the specific language governing permissions and
17e5c31af7Sopenharmony_ci * limitations under the License.
18e5c31af7Sopenharmony_ci *
19e5c31af7Sopenharmony_ci *//*!
20e5c31af7Sopenharmony_ci * \file
21e5c31af7Sopenharmony_ci * \brief Reference renderer interface.
22e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
23e5c31af7Sopenharmony_ci
24e5c31af7Sopenharmony_ci#include "rrRenderer.hpp"
25e5c31af7Sopenharmony_ci#include "tcuVectorUtil.hpp"
26e5c31af7Sopenharmony_ci#include "tcuTextureUtil.hpp"
27e5c31af7Sopenharmony_ci#include "tcuFloat.hpp"
28e5c31af7Sopenharmony_ci#include "rrPrimitiveAssembler.hpp"
29e5c31af7Sopenharmony_ci#include "rrFragmentOperations.hpp"
30e5c31af7Sopenharmony_ci#include "rrRasterizer.hpp"
31e5c31af7Sopenharmony_ci#include "deMemory.h"
32e5c31af7Sopenharmony_ci
33e5c31af7Sopenharmony_ci#include <set>
34e5c31af7Sopenharmony_ci#include <limits>
35e5c31af7Sopenharmony_ci
36e5c31af7Sopenharmony_cinamespace rr
37e5c31af7Sopenharmony_ci{
38e5c31af7Sopenharmony_cinamespace
39e5c31af7Sopenharmony_ci{
40e5c31af7Sopenharmony_ci
41e5c31af7Sopenharmony_citypedef double ClipFloat; // floating point type used in clipping
42e5c31af7Sopenharmony_ci
43e5c31af7Sopenharmony_citypedef tcu::Vector<ClipFloat, 4> ClipVec4;
44e5c31af7Sopenharmony_ci
45e5c31af7Sopenharmony_cistruct RasterizationInternalBuffers
46e5c31af7Sopenharmony_ci{
47e5c31af7Sopenharmony_ci	std::vector<FragmentPacket>		fragmentPackets;
48e5c31af7Sopenharmony_ci	std::vector<GenericVec4>		shaderOutputs;
49e5c31af7Sopenharmony_ci	std::vector<GenericVec4>		shaderOutputsSrc1;
50e5c31af7Sopenharmony_ci	std::vector<Fragment>			shadedFragments;
51e5c31af7Sopenharmony_ci	float*							fragmentDepthBuffer;
52e5c31af7Sopenharmony_ci};
53e5c31af7Sopenharmony_ci
54e5c31af7Sopenharmony_cideUint32 readIndexArray (const IndexType type, const void* ptr, size_t ndx)
55e5c31af7Sopenharmony_ci{
56e5c31af7Sopenharmony_ci	switch (type)
57e5c31af7Sopenharmony_ci	{
58e5c31af7Sopenharmony_ci		case INDEXTYPE_UINT8:
59e5c31af7Sopenharmony_ci			return ((const deUint8*)ptr)[ndx];
60e5c31af7Sopenharmony_ci
61e5c31af7Sopenharmony_ci		case INDEXTYPE_UINT16:
62e5c31af7Sopenharmony_ci		{
63e5c31af7Sopenharmony_ci			deUint16 retVal;
64e5c31af7Sopenharmony_ci			deMemcpy(&retVal, (const deUint8*)ptr + ndx * sizeof(deUint16), sizeof(deUint16));
65e5c31af7Sopenharmony_ci
66e5c31af7Sopenharmony_ci			return retVal;
67e5c31af7Sopenharmony_ci		}
68e5c31af7Sopenharmony_ci
69e5c31af7Sopenharmony_ci		case INDEXTYPE_UINT32:
70e5c31af7Sopenharmony_ci		{
71e5c31af7Sopenharmony_ci			deUint32 retVal;
72e5c31af7Sopenharmony_ci			deMemcpy(&retVal, (const deUint8*)ptr + ndx * sizeof(deUint32), sizeof(deUint32));
73e5c31af7Sopenharmony_ci
74e5c31af7Sopenharmony_ci			return retVal;
75e5c31af7Sopenharmony_ci		}
76e5c31af7Sopenharmony_ci
77e5c31af7Sopenharmony_ci		default:
78e5c31af7Sopenharmony_ci			DE_ASSERT(false);
79e5c31af7Sopenharmony_ci			return 0;
80e5c31af7Sopenharmony_ci	}
81e5c31af7Sopenharmony_ci}
82e5c31af7Sopenharmony_ci
83e5c31af7Sopenharmony_citcu::IVec4 getBufferSize (const rr::MultisampleConstPixelBufferAccess& multisampleBuffer)
84e5c31af7Sopenharmony_ci{
85e5c31af7Sopenharmony_ci	return tcu::IVec4(0, 0, multisampleBuffer.raw().getHeight(), multisampleBuffer.raw().getDepth());
86e5c31af7Sopenharmony_ci}
87e5c31af7Sopenharmony_ci
88e5c31af7Sopenharmony_cibool isEmpty (const rr::MultisampleConstPixelBufferAccess& access)
89e5c31af7Sopenharmony_ci{
90e5c31af7Sopenharmony_ci	return access.raw().getWidth() == 0 || access.raw().getHeight() == 0 || access.raw().getDepth() == 0;
91e5c31af7Sopenharmony_ci}
92e5c31af7Sopenharmony_ci
93e5c31af7Sopenharmony_cistruct DrawContext
94e5c31af7Sopenharmony_ci{
95e5c31af7Sopenharmony_ci	int primitiveID;
96e5c31af7Sopenharmony_ci
97e5c31af7Sopenharmony_ci	DrawContext (void)
98e5c31af7Sopenharmony_ci		: primitiveID(0)
99e5c31af7Sopenharmony_ci	{
100e5c31af7Sopenharmony_ci	}
101e5c31af7Sopenharmony_ci};
102e5c31af7Sopenharmony_ci
103e5c31af7Sopenharmony_ci/*--------------------------------------------------------------------*//*!
104e5c31af7Sopenharmony_ci * \brief Calculates intersection of two rects given as (left, bottom, width, height)
105e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
106e5c31af7Sopenharmony_citcu::IVec4 rectIntersection (const tcu::IVec4& a, const tcu::IVec4& b)
107e5c31af7Sopenharmony_ci{
108e5c31af7Sopenharmony_ci	const tcu::IVec2 pos	= tcu::IVec2(de::max(a.x(), b.x()), de::max(a.y(), b.y()));
109e5c31af7Sopenharmony_ci	const tcu::IVec2 endPos	= tcu::IVec2(de::min(a.x() + a.z(), b.x() + b.z()), de::min(a.y() + a.w(), b.y() + b.w()));
110e5c31af7Sopenharmony_ci
111e5c31af7Sopenharmony_ci	return tcu::IVec4(pos.x(), pos.y(), endPos.x() - pos.x(), endPos.y() - pos.y());
112e5c31af7Sopenharmony_ci}
113e5c31af7Sopenharmony_ci
114e5c31af7Sopenharmony_civoid convertPrimitiveToBaseType(std::vector<pa::Triangle>& output, std::vector<pa::Triangle>& input)
115e5c31af7Sopenharmony_ci{
116e5c31af7Sopenharmony_ci	std::swap(output, input);
117e5c31af7Sopenharmony_ci}
118e5c31af7Sopenharmony_ci
119e5c31af7Sopenharmony_civoid convertPrimitiveToBaseType(std::vector<pa::Line>& output, std::vector<pa::Line>& input)
120e5c31af7Sopenharmony_ci{
121e5c31af7Sopenharmony_ci	std::swap(output, input);
122e5c31af7Sopenharmony_ci}
123e5c31af7Sopenharmony_ci
124e5c31af7Sopenharmony_civoid convertPrimitiveToBaseType(std::vector<pa::Point>& output, std::vector<pa::Point>& input)
125e5c31af7Sopenharmony_ci{
126e5c31af7Sopenharmony_ci	std::swap(output, input);
127e5c31af7Sopenharmony_ci}
128e5c31af7Sopenharmony_ci
129e5c31af7Sopenharmony_civoid convertPrimitiveToBaseType(std::vector<pa::Line>& output, std::vector<pa::LineAdjacency>& input)
130e5c31af7Sopenharmony_ci{
131e5c31af7Sopenharmony_ci	output.resize(input.size());
132e5c31af7Sopenharmony_ci	for (size_t i = 0; i < input.size(); ++i)
133e5c31af7Sopenharmony_ci	{
134e5c31af7Sopenharmony_ci		const int adjacentProvokingVertex	= input[i].provokingIndex;
135e5c31af7Sopenharmony_ci		const int baseProvokingVertexIndex	= adjacentProvokingVertex-1;
136e5c31af7Sopenharmony_ci		output[i] = pa::Line(input[i].v1, input[i].v2, baseProvokingVertexIndex);
137e5c31af7Sopenharmony_ci	}
138e5c31af7Sopenharmony_ci}
139e5c31af7Sopenharmony_ci
140e5c31af7Sopenharmony_civoid convertPrimitiveToBaseType(std::vector<pa::Triangle>& output, std::vector<pa::TriangleAdjacency>& input)
141e5c31af7Sopenharmony_ci{
142e5c31af7Sopenharmony_ci	output.resize(input.size());
143e5c31af7Sopenharmony_ci	for (size_t i = 0; i < input.size(); ++i)
144e5c31af7Sopenharmony_ci	{
145e5c31af7Sopenharmony_ci		const int adjacentProvokingVertex	= input[i].provokingIndex;
146e5c31af7Sopenharmony_ci		const int baseProvokingVertexIndex	= adjacentProvokingVertex/2;
147e5c31af7Sopenharmony_ci		output[i] = pa::Triangle(input[i].v0, input[i].v2, input[i].v4, baseProvokingVertexIndex);
148e5c31af7Sopenharmony_ci	}
149e5c31af7Sopenharmony_ci}
150e5c31af7Sopenharmony_ci
151e5c31af7Sopenharmony_cinamespace cliputil
152e5c31af7Sopenharmony_ci{
153e5c31af7Sopenharmony_ci
154e5c31af7Sopenharmony_ci/*--------------------------------------------------------------------*//*!
155e5c31af7Sopenharmony_ci * \brief Get clipped portion of the second endpoint
156e5c31af7Sopenharmony_ci *
157e5c31af7Sopenharmony_ci * Calculate the intersection of line segment v0-v1 and a given plane. Line
158e5c31af7Sopenharmony_ci * segment is defined by a pair of one-dimensional homogeneous coordinates.
159e5c31af7Sopenharmony_ci *
160e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
161e5c31af7Sopenharmony_ciClipFloat getSegmentVolumeEdgeClip (const ClipFloat v0,
162e5c31af7Sopenharmony_ci									const ClipFloat w0,
163e5c31af7Sopenharmony_ci									const ClipFloat v1,
164e5c31af7Sopenharmony_ci									const ClipFloat w1,
165e5c31af7Sopenharmony_ci									const ClipFloat plane)
166e5c31af7Sopenharmony_ci{
167e5c31af7Sopenharmony_ci	// The +epsilon avoids division by zero without causing a meaningful change in the calculation.
168e5c31af7Sopenharmony_ci	// Fixes divide by zero in builds when using the gcc toolset.
169e5c31af7Sopenharmony_ci	return (plane*w0 - v0) / ((v1 - v0) - plane*(w1 - w0) + std::numeric_limits<ClipFloat>::epsilon());
170e5c31af7Sopenharmony_ci}
171e5c31af7Sopenharmony_ci
172e5c31af7Sopenharmony_ci/*--------------------------------------------------------------------*//*!
173e5c31af7Sopenharmony_ci * \brief Get clipped portion of the endpoint
174e5c31af7Sopenharmony_ci *
175e5c31af7Sopenharmony_ci * How much (in [0-1] range) of a line segment v0-v1 would be clipped
176e5c31af7Sopenharmony_ci * of the v0 end of the line segment by clipping.
177e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
178e5c31af7Sopenharmony_ciClipFloat getLineEndpointClipping (const ClipVec4& v0, const ClipVec4& v1)
179e5c31af7Sopenharmony_ci{
180e5c31af7Sopenharmony_ci	const ClipFloat clipVolumeSize = (ClipFloat)1.0;
181e5c31af7Sopenharmony_ci
182e5c31af7Sopenharmony_ci	if (v0.z() > v0.w())
183e5c31af7Sopenharmony_ci	{
184e5c31af7Sopenharmony_ci		// Clip +Z
185e5c31af7Sopenharmony_ci		return getSegmentVolumeEdgeClip(v0.z(), v0.w(), v1.z(), v1.w(), clipVolumeSize);
186e5c31af7Sopenharmony_ci	}
187e5c31af7Sopenharmony_ci	else if (v0.z() < -v0.w())
188e5c31af7Sopenharmony_ci	{
189e5c31af7Sopenharmony_ci		// Clip -Z
190e5c31af7Sopenharmony_ci		return getSegmentVolumeEdgeClip(v0.z(), v0.w(), v1.z(), v1.w(), -clipVolumeSize);
191e5c31af7Sopenharmony_ci	}
192e5c31af7Sopenharmony_ci	else
193e5c31af7Sopenharmony_ci	{
194e5c31af7Sopenharmony_ci		// no clipping
195e5c31af7Sopenharmony_ci		return (ClipFloat)0.0;
196e5c31af7Sopenharmony_ci	}
197e5c31af7Sopenharmony_ci}
198e5c31af7Sopenharmony_ci
199e5c31af7Sopenharmony_ciClipVec4 vec4ToClipVec4 (const tcu::Vec4& v)
200e5c31af7Sopenharmony_ci{
201e5c31af7Sopenharmony_ci	return ClipVec4((ClipFloat)v.x(), (ClipFloat)v.y(), (ClipFloat)v.z(), (ClipFloat)v.w());
202e5c31af7Sopenharmony_ci}
203e5c31af7Sopenharmony_ci
204e5c31af7Sopenharmony_citcu::Vec4 clipVec4ToVec4 (const ClipVec4& v)
205e5c31af7Sopenharmony_ci{
206e5c31af7Sopenharmony_ci	return tcu::Vec4((float)v.x(), (float)v.y(), (float)v.z(), (float)v.w());
207e5c31af7Sopenharmony_ci}
208e5c31af7Sopenharmony_ci
209e5c31af7Sopenharmony_ciclass ClipVolumePlane
210e5c31af7Sopenharmony_ci{
211e5c31af7Sopenharmony_cipublic:
212e5c31af7Sopenharmony_ci	virtual bool		pointInClipVolume			(const ClipVec4& p) const						= 0;
213e5c31af7Sopenharmony_ci	virtual ClipFloat	clipLineSegmentEnd			(const ClipVec4& v0, const ClipVec4& v1) const	= 0;
214e5c31af7Sopenharmony_ci	virtual ClipVec4	getLineIntersectionPoint	(const ClipVec4& v0, const ClipVec4& v1) const	= 0;
215e5c31af7Sopenharmony_ci};
216e5c31af7Sopenharmony_ci
217e5c31af7Sopenharmony_citemplate <int Sign, int CompNdx>
218e5c31af7Sopenharmony_ciclass ComponentPlane : public ClipVolumePlane
219e5c31af7Sopenharmony_ci{
220e5c31af7Sopenharmony_ci	DE_STATIC_ASSERT(Sign == +1 || Sign == -1);
221e5c31af7Sopenharmony_ci
222e5c31af7Sopenharmony_cipublic:
223e5c31af7Sopenharmony_ci	bool		pointInClipVolume			(const ClipVec4& p) const;
224e5c31af7Sopenharmony_ci	ClipFloat	clipLineSegmentEnd			(const ClipVec4& v0, const ClipVec4& v1) const;
225e5c31af7Sopenharmony_ci	ClipVec4	getLineIntersectionPoint	(const ClipVec4& v0, const ClipVec4& v1) const;
226e5c31af7Sopenharmony_ci};
227e5c31af7Sopenharmony_ci
228e5c31af7Sopenharmony_citemplate <int Sign, int CompNdx>
229e5c31af7Sopenharmony_cibool ComponentPlane<Sign, CompNdx>::pointInClipVolume (const ClipVec4& p) const
230e5c31af7Sopenharmony_ci{
231e5c31af7Sopenharmony_ci	const ClipFloat clipVolumeSize = (ClipFloat)1.0;
232e5c31af7Sopenharmony_ci
233e5c31af7Sopenharmony_ci	return (ClipFloat)(Sign * p[CompNdx]) <= clipVolumeSize * p.w();
234e5c31af7Sopenharmony_ci}
235e5c31af7Sopenharmony_ci
236e5c31af7Sopenharmony_citemplate <int Sign, int CompNdx>
237e5c31af7Sopenharmony_ciClipFloat ComponentPlane<Sign, CompNdx>::clipLineSegmentEnd (const ClipVec4& v0, const ClipVec4& v1) const
238e5c31af7Sopenharmony_ci{
239e5c31af7Sopenharmony_ci	const ClipFloat clipVolumeSize = (ClipFloat)1.0;
240e5c31af7Sopenharmony_ci
241e5c31af7Sopenharmony_ci	return getSegmentVolumeEdgeClip(v0[CompNdx], v0.w(),
242e5c31af7Sopenharmony_ci									v1[CompNdx], v1.w(),
243e5c31af7Sopenharmony_ci									(ClipFloat)Sign * clipVolumeSize);
244e5c31af7Sopenharmony_ci}
245e5c31af7Sopenharmony_ci
246e5c31af7Sopenharmony_citemplate <int Sign, int CompNdx>
247e5c31af7Sopenharmony_ciClipVec4 ComponentPlane<Sign, CompNdx>::getLineIntersectionPoint (const ClipVec4& v0, const ClipVec4& v1) const
248e5c31af7Sopenharmony_ci{
249e5c31af7Sopenharmony_ci	// A point on line might be far away, causing clipping ratio (clipLineSegmentEnd) to become extremely close to 1.0
250e5c31af7Sopenharmony_ci	// even if the another point is not on the plane. Prevent clipping ratio from saturating by using points on line
251e5c31af7Sopenharmony_ci	// that are (nearly) on this and (nearly) on the opposite plane.
252e5c31af7Sopenharmony_ci
253e5c31af7Sopenharmony_ci	const ClipVec4	clippedV0	= tcu::mix(v0, v1, ComponentPlane<+1, CompNdx>().clipLineSegmentEnd(v0, v1));
254e5c31af7Sopenharmony_ci	const ClipVec4	clippedV1	= tcu::mix(v0, v1, ComponentPlane<-1, CompNdx>().clipLineSegmentEnd(v0, v1));
255e5c31af7Sopenharmony_ci	const ClipFloat	clipRatio	= clipLineSegmentEnd(clippedV0, clippedV1);
256e5c31af7Sopenharmony_ci
257e5c31af7Sopenharmony_ci	// Find intersection point of line from v0 to v1 and the current plane. Avoid ratios near 1.0
258e5c31af7Sopenharmony_ci	if (clipRatio <= (ClipFloat)0.5)
259e5c31af7Sopenharmony_ci		return tcu::mix(clippedV0, clippedV1, clipRatio);
260e5c31af7Sopenharmony_ci	else
261e5c31af7Sopenharmony_ci	{
262e5c31af7Sopenharmony_ci		const ClipFloat complementClipRatio = clipLineSegmentEnd(clippedV1, clippedV0);
263e5c31af7Sopenharmony_ci		return tcu::mix(clippedV1, clippedV0, complementClipRatio);
264e5c31af7Sopenharmony_ci	}
265e5c31af7Sopenharmony_ci}
266e5c31af7Sopenharmony_ci
267e5c31af7Sopenharmony_cistruct TriangleVertex
268e5c31af7Sopenharmony_ci{
269e5c31af7Sopenharmony_ci	ClipVec4	position;
270e5c31af7Sopenharmony_ci	ClipFloat	weight[3];		//!< barycentrics
271e5c31af7Sopenharmony_ci};
272e5c31af7Sopenharmony_ci
273e5c31af7Sopenharmony_cistruct SubTriangle
274e5c31af7Sopenharmony_ci{
275e5c31af7Sopenharmony_ci	TriangleVertex vertices[3];
276e5c31af7Sopenharmony_ci};
277e5c31af7Sopenharmony_ci
278e5c31af7Sopenharmony_civoid clipTriangleOneVertex (std::vector<TriangleVertex>& clippedEdges, const ClipVolumePlane& plane, const TriangleVertex& clipped, const TriangleVertex& v1, const TriangleVertex& v2)
279e5c31af7Sopenharmony_ci{
280e5c31af7Sopenharmony_ci	const ClipFloat	degenerateLimit = (ClipFloat)1.0;
281e5c31af7Sopenharmony_ci
282e5c31af7Sopenharmony_ci	// calc clip pos
283e5c31af7Sopenharmony_ci	TriangleVertex	mid1;
284e5c31af7Sopenharmony_ci	TriangleVertex	mid2;
285e5c31af7Sopenharmony_ci	bool			outputDegenerate = false;
286e5c31af7Sopenharmony_ci
287e5c31af7Sopenharmony_ci	{
288e5c31af7Sopenharmony_ci		const TriangleVertex&	inside	= v1;
289e5c31af7Sopenharmony_ci		const TriangleVertex&	outside	= clipped;
290e5c31af7Sopenharmony_ci		      TriangleVertex&	middle	= mid1;
291e5c31af7Sopenharmony_ci
292e5c31af7Sopenharmony_ci		const ClipFloat			hitDist	= plane.clipLineSegmentEnd(inside.position, outside.position);
293e5c31af7Sopenharmony_ci
294e5c31af7Sopenharmony_ci		if (hitDist >= degenerateLimit)
295e5c31af7Sopenharmony_ci		{
296e5c31af7Sopenharmony_ci			// do not generate degenerate triangles
297e5c31af7Sopenharmony_ci			outputDegenerate = true;
298e5c31af7Sopenharmony_ci		}
299e5c31af7Sopenharmony_ci		else
300e5c31af7Sopenharmony_ci		{
301e5c31af7Sopenharmony_ci			const ClipVec4 approximatedClipPoint	= tcu::mix(inside.position, outside.position, hitDist);
302e5c31af7Sopenharmony_ci			const ClipVec4 anotherPointOnLine		= (hitDist > (ClipFloat)0.5) ? (inside.position) : (outside.position);
303e5c31af7Sopenharmony_ci
304e5c31af7Sopenharmony_ci			middle.position = plane.getLineIntersectionPoint(approximatedClipPoint, anotherPointOnLine);
305e5c31af7Sopenharmony_ci			middle.weight[0] = tcu::mix(inside.weight[0], outside.weight[0], hitDist);
306e5c31af7Sopenharmony_ci			middle.weight[1] = tcu::mix(inside.weight[1], outside.weight[1], hitDist);
307e5c31af7Sopenharmony_ci			middle.weight[2] = tcu::mix(inside.weight[2], outside.weight[2], hitDist);
308e5c31af7Sopenharmony_ci		}
309e5c31af7Sopenharmony_ci	}
310e5c31af7Sopenharmony_ci
311e5c31af7Sopenharmony_ci	{
312e5c31af7Sopenharmony_ci		const TriangleVertex&	inside	= v2;
313e5c31af7Sopenharmony_ci		const TriangleVertex&	outside	= clipped;
314e5c31af7Sopenharmony_ci		      TriangleVertex&	middle	= mid2;
315e5c31af7Sopenharmony_ci
316e5c31af7Sopenharmony_ci		const ClipFloat			hitDist	= plane.clipLineSegmentEnd(inside.position, outside.position);
317e5c31af7Sopenharmony_ci
318e5c31af7Sopenharmony_ci		if (hitDist >= degenerateLimit)
319e5c31af7Sopenharmony_ci		{
320e5c31af7Sopenharmony_ci			// do not generate degenerate triangles
321e5c31af7Sopenharmony_ci			outputDegenerate = true;
322e5c31af7Sopenharmony_ci		}
323e5c31af7Sopenharmony_ci		else
324e5c31af7Sopenharmony_ci		{
325e5c31af7Sopenharmony_ci			const ClipVec4 approximatedClipPoint	= tcu::mix(inside.position, outside.position, hitDist);
326e5c31af7Sopenharmony_ci			const ClipVec4 anotherPointOnLine		= (hitDist > (ClipFloat)0.5) ? (inside.position) : (outside.position);
327e5c31af7Sopenharmony_ci
328e5c31af7Sopenharmony_ci			middle.position = plane.getLineIntersectionPoint(approximatedClipPoint, anotherPointOnLine);
329e5c31af7Sopenharmony_ci			middle.weight[0] = tcu::mix(inside.weight[0], outside.weight[0], hitDist);
330e5c31af7Sopenharmony_ci			middle.weight[1] = tcu::mix(inside.weight[1], outside.weight[1], hitDist);
331e5c31af7Sopenharmony_ci			middle.weight[2] = tcu::mix(inside.weight[2], outside.weight[2], hitDist);
332e5c31af7Sopenharmony_ci		}
333e5c31af7Sopenharmony_ci	}
334e5c31af7Sopenharmony_ci
335e5c31af7Sopenharmony_ci	if (!outputDegenerate)
336e5c31af7Sopenharmony_ci	{
337e5c31af7Sopenharmony_ci		// gen quad (v1) -> mid1 -> mid2 -> (v2)
338e5c31af7Sopenharmony_ci		clippedEdges.push_back(v1);
339e5c31af7Sopenharmony_ci		clippedEdges.push_back(mid1);
340e5c31af7Sopenharmony_ci		clippedEdges.push_back(mid2);
341e5c31af7Sopenharmony_ci		clippedEdges.push_back(v2);
342e5c31af7Sopenharmony_ci	}
343e5c31af7Sopenharmony_ci	else
344e5c31af7Sopenharmony_ci	{
345e5c31af7Sopenharmony_ci		// don't modify
346e5c31af7Sopenharmony_ci		clippedEdges.push_back(v1);
347e5c31af7Sopenharmony_ci		clippedEdges.push_back(clipped);
348e5c31af7Sopenharmony_ci		clippedEdges.push_back(v2);
349e5c31af7Sopenharmony_ci	}
350e5c31af7Sopenharmony_ci}
351e5c31af7Sopenharmony_ci
352e5c31af7Sopenharmony_civoid clipTriangleTwoVertices (std::vector<TriangleVertex>& clippedEdges, const ClipVolumePlane& plane, const TriangleVertex& v0, const TriangleVertex& clipped1, const TriangleVertex& clipped2)
353e5c31af7Sopenharmony_ci{
354e5c31af7Sopenharmony_ci	const ClipFloat	unclippableLimit = (ClipFloat)1.0;
355e5c31af7Sopenharmony_ci
356e5c31af7Sopenharmony_ci	// calc clip pos
357e5c31af7Sopenharmony_ci	TriangleVertex	mid1;
358e5c31af7Sopenharmony_ci	TriangleVertex	mid2;
359e5c31af7Sopenharmony_ci	bool			unclippableVertex1 = false;
360e5c31af7Sopenharmony_ci	bool			unclippableVertex2 = false;
361e5c31af7Sopenharmony_ci
362e5c31af7Sopenharmony_ci	{
363e5c31af7Sopenharmony_ci		const TriangleVertex&	inside	= v0;
364e5c31af7Sopenharmony_ci		const TriangleVertex&	outside	= clipped1;
365e5c31af7Sopenharmony_ci		      TriangleVertex&	middle	= mid1;
366e5c31af7Sopenharmony_ci
367e5c31af7Sopenharmony_ci		const ClipFloat			hitDist	= plane.clipLineSegmentEnd(inside.position, outside.position);
368e5c31af7Sopenharmony_ci
369e5c31af7Sopenharmony_ci		if (hitDist >= unclippableLimit)
370e5c31af7Sopenharmony_ci		{
371e5c31af7Sopenharmony_ci			// this edge cannot be clipped because the edge is really close to the volume boundary
372e5c31af7Sopenharmony_ci			unclippableVertex1 = true;
373e5c31af7Sopenharmony_ci		}
374e5c31af7Sopenharmony_ci		else
375e5c31af7Sopenharmony_ci		{
376e5c31af7Sopenharmony_ci			const ClipVec4 approximatedClipPoint	= tcu::mix(inside.position, outside.position, hitDist);
377e5c31af7Sopenharmony_ci			const ClipVec4 anotherPointOnLine		= (hitDist > (ClipFloat)0.5) ? (inside.position) : (outside.position);
378e5c31af7Sopenharmony_ci
379e5c31af7Sopenharmony_ci			middle.position = plane.getLineIntersectionPoint(approximatedClipPoint, anotherPointOnLine);
380e5c31af7Sopenharmony_ci			middle.weight[0] = tcu::mix(inside.weight[0], outside.weight[0], hitDist);
381e5c31af7Sopenharmony_ci			middle.weight[1] = tcu::mix(inside.weight[1], outside.weight[1], hitDist);
382e5c31af7Sopenharmony_ci			middle.weight[2] = tcu::mix(inside.weight[2], outside.weight[2], hitDist);
383e5c31af7Sopenharmony_ci		}
384e5c31af7Sopenharmony_ci	}
385e5c31af7Sopenharmony_ci
386e5c31af7Sopenharmony_ci	{
387e5c31af7Sopenharmony_ci		const TriangleVertex&	inside	= v0;
388e5c31af7Sopenharmony_ci		const TriangleVertex&	outside	= clipped2;
389e5c31af7Sopenharmony_ci		      TriangleVertex&	middle	= mid2;
390e5c31af7Sopenharmony_ci
391e5c31af7Sopenharmony_ci		const ClipFloat			hitDist	= plane.clipLineSegmentEnd(inside.position, outside.position);
392e5c31af7Sopenharmony_ci
393e5c31af7Sopenharmony_ci		if (hitDist >= unclippableLimit)
394e5c31af7Sopenharmony_ci		{
395e5c31af7Sopenharmony_ci			// this edge cannot be clipped because the edge is really close to the volume boundary
396e5c31af7Sopenharmony_ci			unclippableVertex2 = true;
397e5c31af7Sopenharmony_ci		}
398e5c31af7Sopenharmony_ci		else
399e5c31af7Sopenharmony_ci		{
400e5c31af7Sopenharmony_ci			const ClipVec4 approximatedClipPoint	= tcu::mix(inside.position, outside.position, hitDist);
401e5c31af7Sopenharmony_ci			const ClipVec4 anotherPointOnLine		= (hitDist > (ClipFloat)0.5) ? (inside.position) : (outside.position);
402e5c31af7Sopenharmony_ci
403e5c31af7Sopenharmony_ci			middle.position = plane.getLineIntersectionPoint(approximatedClipPoint, anotherPointOnLine);
404e5c31af7Sopenharmony_ci			middle.weight[0] = tcu::mix(inside.weight[0], outside.weight[0], hitDist);
405e5c31af7Sopenharmony_ci			middle.weight[1] = tcu::mix(inside.weight[1], outside.weight[1], hitDist);
406e5c31af7Sopenharmony_ci			middle.weight[2] = tcu::mix(inside.weight[2], outside.weight[2], hitDist);
407e5c31af7Sopenharmony_ci		}
408e5c31af7Sopenharmony_ci	}
409e5c31af7Sopenharmony_ci
410e5c31af7Sopenharmony_ci	if (!unclippableVertex1 && !unclippableVertex2)
411e5c31af7Sopenharmony_ci	{
412e5c31af7Sopenharmony_ci		// gen triangle (v0) -> mid1 -> mid2
413e5c31af7Sopenharmony_ci		clippedEdges.push_back(v0);
414e5c31af7Sopenharmony_ci		clippedEdges.push_back(mid1);
415e5c31af7Sopenharmony_ci		clippedEdges.push_back(mid2);
416e5c31af7Sopenharmony_ci	}
417e5c31af7Sopenharmony_ci	else if (!unclippableVertex1 && unclippableVertex2)
418e5c31af7Sopenharmony_ci	{
419e5c31af7Sopenharmony_ci		// clip just vertex 1
420e5c31af7Sopenharmony_ci		clippedEdges.push_back(v0);
421e5c31af7Sopenharmony_ci		clippedEdges.push_back(mid1);
422e5c31af7Sopenharmony_ci		clippedEdges.push_back(clipped2);
423e5c31af7Sopenharmony_ci	}
424e5c31af7Sopenharmony_ci	else if (unclippableVertex1 && !unclippableVertex2)
425e5c31af7Sopenharmony_ci	{
426e5c31af7Sopenharmony_ci		// clip just vertex 2
427e5c31af7Sopenharmony_ci		clippedEdges.push_back(v0);
428e5c31af7Sopenharmony_ci		clippedEdges.push_back(clipped1);
429e5c31af7Sopenharmony_ci		clippedEdges.push_back(mid2);
430e5c31af7Sopenharmony_ci	}
431e5c31af7Sopenharmony_ci	else
432e5c31af7Sopenharmony_ci	{
433e5c31af7Sopenharmony_ci		// don't modify
434e5c31af7Sopenharmony_ci		clippedEdges.push_back(v0);
435e5c31af7Sopenharmony_ci		clippedEdges.push_back(clipped1);
436e5c31af7Sopenharmony_ci		clippedEdges.push_back(clipped2);
437e5c31af7Sopenharmony_ci	}
438e5c31af7Sopenharmony_ci}
439e5c31af7Sopenharmony_ci
440e5c31af7Sopenharmony_civoid clipTriangleToPlane (std::vector<TriangleVertex>& clippedEdges, const TriangleVertex* vertices, const ClipVolumePlane& plane)
441e5c31af7Sopenharmony_ci{
442e5c31af7Sopenharmony_ci	const bool v0Clipped = !plane.pointInClipVolume(vertices[0].position);
443e5c31af7Sopenharmony_ci	const bool v1Clipped = !plane.pointInClipVolume(vertices[1].position);
444e5c31af7Sopenharmony_ci	const bool v2Clipped = !plane.pointInClipVolume(vertices[2].position);
445e5c31af7Sopenharmony_ci	const int  clipCount = ((v0Clipped) ? (1) : (0)) + ((v1Clipped) ? (1) : (0)) + ((v2Clipped) ? (1) : (0));
446e5c31af7Sopenharmony_ci
447e5c31af7Sopenharmony_ci	if (clipCount == 0)
448e5c31af7Sopenharmony_ci	{
449e5c31af7Sopenharmony_ci		// pass
450e5c31af7Sopenharmony_ci		clippedEdges.insert(clippedEdges.begin(), vertices, vertices + 3);
451e5c31af7Sopenharmony_ci	}
452e5c31af7Sopenharmony_ci	else if (clipCount == 1)
453e5c31af7Sopenharmony_ci	{
454e5c31af7Sopenharmony_ci		// clip one vertex
455e5c31af7Sopenharmony_ci		if (v0Clipped)			clipTriangleOneVertex(clippedEdges, plane, vertices[0], vertices[1], vertices[2]);
456e5c31af7Sopenharmony_ci		else if (v1Clipped)		clipTriangleOneVertex(clippedEdges, plane, vertices[1], vertices[2], vertices[0]);
457e5c31af7Sopenharmony_ci		else					clipTriangleOneVertex(clippedEdges, plane, vertices[2], vertices[0], vertices[1]);
458e5c31af7Sopenharmony_ci	}
459e5c31af7Sopenharmony_ci	else if (clipCount == 2)
460e5c31af7Sopenharmony_ci	{
461e5c31af7Sopenharmony_ci		// clip two vertices
462e5c31af7Sopenharmony_ci		if (!v0Clipped)			clipTriangleTwoVertices(clippedEdges, plane, vertices[0], vertices[1], vertices[2]);
463e5c31af7Sopenharmony_ci		else if (!v1Clipped)	clipTriangleTwoVertices(clippedEdges, plane, vertices[1], vertices[2], vertices[0]);
464e5c31af7Sopenharmony_ci		else					clipTriangleTwoVertices(clippedEdges, plane, vertices[2], vertices[0], vertices[1]);
465e5c31af7Sopenharmony_ci	}
466e5c31af7Sopenharmony_ci	else if (clipCount == 3)
467e5c31af7Sopenharmony_ci	{
468e5c31af7Sopenharmony_ci		// discard
469e5c31af7Sopenharmony_ci	}
470e5c31af7Sopenharmony_ci	else
471e5c31af7Sopenharmony_ci	{
472e5c31af7Sopenharmony_ci		DE_ASSERT(DE_FALSE);
473e5c31af7Sopenharmony_ci	}
474e5c31af7Sopenharmony_ci}
475e5c31af7Sopenharmony_ci
476e5c31af7Sopenharmony_ci} // cliputil
477e5c31af7Sopenharmony_ci
478e5c31af7Sopenharmony_citcu::Vec2 to2DCartesian (const tcu::Vec4& p)
479e5c31af7Sopenharmony_ci{
480e5c31af7Sopenharmony_ci	return tcu::Vec2(p.x(), p.y()) / p.w();
481e5c31af7Sopenharmony_ci}
482e5c31af7Sopenharmony_ci
483e5c31af7Sopenharmony_cifloat cross2D (const tcu::Vec2& a, const tcu::Vec2& b)
484e5c31af7Sopenharmony_ci{
485e5c31af7Sopenharmony_ci	return tcu::cross(tcu::Vec3(a.x(), a.y(), 0.0f), tcu::Vec3(b.x(), b.y(), 0.0f)).z();
486e5c31af7Sopenharmony_ci}
487e5c31af7Sopenharmony_ci
488e5c31af7Sopenharmony_civoid flatshadePrimitiveVertices (pa::Triangle& target, size_t outputNdx)
489e5c31af7Sopenharmony_ci{
490e5c31af7Sopenharmony_ci	const rr::GenericVec4 flatValue = target.getProvokingVertex()->outputs[outputNdx];
491e5c31af7Sopenharmony_ci	target.v0->outputs[outputNdx] = flatValue;
492e5c31af7Sopenharmony_ci	target.v1->outputs[outputNdx] = flatValue;
493e5c31af7Sopenharmony_ci	target.v2->outputs[outputNdx] = flatValue;
494e5c31af7Sopenharmony_ci}
495e5c31af7Sopenharmony_ci
496e5c31af7Sopenharmony_civoid flatshadePrimitiveVertices (pa::Line& target, size_t outputNdx)
497e5c31af7Sopenharmony_ci{
498e5c31af7Sopenharmony_ci	const rr::GenericVec4 flatValue = target.getProvokingVertex()->outputs[outputNdx];
499e5c31af7Sopenharmony_ci	target.v0->outputs[outputNdx] = flatValue;
500e5c31af7Sopenharmony_ci	target.v1->outputs[outputNdx] = flatValue;
501e5c31af7Sopenharmony_ci}
502e5c31af7Sopenharmony_ci
503e5c31af7Sopenharmony_civoid flatshadePrimitiveVertices (pa::Point& target, size_t outputNdx)
504e5c31af7Sopenharmony_ci{
505e5c31af7Sopenharmony_ci	DE_UNREF(target);
506e5c31af7Sopenharmony_ci	DE_UNREF(outputNdx);
507e5c31af7Sopenharmony_ci}
508e5c31af7Sopenharmony_ci
509e5c31af7Sopenharmony_citemplate <typename ContainerType>
510e5c31af7Sopenharmony_civoid flatshadeVertices (const Program& program, ContainerType& list)
511e5c31af7Sopenharmony_ci{
512e5c31af7Sopenharmony_ci	// flatshade
513e5c31af7Sopenharmony_ci	const std::vector<rr::VertexVaryingInfo>& fragInputs = (program.geometryShader) ? (program.geometryShader->getOutputs()) : (program.vertexShader->getOutputs());
514e5c31af7Sopenharmony_ci
515e5c31af7Sopenharmony_ci	for (size_t inputNdx = 0; inputNdx < fragInputs.size(); ++inputNdx)
516e5c31af7Sopenharmony_ci		if (fragInputs[inputNdx].flatshade)
517e5c31af7Sopenharmony_ci			for (typename ContainerType::iterator it = list.begin(); it != list.end(); ++it)
518e5c31af7Sopenharmony_ci				flatshadePrimitiveVertices(*it, inputNdx);
519e5c31af7Sopenharmony_ci}
520e5c31af7Sopenharmony_ci
521e5c31af7Sopenharmony_ci/*--------------------------------------------------------------------*//*!
522e5c31af7Sopenharmony_ci * Clip triangles to the clip volume.
523e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
524e5c31af7Sopenharmony_civoid clipPrimitives (std::vector<pa::Triangle>&		list,
525e5c31af7Sopenharmony_ci					 const Program&					program,
526e5c31af7Sopenharmony_ci					 bool							clipWithZPlanes,
527e5c31af7Sopenharmony_ci					 VertexPacketAllocator&			vpalloc)
528e5c31af7Sopenharmony_ci{
529e5c31af7Sopenharmony_ci	using namespace cliputil;
530e5c31af7Sopenharmony_ci
531e5c31af7Sopenharmony_ci	cliputil::ComponentPlane<+1, 0> clipPosX;
532e5c31af7Sopenharmony_ci	cliputil::ComponentPlane<-1, 0> clipNegX;
533e5c31af7Sopenharmony_ci	cliputil::ComponentPlane<+1, 1> clipPosY;
534e5c31af7Sopenharmony_ci	cliputil::ComponentPlane<-1, 1> clipNegY;
535e5c31af7Sopenharmony_ci	cliputil::ComponentPlane<+1, 2> clipPosZ;
536e5c31af7Sopenharmony_ci	cliputil::ComponentPlane<-1, 2> clipNegZ;
537e5c31af7Sopenharmony_ci
538e5c31af7Sopenharmony_ci	const std::vector<rr::VertexVaryingInfo>&	fragInputs			= (program.geometryShader) ? (program.geometryShader->getOutputs()) : (program.vertexShader->getOutputs());
539e5c31af7Sopenharmony_ci	const ClipVolumePlane*						planes[]			= { &clipPosX, &clipNegX, &clipPosY, &clipNegY, &clipPosZ, &clipNegZ };
540e5c31af7Sopenharmony_ci	const int									numPlanes			= (clipWithZPlanes) ? (6) : (4);
541e5c31af7Sopenharmony_ci
542e5c31af7Sopenharmony_ci	std::vector<pa::Triangle>					outputTriangles;
543e5c31af7Sopenharmony_ci
544e5c31af7Sopenharmony_ci	for (int inputTriangleNdx = 0; inputTriangleNdx < (int)list.size(); ++inputTriangleNdx)
545e5c31af7Sopenharmony_ci	{
546e5c31af7Sopenharmony_ci		bool clippedByPlane[6];
547e5c31af7Sopenharmony_ci
548e5c31af7Sopenharmony_ci		// Needs clipping?
549e5c31af7Sopenharmony_ci		{
550e5c31af7Sopenharmony_ci			bool discardPrimitive	= false;
551e5c31af7Sopenharmony_ci			bool fullyInClipVolume	= true;
552e5c31af7Sopenharmony_ci
553e5c31af7Sopenharmony_ci			for (int planeNdx = 0; planeNdx < numPlanes; ++planeNdx)
554e5c31af7Sopenharmony_ci			{
555e5c31af7Sopenharmony_ci				const ClipVolumePlane*	plane			= planes[planeNdx];
556e5c31af7Sopenharmony_ci				const bool				v0InsidePlane	= plane->pointInClipVolume(vec4ToClipVec4(list[inputTriangleNdx].v0->position));
557e5c31af7Sopenharmony_ci				const bool				v1InsidePlane	= plane->pointInClipVolume(vec4ToClipVec4(list[inputTriangleNdx].v1->position));
558e5c31af7Sopenharmony_ci				const bool				v2InsidePlane	= plane->pointInClipVolume(vec4ToClipVec4(list[inputTriangleNdx].v2->position));
559e5c31af7Sopenharmony_ci
560e5c31af7Sopenharmony_ci				// Fully outside
561e5c31af7Sopenharmony_ci				if (!v0InsidePlane && !v1InsidePlane && !v2InsidePlane)
562e5c31af7Sopenharmony_ci				{
563e5c31af7Sopenharmony_ci					discardPrimitive = true;
564e5c31af7Sopenharmony_ci					break;
565e5c31af7Sopenharmony_ci				}
566e5c31af7Sopenharmony_ci				// Partially outside
567e5c31af7Sopenharmony_ci				else if (!v0InsidePlane || !v1InsidePlane || !v2InsidePlane)
568e5c31af7Sopenharmony_ci				{
569e5c31af7Sopenharmony_ci					clippedByPlane[planeNdx] = true;
570e5c31af7Sopenharmony_ci					fullyInClipVolume = false;
571e5c31af7Sopenharmony_ci				}
572e5c31af7Sopenharmony_ci				// Fully inside
573e5c31af7Sopenharmony_ci				else
574e5c31af7Sopenharmony_ci					clippedByPlane[planeNdx] = false;
575e5c31af7Sopenharmony_ci			}
576e5c31af7Sopenharmony_ci
577e5c31af7Sopenharmony_ci			if (discardPrimitive)
578e5c31af7Sopenharmony_ci				continue;
579e5c31af7Sopenharmony_ci
580e5c31af7Sopenharmony_ci			if (fullyInClipVolume)
581e5c31af7Sopenharmony_ci			{
582e5c31af7Sopenharmony_ci				outputTriangles.push_back(list[inputTriangleNdx]);
583e5c31af7Sopenharmony_ci				continue;
584e5c31af7Sopenharmony_ci			}
585e5c31af7Sopenharmony_ci		}
586e5c31af7Sopenharmony_ci
587e5c31af7Sopenharmony_ci		// Clip
588e5c31af7Sopenharmony_ci		{
589e5c31af7Sopenharmony_ci			std::vector<SubTriangle>	subTriangles	(1);
590e5c31af7Sopenharmony_ci			SubTriangle&				initialTri		= subTriangles[0];
591e5c31af7Sopenharmony_ci
592e5c31af7Sopenharmony_ci			initialTri.vertices[0].position = vec4ToClipVec4(list[inputTriangleNdx].v0->position);
593e5c31af7Sopenharmony_ci			initialTri.vertices[0].weight[0] = (ClipFloat)1.0;
594e5c31af7Sopenharmony_ci			initialTri.vertices[0].weight[1] = (ClipFloat)0.0;
595e5c31af7Sopenharmony_ci			initialTri.vertices[0].weight[2] = (ClipFloat)0.0;
596e5c31af7Sopenharmony_ci
597e5c31af7Sopenharmony_ci			initialTri.vertices[1].position = vec4ToClipVec4(list[inputTriangleNdx].v1->position);
598e5c31af7Sopenharmony_ci			initialTri.vertices[1].weight[0] = (ClipFloat)0.0;
599e5c31af7Sopenharmony_ci			initialTri.vertices[1].weight[1] = (ClipFloat)1.0;
600e5c31af7Sopenharmony_ci			initialTri.vertices[1].weight[2] = (ClipFloat)0.0;
601e5c31af7Sopenharmony_ci
602e5c31af7Sopenharmony_ci			initialTri.vertices[2].position = vec4ToClipVec4(list[inputTriangleNdx].v2->position);
603e5c31af7Sopenharmony_ci			initialTri.vertices[2].weight[0] = (ClipFloat)0.0;
604e5c31af7Sopenharmony_ci			initialTri.vertices[2].weight[1] = (ClipFloat)0.0;
605e5c31af7Sopenharmony_ci			initialTri.vertices[2].weight[2] = (ClipFloat)1.0;
606e5c31af7Sopenharmony_ci
607e5c31af7Sopenharmony_ci			// Clip all subtriangles to all relevant planes
608e5c31af7Sopenharmony_ci			for (int planeNdx = 0; planeNdx < numPlanes; ++planeNdx)
609e5c31af7Sopenharmony_ci			{
610e5c31af7Sopenharmony_ci				std::vector<SubTriangle> nextPhaseSubTriangles;
611e5c31af7Sopenharmony_ci
612e5c31af7Sopenharmony_ci				if (!clippedByPlane[planeNdx])
613e5c31af7Sopenharmony_ci					continue;
614e5c31af7Sopenharmony_ci
615e5c31af7Sopenharmony_ci				for (int subTriangleNdx = 0; subTriangleNdx < (int)subTriangles.size(); ++subTriangleNdx)
616e5c31af7Sopenharmony_ci				{
617e5c31af7Sopenharmony_ci					std::vector<TriangleVertex> convexPrimitive;
618e5c31af7Sopenharmony_ci
619e5c31af7Sopenharmony_ci					// Clip triangle and form a convex n-gon ( n c {3, 4} )
620e5c31af7Sopenharmony_ci					clipTriangleToPlane(convexPrimitive, subTriangles[subTriangleNdx].vertices, *planes[planeNdx]);
621e5c31af7Sopenharmony_ci
622e5c31af7Sopenharmony_ci					// Subtriangle completely discarded
623e5c31af7Sopenharmony_ci					if (convexPrimitive.empty())
624e5c31af7Sopenharmony_ci						continue;
625e5c31af7Sopenharmony_ci
626e5c31af7Sopenharmony_ci					DE_ASSERT(convexPrimitive.size() == 3 || convexPrimitive.size() == 4);
627e5c31af7Sopenharmony_ci
628e5c31af7Sopenharmony_ci					//Triangulate planar convex n-gon
629e5c31af7Sopenharmony_ci					{
630e5c31af7Sopenharmony_ci						TriangleVertex& v0 = convexPrimitive[0];
631e5c31af7Sopenharmony_ci
632e5c31af7Sopenharmony_ci						for (int subsubTriangleNdx = 1; subsubTriangleNdx + 1 < (int)convexPrimitive.size(); ++subsubTriangleNdx)
633e5c31af7Sopenharmony_ci						{
634e5c31af7Sopenharmony_ci							const float				degenerateEpsilon	= 1.0e-6f;
635e5c31af7Sopenharmony_ci							const TriangleVertex&	v1					= convexPrimitive[subsubTriangleNdx];
636e5c31af7Sopenharmony_ci							const TriangleVertex&	v2					= convexPrimitive[subsubTriangleNdx + 1];
637e5c31af7Sopenharmony_ci							const float				visibleArea			= de::abs(cross2D(to2DCartesian(clipVec4ToVec4(v1.position)) - to2DCartesian(clipVec4ToVec4(v0.position)),
638e5c31af7Sopenharmony_ci																						  to2DCartesian(clipVec4ToVec4(v2.position)) - to2DCartesian(clipVec4ToVec4(v0.position))));
639e5c31af7Sopenharmony_ci
640e5c31af7Sopenharmony_ci							// has surface area (is not a degenerate)
641e5c31af7Sopenharmony_ci							if (visibleArea >= degenerateEpsilon)
642e5c31af7Sopenharmony_ci							{
643e5c31af7Sopenharmony_ci								SubTriangle subsubTriangle;
644e5c31af7Sopenharmony_ci
645e5c31af7Sopenharmony_ci								subsubTriangle.vertices[0] = v0;
646e5c31af7Sopenharmony_ci								subsubTriangle.vertices[1] = v1;
647e5c31af7Sopenharmony_ci								subsubTriangle.vertices[2] = v2;
648e5c31af7Sopenharmony_ci
649e5c31af7Sopenharmony_ci								nextPhaseSubTriangles.push_back(subsubTriangle);
650e5c31af7Sopenharmony_ci							}
651e5c31af7Sopenharmony_ci						}
652e5c31af7Sopenharmony_ci					}
653e5c31af7Sopenharmony_ci				}
654e5c31af7Sopenharmony_ci
655e5c31af7Sopenharmony_ci				subTriangles.swap(nextPhaseSubTriangles);
656e5c31af7Sopenharmony_ci			}
657e5c31af7Sopenharmony_ci
658e5c31af7Sopenharmony_ci			// Rebuild pa::Triangles from subtriangles
659e5c31af7Sopenharmony_ci			for (int subTriangleNdx = 0; subTriangleNdx < (int)subTriangles.size(); ++subTriangleNdx)
660e5c31af7Sopenharmony_ci			{
661e5c31af7Sopenharmony_ci				VertexPacket*	p0				= vpalloc.alloc();
662e5c31af7Sopenharmony_ci				VertexPacket*	p1				= vpalloc.alloc();
663e5c31af7Sopenharmony_ci				VertexPacket*	p2				= vpalloc.alloc();
664e5c31af7Sopenharmony_ci				pa::Triangle	ngonFragment	(p0, p1, p2, -1);
665e5c31af7Sopenharmony_ci
666e5c31af7Sopenharmony_ci				p0->position = clipVec4ToVec4(subTriangles[subTriangleNdx].vertices[0].position);
667e5c31af7Sopenharmony_ci				p1->position = clipVec4ToVec4(subTriangles[subTriangleNdx].vertices[1].position);
668e5c31af7Sopenharmony_ci				p2->position = clipVec4ToVec4(subTriangles[subTriangleNdx].vertices[2].position);
669e5c31af7Sopenharmony_ci
670e5c31af7Sopenharmony_ci				for (size_t outputNdx = 0; outputNdx < fragInputs.size(); ++outputNdx)
671e5c31af7Sopenharmony_ci				{
672e5c31af7Sopenharmony_ci					if (fragInputs[outputNdx].type == GENERICVECTYPE_FLOAT)
673e5c31af7Sopenharmony_ci					{
674e5c31af7Sopenharmony_ci						const tcu::Vec4 out0 = list[inputTriangleNdx].v0->outputs[outputNdx].get<float>();
675e5c31af7Sopenharmony_ci						const tcu::Vec4 out1 = list[inputTriangleNdx].v1->outputs[outputNdx].get<float>();
676e5c31af7Sopenharmony_ci						const tcu::Vec4 out2 = list[inputTriangleNdx].v2->outputs[outputNdx].get<float>();
677e5c31af7Sopenharmony_ci
678e5c31af7Sopenharmony_ci						p0->outputs[outputNdx] = (float)subTriangles[subTriangleNdx].vertices[0].weight[0] * out0
679e5c31af7Sopenharmony_ci											   + (float)subTriangles[subTriangleNdx].vertices[0].weight[1] * out1
680e5c31af7Sopenharmony_ci											   + (float)subTriangles[subTriangleNdx].vertices[0].weight[2] * out2;
681e5c31af7Sopenharmony_ci
682e5c31af7Sopenharmony_ci						p1->outputs[outputNdx] = (float)subTriangles[subTriangleNdx].vertices[1].weight[0] * out0
683e5c31af7Sopenharmony_ci											   + (float)subTriangles[subTriangleNdx].vertices[1].weight[1] * out1
684e5c31af7Sopenharmony_ci											   + (float)subTriangles[subTriangleNdx].vertices[1].weight[2] * out2;
685e5c31af7Sopenharmony_ci
686e5c31af7Sopenharmony_ci						p2->outputs[outputNdx] = (float)subTriangles[subTriangleNdx].vertices[2].weight[0] * out0
687e5c31af7Sopenharmony_ci											   + (float)subTriangles[subTriangleNdx].vertices[2].weight[1] * out1
688e5c31af7Sopenharmony_ci											   + (float)subTriangles[subTriangleNdx].vertices[2].weight[2] * out2;
689e5c31af7Sopenharmony_ci					}
690e5c31af7Sopenharmony_ci					else
691e5c31af7Sopenharmony_ci					{
692e5c31af7Sopenharmony_ci						// only floats are interpolated, all others must be flatshaded then
693e5c31af7Sopenharmony_ci						p0->outputs[outputNdx] = list[inputTriangleNdx].getProvokingVertex()->outputs[outputNdx];
694e5c31af7Sopenharmony_ci						p1->outputs[outputNdx] = list[inputTriangleNdx].getProvokingVertex()->outputs[outputNdx];
695e5c31af7Sopenharmony_ci						p2->outputs[outputNdx] = list[inputTriangleNdx].getProvokingVertex()->outputs[outputNdx];
696e5c31af7Sopenharmony_ci					}
697e5c31af7Sopenharmony_ci				}
698e5c31af7Sopenharmony_ci
699e5c31af7Sopenharmony_ci				outputTriangles.push_back(ngonFragment);
700e5c31af7Sopenharmony_ci			}
701e5c31af7Sopenharmony_ci		}
702e5c31af7Sopenharmony_ci	}
703e5c31af7Sopenharmony_ci
704e5c31af7Sopenharmony_ci	// output result
705e5c31af7Sopenharmony_ci	list.swap(outputTriangles);
706e5c31af7Sopenharmony_ci}
707e5c31af7Sopenharmony_ci
708e5c31af7Sopenharmony_ci/*--------------------------------------------------------------------*//*!
709e5c31af7Sopenharmony_ci * Clip lines to the near and far clip planes.
710e5c31af7Sopenharmony_ci *
711e5c31af7Sopenharmony_ci * Clipping to other planes is a by-product of the viewport test  (i.e.
712e5c31af7Sopenharmony_ci * rasterization area selection).
713e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
714e5c31af7Sopenharmony_civoid clipPrimitives (std::vector<pa::Line>&			list,
715e5c31af7Sopenharmony_ci					 const Program&					program,
716e5c31af7Sopenharmony_ci					 bool							clipWithZPlanes,
717e5c31af7Sopenharmony_ci					 VertexPacketAllocator&			vpalloc)
718e5c31af7Sopenharmony_ci{
719e5c31af7Sopenharmony_ci	DE_UNREF(vpalloc);
720e5c31af7Sopenharmony_ci
721e5c31af7Sopenharmony_ci	using namespace cliputil;
722e5c31af7Sopenharmony_ci
723e5c31af7Sopenharmony_ci	// Lines are clipped only by the far and the near planes here. Line clipping by other planes done in the rasterization phase
724e5c31af7Sopenharmony_ci
725e5c31af7Sopenharmony_ci	const std::vector<rr::VertexVaryingInfo>&	fragInputs	= (program.geometryShader) ? (program.geometryShader->getOutputs()) : (program.vertexShader->getOutputs());
726e5c31af7Sopenharmony_ci	std::vector<pa::Line>						visibleLines;
727e5c31af7Sopenharmony_ci
728e5c31af7Sopenharmony_ci	// Z-clipping disabled, don't do anything
729e5c31af7Sopenharmony_ci	if (!clipWithZPlanes)
730e5c31af7Sopenharmony_ci		return;
731e5c31af7Sopenharmony_ci
732e5c31af7Sopenharmony_ci	for (size_t ndx = 0; ndx < list.size(); ++ndx)
733e5c31af7Sopenharmony_ci	{
734e5c31af7Sopenharmony_ci		pa::Line& l = list[ndx];
735e5c31af7Sopenharmony_ci
736e5c31af7Sopenharmony_ci		// Totally discarded?
737e5c31af7Sopenharmony_ci		if ((l.v0->position.z() < -l.v0->position.w() && l.v1->position.z() < -l.v1->position.w()) ||
738e5c31af7Sopenharmony_ci			(l.v0->position.z() >  l.v0->position.w() && l.v1->position.z() >  l.v1->position.w()))
739e5c31af7Sopenharmony_ci			continue; // discard
740e5c31af7Sopenharmony_ci
741e5c31af7Sopenharmony_ci		// Something is visible
742e5c31af7Sopenharmony_ci
743e5c31af7Sopenharmony_ci		const ClipVec4	p0	= vec4ToClipVec4(l.v0->position);
744e5c31af7Sopenharmony_ci		const ClipVec4	p1	= vec4ToClipVec4(l.v1->position);
745e5c31af7Sopenharmony_ci		const ClipFloat	t0	= getLineEndpointClipping(p0, p1);
746e5c31af7Sopenharmony_ci		const ClipFloat	t1	= getLineEndpointClipping(p1, p0);
747e5c31af7Sopenharmony_ci
748e5c31af7Sopenharmony_ci		// Not clipped at all?
749e5c31af7Sopenharmony_ci		if (t0 == (ClipFloat)0.0 && t1 == (ClipFloat)0.0)
750e5c31af7Sopenharmony_ci		{
751e5c31af7Sopenharmony_ci			visibleLines.push_back(pa::Line(l.v0, l.v1, -1));
752e5c31af7Sopenharmony_ci		}
753e5c31af7Sopenharmony_ci		else
754e5c31af7Sopenharmony_ci		{
755e5c31af7Sopenharmony_ci			// Clip position
756e5c31af7Sopenharmony_ci			l.v0->position = clipVec4ToVec4(tcu::mix(p0, p1, t0));
757e5c31af7Sopenharmony_ci			l.v1->position = clipVec4ToVec4(tcu::mix(p1, p0, t1));
758e5c31af7Sopenharmony_ci
759e5c31af7Sopenharmony_ci			// Clip attributes
760e5c31af7Sopenharmony_ci			for (size_t outputNdx = 0; outputNdx < fragInputs.size(); ++outputNdx)
761e5c31af7Sopenharmony_ci			{
762e5c31af7Sopenharmony_ci				// only floats are clipped, other types are flatshaded
763e5c31af7Sopenharmony_ci				if (fragInputs[outputNdx].type == GENERICVECTYPE_FLOAT)
764e5c31af7Sopenharmony_ci				{
765e5c31af7Sopenharmony_ci					const tcu::Vec4 a0 = l.v0->outputs[outputNdx].get<float>();
766e5c31af7Sopenharmony_ci					const tcu::Vec4 a1 = l.v1->outputs[outputNdx].get<float>();
767e5c31af7Sopenharmony_ci
768e5c31af7Sopenharmony_ci					l.v0->outputs[outputNdx] = tcu::mix(a0, a1, (float)t0);
769e5c31af7Sopenharmony_ci					l.v1->outputs[outputNdx] = tcu::mix(a1, a0, (float)t1);
770e5c31af7Sopenharmony_ci				}
771e5c31af7Sopenharmony_ci			}
772e5c31af7Sopenharmony_ci
773e5c31af7Sopenharmony_ci			visibleLines.push_back(pa::Line(l.v0, l.v1, -1));
774e5c31af7Sopenharmony_ci		}
775e5c31af7Sopenharmony_ci	}
776e5c31af7Sopenharmony_ci
777e5c31af7Sopenharmony_ci	// return visible in list
778e5c31af7Sopenharmony_ci	std::swap(visibleLines, list);
779e5c31af7Sopenharmony_ci}
780e5c31af7Sopenharmony_ci
781e5c31af7Sopenharmony_ci/*--------------------------------------------------------------------*//*!
782e5c31af7Sopenharmony_ci * Discard points not within clip volume. Clipping is a by-product
783e5c31af7Sopenharmony_ci * of the viewport test.
784e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
785e5c31af7Sopenharmony_civoid clipPrimitives (std::vector<pa::Point>&		list,
786e5c31af7Sopenharmony_ci					 const Program&					program,
787e5c31af7Sopenharmony_ci					 bool							clipWithZPlanes,
788e5c31af7Sopenharmony_ci					 VertexPacketAllocator&			vpalloc)
789e5c31af7Sopenharmony_ci{
790e5c31af7Sopenharmony_ci	DE_UNREF(vpalloc);
791e5c31af7Sopenharmony_ci	DE_UNREF(program);
792e5c31af7Sopenharmony_ci
793e5c31af7Sopenharmony_ci	std::vector<pa::Point> visiblePoints;
794e5c31af7Sopenharmony_ci
795e5c31af7Sopenharmony_ci	// Z-clipping disabled, don't do anything
796e5c31af7Sopenharmony_ci	if (!clipWithZPlanes)
797e5c31af7Sopenharmony_ci		return;
798e5c31af7Sopenharmony_ci
799e5c31af7Sopenharmony_ci	for (size_t ndx = 0; ndx < list.size(); ++ndx)
800e5c31af7Sopenharmony_ci	{
801e5c31af7Sopenharmony_ci		pa::Point& p = list[ndx];
802e5c31af7Sopenharmony_ci
803e5c31af7Sopenharmony_ci		// points are discarded if Z is not in range. (Wide) point clipping is done in the rasterization phase
804e5c31af7Sopenharmony_ci		if (de::inRange(p.v0->position.z(), -p.v0->position.w(), p.v0->position.w()))
805e5c31af7Sopenharmony_ci			visiblePoints.push_back(pa::Point(p.v0));
806e5c31af7Sopenharmony_ci	}
807e5c31af7Sopenharmony_ci
808e5c31af7Sopenharmony_ci	// return visible in list
809e5c31af7Sopenharmony_ci	std::swap(visiblePoints, list);
810e5c31af7Sopenharmony_ci}
811e5c31af7Sopenharmony_ci
812e5c31af7Sopenharmony_civoid transformVertexClipCoordsToWindowCoords (const RenderState& state, VertexPacket& packet)
813e5c31af7Sopenharmony_ci{
814e5c31af7Sopenharmony_ci	// To normalized device coords
815e5c31af7Sopenharmony_ci	{
816e5c31af7Sopenharmony_ci		packet.position = tcu::Vec4(packet.position.x()/packet.position.w(),
817e5c31af7Sopenharmony_ci									packet.position.y()/packet.position.w(),
818e5c31af7Sopenharmony_ci									packet.position.z()/packet.position.w(),
819e5c31af7Sopenharmony_ci									1.0f               /packet.position.w());
820e5c31af7Sopenharmony_ci	}
821e5c31af7Sopenharmony_ci
822e5c31af7Sopenharmony_ci	// To window coords
823e5c31af7Sopenharmony_ci	{
824e5c31af7Sopenharmony_ci		const WindowRectangle&	viewport	= state.viewport.rect;
825e5c31af7Sopenharmony_ci		const float				halfW		= (float)(viewport.width) / 2.0f;
826e5c31af7Sopenharmony_ci		const float				halfH		= (float)(viewport.height) / 2.0f;
827e5c31af7Sopenharmony_ci		const float				oX			= (float)viewport.left + halfW;
828e5c31af7Sopenharmony_ci		const float				oY			= (float)viewport.bottom + halfH;
829e5c31af7Sopenharmony_ci		const float				zn			= state.viewport.zn;
830e5c31af7Sopenharmony_ci		const float				zf			= state.viewport.zf;
831e5c31af7Sopenharmony_ci
832e5c31af7Sopenharmony_ci		packet.position = tcu::Vec4(packet.position.x()*halfW + oX,
833e5c31af7Sopenharmony_ci									packet.position.y()*halfH + oY,
834e5c31af7Sopenharmony_ci									packet.position.z()*(zf - zn)/2.0f + (zn + zf)/2.0f,
835e5c31af7Sopenharmony_ci									packet.position.w());
836e5c31af7Sopenharmony_ci	}
837e5c31af7Sopenharmony_ci}
838e5c31af7Sopenharmony_ci
839e5c31af7Sopenharmony_civoid transformPrimitiveClipCoordsToWindowCoords (const RenderState& state, pa::Triangle& target)
840e5c31af7Sopenharmony_ci{
841e5c31af7Sopenharmony_ci	transformVertexClipCoordsToWindowCoords(state, *target.v0);
842e5c31af7Sopenharmony_ci	transformVertexClipCoordsToWindowCoords(state, *target.v1);
843e5c31af7Sopenharmony_ci	transformVertexClipCoordsToWindowCoords(state, *target.v2);
844e5c31af7Sopenharmony_ci}
845e5c31af7Sopenharmony_ci
846e5c31af7Sopenharmony_civoid transformPrimitiveClipCoordsToWindowCoords (const RenderState& state, pa::Line& target)
847e5c31af7Sopenharmony_ci{
848e5c31af7Sopenharmony_ci	transformVertexClipCoordsToWindowCoords(state, *target.v0);
849e5c31af7Sopenharmony_ci	transformVertexClipCoordsToWindowCoords(state, *target.v1);
850e5c31af7Sopenharmony_ci}
851e5c31af7Sopenharmony_ci
852e5c31af7Sopenharmony_civoid transformPrimitiveClipCoordsToWindowCoords (const RenderState& state, pa::Point& target)
853e5c31af7Sopenharmony_ci{
854e5c31af7Sopenharmony_ci	transformVertexClipCoordsToWindowCoords(state, *target.v0);
855e5c31af7Sopenharmony_ci}
856e5c31af7Sopenharmony_ci
857e5c31af7Sopenharmony_citemplate <typename ContainerType>
858e5c31af7Sopenharmony_civoid transformClipCoordsToWindowCoords (const RenderState& state, ContainerType& list)
859e5c31af7Sopenharmony_ci{
860e5c31af7Sopenharmony_ci	for (typename ContainerType::iterator it = list.begin(); it != list.end(); ++it)
861e5c31af7Sopenharmony_ci		transformPrimitiveClipCoordsToWindowCoords(state, *it);
862e5c31af7Sopenharmony_ci}
863e5c31af7Sopenharmony_ci
864e5c31af7Sopenharmony_civoid makeSharedVerticeDistinct (VertexPacket*& packet, std::set<VertexPacket*, std::less<void*> >& vertices, VertexPacketAllocator& vpalloc)
865e5c31af7Sopenharmony_ci{
866e5c31af7Sopenharmony_ci	// distinct
867e5c31af7Sopenharmony_ci	if (vertices.find(packet) == vertices.end())
868e5c31af7Sopenharmony_ci	{
869e5c31af7Sopenharmony_ci		vertices.insert(packet);
870e5c31af7Sopenharmony_ci	}
871e5c31af7Sopenharmony_ci	else
872e5c31af7Sopenharmony_ci	{
873e5c31af7Sopenharmony_ci		VertexPacket* newPacket = vpalloc.alloc();
874e5c31af7Sopenharmony_ci
875e5c31af7Sopenharmony_ci		// copy packet output values
876e5c31af7Sopenharmony_ci		newPacket->position		= packet->position;
877e5c31af7Sopenharmony_ci		newPacket->pointSize	= packet->pointSize;
878e5c31af7Sopenharmony_ci		newPacket->primitiveID	= packet->primitiveID;
879e5c31af7Sopenharmony_ci
880e5c31af7Sopenharmony_ci		for (size_t outputNdx = 0; outputNdx < vpalloc.getNumVertexOutputs(); ++outputNdx)
881e5c31af7Sopenharmony_ci			newPacket->outputs[outputNdx] = packet->outputs[outputNdx];
882e5c31af7Sopenharmony_ci
883e5c31af7Sopenharmony_ci		// no need to insert new packet to "vertices" as newPacket is unique
884e5c31af7Sopenharmony_ci		packet = newPacket;
885e5c31af7Sopenharmony_ci	}
886e5c31af7Sopenharmony_ci}
887e5c31af7Sopenharmony_ci
888e5c31af7Sopenharmony_civoid makeSharedVerticesDistinct (pa::Triangle& target, std::set<VertexPacket*, std::less<void*> >& vertices, VertexPacketAllocator& vpalloc)
889e5c31af7Sopenharmony_ci{
890e5c31af7Sopenharmony_ci	makeSharedVerticeDistinct(target.v0, vertices, vpalloc);
891e5c31af7Sopenharmony_ci	makeSharedVerticeDistinct(target.v1, vertices, vpalloc);
892e5c31af7Sopenharmony_ci	makeSharedVerticeDistinct(target.v2, vertices, vpalloc);
893e5c31af7Sopenharmony_ci}
894e5c31af7Sopenharmony_ci
895e5c31af7Sopenharmony_civoid makeSharedVerticesDistinct (pa::Line& target, std::set<VertexPacket*, std::less<void*> >& vertices, VertexPacketAllocator& vpalloc)
896e5c31af7Sopenharmony_ci{
897e5c31af7Sopenharmony_ci	makeSharedVerticeDistinct(target.v0, vertices, vpalloc);
898e5c31af7Sopenharmony_ci	makeSharedVerticeDistinct(target.v1, vertices, vpalloc);
899e5c31af7Sopenharmony_ci}
900e5c31af7Sopenharmony_ci
901e5c31af7Sopenharmony_civoid makeSharedVerticesDistinct (pa::Point& target, std::set<VertexPacket*, std::less<void*> >& vertices, VertexPacketAllocator& vpalloc)
902e5c31af7Sopenharmony_ci{
903e5c31af7Sopenharmony_ci	makeSharedVerticeDistinct(target.v0, vertices, vpalloc);
904e5c31af7Sopenharmony_ci}
905e5c31af7Sopenharmony_ci
906e5c31af7Sopenharmony_citemplate <typename ContainerType>
907e5c31af7Sopenharmony_civoid makeSharedVerticesDistinct (ContainerType& list, VertexPacketAllocator& vpalloc)
908e5c31af7Sopenharmony_ci{
909e5c31af7Sopenharmony_ci	std::set<VertexPacket*, std::less<void*> > vertices;
910e5c31af7Sopenharmony_ci
911e5c31af7Sopenharmony_ci	for (typename ContainerType::iterator it = list.begin(); it != list.end(); ++it)
912e5c31af7Sopenharmony_ci		makeSharedVerticesDistinct(*it, vertices, vpalloc);
913e5c31af7Sopenharmony_ci}
914e5c31af7Sopenharmony_ci
915e5c31af7Sopenharmony_civoid generatePrimitiveIDs (pa::Triangle& target, int id)
916e5c31af7Sopenharmony_ci{
917e5c31af7Sopenharmony_ci	target.v0->primitiveID = id;
918e5c31af7Sopenharmony_ci	target.v1->primitiveID = id;
919e5c31af7Sopenharmony_ci	target.v2->primitiveID = id;
920e5c31af7Sopenharmony_ci}
921e5c31af7Sopenharmony_ci
922e5c31af7Sopenharmony_civoid generatePrimitiveIDs (pa::Line& target, int id)
923e5c31af7Sopenharmony_ci{
924e5c31af7Sopenharmony_ci	target.v0->primitiveID = id;
925e5c31af7Sopenharmony_ci	target.v1->primitiveID = id;
926e5c31af7Sopenharmony_ci}
927e5c31af7Sopenharmony_ci
928e5c31af7Sopenharmony_civoid generatePrimitiveIDs (pa::Point& target, int id)
929e5c31af7Sopenharmony_ci{
930e5c31af7Sopenharmony_ci	target.v0->primitiveID = id;
931e5c31af7Sopenharmony_ci}
932e5c31af7Sopenharmony_ci
933e5c31af7Sopenharmony_citemplate <typename ContainerType>
934e5c31af7Sopenharmony_civoid generatePrimitiveIDs (ContainerType& list, DrawContext& drawContext)
935e5c31af7Sopenharmony_ci{
936e5c31af7Sopenharmony_ci	for (typename ContainerType::iterator it = list.begin(); it != list.end(); ++it)
937e5c31af7Sopenharmony_ci		generatePrimitiveIDs(*it, drawContext.primitiveID++);
938e5c31af7Sopenharmony_ci}
939e5c31af7Sopenharmony_ci
940e5c31af7Sopenharmony_cistatic float findTriangleVertexDepthSlope (const tcu::Vec4& p, const tcu::Vec4& v0, const tcu::Vec4& v1)
941e5c31af7Sopenharmony_ci{
942e5c31af7Sopenharmony_ci	// screen space
943e5c31af7Sopenharmony_ci	const tcu::Vec3 ssp		=  p.swizzle(0, 1, 2);
944e5c31af7Sopenharmony_ci	const tcu::Vec3 ssv0	= v0.swizzle(0, 1, 2);
945e5c31af7Sopenharmony_ci	const tcu::Vec3 ssv1	= v1.swizzle(0, 1, 2);
946e5c31af7Sopenharmony_ci
947e5c31af7Sopenharmony_ci	// dx & dy
948e5c31af7Sopenharmony_ci
949e5c31af7Sopenharmony_ci	const tcu::Vec3 a		= ssv0.swizzle(0,1,2) - ssp.swizzle(0,1,2);
950e5c31af7Sopenharmony_ci	const tcu::Vec3 b		= ssv1.swizzle(0,1,2) - ssp.swizzle(0,1,2);
951e5c31af7Sopenharmony_ci	const float		epsilon	= 0.0001f;
952e5c31af7Sopenharmony_ci	const float		det		= (a.x() * b.y() - b.x() * a.y());
953e5c31af7Sopenharmony_ci
954e5c31af7Sopenharmony_ci	// degenerate triangle, it won't generate any fragments anyway. Return value doesn't matter
955e5c31af7Sopenharmony_ci	if (de::abs(det) < epsilon)
956e5c31af7Sopenharmony_ci		return 0.0f;
957e5c31af7Sopenharmony_ci
958e5c31af7Sopenharmony_ci	const tcu::Vec2	dxDir	= tcu::Vec2( b.y(), -a.y()) / det;
959e5c31af7Sopenharmony_ci	const tcu::Vec2	dyDir	= tcu::Vec2(-b.x(),  a.x()) / det;
960e5c31af7Sopenharmony_ci
961e5c31af7Sopenharmony_ci	const float		dzdx	= dxDir.x() * a.z() + dxDir.y() * b.z();
962e5c31af7Sopenharmony_ci	const float		dzdy	= dyDir.x() * a.z() + dyDir.y() * b.z();
963e5c31af7Sopenharmony_ci
964e5c31af7Sopenharmony_ci	// approximate using max(|dz/dx|, |dz/dy|)
965e5c31af7Sopenharmony_ci	return de::max(de::abs(dzdx), de::abs(dzdy));
966e5c31af7Sopenharmony_ci}
967e5c31af7Sopenharmony_ci
968e5c31af7Sopenharmony_cistatic float findPrimitiveMaximumDepthSlope (const pa::Triangle& triangle)
969e5c31af7Sopenharmony_ci{
970e5c31af7Sopenharmony_ci	const float d1 = findTriangleVertexDepthSlope(triangle.v0->position, triangle.v1->position, triangle.v2->position);
971e5c31af7Sopenharmony_ci	const float d2 = findTriangleVertexDepthSlope(triangle.v1->position, triangle.v2->position, triangle.v0->position);
972e5c31af7Sopenharmony_ci	const float d3 = findTriangleVertexDepthSlope(triangle.v2->position, triangle.v0->position, triangle.v1->position);
973e5c31af7Sopenharmony_ci
974e5c31af7Sopenharmony_ci	return de::max(d1, de::max(d2, d3));
975e5c31af7Sopenharmony_ci}
976e5c31af7Sopenharmony_ci
977e5c31af7Sopenharmony_cistatic float getFloatingPointMinimumResolvableDifference (float maxZValue, tcu::TextureFormat::ChannelType type)
978e5c31af7Sopenharmony_ci{
979e5c31af7Sopenharmony_ci	if (type == tcu::TextureFormat::FLOAT)
980e5c31af7Sopenharmony_ci	{
981e5c31af7Sopenharmony_ci		// 32f
982e5c31af7Sopenharmony_ci		const int maxExponent = tcu::Float32(maxZValue).exponent();
983e5c31af7Sopenharmony_ci		return tcu::Float32::construct(+1, maxExponent - 23, 1 << 23).asFloat();
984e5c31af7Sopenharmony_ci	}
985e5c31af7Sopenharmony_ci
986e5c31af7Sopenharmony_ci	// unexpected format
987e5c31af7Sopenharmony_ci	DE_ASSERT(false);
988e5c31af7Sopenharmony_ci	return 0.0f;
989e5c31af7Sopenharmony_ci}
990e5c31af7Sopenharmony_ci
991e5c31af7Sopenharmony_cistatic float getFixedPointMinimumResolvableDifference (int numBits)
992e5c31af7Sopenharmony_ci{
993e5c31af7Sopenharmony_ci	return tcu::Float32::construct(+1, -numBits, 1 << 23).asFloat();
994e5c31af7Sopenharmony_ci}
995e5c31af7Sopenharmony_ci
996e5c31af7Sopenharmony_cistatic float findPrimitiveMinimumResolvableDifference (const pa::Triangle& triangle, const rr::MultisampleConstPixelBufferAccess& depthAccess)
997e5c31af7Sopenharmony_ci{
998e5c31af7Sopenharmony_ci	const float								maxZvalue		= de::max(de::max(triangle.v0->position.z(), triangle.v1->position.z()), triangle.v2->position.z());
999e5c31af7Sopenharmony_ci	const tcu::TextureFormat				format			= depthAccess.raw().getFormat();
1000e5c31af7Sopenharmony_ci	const tcu::TextureFormat::ChannelOrder	order			= format.order;
1001e5c31af7Sopenharmony_ci
1002e5c31af7Sopenharmony_ci	if (order == tcu::TextureFormat::D)
1003e5c31af7Sopenharmony_ci	{
1004e5c31af7Sopenharmony_ci		// depth only
1005e5c31af7Sopenharmony_ci		const tcu::TextureFormat::ChannelType	channelType		= format.type;
1006e5c31af7Sopenharmony_ci		const tcu::TextureChannelClass			channelClass	= tcu::getTextureChannelClass(channelType);
1007e5c31af7Sopenharmony_ci		const int								numBits			= tcu::getTextureFormatBitDepth(format).x();
1008e5c31af7Sopenharmony_ci
1009e5c31af7Sopenharmony_ci		if (channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT)
1010e5c31af7Sopenharmony_ci			return getFloatingPointMinimumResolvableDifference(maxZvalue, channelType);
1011e5c31af7Sopenharmony_ci		else
1012e5c31af7Sopenharmony_ci			// \note channelClass might be CLASS_LAST but that's ok
1013e5c31af7Sopenharmony_ci			return getFixedPointMinimumResolvableDifference(numBits);
1014e5c31af7Sopenharmony_ci	}
1015e5c31af7Sopenharmony_ci	else if (order == tcu::TextureFormat::DS)
1016e5c31af7Sopenharmony_ci	{
1017e5c31af7Sopenharmony_ci		// depth stencil, special cases for possible combined formats
1018e5c31af7Sopenharmony_ci		if (format.type == tcu::TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV)
1019e5c31af7Sopenharmony_ci			return getFloatingPointMinimumResolvableDifference(maxZvalue, tcu::TextureFormat::FLOAT);
1020e5c31af7Sopenharmony_ci		else if (format.type == tcu::TextureFormat::UNSIGNED_INT_24_8)
1021e5c31af7Sopenharmony_ci			return getFixedPointMinimumResolvableDifference(24);
1022e5c31af7Sopenharmony_ci	}
1023e5c31af7Sopenharmony_ci
1024e5c31af7Sopenharmony_ci	// unexpected format
1025e5c31af7Sopenharmony_ci	DE_ASSERT(false);
1026e5c31af7Sopenharmony_ci	return 0.0f;
1027e5c31af7Sopenharmony_ci}
1028e5c31af7Sopenharmony_ci
1029e5c31af7Sopenharmony_civoid writeFragmentPackets (const RenderState&					state,
1030e5c31af7Sopenharmony_ci						   const RenderTarget&					renderTarget,
1031e5c31af7Sopenharmony_ci						   const Program&						program,
1032e5c31af7Sopenharmony_ci						   const FragmentPacket*				fragmentPackets,
1033e5c31af7Sopenharmony_ci						   int									numRasterizedPackets,
1034e5c31af7Sopenharmony_ci						   rr::FaceType							facetype,
1035e5c31af7Sopenharmony_ci						   const std::vector<rr::GenericVec4>&	fragmentOutputArray,
1036e5c31af7Sopenharmony_ci						   const std::vector<rr::GenericVec4>&	fragmentOutputArraySrc1,
1037e5c31af7Sopenharmony_ci						   const float*							depthValues,
1038e5c31af7Sopenharmony_ci						   std::vector<Fragment>&				fragmentBuffer)
1039e5c31af7Sopenharmony_ci{
1040e5c31af7Sopenharmony_ci	const int			numSamples		= renderTarget.getNumSamples();
1041e5c31af7Sopenharmony_ci	const size_t		numOutputs		= program.fragmentShader->getOutputs().size();
1042e5c31af7Sopenharmony_ci	FragmentProcessor	fragProcessor;
1043e5c31af7Sopenharmony_ci
1044e5c31af7Sopenharmony_ci	DE_ASSERT(fragmentOutputArray.size() >= (size_t)numRasterizedPackets*4*numOutputs);
1045e5c31af7Sopenharmony_ci	DE_ASSERT(fragmentBuffer.size()      >= (size_t)numRasterizedPackets*4);
1046e5c31af7Sopenharmony_ci
1047e5c31af7Sopenharmony_ci	// Translate fragments but do not set the value yet
1048e5c31af7Sopenharmony_ci	{
1049e5c31af7Sopenharmony_ci		int	fragCount = 0;
1050e5c31af7Sopenharmony_ci		for (int packetNdx = 0; packetNdx < numRasterizedPackets; ++packetNdx)
1051e5c31af7Sopenharmony_ci		for (int fragNdx = 0; fragNdx < 4; fragNdx++)
1052e5c31af7Sopenharmony_ci		{
1053e5c31af7Sopenharmony_ci			const FragmentPacket&	packet	= fragmentPackets[packetNdx];
1054e5c31af7Sopenharmony_ci			const int				xo		= fragNdx%2;
1055e5c31af7Sopenharmony_ci			const int				yo		= fragNdx/2;
1056e5c31af7Sopenharmony_ci
1057e5c31af7Sopenharmony_ci			if (getCoverageAnyFragmentSampleLive(packet.coverage, numSamples, xo, yo))
1058e5c31af7Sopenharmony_ci			{
1059e5c31af7Sopenharmony_ci				Fragment& fragment		= fragmentBuffer[fragCount++];
1060e5c31af7Sopenharmony_ci
1061e5c31af7Sopenharmony_ci				fragment.pixelCoord		= packet.position + tcu::IVec2(xo, yo);
1062e5c31af7Sopenharmony_ci				fragment.coverage		= (deUint32)((packet.coverage & getCoverageFragmentSampleBits(numSamples, xo, yo)) >> getCoverageOffset(numSamples, xo, yo));
1063e5c31af7Sopenharmony_ci				fragment.sampleDepths	= (depthValues) ? (&depthValues[(packetNdx*4 + yo*2 + xo)*numSamples]) : (DE_NULL);
1064e5c31af7Sopenharmony_ci			}
1065e5c31af7Sopenharmony_ci		}
1066e5c31af7Sopenharmony_ci	}
1067e5c31af7Sopenharmony_ci
1068e5c31af7Sopenharmony_ci	// Set per output output values
1069e5c31af7Sopenharmony_ci	{
1070e5c31af7Sopenharmony_ci		rr::FragmentOperationState noStencilDepthWriteState(state.fragOps);
1071e5c31af7Sopenharmony_ci		noStencilDepthWriteState.depthMask						= false;
1072e5c31af7Sopenharmony_ci		noStencilDepthWriteState.stencilStates[facetype].sFail	= STENCILOP_KEEP;
1073e5c31af7Sopenharmony_ci		noStencilDepthWriteState.stencilStates[facetype].dpFail	= STENCILOP_KEEP;
1074e5c31af7Sopenharmony_ci		noStencilDepthWriteState.stencilStates[facetype].dpPass	= STENCILOP_KEEP;
1075e5c31af7Sopenharmony_ci
1076e5c31af7Sopenharmony_ci		int	fragCount = 0;
1077e5c31af7Sopenharmony_ci		for (size_t outputNdx = 0; outputNdx < numOutputs; ++outputNdx)
1078e5c31af7Sopenharmony_ci		{
1079e5c31af7Sopenharmony_ci			// Only the last output-pass has default state, other passes have stencil & depth writemask=0
1080e5c31af7Sopenharmony_ci			const rr::FragmentOperationState& fragOpsState = (outputNdx == numOutputs-1) ? (state.fragOps) : (noStencilDepthWriteState);
1081e5c31af7Sopenharmony_ci
1082e5c31af7Sopenharmony_ci			for (int packetNdx = 0; packetNdx < numRasterizedPackets; ++packetNdx)
1083e5c31af7Sopenharmony_ci			for (int fragNdx = 0; fragNdx < 4; fragNdx++)
1084e5c31af7Sopenharmony_ci			{
1085e5c31af7Sopenharmony_ci				const FragmentPacket&	packet	= fragmentPackets[packetNdx];
1086e5c31af7Sopenharmony_ci				const int				xo		= fragNdx%2;
1087e5c31af7Sopenharmony_ci				const int				yo		= fragNdx/2;
1088e5c31af7Sopenharmony_ci
1089e5c31af7Sopenharmony_ci				// Add only fragments that have live samples to shaded fragments queue.
1090e5c31af7Sopenharmony_ci				if (getCoverageAnyFragmentSampleLive(packet.coverage, numSamples, xo, yo))
1091e5c31af7Sopenharmony_ci				{
1092e5c31af7Sopenharmony_ci					Fragment& fragment		= fragmentBuffer[fragCount++];
1093e5c31af7Sopenharmony_ci					fragment.value			= fragmentOutputArray[(packetNdx*4 + fragNdx) * numOutputs + outputNdx];
1094e5c31af7Sopenharmony_ci					fragment.value1			= fragmentOutputArraySrc1[(packetNdx*4 + fragNdx) * numOutputs + outputNdx];
1095e5c31af7Sopenharmony_ci				}
1096e5c31af7Sopenharmony_ci			}
1097e5c31af7Sopenharmony_ci
1098e5c31af7Sopenharmony_ci			// Execute per-fragment ops and write
1099e5c31af7Sopenharmony_ci			fragProcessor.render(renderTarget.getColorBuffer((int)outputNdx), renderTarget.getDepthBuffer(), renderTarget.getStencilBuffer(), &fragmentBuffer[0], fragCount, facetype, fragOpsState);
1100e5c31af7Sopenharmony_ci		}
1101e5c31af7Sopenharmony_ci	}
1102e5c31af7Sopenharmony_ci}
1103e5c31af7Sopenharmony_ci
1104e5c31af7Sopenharmony_civoid rasterizePrimitive (const RenderState&					state,
1105e5c31af7Sopenharmony_ci						 const RenderTarget&				renderTarget,
1106e5c31af7Sopenharmony_ci						 const Program&						program,
1107e5c31af7Sopenharmony_ci						 const pa::Triangle&				triangle,
1108e5c31af7Sopenharmony_ci						 const tcu::IVec4&					renderTargetRect,
1109e5c31af7Sopenharmony_ci						 RasterizationInternalBuffers&		buffers)
1110e5c31af7Sopenharmony_ci{
1111e5c31af7Sopenharmony_ci	const int			numSamples		= renderTarget.getNumSamples();
1112e5c31af7Sopenharmony_ci	const float			depthClampMin	= de::min(state.viewport.zn, state.viewport.zf);
1113e5c31af7Sopenharmony_ci	const float			depthClampMax	= de::max(state.viewport.zn, state.viewport.zf);
1114e5c31af7Sopenharmony_ci	TriangleRasterizer	rasterizer		(renderTargetRect, numSamples, state.rasterization, state.subpixelBits);
1115e5c31af7Sopenharmony_ci	float				depthOffset		= 0.0f;
1116e5c31af7Sopenharmony_ci
1117e5c31af7Sopenharmony_ci	rasterizer.init(triangle.v0->position, triangle.v1->position, triangle.v2->position);
1118e5c31af7Sopenharmony_ci
1119e5c31af7Sopenharmony_ci	// Culling
1120e5c31af7Sopenharmony_ci	const FaceType visibleFace = rasterizer.getVisibleFace();
1121e5c31af7Sopenharmony_ci	if ((state.cullMode == CULLMODE_FRONT	&& visibleFace == FACETYPE_FRONT) ||
1122e5c31af7Sopenharmony_ci		(state.cullMode == CULLMODE_BACK	&& visibleFace == FACETYPE_BACK))
1123e5c31af7Sopenharmony_ci		return;
1124e5c31af7Sopenharmony_ci
1125e5c31af7Sopenharmony_ci	// Shading context
1126e5c31af7Sopenharmony_ci	FragmentShadingContext shadingContext(triangle.v0->outputs, triangle.v1->outputs, triangle.v2->outputs, &buffers.shaderOutputs[0], &buffers.shaderOutputsSrc1[0], buffers.fragmentDepthBuffer, triangle.v2->primitiveID, (int)program.fragmentShader->getOutputs().size(), numSamples, rasterizer.getVisibleFace());
1127e5c31af7Sopenharmony_ci
1128e5c31af7Sopenharmony_ci	// Polygon offset
1129e5c31af7Sopenharmony_ci	if (buffers.fragmentDepthBuffer && state.fragOps.polygonOffsetEnabled)
1130e5c31af7Sopenharmony_ci	{
1131e5c31af7Sopenharmony_ci		const float maximumDepthSlope			= findPrimitiveMaximumDepthSlope(triangle);
1132e5c31af7Sopenharmony_ci		const float minimumResolvableDifference	= findPrimitiveMinimumResolvableDifference(triangle, renderTarget.getDepthBuffer());
1133e5c31af7Sopenharmony_ci
1134e5c31af7Sopenharmony_ci		depthOffset = maximumDepthSlope * state.fragOps.polygonOffsetFactor + minimumResolvableDifference * state.fragOps.polygonOffsetUnits;
1135e5c31af7Sopenharmony_ci	}
1136e5c31af7Sopenharmony_ci
1137e5c31af7Sopenharmony_ci	// Execute rasterize - shade - write loop
1138e5c31af7Sopenharmony_ci	for (;;)
1139e5c31af7Sopenharmony_ci	{
1140e5c31af7Sopenharmony_ci		const int	maxFragmentPackets		= (int)buffers.fragmentPackets.size();
1141e5c31af7Sopenharmony_ci		int			numRasterizedPackets	= 0;
1142e5c31af7Sopenharmony_ci
1143e5c31af7Sopenharmony_ci		// Rasterize
1144e5c31af7Sopenharmony_ci
1145e5c31af7Sopenharmony_ci		rasterizer.rasterize(&buffers.fragmentPackets[0], buffers.fragmentDepthBuffer, maxFragmentPackets, numRasterizedPackets);
1146e5c31af7Sopenharmony_ci
1147e5c31af7Sopenharmony_ci		// numRasterizedPackets is guaranteed to be greater than zero for shadeFragments()
1148e5c31af7Sopenharmony_ci
1149e5c31af7Sopenharmony_ci		if (!numRasterizedPackets)
1150e5c31af7Sopenharmony_ci			break; // Rasterization finished.
1151e5c31af7Sopenharmony_ci
1152e5c31af7Sopenharmony_ci		// Polygon offset
1153e5c31af7Sopenharmony_ci		if (buffers.fragmentDepthBuffer && state.fragOps.polygonOffsetEnabled)
1154e5c31af7Sopenharmony_ci			for (int sampleNdx = 0; sampleNdx < numRasterizedPackets * 4 * numSamples; ++sampleNdx)
1155e5c31af7Sopenharmony_ci				buffers.fragmentDepthBuffer[sampleNdx] = de::clamp(buffers.fragmentDepthBuffer[sampleNdx] + depthOffset, 0.0f, 1.0f);
1156e5c31af7Sopenharmony_ci
1157e5c31af7Sopenharmony_ci		// Shade
1158e5c31af7Sopenharmony_ci
1159e5c31af7Sopenharmony_ci		program.fragmentShader->shadeFragments(&buffers.fragmentPackets[0], numRasterizedPackets, shadingContext);
1160e5c31af7Sopenharmony_ci
1161e5c31af7Sopenharmony_ci		// Depth clamp
1162e5c31af7Sopenharmony_ci		if (buffers.fragmentDepthBuffer && state.fragOps.depthClampEnabled)
1163e5c31af7Sopenharmony_ci			for (int sampleNdx = 0; sampleNdx < numRasterizedPackets * 4 * numSamples; ++sampleNdx)
1164e5c31af7Sopenharmony_ci				buffers.fragmentDepthBuffer[sampleNdx] = de::clamp(buffers.fragmentDepthBuffer[sampleNdx], depthClampMin, depthClampMax);
1165e5c31af7Sopenharmony_ci
1166e5c31af7Sopenharmony_ci		// Handle fragment shader outputs
1167e5c31af7Sopenharmony_ci
1168e5c31af7Sopenharmony_ci		writeFragmentPackets(state, renderTarget, program, &buffers.fragmentPackets[0], numRasterizedPackets, visibleFace, buffers.shaderOutputs, buffers.shaderOutputsSrc1, buffers.fragmentDepthBuffer, buffers.shadedFragments);
1169e5c31af7Sopenharmony_ci	}
1170e5c31af7Sopenharmony_ci}
1171e5c31af7Sopenharmony_ci
1172e5c31af7Sopenharmony_civoid rasterizePrimitive (const RenderState&					state,
1173e5c31af7Sopenharmony_ci						 const RenderTarget&				renderTarget,
1174e5c31af7Sopenharmony_ci						 const Program&						program,
1175e5c31af7Sopenharmony_ci						 const pa::Line&					line,
1176e5c31af7Sopenharmony_ci						 const tcu::IVec4&					renderTargetRect,
1177e5c31af7Sopenharmony_ci						 RasterizationInternalBuffers&		buffers)
1178e5c31af7Sopenharmony_ci{
1179e5c31af7Sopenharmony_ci	const int					numSamples			= renderTarget.getNumSamples();
1180e5c31af7Sopenharmony_ci	const float					depthClampMin		= de::min(state.viewport.zn, state.viewport.zf);
1181e5c31af7Sopenharmony_ci	const float					depthClampMax		= de::max(state.viewport.zn, state.viewport.zf);
1182e5c31af7Sopenharmony_ci	const bool					msaa				= numSamples > 1;
1183e5c31af7Sopenharmony_ci	FragmentShadingContext		shadingContext		(line.v0->outputs, line.v1->outputs, DE_NULL, &buffers.shaderOutputs[0], &buffers.shaderOutputsSrc1[0], buffers.fragmentDepthBuffer, line.v1->primitiveID, (int)program.fragmentShader->getOutputs().size(), numSamples, FACETYPE_FRONT);
1184e5c31af7Sopenharmony_ci	SingleSampleLineRasterizer	aliasedRasterizer	(renderTargetRect, state.subpixelBits);
1185e5c31af7Sopenharmony_ci	MultiSampleLineRasterizer	msaaRasterizer		(numSamples, renderTargetRect, state.subpixelBits);
1186e5c31af7Sopenharmony_ci
1187e5c31af7Sopenharmony_ci	// Initialize rasterization.
1188e5c31af7Sopenharmony_ci	if (msaa)
1189e5c31af7Sopenharmony_ci		msaaRasterizer.init(line.v0->position, line.v1->position, state.line.lineWidth);
1190e5c31af7Sopenharmony_ci	else
1191e5c31af7Sopenharmony_ci		aliasedRasterizer.init(line.v0->position, line.v1->position, state.line.lineWidth, 1, 0xFFFF);
1192e5c31af7Sopenharmony_ci
1193e5c31af7Sopenharmony_ci	for (;;)
1194e5c31af7Sopenharmony_ci	{
1195e5c31af7Sopenharmony_ci		const int	maxFragmentPackets		= (int)buffers.fragmentPackets.size();
1196e5c31af7Sopenharmony_ci		int			numRasterizedPackets	= 0;
1197e5c31af7Sopenharmony_ci
1198e5c31af7Sopenharmony_ci		// Rasterize
1199e5c31af7Sopenharmony_ci
1200e5c31af7Sopenharmony_ci		if (msaa)
1201e5c31af7Sopenharmony_ci			msaaRasterizer.rasterize	(&buffers.fragmentPackets[0], buffers.fragmentDepthBuffer, maxFragmentPackets, numRasterizedPackets);
1202e5c31af7Sopenharmony_ci		else
1203e5c31af7Sopenharmony_ci			aliasedRasterizer.rasterize	(&buffers.fragmentPackets[0], buffers.fragmentDepthBuffer, maxFragmentPackets, numRasterizedPackets);
1204e5c31af7Sopenharmony_ci
1205e5c31af7Sopenharmony_ci		// numRasterizedPackets is guaranteed to be greater than zero for shadeFragments()
1206e5c31af7Sopenharmony_ci
1207e5c31af7Sopenharmony_ci		if (!numRasterizedPackets)
1208e5c31af7Sopenharmony_ci			break; // Rasterization finished.
1209e5c31af7Sopenharmony_ci
1210e5c31af7Sopenharmony_ci		// Shade
1211e5c31af7Sopenharmony_ci
1212e5c31af7Sopenharmony_ci		program.fragmentShader->shadeFragments(&buffers.fragmentPackets[0], numRasterizedPackets, shadingContext);
1213e5c31af7Sopenharmony_ci
1214e5c31af7Sopenharmony_ci		// Depth clamp
1215e5c31af7Sopenharmony_ci		if (buffers.fragmentDepthBuffer && state.fragOps.depthClampEnabled)
1216e5c31af7Sopenharmony_ci			for (int sampleNdx = 0; sampleNdx < numRasterizedPackets * 4 * numSamples; ++sampleNdx)
1217e5c31af7Sopenharmony_ci				buffers.fragmentDepthBuffer[sampleNdx] = de::clamp(buffers.fragmentDepthBuffer[sampleNdx], depthClampMin, depthClampMax);
1218e5c31af7Sopenharmony_ci
1219e5c31af7Sopenharmony_ci		// Handle fragment shader outputs
1220e5c31af7Sopenharmony_ci
1221e5c31af7Sopenharmony_ci		writeFragmentPackets(state, renderTarget, program, &buffers.fragmentPackets[0], numRasterizedPackets, rr::FACETYPE_FRONT, buffers.shaderOutputs, buffers.shaderOutputsSrc1, buffers.fragmentDepthBuffer, buffers.shadedFragments);
1222e5c31af7Sopenharmony_ci	}
1223e5c31af7Sopenharmony_ci}
1224e5c31af7Sopenharmony_ci
1225e5c31af7Sopenharmony_civoid rasterizePrimitive (const RenderState&					state,
1226e5c31af7Sopenharmony_ci						 const RenderTarget&				renderTarget,
1227e5c31af7Sopenharmony_ci						 const Program&						program,
1228e5c31af7Sopenharmony_ci						 const pa::Point&					point,
1229e5c31af7Sopenharmony_ci						 const tcu::IVec4&					renderTargetRect,
1230e5c31af7Sopenharmony_ci						 RasterizationInternalBuffers&		buffers)
1231e5c31af7Sopenharmony_ci{
1232e5c31af7Sopenharmony_ci	const int			numSamples		= renderTarget.getNumSamples();
1233e5c31af7Sopenharmony_ci	const float			depthClampMin	= de::min(state.viewport.zn, state.viewport.zf);
1234e5c31af7Sopenharmony_ci	const float			depthClampMax	= de::max(state.viewport.zn, state.viewport.zf);
1235e5c31af7Sopenharmony_ci	TriangleRasterizer	rasterizer1		(renderTargetRect, numSamples, state.rasterization, state.subpixelBits);
1236e5c31af7Sopenharmony_ci	TriangleRasterizer	rasterizer2		(renderTargetRect, numSamples, state.rasterization, state.subpixelBits);
1237e5c31af7Sopenharmony_ci
1238e5c31af7Sopenharmony_ci	// draw point as two triangles
1239e5c31af7Sopenharmony_ci	const float offset				= point.v0->pointSize / 2.0f;
1240e5c31af7Sopenharmony_ci	const tcu::Vec4		w0			= tcu::Vec4(point.v0->position.x() + offset, point.v0->position.y() + offset, point.v0->position.z(), point.v0->position.w());
1241e5c31af7Sopenharmony_ci	const tcu::Vec4		w1			= tcu::Vec4(point.v0->position.x() - offset, point.v0->position.y() + offset, point.v0->position.z(), point.v0->position.w());
1242e5c31af7Sopenharmony_ci	const tcu::Vec4		w2			= tcu::Vec4(point.v0->position.x() - offset, point.v0->position.y() - offset, point.v0->position.z(), point.v0->position.w());
1243e5c31af7Sopenharmony_ci	const tcu::Vec4		w3			= tcu::Vec4(point.v0->position.x() + offset, point.v0->position.y() - offset, point.v0->position.z(), point.v0->position.w());
1244e5c31af7Sopenharmony_ci
1245e5c31af7Sopenharmony_ci	rasterizer1.init(w0, w1, w2);
1246e5c31af7Sopenharmony_ci	rasterizer2.init(w0, w2, w3);
1247e5c31af7Sopenharmony_ci
1248e5c31af7Sopenharmony_ci	// Shading context
1249e5c31af7Sopenharmony_ci	FragmentShadingContext shadingContext(point.v0->outputs, DE_NULL, DE_NULL, &buffers.shaderOutputs[0], &buffers.shaderOutputsSrc1[0], buffers.fragmentDepthBuffer, point.v0->primitiveID, (int)program.fragmentShader->getOutputs().size(), numSamples, FACETYPE_FRONT);
1250e5c31af7Sopenharmony_ci
1251e5c31af7Sopenharmony_ci	// Execute rasterize - shade - write loop
1252e5c31af7Sopenharmony_ci	for (;;)
1253e5c31af7Sopenharmony_ci	{
1254e5c31af7Sopenharmony_ci		const int	maxFragmentPackets		= (int)buffers.fragmentPackets.size();
1255e5c31af7Sopenharmony_ci		int			numRasterizedPackets	= 0;
1256e5c31af7Sopenharmony_ci
1257e5c31af7Sopenharmony_ci		// Rasterize both triangles
1258e5c31af7Sopenharmony_ci
1259e5c31af7Sopenharmony_ci		rasterizer1.rasterize(&buffers.fragmentPackets[0], buffers.fragmentDepthBuffer, maxFragmentPackets, numRasterizedPackets);
1260e5c31af7Sopenharmony_ci		if (numRasterizedPackets != maxFragmentPackets)
1261e5c31af7Sopenharmony_ci		{
1262e5c31af7Sopenharmony_ci			float* const	depthBufferAppendPointer	= (buffers.fragmentDepthBuffer) ? (buffers.fragmentDepthBuffer + numRasterizedPackets*numSamples*4) : (DE_NULL);
1263e5c31af7Sopenharmony_ci			int				numRasterizedPackets2		= 0;
1264e5c31af7Sopenharmony_ci
1265e5c31af7Sopenharmony_ci			rasterizer2.rasterize(&buffers.fragmentPackets[numRasterizedPackets], depthBufferAppendPointer, maxFragmentPackets - numRasterizedPackets, numRasterizedPackets2);
1266e5c31af7Sopenharmony_ci
1267e5c31af7Sopenharmony_ci			numRasterizedPackets += numRasterizedPackets2;
1268e5c31af7Sopenharmony_ci		}
1269e5c31af7Sopenharmony_ci
1270e5c31af7Sopenharmony_ci		// numRasterizedPackets is guaranteed to be greater than zero for shadeFragments()
1271e5c31af7Sopenharmony_ci
1272e5c31af7Sopenharmony_ci		if (!numRasterizedPackets)
1273e5c31af7Sopenharmony_ci			break; // Rasterization finished.
1274e5c31af7Sopenharmony_ci
1275e5c31af7Sopenharmony_ci		// Shade
1276e5c31af7Sopenharmony_ci
1277e5c31af7Sopenharmony_ci		program.fragmentShader->shadeFragments(&buffers.fragmentPackets[0], numRasterizedPackets, shadingContext);
1278e5c31af7Sopenharmony_ci
1279e5c31af7Sopenharmony_ci		// Depth clamp
1280e5c31af7Sopenharmony_ci		if (buffers.fragmentDepthBuffer && state.fragOps.depthClampEnabled)
1281e5c31af7Sopenharmony_ci			for (int sampleNdx = 0; sampleNdx < numRasterizedPackets * 4 * numSamples; ++sampleNdx)
1282e5c31af7Sopenharmony_ci				buffers.fragmentDepthBuffer[sampleNdx] = de::clamp(buffers.fragmentDepthBuffer[sampleNdx], depthClampMin, depthClampMax);
1283e5c31af7Sopenharmony_ci
1284e5c31af7Sopenharmony_ci		// Handle fragment shader outputs
1285e5c31af7Sopenharmony_ci
1286e5c31af7Sopenharmony_ci		writeFragmentPackets(state, renderTarget, program, &buffers.fragmentPackets[0], numRasterizedPackets, rr::FACETYPE_FRONT, buffers.shaderOutputs, buffers.shaderOutputsSrc1, buffers.fragmentDepthBuffer, buffers.shadedFragments);
1287e5c31af7Sopenharmony_ci	}
1288e5c31af7Sopenharmony_ci}
1289e5c31af7Sopenharmony_ci
1290e5c31af7Sopenharmony_citemplate <typename ContainerType>
1291e5c31af7Sopenharmony_civoid rasterize (const RenderState&					state,
1292e5c31af7Sopenharmony_ci				const RenderTarget&					renderTarget,
1293e5c31af7Sopenharmony_ci				const Program&						program,
1294e5c31af7Sopenharmony_ci				const ContainerType&				list)
1295e5c31af7Sopenharmony_ci{
1296e5c31af7Sopenharmony_ci	const int						numSamples			= renderTarget.getNumSamples();
1297e5c31af7Sopenharmony_ci	const int						numFragmentOutputs	= (int)program.fragmentShader->getOutputs().size();
1298e5c31af7Sopenharmony_ci	const size_t					maxFragmentPackets	= 128;
1299e5c31af7Sopenharmony_ci
1300e5c31af7Sopenharmony_ci	const tcu::IVec4				viewportRect		= tcu::IVec4(state.viewport.rect.left, state.viewport.rect.bottom, state.viewport.rect.width, state.viewport.rect.height);
1301e5c31af7Sopenharmony_ci	const tcu::IVec4				bufferRect			= getBufferSize(renderTarget.getColorBuffer(0));
1302e5c31af7Sopenharmony_ci	const tcu::IVec4				renderTargetRect	= rectIntersection(viewportRect, bufferRect);
1303e5c31af7Sopenharmony_ci
1304e5c31af7Sopenharmony_ci	// shared buffers for all primitives
1305e5c31af7Sopenharmony_ci	std::vector<FragmentPacket>		fragmentPackets		(maxFragmentPackets);
1306e5c31af7Sopenharmony_ci	std::vector<GenericVec4>		shaderOutputs		(maxFragmentPackets*4*numFragmentOutputs);
1307e5c31af7Sopenharmony_ci	std::vector<GenericVec4>		shaderOutputsSrc1	(maxFragmentPackets*4*numFragmentOutputs);
1308e5c31af7Sopenharmony_ci	std::vector<Fragment>			shadedFragments		(maxFragmentPackets*4);
1309e5c31af7Sopenharmony_ci	std::vector<float>				depthValues			(0);
1310e5c31af7Sopenharmony_ci	float*							depthBufferPointer	= DE_NULL;
1311e5c31af7Sopenharmony_ci
1312e5c31af7Sopenharmony_ci	RasterizationInternalBuffers	buffers;
1313e5c31af7Sopenharmony_ci
1314e5c31af7Sopenharmony_ci	// calculate depth only if we have a depth buffer
1315e5c31af7Sopenharmony_ci	if (!isEmpty(renderTarget.getDepthBuffer()))
1316e5c31af7Sopenharmony_ci	{
1317e5c31af7Sopenharmony_ci		depthValues.resize(maxFragmentPackets*4*numSamples);
1318e5c31af7Sopenharmony_ci		depthBufferPointer = &depthValues[0];
1319e5c31af7Sopenharmony_ci	}
1320e5c31af7Sopenharmony_ci
1321e5c31af7Sopenharmony_ci	// set buffers
1322e5c31af7Sopenharmony_ci	buffers.fragmentPackets.swap(fragmentPackets);
1323e5c31af7Sopenharmony_ci	buffers.shaderOutputs.swap(shaderOutputs);
1324e5c31af7Sopenharmony_ci	buffers.shaderOutputsSrc1.swap(shaderOutputsSrc1);
1325e5c31af7Sopenharmony_ci	buffers.shadedFragments.swap(shadedFragments);
1326e5c31af7Sopenharmony_ci	buffers.fragmentDepthBuffer = depthBufferPointer;
1327e5c31af7Sopenharmony_ci
1328e5c31af7Sopenharmony_ci	// rasterize
1329e5c31af7Sopenharmony_ci	for (typename ContainerType::const_iterator it = list.begin(); it != list.end(); ++it)
1330e5c31af7Sopenharmony_ci		rasterizePrimitive(state, renderTarget, program, *it, renderTargetRect, buffers);
1331e5c31af7Sopenharmony_ci}
1332e5c31af7Sopenharmony_ci
1333e5c31af7Sopenharmony_ci/*--------------------------------------------------------------------*//*!
1334e5c31af7Sopenharmony_ci * Draws transformed triangles, lines or points to render target
1335e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
1336e5c31af7Sopenharmony_citemplate <typename ContainerType>
1337e5c31af7Sopenharmony_civoid drawBasicPrimitives (const RenderState& state, const RenderTarget& renderTarget, const Program& program, ContainerType& primList, VertexPacketAllocator& vpalloc)
1338e5c31af7Sopenharmony_ci{
1339e5c31af7Sopenharmony_ci	const bool clipZ = !state.fragOps.depthClampEnabled;
1340e5c31af7Sopenharmony_ci
1341e5c31af7Sopenharmony_ci	// Transform feedback
1342e5c31af7Sopenharmony_ci
1343e5c31af7Sopenharmony_ci	// Flatshading
1344e5c31af7Sopenharmony_ci	flatshadeVertices(program, primList);
1345e5c31af7Sopenharmony_ci
1346e5c31af7Sopenharmony_ci	// Clipping
1347e5c31af7Sopenharmony_ci	// \todo [jarkko] is creating & swapping std::vectors really a good solution?
1348e5c31af7Sopenharmony_ci	clipPrimitives(primList, program, clipZ, vpalloc);
1349e5c31af7Sopenharmony_ci
1350e5c31af7Sopenharmony_ci	// Transform vertices to window coords
1351e5c31af7Sopenharmony_ci	transformClipCoordsToWindowCoords(state, primList);
1352e5c31af7Sopenharmony_ci
1353e5c31af7Sopenharmony_ci	// Rasterize and paint
1354e5c31af7Sopenharmony_ci	rasterize(state, renderTarget, program, primList);
1355e5c31af7Sopenharmony_ci}
1356e5c31af7Sopenharmony_ci
1357e5c31af7Sopenharmony_civoid copyVertexPacketPointers(const VertexPacket** dst, const pa::Point& in)
1358e5c31af7Sopenharmony_ci{
1359e5c31af7Sopenharmony_ci	dst[0] = in.v0;
1360e5c31af7Sopenharmony_ci}
1361e5c31af7Sopenharmony_ci
1362e5c31af7Sopenharmony_civoid copyVertexPacketPointers(const VertexPacket** dst, const pa::Line& in)
1363e5c31af7Sopenharmony_ci{
1364e5c31af7Sopenharmony_ci	dst[0] = in.v0;
1365e5c31af7Sopenharmony_ci	dst[1] = in.v1;
1366e5c31af7Sopenharmony_ci}
1367e5c31af7Sopenharmony_ci
1368e5c31af7Sopenharmony_civoid copyVertexPacketPointers(const VertexPacket** dst, const pa::Triangle& in)
1369e5c31af7Sopenharmony_ci{
1370e5c31af7Sopenharmony_ci	dst[0] = in.v0;
1371e5c31af7Sopenharmony_ci	dst[1] = in.v1;
1372e5c31af7Sopenharmony_ci	dst[2] = in.v2;
1373e5c31af7Sopenharmony_ci}
1374e5c31af7Sopenharmony_ci
1375e5c31af7Sopenharmony_civoid copyVertexPacketPointers(const VertexPacket** dst, const pa::LineAdjacency& in)
1376e5c31af7Sopenharmony_ci{
1377e5c31af7Sopenharmony_ci	dst[0] = in.v0;
1378e5c31af7Sopenharmony_ci	dst[1] = in.v1;
1379e5c31af7Sopenharmony_ci	dst[2] = in.v2;
1380e5c31af7Sopenharmony_ci	dst[3] = in.v3;
1381e5c31af7Sopenharmony_ci}
1382e5c31af7Sopenharmony_ci
1383e5c31af7Sopenharmony_civoid copyVertexPacketPointers(const VertexPacket** dst, const pa::TriangleAdjacency& in)
1384e5c31af7Sopenharmony_ci{
1385e5c31af7Sopenharmony_ci	dst[0] = in.v0;
1386e5c31af7Sopenharmony_ci	dst[1] = in.v1;
1387e5c31af7Sopenharmony_ci	dst[2] = in.v2;
1388e5c31af7Sopenharmony_ci	dst[3] = in.v3;
1389e5c31af7Sopenharmony_ci	dst[4] = in.v4;
1390e5c31af7Sopenharmony_ci	dst[5] = in.v5;
1391e5c31af7Sopenharmony_ci}
1392e5c31af7Sopenharmony_ci
1393e5c31af7Sopenharmony_citemplate <PrimitiveType DrawPrimitiveType> // \note DrawPrimitiveType  can only be Points, line_strip, or triangle_strip
1394e5c31af7Sopenharmony_civoid drawGeometryShaderOutputAsPrimitives (const RenderState& state, const RenderTarget& renderTarget, const Program& program, VertexPacket* const* vertices, size_t numVertices, VertexPacketAllocator& vpalloc)
1395e5c31af7Sopenharmony_ci{
1396e5c31af7Sopenharmony_ci	// Run primitive assembly for generated stream
1397e5c31af7Sopenharmony_ci
1398e5c31af7Sopenharmony_ci	const size_t															assemblerPrimitiveCount		= PrimitiveTypeTraits<DrawPrimitiveType>::Assembler::getPrimitiveCount(numVertices);
1399e5c31af7Sopenharmony_ci	std::vector<typename PrimitiveTypeTraits<DrawPrimitiveType>::BaseType>	inputPrimitives				(assemblerPrimitiveCount);
1400e5c31af7Sopenharmony_ci
1401e5c31af7Sopenharmony_ci	PrimitiveTypeTraits<DrawPrimitiveType>::Assembler::exec(inputPrimitives.begin(), vertices, numVertices, state.provokingVertexConvention); // \note input Primitives are baseType_t => only basic primitives (non adjacency) will compile
1402e5c31af7Sopenharmony_ci
1403e5c31af7Sopenharmony_ci	// Make shared vertices distinct
1404e5c31af7Sopenharmony_ci
1405e5c31af7Sopenharmony_ci	makeSharedVerticesDistinct(inputPrimitives, vpalloc);
1406e5c31af7Sopenharmony_ci
1407e5c31af7Sopenharmony_ci	// Draw assembled primitives
1408e5c31af7Sopenharmony_ci
1409e5c31af7Sopenharmony_ci	drawBasicPrimitives(state, renderTarget, program, inputPrimitives, vpalloc);
1410e5c31af7Sopenharmony_ci}
1411e5c31af7Sopenharmony_ci
1412e5c31af7Sopenharmony_citemplate <PrimitiveType DrawPrimitiveType>
1413e5c31af7Sopenharmony_civoid drawWithGeometryShader(const RenderState& state, const RenderTarget& renderTarget, const Program& program, std::vector<typename PrimitiveTypeTraits<DrawPrimitiveType>::Type>& input, DrawContext& drawContext)
1414e5c31af7Sopenharmony_ci{
1415e5c31af7Sopenharmony_ci	// Vertices outputted by geometry shader may have different number of output variables than the original, create new memory allocator
1416e5c31af7Sopenharmony_ci	VertexPacketAllocator vpalloc(program.geometryShader->getOutputs().size());
1417e5c31af7Sopenharmony_ci
1418e5c31af7Sopenharmony_ci	// Run geometry shader for all primitives
1419e5c31af7Sopenharmony_ci	GeometryEmitter					emitter			(vpalloc, program.geometryShader->getNumVerticesOut());
1420e5c31af7Sopenharmony_ci	std::vector<PrimitivePacket>	primitives		(input.size());
1421e5c31af7Sopenharmony_ci	const int						numInvocations	= (int)program.geometryShader->getNumInvocations();
1422e5c31af7Sopenharmony_ci	const int						verticesIn		= PrimitiveTypeTraits<DrawPrimitiveType>::Type::NUM_VERTICES;
1423e5c31af7Sopenharmony_ci
1424e5c31af7Sopenharmony_ci	for (size_t primitiveNdx = 0; primitiveNdx < input.size(); ++primitiveNdx)
1425e5c31af7Sopenharmony_ci	{
1426e5c31af7Sopenharmony_ci		primitives[primitiveNdx].primitiveIDIn = drawContext.primitiveID++;
1427e5c31af7Sopenharmony_ci		copyVertexPacketPointers(primitives[primitiveNdx].vertices, input[primitiveNdx]);
1428e5c31af7Sopenharmony_ci	}
1429e5c31af7Sopenharmony_ci
1430e5c31af7Sopenharmony_ci	if (primitives.empty())
1431e5c31af7Sopenharmony_ci		return;
1432e5c31af7Sopenharmony_ci
1433e5c31af7Sopenharmony_ci	for (int invocationNdx = 0; invocationNdx < numInvocations; ++invocationNdx)
1434e5c31af7Sopenharmony_ci	{
1435e5c31af7Sopenharmony_ci		// Shading invocation
1436e5c31af7Sopenharmony_ci
1437e5c31af7Sopenharmony_ci		program.geometryShader->shadePrimitives(emitter, verticesIn, &primitives[0], (int)primitives.size(), invocationNdx);
1438e5c31af7Sopenharmony_ci
1439e5c31af7Sopenharmony_ci		// Find primitives in the emitted vertices
1440e5c31af7Sopenharmony_ci
1441e5c31af7Sopenharmony_ci		std::vector<VertexPacket*> emitted;
1442e5c31af7Sopenharmony_ci		emitter.moveEmittedTo(emitted);
1443e5c31af7Sopenharmony_ci
1444e5c31af7Sopenharmony_ci		for (size_t primitiveBegin = 0; primitiveBegin < emitted.size();)
1445e5c31af7Sopenharmony_ci		{
1446e5c31af7Sopenharmony_ci			size_t primitiveEnd;
1447e5c31af7Sopenharmony_ci
1448e5c31af7Sopenharmony_ci			// Find primitive begin
1449e5c31af7Sopenharmony_ci			if (!emitted[primitiveBegin])
1450e5c31af7Sopenharmony_ci			{
1451e5c31af7Sopenharmony_ci				++primitiveBegin;
1452e5c31af7Sopenharmony_ci				continue;
1453e5c31af7Sopenharmony_ci			}
1454e5c31af7Sopenharmony_ci
1455e5c31af7Sopenharmony_ci			// Find primitive end
1456e5c31af7Sopenharmony_ci
1457e5c31af7Sopenharmony_ci			primitiveEnd = primitiveBegin + 1;
1458e5c31af7Sopenharmony_ci			for (; (primitiveEnd < emitted.size()) && emitted[primitiveEnd]; ++primitiveEnd); // find primitive end
1459e5c31af7Sopenharmony_ci
1460e5c31af7Sopenharmony_ci			// Draw range [begin, end)
1461e5c31af7Sopenharmony_ci
1462e5c31af7Sopenharmony_ci			switch (program.geometryShader->getOutputType())
1463e5c31af7Sopenharmony_ci			{
1464e5c31af7Sopenharmony_ci				case rr::GEOMETRYSHADEROUTPUTTYPE_POINTS:			drawGeometryShaderOutputAsPrimitives<PRIMITIVETYPE_POINTS>			(state, renderTarget, program, &emitted[primitiveBegin], primitiveEnd-primitiveBegin, vpalloc); break;
1465e5c31af7Sopenharmony_ci				case rr::GEOMETRYSHADEROUTPUTTYPE_LINE_STRIP:		drawGeometryShaderOutputAsPrimitives<PRIMITIVETYPE_LINE_STRIP>		(state, renderTarget, program, &emitted[primitiveBegin], primitiveEnd-primitiveBegin, vpalloc); break;
1466e5c31af7Sopenharmony_ci				case rr::GEOMETRYSHADEROUTPUTTYPE_TRIANGLE_STRIP:	drawGeometryShaderOutputAsPrimitives<PRIMITIVETYPE_TRIANGLE_STRIP>	(state, renderTarget, program, &emitted[primitiveBegin], primitiveEnd-primitiveBegin, vpalloc); break;
1467e5c31af7Sopenharmony_ci				default:
1468e5c31af7Sopenharmony_ci					DE_ASSERT(DE_FALSE);
1469e5c31af7Sopenharmony_ci			}
1470e5c31af7Sopenharmony_ci
1471e5c31af7Sopenharmony_ci			// Next primitive
1472e5c31af7Sopenharmony_ci			primitiveBegin = primitiveEnd + 1;
1473e5c31af7Sopenharmony_ci		}
1474e5c31af7Sopenharmony_ci	}
1475e5c31af7Sopenharmony_ci}
1476e5c31af7Sopenharmony_ci
1477e5c31af7Sopenharmony_ci/*--------------------------------------------------------------------*//*!
1478e5c31af7Sopenharmony_ci * Assembles, tesselates, runs geometry shader and draws primitives of any type from vertex list.
1479e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
1480e5c31af7Sopenharmony_citemplate <PrimitiveType DrawPrimitiveType>
1481e5c31af7Sopenharmony_civoid drawAsPrimitives (const RenderState& state, const RenderTarget& renderTarget, const Program& program, VertexPacket* const* vertices, int numVertices, DrawContext& drawContext, VertexPacketAllocator& vpalloc)
1482e5c31af7Sopenharmony_ci{
1483e5c31af7Sopenharmony_ci	// Assemble primitives (deconstruct stips & loops)
1484e5c31af7Sopenharmony_ci	const size_t															assemblerPrimitiveCount		= PrimitiveTypeTraits<DrawPrimitiveType>::Assembler::getPrimitiveCount(numVertices);
1485e5c31af7Sopenharmony_ci	std::vector<typename PrimitiveTypeTraits<DrawPrimitiveType>::Type>		inputPrimitives				(assemblerPrimitiveCount);
1486e5c31af7Sopenharmony_ci
1487e5c31af7Sopenharmony_ci	PrimitiveTypeTraits<DrawPrimitiveType>::Assembler::exec(inputPrimitives.begin(), vertices, (size_t)numVertices, state.provokingVertexConvention);
1488e5c31af7Sopenharmony_ci
1489e5c31af7Sopenharmony_ci	// Tesselate
1490e5c31af7Sopenharmony_ci	//if (state.tesselation)
1491e5c31af7Sopenharmony_ci	//	primList = state.tesselation.exec(primList);
1492e5c31af7Sopenharmony_ci
1493e5c31af7Sopenharmony_ci	// Geometry shader
1494e5c31af7Sopenharmony_ci	if (program.geometryShader)
1495e5c31af7Sopenharmony_ci	{
1496e5c31af7Sopenharmony_ci		// If there is an active geometry shader, it will convert any primitive type to basic types
1497e5c31af7Sopenharmony_ci		drawWithGeometryShader<DrawPrimitiveType>(state, renderTarget, program, inputPrimitives, drawContext);
1498e5c31af7Sopenharmony_ci	}
1499e5c31af7Sopenharmony_ci	else
1500e5c31af7Sopenharmony_ci	{
1501e5c31af7Sopenharmony_ci		std::vector<typename PrimitiveTypeTraits<DrawPrimitiveType>::BaseType> basePrimitives;
1502e5c31af7Sopenharmony_ci
1503e5c31af7Sopenharmony_ci		// convert types from X_adjacency to X
1504e5c31af7Sopenharmony_ci		convertPrimitiveToBaseType(basePrimitives, inputPrimitives);
1505e5c31af7Sopenharmony_ci
1506e5c31af7Sopenharmony_ci		// Make shared vertices distinct. Needed for that the translation to screen space happens only once per vertex, and for flatshading
1507e5c31af7Sopenharmony_ci		makeSharedVerticesDistinct(basePrimitives, vpalloc);
1508e5c31af7Sopenharmony_ci
1509e5c31af7Sopenharmony_ci		// A primitive ID will be generated even if no geometry shader is active
1510e5c31af7Sopenharmony_ci		generatePrimitiveIDs(basePrimitives, drawContext);
1511e5c31af7Sopenharmony_ci
1512e5c31af7Sopenharmony_ci		// Draw as a basic type
1513e5c31af7Sopenharmony_ci		drawBasicPrimitives(state, renderTarget, program, basePrimitives, vpalloc);
1514e5c31af7Sopenharmony_ci	}
1515e5c31af7Sopenharmony_ci}
1516e5c31af7Sopenharmony_ci
1517e5c31af7Sopenharmony_cibool isValidCommand (const DrawCommand& command, int numInstances)
1518e5c31af7Sopenharmony_ci{
1519e5c31af7Sopenharmony_ci	// numInstances should be valid
1520e5c31af7Sopenharmony_ci	if (numInstances < 0)
1521e5c31af7Sopenharmony_ci		return false;
1522e5c31af7Sopenharmony_ci
1523e5c31af7Sopenharmony_ci	// Shaders should have the same varyings
1524e5c31af7Sopenharmony_ci	if (command.program.geometryShader)
1525e5c31af7Sopenharmony_ci	{
1526e5c31af7Sopenharmony_ci		if (command.program.vertexShader->getOutputs() != command.program.geometryShader->getInputs())
1527e5c31af7Sopenharmony_ci			return false;
1528e5c31af7Sopenharmony_ci
1529e5c31af7Sopenharmony_ci		if (command.program.geometryShader->getOutputs() != command.program.fragmentShader->getInputs())
1530e5c31af7Sopenharmony_ci			return false;
1531e5c31af7Sopenharmony_ci	}
1532e5c31af7Sopenharmony_ci	else
1533e5c31af7Sopenharmony_ci	{
1534e5c31af7Sopenharmony_ci		if (command.program.vertexShader->getOutputs() != command.program.fragmentShader->getInputs())
1535e5c31af7Sopenharmony_ci			return false;
1536e5c31af7Sopenharmony_ci	}
1537e5c31af7Sopenharmony_ci
1538e5c31af7Sopenharmony_ci	// Shader input/output types are set
1539e5c31af7Sopenharmony_ci	for (size_t varyingNdx = 0; varyingNdx < command.program.vertexShader->getInputs().size(); ++varyingNdx)
1540e5c31af7Sopenharmony_ci		if (command.program.vertexShader->getInputs()[varyingNdx].type != GENERICVECTYPE_FLOAT &&
1541e5c31af7Sopenharmony_ci			command.program.vertexShader->getInputs()[varyingNdx].type != GENERICVECTYPE_INT32 &&
1542e5c31af7Sopenharmony_ci			command.program.vertexShader->getInputs()[varyingNdx].type != GENERICVECTYPE_UINT32)
1543e5c31af7Sopenharmony_ci			return false;
1544e5c31af7Sopenharmony_ci	for (size_t varyingNdx = 0; varyingNdx < command.program.vertexShader->getOutputs().size(); ++varyingNdx)
1545e5c31af7Sopenharmony_ci		if (command.program.vertexShader->getOutputs()[varyingNdx].type != GENERICVECTYPE_FLOAT &&
1546e5c31af7Sopenharmony_ci			command.program.vertexShader->getOutputs()[varyingNdx].type != GENERICVECTYPE_INT32 &&
1547e5c31af7Sopenharmony_ci			command.program.vertexShader->getOutputs()[varyingNdx].type != GENERICVECTYPE_UINT32)
1548e5c31af7Sopenharmony_ci			return false;
1549e5c31af7Sopenharmony_ci
1550e5c31af7Sopenharmony_ci	for (size_t varyingNdx = 0; varyingNdx < command.program.fragmentShader->getInputs().size(); ++varyingNdx)
1551e5c31af7Sopenharmony_ci		if (command.program.fragmentShader->getInputs()[varyingNdx].type != GENERICVECTYPE_FLOAT &&
1552e5c31af7Sopenharmony_ci			command.program.fragmentShader->getInputs()[varyingNdx].type != GENERICVECTYPE_INT32 &&
1553e5c31af7Sopenharmony_ci			command.program.fragmentShader->getInputs()[varyingNdx].type != GENERICVECTYPE_UINT32)
1554e5c31af7Sopenharmony_ci			return false;
1555e5c31af7Sopenharmony_ci	for (size_t varyingNdx = 0; varyingNdx < command.program.fragmentShader->getOutputs().size(); ++varyingNdx)
1556e5c31af7Sopenharmony_ci		if (command.program.fragmentShader->getOutputs()[varyingNdx].type != GENERICVECTYPE_FLOAT &&
1557e5c31af7Sopenharmony_ci			command.program.fragmentShader->getOutputs()[varyingNdx].type != GENERICVECTYPE_INT32 &&
1558e5c31af7Sopenharmony_ci			command.program.fragmentShader->getOutputs()[varyingNdx].type != GENERICVECTYPE_UINT32)
1559e5c31af7Sopenharmony_ci			return false;
1560e5c31af7Sopenharmony_ci
1561e5c31af7Sopenharmony_ci	if (command.program.geometryShader)
1562e5c31af7Sopenharmony_ci	{
1563e5c31af7Sopenharmony_ci		for (size_t varyingNdx = 0; varyingNdx < command.program.geometryShader->getInputs().size(); ++varyingNdx)
1564e5c31af7Sopenharmony_ci			if (command.program.geometryShader->getInputs()[varyingNdx].type != GENERICVECTYPE_FLOAT &&
1565e5c31af7Sopenharmony_ci				command.program.geometryShader->getInputs()[varyingNdx].type != GENERICVECTYPE_INT32 &&
1566e5c31af7Sopenharmony_ci				command.program.geometryShader->getInputs()[varyingNdx].type != GENERICVECTYPE_UINT32)
1567e5c31af7Sopenharmony_ci				return false;
1568e5c31af7Sopenharmony_ci		for (size_t varyingNdx = 0; varyingNdx < command.program.geometryShader->getOutputs().size(); ++varyingNdx)
1569e5c31af7Sopenharmony_ci			if (command.program.geometryShader->getOutputs()[varyingNdx].type != GENERICVECTYPE_FLOAT &&
1570e5c31af7Sopenharmony_ci				command.program.geometryShader->getOutputs()[varyingNdx].type != GENERICVECTYPE_INT32 &&
1571e5c31af7Sopenharmony_ci				command.program.geometryShader->getOutputs()[varyingNdx].type != GENERICVECTYPE_UINT32)
1572e5c31af7Sopenharmony_ci				return false;
1573e5c31af7Sopenharmony_ci	}
1574e5c31af7Sopenharmony_ci
1575e5c31af7Sopenharmony_ci	// Enough vertex inputs?
1576e5c31af7Sopenharmony_ci	if ((size_t)command.numVertexAttribs < command.program.vertexShader->getInputs().size())
1577e5c31af7Sopenharmony_ci		return false;
1578e5c31af7Sopenharmony_ci
1579e5c31af7Sopenharmony_ci	// There is a fragment output sink for each output?
1580e5c31af7Sopenharmony_ci	if ((size_t)command.renderTarget.getNumColorBuffers() < command.program.fragmentShader->getOutputs().size())
1581e5c31af7Sopenharmony_ci		return false;
1582e5c31af7Sopenharmony_ci
1583e5c31af7Sopenharmony_ci	// All destination buffers should have same number of samples and same size
1584e5c31af7Sopenharmony_ci	for (int outputNdx = 0; outputNdx < command.renderTarget.getNumColorBuffers(); ++outputNdx)
1585e5c31af7Sopenharmony_ci	{
1586e5c31af7Sopenharmony_ci		if (getBufferSize(command.renderTarget.getColorBuffer(0)) != getBufferSize(command.renderTarget.getColorBuffer(outputNdx)))
1587e5c31af7Sopenharmony_ci			return false;
1588e5c31af7Sopenharmony_ci
1589e5c31af7Sopenharmony_ci		if (command.renderTarget.getNumSamples() != command.renderTarget.getColorBuffer(outputNdx).getNumSamples())
1590e5c31af7Sopenharmony_ci			return false;
1591e5c31af7Sopenharmony_ci	}
1592e5c31af7Sopenharmony_ci
1593e5c31af7Sopenharmony_ci	// All destination buffers should have same basic type as matching fragment output
1594e5c31af7Sopenharmony_ci	for (size_t varyingNdx = 0; varyingNdx < command.program.fragmentShader->getOutputs().size(); ++varyingNdx)
1595e5c31af7Sopenharmony_ci	{
1596e5c31af7Sopenharmony_ci		const tcu::TextureChannelClass	colorbufferClass = tcu::getTextureChannelClass(command.renderTarget.getColorBuffer((int)varyingNdx).raw().getFormat().type);
1597e5c31af7Sopenharmony_ci		const GenericVecType			colorType		 = (colorbufferClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER) ? (rr::GENERICVECTYPE_INT32) : ((colorbufferClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER) ? (rr::GENERICVECTYPE_UINT32) : (rr::GENERICVECTYPE_FLOAT));
1598e5c31af7Sopenharmony_ci
1599e5c31af7Sopenharmony_ci		if (command.program.fragmentShader->getOutputs()[varyingNdx].type != colorType)
1600e5c31af7Sopenharmony_ci			return false;
1601e5c31af7Sopenharmony_ci	}
1602e5c31af7Sopenharmony_ci
1603e5c31af7Sopenharmony_ci	// Integer values are flatshaded
1604e5c31af7Sopenharmony_ci	for (size_t outputNdx = 0; outputNdx < command.program.vertexShader->getOutputs().size(); ++outputNdx)
1605e5c31af7Sopenharmony_ci	{
1606e5c31af7Sopenharmony_ci		if (!command.program.vertexShader->getOutputs()[outputNdx].flatshade &&
1607e5c31af7Sopenharmony_ci			(command.program.vertexShader->getOutputs()[outputNdx].type == GENERICVECTYPE_INT32 ||
1608e5c31af7Sopenharmony_ci			 command.program.vertexShader->getOutputs()[outputNdx].type == GENERICVECTYPE_UINT32))
1609e5c31af7Sopenharmony_ci			return false;
1610e5c31af7Sopenharmony_ci	}
1611e5c31af7Sopenharmony_ci	if (command.program.geometryShader)
1612e5c31af7Sopenharmony_ci		for (size_t outputNdx = 0; outputNdx < command.program.geometryShader->getOutputs().size(); ++outputNdx)
1613e5c31af7Sopenharmony_ci		{
1614e5c31af7Sopenharmony_ci			if (!command.program.geometryShader->getOutputs()[outputNdx].flatshade &&
1615e5c31af7Sopenharmony_ci				(command.program.geometryShader->getOutputs()[outputNdx].type == GENERICVECTYPE_INT32 ||
1616e5c31af7Sopenharmony_ci				 command.program.geometryShader->getOutputs()[outputNdx].type == GENERICVECTYPE_UINT32))
1617e5c31af7Sopenharmony_ci				return false;
1618e5c31af7Sopenharmony_ci		}
1619e5c31af7Sopenharmony_ci
1620e5c31af7Sopenharmony_ci	// Draw primitive is valid for geometry shader
1621e5c31af7Sopenharmony_ci	if (command.program.geometryShader)
1622e5c31af7Sopenharmony_ci	{
1623e5c31af7Sopenharmony_ci		if (command.program.geometryShader->getInputType() == rr::GEOMETRYSHADERINPUTTYPE_POINTS && command.primitives.getPrimitiveType() != PRIMITIVETYPE_POINTS)
1624e5c31af7Sopenharmony_ci			return false;
1625e5c31af7Sopenharmony_ci
1626e5c31af7Sopenharmony_ci		if (command.program.geometryShader->getInputType() == rr::GEOMETRYSHADERINPUTTYPE_LINES &&
1627e5c31af7Sopenharmony_ci			(command.primitives.getPrimitiveType() != PRIMITIVETYPE_LINES &&
1628e5c31af7Sopenharmony_ci			 command.primitives.getPrimitiveType() != PRIMITIVETYPE_LINE_STRIP &&
1629e5c31af7Sopenharmony_ci			 command.primitives.getPrimitiveType() != PRIMITIVETYPE_LINE_LOOP))
1630e5c31af7Sopenharmony_ci			return false;
1631e5c31af7Sopenharmony_ci
1632e5c31af7Sopenharmony_ci		if (command.program.geometryShader->getInputType() == rr::GEOMETRYSHADERINPUTTYPE_TRIANGLES &&
1633e5c31af7Sopenharmony_ci			(command.primitives.getPrimitiveType() != PRIMITIVETYPE_TRIANGLES &&
1634e5c31af7Sopenharmony_ci			 command.primitives.getPrimitiveType() != PRIMITIVETYPE_TRIANGLE_STRIP &&
1635e5c31af7Sopenharmony_ci			 command.primitives.getPrimitiveType() != PRIMITIVETYPE_TRIANGLE_FAN))
1636e5c31af7Sopenharmony_ci			return false;
1637e5c31af7Sopenharmony_ci
1638e5c31af7Sopenharmony_ci		if (command.program.geometryShader->getInputType() == rr::GEOMETRYSHADERINPUTTYPE_LINES_ADJACENCY &&
1639e5c31af7Sopenharmony_ci			(command.primitives.getPrimitiveType() != PRIMITIVETYPE_LINES_ADJACENCY &&
1640e5c31af7Sopenharmony_ci			 command.primitives.getPrimitiveType() != PRIMITIVETYPE_LINE_STRIP_ADJACENCY))
1641e5c31af7Sopenharmony_ci			return false;
1642e5c31af7Sopenharmony_ci
1643e5c31af7Sopenharmony_ci		if (command.program.geometryShader->getInputType() == rr::GEOMETRYSHADERINPUTTYPE_TRIANGLES_ADJACENCY &&
1644e5c31af7Sopenharmony_ci			(command.primitives.getPrimitiveType() != PRIMITIVETYPE_TRIANGLES_ADJACENCY &&
1645e5c31af7Sopenharmony_ci			 command.primitives.getPrimitiveType() != PRIMITIVETYPE_TRIANGLE_STRIP_ADJACENCY))
1646e5c31af7Sopenharmony_ci			return false;
1647e5c31af7Sopenharmony_ci	}
1648e5c31af7Sopenharmony_ci
1649e5c31af7Sopenharmony_ci	return true;
1650e5c31af7Sopenharmony_ci}
1651e5c31af7Sopenharmony_ci
1652e5c31af7Sopenharmony_ci} // anonymous
1653e5c31af7Sopenharmony_ci
1654e5c31af7Sopenharmony_ciRenderTarget::RenderTarget (const MultisamplePixelBufferAccess& colorMultisampleBuffer,
1655e5c31af7Sopenharmony_ci							const MultisamplePixelBufferAccess& depthMultisampleBuffer,
1656e5c31af7Sopenharmony_ci							const MultisamplePixelBufferAccess& stencilMultisampleBuffer)
1657e5c31af7Sopenharmony_ci	: m_numColorBuffers	(1)
1658e5c31af7Sopenharmony_ci	, m_depthBuffer		(MultisamplePixelBufferAccess::fromMultisampleAccess(tcu::getEffectiveDepthStencilAccess(depthMultisampleBuffer.raw(), tcu::Sampler::MODE_DEPTH)))
1659e5c31af7Sopenharmony_ci	, m_stencilBuffer	(MultisamplePixelBufferAccess::fromMultisampleAccess(tcu::getEffectiveDepthStencilAccess(stencilMultisampleBuffer.raw(), tcu::Sampler::MODE_STENCIL)))
1660e5c31af7Sopenharmony_ci{
1661e5c31af7Sopenharmony_ci	m_colorBuffers[0] = colorMultisampleBuffer;
1662e5c31af7Sopenharmony_ci}
1663e5c31af7Sopenharmony_ci
1664e5c31af7Sopenharmony_ciint RenderTarget::getNumSamples (void) const
1665e5c31af7Sopenharmony_ci{
1666e5c31af7Sopenharmony_ci	DE_ASSERT(m_numColorBuffers > 0);
1667e5c31af7Sopenharmony_ci	return m_colorBuffers[0].getNumSamples();
1668e5c31af7Sopenharmony_ci}
1669e5c31af7Sopenharmony_ci
1670e5c31af7Sopenharmony_ciDrawIndices::DrawIndices (const deUint32* ptr, int baseVertex_)
1671e5c31af7Sopenharmony_ci	: indices	(ptr)
1672e5c31af7Sopenharmony_ci	, indexType	(INDEXTYPE_UINT32)
1673e5c31af7Sopenharmony_ci	, baseVertex(baseVertex_)
1674e5c31af7Sopenharmony_ci{
1675e5c31af7Sopenharmony_ci}
1676e5c31af7Sopenharmony_ci
1677e5c31af7Sopenharmony_ciDrawIndices::DrawIndices (const deUint16* ptr, int baseVertex_)
1678e5c31af7Sopenharmony_ci	: indices	(ptr)
1679e5c31af7Sopenharmony_ci	, indexType	(INDEXTYPE_UINT16)
1680e5c31af7Sopenharmony_ci	, baseVertex(baseVertex_)
1681e5c31af7Sopenharmony_ci{
1682e5c31af7Sopenharmony_ci}
1683e5c31af7Sopenharmony_ci
1684e5c31af7Sopenharmony_ciDrawIndices::DrawIndices (const deUint8* ptr, int baseVertex_)
1685e5c31af7Sopenharmony_ci	: indices	(ptr)
1686e5c31af7Sopenharmony_ci	, indexType	(INDEXTYPE_UINT8)
1687e5c31af7Sopenharmony_ci	, baseVertex(baseVertex_)
1688e5c31af7Sopenharmony_ci{
1689e5c31af7Sopenharmony_ci}
1690e5c31af7Sopenharmony_ci
1691e5c31af7Sopenharmony_ciDrawIndices::DrawIndices (const void* ptr, IndexType type, int baseVertex_)
1692e5c31af7Sopenharmony_ci	: indices	(ptr)
1693e5c31af7Sopenharmony_ci	, indexType	(type)
1694e5c31af7Sopenharmony_ci	, baseVertex(baseVertex_)
1695e5c31af7Sopenharmony_ci{
1696e5c31af7Sopenharmony_ci}
1697e5c31af7Sopenharmony_ci
1698e5c31af7Sopenharmony_ciPrimitiveList::PrimitiveList (PrimitiveType primitiveType, int numElements, const int firstElement)
1699e5c31af7Sopenharmony_ci	: m_primitiveType	(primitiveType)
1700e5c31af7Sopenharmony_ci	, m_numElements		(numElements)
1701e5c31af7Sopenharmony_ci	, m_indices			(DE_NULL)
1702e5c31af7Sopenharmony_ci	, m_indexType		(INDEXTYPE_LAST)
1703e5c31af7Sopenharmony_ci	, m_baseVertex		(firstElement)
1704e5c31af7Sopenharmony_ci{
1705e5c31af7Sopenharmony_ci	DE_ASSERT(numElements >= 0 && "Invalid numElements");
1706e5c31af7Sopenharmony_ci	DE_ASSERT(firstElement >= 0 && "Invalid firstElement");
1707e5c31af7Sopenharmony_ci}
1708e5c31af7Sopenharmony_ci
1709e5c31af7Sopenharmony_ciPrimitiveList::PrimitiveList (PrimitiveType primitiveType, int numElements, const DrawIndices& indices)
1710e5c31af7Sopenharmony_ci	: m_primitiveType	(primitiveType)
1711e5c31af7Sopenharmony_ci	, m_numElements		((size_t)numElements)
1712e5c31af7Sopenharmony_ci	, m_indices			(indices.indices)
1713e5c31af7Sopenharmony_ci	, m_indexType		(indices.indexType)
1714e5c31af7Sopenharmony_ci	, m_baseVertex		(indices.baseVertex)
1715e5c31af7Sopenharmony_ci{
1716e5c31af7Sopenharmony_ci	DE_ASSERT(numElements >= 0 && "Invalid numElements");
1717e5c31af7Sopenharmony_ci}
1718e5c31af7Sopenharmony_ci
1719e5c31af7Sopenharmony_cisize_t PrimitiveList::getIndex (size_t elementNdx) const
1720e5c31af7Sopenharmony_ci{
1721e5c31af7Sopenharmony_ci	// indices == DE_NULL interpreted as command.indices = [first (=baseVertex) + 0, first + 1, first + 2...]
1722e5c31af7Sopenharmony_ci	if (m_indices)
1723e5c31af7Sopenharmony_ci	{
1724e5c31af7Sopenharmony_ci		int index = m_baseVertex + (int)readIndexArray(m_indexType, m_indices, elementNdx);
1725e5c31af7Sopenharmony_ci		DE_ASSERT(index >= 0); // do not access indices < 0
1726e5c31af7Sopenharmony_ci
1727e5c31af7Sopenharmony_ci		return (size_t)index;
1728e5c31af7Sopenharmony_ci	}
1729e5c31af7Sopenharmony_ci	else
1730e5c31af7Sopenharmony_ci		return (size_t)(m_baseVertex) + elementNdx;
1731e5c31af7Sopenharmony_ci}
1732e5c31af7Sopenharmony_ci
1733e5c31af7Sopenharmony_cibool PrimitiveList::isRestartIndex (size_t elementNdx, deUint32 restartIndex) const
1734e5c31af7Sopenharmony_ci{
1735e5c31af7Sopenharmony_ci	// implicit index or explicit index (without base vertex) equals restart
1736e5c31af7Sopenharmony_ci	if (m_indices)
1737e5c31af7Sopenharmony_ci		return readIndexArray(m_indexType, m_indices, elementNdx) == restartIndex;
1738e5c31af7Sopenharmony_ci	else
1739e5c31af7Sopenharmony_ci		return elementNdx == (size_t)restartIndex;
1740e5c31af7Sopenharmony_ci}
1741e5c31af7Sopenharmony_ci
1742e5c31af7Sopenharmony_ciRenderer::Renderer (void)
1743e5c31af7Sopenharmony_ci{
1744e5c31af7Sopenharmony_ci}
1745e5c31af7Sopenharmony_ci
1746e5c31af7Sopenharmony_ciRenderer::~Renderer (void)
1747e5c31af7Sopenharmony_ci{
1748e5c31af7Sopenharmony_ci}
1749e5c31af7Sopenharmony_ci
1750e5c31af7Sopenharmony_civoid Renderer::draw (const DrawCommand& command) const
1751e5c31af7Sopenharmony_ci{
1752e5c31af7Sopenharmony_ci	drawInstanced(command, 1);
1753e5c31af7Sopenharmony_ci}
1754e5c31af7Sopenharmony_ci
1755e5c31af7Sopenharmony_civoid Renderer::drawInstanced (const DrawCommand& command, int numInstances) const
1756e5c31af7Sopenharmony_ci{
1757e5c31af7Sopenharmony_ci	// Do not run bad commands
1758e5c31af7Sopenharmony_ci	{
1759e5c31af7Sopenharmony_ci		const bool validCommand = isValidCommand(command, numInstances);
1760e5c31af7Sopenharmony_ci		if (!validCommand)
1761e5c31af7Sopenharmony_ci		{
1762e5c31af7Sopenharmony_ci			DE_ASSERT(false);
1763e5c31af7Sopenharmony_ci			return;
1764e5c31af7Sopenharmony_ci		}
1765e5c31af7Sopenharmony_ci	}
1766e5c31af7Sopenharmony_ci
1767e5c31af7Sopenharmony_ci	// Do not draw if nothing to draw
1768e5c31af7Sopenharmony_ci	{
1769e5c31af7Sopenharmony_ci		if (command.primitives.getNumElements() == 0 || numInstances == 0)
1770e5c31af7Sopenharmony_ci			return;
1771e5c31af7Sopenharmony_ci	}
1772e5c31af7Sopenharmony_ci
1773e5c31af7Sopenharmony_ci	// Prepare transformation
1774e5c31af7Sopenharmony_ci
1775e5c31af7Sopenharmony_ci	const size_t				numVaryings = command.program.vertexShader->getOutputs().size();
1776e5c31af7Sopenharmony_ci	VertexPacketAllocator		vpalloc(numVaryings);
1777e5c31af7Sopenharmony_ci	std::vector<VertexPacket*>	vertexPackets = vpalloc.allocArray(command.primitives.getNumElements());
1778e5c31af7Sopenharmony_ci	DrawContext					drawContext;
1779e5c31af7Sopenharmony_ci
1780e5c31af7Sopenharmony_ci	for (int instanceID = 0; instanceID < numInstances; ++instanceID)
1781e5c31af7Sopenharmony_ci	{
1782e5c31af7Sopenharmony_ci		// Each instance has its own primitives
1783e5c31af7Sopenharmony_ci		drawContext.primitiveID = 0;
1784e5c31af7Sopenharmony_ci
1785e5c31af7Sopenharmony_ci		for (size_t elementNdx = 0; elementNdx < command.primitives.getNumElements(); ++elementNdx)
1786e5c31af7Sopenharmony_ci		{
1787e5c31af7Sopenharmony_ci			int numVertexPackets = 0;
1788e5c31af7Sopenharmony_ci
1789e5c31af7Sopenharmony_ci			// collect primitive vertices until restart
1790e5c31af7Sopenharmony_ci
1791e5c31af7Sopenharmony_ci			while (elementNdx < command.primitives.getNumElements() &&
1792e5c31af7Sopenharmony_ci					!(command.state.restart.enabled && command.primitives.isRestartIndex(elementNdx, command.state.restart.restartIndex)))
1793e5c31af7Sopenharmony_ci			{
1794e5c31af7Sopenharmony_ci				// input
1795e5c31af7Sopenharmony_ci				vertexPackets[numVertexPackets]->instanceNdx	= instanceID;
1796e5c31af7Sopenharmony_ci				vertexPackets[numVertexPackets]->vertexNdx		= (int)command.primitives.getIndex(elementNdx);
1797e5c31af7Sopenharmony_ci
1798e5c31af7Sopenharmony_ci				// output
1799e5c31af7Sopenharmony_ci				vertexPackets[numVertexPackets]->pointSize		= command.state.point.pointSize;	// default value from the current state
1800e5c31af7Sopenharmony_ci				vertexPackets[numVertexPackets]->position		= tcu::Vec4(0, 0, 0, 0);			// no undefined values
1801e5c31af7Sopenharmony_ci
1802e5c31af7Sopenharmony_ci				++numVertexPackets;
1803e5c31af7Sopenharmony_ci				++elementNdx;
1804e5c31af7Sopenharmony_ci			}
1805e5c31af7Sopenharmony_ci
1806e5c31af7Sopenharmony_ci			// Duplicated restart shade
1807e5c31af7Sopenharmony_ci			if (numVertexPackets == 0)
1808e5c31af7Sopenharmony_ci				continue;
1809e5c31af7Sopenharmony_ci
1810e5c31af7Sopenharmony_ci			// \todo Vertex cache?
1811e5c31af7Sopenharmony_ci
1812e5c31af7Sopenharmony_ci			// Transform vertices
1813e5c31af7Sopenharmony_ci
1814e5c31af7Sopenharmony_ci			command.program.vertexShader->shadeVertices(command.vertexAttribs, &vertexPackets[0], numVertexPackets);
1815e5c31af7Sopenharmony_ci
1816e5c31af7Sopenharmony_ci			// Draw primitives
1817e5c31af7Sopenharmony_ci
1818e5c31af7Sopenharmony_ci			switch (command.primitives.getPrimitiveType())
1819e5c31af7Sopenharmony_ci			{
1820e5c31af7Sopenharmony_ci				case PRIMITIVETYPE_TRIANGLES:				{ drawAsPrimitives<PRIMITIVETYPE_TRIANGLES>					(command.state, command.renderTarget, command.program, &vertexPackets[0], numVertexPackets, drawContext, vpalloc);	break; }
1821e5c31af7Sopenharmony_ci				case PRIMITIVETYPE_TRIANGLE_STRIP:			{ drawAsPrimitives<PRIMITIVETYPE_TRIANGLE_STRIP>			(command.state, command.renderTarget, command.program, &vertexPackets[0], numVertexPackets, drawContext, vpalloc);	break; }
1822e5c31af7Sopenharmony_ci				case PRIMITIVETYPE_TRIANGLE_FAN:			{ drawAsPrimitives<PRIMITIVETYPE_TRIANGLE_FAN>				(command.state, command.renderTarget, command.program, &vertexPackets[0], numVertexPackets, drawContext, vpalloc);	break; }
1823e5c31af7Sopenharmony_ci				case PRIMITIVETYPE_LINES:					{ drawAsPrimitives<PRIMITIVETYPE_LINES>						(command.state, command.renderTarget, command.program, &vertexPackets[0], numVertexPackets, drawContext, vpalloc);	break; }
1824e5c31af7Sopenharmony_ci				case PRIMITIVETYPE_LINE_STRIP:				{ drawAsPrimitives<PRIMITIVETYPE_LINE_STRIP>				(command.state, command.renderTarget, command.program, &vertexPackets[0], numVertexPackets, drawContext, vpalloc);	break; }
1825e5c31af7Sopenharmony_ci				case PRIMITIVETYPE_LINE_LOOP:				{ drawAsPrimitives<PRIMITIVETYPE_LINE_LOOP>					(command.state, command.renderTarget, command.program, &vertexPackets[0], numVertexPackets, drawContext, vpalloc);	break; }
1826e5c31af7Sopenharmony_ci				case PRIMITIVETYPE_POINTS:					{ drawAsPrimitives<PRIMITIVETYPE_POINTS>					(command.state, command.renderTarget, command.program, &vertexPackets[0], numVertexPackets, drawContext, vpalloc);	break; }
1827e5c31af7Sopenharmony_ci				case PRIMITIVETYPE_LINES_ADJACENCY:			{ drawAsPrimitives<PRIMITIVETYPE_LINES_ADJACENCY>			(command.state, command.renderTarget, command.program, &vertexPackets[0], numVertexPackets, drawContext, vpalloc);	break; }
1828e5c31af7Sopenharmony_ci				case PRIMITIVETYPE_LINE_STRIP_ADJACENCY:	{ drawAsPrimitives<PRIMITIVETYPE_LINE_STRIP_ADJACENCY>		(command.state, command.renderTarget, command.program, &vertexPackets[0], numVertexPackets, drawContext, vpalloc);	break; }
1829e5c31af7Sopenharmony_ci				case PRIMITIVETYPE_TRIANGLES_ADJACENCY:		{ drawAsPrimitives<PRIMITIVETYPE_TRIANGLES_ADJACENCY>		(command.state, command.renderTarget, command.program, &vertexPackets[0], numVertexPackets, drawContext, vpalloc);	break; }
1830e5c31af7Sopenharmony_ci				case PRIMITIVETYPE_TRIANGLE_STRIP_ADJACENCY:{ drawAsPrimitives<PRIMITIVETYPE_TRIANGLE_STRIP_ADJACENCY>	(command.state, command.renderTarget, command.program, &vertexPackets[0], numVertexPackets, drawContext, vpalloc);	break; }
1831e5c31af7Sopenharmony_ci				default:
1832e5c31af7Sopenharmony_ci					DE_ASSERT(DE_FALSE);
1833e5c31af7Sopenharmony_ci			}
1834e5c31af7Sopenharmony_ci		}
1835e5c31af7Sopenharmony_ci	}
1836e5c31af7Sopenharmony_ci}
1837e5c31af7Sopenharmony_ci
1838e5c31af7Sopenharmony_ci} // rr
1839