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