/************************************************************************** * * Copyright 2008 VMware, Inc. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * **************************************************************************/ #ifndef U_PRIM_H #define U_PRIM_H #include "pipe/p_defines.h" #include "util/u_debug.h" #ifdef __cplusplus extern "C" { #endif struct u_prim_vertex_count { unsigned min; unsigned incr; }; /** * Decompose a primitive that is a loop, a strip, or a fan. Return the * original primitive if it is already decomposed. */ static inline enum pipe_prim_type u_decomposed_prim(enum pipe_prim_type prim) { switch (prim) { case PIPE_PRIM_LINE_LOOP: case PIPE_PRIM_LINE_STRIP: return PIPE_PRIM_LINES; case PIPE_PRIM_TRIANGLE_STRIP: case PIPE_PRIM_TRIANGLE_FAN: return PIPE_PRIM_TRIANGLES; case PIPE_PRIM_QUAD_STRIP: return PIPE_PRIM_QUADS; case PIPE_PRIM_LINE_STRIP_ADJACENCY: return PIPE_PRIM_LINES_ADJACENCY; case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY: return PIPE_PRIM_TRIANGLES_ADJACENCY; default: return prim; } } /** * Reduce a primitive to one of PIPE_PRIM_POINTS, PIPE_PRIM_LINES, and * PIPE_PRIM_TRIANGLES. */ static inline enum pipe_prim_type u_reduced_prim(enum pipe_prim_type prim) { switch (prim) { case PIPE_PRIM_POINTS: return PIPE_PRIM_POINTS; case PIPE_PRIM_LINES: case PIPE_PRIM_LINE_LOOP: case PIPE_PRIM_LINE_STRIP: case PIPE_PRIM_LINES_ADJACENCY: case PIPE_PRIM_LINE_STRIP_ADJACENCY: return PIPE_PRIM_LINES; default: return PIPE_PRIM_TRIANGLES; } } /** * Re-assemble a primitive to remove its adjacency. */ static inline enum pipe_prim_type u_assembled_prim(enum pipe_prim_type prim) { switch (prim) { case PIPE_PRIM_LINES_ADJACENCY: case PIPE_PRIM_LINE_STRIP_ADJACENCY: return PIPE_PRIM_LINES; case PIPE_PRIM_TRIANGLES_ADJACENCY: case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY: return PIPE_PRIM_TRIANGLES; default: return prim; } } /** * Return the vertex count information for a primitive. * * Note that if this function is called directly or indirectly anywhere in a * source file, it will increase the size of the binary slightly more than * expected because of the use of a table. */ static inline const struct u_prim_vertex_count * u_prim_vertex_count(enum pipe_prim_type prim) { static const struct u_prim_vertex_count prim_table[PIPE_PRIM_MAX] = { { 1, 1 }, /* PIPE_PRIM_POINTS */ { 2, 2 }, /* PIPE_PRIM_LINES */ { 2, 1 }, /* PIPE_PRIM_LINE_LOOP */ { 2, 1 }, /* PIPE_PRIM_LINE_STRIP */ { 3, 3 }, /* PIPE_PRIM_TRIANGLES */ { 3, 1 }, /* PIPE_PRIM_TRIANGLE_STRIP */ { 3, 1 }, /* PIPE_PRIM_TRIANGLE_FAN */ { 4, 4 }, /* PIPE_PRIM_QUADS */ { 4, 2 }, /* PIPE_PRIM_QUAD_STRIP */ { 3, 1 }, /* PIPE_PRIM_POLYGON */ { 4, 4 }, /* PIPE_PRIM_LINES_ADJACENCY */ { 4, 1 }, /* PIPE_PRIM_LINE_STRIP_ADJACENCY */ { 6, 6 }, /* PIPE_PRIM_TRIANGLES_ADJACENCY */ { 6, 2 }, /* PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY */ }; return (likely(prim < PIPE_PRIM_MAX)) ? &prim_table[prim] : NULL; } /** * Given a vertex count, return the number of primitives. * For polygons, return the number of triangles. */ static inline unsigned u_prims_for_vertices(enum pipe_prim_type prim, unsigned num) { const struct u_prim_vertex_count *info = u_prim_vertex_count(prim); assert(info); assert(info->incr != 0); if (num < info->min) return 0; return 1 + ((num - info->min) / info->incr); } static inline boolean u_validate_pipe_prim(enum pipe_prim_type pipe_prim, unsigned nr) { const struct u_prim_vertex_count *count = u_prim_vertex_count(pipe_prim); return (count && nr >= count->min); } static inline boolean u_trim_pipe_prim(enum pipe_prim_type pipe_prim, unsigned *nr) { const struct u_prim_vertex_count *count = u_prim_vertex_count(pipe_prim); if (count && *nr >= count->min) { if (count->incr > 1) *nr -= (*nr % count->incr); return TRUE; } else { *nr = 0; return FALSE; } } static inline unsigned u_vertices_per_prim(enum pipe_prim_type primitive) { switch(primitive) { case PIPE_PRIM_POINTS: return 1; case PIPE_PRIM_LINES: case PIPE_PRIM_LINE_LOOP: case PIPE_PRIM_LINE_STRIP: return 2; case PIPE_PRIM_TRIANGLES: case PIPE_PRIM_TRIANGLE_STRIP: case PIPE_PRIM_TRIANGLE_FAN: return 3; case PIPE_PRIM_LINES_ADJACENCY: case PIPE_PRIM_LINE_STRIP_ADJACENCY: return 4; case PIPE_PRIM_TRIANGLES_ADJACENCY: case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY: return 6; /* following primitives should never be used * with geometry shaders abd their size is * undefined */ case PIPE_PRIM_POLYGON: case PIPE_PRIM_QUADS: case PIPE_PRIM_QUAD_STRIP: default: debug_printf("Unrecognized geometry shader primitive"); return 3; } } /** * Returns the number of decomposed primitives for the given * vertex count. * Parts of the pipline are invoked once for each triangle in * triangle strip, triangle fans and triangles and once * for each line in line strip, line loop, lines. Also * statistics depend on knowing the exact number of decomposed * primitives for a set of vertices. */ static inline unsigned u_decomposed_prims_for_vertices(enum pipe_prim_type primitive, int vertices) { switch (primitive) { case PIPE_PRIM_POINTS: return vertices; case PIPE_PRIM_LINES: return vertices / 2; case PIPE_PRIM_LINE_LOOP: return (vertices >= 2) ? vertices : 0; case PIPE_PRIM_LINE_STRIP: return (vertices >= 2) ? vertices - 1 : 0; case PIPE_PRIM_TRIANGLES: return vertices / 3; case PIPE_PRIM_TRIANGLE_STRIP: return (vertices >= 3) ? vertices - 2 : 0; case PIPE_PRIM_TRIANGLE_FAN: return (vertices >= 3) ? vertices - 2 : 0; case PIPE_PRIM_LINES_ADJACENCY: return vertices / 4; case PIPE_PRIM_LINE_STRIP_ADJACENCY: return (vertices >= 4) ? vertices - 3 : 0; case PIPE_PRIM_TRIANGLES_ADJACENCY: return vertices / 6; case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY: return (vertices >= 6) ? 1 + (vertices - 6) / 2 : 0; case PIPE_PRIM_QUADS: return vertices / 4; case PIPE_PRIM_QUAD_STRIP: return (vertices >= 4) ? (vertices - 2) / 2 : 0; /* Polygons can't be decomposed * because the number of their vertices isn't known so * for them and whatever else we don't recognize just * return 1 if the number of vertices is greater than * or equal to 3 and zero otherwise */ case PIPE_PRIM_POLYGON: default: debug_printf("Invalid decomposition primitive!\n"); return (vertices >= 3) ? 1 : 0; } } /** * Returns the number of reduced/tessellated primitives for the given vertex * count. Each quad is treated as two triangles. Polygons are treated as * triangle fans. */ static inline unsigned u_reduced_prims_for_vertices(enum pipe_prim_type primitive, int vertices) { switch (primitive) { case PIPE_PRIM_QUADS: case PIPE_PRIM_QUAD_STRIP: return u_decomposed_prims_for_vertices(primitive, vertices) * 2; case PIPE_PRIM_POLYGON: primitive = PIPE_PRIM_TRIANGLE_FAN; /* fall through */ default: return u_decomposed_prims_for_vertices(primitive, vertices); } } static inline enum pipe_prim_type u_base_prim_type(enum pipe_prim_type prim_type) { switch(prim_type) { case PIPE_PRIM_POINTS: return PIPE_PRIM_POINTS; case PIPE_PRIM_LINES: case PIPE_PRIM_LINE_LOOP: case PIPE_PRIM_LINE_STRIP: case PIPE_PRIM_LINES_ADJACENCY: case PIPE_PRIM_LINE_STRIP_ADJACENCY: return PIPE_PRIM_LINES; case PIPE_PRIM_TRIANGLES: case PIPE_PRIM_TRIANGLE_STRIP: case PIPE_PRIM_TRIANGLE_FAN: case PIPE_PRIM_TRIANGLES_ADJACENCY: case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY: return PIPE_PRIM_TRIANGLES; case PIPE_PRIM_QUADS: case PIPE_PRIM_QUAD_STRIP: return PIPE_PRIM_QUADS; default: return prim_type; } } static inline unsigned u_vertices_for_prims(enum pipe_prim_type prim_type, int count) { if (count <= 0) return 0; /* We can only figure out the number of vertices from a number of primitives * if we are using basic primitives (so no loops, strips, fans, etc). */ assert(prim_type == u_base_prim_type(prim_type) && prim_type != PIPE_PRIM_PATCHES && prim_type != PIPE_PRIM_POLYGON); const struct u_prim_vertex_count *info = u_prim_vertex_count(prim_type); assert(info); return info->min + (count - 1) * info->incr; } /** * Returns the number of stream out outputs for a given number of vertices and * primitive type. */ static inline unsigned u_stream_outputs_for_vertices(enum pipe_prim_type primitive, unsigned nr) { /* Extraneous vertices don't contribute to stream outputs */ u_trim_pipe_prim(primitive, &nr); /* Polygons are special, since they are a single primitive with many * vertices. In this case, we just have an output for each vertex (after * trimming) */ if (primitive == PIPE_PRIM_POLYGON) return nr; /* Normally, consider how many primitives are actually generated */ unsigned prims = u_decomposed_prims_for_vertices(primitive, nr); /* One output per vertex after decomposition */ enum pipe_prim_type base = u_base_prim_type(primitive); return u_vertices_for_prims(base, prims); } const char *u_prim_name(enum pipe_prim_type pipe_prim); #ifdef __cplusplus } #endif #endif