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