xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/freedreno/a6xx/fd6_vsc.cc (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright © 2020 Google, Inc.
3  * SPDX-License-Identifier: MIT
4  */
5 
6 #define FD_BO_NO_HARDPIN 1
7 
8 #include "pipe/p_state.h"
9 
10 #include "freedreno_batch.h"
11 #include "freedreno_gmem.h"
12 
13 #include "fd6_vsc.h"
14 
15 /*
16  * Helper util to update expected vsc draw and primitive stream sizes, see
17  * https://gitlab.freedesktop.org/freedreno/freedreno/-/wikis/Visibility-Stream-Format
18  */
19 
20 enum bits_per {
21    byte = 8,
22    dword = 4 * byte,
23 };
24 
25 /**
26  * Determine # of bits required to store a given number, see
27  * https://gitlab.freedesktop.org/freedreno/freedreno/-/wikis/Visibility-Stream-Format#numbers
28  */
29 static unsigned
number_size_bits(unsigned nr)30 number_size_bits(unsigned nr)
31 {
32    unsigned n = util_last_bit(nr);
33    assert(n); /* encoding 0 is not possible */
34    return n + (n - 1);
35 }
36 
37 /**
38  * Determine # of bits requred to store a given bitfield, see
39  * https://gitlab.freedesktop.org/freedreno/freedreno/-/wikis/Visibility-Stream-Format#bitfields
40  */
41 static unsigned
bitfield_size_bits(unsigned n)42 bitfield_size_bits(unsigned n)
43 {
44    return n + 1; /* worst case is always 1 + nr of bits */
45 }
46 
47 static unsigned
prim_count(const struct pipe_draw_info * info,const struct pipe_draw_start_count_bias * draw)48 prim_count(const struct pipe_draw_info *info,
49            const struct pipe_draw_start_count_bias *draw)
50 {
51    /* MESA_PRIM_COUNT used internally for RECTLIST blits on 3d pipe: */
52    unsigned vtx_per_prim =
53       (info->mode == MESA_PRIM_COUNT) ? 2 : mesa_vertices_per_prim(info->mode);
54    return MAX2(1, (draw->count * info->instance_count) / vtx_per_prim);
55 }
56 
57 /**
58  * The primitive stream uses a run-length encoding, where each packet contains a
59  * bitfield of bins covered and then the number of primitives which have the
60  * same bitfield. Each packet consists of the following, in order:
61  *
62  *  - The (compressed) bitfield of bins covered
63  *  - The number of primitives with this bitset
64  *  - Checksum
65  *
66  * The worst case would be that each primitive has a different bitmask.  In
67  * practice, assuming ever other primitive has a different bitmask still gets us
68  * conservatively large primitive stream sizes.  (Ie. 10x what is needed, vs.
69  * 20x)
70  *
71  * https://gitlab.freedesktop.org/freedreno/freedreno/-/wikis/Visibility-Stream-Format#primitive-streams
72  */
73 static unsigned
primitive_stream_size_bits(const struct pipe_draw_info * info,const struct pipe_draw_start_count_bias * draw,unsigned num_bins)74 primitive_stream_size_bits(const struct pipe_draw_info *info,
75                            const struct pipe_draw_start_count_bias *draw,
76                            unsigned num_bins)
77 {
78    unsigned num_prims = prim_count(info, draw);
79    unsigned nbits =
80       (bitfield_size_bits(num_bins) /* bitfield of bins covered */
81        + number_size_bits(1)        /* number of primitives with this bitset */
82        + 1                          /* checksum */
83        ) *
84       DIV_ROUND_UP(num_prims, 2);
85    return align(nbits, dword);
86 }
87 
88 /**
89  * Each draw stream packet contains the following:
90  *
91  *  - Bin bitfield
92  *  - Last instance bit
93  *  - If bitfield is empty, the number of draws it is empty for, otherwise
94  *    the size of the corresponding primitive stream in DWORD's.
95  *  - Checksum
96  *
97  * https://gitlab.freedesktop.org/freedreno/freedreno/-/wikis/Visibility-Stream-Format#draw-streams
98  */
99 static unsigned
draw_stream_size_bits(const struct pipe_draw_info * info,unsigned num_bins,unsigned prim_strm_bits)100 draw_stream_size_bits(const struct pipe_draw_info *info, unsigned num_bins,
101                       unsigned prim_strm_bits)
102 {
103    unsigned ndwords = prim_strm_bits / dword;
104    return (bitfield_size_bits(num_bins) /* bitfield of bins */
105            + 1                          /* last-instance-bit */
106            + number_size_bits(ndwords)  /* size of corresponding prim strm */
107            + 1                          /* checksum */
108            ) *
109           MAX2(1, info->instance_count);
110 }
111 
112 void
fd6_vsc_update_sizes(struct fd_batch * batch,const struct pipe_draw_info * info,const struct pipe_draw_start_count_bias * draw)113 fd6_vsc_update_sizes(struct fd_batch *batch, const struct pipe_draw_info *info,
114                      const struct pipe_draw_start_count_bias *draw)
115 {
116    if (!batch->num_bins_per_pipe) {
117       batch->num_bins_per_pipe = fd_gmem_estimate_bins_per_pipe(batch);
118 
119       /* This is a convenient spot to add the size of the final draw-
120        * stream packet:
121        *
122        * If there are N bins, the final packet, after all the draws are
123        * done, consists of a 1 followed by N + 17 0's, plus a final 1.
124        * This uses the otherwise-unused pattern of a non-empty bitfield
125        * (initial 1) that is nontheless empty (has all 0's)
126        */
127       unsigned final_pkt_sz = 1 + batch->num_bins_per_pipe + 17 + 1;
128       batch->prim_strm_bits = align(final_pkt_sz, dword);
129    }
130 
131    unsigned prim_strm_bits =
132       primitive_stream_size_bits(info, draw, batch->num_bins_per_pipe);
133    unsigned draw_strm_bits =
134       draw_stream_size_bits(info, batch->num_bins_per_pipe, prim_strm_bits);
135 
136 #if 0
137    mesa_logd("vsc: prim_strm_bits=%d, draw_strm_bits=%d, nb=%u, ic=%u, c=%u, pc=%u (%s)",
138              prim_strm_bits, draw_strm_bits, batch->num_bins_per_pipe,
139              info->instance_count, info->count,
140              (info->count * info->instance_count) /
141              mesa_vertices_per_prim(info->mode),
142              u_prim_name(info->mode));
143 #endif
144 
145    batch->prim_strm_bits += prim_strm_bits;
146    batch->draw_strm_bits += draw_strm_bits;
147 }
148