1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2019 Google LLC
3bf215546Sopenharmony_ci * SPDX-License-Identifier: MIT
4bf215546Sopenharmony_ci */
5bf215546Sopenharmony_ci
6bf215546Sopenharmony_ci#ifndef TU_CS_H
7bf215546Sopenharmony_ci#define TU_CS_H
8bf215546Sopenharmony_ci
9bf215546Sopenharmony_ci#include "tu_common.h"
10bf215546Sopenharmony_ci
11bf215546Sopenharmony_ci#include "freedreno_pm4.h"
12bf215546Sopenharmony_ci
13bf215546Sopenharmony_ci#include "tu_drm.h"
14bf215546Sopenharmony_ci
15bf215546Sopenharmony_ci/* For breadcrumbs we may open a network socket based on the envvar,
16bf215546Sopenharmony_ci * it's not something that should be enabled by default.
17bf215546Sopenharmony_ci */
18bf215546Sopenharmony_ci#define TU_BREADCRUMBS_ENABLED 0
19bf215546Sopenharmony_ci
20bf215546Sopenharmony_cienum tu_cs_mode
21bf215546Sopenharmony_ci{
22bf215546Sopenharmony_ci
23bf215546Sopenharmony_ci   /*
24bf215546Sopenharmony_ci    * A command stream in TU_CS_MODE_GROW mode grows automatically whenever it
25bf215546Sopenharmony_ci    * is full.  tu_cs_begin must be called before command packet emission and
26bf215546Sopenharmony_ci    * tu_cs_end must be called after.
27bf215546Sopenharmony_ci    *
28bf215546Sopenharmony_ci    * This mode may create multiple entries internally.  The entries must be
29bf215546Sopenharmony_ci    * submitted together.
30bf215546Sopenharmony_ci    */
31bf215546Sopenharmony_ci   TU_CS_MODE_GROW,
32bf215546Sopenharmony_ci
33bf215546Sopenharmony_ci   /*
34bf215546Sopenharmony_ci    * A command stream in TU_CS_MODE_EXTERNAL mode wraps an external,
35bf215546Sopenharmony_ci    * fixed-size buffer.  tu_cs_begin and tu_cs_end are optional and have no
36bf215546Sopenharmony_ci    * effect on it.
37bf215546Sopenharmony_ci    *
38bf215546Sopenharmony_ci    * This mode does not create any entry or any BO.
39bf215546Sopenharmony_ci    */
40bf215546Sopenharmony_ci   TU_CS_MODE_EXTERNAL,
41bf215546Sopenharmony_ci
42bf215546Sopenharmony_ci   /*
43bf215546Sopenharmony_ci    * A command stream in TU_CS_MODE_SUB_STREAM mode does not support direct
44bf215546Sopenharmony_ci    * command packet emission.  tu_cs_begin_sub_stream must be called to get a
45bf215546Sopenharmony_ci    * sub-stream to emit comamnd packets to.  When done with the sub-stream,
46bf215546Sopenharmony_ci    * tu_cs_end_sub_stream must be called.
47bf215546Sopenharmony_ci    *
48bf215546Sopenharmony_ci    * This mode does not create any entry internally.
49bf215546Sopenharmony_ci    */
50bf215546Sopenharmony_ci   TU_CS_MODE_SUB_STREAM,
51bf215546Sopenharmony_ci};
52bf215546Sopenharmony_ci
53bf215546Sopenharmony_cistruct tu_cs_entry
54bf215546Sopenharmony_ci{
55bf215546Sopenharmony_ci   /* No ownership */
56bf215546Sopenharmony_ci   const struct tu_bo *bo;
57bf215546Sopenharmony_ci
58bf215546Sopenharmony_ci   uint32_t size;
59bf215546Sopenharmony_ci   uint32_t offset;
60bf215546Sopenharmony_ci};
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_cistruct tu_cs_memory {
63bf215546Sopenharmony_ci   uint32_t *map;
64bf215546Sopenharmony_ci   uint64_t iova;
65bf215546Sopenharmony_ci};
66bf215546Sopenharmony_ci
67bf215546Sopenharmony_cistruct tu_draw_state {
68bf215546Sopenharmony_ci   uint64_t iova : 48;
69bf215546Sopenharmony_ci   uint32_t size : 16;
70bf215546Sopenharmony_ci};
71bf215546Sopenharmony_ci
72bf215546Sopenharmony_ci#define TU_COND_EXEC_STACK_SIZE 4
73bf215546Sopenharmony_ci
74bf215546Sopenharmony_cistruct tu_cs
75bf215546Sopenharmony_ci{
76bf215546Sopenharmony_ci   uint32_t *start;
77bf215546Sopenharmony_ci   uint32_t *cur;
78bf215546Sopenharmony_ci   uint32_t *reserved_end;
79bf215546Sopenharmony_ci   uint32_t *end;
80bf215546Sopenharmony_ci
81bf215546Sopenharmony_ci   struct tu_device *device;
82bf215546Sopenharmony_ci   enum tu_cs_mode mode;
83bf215546Sopenharmony_ci   uint32_t next_bo_size;
84bf215546Sopenharmony_ci
85bf215546Sopenharmony_ci   struct tu_cs_entry *entries;
86bf215546Sopenharmony_ci   uint32_t entry_count;
87bf215546Sopenharmony_ci   uint32_t entry_capacity;
88bf215546Sopenharmony_ci
89bf215546Sopenharmony_ci   struct tu_bo **bos;
90bf215546Sopenharmony_ci   uint32_t bo_count;
91bf215546Sopenharmony_ci   uint32_t bo_capacity;
92bf215546Sopenharmony_ci
93bf215546Sopenharmony_ci   /* Optional BO that this CS is sub-allocated from for TU_CS_MODE_SUB_STREAM */
94bf215546Sopenharmony_ci   struct tu_bo *refcount_bo;
95bf215546Sopenharmony_ci
96bf215546Sopenharmony_ci   /* state for cond_exec_start/cond_exec_end */
97bf215546Sopenharmony_ci   uint32_t cond_stack_depth;
98bf215546Sopenharmony_ci   uint32_t cond_flags[TU_COND_EXEC_STACK_SIZE];
99bf215546Sopenharmony_ci   uint32_t *cond_dwords[TU_COND_EXEC_STACK_SIZE];
100bf215546Sopenharmony_ci
101bf215546Sopenharmony_ci   uint32_t breadcrumb_emit_after;
102bf215546Sopenharmony_ci};
103bf215546Sopenharmony_ci
104bf215546Sopenharmony_civoid
105bf215546Sopenharmony_citu_breadcrumbs_init(struct tu_device *device);
106bf215546Sopenharmony_ci
107bf215546Sopenharmony_civoid
108bf215546Sopenharmony_citu_breadcrumbs_finish(struct tu_device *device);
109bf215546Sopenharmony_ci
110bf215546Sopenharmony_civoid
111bf215546Sopenharmony_citu_cs_init(struct tu_cs *cs,
112bf215546Sopenharmony_ci           struct tu_device *device,
113bf215546Sopenharmony_ci           enum tu_cs_mode mode,
114bf215546Sopenharmony_ci           uint32_t initial_size);
115bf215546Sopenharmony_ci
116bf215546Sopenharmony_civoid
117bf215546Sopenharmony_citu_cs_init_external(struct tu_cs *cs, struct tu_device *device,
118bf215546Sopenharmony_ci                    uint32_t *start, uint32_t *end);
119bf215546Sopenharmony_ci
120bf215546Sopenharmony_civoid
121bf215546Sopenharmony_citu_cs_init_suballoc(struct tu_cs *cs, struct tu_device *device,
122bf215546Sopenharmony_ci                    struct tu_suballoc_bo *bo);
123bf215546Sopenharmony_ci
124bf215546Sopenharmony_civoid
125bf215546Sopenharmony_citu_cs_finish(struct tu_cs *cs);
126bf215546Sopenharmony_ci
127bf215546Sopenharmony_civoid
128bf215546Sopenharmony_citu_cs_begin(struct tu_cs *cs);
129bf215546Sopenharmony_ci
130bf215546Sopenharmony_civoid
131bf215546Sopenharmony_citu_cs_end(struct tu_cs *cs);
132bf215546Sopenharmony_ci
133bf215546Sopenharmony_ciVkResult
134bf215546Sopenharmony_citu_cs_begin_sub_stream(struct tu_cs *cs, uint32_t size, struct tu_cs *sub_cs);
135bf215546Sopenharmony_ci
136bf215546Sopenharmony_ciVkResult
137bf215546Sopenharmony_citu_cs_alloc(struct tu_cs *cs,
138bf215546Sopenharmony_ci            uint32_t count,
139bf215546Sopenharmony_ci            uint32_t size,
140bf215546Sopenharmony_ci            struct tu_cs_memory *memory);
141bf215546Sopenharmony_ci
142bf215546Sopenharmony_cistruct tu_cs_entry
143bf215546Sopenharmony_citu_cs_end_sub_stream(struct tu_cs *cs, struct tu_cs *sub_cs);
144bf215546Sopenharmony_ci
145bf215546Sopenharmony_cistatic inline struct tu_draw_state
146bf215546Sopenharmony_citu_cs_end_draw_state(struct tu_cs *cs, struct tu_cs *sub_cs)
147bf215546Sopenharmony_ci{
148bf215546Sopenharmony_ci   struct tu_cs_entry entry = tu_cs_end_sub_stream(cs, sub_cs);
149bf215546Sopenharmony_ci   return (struct tu_draw_state) {
150bf215546Sopenharmony_ci      .iova = entry.bo->iova + entry.offset,
151bf215546Sopenharmony_ci      .size = entry.size / sizeof(uint32_t),
152bf215546Sopenharmony_ci   };
153bf215546Sopenharmony_ci}
154bf215546Sopenharmony_ci
155bf215546Sopenharmony_ciVkResult
156bf215546Sopenharmony_citu_cs_reserve_space(struct tu_cs *cs, uint32_t reserved_size);
157bf215546Sopenharmony_ci
158bf215546Sopenharmony_cistatic inline struct tu_draw_state
159bf215546Sopenharmony_citu_cs_draw_state(struct tu_cs *sub_cs, struct tu_cs *cs, uint32_t size)
160bf215546Sopenharmony_ci{
161bf215546Sopenharmony_ci   struct tu_cs_memory memory;
162bf215546Sopenharmony_ci
163bf215546Sopenharmony_ci   /* TODO: clean this up */
164bf215546Sopenharmony_ci   tu_cs_alloc(sub_cs, size, 1, &memory);
165bf215546Sopenharmony_ci   tu_cs_init_external(cs, sub_cs->device, memory.map, memory.map + size);
166bf215546Sopenharmony_ci   tu_cs_begin(cs);
167bf215546Sopenharmony_ci   tu_cs_reserve_space(cs, size);
168bf215546Sopenharmony_ci
169bf215546Sopenharmony_ci   return (struct tu_draw_state) {
170bf215546Sopenharmony_ci      .iova = memory.iova,
171bf215546Sopenharmony_ci      .size = size,
172bf215546Sopenharmony_ci   };
173bf215546Sopenharmony_ci}
174bf215546Sopenharmony_ci
175bf215546Sopenharmony_civoid
176bf215546Sopenharmony_citu_cs_reset(struct tu_cs *cs);
177bf215546Sopenharmony_ci
178bf215546Sopenharmony_ciVkResult
179bf215546Sopenharmony_citu_cs_add_entries(struct tu_cs *cs, struct tu_cs *target);
180bf215546Sopenharmony_ci
181bf215546Sopenharmony_ci/**
182bf215546Sopenharmony_ci * Get the size of the command packets emitted since the last call to
183bf215546Sopenharmony_ci * tu_cs_add_entry.
184bf215546Sopenharmony_ci */
185bf215546Sopenharmony_cistatic inline uint32_t
186bf215546Sopenharmony_citu_cs_get_size(const struct tu_cs *cs)
187bf215546Sopenharmony_ci{
188bf215546Sopenharmony_ci   return cs->cur - cs->start;
189bf215546Sopenharmony_ci}
190bf215546Sopenharmony_ci
191bf215546Sopenharmony_ci/**
192bf215546Sopenharmony_ci * Return true if there is no command packet emitted since the last call to
193bf215546Sopenharmony_ci * tu_cs_add_entry.
194bf215546Sopenharmony_ci */
195bf215546Sopenharmony_cistatic inline uint32_t
196bf215546Sopenharmony_citu_cs_is_empty(const struct tu_cs *cs)
197bf215546Sopenharmony_ci{
198bf215546Sopenharmony_ci   return tu_cs_get_size(cs) == 0;
199bf215546Sopenharmony_ci}
200bf215546Sopenharmony_ci
201bf215546Sopenharmony_ci/**
202bf215546Sopenharmony_ci * Discard all entries.  This allows \a cs to be reused while keeping the
203bf215546Sopenharmony_ci * existing BOs and command packets intact.
204bf215546Sopenharmony_ci */
205bf215546Sopenharmony_cistatic inline void
206bf215546Sopenharmony_citu_cs_discard_entries(struct tu_cs *cs)
207bf215546Sopenharmony_ci{
208bf215546Sopenharmony_ci   assert(cs->mode == TU_CS_MODE_GROW);
209bf215546Sopenharmony_ci   cs->entry_count = 0;
210bf215546Sopenharmony_ci}
211bf215546Sopenharmony_ci
212bf215546Sopenharmony_ci/**
213bf215546Sopenharmony_ci * Get the size needed for tu_cs_emit_call.
214bf215546Sopenharmony_ci */
215bf215546Sopenharmony_cistatic inline uint32_t
216bf215546Sopenharmony_citu_cs_get_call_size(const struct tu_cs *cs)
217bf215546Sopenharmony_ci{
218bf215546Sopenharmony_ci   assert(cs->mode == TU_CS_MODE_GROW);
219bf215546Sopenharmony_ci   /* each CP_INDIRECT_BUFFER needs 4 dwords */
220bf215546Sopenharmony_ci   return cs->entry_count * 4;
221bf215546Sopenharmony_ci}
222bf215546Sopenharmony_ci
223bf215546Sopenharmony_ci/**
224bf215546Sopenharmony_ci * Assert that we did not exceed the reserved space.
225bf215546Sopenharmony_ci */
226bf215546Sopenharmony_cistatic inline void
227bf215546Sopenharmony_citu_cs_sanity_check(const struct tu_cs *cs)
228bf215546Sopenharmony_ci{
229bf215546Sopenharmony_ci   assert(cs->start <= cs->cur);
230bf215546Sopenharmony_ci   assert(cs->cur <= cs->reserved_end);
231bf215546Sopenharmony_ci   assert(cs->reserved_end <= cs->end);
232bf215546Sopenharmony_ci}
233bf215546Sopenharmony_ci
234bf215546Sopenharmony_civoid
235bf215546Sopenharmony_citu_cs_emit_sync_breadcrumb(struct tu_cs *cs, uint8_t opcode, uint16_t cnt);
236bf215546Sopenharmony_ci
237bf215546Sopenharmony_ci/**
238bf215546Sopenharmony_ci * Emit a uint32_t value into a command stream, without boundary checking.
239bf215546Sopenharmony_ci */
240bf215546Sopenharmony_cistatic inline void
241bf215546Sopenharmony_citu_cs_emit(struct tu_cs *cs, uint32_t value)
242bf215546Sopenharmony_ci{
243bf215546Sopenharmony_ci   assert(cs->cur < cs->reserved_end);
244bf215546Sopenharmony_ci   *cs->cur = value;
245bf215546Sopenharmony_ci   ++cs->cur;
246bf215546Sopenharmony_ci
247bf215546Sopenharmony_ci#if TU_BREADCRUMBS_ENABLED
248bf215546Sopenharmony_ci   cs->breadcrumb_emit_after--;
249bf215546Sopenharmony_ci   if (cs->breadcrumb_emit_after == 0)
250bf215546Sopenharmony_ci      tu_cs_emit_sync_breadcrumb(cs, -1, 0);
251bf215546Sopenharmony_ci#endif
252bf215546Sopenharmony_ci}
253bf215546Sopenharmony_ci
254bf215546Sopenharmony_ci/**
255bf215546Sopenharmony_ci * Emit an array of uint32_t into a command stream, without boundary checking.
256bf215546Sopenharmony_ci */
257bf215546Sopenharmony_cistatic inline void
258bf215546Sopenharmony_citu_cs_emit_array(struct tu_cs *cs, const uint32_t *values, uint32_t length)
259bf215546Sopenharmony_ci{
260bf215546Sopenharmony_ci   assert(cs->cur + length <= cs->reserved_end);
261bf215546Sopenharmony_ci   memcpy(cs->cur, values, sizeof(uint32_t) * length);
262bf215546Sopenharmony_ci   cs->cur += length;
263bf215546Sopenharmony_ci}
264bf215546Sopenharmony_ci
265bf215546Sopenharmony_ci/**
266bf215546Sopenharmony_ci * Get the size of the remaining space in the current BO.
267bf215546Sopenharmony_ci */
268bf215546Sopenharmony_cistatic inline uint32_t
269bf215546Sopenharmony_citu_cs_get_space(const struct tu_cs *cs)
270bf215546Sopenharmony_ci{
271bf215546Sopenharmony_ci   return cs->end - cs->cur;
272bf215546Sopenharmony_ci}
273bf215546Sopenharmony_ci
274bf215546Sopenharmony_cistatic inline void
275bf215546Sopenharmony_citu_cs_reserve(struct tu_cs *cs, uint32_t reserved_size)
276bf215546Sopenharmony_ci{
277bf215546Sopenharmony_ci   if (cs->mode != TU_CS_MODE_GROW) {
278bf215546Sopenharmony_ci      assert(tu_cs_get_space(cs) >= reserved_size);
279bf215546Sopenharmony_ci      assert(cs->reserved_end == cs->end);
280bf215546Sopenharmony_ci      return;
281bf215546Sopenharmony_ci   }
282bf215546Sopenharmony_ci
283bf215546Sopenharmony_ci   if (tu_cs_get_space(cs) >= reserved_size &&
284bf215546Sopenharmony_ci       cs->entry_count < cs->entry_capacity) {
285bf215546Sopenharmony_ci      cs->reserved_end = cs->cur + reserved_size;
286bf215546Sopenharmony_ci      return;
287bf215546Sopenharmony_ci   }
288bf215546Sopenharmony_ci
289bf215546Sopenharmony_ci   ASSERTED VkResult result = tu_cs_reserve_space(cs, reserved_size);
290bf215546Sopenharmony_ci   /* TODO: set this error in tu_cs and use it */
291bf215546Sopenharmony_ci   assert(result == VK_SUCCESS);
292bf215546Sopenharmony_ci}
293bf215546Sopenharmony_ci
294bf215546Sopenharmony_ci/**
295bf215546Sopenharmony_ci * Emit a type-4 command packet header into a command stream.
296bf215546Sopenharmony_ci */
297bf215546Sopenharmony_cistatic inline void
298bf215546Sopenharmony_citu_cs_emit_pkt4(struct tu_cs *cs, uint16_t regindx, uint16_t cnt)
299bf215546Sopenharmony_ci{
300bf215546Sopenharmony_ci   tu_cs_reserve(cs, cnt + 1);
301bf215546Sopenharmony_ci   tu_cs_emit(cs, pm4_pkt4_hdr(regindx, cnt));
302bf215546Sopenharmony_ci}
303bf215546Sopenharmony_ci
304bf215546Sopenharmony_ci/**
305bf215546Sopenharmony_ci * Emit a type-7 command packet header into a command stream.
306bf215546Sopenharmony_ci */
307bf215546Sopenharmony_cistatic inline void
308bf215546Sopenharmony_citu_cs_emit_pkt7(struct tu_cs *cs, uint8_t opcode, uint16_t cnt)
309bf215546Sopenharmony_ci{
310bf215546Sopenharmony_ci#if TU_BREADCRUMBS_ENABLED
311bf215546Sopenharmony_ci   tu_cs_emit_sync_breadcrumb(cs, opcode, cnt + 1);
312bf215546Sopenharmony_ci#endif
313bf215546Sopenharmony_ci
314bf215546Sopenharmony_ci   tu_cs_reserve(cs, cnt + 1);
315bf215546Sopenharmony_ci   tu_cs_emit(cs, pm4_pkt7_hdr(opcode, cnt));
316bf215546Sopenharmony_ci}
317bf215546Sopenharmony_ci
318bf215546Sopenharmony_cistatic inline void
319bf215546Sopenharmony_citu_cs_emit_wfi(struct tu_cs *cs)
320bf215546Sopenharmony_ci{
321bf215546Sopenharmony_ci   tu_cs_emit_pkt7(cs, CP_WAIT_FOR_IDLE, 0);
322bf215546Sopenharmony_ci}
323bf215546Sopenharmony_ci
324bf215546Sopenharmony_cistatic inline void
325bf215546Sopenharmony_citu_cs_emit_qw(struct tu_cs *cs, uint64_t value)
326bf215546Sopenharmony_ci{
327bf215546Sopenharmony_ci   tu_cs_emit(cs, (uint32_t) value);
328bf215546Sopenharmony_ci   tu_cs_emit(cs, (uint32_t) (value >> 32));
329bf215546Sopenharmony_ci}
330bf215546Sopenharmony_ci
331bf215546Sopenharmony_cistatic inline void
332bf215546Sopenharmony_citu_cs_emit_write_reg(struct tu_cs *cs, uint16_t reg, uint32_t value)
333bf215546Sopenharmony_ci{
334bf215546Sopenharmony_ci   tu_cs_emit_pkt4(cs, reg, 1);
335bf215546Sopenharmony_ci   tu_cs_emit(cs, value);
336bf215546Sopenharmony_ci}
337bf215546Sopenharmony_ci
338bf215546Sopenharmony_ci/**
339bf215546Sopenharmony_ci * Emit a CP_INDIRECT_BUFFER command packet.
340bf215546Sopenharmony_ci */
341bf215546Sopenharmony_cistatic inline void
342bf215546Sopenharmony_citu_cs_emit_ib(struct tu_cs *cs, const struct tu_cs_entry *entry)
343bf215546Sopenharmony_ci{
344bf215546Sopenharmony_ci   assert(entry->bo);
345bf215546Sopenharmony_ci   assert(entry->size && entry->offset + entry->size <= entry->bo->size);
346bf215546Sopenharmony_ci   assert(entry->size % sizeof(uint32_t) == 0);
347bf215546Sopenharmony_ci   assert(entry->offset % sizeof(uint32_t) == 0);
348bf215546Sopenharmony_ci
349bf215546Sopenharmony_ci   tu_cs_emit_pkt7(cs, CP_INDIRECT_BUFFER, 3);
350bf215546Sopenharmony_ci   tu_cs_emit_qw(cs, entry->bo->iova + entry->offset);
351bf215546Sopenharmony_ci   tu_cs_emit(cs, entry->size / sizeof(uint32_t));
352bf215546Sopenharmony_ci}
353bf215546Sopenharmony_ci
354bf215546Sopenharmony_ci/* for compute which isn't using SET_DRAW_STATE */
355bf215546Sopenharmony_cistatic inline void
356bf215546Sopenharmony_citu_cs_emit_state_ib(struct tu_cs *cs, struct tu_draw_state state)
357bf215546Sopenharmony_ci{
358bf215546Sopenharmony_ci   if (state.size) {
359bf215546Sopenharmony_ci      tu_cs_emit_pkt7(cs, CP_INDIRECT_BUFFER, 3);
360bf215546Sopenharmony_ci      tu_cs_emit_qw(cs, state.iova);
361bf215546Sopenharmony_ci      tu_cs_emit(cs, state.size);
362bf215546Sopenharmony_ci   }
363bf215546Sopenharmony_ci}
364bf215546Sopenharmony_ci
365bf215546Sopenharmony_ci/**
366bf215546Sopenharmony_ci * Emit a CP_INDIRECT_BUFFER command packet for each entry in the target
367bf215546Sopenharmony_ci * command stream.
368bf215546Sopenharmony_ci */
369bf215546Sopenharmony_cistatic inline void
370bf215546Sopenharmony_citu_cs_emit_call(struct tu_cs *cs, const struct tu_cs *target)
371bf215546Sopenharmony_ci{
372bf215546Sopenharmony_ci   assert(target->mode == TU_CS_MODE_GROW);
373bf215546Sopenharmony_ci   for (uint32_t i = 0; i < target->entry_count; i++)
374bf215546Sopenharmony_ci      tu_cs_emit_ib(cs, target->entries + i);
375bf215546Sopenharmony_ci}
376bf215546Sopenharmony_ci
377bf215546Sopenharmony_ci/* Helpers for bracketing a large sequence of commands of unknown size inside
378bf215546Sopenharmony_ci * a CP_COND_REG_EXEC packet.
379bf215546Sopenharmony_ci */
380bf215546Sopenharmony_cistatic inline void
381bf215546Sopenharmony_citu_cond_exec_start(struct tu_cs *cs, uint32_t cond_flags)
382bf215546Sopenharmony_ci{
383bf215546Sopenharmony_ci   assert(cs->mode == TU_CS_MODE_GROW);
384bf215546Sopenharmony_ci   assert(cs->cond_stack_depth < TU_COND_EXEC_STACK_SIZE);
385bf215546Sopenharmony_ci
386bf215546Sopenharmony_ci   tu_cs_emit_pkt7(cs, CP_COND_REG_EXEC, 2);
387bf215546Sopenharmony_ci   tu_cs_emit(cs, cond_flags);
388bf215546Sopenharmony_ci
389bf215546Sopenharmony_ci   cs->cond_flags[cs->cond_stack_depth] = cond_flags;
390bf215546Sopenharmony_ci   cs->cond_dwords[cs->cond_stack_depth] = cs->cur;
391bf215546Sopenharmony_ci
392bf215546Sopenharmony_ci   /* Emit dummy DWORD field here */
393bf215546Sopenharmony_ci   tu_cs_emit(cs, CP_COND_REG_EXEC_1_DWORDS(0));
394bf215546Sopenharmony_ci
395bf215546Sopenharmony_ci   cs->cond_stack_depth++;
396bf215546Sopenharmony_ci}
397bf215546Sopenharmony_ci#define CP_COND_EXEC_0_RENDER_MODE_GMEM \
398bf215546Sopenharmony_ci   (CP_COND_REG_EXEC_0_MODE(RENDER_MODE) | CP_COND_REG_EXEC_0_GMEM)
399bf215546Sopenharmony_ci#define CP_COND_EXEC_0_RENDER_MODE_SYSMEM \
400bf215546Sopenharmony_ci   (CP_COND_REG_EXEC_0_MODE(RENDER_MODE) | CP_COND_REG_EXEC_0_SYSMEM)
401bf215546Sopenharmony_ci
402bf215546Sopenharmony_cistatic inline void
403bf215546Sopenharmony_citu_cond_exec_end(struct tu_cs *cs)
404bf215546Sopenharmony_ci{
405bf215546Sopenharmony_ci   assert(cs->cond_stack_depth > 0);
406bf215546Sopenharmony_ci   cs->cond_stack_depth--;
407bf215546Sopenharmony_ci
408bf215546Sopenharmony_ci   cs->cond_flags[cs->cond_stack_depth] = 0;
409bf215546Sopenharmony_ci   /* Subtract one here to account for the DWORD field itself. */
410bf215546Sopenharmony_ci   *cs->cond_dwords[cs->cond_stack_depth] =
411bf215546Sopenharmony_ci      cs->cur - cs->cond_dwords[cs->cond_stack_depth] - 1;
412bf215546Sopenharmony_ci}
413bf215546Sopenharmony_ci
414bf215546Sopenharmony_ci/* Temporary struct for tracking a register state to be written, used by
415bf215546Sopenharmony_ci * a6xx-pack.h and tu_cs_emit_regs()
416bf215546Sopenharmony_ci */
417bf215546Sopenharmony_cistruct tu_reg_value {
418bf215546Sopenharmony_ci   uint32_t reg;
419bf215546Sopenharmony_ci   uint64_t value;
420bf215546Sopenharmony_ci   bool is_address;
421bf215546Sopenharmony_ci   struct tu_bo *bo;
422bf215546Sopenharmony_ci   bool bo_write;
423bf215546Sopenharmony_ci   uint32_t bo_offset;
424bf215546Sopenharmony_ci   uint32_t bo_shift;
425bf215546Sopenharmony_ci};
426bf215546Sopenharmony_ci
427bf215546Sopenharmony_ci#define fd_reg_pair tu_reg_value
428bf215546Sopenharmony_ci#define __bo_type struct tu_bo *
429bf215546Sopenharmony_ci
430bf215546Sopenharmony_ci#include "a6xx-pack.xml.h"
431bf215546Sopenharmony_ci
432bf215546Sopenharmony_ci#define __assert_eq(a, b)                                               \
433bf215546Sopenharmony_ci   do {                                                                 \
434bf215546Sopenharmony_ci      if ((a) != (b)) {                                                 \
435bf215546Sopenharmony_ci         fprintf(stderr, "assert failed: " #a " (0x%x) != " #b " (0x%x)\n", a, b); \
436bf215546Sopenharmony_ci         assert((a) == (b));                                            \
437bf215546Sopenharmony_ci      }                                                                 \
438bf215546Sopenharmony_ci   } while (0)
439bf215546Sopenharmony_ci
440bf215546Sopenharmony_ci#define __ONE_REG(i, regs)                                      \
441bf215546Sopenharmony_ci   do {                                                         \
442bf215546Sopenharmony_ci      if (i < ARRAY_SIZE(regs) && regs[i].reg > 0) {            \
443bf215546Sopenharmony_ci         __assert_eq(regs[0].reg + i, regs[i].reg);             \
444bf215546Sopenharmony_ci         if (regs[i].bo) {                                      \
445bf215546Sopenharmony_ci            uint64_t v = regs[i].bo->iova + regs[i].bo_offset;  \
446bf215546Sopenharmony_ci            v >>= regs[i].bo_shift;                             \
447bf215546Sopenharmony_ci            v |= regs[i].value;                                 \
448bf215546Sopenharmony_ci                                                                \
449bf215546Sopenharmony_ci            *p++ = v;                                           \
450bf215546Sopenharmony_ci            *p++ = v >> 32;                                     \
451bf215546Sopenharmony_ci         } else {                                               \
452bf215546Sopenharmony_ci            *p++ = regs[i].value;                               \
453bf215546Sopenharmony_ci            if (regs[i].is_address)                             \
454bf215546Sopenharmony_ci               *p++ = regs[i].value >> 32;                      \
455bf215546Sopenharmony_ci         }                                                      \
456bf215546Sopenharmony_ci      }                                                         \
457bf215546Sopenharmony_ci   } while (0)
458bf215546Sopenharmony_ci
459bf215546Sopenharmony_ci/* Emits a sequence of register writes in order using a pkt4.  This will check
460bf215546Sopenharmony_ci * (at runtime on a !NDEBUG build) that the registers were actually set up in
461bf215546Sopenharmony_ci * order in the code.
462bf215546Sopenharmony_ci *
463bf215546Sopenharmony_ci * Note that references to buffers aren't automatically added to the CS,
464bf215546Sopenharmony_ci * unlike in freedreno.  We are clever in various places to avoid duplicating
465bf215546Sopenharmony_ci * the reference add work.
466bf215546Sopenharmony_ci *
467bf215546Sopenharmony_ci * Also, 64-bit address registers don't have a way (currently) to set a 64-bit
468bf215546Sopenharmony_ci * address without having a reference to a BO, since the .dword field in the
469bf215546Sopenharmony_ci * register's struct is only 32-bit wide.  We should fix this in the pack
470bf215546Sopenharmony_ci * codegen later.
471bf215546Sopenharmony_ci */
472bf215546Sopenharmony_ci#define tu_cs_emit_regs(cs, ...) do {                   \
473bf215546Sopenharmony_ci   const struct fd_reg_pair regs[] = { __VA_ARGS__ };   \
474bf215546Sopenharmony_ci   unsigned count = ARRAY_SIZE(regs);                   \
475bf215546Sopenharmony_ci                                                        \
476bf215546Sopenharmony_ci   STATIC_ASSERT(ARRAY_SIZE(regs) > 0);                 \
477bf215546Sopenharmony_ci   STATIC_ASSERT(ARRAY_SIZE(regs) <= 16);               \
478bf215546Sopenharmony_ci                                                        \
479bf215546Sopenharmony_ci   tu_cs_emit_pkt4((cs), regs[0].reg, count);             \
480bf215546Sopenharmony_ci   uint32_t *p = (cs)->cur;                               \
481bf215546Sopenharmony_ci   __ONE_REG( 0, regs);                                 \
482bf215546Sopenharmony_ci   __ONE_REG( 1, regs);                                 \
483bf215546Sopenharmony_ci   __ONE_REG( 2, regs);                                 \
484bf215546Sopenharmony_ci   __ONE_REG( 3, regs);                                 \
485bf215546Sopenharmony_ci   __ONE_REG( 4, regs);                                 \
486bf215546Sopenharmony_ci   __ONE_REG( 5, regs);                                 \
487bf215546Sopenharmony_ci   __ONE_REG( 6, regs);                                 \
488bf215546Sopenharmony_ci   __ONE_REG( 7, regs);                                 \
489bf215546Sopenharmony_ci   __ONE_REG( 8, regs);                                 \
490bf215546Sopenharmony_ci   __ONE_REG( 9, regs);                                 \
491bf215546Sopenharmony_ci   __ONE_REG(10, regs);                                 \
492bf215546Sopenharmony_ci   __ONE_REG(11, regs);                                 \
493bf215546Sopenharmony_ci   __ONE_REG(12, regs);                                 \
494bf215546Sopenharmony_ci   __ONE_REG(13, regs);                                 \
495bf215546Sopenharmony_ci   __ONE_REG(14, regs);                                 \
496bf215546Sopenharmony_ci   __ONE_REG(15, regs);                                 \
497bf215546Sopenharmony_ci   (cs)->cur = p;                                         \
498bf215546Sopenharmony_ci   } while (0)
499bf215546Sopenharmony_ci
500bf215546Sopenharmony_ci#endif /* TU_CS_H */
501