mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-01-08 19:20:12 +01:00
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>
147 lines
4.3 KiB
C
147 lines
4.3 KiB
C
/*
|
|
* 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;
|
|
}
|
|
}
|