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