1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2019 Google LLC
3bf215546Sopenharmony_ci * SPDX-License-Identifier: MIT
4bf215546Sopenharmony_ci */
5bf215546Sopenharmony_ci
6bf215546Sopenharmony_ci#include "tu_cs.h"
7bf215546Sopenharmony_ci
8bf215546Sopenharmony_ci#include "tu_suballoc.h"
9bf215546Sopenharmony_ci
10bf215546Sopenharmony_ci/**
11bf215546Sopenharmony_ci * Initialize a command stream.
12bf215546Sopenharmony_ci */
13bf215546Sopenharmony_civoid
14bf215546Sopenharmony_citu_cs_init(struct tu_cs *cs,
15bf215546Sopenharmony_ci           struct tu_device *device,
16bf215546Sopenharmony_ci           enum tu_cs_mode mode,
17bf215546Sopenharmony_ci           uint32_t initial_size)
18bf215546Sopenharmony_ci{
19bf215546Sopenharmony_ci   assert(mode != TU_CS_MODE_EXTERNAL);
20bf215546Sopenharmony_ci
21bf215546Sopenharmony_ci   memset(cs, 0, sizeof(*cs));
22bf215546Sopenharmony_ci
23bf215546Sopenharmony_ci   cs->device = device;
24bf215546Sopenharmony_ci   cs->mode = mode;
25bf215546Sopenharmony_ci   cs->next_bo_size = initial_size;
26bf215546Sopenharmony_ci}
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci/**
29bf215546Sopenharmony_ci * Initialize a command stream as a wrapper to an external buffer.
30bf215546Sopenharmony_ci */
31bf215546Sopenharmony_civoid
32bf215546Sopenharmony_citu_cs_init_external(struct tu_cs *cs, struct tu_device *device,
33bf215546Sopenharmony_ci                    uint32_t *start, uint32_t *end)
34bf215546Sopenharmony_ci{
35bf215546Sopenharmony_ci   memset(cs, 0, sizeof(*cs));
36bf215546Sopenharmony_ci
37bf215546Sopenharmony_ci   cs->device = device;
38bf215546Sopenharmony_ci   cs->mode = TU_CS_MODE_EXTERNAL;
39bf215546Sopenharmony_ci   cs->start = cs->reserved_end = cs->cur = start;
40bf215546Sopenharmony_ci   cs->end = end;
41bf215546Sopenharmony_ci}
42bf215546Sopenharmony_ci
43bf215546Sopenharmony_ci/**
44bf215546Sopenharmony_ci * Initialize a sub-command stream as a wrapper to an externally sub-allocated
45bf215546Sopenharmony_ci * buffer.
46bf215546Sopenharmony_ci */
47bf215546Sopenharmony_civoid
48bf215546Sopenharmony_citu_cs_init_suballoc(struct tu_cs *cs, struct tu_device *device,
49bf215546Sopenharmony_ci                    struct tu_suballoc_bo *suballoc_bo)
50bf215546Sopenharmony_ci{
51bf215546Sopenharmony_ci   uint32_t *start = tu_suballoc_bo_map(suballoc_bo);
52bf215546Sopenharmony_ci   uint32_t *end = start + (suballoc_bo->size >> 2);
53bf215546Sopenharmony_ci
54bf215546Sopenharmony_ci   memset(cs, 0, sizeof(*cs));
55bf215546Sopenharmony_ci   cs->device = device;
56bf215546Sopenharmony_ci   cs->mode = TU_CS_MODE_SUB_STREAM;
57bf215546Sopenharmony_ci   cs->start = cs->reserved_end = cs->cur = start;
58bf215546Sopenharmony_ci   cs->end = end;
59bf215546Sopenharmony_ci   cs->refcount_bo = tu_bo_get_ref(suballoc_bo->bo);
60bf215546Sopenharmony_ci}
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_ci/**
63bf215546Sopenharmony_ci * Finish and release all resources owned by a command stream.
64bf215546Sopenharmony_ci */
65bf215546Sopenharmony_civoid
66bf215546Sopenharmony_citu_cs_finish(struct tu_cs *cs)
67bf215546Sopenharmony_ci{
68bf215546Sopenharmony_ci   for (uint32_t i = 0; i < cs->bo_count; ++i) {
69bf215546Sopenharmony_ci      tu_bo_finish(cs->device, cs->bos[i]);
70bf215546Sopenharmony_ci   }
71bf215546Sopenharmony_ci
72bf215546Sopenharmony_ci   if (cs->refcount_bo)
73bf215546Sopenharmony_ci      tu_bo_finish(cs->device, cs->refcount_bo);
74bf215546Sopenharmony_ci
75bf215546Sopenharmony_ci   free(cs->entries);
76bf215546Sopenharmony_ci   free(cs->bos);
77bf215546Sopenharmony_ci}
78bf215546Sopenharmony_ci
79bf215546Sopenharmony_cistatic struct tu_bo *
80bf215546Sopenharmony_citu_cs_current_bo(const struct tu_cs *cs)
81bf215546Sopenharmony_ci{
82bf215546Sopenharmony_ci   if (cs->refcount_bo) {
83bf215546Sopenharmony_ci      return cs->refcount_bo;
84bf215546Sopenharmony_ci   } else {
85bf215546Sopenharmony_ci      assert(cs->bo_count);
86bf215546Sopenharmony_ci      return cs->bos[cs->bo_count - 1];
87bf215546Sopenharmony_ci   }
88bf215546Sopenharmony_ci}
89bf215546Sopenharmony_ci
90bf215546Sopenharmony_ci/**
91bf215546Sopenharmony_ci * Get the offset of the command packets emitted since the last call to
92bf215546Sopenharmony_ci * tu_cs_add_entry.
93bf215546Sopenharmony_ci */
94bf215546Sopenharmony_cistatic uint32_t
95bf215546Sopenharmony_citu_cs_get_offset(const struct tu_cs *cs)
96bf215546Sopenharmony_ci{
97bf215546Sopenharmony_ci   return cs->start - (uint32_t *) tu_cs_current_bo(cs)->map;
98bf215546Sopenharmony_ci}
99bf215546Sopenharmony_ci
100bf215546Sopenharmony_ci/*
101bf215546Sopenharmony_ci * Allocate and add a BO to a command stream.  Following command packets will
102bf215546Sopenharmony_ci * be emitted to the new BO.
103bf215546Sopenharmony_ci */
104bf215546Sopenharmony_cistatic VkResult
105bf215546Sopenharmony_citu_cs_add_bo(struct tu_cs *cs, uint32_t size)
106bf215546Sopenharmony_ci{
107bf215546Sopenharmony_ci   /* no BO for TU_CS_MODE_EXTERNAL */
108bf215546Sopenharmony_ci   assert(cs->mode != TU_CS_MODE_EXTERNAL);
109bf215546Sopenharmony_ci   /* No adding more BOs if suballocating from a suballoc_bo. */
110bf215546Sopenharmony_ci   assert(!cs->refcount_bo);
111bf215546Sopenharmony_ci
112bf215546Sopenharmony_ci   /* no dangling command packet */
113bf215546Sopenharmony_ci   assert(tu_cs_is_empty(cs));
114bf215546Sopenharmony_ci
115bf215546Sopenharmony_ci   /* grow cs->bos if needed */
116bf215546Sopenharmony_ci   if (cs->bo_count == cs->bo_capacity) {
117bf215546Sopenharmony_ci      uint32_t new_capacity = MAX2(4, 2 * cs->bo_capacity);
118bf215546Sopenharmony_ci      struct tu_bo **new_bos =
119bf215546Sopenharmony_ci         realloc(cs->bos, new_capacity * sizeof(struct tu_bo *));
120bf215546Sopenharmony_ci      if (!new_bos)
121bf215546Sopenharmony_ci         return VK_ERROR_OUT_OF_HOST_MEMORY;
122bf215546Sopenharmony_ci
123bf215546Sopenharmony_ci      cs->bo_capacity = new_capacity;
124bf215546Sopenharmony_ci      cs->bos = new_bos;
125bf215546Sopenharmony_ci   }
126bf215546Sopenharmony_ci
127bf215546Sopenharmony_ci   struct tu_bo *new_bo;
128bf215546Sopenharmony_ci
129bf215546Sopenharmony_ci   VkResult result =
130bf215546Sopenharmony_ci      tu_bo_init_new(cs->device, &new_bo, size * sizeof(uint32_t),
131bf215546Sopenharmony_ci                     TU_BO_ALLOC_GPU_READ_ONLY | TU_BO_ALLOC_ALLOW_DUMP);
132bf215546Sopenharmony_ci   if (result != VK_SUCCESS) {
133bf215546Sopenharmony_ci      return result;
134bf215546Sopenharmony_ci   }
135bf215546Sopenharmony_ci
136bf215546Sopenharmony_ci   result = tu_bo_map(cs->device, new_bo);
137bf215546Sopenharmony_ci   if (result != VK_SUCCESS) {
138bf215546Sopenharmony_ci      tu_bo_finish(cs->device, new_bo);
139bf215546Sopenharmony_ci      return result;
140bf215546Sopenharmony_ci   }
141bf215546Sopenharmony_ci
142bf215546Sopenharmony_ci   cs->bos[cs->bo_count++] = new_bo;
143bf215546Sopenharmony_ci
144bf215546Sopenharmony_ci   cs->start = cs->cur = cs->reserved_end = (uint32_t *) new_bo->map;
145bf215546Sopenharmony_ci   cs->end = cs->start + new_bo->size / sizeof(uint32_t);
146bf215546Sopenharmony_ci
147bf215546Sopenharmony_ci   return VK_SUCCESS;
148bf215546Sopenharmony_ci}
149bf215546Sopenharmony_ci
150bf215546Sopenharmony_ci/**
151bf215546Sopenharmony_ci * Reserve an IB entry.
152bf215546Sopenharmony_ci */
153bf215546Sopenharmony_cistatic VkResult
154bf215546Sopenharmony_citu_cs_reserve_entry(struct tu_cs *cs)
155bf215546Sopenharmony_ci{
156bf215546Sopenharmony_ci   /* entries are only for TU_CS_MODE_GROW */
157bf215546Sopenharmony_ci   assert(cs->mode == TU_CS_MODE_GROW);
158bf215546Sopenharmony_ci
159bf215546Sopenharmony_ci   /* grow cs->entries if needed */
160bf215546Sopenharmony_ci   if (cs->entry_count == cs->entry_capacity) {
161bf215546Sopenharmony_ci      uint32_t new_capacity = MAX2(4, cs->entry_capacity * 2);
162bf215546Sopenharmony_ci      struct tu_cs_entry *new_entries =
163bf215546Sopenharmony_ci         realloc(cs->entries, new_capacity * sizeof(struct tu_cs_entry));
164bf215546Sopenharmony_ci      if (!new_entries)
165bf215546Sopenharmony_ci         return VK_ERROR_OUT_OF_HOST_MEMORY;
166bf215546Sopenharmony_ci
167bf215546Sopenharmony_ci      cs->entry_capacity = new_capacity;
168bf215546Sopenharmony_ci      cs->entries = new_entries;
169bf215546Sopenharmony_ci   }
170bf215546Sopenharmony_ci
171bf215546Sopenharmony_ci   return VK_SUCCESS;
172bf215546Sopenharmony_ci}
173bf215546Sopenharmony_ci
174bf215546Sopenharmony_ci/**
175bf215546Sopenharmony_ci * Add an IB entry for the command packets emitted since the last call to this
176bf215546Sopenharmony_ci * function.
177bf215546Sopenharmony_ci */
178bf215546Sopenharmony_cistatic void
179bf215546Sopenharmony_citu_cs_add_entry(struct tu_cs *cs)
180bf215546Sopenharmony_ci{
181bf215546Sopenharmony_ci   /* entries are only for TU_CS_MODE_GROW */
182bf215546Sopenharmony_ci   assert(cs->mode == TU_CS_MODE_GROW);
183bf215546Sopenharmony_ci
184bf215546Sopenharmony_ci   /* disallow empty entry */
185bf215546Sopenharmony_ci   assert(!tu_cs_is_empty(cs));
186bf215546Sopenharmony_ci
187bf215546Sopenharmony_ci   /*
188bf215546Sopenharmony_ci    * because we disallow empty entry, tu_cs_add_bo and tu_cs_reserve_entry
189bf215546Sopenharmony_ci    * must both have been called
190bf215546Sopenharmony_ci    */
191bf215546Sopenharmony_ci   assert(cs->bo_count);
192bf215546Sopenharmony_ci   assert(cs->entry_count < cs->entry_capacity);
193bf215546Sopenharmony_ci
194bf215546Sopenharmony_ci   /* add an entry for [cs->start, cs->cur] */
195bf215546Sopenharmony_ci   cs->entries[cs->entry_count++] = (struct tu_cs_entry) {
196bf215546Sopenharmony_ci      .bo = tu_cs_current_bo(cs),
197bf215546Sopenharmony_ci      .size = tu_cs_get_size(cs) * sizeof(uint32_t),
198bf215546Sopenharmony_ci      .offset = tu_cs_get_offset(cs) * sizeof(uint32_t),
199bf215546Sopenharmony_ci   };
200bf215546Sopenharmony_ci
201bf215546Sopenharmony_ci   cs->start = cs->cur;
202bf215546Sopenharmony_ci}
203bf215546Sopenharmony_ci
204bf215546Sopenharmony_ci/**
205bf215546Sopenharmony_ci * same behavior as tu_cs_emit_call but without the indirect
206bf215546Sopenharmony_ci */
207bf215546Sopenharmony_ciVkResult
208bf215546Sopenharmony_citu_cs_add_entries(struct tu_cs *cs, struct tu_cs *target)
209bf215546Sopenharmony_ci{
210bf215546Sopenharmony_ci   VkResult result;
211bf215546Sopenharmony_ci
212bf215546Sopenharmony_ci   assert(cs->mode == TU_CS_MODE_GROW);
213bf215546Sopenharmony_ci   assert(target->mode == TU_CS_MODE_GROW);
214bf215546Sopenharmony_ci
215bf215546Sopenharmony_ci   if (!tu_cs_is_empty(cs))
216bf215546Sopenharmony_ci      tu_cs_add_entry(cs);
217bf215546Sopenharmony_ci
218bf215546Sopenharmony_ci   for (unsigned i = 0; i < target->entry_count; i++) {
219bf215546Sopenharmony_ci      result = tu_cs_reserve_entry(cs);
220bf215546Sopenharmony_ci      if (result != VK_SUCCESS)
221bf215546Sopenharmony_ci         return result;
222bf215546Sopenharmony_ci      cs->entries[cs->entry_count++] = target->entries[i];
223bf215546Sopenharmony_ci   }
224bf215546Sopenharmony_ci
225bf215546Sopenharmony_ci   return VK_SUCCESS;
226bf215546Sopenharmony_ci}
227bf215546Sopenharmony_ci
228bf215546Sopenharmony_ci/**
229bf215546Sopenharmony_ci * Begin (or continue) command packet emission.  This does nothing but sanity
230bf215546Sopenharmony_ci * checks currently.  \a cs must not be in TU_CS_MODE_SUB_STREAM mode.
231bf215546Sopenharmony_ci */
232bf215546Sopenharmony_civoid
233bf215546Sopenharmony_citu_cs_begin(struct tu_cs *cs)
234bf215546Sopenharmony_ci{
235bf215546Sopenharmony_ci   assert(cs->mode != TU_CS_MODE_SUB_STREAM);
236bf215546Sopenharmony_ci   assert(tu_cs_is_empty(cs));
237bf215546Sopenharmony_ci}
238bf215546Sopenharmony_ci
239bf215546Sopenharmony_ci/**
240bf215546Sopenharmony_ci * End command packet emission.  This adds an IB entry when \a cs is in
241bf215546Sopenharmony_ci * TU_CS_MODE_GROW mode.
242bf215546Sopenharmony_ci */
243bf215546Sopenharmony_civoid
244bf215546Sopenharmony_citu_cs_end(struct tu_cs *cs)
245bf215546Sopenharmony_ci{
246bf215546Sopenharmony_ci   assert(cs->mode != TU_CS_MODE_SUB_STREAM);
247bf215546Sopenharmony_ci
248bf215546Sopenharmony_ci   if (cs->mode == TU_CS_MODE_GROW && !tu_cs_is_empty(cs))
249bf215546Sopenharmony_ci      tu_cs_add_entry(cs);
250bf215546Sopenharmony_ci}
251bf215546Sopenharmony_ci
252bf215546Sopenharmony_ci/**
253bf215546Sopenharmony_ci * Begin command packet emission to a sub-stream.  \a cs must be in
254bf215546Sopenharmony_ci * TU_CS_MODE_SUB_STREAM mode.
255bf215546Sopenharmony_ci *
256bf215546Sopenharmony_ci * Return \a sub_cs which is in TU_CS_MODE_EXTERNAL mode.  tu_cs_begin and
257bf215546Sopenharmony_ci * tu_cs_reserve_space are implied and \a sub_cs is ready for command packet
258bf215546Sopenharmony_ci * emission.
259bf215546Sopenharmony_ci */
260bf215546Sopenharmony_ciVkResult
261bf215546Sopenharmony_citu_cs_begin_sub_stream(struct tu_cs *cs, uint32_t size, struct tu_cs *sub_cs)
262bf215546Sopenharmony_ci{
263bf215546Sopenharmony_ci   assert(cs->mode == TU_CS_MODE_SUB_STREAM);
264bf215546Sopenharmony_ci   assert(size);
265bf215546Sopenharmony_ci
266bf215546Sopenharmony_ci   VkResult result = tu_cs_reserve_space(cs, size);
267bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
268bf215546Sopenharmony_ci      return result;
269bf215546Sopenharmony_ci
270bf215546Sopenharmony_ci   tu_cs_init_external(sub_cs, cs->device, cs->cur, cs->reserved_end);
271bf215546Sopenharmony_ci   tu_cs_begin(sub_cs);
272bf215546Sopenharmony_ci   result = tu_cs_reserve_space(sub_cs, size);
273bf215546Sopenharmony_ci   assert(result == VK_SUCCESS);
274bf215546Sopenharmony_ci
275bf215546Sopenharmony_ci   return VK_SUCCESS;
276bf215546Sopenharmony_ci}
277bf215546Sopenharmony_ci
278bf215546Sopenharmony_ci/**
279bf215546Sopenharmony_ci * Allocate count*size dwords, aligned to size dwords.
280bf215546Sopenharmony_ci * \a cs must be in TU_CS_MODE_SUB_STREAM mode.
281bf215546Sopenharmony_ci *
282bf215546Sopenharmony_ci */
283bf215546Sopenharmony_ciVkResult
284bf215546Sopenharmony_citu_cs_alloc(struct tu_cs *cs,
285bf215546Sopenharmony_ci            uint32_t count,
286bf215546Sopenharmony_ci            uint32_t size,
287bf215546Sopenharmony_ci            struct tu_cs_memory *memory)
288bf215546Sopenharmony_ci{
289bf215546Sopenharmony_ci   assert(cs->mode == TU_CS_MODE_SUB_STREAM);
290bf215546Sopenharmony_ci   assert(size && size <= 1024);
291bf215546Sopenharmony_ci
292bf215546Sopenharmony_ci   if (!count)
293bf215546Sopenharmony_ci      return VK_SUCCESS;
294bf215546Sopenharmony_ci
295bf215546Sopenharmony_ci   /* TODO: smarter way to deal with alignment? */
296bf215546Sopenharmony_ci
297bf215546Sopenharmony_ci   VkResult result = tu_cs_reserve_space(cs, count * size + (size-1));
298bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
299bf215546Sopenharmony_ci      return result;
300bf215546Sopenharmony_ci
301bf215546Sopenharmony_ci   struct tu_bo *bo = tu_cs_current_bo(cs);
302bf215546Sopenharmony_ci   size_t offset = align(tu_cs_get_offset(cs), size);
303bf215546Sopenharmony_ci
304bf215546Sopenharmony_ci   memory->map = bo->map + offset * sizeof(uint32_t);
305bf215546Sopenharmony_ci   memory->iova = bo->iova + offset * sizeof(uint32_t);
306bf215546Sopenharmony_ci
307bf215546Sopenharmony_ci   cs->start = cs->cur = (uint32_t*) bo->map + offset + count * size;
308bf215546Sopenharmony_ci
309bf215546Sopenharmony_ci   return VK_SUCCESS;
310bf215546Sopenharmony_ci}
311bf215546Sopenharmony_ci
312bf215546Sopenharmony_ci/**
313bf215546Sopenharmony_ci * End command packet emission to a sub-stream.  \a sub_cs becomes invalid
314bf215546Sopenharmony_ci * after this call.
315bf215546Sopenharmony_ci *
316bf215546Sopenharmony_ci * Return an IB entry for the sub-stream.  The entry has the same lifetime as
317bf215546Sopenharmony_ci * \a cs.
318bf215546Sopenharmony_ci */
319bf215546Sopenharmony_cistruct tu_cs_entry
320bf215546Sopenharmony_citu_cs_end_sub_stream(struct tu_cs *cs, struct tu_cs *sub_cs)
321bf215546Sopenharmony_ci{
322bf215546Sopenharmony_ci   assert(cs->mode == TU_CS_MODE_SUB_STREAM);
323bf215546Sopenharmony_ci   assert(sub_cs->start == cs->cur && sub_cs->end == cs->reserved_end);
324bf215546Sopenharmony_ci   tu_cs_sanity_check(sub_cs);
325bf215546Sopenharmony_ci
326bf215546Sopenharmony_ci   tu_cs_end(sub_cs);
327bf215546Sopenharmony_ci
328bf215546Sopenharmony_ci   cs->cur = sub_cs->cur;
329bf215546Sopenharmony_ci
330bf215546Sopenharmony_ci   struct tu_cs_entry entry = {
331bf215546Sopenharmony_ci      .bo = tu_cs_current_bo(cs),
332bf215546Sopenharmony_ci      .size = tu_cs_get_size(cs) * sizeof(uint32_t),
333bf215546Sopenharmony_ci      .offset = tu_cs_get_offset(cs) * sizeof(uint32_t),
334bf215546Sopenharmony_ci   };
335bf215546Sopenharmony_ci
336bf215546Sopenharmony_ci   cs->start = cs->cur;
337bf215546Sopenharmony_ci
338bf215546Sopenharmony_ci   return entry;
339bf215546Sopenharmony_ci}
340bf215546Sopenharmony_ci
341bf215546Sopenharmony_ci/**
342bf215546Sopenharmony_ci * Reserve space from a command stream for \a reserved_size uint32_t values.
343bf215546Sopenharmony_ci * This never fails when \a cs has mode TU_CS_MODE_EXTERNAL.
344bf215546Sopenharmony_ci */
345bf215546Sopenharmony_ciVkResult
346bf215546Sopenharmony_citu_cs_reserve_space(struct tu_cs *cs, uint32_t reserved_size)
347bf215546Sopenharmony_ci{
348bf215546Sopenharmony_ci   if (tu_cs_get_space(cs) < reserved_size) {
349bf215546Sopenharmony_ci      if (cs->mode == TU_CS_MODE_EXTERNAL) {
350bf215546Sopenharmony_ci         unreachable("cannot grow external buffer");
351bf215546Sopenharmony_ci         return VK_ERROR_OUT_OF_HOST_MEMORY;
352bf215546Sopenharmony_ci      }
353bf215546Sopenharmony_ci
354bf215546Sopenharmony_ci      /* add an entry for the exiting command packets */
355bf215546Sopenharmony_ci      if (!tu_cs_is_empty(cs)) {
356bf215546Sopenharmony_ci         /* no direct command packet for TU_CS_MODE_SUB_STREAM */
357bf215546Sopenharmony_ci         assert(cs->mode != TU_CS_MODE_SUB_STREAM);
358bf215546Sopenharmony_ci
359bf215546Sopenharmony_ci         tu_cs_add_entry(cs);
360bf215546Sopenharmony_ci      }
361bf215546Sopenharmony_ci
362bf215546Sopenharmony_ci      for (uint32_t i = 0; i < cs->cond_stack_depth; i++) {
363bf215546Sopenharmony_ci         /* Subtract one here to account for the DWORD field itself. */
364bf215546Sopenharmony_ci         *cs->cond_dwords[i] = cs->cur - cs->cond_dwords[i] - 1;
365bf215546Sopenharmony_ci
366bf215546Sopenharmony_ci         /* space for CP_COND_REG_EXEC in next bo */
367bf215546Sopenharmony_ci         reserved_size += 3;
368bf215546Sopenharmony_ci      }
369bf215546Sopenharmony_ci
370bf215546Sopenharmony_ci      /* switch to a new BO */
371bf215546Sopenharmony_ci      uint32_t new_size = MAX2(cs->next_bo_size, reserved_size);
372bf215546Sopenharmony_ci      VkResult result = tu_cs_add_bo(cs, new_size);
373bf215546Sopenharmony_ci      if (result != VK_SUCCESS)
374bf215546Sopenharmony_ci         return result;
375bf215546Sopenharmony_ci
376bf215546Sopenharmony_ci      if (cs->cond_stack_depth) {
377bf215546Sopenharmony_ci         cs->reserved_end = cs->cur + reserved_size;
378bf215546Sopenharmony_ci      }
379bf215546Sopenharmony_ci
380bf215546Sopenharmony_ci      /* Re-emit CP_COND_REG_EXECs */
381bf215546Sopenharmony_ci      for (uint32_t i = 0; i < cs->cond_stack_depth; i++) {
382bf215546Sopenharmony_ci         tu_cs_emit_pkt7(cs, CP_COND_REG_EXEC, 2);
383bf215546Sopenharmony_ci         tu_cs_emit(cs, cs->cond_flags[i]);
384bf215546Sopenharmony_ci
385bf215546Sopenharmony_ci         cs->cond_dwords[i] = cs->cur;
386bf215546Sopenharmony_ci
387bf215546Sopenharmony_ci         /* Emit dummy DWORD field here */
388bf215546Sopenharmony_ci         tu_cs_emit(cs, CP_COND_REG_EXEC_1_DWORDS(0));
389bf215546Sopenharmony_ci      }
390bf215546Sopenharmony_ci
391bf215546Sopenharmony_ci      /* double the size for the next bo, also there is an upper
392bf215546Sopenharmony_ci       * bound on IB size, which appears to be 0x0fffff
393bf215546Sopenharmony_ci       */
394bf215546Sopenharmony_ci      new_size = MIN2(new_size << 1, 0x0fffff);
395bf215546Sopenharmony_ci      if (cs->next_bo_size < new_size)
396bf215546Sopenharmony_ci         cs->next_bo_size = new_size;
397bf215546Sopenharmony_ci   }
398bf215546Sopenharmony_ci
399bf215546Sopenharmony_ci   assert(tu_cs_get_space(cs) >= reserved_size);
400bf215546Sopenharmony_ci   cs->reserved_end = cs->cur + reserved_size;
401bf215546Sopenharmony_ci
402bf215546Sopenharmony_ci   if (cs->mode == TU_CS_MODE_GROW) {
403bf215546Sopenharmony_ci      /* reserve an entry for the next call to this function or tu_cs_end */
404bf215546Sopenharmony_ci      return tu_cs_reserve_entry(cs);
405bf215546Sopenharmony_ci   }
406bf215546Sopenharmony_ci
407bf215546Sopenharmony_ci   return VK_SUCCESS;
408bf215546Sopenharmony_ci}
409bf215546Sopenharmony_ci
410bf215546Sopenharmony_ci/**
411bf215546Sopenharmony_ci * Reset a command stream to its initial state.  This discards all comand
412bf215546Sopenharmony_ci * packets in \a cs, but does not necessarily release all resources.
413bf215546Sopenharmony_ci */
414bf215546Sopenharmony_civoid
415bf215546Sopenharmony_citu_cs_reset(struct tu_cs *cs)
416bf215546Sopenharmony_ci{
417bf215546Sopenharmony_ci   if (cs->mode == TU_CS_MODE_EXTERNAL) {
418bf215546Sopenharmony_ci      assert(!cs->bo_count && !cs->refcount_bo && !cs->entry_count);
419bf215546Sopenharmony_ci      cs->reserved_end = cs->cur = cs->start;
420bf215546Sopenharmony_ci      return;
421bf215546Sopenharmony_ci   }
422bf215546Sopenharmony_ci
423bf215546Sopenharmony_ci   for (uint32_t i = 0; i + 1 < cs->bo_count; ++i) {
424bf215546Sopenharmony_ci      tu_bo_finish(cs->device, cs->bos[i]);
425bf215546Sopenharmony_ci   }
426bf215546Sopenharmony_ci
427bf215546Sopenharmony_ci   if (cs->bo_count) {
428bf215546Sopenharmony_ci      cs->bos[0] = cs->bos[cs->bo_count - 1];
429bf215546Sopenharmony_ci      cs->bo_count = 1;
430bf215546Sopenharmony_ci
431bf215546Sopenharmony_ci      cs->start = cs->cur = cs->reserved_end = (uint32_t *) cs->bos[0]->map;
432bf215546Sopenharmony_ci      cs->end = cs->start + cs->bos[0]->size / sizeof(uint32_t);
433bf215546Sopenharmony_ci   }
434bf215546Sopenharmony_ci
435bf215546Sopenharmony_ci   cs->entry_count = 0;
436bf215546Sopenharmony_ci}
437