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