1bf215546Sopenharmony_ci/**************************************************************************
2bf215546Sopenharmony_ci *
3bf215546Sopenharmony_ci * Copyright 2017 Advanced Micro Devices, Inc.
4bf215546Sopenharmony_ci * All Rights Reserved.
5bf215546Sopenharmony_ci *
6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
8bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
9bf215546Sopenharmony_ci * on the rights to use, copy, modify, merge, publish, distribute, sub
10bf215546Sopenharmony_ci * license, and/or sell copies of the Software, and to permit persons to whom
11bf215546Sopenharmony_ci * the Software is furnished to do so, subject to the following conditions:
12bf215546Sopenharmony_ci *
13bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
14bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
15bf215546Sopenharmony_ci * Software.
16bf215546Sopenharmony_ci *
17bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
20bf215546Sopenharmony_ci * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
21bf215546Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22bf215546Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
23bf215546Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE.
24bf215546Sopenharmony_ci *
25bf215546Sopenharmony_ci **************************************************************************/
26bf215546Sopenharmony_ci
27bf215546Sopenharmony_ci#include "util/u_threaded_context.h"
28bf215546Sopenharmony_ci#include "util/u_cpu_detect.h"
29bf215546Sopenharmony_ci#include "util/format/u_format.h"
30bf215546Sopenharmony_ci#include "util/u_inlines.h"
31bf215546Sopenharmony_ci#include "util/u_memory.h"
32bf215546Sopenharmony_ci#include "util/u_upload_mgr.h"
33bf215546Sopenharmony_ci#include "driver_trace/tr_context.h"
34bf215546Sopenharmony_ci#include "util/log.h"
35bf215546Sopenharmony_ci#include "compiler/shader_info.h"
36bf215546Sopenharmony_ci
37bf215546Sopenharmony_ci#if TC_DEBUG >= 1
38bf215546Sopenharmony_ci#define tc_assert assert
39bf215546Sopenharmony_ci#else
40bf215546Sopenharmony_ci#define tc_assert(x)
41bf215546Sopenharmony_ci#endif
42bf215546Sopenharmony_ci
43bf215546Sopenharmony_ci#if TC_DEBUG >= 2
44bf215546Sopenharmony_ci#define tc_printf mesa_logi
45bf215546Sopenharmony_ci#define tc_asprintf asprintf
46bf215546Sopenharmony_ci#define tc_strcmp strcmp
47bf215546Sopenharmony_ci#else
48bf215546Sopenharmony_ci#define tc_printf(...)
49bf215546Sopenharmony_ci#define tc_asprintf(...) 0
50bf215546Sopenharmony_ci#define tc_strcmp(...) 0
51bf215546Sopenharmony_ci#endif
52bf215546Sopenharmony_ci
53bf215546Sopenharmony_ci#define TC_SENTINEL 0x5ca1ab1e
54bf215546Sopenharmony_ci
55bf215546Sopenharmony_cienum tc_call_id {
56bf215546Sopenharmony_ci#define CALL(name) TC_CALL_##name,
57bf215546Sopenharmony_ci#include "u_threaded_context_calls.h"
58bf215546Sopenharmony_ci#undef CALL
59bf215546Sopenharmony_ci   TC_NUM_CALLS,
60bf215546Sopenharmony_ci};
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_ci#if TC_DEBUG >= 3
63bf215546Sopenharmony_cistatic const char *tc_call_names[] = {
64bf215546Sopenharmony_ci#define CALL(name) #name,
65bf215546Sopenharmony_ci#include "u_threaded_context_calls.h"
66bf215546Sopenharmony_ci#undef CALL
67bf215546Sopenharmony_ci};
68bf215546Sopenharmony_ci#endif
69bf215546Sopenharmony_ci
70bf215546Sopenharmony_citypedef uint16_t (*tc_execute)(struct pipe_context *pipe, void *call, uint64_t *last);
71bf215546Sopenharmony_ci
72bf215546Sopenharmony_cistatic const tc_execute execute_func[TC_NUM_CALLS];
73bf215546Sopenharmony_ci
74bf215546Sopenharmony_cistatic void
75bf215546Sopenharmony_citc_buffer_subdata(struct pipe_context *_pipe,
76bf215546Sopenharmony_ci                  struct pipe_resource *resource,
77bf215546Sopenharmony_ci                  unsigned usage, unsigned offset,
78bf215546Sopenharmony_ci                  unsigned size, const void *data);
79bf215546Sopenharmony_ci
80bf215546Sopenharmony_cistatic void
81bf215546Sopenharmony_citc_batch_check(UNUSED struct tc_batch *batch)
82bf215546Sopenharmony_ci{
83bf215546Sopenharmony_ci   tc_assert(batch->sentinel == TC_SENTINEL);
84bf215546Sopenharmony_ci   tc_assert(batch->num_total_slots <= TC_SLOTS_PER_BATCH);
85bf215546Sopenharmony_ci}
86bf215546Sopenharmony_ci
87bf215546Sopenharmony_cistatic void
88bf215546Sopenharmony_citc_debug_check(struct threaded_context *tc)
89bf215546Sopenharmony_ci{
90bf215546Sopenharmony_ci   for (unsigned i = 0; i < TC_MAX_BATCHES; i++) {
91bf215546Sopenharmony_ci      tc_batch_check(&tc->batch_slots[i]);
92bf215546Sopenharmony_ci      tc_assert(tc->batch_slots[i].tc == tc);
93bf215546Sopenharmony_ci   }
94bf215546Sopenharmony_ci}
95bf215546Sopenharmony_ci
96bf215546Sopenharmony_cistatic void
97bf215546Sopenharmony_citc_set_driver_thread(struct threaded_context *tc)
98bf215546Sopenharmony_ci{
99bf215546Sopenharmony_ci#ifndef NDEBUG
100bf215546Sopenharmony_ci   tc->driver_thread = util_get_thread_id();
101bf215546Sopenharmony_ci#endif
102bf215546Sopenharmony_ci}
103bf215546Sopenharmony_ci
104bf215546Sopenharmony_cistatic void
105bf215546Sopenharmony_citc_clear_driver_thread(struct threaded_context *tc)
106bf215546Sopenharmony_ci{
107bf215546Sopenharmony_ci#ifndef NDEBUG
108bf215546Sopenharmony_ci   memset(&tc->driver_thread, 0, sizeof(tc->driver_thread));
109bf215546Sopenharmony_ci#endif
110bf215546Sopenharmony_ci}
111bf215546Sopenharmony_ci
112bf215546Sopenharmony_cistatic void *
113bf215546Sopenharmony_cito_call_check(void *ptr, unsigned num_slots)
114bf215546Sopenharmony_ci{
115bf215546Sopenharmony_ci#if TC_DEBUG >= 1
116bf215546Sopenharmony_ci   struct tc_call_base *call = ptr;
117bf215546Sopenharmony_ci   tc_assert(call->num_slots == num_slots);
118bf215546Sopenharmony_ci#endif
119bf215546Sopenharmony_ci   return ptr;
120bf215546Sopenharmony_ci}
121bf215546Sopenharmony_ci#define to_call(ptr, type) ((struct type *)to_call_check((void *)(ptr), call_size(type)))
122bf215546Sopenharmony_ci
123bf215546Sopenharmony_ci#define size_to_slots(size)      DIV_ROUND_UP(size, 8)
124bf215546Sopenharmony_ci#define call_size(type)          size_to_slots(sizeof(struct type))
125bf215546Sopenharmony_ci#define call_size_with_slots(type, num_slots) size_to_slots( \
126bf215546Sopenharmony_ci   sizeof(struct type) + sizeof(((struct type*)NULL)->slot[0]) * (num_slots))
127bf215546Sopenharmony_ci#define get_next_call(ptr, type) ((struct type*)((uint64_t*)ptr + call_size(type)))
128bf215546Sopenharmony_ci
129bf215546Sopenharmony_ci/* Assign src to dst while dst is uninitialized. */
130bf215546Sopenharmony_cistatic inline void
131bf215546Sopenharmony_citc_set_resource_reference(struct pipe_resource **dst, struct pipe_resource *src)
132bf215546Sopenharmony_ci{
133bf215546Sopenharmony_ci   *dst = src;
134bf215546Sopenharmony_ci   pipe_reference(NULL, &src->reference); /* only increment refcount */
135bf215546Sopenharmony_ci}
136bf215546Sopenharmony_ci
137bf215546Sopenharmony_ci/* Assign src to dst while dst is uninitialized. */
138bf215546Sopenharmony_cistatic inline void
139bf215546Sopenharmony_citc_set_vertex_state_reference(struct pipe_vertex_state **dst,
140bf215546Sopenharmony_ci                              struct pipe_vertex_state *src)
141bf215546Sopenharmony_ci{
142bf215546Sopenharmony_ci   *dst = src;
143bf215546Sopenharmony_ci   pipe_reference(NULL, &src->reference); /* only increment refcount */
144bf215546Sopenharmony_ci}
145bf215546Sopenharmony_ci
146bf215546Sopenharmony_ci/* Unreference dst but don't touch the dst pointer. */
147bf215546Sopenharmony_cistatic inline void
148bf215546Sopenharmony_citc_drop_resource_reference(struct pipe_resource *dst)
149bf215546Sopenharmony_ci{
150bf215546Sopenharmony_ci   if (pipe_reference(&dst->reference, NULL)) /* only decrement refcount */
151bf215546Sopenharmony_ci      pipe_resource_destroy(dst);
152bf215546Sopenharmony_ci}
153bf215546Sopenharmony_ci
154bf215546Sopenharmony_ci/* Unreference dst but don't touch the dst pointer. */
155bf215546Sopenharmony_cistatic inline void
156bf215546Sopenharmony_citc_drop_surface_reference(struct pipe_surface *dst)
157bf215546Sopenharmony_ci{
158bf215546Sopenharmony_ci   if (pipe_reference(&dst->reference, NULL)) /* only decrement refcount */
159bf215546Sopenharmony_ci      dst->context->surface_destroy(dst->context, dst);
160bf215546Sopenharmony_ci}
161bf215546Sopenharmony_ci
162bf215546Sopenharmony_ci/* Unreference dst but don't touch the dst pointer. */
163bf215546Sopenharmony_cistatic inline void
164bf215546Sopenharmony_citc_drop_so_target_reference(struct pipe_stream_output_target *dst)
165bf215546Sopenharmony_ci{
166bf215546Sopenharmony_ci   if (pipe_reference(&dst->reference, NULL)) /* only decrement refcount */
167bf215546Sopenharmony_ci      dst->context->stream_output_target_destroy(dst->context, dst);
168bf215546Sopenharmony_ci}
169bf215546Sopenharmony_ci
170bf215546Sopenharmony_ci/**
171bf215546Sopenharmony_ci * Subtract the given number of references.
172bf215546Sopenharmony_ci */
173bf215546Sopenharmony_cistatic inline void
174bf215546Sopenharmony_citc_drop_vertex_state_references(struct pipe_vertex_state *dst, int num_refs)
175bf215546Sopenharmony_ci{
176bf215546Sopenharmony_ci   int count = p_atomic_add_return(&dst->reference.count, -num_refs);
177bf215546Sopenharmony_ci
178bf215546Sopenharmony_ci   assert(count >= 0);
179bf215546Sopenharmony_ci   /* Underflows shouldn't happen, but let's be safe. */
180bf215546Sopenharmony_ci   if (count <= 0)
181bf215546Sopenharmony_ci      dst->screen->vertex_state_destroy(dst->screen, dst);
182bf215546Sopenharmony_ci}
183bf215546Sopenharmony_ci
184bf215546Sopenharmony_ci/* We don't want to read or write min_index and max_index, because
185bf215546Sopenharmony_ci * it shouldn't be needed by drivers at this point.
186bf215546Sopenharmony_ci */
187bf215546Sopenharmony_ci#define DRAW_INFO_SIZE_WITHOUT_MIN_MAX_INDEX \
188bf215546Sopenharmony_ci   offsetof(struct pipe_draw_info, min_index)
189bf215546Sopenharmony_ci
190bf215546Sopenharmony_cistatic void
191bf215546Sopenharmony_citc_batch_execute(void *job, UNUSED void *gdata, int thread_index)
192bf215546Sopenharmony_ci{
193bf215546Sopenharmony_ci   struct tc_batch *batch = job;
194bf215546Sopenharmony_ci   struct pipe_context *pipe = batch->tc->pipe;
195bf215546Sopenharmony_ci   uint64_t *last = &batch->slots[batch->num_total_slots];
196bf215546Sopenharmony_ci
197bf215546Sopenharmony_ci   tc_batch_check(batch);
198bf215546Sopenharmony_ci   tc_set_driver_thread(batch->tc);
199bf215546Sopenharmony_ci
200bf215546Sopenharmony_ci   assert(!batch->token);
201bf215546Sopenharmony_ci
202bf215546Sopenharmony_ci   for (uint64_t *iter = batch->slots; iter != last;) {
203bf215546Sopenharmony_ci      struct tc_call_base *call = (struct tc_call_base *)iter;
204bf215546Sopenharmony_ci
205bf215546Sopenharmony_ci      tc_assert(call->sentinel == TC_SENTINEL);
206bf215546Sopenharmony_ci
207bf215546Sopenharmony_ci#if TC_DEBUG >= 3
208bf215546Sopenharmony_ci      tc_printf("CALL: %s", tc_call_names[call->call_id]);
209bf215546Sopenharmony_ci#endif
210bf215546Sopenharmony_ci
211bf215546Sopenharmony_ci      iter += execute_func[call->call_id](pipe, call, last);
212bf215546Sopenharmony_ci   }
213bf215546Sopenharmony_ci
214bf215546Sopenharmony_ci   /* Add the fence to the list of fences for the driver to signal at the next
215bf215546Sopenharmony_ci    * flush, which we use for tracking which buffers are referenced by
216bf215546Sopenharmony_ci    * an unflushed command buffer.
217bf215546Sopenharmony_ci    */
218bf215546Sopenharmony_ci   struct threaded_context *tc = batch->tc;
219bf215546Sopenharmony_ci   struct util_queue_fence *fence =
220bf215546Sopenharmony_ci      &tc->buffer_lists[batch->buffer_list_index].driver_flushed_fence;
221bf215546Sopenharmony_ci
222bf215546Sopenharmony_ci   if (tc->options.driver_calls_flush_notify) {
223bf215546Sopenharmony_ci      tc->signal_fences_next_flush[tc->num_signal_fences_next_flush++] = fence;
224bf215546Sopenharmony_ci
225bf215546Sopenharmony_ci      /* Since our buffer lists are chained as a ring, we need to flush
226bf215546Sopenharmony_ci       * the context twice as we go around the ring to make the driver signal
227bf215546Sopenharmony_ci       * the buffer list fences, so that the producer thread can reuse the buffer
228bf215546Sopenharmony_ci       * list structures for the next batches without waiting.
229bf215546Sopenharmony_ci       */
230bf215546Sopenharmony_ci      unsigned half_ring = TC_MAX_BUFFER_LISTS / 2;
231bf215546Sopenharmony_ci      if (batch->buffer_list_index % half_ring == half_ring - 1)
232bf215546Sopenharmony_ci         pipe->flush(pipe, NULL, PIPE_FLUSH_ASYNC);
233bf215546Sopenharmony_ci   } else {
234bf215546Sopenharmony_ci      util_queue_fence_signal(fence);
235bf215546Sopenharmony_ci   }
236bf215546Sopenharmony_ci
237bf215546Sopenharmony_ci   tc_clear_driver_thread(batch->tc);
238bf215546Sopenharmony_ci   tc_batch_check(batch);
239bf215546Sopenharmony_ci   batch->num_total_slots = 0;
240bf215546Sopenharmony_ci}
241bf215546Sopenharmony_ci
242bf215546Sopenharmony_cistatic void
243bf215546Sopenharmony_citc_begin_next_buffer_list(struct threaded_context *tc)
244bf215546Sopenharmony_ci{
245bf215546Sopenharmony_ci   tc->next_buf_list = (tc->next_buf_list + 1) % TC_MAX_BUFFER_LISTS;
246bf215546Sopenharmony_ci
247bf215546Sopenharmony_ci   tc->batch_slots[tc->next].buffer_list_index = tc->next_buf_list;
248bf215546Sopenharmony_ci
249bf215546Sopenharmony_ci   /* Clear the buffer list in the new empty batch. */
250bf215546Sopenharmony_ci   struct tc_buffer_list *buf_list = &tc->buffer_lists[tc->next_buf_list];
251bf215546Sopenharmony_ci   assert(util_queue_fence_is_signalled(&buf_list->driver_flushed_fence));
252bf215546Sopenharmony_ci   util_queue_fence_reset(&buf_list->driver_flushed_fence); /* set to unsignalled */
253bf215546Sopenharmony_ci   BITSET_ZERO(buf_list->buffer_list);
254bf215546Sopenharmony_ci
255bf215546Sopenharmony_ci   tc->add_all_gfx_bindings_to_buffer_list = true;
256bf215546Sopenharmony_ci   tc->add_all_compute_bindings_to_buffer_list = true;
257bf215546Sopenharmony_ci}
258bf215546Sopenharmony_ci
259bf215546Sopenharmony_cistatic void
260bf215546Sopenharmony_citc_batch_flush(struct threaded_context *tc)
261bf215546Sopenharmony_ci{
262bf215546Sopenharmony_ci   struct tc_batch *next = &tc->batch_slots[tc->next];
263bf215546Sopenharmony_ci
264bf215546Sopenharmony_ci   tc_assert(next->num_total_slots != 0);
265bf215546Sopenharmony_ci   tc_batch_check(next);
266bf215546Sopenharmony_ci   tc_debug_check(tc);
267bf215546Sopenharmony_ci   tc->bytes_mapped_estimate = 0;
268bf215546Sopenharmony_ci   p_atomic_add(&tc->num_offloaded_slots, next->num_total_slots);
269bf215546Sopenharmony_ci
270bf215546Sopenharmony_ci   if (next->token) {
271bf215546Sopenharmony_ci      next->token->tc = NULL;
272bf215546Sopenharmony_ci      tc_unflushed_batch_token_reference(&next->token, NULL);
273bf215546Sopenharmony_ci   }
274bf215546Sopenharmony_ci
275bf215546Sopenharmony_ci   util_queue_add_job(&tc->queue, next, &next->fence, tc_batch_execute,
276bf215546Sopenharmony_ci                      NULL, 0);
277bf215546Sopenharmony_ci   tc->last = tc->next;
278bf215546Sopenharmony_ci   tc->next = (tc->next + 1) % TC_MAX_BATCHES;
279bf215546Sopenharmony_ci   tc_begin_next_buffer_list(tc);
280bf215546Sopenharmony_ci}
281bf215546Sopenharmony_ci
282bf215546Sopenharmony_ci/* This is the function that adds variable-sized calls into the current
283bf215546Sopenharmony_ci * batch. It also flushes the batch if there is not enough space there.
284bf215546Sopenharmony_ci * All other higher-level "add" functions use it.
285bf215546Sopenharmony_ci */
286bf215546Sopenharmony_cistatic void *
287bf215546Sopenharmony_citc_add_sized_call(struct threaded_context *tc, enum tc_call_id id,
288bf215546Sopenharmony_ci                  unsigned num_slots)
289bf215546Sopenharmony_ci{
290bf215546Sopenharmony_ci   struct tc_batch *next = &tc->batch_slots[tc->next];
291bf215546Sopenharmony_ci   assert(num_slots <= TC_SLOTS_PER_BATCH);
292bf215546Sopenharmony_ci   tc_debug_check(tc);
293bf215546Sopenharmony_ci
294bf215546Sopenharmony_ci   if (unlikely(next->num_total_slots + num_slots > TC_SLOTS_PER_BATCH)) {
295bf215546Sopenharmony_ci      tc_batch_flush(tc);
296bf215546Sopenharmony_ci      next = &tc->batch_slots[tc->next];
297bf215546Sopenharmony_ci      tc_assert(next->num_total_slots == 0);
298bf215546Sopenharmony_ci   }
299bf215546Sopenharmony_ci
300bf215546Sopenharmony_ci   tc_assert(util_queue_fence_is_signalled(&next->fence));
301bf215546Sopenharmony_ci
302bf215546Sopenharmony_ci   struct tc_call_base *call = (struct tc_call_base*)&next->slots[next->num_total_slots];
303bf215546Sopenharmony_ci   next->num_total_slots += num_slots;
304bf215546Sopenharmony_ci
305bf215546Sopenharmony_ci#if !defined(NDEBUG) && TC_DEBUG >= 1
306bf215546Sopenharmony_ci   call->sentinel = TC_SENTINEL;
307bf215546Sopenharmony_ci#endif
308bf215546Sopenharmony_ci   call->call_id = id;
309bf215546Sopenharmony_ci   call->num_slots = num_slots;
310bf215546Sopenharmony_ci
311bf215546Sopenharmony_ci#if TC_DEBUG >= 3
312bf215546Sopenharmony_ci   tc_printf("ENQUEUE: %s", tc_call_names[id]);
313bf215546Sopenharmony_ci#endif
314bf215546Sopenharmony_ci
315bf215546Sopenharmony_ci   tc_debug_check(tc);
316bf215546Sopenharmony_ci   return call;
317bf215546Sopenharmony_ci}
318bf215546Sopenharmony_ci
319bf215546Sopenharmony_ci#define tc_add_call(tc, execute, type) \
320bf215546Sopenharmony_ci   ((struct type*)tc_add_sized_call(tc, execute, call_size(type)))
321bf215546Sopenharmony_ci
322bf215546Sopenharmony_ci#define tc_add_slot_based_call(tc, execute, type, num_slots) \
323bf215546Sopenharmony_ci   ((struct type*)tc_add_sized_call(tc, execute, \
324bf215546Sopenharmony_ci                                    call_size_with_slots(type, num_slots)))
325bf215546Sopenharmony_ci
326bf215546Sopenharmony_cistatic bool
327bf215546Sopenharmony_citc_is_sync(struct threaded_context *tc)
328bf215546Sopenharmony_ci{
329bf215546Sopenharmony_ci   struct tc_batch *last = &tc->batch_slots[tc->last];
330bf215546Sopenharmony_ci   struct tc_batch *next = &tc->batch_slots[tc->next];
331bf215546Sopenharmony_ci
332bf215546Sopenharmony_ci   return util_queue_fence_is_signalled(&last->fence) &&
333bf215546Sopenharmony_ci          !next->num_total_slots;
334bf215546Sopenharmony_ci}
335bf215546Sopenharmony_ci
336bf215546Sopenharmony_cistatic void
337bf215546Sopenharmony_ci_tc_sync(struct threaded_context *tc, UNUSED const char *info, UNUSED const char *func)
338bf215546Sopenharmony_ci{
339bf215546Sopenharmony_ci   struct tc_batch *last = &tc->batch_slots[tc->last];
340bf215546Sopenharmony_ci   struct tc_batch *next = &tc->batch_slots[tc->next];
341bf215546Sopenharmony_ci   bool synced = false;
342bf215546Sopenharmony_ci
343bf215546Sopenharmony_ci   tc_debug_check(tc);
344bf215546Sopenharmony_ci
345bf215546Sopenharmony_ci   /* Only wait for queued calls... */
346bf215546Sopenharmony_ci   if (!util_queue_fence_is_signalled(&last->fence)) {
347bf215546Sopenharmony_ci      util_queue_fence_wait(&last->fence);
348bf215546Sopenharmony_ci      synced = true;
349bf215546Sopenharmony_ci   }
350bf215546Sopenharmony_ci
351bf215546Sopenharmony_ci   tc_debug_check(tc);
352bf215546Sopenharmony_ci
353bf215546Sopenharmony_ci   if (next->token) {
354bf215546Sopenharmony_ci      next->token->tc = NULL;
355bf215546Sopenharmony_ci      tc_unflushed_batch_token_reference(&next->token, NULL);
356bf215546Sopenharmony_ci   }
357bf215546Sopenharmony_ci
358bf215546Sopenharmony_ci   /* .. and execute unflushed calls directly. */
359bf215546Sopenharmony_ci   if (next->num_total_slots) {
360bf215546Sopenharmony_ci      p_atomic_add(&tc->num_direct_slots, next->num_total_slots);
361bf215546Sopenharmony_ci      tc->bytes_mapped_estimate = 0;
362bf215546Sopenharmony_ci      tc_batch_execute(next, NULL, 0);
363bf215546Sopenharmony_ci      tc_begin_next_buffer_list(tc);
364bf215546Sopenharmony_ci      synced = true;
365bf215546Sopenharmony_ci   }
366bf215546Sopenharmony_ci
367bf215546Sopenharmony_ci   if (synced) {
368bf215546Sopenharmony_ci      p_atomic_inc(&tc->num_syncs);
369bf215546Sopenharmony_ci
370bf215546Sopenharmony_ci      if (tc_strcmp(func, "tc_destroy") != 0) {
371bf215546Sopenharmony_ci         tc_printf("sync %s %s", func, info);
372bf215546Sopenharmony_ci	  }
373bf215546Sopenharmony_ci   }
374bf215546Sopenharmony_ci
375bf215546Sopenharmony_ci   tc_debug_check(tc);
376bf215546Sopenharmony_ci}
377bf215546Sopenharmony_ci
378bf215546Sopenharmony_ci#define tc_sync(tc) _tc_sync(tc, "", __func__)
379bf215546Sopenharmony_ci#define tc_sync_msg(tc, info) _tc_sync(tc, info, __func__)
380bf215546Sopenharmony_ci
381bf215546Sopenharmony_ci/**
382bf215546Sopenharmony_ci * Call this from fence_finish for same-context fence waits of deferred fences
383bf215546Sopenharmony_ci * that haven't been flushed yet.
384bf215546Sopenharmony_ci *
385bf215546Sopenharmony_ci * The passed pipe_context must be the one passed to pipe_screen::fence_finish,
386bf215546Sopenharmony_ci * i.e., the wrapped one.
387bf215546Sopenharmony_ci */
388bf215546Sopenharmony_civoid
389bf215546Sopenharmony_cithreaded_context_flush(struct pipe_context *_pipe,
390bf215546Sopenharmony_ci                       struct tc_unflushed_batch_token *token,
391bf215546Sopenharmony_ci                       bool prefer_async)
392bf215546Sopenharmony_ci{
393bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
394bf215546Sopenharmony_ci
395bf215546Sopenharmony_ci   /* This is called from the gallium frontend / application thread. */
396bf215546Sopenharmony_ci   if (token->tc && token->tc == tc) {
397bf215546Sopenharmony_ci      struct tc_batch *last = &tc->batch_slots[tc->last];
398bf215546Sopenharmony_ci
399bf215546Sopenharmony_ci      /* Prefer to do the flush in the driver thread if it is already
400bf215546Sopenharmony_ci       * running. That should be better for cache locality.
401bf215546Sopenharmony_ci       */
402bf215546Sopenharmony_ci      if (prefer_async || !util_queue_fence_is_signalled(&last->fence))
403bf215546Sopenharmony_ci         tc_batch_flush(tc);
404bf215546Sopenharmony_ci      else
405bf215546Sopenharmony_ci         tc_sync(token->tc);
406bf215546Sopenharmony_ci   }
407bf215546Sopenharmony_ci}
408bf215546Sopenharmony_ci
409bf215546Sopenharmony_ci/* Must be called before TC binds, maps, invalidates, or adds a buffer to a buffer list. */
410bf215546Sopenharmony_cistatic void tc_touch_buffer(struct threaded_context *tc, struct threaded_resource *buf)
411bf215546Sopenharmony_ci{
412bf215546Sopenharmony_ci   const struct threaded_context *first_user = buf->first_user;
413bf215546Sopenharmony_ci
414bf215546Sopenharmony_ci   /* Fast path exit to avoid additional branches */
415bf215546Sopenharmony_ci   if (likely(first_user == tc))
416bf215546Sopenharmony_ci      return;
417bf215546Sopenharmony_ci
418bf215546Sopenharmony_ci   if (!first_user)
419bf215546Sopenharmony_ci      first_user = p_atomic_cmpxchg_ptr(&buf->first_user, NULL, tc);
420bf215546Sopenharmony_ci
421bf215546Sopenharmony_ci   /* The NULL check might seem unnecessary here but it's actually critical:
422bf215546Sopenharmony_ci    * p_atomic_cmpxchg will return NULL if it succeeds, meaning that NULL is
423bf215546Sopenharmony_ci    * equivalent to "we're the first user" here. (It's equally important not
424bf215546Sopenharmony_ci    * to ignore the result of the cmpxchg above, since it might fail.)
425bf215546Sopenharmony_ci    * Without the NULL check, we'd set the flag unconditionally, which is bad.
426bf215546Sopenharmony_ci    */
427bf215546Sopenharmony_ci   if (first_user && first_user != tc && !buf->used_by_multiple_contexts)
428bf215546Sopenharmony_ci      buf->used_by_multiple_contexts = true;
429bf215546Sopenharmony_ci}
430bf215546Sopenharmony_ci
431bf215546Sopenharmony_cistatic bool tc_is_buffer_shared(struct threaded_resource *buf)
432bf215546Sopenharmony_ci{
433bf215546Sopenharmony_ci   return buf->is_shared || buf->used_by_multiple_contexts;
434bf215546Sopenharmony_ci}
435bf215546Sopenharmony_ci
436bf215546Sopenharmony_cistatic void
437bf215546Sopenharmony_citc_add_to_buffer_list(struct threaded_context *tc, struct tc_buffer_list *next, struct pipe_resource *buf)
438bf215546Sopenharmony_ci{
439bf215546Sopenharmony_ci   struct threaded_resource *tbuf = threaded_resource(buf);
440bf215546Sopenharmony_ci   tc_touch_buffer(tc, tbuf);
441bf215546Sopenharmony_ci
442bf215546Sopenharmony_ci   uint32_t id = tbuf->buffer_id_unique;
443bf215546Sopenharmony_ci   BITSET_SET(next->buffer_list, id & TC_BUFFER_ID_MASK);
444bf215546Sopenharmony_ci}
445bf215546Sopenharmony_ci
446bf215546Sopenharmony_ci/* Set a buffer binding and add it to the buffer list. */
447bf215546Sopenharmony_cistatic void
448bf215546Sopenharmony_citc_bind_buffer(struct threaded_context *tc, uint32_t *binding, struct tc_buffer_list *next, struct pipe_resource *buf)
449bf215546Sopenharmony_ci{
450bf215546Sopenharmony_ci   struct threaded_resource *tbuf = threaded_resource(buf);
451bf215546Sopenharmony_ci   tc_touch_buffer(tc, tbuf);
452bf215546Sopenharmony_ci
453bf215546Sopenharmony_ci   uint32_t id = tbuf->buffer_id_unique;
454bf215546Sopenharmony_ci   *binding = id;
455bf215546Sopenharmony_ci   BITSET_SET(next->buffer_list, id & TC_BUFFER_ID_MASK);
456bf215546Sopenharmony_ci}
457bf215546Sopenharmony_ci
458bf215546Sopenharmony_ci/* Reset a buffer binding. */
459bf215546Sopenharmony_cistatic void
460bf215546Sopenharmony_citc_unbind_buffer(uint32_t *binding)
461bf215546Sopenharmony_ci{
462bf215546Sopenharmony_ci   *binding = 0;
463bf215546Sopenharmony_ci}
464bf215546Sopenharmony_ci
465bf215546Sopenharmony_ci/* Reset a range of buffer binding slots. */
466bf215546Sopenharmony_cistatic void
467bf215546Sopenharmony_citc_unbind_buffers(uint32_t *binding, unsigned count)
468bf215546Sopenharmony_ci{
469bf215546Sopenharmony_ci   if (count)
470bf215546Sopenharmony_ci      memset(binding, 0, sizeof(*binding) * count);
471bf215546Sopenharmony_ci}
472bf215546Sopenharmony_ci
473bf215546Sopenharmony_cistatic void
474bf215546Sopenharmony_citc_add_bindings_to_buffer_list(BITSET_WORD *buffer_list, const uint32_t *bindings,
475bf215546Sopenharmony_ci                               unsigned count)
476bf215546Sopenharmony_ci{
477bf215546Sopenharmony_ci   for (unsigned i = 0; i < count; i++) {
478bf215546Sopenharmony_ci      if (bindings[i])
479bf215546Sopenharmony_ci         BITSET_SET(buffer_list, bindings[i] & TC_BUFFER_ID_MASK);
480bf215546Sopenharmony_ci   }
481bf215546Sopenharmony_ci}
482bf215546Sopenharmony_ci
483bf215546Sopenharmony_cistatic bool
484bf215546Sopenharmony_citc_rebind_bindings(uint32_t old_id, uint32_t new_id, uint32_t *bindings,
485bf215546Sopenharmony_ci                   unsigned count)
486bf215546Sopenharmony_ci{
487bf215546Sopenharmony_ci   unsigned rebind_count = 0;
488bf215546Sopenharmony_ci
489bf215546Sopenharmony_ci   for (unsigned i = 0; i < count; i++) {
490bf215546Sopenharmony_ci      if (bindings[i] == old_id) {
491bf215546Sopenharmony_ci         bindings[i] = new_id;
492bf215546Sopenharmony_ci         rebind_count++;
493bf215546Sopenharmony_ci      }
494bf215546Sopenharmony_ci   }
495bf215546Sopenharmony_ci   return rebind_count;
496bf215546Sopenharmony_ci}
497bf215546Sopenharmony_ci
498bf215546Sopenharmony_cistatic void
499bf215546Sopenharmony_citc_add_shader_bindings_to_buffer_list(struct threaded_context *tc,
500bf215546Sopenharmony_ci                                      BITSET_WORD *buffer_list,
501bf215546Sopenharmony_ci                                      enum pipe_shader_type shader)
502bf215546Sopenharmony_ci{
503bf215546Sopenharmony_ci   tc_add_bindings_to_buffer_list(buffer_list, tc->const_buffers[shader],
504bf215546Sopenharmony_ci                                  tc->max_const_buffers);
505bf215546Sopenharmony_ci   if (tc->seen_shader_buffers[shader]) {
506bf215546Sopenharmony_ci      tc_add_bindings_to_buffer_list(buffer_list, tc->shader_buffers[shader],
507bf215546Sopenharmony_ci                                     tc->max_shader_buffers);
508bf215546Sopenharmony_ci   }
509bf215546Sopenharmony_ci   if (tc->seen_image_buffers[shader]) {
510bf215546Sopenharmony_ci      tc_add_bindings_to_buffer_list(buffer_list, tc->image_buffers[shader],
511bf215546Sopenharmony_ci                                     tc->max_images);
512bf215546Sopenharmony_ci   }
513bf215546Sopenharmony_ci   if (tc->seen_sampler_buffers[shader]) {
514bf215546Sopenharmony_ci      tc_add_bindings_to_buffer_list(buffer_list, tc->sampler_buffers[shader],
515bf215546Sopenharmony_ci                                     tc->max_samplers);
516bf215546Sopenharmony_ci   }
517bf215546Sopenharmony_ci}
518bf215546Sopenharmony_ci
519bf215546Sopenharmony_cistatic unsigned
520bf215546Sopenharmony_citc_rebind_shader_bindings(struct threaded_context *tc, uint32_t old_id,
521bf215546Sopenharmony_ci                          uint32_t new_id, enum pipe_shader_type shader, uint32_t *rebind_mask)
522bf215546Sopenharmony_ci{
523bf215546Sopenharmony_ci   unsigned ubo = 0, ssbo = 0, img = 0, sampler = 0;
524bf215546Sopenharmony_ci
525bf215546Sopenharmony_ci   ubo = tc_rebind_bindings(old_id, new_id, tc->const_buffers[shader],
526bf215546Sopenharmony_ci                            tc->max_const_buffers);
527bf215546Sopenharmony_ci   if (ubo)
528bf215546Sopenharmony_ci      *rebind_mask |= BITFIELD_BIT(TC_BINDING_UBO_VS) << shader;
529bf215546Sopenharmony_ci   if (tc->seen_shader_buffers[shader]) {
530bf215546Sopenharmony_ci      ssbo = tc_rebind_bindings(old_id, new_id, tc->shader_buffers[shader],
531bf215546Sopenharmony_ci                                tc->max_shader_buffers);
532bf215546Sopenharmony_ci      if (ssbo)
533bf215546Sopenharmony_ci         *rebind_mask |= BITFIELD_BIT(TC_BINDING_SSBO_VS) << shader;
534bf215546Sopenharmony_ci   }
535bf215546Sopenharmony_ci   if (tc->seen_image_buffers[shader]) {
536bf215546Sopenharmony_ci      img = tc_rebind_bindings(old_id, new_id, tc->image_buffers[shader],
537bf215546Sopenharmony_ci                               tc->max_images);
538bf215546Sopenharmony_ci      if (img)
539bf215546Sopenharmony_ci         *rebind_mask |= BITFIELD_BIT(TC_BINDING_IMAGE_VS) << shader;
540bf215546Sopenharmony_ci   }
541bf215546Sopenharmony_ci   if (tc->seen_sampler_buffers[shader]) {
542bf215546Sopenharmony_ci      sampler = tc_rebind_bindings(old_id, new_id, tc->sampler_buffers[shader],
543bf215546Sopenharmony_ci                                   tc->max_samplers);
544bf215546Sopenharmony_ci      if (sampler)
545bf215546Sopenharmony_ci         *rebind_mask |= BITFIELD_BIT(TC_BINDING_SAMPLERVIEW_VS) << shader;
546bf215546Sopenharmony_ci   }
547bf215546Sopenharmony_ci   return ubo + ssbo + img + sampler;
548bf215546Sopenharmony_ci}
549bf215546Sopenharmony_ci
550bf215546Sopenharmony_ci/* Add all bound buffers used by VS/TCS/TES/GS/FS to the buffer list.
551bf215546Sopenharmony_ci * This is called by the first draw call in a batch when we want to inherit
552bf215546Sopenharmony_ci * all bindings set by the previous batch.
553bf215546Sopenharmony_ci */
554bf215546Sopenharmony_cistatic void
555bf215546Sopenharmony_citc_add_all_gfx_bindings_to_buffer_list(struct threaded_context *tc)
556bf215546Sopenharmony_ci{
557bf215546Sopenharmony_ci   BITSET_WORD *buffer_list = tc->buffer_lists[tc->next_buf_list].buffer_list;
558bf215546Sopenharmony_ci
559bf215546Sopenharmony_ci   tc_add_bindings_to_buffer_list(buffer_list, tc->vertex_buffers, tc->max_vertex_buffers);
560bf215546Sopenharmony_ci   if (tc->seen_streamout_buffers)
561bf215546Sopenharmony_ci      tc_add_bindings_to_buffer_list(buffer_list, tc->streamout_buffers, PIPE_MAX_SO_BUFFERS);
562bf215546Sopenharmony_ci
563bf215546Sopenharmony_ci   tc_add_shader_bindings_to_buffer_list(tc, buffer_list, PIPE_SHADER_VERTEX);
564bf215546Sopenharmony_ci   tc_add_shader_bindings_to_buffer_list(tc, buffer_list, PIPE_SHADER_FRAGMENT);
565bf215546Sopenharmony_ci
566bf215546Sopenharmony_ci   if (tc->seen_tcs)
567bf215546Sopenharmony_ci      tc_add_shader_bindings_to_buffer_list(tc, buffer_list, PIPE_SHADER_TESS_CTRL);
568bf215546Sopenharmony_ci   if (tc->seen_tes)
569bf215546Sopenharmony_ci      tc_add_shader_bindings_to_buffer_list(tc, buffer_list, PIPE_SHADER_TESS_EVAL);
570bf215546Sopenharmony_ci   if (tc->seen_gs)
571bf215546Sopenharmony_ci      tc_add_shader_bindings_to_buffer_list(tc, buffer_list, PIPE_SHADER_GEOMETRY);
572bf215546Sopenharmony_ci
573bf215546Sopenharmony_ci   tc->add_all_gfx_bindings_to_buffer_list = false;
574bf215546Sopenharmony_ci}
575bf215546Sopenharmony_ci
576bf215546Sopenharmony_ci/* Add all bound buffers used by compute to the buffer list.
577bf215546Sopenharmony_ci * This is called by the first compute call in a batch when we want to inherit
578bf215546Sopenharmony_ci * all bindings set by the previous batch.
579bf215546Sopenharmony_ci */
580bf215546Sopenharmony_cistatic void
581bf215546Sopenharmony_citc_add_all_compute_bindings_to_buffer_list(struct threaded_context *tc)
582bf215546Sopenharmony_ci{
583bf215546Sopenharmony_ci   BITSET_WORD *buffer_list = tc->buffer_lists[tc->next_buf_list].buffer_list;
584bf215546Sopenharmony_ci
585bf215546Sopenharmony_ci   tc_add_shader_bindings_to_buffer_list(tc, buffer_list, PIPE_SHADER_COMPUTE);
586bf215546Sopenharmony_ci   tc->add_all_compute_bindings_to_buffer_list = false;
587bf215546Sopenharmony_ci}
588bf215546Sopenharmony_ci
589bf215546Sopenharmony_cistatic unsigned
590bf215546Sopenharmony_citc_rebind_buffer(struct threaded_context *tc, uint32_t old_id, uint32_t new_id, uint32_t *rebind_mask)
591bf215546Sopenharmony_ci{
592bf215546Sopenharmony_ci   unsigned vbo = 0, so = 0;
593bf215546Sopenharmony_ci
594bf215546Sopenharmony_ci   vbo = tc_rebind_bindings(old_id, new_id, tc->vertex_buffers,
595bf215546Sopenharmony_ci                            tc->max_vertex_buffers);
596bf215546Sopenharmony_ci   if (vbo)
597bf215546Sopenharmony_ci      *rebind_mask |= BITFIELD_BIT(TC_BINDING_VERTEX_BUFFER);
598bf215546Sopenharmony_ci
599bf215546Sopenharmony_ci   if (tc->seen_streamout_buffers) {
600bf215546Sopenharmony_ci      so = tc_rebind_bindings(old_id, new_id, tc->streamout_buffers,
601bf215546Sopenharmony_ci                              PIPE_MAX_SO_BUFFERS);
602bf215546Sopenharmony_ci      if (so)
603bf215546Sopenharmony_ci         *rebind_mask |= BITFIELD_BIT(TC_BINDING_STREAMOUT_BUFFER);
604bf215546Sopenharmony_ci   }
605bf215546Sopenharmony_ci   unsigned rebound = vbo + so;
606bf215546Sopenharmony_ci
607bf215546Sopenharmony_ci   rebound += tc_rebind_shader_bindings(tc, old_id, new_id, PIPE_SHADER_VERTEX, rebind_mask);
608bf215546Sopenharmony_ci   rebound += tc_rebind_shader_bindings(tc, old_id, new_id, PIPE_SHADER_FRAGMENT, rebind_mask);
609bf215546Sopenharmony_ci
610bf215546Sopenharmony_ci   if (tc->seen_tcs)
611bf215546Sopenharmony_ci      rebound += tc_rebind_shader_bindings(tc, old_id, new_id, PIPE_SHADER_TESS_CTRL, rebind_mask);
612bf215546Sopenharmony_ci   if (tc->seen_tes)
613bf215546Sopenharmony_ci      rebound += tc_rebind_shader_bindings(tc, old_id, new_id, PIPE_SHADER_TESS_EVAL, rebind_mask);
614bf215546Sopenharmony_ci   if (tc->seen_gs)
615bf215546Sopenharmony_ci      rebound += tc_rebind_shader_bindings(tc, old_id, new_id, PIPE_SHADER_GEOMETRY, rebind_mask);
616bf215546Sopenharmony_ci
617bf215546Sopenharmony_ci   rebound += tc_rebind_shader_bindings(tc, old_id, new_id, PIPE_SHADER_COMPUTE, rebind_mask);
618bf215546Sopenharmony_ci
619bf215546Sopenharmony_ci   if (rebound)
620bf215546Sopenharmony_ci      BITSET_SET(tc->buffer_lists[tc->next_buf_list].buffer_list, new_id & TC_BUFFER_ID_MASK);
621bf215546Sopenharmony_ci   return rebound;
622bf215546Sopenharmony_ci}
623bf215546Sopenharmony_ci
624bf215546Sopenharmony_cistatic bool
625bf215546Sopenharmony_citc_is_buffer_bound_with_mask(uint32_t id, uint32_t *bindings, unsigned binding_mask)
626bf215546Sopenharmony_ci{
627bf215546Sopenharmony_ci   while (binding_mask) {
628bf215546Sopenharmony_ci      if (bindings[u_bit_scan(&binding_mask)] == id)
629bf215546Sopenharmony_ci         return true;
630bf215546Sopenharmony_ci   }
631bf215546Sopenharmony_ci   return false;
632bf215546Sopenharmony_ci}
633bf215546Sopenharmony_ci
634bf215546Sopenharmony_cistatic bool
635bf215546Sopenharmony_citc_is_buffer_shader_bound_for_write(struct threaded_context *tc, uint32_t id,
636bf215546Sopenharmony_ci                                    enum pipe_shader_type shader)
637bf215546Sopenharmony_ci{
638bf215546Sopenharmony_ci   if (tc->seen_shader_buffers[shader] &&
639bf215546Sopenharmony_ci       tc_is_buffer_bound_with_mask(id, tc->shader_buffers[shader],
640bf215546Sopenharmony_ci                                    tc->shader_buffers_writeable_mask[shader]))
641bf215546Sopenharmony_ci      return true;
642bf215546Sopenharmony_ci
643bf215546Sopenharmony_ci   if (tc->seen_image_buffers[shader] &&
644bf215546Sopenharmony_ci       tc_is_buffer_bound_with_mask(id, tc->image_buffers[shader],
645bf215546Sopenharmony_ci                                    tc->image_buffers_writeable_mask[shader]))
646bf215546Sopenharmony_ci      return true;
647bf215546Sopenharmony_ci
648bf215546Sopenharmony_ci   return false;
649bf215546Sopenharmony_ci}
650bf215546Sopenharmony_ci
651bf215546Sopenharmony_cistatic bool
652bf215546Sopenharmony_citc_is_buffer_bound_for_write(struct threaded_context *tc, uint32_t id)
653bf215546Sopenharmony_ci{
654bf215546Sopenharmony_ci   if (tc->seen_streamout_buffers &&
655bf215546Sopenharmony_ci       tc_is_buffer_bound_with_mask(id, tc->streamout_buffers,
656bf215546Sopenharmony_ci                                    BITFIELD_MASK(PIPE_MAX_SO_BUFFERS)))
657bf215546Sopenharmony_ci      return true;
658bf215546Sopenharmony_ci
659bf215546Sopenharmony_ci   if (tc_is_buffer_shader_bound_for_write(tc, id, PIPE_SHADER_VERTEX) ||
660bf215546Sopenharmony_ci       tc_is_buffer_shader_bound_for_write(tc, id, PIPE_SHADER_FRAGMENT) ||
661bf215546Sopenharmony_ci       tc_is_buffer_shader_bound_for_write(tc, id, PIPE_SHADER_COMPUTE))
662bf215546Sopenharmony_ci      return true;
663bf215546Sopenharmony_ci
664bf215546Sopenharmony_ci   if (tc->seen_tcs &&
665bf215546Sopenharmony_ci       tc_is_buffer_shader_bound_for_write(tc, id, PIPE_SHADER_TESS_CTRL))
666bf215546Sopenharmony_ci      return true;
667bf215546Sopenharmony_ci
668bf215546Sopenharmony_ci   if (tc->seen_tes &&
669bf215546Sopenharmony_ci       tc_is_buffer_shader_bound_for_write(tc, id, PIPE_SHADER_TESS_EVAL))
670bf215546Sopenharmony_ci      return true;
671bf215546Sopenharmony_ci
672bf215546Sopenharmony_ci   if (tc->seen_gs &&
673bf215546Sopenharmony_ci       tc_is_buffer_shader_bound_for_write(tc, id, PIPE_SHADER_GEOMETRY))
674bf215546Sopenharmony_ci      return true;
675bf215546Sopenharmony_ci
676bf215546Sopenharmony_ci   return false;
677bf215546Sopenharmony_ci}
678bf215546Sopenharmony_ci
679bf215546Sopenharmony_cistatic bool
680bf215546Sopenharmony_citc_is_buffer_busy(struct threaded_context *tc, struct threaded_resource *tbuf,
681bf215546Sopenharmony_ci                  unsigned map_usage)
682bf215546Sopenharmony_ci{
683bf215546Sopenharmony_ci   if (!tc->options.is_resource_busy)
684bf215546Sopenharmony_ci      return true;
685bf215546Sopenharmony_ci
686bf215546Sopenharmony_ci   uint32_t id_hash = tbuf->buffer_id_unique & TC_BUFFER_ID_MASK;
687bf215546Sopenharmony_ci
688bf215546Sopenharmony_ci   for (unsigned i = 0; i < TC_MAX_BUFFER_LISTS; i++) {
689bf215546Sopenharmony_ci      struct tc_buffer_list *buf_list = &tc->buffer_lists[i];
690bf215546Sopenharmony_ci
691bf215546Sopenharmony_ci      /* If the buffer is referenced by a batch that hasn't been flushed (by tc or the driver),
692bf215546Sopenharmony_ci       * then the buffer is considered busy. */
693bf215546Sopenharmony_ci      if (!util_queue_fence_is_signalled(&buf_list->driver_flushed_fence) &&
694bf215546Sopenharmony_ci          BITSET_TEST(buf_list->buffer_list, id_hash))
695bf215546Sopenharmony_ci         return true;
696bf215546Sopenharmony_ci   }
697bf215546Sopenharmony_ci
698bf215546Sopenharmony_ci   /* The buffer isn't referenced by any unflushed batch: we can safely ask to the driver whether
699bf215546Sopenharmony_ci    * this buffer is busy or not. */
700bf215546Sopenharmony_ci   return tc->options.is_resource_busy(tc->pipe->screen, tbuf->latest, map_usage);
701bf215546Sopenharmony_ci}
702bf215546Sopenharmony_ci
703bf215546Sopenharmony_ci/**
704bf215546Sopenharmony_ci * allow_cpu_storage should be false for user memory and imported buffers.
705bf215546Sopenharmony_ci */
706bf215546Sopenharmony_civoid
707bf215546Sopenharmony_cithreaded_resource_init(struct pipe_resource *res, bool allow_cpu_storage)
708bf215546Sopenharmony_ci{
709bf215546Sopenharmony_ci   struct threaded_resource *tres = threaded_resource(res);
710bf215546Sopenharmony_ci
711bf215546Sopenharmony_ci   tres->first_user = NULL;
712bf215546Sopenharmony_ci   tres->used_by_multiple_contexts = false;
713bf215546Sopenharmony_ci   tres->latest = &tres->b;
714bf215546Sopenharmony_ci   tres->cpu_storage = NULL;
715bf215546Sopenharmony_ci   util_range_init(&tres->valid_buffer_range);
716bf215546Sopenharmony_ci   tres->is_shared = false;
717bf215546Sopenharmony_ci   tres->is_user_ptr = false;
718bf215546Sopenharmony_ci   tres->buffer_id_unique = 0;
719bf215546Sopenharmony_ci   tres->pending_staging_uploads = 0;
720bf215546Sopenharmony_ci   util_range_init(&tres->pending_staging_uploads_range);
721bf215546Sopenharmony_ci
722bf215546Sopenharmony_ci   if (allow_cpu_storage &&
723bf215546Sopenharmony_ci       !(res->flags & (PIPE_RESOURCE_FLAG_MAP_PERSISTENT |
724bf215546Sopenharmony_ci                       PIPE_RESOURCE_FLAG_SPARSE |
725bf215546Sopenharmony_ci                       PIPE_RESOURCE_FLAG_ENCRYPTED)) &&
726bf215546Sopenharmony_ci       /* We need buffer invalidation and buffer busyness tracking for the CPU
727bf215546Sopenharmony_ci        * storage, which aren't supported with pipe_vertex_state. */
728bf215546Sopenharmony_ci       !(res->bind & PIPE_BIND_VERTEX_STATE))
729bf215546Sopenharmony_ci      tres->allow_cpu_storage = true;
730bf215546Sopenharmony_ci   else
731bf215546Sopenharmony_ci      tres->allow_cpu_storage = false;
732bf215546Sopenharmony_ci}
733bf215546Sopenharmony_ci
734bf215546Sopenharmony_civoid
735bf215546Sopenharmony_cithreaded_resource_deinit(struct pipe_resource *res)
736bf215546Sopenharmony_ci{
737bf215546Sopenharmony_ci   struct threaded_resource *tres = threaded_resource(res);
738bf215546Sopenharmony_ci
739bf215546Sopenharmony_ci   if (tres->latest != &tres->b)
740bf215546Sopenharmony_ci           pipe_resource_reference(&tres->latest, NULL);
741bf215546Sopenharmony_ci   util_range_destroy(&tres->valid_buffer_range);
742bf215546Sopenharmony_ci   util_range_destroy(&tres->pending_staging_uploads_range);
743bf215546Sopenharmony_ci   align_free(tres->cpu_storage);
744bf215546Sopenharmony_ci}
745bf215546Sopenharmony_ci
746bf215546Sopenharmony_cistruct pipe_context *
747bf215546Sopenharmony_cithreaded_context_unwrap_sync(struct pipe_context *pipe)
748bf215546Sopenharmony_ci{
749bf215546Sopenharmony_ci   if (!pipe || !pipe->priv)
750bf215546Sopenharmony_ci      return pipe;
751bf215546Sopenharmony_ci
752bf215546Sopenharmony_ci   tc_sync(threaded_context(pipe));
753bf215546Sopenharmony_ci   return (struct pipe_context*)pipe->priv;
754bf215546Sopenharmony_ci}
755bf215546Sopenharmony_ci
756bf215546Sopenharmony_ci
757bf215546Sopenharmony_ci/********************************************************************
758bf215546Sopenharmony_ci * simple functions
759bf215546Sopenharmony_ci */
760bf215546Sopenharmony_ci
761bf215546Sopenharmony_ci#define TC_FUNC1(func, qualifier, type, deref, addr, ...) \
762bf215546Sopenharmony_ci   struct tc_call_##func { \
763bf215546Sopenharmony_ci      struct tc_call_base base; \
764bf215546Sopenharmony_ci      type state; \
765bf215546Sopenharmony_ci   }; \
766bf215546Sopenharmony_ci   \
767bf215546Sopenharmony_ci   static uint16_t \
768bf215546Sopenharmony_ci   tc_call_##func(struct pipe_context *pipe, void *call, uint64_t *last) \
769bf215546Sopenharmony_ci   { \
770bf215546Sopenharmony_ci      pipe->func(pipe, addr(to_call(call, tc_call_##func)->state)); \
771bf215546Sopenharmony_ci      return call_size(tc_call_##func); \
772bf215546Sopenharmony_ci   } \
773bf215546Sopenharmony_ci   \
774bf215546Sopenharmony_ci   static void \
775bf215546Sopenharmony_ci   tc_##func(struct pipe_context *_pipe, qualifier type deref param) \
776bf215546Sopenharmony_ci   { \
777bf215546Sopenharmony_ci      struct threaded_context *tc = threaded_context(_pipe); \
778bf215546Sopenharmony_ci      struct tc_call_##func *p = (struct tc_call_##func*) \
779bf215546Sopenharmony_ci                     tc_add_call(tc, TC_CALL_##func, tc_call_##func); \
780bf215546Sopenharmony_ci      p->state = deref(param); \
781bf215546Sopenharmony_ci      __VA_ARGS__; \
782bf215546Sopenharmony_ci   }
783bf215546Sopenharmony_ci
784bf215546Sopenharmony_ciTC_FUNC1(set_active_query_state, , bool, , )
785bf215546Sopenharmony_ci
786bf215546Sopenharmony_ciTC_FUNC1(set_blend_color, const, struct pipe_blend_color, *, &)
787bf215546Sopenharmony_ciTC_FUNC1(set_stencil_ref, const, struct pipe_stencil_ref, , )
788bf215546Sopenharmony_ciTC_FUNC1(set_clip_state, const, struct pipe_clip_state, *, &)
789bf215546Sopenharmony_ciTC_FUNC1(set_sample_mask, , unsigned, , )
790bf215546Sopenharmony_ciTC_FUNC1(set_min_samples, , unsigned, , )
791bf215546Sopenharmony_ciTC_FUNC1(set_polygon_stipple, const, struct pipe_poly_stipple, *, &)
792bf215546Sopenharmony_ci
793bf215546Sopenharmony_ciTC_FUNC1(texture_barrier, , unsigned, , )
794bf215546Sopenharmony_ciTC_FUNC1(memory_barrier, , unsigned, , )
795bf215546Sopenharmony_ciTC_FUNC1(delete_texture_handle, , uint64_t, , )
796bf215546Sopenharmony_ciTC_FUNC1(delete_image_handle, , uint64_t, , )
797bf215546Sopenharmony_ciTC_FUNC1(set_frontend_noop, , bool, , )
798bf215546Sopenharmony_ci
799bf215546Sopenharmony_ci
800bf215546Sopenharmony_ci/********************************************************************
801bf215546Sopenharmony_ci * queries
802bf215546Sopenharmony_ci */
803bf215546Sopenharmony_ci
804bf215546Sopenharmony_cistatic struct pipe_query *
805bf215546Sopenharmony_citc_create_query(struct pipe_context *_pipe, unsigned query_type,
806bf215546Sopenharmony_ci                unsigned index)
807bf215546Sopenharmony_ci{
808bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
809bf215546Sopenharmony_ci   struct pipe_context *pipe = tc->pipe;
810bf215546Sopenharmony_ci
811bf215546Sopenharmony_ci   return pipe->create_query(pipe, query_type, index);
812bf215546Sopenharmony_ci}
813bf215546Sopenharmony_ci
814bf215546Sopenharmony_cistatic struct pipe_query *
815bf215546Sopenharmony_citc_create_batch_query(struct pipe_context *_pipe, unsigned num_queries,
816bf215546Sopenharmony_ci                      unsigned *query_types)
817bf215546Sopenharmony_ci{
818bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
819bf215546Sopenharmony_ci   struct pipe_context *pipe = tc->pipe;
820bf215546Sopenharmony_ci
821bf215546Sopenharmony_ci   return pipe->create_batch_query(pipe, num_queries, query_types);
822bf215546Sopenharmony_ci}
823bf215546Sopenharmony_ci
824bf215546Sopenharmony_cistruct tc_query_call {
825bf215546Sopenharmony_ci   struct tc_call_base base;
826bf215546Sopenharmony_ci   struct pipe_query *query;
827bf215546Sopenharmony_ci};
828bf215546Sopenharmony_ci
829bf215546Sopenharmony_cistatic uint16_t
830bf215546Sopenharmony_citc_call_destroy_query(struct pipe_context *pipe, void *call, uint64_t *last)
831bf215546Sopenharmony_ci{
832bf215546Sopenharmony_ci   struct pipe_query *query = to_call(call, tc_query_call)->query;
833bf215546Sopenharmony_ci   struct threaded_query *tq = threaded_query(query);
834bf215546Sopenharmony_ci
835bf215546Sopenharmony_ci   if (list_is_linked(&tq->head_unflushed))
836bf215546Sopenharmony_ci      list_del(&tq->head_unflushed);
837bf215546Sopenharmony_ci
838bf215546Sopenharmony_ci   pipe->destroy_query(pipe, query);
839bf215546Sopenharmony_ci   return call_size(tc_query_call);
840bf215546Sopenharmony_ci}
841bf215546Sopenharmony_ci
842bf215546Sopenharmony_cistatic void
843bf215546Sopenharmony_citc_destroy_query(struct pipe_context *_pipe, struct pipe_query *query)
844bf215546Sopenharmony_ci{
845bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
846bf215546Sopenharmony_ci
847bf215546Sopenharmony_ci   tc_add_call(tc, TC_CALL_destroy_query, tc_query_call)->query = query;
848bf215546Sopenharmony_ci}
849bf215546Sopenharmony_ci
850bf215546Sopenharmony_cistatic uint16_t
851bf215546Sopenharmony_citc_call_begin_query(struct pipe_context *pipe, void *call, uint64_t *last)
852bf215546Sopenharmony_ci{
853bf215546Sopenharmony_ci   pipe->begin_query(pipe, to_call(call, tc_query_call)->query);
854bf215546Sopenharmony_ci   return call_size(tc_query_call);
855bf215546Sopenharmony_ci}
856bf215546Sopenharmony_ci
857bf215546Sopenharmony_cistatic bool
858bf215546Sopenharmony_citc_begin_query(struct pipe_context *_pipe, struct pipe_query *query)
859bf215546Sopenharmony_ci{
860bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
861bf215546Sopenharmony_ci
862bf215546Sopenharmony_ci   tc_add_call(tc, TC_CALL_begin_query, tc_query_call)->query = query;
863bf215546Sopenharmony_ci   return true; /* we don't care about the return value for this call */
864bf215546Sopenharmony_ci}
865bf215546Sopenharmony_ci
866bf215546Sopenharmony_cistruct tc_end_query_call {
867bf215546Sopenharmony_ci   struct tc_call_base base;
868bf215546Sopenharmony_ci   struct threaded_context *tc;
869bf215546Sopenharmony_ci   struct pipe_query *query;
870bf215546Sopenharmony_ci};
871bf215546Sopenharmony_ci
872bf215546Sopenharmony_cistatic uint16_t
873bf215546Sopenharmony_citc_call_end_query(struct pipe_context *pipe, void *call, uint64_t *last)
874bf215546Sopenharmony_ci{
875bf215546Sopenharmony_ci   struct tc_end_query_call *p = to_call(call, tc_end_query_call);
876bf215546Sopenharmony_ci   struct threaded_query *tq = threaded_query(p->query);
877bf215546Sopenharmony_ci
878bf215546Sopenharmony_ci   if (!list_is_linked(&tq->head_unflushed))
879bf215546Sopenharmony_ci      list_add(&tq->head_unflushed, &p->tc->unflushed_queries);
880bf215546Sopenharmony_ci
881bf215546Sopenharmony_ci   pipe->end_query(pipe, p->query);
882bf215546Sopenharmony_ci   return call_size(tc_end_query_call);
883bf215546Sopenharmony_ci}
884bf215546Sopenharmony_ci
885bf215546Sopenharmony_cistatic bool
886bf215546Sopenharmony_citc_end_query(struct pipe_context *_pipe, struct pipe_query *query)
887bf215546Sopenharmony_ci{
888bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
889bf215546Sopenharmony_ci   struct threaded_query *tq = threaded_query(query);
890bf215546Sopenharmony_ci   struct tc_end_query_call *call =
891bf215546Sopenharmony_ci      tc_add_call(tc, TC_CALL_end_query, tc_end_query_call);
892bf215546Sopenharmony_ci
893bf215546Sopenharmony_ci   call->tc = tc;
894bf215546Sopenharmony_ci   call->query = query;
895bf215546Sopenharmony_ci
896bf215546Sopenharmony_ci   tq->flushed = false;
897bf215546Sopenharmony_ci
898bf215546Sopenharmony_ci   return true; /* we don't care about the return value for this call */
899bf215546Sopenharmony_ci}
900bf215546Sopenharmony_ci
901bf215546Sopenharmony_cistatic bool
902bf215546Sopenharmony_citc_get_query_result(struct pipe_context *_pipe,
903bf215546Sopenharmony_ci                    struct pipe_query *query, bool wait,
904bf215546Sopenharmony_ci                    union pipe_query_result *result)
905bf215546Sopenharmony_ci{
906bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
907bf215546Sopenharmony_ci   struct threaded_query *tq = threaded_query(query);
908bf215546Sopenharmony_ci   struct pipe_context *pipe = tc->pipe;
909bf215546Sopenharmony_ci   bool flushed = tq->flushed;
910bf215546Sopenharmony_ci
911bf215546Sopenharmony_ci   if (!flushed) {
912bf215546Sopenharmony_ci      tc_sync_msg(tc, wait ? "wait" : "nowait");
913bf215546Sopenharmony_ci      tc_set_driver_thread(tc);
914bf215546Sopenharmony_ci   }
915bf215546Sopenharmony_ci
916bf215546Sopenharmony_ci   bool success = pipe->get_query_result(pipe, query, wait, result);
917bf215546Sopenharmony_ci
918bf215546Sopenharmony_ci   if (!flushed)
919bf215546Sopenharmony_ci      tc_clear_driver_thread(tc);
920bf215546Sopenharmony_ci
921bf215546Sopenharmony_ci   if (success) {
922bf215546Sopenharmony_ci      tq->flushed = true;
923bf215546Sopenharmony_ci      if (list_is_linked(&tq->head_unflushed)) {
924bf215546Sopenharmony_ci         /* This is safe because it can only happen after we sync'd. */
925bf215546Sopenharmony_ci         list_del(&tq->head_unflushed);
926bf215546Sopenharmony_ci      }
927bf215546Sopenharmony_ci   }
928bf215546Sopenharmony_ci   return success;
929bf215546Sopenharmony_ci}
930bf215546Sopenharmony_ci
931bf215546Sopenharmony_cistruct tc_query_result_resource {
932bf215546Sopenharmony_ci   struct tc_call_base base;
933bf215546Sopenharmony_ci   enum pipe_query_flags flags:8;
934bf215546Sopenharmony_ci   enum pipe_query_value_type result_type:8;
935bf215546Sopenharmony_ci   int8_t index; /* it can be -1 */
936bf215546Sopenharmony_ci   unsigned offset;
937bf215546Sopenharmony_ci   struct pipe_query *query;
938bf215546Sopenharmony_ci   struct pipe_resource *resource;
939bf215546Sopenharmony_ci};
940bf215546Sopenharmony_ci
941bf215546Sopenharmony_cistatic uint16_t
942bf215546Sopenharmony_citc_call_get_query_result_resource(struct pipe_context *pipe, void *call, uint64_t *last)
943bf215546Sopenharmony_ci{
944bf215546Sopenharmony_ci   struct tc_query_result_resource *p = to_call(call, tc_query_result_resource);
945bf215546Sopenharmony_ci
946bf215546Sopenharmony_ci   pipe->get_query_result_resource(pipe, p->query, p->flags, p->result_type,
947bf215546Sopenharmony_ci                                   p->index, p->resource, p->offset);
948bf215546Sopenharmony_ci   tc_drop_resource_reference(p->resource);
949bf215546Sopenharmony_ci   return call_size(tc_query_result_resource);
950bf215546Sopenharmony_ci}
951bf215546Sopenharmony_ci
952bf215546Sopenharmony_cistatic void
953bf215546Sopenharmony_citc_get_query_result_resource(struct pipe_context *_pipe,
954bf215546Sopenharmony_ci                             struct pipe_query *query,
955bf215546Sopenharmony_ci                             enum pipe_query_flags flags,
956bf215546Sopenharmony_ci                             enum pipe_query_value_type result_type, int index,
957bf215546Sopenharmony_ci                             struct pipe_resource *resource, unsigned offset)
958bf215546Sopenharmony_ci{
959bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
960bf215546Sopenharmony_ci
961bf215546Sopenharmony_ci   tc_buffer_disable_cpu_storage(resource);
962bf215546Sopenharmony_ci
963bf215546Sopenharmony_ci   struct tc_query_result_resource *p =
964bf215546Sopenharmony_ci      tc_add_call(tc, TC_CALL_get_query_result_resource,
965bf215546Sopenharmony_ci                  tc_query_result_resource);
966bf215546Sopenharmony_ci   p->query = query;
967bf215546Sopenharmony_ci   p->flags = flags;
968bf215546Sopenharmony_ci   p->result_type = result_type;
969bf215546Sopenharmony_ci   p->index = index;
970bf215546Sopenharmony_ci   tc_set_resource_reference(&p->resource, resource);
971bf215546Sopenharmony_ci   tc_add_to_buffer_list(tc, &tc->buffer_lists[tc->next_buf_list], resource);
972bf215546Sopenharmony_ci   p->offset = offset;
973bf215546Sopenharmony_ci}
974bf215546Sopenharmony_ci
975bf215546Sopenharmony_cistruct tc_render_condition {
976bf215546Sopenharmony_ci   struct tc_call_base base;
977bf215546Sopenharmony_ci   bool condition;
978bf215546Sopenharmony_ci   unsigned mode;
979bf215546Sopenharmony_ci   struct pipe_query *query;
980bf215546Sopenharmony_ci};
981bf215546Sopenharmony_ci
982bf215546Sopenharmony_cistatic uint16_t
983bf215546Sopenharmony_citc_call_render_condition(struct pipe_context *pipe, void *call, uint64_t *last)
984bf215546Sopenharmony_ci{
985bf215546Sopenharmony_ci   struct tc_render_condition *p = to_call(call, tc_render_condition);
986bf215546Sopenharmony_ci   pipe->render_condition(pipe, p->query, p->condition, p->mode);
987bf215546Sopenharmony_ci   return call_size(tc_render_condition);
988bf215546Sopenharmony_ci}
989bf215546Sopenharmony_ci
990bf215546Sopenharmony_cistatic void
991bf215546Sopenharmony_citc_render_condition(struct pipe_context *_pipe,
992bf215546Sopenharmony_ci                    struct pipe_query *query, bool condition,
993bf215546Sopenharmony_ci                    enum pipe_render_cond_flag mode)
994bf215546Sopenharmony_ci{
995bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
996bf215546Sopenharmony_ci   struct tc_render_condition *p =
997bf215546Sopenharmony_ci      tc_add_call(tc, TC_CALL_render_condition, tc_render_condition);
998bf215546Sopenharmony_ci
999bf215546Sopenharmony_ci   p->query = query;
1000bf215546Sopenharmony_ci   p->condition = condition;
1001bf215546Sopenharmony_ci   p->mode = mode;
1002bf215546Sopenharmony_ci}
1003bf215546Sopenharmony_ci
1004bf215546Sopenharmony_ci
1005bf215546Sopenharmony_ci/********************************************************************
1006bf215546Sopenharmony_ci * constant (immutable) states
1007bf215546Sopenharmony_ci */
1008bf215546Sopenharmony_ci
1009bf215546Sopenharmony_ci#define TC_CSO_CREATE(name, sname) \
1010bf215546Sopenharmony_ci   static void * \
1011bf215546Sopenharmony_ci   tc_create_##name##_state(struct pipe_context *_pipe, \
1012bf215546Sopenharmony_ci                            const struct pipe_##sname##_state *state) \
1013bf215546Sopenharmony_ci   { \
1014bf215546Sopenharmony_ci      struct pipe_context *pipe = threaded_context(_pipe)->pipe; \
1015bf215546Sopenharmony_ci      return pipe->create_##name##_state(pipe, state); \
1016bf215546Sopenharmony_ci   }
1017bf215546Sopenharmony_ci
1018bf215546Sopenharmony_ci#define TC_CSO_BIND(name, ...) TC_FUNC1(bind_##name##_state, , void *, , , ##__VA_ARGS__)
1019bf215546Sopenharmony_ci#define TC_CSO_DELETE(name) TC_FUNC1(delete_##name##_state, , void *, , )
1020bf215546Sopenharmony_ci
1021bf215546Sopenharmony_ci#define TC_CSO(name, sname, ...) \
1022bf215546Sopenharmony_ci   TC_CSO_CREATE(name, sname) \
1023bf215546Sopenharmony_ci   TC_CSO_BIND(name, ##__VA_ARGS__) \
1024bf215546Sopenharmony_ci   TC_CSO_DELETE(name)
1025bf215546Sopenharmony_ci
1026bf215546Sopenharmony_ci#define TC_CSO_WHOLE(name) TC_CSO(name, name)
1027bf215546Sopenharmony_ci#define TC_CSO_SHADER(name) TC_CSO(name, shader)
1028bf215546Sopenharmony_ci#define TC_CSO_SHADER_TRACK(name) TC_CSO(name, shader, tc->seen_##name = true;)
1029bf215546Sopenharmony_ci
1030bf215546Sopenharmony_ciTC_CSO_WHOLE(blend)
1031bf215546Sopenharmony_ciTC_CSO_WHOLE(rasterizer)
1032bf215546Sopenharmony_ciTC_CSO_WHOLE(depth_stencil_alpha)
1033bf215546Sopenharmony_ciTC_CSO_WHOLE(compute)
1034bf215546Sopenharmony_ciTC_CSO_SHADER(fs)
1035bf215546Sopenharmony_ciTC_CSO_SHADER(vs)
1036bf215546Sopenharmony_ciTC_CSO_SHADER_TRACK(gs)
1037bf215546Sopenharmony_ciTC_CSO_SHADER_TRACK(tcs)
1038bf215546Sopenharmony_ciTC_CSO_SHADER_TRACK(tes)
1039bf215546Sopenharmony_ciTC_CSO_CREATE(sampler, sampler)
1040bf215546Sopenharmony_ciTC_CSO_DELETE(sampler)
1041bf215546Sopenharmony_ciTC_CSO_BIND(vertex_elements)
1042bf215546Sopenharmony_ciTC_CSO_DELETE(vertex_elements)
1043bf215546Sopenharmony_ci
1044bf215546Sopenharmony_cistatic void *
1045bf215546Sopenharmony_citc_create_vertex_elements_state(struct pipe_context *_pipe, unsigned count,
1046bf215546Sopenharmony_ci                                const struct pipe_vertex_element *elems)
1047bf215546Sopenharmony_ci{
1048bf215546Sopenharmony_ci   struct pipe_context *pipe = threaded_context(_pipe)->pipe;
1049bf215546Sopenharmony_ci
1050bf215546Sopenharmony_ci   return pipe->create_vertex_elements_state(pipe, count, elems);
1051bf215546Sopenharmony_ci}
1052bf215546Sopenharmony_ci
1053bf215546Sopenharmony_cistruct tc_sampler_states {
1054bf215546Sopenharmony_ci   struct tc_call_base base;
1055bf215546Sopenharmony_ci   ubyte shader, start, count;
1056bf215546Sopenharmony_ci   void *slot[0]; /* more will be allocated if needed */
1057bf215546Sopenharmony_ci};
1058bf215546Sopenharmony_ci
1059bf215546Sopenharmony_cistatic uint16_t
1060bf215546Sopenharmony_citc_call_bind_sampler_states(struct pipe_context *pipe, void *call, uint64_t *last)
1061bf215546Sopenharmony_ci{
1062bf215546Sopenharmony_ci   struct tc_sampler_states *p = (struct tc_sampler_states *)call;
1063bf215546Sopenharmony_ci
1064bf215546Sopenharmony_ci   pipe->bind_sampler_states(pipe, p->shader, p->start, p->count, p->slot);
1065bf215546Sopenharmony_ci   return p->base.num_slots;
1066bf215546Sopenharmony_ci}
1067bf215546Sopenharmony_ci
1068bf215546Sopenharmony_cistatic void
1069bf215546Sopenharmony_citc_bind_sampler_states(struct pipe_context *_pipe,
1070bf215546Sopenharmony_ci                       enum pipe_shader_type shader,
1071bf215546Sopenharmony_ci                       unsigned start, unsigned count, void **states)
1072bf215546Sopenharmony_ci{
1073bf215546Sopenharmony_ci   if (!count)
1074bf215546Sopenharmony_ci      return;
1075bf215546Sopenharmony_ci
1076bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
1077bf215546Sopenharmony_ci   struct tc_sampler_states *p =
1078bf215546Sopenharmony_ci      tc_add_slot_based_call(tc, TC_CALL_bind_sampler_states, tc_sampler_states, count);
1079bf215546Sopenharmony_ci
1080bf215546Sopenharmony_ci   p->shader = shader;
1081bf215546Sopenharmony_ci   p->start = start;
1082bf215546Sopenharmony_ci   p->count = count;
1083bf215546Sopenharmony_ci   memcpy(p->slot, states, count * sizeof(states[0]));
1084bf215546Sopenharmony_ci}
1085bf215546Sopenharmony_ci
1086bf215546Sopenharmony_cistatic void
1087bf215546Sopenharmony_citc_link_shader(struct pipe_context *_pipe, void **shaders)
1088bf215546Sopenharmony_ci{
1089bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
1090bf215546Sopenharmony_ci   tc->pipe->link_shader(tc->pipe, shaders);
1091bf215546Sopenharmony_ci}
1092bf215546Sopenharmony_ci/********************************************************************
1093bf215546Sopenharmony_ci * immediate states
1094bf215546Sopenharmony_ci */
1095bf215546Sopenharmony_ci
1096bf215546Sopenharmony_cistruct tc_framebuffer {
1097bf215546Sopenharmony_ci   struct tc_call_base base;
1098bf215546Sopenharmony_ci   struct pipe_framebuffer_state state;
1099bf215546Sopenharmony_ci};
1100bf215546Sopenharmony_ci
1101bf215546Sopenharmony_cistatic uint16_t
1102bf215546Sopenharmony_citc_call_set_framebuffer_state(struct pipe_context *pipe, void *call, uint64_t *last)
1103bf215546Sopenharmony_ci{
1104bf215546Sopenharmony_ci   struct pipe_framebuffer_state *p = &to_call(call, tc_framebuffer)->state;
1105bf215546Sopenharmony_ci
1106bf215546Sopenharmony_ci   pipe->set_framebuffer_state(pipe, p);
1107bf215546Sopenharmony_ci
1108bf215546Sopenharmony_ci   unsigned nr_cbufs = p->nr_cbufs;
1109bf215546Sopenharmony_ci   for (unsigned i = 0; i < nr_cbufs; i++)
1110bf215546Sopenharmony_ci      tc_drop_surface_reference(p->cbufs[i]);
1111bf215546Sopenharmony_ci   tc_drop_surface_reference(p->zsbuf);
1112bf215546Sopenharmony_ci   return call_size(tc_framebuffer);
1113bf215546Sopenharmony_ci}
1114bf215546Sopenharmony_ci
1115bf215546Sopenharmony_cistatic void
1116bf215546Sopenharmony_citc_set_framebuffer_state(struct pipe_context *_pipe,
1117bf215546Sopenharmony_ci                         const struct pipe_framebuffer_state *fb)
1118bf215546Sopenharmony_ci{
1119bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
1120bf215546Sopenharmony_ci   struct tc_framebuffer *p =
1121bf215546Sopenharmony_ci      tc_add_call(tc, TC_CALL_set_framebuffer_state, tc_framebuffer);
1122bf215546Sopenharmony_ci   unsigned nr_cbufs = fb->nr_cbufs;
1123bf215546Sopenharmony_ci
1124bf215546Sopenharmony_ci   p->state.width = fb->width;
1125bf215546Sopenharmony_ci   p->state.height = fb->height;
1126bf215546Sopenharmony_ci   p->state.samples = fb->samples;
1127bf215546Sopenharmony_ci   p->state.layers = fb->layers;
1128bf215546Sopenharmony_ci   p->state.nr_cbufs = nr_cbufs;
1129bf215546Sopenharmony_ci
1130bf215546Sopenharmony_ci   for (unsigned i = 0; i < nr_cbufs; i++) {
1131bf215546Sopenharmony_ci      p->state.cbufs[i] = NULL;
1132bf215546Sopenharmony_ci      pipe_surface_reference(&p->state.cbufs[i], fb->cbufs[i]);
1133bf215546Sopenharmony_ci   }
1134bf215546Sopenharmony_ci   p->state.zsbuf = NULL;
1135bf215546Sopenharmony_ci   pipe_surface_reference(&p->state.zsbuf, fb->zsbuf);
1136bf215546Sopenharmony_ci}
1137bf215546Sopenharmony_ci
1138bf215546Sopenharmony_cistruct tc_tess_state {
1139bf215546Sopenharmony_ci   struct tc_call_base base;
1140bf215546Sopenharmony_ci   float state[6];
1141bf215546Sopenharmony_ci};
1142bf215546Sopenharmony_ci
1143bf215546Sopenharmony_cistatic uint16_t
1144bf215546Sopenharmony_citc_call_set_tess_state(struct pipe_context *pipe, void *call, uint64_t *last)
1145bf215546Sopenharmony_ci{
1146bf215546Sopenharmony_ci   float *p = to_call(call, tc_tess_state)->state;
1147bf215546Sopenharmony_ci
1148bf215546Sopenharmony_ci   pipe->set_tess_state(pipe, p, p + 4);
1149bf215546Sopenharmony_ci   return call_size(tc_tess_state);
1150bf215546Sopenharmony_ci}
1151bf215546Sopenharmony_ci
1152bf215546Sopenharmony_cistatic void
1153bf215546Sopenharmony_citc_set_tess_state(struct pipe_context *_pipe,
1154bf215546Sopenharmony_ci                  const float default_outer_level[4],
1155bf215546Sopenharmony_ci                  const float default_inner_level[2])
1156bf215546Sopenharmony_ci{
1157bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
1158bf215546Sopenharmony_ci   float *p = tc_add_call(tc, TC_CALL_set_tess_state, tc_tess_state)->state;
1159bf215546Sopenharmony_ci
1160bf215546Sopenharmony_ci   memcpy(p, default_outer_level, 4 * sizeof(float));
1161bf215546Sopenharmony_ci   memcpy(p + 4, default_inner_level, 2 * sizeof(float));
1162bf215546Sopenharmony_ci}
1163bf215546Sopenharmony_ci
1164bf215546Sopenharmony_cistruct tc_patch_vertices {
1165bf215546Sopenharmony_ci   struct tc_call_base base;
1166bf215546Sopenharmony_ci   ubyte patch_vertices;
1167bf215546Sopenharmony_ci};
1168bf215546Sopenharmony_ci
1169bf215546Sopenharmony_cistatic uint16_t
1170bf215546Sopenharmony_citc_call_set_patch_vertices(struct pipe_context *pipe, void *call, uint64_t *last)
1171bf215546Sopenharmony_ci{
1172bf215546Sopenharmony_ci   uint8_t patch_vertices = to_call(call, tc_patch_vertices)->patch_vertices;
1173bf215546Sopenharmony_ci
1174bf215546Sopenharmony_ci   pipe->set_patch_vertices(pipe, patch_vertices);
1175bf215546Sopenharmony_ci   return call_size(tc_patch_vertices);
1176bf215546Sopenharmony_ci}
1177bf215546Sopenharmony_ci
1178bf215546Sopenharmony_cistatic void
1179bf215546Sopenharmony_citc_set_patch_vertices(struct pipe_context *_pipe, uint8_t patch_vertices)
1180bf215546Sopenharmony_ci{
1181bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
1182bf215546Sopenharmony_ci
1183bf215546Sopenharmony_ci   tc_add_call(tc, TC_CALL_set_patch_vertices,
1184bf215546Sopenharmony_ci               tc_patch_vertices)->patch_vertices = patch_vertices;
1185bf215546Sopenharmony_ci}
1186bf215546Sopenharmony_ci
1187bf215546Sopenharmony_cistruct tc_constant_buffer_base {
1188bf215546Sopenharmony_ci   struct tc_call_base base;
1189bf215546Sopenharmony_ci   ubyte shader, index;
1190bf215546Sopenharmony_ci   bool is_null;
1191bf215546Sopenharmony_ci};
1192bf215546Sopenharmony_ci
1193bf215546Sopenharmony_cistruct tc_constant_buffer {
1194bf215546Sopenharmony_ci   struct tc_constant_buffer_base base;
1195bf215546Sopenharmony_ci   struct pipe_constant_buffer cb;
1196bf215546Sopenharmony_ci};
1197bf215546Sopenharmony_ci
1198bf215546Sopenharmony_cistatic uint16_t
1199bf215546Sopenharmony_citc_call_set_constant_buffer(struct pipe_context *pipe, void *call, uint64_t *last)
1200bf215546Sopenharmony_ci{
1201bf215546Sopenharmony_ci   struct tc_constant_buffer *p = (struct tc_constant_buffer *)call;
1202bf215546Sopenharmony_ci
1203bf215546Sopenharmony_ci   if (unlikely(p->base.is_null)) {
1204bf215546Sopenharmony_ci      pipe->set_constant_buffer(pipe, p->base.shader, p->base.index, false, NULL);
1205bf215546Sopenharmony_ci      return call_size(tc_constant_buffer_base);
1206bf215546Sopenharmony_ci   }
1207bf215546Sopenharmony_ci
1208bf215546Sopenharmony_ci   pipe->set_constant_buffer(pipe, p->base.shader, p->base.index, true, &p->cb);
1209bf215546Sopenharmony_ci   return call_size(tc_constant_buffer);
1210bf215546Sopenharmony_ci}
1211bf215546Sopenharmony_ci
1212bf215546Sopenharmony_cistatic void
1213bf215546Sopenharmony_citc_set_constant_buffer(struct pipe_context *_pipe,
1214bf215546Sopenharmony_ci                       enum pipe_shader_type shader, uint index,
1215bf215546Sopenharmony_ci                       bool take_ownership,
1216bf215546Sopenharmony_ci                       const struct pipe_constant_buffer *cb)
1217bf215546Sopenharmony_ci{
1218bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
1219bf215546Sopenharmony_ci
1220bf215546Sopenharmony_ci   if (unlikely(!cb || (!cb->buffer && !cb->user_buffer))) {
1221bf215546Sopenharmony_ci      struct tc_constant_buffer_base *p =
1222bf215546Sopenharmony_ci         tc_add_call(tc, TC_CALL_set_constant_buffer, tc_constant_buffer_base);
1223bf215546Sopenharmony_ci      p->shader = shader;
1224bf215546Sopenharmony_ci      p->index = index;
1225bf215546Sopenharmony_ci      p->is_null = true;
1226bf215546Sopenharmony_ci      tc_unbind_buffer(&tc->const_buffers[shader][index]);
1227bf215546Sopenharmony_ci      return;
1228bf215546Sopenharmony_ci   }
1229bf215546Sopenharmony_ci
1230bf215546Sopenharmony_ci   struct pipe_resource *buffer;
1231bf215546Sopenharmony_ci   unsigned offset;
1232bf215546Sopenharmony_ci
1233bf215546Sopenharmony_ci   if (cb->user_buffer) {
1234bf215546Sopenharmony_ci      /* This must be done before adding set_constant_buffer, because it could
1235bf215546Sopenharmony_ci       * generate e.g. transfer_unmap and flush partially-uninitialized
1236bf215546Sopenharmony_ci       * set_constant_buffer to the driver if it was done afterwards.
1237bf215546Sopenharmony_ci       */
1238bf215546Sopenharmony_ci      buffer = NULL;
1239bf215546Sopenharmony_ci      u_upload_data(tc->base.const_uploader, 0, cb->buffer_size,
1240bf215546Sopenharmony_ci                    tc->ubo_alignment, cb->user_buffer, &offset, &buffer);
1241bf215546Sopenharmony_ci      u_upload_unmap(tc->base.const_uploader);
1242bf215546Sopenharmony_ci      take_ownership = true;
1243bf215546Sopenharmony_ci   } else {
1244bf215546Sopenharmony_ci      buffer = cb->buffer;
1245bf215546Sopenharmony_ci      offset = cb->buffer_offset;
1246bf215546Sopenharmony_ci   }
1247bf215546Sopenharmony_ci
1248bf215546Sopenharmony_ci   struct tc_constant_buffer *p =
1249bf215546Sopenharmony_ci      tc_add_call(tc, TC_CALL_set_constant_buffer, tc_constant_buffer);
1250bf215546Sopenharmony_ci   p->base.shader = shader;
1251bf215546Sopenharmony_ci   p->base.index = index;
1252bf215546Sopenharmony_ci   p->base.is_null = false;
1253bf215546Sopenharmony_ci   p->cb.user_buffer = NULL;
1254bf215546Sopenharmony_ci   p->cb.buffer_offset = offset;
1255bf215546Sopenharmony_ci   p->cb.buffer_size = cb->buffer_size;
1256bf215546Sopenharmony_ci
1257bf215546Sopenharmony_ci   if (take_ownership)
1258bf215546Sopenharmony_ci      p->cb.buffer = buffer;
1259bf215546Sopenharmony_ci   else
1260bf215546Sopenharmony_ci      tc_set_resource_reference(&p->cb.buffer, buffer);
1261bf215546Sopenharmony_ci
1262bf215546Sopenharmony_ci   if (buffer) {
1263bf215546Sopenharmony_ci      tc_bind_buffer(tc, &tc->const_buffers[shader][index],
1264bf215546Sopenharmony_ci                     &tc->buffer_lists[tc->next_buf_list], buffer);
1265bf215546Sopenharmony_ci   } else {
1266bf215546Sopenharmony_ci      tc_unbind_buffer(&tc->const_buffers[shader][index]);
1267bf215546Sopenharmony_ci   }
1268bf215546Sopenharmony_ci}
1269bf215546Sopenharmony_ci
1270bf215546Sopenharmony_cistruct tc_inlinable_constants {
1271bf215546Sopenharmony_ci   struct tc_call_base base;
1272bf215546Sopenharmony_ci   ubyte shader;
1273bf215546Sopenharmony_ci   ubyte num_values;
1274bf215546Sopenharmony_ci   uint32_t values[MAX_INLINABLE_UNIFORMS];
1275bf215546Sopenharmony_ci};
1276bf215546Sopenharmony_ci
1277bf215546Sopenharmony_cistatic uint16_t
1278bf215546Sopenharmony_citc_call_set_inlinable_constants(struct pipe_context *pipe, void *call, uint64_t *last)
1279bf215546Sopenharmony_ci{
1280bf215546Sopenharmony_ci   struct tc_inlinable_constants *p = to_call(call, tc_inlinable_constants);
1281bf215546Sopenharmony_ci
1282bf215546Sopenharmony_ci   pipe->set_inlinable_constants(pipe, p->shader, p->num_values, p->values);
1283bf215546Sopenharmony_ci   return call_size(tc_inlinable_constants);
1284bf215546Sopenharmony_ci}
1285bf215546Sopenharmony_ci
1286bf215546Sopenharmony_cistatic void
1287bf215546Sopenharmony_citc_set_inlinable_constants(struct pipe_context *_pipe,
1288bf215546Sopenharmony_ci                           enum pipe_shader_type shader,
1289bf215546Sopenharmony_ci                           uint num_values, uint32_t *values)
1290bf215546Sopenharmony_ci{
1291bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
1292bf215546Sopenharmony_ci   struct tc_inlinable_constants *p =
1293bf215546Sopenharmony_ci      tc_add_call(tc, TC_CALL_set_inlinable_constants, tc_inlinable_constants);
1294bf215546Sopenharmony_ci   p->shader = shader;
1295bf215546Sopenharmony_ci   p->num_values = num_values;
1296bf215546Sopenharmony_ci   memcpy(p->values, values, num_values * 4);
1297bf215546Sopenharmony_ci}
1298bf215546Sopenharmony_ci
1299bf215546Sopenharmony_cistruct tc_sample_locations {
1300bf215546Sopenharmony_ci   struct tc_call_base base;
1301bf215546Sopenharmony_ci   uint16_t size;
1302bf215546Sopenharmony_ci   uint8_t slot[0];
1303bf215546Sopenharmony_ci};
1304bf215546Sopenharmony_ci
1305bf215546Sopenharmony_ci
1306bf215546Sopenharmony_cistatic uint16_t
1307bf215546Sopenharmony_citc_call_set_sample_locations(struct pipe_context *pipe, void *call, uint64_t *last)
1308bf215546Sopenharmony_ci{
1309bf215546Sopenharmony_ci   struct tc_sample_locations *p = (struct tc_sample_locations *)call;
1310bf215546Sopenharmony_ci
1311bf215546Sopenharmony_ci   pipe->set_sample_locations(pipe, p->size, p->slot);
1312bf215546Sopenharmony_ci   return p->base.num_slots;
1313bf215546Sopenharmony_ci}
1314bf215546Sopenharmony_ci
1315bf215546Sopenharmony_cistatic void
1316bf215546Sopenharmony_citc_set_sample_locations(struct pipe_context *_pipe, size_t size, const uint8_t *locations)
1317bf215546Sopenharmony_ci{
1318bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
1319bf215546Sopenharmony_ci   struct tc_sample_locations *p =
1320bf215546Sopenharmony_ci      tc_add_slot_based_call(tc, TC_CALL_set_sample_locations,
1321bf215546Sopenharmony_ci                             tc_sample_locations, size);
1322bf215546Sopenharmony_ci
1323bf215546Sopenharmony_ci   p->size = size;
1324bf215546Sopenharmony_ci   memcpy(p->slot, locations, size);
1325bf215546Sopenharmony_ci}
1326bf215546Sopenharmony_ci
1327bf215546Sopenharmony_cistruct tc_scissors {
1328bf215546Sopenharmony_ci   struct tc_call_base base;
1329bf215546Sopenharmony_ci   ubyte start, count;
1330bf215546Sopenharmony_ci   struct pipe_scissor_state slot[0]; /* more will be allocated if needed */
1331bf215546Sopenharmony_ci};
1332bf215546Sopenharmony_ci
1333bf215546Sopenharmony_cistatic uint16_t
1334bf215546Sopenharmony_citc_call_set_scissor_states(struct pipe_context *pipe, void *call, uint64_t *last)
1335bf215546Sopenharmony_ci{
1336bf215546Sopenharmony_ci   struct tc_scissors *p = (struct tc_scissors *)call;
1337bf215546Sopenharmony_ci
1338bf215546Sopenharmony_ci   pipe->set_scissor_states(pipe, p->start, p->count, p->slot);
1339bf215546Sopenharmony_ci   return p->base.num_slots;
1340bf215546Sopenharmony_ci}
1341bf215546Sopenharmony_ci
1342bf215546Sopenharmony_cistatic void
1343bf215546Sopenharmony_citc_set_scissor_states(struct pipe_context *_pipe,
1344bf215546Sopenharmony_ci                      unsigned start, unsigned count,
1345bf215546Sopenharmony_ci                      const struct pipe_scissor_state *states)
1346bf215546Sopenharmony_ci{
1347bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
1348bf215546Sopenharmony_ci   struct tc_scissors *p =
1349bf215546Sopenharmony_ci      tc_add_slot_based_call(tc, TC_CALL_set_scissor_states, tc_scissors, count);
1350bf215546Sopenharmony_ci
1351bf215546Sopenharmony_ci   p->start = start;
1352bf215546Sopenharmony_ci   p->count = count;
1353bf215546Sopenharmony_ci   memcpy(&p->slot, states, count * sizeof(states[0]));
1354bf215546Sopenharmony_ci}
1355bf215546Sopenharmony_ci
1356bf215546Sopenharmony_cistruct tc_viewports {
1357bf215546Sopenharmony_ci   struct tc_call_base base;
1358bf215546Sopenharmony_ci   ubyte start, count;
1359bf215546Sopenharmony_ci   struct pipe_viewport_state slot[0]; /* more will be allocated if needed */
1360bf215546Sopenharmony_ci};
1361bf215546Sopenharmony_ci
1362bf215546Sopenharmony_cistatic uint16_t
1363bf215546Sopenharmony_citc_call_set_viewport_states(struct pipe_context *pipe, void *call, uint64_t *last)
1364bf215546Sopenharmony_ci{
1365bf215546Sopenharmony_ci   struct tc_viewports *p = (struct tc_viewports *)call;
1366bf215546Sopenharmony_ci
1367bf215546Sopenharmony_ci   pipe->set_viewport_states(pipe, p->start, p->count, p->slot);
1368bf215546Sopenharmony_ci   return p->base.num_slots;
1369bf215546Sopenharmony_ci}
1370bf215546Sopenharmony_ci
1371bf215546Sopenharmony_cistatic void
1372bf215546Sopenharmony_citc_set_viewport_states(struct pipe_context *_pipe,
1373bf215546Sopenharmony_ci                       unsigned start, unsigned count,
1374bf215546Sopenharmony_ci                       const struct pipe_viewport_state *states)
1375bf215546Sopenharmony_ci{
1376bf215546Sopenharmony_ci   if (!count)
1377bf215546Sopenharmony_ci      return;
1378bf215546Sopenharmony_ci
1379bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
1380bf215546Sopenharmony_ci   struct tc_viewports *p =
1381bf215546Sopenharmony_ci      tc_add_slot_based_call(tc, TC_CALL_set_viewport_states, tc_viewports, count);
1382bf215546Sopenharmony_ci
1383bf215546Sopenharmony_ci   p->start = start;
1384bf215546Sopenharmony_ci   p->count = count;
1385bf215546Sopenharmony_ci   memcpy(&p->slot, states, count * sizeof(states[0]));
1386bf215546Sopenharmony_ci}
1387bf215546Sopenharmony_ci
1388bf215546Sopenharmony_cistruct tc_window_rects {
1389bf215546Sopenharmony_ci   struct tc_call_base base;
1390bf215546Sopenharmony_ci   bool include;
1391bf215546Sopenharmony_ci   ubyte count;
1392bf215546Sopenharmony_ci   struct pipe_scissor_state slot[0]; /* more will be allocated if needed */
1393bf215546Sopenharmony_ci};
1394bf215546Sopenharmony_ci
1395bf215546Sopenharmony_cistatic uint16_t
1396bf215546Sopenharmony_citc_call_set_window_rectangles(struct pipe_context *pipe, void *call, uint64_t *last)
1397bf215546Sopenharmony_ci{
1398bf215546Sopenharmony_ci   struct tc_window_rects *p = (struct tc_window_rects *)call;
1399bf215546Sopenharmony_ci
1400bf215546Sopenharmony_ci   pipe->set_window_rectangles(pipe, p->include, p->count, p->slot);
1401bf215546Sopenharmony_ci   return p->base.num_slots;
1402bf215546Sopenharmony_ci}
1403bf215546Sopenharmony_ci
1404bf215546Sopenharmony_cistatic void
1405bf215546Sopenharmony_citc_set_window_rectangles(struct pipe_context *_pipe, bool include,
1406bf215546Sopenharmony_ci                         unsigned count,
1407bf215546Sopenharmony_ci                         const struct pipe_scissor_state *rects)
1408bf215546Sopenharmony_ci{
1409bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
1410bf215546Sopenharmony_ci   struct tc_window_rects *p =
1411bf215546Sopenharmony_ci      tc_add_slot_based_call(tc, TC_CALL_set_window_rectangles, tc_window_rects, count);
1412bf215546Sopenharmony_ci
1413bf215546Sopenharmony_ci   p->include = include;
1414bf215546Sopenharmony_ci   p->count = count;
1415bf215546Sopenharmony_ci   memcpy(p->slot, rects, count * sizeof(rects[0]));
1416bf215546Sopenharmony_ci}
1417bf215546Sopenharmony_ci
1418bf215546Sopenharmony_cistruct tc_sampler_views {
1419bf215546Sopenharmony_ci   struct tc_call_base base;
1420bf215546Sopenharmony_ci   ubyte shader, start, count, unbind_num_trailing_slots;
1421bf215546Sopenharmony_ci   struct pipe_sampler_view *slot[0]; /* more will be allocated if needed */
1422bf215546Sopenharmony_ci};
1423bf215546Sopenharmony_ci
1424bf215546Sopenharmony_cistatic uint16_t
1425bf215546Sopenharmony_citc_call_set_sampler_views(struct pipe_context *pipe, void *call, uint64_t *last)
1426bf215546Sopenharmony_ci{
1427bf215546Sopenharmony_ci   struct tc_sampler_views *p = (struct tc_sampler_views *)call;
1428bf215546Sopenharmony_ci
1429bf215546Sopenharmony_ci   pipe->set_sampler_views(pipe, p->shader, p->start, p->count,
1430bf215546Sopenharmony_ci                           p->unbind_num_trailing_slots, true, p->slot);
1431bf215546Sopenharmony_ci   return p->base.num_slots;
1432bf215546Sopenharmony_ci}
1433bf215546Sopenharmony_ci
1434bf215546Sopenharmony_cistatic void
1435bf215546Sopenharmony_citc_set_sampler_views(struct pipe_context *_pipe,
1436bf215546Sopenharmony_ci                     enum pipe_shader_type shader,
1437bf215546Sopenharmony_ci                     unsigned start, unsigned count,
1438bf215546Sopenharmony_ci                     unsigned unbind_num_trailing_slots, bool take_ownership,
1439bf215546Sopenharmony_ci                     struct pipe_sampler_view **views)
1440bf215546Sopenharmony_ci{
1441bf215546Sopenharmony_ci   if (!count && !unbind_num_trailing_slots)
1442bf215546Sopenharmony_ci      return;
1443bf215546Sopenharmony_ci
1444bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
1445bf215546Sopenharmony_ci   struct tc_sampler_views *p =
1446bf215546Sopenharmony_ci      tc_add_slot_based_call(tc, TC_CALL_set_sampler_views, tc_sampler_views,
1447bf215546Sopenharmony_ci                             views ? count : 0);
1448bf215546Sopenharmony_ci
1449bf215546Sopenharmony_ci   p->shader = shader;
1450bf215546Sopenharmony_ci   p->start = start;
1451bf215546Sopenharmony_ci
1452bf215546Sopenharmony_ci   if (views) {
1453bf215546Sopenharmony_ci      struct tc_buffer_list *next = &tc->buffer_lists[tc->next_buf_list];
1454bf215546Sopenharmony_ci
1455bf215546Sopenharmony_ci      p->count = count;
1456bf215546Sopenharmony_ci      p->unbind_num_trailing_slots = unbind_num_trailing_slots;
1457bf215546Sopenharmony_ci
1458bf215546Sopenharmony_ci      if (take_ownership) {
1459bf215546Sopenharmony_ci         memcpy(p->slot, views, sizeof(*views) * count);
1460bf215546Sopenharmony_ci
1461bf215546Sopenharmony_ci         for (unsigned i = 0; i < count; i++) {
1462bf215546Sopenharmony_ci            if (views[i] && views[i]->target == PIPE_BUFFER) {
1463bf215546Sopenharmony_ci               tc_bind_buffer(tc, &tc->sampler_buffers[shader][start + i], next,
1464bf215546Sopenharmony_ci                              views[i]->texture);
1465bf215546Sopenharmony_ci            } else {
1466bf215546Sopenharmony_ci               tc_unbind_buffer(&tc->sampler_buffers[shader][start + i]);
1467bf215546Sopenharmony_ci            }
1468bf215546Sopenharmony_ci         }
1469bf215546Sopenharmony_ci      } else {
1470bf215546Sopenharmony_ci         for (unsigned i = 0; i < count; i++) {
1471bf215546Sopenharmony_ci            p->slot[i] = NULL;
1472bf215546Sopenharmony_ci            pipe_sampler_view_reference(&p->slot[i], views[i]);
1473bf215546Sopenharmony_ci
1474bf215546Sopenharmony_ci            if (views[i] && views[i]->target == PIPE_BUFFER) {
1475bf215546Sopenharmony_ci               tc_bind_buffer(tc, &tc->sampler_buffers[shader][start + i], next,
1476bf215546Sopenharmony_ci                              views[i]->texture);
1477bf215546Sopenharmony_ci            } else {
1478bf215546Sopenharmony_ci               tc_unbind_buffer(&tc->sampler_buffers[shader][start + i]);
1479bf215546Sopenharmony_ci            }
1480bf215546Sopenharmony_ci         }
1481bf215546Sopenharmony_ci      }
1482bf215546Sopenharmony_ci
1483bf215546Sopenharmony_ci      tc_unbind_buffers(&tc->sampler_buffers[shader][start + count],
1484bf215546Sopenharmony_ci                        unbind_num_trailing_slots);
1485bf215546Sopenharmony_ci      tc->seen_sampler_buffers[shader] = true;
1486bf215546Sopenharmony_ci   } else {
1487bf215546Sopenharmony_ci      p->count = 0;
1488bf215546Sopenharmony_ci      p->unbind_num_trailing_slots = count + unbind_num_trailing_slots;
1489bf215546Sopenharmony_ci
1490bf215546Sopenharmony_ci      tc_unbind_buffers(&tc->sampler_buffers[shader][start],
1491bf215546Sopenharmony_ci                        count + unbind_num_trailing_slots);
1492bf215546Sopenharmony_ci   }
1493bf215546Sopenharmony_ci}
1494bf215546Sopenharmony_ci
1495bf215546Sopenharmony_cistruct tc_shader_images {
1496bf215546Sopenharmony_ci   struct tc_call_base base;
1497bf215546Sopenharmony_ci   ubyte shader, start, count;
1498bf215546Sopenharmony_ci   ubyte unbind_num_trailing_slots;
1499bf215546Sopenharmony_ci   struct pipe_image_view slot[0]; /* more will be allocated if needed */
1500bf215546Sopenharmony_ci};
1501bf215546Sopenharmony_ci
1502bf215546Sopenharmony_cistatic uint16_t
1503bf215546Sopenharmony_citc_call_set_shader_images(struct pipe_context *pipe, void *call, uint64_t *last)
1504bf215546Sopenharmony_ci{
1505bf215546Sopenharmony_ci   struct tc_shader_images *p = (struct tc_shader_images *)call;
1506bf215546Sopenharmony_ci   unsigned count = p->count;
1507bf215546Sopenharmony_ci
1508bf215546Sopenharmony_ci   if (!p->count) {
1509bf215546Sopenharmony_ci      pipe->set_shader_images(pipe, p->shader, p->start, 0,
1510bf215546Sopenharmony_ci                              p->unbind_num_trailing_slots, NULL);
1511bf215546Sopenharmony_ci      return call_size(tc_shader_images);
1512bf215546Sopenharmony_ci   }
1513bf215546Sopenharmony_ci
1514bf215546Sopenharmony_ci   pipe->set_shader_images(pipe, p->shader, p->start, p->count,
1515bf215546Sopenharmony_ci                           p->unbind_num_trailing_slots, p->slot);
1516bf215546Sopenharmony_ci
1517bf215546Sopenharmony_ci   for (unsigned i = 0; i < count; i++)
1518bf215546Sopenharmony_ci      tc_drop_resource_reference(p->slot[i].resource);
1519bf215546Sopenharmony_ci
1520bf215546Sopenharmony_ci   return p->base.num_slots;
1521bf215546Sopenharmony_ci}
1522bf215546Sopenharmony_ci
1523bf215546Sopenharmony_cistatic void
1524bf215546Sopenharmony_citc_set_shader_images(struct pipe_context *_pipe,
1525bf215546Sopenharmony_ci                     enum pipe_shader_type shader,
1526bf215546Sopenharmony_ci                     unsigned start, unsigned count,
1527bf215546Sopenharmony_ci                     unsigned unbind_num_trailing_slots,
1528bf215546Sopenharmony_ci                     const struct pipe_image_view *images)
1529bf215546Sopenharmony_ci{
1530bf215546Sopenharmony_ci   if (!count && !unbind_num_trailing_slots)
1531bf215546Sopenharmony_ci      return;
1532bf215546Sopenharmony_ci
1533bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
1534bf215546Sopenharmony_ci   struct tc_shader_images *p =
1535bf215546Sopenharmony_ci      tc_add_slot_based_call(tc, TC_CALL_set_shader_images, tc_shader_images,
1536bf215546Sopenharmony_ci                             images ? count : 0);
1537bf215546Sopenharmony_ci   unsigned writable_buffers = 0;
1538bf215546Sopenharmony_ci
1539bf215546Sopenharmony_ci   p->shader = shader;
1540bf215546Sopenharmony_ci   p->start = start;
1541bf215546Sopenharmony_ci
1542bf215546Sopenharmony_ci   if (images) {
1543bf215546Sopenharmony_ci      p->count = count;
1544bf215546Sopenharmony_ci      p->unbind_num_trailing_slots = unbind_num_trailing_slots;
1545bf215546Sopenharmony_ci
1546bf215546Sopenharmony_ci      struct tc_buffer_list *next = &tc->buffer_lists[tc->next_buf_list];
1547bf215546Sopenharmony_ci
1548bf215546Sopenharmony_ci      for (unsigned i = 0; i < count; i++) {
1549bf215546Sopenharmony_ci         struct pipe_resource *resource = images[i].resource;
1550bf215546Sopenharmony_ci
1551bf215546Sopenharmony_ci         tc_set_resource_reference(&p->slot[i].resource, resource);
1552bf215546Sopenharmony_ci
1553bf215546Sopenharmony_ci         if (resource && resource->target == PIPE_BUFFER) {
1554bf215546Sopenharmony_ci            tc_bind_buffer(tc, &tc->image_buffers[shader][start + i], next, resource);
1555bf215546Sopenharmony_ci
1556bf215546Sopenharmony_ci            if (images[i].access & PIPE_IMAGE_ACCESS_WRITE) {
1557bf215546Sopenharmony_ci               struct threaded_resource *tres = threaded_resource(resource);
1558bf215546Sopenharmony_ci
1559bf215546Sopenharmony_ci               tc_buffer_disable_cpu_storage(resource);
1560bf215546Sopenharmony_ci               util_range_add(&tres->b, &tres->valid_buffer_range,
1561bf215546Sopenharmony_ci                              images[i].u.buf.offset,
1562bf215546Sopenharmony_ci                              images[i].u.buf.offset + images[i].u.buf.size);
1563bf215546Sopenharmony_ci               writable_buffers |= BITFIELD_BIT(start + i);
1564bf215546Sopenharmony_ci            }
1565bf215546Sopenharmony_ci         } else {
1566bf215546Sopenharmony_ci            tc_unbind_buffer(&tc->image_buffers[shader][start + i]);
1567bf215546Sopenharmony_ci         }
1568bf215546Sopenharmony_ci      }
1569bf215546Sopenharmony_ci      memcpy(p->slot, images, count * sizeof(images[0]));
1570bf215546Sopenharmony_ci
1571bf215546Sopenharmony_ci      tc_unbind_buffers(&tc->image_buffers[shader][start + count],
1572bf215546Sopenharmony_ci                        unbind_num_trailing_slots);
1573bf215546Sopenharmony_ci      tc->seen_image_buffers[shader] = true;
1574bf215546Sopenharmony_ci   } else {
1575bf215546Sopenharmony_ci      p->count = 0;
1576bf215546Sopenharmony_ci      p->unbind_num_trailing_slots = count + unbind_num_trailing_slots;
1577bf215546Sopenharmony_ci
1578bf215546Sopenharmony_ci      tc_unbind_buffers(&tc->image_buffers[shader][start],
1579bf215546Sopenharmony_ci                        count + unbind_num_trailing_slots);
1580bf215546Sopenharmony_ci   }
1581bf215546Sopenharmony_ci
1582bf215546Sopenharmony_ci   tc->image_buffers_writeable_mask[shader] &= ~BITFIELD_RANGE(start, count);
1583bf215546Sopenharmony_ci   tc->image_buffers_writeable_mask[shader] |= writable_buffers;
1584bf215546Sopenharmony_ci}
1585bf215546Sopenharmony_ci
1586bf215546Sopenharmony_cistruct tc_shader_buffers {
1587bf215546Sopenharmony_ci   struct tc_call_base base;
1588bf215546Sopenharmony_ci   ubyte shader, start, count;
1589bf215546Sopenharmony_ci   bool unbind;
1590bf215546Sopenharmony_ci   unsigned writable_bitmask;
1591bf215546Sopenharmony_ci   struct pipe_shader_buffer slot[0]; /* more will be allocated if needed */
1592bf215546Sopenharmony_ci};
1593bf215546Sopenharmony_ci
1594bf215546Sopenharmony_cistatic uint16_t
1595bf215546Sopenharmony_citc_call_set_shader_buffers(struct pipe_context *pipe, void *call, uint64_t *last)
1596bf215546Sopenharmony_ci{
1597bf215546Sopenharmony_ci   struct tc_shader_buffers *p = (struct tc_shader_buffers *)call;
1598bf215546Sopenharmony_ci   unsigned count = p->count;
1599bf215546Sopenharmony_ci
1600bf215546Sopenharmony_ci   if (p->unbind) {
1601bf215546Sopenharmony_ci      pipe->set_shader_buffers(pipe, p->shader, p->start, p->count, NULL, 0);
1602bf215546Sopenharmony_ci      return call_size(tc_shader_buffers);
1603bf215546Sopenharmony_ci   }
1604bf215546Sopenharmony_ci
1605bf215546Sopenharmony_ci   pipe->set_shader_buffers(pipe, p->shader, p->start, p->count, p->slot,
1606bf215546Sopenharmony_ci                            p->writable_bitmask);
1607bf215546Sopenharmony_ci
1608bf215546Sopenharmony_ci   for (unsigned i = 0; i < count; i++)
1609bf215546Sopenharmony_ci      tc_drop_resource_reference(p->slot[i].buffer);
1610bf215546Sopenharmony_ci
1611bf215546Sopenharmony_ci   return p->base.num_slots;
1612bf215546Sopenharmony_ci}
1613bf215546Sopenharmony_ci
1614bf215546Sopenharmony_cistatic void
1615bf215546Sopenharmony_citc_set_shader_buffers(struct pipe_context *_pipe,
1616bf215546Sopenharmony_ci                      enum pipe_shader_type shader,
1617bf215546Sopenharmony_ci                      unsigned start, unsigned count,
1618bf215546Sopenharmony_ci                      const struct pipe_shader_buffer *buffers,
1619bf215546Sopenharmony_ci                      unsigned writable_bitmask)
1620bf215546Sopenharmony_ci{
1621bf215546Sopenharmony_ci   if (!count)
1622bf215546Sopenharmony_ci      return;
1623bf215546Sopenharmony_ci
1624bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
1625bf215546Sopenharmony_ci   struct tc_shader_buffers *p =
1626bf215546Sopenharmony_ci      tc_add_slot_based_call(tc, TC_CALL_set_shader_buffers, tc_shader_buffers,
1627bf215546Sopenharmony_ci                             buffers ? count : 0);
1628bf215546Sopenharmony_ci
1629bf215546Sopenharmony_ci   p->shader = shader;
1630bf215546Sopenharmony_ci   p->start = start;
1631bf215546Sopenharmony_ci   p->count = count;
1632bf215546Sopenharmony_ci   p->unbind = buffers == NULL;
1633bf215546Sopenharmony_ci   p->writable_bitmask = writable_bitmask;
1634bf215546Sopenharmony_ci
1635bf215546Sopenharmony_ci   if (buffers) {
1636bf215546Sopenharmony_ci      struct tc_buffer_list *next = &tc->buffer_lists[tc->next_buf_list];
1637bf215546Sopenharmony_ci
1638bf215546Sopenharmony_ci      for (unsigned i = 0; i < count; i++) {
1639bf215546Sopenharmony_ci         struct pipe_shader_buffer *dst = &p->slot[i];
1640bf215546Sopenharmony_ci         const struct pipe_shader_buffer *src = buffers + i;
1641bf215546Sopenharmony_ci
1642bf215546Sopenharmony_ci         tc_set_resource_reference(&dst->buffer, src->buffer);
1643bf215546Sopenharmony_ci         dst->buffer_offset = src->buffer_offset;
1644bf215546Sopenharmony_ci         dst->buffer_size = src->buffer_size;
1645bf215546Sopenharmony_ci
1646bf215546Sopenharmony_ci         if (src->buffer) {
1647bf215546Sopenharmony_ci            struct threaded_resource *tres = threaded_resource(src->buffer);
1648bf215546Sopenharmony_ci
1649bf215546Sopenharmony_ci            tc_bind_buffer(tc, &tc->shader_buffers[shader][start + i], next, &tres->b);
1650bf215546Sopenharmony_ci
1651bf215546Sopenharmony_ci            if (writable_bitmask & BITFIELD_BIT(i)) {
1652bf215546Sopenharmony_ci               tc_buffer_disable_cpu_storage(src->buffer);
1653bf215546Sopenharmony_ci               util_range_add(&tres->b, &tres->valid_buffer_range,
1654bf215546Sopenharmony_ci                              src->buffer_offset,
1655bf215546Sopenharmony_ci                              src->buffer_offset + src->buffer_size);
1656bf215546Sopenharmony_ci            }
1657bf215546Sopenharmony_ci         } else {
1658bf215546Sopenharmony_ci            tc_unbind_buffer(&tc->shader_buffers[shader][start + i]);
1659bf215546Sopenharmony_ci         }
1660bf215546Sopenharmony_ci      }
1661bf215546Sopenharmony_ci      tc->seen_shader_buffers[shader] = true;
1662bf215546Sopenharmony_ci   } else {
1663bf215546Sopenharmony_ci      tc_unbind_buffers(&tc->shader_buffers[shader][start], count);
1664bf215546Sopenharmony_ci   }
1665bf215546Sopenharmony_ci
1666bf215546Sopenharmony_ci   tc->shader_buffers_writeable_mask[shader] &= ~BITFIELD_RANGE(start, count);
1667bf215546Sopenharmony_ci   tc->shader_buffers_writeable_mask[shader] |= writable_bitmask << start;
1668bf215546Sopenharmony_ci}
1669bf215546Sopenharmony_ci
1670bf215546Sopenharmony_cistruct tc_vertex_buffers {
1671bf215546Sopenharmony_ci   struct tc_call_base base;
1672bf215546Sopenharmony_ci   ubyte start, count;
1673bf215546Sopenharmony_ci   ubyte unbind_num_trailing_slots;
1674bf215546Sopenharmony_ci   struct pipe_vertex_buffer slot[0]; /* more will be allocated if needed */
1675bf215546Sopenharmony_ci};
1676bf215546Sopenharmony_ci
1677bf215546Sopenharmony_cistatic uint16_t
1678bf215546Sopenharmony_citc_call_set_vertex_buffers(struct pipe_context *pipe, void *call, uint64_t *last)
1679bf215546Sopenharmony_ci{
1680bf215546Sopenharmony_ci   struct tc_vertex_buffers *p = (struct tc_vertex_buffers *)call;
1681bf215546Sopenharmony_ci   unsigned count = p->count;
1682bf215546Sopenharmony_ci
1683bf215546Sopenharmony_ci   if (!count) {
1684bf215546Sopenharmony_ci      pipe->set_vertex_buffers(pipe, p->start, 0,
1685bf215546Sopenharmony_ci                               p->unbind_num_trailing_slots, false, NULL);
1686bf215546Sopenharmony_ci      return call_size(tc_vertex_buffers);
1687bf215546Sopenharmony_ci   }
1688bf215546Sopenharmony_ci
1689bf215546Sopenharmony_ci   for (unsigned i = 0; i < count; i++)
1690bf215546Sopenharmony_ci      tc_assert(!p->slot[i].is_user_buffer);
1691bf215546Sopenharmony_ci
1692bf215546Sopenharmony_ci   pipe->set_vertex_buffers(pipe, p->start, count,
1693bf215546Sopenharmony_ci                            p->unbind_num_trailing_slots, true, p->slot);
1694bf215546Sopenharmony_ci   return p->base.num_slots;
1695bf215546Sopenharmony_ci}
1696bf215546Sopenharmony_ci
1697bf215546Sopenharmony_cistatic void
1698bf215546Sopenharmony_citc_set_vertex_buffers(struct pipe_context *_pipe,
1699bf215546Sopenharmony_ci                      unsigned start, unsigned count,
1700bf215546Sopenharmony_ci                      unsigned unbind_num_trailing_slots,
1701bf215546Sopenharmony_ci                      bool take_ownership,
1702bf215546Sopenharmony_ci                      const struct pipe_vertex_buffer *buffers)
1703bf215546Sopenharmony_ci{
1704bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
1705bf215546Sopenharmony_ci
1706bf215546Sopenharmony_ci   if (!count && !unbind_num_trailing_slots)
1707bf215546Sopenharmony_ci      return;
1708bf215546Sopenharmony_ci
1709bf215546Sopenharmony_ci   if (count && buffers) {
1710bf215546Sopenharmony_ci      struct tc_vertex_buffers *p =
1711bf215546Sopenharmony_ci         tc_add_slot_based_call(tc, TC_CALL_set_vertex_buffers, tc_vertex_buffers, count);
1712bf215546Sopenharmony_ci      p->start = start;
1713bf215546Sopenharmony_ci      p->count = count;
1714bf215546Sopenharmony_ci      p->unbind_num_trailing_slots = unbind_num_trailing_slots;
1715bf215546Sopenharmony_ci
1716bf215546Sopenharmony_ci      struct tc_buffer_list *next = &tc->buffer_lists[tc->next_buf_list];
1717bf215546Sopenharmony_ci
1718bf215546Sopenharmony_ci      if (take_ownership) {
1719bf215546Sopenharmony_ci         memcpy(p->slot, buffers, count * sizeof(struct pipe_vertex_buffer));
1720bf215546Sopenharmony_ci
1721bf215546Sopenharmony_ci         for (unsigned i = 0; i < count; i++) {
1722bf215546Sopenharmony_ci            struct pipe_resource *buf = buffers[i].buffer.resource;
1723bf215546Sopenharmony_ci
1724bf215546Sopenharmony_ci            if (buf) {
1725bf215546Sopenharmony_ci               tc_bind_buffer(tc, &tc->vertex_buffers[start + i], next, buf);
1726bf215546Sopenharmony_ci            } else {
1727bf215546Sopenharmony_ci               tc_unbind_buffer(&tc->vertex_buffers[start + i]);
1728bf215546Sopenharmony_ci            }
1729bf215546Sopenharmony_ci         }
1730bf215546Sopenharmony_ci      } else {
1731bf215546Sopenharmony_ci         for (unsigned i = 0; i < count; i++) {
1732bf215546Sopenharmony_ci            struct pipe_vertex_buffer *dst = &p->slot[i];
1733bf215546Sopenharmony_ci            const struct pipe_vertex_buffer *src = buffers + i;
1734bf215546Sopenharmony_ci            struct pipe_resource *buf = src->buffer.resource;
1735bf215546Sopenharmony_ci
1736bf215546Sopenharmony_ci            tc_assert(!src->is_user_buffer);
1737bf215546Sopenharmony_ci            dst->stride = src->stride;
1738bf215546Sopenharmony_ci            dst->is_user_buffer = false;
1739bf215546Sopenharmony_ci            tc_set_resource_reference(&dst->buffer.resource, buf);
1740bf215546Sopenharmony_ci            dst->buffer_offset = src->buffer_offset;
1741bf215546Sopenharmony_ci
1742bf215546Sopenharmony_ci            if (buf) {
1743bf215546Sopenharmony_ci               tc_bind_buffer(tc, &tc->vertex_buffers[start + i], next, buf);
1744bf215546Sopenharmony_ci            } else {
1745bf215546Sopenharmony_ci               tc_unbind_buffer(&tc->vertex_buffers[start + i]);
1746bf215546Sopenharmony_ci            }
1747bf215546Sopenharmony_ci         }
1748bf215546Sopenharmony_ci      }
1749bf215546Sopenharmony_ci
1750bf215546Sopenharmony_ci      tc_unbind_buffers(&tc->vertex_buffers[start + count],
1751bf215546Sopenharmony_ci                        unbind_num_trailing_slots);
1752bf215546Sopenharmony_ci   } else {
1753bf215546Sopenharmony_ci      struct tc_vertex_buffers *p =
1754bf215546Sopenharmony_ci         tc_add_slot_based_call(tc, TC_CALL_set_vertex_buffers, tc_vertex_buffers, 0);
1755bf215546Sopenharmony_ci      p->start = start;
1756bf215546Sopenharmony_ci      p->count = 0;
1757bf215546Sopenharmony_ci      p->unbind_num_trailing_slots = count + unbind_num_trailing_slots;
1758bf215546Sopenharmony_ci
1759bf215546Sopenharmony_ci      tc_unbind_buffers(&tc->vertex_buffers[start],
1760bf215546Sopenharmony_ci                        count + unbind_num_trailing_slots);
1761bf215546Sopenharmony_ci   }
1762bf215546Sopenharmony_ci}
1763bf215546Sopenharmony_ci
1764bf215546Sopenharmony_cistruct tc_stream_outputs {
1765bf215546Sopenharmony_ci   struct tc_call_base base;
1766bf215546Sopenharmony_ci   unsigned count;
1767bf215546Sopenharmony_ci   struct pipe_stream_output_target *targets[PIPE_MAX_SO_BUFFERS];
1768bf215546Sopenharmony_ci   unsigned offsets[PIPE_MAX_SO_BUFFERS];
1769bf215546Sopenharmony_ci};
1770bf215546Sopenharmony_ci
1771bf215546Sopenharmony_cistatic uint16_t
1772bf215546Sopenharmony_citc_call_set_stream_output_targets(struct pipe_context *pipe, void *call, uint64_t *last)
1773bf215546Sopenharmony_ci{
1774bf215546Sopenharmony_ci   struct tc_stream_outputs *p = to_call(call, tc_stream_outputs);
1775bf215546Sopenharmony_ci   unsigned count = p->count;
1776bf215546Sopenharmony_ci
1777bf215546Sopenharmony_ci   pipe->set_stream_output_targets(pipe, count, p->targets, p->offsets);
1778bf215546Sopenharmony_ci   for (unsigned i = 0; i < count; i++)
1779bf215546Sopenharmony_ci      tc_drop_so_target_reference(p->targets[i]);
1780bf215546Sopenharmony_ci
1781bf215546Sopenharmony_ci   return call_size(tc_stream_outputs);
1782bf215546Sopenharmony_ci}
1783bf215546Sopenharmony_ci
1784bf215546Sopenharmony_cistatic void
1785bf215546Sopenharmony_citc_set_stream_output_targets(struct pipe_context *_pipe,
1786bf215546Sopenharmony_ci                             unsigned count,
1787bf215546Sopenharmony_ci                             struct pipe_stream_output_target **tgs,
1788bf215546Sopenharmony_ci                             const unsigned *offsets)
1789bf215546Sopenharmony_ci{
1790bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
1791bf215546Sopenharmony_ci   struct tc_stream_outputs *p =
1792bf215546Sopenharmony_ci      tc_add_call(tc, TC_CALL_set_stream_output_targets, tc_stream_outputs);
1793bf215546Sopenharmony_ci   struct tc_buffer_list *next = &tc->buffer_lists[tc->next_buf_list];
1794bf215546Sopenharmony_ci
1795bf215546Sopenharmony_ci   for (unsigned i = 0; i < count; i++) {
1796bf215546Sopenharmony_ci      p->targets[i] = NULL;
1797bf215546Sopenharmony_ci      pipe_so_target_reference(&p->targets[i], tgs[i]);
1798bf215546Sopenharmony_ci      if (tgs[i]) {
1799bf215546Sopenharmony_ci         tc_buffer_disable_cpu_storage(tgs[i]->buffer);
1800bf215546Sopenharmony_ci         tc_bind_buffer(tc, &tc->streamout_buffers[i], next, tgs[i]->buffer);
1801bf215546Sopenharmony_ci      } else {
1802bf215546Sopenharmony_ci         tc_unbind_buffer(&tc->streamout_buffers[i]);
1803bf215546Sopenharmony_ci      }
1804bf215546Sopenharmony_ci   }
1805bf215546Sopenharmony_ci   p->count = count;
1806bf215546Sopenharmony_ci   memcpy(p->offsets, offsets, count * sizeof(unsigned));
1807bf215546Sopenharmony_ci
1808bf215546Sopenharmony_ci   tc_unbind_buffers(&tc->streamout_buffers[count], PIPE_MAX_SO_BUFFERS - count);
1809bf215546Sopenharmony_ci   if (count)
1810bf215546Sopenharmony_ci      tc->seen_streamout_buffers = true;
1811bf215546Sopenharmony_ci}
1812bf215546Sopenharmony_ci
1813bf215546Sopenharmony_cistatic void
1814bf215546Sopenharmony_citc_set_compute_resources(struct pipe_context *_pipe, unsigned start,
1815bf215546Sopenharmony_ci                         unsigned count, struct pipe_surface **resources)
1816bf215546Sopenharmony_ci{
1817bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
1818bf215546Sopenharmony_ci   struct pipe_context *pipe = tc->pipe;
1819bf215546Sopenharmony_ci
1820bf215546Sopenharmony_ci   tc_sync(tc);
1821bf215546Sopenharmony_ci   pipe->set_compute_resources(pipe, start, count, resources);
1822bf215546Sopenharmony_ci}
1823bf215546Sopenharmony_ci
1824bf215546Sopenharmony_cistatic void
1825bf215546Sopenharmony_citc_set_global_binding(struct pipe_context *_pipe, unsigned first,
1826bf215546Sopenharmony_ci                      unsigned count, struct pipe_resource **resources,
1827bf215546Sopenharmony_ci                      uint32_t **handles)
1828bf215546Sopenharmony_ci{
1829bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
1830bf215546Sopenharmony_ci   struct pipe_context *pipe = tc->pipe;
1831bf215546Sopenharmony_ci
1832bf215546Sopenharmony_ci   tc_sync(tc);
1833bf215546Sopenharmony_ci   pipe->set_global_binding(pipe, first, count, resources, handles);
1834bf215546Sopenharmony_ci}
1835bf215546Sopenharmony_ci
1836bf215546Sopenharmony_ci
1837bf215546Sopenharmony_ci/********************************************************************
1838bf215546Sopenharmony_ci * views
1839bf215546Sopenharmony_ci */
1840bf215546Sopenharmony_ci
1841bf215546Sopenharmony_cistatic struct pipe_surface *
1842bf215546Sopenharmony_citc_create_surface(struct pipe_context *_pipe,
1843bf215546Sopenharmony_ci                  struct pipe_resource *resource,
1844bf215546Sopenharmony_ci                  const struct pipe_surface *surf_tmpl)
1845bf215546Sopenharmony_ci{
1846bf215546Sopenharmony_ci   struct pipe_context *pipe = threaded_context(_pipe)->pipe;
1847bf215546Sopenharmony_ci   struct pipe_surface *view =
1848bf215546Sopenharmony_ci         pipe->create_surface(pipe, resource, surf_tmpl);
1849bf215546Sopenharmony_ci
1850bf215546Sopenharmony_ci   if (view)
1851bf215546Sopenharmony_ci      view->context = _pipe;
1852bf215546Sopenharmony_ci   return view;
1853bf215546Sopenharmony_ci}
1854bf215546Sopenharmony_ci
1855bf215546Sopenharmony_cistatic void
1856bf215546Sopenharmony_citc_surface_destroy(struct pipe_context *_pipe,
1857bf215546Sopenharmony_ci                   struct pipe_surface *surf)
1858bf215546Sopenharmony_ci{
1859bf215546Sopenharmony_ci   struct pipe_context *pipe = threaded_context(_pipe)->pipe;
1860bf215546Sopenharmony_ci
1861bf215546Sopenharmony_ci   pipe->surface_destroy(pipe, surf);
1862bf215546Sopenharmony_ci}
1863bf215546Sopenharmony_ci
1864bf215546Sopenharmony_cistatic struct pipe_sampler_view *
1865bf215546Sopenharmony_citc_create_sampler_view(struct pipe_context *_pipe,
1866bf215546Sopenharmony_ci                       struct pipe_resource *resource,
1867bf215546Sopenharmony_ci                       const struct pipe_sampler_view *templ)
1868bf215546Sopenharmony_ci{
1869bf215546Sopenharmony_ci   struct pipe_context *pipe = threaded_context(_pipe)->pipe;
1870bf215546Sopenharmony_ci   struct pipe_sampler_view *view =
1871bf215546Sopenharmony_ci         pipe->create_sampler_view(pipe, resource, templ);
1872bf215546Sopenharmony_ci
1873bf215546Sopenharmony_ci   if (view)
1874bf215546Sopenharmony_ci      view->context = _pipe;
1875bf215546Sopenharmony_ci   return view;
1876bf215546Sopenharmony_ci}
1877bf215546Sopenharmony_ci
1878bf215546Sopenharmony_cistatic void
1879bf215546Sopenharmony_citc_sampler_view_destroy(struct pipe_context *_pipe,
1880bf215546Sopenharmony_ci                        struct pipe_sampler_view *view)
1881bf215546Sopenharmony_ci{
1882bf215546Sopenharmony_ci   struct pipe_context *pipe = threaded_context(_pipe)->pipe;
1883bf215546Sopenharmony_ci
1884bf215546Sopenharmony_ci   pipe->sampler_view_destroy(pipe, view);
1885bf215546Sopenharmony_ci}
1886bf215546Sopenharmony_ci
1887bf215546Sopenharmony_cistatic struct pipe_stream_output_target *
1888bf215546Sopenharmony_citc_create_stream_output_target(struct pipe_context *_pipe,
1889bf215546Sopenharmony_ci                               struct pipe_resource *res,
1890bf215546Sopenharmony_ci                               unsigned buffer_offset,
1891bf215546Sopenharmony_ci                               unsigned buffer_size)
1892bf215546Sopenharmony_ci{
1893bf215546Sopenharmony_ci   struct pipe_context *pipe = threaded_context(_pipe)->pipe;
1894bf215546Sopenharmony_ci   struct threaded_resource *tres = threaded_resource(res);
1895bf215546Sopenharmony_ci   struct pipe_stream_output_target *view;
1896bf215546Sopenharmony_ci
1897bf215546Sopenharmony_ci   util_range_add(&tres->b, &tres->valid_buffer_range, buffer_offset,
1898bf215546Sopenharmony_ci                  buffer_offset + buffer_size);
1899bf215546Sopenharmony_ci
1900bf215546Sopenharmony_ci   view = pipe->create_stream_output_target(pipe, res, buffer_offset,
1901bf215546Sopenharmony_ci                                            buffer_size);
1902bf215546Sopenharmony_ci   if (view)
1903bf215546Sopenharmony_ci      view->context = _pipe;
1904bf215546Sopenharmony_ci   return view;
1905bf215546Sopenharmony_ci}
1906bf215546Sopenharmony_ci
1907bf215546Sopenharmony_cistatic void
1908bf215546Sopenharmony_citc_stream_output_target_destroy(struct pipe_context *_pipe,
1909bf215546Sopenharmony_ci                                struct pipe_stream_output_target *target)
1910bf215546Sopenharmony_ci{
1911bf215546Sopenharmony_ci   struct pipe_context *pipe = threaded_context(_pipe)->pipe;
1912bf215546Sopenharmony_ci
1913bf215546Sopenharmony_ci   pipe->stream_output_target_destroy(pipe, target);
1914bf215546Sopenharmony_ci}
1915bf215546Sopenharmony_ci
1916bf215546Sopenharmony_ci
1917bf215546Sopenharmony_ci/********************************************************************
1918bf215546Sopenharmony_ci * bindless
1919bf215546Sopenharmony_ci */
1920bf215546Sopenharmony_ci
1921bf215546Sopenharmony_cistatic uint64_t
1922bf215546Sopenharmony_citc_create_texture_handle(struct pipe_context *_pipe,
1923bf215546Sopenharmony_ci                         struct pipe_sampler_view *view,
1924bf215546Sopenharmony_ci                         const struct pipe_sampler_state *state)
1925bf215546Sopenharmony_ci{
1926bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
1927bf215546Sopenharmony_ci   struct pipe_context *pipe = tc->pipe;
1928bf215546Sopenharmony_ci
1929bf215546Sopenharmony_ci   tc_sync(tc);
1930bf215546Sopenharmony_ci   return pipe->create_texture_handle(pipe, view, state);
1931bf215546Sopenharmony_ci}
1932bf215546Sopenharmony_ci
1933bf215546Sopenharmony_cistruct tc_make_texture_handle_resident {
1934bf215546Sopenharmony_ci   struct tc_call_base base;
1935bf215546Sopenharmony_ci   bool resident;
1936bf215546Sopenharmony_ci   uint64_t handle;
1937bf215546Sopenharmony_ci};
1938bf215546Sopenharmony_ci
1939bf215546Sopenharmony_cistatic uint16_t
1940bf215546Sopenharmony_citc_call_make_texture_handle_resident(struct pipe_context *pipe, void *call, uint64_t *last)
1941bf215546Sopenharmony_ci{
1942bf215546Sopenharmony_ci   struct tc_make_texture_handle_resident *p =
1943bf215546Sopenharmony_ci      to_call(call, tc_make_texture_handle_resident);
1944bf215546Sopenharmony_ci
1945bf215546Sopenharmony_ci   pipe->make_texture_handle_resident(pipe, p->handle, p->resident);
1946bf215546Sopenharmony_ci   return call_size(tc_make_texture_handle_resident);
1947bf215546Sopenharmony_ci}
1948bf215546Sopenharmony_ci
1949bf215546Sopenharmony_cistatic void
1950bf215546Sopenharmony_citc_make_texture_handle_resident(struct pipe_context *_pipe, uint64_t handle,
1951bf215546Sopenharmony_ci                                bool resident)
1952bf215546Sopenharmony_ci{
1953bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
1954bf215546Sopenharmony_ci   struct tc_make_texture_handle_resident *p =
1955bf215546Sopenharmony_ci      tc_add_call(tc, TC_CALL_make_texture_handle_resident,
1956bf215546Sopenharmony_ci                  tc_make_texture_handle_resident);
1957bf215546Sopenharmony_ci
1958bf215546Sopenharmony_ci   p->handle = handle;
1959bf215546Sopenharmony_ci   p->resident = resident;
1960bf215546Sopenharmony_ci}
1961bf215546Sopenharmony_ci
1962bf215546Sopenharmony_cistatic uint64_t
1963bf215546Sopenharmony_citc_create_image_handle(struct pipe_context *_pipe,
1964bf215546Sopenharmony_ci                       const struct pipe_image_view *image)
1965bf215546Sopenharmony_ci{
1966bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
1967bf215546Sopenharmony_ci   struct pipe_context *pipe = tc->pipe;
1968bf215546Sopenharmony_ci
1969bf215546Sopenharmony_ci   if (image->resource->target == PIPE_BUFFER)
1970bf215546Sopenharmony_ci      tc_buffer_disable_cpu_storage(image->resource);
1971bf215546Sopenharmony_ci
1972bf215546Sopenharmony_ci   tc_sync(tc);
1973bf215546Sopenharmony_ci   return pipe->create_image_handle(pipe, image);
1974bf215546Sopenharmony_ci}
1975bf215546Sopenharmony_ci
1976bf215546Sopenharmony_cistruct tc_make_image_handle_resident {
1977bf215546Sopenharmony_ci   struct tc_call_base base;
1978bf215546Sopenharmony_ci   bool resident;
1979bf215546Sopenharmony_ci   unsigned access;
1980bf215546Sopenharmony_ci   uint64_t handle;
1981bf215546Sopenharmony_ci};
1982bf215546Sopenharmony_ci
1983bf215546Sopenharmony_cistatic uint16_t
1984bf215546Sopenharmony_citc_call_make_image_handle_resident(struct pipe_context *pipe, void *call, uint64_t *last)
1985bf215546Sopenharmony_ci{
1986bf215546Sopenharmony_ci   struct tc_make_image_handle_resident *p =
1987bf215546Sopenharmony_ci      to_call(call, tc_make_image_handle_resident);
1988bf215546Sopenharmony_ci
1989bf215546Sopenharmony_ci   pipe->make_image_handle_resident(pipe, p->handle, p->access, p->resident);
1990bf215546Sopenharmony_ci   return call_size(tc_make_image_handle_resident);
1991bf215546Sopenharmony_ci}
1992bf215546Sopenharmony_ci
1993bf215546Sopenharmony_cistatic void
1994bf215546Sopenharmony_citc_make_image_handle_resident(struct pipe_context *_pipe, uint64_t handle,
1995bf215546Sopenharmony_ci                              unsigned access, bool resident)
1996bf215546Sopenharmony_ci{
1997bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
1998bf215546Sopenharmony_ci   struct tc_make_image_handle_resident *p =
1999bf215546Sopenharmony_ci      tc_add_call(tc, TC_CALL_make_image_handle_resident,
2000bf215546Sopenharmony_ci                  tc_make_image_handle_resident);
2001bf215546Sopenharmony_ci
2002bf215546Sopenharmony_ci   p->handle = handle;
2003bf215546Sopenharmony_ci   p->access = access;
2004bf215546Sopenharmony_ci   p->resident = resident;
2005bf215546Sopenharmony_ci}
2006bf215546Sopenharmony_ci
2007bf215546Sopenharmony_ci
2008bf215546Sopenharmony_ci/********************************************************************
2009bf215546Sopenharmony_ci * transfer
2010bf215546Sopenharmony_ci */
2011bf215546Sopenharmony_ci
2012bf215546Sopenharmony_cistruct tc_replace_buffer_storage {
2013bf215546Sopenharmony_ci   struct tc_call_base base;
2014bf215546Sopenharmony_ci   uint16_t num_rebinds;
2015bf215546Sopenharmony_ci   uint32_t rebind_mask;
2016bf215546Sopenharmony_ci   uint32_t delete_buffer_id;
2017bf215546Sopenharmony_ci   struct pipe_resource *dst;
2018bf215546Sopenharmony_ci   struct pipe_resource *src;
2019bf215546Sopenharmony_ci   tc_replace_buffer_storage_func func;
2020bf215546Sopenharmony_ci};
2021bf215546Sopenharmony_ci
2022bf215546Sopenharmony_cistatic uint16_t
2023bf215546Sopenharmony_citc_call_replace_buffer_storage(struct pipe_context *pipe, void *call, uint64_t *last)
2024bf215546Sopenharmony_ci{
2025bf215546Sopenharmony_ci   struct tc_replace_buffer_storage *p = to_call(call, tc_replace_buffer_storage);
2026bf215546Sopenharmony_ci
2027bf215546Sopenharmony_ci   p->func(pipe, p->dst, p->src, p->num_rebinds, p->rebind_mask, p->delete_buffer_id);
2028bf215546Sopenharmony_ci
2029bf215546Sopenharmony_ci   tc_drop_resource_reference(p->dst);
2030bf215546Sopenharmony_ci   tc_drop_resource_reference(p->src);
2031bf215546Sopenharmony_ci   return call_size(tc_replace_buffer_storage);
2032bf215546Sopenharmony_ci}
2033bf215546Sopenharmony_ci
2034bf215546Sopenharmony_ci/* Return true if the buffer has been invalidated or is idle.
2035bf215546Sopenharmony_ci * Note that callers must've called tc_touch_buffer before calling
2036bf215546Sopenharmony_ci * this function. */
2037bf215546Sopenharmony_cistatic bool
2038bf215546Sopenharmony_citc_invalidate_buffer(struct threaded_context *tc,
2039bf215546Sopenharmony_ci                     struct threaded_resource *tbuf)
2040bf215546Sopenharmony_ci{
2041bf215546Sopenharmony_ci   if (!tc_is_buffer_busy(tc, tbuf, PIPE_MAP_READ_WRITE)) {
2042bf215546Sopenharmony_ci      /* It's idle, so invalidation would be a no-op, but we can still clear
2043bf215546Sopenharmony_ci       * the valid range because we are technically doing invalidation, but
2044bf215546Sopenharmony_ci       * skipping it because it's useless.
2045bf215546Sopenharmony_ci       *
2046bf215546Sopenharmony_ci       * If the buffer is bound for write, we can't invalidate the range.
2047bf215546Sopenharmony_ci       */
2048bf215546Sopenharmony_ci      if (!tc_is_buffer_bound_for_write(tc, tbuf->buffer_id_unique))
2049bf215546Sopenharmony_ci         util_range_set_empty(&tbuf->valid_buffer_range);
2050bf215546Sopenharmony_ci      return true;
2051bf215546Sopenharmony_ci   }
2052bf215546Sopenharmony_ci
2053bf215546Sopenharmony_ci   struct pipe_screen *screen = tc->base.screen;
2054bf215546Sopenharmony_ci   struct pipe_resource *new_buf;
2055bf215546Sopenharmony_ci
2056bf215546Sopenharmony_ci   /* Shared, pinned, and sparse buffers can't be reallocated. */
2057bf215546Sopenharmony_ci   if (tc_is_buffer_shared(tbuf) ||
2058bf215546Sopenharmony_ci       tbuf->is_user_ptr ||
2059bf215546Sopenharmony_ci       tbuf->b.flags & (PIPE_RESOURCE_FLAG_SPARSE | PIPE_RESOURCE_FLAG_UNMAPPABLE))
2060bf215546Sopenharmony_ci      return false;
2061bf215546Sopenharmony_ci
2062bf215546Sopenharmony_ci   /* Allocate a new one. */
2063bf215546Sopenharmony_ci   new_buf = screen->resource_create(screen, &tbuf->b);
2064bf215546Sopenharmony_ci   if (!new_buf)
2065bf215546Sopenharmony_ci      return false;
2066bf215546Sopenharmony_ci
2067bf215546Sopenharmony_ci   /* Replace the "latest" pointer. */
2068bf215546Sopenharmony_ci   if (tbuf->latest != &tbuf->b)
2069bf215546Sopenharmony_ci      pipe_resource_reference(&tbuf->latest, NULL);
2070bf215546Sopenharmony_ci
2071bf215546Sopenharmony_ci   tbuf->latest = new_buf;
2072bf215546Sopenharmony_ci
2073bf215546Sopenharmony_ci   uint32_t delete_buffer_id = tbuf->buffer_id_unique;
2074bf215546Sopenharmony_ci
2075bf215546Sopenharmony_ci   /* Enqueue storage replacement of the original buffer. */
2076bf215546Sopenharmony_ci   struct tc_replace_buffer_storage *p =
2077bf215546Sopenharmony_ci      tc_add_call(tc, TC_CALL_replace_buffer_storage,
2078bf215546Sopenharmony_ci                  tc_replace_buffer_storage);
2079bf215546Sopenharmony_ci
2080bf215546Sopenharmony_ci   p->func = tc->replace_buffer_storage;
2081bf215546Sopenharmony_ci   tc_set_resource_reference(&p->dst, &tbuf->b);
2082bf215546Sopenharmony_ci   tc_set_resource_reference(&p->src, new_buf);
2083bf215546Sopenharmony_ci   p->delete_buffer_id = delete_buffer_id;
2084bf215546Sopenharmony_ci   p->rebind_mask = 0;
2085bf215546Sopenharmony_ci
2086bf215546Sopenharmony_ci   /* Treat the current buffer as the new buffer. */
2087bf215546Sopenharmony_ci   bool bound_for_write = tc_is_buffer_bound_for_write(tc, tbuf->buffer_id_unique);
2088bf215546Sopenharmony_ci   p->num_rebinds = tc_rebind_buffer(tc, tbuf->buffer_id_unique,
2089bf215546Sopenharmony_ci                                     threaded_resource(new_buf)->buffer_id_unique,
2090bf215546Sopenharmony_ci                                     &p->rebind_mask);
2091bf215546Sopenharmony_ci
2092bf215546Sopenharmony_ci   /* If the buffer is not bound for write, clear the valid range. */
2093bf215546Sopenharmony_ci   if (!bound_for_write)
2094bf215546Sopenharmony_ci      util_range_set_empty(&tbuf->valid_buffer_range);
2095bf215546Sopenharmony_ci
2096bf215546Sopenharmony_ci   tbuf->buffer_id_unique = threaded_resource(new_buf)->buffer_id_unique;
2097bf215546Sopenharmony_ci   threaded_resource(new_buf)->buffer_id_unique = 0;
2098bf215546Sopenharmony_ci
2099bf215546Sopenharmony_ci   return true;
2100bf215546Sopenharmony_ci}
2101bf215546Sopenharmony_ci
2102bf215546Sopenharmony_ci/* Note that callers must've called tc_touch_buffer first before
2103bf215546Sopenharmony_ci * calling tc_improve_map_buffer_flags. */
2104bf215546Sopenharmony_cistatic unsigned
2105bf215546Sopenharmony_citc_improve_map_buffer_flags(struct threaded_context *tc,
2106bf215546Sopenharmony_ci                            struct threaded_resource *tres, unsigned usage,
2107bf215546Sopenharmony_ci                            unsigned offset, unsigned size)
2108bf215546Sopenharmony_ci{
2109bf215546Sopenharmony_ci   /* Never invalidate inside the driver and never infer "unsynchronized". */
2110bf215546Sopenharmony_ci   unsigned tc_flags = TC_TRANSFER_MAP_NO_INVALIDATE |
2111bf215546Sopenharmony_ci                       TC_TRANSFER_MAP_NO_INFER_UNSYNCHRONIZED;
2112bf215546Sopenharmony_ci
2113bf215546Sopenharmony_ci   /* Prevent a reentry. */
2114bf215546Sopenharmony_ci   if (usage & tc_flags)
2115bf215546Sopenharmony_ci      return usage;
2116bf215546Sopenharmony_ci
2117bf215546Sopenharmony_ci   /* Use the staging upload if it's preferred. */
2118bf215546Sopenharmony_ci   if (usage & (PIPE_MAP_DISCARD_RANGE |
2119bf215546Sopenharmony_ci                PIPE_MAP_DISCARD_WHOLE_RESOURCE) &&
2120bf215546Sopenharmony_ci       !(usage & PIPE_MAP_PERSISTENT) &&
2121bf215546Sopenharmony_ci       tres->b.flags & PIPE_RESOURCE_FLAG_DONT_MAP_DIRECTLY &&
2122bf215546Sopenharmony_ci       tc->use_forced_staging_uploads) {
2123bf215546Sopenharmony_ci      usage &= ~(PIPE_MAP_DISCARD_WHOLE_RESOURCE |
2124bf215546Sopenharmony_ci                 PIPE_MAP_UNSYNCHRONIZED);
2125bf215546Sopenharmony_ci
2126bf215546Sopenharmony_ci      return usage | tc_flags | PIPE_MAP_DISCARD_RANGE;
2127bf215546Sopenharmony_ci   }
2128bf215546Sopenharmony_ci
2129bf215546Sopenharmony_ci   /* Sparse buffers can't be mapped directly and can't be reallocated
2130bf215546Sopenharmony_ci    * (fully invalidated). That may just be a radeonsi limitation, but
2131bf215546Sopenharmony_ci    * the threaded context must obey it with radeonsi.
2132bf215546Sopenharmony_ci    */
2133bf215546Sopenharmony_ci   if (tres->b.flags & (PIPE_RESOURCE_FLAG_SPARSE | PIPE_RESOURCE_FLAG_UNMAPPABLE)) {
2134bf215546Sopenharmony_ci      /* We can use DISCARD_RANGE instead of full discard. This is the only
2135bf215546Sopenharmony_ci       * fast path for sparse buffers that doesn't need thread synchronization.
2136bf215546Sopenharmony_ci       */
2137bf215546Sopenharmony_ci      if (usage & PIPE_MAP_DISCARD_WHOLE_RESOURCE)
2138bf215546Sopenharmony_ci         usage |= PIPE_MAP_DISCARD_RANGE;
2139bf215546Sopenharmony_ci
2140bf215546Sopenharmony_ci      /* Allow DISCARD_WHOLE_RESOURCE and infering UNSYNCHRONIZED in drivers.
2141bf215546Sopenharmony_ci       * The threaded context doesn't do unsychronized mappings and invalida-
2142bf215546Sopenharmony_ci       * tions of sparse buffers, therefore a correct driver behavior won't
2143bf215546Sopenharmony_ci       * result in an incorrect behavior with the threaded context.
2144bf215546Sopenharmony_ci       */
2145bf215546Sopenharmony_ci      return usage;
2146bf215546Sopenharmony_ci   }
2147bf215546Sopenharmony_ci
2148bf215546Sopenharmony_ci   usage |= tc_flags;
2149bf215546Sopenharmony_ci
2150bf215546Sopenharmony_ci   /* Handle CPU reads trivially. */
2151bf215546Sopenharmony_ci   if (usage & PIPE_MAP_READ) {
2152bf215546Sopenharmony_ci      if (usage & PIPE_MAP_UNSYNCHRONIZED)
2153bf215546Sopenharmony_ci         usage |= TC_TRANSFER_MAP_THREADED_UNSYNC; /* don't sync */
2154bf215546Sopenharmony_ci
2155bf215546Sopenharmony_ci      /* Drivers aren't allowed to do buffer invalidations. */
2156bf215546Sopenharmony_ci      return usage & ~PIPE_MAP_DISCARD_WHOLE_RESOURCE;
2157bf215546Sopenharmony_ci   }
2158bf215546Sopenharmony_ci
2159bf215546Sopenharmony_ci   /* See if the buffer range being mapped has never been initialized or
2160bf215546Sopenharmony_ci    * the buffer is idle, in which case it can be mapped unsynchronized. */
2161bf215546Sopenharmony_ci   if (!(usage & PIPE_MAP_UNSYNCHRONIZED) &&
2162bf215546Sopenharmony_ci       ((!tres->is_shared &&
2163bf215546Sopenharmony_ci         !util_ranges_intersect(&tres->valid_buffer_range, offset, offset + size)) ||
2164bf215546Sopenharmony_ci        !tc_is_buffer_busy(tc, tres, usage)))
2165bf215546Sopenharmony_ci      usage |= PIPE_MAP_UNSYNCHRONIZED;
2166bf215546Sopenharmony_ci
2167bf215546Sopenharmony_ci   if (!(usage & PIPE_MAP_UNSYNCHRONIZED)) {
2168bf215546Sopenharmony_ci      /* If discarding the entire range, discard the whole resource instead. */
2169bf215546Sopenharmony_ci      if (usage & PIPE_MAP_DISCARD_RANGE &&
2170bf215546Sopenharmony_ci          offset == 0 && size == tres->b.width0)
2171bf215546Sopenharmony_ci         usage |= PIPE_MAP_DISCARD_WHOLE_RESOURCE;
2172bf215546Sopenharmony_ci
2173bf215546Sopenharmony_ci      /* Discard the whole resource if needed. */
2174bf215546Sopenharmony_ci      if (usage & PIPE_MAP_DISCARD_WHOLE_RESOURCE) {
2175bf215546Sopenharmony_ci         if (tc_invalidate_buffer(tc, tres))
2176bf215546Sopenharmony_ci            usage |= PIPE_MAP_UNSYNCHRONIZED;
2177bf215546Sopenharmony_ci         else
2178bf215546Sopenharmony_ci            usage |= PIPE_MAP_DISCARD_RANGE; /* fallback */
2179bf215546Sopenharmony_ci      }
2180bf215546Sopenharmony_ci   }
2181bf215546Sopenharmony_ci
2182bf215546Sopenharmony_ci   /* We won't need this flag anymore. */
2183bf215546Sopenharmony_ci   /* TODO: We might not need TC_TRANSFER_MAP_NO_INVALIDATE with this. */
2184bf215546Sopenharmony_ci   usage &= ~PIPE_MAP_DISCARD_WHOLE_RESOURCE;
2185bf215546Sopenharmony_ci
2186bf215546Sopenharmony_ci   /* GL_AMD_pinned_memory and persistent mappings can't use staging
2187bf215546Sopenharmony_ci    * buffers. */
2188bf215546Sopenharmony_ci   if (usage & (PIPE_MAP_UNSYNCHRONIZED |
2189bf215546Sopenharmony_ci                PIPE_MAP_PERSISTENT) ||
2190bf215546Sopenharmony_ci       tres->is_user_ptr)
2191bf215546Sopenharmony_ci      usage &= ~PIPE_MAP_DISCARD_RANGE;
2192bf215546Sopenharmony_ci
2193bf215546Sopenharmony_ci   /* Unsychronized buffer mappings don't have to synchronize the thread. */
2194bf215546Sopenharmony_ci   if (usage & PIPE_MAP_UNSYNCHRONIZED) {
2195bf215546Sopenharmony_ci      usage &= ~PIPE_MAP_DISCARD_RANGE;
2196bf215546Sopenharmony_ci      usage |= TC_TRANSFER_MAP_THREADED_UNSYNC; /* notify the driver */
2197bf215546Sopenharmony_ci   }
2198bf215546Sopenharmony_ci
2199bf215546Sopenharmony_ci   return usage;
2200bf215546Sopenharmony_ci}
2201bf215546Sopenharmony_ci
2202bf215546Sopenharmony_cistatic void *
2203bf215546Sopenharmony_citc_buffer_map(struct pipe_context *_pipe,
2204bf215546Sopenharmony_ci              struct pipe_resource *resource, unsigned level,
2205bf215546Sopenharmony_ci              unsigned usage, const struct pipe_box *box,
2206bf215546Sopenharmony_ci              struct pipe_transfer **transfer)
2207bf215546Sopenharmony_ci{
2208bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
2209bf215546Sopenharmony_ci   struct threaded_resource *tres = threaded_resource(resource);
2210bf215546Sopenharmony_ci   struct pipe_context *pipe = tc->pipe;
2211bf215546Sopenharmony_ci
2212bf215546Sopenharmony_ci   /* PIPE_MAP_THREAD_SAFE is for glthread, which shouldn't use the CPU storage and
2213bf215546Sopenharmony_ci    * this shouldn't normally be necessary because glthread only uses large buffers.
2214bf215546Sopenharmony_ci    */
2215bf215546Sopenharmony_ci   if (usage & PIPE_MAP_THREAD_SAFE)
2216bf215546Sopenharmony_ci      tc_buffer_disable_cpu_storage(resource);
2217bf215546Sopenharmony_ci
2218bf215546Sopenharmony_ci   tc_touch_buffer(tc, tres);
2219bf215546Sopenharmony_ci
2220bf215546Sopenharmony_ci   /* CPU storage relies on buffer invalidation never failing. With shared buffers,
2221bf215546Sopenharmony_ci    * invalidation might not always be possible, so CPU storage can't be used.
2222bf215546Sopenharmony_ci    */
2223bf215546Sopenharmony_ci   if (tc_is_buffer_shared(tres))
2224bf215546Sopenharmony_ci      tc_buffer_disable_cpu_storage(resource);
2225bf215546Sopenharmony_ci
2226bf215546Sopenharmony_ci   usage = tc_improve_map_buffer_flags(tc, tres, usage, box->x, box->width);
2227bf215546Sopenharmony_ci
2228bf215546Sopenharmony_ci   /* If the CPU storage is enabled, return it directly. */
2229bf215546Sopenharmony_ci   if (tres->allow_cpu_storage && !(usage & TC_TRANSFER_MAP_UPLOAD_CPU_STORAGE)) {
2230bf215546Sopenharmony_ci      /* We can't let resource_copy_region disable the CPU storage. */
2231bf215546Sopenharmony_ci      assert(!(tres->b.flags & PIPE_RESOURCE_FLAG_DONT_MAP_DIRECTLY));
2232bf215546Sopenharmony_ci
2233bf215546Sopenharmony_ci      if (!tres->cpu_storage) {
2234bf215546Sopenharmony_ci         tres->cpu_storage = align_malloc(resource->width0, tc->map_buffer_alignment);
2235bf215546Sopenharmony_ci
2236bf215546Sopenharmony_ci         if (tres->cpu_storage && tres->valid_buffer_range.end) {
2237bf215546Sopenharmony_ci            /* The GPU buffer contains valid data. Copy them to the CPU storage. */
2238bf215546Sopenharmony_ci            struct pipe_box box2;
2239bf215546Sopenharmony_ci            struct pipe_transfer *transfer2;
2240bf215546Sopenharmony_ci
2241bf215546Sopenharmony_ci            unsigned valid_range_len = tres->valid_buffer_range.end - tres->valid_buffer_range.start;
2242bf215546Sopenharmony_ci            u_box_1d(tres->valid_buffer_range.start, valid_range_len, &box2);
2243bf215546Sopenharmony_ci
2244bf215546Sopenharmony_ci            tc_sync_msg(tc, "cpu storage GPU -> CPU copy");
2245bf215546Sopenharmony_ci            tc_set_driver_thread(tc);
2246bf215546Sopenharmony_ci
2247bf215546Sopenharmony_ci            void *ret = pipe->buffer_map(pipe, tres->latest ? tres->latest : resource,
2248bf215546Sopenharmony_ci                                         0, PIPE_MAP_READ, &box2, &transfer2);
2249bf215546Sopenharmony_ci            memcpy(&((uint8_t*)tres->cpu_storage)[tres->valid_buffer_range.start],
2250bf215546Sopenharmony_ci                   ret,
2251bf215546Sopenharmony_ci                   valid_range_len);
2252bf215546Sopenharmony_ci            pipe->buffer_unmap(pipe, transfer2);
2253bf215546Sopenharmony_ci
2254bf215546Sopenharmony_ci            tc_clear_driver_thread(tc);
2255bf215546Sopenharmony_ci         }
2256bf215546Sopenharmony_ci      }
2257bf215546Sopenharmony_ci
2258bf215546Sopenharmony_ci      if (tres->cpu_storage) {
2259bf215546Sopenharmony_ci         struct threaded_transfer *ttrans = slab_zalloc(&tc->pool_transfers);
2260bf215546Sopenharmony_ci         ttrans->b.resource = resource;
2261bf215546Sopenharmony_ci         ttrans->b.usage = usage;
2262bf215546Sopenharmony_ci         ttrans->b.box = *box;
2263bf215546Sopenharmony_ci         ttrans->valid_buffer_range = &tres->valid_buffer_range;
2264bf215546Sopenharmony_ci         ttrans->cpu_storage_mapped = true;
2265bf215546Sopenharmony_ci         *transfer = &ttrans->b;
2266bf215546Sopenharmony_ci
2267bf215546Sopenharmony_ci         return (uint8_t*)tres->cpu_storage + box->x;
2268bf215546Sopenharmony_ci      } else {
2269bf215546Sopenharmony_ci         tres->allow_cpu_storage = false;
2270bf215546Sopenharmony_ci      }
2271bf215546Sopenharmony_ci   }
2272bf215546Sopenharmony_ci
2273bf215546Sopenharmony_ci   /* Do a staging transfer within the threaded context. The driver should
2274bf215546Sopenharmony_ci    * only get resource_copy_region.
2275bf215546Sopenharmony_ci    */
2276bf215546Sopenharmony_ci   if (usage & PIPE_MAP_DISCARD_RANGE) {
2277bf215546Sopenharmony_ci      struct threaded_transfer *ttrans = slab_zalloc(&tc->pool_transfers);
2278bf215546Sopenharmony_ci      uint8_t *map;
2279bf215546Sopenharmony_ci
2280bf215546Sopenharmony_ci      u_upload_alloc(tc->base.stream_uploader, 0,
2281bf215546Sopenharmony_ci                     box->width + (box->x % tc->map_buffer_alignment),
2282bf215546Sopenharmony_ci                     tc->map_buffer_alignment, &ttrans->b.offset,
2283bf215546Sopenharmony_ci                     &ttrans->staging, (void**)&map);
2284bf215546Sopenharmony_ci      if (!map) {
2285bf215546Sopenharmony_ci         slab_free(&tc->pool_transfers, ttrans);
2286bf215546Sopenharmony_ci         return NULL;
2287bf215546Sopenharmony_ci      }
2288bf215546Sopenharmony_ci
2289bf215546Sopenharmony_ci      ttrans->b.resource = resource;
2290bf215546Sopenharmony_ci      ttrans->b.level = 0;
2291bf215546Sopenharmony_ci      ttrans->b.usage = usage;
2292bf215546Sopenharmony_ci      ttrans->b.box = *box;
2293bf215546Sopenharmony_ci      ttrans->b.stride = 0;
2294bf215546Sopenharmony_ci      ttrans->b.layer_stride = 0;
2295bf215546Sopenharmony_ci      ttrans->valid_buffer_range = &tres->valid_buffer_range;
2296bf215546Sopenharmony_ci      ttrans->cpu_storage_mapped = false;
2297bf215546Sopenharmony_ci      *transfer = &ttrans->b;
2298bf215546Sopenharmony_ci
2299bf215546Sopenharmony_ci      p_atomic_inc(&tres->pending_staging_uploads);
2300bf215546Sopenharmony_ci      util_range_add(resource, &tres->pending_staging_uploads_range,
2301bf215546Sopenharmony_ci                     box->x, box->x + box->width);
2302bf215546Sopenharmony_ci
2303bf215546Sopenharmony_ci      return map + (box->x % tc->map_buffer_alignment);
2304bf215546Sopenharmony_ci   }
2305bf215546Sopenharmony_ci
2306bf215546Sopenharmony_ci   if (usage & PIPE_MAP_UNSYNCHRONIZED &&
2307bf215546Sopenharmony_ci       p_atomic_read(&tres->pending_staging_uploads) &&
2308bf215546Sopenharmony_ci       util_ranges_intersect(&tres->pending_staging_uploads_range, box->x, box->x + box->width)) {
2309bf215546Sopenharmony_ci      /* Write conflict detected between a staging transfer and the direct mapping we're
2310bf215546Sopenharmony_ci       * going to do. Resolve the conflict by ignoring UNSYNCHRONIZED so the direct mapping
2311bf215546Sopenharmony_ci       * will have to wait for the staging transfer completion.
2312bf215546Sopenharmony_ci       * Note: The conflict detection is only based on the mapped range, not on the actual
2313bf215546Sopenharmony_ci       * written range(s).
2314bf215546Sopenharmony_ci       */
2315bf215546Sopenharmony_ci      usage &= ~PIPE_MAP_UNSYNCHRONIZED & ~TC_TRANSFER_MAP_THREADED_UNSYNC;
2316bf215546Sopenharmony_ci      tc->use_forced_staging_uploads = false;
2317bf215546Sopenharmony_ci   }
2318bf215546Sopenharmony_ci
2319bf215546Sopenharmony_ci   /* Unsychronized buffer mappings don't have to synchronize the thread. */
2320bf215546Sopenharmony_ci   if (!(usage & TC_TRANSFER_MAP_THREADED_UNSYNC)) {
2321bf215546Sopenharmony_ci      tc_sync_msg(tc, usage & PIPE_MAP_DISCARD_RANGE ? "  discard_range" :
2322bf215546Sopenharmony_ci                      usage & PIPE_MAP_READ ? "  read" : "  staging conflict");
2323bf215546Sopenharmony_ci      tc_set_driver_thread(tc);
2324bf215546Sopenharmony_ci   }
2325bf215546Sopenharmony_ci
2326bf215546Sopenharmony_ci   tc->bytes_mapped_estimate += box->width;
2327bf215546Sopenharmony_ci
2328bf215546Sopenharmony_ci   void *ret = pipe->buffer_map(pipe, tres->latest ? tres->latest : resource,
2329bf215546Sopenharmony_ci                                level, usage, box, transfer);
2330bf215546Sopenharmony_ci   threaded_transfer(*transfer)->valid_buffer_range = &tres->valid_buffer_range;
2331bf215546Sopenharmony_ci   threaded_transfer(*transfer)->cpu_storage_mapped = false;
2332bf215546Sopenharmony_ci
2333bf215546Sopenharmony_ci   if (!(usage & TC_TRANSFER_MAP_THREADED_UNSYNC))
2334bf215546Sopenharmony_ci      tc_clear_driver_thread(tc);
2335bf215546Sopenharmony_ci
2336bf215546Sopenharmony_ci   return ret;
2337bf215546Sopenharmony_ci}
2338bf215546Sopenharmony_ci
2339bf215546Sopenharmony_cistatic void *
2340bf215546Sopenharmony_citc_texture_map(struct pipe_context *_pipe,
2341bf215546Sopenharmony_ci               struct pipe_resource *resource, unsigned level,
2342bf215546Sopenharmony_ci               unsigned usage, const struct pipe_box *box,
2343bf215546Sopenharmony_ci               struct pipe_transfer **transfer)
2344bf215546Sopenharmony_ci{
2345bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
2346bf215546Sopenharmony_ci   struct threaded_resource *tres = threaded_resource(resource);
2347bf215546Sopenharmony_ci   struct pipe_context *pipe = tc->pipe;
2348bf215546Sopenharmony_ci
2349bf215546Sopenharmony_ci   tc_sync_msg(tc, "texture");
2350bf215546Sopenharmony_ci   tc_set_driver_thread(tc);
2351bf215546Sopenharmony_ci
2352bf215546Sopenharmony_ci   tc->bytes_mapped_estimate += box->width;
2353bf215546Sopenharmony_ci
2354bf215546Sopenharmony_ci   void *ret = pipe->texture_map(pipe, tres->latest ? tres->latest : resource,
2355bf215546Sopenharmony_ci                                 level, usage, box, transfer);
2356bf215546Sopenharmony_ci
2357bf215546Sopenharmony_ci   if (!(usage & TC_TRANSFER_MAP_THREADED_UNSYNC))
2358bf215546Sopenharmony_ci      tc_clear_driver_thread(tc);
2359bf215546Sopenharmony_ci
2360bf215546Sopenharmony_ci   return ret;
2361bf215546Sopenharmony_ci}
2362bf215546Sopenharmony_ci
2363bf215546Sopenharmony_cistruct tc_transfer_flush_region {
2364bf215546Sopenharmony_ci   struct tc_call_base base;
2365bf215546Sopenharmony_ci   struct pipe_box box;
2366bf215546Sopenharmony_ci   struct pipe_transfer *transfer;
2367bf215546Sopenharmony_ci};
2368bf215546Sopenharmony_ci
2369bf215546Sopenharmony_cistatic uint16_t
2370bf215546Sopenharmony_citc_call_transfer_flush_region(struct pipe_context *pipe, void *call, uint64_t *last)
2371bf215546Sopenharmony_ci{
2372bf215546Sopenharmony_ci   struct tc_transfer_flush_region *p = to_call(call, tc_transfer_flush_region);
2373bf215546Sopenharmony_ci
2374bf215546Sopenharmony_ci   pipe->transfer_flush_region(pipe, p->transfer, &p->box);
2375bf215546Sopenharmony_ci   return call_size(tc_transfer_flush_region);
2376bf215546Sopenharmony_ci}
2377bf215546Sopenharmony_ci
2378bf215546Sopenharmony_cistruct tc_resource_copy_region {
2379bf215546Sopenharmony_ci   struct tc_call_base base;
2380bf215546Sopenharmony_ci   unsigned dst_level;
2381bf215546Sopenharmony_ci   unsigned dstx, dsty, dstz;
2382bf215546Sopenharmony_ci   unsigned src_level;
2383bf215546Sopenharmony_ci   struct pipe_box src_box;
2384bf215546Sopenharmony_ci   struct pipe_resource *dst;
2385bf215546Sopenharmony_ci   struct pipe_resource *src;
2386bf215546Sopenharmony_ci};
2387bf215546Sopenharmony_ci
2388bf215546Sopenharmony_cistatic void
2389bf215546Sopenharmony_citc_resource_copy_region(struct pipe_context *_pipe,
2390bf215546Sopenharmony_ci                        struct pipe_resource *dst, unsigned dst_level,
2391bf215546Sopenharmony_ci                        unsigned dstx, unsigned dsty, unsigned dstz,
2392bf215546Sopenharmony_ci                        struct pipe_resource *src, unsigned src_level,
2393bf215546Sopenharmony_ci                        const struct pipe_box *src_box);
2394bf215546Sopenharmony_ci
2395bf215546Sopenharmony_cistatic void
2396bf215546Sopenharmony_citc_buffer_do_flush_region(struct threaded_context *tc,
2397bf215546Sopenharmony_ci                          struct threaded_transfer *ttrans,
2398bf215546Sopenharmony_ci                          const struct pipe_box *box)
2399bf215546Sopenharmony_ci{
2400bf215546Sopenharmony_ci   struct threaded_resource *tres = threaded_resource(ttrans->b.resource);
2401bf215546Sopenharmony_ci
2402bf215546Sopenharmony_ci   if (ttrans->staging) {
2403bf215546Sopenharmony_ci      struct pipe_box src_box;
2404bf215546Sopenharmony_ci
2405bf215546Sopenharmony_ci      u_box_1d(ttrans->b.offset + ttrans->b.box.x % tc->map_buffer_alignment +
2406bf215546Sopenharmony_ci               (box->x - ttrans->b.box.x),
2407bf215546Sopenharmony_ci               box->width, &src_box);
2408bf215546Sopenharmony_ci
2409bf215546Sopenharmony_ci      /* Copy the staging buffer into the original one. */
2410bf215546Sopenharmony_ci      tc_resource_copy_region(&tc->base, ttrans->b.resource, 0, box->x, 0, 0,
2411bf215546Sopenharmony_ci                              ttrans->staging, 0, &src_box);
2412bf215546Sopenharmony_ci   }
2413bf215546Sopenharmony_ci
2414bf215546Sopenharmony_ci   /* Don't update the valid range when we're uploading the CPU storage
2415bf215546Sopenharmony_ci    * because it includes the uninitialized range too.
2416bf215546Sopenharmony_ci    */
2417bf215546Sopenharmony_ci   if (!(ttrans->b.usage & TC_TRANSFER_MAP_UPLOAD_CPU_STORAGE)) {
2418bf215546Sopenharmony_ci      util_range_add(&tres->b, ttrans->valid_buffer_range,
2419bf215546Sopenharmony_ci                     box->x, box->x + box->width);
2420bf215546Sopenharmony_ci   }
2421bf215546Sopenharmony_ci}
2422bf215546Sopenharmony_ci
2423bf215546Sopenharmony_cistatic void
2424bf215546Sopenharmony_citc_transfer_flush_region(struct pipe_context *_pipe,
2425bf215546Sopenharmony_ci                         struct pipe_transfer *transfer,
2426bf215546Sopenharmony_ci                         const struct pipe_box *rel_box)
2427bf215546Sopenharmony_ci{
2428bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
2429bf215546Sopenharmony_ci   struct threaded_transfer *ttrans = threaded_transfer(transfer);
2430bf215546Sopenharmony_ci   struct threaded_resource *tres = threaded_resource(transfer->resource);
2431bf215546Sopenharmony_ci   unsigned required_usage = PIPE_MAP_WRITE |
2432bf215546Sopenharmony_ci                             PIPE_MAP_FLUSH_EXPLICIT;
2433bf215546Sopenharmony_ci
2434bf215546Sopenharmony_ci   if (tres->b.target == PIPE_BUFFER) {
2435bf215546Sopenharmony_ci      if ((transfer->usage & required_usage) == required_usage) {
2436bf215546Sopenharmony_ci         struct pipe_box box;
2437bf215546Sopenharmony_ci
2438bf215546Sopenharmony_ci         u_box_1d(transfer->box.x + rel_box->x, rel_box->width, &box);
2439bf215546Sopenharmony_ci         tc_buffer_do_flush_region(tc, ttrans, &box);
2440bf215546Sopenharmony_ci      }
2441bf215546Sopenharmony_ci
2442bf215546Sopenharmony_ci      /* Staging transfers don't send the call to the driver.
2443bf215546Sopenharmony_ci       *
2444bf215546Sopenharmony_ci       * Transfers using the CPU storage shouldn't call transfer_flush_region
2445bf215546Sopenharmony_ci       * in the driver because the buffer is not really mapped on the driver
2446bf215546Sopenharmony_ci       * side and the CPU storage always re-uploads everything (flush_region
2447bf215546Sopenharmony_ci       * makes no difference).
2448bf215546Sopenharmony_ci       */
2449bf215546Sopenharmony_ci      if (ttrans->staging || ttrans->cpu_storage_mapped)
2450bf215546Sopenharmony_ci         return;
2451bf215546Sopenharmony_ci   }
2452bf215546Sopenharmony_ci
2453bf215546Sopenharmony_ci   struct tc_transfer_flush_region *p =
2454bf215546Sopenharmony_ci      tc_add_call(tc, TC_CALL_transfer_flush_region, tc_transfer_flush_region);
2455bf215546Sopenharmony_ci   p->transfer = transfer;
2456bf215546Sopenharmony_ci   p->box = *rel_box;
2457bf215546Sopenharmony_ci}
2458bf215546Sopenharmony_ci
2459bf215546Sopenharmony_cistatic void
2460bf215546Sopenharmony_citc_flush(struct pipe_context *_pipe, struct pipe_fence_handle **fence,
2461bf215546Sopenharmony_ci         unsigned flags);
2462bf215546Sopenharmony_ci
2463bf215546Sopenharmony_cistruct tc_buffer_unmap {
2464bf215546Sopenharmony_ci   struct tc_call_base base;
2465bf215546Sopenharmony_ci   bool was_staging_transfer;
2466bf215546Sopenharmony_ci   union {
2467bf215546Sopenharmony_ci      struct pipe_transfer *transfer;
2468bf215546Sopenharmony_ci      struct pipe_resource *resource;
2469bf215546Sopenharmony_ci   };
2470bf215546Sopenharmony_ci};
2471bf215546Sopenharmony_ci
2472bf215546Sopenharmony_cistatic uint16_t
2473bf215546Sopenharmony_citc_call_buffer_unmap(struct pipe_context *pipe, void *call, uint64_t *last)
2474bf215546Sopenharmony_ci{
2475bf215546Sopenharmony_ci   struct tc_buffer_unmap *p = to_call(call, tc_buffer_unmap);
2476bf215546Sopenharmony_ci
2477bf215546Sopenharmony_ci   if (p->was_staging_transfer) {
2478bf215546Sopenharmony_ci      struct threaded_resource *tres = threaded_resource(p->resource);
2479bf215546Sopenharmony_ci      /* Nothing to do except keeping track of staging uploads */
2480bf215546Sopenharmony_ci      assert(tres->pending_staging_uploads > 0);
2481bf215546Sopenharmony_ci      p_atomic_dec(&tres->pending_staging_uploads);
2482bf215546Sopenharmony_ci      tc_drop_resource_reference(p->resource);
2483bf215546Sopenharmony_ci   } else {
2484bf215546Sopenharmony_ci      pipe->buffer_unmap(pipe, p->transfer);
2485bf215546Sopenharmony_ci   }
2486bf215546Sopenharmony_ci
2487bf215546Sopenharmony_ci   return call_size(tc_buffer_unmap);
2488bf215546Sopenharmony_ci}
2489bf215546Sopenharmony_ci
2490bf215546Sopenharmony_cistatic void
2491bf215546Sopenharmony_citc_buffer_unmap(struct pipe_context *_pipe, struct pipe_transfer *transfer)
2492bf215546Sopenharmony_ci{
2493bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
2494bf215546Sopenharmony_ci   struct threaded_transfer *ttrans = threaded_transfer(transfer);
2495bf215546Sopenharmony_ci   struct threaded_resource *tres = threaded_resource(transfer->resource);
2496bf215546Sopenharmony_ci
2497bf215546Sopenharmony_ci   /* PIPE_MAP_THREAD_SAFE is only valid with UNSYNCHRONIZED. It can be
2498bf215546Sopenharmony_ci    * called from any thread and bypasses all multithreaded queues.
2499bf215546Sopenharmony_ci    */
2500bf215546Sopenharmony_ci   if (transfer->usage & PIPE_MAP_THREAD_SAFE) {
2501bf215546Sopenharmony_ci      assert(transfer->usage & PIPE_MAP_UNSYNCHRONIZED);
2502bf215546Sopenharmony_ci      assert(!(transfer->usage & (PIPE_MAP_FLUSH_EXPLICIT |
2503bf215546Sopenharmony_ci                                  PIPE_MAP_DISCARD_RANGE)));
2504bf215546Sopenharmony_ci
2505bf215546Sopenharmony_ci      struct pipe_context *pipe = tc->pipe;
2506bf215546Sopenharmony_ci      util_range_add(&tres->b, ttrans->valid_buffer_range,
2507bf215546Sopenharmony_ci                      transfer->box.x, transfer->box.x + transfer->box.width);
2508bf215546Sopenharmony_ci
2509bf215546Sopenharmony_ci      pipe->buffer_unmap(pipe, transfer);
2510bf215546Sopenharmony_ci      return;
2511bf215546Sopenharmony_ci   }
2512bf215546Sopenharmony_ci
2513bf215546Sopenharmony_ci   if (transfer->usage & PIPE_MAP_WRITE &&
2514bf215546Sopenharmony_ci       !(transfer->usage & PIPE_MAP_FLUSH_EXPLICIT))
2515bf215546Sopenharmony_ci      tc_buffer_do_flush_region(tc, ttrans, &transfer->box);
2516bf215546Sopenharmony_ci
2517bf215546Sopenharmony_ci   if (ttrans->cpu_storage_mapped) {
2518bf215546Sopenharmony_ci      /* GL allows simultaneous GPU stores with mapped buffers as long as GPU stores don't
2519bf215546Sopenharmony_ci       * touch the mapped range. That's a problem because GPU stores free the CPU storage.
2520bf215546Sopenharmony_ci       * If that happens, we just ignore the unmap call and don't upload anything to prevent
2521bf215546Sopenharmony_ci       * a crash.
2522bf215546Sopenharmony_ci       *
2523bf215546Sopenharmony_ci       * Disallow the CPU storage in the driver to work around this.
2524bf215546Sopenharmony_ci       */
2525bf215546Sopenharmony_ci      assert(tres->cpu_storage);
2526bf215546Sopenharmony_ci
2527bf215546Sopenharmony_ci      if (tres->cpu_storage) {
2528bf215546Sopenharmony_ci         /* Invalidations shouldn't fail as long as CPU storage is allowed. */
2529bf215546Sopenharmony_ci         ASSERTED bool invalidated = tc_invalidate_buffer(tc, tres);
2530bf215546Sopenharmony_ci         assert(invalidated);
2531bf215546Sopenharmony_ci
2532bf215546Sopenharmony_ci         tc_buffer_subdata(&tc->base, &tres->b,
2533bf215546Sopenharmony_ci                           PIPE_MAP_UNSYNCHRONIZED |
2534bf215546Sopenharmony_ci                           TC_TRANSFER_MAP_UPLOAD_CPU_STORAGE,
2535bf215546Sopenharmony_ci                           0, tres->b.width0, tres->cpu_storage);
2536bf215546Sopenharmony_ci         /* This shouldn't have been freed by buffer_subdata. */
2537bf215546Sopenharmony_ci         assert(tres->cpu_storage);
2538bf215546Sopenharmony_ci      } else {
2539bf215546Sopenharmony_ci         static bool warned_once = false;
2540bf215546Sopenharmony_ci         if (!warned_once) {
2541bf215546Sopenharmony_ci            fprintf(stderr, "This application is incompatible with cpu_storage.\n");
2542bf215546Sopenharmony_ci            fprintf(stderr, "Use tc_max_cpu_storage_size=0 to disable it and report this issue to Mesa.\n");
2543bf215546Sopenharmony_ci            warned_once = true;
2544bf215546Sopenharmony_ci         }
2545bf215546Sopenharmony_ci      }
2546bf215546Sopenharmony_ci
2547bf215546Sopenharmony_ci      tc_drop_resource_reference(ttrans->staging);
2548bf215546Sopenharmony_ci      slab_free(&tc->pool_transfers, ttrans);
2549bf215546Sopenharmony_ci      return;
2550bf215546Sopenharmony_ci   }
2551bf215546Sopenharmony_ci
2552bf215546Sopenharmony_ci   bool was_staging_transfer = false;
2553bf215546Sopenharmony_ci
2554bf215546Sopenharmony_ci   if (ttrans->staging) {
2555bf215546Sopenharmony_ci      was_staging_transfer = true;
2556bf215546Sopenharmony_ci
2557bf215546Sopenharmony_ci      tc_drop_resource_reference(ttrans->staging);
2558bf215546Sopenharmony_ci      slab_free(&tc->pool_transfers, ttrans);
2559bf215546Sopenharmony_ci   }
2560bf215546Sopenharmony_ci
2561bf215546Sopenharmony_ci   struct tc_buffer_unmap *p = tc_add_call(tc, TC_CALL_buffer_unmap,
2562bf215546Sopenharmony_ci                                           tc_buffer_unmap);
2563bf215546Sopenharmony_ci   if (was_staging_transfer) {
2564bf215546Sopenharmony_ci      tc_set_resource_reference(&p->resource, &tres->b);
2565bf215546Sopenharmony_ci      p->was_staging_transfer = true;
2566bf215546Sopenharmony_ci   } else {
2567bf215546Sopenharmony_ci      p->transfer = transfer;
2568bf215546Sopenharmony_ci      p->was_staging_transfer = false;
2569bf215546Sopenharmony_ci   }
2570bf215546Sopenharmony_ci
2571bf215546Sopenharmony_ci   /* tc_buffer_map directly maps the buffers, but tc_buffer_unmap
2572bf215546Sopenharmony_ci    * defers the unmap operation to the batch execution.
2573bf215546Sopenharmony_ci    * bytes_mapped_estimate is an estimation of the map/unmap bytes delta
2574bf215546Sopenharmony_ci    * and if it goes over an optional limit the current batch is flushed,
2575bf215546Sopenharmony_ci    * to reclaim some RAM. */
2576bf215546Sopenharmony_ci   if (!ttrans->staging && tc->bytes_mapped_limit &&
2577bf215546Sopenharmony_ci       tc->bytes_mapped_estimate > tc->bytes_mapped_limit) {
2578bf215546Sopenharmony_ci      tc_flush(_pipe, NULL, PIPE_FLUSH_ASYNC);
2579bf215546Sopenharmony_ci   }
2580bf215546Sopenharmony_ci}
2581bf215546Sopenharmony_ci
2582bf215546Sopenharmony_cistruct tc_texture_unmap {
2583bf215546Sopenharmony_ci   struct tc_call_base base;
2584bf215546Sopenharmony_ci   struct pipe_transfer *transfer;
2585bf215546Sopenharmony_ci};
2586bf215546Sopenharmony_ci
2587bf215546Sopenharmony_cistatic uint16_t
2588bf215546Sopenharmony_citc_call_texture_unmap(struct pipe_context *pipe, void *call, uint64_t *last)
2589bf215546Sopenharmony_ci{
2590bf215546Sopenharmony_ci   struct tc_texture_unmap *p = (struct tc_texture_unmap *) call;
2591bf215546Sopenharmony_ci
2592bf215546Sopenharmony_ci   pipe->texture_unmap(pipe, p->transfer);
2593bf215546Sopenharmony_ci   return call_size(tc_texture_unmap);
2594bf215546Sopenharmony_ci}
2595bf215546Sopenharmony_ci
2596bf215546Sopenharmony_cistatic void
2597bf215546Sopenharmony_citc_texture_unmap(struct pipe_context *_pipe, struct pipe_transfer *transfer)
2598bf215546Sopenharmony_ci{
2599bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
2600bf215546Sopenharmony_ci   struct threaded_transfer *ttrans = threaded_transfer(transfer);
2601bf215546Sopenharmony_ci
2602bf215546Sopenharmony_ci   tc_add_call(tc, TC_CALL_texture_unmap, tc_texture_unmap)->transfer = transfer;
2603bf215546Sopenharmony_ci
2604bf215546Sopenharmony_ci   /* tc_texture_map directly maps the textures, but tc_texture_unmap
2605bf215546Sopenharmony_ci    * defers the unmap operation to the batch execution.
2606bf215546Sopenharmony_ci    * bytes_mapped_estimate is an estimation of the map/unmap bytes delta
2607bf215546Sopenharmony_ci    * and if it goes over an optional limit the current batch is flushed,
2608bf215546Sopenharmony_ci    * to reclaim some RAM. */
2609bf215546Sopenharmony_ci   if (!ttrans->staging && tc->bytes_mapped_limit &&
2610bf215546Sopenharmony_ci       tc->bytes_mapped_estimate > tc->bytes_mapped_limit) {
2611bf215546Sopenharmony_ci      tc_flush(_pipe, NULL, PIPE_FLUSH_ASYNC);
2612bf215546Sopenharmony_ci   }
2613bf215546Sopenharmony_ci}
2614bf215546Sopenharmony_ci
2615bf215546Sopenharmony_cistruct tc_buffer_subdata {
2616bf215546Sopenharmony_ci   struct tc_call_base base;
2617bf215546Sopenharmony_ci   unsigned usage, offset, size;
2618bf215546Sopenharmony_ci   struct pipe_resource *resource;
2619bf215546Sopenharmony_ci   char slot[0]; /* more will be allocated if needed */
2620bf215546Sopenharmony_ci};
2621bf215546Sopenharmony_ci
2622bf215546Sopenharmony_cistatic uint16_t
2623bf215546Sopenharmony_citc_call_buffer_subdata(struct pipe_context *pipe, void *call, uint64_t *last)
2624bf215546Sopenharmony_ci{
2625bf215546Sopenharmony_ci   struct tc_buffer_subdata *p = (struct tc_buffer_subdata *)call;
2626bf215546Sopenharmony_ci
2627bf215546Sopenharmony_ci   pipe->buffer_subdata(pipe, p->resource, p->usage, p->offset, p->size,
2628bf215546Sopenharmony_ci                        p->slot);
2629bf215546Sopenharmony_ci   tc_drop_resource_reference(p->resource);
2630bf215546Sopenharmony_ci   return p->base.num_slots;
2631bf215546Sopenharmony_ci}
2632bf215546Sopenharmony_ci
2633bf215546Sopenharmony_cistatic void
2634bf215546Sopenharmony_citc_buffer_subdata(struct pipe_context *_pipe,
2635bf215546Sopenharmony_ci                  struct pipe_resource *resource,
2636bf215546Sopenharmony_ci                  unsigned usage, unsigned offset,
2637bf215546Sopenharmony_ci                  unsigned size, const void *data)
2638bf215546Sopenharmony_ci{
2639bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
2640bf215546Sopenharmony_ci   struct threaded_resource *tres = threaded_resource(resource);
2641bf215546Sopenharmony_ci
2642bf215546Sopenharmony_ci   if (!size)
2643bf215546Sopenharmony_ci      return;
2644bf215546Sopenharmony_ci
2645bf215546Sopenharmony_ci   tc_touch_buffer(tc, tres);
2646bf215546Sopenharmony_ci
2647bf215546Sopenharmony_ci   usage |= PIPE_MAP_WRITE;
2648bf215546Sopenharmony_ci
2649bf215546Sopenharmony_ci   /* PIPE_MAP_DIRECTLY supresses implicit DISCARD_RANGE. */
2650bf215546Sopenharmony_ci   if (!(usage & PIPE_MAP_DIRECTLY))
2651bf215546Sopenharmony_ci      usage |= PIPE_MAP_DISCARD_RANGE;
2652bf215546Sopenharmony_ci
2653bf215546Sopenharmony_ci   usage = tc_improve_map_buffer_flags(tc, tres, usage, offset, size);
2654bf215546Sopenharmony_ci
2655bf215546Sopenharmony_ci   /* Unsychronized and big transfers should use transfer_map. Also handle
2656bf215546Sopenharmony_ci    * full invalidations, because drivers aren't allowed to do them.
2657bf215546Sopenharmony_ci    */
2658bf215546Sopenharmony_ci   if (usage & (PIPE_MAP_UNSYNCHRONIZED |
2659bf215546Sopenharmony_ci                PIPE_MAP_DISCARD_WHOLE_RESOURCE) ||
2660bf215546Sopenharmony_ci       size > TC_MAX_SUBDATA_BYTES ||
2661bf215546Sopenharmony_ci       tres->cpu_storage) {
2662bf215546Sopenharmony_ci      struct pipe_transfer *transfer;
2663bf215546Sopenharmony_ci      struct pipe_box box;
2664bf215546Sopenharmony_ci      uint8_t *map = NULL;
2665bf215546Sopenharmony_ci
2666bf215546Sopenharmony_ci      u_box_1d(offset, size, &box);
2667bf215546Sopenharmony_ci
2668bf215546Sopenharmony_ci      /* CPU storage is only useful for partial updates. It can add overhead
2669bf215546Sopenharmony_ci       * on glBufferData calls so avoid using it.
2670bf215546Sopenharmony_ci       */
2671bf215546Sopenharmony_ci      if (!tres->cpu_storage && offset == 0 && size == resource->width0)
2672bf215546Sopenharmony_ci         usage |= TC_TRANSFER_MAP_UPLOAD_CPU_STORAGE;
2673bf215546Sopenharmony_ci
2674bf215546Sopenharmony_ci      map = tc_buffer_map(_pipe, resource, 0, usage, &box, &transfer);
2675bf215546Sopenharmony_ci      if (map) {
2676bf215546Sopenharmony_ci         memcpy(map, data, size);
2677bf215546Sopenharmony_ci         tc_buffer_unmap(_pipe, transfer);
2678bf215546Sopenharmony_ci      }
2679bf215546Sopenharmony_ci      return;
2680bf215546Sopenharmony_ci   }
2681bf215546Sopenharmony_ci
2682bf215546Sopenharmony_ci   util_range_add(&tres->b, &tres->valid_buffer_range, offset, offset + size);
2683bf215546Sopenharmony_ci
2684bf215546Sopenharmony_ci   /* The upload is small. Enqueue it. */
2685bf215546Sopenharmony_ci   struct tc_buffer_subdata *p =
2686bf215546Sopenharmony_ci      tc_add_slot_based_call(tc, TC_CALL_buffer_subdata, tc_buffer_subdata, size);
2687bf215546Sopenharmony_ci
2688bf215546Sopenharmony_ci   tc_set_resource_reference(&p->resource, resource);
2689bf215546Sopenharmony_ci   /* This is will always be busy because if it wasn't, tc_improve_map_buffer-
2690bf215546Sopenharmony_ci    * _flags would set UNSYNCHRONIZED and we wouldn't get here.
2691bf215546Sopenharmony_ci    */
2692bf215546Sopenharmony_ci   tc_add_to_buffer_list(tc, &tc->buffer_lists[tc->next_buf_list], resource);
2693bf215546Sopenharmony_ci   p->usage = usage;
2694bf215546Sopenharmony_ci   p->offset = offset;
2695bf215546Sopenharmony_ci   p->size = size;
2696bf215546Sopenharmony_ci   memcpy(p->slot, data, size);
2697bf215546Sopenharmony_ci}
2698bf215546Sopenharmony_ci
2699bf215546Sopenharmony_cistruct tc_texture_subdata {
2700bf215546Sopenharmony_ci   struct tc_call_base base;
2701bf215546Sopenharmony_ci   unsigned level, usage, stride, layer_stride;
2702bf215546Sopenharmony_ci   struct pipe_box box;
2703bf215546Sopenharmony_ci   struct pipe_resource *resource;
2704bf215546Sopenharmony_ci   char slot[0]; /* more will be allocated if needed */
2705bf215546Sopenharmony_ci};
2706bf215546Sopenharmony_ci
2707bf215546Sopenharmony_cistatic uint16_t
2708bf215546Sopenharmony_citc_call_texture_subdata(struct pipe_context *pipe, void *call, uint64_t *last)
2709bf215546Sopenharmony_ci{
2710bf215546Sopenharmony_ci   struct tc_texture_subdata *p = (struct tc_texture_subdata *)call;
2711bf215546Sopenharmony_ci
2712bf215546Sopenharmony_ci   pipe->texture_subdata(pipe, p->resource, p->level, p->usage, &p->box,
2713bf215546Sopenharmony_ci                         p->slot, p->stride, p->layer_stride);
2714bf215546Sopenharmony_ci   tc_drop_resource_reference(p->resource);
2715bf215546Sopenharmony_ci   return p->base.num_slots;
2716bf215546Sopenharmony_ci}
2717bf215546Sopenharmony_ci
2718bf215546Sopenharmony_cistatic void
2719bf215546Sopenharmony_citc_texture_subdata(struct pipe_context *_pipe,
2720bf215546Sopenharmony_ci                   struct pipe_resource *resource,
2721bf215546Sopenharmony_ci                   unsigned level, unsigned usage,
2722bf215546Sopenharmony_ci                   const struct pipe_box *box,
2723bf215546Sopenharmony_ci                   const void *data, unsigned stride,
2724bf215546Sopenharmony_ci                   unsigned layer_stride)
2725bf215546Sopenharmony_ci{
2726bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
2727bf215546Sopenharmony_ci   unsigned size;
2728bf215546Sopenharmony_ci
2729bf215546Sopenharmony_ci   assert(box->height >= 1);
2730bf215546Sopenharmony_ci   assert(box->depth >= 1);
2731bf215546Sopenharmony_ci
2732bf215546Sopenharmony_ci   size = (box->depth - 1) * layer_stride +
2733bf215546Sopenharmony_ci          (box->height - 1) * stride +
2734bf215546Sopenharmony_ci          box->width * util_format_get_blocksize(resource->format);
2735bf215546Sopenharmony_ci   if (!size)
2736bf215546Sopenharmony_ci      return;
2737bf215546Sopenharmony_ci
2738bf215546Sopenharmony_ci   /* Small uploads can be enqueued, big uploads must sync. */
2739bf215546Sopenharmony_ci   if (size <= TC_MAX_SUBDATA_BYTES) {
2740bf215546Sopenharmony_ci      struct tc_texture_subdata *p =
2741bf215546Sopenharmony_ci         tc_add_slot_based_call(tc, TC_CALL_texture_subdata, tc_texture_subdata, size);
2742bf215546Sopenharmony_ci
2743bf215546Sopenharmony_ci      tc_set_resource_reference(&p->resource, resource);
2744bf215546Sopenharmony_ci      p->level = level;
2745bf215546Sopenharmony_ci      p->usage = usage;
2746bf215546Sopenharmony_ci      p->box = *box;
2747bf215546Sopenharmony_ci      p->stride = stride;
2748bf215546Sopenharmony_ci      p->layer_stride = layer_stride;
2749bf215546Sopenharmony_ci      memcpy(p->slot, data, size);
2750bf215546Sopenharmony_ci   } else {
2751bf215546Sopenharmony_ci      struct pipe_context *pipe = tc->pipe;
2752bf215546Sopenharmony_ci
2753bf215546Sopenharmony_ci      tc_sync(tc);
2754bf215546Sopenharmony_ci      tc_set_driver_thread(tc);
2755bf215546Sopenharmony_ci      pipe->texture_subdata(pipe, resource, level, usage, box, data,
2756bf215546Sopenharmony_ci                            stride, layer_stride);
2757bf215546Sopenharmony_ci      tc_clear_driver_thread(tc);
2758bf215546Sopenharmony_ci   }
2759bf215546Sopenharmony_ci}
2760bf215546Sopenharmony_ci
2761bf215546Sopenharmony_ci
2762bf215546Sopenharmony_ci/********************************************************************
2763bf215546Sopenharmony_ci * miscellaneous
2764bf215546Sopenharmony_ci */
2765bf215546Sopenharmony_ci
2766bf215546Sopenharmony_ci#define TC_FUNC_SYNC_RET0(ret_type, func) \
2767bf215546Sopenharmony_ci   static ret_type \
2768bf215546Sopenharmony_ci   tc_##func(struct pipe_context *_pipe) \
2769bf215546Sopenharmony_ci   { \
2770bf215546Sopenharmony_ci      struct threaded_context *tc = threaded_context(_pipe); \
2771bf215546Sopenharmony_ci      struct pipe_context *pipe = tc->pipe; \
2772bf215546Sopenharmony_ci      tc_sync(tc); \
2773bf215546Sopenharmony_ci      return pipe->func(pipe); \
2774bf215546Sopenharmony_ci   }
2775bf215546Sopenharmony_ci
2776bf215546Sopenharmony_ciTC_FUNC_SYNC_RET0(uint64_t, get_timestamp)
2777bf215546Sopenharmony_ci
2778bf215546Sopenharmony_cistatic void
2779bf215546Sopenharmony_citc_get_sample_position(struct pipe_context *_pipe,
2780bf215546Sopenharmony_ci                       unsigned sample_count, unsigned sample_index,
2781bf215546Sopenharmony_ci                       float *out_value)
2782bf215546Sopenharmony_ci{
2783bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
2784bf215546Sopenharmony_ci   struct pipe_context *pipe = tc->pipe;
2785bf215546Sopenharmony_ci
2786bf215546Sopenharmony_ci   tc_sync(tc);
2787bf215546Sopenharmony_ci   pipe->get_sample_position(pipe, sample_count, sample_index,
2788bf215546Sopenharmony_ci                             out_value);
2789bf215546Sopenharmony_ci}
2790bf215546Sopenharmony_ci
2791bf215546Sopenharmony_cistatic enum pipe_reset_status
2792bf215546Sopenharmony_citc_get_device_reset_status(struct pipe_context *_pipe)
2793bf215546Sopenharmony_ci{
2794bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
2795bf215546Sopenharmony_ci   struct pipe_context *pipe = tc->pipe;
2796bf215546Sopenharmony_ci
2797bf215546Sopenharmony_ci   if (!tc->options.unsynchronized_get_device_reset_status)
2798bf215546Sopenharmony_ci      tc_sync(tc);
2799bf215546Sopenharmony_ci
2800bf215546Sopenharmony_ci   return pipe->get_device_reset_status(pipe);
2801bf215546Sopenharmony_ci}
2802bf215546Sopenharmony_ci
2803bf215546Sopenharmony_cistatic void
2804bf215546Sopenharmony_citc_set_device_reset_callback(struct pipe_context *_pipe,
2805bf215546Sopenharmony_ci                             const struct pipe_device_reset_callback *cb)
2806bf215546Sopenharmony_ci{
2807bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
2808bf215546Sopenharmony_ci   struct pipe_context *pipe = tc->pipe;
2809bf215546Sopenharmony_ci
2810bf215546Sopenharmony_ci   tc_sync(tc);
2811bf215546Sopenharmony_ci   pipe->set_device_reset_callback(pipe, cb);
2812bf215546Sopenharmony_ci}
2813bf215546Sopenharmony_ci
2814bf215546Sopenharmony_cistruct tc_string_marker {
2815bf215546Sopenharmony_ci   struct tc_call_base base;
2816bf215546Sopenharmony_ci   int len;
2817bf215546Sopenharmony_ci   char slot[0]; /* more will be allocated if needed */
2818bf215546Sopenharmony_ci};
2819bf215546Sopenharmony_ci
2820bf215546Sopenharmony_cistatic uint16_t
2821bf215546Sopenharmony_citc_call_emit_string_marker(struct pipe_context *pipe, void *call, uint64_t *last)
2822bf215546Sopenharmony_ci{
2823bf215546Sopenharmony_ci   struct tc_string_marker *p = (struct tc_string_marker *)call;
2824bf215546Sopenharmony_ci   pipe->emit_string_marker(pipe, p->slot, p->len);
2825bf215546Sopenharmony_ci   return p->base.num_slots;
2826bf215546Sopenharmony_ci}
2827bf215546Sopenharmony_ci
2828bf215546Sopenharmony_cistatic void
2829bf215546Sopenharmony_citc_emit_string_marker(struct pipe_context *_pipe,
2830bf215546Sopenharmony_ci                      const char *string, int len)
2831bf215546Sopenharmony_ci{
2832bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
2833bf215546Sopenharmony_ci
2834bf215546Sopenharmony_ci   if (len <= TC_MAX_STRING_MARKER_BYTES) {
2835bf215546Sopenharmony_ci      struct tc_string_marker *p =
2836bf215546Sopenharmony_ci         tc_add_slot_based_call(tc, TC_CALL_emit_string_marker, tc_string_marker, len);
2837bf215546Sopenharmony_ci
2838bf215546Sopenharmony_ci      memcpy(p->slot, string, len);
2839bf215546Sopenharmony_ci      p->len = len;
2840bf215546Sopenharmony_ci   } else {
2841bf215546Sopenharmony_ci      struct pipe_context *pipe = tc->pipe;
2842bf215546Sopenharmony_ci
2843bf215546Sopenharmony_ci      tc_sync(tc);
2844bf215546Sopenharmony_ci      tc_set_driver_thread(tc);
2845bf215546Sopenharmony_ci      pipe->emit_string_marker(pipe, string, len);
2846bf215546Sopenharmony_ci      tc_clear_driver_thread(tc);
2847bf215546Sopenharmony_ci   }
2848bf215546Sopenharmony_ci}
2849bf215546Sopenharmony_ci
2850bf215546Sopenharmony_cistatic void
2851bf215546Sopenharmony_citc_dump_debug_state(struct pipe_context *_pipe, FILE *stream,
2852bf215546Sopenharmony_ci                    unsigned flags)
2853bf215546Sopenharmony_ci{
2854bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
2855bf215546Sopenharmony_ci   struct pipe_context *pipe = tc->pipe;
2856bf215546Sopenharmony_ci
2857bf215546Sopenharmony_ci   tc_sync(tc);
2858bf215546Sopenharmony_ci   pipe->dump_debug_state(pipe, stream, flags);
2859bf215546Sopenharmony_ci}
2860bf215546Sopenharmony_ci
2861bf215546Sopenharmony_cistatic void
2862bf215546Sopenharmony_citc_set_debug_callback(struct pipe_context *_pipe,
2863bf215546Sopenharmony_ci                      const struct util_debug_callback *cb)
2864bf215546Sopenharmony_ci{
2865bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
2866bf215546Sopenharmony_ci   struct pipe_context *pipe = tc->pipe;
2867bf215546Sopenharmony_ci
2868bf215546Sopenharmony_ci   tc_sync(tc);
2869bf215546Sopenharmony_ci
2870bf215546Sopenharmony_ci   /* Drop all synchronous debug callbacks. Drivers are expected to be OK
2871bf215546Sopenharmony_ci    * with this. shader-db will use an environment variable to disable
2872bf215546Sopenharmony_ci    * the threaded context.
2873bf215546Sopenharmony_ci    */
2874bf215546Sopenharmony_ci   if (cb && !cb->async)
2875bf215546Sopenharmony_ci      pipe->set_debug_callback(pipe, NULL);
2876bf215546Sopenharmony_ci   else
2877bf215546Sopenharmony_ci      pipe->set_debug_callback(pipe, cb);
2878bf215546Sopenharmony_ci}
2879bf215546Sopenharmony_ci
2880bf215546Sopenharmony_cistatic void
2881bf215546Sopenharmony_citc_set_log_context(struct pipe_context *_pipe, struct u_log_context *log)
2882bf215546Sopenharmony_ci{
2883bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
2884bf215546Sopenharmony_ci   struct pipe_context *pipe = tc->pipe;
2885bf215546Sopenharmony_ci
2886bf215546Sopenharmony_ci   tc_sync(tc);
2887bf215546Sopenharmony_ci   pipe->set_log_context(pipe, log);
2888bf215546Sopenharmony_ci}
2889bf215546Sopenharmony_ci
2890bf215546Sopenharmony_cistatic void
2891bf215546Sopenharmony_citc_create_fence_fd(struct pipe_context *_pipe,
2892bf215546Sopenharmony_ci                   struct pipe_fence_handle **fence, int fd,
2893bf215546Sopenharmony_ci                   enum pipe_fd_type type)
2894bf215546Sopenharmony_ci{
2895bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
2896bf215546Sopenharmony_ci   struct pipe_context *pipe = tc->pipe;
2897bf215546Sopenharmony_ci
2898bf215546Sopenharmony_ci   tc_sync(tc);
2899bf215546Sopenharmony_ci   pipe->create_fence_fd(pipe, fence, fd, type);
2900bf215546Sopenharmony_ci}
2901bf215546Sopenharmony_ci
2902bf215546Sopenharmony_cistruct tc_fence_call {
2903bf215546Sopenharmony_ci   struct tc_call_base base;
2904bf215546Sopenharmony_ci   struct pipe_fence_handle *fence;
2905bf215546Sopenharmony_ci};
2906bf215546Sopenharmony_ci
2907bf215546Sopenharmony_cistatic uint16_t
2908bf215546Sopenharmony_citc_call_fence_server_sync(struct pipe_context *pipe, void *call, uint64_t *last)
2909bf215546Sopenharmony_ci{
2910bf215546Sopenharmony_ci   struct pipe_fence_handle *fence = to_call(call, tc_fence_call)->fence;
2911bf215546Sopenharmony_ci
2912bf215546Sopenharmony_ci   pipe->fence_server_sync(pipe, fence);
2913bf215546Sopenharmony_ci   pipe->screen->fence_reference(pipe->screen, &fence, NULL);
2914bf215546Sopenharmony_ci   return call_size(tc_fence_call);
2915bf215546Sopenharmony_ci}
2916bf215546Sopenharmony_ci
2917bf215546Sopenharmony_cistatic void
2918bf215546Sopenharmony_citc_fence_server_sync(struct pipe_context *_pipe,
2919bf215546Sopenharmony_ci                     struct pipe_fence_handle *fence)
2920bf215546Sopenharmony_ci{
2921bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
2922bf215546Sopenharmony_ci   struct pipe_screen *screen = tc->pipe->screen;
2923bf215546Sopenharmony_ci   struct tc_fence_call *call = tc_add_call(tc, TC_CALL_fence_server_sync,
2924bf215546Sopenharmony_ci                                            tc_fence_call);
2925bf215546Sopenharmony_ci
2926bf215546Sopenharmony_ci   call->fence = NULL;
2927bf215546Sopenharmony_ci   screen->fence_reference(screen, &call->fence, fence);
2928bf215546Sopenharmony_ci}
2929bf215546Sopenharmony_ci
2930bf215546Sopenharmony_cistatic void
2931bf215546Sopenharmony_citc_fence_server_signal(struct pipe_context *_pipe,
2932bf215546Sopenharmony_ci                           struct pipe_fence_handle *fence)
2933bf215546Sopenharmony_ci{
2934bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
2935bf215546Sopenharmony_ci   struct pipe_context *pipe = tc->pipe;
2936bf215546Sopenharmony_ci   tc_sync(tc);
2937bf215546Sopenharmony_ci   pipe->fence_server_signal(pipe, fence);
2938bf215546Sopenharmony_ci}
2939bf215546Sopenharmony_ci
2940bf215546Sopenharmony_cistatic struct pipe_video_codec *
2941bf215546Sopenharmony_citc_create_video_codec(UNUSED struct pipe_context *_pipe,
2942bf215546Sopenharmony_ci                      UNUSED const struct pipe_video_codec *templ)
2943bf215546Sopenharmony_ci{
2944bf215546Sopenharmony_ci   unreachable("Threaded context should not be enabled for video APIs");
2945bf215546Sopenharmony_ci   return NULL;
2946bf215546Sopenharmony_ci}
2947bf215546Sopenharmony_ci
2948bf215546Sopenharmony_cistatic struct pipe_video_buffer *
2949bf215546Sopenharmony_citc_create_video_buffer(UNUSED struct pipe_context *_pipe,
2950bf215546Sopenharmony_ci                       UNUSED const struct pipe_video_buffer *templ)
2951bf215546Sopenharmony_ci{
2952bf215546Sopenharmony_ci   unreachable("Threaded context should not be enabled for video APIs");
2953bf215546Sopenharmony_ci   return NULL;
2954bf215546Sopenharmony_ci}
2955bf215546Sopenharmony_ci
2956bf215546Sopenharmony_cistruct tc_context_param {
2957bf215546Sopenharmony_ci   struct tc_call_base base;
2958bf215546Sopenharmony_ci   enum pipe_context_param param;
2959bf215546Sopenharmony_ci   unsigned value;
2960bf215546Sopenharmony_ci};
2961bf215546Sopenharmony_ci
2962bf215546Sopenharmony_cistatic uint16_t
2963bf215546Sopenharmony_citc_call_set_context_param(struct pipe_context *pipe, void *call, uint64_t *last)
2964bf215546Sopenharmony_ci{
2965bf215546Sopenharmony_ci   struct tc_context_param *p = to_call(call, tc_context_param);
2966bf215546Sopenharmony_ci
2967bf215546Sopenharmony_ci   if (pipe->set_context_param)
2968bf215546Sopenharmony_ci      pipe->set_context_param(pipe, p->param, p->value);
2969bf215546Sopenharmony_ci
2970bf215546Sopenharmony_ci   return call_size(tc_context_param);
2971bf215546Sopenharmony_ci}
2972bf215546Sopenharmony_ci
2973bf215546Sopenharmony_cistatic void
2974bf215546Sopenharmony_citc_set_context_param(struct pipe_context *_pipe,
2975bf215546Sopenharmony_ci                           enum pipe_context_param param,
2976bf215546Sopenharmony_ci                           unsigned value)
2977bf215546Sopenharmony_ci{
2978bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
2979bf215546Sopenharmony_ci
2980bf215546Sopenharmony_ci   if (param == PIPE_CONTEXT_PARAM_PIN_THREADS_TO_L3_CACHE) {
2981bf215546Sopenharmony_ci      /* Pin the gallium thread as requested. */
2982bf215546Sopenharmony_ci      util_set_thread_affinity(tc->queue.threads[0],
2983bf215546Sopenharmony_ci                               util_get_cpu_caps()->L3_affinity_mask[value],
2984bf215546Sopenharmony_ci                               NULL, util_get_cpu_caps()->num_cpu_mask_bits);
2985bf215546Sopenharmony_ci
2986bf215546Sopenharmony_ci      /* Execute this immediately (without enqueuing).
2987bf215546Sopenharmony_ci       * It's required to be thread-safe.
2988bf215546Sopenharmony_ci       */
2989bf215546Sopenharmony_ci      struct pipe_context *pipe = tc->pipe;
2990bf215546Sopenharmony_ci      if (pipe->set_context_param)
2991bf215546Sopenharmony_ci         pipe->set_context_param(pipe, param, value);
2992bf215546Sopenharmony_ci      return;
2993bf215546Sopenharmony_ci   }
2994bf215546Sopenharmony_ci
2995bf215546Sopenharmony_ci   if (tc->pipe->set_context_param) {
2996bf215546Sopenharmony_ci      struct tc_context_param *call =
2997bf215546Sopenharmony_ci         tc_add_call(tc, TC_CALL_set_context_param, tc_context_param);
2998bf215546Sopenharmony_ci
2999bf215546Sopenharmony_ci      call->param = param;
3000bf215546Sopenharmony_ci      call->value = value;
3001bf215546Sopenharmony_ci   }
3002bf215546Sopenharmony_ci}
3003bf215546Sopenharmony_ci
3004bf215546Sopenharmony_ci
3005bf215546Sopenharmony_ci/********************************************************************
3006bf215546Sopenharmony_ci * draw, launch, clear, blit, copy, flush
3007bf215546Sopenharmony_ci */
3008bf215546Sopenharmony_ci
3009bf215546Sopenharmony_cistruct tc_flush_call {
3010bf215546Sopenharmony_ci   struct tc_call_base base;
3011bf215546Sopenharmony_ci   unsigned flags;
3012bf215546Sopenharmony_ci   struct threaded_context *tc;
3013bf215546Sopenharmony_ci   struct pipe_fence_handle *fence;
3014bf215546Sopenharmony_ci};
3015bf215546Sopenharmony_ci
3016bf215546Sopenharmony_cistatic void
3017bf215546Sopenharmony_citc_flush_queries(struct threaded_context *tc)
3018bf215546Sopenharmony_ci{
3019bf215546Sopenharmony_ci   struct threaded_query *tq, *tmp;
3020bf215546Sopenharmony_ci   LIST_FOR_EACH_ENTRY_SAFE(tq, tmp, &tc->unflushed_queries, head_unflushed) {
3021bf215546Sopenharmony_ci      list_del(&tq->head_unflushed);
3022bf215546Sopenharmony_ci
3023bf215546Sopenharmony_ci      /* Memory release semantics: due to a possible race with
3024bf215546Sopenharmony_ci       * tc_get_query_result, we must ensure that the linked list changes
3025bf215546Sopenharmony_ci       * are visible before setting tq->flushed.
3026bf215546Sopenharmony_ci       */
3027bf215546Sopenharmony_ci      p_atomic_set(&tq->flushed, true);
3028bf215546Sopenharmony_ci   }
3029bf215546Sopenharmony_ci}
3030bf215546Sopenharmony_ci
3031bf215546Sopenharmony_cistatic uint16_t
3032bf215546Sopenharmony_citc_call_flush(struct pipe_context *pipe, void *call, uint64_t *last)
3033bf215546Sopenharmony_ci{
3034bf215546Sopenharmony_ci   struct tc_flush_call *p = to_call(call, tc_flush_call);
3035bf215546Sopenharmony_ci   struct pipe_screen *screen = pipe->screen;
3036bf215546Sopenharmony_ci
3037bf215546Sopenharmony_ci   pipe->flush(pipe, p->fence ? &p->fence : NULL, p->flags);
3038bf215546Sopenharmony_ci   screen->fence_reference(screen, &p->fence, NULL);
3039bf215546Sopenharmony_ci
3040bf215546Sopenharmony_ci   if (!(p->flags & PIPE_FLUSH_DEFERRED))
3041bf215546Sopenharmony_ci      tc_flush_queries(p->tc);
3042bf215546Sopenharmony_ci
3043bf215546Sopenharmony_ci   return call_size(tc_flush_call);
3044bf215546Sopenharmony_ci}
3045bf215546Sopenharmony_ci
3046bf215546Sopenharmony_cistatic void
3047bf215546Sopenharmony_citc_flush(struct pipe_context *_pipe, struct pipe_fence_handle **fence,
3048bf215546Sopenharmony_ci         unsigned flags)
3049bf215546Sopenharmony_ci{
3050bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
3051bf215546Sopenharmony_ci   struct pipe_context *pipe = tc->pipe;
3052bf215546Sopenharmony_ci   struct pipe_screen *screen = pipe->screen;
3053bf215546Sopenharmony_ci   bool async = flags & (PIPE_FLUSH_DEFERRED | PIPE_FLUSH_ASYNC);
3054bf215546Sopenharmony_ci
3055bf215546Sopenharmony_ci   if (async && tc->options.create_fence) {
3056bf215546Sopenharmony_ci      if (fence) {
3057bf215546Sopenharmony_ci         struct tc_batch *next = &tc->batch_slots[tc->next];
3058bf215546Sopenharmony_ci
3059bf215546Sopenharmony_ci         if (!next->token) {
3060bf215546Sopenharmony_ci            next->token = malloc(sizeof(*next->token));
3061bf215546Sopenharmony_ci            if (!next->token)
3062bf215546Sopenharmony_ci               goto out_of_memory;
3063bf215546Sopenharmony_ci
3064bf215546Sopenharmony_ci            pipe_reference_init(&next->token->ref, 1);
3065bf215546Sopenharmony_ci            next->token->tc = tc;
3066bf215546Sopenharmony_ci         }
3067bf215546Sopenharmony_ci
3068bf215546Sopenharmony_ci         screen->fence_reference(screen, fence,
3069bf215546Sopenharmony_ci                                 tc->options.create_fence(pipe, next->token));
3070bf215546Sopenharmony_ci         if (!*fence)
3071bf215546Sopenharmony_ci            goto out_of_memory;
3072bf215546Sopenharmony_ci      }
3073bf215546Sopenharmony_ci
3074bf215546Sopenharmony_ci      struct tc_flush_call *p = tc_add_call(tc, TC_CALL_flush, tc_flush_call);
3075bf215546Sopenharmony_ci      p->tc = tc;
3076bf215546Sopenharmony_ci      p->fence = fence ? *fence : NULL;
3077bf215546Sopenharmony_ci      p->flags = flags | TC_FLUSH_ASYNC;
3078bf215546Sopenharmony_ci
3079bf215546Sopenharmony_ci      if (!(flags & PIPE_FLUSH_DEFERRED))
3080bf215546Sopenharmony_ci         tc_batch_flush(tc);
3081bf215546Sopenharmony_ci      return;
3082bf215546Sopenharmony_ci   }
3083bf215546Sopenharmony_ci
3084bf215546Sopenharmony_ciout_of_memory:
3085bf215546Sopenharmony_ci   tc_sync_msg(tc, flags & PIPE_FLUSH_END_OF_FRAME ? "end of frame" :
3086bf215546Sopenharmony_ci                   flags & PIPE_FLUSH_DEFERRED ? "deferred fence" : "normal");
3087bf215546Sopenharmony_ci
3088bf215546Sopenharmony_ci   if (!(flags & PIPE_FLUSH_DEFERRED))
3089bf215546Sopenharmony_ci      tc_flush_queries(tc);
3090bf215546Sopenharmony_ci   tc_set_driver_thread(tc);
3091bf215546Sopenharmony_ci   pipe->flush(pipe, fence, flags);
3092bf215546Sopenharmony_ci   tc_clear_driver_thread(tc);
3093bf215546Sopenharmony_ci}
3094bf215546Sopenharmony_ci
3095bf215546Sopenharmony_cistruct tc_draw_single {
3096bf215546Sopenharmony_ci   struct tc_call_base base;
3097bf215546Sopenharmony_ci   unsigned index_bias;
3098bf215546Sopenharmony_ci   struct pipe_draw_info info;
3099bf215546Sopenharmony_ci};
3100bf215546Sopenharmony_ci
3101bf215546Sopenharmony_cistruct tc_draw_single_drawid {
3102bf215546Sopenharmony_ci   struct tc_draw_single base;
3103bf215546Sopenharmony_ci   unsigned drawid_offset;
3104bf215546Sopenharmony_ci};
3105bf215546Sopenharmony_ci
3106bf215546Sopenharmony_cistatic uint16_t
3107bf215546Sopenharmony_citc_call_draw_single_drawid(struct pipe_context *pipe, void *call, uint64_t *last)
3108bf215546Sopenharmony_ci{
3109bf215546Sopenharmony_ci   struct tc_draw_single_drawid *info_drawid = to_call(call, tc_draw_single_drawid);
3110bf215546Sopenharmony_ci   struct tc_draw_single *info = &info_drawid->base;
3111bf215546Sopenharmony_ci
3112bf215546Sopenharmony_ci   /* u_threaded_context stores start/count in min/max_index for single draws. */
3113bf215546Sopenharmony_ci   /* Drivers using u_threaded_context shouldn't use min/max_index. */
3114bf215546Sopenharmony_ci   struct pipe_draw_start_count_bias draw;
3115bf215546Sopenharmony_ci
3116bf215546Sopenharmony_ci   draw.start = info->info.min_index;
3117bf215546Sopenharmony_ci   draw.count = info->info.max_index;
3118bf215546Sopenharmony_ci   draw.index_bias = info->index_bias;
3119bf215546Sopenharmony_ci
3120bf215546Sopenharmony_ci   info->info.index_bounds_valid = false;
3121bf215546Sopenharmony_ci   info->info.has_user_indices = false;
3122bf215546Sopenharmony_ci   info->info.take_index_buffer_ownership = false;
3123bf215546Sopenharmony_ci
3124bf215546Sopenharmony_ci   pipe->draw_vbo(pipe, &info->info, info_drawid->drawid_offset, NULL, &draw, 1);
3125bf215546Sopenharmony_ci   if (info->info.index_size)
3126bf215546Sopenharmony_ci      tc_drop_resource_reference(info->info.index.resource);
3127bf215546Sopenharmony_ci
3128bf215546Sopenharmony_ci   return call_size(tc_draw_single_drawid);
3129bf215546Sopenharmony_ci}
3130bf215546Sopenharmony_ci
3131bf215546Sopenharmony_cistatic void
3132bf215546Sopenharmony_cisimplify_draw_info(struct pipe_draw_info *info)
3133bf215546Sopenharmony_ci{
3134bf215546Sopenharmony_ci   /* Clear these fields to facilitate draw merging.
3135bf215546Sopenharmony_ci    * Drivers shouldn't use them.
3136bf215546Sopenharmony_ci    */
3137bf215546Sopenharmony_ci   info->has_user_indices = false;
3138bf215546Sopenharmony_ci   info->index_bounds_valid = false;
3139bf215546Sopenharmony_ci   info->take_index_buffer_ownership = false;
3140bf215546Sopenharmony_ci   info->index_bias_varies = false;
3141bf215546Sopenharmony_ci   info->_pad = 0;
3142bf215546Sopenharmony_ci
3143bf215546Sopenharmony_ci   /* This shouldn't be set when merging single draws. */
3144bf215546Sopenharmony_ci   info->increment_draw_id = false;
3145bf215546Sopenharmony_ci
3146bf215546Sopenharmony_ci   if (info->index_size) {
3147bf215546Sopenharmony_ci      if (!info->primitive_restart)
3148bf215546Sopenharmony_ci         info->restart_index = 0;
3149bf215546Sopenharmony_ci   } else {
3150bf215546Sopenharmony_ci      assert(!info->primitive_restart);
3151bf215546Sopenharmony_ci      info->primitive_restart = false;
3152bf215546Sopenharmony_ci      info->restart_index = 0;
3153bf215546Sopenharmony_ci      info->index.resource = NULL;
3154bf215546Sopenharmony_ci   }
3155bf215546Sopenharmony_ci}
3156bf215546Sopenharmony_ci
3157bf215546Sopenharmony_cistatic bool
3158bf215546Sopenharmony_ciis_next_call_a_mergeable_draw(struct tc_draw_single *first,
3159bf215546Sopenharmony_ci                              struct tc_draw_single *next)
3160bf215546Sopenharmony_ci{
3161bf215546Sopenharmony_ci   if (next->base.call_id != TC_CALL_draw_single)
3162bf215546Sopenharmony_ci      return false;
3163bf215546Sopenharmony_ci
3164bf215546Sopenharmony_ci   simplify_draw_info(&next->info);
3165bf215546Sopenharmony_ci
3166bf215546Sopenharmony_ci   STATIC_ASSERT(offsetof(struct pipe_draw_info, min_index) ==
3167bf215546Sopenharmony_ci                 sizeof(struct pipe_draw_info) - 8);
3168bf215546Sopenharmony_ci   STATIC_ASSERT(offsetof(struct pipe_draw_info, max_index) ==
3169bf215546Sopenharmony_ci                 sizeof(struct pipe_draw_info) - 4);
3170bf215546Sopenharmony_ci   /* All fields must be the same except start and count. */
3171bf215546Sopenharmony_ci   /* u_threaded_context stores start/count in min/max_index for single draws. */
3172bf215546Sopenharmony_ci   return memcmp((uint32_t*)&first->info, (uint32_t*)&next->info,
3173bf215546Sopenharmony_ci                 DRAW_INFO_SIZE_WITHOUT_MIN_MAX_INDEX) == 0;
3174bf215546Sopenharmony_ci}
3175bf215546Sopenharmony_ci
3176bf215546Sopenharmony_cistatic uint16_t
3177bf215546Sopenharmony_citc_call_draw_single(struct pipe_context *pipe, void *call, uint64_t *last_ptr)
3178bf215546Sopenharmony_ci{
3179bf215546Sopenharmony_ci   /* Draw call merging. */
3180bf215546Sopenharmony_ci   struct tc_draw_single *first = to_call(call, tc_draw_single);
3181bf215546Sopenharmony_ci   struct tc_draw_single *last = (struct tc_draw_single *)last_ptr;
3182bf215546Sopenharmony_ci   struct tc_draw_single *next = get_next_call(first, tc_draw_single);
3183bf215546Sopenharmony_ci
3184bf215546Sopenharmony_ci   /* If at least 2 consecutive draw calls can be merged... */
3185bf215546Sopenharmony_ci   if (next != last &&
3186bf215546Sopenharmony_ci       next->base.call_id == TC_CALL_draw_single) {
3187bf215546Sopenharmony_ci      simplify_draw_info(&first->info);
3188bf215546Sopenharmony_ci
3189bf215546Sopenharmony_ci      if (is_next_call_a_mergeable_draw(first, next)) {
3190bf215546Sopenharmony_ci         /* The maximum number of merged draws is given by the batch size. */
3191bf215546Sopenharmony_ci         struct pipe_draw_start_count_bias multi[TC_SLOTS_PER_BATCH / call_size(tc_draw_single)];
3192bf215546Sopenharmony_ci         unsigned num_draws = 2;
3193bf215546Sopenharmony_ci         bool index_bias_varies = first->index_bias != next->index_bias;
3194bf215546Sopenharmony_ci
3195bf215546Sopenharmony_ci         /* u_threaded_context stores start/count in min/max_index for single draws. */
3196bf215546Sopenharmony_ci         multi[0].start = first->info.min_index;
3197bf215546Sopenharmony_ci         multi[0].count = first->info.max_index;
3198bf215546Sopenharmony_ci         multi[0].index_bias = first->index_bias;
3199bf215546Sopenharmony_ci         multi[1].start = next->info.min_index;
3200bf215546Sopenharmony_ci         multi[1].count = next->info.max_index;
3201bf215546Sopenharmony_ci         multi[1].index_bias = next->index_bias;
3202bf215546Sopenharmony_ci
3203bf215546Sopenharmony_ci         /* Find how many other draws can be merged. */
3204bf215546Sopenharmony_ci         next = get_next_call(next, tc_draw_single);
3205bf215546Sopenharmony_ci         for (; next != last && is_next_call_a_mergeable_draw(first, next);
3206bf215546Sopenharmony_ci              next = get_next_call(next, tc_draw_single), num_draws++) {
3207bf215546Sopenharmony_ci            /* u_threaded_context stores start/count in min/max_index for single draws. */
3208bf215546Sopenharmony_ci            multi[num_draws].start = next->info.min_index;
3209bf215546Sopenharmony_ci            multi[num_draws].count = next->info.max_index;
3210bf215546Sopenharmony_ci            multi[num_draws].index_bias = next->index_bias;
3211bf215546Sopenharmony_ci            index_bias_varies |= first->index_bias != next->index_bias;
3212bf215546Sopenharmony_ci         }
3213bf215546Sopenharmony_ci
3214bf215546Sopenharmony_ci         first->info.index_bias_varies = index_bias_varies;
3215bf215546Sopenharmony_ci         pipe->draw_vbo(pipe, &first->info, 0, NULL, multi, num_draws);
3216bf215546Sopenharmony_ci
3217bf215546Sopenharmony_ci         /* Since all draws use the same index buffer, drop all references at once. */
3218bf215546Sopenharmony_ci         if (first->info.index_size)
3219bf215546Sopenharmony_ci            pipe_drop_resource_references(first->info.index.resource, num_draws);
3220bf215546Sopenharmony_ci
3221bf215546Sopenharmony_ci         return call_size(tc_draw_single) * num_draws;
3222bf215546Sopenharmony_ci      }
3223bf215546Sopenharmony_ci   }
3224bf215546Sopenharmony_ci
3225bf215546Sopenharmony_ci   /* u_threaded_context stores start/count in min/max_index for single draws. */
3226bf215546Sopenharmony_ci   /* Drivers using u_threaded_context shouldn't use min/max_index. */
3227bf215546Sopenharmony_ci   struct pipe_draw_start_count_bias draw;
3228bf215546Sopenharmony_ci
3229bf215546Sopenharmony_ci   draw.start = first->info.min_index;
3230bf215546Sopenharmony_ci   draw.count = first->info.max_index;
3231bf215546Sopenharmony_ci   draw.index_bias = first->index_bias;
3232bf215546Sopenharmony_ci
3233bf215546Sopenharmony_ci   first->info.index_bounds_valid = false;
3234bf215546Sopenharmony_ci   first->info.has_user_indices = false;
3235bf215546Sopenharmony_ci   first->info.take_index_buffer_ownership = false;
3236bf215546Sopenharmony_ci
3237bf215546Sopenharmony_ci   pipe->draw_vbo(pipe, &first->info, 0, NULL, &draw, 1);
3238bf215546Sopenharmony_ci   if (first->info.index_size)
3239bf215546Sopenharmony_ci      tc_drop_resource_reference(first->info.index.resource);
3240bf215546Sopenharmony_ci
3241bf215546Sopenharmony_ci   return call_size(tc_draw_single);
3242bf215546Sopenharmony_ci}
3243bf215546Sopenharmony_ci
3244bf215546Sopenharmony_cistruct tc_draw_indirect {
3245bf215546Sopenharmony_ci   struct tc_call_base base;
3246bf215546Sopenharmony_ci   struct pipe_draw_start_count_bias draw;
3247bf215546Sopenharmony_ci   struct pipe_draw_info info;
3248bf215546Sopenharmony_ci   struct pipe_draw_indirect_info indirect;
3249bf215546Sopenharmony_ci};
3250bf215546Sopenharmony_ci
3251bf215546Sopenharmony_cistatic uint16_t
3252bf215546Sopenharmony_citc_call_draw_indirect(struct pipe_context *pipe, void *call, uint64_t *last)
3253bf215546Sopenharmony_ci{
3254bf215546Sopenharmony_ci   struct tc_draw_indirect *info = to_call(call, tc_draw_indirect);
3255bf215546Sopenharmony_ci
3256bf215546Sopenharmony_ci   info->info.index_bounds_valid = false;
3257bf215546Sopenharmony_ci   info->info.take_index_buffer_ownership = false;
3258bf215546Sopenharmony_ci
3259bf215546Sopenharmony_ci   pipe->draw_vbo(pipe, &info->info, 0, &info->indirect, &info->draw, 1);
3260bf215546Sopenharmony_ci   if (info->info.index_size)
3261bf215546Sopenharmony_ci      tc_drop_resource_reference(info->info.index.resource);
3262bf215546Sopenharmony_ci
3263bf215546Sopenharmony_ci   tc_drop_resource_reference(info->indirect.buffer);
3264bf215546Sopenharmony_ci   tc_drop_resource_reference(info->indirect.indirect_draw_count);
3265bf215546Sopenharmony_ci   tc_drop_so_target_reference(info->indirect.count_from_stream_output);
3266bf215546Sopenharmony_ci   return call_size(tc_draw_indirect);
3267bf215546Sopenharmony_ci}
3268bf215546Sopenharmony_ci
3269bf215546Sopenharmony_cistruct tc_draw_multi {
3270bf215546Sopenharmony_ci   struct tc_call_base base;
3271bf215546Sopenharmony_ci   unsigned num_draws;
3272bf215546Sopenharmony_ci   struct pipe_draw_info info;
3273bf215546Sopenharmony_ci   struct pipe_draw_start_count_bias slot[]; /* variable-sized array */
3274bf215546Sopenharmony_ci};
3275bf215546Sopenharmony_ci
3276bf215546Sopenharmony_cistatic uint16_t
3277bf215546Sopenharmony_citc_call_draw_multi(struct pipe_context *pipe, void *call, uint64_t *last)
3278bf215546Sopenharmony_ci{
3279bf215546Sopenharmony_ci   struct tc_draw_multi *info = (struct tc_draw_multi*)call;
3280bf215546Sopenharmony_ci
3281bf215546Sopenharmony_ci   info->info.has_user_indices = false;
3282bf215546Sopenharmony_ci   info->info.index_bounds_valid = false;
3283bf215546Sopenharmony_ci   info->info.take_index_buffer_ownership = false;
3284bf215546Sopenharmony_ci
3285bf215546Sopenharmony_ci   pipe->draw_vbo(pipe, &info->info, 0, NULL, info->slot, info->num_draws);
3286bf215546Sopenharmony_ci   if (info->info.index_size)
3287bf215546Sopenharmony_ci      tc_drop_resource_reference(info->info.index.resource);
3288bf215546Sopenharmony_ci
3289bf215546Sopenharmony_ci   return info->base.num_slots;
3290bf215546Sopenharmony_ci}
3291bf215546Sopenharmony_ci
3292bf215546Sopenharmony_ci#define DRAW_INFO_SIZE_WITHOUT_INDEXBUF_AND_MIN_MAX_INDEX \
3293bf215546Sopenharmony_ci   offsetof(struct pipe_draw_info, index)
3294bf215546Sopenharmony_ci
3295bf215546Sopenharmony_civoid
3296bf215546Sopenharmony_citc_draw_vbo(struct pipe_context *_pipe, const struct pipe_draw_info *info,
3297bf215546Sopenharmony_ci            unsigned drawid_offset,
3298bf215546Sopenharmony_ci            const struct pipe_draw_indirect_info *indirect,
3299bf215546Sopenharmony_ci            const struct pipe_draw_start_count_bias *draws,
3300bf215546Sopenharmony_ci            unsigned num_draws)
3301bf215546Sopenharmony_ci{
3302bf215546Sopenharmony_ci   STATIC_ASSERT(DRAW_INFO_SIZE_WITHOUT_INDEXBUF_AND_MIN_MAX_INDEX +
3303bf215546Sopenharmony_ci                 sizeof(intptr_t) == offsetof(struct pipe_draw_info, min_index));
3304bf215546Sopenharmony_ci
3305bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
3306bf215546Sopenharmony_ci   unsigned index_size = info->index_size;
3307bf215546Sopenharmony_ci   bool has_user_indices = info->has_user_indices;
3308bf215546Sopenharmony_ci
3309bf215546Sopenharmony_ci   if (unlikely(indirect)) {
3310bf215546Sopenharmony_ci      assert(!has_user_indices);
3311bf215546Sopenharmony_ci      assert(num_draws == 1);
3312bf215546Sopenharmony_ci
3313bf215546Sopenharmony_ci      struct tc_draw_indirect *p =
3314bf215546Sopenharmony_ci         tc_add_call(tc, TC_CALL_draw_indirect, tc_draw_indirect);
3315bf215546Sopenharmony_ci      struct tc_buffer_list *next = &tc->buffer_lists[tc->next_buf_list];
3316bf215546Sopenharmony_ci
3317bf215546Sopenharmony_ci      if (index_size) {
3318bf215546Sopenharmony_ci         if (!info->take_index_buffer_ownership) {
3319bf215546Sopenharmony_ci            tc_set_resource_reference(&p->info.index.resource,
3320bf215546Sopenharmony_ci                                      info->index.resource);
3321bf215546Sopenharmony_ci         }
3322bf215546Sopenharmony_ci         tc_add_to_buffer_list(tc, next, info->index.resource);
3323bf215546Sopenharmony_ci      }
3324bf215546Sopenharmony_ci      memcpy(&p->info, info, DRAW_INFO_SIZE_WITHOUT_MIN_MAX_INDEX);
3325bf215546Sopenharmony_ci
3326bf215546Sopenharmony_ci      tc_set_resource_reference(&p->indirect.buffer, indirect->buffer);
3327bf215546Sopenharmony_ci      tc_set_resource_reference(&p->indirect.indirect_draw_count,
3328bf215546Sopenharmony_ci                                indirect->indirect_draw_count);
3329bf215546Sopenharmony_ci      p->indirect.count_from_stream_output = NULL;
3330bf215546Sopenharmony_ci      pipe_so_target_reference(&p->indirect.count_from_stream_output,
3331bf215546Sopenharmony_ci                               indirect->count_from_stream_output);
3332bf215546Sopenharmony_ci
3333bf215546Sopenharmony_ci      if (indirect->buffer)
3334bf215546Sopenharmony_ci         tc_add_to_buffer_list(tc, next, indirect->buffer);
3335bf215546Sopenharmony_ci      if (indirect->indirect_draw_count)
3336bf215546Sopenharmony_ci         tc_add_to_buffer_list(tc, next, indirect->indirect_draw_count);
3337bf215546Sopenharmony_ci      if (indirect->count_from_stream_output)
3338bf215546Sopenharmony_ci         tc_add_to_buffer_list(tc, next, indirect->count_from_stream_output->buffer);
3339bf215546Sopenharmony_ci
3340bf215546Sopenharmony_ci      memcpy(&p->indirect, indirect, sizeof(*indirect));
3341bf215546Sopenharmony_ci      p->draw.start = draws[0].start;
3342bf215546Sopenharmony_ci
3343bf215546Sopenharmony_ci      /* This must be after tc_add_call, which can flush the batch. */
3344bf215546Sopenharmony_ci      if (unlikely(tc->add_all_gfx_bindings_to_buffer_list))
3345bf215546Sopenharmony_ci         tc_add_all_gfx_bindings_to_buffer_list(tc);
3346bf215546Sopenharmony_ci      return;
3347bf215546Sopenharmony_ci   }
3348bf215546Sopenharmony_ci
3349bf215546Sopenharmony_ci   if (num_draws == 1) {
3350bf215546Sopenharmony_ci      /* Single draw. */
3351bf215546Sopenharmony_ci      if (index_size && has_user_indices) {
3352bf215546Sopenharmony_ci         unsigned size = draws[0].count * index_size;
3353bf215546Sopenharmony_ci         struct pipe_resource *buffer = NULL;
3354bf215546Sopenharmony_ci         unsigned offset;
3355bf215546Sopenharmony_ci
3356bf215546Sopenharmony_ci         if (!size)
3357bf215546Sopenharmony_ci            return;
3358bf215546Sopenharmony_ci
3359bf215546Sopenharmony_ci         /* This must be done before adding draw_vbo, because it could generate
3360bf215546Sopenharmony_ci          * e.g. transfer_unmap and flush partially-uninitialized draw_vbo
3361bf215546Sopenharmony_ci          * to the driver if it was done afterwards.
3362bf215546Sopenharmony_ci          */
3363bf215546Sopenharmony_ci         u_upload_data(tc->base.stream_uploader, 0, size, 4,
3364bf215546Sopenharmony_ci                       (uint8_t*)info->index.user + draws[0].start * index_size,
3365bf215546Sopenharmony_ci                       &offset, &buffer);
3366bf215546Sopenharmony_ci         if (unlikely(!buffer))
3367bf215546Sopenharmony_ci            return;
3368bf215546Sopenharmony_ci
3369bf215546Sopenharmony_ci         struct tc_draw_single *p = drawid_offset > 0 ?
3370bf215546Sopenharmony_ci            &tc_add_call(tc, TC_CALL_draw_single_drawid, tc_draw_single_drawid)->base :
3371bf215546Sopenharmony_ci            tc_add_call(tc, TC_CALL_draw_single, tc_draw_single);
3372bf215546Sopenharmony_ci         memcpy(&p->info, info, DRAW_INFO_SIZE_WITHOUT_INDEXBUF_AND_MIN_MAX_INDEX);
3373bf215546Sopenharmony_ci         p->info.index.resource = buffer;
3374bf215546Sopenharmony_ci         if (drawid_offset > 0)
3375bf215546Sopenharmony_ci            ((struct tc_draw_single_drawid*)p)->drawid_offset = drawid_offset;
3376bf215546Sopenharmony_ci         /* u_threaded_context stores start/count in min/max_index for single draws. */
3377bf215546Sopenharmony_ci         p->info.min_index = offset >> util_logbase2(index_size);
3378bf215546Sopenharmony_ci         p->info.max_index = draws[0].count;
3379bf215546Sopenharmony_ci         p->index_bias = draws[0].index_bias;
3380bf215546Sopenharmony_ci      } else {
3381bf215546Sopenharmony_ci         /* Non-indexed call or indexed with a real index buffer. */
3382bf215546Sopenharmony_ci         struct tc_draw_single *p = drawid_offset > 0 ?
3383bf215546Sopenharmony_ci            &tc_add_call(tc, TC_CALL_draw_single_drawid, tc_draw_single_drawid)->base :
3384bf215546Sopenharmony_ci            tc_add_call(tc, TC_CALL_draw_single, tc_draw_single);
3385bf215546Sopenharmony_ci         if (index_size) {
3386bf215546Sopenharmony_ci            if (!info->take_index_buffer_ownership) {
3387bf215546Sopenharmony_ci               tc_set_resource_reference(&p->info.index.resource,
3388bf215546Sopenharmony_ci                                         info->index.resource);
3389bf215546Sopenharmony_ci            }
3390bf215546Sopenharmony_ci            tc_add_to_buffer_list(tc, &tc->buffer_lists[tc->next_buf_list], info->index.resource);
3391bf215546Sopenharmony_ci         }
3392bf215546Sopenharmony_ci         if (drawid_offset > 0)
3393bf215546Sopenharmony_ci            ((struct tc_draw_single_drawid*)p)->drawid_offset = drawid_offset;
3394bf215546Sopenharmony_ci         memcpy(&p->info, info, DRAW_INFO_SIZE_WITHOUT_MIN_MAX_INDEX);
3395bf215546Sopenharmony_ci         /* u_threaded_context stores start/count in min/max_index for single draws. */
3396bf215546Sopenharmony_ci         p->info.min_index = draws[0].start;
3397bf215546Sopenharmony_ci         p->info.max_index = draws[0].count;
3398bf215546Sopenharmony_ci         p->index_bias = draws[0].index_bias;
3399bf215546Sopenharmony_ci      }
3400bf215546Sopenharmony_ci
3401bf215546Sopenharmony_ci      /* This must be after tc_add_call, which can flush the batch. */
3402bf215546Sopenharmony_ci      if (unlikely(tc->add_all_gfx_bindings_to_buffer_list))
3403bf215546Sopenharmony_ci         tc_add_all_gfx_bindings_to_buffer_list(tc);
3404bf215546Sopenharmony_ci      return;
3405bf215546Sopenharmony_ci   }
3406bf215546Sopenharmony_ci
3407bf215546Sopenharmony_ci   const int draw_overhead_bytes = sizeof(struct tc_draw_multi);
3408bf215546Sopenharmony_ci   const int one_draw_slot_bytes = sizeof(((struct tc_draw_multi*)NULL)->slot[0]);
3409bf215546Sopenharmony_ci   const int slots_for_one_draw = DIV_ROUND_UP(draw_overhead_bytes + one_draw_slot_bytes,
3410bf215546Sopenharmony_ci                                               sizeof(struct tc_call_base));
3411bf215546Sopenharmony_ci   /* Multi draw. */
3412bf215546Sopenharmony_ci   if (index_size && has_user_indices) {
3413bf215546Sopenharmony_ci      struct pipe_resource *buffer = NULL;
3414bf215546Sopenharmony_ci      unsigned buffer_offset, total_count = 0;
3415bf215546Sopenharmony_ci      unsigned index_size_shift = util_logbase2(index_size);
3416bf215546Sopenharmony_ci      uint8_t *ptr = NULL;
3417bf215546Sopenharmony_ci
3418bf215546Sopenharmony_ci      /* Get the total count. */
3419bf215546Sopenharmony_ci      for (unsigned i = 0; i < num_draws; i++)
3420bf215546Sopenharmony_ci         total_count += draws[i].count;
3421bf215546Sopenharmony_ci
3422bf215546Sopenharmony_ci      if (!total_count)
3423bf215546Sopenharmony_ci         return;
3424bf215546Sopenharmony_ci
3425bf215546Sopenharmony_ci      /* Allocate space for all index buffers.
3426bf215546Sopenharmony_ci       *
3427bf215546Sopenharmony_ci       * This must be done before adding draw_vbo, because it could generate
3428bf215546Sopenharmony_ci       * e.g. transfer_unmap and flush partially-uninitialized draw_vbo
3429bf215546Sopenharmony_ci       * to the driver if it was done afterwards.
3430bf215546Sopenharmony_ci       */
3431bf215546Sopenharmony_ci      u_upload_alloc(tc->base.stream_uploader, 0,
3432bf215546Sopenharmony_ci                     total_count << index_size_shift, 4,
3433bf215546Sopenharmony_ci                     &buffer_offset, &buffer, (void**)&ptr);
3434bf215546Sopenharmony_ci      if (unlikely(!buffer))
3435bf215546Sopenharmony_ci         return;
3436bf215546Sopenharmony_ci
3437bf215546Sopenharmony_ci      int total_offset = 0;
3438bf215546Sopenharmony_ci      unsigned offset = 0;
3439bf215546Sopenharmony_ci      while (num_draws) {
3440bf215546Sopenharmony_ci         struct tc_batch *next = &tc->batch_slots[tc->next];
3441bf215546Sopenharmony_ci
3442bf215546Sopenharmony_ci         int nb_slots_left = TC_SLOTS_PER_BATCH - next->num_total_slots;
3443bf215546Sopenharmony_ci         /* If there isn't enough place for one draw, try to fill the next one */
3444bf215546Sopenharmony_ci         if (nb_slots_left < slots_for_one_draw)
3445bf215546Sopenharmony_ci            nb_slots_left = TC_SLOTS_PER_BATCH;
3446bf215546Sopenharmony_ci         const int size_left_bytes = nb_slots_left * sizeof(struct tc_call_base);
3447bf215546Sopenharmony_ci
3448bf215546Sopenharmony_ci         /* How many draws can we fit in the current batch */
3449bf215546Sopenharmony_ci         const int dr = MIN2(num_draws, (size_left_bytes - draw_overhead_bytes) / one_draw_slot_bytes);
3450bf215546Sopenharmony_ci
3451bf215546Sopenharmony_ci         struct tc_draw_multi *p =
3452bf215546Sopenharmony_ci            tc_add_slot_based_call(tc, TC_CALL_draw_multi, tc_draw_multi,
3453bf215546Sopenharmony_ci                                   dr);
3454bf215546Sopenharmony_ci         memcpy(&p->info, info, DRAW_INFO_SIZE_WITHOUT_INDEXBUF_AND_MIN_MAX_INDEX);
3455bf215546Sopenharmony_ci
3456bf215546Sopenharmony_ci         if (total_offset == 0)
3457bf215546Sopenharmony_ci            /* the first slot inherits the reference from u_upload_alloc() */
3458bf215546Sopenharmony_ci            p->info.index.resource = buffer;
3459bf215546Sopenharmony_ci         else
3460bf215546Sopenharmony_ci            /* all following slots need a new reference */
3461bf215546Sopenharmony_ci            tc_set_resource_reference(&p->info.index.resource, buffer);
3462bf215546Sopenharmony_ci
3463bf215546Sopenharmony_ci         p->num_draws = dr;
3464bf215546Sopenharmony_ci
3465bf215546Sopenharmony_ci         /* Upload index buffers. */
3466bf215546Sopenharmony_ci         for (unsigned i = 0; i < dr; i++) {
3467bf215546Sopenharmony_ci            unsigned count = draws[i + total_offset].count;
3468bf215546Sopenharmony_ci
3469bf215546Sopenharmony_ci            if (!count) {
3470bf215546Sopenharmony_ci               p->slot[i].start = 0;
3471bf215546Sopenharmony_ci               p->slot[i].count = 0;
3472bf215546Sopenharmony_ci               p->slot[i].index_bias = 0;
3473bf215546Sopenharmony_ci               continue;
3474bf215546Sopenharmony_ci            }
3475bf215546Sopenharmony_ci
3476bf215546Sopenharmony_ci            unsigned size = count << index_size_shift;
3477bf215546Sopenharmony_ci            memcpy(ptr + offset,
3478bf215546Sopenharmony_ci                   (uint8_t*)info->index.user +
3479bf215546Sopenharmony_ci                   (draws[i + total_offset].start << index_size_shift), size);
3480bf215546Sopenharmony_ci            p->slot[i].start = (buffer_offset + offset) >> index_size_shift;
3481bf215546Sopenharmony_ci            p->slot[i].count = count;
3482bf215546Sopenharmony_ci            p->slot[i].index_bias = draws[i + total_offset].index_bias;
3483bf215546Sopenharmony_ci            offset += size;
3484bf215546Sopenharmony_ci         }
3485bf215546Sopenharmony_ci
3486bf215546Sopenharmony_ci         total_offset += dr;
3487bf215546Sopenharmony_ci         num_draws -= dr;
3488bf215546Sopenharmony_ci      }
3489bf215546Sopenharmony_ci   } else {
3490bf215546Sopenharmony_ci      int total_offset = 0;
3491bf215546Sopenharmony_ci      bool take_index_buffer_ownership = info->take_index_buffer_ownership;
3492bf215546Sopenharmony_ci      while (num_draws) {
3493bf215546Sopenharmony_ci         struct tc_batch *next = &tc->batch_slots[tc->next];
3494bf215546Sopenharmony_ci
3495bf215546Sopenharmony_ci         int nb_slots_left = TC_SLOTS_PER_BATCH - next->num_total_slots;
3496bf215546Sopenharmony_ci         /* If there isn't enough place for one draw, try to fill the next one */
3497bf215546Sopenharmony_ci         if (nb_slots_left < slots_for_one_draw)
3498bf215546Sopenharmony_ci            nb_slots_left = TC_SLOTS_PER_BATCH;
3499bf215546Sopenharmony_ci         const int size_left_bytes = nb_slots_left * sizeof(struct tc_call_base);
3500bf215546Sopenharmony_ci
3501bf215546Sopenharmony_ci         /* How many draws can we fit in the current batch */
3502bf215546Sopenharmony_ci         const int dr = MIN2(num_draws, (size_left_bytes - draw_overhead_bytes) / one_draw_slot_bytes);
3503bf215546Sopenharmony_ci
3504bf215546Sopenharmony_ci         /* Non-indexed call or indexed with a real index buffer. */
3505bf215546Sopenharmony_ci         struct tc_draw_multi *p =
3506bf215546Sopenharmony_ci            tc_add_slot_based_call(tc, TC_CALL_draw_multi, tc_draw_multi,
3507bf215546Sopenharmony_ci                                   dr);
3508bf215546Sopenharmony_ci         if (index_size) {
3509bf215546Sopenharmony_ci            if (!take_index_buffer_ownership) {
3510bf215546Sopenharmony_ci               tc_set_resource_reference(&p->info.index.resource,
3511bf215546Sopenharmony_ci                                         info->index.resource);
3512bf215546Sopenharmony_ci            }
3513bf215546Sopenharmony_ci            tc_add_to_buffer_list(tc, &tc->buffer_lists[tc->next_buf_list], info->index.resource);
3514bf215546Sopenharmony_ci         }
3515bf215546Sopenharmony_ci         take_index_buffer_ownership = false;
3516bf215546Sopenharmony_ci         memcpy(&p->info, info, DRAW_INFO_SIZE_WITHOUT_MIN_MAX_INDEX);
3517bf215546Sopenharmony_ci         p->num_draws = dr;
3518bf215546Sopenharmony_ci         memcpy(p->slot, &draws[total_offset], sizeof(draws[0]) * dr);
3519bf215546Sopenharmony_ci         num_draws -= dr;
3520bf215546Sopenharmony_ci
3521bf215546Sopenharmony_ci         total_offset += dr;
3522bf215546Sopenharmony_ci      }
3523bf215546Sopenharmony_ci   }
3524bf215546Sopenharmony_ci
3525bf215546Sopenharmony_ci   /* This must be after tc_add_*call, which can flush the batch. */
3526bf215546Sopenharmony_ci   if (unlikely(tc->add_all_gfx_bindings_to_buffer_list))
3527bf215546Sopenharmony_ci      tc_add_all_gfx_bindings_to_buffer_list(tc);
3528bf215546Sopenharmony_ci}
3529bf215546Sopenharmony_ci
3530bf215546Sopenharmony_cistruct tc_draw_vstate_single {
3531bf215546Sopenharmony_ci   struct tc_call_base base;
3532bf215546Sopenharmony_ci   struct pipe_draw_start_count_bias draw;
3533bf215546Sopenharmony_ci
3534bf215546Sopenharmony_ci   /* The following states must be together without holes because they are
3535bf215546Sopenharmony_ci    * compared by draw merging.
3536bf215546Sopenharmony_ci    */
3537bf215546Sopenharmony_ci   struct pipe_vertex_state *state;
3538bf215546Sopenharmony_ci   uint32_t partial_velem_mask;
3539bf215546Sopenharmony_ci   struct pipe_draw_vertex_state_info info;
3540bf215546Sopenharmony_ci};
3541bf215546Sopenharmony_ci
3542bf215546Sopenharmony_cistatic bool
3543bf215546Sopenharmony_ciis_next_call_a_mergeable_draw_vstate(struct tc_draw_vstate_single *first,
3544bf215546Sopenharmony_ci                                     struct tc_draw_vstate_single *next)
3545bf215546Sopenharmony_ci{
3546bf215546Sopenharmony_ci   if (next->base.call_id != TC_CALL_draw_vstate_single)
3547bf215546Sopenharmony_ci      return false;
3548bf215546Sopenharmony_ci
3549bf215546Sopenharmony_ci   return !memcmp(&first->state, &next->state,
3550bf215546Sopenharmony_ci                  offsetof(struct tc_draw_vstate_single, info) +
3551bf215546Sopenharmony_ci                  sizeof(struct pipe_draw_vertex_state_info) -
3552bf215546Sopenharmony_ci                  offsetof(struct tc_draw_vstate_single, state));
3553bf215546Sopenharmony_ci}
3554bf215546Sopenharmony_ci
3555bf215546Sopenharmony_cistatic uint16_t
3556bf215546Sopenharmony_citc_call_draw_vstate_single(struct pipe_context *pipe, void *call, uint64_t *last_ptr)
3557bf215546Sopenharmony_ci{
3558bf215546Sopenharmony_ci   /* Draw call merging. */
3559bf215546Sopenharmony_ci   struct tc_draw_vstate_single *first = to_call(call, tc_draw_vstate_single);
3560bf215546Sopenharmony_ci   struct tc_draw_vstate_single *last = (struct tc_draw_vstate_single *)last_ptr;
3561bf215546Sopenharmony_ci   struct tc_draw_vstate_single *next = get_next_call(first, tc_draw_vstate_single);
3562bf215546Sopenharmony_ci
3563bf215546Sopenharmony_ci   /* If at least 2 consecutive draw calls can be merged... */
3564bf215546Sopenharmony_ci   if (next != last &&
3565bf215546Sopenharmony_ci       is_next_call_a_mergeable_draw_vstate(first, next)) {
3566bf215546Sopenharmony_ci      /* The maximum number of merged draws is given by the batch size. */
3567bf215546Sopenharmony_ci      struct pipe_draw_start_count_bias draws[TC_SLOTS_PER_BATCH /
3568bf215546Sopenharmony_ci                                              call_size(tc_draw_vstate_single)];
3569bf215546Sopenharmony_ci      unsigned num_draws = 2;
3570bf215546Sopenharmony_ci
3571bf215546Sopenharmony_ci      draws[0] = first->draw;
3572bf215546Sopenharmony_ci      draws[1] = next->draw;
3573bf215546Sopenharmony_ci
3574bf215546Sopenharmony_ci      /* Find how many other draws can be merged. */
3575bf215546Sopenharmony_ci      next = get_next_call(next, tc_draw_vstate_single);
3576bf215546Sopenharmony_ci      for (; next != last &&
3577bf215546Sopenharmony_ci           is_next_call_a_mergeable_draw_vstate(first, next);
3578bf215546Sopenharmony_ci           next = get_next_call(next, tc_draw_vstate_single),
3579bf215546Sopenharmony_ci           num_draws++)
3580bf215546Sopenharmony_ci         draws[num_draws] = next->draw;
3581bf215546Sopenharmony_ci
3582bf215546Sopenharmony_ci      pipe->draw_vertex_state(pipe, first->state, first->partial_velem_mask,
3583bf215546Sopenharmony_ci                              first->info, draws, num_draws);
3584bf215546Sopenharmony_ci      /* Since all draws use the same state, drop all references at once. */
3585bf215546Sopenharmony_ci      tc_drop_vertex_state_references(first->state, num_draws);
3586bf215546Sopenharmony_ci
3587bf215546Sopenharmony_ci      return call_size(tc_draw_vstate_single) * num_draws;
3588bf215546Sopenharmony_ci   }
3589bf215546Sopenharmony_ci
3590bf215546Sopenharmony_ci   pipe->draw_vertex_state(pipe, first->state, first->partial_velem_mask,
3591bf215546Sopenharmony_ci                           first->info, &first->draw, 1);
3592bf215546Sopenharmony_ci   tc_drop_vertex_state_references(first->state, 1);
3593bf215546Sopenharmony_ci   return call_size(tc_draw_vstate_single);
3594bf215546Sopenharmony_ci}
3595bf215546Sopenharmony_ci
3596bf215546Sopenharmony_cistruct tc_draw_vstate_multi {
3597bf215546Sopenharmony_ci   struct tc_call_base base;
3598bf215546Sopenharmony_ci   uint32_t partial_velem_mask;
3599bf215546Sopenharmony_ci   struct pipe_draw_vertex_state_info info;
3600bf215546Sopenharmony_ci   unsigned num_draws;
3601bf215546Sopenharmony_ci   struct pipe_vertex_state *state;
3602bf215546Sopenharmony_ci   struct pipe_draw_start_count_bias slot[0];
3603bf215546Sopenharmony_ci};
3604bf215546Sopenharmony_ci
3605bf215546Sopenharmony_cistatic uint16_t
3606bf215546Sopenharmony_citc_call_draw_vstate_multi(struct pipe_context *pipe, void *call, uint64_t *last)
3607bf215546Sopenharmony_ci{
3608bf215546Sopenharmony_ci   struct tc_draw_vstate_multi *info = (struct tc_draw_vstate_multi*)call;
3609bf215546Sopenharmony_ci
3610bf215546Sopenharmony_ci   pipe->draw_vertex_state(pipe, info->state, info->partial_velem_mask,
3611bf215546Sopenharmony_ci                           info->info, info->slot, info->num_draws);
3612bf215546Sopenharmony_ci   tc_drop_vertex_state_references(info->state, 1);
3613bf215546Sopenharmony_ci   return info->base.num_slots;
3614bf215546Sopenharmony_ci}
3615bf215546Sopenharmony_ci
3616bf215546Sopenharmony_cistatic void
3617bf215546Sopenharmony_citc_draw_vertex_state(struct pipe_context *_pipe,
3618bf215546Sopenharmony_ci                     struct pipe_vertex_state *state,
3619bf215546Sopenharmony_ci                     uint32_t partial_velem_mask,
3620bf215546Sopenharmony_ci                     struct pipe_draw_vertex_state_info info,
3621bf215546Sopenharmony_ci                     const struct pipe_draw_start_count_bias *draws,
3622bf215546Sopenharmony_ci                     unsigned num_draws)
3623bf215546Sopenharmony_ci{
3624bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
3625bf215546Sopenharmony_ci
3626bf215546Sopenharmony_ci   if (num_draws == 1) {
3627bf215546Sopenharmony_ci      /* Single draw. */
3628bf215546Sopenharmony_ci      struct tc_draw_vstate_single *p =
3629bf215546Sopenharmony_ci         tc_add_call(tc, TC_CALL_draw_vstate_single, tc_draw_vstate_single);
3630bf215546Sopenharmony_ci      p->partial_velem_mask = partial_velem_mask;
3631bf215546Sopenharmony_ci      p->draw = draws[0];
3632bf215546Sopenharmony_ci      p->info.mode = info.mode;
3633bf215546Sopenharmony_ci      p->info.take_vertex_state_ownership = false;
3634bf215546Sopenharmony_ci
3635bf215546Sopenharmony_ci      /* This should be always 0 for simplicity because we assume that
3636bf215546Sopenharmony_ci       * index_bias doesn't vary.
3637bf215546Sopenharmony_ci       */
3638bf215546Sopenharmony_ci      assert(draws[0].index_bias == 0);
3639bf215546Sopenharmony_ci
3640bf215546Sopenharmony_ci      if (!info.take_vertex_state_ownership)
3641bf215546Sopenharmony_ci         tc_set_vertex_state_reference(&p->state, state);
3642bf215546Sopenharmony_ci      else
3643bf215546Sopenharmony_ci         p->state = state;
3644bf215546Sopenharmony_ci
3645bf215546Sopenharmony_ci
3646bf215546Sopenharmony_ci      /* This must be after tc_add_*call, which can flush the batch. */
3647bf215546Sopenharmony_ci      if (unlikely(tc->add_all_gfx_bindings_to_buffer_list))
3648bf215546Sopenharmony_ci         tc_add_all_gfx_bindings_to_buffer_list(tc);
3649bf215546Sopenharmony_ci      return;
3650bf215546Sopenharmony_ci   }
3651bf215546Sopenharmony_ci
3652bf215546Sopenharmony_ci   const int draw_overhead_bytes = sizeof(struct tc_draw_vstate_multi);
3653bf215546Sopenharmony_ci   const int one_draw_slot_bytes = sizeof(((struct tc_draw_vstate_multi*)NULL)->slot[0]);
3654bf215546Sopenharmony_ci   const int slots_for_one_draw = DIV_ROUND_UP(draw_overhead_bytes + one_draw_slot_bytes,
3655bf215546Sopenharmony_ci                                               sizeof(struct tc_call_base));
3656bf215546Sopenharmony_ci   /* Multi draw. */
3657bf215546Sopenharmony_ci   int total_offset = 0;
3658bf215546Sopenharmony_ci   bool take_vertex_state_ownership = info.take_vertex_state_ownership;
3659bf215546Sopenharmony_ci   while (num_draws) {
3660bf215546Sopenharmony_ci      struct tc_batch *next = &tc->batch_slots[tc->next];
3661bf215546Sopenharmony_ci
3662bf215546Sopenharmony_ci      int nb_slots_left = TC_SLOTS_PER_BATCH - next->num_total_slots;
3663bf215546Sopenharmony_ci      /* If there isn't enough place for one draw, try to fill the next one */
3664bf215546Sopenharmony_ci      if (nb_slots_left < slots_for_one_draw)
3665bf215546Sopenharmony_ci         nb_slots_left = TC_SLOTS_PER_BATCH;
3666bf215546Sopenharmony_ci      const int size_left_bytes = nb_slots_left * sizeof(struct tc_call_base);
3667bf215546Sopenharmony_ci
3668bf215546Sopenharmony_ci      /* How many draws can we fit in the current batch */
3669bf215546Sopenharmony_ci      const int dr = MIN2(num_draws, (size_left_bytes - draw_overhead_bytes) / one_draw_slot_bytes);
3670bf215546Sopenharmony_ci
3671bf215546Sopenharmony_ci      /* Non-indexed call or indexed with a real index buffer. */
3672bf215546Sopenharmony_ci      struct tc_draw_vstate_multi *p =
3673bf215546Sopenharmony_ci         tc_add_slot_based_call(tc, TC_CALL_draw_vstate_multi, tc_draw_vstate_multi, dr);
3674bf215546Sopenharmony_ci
3675bf215546Sopenharmony_ci      if (!take_vertex_state_ownership)
3676bf215546Sopenharmony_ci         tc_set_vertex_state_reference(&p->state, state);
3677bf215546Sopenharmony_ci      else
3678bf215546Sopenharmony_ci         p->state = state;
3679bf215546Sopenharmony_ci
3680bf215546Sopenharmony_ci      take_vertex_state_ownership = false;
3681bf215546Sopenharmony_ci      p->partial_velem_mask = partial_velem_mask;
3682bf215546Sopenharmony_ci      p->info.mode = info.mode;
3683bf215546Sopenharmony_ci      p->info.take_vertex_state_ownership = false;
3684bf215546Sopenharmony_ci      p->num_draws = dr;
3685bf215546Sopenharmony_ci      memcpy(p->slot, &draws[total_offset], sizeof(draws[0]) * dr);
3686bf215546Sopenharmony_ci      num_draws -= dr;
3687bf215546Sopenharmony_ci
3688bf215546Sopenharmony_ci      total_offset += dr;
3689bf215546Sopenharmony_ci   }
3690bf215546Sopenharmony_ci
3691bf215546Sopenharmony_ci
3692bf215546Sopenharmony_ci   /* This must be after tc_add_*call, which can flush the batch. */
3693bf215546Sopenharmony_ci   if (unlikely(tc->add_all_gfx_bindings_to_buffer_list))
3694bf215546Sopenharmony_ci      tc_add_all_gfx_bindings_to_buffer_list(tc);
3695bf215546Sopenharmony_ci}
3696bf215546Sopenharmony_ci
3697bf215546Sopenharmony_cistruct tc_launch_grid_call {
3698bf215546Sopenharmony_ci   struct tc_call_base base;
3699bf215546Sopenharmony_ci   struct pipe_grid_info info;
3700bf215546Sopenharmony_ci};
3701bf215546Sopenharmony_ci
3702bf215546Sopenharmony_cistatic uint16_t
3703bf215546Sopenharmony_citc_call_launch_grid(struct pipe_context *pipe, void *call, uint64_t *last)
3704bf215546Sopenharmony_ci{
3705bf215546Sopenharmony_ci   struct pipe_grid_info *p = &to_call(call, tc_launch_grid_call)->info;
3706bf215546Sopenharmony_ci
3707bf215546Sopenharmony_ci   pipe->launch_grid(pipe, p);
3708bf215546Sopenharmony_ci   tc_drop_resource_reference(p->indirect);
3709bf215546Sopenharmony_ci   return call_size(tc_launch_grid_call);
3710bf215546Sopenharmony_ci}
3711bf215546Sopenharmony_ci
3712bf215546Sopenharmony_cistatic void
3713bf215546Sopenharmony_citc_launch_grid(struct pipe_context *_pipe,
3714bf215546Sopenharmony_ci               const struct pipe_grid_info *info)
3715bf215546Sopenharmony_ci{
3716bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
3717bf215546Sopenharmony_ci   struct tc_launch_grid_call *p = tc_add_call(tc, TC_CALL_launch_grid,
3718bf215546Sopenharmony_ci                                               tc_launch_grid_call);
3719bf215546Sopenharmony_ci   assert(info->input == NULL);
3720bf215546Sopenharmony_ci
3721bf215546Sopenharmony_ci   tc_set_resource_reference(&p->info.indirect, info->indirect);
3722bf215546Sopenharmony_ci   memcpy(&p->info, info, sizeof(*info));
3723bf215546Sopenharmony_ci
3724bf215546Sopenharmony_ci   if (info->indirect)
3725bf215546Sopenharmony_ci      tc_add_to_buffer_list(tc, &tc->buffer_lists[tc->next_buf_list], info->indirect);
3726bf215546Sopenharmony_ci
3727bf215546Sopenharmony_ci   /* This must be after tc_add_*call, which can flush the batch. */
3728bf215546Sopenharmony_ci   if (unlikely(tc->add_all_compute_bindings_to_buffer_list))
3729bf215546Sopenharmony_ci      tc_add_all_compute_bindings_to_buffer_list(tc);
3730bf215546Sopenharmony_ci}
3731bf215546Sopenharmony_ci
3732bf215546Sopenharmony_cistatic uint16_t
3733bf215546Sopenharmony_citc_call_resource_copy_region(struct pipe_context *pipe, void *call, uint64_t *last)
3734bf215546Sopenharmony_ci{
3735bf215546Sopenharmony_ci   struct tc_resource_copy_region *p = to_call(call, tc_resource_copy_region);
3736bf215546Sopenharmony_ci
3737bf215546Sopenharmony_ci   pipe->resource_copy_region(pipe, p->dst, p->dst_level, p->dstx, p->dsty,
3738bf215546Sopenharmony_ci                              p->dstz, p->src, p->src_level, &p->src_box);
3739bf215546Sopenharmony_ci   tc_drop_resource_reference(p->dst);
3740bf215546Sopenharmony_ci   tc_drop_resource_reference(p->src);
3741bf215546Sopenharmony_ci   return call_size(tc_resource_copy_region);
3742bf215546Sopenharmony_ci}
3743bf215546Sopenharmony_ci
3744bf215546Sopenharmony_cistatic void
3745bf215546Sopenharmony_citc_resource_copy_region(struct pipe_context *_pipe,
3746bf215546Sopenharmony_ci                        struct pipe_resource *dst, unsigned dst_level,
3747bf215546Sopenharmony_ci                        unsigned dstx, unsigned dsty, unsigned dstz,
3748bf215546Sopenharmony_ci                        struct pipe_resource *src, unsigned src_level,
3749bf215546Sopenharmony_ci                        const struct pipe_box *src_box)
3750bf215546Sopenharmony_ci{
3751bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
3752bf215546Sopenharmony_ci   struct threaded_resource *tdst = threaded_resource(dst);
3753bf215546Sopenharmony_ci   struct tc_resource_copy_region *p =
3754bf215546Sopenharmony_ci      tc_add_call(tc, TC_CALL_resource_copy_region,
3755bf215546Sopenharmony_ci                  tc_resource_copy_region);
3756bf215546Sopenharmony_ci
3757bf215546Sopenharmony_ci   if (dst->target == PIPE_BUFFER)
3758bf215546Sopenharmony_ci      tc_buffer_disable_cpu_storage(dst);
3759bf215546Sopenharmony_ci
3760bf215546Sopenharmony_ci   tc_set_resource_reference(&p->dst, dst);
3761bf215546Sopenharmony_ci   p->dst_level = dst_level;
3762bf215546Sopenharmony_ci   p->dstx = dstx;
3763bf215546Sopenharmony_ci   p->dsty = dsty;
3764bf215546Sopenharmony_ci   p->dstz = dstz;
3765bf215546Sopenharmony_ci   tc_set_resource_reference(&p->src, src);
3766bf215546Sopenharmony_ci   p->src_level = src_level;
3767bf215546Sopenharmony_ci   p->src_box = *src_box;
3768bf215546Sopenharmony_ci
3769bf215546Sopenharmony_ci   if (dst->target == PIPE_BUFFER) {
3770bf215546Sopenharmony_ci      struct tc_buffer_list *next = &tc->buffer_lists[tc->next_buf_list];
3771bf215546Sopenharmony_ci
3772bf215546Sopenharmony_ci      tc_add_to_buffer_list(tc, next, src);
3773bf215546Sopenharmony_ci      tc_add_to_buffer_list(tc, next, dst);
3774bf215546Sopenharmony_ci
3775bf215546Sopenharmony_ci      util_range_add(&tdst->b, &tdst->valid_buffer_range,
3776bf215546Sopenharmony_ci                     dstx, dstx + src_box->width);
3777bf215546Sopenharmony_ci   }
3778bf215546Sopenharmony_ci}
3779bf215546Sopenharmony_ci
3780bf215546Sopenharmony_cistruct tc_blit_call {
3781bf215546Sopenharmony_ci   struct tc_call_base base;
3782bf215546Sopenharmony_ci   struct pipe_blit_info info;
3783bf215546Sopenharmony_ci};
3784bf215546Sopenharmony_ci
3785bf215546Sopenharmony_cistatic uint16_t
3786bf215546Sopenharmony_citc_call_blit(struct pipe_context *pipe, void *call, uint64_t *last)
3787bf215546Sopenharmony_ci{
3788bf215546Sopenharmony_ci   struct pipe_blit_info *blit = &to_call(call, tc_blit_call)->info;
3789bf215546Sopenharmony_ci
3790bf215546Sopenharmony_ci   pipe->blit(pipe, blit);
3791bf215546Sopenharmony_ci   tc_drop_resource_reference(blit->dst.resource);
3792bf215546Sopenharmony_ci   tc_drop_resource_reference(blit->src.resource);
3793bf215546Sopenharmony_ci   return call_size(tc_blit_call);
3794bf215546Sopenharmony_ci}
3795bf215546Sopenharmony_ci
3796bf215546Sopenharmony_cistatic void
3797bf215546Sopenharmony_citc_blit(struct pipe_context *_pipe, const struct pipe_blit_info *info)
3798bf215546Sopenharmony_ci{
3799bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
3800bf215546Sopenharmony_ci   struct tc_blit_call *blit = tc_add_call(tc, TC_CALL_blit, tc_blit_call);
3801bf215546Sopenharmony_ci
3802bf215546Sopenharmony_ci   tc_set_resource_reference(&blit->info.dst.resource, info->dst.resource);
3803bf215546Sopenharmony_ci   tc_set_resource_reference(&blit->info.src.resource, info->src.resource);
3804bf215546Sopenharmony_ci   memcpy(&blit->info, info, sizeof(*info));
3805bf215546Sopenharmony_ci}
3806bf215546Sopenharmony_ci
3807bf215546Sopenharmony_cistruct tc_generate_mipmap {
3808bf215546Sopenharmony_ci   struct tc_call_base base;
3809bf215546Sopenharmony_ci   enum pipe_format format;
3810bf215546Sopenharmony_ci   unsigned base_level;
3811bf215546Sopenharmony_ci   unsigned last_level;
3812bf215546Sopenharmony_ci   unsigned first_layer;
3813bf215546Sopenharmony_ci   unsigned last_layer;
3814bf215546Sopenharmony_ci   struct pipe_resource *res;
3815bf215546Sopenharmony_ci};
3816bf215546Sopenharmony_ci
3817bf215546Sopenharmony_cistatic uint16_t
3818bf215546Sopenharmony_citc_call_generate_mipmap(struct pipe_context *pipe, void *call, uint64_t *last)
3819bf215546Sopenharmony_ci{
3820bf215546Sopenharmony_ci   struct tc_generate_mipmap *p = to_call(call, tc_generate_mipmap);
3821bf215546Sopenharmony_ci   ASSERTED bool result = pipe->generate_mipmap(pipe, p->res, p->format,
3822bf215546Sopenharmony_ci                                                    p->base_level,
3823bf215546Sopenharmony_ci                                                    p->last_level,
3824bf215546Sopenharmony_ci                                                    p->first_layer,
3825bf215546Sopenharmony_ci                                                    p->last_layer);
3826bf215546Sopenharmony_ci   assert(result);
3827bf215546Sopenharmony_ci   tc_drop_resource_reference(p->res);
3828bf215546Sopenharmony_ci   return call_size(tc_generate_mipmap);
3829bf215546Sopenharmony_ci}
3830bf215546Sopenharmony_ci
3831bf215546Sopenharmony_cistatic bool
3832bf215546Sopenharmony_citc_generate_mipmap(struct pipe_context *_pipe,
3833bf215546Sopenharmony_ci                   struct pipe_resource *res,
3834bf215546Sopenharmony_ci                   enum pipe_format format,
3835bf215546Sopenharmony_ci                   unsigned base_level,
3836bf215546Sopenharmony_ci                   unsigned last_level,
3837bf215546Sopenharmony_ci                   unsigned first_layer,
3838bf215546Sopenharmony_ci                   unsigned last_layer)
3839bf215546Sopenharmony_ci{
3840bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
3841bf215546Sopenharmony_ci   struct pipe_context *pipe = tc->pipe;
3842bf215546Sopenharmony_ci   struct pipe_screen *screen = pipe->screen;
3843bf215546Sopenharmony_ci   unsigned bind = PIPE_BIND_SAMPLER_VIEW;
3844bf215546Sopenharmony_ci
3845bf215546Sopenharmony_ci   if (util_format_is_depth_or_stencil(format))
3846bf215546Sopenharmony_ci      bind = PIPE_BIND_DEPTH_STENCIL;
3847bf215546Sopenharmony_ci   else
3848bf215546Sopenharmony_ci      bind = PIPE_BIND_RENDER_TARGET;
3849bf215546Sopenharmony_ci
3850bf215546Sopenharmony_ci   if (!screen->is_format_supported(screen, format, res->target,
3851bf215546Sopenharmony_ci                                    res->nr_samples, res->nr_storage_samples,
3852bf215546Sopenharmony_ci                                    bind))
3853bf215546Sopenharmony_ci      return false;
3854bf215546Sopenharmony_ci
3855bf215546Sopenharmony_ci   struct tc_generate_mipmap *p =
3856bf215546Sopenharmony_ci      tc_add_call(tc, TC_CALL_generate_mipmap, tc_generate_mipmap);
3857bf215546Sopenharmony_ci
3858bf215546Sopenharmony_ci   tc_set_resource_reference(&p->res, res);
3859bf215546Sopenharmony_ci   p->format = format;
3860bf215546Sopenharmony_ci   p->base_level = base_level;
3861bf215546Sopenharmony_ci   p->last_level = last_level;
3862bf215546Sopenharmony_ci   p->first_layer = first_layer;
3863bf215546Sopenharmony_ci   p->last_layer = last_layer;
3864bf215546Sopenharmony_ci   return true;
3865bf215546Sopenharmony_ci}
3866bf215546Sopenharmony_ci
3867bf215546Sopenharmony_cistruct tc_resource_call {
3868bf215546Sopenharmony_ci   struct tc_call_base base;
3869bf215546Sopenharmony_ci   struct pipe_resource *resource;
3870bf215546Sopenharmony_ci};
3871bf215546Sopenharmony_ci
3872bf215546Sopenharmony_cistatic uint16_t
3873bf215546Sopenharmony_citc_call_flush_resource(struct pipe_context *pipe, void *call, uint64_t *last)
3874bf215546Sopenharmony_ci{
3875bf215546Sopenharmony_ci   struct pipe_resource *resource = to_call(call, tc_resource_call)->resource;
3876bf215546Sopenharmony_ci
3877bf215546Sopenharmony_ci   pipe->flush_resource(pipe, resource);
3878bf215546Sopenharmony_ci   tc_drop_resource_reference(resource);
3879bf215546Sopenharmony_ci   return call_size(tc_resource_call);
3880bf215546Sopenharmony_ci}
3881bf215546Sopenharmony_ci
3882bf215546Sopenharmony_cistatic void
3883bf215546Sopenharmony_citc_flush_resource(struct pipe_context *_pipe, struct pipe_resource *resource)
3884bf215546Sopenharmony_ci{
3885bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
3886bf215546Sopenharmony_ci   struct tc_resource_call *call = tc_add_call(tc, TC_CALL_flush_resource,
3887bf215546Sopenharmony_ci                                               tc_resource_call);
3888bf215546Sopenharmony_ci
3889bf215546Sopenharmony_ci   tc_set_resource_reference(&call->resource, resource);
3890bf215546Sopenharmony_ci}
3891bf215546Sopenharmony_ci
3892bf215546Sopenharmony_cistatic uint16_t
3893bf215546Sopenharmony_citc_call_invalidate_resource(struct pipe_context *pipe, void *call, uint64_t *last)
3894bf215546Sopenharmony_ci{
3895bf215546Sopenharmony_ci   struct pipe_resource *resource = to_call(call, tc_resource_call)->resource;
3896bf215546Sopenharmony_ci
3897bf215546Sopenharmony_ci   pipe->invalidate_resource(pipe, resource);
3898bf215546Sopenharmony_ci   tc_drop_resource_reference(resource);
3899bf215546Sopenharmony_ci   return call_size(tc_resource_call);
3900bf215546Sopenharmony_ci}
3901bf215546Sopenharmony_ci
3902bf215546Sopenharmony_cistatic void
3903bf215546Sopenharmony_citc_invalidate_resource(struct pipe_context *_pipe,
3904bf215546Sopenharmony_ci                       struct pipe_resource *resource)
3905bf215546Sopenharmony_ci{
3906bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
3907bf215546Sopenharmony_ci
3908bf215546Sopenharmony_ci   if (resource->target == PIPE_BUFFER) {
3909bf215546Sopenharmony_ci      /* This can fail, in which case we simply ignore the invalidation request. */
3910bf215546Sopenharmony_ci      struct threaded_resource *tbuf = threaded_resource(resource);
3911bf215546Sopenharmony_ci      tc_touch_buffer(tc, tbuf);
3912bf215546Sopenharmony_ci      tc_invalidate_buffer(tc, tbuf);
3913bf215546Sopenharmony_ci      return;
3914bf215546Sopenharmony_ci   }
3915bf215546Sopenharmony_ci
3916bf215546Sopenharmony_ci   struct tc_resource_call *call = tc_add_call(tc, TC_CALL_invalidate_resource,
3917bf215546Sopenharmony_ci                                               tc_resource_call);
3918bf215546Sopenharmony_ci   tc_set_resource_reference(&call->resource, resource);
3919bf215546Sopenharmony_ci}
3920bf215546Sopenharmony_ci
3921bf215546Sopenharmony_cistruct tc_clear {
3922bf215546Sopenharmony_ci   struct tc_call_base base;
3923bf215546Sopenharmony_ci   bool scissor_state_set;
3924bf215546Sopenharmony_ci   uint8_t stencil;
3925bf215546Sopenharmony_ci   uint16_t buffers;
3926bf215546Sopenharmony_ci   float depth;
3927bf215546Sopenharmony_ci   struct pipe_scissor_state scissor_state;
3928bf215546Sopenharmony_ci   union pipe_color_union color;
3929bf215546Sopenharmony_ci};
3930bf215546Sopenharmony_ci
3931bf215546Sopenharmony_cistatic uint16_t
3932bf215546Sopenharmony_citc_call_clear(struct pipe_context *pipe, void *call, uint64_t *last)
3933bf215546Sopenharmony_ci{
3934bf215546Sopenharmony_ci   struct tc_clear *p = to_call(call, tc_clear);
3935bf215546Sopenharmony_ci
3936bf215546Sopenharmony_ci   pipe->clear(pipe, p->buffers, p->scissor_state_set ? &p->scissor_state : NULL, &p->color, p->depth, p->stencil);
3937bf215546Sopenharmony_ci   return call_size(tc_clear);
3938bf215546Sopenharmony_ci}
3939bf215546Sopenharmony_ci
3940bf215546Sopenharmony_cistatic void
3941bf215546Sopenharmony_citc_clear(struct pipe_context *_pipe, unsigned buffers, const struct pipe_scissor_state *scissor_state,
3942bf215546Sopenharmony_ci         const union pipe_color_union *color, double depth,
3943bf215546Sopenharmony_ci         unsigned stencil)
3944bf215546Sopenharmony_ci{
3945bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
3946bf215546Sopenharmony_ci   struct tc_clear *p = tc_add_call(tc, TC_CALL_clear, tc_clear);
3947bf215546Sopenharmony_ci
3948bf215546Sopenharmony_ci   p->buffers = buffers;
3949bf215546Sopenharmony_ci   if (scissor_state)
3950bf215546Sopenharmony_ci      p->scissor_state = *scissor_state;
3951bf215546Sopenharmony_ci   p->scissor_state_set = !!scissor_state;
3952bf215546Sopenharmony_ci   p->color = *color;
3953bf215546Sopenharmony_ci   p->depth = depth;
3954bf215546Sopenharmony_ci   p->stencil = stencil;
3955bf215546Sopenharmony_ci}
3956bf215546Sopenharmony_ci
3957bf215546Sopenharmony_cistruct tc_clear_render_target {
3958bf215546Sopenharmony_ci   struct tc_call_base base;
3959bf215546Sopenharmony_ci   bool render_condition_enabled;
3960bf215546Sopenharmony_ci   unsigned dstx;
3961bf215546Sopenharmony_ci   unsigned dsty;
3962bf215546Sopenharmony_ci   unsigned width;
3963bf215546Sopenharmony_ci   unsigned height;
3964bf215546Sopenharmony_ci   union pipe_color_union color;
3965bf215546Sopenharmony_ci   struct pipe_surface *dst;
3966bf215546Sopenharmony_ci};
3967bf215546Sopenharmony_ci
3968bf215546Sopenharmony_cistatic uint16_t
3969bf215546Sopenharmony_citc_call_clear_render_target(struct pipe_context *pipe, void *call, uint64_t *last)
3970bf215546Sopenharmony_ci{
3971bf215546Sopenharmony_ci   struct tc_clear_render_target *p = to_call(call, tc_clear_render_target);
3972bf215546Sopenharmony_ci
3973bf215546Sopenharmony_ci   pipe->clear_render_target(pipe, p->dst, &p->color, p->dstx, p->dsty, p->width, p->height,
3974bf215546Sopenharmony_ci                             p->render_condition_enabled);
3975bf215546Sopenharmony_ci   tc_drop_surface_reference(p->dst);
3976bf215546Sopenharmony_ci   return call_size(tc_clear_render_target);
3977bf215546Sopenharmony_ci}
3978bf215546Sopenharmony_ci
3979bf215546Sopenharmony_cistatic void
3980bf215546Sopenharmony_citc_clear_render_target(struct pipe_context *_pipe,
3981bf215546Sopenharmony_ci                       struct pipe_surface *dst,
3982bf215546Sopenharmony_ci                       const union pipe_color_union *color,
3983bf215546Sopenharmony_ci                       unsigned dstx, unsigned dsty,
3984bf215546Sopenharmony_ci                       unsigned width, unsigned height,
3985bf215546Sopenharmony_ci                       bool render_condition_enabled)
3986bf215546Sopenharmony_ci{
3987bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
3988bf215546Sopenharmony_ci   struct tc_clear_render_target *p = tc_add_call(tc, TC_CALL_clear_render_target, tc_clear_render_target);
3989bf215546Sopenharmony_ci   p->dst = NULL;
3990bf215546Sopenharmony_ci   pipe_surface_reference(&p->dst, dst);
3991bf215546Sopenharmony_ci   p->color = *color;
3992bf215546Sopenharmony_ci   p->dstx = dstx;
3993bf215546Sopenharmony_ci   p->dsty = dsty;
3994bf215546Sopenharmony_ci   p->width = width;
3995bf215546Sopenharmony_ci   p->height = height;
3996bf215546Sopenharmony_ci   p->render_condition_enabled = render_condition_enabled;
3997bf215546Sopenharmony_ci}
3998bf215546Sopenharmony_ci
3999bf215546Sopenharmony_ci
4000bf215546Sopenharmony_cistruct tc_clear_depth_stencil {
4001bf215546Sopenharmony_ci   struct tc_call_base base;
4002bf215546Sopenharmony_ci   bool render_condition_enabled;
4003bf215546Sopenharmony_ci   float depth;
4004bf215546Sopenharmony_ci   unsigned clear_flags;
4005bf215546Sopenharmony_ci   unsigned stencil;
4006bf215546Sopenharmony_ci   unsigned dstx;
4007bf215546Sopenharmony_ci   unsigned dsty;
4008bf215546Sopenharmony_ci   unsigned width;
4009bf215546Sopenharmony_ci   unsigned height;
4010bf215546Sopenharmony_ci   struct pipe_surface *dst;
4011bf215546Sopenharmony_ci};
4012bf215546Sopenharmony_ci
4013bf215546Sopenharmony_ci
4014bf215546Sopenharmony_cistatic uint16_t
4015bf215546Sopenharmony_citc_call_clear_depth_stencil(struct pipe_context *pipe, void *call, uint64_t *last)
4016bf215546Sopenharmony_ci{
4017bf215546Sopenharmony_ci   struct tc_clear_depth_stencil *p = to_call(call, tc_clear_depth_stencil);
4018bf215546Sopenharmony_ci
4019bf215546Sopenharmony_ci   pipe->clear_depth_stencil(pipe, p->dst, p->clear_flags, p->depth, p->stencil,
4020bf215546Sopenharmony_ci                             p->dstx, p->dsty, p->width, p->height,
4021bf215546Sopenharmony_ci                             p->render_condition_enabled);
4022bf215546Sopenharmony_ci   tc_drop_surface_reference(p->dst);
4023bf215546Sopenharmony_ci   return call_size(tc_clear_depth_stencil);
4024bf215546Sopenharmony_ci}
4025bf215546Sopenharmony_ci
4026bf215546Sopenharmony_cistatic void
4027bf215546Sopenharmony_citc_clear_depth_stencil(struct pipe_context *_pipe,
4028bf215546Sopenharmony_ci                       struct pipe_surface *dst, unsigned clear_flags,
4029bf215546Sopenharmony_ci                       double depth, unsigned stencil, unsigned dstx,
4030bf215546Sopenharmony_ci                       unsigned dsty, unsigned width, unsigned height,
4031bf215546Sopenharmony_ci                       bool render_condition_enabled)
4032bf215546Sopenharmony_ci{
4033bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
4034bf215546Sopenharmony_ci   struct tc_clear_depth_stencil *p = tc_add_call(tc, TC_CALL_clear_depth_stencil, tc_clear_depth_stencil);
4035bf215546Sopenharmony_ci   p->dst = NULL;
4036bf215546Sopenharmony_ci   pipe_surface_reference(&p->dst, dst);
4037bf215546Sopenharmony_ci   p->clear_flags = clear_flags;
4038bf215546Sopenharmony_ci   p->depth = depth;
4039bf215546Sopenharmony_ci   p->stencil = stencil;
4040bf215546Sopenharmony_ci   p->dstx = dstx;
4041bf215546Sopenharmony_ci   p->dsty = dsty;
4042bf215546Sopenharmony_ci   p->width = width;
4043bf215546Sopenharmony_ci   p->height = height;
4044bf215546Sopenharmony_ci   p->render_condition_enabled = render_condition_enabled;
4045bf215546Sopenharmony_ci}
4046bf215546Sopenharmony_ci
4047bf215546Sopenharmony_cistruct tc_clear_buffer {
4048bf215546Sopenharmony_ci   struct tc_call_base base;
4049bf215546Sopenharmony_ci   uint8_t clear_value_size;
4050bf215546Sopenharmony_ci   unsigned offset;
4051bf215546Sopenharmony_ci   unsigned size;
4052bf215546Sopenharmony_ci   char clear_value[16];
4053bf215546Sopenharmony_ci   struct pipe_resource *res;
4054bf215546Sopenharmony_ci};
4055bf215546Sopenharmony_ci
4056bf215546Sopenharmony_cistatic uint16_t
4057bf215546Sopenharmony_citc_call_clear_buffer(struct pipe_context *pipe, void *call, uint64_t *last)
4058bf215546Sopenharmony_ci{
4059bf215546Sopenharmony_ci   struct tc_clear_buffer *p = to_call(call, tc_clear_buffer);
4060bf215546Sopenharmony_ci
4061bf215546Sopenharmony_ci   pipe->clear_buffer(pipe, p->res, p->offset, p->size, p->clear_value,
4062bf215546Sopenharmony_ci                      p->clear_value_size);
4063bf215546Sopenharmony_ci   tc_drop_resource_reference(p->res);
4064bf215546Sopenharmony_ci   return call_size(tc_clear_buffer);
4065bf215546Sopenharmony_ci}
4066bf215546Sopenharmony_ci
4067bf215546Sopenharmony_cistatic void
4068bf215546Sopenharmony_citc_clear_buffer(struct pipe_context *_pipe, struct pipe_resource *res,
4069bf215546Sopenharmony_ci                unsigned offset, unsigned size,
4070bf215546Sopenharmony_ci                const void *clear_value, int clear_value_size)
4071bf215546Sopenharmony_ci{
4072bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
4073bf215546Sopenharmony_ci   struct threaded_resource *tres = threaded_resource(res);
4074bf215546Sopenharmony_ci   struct tc_clear_buffer *p =
4075bf215546Sopenharmony_ci      tc_add_call(tc, TC_CALL_clear_buffer, tc_clear_buffer);
4076bf215546Sopenharmony_ci
4077bf215546Sopenharmony_ci   tc_buffer_disable_cpu_storage(res);
4078bf215546Sopenharmony_ci
4079bf215546Sopenharmony_ci   tc_set_resource_reference(&p->res, res);
4080bf215546Sopenharmony_ci   tc_add_to_buffer_list(tc, &tc->buffer_lists[tc->next_buf_list], res);
4081bf215546Sopenharmony_ci   p->offset = offset;
4082bf215546Sopenharmony_ci   p->size = size;
4083bf215546Sopenharmony_ci   memcpy(p->clear_value, clear_value, clear_value_size);
4084bf215546Sopenharmony_ci   p->clear_value_size = clear_value_size;
4085bf215546Sopenharmony_ci
4086bf215546Sopenharmony_ci   util_range_add(&tres->b, &tres->valid_buffer_range, offset, offset + size);
4087bf215546Sopenharmony_ci}
4088bf215546Sopenharmony_ci
4089bf215546Sopenharmony_cistruct tc_clear_texture {
4090bf215546Sopenharmony_ci   struct tc_call_base base;
4091bf215546Sopenharmony_ci   unsigned level;
4092bf215546Sopenharmony_ci   struct pipe_box box;
4093bf215546Sopenharmony_ci   char data[16];
4094bf215546Sopenharmony_ci   struct pipe_resource *res;
4095bf215546Sopenharmony_ci};
4096bf215546Sopenharmony_ci
4097bf215546Sopenharmony_cistatic uint16_t
4098bf215546Sopenharmony_citc_call_clear_texture(struct pipe_context *pipe, void *call, uint64_t *last)
4099bf215546Sopenharmony_ci{
4100bf215546Sopenharmony_ci   struct tc_clear_texture *p = to_call(call, tc_clear_texture);
4101bf215546Sopenharmony_ci
4102bf215546Sopenharmony_ci   pipe->clear_texture(pipe, p->res, p->level, &p->box, p->data);
4103bf215546Sopenharmony_ci   tc_drop_resource_reference(p->res);
4104bf215546Sopenharmony_ci   return call_size(tc_clear_texture);
4105bf215546Sopenharmony_ci}
4106bf215546Sopenharmony_ci
4107bf215546Sopenharmony_cistatic void
4108bf215546Sopenharmony_citc_clear_texture(struct pipe_context *_pipe, struct pipe_resource *res,
4109bf215546Sopenharmony_ci                 unsigned level, const struct pipe_box *box, const void *data)
4110bf215546Sopenharmony_ci{
4111bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
4112bf215546Sopenharmony_ci   struct tc_clear_texture *p =
4113bf215546Sopenharmony_ci      tc_add_call(tc, TC_CALL_clear_texture, tc_clear_texture);
4114bf215546Sopenharmony_ci
4115bf215546Sopenharmony_ci   tc_set_resource_reference(&p->res, res);
4116bf215546Sopenharmony_ci   p->level = level;
4117bf215546Sopenharmony_ci   p->box = *box;
4118bf215546Sopenharmony_ci   memcpy(p->data, data,
4119bf215546Sopenharmony_ci          util_format_get_blocksize(res->format));
4120bf215546Sopenharmony_ci}
4121bf215546Sopenharmony_ci
4122bf215546Sopenharmony_cistruct tc_resource_commit {
4123bf215546Sopenharmony_ci   struct tc_call_base base;
4124bf215546Sopenharmony_ci   bool commit;
4125bf215546Sopenharmony_ci   unsigned level;
4126bf215546Sopenharmony_ci   struct pipe_box box;
4127bf215546Sopenharmony_ci   struct pipe_resource *res;
4128bf215546Sopenharmony_ci};
4129bf215546Sopenharmony_ci
4130bf215546Sopenharmony_cistatic uint16_t
4131bf215546Sopenharmony_citc_call_resource_commit(struct pipe_context *pipe, void *call, uint64_t *last)
4132bf215546Sopenharmony_ci{
4133bf215546Sopenharmony_ci   struct tc_resource_commit *p = to_call(call, tc_resource_commit);
4134bf215546Sopenharmony_ci
4135bf215546Sopenharmony_ci   pipe->resource_commit(pipe, p->res, p->level, &p->box, p->commit);
4136bf215546Sopenharmony_ci   tc_drop_resource_reference(p->res);
4137bf215546Sopenharmony_ci   return call_size(tc_resource_commit);
4138bf215546Sopenharmony_ci}
4139bf215546Sopenharmony_ci
4140bf215546Sopenharmony_cistatic bool
4141bf215546Sopenharmony_citc_resource_commit(struct pipe_context *_pipe, struct pipe_resource *res,
4142bf215546Sopenharmony_ci                   unsigned level, struct pipe_box *box, bool commit)
4143bf215546Sopenharmony_ci{
4144bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
4145bf215546Sopenharmony_ci   struct tc_resource_commit *p =
4146bf215546Sopenharmony_ci      tc_add_call(tc, TC_CALL_resource_commit, tc_resource_commit);
4147bf215546Sopenharmony_ci
4148bf215546Sopenharmony_ci   tc_set_resource_reference(&p->res, res);
4149bf215546Sopenharmony_ci   p->level = level;
4150bf215546Sopenharmony_ci   p->box = *box;
4151bf215546Sopenharmony_ci   p->commit = commit;
4152bf215546Sopenharmony_ci   return true; /* we don't care about the return value for this call */
4153bf215546Sopenharmony_ci}
4154bf215546Sopenharmony_ci
4155bf215546Sopenharmony_cistatic unsigned
4156bf215546Sopenharmony_citc_init_intel_perf_query_info(struct pipe_context *_pipe)
4157bf215546Sopenharmony_ci{
4158bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
4159bf215546Sopenharmony_ci   struct pipe_context *pipe = tc->pipe;
4160bf215546Sopenharmony_ci
4161bf215546Sopenharmony_ci   return pipe->init_intel_perf_query_info(pipe);
4162bf215546Sopenharmony_ci}
4163bf215546Sopenharmony_ci
4164bf215546Sopenharmony_cistatic void
4165bf215546Sopenharmony_citc_get_intel_perf_query_info(struct pipe_context *_pipe,
4166bf215546Sopenharmony_ci                             unsigned query_index,
4167bf215546Sopenharmony_ci                             const char **name,
4168bf215546Sopenharmony_ci                             uint32_t *data_size,
4169bf215546Sopenharmony_ci                             uint32_t *n_counters,
4170bf215546Sopenharmony_ci                             uint32_t *n_active)
4171bf215546Sopenharmony_ci{
4172bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
4173bf215546Sopenharmony_ci   struct pipe_context *pipe = tc->pipe;
4174bf215546Sopenharmony_ci
4175bf215546Sopenharmony_ci   tc_sync(tc); /* n_active vs begin/end_intel_perf_query */
4176bf215546Sopenharmony_ci   pipe->get_intel_perf_query_info(pipe, query_index, name, data_size,
4177bf215546Sopenharmony_ci         n_counters, n_active);
4178bf215546Sopenharmony_ci}
4179bf215546Sopenharmony_ci
4180bf215546Sopenharmony_cistatic void
4181bf215546Sopenharmony_citc_get_intel_perf_query_counter_info(struct pipe_context *_pipe,
4182bf215546Sopenharmony_ci                                     unsigned query_index,
4183bf215546Sopenharmony_ci                                     unsigned counter_index,
4184bf215546Sopenharmony_ci                                     const char **name,
4185bf215546Sopenharmony_ci                                     const char **desc,
4186bf215546Sopenharmony_ci                                     uint32_t *offset,
4187bf215546Sopenharmony_ci                                     uint32_t *data_size,
4188bf215546Sopenharmony_ci                                     uint32_t *type_enum,
4189bf215546Sopenharmony_ci                                     uint32_t *data_type_enum,
4190bf215546Sopenharmony_ci                                     uint64_t *raw_max)
4191bf215546Sopenharmony_ci{
4192bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
4193bf215546Sopenharmony_ci   struct pipe_context *pipe = tc->pipe;
4194bf215546Sopenharmony_ci
4195bf215546Sopenharmony_ci   pipe->get_intel_perf_query_counter_info(pipe, query_index, counter_index,
4196bf215546Sopenharmony_ci         name, desc, offset, data_size, type_enum, data_type_enum, raw_max);
4197bf215546Sopenharmony_ci}
4198bf215546Sopenharmony_ci
4199bf215546Sopenharmony_cistatic struct pipe_query *
4200bf215546Sopenharmony_citc_new_intel_perf_query_obj(struct pipe_context *_pipe, unsigned query_index)
4201bf215546Sopenharmony_ci{
4202bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
4203bf215546Sopenharmony_ci   struct pipe_context *pipe = tc->pipe;
4204bf215546Sopenharmony_ci
4205bf215546Sopenharmony_ci   return pipe->new_intel_perf_query_obj(pipe, query_index);
4206bf215546Sopenharmony_ci}
4207bf215546Sopenharmony_ci
4208bf215546Sopenharmony_cistatic uint16_t
4209bf215546Sopenharmony_citc_call_begin_intel_perf_query(struct pipe_context *pipe, void *call, uint64_t *last)
4210bf215546Sopenharmony_ci{
4211bf215546Sopenharmony_ci   (void)pipe->begin_intel_perf_query(pipe, to_call(call, tc_query_call)->query);
4212bf215546Sopenharmony_ci   return call_size(tc_query_call);
4213bf215546Sopenharmony_ci}
4214bf215546Sopenharmony_ci
4215bf215546Sopenharmony_cistatic bool
4216bf215546Sopenharmony_citc_begin_intel_perf_query(struct pipe_context *_pipe, struct pipe_query *q)
4217bf215546Sopenharmony_ci{
4218bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
4219bf215546Sopenharmony_ci
4220bf215546Sopenharmony_ci   tc_add_call(tc, TC_CALL_begin_intel_perf_query, tc_query_call)->query = q;
4221bf215546Sopenharmony_ci
4222bf215546Sopenharmony_ci   /* assume success, begin failure can be signaled from get_intel_perf_query_data */
4223bf215546Sopenharmony_ci   return true;
4224bf215546Sopenharmony_ci}
4225bf215546Sopenharmony_ci
4226bf215546Sopenharmony_cistatic uint16_t
4227bf215546Sopenharmony_citc_call_end_intel_perf_query(struct pipe_context *pipe, void *call, uint64_t *last)
4228bf215546Sopenharmony_ci{
4229bf215546Sopenharmony_ci   pipe->end_intel_perf_query(pipe, to_call(call, tc_query_call)->query);
4230bf215546Sopenharmony_ci   return call_size(tc_query_call);
4231bf215546Sopenharmony_ci}
4232bf215546Sopenharmony_ci
4233bf215546Sopenharmony_cistatic void
4234bf215546Sopenharmony_citc_end_intel_perf_query(struct pipe_context *_pipe, struct pipe_query *q)
4235bf215546Sopenharmony_ci{
4236bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
4237bf215546Sopenharmony_ci
4238bf215546Sopenharmony_ci   tc_add_call(tc, TC_CALL_end_intel_perf_query, tc_query_call)->query = q;
4239bf215546Sopenharmony_ci}
4240bf215546Sopenharmony_ci
4241bf215546Sopenharmony_cistatic void
4242bf215546Sopenharmony_citc_delete_intel_perf_query(struct pipe_context *_pipe, struct pipe_query *q)
4243bf215546Sopenharmony_ci{
4244bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
4245bf215546Sopenharmony_ci   struct pipe_context *pipe = tc->pipe;
4246bf215546Sopenharmony_ci
4247bf215546Sopenharmony_ci   tc_sync(tc); /* flush potentially pending begin/end_intel_perf_queries */
4248bf215546Sopenharmony_ci   pipe->delete_intel_perf_query(pipe, q);
4249bf215546Sopenharmony_ci}
4250bf215546Sopenharmony_ci
4251bf215546Sopenharmony_cistatic void
4252bf215546Sopenharmony_citc_wait_intel_perf_query(struct pipe_context *_pipe, struct pipe_query *q)
4253bf215546Sopenharmony_ci{
4254bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
4255bf215546Sopenharmony_ci   struct pipe_context *pipe = tc->pipe;
4256bf215546Sopenharmony_ci
4257bf215546Sopenharmony_ci   tc_sync(tc); /* flush potentially pending begin/end_intel_perf_queries */
4258bf215546Sopenharmony_ci   pipe->wait_intel_perf_query(pipe, q);
4259bf215546Sopenharmony_ci}
4260bf215546Sopenharmony_ci
4261bf215546Sopenharmony_cistatic bool
4262bf215546Sopenharmony_citc_is_intel_perf_query_ready(struct pipe_context *_pipe, struct pipe_query *q)
4263bf215546Sopenharmony_ci{
4264bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
4265bf215546Sopenharmony_ci   struct pipe_context *pipe = tc->pipe;
4266bf215546Sopenharmony_ci
4267bf215546Sopenharmony_ci   tc_sync(tc); /* flush potentially pending begin/end_intel_perf_queries */
4268bf215546Sopenharmony_ci   return pipe->is_intel_perf_query_ready(pipe, q);
4269bf215546Sopenharmony_ci}
4270bf215546Sopenharmony_ci
4271bf215546Sopenharmony_cistatic bool
4272bf215546Sopenharmony_citc_get_intel_perf_query_data(struct pipe_context *_pipe,
4273bf215546Sopenharmony_ci                             struct pipe_query *q,
4274bf215546Sopenharmony_ci                             size_t data_size,
4275bf215546Sopenharmony_ci                             uint32_t *data,
4276bf215546Sopenharmony_ci                             uint32_t *bytes_written)
4277bf215546Sopenharmony_ci{
4278bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
4279bf215546Sopenharmony_ci   struct pipe_context *pipe = tc->pipe;
4280bf215546Sopenharmony_ci
4281bf215546Sopenharmony_ci   tc_sync(tc); /* flush potentially pending begin/end_intel_perf_queries */
4282bf215546Sopenharmony_ci   return pipe->get_intel_perf_query_data(pipe, q, data_size, data, bytes_written);
4283bf215546Sopenharmony_ci}
4284bf215546Sopenharmony_ci
4285bf215546Sopenharmony_ci/********************************************************************
4286bf215546Sopenharmony_ci * callback
4287bf215546Sopenharmony_ci */
4288bf215546Sopenharmony_ci
4289bf215546Sopenharmony_cistruct tc_callback_call {
4290bf215546Sopenharmony_ci   struct tc_call_base base;
4291bf215546Sopenharmony_ci   void (*fn)(void *data);
4292bf215546Sopenharmony_ci   void *data;
4293bf215546Sopenharmony_ci};
4294bf215546Sopenharmony_ci
4295bf215546Sopenharmony_cistatic uint16_t
4296bf215546Sopenharmony_citc_call_callback(UNUSED struct pipe_context *pipe, void *call, uint64_t *last)
4297bf215546Sopenharmony_ci{
4298bf215546Sopenharmony_ci   struct tc_callback_call *p = to_call(call, tc_callback_call);
4299bf215546Sopenharmony_ci
4300bf215546Sopenharmony_ci   p->fn(p->data);
4301bf215546Sopenharmony_ci   return call_size(tc_callback_call);
4302bf215546Sopenharmony_ci}
4303bf215546Sopenharmony_ci
4304bf215546Sopenharmony_cistatic void
4305bf215546Sopenharmony_citc_callback(struct pipe_context *_pipe, void (*fn)(void *), void *data,
4306bf215546Sopenharmony_ci            bool asap)
4307bf215546Sopenharmony_ci{
4308bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
4309bf215546Sopenharmony_ci
4310bf215546Sopenharmony_ci   if (asap && tc_is_sync(tc)) {
4311bf215546Sopenharmony_ci      fn(data);
4312bf215546Sopenharmony_ci      return;
4313bf215546Sopenharmony_ci   }
4314bf215546Sopenharmony_ci
4315bf215546Sopenharmony_ci   struct tc_callback_call *p =
4316bf215546Sopenharmony_ci      tc_add_call(tc, TC_CALL_callback, tc_callback_call);
4317bf215546Sopenharmony_ci   p->fn = fn;
4318bf215546Sopenharmony_ci   p->data = data;
4319bf215546Sopenharmony_ci}
4320bf215546Sopenharmony_ci
4321bf215546Sopenharmony_ci
4322bf215546Sopenharmony_ci/********************************************************************
4323bf215546Sopenharmony_ci * create & destroy
4324bf215546Sopenharmony_ci */
4325bf215546Sopenharmony_ci
4326bf215546Sopenharmony_cistatic void
4327bf215546Sopenharmony_citc_destroy(struct pipe_context *_pipe)
4328bf215546Sopenharmony_ci{
4329bf215546Sopenharmony_ci   struct threaded_context *tc = threaded_context(_pipe);
4330bf215546Sopenharmony_ci   struct pipe_context *pipe = tc->pipe;
4331bf215546Sopenharmony_ci
4332bf215546Sopenharmony_ci   if (tc->base.const_uploader &&
4333bf215546Sopenharmony_ci       tc->base.stream_uploader != tc->base.const_uploader)
4334bf215546Sopenharmony_ci      u_upload_destroy(tc->base.const_uploader);
4335bf215546Sopenharmony_ci
4336bf215546Sopenharmony_ci   if (tc->base.stream_uploader)
4337bf215546Sopenharmony_ci      u_upload_destroy(tc->base.stream_uploader);
4338bf215546Sopenharmony_ci
4339bf215546Sopenharmony_ci   tc_sync(tc);
4340bf215546Sopenharmony_ci
4341bf215546Sopenharmony_ci   if (util_queue_is_initialized(&tc->queue)) {
4342bf215546Sopenharmony_ci      util_queue_destroy(&tc->queue);
4343bf215546Sopenharmony_ci
4344bf215546Sopenharmony_ci      for (unsigned i = 0; i < TC_MAX_BATCHES; i++) {
4345bf215546Sopenharmony_ci         util_queue_fence_destroy(&tc->batch_slots[i].fence);
4346bf215546Sopenharmony_ci         assert(!tc->batch_slots[i].token);
4347bf215546Sopenharmony_ci      }
4348bf215546Sopenharmony_ci   }
4349bf215546Sopenharmony_ci
4350bf215546Sopenharmony_ci   slab_destroy_child(&tc->pool_transfers);
4351bf215546Sopenharmony_ci   assert(tc->batch_slots[tc->next].num_total_slots == 0);
4352bf215546Sopenharmony_ci   pipe->destroy(pipe);
4353bf215546Sopenharmony_ci
4354bf215546Sopenharmony_ci   for (unsigned i = 0; i < TC_MAX_BUFFER_LISTS; i++) {
4355bf215546Sopenharmony_ci      if (!util_queue_fence_is_signalled(&tc->buffer_lists[i].driver_flushed_fence))
4356bf215546Sopenharmony_ci         util_queue_fence_signal(&tc->buffer_lists[i].driver_flushed_fence);
4357bf215546Sopenharmony_ci      util_queue_fence_destroy(&tc->buffer_lists[i].driver_flushed_fence);
4358bf215546Sopenharmony_ci   }
4359bf215546Sopenharmony_ci
4360bf215546Sopenharmony_ci   FREE(tc);
4361bf215546Sopenharmony_ci}
4362bf215546Sopenharmony_ci
4363bf215546Sopenharmony_cistatic const tc_execute execute_func[TC_NUM_CALLS] = {
4364bf215546Sopenharmony_ci#define CALL(name) tc_call_##name,
4365bf215546Sopenharmony_ci#include "u_threaded_context_calls.h"
4366bf215546Sopenharmony_ci#undef CALL
4367bf215546Sopenharmony_ci};
4368bf215546Sopenharmony_ci
4369bf215546Sopenharmony_civoid tc_driver_internal_flush_notify(struct threaded_context *tc)
4370bf215546Sopenharmony_ci{
4371bf215546Sopenharmony_ci   /* Allow drivers to call this function even for internal contexts that
4372bf215546Sopenharmony_ci    * don't have tc. It simplifies drivers.
4373bf215546Sopenharmony_ci    */
4374bf215546Sopenharmony_ci   if (!tc)
4375bf215546Sopenharmony_ci      return;
4376bf215546Sopenharmony_ci
4377bf215546Sopenharmony_ci   /* Signal fences set by tc_batch_execute. */
4378bf215546Sopenharmony_ci   for (unsigned i = 0; i < tc->num_signal_fences_next_flush; i++)
4379bf215546Sopenharmony_ci      util_queue_fence_signal(tc->signal_fences_next_flush[i]);
4380bf215546Sopenharmony_ci
4381bf215546Sopenharmony_ci   tc->num_signal_fences_next_flush = 0;
4382bf215546Sopenharmony_ci}
4383bf215546Sopenharmony_ci
4384bf215546Sopenharmony_ci/**
4385bf215546Sopenharmony_ci * Wrap an existing pipe_context into a threaded_context.
4386bf215546Sopenharmony_ci *
4387bf215546Sopenharmony_ci * \param pipe                 pipe_context to wrap
4388bf215546Sopenharmony_ci * \param parent_transfer_pool parent slab pool set up for creating pipe_-
4389bf215546Sopenharmony_ci *                             transfer objects; the driver should have one
4390bf215546Sopenharmony_ci *                             in pipe_screen.
4391bf215546Sopenharmony_ci * \param replace_buffer  callback for replacing a pipe_resource's storage
4392bf215546Sopenharmony_ci *                        with another pipe_resource's storage.
4393bf215546Sopenharmony_ci * \param options         optional TC options/callbacks
4394bf215546Sopenharmony_ci * \param out  if successful, the threaded_context will be returned here in
4395bf215546Sopenharmony_ci *             addition to the return value if "out" != NULL
4396bf215546Sopenharmony_ci */
4397bf215546Sopenharmony_cistruct pipe_context *
4398bf215546Sopenharmony_cithreaded_context_create(struct pipe_context *pipe,
4399bf215546Sopenharmony_ci                        struct slab_parent_pool *parent_transfer_pool,
4400bf215546Sopenharmony_ci                        tc_replace_buffer_storage_func replace_buffer,
4401bf215546Sopenharmony_ci                        const struct threaded_context_options *options,
4402bf215546Sopenharmony_ci                        struct threaded_context **out)
4403bf215546Sopenharmony_ci{
4404bf215546Sopenharmony_ci   struct threaded_context *tc;
4405bf215546Sopenharmony_ci
4406bf215546Sopenharmony_ci   if (!pipe)
4407bf215546Sopenharmony_ci      return NULL;
4408bf215546Sopenharmony_ci
4409bf215546Sopenharmony_ci   if (!debug_get_bool_option("GALLIUM_THREAD", util_get_cpu_caps()->nr_cpus > 1))
4410bf215546Sopenharmony_ci      return pipe;
4411bf215546Sopenharmony_ci
4412bf215546Sopenharmony_ci   tc = CALLOC_STRUCT(threaded_context);
4413bf215546Sopenharmony_ci   if (!tc) {
4414bf215546Sopenharmony_ci      pipe->destroy(pipe);
4415bf215546Sopenharmony_ci      return NULL;
4416bf215546Sopenharmony_ci   }
4417bf215546Sopenharmony_ci
4418bf215546Sopenharmony_ci   if (options)
4419bf215546Sopenharmony_ci      tc->options = *options;
4420bf215546Sopenharmony_ci
4421bf215546Sopenharmony_ci   pipe = trace_context_create_threaded(pipe->screen, pipe, &replace_buffer, &tc->options);
4422bf215546Sopenharmony_ci
4423bf215546Sopenharmony_ci   /* The driver context isn't wrapped, so set its "priv" to NULL. */
4424bf215546Sopenharmony_ci   pipe->priv = NULL;
4425bf215546Sopenharmony_ci
4426bf215546Sopenharmony_ci   tc->pipe = pipe;
4427bf215546Sopenharmony_ci   tc->replace_buffer_storage = replace_buffer;
4428bf215546Sopenharmony_ci   tc->map_buffer_alignment =
4429bf215546Sopenharmony_ci      pipe->screen->get_param(pipe->screen, PIPE_CAP_MIN_MAP_BUFFER_ALIGNMENT);
4430bf215546Sopenharmony_ci   tc->ubo_alignment =
4431bf215546Sopenharmony_ci      MAX2(pipe->screen->get_param(pipe->screen, PIPE_CAP_CONSTANT_BUFFER_OFFSET_ALIGNMENT), 64);
4432bf215546Sopenharmony_ci   tc->base.priv = pipe; /* priv points to the wrapped driver context */
4433bf215546Sopenharmony_ci   tc->base.screen = pipe->screen;
4434bf215546Sopenharmony_ci   tc->base.destroy = tc_destroy;
4435bf215546Sopenharmony_ci   tc->base.callback = tc_callback;
4436bf215546Sopenharmony_ci
4437bf215546Sopenharmony_ci   tc->base.stream_uploader = u_upload_clone(&tc->base, pipe->stream_uploader);
4438bf215546Sopenharmony_ci   if (pipe->stream_uploader == pipe->const_uploader)
4439bf215546Sopenharmony_ci      tc->base.const_uploader = tc->base.stream_uploader;
4440bf215546Sopenharmony_ci   else
4441bf215546Sopenharmony_ci      tc->base.const_uploader = u_upload_clone(&tc->base, pipe->const_uploader);
4442bf215546Sopenharmony_ci
4443bf215546Sopenharmony_ci   if (!tc->base.stream_uploader || !tc->base.const_uploader)
4444bf215546Sopenharmony_ci      goto fail;
4445bf215546Sopenharmony_ci
4446bf215546Sopenharmony_ci   tc->use_forced_staging_uploads = true;
4447bf215546Sopenharmony_ci
4448bf215546Sopenharmony_ci   /* The queue size is the number of batches "waiting". Batches are removed
4449bf215546Sopenharmony_ci    * from the queue before being executed, so keep one tc_batch slot for that
4450bf215546Sopenharmony_ci    * execution. Also, keep one unused slot for an unflushed batch.
4451bf215546Sopenharmony_ci    */
4452bf215546Sopenharmony_ci   if (!util_queue_init(&tc->queue, "gdrv", TC_MAX_BATCHES - 2, 1, 0, NULL))
4453bf215546Sopenharmony_ci      goto fail;
4454bf215546Sopenharmony_ci
4455bf215546Sopenharmony_ci   for (unsigned i = 0; i < TC_MAX_BATCHES; i++) {
4456bf215546Sopenharmony_ci#if !defined(NDEBUG) && TC_DEBUG >= 1
4457bf215546Sopenharmony_ci      tc->batch_slots[i].sentinel = TC_SENTINEL;
4458bf215546Sopenharmony_ci#endif
4459bf215546Sopenharmony_ci      tc->batch_slots[i].tc = tc;
4460bf215546Sopenharmony_ci      util_queue_fence_init(&tc->batch_slots[i].fence);
4461bf215546Sopenharmony_ci   }
4462bf215546Sopenharmony_ci   for (unsigned i = 0; i < TC_MAX_BUFFER_LISTS; i++)
4463bf215546Sopenharmony_ci      util_queue_fence_init(&tc->buffer_lists[i].driver_flushed_fence);
4464bf215546Sopenharmony_ci
4465bf215546Sopenharmony_ci   list_inithead(&tc->unflushed_queries);
4466bf215546Sopenharmony_ci
4467bf215546Sopenharmony_ci   slab_create_child(&tc->pool_transfers, parent_transfer_pool);
4468bf215546Sopenharmony_ci
4469bf215546Sopenharmony_ci   /* If you have different limits in each shader stage, set the maximum. */
4470bf215546Sopenharmony_ci   struct pipe_screen *screen = pipe->screen;;
4471bf215546Sopenharmony_ci   tc->max_vertex_buffers =
4472bf215546Sopenharmony_ci      screen->get_param(screen, PIPE_CAP_MAX_VERTEX_BUFFERS);
4473bf215546Sopenharmony_ci   tc->max_const_buffers =
4474bf215546Sopenharmony_ci      screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT,
4475bf215546Sopenharmony_ci                               PIPE_SHADER_CAP_MAX_CONST_BUFFERS);
4476bf215546Sopenharmony_ci   tc->max_shader_buffers =
4477bf215546Sopenharmony_ci      screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT,
4478bf215546Sopenharmony_ci                               PIPE_SHADER_CAP_MAX_SHADER_BUFFERS);
4479bf215546Sopenharmony_ci   tc->max_images =
4480bf215546Sopenharmony_ci      screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT,
4481bf215546Sopenharmony_ci                               PIPE_SHADER_CAP_MAX_SHADER_IMAGES);
4482bf215546Sopenharmony_ci   tc->max_samplers =
4483bf215546Sopenharmony_ci      screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT,
4484bf215546Sopenharmony_ci                               PIPE_SHADER_CAP_MAX_TEXTURE_SAMPLERS);
4485bf215546Sopenharmony_ci
4486bf215546Sopenharmony_ci   tc->base.set_context_param = tc_set_context_param; /* always set this */
4487bf215546Sopenharmony_ci
4488bf215546Sopenharmony_ci#define CTX_INIT(_member) \
4489bf215546Sopenharmony_ci   tc->base._member = tc->pipe->_member ? tc_##_member : NULL
4490bf215546Sopenharmony_ci
4491bf215546Sopenharmony_ci   CTX_INIT(flush);
4492bf215546Sopenharmony_ci   CTX_INIT(draw_vbo);
4493bf215546Sopenharmony_ci   CTX_INIT(draw_vertex_state);
4494bf215546Sopenharmony_ci   CTX_INIT(launch_grid);
4495bf215546Sopenharmony_ci   CTX_INIT(resource_copy_region);
4496bf215546Sopenharmony_ci   CTX_INIT(blit);
4497bf215546Sopenharmony_ci   CTX_INIT(clear);
4498bf215546Sopenharmony_ci   CTX_INIT(clear_render_target);
4499bf215546Sopenharmony_ci   CTX_INIT(clear_depth_stencil);
4500bf215546Sopenharmony_ci   CTX_INIT(clear_buffer);
4501bf215546Sopenharmony_ci   CTX_INIT(clear_texture);
4502bf215546Sopenharmony_ci   CTX_INIT(flush_resource);
4503bf215546Sopenharmony_ci   CTX_INIT(generate_mipmap);
4504bf215546Sopenharmony_ci   CTX_INIT(render_condition);
4505bf215546Sopenharmony_ci   CTX_INIT(create_query);
4506bf215546Sopenharmony_ci   CTX_INIT(create_batch_query);
4507bf215546Sopenharmony_ci   CTX_INIT(destroy_query);
4508bf215546Sopenharmony_ci   CTX_INIT(begin_query);
4509bf215546Sopenharmony_ci   CTX_INIT(end_query);
4510bf215546Sopenharmony_ci   CTX_INIT(get_query_result);
4511bf215546Sopenharmony_ci   CTX_INIT(get_query_result_resource);
4512bf215546Sopenharmony_ci   CTX_INIT(set_active_query_state);
4513bf215546Sopenharmony_ci   CTX_INIT(create_blend_state);
4514bf215546Sopenharmony_ci   CTX_INIT(bind_blend_state);
4515bf215546Sopenharmony_ci   CTX_INIT(delete_blend_state);
4516bf215546Sopenharmony_ci   CTX_INIT(create_sampler_state);
4517bf215546Sopenharmony_ci   CTX_INIT(bind_sampler_states);
4518bf215546Sopenharmony_ci   CTX_INIT(delete_sampler_state);
4519bf215546Sopenharmony_ci   CTX_INIT(create_rasterizer_state);
4520bf215546Sopenharmony_ci   CTX_INIT(bind_rasterizer_state);
4521bf215546Sopenharmony_ci   CTX_INIT(delete_rasterizer_state);
4522bf215546Sopenharmony_ci   CTX_INIT(create_depth_stencil_alpha_state);
4523bf215546Sopenharmony_ci   CTX_INIT(bind_depth_stencil_alpha_state);
4524bf215546Sopenharmony_ci   CTX_INIT(delete_depth_stencil_alpha_state);
4525bf215546Sopenharmony_ci   CTX_INIT(link_shader);
4526bf215546Sopenharmony_ci   CTX_INIT(create_fs_state);
4527bf215546Sopenharmony_ci   CTX_INIT(bind_fs_state);
4528bf215546Sopenharmony_ci   CTX_INIT(delete_fs_state);
4529bf215546Sopenharmony_ci   CTX_INIT(create_vs_state);
4530bf215546Sopenharmony_ci   CTX_INIT(bind_vs_state);
4531bf215546Sopenharmony_ci   CTX_INIT(delete_vs_state);
4532bf215546Sopenharmony_ci   CTX_INIT(create_gs_state);
4533bf215546Sopenharmony_ci   CTX_INIT(bind_gs_state);
4534bf215546Sopenharmony_ci   CTX_INIT(delete_gs_state);
4535bf215546Sopenharmony_ci   CTX_INIT(create_tcs_state);
4536bf215546Sopenharmony_ci   CTX_INIT(bind_tcs_state);
4537bf215546Sopenharmony_ci   CTX_INIT(delete_tcs_state);
4538bf215546Sopenharmony_ci   CTX_INIT(create_tes_state);
4539bf215546Sopenharmony_ci   CTX_INIT(bind_tes_state);
4540bf215546Sopenharmony_ci   CTX_INIT(delete_tes_state);
4541bf215546Sopenharmony_ci   CTX_INIT(create_compute_state);
4542bf215546Sopenharmony_ci   CTX_INIT(bind_compute_state);
4543bf215546Sopenharmony_ci   CTX_INIT(delete_compute_state);
4544bf215546Sopenharmony_ci   CTX_INIT(create_vertex_elements_state);
4545bf215546Sopenharmony_ci   CTX_INIT(bind_vertex_elements_state);
4546bf215546Sopenharmony_ci   CTX_INIT(delete_vertex_elements_state);
4547bf215546Sopenharmony_ci   CTX_INIT(set_blend_color);
4548bf215546Sopenharmony_ci   CTX_INIT(set_stencil_ref);
4549bf215546Sopenharmony_ci   CTX_INIT(set_sample_mask);
4550bf215546Sopenharmony_ci   CTX_INIT(set_min_samples);
4551bf215546Sopenharmony_ci   CTX_INIT(set_clip_state);
4552bf215546Sopenharmony_ci   CTX_INIT(set_constant_buffer);
4553bf215546Sopenharmony_ci   CTX_INIT(set_inlinable_constants);
4554bf215546Sopenharmony_ci   CTX_INIT(set_framebuffer_state);
4555bf215546Sopenharmony_ci   CTX_INIT(set_polygon_stipple);
4556bf215546Sopenharmony_ci   CTX_INIT(set_sample_locations);
4557bf215546Sopenharmony_ci   CTX_INIT(set_scissor_states);
4558bf215546Sopenharmony_ci   CTX_INIT(set_viewport_states);
4559bf215546Sopenharmony_ci   CTX_INIT(set_window_rectangles);
4560bf215546Sopenharmony_ci   CTX_INIT(set_sampler_views);
4561bf215546Sopenharmony_ci   CTX_INIT(set_tess_state);
4562bf215546Sopenharmony_ci   CTX_INIT(set_patch_vertices);
4563bf215546Sopenharmony_ci   CTX_INIT(set_shader_buffers);
4564bf215546Sopenharmony_ci   CTX_INIT(set_shader_images);
4565bf215546Sopenharmony_ci   CTX_INIT(set_vertex_buffers);
4566bf215546Sopenharmony_ci   CTX_INIT(create_stream_output_target);
4567bf215546Sopenharmony_ci   CTX_INIT(stream_output_target_destroy);
4568bf215546Sopenharmony_ci   CTX_INIT(set_stream_output_targets);
4569bf215546Sopenharmony_ci   CTX_INIT(create_sampler_view);
4570bf215546Sopenharmony_ci   CTX_INIT(sampler_view_destroy);
4571bf215546Sopenharmony_ci   CTX_INIT(create_surface);
4572bf215546Sopenharmony_ci   CTX_INIT(surface_destroy);
4573bf215546Sopenharmony_ci   CTX_INIT(buffer_map);
4574bf215546Sopenharmony_ci   CTX_INIT(texture_map);
4575bf215546Sopenharmony_ci   CTX_INIT(transfer_flush_region);
4576bf215546Sopenharmony_ci   CTX_INIT(buffer_unmap);
4577bf215546Sopenharmony_ci   CTX_INIT(texture_unmap);
4578bf215546Sopenharmony_ci   CTX_INIT(buffer_subdata);
4579bf215546Sopenharmony_ci   CTX_INIT(texture_subdata);
4580bf215546Sopenharmony_ci   CTX_INIT(texture_barrier);
4581bf215546Sopenharmony_ci   CTX_INIT(memory_barrier);
4582bf215546Sopenharmony_ci   CTX_INIT(resource_commit);
4583bf215546Sopenharmony_ci   CTX_INIT(create_video_codec);
4584bf215546Sopenharmony_ci   CTX_INIT(create_video_buffer);
4585bf215546Sopenharmony_ci   CTX_INIT(set_compute_resources);
4586bf215546Sopenharmony_ci   CTX_INIT(set_global_binding);
4587bf215546Sopenharmony_ci   CTX_INIT(get_sample_position);
4588bf215546Sopenharmony_ci   CTX_INIT(invalidate_resource);
4589bf215546Sopenharmony_ci   CTX_INIT(get_device_reset_status);
4590bf215546Sopenharmony_ci   CTX_INIT(set_device_reset_callback);
4591bf215546Sopenharmony_ci   CTX_INIT(dump_debug_state);
4592bf215546Sopenharmony_ci   CTX_INIT(set_log_context);
4593bf215546Sopenharmony_ci   CTX_INIT(emit_string_marker);
4594bf215546Sopenharmony_ci   CTX_INIT(set_debug_callback);
4595bf215546Sopenharmony_ci   CTX_INIT(create_fence_fd);
4596bf215546Sopenharmony_ci   CTX_INIT(fence_server_sync);
4597bf215546Sopenharmony_ci   CTX_INIT(fence_server_signal);
4598bf215546Sopenharmony_ci   CTX_INIT(get_timestamp);
4599bf215546Sopenharmony_ci   CTX_INIT(create_texture_handle);
4600bf215546Sopenharmony_ci   CTX_INIT(delete_texture_handle);
4601bf215546Sopenharmony_ci   CTX_INIT(make_texture_handle_resident);
4602bf215546Sopenharmony_ci   CTX_INIT(create_image_handle);
4603bf215546Sopenharmony_ci   CTX_INIT(delete_image_handle);
4604bf215546Sopenharmony_ci   CTX_INIT(make_image_handle_resident);
4605bf215546Sopenharmony_ci   CTX_INIT(set_frontend_noop);
4606bf215546Sopenharmony_ci   CTX_INIT(init_intel_perf_query_info);
4607bf215546Sopenharmony_ci   CTX_INIT(get_intel_perf_query_info);
4608bf215546Sopenharmony_ci   CTX_INIT(get_intel_perf_query_counter_info);
4609bf215546Sopenharmony_ci   CTX_INIT(new_intel_perf_query_obj);
4610bf215546Sopenharmony_ci   CTX_INIT(begin_intel_perf_query);
4611bf215546Sopenharmony_ci   CTX_INIT(end_intel_perf_query);
4612bf215546Sopenharmony_ci   CTX_INIT(delete_intel_perf_query);
4613bf215546Sopenharmony_ci   CTX_INIT(wait_intel_perf_query);
4614bf215546Sopenharmony_ci   CTX_INIT(is_intel_perf_query_ready);
4615bf215546Sopenharmony_ci   CTX_INIT(get_intel_perf_query_data);
4616bf215546Sopenharmony_ci#undef CTX_INIT
4617bf215546Sopenharmony_ci
4618bf215546Sopenharmony_ci   if (out)
4619bf215546Sopenharmony_ci      *out = tc;
4620bf215546Sopenharmony_ci
4621bf215546Sopenharmony_ci   tc_begin_next_buffer_list(tc);
4622bf215546Sopenharmony_ci   return &tc->base;
4623bf215546Sopenharmony_ci
4624bf215546Sopenharmony_cifail:
4625bf215546Sopenharmony_ci   tc_destroy(&tc->base);
4626bf215546Sopenharmony_ci   return NULL;
4627bf215546Sopenharmony_ci}
4628bf215546Sopenharmony_ci
4629bf215546Sopenharmony_civoid
4630bf215546Sopenharmony_cithreaded_context_init_bytes_mapped_limit(struct threaded_context *tc, unsigned divisor)
4631bf215546Sopenharmony_ci{
4632bf215546Sopenharmony_ci   uint64_t total_ram;
4633bf215546Sopenharmony_ci   if (os_get_total_physical_memory(&total_ram)) {
4634bf215546Sopenharmony_ci      tc->bytes_mapped_limit = total_ram / divisor;
4635bf215546Sopenharmony_ci      if (sizeof(void*) == 4)
4636bf215546Sopenharmony_ci         tc->bytes_mapped_limit = MIN2(tc->bytes_mapped_limit, 512*1024*1024UL);
4637bf215546Sopenharmony_ci   }
4638bf215546Sopenharmony_ci}
4639