1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright (C) 2016 Rob Clark <robclark@freedesktop.org>
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21bf215546Sopenharmony_ci * SOFTWARE.
22bf215546Sopenharmony_ci *
23bf215546Sopenharmony_ci * Authors:
24bf215546Sopenharmony_ci *    Rob Clark <robclark@freedesktop.org>
25bf215546Sopenharmony_ci */
26bf215546Sopenharmony_ci
27bf215546Sopenharmony_ci#include "util/hash_table.h"
28bf215546Sopenharmony_ci#include "util/list.h"
29bf215546Sopenharmony_ci#include "util/set.h"
30bf215546Sopenharmony_ci#include "util/u_string.h"
31bf215546Sopenharmony_ci
32bf215546Sopenharmony_ci#include "freedreno_batch.h"
33bf215546Sopenharmony_ci#include "freedreno_context.h"
34bf215546Sopenharmony_ci#include "freedreno_fence.h"
35bf215546Sopenharmony_ci#include "freedreno_query_hw.h"
36bf215546Sopenharmony_ci#include "freedreno_resource.h"
37bf215546Sopenharmony_ci
38bf215546Sopenharmony_cistatic struct fd_ringbuffer *
39bf215546Sopenharmony_cialloc_ring(struct fd_batch *batch, unsigned sz, enum fd_ringbuffer_flags flags)
40bf215546Sopenharmony_ci{
41bf215546Sopenharmony_ci   struct fd_context *ctx = batch->ctx;
42bf215546Sopenharmony_ci
43bf215546Sopenharmony_ci   /* if kernel is too old to support unlimited # of cmd buffers, we
44bf215546Sopenharmony_ci    * have no option but to allocate large worst-case sizes so that
45bf215546Sopenharmony_ci    * we don't need to grow the ringbuffer.  Performance is likely to
46bf215546Sopenharmony_ci    * suffer, but there is no good alternative.
47bf215546Sopenharmony_ci    *
48bf215546Sopenharmony_ci    * Otherwise if supported, allocate a growable ring with initial
49bf215546Sopenharmony_ci    * size of zero.
50bf215546Sopenharmony_ci    */
51bf215546Sopenharmony_ci   if ((fd_device_version(ctx->screen->dev) >= FD_VERSION_UNLIMITED_CMDS) &&
52bf215546Sopenharmony_ci       !FD_DBG(NOGROW)) {
53bf215546Sopenharmony_ci      flags |= FD_RINGBUFFER_GROWABLE;
54bf215546Sopenharmony_ci      sz = 0;
55bf215546Sopenharmony_ci   }
56bf215546Sopenharmony_ci
57bf215546Sopenharmony_ci   return fd_submit_new_ringbuffer(batch->submit, sz, flags);
58bf215546Sopenharmony_ci}
59bf215546Sopenharmony_ci
60bf215546Sopenharmony_cistatic void
61bf215546Sopenharmony_cibatch_init(struct fd_batch *batch)
62bf215546Sopenharmony_ci{
63bf215546Sopenharmony_ci   struct fd_context *ctx = batch->ctx;
64bf215546Sopenharmony_ci
65bf215546Sopenharmony_ci   batch->submit = fd_submit_new(ctx->pipe);
66bf215546Sopenharmony_ci   if (batch->nondraw) {
67bf215546Sopenharmony_ci      batch->gmem = alloc_ring(batch, 0x1000, FD_RINGBUFFER_PRIMARY);
68bf215546Sopenharmony_ci      batch->draw = alloc_ring(batch, 0x100000, 0);
69bf215546Sopenharmony_ci   } else {
70bf215546Sopenharmony_ci      batch->gmem = alloc_ring(batch, 0x100000, FD_RINGBUFFER_PRIMARY);
71bf215546Sopenharmony_ci      batch->draw = alloc_ring(batch, 0x100000, 0);
72bf215546Sopenharmony_ci
73bf215546Sopenharmony_ci      /* a6xx+ re-uses draw rb for both draw and binning pass: */
74bf215546Sopenharmony_ci      if (ctx->screen->gen < 6) {
75bf215546Sopenharmony_ci         batch->binning = alloc_ring(batch, 0x100000, 0);
76bf215546Sopenharmony_ci      }
77bf215546Sopenharmony_ci   }
78bf215546Sopenharmony_ci
79bf215546Sopenharmony_ci   batch->in_fence_fd = -1;
80bf215546Sopenharmony_ci   batch->fence = NULL;
81bf215546Sopenharmony_ci
82bf215546Sopenharmony_ci   /* Work around problems on earlier gens with submit merging, etc,
83bf215546Sopenharmony_ci    * by always creating a fence to request that the submit is flushed
84bf215546Sopenharmony_ci    * immediately:
85bf215546Sopenharmony_ci    */
86bf215546Sopenharmony_ci   if (ctx->screen->gen < 6)
87bf215546Sopenharmony_ci      batch->fence = fd_fence_create(batch);
88bf215546Sopenharmony_ci
89bf215546Sopenharmony_ci   batch->cleared = 0;
90bf215546Sopenharmony_ci   batch->fast_cleared = 0;
91bf215546Sopenharmony_ci   batch->invalidated = 0;
92bf215546Sopenharmony_ci   batch->restore = batch->resolve = 0;
93bf215546Sopenharmony_ci   batch->needs_flush = false;
94bf215546Sopenharmony_ci   batch->flushed = false;
95bf215546Sopenharmony_ci   batch->gmem_reason = 0;
96bf215546Sopenharmony_ci   batch->num_draws = 0;
97bf215546Sopenharmony_ci   batch->num_vertices = 0;
98bf215546Sopenharmony_ci   batch->num_bins_per_pipe = 0;
99bf215546Sopenharmony_ci   batch->prim_strm_bits = 0;
100bf215546Sopenharmony_ci   batch->draw_strm_bits = 0;
101bf215546Sopenharmony_ci
102bf215546Sopenharmony_ci   fd_reset_wfi(batch);
103bf215546Sopenharmony_ci
104bf215546Sopenharmony_ci   util_dynarray_init(&batch->draw_patches, NULL);
105bf215546Sopenharmony_ci   util_dynarray_init(&batch->fb_read_patches, NULL);
106bf215546Sopenharmony_ci
107bf215546Sopenharmony_ci   if (is_a2xx(ctx->screen)) {
108bf215546Sopenharmony_ci      util_dynarray_init(&batch->shader_patches, NULL);
109bf215546Sopenharmony_ci      util_dynarray_init(&batch->gmem_patches, NULL);
110bf215546Sopenharmony_ci   }
111bf215546Sopenharmony_ci
112bf215546Sopenharmony_ci   if (is_a3xx(ctx->screen))
113bf215546Sopenharmony_ci      util_dynarray_init(&batch->rbrc_patches, NULL);
114bf215546Sopenharmony_ci
115bf215546Sopenharmony_ci   assert(batch->resources->entries == 0);
116bf215546Sopenharmony_ci
117bf215546Sopenharmony_ci   util_dynarray_init(&batch->samples, NULL);
118bf215546Sopenharmony_ci
119bf215546Sopenharmony_ci   u_trace_init(&batch->trace, &ctx->trace_context);
120bf215546Sopenharmony_ci   batch->last_timestamp_cmd = NULL;
121bf215546Sopenharmony_ci}
122bf215546Sopenharmony_ci
123bf215546Sopenharmony_cistruct fd_batch *
124bf215546Sopenharmony_cifd_batch_create(struct fd_context *ctx, bool nondraw)
125bf215546Sopenharmony_ci{
126bf215546Sopenharmony_ci   struct fd_batch *batch = CALLOC_STRUCT(fd_batch);
127bf215546Sopenharmony_ci
128bf215546Sopenharmony_ci   if (!batch)
129bf215546Sopenharmony_ci      return NULL;
130bf215546Sopenharmony_ci
131bf215546Sopenharmony_ci   DBG("%p", batch);
132bf215546Sopenharmony_ci
133bf215546Sopenharmony_ci   pipe_reference_init(&batch->reference, 1);
134bf215546Sopenharmony_ci   batch->ctx = ctx;
135bf215546Sopenharmony_ci   batch->nondraw = nondraw;
136bf215546Sopenharmony_ci
137bf215546Sopenharmony_ci   simple_mtx_init(&batch->submit_lock, mtx_plain);
138bf215546Sopenharmony_ci
139bf215546Sopenharmony_ci   batch->resources =
140bf215546Sopenharmony_ci      _mesa_set_create(NULL, _mesa_hash_pointer, _mesa_key_pointer_equal);
141bf215546Sopenharmony_ci
142bf215546Sopenharmony_ci   batch_init(batch);
143bf215546Sopenharmony_ci
144bf215546Sopenharmony_ci   return batch;
145bf215546Sopenharmony_ci}
146bf215546Sopenharmony_ci
147bf215546Sopenharmony_cistatic void
148bf215546Sopenharmony_cicleanup_submit(struct fd_batch *batch)
149bf215546Sopenharmony_ci{
150bf215546Sopenharmony_ci   if (!batch->submit)
151bf215546Sopenharmony_ci      return;
152bf215546Sopenharmony_ci
153bf215546Sopenharmony_ci   fd_ringbuffer_del(batch->draw);
154bf215546Sopenharmony_ci   fd_ringbuffer_del(batch->gmem);
155bf215546Sopenharmony_ci
156bf215546Sopenharmony_ci   if (batch->binning) {
157bf215546Sopenharmony_ci      fd_ringbuffer_del(batch->binning);
158bf215546Sopenharmony_ci      batch->binning = NULL;
159bf215546Sopenharmony_ci   }
160bf215546Sopenharmony_ci
161bf215546Sopenharmony_ci   if (batch->prologue) {
162bf215546Sopenharmony_ci      fd_ringbuffer_del(batch->prologue);
163bf215546Sopenharmony_ci      batch->prologue = NULL;
164bf215546Sopenharmony_ci   }
165bf215546Sopenharmony_ci
166bf215546Sopenharmony_ci   if (batch->epilogue) {
167bf215546Sopenharmony_ci      fd_ringbuffer_del(batch->epilogue);
168bf215546Sopenharmony_ci      batch->epilogue = NULL;
169bf215546Sopenharmony_ci   }
170bf215546Sopenharmony_ci
171bf215546Sopenharmony_ci   if (batch->tile_setup) {
172bf215546Sopenharmony_ci      fd_ringbuffer_del(batch->tile_setup);
173bf215546Sopenharmony_ci      batch->tile_setup = NULL;
174bf215546Sopenharmony_ci   }
175bf215546Sopenharmony_ci
176bf215546Sopenharmony_ci   if (batch->tile_fini) {
177bf215546Sopenharmony_ci      fd_ringbuffer_del(batch->tile_fini);
178bf215546Sopenharmony_ci      batch->tile_fini = NULL;
179bf215546Sopenharmony_ci   }
180bf215546Sopenharmony_ci
181bf215546Sopenharmony_ci   fd_submit_del(batch->submit);
182bf215546Sopenharmony_ci   batch->submit = NULL;
183bf215546Sopenharmony_ci}
184bf215546Sopenharmony_ci
185bf215546Sopenharmony_cistatic void
186bf215546Sopenharmony_cibatch_fini(struct fd_batch *batch)
187bf215546Sopenharmony_ci{
188bf215546Sopenharmony_ci   DBG("%p", batch);
189bf215546Sopenharmony_ci
190bf215546Sopenharmony_ci   pipe_resource_reference(&batch->query_buf, NULL);
191bf215546Sopenharmony_ci
192bf215546Sopenharmony_ci   if (batch->in_fence_fd != -1)
193bf215546Sopenharmony_ci      close(batch->in_fence_fd);
194bf215546Sopenharmony_ci
195bf215546Sopenharmony_ci   /* in case batch wasn't flushed but fence was created: */
196bf215546Sopenharmony_ci   if (batch->fence)
197bf215546Sopenharmony_ci      fd_fence_set_batch(batch->fence, NULL);
198bf215546Sopenharmony_ci
199bf215546Sopenharmony_ci   fd_fence_ref(&batch->fence, NULL);
200bf215546Sopenharmony_ci
201bf215546Sopenharmony_ci   cleanup_submit(batch);
202bf215546Sopenharmony_ci
203bf215546Sopenharmony_ci   util_dynarray_fini(&batch->draw_patches);
204bf215546Sopenharmony_ci   util_dynarray_fini(&batch->fb_read_patches);
205bf215546Sopenharmony_ci
206bf215546Sopenharmony_ci   if (is_a2xx(batch->ctx->screen)) {
207bf215546Sopenharmony_ci      util_dynarray_fini(&batch->shader_patches);
208bf215546Sopenharmony_ci      util_dynarray_fini(&batch->gmem_patches);
209bf215546Sopenharmony_ci   }
210bf215546Sopenharmony_ci
211bf215546Sopenharmony_ci   if (is_a3xx(batch->ctx->screen))
212bf215546Sopenharmony_ci      util_dynarray_fini(&batch->rbrc_patches);
213bf215546Sopenharmony_ci
214bf215546Sopenharmony_ci   while (batch->samples.size > 0) {
215bf215546Sopenharmony_ci      struct fd_hw_sample *samp =
216bf215546Sopenharmony_ci         util_dynarray_pop(&batch->samples, struct fd_hw_sample *);
217bf215546Sopenharmony_ci      fd_hw_sample_reference(batch->ctx, &samp, NULL);
218bf215546Sopenharmony_ci   }
219bf215546Sopenharmony_ci   util_dynarray_fini(&batch->samples);
220bf215546Sopenharmony_ci
221bf215546Sopenharmony_ci   u_trace_fini(&batch->trace);
222bf215546Sopenharmony_ci}
223bf215546Sopenharmony_ci
224bf215546Sopenharmony_cistatic void
225bf215546Sopenharmony_cibatch_flush_dependencies(struct fd_batch *batch) assert_dt
226bf215546Sopenharmony_ci{
227bf215546Sopenharmony_ci   struct fd_batch_cache *cache = &batch->ctx->screen->batch_cache;
228bf215546Sopenharmony_ci   struct fd_batch *dep;
229bf215546Sopenharmony_ci
230bf215546Sopenharmony_ci   foreach_batch (dep, cache, batch->dependents_mask) {
231bf215546Sopenharmony_ci      fd_batch_flush(dep);
232bf215546Sopenharmony_ci      fd_batch_reference(&dep, NULL);
233bf215546Sopenharmony_ci   }
234bf215546Sopenharmony_ci
235bf215546Sopenharmony_ci   batch->dependents_mask = 0;
236bf215546Sopenharmony_ci}
237bf215546Sopenharmony_ci
238bf215546Sopenharmony_cistatic void
239bf215546Sopenharmony_cibatch_reset_dependencies(struct fd_batch *batch)
240bf215546Sopenharmony_ci{
241bf215546Sopenharmony_ci   struct fd_batch_cache *cache = &batch->ctx->screen->batch_cache;
242bf215546Sopenharmony_ci   struct fd_batch *dep;
243bf215546Sopenharmony_ci
244bf215546Sopenharmony_ci   foreach_batch (dep, cache, batch->dependents_mask) {
245bf215546Sopenharmony_ci      fd_batch_reference(&dep, NULL);
246bf215546Sopenharmony_ci   }
247bf215546Sopenharmony_ci
248bf215546Sopenharmony_ci   batch->dependents_mask = 0;
249bf215546Sopenharmony_ci}
250bf215546Sopenharmony_ci
251bf215546Sopenharmony_cistatic void
252bf215546Sopenharmony_cibatch_reset_resources(struct fd_batch *batch)
253bf215546Sopenharmony_ci{
254bf215546Sopenharmony_ci   fd_screen_assert_locked(batch->ctx->screen);
255bf215546Sopenharmony_ci
256bf215546Sopenharmony_ci   set_foreach (batch->resources, entry) {
257bf215546Sopenharmony_ci      struct fd_resource *rsc = (struct fd_resource *)entry->key;
258bf215546Sopenharmony_ci      _mesa_set_remove(batch->resources, entry);
259bf215546Sopenharmony_ci      assert(rsc->track->batch_mask & (1 << batch->idx));
260bf215546Sopenharmony_ci      rsc->track->batch_mask &= ~(1 << batch->idx);
261bf215546Sopenharmony_ci      if (rsc->track->write_batch == batch)
262bf215546Sopenharmony_ci         fd_batch_reference_locked(&rsc->track->write_batch, NULL);
263bf215546Sopenharmony_ci   }
264bf215546Sopenharmony_ci}
265bf215546Sopenharmony_ci
266bf215546Sopenharmony_cistatic void
267bf215546Sopenharmony_cibatch_reset(struct fd_batch *batch) assert_dt
268bf215546Sopenharmony_ci{
269bf215546Sopenharmony_ci   DBG("%p", batch);
270bf215546Sopenharmony_ci
271bf215546Sopenharmony_ci   batch_reset_dependencies(batch);
272bf215546Sopenharmony_ci
273bf215546Sopenharmony_ci   fd_screen_lock(batch->ctx->screen);
274bf215546Sopenharmony_ci   batch_reset_resources(batch);
275bf215546Sopenharmony_ci   fd_screen_unlock(batch->ctx->screen);
276bf215546Sopenharmony_ci
277bf215546Sopenharmony_ci   batch_fini(batch);
278bf215546Sopenharmony_ci   batch_init(batch);
279bf215546Sopenharmony_ci}
280bf215546Sopenharmony_ci
281bf215546Sopenharmony_civoid
282bf215546Sopenharmony_cifd_batch_reset(struct fd_batch *batch)
283bf215546Sopenharmony_ci{
284bf215546Sopenharmony_ci   if (batch->needs_flush)
285bf215546Sopenharmony_ci      batch_reset(batch);
286bf215546Sopenharmony_ci}
287bf215546Sopenharmony_ci
288bf215546Sopenharmony_civoid
289bf215546Sopenharmony_ci__fd_batch_destroy(struct fd_batch *batch)
290bf215546Sopenharmony_ci{
291bf215546Sopenharmony_ci   struct fd_context *ctx = batch->ctx;
292bf215546Sopenharmony_ci
293bf215546Sopenharmony_ci   DBG("%p", batch);
294bf215546Sopenharmony_ci
295bf215546Sopenharmony_ci   fd_screen_assert_locked(batch->ctx->screen);
296bf215546Sopenharmony_ci
297bf215546Sopenharmony_ci   fd_bc_invalidate_batch(batch, true);
298bf215546Sopenharmony_ci
299bf215546Sopenharmony_ci   batch_reset_resources(batch);
300bf215546Sopenharmony_ci   assert(batch->resources->entries == 0);
301bf215546Sopenharmony_ci   _mesa_set_destroy(batch->resources, NULL);
302bf215546Sopenharmony_ci
303bf215546Sopenharmony_ci   fd_screen_unlock(ctx->screen);
304bf215546Sopenharmony_ci   batch_reset_dependencies(batch);
305bf215546Sopenharmony_ci   assert(batch->dependents_mask == 0);
306bf215546Sopenharmony_ci
307bf215546Sopenharmony_ci   util_copy_framebuffer_state(&batch->framebuffer, NULL);
308bf215546Sopenharmony_ci   batch_fini(batch);
309bf215546Sopenharmony_ci
310bf215546Sopenharmony_ci   simple_mtx_destroy(&batch->submit_lock);
311bf215546Sopenharmony_ci
312bf215546Sopenharmony_ci   free(batch->key);
313bf215546Sopenharmony_ci   free(batch);
314bf215546Sopenharmony_ci   fd_screen_lock(ctx->screen);
315bf215546Sopenharmony_ci}
316bf215546Sopenharmony_ci
317bf215546Sopenharmony_civoid
318bf215546Sopenharmony_ci__fd_batch_describe(char *buf, const struct fd_batch *batch)
319bf215546Sopenharmony_ci{
320bf215546Sopenharmony_ci   sprintf(buf, "fd_batch<%u>", batch->seqno);
321bf215546Sopenharmony_ci}
322bf215546Sopenharmony_ci
323bf215546Sopenharmony_ci/* Get per-batch prologue */
324bf215546Sopenharmony_cistruct fd_ringbuffer *
325bf215546Sopenharmony_cifd_batch_get_prologue(struct fd_batch *batch)
326bf215546Sopenharmony_ci{
327bf215546Sopenharmony_ci   if (!batch->prologue)
328bf215546Sopenharmony_ci      batch->prologue = alloc_ring(batch, 0x1000, 0);
329bf215546Sopenharmony_ci   return batch->prologue;
330bf215546Sopenharmony_ci}
331bf215546Sopenharmony_ci
332bf215546Sopenharmony_ci/* Only called from fd_batch_flush() */
333bf215546Sopenharmony_cistatic void
334bf215546Sopenharmony_cibatch_flush(struct fd_batch *batch) assert_dt
335bf215546Sopenharmony_ci{
336bf215546Sopenharmony_ci   DBG("%p: needs_flush=%d", batch, batch->needs_flush);
337bf215546Sopenharmony_ci
338bf215546Sopenharmony_ci   if (!fd_batch_lock_submit(batch))
339bf215546Sopenharmony_ci      return;
340bf215546Sopenharmony_ci
341bf215546Sopenharmony_ci   batch->needs_flush = false;
342bf215546Sopenharmony_ci
343bf215546Sopenharmony_ci   /* close out the draw cmds by making sure any active queries are
344bf215546Sopenharmony_ci    * paused:
345bf215546Sopenharmony_ci    */
346bf215546Sopenharmony_ci   fd_batch_finish_queries(batch);
347bf215546Sopenharmony_ci
348bf215546Sopenharmony_ci   batch_flush_dependencies(batch);
349bf215546Sopenharmony_ci
350bf215546Sopenharmony_ci   fd_screen_lock(batch->ctx->screen);
351bf215546Sopenharmony_ci   batch_reset_resources(batch);
352bf215546Sopenharmony_ci   /* NOTE: remove=false removes the batch from the hashtable, so future
353bf215546Sopenharmony_ci    * lookups won't cache-hit a flushed batch, but leaves the weak reference
354bf215546Sopenharmony_ci    * to the batch to avoid having multiple batches with same batch->idx, as
355bf215546Sopenharmony_ci    * that causes all sorts of hilarity.
356bf215546Sopenharmony_ci    */
357bf215546Sopenharmony_ci   fd_bc_invalidate_batch(batch, false);
358bf215546Sopenharmony_ci   batch->flushed = true;
359bf215546Sopenharmony_ci
360bf215546Sopenharmony_ci   if (batch == batch->ctx->batch)
361bf215546Sopenharmony_ci      fd_batch_reference_locked(&batch->ctx->batch, NULL);
362bf215546Sopenharmony_ci
363bf215546Sopenharmony_ci   fd_screen_unlock(batch->ctx->screen);
364bf215546Sopenharmony_ci
365bf215546Sopenharmony_ci   if (batch->fence)
366bf215546Sopenharmony_ci      fd_fence_ref(&batch->ctx->last_fence, batch->fence);
367bf215546Sopenharmony_ci
368bf215546Sopenharmony_ci   fd_gmem_render_tiles(batch);
369bf215546Sopenharmony_ci
370bf215546Sopenharmony_ci   assert(batch->reference.count > 0);
371bf215546Sopenharmony_ci
372bf215546Sopenharmony_ci   cleanup_submit(batch);
373bf215546Sopenharmony_ci   fd_batch_unlock_submit(batch);
374bf215546Sopenharmony_ci}
375bf215546Sopenharmony_ci
376bf215546Sopenharmony_ci/* NOTE: could drop the last ref to batch
377bf215546Sopenharmony_ci */
378bf215546Sopenharmony_civoid
379bf215546Sopenharmony_cifd_batch_flush(struct fd_batch *batch)
380bf215546Sopenharmony_ci{
381bf215546Sopenharmony_ci   struct fd_batch *tmp = NULL;
382bf215546Sopenharmony_ci
383bf215546Sopenharmony_ci   /* NOTE: we need to hold an extra ref across the body of flush,
384bf215546Sopenharmony_ci    * since the last ref to this batch could be dropped when cleaning
385bf215546Sopenharmony_ci    * up used_resources
386bf215546Sopenharmony_ci    */
387bf215546Sopenharmony_ci   fd_batch_reference(&tmp, batch);
388bf215546Sopenharmony_ci   batch_flush(tmp);
389bf215546Sopenharmony_ci   fd_batch_reference(&tmp, NULL);
390bf215546Sopenharmony_ci}
391bf215546Sopenharmony_ci
392bf215546Sopenharmony_ci/* find a batches dependents mask, including recursive dependencies: */
393bf215546Sopenharmony_cistatic uint32_t
394bf215546Sopenharmony_cirecursive_dependents_mask(struct fd_batch *batch)
395bf215546Sopenharmony_ci{
396bf215546Sopenharmony_ci   struct fd_batch_cache *cache = &batch->ctx->screen->batch_cache;
397bf215546Sopenharmony_ci   struct fd_batch *dep;
398bf215546Sopenharmony_ci   uint32_t dependents_mask = batch->dependents_mask;
399bf215546Sopenharmony_ci
400bf215546Sopenharmony_ci   foreach_batch (dep, cache, batch->dependents_mask)
401bf215546Sopenharmony_ci      dependents_mask |= recursive_dependents_mask(dep);
402bf215546Sopenharmony_ci
403bf215546Sopenharmony_ci   return dependents_mask;
404bf215546Sopenharmony_ci}
405bf215546Sopenharmony_ci
406bf215546Sopenharmony_civoid
407bf215546Sopenharmony_cifd_batch_add_dep(struct fd_batch *batch, struct fd_batch *dep)
408bf215546Sopenharmony_ci{
409bf215546Sopenharmony_ci   fd_screen_assert_locked(batch->ctx->screen);
410bf215546Sopenharmony_ci
411bf215546Sopenharmony_ci   if (batch->dependents_mask & (1 << dep->idx))
412bf215546Sopenharmony_ci      return;
413bf215546Sopenharmony_ci
414bf215546Sopenharmony_ci   /* a loop should not be possible */
415bf215546Sopenharmony_ci   assert(!((1 << batch->idx) & recursive_dependents_mask(dep)));
416bf215546Sopenharmony_ci
417bf215546Sopenharmony_ci   struct fd_batch *other = NULL;
418bf215546Sopenharmony_ci   fd_batch_reference_locked(&other, dep);
419bf215546Sopenharmony_ci   batch->dependents_mask |= (1 << dep->idx);
420bf215546Sopenharmony_ci   DBG("%p: added dependency on %p", batch, dep);
421bf215546Sopenharmony_ci}
422bf215546Sopenharmony_ci
423bf215546Sopenharmony_cistatic void
424bf215546Sopenharmony_ciflush_write_batch(struct fd_resource *rsc) assert_dt
425bf215546Sopenharmony_ci{
426bf215546Sopenharmony_ci   struct fd_batch *b = NULL;
427bf215546Sopenharmony_ci   fd_batch_reference_locked(&b, rsc->track->write_batch);
428bf215546Sopenharmony_ci
429bf215546Sopenharmony_ci   fd_screen_unlock(b->ctx->screen);
430bf215546Sopenharmony_ci   fd_batch_flush(b);
431bf215546Sopenharmony_ci   fd_screen_lock(b->ctx->screen);
432bf215546Sopenharmony_ci
433bf215546Sopenharmony_ci   fd_batch_reference_locked(&b, NULL);
434bf215546Sopenharmony_ci}
435bf215546Sopenharmony_ci
436bf215546Sopenharmony_cistatic void
437bf215546Sopenharmony_cifd_batch_add_resource(struct fd_batch *batch, struct fd_resource *rsc)
438bf215546Sopenharmony_ci{
439bf215546Sopenharmony_ci
440bf215546Sopenharmony_ci   if (likely(fd_batch_references_resource(batch, rsc))) {
441bf215546Sopenharmony_ci      assert(_mesa_set_search_pre_hashed(batch->resources, rsc->hash, rsc));
442bf215546Sopenharmony_ci      return;
443bf215546Sopenharmony_ci   }
444bf215546Sopenharmony_ci
445bf215546Sopenharmony_ci   assert(!_mesa_set_search(batch->resources, rsc));
446bf215546Sopenharmony_ci
447bf215546Sopenharmony_ci   _mesa_set_add_pre_hashed(batch->resources, rsc->hash, rsc);
448bf215546Sopenharmony_ci   rsc->track->batch_mask |= (1 << batch->idx);
449bf215546Sopenharmony_ci}
450bf215546Sopenharmony_ci
451bf215546Sopenharmony_civoid
452bf215546Sopenharmony_cifd_batch_resource_write(struct fd_batch *batch, struct fd_resource *rsc)
453bf215546Sopenharmony_ci{
454bf215546Sopenharmony_ci   fd_screen_assert_locked(batch->ctx->screen);
455bf215546Sopenharmony_ci
456bf215546Sopenharmony_ci   DBG("%p: write %p", batch, rsc);
457bf215546Sopenharmony_ci
458bf215546Sopenharmony_ci   /* Must do this before the early out, so we unset a previous resource
459bf215546Sopenharmony_ci    * invalidate (which may have left the write_batch state in place).
460bf215546Sopenharmony_ci    */
461bf215546Sopenharmony_ci   rsc->valid = true;
462bf215546Sopenharmony_ci
463bf215546Sopenharmony_ci   if (rsc->track->write_batch == batch)
464bf215546Sopenharmony_ci      return;
465bf215546Sopenharmony_ci
466bf215546Sopenharmony_ci   fd_batch_write_prep(batch, rsc);
467bf215546Sopenharmony_ci
468bf215546Sopenharmony_ci   if (rsc->stencil)
469bf215546Sopenharmony_ci      fd_batch_resource_write(batch, rsc->stencil);
470bf215546Sopenharmony_ci
471bf215546Sopenharmony_ci   /* note, invalidate write batch, to avoid further writes to rsc
472bf215546Sopenharmony_ci    * resulting in a write-after-read hazard.
473bf215546Sopenharmony_ci    */
474bf215546Sopenharmony_ci   /* if we are pending read or write by any other batch: */
475bf215546Sopenharmony_ci   if (unlikely(rsc->track->batch_mask & ~(1 << batch->idx))) {
476bf215546Sopenharmony_ci      struct fd_batch_cache *cache = &batch->ctx->screen->batch_cache;
477bf215546Sopenharmony_ci      struct fd_batch *dep;
478bf215546Sopenharmony_ci
479bf215546Sopenharmony_ci      if (rsc->track->write_batch)
480bf215546Sopenharmony_ci         flush_write_batch(rsc);
481bf215546Sopenharmony_ci
482bf215546Sopenharmony_ci      foreach_batch (dep, cache, rsc->track->batch_mask) {
483bf215546Sopenharmony_ci         struct fd_batch *b = NULL;
484bf215546Sopenharmony_ci         if (dep == batch)
485bf215546Sopenharmony_ci            continue;
486bf215546Sopenharmony_ci         /* note that batch_add_dep could flush and unref dep, so
487bf215546Sopenharmony_ci          * we need to hold a reference to keep it live for the
488bf215546Sopenharmony_ci          * fd_bc_invalidate_batch()
489bf215546Sopenharmony_ci          */
490bf215546Sopenharmony_ci         fd_batch_reference(&b, dep);
491bf215546Sopenharmony_ci         fd_batch_add_dep(batch, b);
492bf215546Sopenharmony_ci         fd_bc_invalidate_batch(b, false);
493bf215546Sopenharmony_ci         fd_batch_reference_locked(&b, NULL);
494bf215546Sopenharmony_ci      }
495bf215546Sopenharmony_ci   }
496bf215546Sopenharmony_ci   fd_batch_reference_locked(&rsc->track->write_batch, batch);
497bf215546Sopenharmony_ci
498bf215546Sopenharmony_ci   fd_batch_add_resource(batch, rsc);
499bf215546Sopenharmony_ci}
500bf215546Sopenharmony_ci
501bf215546Sopenharmony_civoid
502bf215546Sopenharmony_cifd_batch_resource_read_slowpath(struct fd_batch *batch, struct fd_resource *rsc)
503bf215546Sopenharmony_ci{
504bf215546Sopenharmony_ci   fd_screen_assert_locked(batch->ctx->screen);
505bf215546Sopenharmony_ci
506bf215546Sopenharmony_ci   if (rsc->stencil)
507bf215546Sopenharmony_ci      fd_batch_resource_read(batch, rsc->stencil);
508bf215546Sopenharmony_ci
509bf215546Sopenharmony_ci   DBG("%p: read %p", batch, rsc);
510bf215546Sopenharmony_ci
511bf215546Sopenharmony_ci   /* If reading a resource pending a write, go ahead and flush the
512bf215546Sopenharmony_ci    * writer.  This avoids situations where we end up having to
513bf215546Sopenharmony_ci    * flush the current batch in _resource_used()
514bf215546Sopenharmony_ci    */
515bf215546Sopenharmony_ci   if (unlikely(rsc->track->write_batch && rsc->track->write_batch != batch))
516bf215546Sopenharmony_ci      flush_write_batch(rsc);
517bf215546Sopenharmony_ci
518bf215546Sopenharmony_ci   fd_batch_add_resource(batch, rsc);
519bf215546Sopenharmony_ci}
520bf215546Sopenharmony_ci
521bf215546Sopenharmony_civoid
522bf215546Sopenharmony_cifd_batch_check_size(struct fd_batch *batch)
523bf215546Sopenharmony_ci{
524bf215546Sopenharmony_ci   if (FD_DBG(FLUSH)) {
525bf215546Sopenharmony_ci      fd_batch_flush(batch);
526bf215546Sopenharmony_ci      return;
527bf215546Sopenharmony_ci   }
528bf215546Sopenharmony_ci
529bf215546Sopenharmony_ci   /* Place a reasonable upper bound on prim/draw stream buffer size: */
530bf215546Sopenharmony_ci   const unsigned limit_bits = 8 * 8 * 1024 * 1024;
531bf215546Sopenharmony_ci   if ((batch->prim_strm_bits > limit_bits) ||
532bf215546Sopenharmony_ci       (batch->draw_strm_bits > limit_bits)) {
533bf215546Sopenharmony_ci      fd_batch_flush(batch);
534bf215546Sopenharmony_ci      return;
535bf215546Sopenharmony_ci   }
536bf215546Sopenharmony_ci
537bf215546Sopenharmony_ci   if (!fd_ringbuffer_check_size(batch->draw))
538bf215546Sopenharmony_ci      fd_batch_flush(batch);
539bf215546Sopenharmony_ci}
540bf215546Sopenharmony_ci
541bf215546Sopenharmony_ci/* emit a WAIT_FOR_IDLE only if needed, ie. if there has not already
542bf215546Sopenharmony_ci * been one since last draw:
543bf215546Sopenharmony_ci */
544bf215546Sopenharmony_civoid
545bf215546Sopenharmony_cifd_wfi(struct fd_batch *batch, struct fd_ringbuffer *ring)
546bf215546Sopenharmony_ci{
547bf215546Sopenharmony_ci   if (batch->needs_wfi) {
548bf215546Sopenharmony_ci      if (batch->ctx->screen->gen >= 5)
549bf215546Sopenharmony_ci         OUT_WFI5(ring);
550bf215546Sopenharmony_ci      else
551bf215546Sopenharmony_ci         OUT_WFI(ring);
552bf215546Sopenharmony_ci      batch->needs_wfi = false;
553bf215546Sopenharmony_ci   }
554bf215546Sopenharmony_ci}
555