diff --git a/src/asahi/libagx/geometry.cl b/src/asahi/libagx/geometry.cl index d5432fefd08..8f13672db61 100644 --- a/src/asahi/libagx/geometry.cl +++ b/src/asahi/libagx/geometry.cl @@ -6,146 +6,11 @@ #include "compiler/libcl/libcl_vk.h" #include "poly/geometry.h" +#include "poly/prim.h" #include "poly/tessellator.h" #include "util/macros.h" #include "util/u_math.h" -/* Swap the two non-provoking vertices in odd triangles. This generates a vertex - * ID list with a consistent winding order. - * - * Holding prim and flatshade_first constant, the map : [0, 1, 2] -> [0, 1, 2] - * is its own inverse. It is hence used both vertex fetch and transform - * feedback. - */ -static uint -map_vertex_in_tri_strip(uint prim, uint vert, bool flatshade_first) -{ - unsigned pv = flatshade_first ? 0 : 2; - - bool even = (prim & 1) == 0; - bool provoking = vert == pv; - - return (provoking || even) ? vert : ((3 - pv) - vert); -} - -static uint -vertex_id_for_line_loop(uint prim, uint vert, uint num_prims) -{ - /* (0, 1), (1, 2), (2, 0) */ - if (prim == (num_prims - 1) && vert == 1) - return 0; - else - return prim + vert; -} - -static uint -vertex_id_for_tri_fan(uint prim, uint vert, bool flatshade_first) -{ - /* Vulkan spec section 20.1.7 gives (i + 1, i + 2, 0) for a provoking - * first. OpenGL instead wants (0, i + 1, i + 2) with a provoking last. - * Piglit clipflat expects us to switch between these orders depending on - * provoking vertex, to avoid trivializing the fan. - * - * Rotate accordingly. - */ - if (flatshade_first) { - vert = (vert == 2) ? 0 : (vert + 1); - } - - /* The simpler form assuming last is provoking. */ - return (vert == 0) ? 0 : prim + vert; -} - -static uint -vertex_id_for_tri_strip_adj(uint prim, uint vert, uint num_prims, - bool flatshade_first) -{ - /* See Vulkan spec section 20.1.11 "Triangle Strips With Adjancency". - * - * There are different cases for first/middle/last/only primitives and for - * odd/even primitives. Determine which case we're in. - */ - bool last = prim == (num_prims - 1); - bool first = prim == 0; - bool even = (prim & 1) == 0; - bool even_or_first = even || first; - - /* When the last vertex is provoking, we rotate the primitives - * accordingly. This seems required for OpenGL. - */ - if (!flatshade_first && !even_or_first) { - vert = (vert + 4u) % 6u; - } - - /* Offsets per the spec. The spec lists 6 cases with 6 offsets. Luckily, - * there are lots of patterns we can exploit, avoiding a full 6x6 LUT. - * - * Here we assume the first vertex is provoking, the Vulkan default. - */ - uint offsets[6] = { - 0, - first ? 1 : (even ? -2 : 3), - even_or_first ? 2 : 4, - last ? 5 : 6, - even_or_first ? 4 : 2, - even_or_first ? 3 : -2, - }; - - /* Ensure NIR can see thru the local array */ - uint offset = 0; - for (uint i = 1; i < 6; ++i) { - if (i == vert) - offset = offsets[i]; - } - - /* Finally add to the base of the primitive */ - return (prim * 2) + offset; -} - -static uint -vertex_id_for_topology(enum mesa_prim mode, bool flatshade_first, uint prim, - uint vert, uint num_prims) -{ - switch (mode) { - case MESA_PRIM_POINTS: - case MESA_PRIM_LINES: - case MESA_PRIM_TRIANGLES: - case MESA_PRIM_LINES_ADJACENCY: - case MESA_PRIM_TRIANGLES_ADJACENCY: - /* Regular primitive: every N vertices defines a primitive */ - return (prim * mesa_vertices_per_prim(mode)) + vert; - - case MESA_PRIM_LINE_LOOP: - return vertex_id_for_line_loop(prim, vert, num_prims); - - case MESA_PRIM_LINE_STRIP: - case MESA_PRIM_LINE_STRIP_ADJACENCY: - /* (i, i + 1) or (i, ..., i + 3) */ - return prim + vert; - - case MESA_PRIM_TRIANGLE_STRIP: { - /* Order depends on the provoking vert. - * - * First: (0, 1, 2), (1, 3, 2), (2, 3, 4). - * Last: (0, 1, 2), (2, 1, 3), (2, 3, 4). - * - * Pull the (maybe swapped) vert from the corresponding primitive - */ - return prim + map_vertex_in_tri_strip(prim, vert, flatshade_first); - } - - case MESA_PRIM_TRIANGLE_FAN: - return vertex_id_for_tri_fan(prim, vert, flatshade_first); - - case MESA_PRIM_TRIANGLE_STRIP_ADJACENCY: - return vertex_id_for_tri_strip_adj(prim, vert, num_prims, - flatshade_first); - - default: - return 0; - } -} - KERNEL(1) libagx_increment_ia(global uint32_t *ia_vertices, global uint32_t *ia_primitives, @@ -321,7 +186,7 @@ libagx_unroll_restart(global struct poly_heap *heap, uint64_t index_buffer, for (uint i = tid; i < subprims; i += 1024) { for (uint vtx = 0; vtx < per_prim; ++vtx) { uint id = - vertex_id_for_topology(mode, flatshade_first, i, vtx, subprims); + poly_vertex_id_for_topology(mode, flatshade_first, i, vtx, subprims); uint offset = needle + id; uint x = ((out_prims_base + i) * per_prim) + vtx; diff --git a/src/poly/cl/geometry.cl b/src/poly/cl/geometry.cl index 4c1e1dabba3..b7f48d82033 100644 --- a/src/poly/cl/geometry.cl +++ b/src/poly/cl/geometry.cl @@ -7,30 +7,13 @@ #include "compiler/libcl/libcl_vk.h" #include "poly/geometry.h" +#include "poly/prim.h" #include "poly/tessellator.h" #include "util/macros.h" #include "util/u_math.h" uint64_t nir_ro_to_rw_poly(uint64_t address); -/* Swap the two non-provoking vertices in odd triangles. This generates a vertex - * ID list with a consistent winding order. - * - * Holding prim and flatshade_first constant, the map : [0, 1, 2] -> [0, 1, 2] - * is its own inverse. It is hence used both vertex fetch and transform - * feedback. - */ -static uint -map_vertex_in_tri_strip(uint prim, uint vert, bool flatshade_first) -{ - unsigned pv = flatshade_first ? 0 : 2; - - bool even = (prim & 1) == 0; - bool provoking = vert == pv; - - return (provoking || even) ? vert : ((3 - pv) - vert); -} - static inline uint xfb_prim(uint id, uint n, uint copy) { @@ -60,7 +43,7 @@ poly_xfb_vertex_offset(uint n, uint invocation_base_prim, uint strip_base_prim, uint vert = vert_0 - copy; if (n == 3) { - vert = map_vertex_in_tri_strip(prim, vert, flatshade_first); + vert = poly_map_vertex_in_tri_strip(prim, vert, flatshade_first); } /* Tally up in the whole buffer */ @@ -78,16 +61,6 @@ poly_xfb_vertex_address(constant struct poly_geometry_params *p, uint index, return (uintptr_t)(p->xfb_base[buffer]) + xfb_offset; } -static uint -vertex_id_for_line_loop(uint prim, uint vert, uint num_prims) -{ - /* (0, 1), (1, 2), (2, 0) */ - if (prim == (num_prims - 1) && vert == 1) - return 0; - else - return prim + vert; -} - uint poly_vertex_id_for_line_class(enum mesa_prim mode, uint prim, uint vert, uint num_prims) @@ -102,24 +75,6 @@ poly_vertex_id_for_line_class(enum mesa_prim mode, uint prim, uint vert, return prim + vert; } -static uint -vertex_id_for_tri_fan(uint prim, uint vert, bool flatshade_first) -{ - /* Vulkan spec section 20.1.7 gives (i + 1, i + 2, 0) for a provoking - * first. OpenGL instead wants (0, i + 1, i + 2) with a provoking last. - * Piglit clipflat expects us to switch between these orders depending on - * provoking vertex, to avoid trivializing the fan. - * - * Rotate accordingly. - */ - if (flatshade_first) { - vert = (vert == 2) ? 0 : (vert + 1); - } - - /* The simpler form assuming last is provoking. */ - return (vert == 0) ? 0 : prim + vert; -} - uint poly_vertex_id_for_tri_class(enum mesa_prim mode, uint prim, uint vert, bool flatshade_first) @@ -158,108 +113,18 @@ poly_vertex_id_for_line_adj_class(enum mesa_prim mode, uint prim, uint vert) return prim + vert; } -static uint -vertex_id_for_tri_strip_adj(uint prim, uint vert, uint num_prims, - bool flatshade_first) -{ - /* See Vulkan spec section 20.1.11 "Triangle Strips With Adjancency". - * - * There are different cases for first/middle/last/only primitives and for - * odd/even primitives. Determine which case we're in. - */ - bool last = prim == (num_prims - 1); - bool first = prim == 0; - bool even = (prim & 1) == 0; - bool even_or_first = even || first; - - /* When the last vertex is provoking, we rotate the primitives - * accordingly. This seems required for OpenGL. - */ - if (!flatshade_first && !even_or_first) { - vert = (vert + 4u) % 6u; - } - - /* Offsets per the spec. The spec lists 6 cases with 6 offsets. Luckily, - * there are lots of patterns we can exploit, avoiding a full 6x6 LUT. - * - * Here we assume the first vertex is provoking, the Vulkan default. - */ - uint offsets[6] = { - 0, - first ? 1 : (even ? -2 : 3), - even_or_first ? 2 : 4, - last ? 5 : 6, - even_or_first ? 4 : 2, - even_or_first ? 3 : -2, - }; - - /* Ensure NIR can see thru the local array */ - uint offset = 0; - for (uint i = 1; i < 6; ++i) { - if (i == vert) - offset = offsets[i]; - } - - /* Finally add to the base of the primitive */ - return (prim * 2) + offset; -} - uint poly_vertex_id_for_tri_adj_class(enum mesa_prim mode, uint prim, uint vert, uint nr, bool flatshade_first) { /* Tri adj list or tri adj strip */ if (mode == MESA_PRIM_TRIANGLE_STRIP_ADJACENCY) { - return vertex_id_for_tri_strip_adj(prim, vert, nr, flatshade_first); + return poly_vertex_id_for_tri_strip_adj(prim, vert, nr, flatshade_first); } else { return (6 * prim) + vert; } } -static uint -vertex_id_for_topology(enum mesa_prim mode, bool flatshade_first, uint prim, - uint vert, uint num_prims) -{ - switch (mode) { - case MESA_PRIM_POINTS: - case MESA_PRIM_LINES: - case MESA_PRIM_TRIANGLES: - case MESA_PRIM_LINES_ADJACENCY: - case MESA_PRIM_TRIANGLES_ADJACENCY: - /* Regular primitive: every N vertices defines a primitive */ - return (prim * mesa_vertices_per_prim(mode)) + vert; - - case MESA_PRIM_LINE_LOOP: - return vertex_id_for_line_loop(prim, vert, num_prims); - - case MESA_PRIM_LINE_STRIP: - case MESA_PRIM_LINE_STRIP_ADJACENCY: - /* (i, i + 1) or (i, ..., i + 3) */ - return prim + vert; - - case MESA_PRIM_TRIANGLE_STRIP: { - /* Order depends on the provoking vert. - * - * First: (0, 1, 2), (1, 3, 2), (2, 3, 4). - * Last: (0, 1, 2), (2, 1, 3), (2, 3, 4). - * - * Pull the (maybe swapped) vert from the corresponding primitive - */ - return prim + map_vertex_in_tri_strip(prim, vert, flatshade_first); - } - - case MESA_PRIM_TRIANGLE_FAN: - return vertex_id_for_tri_fan(prim, vert, flatshade_first); - - case MESA_PRIM_TRIANGLE_STRIP_ADJACENCY: - return vertex_id_for_tri_strip_adj(prim, vert, num_prims, - flatshade_first); - - default: - return 0; - } -} - uint poly_map_to_line_adj(uint id) { diff --git a/src/poly/prim.h b/src/poly/prim.h new file mode 100644 index 00000000000..1eeb126b59e --- /dev/null +++ b/src/poly/prim.h @@ -0,0 +1,147 @@ +/* + * Copyright 2023 Alyssa Rosenzweig + * Copyright 2023 Valve Corporation + * Copyright 2025 Collabora Ltd. + * SPDX-License-Identifier: MIT + */ + +#include "compiler/libcl/libcl.h" +#include "compiler/shader_enums.h" + +#pragma once + +/* Swap the two non-provoking vertices in odd triangles. This generates a vertex + * ID list with a consistent winding order. + * + * Holding prim and flatshade_first constant, the map : [0, 1, 2] -> [0, 1, 2] + * is its own inverse. It is hence used both vertex fetch and transform + * feedback. + */ +static inline uint32_t +poly_map_vertex_in_tri_strip(uint32_t prim, uint32_t vert, bool flatshade_first) +{ + unsigned pv = flatshade_first ? 0 : 2; + + bool even = (prim & 1) == 0; + bool provoking = vert == pv; + + return (provoking || even) ? vert : ((3 - pv) - vert); +} + +static inline uint32_t +poly_vertex_id_for_line_loop(uint32_t prim, uint32_t vert, uint32_t num_prims) +{ + /* (0, 1), (1, 2), (2, 0) */ + if (prim == (num_prims - 1) && vert == 1) + return 0; + else + return prim + vert; +} + +static inline uint32_t +poly_vertex_id_for_tri_fan(uint32_t prim, uint32_t vert, bool flatshade_first) +{ + /* Vulkan spec section 20.1.7 gives (i + 1, i + 2, 0) for a provoking + * first. OpenGL instead wants (0, i + 1, i + 2) with a provoking last. + * Piglit clipflat expects us to switch between these orders depending on + * provoking vertex, to avoid trivializing the fan. + * + * Rotate accordingly. + */ + if (flatshade_first) { + vert = (vert == 2) ? 0 : (vert + 1); + } + + /* The simpler form assuming last is provoking. */ + return (vert == 0) ? 0 : prim + vert; +} + +static inline uint32_t +poly_vertex_id_for_tri_strip_adj(uint32_t prim, uint32_t vert, + uint32_t num_prims, bool flatshade_first) +{ + /* See Vulkan spec section 20.1.11 "Triangle Strips With Adjancency". + * + * There are different cases for first/middle/last/only primitives and for + * odd/even primitives. Determine which case we're in. + */ + bool last = prim == (num_prims - 1); + bool first = prim == 0; + bool even = (prim & 1) == 0; + bool even_or_first = even || first; + + /* When the last vertex is provoking, we rotate the primitives + * accordingly. This seems required for OpenGL. + */ + if (!flatshade_first && !even_or_first) { + vert = (vert + 4u) % 6u; + } + + /* Offsets per the spec. The spec lists 6 cases with 6 offsets. Luckily, + * there are lots of patterns we can exploit, avoiding a full 6x6 LUT. + * + * Here we assume the first vertex is provoking, the Vulkan default. + */ + uint32_t offsets[6] = { + 0, + first ? 1 : (even ? -2 : 3), + even_or_first ? 2 : 4, + last ? 5 : 6, + even_or_first ? 4 : 2, + even_or_first ? 3 : -2, + }; + + /* Ensure NIR can see thru the local array */ + uint32_t offset = 0; + for (uint32_t i = 1; i < 6; ++i) { + if (i == vert) + offset = offsets[i]; + } + + /* Finally add to the base of the primitive */ + return (prim * 2) + offset; +} + +static inline uint32_t +poly_vertex_id_for_topology(enum mesa_prim mode, bool flatshade_first, + uint32_t prim, uint32_t vert, uint32_t num_prims) +{ + switch (mode) { + case MESA_PRIM_POINTS: + case MESA_PRIM_LINES: + case MESA_PRIM_TRIANGLES: + case MESA_PRIM_LINES_ADJACENCY: + case MESA_PRIM_TRIANGLES_ADJACENCY: + /* Regular primitive: every N vertices defines a primitive */ + return (prim * mesa_vertices_per_prim(mode)) + vert; + + case MESA_PRIM_LINE_LOOP: + return poly_vertex_id_for_line_loop(prim, vert, num_prims); + + case MESA_PRIM_LINE_STRIP: + case MESA_PRIM_LINE_STRIP_ADJACENCY: + /* (i, i + 1) or (i, ..., i + 3) */ + return prim + vert; + + case MESA_PRIM_TRIANGLE_STRIP: { + /* Order depends on the provoking vert. + * + * First: (0, 1, 2), (1, 3, 2), (2, 3, 4). + * Last: (0, 1, 2), (2, 1, 3), (2, 3, 4). + * + * Pull the (maybe swapped) vert from the corresponding primitive + */ + return prim + poly_map_vertex_in_tri_strip(prim, vert, flatshade_first); + } + + case MESA_PRIM_TRIANGLE_FAN: + return poly_vertex_id_for_tri_fan(prim, vert, flatshade_first); + + case MESA_PRIM_TRIANGLE_STRIP_ADJACENCY: + return poly_vertex_id_for_tri_strip_adj(prim, vert, num_prims, + flatshade_first); + + default: + return 0; + } +}