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