• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef NV_PUSH_H
2 #define NV_PUSH_H
3 
4 #include "nvtypes.h"
5 #include "util/macros.h"
6 
7 #include <assert.h>
8 #include <stddef.h>
9 #include <string.h>
10 #include <stdio.h>
11 
12 struct nv_device_info;
13 
14 struct nv_push {
15    uint32_t *start;
16    uint32_t *end;
17    uint32_t *limit;
18 
19    /* A pointer to the last method header */
20    uint32_t *last_hdr;
21 
22    /* The value in the last method header, used to avoid read-back */
23    uint32_t last_hdr_dw;
24 };
25 
26 static inline void
nv_push_init(struct nv_push * push,uint32_t * start,size_t dw_count)27 nv_push_init(struct nv_push *push, uint32_t *start, size_t dw_count)
28 {
29    push->start = start;
30    push->end = start;
31    push->limit = start + dw_count;
32    push->last_hdr = NULL;
33    push->last_hdr_dw = 0;
34 }
35 
36 static inline size_t
nv_push_dw_count(struct nv_push * push)37 nv_push_dw_count(struct nv_push *push)
38 {
39    assert(push->start <= push->end);
40    assert(push->end <= push->limit);
41    return push->end - push->start;
42 }
43 
44 #ifndef NDEBUG
45 void nv_push_validate(struct nv_push *push);
46 #else
nv_push_validate(struct nv_push * push)47 static inline void nv_push_validate(struct nv_push *push) { }
48 #endif
49 
50 void vk_push_print(FILE *fp, const struct nv_push *push,
51                    const struct nv_device_info *devinfo);
52 
53 #define SUBC_NV9097 0
54 #define SUBC_NVA097 0
55 #define SUBC_NVB097 0
56 #define SUBC_NVB197 0
57 #define SUBC_NVC097 0
58 #define SUBC_NVC397 0
59 #define SUBC_NVC597 0
60 #define SUBC_NVC797 0
61 
62 #define SUBC_NV90C0 1
63 #define SUBC_NVA0C0 1
64 #define SUBC_NVB0C0 1
65 #define SUBC_NVB1C0 1
66 #define SUBC_NVC0C0 1
67 #define SUBC_NVC3C0 1
68 #define SUBC_NVC6C0 1
69 
70 #define SUBC_NV9039 2
71 
72 #define SUBC_NV902D 3
73 
74 #define SUBC_NV90B5 4
75 #define SUBC_NVC1B5 4
76 
77 static inline uint32_t
NVC0_FIFO_PKHDR_SQ(int subc,int mthd,unsigned size)78 NVC0_FIFO_PKHDR_SQ(int subc, int mthd, unsigned size)
79 {
80    return 0x20000000 | (size << 16) | (subc << 13) | (mthd >> 2);
81 }
82 
83 static inline void
__push_verify(struct nv_push * push)84 __push_verify(struct nv_push *push)
85 {
86    if (push->last_hdr == NULL)
87       return;
88 
89    /* check for immd */
90    if (push->last_hdr_dw >> 29 == 4)
91       return;
92 
93    ASSERTED uint32_t last_count = (push->last_hdr_dw & 0x1fff0000);
94    assert(last_count);
95 }
96 
97 static inline void
__push_hdr(struct nv_push * push,uint32_t hdr)98 __push_hdr(struct nv_push *push, uint32_t hdr)
99 {
100    __push_verify(push);
101 
102    *push->end = hdr;
103    push->last_hdr_dw = hdr;
104    push->last_hdr = push->end;
105    push->end++;
106 }
107 
108 static inline void
__push_mthd_size(struct nv_push * push,int subc,uint32_t mthd,unsigned size)109 __push_mthd_size(struct nv_push *push, int subc, uint32_t mthd, unsigned size)
110 {
111    __push_hdr(push, NVC0_FIFO_PKHDR_SQ(subc, mthd, size));
112 }
113 
114 static inline void
__push_mthd(struct nv_push * push,int subc,uint32_t mthd)115 __push_mthd(struct nv_push *push, int subc, uint32_t mthd)
116 {
117    __push_mthd_size(push, subc, mthd, 0);
118 }
119 
120 #define P_MTHD(push, class, mthd) __push_mthd(push, SUBC_##class, class##_##mthd)
121 
122 static inline uint32_t
NVC0_FIFO_PKHDR_IL(int subc,int mthd,uint16_t data)123 NVC0_FIFO_PKHDR_IL(int subc, int mthd, uint16_t data)
124 {
125    assert(!(data & ~0x1fff));
126    return 0x80000000 | (data << 16) | (subc << 13) | (mthd >> 2);
127 }
128 
129 static inline void
__push_immd(struct nv_push * push,int subc,uint32_t mthd,uint32_t val)130 __push_immd(struct nv_push *push, int subc, uint32_t mthd, uint32_t val)
131 {
132    __push_hdr(push, NVC0_FIFO_PKHDR_IL(subc, mthd, val));
133 }
134 
135 #define P_IMMD(push, class, mthd, args...) do {                         \
136    uint32_t __val;                                                      \
137    VA_##class##_##mthd(__val, args);                                    \
138    if (__builtin_constant_p(__val & ~0x1fff) && !(__val & ~0x1fff)) {   \
139       __push_immd(push, SUBC_##class, class##_##mthd, __val);           \
140    } else {                                                             \
141       __push_mthd_size(push, SUBC_##class, class##_##mthd, 0);          \
142       nv_push_val(push, class##_##mthd, __val);                        \
143    }                                                                    \
144 } while(0)
145 
146 static inline uint32_t
NVC0_FIFO_PKHDR_1I(int subc,int mthd,unsigned size)147 NVC0_FIFO_PKHDR_1I(int subc, int mthd, unsigned size)
148 {
149    return 0xa0000000 | (size << 16) | (subc << 13) | (mthd >> 2);
150 }
151 
152 static inline void
__push_1inc(struct nv_push * push,int subc,uint32_t mthd)153 __push_1inc(struct nv_push *push, int subc, uint32_t mthd)
154 {
155    __push_hdr(push, NVC0_FIFO_PKHDR_1I(subc, mthd, 0));
156 }
157 
158 #define P_1INC(push, class, mthd) __push_1inc(push, SUBC_##class, class##_##mthd)
159 
160 static inline uint32_t
NVC0_FIFO_PKHDR_0I(int subc,int mthd,unsigned size)161 NVC0_FIFO_PKHDR_0I(int subc, int mthd, unsigned size)
162 {
163    return 0x60000000 | (size << 16) | (subc << 13) | (mthd >> 2);
164 }
165 
166 static inline void
__push_0inc(struct nv_push * push,int subc,uint32_t mthd)167 __push_0inc(struct nv_push *push, int subc, uint32_t mthd)
168 {
169    __push_hdr(push, NVC0_FIFO_PKHDR_0I(subc, mthd, 0));
170 }
171 
172 #define P_0INC(push, class, mthd) __push_0inc(push, SUBC_##class, class##_##mthd)
173 
174 #define NV_PUSH_MAX_COUNT 0x1fff
175 
176 static inline bool
nv_push_update_count(struct nv_push * push,uint16_t count)177 nv_push_update_count(struct nv_push *push, uint16_t count)
178 {
179    assert(push->last_hdr != NULL);
180 
181    assert(count <= NV_PUSH_MAX_COUNT);
182    if (count > NV_PUSH_MAX_COUNT)
183       return false;
184 
185    uint32_t hdr_dw = push->last_hdr_dw;
186 
187    /* size is encoded at 28:16 */
188    uint32_t new_count = (count + (hdr_dw >> 16)) & NV_PUSH_MAX_COUNT;
189    bool overflow = new_count < count;
190    /* if we would overflow, don't change anything and just let it be */
191    assert(!overflow);
192    if (overflow)
193       return false;
194 
195    hdr_dw &= ~0x1fff0000;
196    hdr_dw |= new_count << 16;
197    push->last_hdr_dw = hdr_dw;
198    *push->last_hdr = hdr_dw;
199    return true;
200 }
201 
202 static inline void
P_INLINE_DATA(struct nv_push * push,uint32_t value)203 P_INLINE_DATA(struct nv_push *push, uint32_t value)
204 {
205    assert(push->end < push->limit);
206    if (nv_push_update_count(push, 1)) {
207       /* push new value */
208       *push->end = value;
209       push->end++;
210    }
211 }
212 
213 static inline void
P_INLINE_FLOAT(struct nv_push * push,float value)214 P_INLINE_FLOAT(struct nv_push *push, float value)
215 {
216    assert(push->end < push->limit);
217    if (nv_push_update_count(push, 1)) {
218       /* push new value */
219       *(float *)push->end = value;
220       push->end++;
221    }
222 }
223 
224 static inline void
P_INLINE_ARRAY(struct nv_push * push,const uint32_t * data,int num_dw)225 P_INLINE_ARRAY(struct nv_push *push, const uint32_t *data, int num_dw)
226 {
227    assert(push->end + num_dw <= push->limit);
228    if (nv_push_update_count(push, num_dw)) {
229       /* push new value */
230       memcpy(push->end, data, num_dw * 4);
231       push->end += num_dw;
232    }
233 }
234 
235 /* internally used by generated inlines. */
236 static inline void
nv_push_val(struct nv_push * push,uint32_t idx,uint32_t val)237 nv_push_val(struct nv_push *push, uint32_t idx, uint32_t val)
238 {
239    ASSERTED uint32_t last_hdr_dw = push->last_hdr_dw;
240    ASSERTED bool is_0inc = (last_hdr_dw & 0xe0000000) == 0x60000000;
241    ASSERTED bool is_1inc = (last_hdr_dw & 0xe0000000) == 0xa0000000;
242    ASSERTED bool is_immd = (last_hdr_dw & 0xe0000000) == 0x80000000;
243    ASSERTED uint16_t last_method = (last_hdr_dw & 0x1fff) << 2;
244 
245    uint16_t distance = push->end - push->last_hdr - 1;
246    if (is_0inc)
247       distance = 0;
248    else if (is_1inc)
249       distance = MIN2(1, distance);
250    last_method += distance * 4;
251 
252    /* can't have empty headers ever */
253    assert(last_hdr_dw);
254    assert(!is_immd);
255    assert(last_method == idx);
256    assert(push->end < push->limit);
257 
258    P_INLINE_DATA(push, val);
259 }
260 
261 static inline void
nv_push_raw(struct nv_push * push,uint32_t * raw_dw,uint32_t dw_count)262 nv_push_raw(struct nv_push *push, uint32_t *raw_dw, uint32_t dw_count)
263 {
264    assert(push->end + dw_count <= push->limit);
265    memcpy(push->end, raw_dw, dw_count * 4);
266    push->end += dw_count;
267    push->last_hdr = NULL;
268 }
269 
270 #endif /* NV_PUSH_H */
271