poly/asahi: Pull a bunch of vertex_id_for helpers into poly/prim.h

There's nothing really CL-specific about any of these.

Acked-by: Alyssa Rosenzweig <alyssa.rosenzweig@intel.com>
Reviewed-by: Mary Guillemard <mary@mary.zone>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/38404>
This commit is contained in:
Faith Ekstrand 2025-11-14 16:19:48 -05:00 committed by Marge Bot
parent 27b2290abe
commit ddff3700a4
3 changed files with 152 additions and 275 deletions

View file

@ -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;

View file

@ -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)
{

147
src/poly/prim.h Normal file
View file

@ -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;
}
}