#ifndef _RRPRIMITIVEASSEMBLER_HPP #define _RRPRIMITIVEASSEMBLER_HPP /*------------------------------------------------------------------------- * drawElements Quality Program Reference Renderer * ----------------------------------------------- * * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief Primitive assembler *//*--------------------------------------------------------------------*/ #include "rrDefs.hpp" #include "rrVertexPacket.hpp" namespace rr { namespace pa { struct Triangle { enum { NUM_VERTICES = 3 }; Triangle(void) : v0(DE_NULL), v1(DE_NULL), v2(DE_NULL), provokingIndex(-1) { } Triangle(VertexPacket *v0_, VertexPacket *v1_, VertexPacket *v2_, int provokingIndex_) : v0(v0_) , v1(v1_) , v2(v2_) , provokingIndex(provokingIndex_) { } VertexPacket *getProvokingVertex(void) { switch (provokingIndex) { case 0: return v0; case 1: return v1; case 2: return v2; default: DE_ASSERT(false); return DE_NULL; } } VertexPacket *v0; VertexPacket *v1; VertexPacket *v2; int provokingIndex; } DE_WARN_UNUSED_TYPE; struct Triangles { template static void exec(Iterator outputIterator, VertexPacket *const *vertices, size_t numVertices, rr::ProvokingVertex provokingConvention) { const int provokingOffset = (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (0) : (2); for (size_t ndx = 0; ndx + 2 < numVertices; ndx += 3) *(outputIterator++) = Triangle(vertices[ndx], vertices[ndx + 1], vertices[ndx + 2], provokingOffset); } static size_t getPrimitiveCount(size_t vertices) { return vertices / 3; } } DE_WARN_UNUSED_TYPE; struct TriangleStrip { template static void exec(Iterator outputIterator, VertexPacket *const *vertices, size_t numVertices, rr::ProvokingVertex provokingConvention) { if (numVertices < 3) { } else { VertexPacket *vert0 = vertices[0]; VertexPacket *vert1 = vertices[1]; size_t ndx = 2; for (;;) { { if (ndx >= numVertices) break; *(outputIterator++) = Triangle(vert0, vert1, vertices[ndx], (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (0) : (2)); vert0 = vertices[ndx]; ndx++; } { if (ndx >= numVertices) break; *(outputIterator++) = Triangle(vert0, vert1, vertices[ndx], (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (1) : (2)); vert1 = vertices[ndx]; ndx++; } } } } static size_t getPrimitiveCount(size_t vertices) { return (vertices < 3) ? (0) : (vertices - 2); } } DE_WARN_UNUSED_TYPE; struct TriangleFan { template static void exec(Iterator outputIterator, VertexPacket *const *vertices, size_t numVertices, rr::ProvokingVertex provokingConvention) { if (numVertices == 0) { } else { const int provokingOffset = (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (1) : (2); VertexPacket *const first = vertices[0]; for (size_t ndx = 1; ndx + 1 < numVertices; ++ndx) *(outputIterator++) = Triangle(first, vertices[ndx], vertices[ndx + 1], provokingOffset); } } static size_t getPrimitiveCount(size_t vertices) { return (vertices < 3) ? (0) : (vertices - 2); } } DE_WARN_UNUSED_TYPE; struct Line { enum { NUM_VERTICES = 2 }; Line(void) : v0(DE_NULL), v1(DE_NULL), provokingIndex(-1) { } Line(VertexPacket *v0_, VertexPacket *v1_, int provokingIndex_) : v0(v0_), v1(v1_), provokingIndex(provokingIndex_) { } VertexPacket *getProvokingVertex(void) { switch (provokingIndex) { case 0: return v0; case 1: return v1; default: DE_ASSERT(false); return DE_NULL; } } VertexPacket *v0; VertexPacket *v1; int provokingIndex; } DE_WARN_UNUSED_TYPE; struct Lines { template static void exec(Iterator outputIterator, VertexPacket *const *vertices, size_t numVertices, rr::ProvokingVertex provokingConvention) { const int provokingOffset = (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (0) : (1); for (size_t ndx = 0; ndx + 1 < numVertices; ndx += 2) *(outputIterator++) = Line(vertices[ndx], vertices[ndx + 1], provokingOffset); } static size_t getPrimitiveCount(size_t vertices) { return vertices / 2; } } DE_WARN_UNUSED_TYPE; struct LineStrip { template static void exec(Iterator outputIterator, VertexPacket *const *vertices, size_t numVertices, rr::ProvokingVertex provokingConvention) { if (numVertices == 0) { } else { VertexPacket *prev = vertices[0]; for (size_t ndx = 1; ndx < numVertices; ++ndx) { *(outputIterator++) = Line(prev, vertices[ndx], (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (0) : (1)); prev = vertices[ndx]; } } } static size_t getPrimitiveCount(size_t vertices) { return (vertices < 2) ? (0) : (vertices - 1); } } DE_WARN_UNUSED_TYPE; struct LineLoop { template static void exec(Iterator outputIterator, VertexPacket *const *vertices, size_t numVertices, rr::ProvokingVertex provokingConvention) { if (numVertices < 2) { } else { VertexPacket *prev = vertices[0]; for (size_t ndx = 1; ndx < numVertices; ++ndx) { *(outputIterator++) = Line(prev, vertices[ndx], (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (0) : (1)); prev = vertices[ndx]; } *(outputIterator++) = Line(prev, vertices[0], (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (0) : (1)); } } static size_t getPrimitiveCount(size_t vertices) { return (vertices < 2) ? (0) : (vertices); } } DE_WARN_UNUSED_TYPE; struct Point { enum { NUM_VERTICES = 1 }; Point(void) : v0(DE_NULL) { } Point(VertexPacket *v0_) : v0(v0_) { } VertexPacket *v0; } DE_WARN_UNUSED_TYPE; struct Points { template static void exec(Iterator outputIterator, VertexPacket *const *vertices, size_t numVertices, rr::ProvokingVertex provokingConvention) { DE_UNREF(provokingConvention); for (size_t ndx = 0; ndx < numVertices; ++ndx) *(outputIterator++) = Point(vertices[ndx]); } static size_t getPrimitiveCount(size_t vertices) { return (vertices); } } DE_WARN_UNUSED_TYPE; struct LineAdjacency { enum { NUM_VERTICES = 4 }; LineAdjacency(void) : v0(DE_NULL), v1(DE_NULL), v2(DE_NULL), v3(DE_NULL), provokingIndex(-1) { } LineAdjacency(VertexPacket *v0_, VertexPacket *v1_, VertexPacket *v2_, VertexPacket *v3_, int provokingIndex_) : v0(v0_) , v1(v1_) , v2(v2_) , v3(v3_) , provokingIndex(provokingIndex_) { } VertexPacket *getProvokingVertex(void) { switch (provokingIndex) { case 1: return v1; case 2: return v2; default: DE_ASSERT(false); return DE_NULL; } } VertexPacket *v0; VertexPacket *v1; VertexPacket *v2; VertexPacket *v3; int provokingIndex; } DE_WARN_UNUSED_TYPE; struct LinesAdjacency { template static void exec(Iterator outputIterator, VertexPacket *const *vertices, size_t numVertices, rr::ProvokingVertex provokingConvention) { const int provokingOffset = (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (1) : (2); for (size_t ndx = 0; ndx + 3 < numVertices; ndx += 4) *(outputIterator++) = LineAdjacency(vertices[ndx], vertices[ndx + 1], vertices[ndx + 2], vertices[ndx + 3], provokingOffset); } static size_t getPrimitiveCount(size_t vertices) { return vertices / 4; } } DE_WARN_UNUSED_TYPE; struct LineStripAdjacency { template static void exec(Iterator outputIterator, VertexPacket *const *vertices, size_t numVertices, rr::ProvokingVertex provokingConvention) { const int provokingOffset = (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (1) : (2); for (size_t ndx = 0; ndx + 3 < numVertices; ++ndx) *(outputIterator++) = LineAdjacency(vertices[ndx], vertices[ndx + 1], vertices[ndx + 2], vertices[ndx + 3], provokingOffset); } static size_t getPrimitiveCount(size_t vertices) { return (vertices < 4) ? (0) : (vertices - 3); } } DE_WARN_UNUSED_TYPE; struct TriangleAdjacency { enum { NUM_VERTICES = 6 }; TriangleAdjacency(void) : v0(DE_NULL) , v1(DE_NULL) , v2(DE_NULL) , v3(DE_NULL) , v4(DE_NULL) , v5(DE_NULL) , provokingIndex(-1) { } TriangleAdjacency(VertexPacket *v0_, VertexPacket *v1_, VertexPacket *v2_, VertexPacket *v3_, VertexPacket *v4_, VertexPacket *v5_, int provokingIndex_) : v0(v0_) , v1(v1_) , v2(v2_) , v3(v3_) , v4(v4_) , v5(v5_) , provokingIndex(provokingIndex_) { } VertexPacket *getProvokingVertex(void) { switch (provokingIndex) { case 0: return v0; case 2: return v2; case 4: return v4; default: DE_ASSERT(false); return DE_NULL; } } VertexPacket *v0; VertexPacket *v1; //!< adjacent VertexPacket *v2; VertexPacket *v3; //!< adjacent VertexPacket *v4; VertexPacket *v5; //!< adjacent int provokingIndex; } DE_WARN_UNUSED_TYPE; struct TrianglesAdjacency { template static void exec(Iterator outputIterator, VertexPacket *const *vertices, size_t numVertices, rr::ProvokingVertex provokingConvention) { const int provokingOffset = (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (0) : (4); for (size_t ndx = 0; ndx + 5 < numVertices; ndx += 6) *(outputIterator++) = TriangleAdjacency(vertices[ndx], vertices[ndx + 1], vertices[ndx + 2], vertices[ndx + 3], vertices[ndx + 4], vertices[ndx + 5], provokingOffset); } static size_t getPrimitiveCount(size_t vertices) { return vertices / 6; } } DE_WARN_UNUSED_TYPE; struct TriangleStripAdjacency { template static void exec(Iterator outputIterator, VertexPacket *const *vertices, size_t numVertices, rr::ProvokingVertex provokingConvention) { if (numVertices < 6) { } else if (numVertices < 8) { *(outputIterator++) = TriangleAdjacency(vertices[0], vertices[1], vertices[2], vertices[5], vertices[4], vertices[3], (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (0) : (4)); } else { const size_t primitiveCount = getPrimitiveCount(numVertices); size_t i; // first *(outputIterator++) = TriangleAdjacency(vertices[0], vertices[1], vertices[2], vertices[6], vertices[4], vertices[3], (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (0) : (4)); // middle for (i = 1; i + 1 < primitiveCount; ++i) { // odd if (i % 2 == 1) { *(outputIterator++) = TriangleAdjacency(vertices[2 * i + 2], vertices[2 * i - 2], vertices[2 * i + 0], vertices[2 * i + 3], vertices[2 * i + 4], vertices[2 * i + 6], (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (2) : (4)); } // even else { *(outputIterator++) = TriangleAdjacency(vertices[2 * i + 0], vertices[2 * i - 2], vertices[2 * i + 2], vertices[2 * i + 6], vertices[2 * i + 4], vertices[2 * i + 3], (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (0) : (4)); } } // last // odd if (i % 2 == 1) *(outputIterator++) = TriangleAdjacency(vertices[2 * i + 2], vertices[2 * i - 2], vertices[2 * i + 0], vertices[2 * i + 3], vertices[2 * i + 4], vertices[2 * i + 5], (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (2) : (4)); // even else *(outputIterator++) = TriangleAdjacency(vertices[2 * i + 0], vertices[2 * i - 2], vertices[2 * i + 2], vertices[2 * i + 5], vertices[2 * i + 4], vertices[2 * i + 3], (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (0) : (4)); } } static size_t getPrimitiveCount(size_t vertices) { return (vertices < 6) ? 0 : ((vertices - 4) / 2); } } DE_WARN_UNUSED_TYPE; } // namespace pa } // namespace rr #endif // _RRPRIMITIVEASSEMBLER_HPP