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