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