• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**************************************************************************
2  *
3  * Copyright 2017 Advanced Micro Devices, Inc.
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * on the rights to use, copy, modify, merge, publish, distribute, sub
10  * license, and/or sell copies of the Software, and to permit persons to whom
11  * the Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the next
14  * paragraph) shall be included in all copies or substantial portions of the
15  * Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
21  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
23  * USE OR OTHER DEALINGS IN THE SOFTWARE.
24  *
25  **************************************************************************/
26 
27 #include "util/u_threaded_context.h"
28 #include "util/u_cpu_detect.h"
29 #include "util/u_format.h"
30 #include "util/u_inlines.h"
31 #include "util/u_memory.h"
32 #include "util/u_upload_mgr.h"
33 
34 /* 0 = disabled, 1 = assertions, 2 = printfs */
35 #define TC_DEBUG 0
36 
37 #if TC_DEBUG >= 1
38 #define tc_assert assert
39 #else
40 #define tc_assert(x)
41 #endif
42 
43 #if TC_DEBUG >= 2
44 #define tc_printf printf
45 #define tc_asprintf asprintf
46 #define tc_strcmp strcmp
47 #else
48 #define tc_printf(...)
49 #define tc_asprintf(...) 0
50 #define tc_strcmp(...) 0
51 #endif
52 
53 #define TC_SENTINEL 0x5ca1ab1e
54 
55 enum tc_call_id {
56 #define CALL(name) TC_CALL_##name,
57 #include "u_threaded_context_calls.h"
58 #undef CALL
59    TC_NUM_CALLS,
60 };
61 
62 typedef void (*tc_execute)(struct pipe_context *pipe, union tc_payload *payload);
63 
64 static const tc_execute execute_func[TC_NUM_CALLS];
65 
66 static void
tc_batch_check(MAYBE_UNUSED struct tc_batch * batch)67 tc_batch_check(MAYBE_UNUSED struct tc_batch *batch)
68 {
69    tc_assert(batch->sentinel == TC_SENTINEL);
70    tc_assert(batch->num_total_call_slots <= TC_CALLS_PER_BATCH);
71 }
72 
73 static void
tc_debug_check(struct threaded_context * tc)74 tc_debug_check(struct threaded_context *tc)
75 {
76    for (unsigned i = 0; i < TC_MAX_BATCHES; i++) {
77       tc_batch_check(&tc->batch_slots[i]);
78       tc_assert(tc->batch_slots[i].pipe == tc->pipe);
79    }
80 }
81 
82 static void
tc_batch_execute(void * job,UNUSED int thread_index)83 tc_batch_execute(void *job, UNUSED int thread_index)
84 {
85    struct tc_batch *batch = job;
86    struct pipe_context *pipe = batch->pipe;
87    struct tc_call *last = &batch->call[batch->num_total_call_slots];
88 
89    tc_batch_check(batch);
90 
91    assert(!batch->token);
92 
93    for (struct tc_call *iter = batch->call; iter != last;
94         iter += iter->num_call_slots) {
95       tc_assert(iter->sentinel == TC_SENTINEL);
96       execute_func[iter->call_id](pipe, &iter->payload);
97    }
98 
99    tc_batch_check(batch);
100    batch->num_total_call_slots = 0;
101 }
102 
103 static void
tc_batch_flush(struct threaded_context * tc)104 tc_batch_flush(struct threaded_context *tc)
105 {
106    struct tc_batch *next = &tc->batch_slots[tc->next];
107 
108    tc_assert(next->num_total_call_slots != 0);
109    tc_batch_check(next);
110    tc_debug_check(tc);
111    p_atomic_add(&tc->num_offloaded_slots, next->num_total_call_slots);
112 
113    if (next->token) {
114       next->token->tc = NULL;
115       tc_unflushed_batch_token_reference(&next->token, NULL);
116    }
117 
118    util_queue_add_job(&tc->queue, next, &next->fence, tc_batch_execute,
119                       NULL);
120    tc->last = tc->next;
121    tc->next = (tc->next + 1) % TC_MAX_BATCHES;
122 }
123 
124 /* This is the function that adds variable-sized calls into the current
125  * batch. It also flushes the batch if there is not enough space there.
126  * All other higher-level "add" functions use it.
127  */
128 static union tc_payload *
tc_add_sized_call(struct threaded_context * tc,enum tc_call_id id,unsigned payload_size)129 tc_add_sized_call(struct threaded_context *tc, enum tc_call_id id,
130                   unsigned payload_size)
131 {
132    struct tc_batch *next = &tc->batch_slots[tc->next];
133    unsigned total_size = offsetof(struct tc_call, payload) + payload_size;
134    unsigned num_call_slots = DIV_ROUND_UP(total_size, sizeof(struct tc_call));
135 
136    tc_debug_check(tc);
137 
138    if (unlikely(next->num_total_call_slots + num_call_slots > TC_CALLS_PER_BATCH)) {
139       tc_batch_flush(tc);
140       next = &tc->batch_slots[tc->next];
141       tc_assert(next->num_total_call_slots == 0);
142    }
143 
144    tc_assert(util_queue_fence_is_signalled(&next->fence));
145 
146    struct tc_call *call = &next->call[next->num_total_call_slots];
147    next->num_total_call_slots += num_call_slots;
148 
149    call->sentinel = TC_SENTINEL;
150    call->call_id = id;
151    call->num_call_slots = num_call_slots;
152 
153    tc_debug_check(tc);
154    return &call->payload;
155 }
156 
157 #define tc_add_struct_typed_call(tc, execute, type) \
158    ((struct type*)tc_add_sized_call(tc, execute, sizeof(struct type)))
159 
160 #define tc_add_slot_based_call(tc, execute, type, num_slots) \
161    ((struct type*)tc_add_sized_call(tc, execute, \
162                                     sizeof(struct type) + \
163                                     sizeof(((struct type*)NULL)->slot[0]) * \
164                                     (num_slots)))
165 
166 static union tc_payload *
tc_add_small_call(struct threaded_context * tc,enum tc_call_id id)167 tc_add_small_call(struct threaded_context *tc, enum tc_call_id id)
168 {
169    return tc_add_sized_call(tc, id, 0);
170 }
171 
172 static bool
tc_is_sync(struct threaded_context * tc)173 tc_is_sync(struct threaded_context *tc)
174 {
175    struct tc_batch *last = &tc->batch_slots[tc->last];
176    struct tc_batch *next = &tc->batch_slots[tc->next];
177 
178    return util_queue_fence_is_signalled(&last->fence) &&
179           !next->num_total_call_slots;
180 }
181 
182 static void
_tc_sync(struct threaded_context * tc,MAYBE_UNUSED const char * info,MAYBE_UNUSED const char * func)183 _tc_sync(struct threaded_context *tc, MAYBE_UNUSED const char *info, MAYBE_UNUSED const char *func)
184 {
185    struct tc_batch *last = &tc->batch_slots[tc->last];
186    struct tc_batch *next = &tc->batch_slots[tc->next];
187    bool synced = false;
188 
189    tc_debug_check(tc);
190 
191    /* Only wait for queued calls... */
192    if (!util_queue_fence_is_signalled(&last->fence)) {
193       util_queue_fence_wait(&last->fence);
194       synced = true;
195    }
196 
197    tc_debug_check(tc);
198 
199    if (next->token) {
200       next->token->tc = NULL;
201       tc_unflushed_batch_token_reference(&next->token, NULL);
202    }
203 
204    /* .. and execute unflushed calls directly. */
205    if (next->num_total_call_slots) {
206       p_atomic_add(&tc->num_direct_slots, next->num_total_call_slots);
207       tc_batch_execute(next, 0);
208       synced = true;
209    }
210 
211    if (synced) {
212       p_atomic_inc(&tc->num_syncs);
213 
214       if (tc_strcmp(func, "tc_destroy") != 0) {
215          tc_printf("sync %s %s\n", func, info);
216 	  }
217    }
218 
219    tc_debug_check(tc);
220 }
221 
222 #define tc_sync(tc) _tc_sync(tc, "", __func__)
223 #define tc_sync_msg(tc, info) _tc_sync(tc, info, __func__)
224 
225 /**
226  * Call this from fence_finish for same-context fence waits of deferred fences
227  * that haven't been flushed yet.
228  *
229  * The passed pipe_context must be the one passed to pipe_screen::fence_finish,
230  * i.e., the wrapped one.
231  */
232 void
threaded_context_flush(struct pipe_context * _pipe,struct tc_unflushed_batch_token * token,bool prefer_async)233 threaded_context_flush(struct pipe_context *_pipe,
234                        struct tc_unflushed_batch_token *token,
235                        bool prefer_async)
236 {
237    struct threaded_context *tc = threaded_context(_pipe);
238 
239    /* This is called from the state-tracker / application thread. */
240    if (token->tc && token->tc == tc) {
241       struct tc_batch *last = &tc->batch_slots[tc->last];
242 
243       /* Prefer to do the flush in the driver thread if it is already
244        * running. That should be better for cache locality.
245        */
246       if (prefer_async || !util_queue_fence_is_signalled(&last->fence))
247          tc_batch_flush(tc);
248       else
249          tc_sync(token->tc);
250    }
251 }
252 
253 static void
tc_set_resource_reference(struct pipe_resource ** dst,struct pipe_resource * src)254 tc_set_resource_reference(struct pipe_resource **dst, struct pipe_resource *src)
255 {
256    *dst = NULL;
257    pipe_resource_reference(dst, src);
258 }
259 
260 void
threaded_resource_init(struct pipe_resource * res)261 threaded_resource_init(struct pipe_resource *res)
262 {
263    struct threaded_resource *tres = threaded_resource(res);
264 
265    tres->latest = &tres->b;
266    util_range_init(&tres->valid_buffer_range);
267    tres->base_valid_buffer_range = &tres->valid_buffer_range;
268    tres->is_shared = false;
269    tres->is_user_ptr = false;
270 }
271 
272 void
threaded_resource_deinit(struct pipe_resource * res)273 threaded_resource_deinit(struct pipe_resource *res)
274 {
275    struct threaded_resource *tres = threaded_resource(res);
276 
277    if (tres->latest != &tres->b)
278            pipe_resource_reference(&tres->latest, NULL);
279    util_range_destroy(&tres->valid_buffer_range);
280 }
281 
282 struct pipe_context *
threaded_context_unwrap_sync(struct pipe_context * pipe)283 threaded_context_unwrap_sync(struct pipe_context *pipe)
284 {
285    if (!pipe || !pipe->priv)
286       return pipe;
287 
288    tc_sync(threaded_context(pipe));
289    return (struct pipe_context*)pipe->priv;
290 }
291 
292 
293 /********************************************************************
294  * simple functions
295  */
296 
297 #define TC_FUNC1(func, m_payload, qualifier, type, deref, deref2) \
298    static void \
299    tc_call_##func(struct pipe_context *pipe, union tc_payload *payload) \
300    { \
301       pipe->func(pipe, deref2((type*)payload)); \
302    } \
303    \
304    static void \
305    tc_##func(struct pipe_context *_pipe, qualifier type deref param) \
306    { \
307       struct threaded_context *tc = threaded_context(_pipe); \
308       type *p = (type*)tc_add_sized_call(tc, TC_CALL_##func, sizeof(type)); \
309       *p = deref(param); \
310    }
311 
312 TC_FUNC1(set_active_query_state, flags, , boolean, , *)
313 
314 TC_FUNC1(set_blend_color, blend_color, const, struct pipe_blend_color, *, )
315 TC_FUNC1(set_stencil_ref, stencil_ref, const, struct pipe_stencil_ref, *, )
316 TC_FUNC1(set_clip_state, clip_state, const, struct pipe_clip_state, *, )
317 TC_FUNC1(set_sample_mask, sample_mask, , unsigned, , *)
318 TC_FUNC1(set_min_samples, min_samples, , unsigned, , *)
319 TC_FUNC1(set_polygon_stipple, polygon_stipple, const, struct pipe_poly_stipple, *, )
320 
321 TC_FUNC1(texture_barrier, flags, , unsigned, , *)
322 TC_FUNC1(memory_barrier, flags, , unsigned, , *)
323 
324 
325 /********************************************************************
326  * queries
327  */
328 
329 static struct pipe_query *
tc_create_query(struct pipe_context * _pipe,unsigned query_type,unsigned index)330 tc_create_query(struct pipe_context *_pipe, unsigned query_type,
331                 unsigned index)
332 {
333    struct threaded_context *tc = threaded_context(_pipe);
334    struct pipe_context *pipe = tc->pipe;
335 
336    return pipe->create_query(pipe, query_type, index);
337 }
338 
339 static struct pipe_query *
tc_create_batch_query(struct pipe_context * _pipe,unsigned num_queries,unsigned * query_types)340 tc_create_batch_query(struct pipe_context *_pipe, unsigned num_queries,
341                       unsigned *query_types)
342 {
343    struct threaded_context *tc = threaded_context(_pipe);
344    struct pipe_context *pipe = tc->pipe;
345 
346    return pipe->create_batch_query(pipe, num_queries, query_types);
347 }
348 
349 static void
tc_call_destroy_query(struct pipe_context * pipe,union tc_payload * payload)350 tc_call_destroy_query(struct pipe_context *pipe, union tc_payload *payload)
351 {
352    struct threaded_query *tq = threaded_query(payload->query);
353 
354    if (tq->head_unflushed.next)
355       LIST_DEL(&tq->head_unflushed);
356 
357    pipe->destroy_query(pipe, payload->query);
358 }
359 
360 static void
tc_destroy_query(struct pipe_context * _pipe,struct pipe_query * query)361 tc_destroy_query(struct pipe_context *_pipe, struct pipe_query *query)
362 {
363    struct threaded_context *tc = threaded_context(_pipe);
364 
365    tc_add_small_call(tc, TC_CALL_destroy_query)->query = query;
366 }
367 
368 static void
tc_call_begin_query(struct pipe_context * pipe,union tc_payload * payload)369 tc_call_begin_query(struct pipe_context *pipe, union tc_payload *payload)
370 {
371    pipe->begin_query(pipe, payload->query);
372 }
373 
374 static boolean
tc_begin_query(struct pipe_context * _pipe,struct pipe_query * query)375 tc_begin_query(struct pipe_context *_pipe, struct pipe_query *query)
376 {
377    struct threaded_context *tc = threaded_context(_pipe);
378    union tc_payload *payload = tc_add_small_call(tc, TC_CALL_begin_query);
379 
380    payload->query = query;
381    return true; /* we don't care about the return value for this call */
382 }
383 
384 struct tc_end_query_payload {
385    struct threaded_context *tc;
386    struct pipe_query *query;
387 };
388 
389 static void
tc_call_end_query(struct pipe_context * pipe,union tc_payload * payload)390 tc_call_end_query(struct pipe_context *pipe, union tc_payload *payload)
391 {
392    struct tc_end_query_payload *p = (struct tc_end_query_payload *)payload;
393    struct threaded_query *tq = threaded_query(p->query);
394 
395    if (!tq->head_unflushed.next)
396       LIST_ADD(&tq->head_unflushed, &p->tc->unflushed_queries);
397 
398    pipe->end_query(pipe, p->query);
399 }
400 
401 static bool
tc_end_query(struct pipe_context * _pipe,struct pipe_query * query)402 tc_end_query(struct pipe_context *_pipe, struct pipe_query *query)
403 {
404    struct threaded_context *tc = threaded_context(_pipe);
405    struct threaded_query *tq = threaded_query(query);
406    struct tc_end_query_payload *payload =
407       tc_add_struct_typed_call(tc, TC_CALL_end_query, tc_end_query_payload);
408 
409    payload->tc = tc;
410    payload->query = query;
411 
412    tq->flushed = false;
413 
414    return true; /* we don't care about the return value for this call */
415 }
416 
417 static boolean
tc_get_query_result(struct pipe_context * _pipe,struct pipe_query * query,boolean wait,union pipe_query_result * result)418 tc_get_query_result(struct pipe_context *_pipe,
419                     struct pipe_query *query, boolean wait,
420                     union pipe_query_result *result)
421 {
422    struct threaded_context *tc = threaded_context(_pipe);
423    struct threaded_query *tq = threaded_query(query);
424    struct pipe_context *pipe = tc->pipe;
425 
426    if (!tq->flushed)
427       tc_sync_msg(tc, wait ? "wait" : "nowait");
428 
429    bool success = pipe->get_query_result(pipe, query, wait, result);
430 
431    if (success) {
432       tq->flushed = true;
433       if (tq->head_unflushed.next) {
434          /* This is safe because it can only happen after we sync'd. */
435          LIST_DEL(&tq->head_unflushed);
436       }
437    }
438    return success;
439 }
440 
441 struct tc_query_result_resource {
442    struct pipe_query *query;
443    boolean wait;
444    enum pipe_query_value_type result_type;
445    int index;
446    struct pipe_resource *resource;
447    unsigned offset;
448 };
449 
450 static void
tc_call_get_query_result_resource(struct pipe_context * pipe,union tc_payload * payload)451 tc_call_get_query_result_resource(struct pipe_context *pipe,
452                                   union tc_payload *payload)
453 {
454    struct tc_query_result_resource *p = (struct tc_query_result_resource *)payload;
455 
456    pipe->get_query_result_resource(pipe, p->query, p->wait, p->result_type,
457                                    p->index, p->resource, p->offset);
458    pipe_resource_reference(&p->resource, NULL);
459 }
460 
461 static void
tc_get_query_result_resource(struct pipe_context * _pipe,struct pipe_query * query,boolean wait,enum pipe_query_value_type result_type,int index,struct pipe_resource * resource,unsigned offset)462 tc_get_query_result_resource(struct pipe_context *_pipe,
463                              struct pipe_query *query, boolean wait,
464                              enum pipe_query_value_type result_type, int index,
465                              struct pipe_resource *resource, unsigned offset)
466 {
467    struct threaded_context *tc = threaded_context(_pipe);
468    struct tc_query_result_resource *p =
469       tc_add_struct_typed_call(tc, TC_CALL_get_query_result_resource,
470                                tc_query_result_resource);
471 
472    p->query = query;
473    p->wait = wait;
474    p->result_type = result_type;
475    p->index = index;
476    tc_set_resource_reference(&p->resource, resource);
477    p->offset = offset;
478 }
479 
480 struct tc_render_condition {
481    struct pipe_query *query;
482    bool condition;
483    unsigned mode;
484 };
485 
486 static void
tc_call_render_condition(struct pipe_context * pipe,union tc_payload * payload)487 tc_call_render_condition(struct pipe_context *pipe, union tc_payload *payload)
488 {
489    struct tc_render_condition *p = (struct tc_render_condition *)payload;
490    pipe->render_condition(pipe, p->query, p->condition, p->mode);
491 }
492 
493 static void
tc_render_condition(struct pipe_context * _pipe,struct pipe_query * query,boolean condition,enum pipe_render_cond_flag mode)494 tc_render_condition(struct pipe_context *_pipe,
495                     struct pipe_query *query, boolean condition,
496                     enum pipe_render_cond_flag mode)
497 {
498    struct threaded_context *tc = threaded_context(_pipe);
499    struct tc_render_condition *p =
500       tc_add_struct_typed_call(tc, TC_CALL_render_condition, tc_render_condition);
501 
502    p->query = query;
503    p->condition = condition;
504    p->mode = mode;
505 }
506 
507 
508 /********************************************************************
509  * constant (immutable) states
510  */
511 
512 #define TC_CSO_CREATE(name, sname) \
513    static void * \
514    tc_create_##name##_state(struct pipe_context *_pipe, \
515                             const struct pipe_##sname##_state *state) \
516    { \
517       struct pipe_context *pipe = threaded_context(_pipe)->pipe; \
518       return pipe->create_##name##_state(pipe, state); \
519    }
520 
521 #define TC_CSO_BIND(name) TC_FUNC1(bind_##name##_state, cso, , void *, , *)
522 #define TC_CSO_DELETE(name) TC_FUNC1(delete_##name##_state, cso, , void *, , *)
523 
524 #define TC_CSO_WHOLE2(name, sname) \
525    TC_CSO_CREATE(name, sname) \
526    TC_CSO_BIND(name) \
527    TC_CSO_DELETE(name)
528 
529 #define TC_CSO_WHOLE(name) TC_CSO_WHOLE2(name, name)
530 
531 TC_CSO_WHOLE(blend)
TC_CSO_WHOLE(rasterizer)532 TC_CSO_WHOLE(rasterizer)
533 TC_CSO_WHOLE(depth_stencil_alpha)
534 TC_CSO_WHOLE(compute)
535 TC_CSO_WHOLE2(fs, shader)
536 TC_CSO_WHOLE2(vs, shader)
537 TC_CSO_WHOLE2(gs, shader)
538 TC_CSO_WHOLE2(tcs, shader)
539 TC_CSO_WHOLE2(tes, shader)
540 TC_CSO_CREATE(sampler, sampler)
541 TC_CSO_DELETE(sampler)
542 TC_CSO_BIND(vertex_elements)
543 TC_CSO_DELETE(vertex_elements)
544 
545 static void *
546 tc_create_vertex_elements_state(struct pipe_context *_pipe, unsigned count,
547                                 const struct pipe_vertex_element *elems)
548 {
549    struct pipe_context *pipe = threaded_context(_pipe)->pipe;
550 
551    return pipe->create_vertex_elements_state(pipe, count, elems);
552 }
553 
554 struct tc_sampler_states {
555    ubyte shader, start, count;
556    void *slot[0]; /* more will be allocated if needed */
557 };
558 
559 static void
tc_call_bind_sampler_states(struct pipe_context * pipe,union tc_payload * payload)560 tc_call_bind_sampler_states(struct pipe_context *pipe, union tc_payload *payload)
561 {
562    struct tc_sampler_states *p = (struct tc_sampler_states *)payload;
563    pipe->bind_sampler_states(pipe, p->shader, p->start, p->count, p->slot);
564 }
565 
566 static void
tc_bind_sampler_states(struct pipe_context * _pipe,enum pipe_shader_type shader,unsigned start,unsigned count,void ** states)567 tc_bind_sampler_states(struct pipe_context *_pipe,
568                        enum pipe_shader_type shader,
569                        unsigned start, unsigned count, void **states)
570 {
571    if (!count)
572       return;
573 
574    struct threaded_context *tc = threaded_context(_pipe);
575    struct tc_sampler_states *p =
576       tc_add_slot_based_call(tc, TC_CALL_bind_sampler_states, tc_sampler_states, count);
577 
578    p->shader = shader;
579    p->start = start;
580    p->count = count;
581    memcpy(p->slot, states, count * sizeof(states[0]));
582 }
583 
584 
585 /********************************************************************
586  * immediate states
587  */
588 
589 static void
tc_call_set_framebuffer_state(struct pipe_context * pipe,union tc_payload * payload)590 tc_call_set_framebuffer_state(struct pipe_context *pipe, union tc_payload *payload)
591 {
592    struct pipe_framebuffer_state *p = (struct pipe_framebuffer_state *)payload;
593 
594    pipe->set_framebuffer_state(pipe, p);
595 
596    unsigned nr_cbufs = p->nr_cbufs;
597    for (unsigned i = 0; i < nr_cbufs; i++)
598       pipe_surface_reference(&p->cbufs[i], NULL);
599    pipe_surface_reference(&p->zsbuf, NULL);
600 }
601 
602 static void
tc_set_framebuffer_state(struct pipe_context * _pipe,const struct pipe_framebuffer_state * fb)603 tc_set_framebuffer_state(struct pipe_context *_pipe,
604                          const struct pipe_framebuffer_state *fb)
605 {
606    struct threaded_context *tc = threaded_context(_pipe);
607    struct pipe_framebuffer_state *p =
608       tc_add_struct_typed_call(tc, TC_CALL_set_framebuffer_state,
609                                pipe_framebuffer_state);
610    unsigned nr_cbufs = fb->nr_cbufs;
611 
612    p->width = fb->width;
613    p->height = fb->height;
614    p->samples = fb->samples;
615    p->layers = fb->layers;
616    p->nr_cbufs = nr_cbufs;
617 
618    for (unsigned i = 0; i < nr_cbufs; i++) {
619       p->cbufs[i] = NULL;
620       pipe_surface_reference(&p->cbufs[i], fb->cbufs[i]);
621    }
622    p->zsbuf = NULL;
623    pipe_surface_reference(&p->zsbuf, fb->zsbuf);
624 }
625 
626 static void
tc_call_set_tess_state(struct pipe_context * pipe,union tc_payload * payload)627 tc_call_set_tess_state(struct pipe_context *pipe, union tc_payload *payload)
628 {
629    float *p = (float*)payload;
630    pipe->set_tess_state(pipe, p, p + 4);
631 }
632 
633 static void
tc_set_tess_state(struct pipe_context * _pipe,const float default_outer_level[4],const float default_inner_level[2])634 tc_set_tess_state(struct pipe_context *_pipe,
635                   const float default_outer_level[4],
636                   const float default_inner_level[2])
637 {
638    struct threaded_context *tc = threaded_context(_pipe);
639    float *p = (float*)tc_add_sized_call(tc, TC_CALL_set_tess_state,
640                                         sizeof(float) * 6);
641 
642    memcpy(p, default_outer_level, 4 * sizeof(float));
643    memcpy(p + 4, default_inner_level, 2 * sizeof(float));
644 }
645 
646 struct tc_constant_buffer {
647    ubyte shader, index;
648    struct pipe_constant_buffer cb;
649 };
650 
651 static void
tc_call_set_constant_buffer(struct pipe_context * pipe,union tc_payload * payload)652 tc_call_set_constant_buffer(struct pipe_context *pipe, union tc_payload *payload)
653 {
654    struct tc_constant_buffer *p = (struct tc_constant_buffer *)payload;
655 
656    pipe->set_constant_buffer(pipe,
657                              p->shader,
658                              p->index,
659                              &p->cb);
660    pipe_resource_reference(&p->cb.buffer, NULL);
661 }
662 
663 static void
tc_set_constant_buffer(struct pipe_context * _pipe,enum pipe_shader_type shader,uint index,const struct pipe_constant_buffer * cb)664 tc_set_constant_buffer(struct pipe_context *_pipe,
665                        enum pipe_shader_type shader, uint index,
666                        const struct pipe_constant_buffer *cb)
667 {
668    struct threaded_context *tc = threaded_context(_pipe);
669    struct pipe_resource *buffer = NULL;
670    unsigned offset;
671 
672    /* This must be done before adding set_constant_buffer, because it could
673     * generate e.g. transfer_unmap and flush partially-uninitialized
674     * set_constant_buffer to the driver if it was done afterwards.
675     */
676    if (cb && cb->user_buffer) {
677       u_upload_data(tc->base.const_uploader, 0, cb->buffer_size, 64,
678                     cb->user_buffer, &offset, &buffer);
679    }
680 
681    struct tc_constant_buffer *p =
682       tc_add_struct_typed_call(tc, TC_CALL_set_constant_buffer,
683                                tc_constant_buffer);
684    p->shader = shader;
685    p->index = index;
686 
687    if (cb) {
688       if (cb->user_buffer) {
689          p->cb.buffer_size = cb->buffer_size;
690          p->cb.user_buffer = NULL;
691          p->cb.buffer_offset = offset;
692          p->cb.buffer = buffer;
693       } else {
694          tc_set_resource_reference(&p->cb.buffer,
695                                    cb->buffer);
696          memcpy(&p->cb, cb, sizeof(*cb));
697       }
698    } else {
699       memset(&p->cb, 0, sizeof(*cb));
700    }
701 }
702 
703 struct tc_scissors {
704    ubyte start, count;
705    struct pipe_scissor_state slot[0]; /* more will be allocated if needed */
706 };
707 
708 static void
tc_call_set_scissor_states(struct pipe_context * pipe,union tc_payload * payload)709 tc_call_set_scissor_states(struct pipe_context *pipe, union tc_payload *payload)
710 {
711    struct tc_scissors *p = (struct tc_scissors *)payload;
712    pipe->set_scissor_states(pipe, p->start, p->count, p->slot);
713 }
714 
715 static void
tc_set_scissor_states(struct pipe_context * _pipe,unsigned start,unsigned count,const struct pipe_scissor_state * states)716 tc_set_scissor_states(struct pipe_context *_pipe,
717                       unsigned start, unsigned count,
718                       const struct pipe_scissor_state *states)
719 {
720    struct threaded_context *tc = threaded_context(_pipe);
721    struct tc_scissors *p =
722       tc_add_slot_based_call(tc, TC_CALL_set_scissor_states, tc_scissors, count);
723 
724    p->start = start;
725    p->count = count;
726    memcpy(&p->slot, states, count * sizeof(states[0]));
727 }
728 
729 struct tc_viewports {
730    ubyte start, count;
731    struct pipe_viewport_state slot[0]; /* more will be allocated if needed */
732 };
733 
734 static void
tc_call_set_viewport_states(struct pipe_context * pipe,union tc_payload * payload)735 tc_call_set_viewport_states(struct pipe_context *pipe, union tc_payload *payload)
736 {
737    struct tc_viewports *p = (struct tc_viewports *)payload;
738    pipe->set_viewport_states(pipe, p->start, p->count, p->slot);
739 }
740 
741 static void
tc_set_viewport_states(struct pipe_context * _pipe,unsigned start,unsigned count,const struct pipe_viewport_state * states)742 tc_set_viewport_states(struct pipe_context *_pipe,
743                        unsigned start, unsigned count,
744                        const struct pipe_viewport_state *states)
745 {
746    if (!count)
747       return;
748 
749    struct threaded_context *tc = threaded_context(_pipe);
750    struct tc_viewports *p =
751       tc_add_slot_based_call(tc, TC_CALL_set_viewport_states, tc_viewports, count);
752 
753    p->start = start;
754    p->count = count;
755    memcpy(&p->slot, states, count * sizeof(states[0]));
756 }
757 
758 struct tc_window_rects {
759    bool include;
760    ubyte count;
761    struct pipe_scissor_state slot[0]; /* more will be allocated if needed */
762 };
763 
764 static void
tc_call_set_window_rectangles(struct pipe_context * pipe,union tc_payload * payload)765 tc_call_set_window_rectangles(struct pipe_context *pipe,
766                               union tc_payload *payload)
767 {
768    struct tc_window_rects *p = (struct tc_window_rects *)payload;
769    pipe->set_window_rectangles(pipe, p->include, p->count, p->slot);
770 }
771 
772 static void
tc_set_window_rectangles(struct pipe_context * _pipe,boolean include,unsigned count,const struct pipe_scissor_state * rects)773 tc_set_window_rectangles(struct pipe_context *_pipe, boolean include,
774                          unsigned count,
775                          const struct pipe_scissor_state *rects)
776 {
777    struct threaded_context *tc = threaded_context(_pipe);
778    struct tc_window_rects *p =
779       tc_add_slot_based_call(tc, TC_CALL_set_window_rectangles, tc_window_rects, count);
780 
781    p->include = include;
782    p->count = count;
783    memcpy(p->slot, rects, count * sizeof(rects[0]));
784 }
785 
786 struct tc_sampler_views {
787    ubyte shader, start, count;
788    struct pipe_sampler_view *slot[0]; /* more will be allocated if needed */
789 };
790 
791 static void
tc_call_set_sampler_views(struct pipe_context * pipe,union tc_payload * payload)792 tc_call_set_sampler_views(struct pipe_context *pipe, union tc_payload *payload)
793 {
794    struct tc_sampler_views *p = (struct tc_sampler_views *)payload;
795    unsigned count = p->count;
796 
797    pipe->set_sampler_views(pipe, p->shader, p->start, p->count, p->slot);
798    for (unsigned i = 0; i < count; i++)
799       pipe_sampler_view_reference(&p->slot[i], NULL);
800 }
801 
802 static void
tc_set_sampler_views(struct pipe_context * _pipe,enum pipe_shader_type shader,unsigned start,unsigned count,struct pipe_sampler_view ** views)803 tc_set_sampler_views(struct pipe_context *_pipe,
804                      enum pipe_shader_type shader,
805                      unsigned start, unsigned count,
806                      struct pipe_sampler_view **views)
807 {
808    if (!count)
809       return;
810 
811    struct threaded_context *tc = threaded_context(_pipe);
812    struct tc_sampler_views *p =
813       tc_add_slot_based_call(tc, TC_CALL_set_sampler_views, tc_sampler_views, count);
814 
815    p->shader = shader;
816    p->start = start;
817    p->count = count;
818 
819    if (views) {
820       for (unsigned i = 0; i < count; i++) {
821          p->slot[i] = NULL;
822          pipe_sampler_view_reference(&p->slot[i], views[i]);
823       }
824    } else {
825       memset(p->slot, 0, count * sizeof(views[0]));
826    }
827 }
828 
829 struct tc_shader_images {
830    ubyte shader, start, count;
831    bool unbind;
832    struct pipe_image_view slot[0]; /* more will be allocated if needed */
833 };
834 
835 static void
tc_call_set_shader_images(struct pipe_context * pipe,union tc_payload * payload)836 tc_call_set_shader_images(struct pipe_context *pipe, union tc_payload *payload)
837 {
838    struct tc_shader_images *p = (struct tc_shader_images *)payload;
839    unsigned count = p->count;
840 
841    if (p->unbind) {
842       pipe->set_shader_images(pipe, p->shader, p->start, p->count, NULL);
843       return;
844    }
845 
846    pipe->set_shader_images(pipe, p->shader, p->start, p->count, p->slot);
847 
848    for (unsigned i = 0; i < count; i++)
849       pipe_resource_reference(&p->slot[i].resource, NULL);
850 }
851 
852 static void
tc_set_shader_images(struct pipe_context * _pipe,enum pipe_shader_type shader,unsigned start,unsigned count,const struct pipe_image_view * images)853 tc_set_shader_images(struct pipe_context *_pipe,
854                      enum pipe_shader_type shader,
855                      unsigned start, unsigned count,
856                      const struct pipe_image_view *images)
857 {
858    if (!count)
859       return;
860 
861    struct threaded_context *tc = threaded_context(_pipe);
862    struct tc_shader_images *p =
863       tc_add_slot_based_call(tc, TC_CALL_set_shader_images, tc_shader_images,
864                              images ? count : 0);
865 
866    p->shader = shader;
867    p->start = start;
868    p->count = count;
869    p->unbind = images == NULL;
870 
871    if (images) {
872       for (unsigned i = 0; i < count; i++) {
873          tc_set_resource_reference(&p->slot[i].resource, images[i].resource);
874 
875          if (images[i].access & PIPE_IMAGE_ACCESS_WRITE &&
876              images[i].resource &&
877              images[i].resource->target == PIPE_BUFFER) {
878             struct threaded_resource *tres =
879                threaded_resource(images[i].resource);
880 
881             util_range_add(&tres->valid_buffer_range, images[i].u.buf.offset,
882                            images[i].u.buf.offset + images[i].u.buf.size);
883          }
884       }
885       memcpy(p->slot, images, count * sizeof(images[0]));
886    }
887 }
888 
889 struct tc_shader_buffers {
890    ubyte shader, start, count;
891    bool unbind;
892    struct pipe_shader_buffer slot[0]; /* more will be allocated if needed */
893 };
894 
895 static void
tc_call_set_shader_buffers(struct pipe_context * pipe,union tc_payload * payload)896 tc_call_set_shader_buffers(struct pipe_context *pipe, union tc_payload *payload)
897 {
898    struct tc_shader_buffers *p = (struct tc_shader_buffers *)payload;
899    unsigned count = p->count;
900 
901    if (p->unbind) {
902       pipe->set_shader_buffers(pipe, p->shader, p->start, p->count, NULL);
903       return;
904    }
905 
906    pipe->set_shader_buffers(pipe, p->shader, p->start, p->count, p->slot);
907 
908    for (unsigned i = 0; i < count; i++)
909       pipe_resource_reference(&p->slot[i].buffer, NULL);
910 }
911 
912 static void
tc_set_shader_buffers(struct pipe_context * _pipe,enum pipe_shader_type shader,unsigned start,unsigned count,const struct pipe_shader_buffer * buffers)913 tc_set_shader_buffers(struct pipe_context *_pipe,
914                       enum pipe_shader_type shader,
915                       unsigned start, unsigned count,
916                       const struct pipe_shader_buffer *buffers)
917 {
918    if (!count)
919       return;
920 
921    struct threaded_context *tc = threaded_context(_pipe);
922    struct tc_shader_buffers *p =
923       tc_add_slot_based_call(tc, TC_CALL_set_shader_buffers, tc_shader_buffers,
924                              buffers ? count : 0);
925 
926    p->shader = shader;
927    p->start = start;
928    p->count = count;
929    p->unbind = buffers == NULL;
930 
931    if (buffers) {
932       for (unsigned i = 0; i < count; i++) {
933          struct pipe_shader_buffer *dst = &p->slot[i];
934          const struct pipe_shader_buffer *src = buffers + i;
935 
936          tc_set_resource_reference(&dst->buffer, src->buffer);
937          dst->buffer_offset = src->buffer_offset;
938          dst->buffer_size = src->buffer_size;
939 
940          if (src->buffer) {
941             struct threaded_resource *tres = threaded_resource(src->buffer);
942 
943             util_range_add(&tres->valid_buffer_range, src->buffer_offset,
944                            src->buffer_offset + src->buffer_size);
945          }
946       }
947    }
948 }
949 
950 struct tc_vertex_buffers {
951    ubyte start, count;
952    bool unbind;
953    struct pipe_vertex_buffer slot[0]; /* more will be allocated if needed */
954 };
955 
956 static void
tc_call_set_vertex_buffers(struct pipe_context * pipe,union tc_payload * payload)957 tc_call_set_vertex_buffers(struct pipe_context *pipe, union tc_payload *payload)
958 {
959    struct tc_vertex_buffers *p = (struct tc_vertex_buffers *)payload;
960    unsigned count = p->count;
961 
962    if (p->unbind) {
963       pipe->set_vertex_buffers(pipe, p->start, count, NULL);
964       return;
965    }
966 
967    for (unsigned i = 0; i < count; i++)
968       tc_assert(!p->slot[i].is_user_buffer);
969 
970    pipe->set_vertex_buffers(pipe, p->start, count, p->slot);
971    for (unsigned i = 0; i < count; i++)
972       pipe_resource_reference(&p->slot[i].buffer.resource, NULL);
973 }
974 
975 static void
tc_set_vertex_buffers(struct pipe_context * _pipe,unsigned start,unsigned count,const struct pipe_vertex_buffer * buffers)976 tc_set_vertex_buffers(struct pipe_context *_pipe,
977                       unsigned start, unsigned count,
978                       const struct pipe_vertex_buffer *buffers)
979 {
980    struct threaded_context *tc = threaded_context(_pipe);
981 
982    if (!count)
983       return;
984 
985    if (buffers) {
986       struct tc_vertex_buffers *p =
987          tc_add_slot_based_call(tc, TC_CALL_set_vertex_buffers, tc_vertex_buffers, count);
988       p->start = start;
989       p->count = count;
990       p->unbind = false;
991 
992       for (unsigned i = 0; i < count; i++) {
993          struct pipe_vertex_buffer *dst = &p->slot[i];
994          const struct pipe_vertex_buffer *src = buffers + i;
995 
996          tc_assert(!src->is_user_buffer);
997          dst->stride = src->stride;
998          dst->is_user_buffer = false;
999          tc_set_resource_reference(&dst->buffer.resource,
1000                                    src->buffer.resource);
1001          dst->buffer_offset = src->buffer_offset;
1002       }
1003    } else {
1004       struct tc_vertex_buffers *p =
1005          tc_add_slot_based_call(tc, TC_CALL_set_vertex_buffers, tc_vertex_buffers, 0);
1006       p->start = start;
1007       p->count = count;
1008       p->unbind = true;
1009    }
1010 }
1011 
1012 struct tc_stream_outputs {
1013    unsigned count;
1014    struct pipe_stream_output_target *targets[PIPE_MAX_SO_BUFFERS];
1015    unsigned offsets[PIPE_MAX_SO_BUFFERS];
1016 };
1017 
1018 static void
tc_call_set_stream_output_targets(struct pipe_context * pipe,union tc_payload * payload)1019 tc_call_set_stream_output_targets(struct pipe_context *pipe, union tc_payload *payload)
1020 {
1021    struct tc_stream_outputs *p = (struct tc_stream_outputs *)payload;
1022    unsigned count = p->count;
1023 
1024    pipe->set_stream_output_targets(pipe, count, p->targets, p->offsets);
1025    for (unsigned i = 0; i < count; i++)
1026       pipe_so_target_reference(&p->targets[i], NULL);
1027 }
1028 
1029 static void
tc_set_stream_output_targets(struct pipe_context * _pipe,unsigned count,struct pipe_stream_output_target ** tgs,const unsigned * offsets)1030 tc_set_stream_output_targets(struct pipe_context *_pipe,
1031                              unsigned count,
1032                              struct pipe_stream_output_target **tgs,
1033                              const unsigned *offsets)
1034 {
1035    struct threaded_context *tc = threaded_context(_pipe);
1036    struct tc_stream_outputs *p =
1037       tc_add_struct_typed_call(tc, TC_CALL_set_stream_output_targets,
1038                                tc_stream_outputs);
1039 
1040    for (unsigned i = 0; i < count; i++) {
1041       p->targets[i] = NULL;
1042       pipe_so_target_reference(&p->targets[i], tgs[i]);
1043    }
1044    p->count = count;
1045    memcpy(p->offsets, offsets, count * sizeof(unsigned));
1046 }
1047 
1048 static void
tc_set_compute_resources(struct pipe_context * _pipe,unsigned start,unsigned count,struct pipe_surface ** resources)1049 tc_set_compute_resources(struct pipe_context *_pipe, unsigned start,
1050                          unsigned count, struct pipe_surface **resources)
1051 {
1052    struct threaded_context *tc = threaded_context(_pipe);
1053    struct pipe_context *pipe = tc->pipe;
1054 
1055    tc_sync(tc);
1056    pipe->set_compute_resources(pipe, start, count, resources);
1057 }
1058 
1059 static void
tc_set_global_binding(struct pipe_context * _pipe,unsigned first,unsigned count,struct pipe_resource ** resources,uint32_t ** handles)1060 tc_set_global_binding(struct pipe_context *_pipe, unsigned first,
1061                       unsigned count, struct pipe_resource **resources,
1062                       uint32_t **handles)
1063 {
1064    struct threaded_context *tc = threaded_context(_pipe);
1065    struct pipe_context *pipe = tc->pipe;
1066 
1067    tc_sync(tc);
1068    pipe->set_global_binding(pipe, first, count, resources, handles);
1069 }
1070 
1071 
1072 /********************************************************************
1073  * views
1074  */
1075 
1076 static struct pipe_surface *
tc_create_surface(struct pipe_context * _pipe,struct pipe_resource * resource,const struct pipe_surface * surf_tmpl)1077 tc_create_surface(struct pipe_context *_pipe,
1078                   struct pipe_resource *resource,
1079                   const struct pipe_surface *surf_tmpl)
1080 {
1081    struct pipe_context *pipe = threaded_context(_pipe)->pipe;
1082    struct pipe_surface *view =
1083          pipe->create_surface(pipe, resource, surf_tmpl);
1084 
1085    if (view)
1086       view->context = _pipe;
1087    return view;
1088 }
1089 
1090 static void
tc_surface_destroy(struct pipe_context * _pipe,struct pipe_surface * surf)1091 tc_surface_destroy(struct pipe_context *_pipe,
1092                    struct pipe_surface *surf)
1093 {
1094    struct pipe_context *pipe = threaded_context(_pipe)->pipe;
1095 
1096    pipe->surface_destroy(pipe, surf);
1097 }
1098 
1099 static struct pipe_sampler_view *
tc_create_sampler_view(struct pipe_context * _pipe,struct pipe_resource * resource,const struct pipe_sampler_view * templ)1100 tc_create_sampler_view(struct pipe_context *_pipe,
1101                        struct pipe_resource *resource,
1102                        const struct pipe_sampler_view *templ)
1103 {
1104    struct pipe_context *pipe = threaded_context(_pipe)->pipe;
1105    struct pipe_sampler_view *view =
1106          pipe->create_sampler_view(pipe, resource, templ);
1107 
1108    if (view)
1109       view->context = _pipe;
1110    return view;
1111 }
1112 
1113 static void
tc_sampler_view_destroy(struct pipe_context * _pipe,struct pipe_sampler_view * view)1114 tc_sampler_view_destroy(struct pipe_context *_pipe,
1115                         struct pipe_sampler_view *view)
1116 {
1117    struct pipe_context *pipe = threaded_context(_pipe)->pipe;
1118 
1119    pipe->sampler_view_destroy(pipe, view);
1120 }
1121 
1122 static struct pipe_stream_output_target *
tc_create_stream_output_target(struct pipe_context * _pipe,struct pipe_resource * res,unsigned buffer_offset,unsigned buffer_size)1123 tc_create_stream_output_target(struct pipe_context *_pipe,
1124                                struct pipe_resource *res,
1125                                unsigned buffer_offset,
1126                                unsigned buffer_size)
1127 {
1128    struct pipe_context *pipe = threaded_context(_pipe)->pipe;
1129    struct threaded_resource *tres = threaded_resource(res);
1130    struct pipe_stream_output_target *view;
1131 
1132    tc_sync(threaded_context(_pipe));
1133    util_range_add(&tres->valid_buffer_range, buffer_offset,
1134                   buffer_offset + buffer_size);
1135 
1136    view = pipe->create_stream_output_target(pipe, res, buffer_offset,
1137                                             buffer_size);
1138    if (view)
1139       view->context = _pipe;
1140    return view;
1141 }
1142 
1143 static void
tc_stream_output_target_destroy(struct pipe_context * _pipe,struct pipe_stream_output_target * target)1144 tc_stream_output_target_destroy(struct pipe_context *_pipe,
1145                                 struct pipe_stream_output_target *target)
1146 {
1147    struct pipe_context *pipe = threaded_context(_pipe)->pipe;
1148 
1149    pipe->stream_output_target_destroy(pipe, target);
1150 }
1151 
1152 
1153 /********************************************************************
1154  * bindless
1155  */
1156 
1157 static uint64_t
tc_create_texture_handle(struct pipe_context * _pipe,struct pipe_sampler_view * view,const struct pipe_sampler_state * state)1158 tc_create_texture_handle(struct pipe_context *_pipe,
1159                          struct pipe_sampler_view *view,
1160                          const struct pipe_sampler_state *state)
1161 {
1162    struct threaded_context *tc = threaded_context(_pipe);
1163    struct pipe_context *pipe = tc->pipe;
1164 
1165    tc_sync(tc);
1166    return pipe->create_texture_handle(pipe, view, state);
1167 }
1168 
1169 static void
tc_call_delete_texture_handle(struct pipe_context * pipe,union tc_payload * payload)1170 tc_call_delete_texture_handle(struct pipe_context *pipe,
1171                               union tc_payload *payload)
1172 {
1173    pipe->delete_texture_handle(pipe, payload->handle);
1174 }
1175 
1176 static void
tc_delete_texture_handle(struct pipe_context * _pipe,uint64_t handle)1177 tc_delete_texture_handle(struct pipe_context *_pipe, uint64_t handle)
1178 {
1179    struct threaded_context *tc = threaded_context(_pipe);
1180    union tc_payload *payload =
1181       tc_add_small_call(tc, TC_CALL_delete_texture_handle);
1182 
1183    payload->handle = handle;
1184 }
1185 
1186 struct tc_make_texture_handle_resident
1187 {
1188    uint64_t handle;
1189    bool resident;
1190 };
1191 
1192 static void
tc_call_make_texture_handle_resident(struct pipe_context * pipe,union tc_payload * payload)1193 tc_call_make_texture_handle_resident(struct pipe_context *pipe,
1194                                      union tc_payload *payload)
1195 {
1196    struct tc_make_texture_handle_resident *p =
1197       (struct tc_make_texture_handle_resident *)payload;
1198 
1199    pipe->make_texture_handle_resident(pipe, p->handle, p->resident);
1200 }
1201 
1202 static void
tc_make_texture_handle_resident(struct pipe_context * _pipe,uint64_t handle,bool resident)1203 tc_make_texture_handle_resident(struct pipe_context *_pipe, uint64_t handle,
1204                                 bool resident)
1205 {
1206    struct threaded_context *tc = threaded_context(_pipe);
1207    struct tc_make_texture_handle_resident *p =
1208       tc_add_struct_typed_call(tc, TC_CALL_make_texture_handle_resident,
1209                                tc_make_texture_handle_resident);
1210 
1211    p->handle = handle;
1212    p->resident = resident;
1213 }
1214 
1215 static uint64_t
tc_create_image_handle(struct pipe_context * _pipe,const struct pipe_image_view * image)1216 tc_create_image_handle(struct pipe_context *_pipe,
1217                        const struct pipe_image_view *image)
1218 {
1219    struct threaded_context *tc = threaded_context(_pipe);
1220    struct pipe_context *pipe = tc->pipe;
1221 
1222    tc_sync(tc);
1223    return pipe->create_image_handle(pipe, image);
1224 }
1225 
1226 static void
tc_call_delete_image_handle(struct pipe_context * pipe,union tc_payload * payload)1227 tc_call_delete_image_handle(struct pipe_context *pipe,
1228                             union tc_payload *payload)
1229 {
1230    pipe->delete_image_handle(pipe, payload->handle);
1231 }
1232 
1233 static void
tc_delete_image_handle(struct pipe_context * _pipe,uint64_t handle)1234 tc_delete_image_handle(struct pipe_context *_pipe, uint64_t handle)
1235 {
1236    struct threaded_context *tc = threaded_context(_pipe);
1237    union tc_payload *payload =
1238       tc_add_small_call(tc, TC_CALL_delete_image_handle);
1239 
1240    payload->handle = handle;
1241 }
1242 
1243 struct tc_make_image_handle_resident
1244 {
1245    uint64_t handle;
1246    unsigned access;
1247    bool resident;
1248 };
1249 
1250 static void
tc_call_make_image_handle_resident(struct pipe_context * pipe,union tc_payload * payload)1251 tc_call_make_image_handle_resident(struct pipe_context *pipe,
1252                                      union tc_payload *payload)
1253 {
1254    struct tc_make_image_handle_resident *p =
1255       (struct tc_make_image_handle_resident *)payload;
1256 
1257    pipe->make_image_handle_resident(pipe, p->handle, p->access, p->resident);
1258 }
1259 
1260 static void
tc_make_image_handle_resident(struct pipe_context * _pipe,uint64_t handle,unsigned access,bool resident)1261 tc_make_image_handle_resident(struct pipe_context *_pipe, uint64_t handle,
1262                               unsigned access, bool resident)
1263 {
1264    struct threaded_context *tc = threaded_context(_pipe);
1265    struct tc_make_image_handle_resident *p =
1266       tc_add_struct_typed_call(tc, TC_CALL_make_image_handle_resident,
1267                                tc_make_image_handle_resident);
1268 
1269    p->handle = handle;
1270    p->access = access;
1271    p->resident = resident;
1272 }
1273 
1274 
1275 /********************************************************************
1276  * transfer
1277  */
1278 
1279 struct tc_replace_buffer_storage {
1280    struct pipe_resource *dst;
1281    struct pipe_resource *src;
1282    tc_replace_buffer_storage_func func;
1283 };
1284 
1285 static void
tc_call_replace_buffer_storage(struct pipe_context * pipe,union tc_payload * payload)1286 tc_call_replace_buffer_storage(struct pipe_context *pipe,
1287                                union tc_payload *payload)
1288 {
1289    struct tc_replace_buffer_storage *p =
1290       (struct tc_replace_buffer_storage *)payload;
1291 
1292    p->func(pipe, p->dst, p->src);
1293    pipe_resource_reference(&p->dst, NULL);
1294    pipe_resource_reference(&p->src, NULL);
1295 }
1296 
1297 static bool
tc_invalidate_buffer(struct threaded_context * tc,struct threaded_resource * tbuf)1298 tc_invalidate_buffer(struct threaded_context *tc,
1299                      struct threaded_resource *tbuf)
1300 {
1301    /* We can't check if the buffer is idle, so we invalidate it
1302     * unconditionally. */
1303    struct pipe_screen *screen = tc->base.screen;
1304    struct pipe_resource *new_buf;
1305 
1306    /* Shared, pinned, and sparse buffers can't be reallocated. */
1307    if (tbuf->is_shared ||
1308        tbuf->is_user_ptr ||
1309        tbuf->b.flags & PIPE_RESOURCE_FLAG_SPARSE)
1310       return false;
1311 
1312    /* Allocate a new one. */
1313    new_buf = screen->resource_create(screen, &tbuf->b);
1314    if (!new_buf)
1315       return false;
1316 
1317    /* Replace the "latest" pointer. */
1318    if (tbuf->latest != &tbuf->b)
1319       pipe_resource_reference(&tbuf->latest, NULL);
1320 
1321    tbuf->latest = new_buf;
1322    util_range_set_empty(&tbuf->valid_buffer_range);
1323 
1324    /* The valid range should point to the original buffer. */
1325    threaded_resource(new_buf)->base_valid_buffer_range =
1326       &tbuf->valid_buffer_range;
1327 
1328    /* Enqueue storage replacement of the original buffer. */
1329    struct tc_replace_buffer_storage *p =
1330       tc_add_struct_typed_call(tc, TC_CALL_replace_buffer_storage,
1331                                tc_replace_buffer_storage);
1332 
1333    p->func = tc->replace_buffer_storage;
1334    tc_set_resource_reference(&p->dst, &tbuf->b);
1335    tc_set_resource_reference(&p->src, new_buf);
1336    return true;
1337 }
1338 
1339 static unsigned
tc_improve_map_buffer_flags(struct threaded_context * tc,struct threaded_resource * tres,unsigned usage,unsigned offset,unsigned size)1340 tc_improve_map_buffer_flags(struct threaded_context *tc,
1341                             struct threaded_resource *tres, unsigned usage,
1342                             unsigned offset, unsigned size)
1343 {
1344    /* Never invalidate inside the driver and never infer "unsynchronized". */
1345    unsigned tc_flags = TC_TRANSFER_MAP_NO_INVALIDATE |
1346                        TC_TRANSFER_MAP_NO_INFER_UNSYNCHRONIZED;
1347 
1348    /* Prevent a reentry. */
1349    if (usage & tc_flags)
1350       return usage;
1351 
1352    /* Use the staging upload if it's preferred. */
1353    if (usage & (PIPE_TRANSFER_DISCARD_RANGE |
1354                 PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) &&
1355        !(usage & PIPE_TRANSFER_PERSISTENT) &&
1356        /* Try not to decrement the counter if it's not positive. Still racy,
1357         * but it makes it harder to wrap the counter from INT_MIN to INT_MAX. */
1358        tres->max_forced_staging_uploads > 0 &&
1359        p_atomic_dec_return(&tres->max_forced_staging_uploads) >= 0) {
1360       usage &= ~(PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE |
1361                  PIPE_TRANSFER_UNSYNCHRONIZED);
1362 
1363       return usage | tc_flags | PIPE_TRANSFER_DISCARD_RANGE;
1364    }
1365 
1366    /* Sparse buffers can't be mapped directly and can't be reallocated
1367     * (fully invalidated). That may just be a radeonsi limitation, but
1368     * the threaded context must obey it with radeonsi.
1369     */
1370    if (tres->b.flags & PIPE_RESOURCE_FLAG_SPARSE) {
1371       /* We can use DISCARD_RANGE instead of full discard. This is the only
1372        * fast path for sparse buffers that doesn't need thread synchronization.
1373        */
1374       if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE)
1375          usage |= PIPE_TRANSFER_DISCARD_RANGE;
1376 
1377       /* Allow DISCARD_WHOLE_RESOURCE and infering UNSYNCHRONIZED in drivers.
1378        * The threaded context doesn't do unsychronized mappings and invalida-
1379        * tions of sparse buffers, therefore a correct driver behavior won't
1380        * result in an incorrect behavior with the threaded context.
1381        */
1382       return usage;
1383    }
1384 
1385    usage |= tc_flags;
1386 
1387    /* Handle CPU reads trivially. */
1388    if (usage & PIPE_TRANSFER_READ) {
1389       /* Drivers aren't allowed to do buffer invalidations. */
1390       return usage & ~PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE;
1391    }
1392 
1393    /* See if the buffer range being mapped has never been initialized,
1394     * in which case it can be mapped unsynchronized. */
1395    if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED) &&
1396        !tres->is_shared &&
1397        !util_ranges_intersect(&tres->valid_buffer_range, offset, offset + size))
1398       usage |= PIPE_TRANSFER_UNSYNCHRONIZED;
1399 
1400    if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
1401       /* If discarding the entire range, discard the whole resource instead. */
1402       if (usage & PIPE_TRANSFER_DISCARD_RANGE &&
1403           offset == 0 && size == tres->b.width0)
1404          usage |= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE;
1405 
1406       /* Discard the whole resource if needed. */
1407       if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) {
1408          if (tc_invalidate_buffer(tc, tres))
1409             usage |= PIPE_TRANSFER_UNSYNCHRONIZED;
1410          else
1411             usage |= PIPE_TRANSFER_DISCARD_RANGE; /* fallback */
1412       }
1413    }
1414 
1415    /* We won't need this flag anymore. */
1416    /* TODO: We might not need TC_TRANSFER_MAP_NO_INVALIDATE with this. */
1417    usage &= ~PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE;
1418 
1419    /* GL_AMD_pinned_memory and persistent mappings can't use staging
1420     * buffers. */
1421    if (usage & (PIPE_TRANSFER_UNSYNCHRONIZED |
1422                 PIPE_TRANSFER_PERSISTENT) ||
1423        tres->is_user_ptr)
1424       usage &= ~PIPE_TRANSFER_DISCARD_RANGE;
1425 
1426    /* Unsychronized buffer mappings don't have to synchronize the thread. */
1427    if (usage & PIPE_TRANSFER_UNSYNCHRONIZED) {
1428       usage &= ~PIPE_TRANSFER_DISCARD_RANGE;
1429       usage |= TC_TRANSFER_MAP_THREADED_UNSYNC; /* notify the driver */
1430    }
1431 
1432    return usage;
1433 }
1434 
1435 static void *
tc_transfer_map(struct pipe_context * _pipe,struct pipe_resource * resource,unsigned level,unsigned usage,const struct pipe_box * box,struct pipe_transfer ** transfer)1436 tc_transfer_map(struct pipe_context *_pipe,
1437                 struct pipe_resource *resource, unsigned level,
1438                 unsigned usage, const struct pipe_box *box,
1439                 struct pipe_transfer **transfer)
1440 {
1441    struct threaded_context *tc = threaded_context(_pipe);
1442    struct threaded_resource *tres = threaded_resource(resource);
1443    struct pipe_context *pipe = tc->pipe;
1444 
1445    if (resource->target == PIPE_BUFFER) {
1446       usage = tc_improve_map_buffer_flags(tc, tres, usage, box->x, box->width);
1447 
1448       /* Do a staging transfer within the threaded context. The driver should
1449        * only get resource_copy_region.
1450        */
1451       if (usage & PIPE_TRANSFER_DISCARD_RANGE) {
1452          struct threaded_transfer *ttrans = slab_alloc(&tc->pool_transfers);
1453          uint8_t *map;
1454 
1455          ttrans->staging = NULL;
1456 
1457          u_upload_alloc(tc->base.stream_uploader, 0,
1458                         box->width + (box->x % tc->map_buffer_alignment),
1459                         64, &ttrans->offset, &ttrans->staging, (void**)&map);
1460          if (!map) {
1461             slab_free(&tc->pool_transfers, ttrans);
1462             return NULL;
1463          }
1464 
1465          tc_set_resource_reference(&ttrans->b.resource, resource);
1466          ttrans->b.level = 0;
1467          ttrans->b.usage = usage;
1468          ttrans->b.box = *box;
1469          ttrans->b.stride = 0;
1470          ttrans->b.layer_stride = 0;
1471          *transfer = &ttrans->b;
1472          return map + (box->x % tc->map_buffer_alignment);
1473       }
1474    }
1475 
1476    /* Unsychronized buffer mappings don't have to synchronize the thread. */
1477    if (!(usage & TC_TRANSFER_MAP_THREADED_UNSYNC))
1478       tc_sync_msg(tc, resource->target != PIPE_BUFFER ? "  texture" :
1479                       usage & PIPE_TRANSFER_DISCARD_RANGE ? "  discard_range" :
1480                       usage & PIPE_TRANSFER_READ ? "  read" : "  ??");
1481 
1482    return pipe->transfer_map(pipe, tres->latest ? tres->latest : resource,
1483                              level, usage, box, transfer);
1484 }
1485 
1486 struct tc_transfer_flush_region {
1487    struct pipe_transfer *transfer;
1488    struct pipe_box box;
1489 };
1490 
1491 static void
tc_call_transfer_flush_region(struct pipe_context * pipe,union tc_payload * payload)1492 tc_call_transfer_flush_region(struct pipe_context *pipe,
1493                               union tc_payload *payload)
1494 {
1495    struct tc_transfer_flush_region *p =
1496       (struct tc_transfer_flush_region *)payload;
1497 
1498    pipe->transfer_flush_region(pipe, p->transfer, &p->box);
1499 }
1500 
1501 struct tc_resource_copy_region {
1502    struct pipe_resource *dst;
1503    unsigned dst_level;
1504    unsigned dstx, dsty, dstz;
1505    struct pipe_resource *src;
1506    unsigned src_level;
1507    struct pipe_box src_box;
1508 };
1509 
1510 static void
1511 tc_resource_copy_region(struct pipe_context *_pipe,
1512                         struct pipe_resource *dst, unsigned dst_level,
1513                         unsigned dstx, unsigned dsty, unsigned dstz,
1514                         struct pipe_resource *src, unsigned src_level,
1515                         const struct pipe_box *src_box);
1516 
1517 static void
tc_buffer_do_flush_region(struct threaded_context * tc,struct threaded_transfer * ttrans,const struct pipe_box * box)1518 tc_buffer_do_flush_region(struct threaded_context *tc,
1519                           struct threaded_transfer *ttrans,
1520                           const struct pipe_box *box)
1521 {
1522    struct threaded_resource *tres = threaded_resource(ttrans->b.resource);
1523 
1524    if (ttrans->staging) {
1525       struct pipe_box src_box;
1526 
1527       u_box_1d(ttrans->offset + box->x % tc->map_buffer_alignment,
1528                box->width, &src_box);
1529 
1530       /* Copy the staging buffer into the original one. */
1531       tc_resource_copy_region(&tc->base, ttrans->b.resource, 0, box->x, 0, 0,
1532                               ttrans->staging, 0, &src_box);
1533    }
1534 
1535    util_range_add(tres->base_valid_buffer_range, box->x, box->x + box->width);
1536 }
1537 
1538 static void
tc_transfer_flush_region(struct pipe_context * _pipe,struct pipe_transfer * transfer,const struct pipe_box * rel_box)1539 tc_transfer_flush_region(struct pipe_context *_pipe,
1540                          struct pipe_transfer *transfer,
1541                          const struct pipe_box *rel_box)
1542 {
1543    struct threaded_context *tc = threaded_context(_pipe);
1544    struct threaded_transfer *ttrans = threaded_transfer(transfer);
1545    struct threaded_resource *tres = threaded_resource(transfer->resource);
1546    unsigned required_usage = PIPE_TRANSFER_WRITE |
1547                              PIPE_TRANSFER_FLUSH_EXPLICIT;
1548 
1549    if (tres->b.target == PIPE_BUFFER) {
1550       if ((transfer->usage & required_usage) == required_usage) {
1551          struct pipe_box box;
1552 
1553          u_box_1d(transfer->box.x + rel_box->x, rel_box->width, &box);
1554          tc_buffer_do_flush_region(tc, ttrans, &box);
1555       }
1556 
1557       /* Staging transfers don't send the call to the driver. */
1558       if (ttrans->staging)
1559          return;
1560    }
1561 
1562    struct tc_transfer_flush_region *p =
1563       tc_add_struct_typed_call(tc, TC_CALL_transfer_flush_region,
1564                                tc_transfer_flush_region);
1565    p->transfer = transfer;
1566    p->box = *rel_box;
1567 }
1568 
1569 static void
tc_call_transfer_unmap(struct pipe_context * pipe,union tc_payload * payload)1570 tc_call_transfer_unmap(struct pipe_context *pipe, union tc_payload *payload)
1571 {
1572    pipe->transfer_unmap(pipe, payload->transfer);
1573 }
1574 
1575 static void
tc_transfer_unmap(struct pipe_context * _pipe,struct pipe_transfer * transfer)1576 tc_transfer_unmap(struct pipe_context *_pipe, struct pipe_transfer *transfer)
1577 {
1578    struct threaded_context *tc = threaded_context(_pipe);
1579    struct threaded_transfer *ttrans = threaded_transfer(transfer);
1580    struct threaded_resource *tres = threaded_resource(transfer->resource);
1581 
1582    if (tres->b.target == PIPE_BUFFER) {
1583       if (transfer->usage & PIPE_TRANSFER_WRITE &&
1584           !(transfer->usage & PIPE_TRANSFER_FLUSH_EXPLICIT))
1585          tc_buffer_do_flush_region(tc, ttrans, &transfer->box);
1586 
1587       /* Staging transfers don't send the call to the driver. */
1588       if (ttrans->staging) {
1589          pipe_resource_reference(&ttrans->staging, NULL);
1590          pipe_resource_reference(&ttrans->b.resource, NULL);
1591          slab_free(&tc->pool_transfers, ttrans);
1592          return;
1593       }
1594    }
1595 
1596    tc_add_small_call(tc, TC_CALL_transfer_unmap)->transfer = transfer;
1597 }
1598 
1599 struct tc_buffer_subdata {
1600    struct pipe_resource *resource;
1601    unsigned usage, offset, size;
1602    char slot[0]; /* more will be allocated if needed */
1603 };
1604 
1605 static void
tc_call_buffer_subdata(struct pipe_context * pipe,union tc_payload * payload)1606 tc_call_buffer_subdata(struct pipe_context *pipe, union tc_payload *payload)
1607 {
1608    struct tc_buffer_subdata *p = (struct tc_buffer_subdata *)payload;
1609 
1610    pipe->buffer_subdata(pipe, p->resource, p->usage, p->offset, p->size,
1611                         p->slot);
1612    pipe_resource_reference(&p->resource, NULL);
1613 }
1614 
1615 static void
tc_buffer_subdata(struct pipe_context * _pipe,struct pipe_resource * resource,unsigned usage,unsigned offset,unsigned size,const void * data)1616 tc_buffer_subdata(struct pipe_context *_pipe,
1617                   struct pipe_resource *resource,
1618                   unsigned usage, unsigned offset,
1619                   unsigned size, const void *data)
1620 {
1621    struct threaded_context *tc = threaded_context(_pipe);
1622    struct threaded_resource *tres = threaded_resource(resource);
1623 
1624    if (!size)
1625       return;
1626 
1627    usage |= PIPE_TRANSFER_WRITE |
1628             PIPE_TRANSFER_DISCARD_RANGE;
1629 
1630    usage = tc_improve_map_buffer_flags(tc, tres, usage, offset, size);
1631 
1632    /* Unsychronized and big transfers should use transfer_map. Also handle
1633     * full invalidations, because drivers aren't allowed to do them.
1634     */
1635    if (usage & (PIPE_TRANSFER_UNSYNCHRONIZED |
1636                 PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) ||
1637        size > TC_MAX_SUBDATA_BYTES) {
1638       struct pipe_transfer *transfer;
1639       struct pipe_box box;
1640       uint8_t *map = NULL;
1641 
1642       u_box_1d(offset, size, &box);
1643 
1644       map = tc_transfer_map(_pipe, resource, 0, usage, &box, &transfer);
1645       if (map) {
1646          memcpy(map, data, size);
1647          tc_transfer_unmap(_pipe, transfer);
1648       }
1649       return;
1650    }
1651 
1652    util_range_add(&tres->valid_buffer_range, offset, offset + size);
1653 
1654    /* The upload is small. Enqueue it. */
1655    struct tc_buffer_subdata *p =
1656       tc_add_slot_based_call(tc, TC_CALL_buffer_subdata, tc_buffer_subdata, size);
1657 
1658    tc_set_resource_reference(&p->resource, resource);
1659    p->usage = usage;
1660    p->offset = offset;
1661    p->size = size;
1662    memcpy(p->slot, data, size);
1663 }
1664 
1665 struct tc_texture_subdata {
1666    struct pipe_resource *resource;
1667    unsigned level, usage, stride, layer_stride;
1668    struct pipe_box box;
1669    char slot[0]; /* more will be allocated if needed */
1670 };
1671 
1672 static void
tc_call_texture_subdata(struct pipe_context * pipe,union tc_payload * payload)1673 tc_call_texture_subdata(struct pipe_context *pipe, union tc_payload *payload)
1674 {
1675    struct tc_texture_subdata *p = (struct tc_texture_subdata *)payload;
1676 
1677    pipe->texture_subdata(pipe, p->resource, p->level, p->usage, &p->box,
1678                          p->slot, p->stride, p->layer_stride);
1679    pipe_resource_reference(&p->resource, NULL);
1680 }
1681 
1682 static void
tc_texture_subdata(struct pipe_context * _pipe,struct pipe_resource * resource,unsigned level,unsigned usage,const struct pipe_box * box,const void * data,unsigned stride,unsigned layer_stride)1683 tc_texture_subdata(struct pipe_context *_pipe,
1684                    struct pipe_resource *resource,
1685                    unsigned level, unsigned usage,
1686                    const struct pipe_box *box,
1687                    const void *data, unsigned stride,
1688                    unsigned layer_stride)
1689 {
1690    struct threaded_context *tc = threaded_context(_pipe);
1691    unsigned size;
1692 
1693    assert(box->height >= 1);
1694    assert(box->depth >= 1);
1695 
1696    size = (box->depth - 1) * layer_stride +
1697           (box->height - 1) * stride +
1698           box->width * util_format_get_blocksize(resource->format);
1699    if (!size)
1700       return;
1701 
1702    /* Small uploads can be enqueued, big uploads must sync. */
1703    if (size <= TC_MAX_SUBDATA_BYTES) {
1704       struct tc_texture_subdata *p =
1705          tc_add_slot_based_call(tc, TC_CALL_texture_subdata, tc_texture_subdata, size);
1706 
1707       tc_set_resource_reference(&p->resource, resource);
1708       p->level = level;
1709       p->usage = usage;
1710       p->box = *box;
1711       p->stride = stride;
1712       p->layer_stride = layer_stride;
1713       memcpy(p->slot, data, size);
1714    } else {
1715       struct pipe_context *pipe = tc->pipe;
1716 
1717       tc_sync(tc);
1718       pipe->texture_subdata(pipe, resource, level, usage, box, data,
1719                             stride, layer_stride);
1720    }
1721 }
1722 
1723 
1724 /********************************************************************
1725  * miscellaneous
1726  */
1727 
1728 #define TC_FUNC_SYNC_RET0(ret_type, func) \
1729    static ret_type \
1730    tc_##func(struct pipe_context *_pipe) \
1731    { \
1732       struct threaded_context *tc = threaded_context(_pipe); \
1733       struct pipe_context *pipe = tc->pipe; \
1734       tc_sync(tc); \
1735       return pipe->func(pipe); \
1736    }
1737 
TC_FUNC_SYNC_RET0(enum pipe_reset_status,get_device_reset_status)1738 TC_FUNC_SYNC_RET0(enum pipe_reset_status, get_device_reset_status)
1739 TC_FUNC_SYNC_RET0(uint64_t, get_timestamp)
1740 
1741 static void
1742 tc_get_sample_position(struct pipe_context *_pipe,
1743                        unsigned sample_count, unsigned sample_index,
1744                        float *out_value)
1745 {
1746    struct threaded_context *tc = threaded_context(_pipe);
1747    struct pipe_context *pipe = tc->pipe;
1748 
1749    tc_sync(tc);
1750    pipe->get_sample_position(pipe, sample_count, sample_index,
1751                              out_value);
1752 }
1753 
1754 static void
tc_set_device_reset_callback(struct pipe_context * _pipe,const struct pipe_device_reset_callback * cb)1755 tc_set_device_reset_callback(struct pipe_context *_pipe,
1756                              const struct pipe_device_reset_callback *cb)
1757 {
1758    struct threaded_context *tc = threaded_context(_pipe);
1759    struct pipe_context *pipe = tc->pipe;
1760 
1761    tc_sync(tc);
1762    pipe->set_device_reset_callback(pipe, cb);
1763 }
1764 
1765 struct tc_string_marker {
1766    int len;
1767    char slot[0]; /* more will be allocated if needed */
1768 };
1769 
1770 static void
tc_call_emit_string_marker(struct pipe_context * pipe,union tc_payload * payload)1771 tc_call_emit_string_marker(struct pipe_context *pipe, union tc_payload *payload)
1772 {
1773    struct tc_string_marker *p = (struct tc_string_marker *)payload;
1774    pipe->emit_string_marker(pipe, p->slot, p->len);
1775 }
1776 
1777 static void
tc_emit_string_marker(struct pipe_context * _pipe,const char * string,int len)1778 tc_emit_string_marker(struct pipe_context *_pipe,
1779                       const char *string, int len)
1780 {
1781    struct threaded_context *tc = threaded_context(_pipe);
1782 
1783    if (len <= TC_MAX_STRING_MARKER_BYTES) {
1784       struct tc_string_marker *p =
1785          tc_add_slot_based_call(tc, TC_CALL_emit_string_marker, tc_string_marker, len);
1786 
1787       memcpy(p->slot, string, len);
1788       p->len = len;
1789    } else {
1790       struct pipe_context *pipe = tc->pipe;
1791 
1792       tc_sync(tc);
1793       pipe->emit_string_marker(pipe, string, len);
1794    }
1795 }
1796 
1797 static void
tc_dump_debug_state(struct pipe_context * _pipe,FILE * stream,unsigned flags)1798 tc_dump_debug_state(struct pipe_context *_pipe, FILE *stream,
1799                     unsigned flags)
1800 {
1801    struct threaded_context *tc = threaded_context(_pipe);
1802    struct pipe_context *pipe = tc->pipe;
1803 
1804    tc_sync(tc);
1805    pipe->dump_debug_state(pipe, stream, flags);
1806 }
1807 
1808 static void
tc_set_debug_callback(struct pipe_context * _pipe,const struct pipe_debug_callback * cb)1809 tc_set_debug_callback(struct pipe_context *_pipe,
1810                       const struct pipe_debug_callback *cb)
1811 {
1812    struct threaded_context *tc = threaded_context(_pipe);
1813    struct pipe_context *pipe = tc->pipe;
1814 
1815    /* Drop all synchronous debug callbacks. Drivers are expected to be OK
1816     * with this. shader-db will use an environment variable to disable
1817     * the threaded context.
1818     */
1819    if (cb && cb->debug_message && !cb->async)
1820       return;
1821 
1822    tc_sync(tc);
1823    pipe->set_debug_callback(pipe, cb);
1824 }
1825 
1826 static void
tc_set_log_context(struct pipe_context * _pipe,struct u_log_context * log)1827 tc_set_log_context(struct pipe_context *_pipe, struct u_log_context *log)
1828 {
1829    struct threaded_context *tc = threaded_context(_pipe);
1830    struct pipe_context *pipe = tc->pipe;
1831 
1832    tc_sync(tc);
1833    pipe->set_log_context(pipe, log);
1834 }
1835 
1836 static void
tc_create_fence_fd(struct pipe_context * _pipe,struct pipe_fence_handle ** fence,int fd)1837 tc_create_fence_fd(struct pipe_context *_pipe,
1838                    struct pipe_fence_handle **fence, int fd)
1839 {
1840    struct threaded_context *tc = threaded_context(_pipe);
1841    struct pipe_context *pipe = tc->pipe;
1842 
1843    tc_sync(tc);
1844    pipe->create_fence_fd(pipe, fence, fd);
1845 }
1846 
1847 static void
tc_call_fence_server_sync(struct pipe_context * pipe,union tc_payload * payload)1848 tc_call_fence_server_sync(struct pipe_context *pipe, union tc_payload *payload)
1849 {
1850    pipe->fence_server_sync(pipe, payload->fence);
1851    pipe->screen->fence_reference(pipe->screen, &payload->fence, NULL);
1852 }
1853 
1854 static void
tc_fence_server_sync(struct pipe_context * _pipe,struct pipe_fence_handle * fence)1855 tc_fence_server_sync(struct pipe_context *_pipe,
1856                      struct pipe_fence_handle *fence)
1857 {
1858    struct threaded_context *tc = threaded_context(_pipe);
1859    struct pipe_screen *screen = tc->pipe->screen;
1860    union tc_payload *payload = tc_add_small_call(tc, TC_CALL_fence_server_sync);
1861 
1862    payload->fence = NULL;
1863    screen->fence_reference(screen, &payload->fence, fence);
1864 }
1865 
1866 static struct pipe_video_codec *
tc_create_video_codec(UNUSED struct pipe_context * _pipe,UNUSED const struct pipe_video_codec * templ)1867 tc_create_video_codec(UNUSED struct pipe_context *_pipe,
1868                       UNUSED const struct pipe_video_codec *templ)
1869 {
1870    unreachable("Threaded context should not be enabled for video APIs");
1871    return NULL;
1872 }
1873 
1874 static struct pipe_video_buffer *
tc_create_video_buffer(UNUSED struct pipe_context * _pipe,UNUSED const struct pipe_video_buffer * templ)1875 tc_create_video_buffer(UNUSED struct pipe_context *_pipe,
1876                        UNUSED const struct pipe_video_buffer *templ)
1877 {
1878    unreachable("Threaded context should not be enabled for video APIs");
1879    return NULL;
1880 }
1881 
1882 
1883 /********************************************************************
1884  * draw, launch, clear, blit, copy, flush
1885  */
1886 
1887 struct tc_flush_payload {
1888    struct threaded_context *tc;
1889    struct pipe_fence_handle *fence;
1890    unsigned flags;
1891 };
1892 
1893 static void
tc_flush_queries(struct threaded_context * tc)1894 tc_flush_queries(struct threaded_context *tc)
1895 {
1896    struct threaded_query *tq, *tmp;
1897    LIST_FOR_EACH_ENTRY_SAFE(tq, tmp, &tc->unflushed_queries, head_unflushed) {
1898       LIST_DEL(&tq->head_unflushed);
1899 
1900       /* Memory release semantics: due to a possible race with
1901        * tc_get_query_result, we must ensure that the linked list changes
1902        * are visible before setting tq->flushed.
1903        */
1904       p_atomic_set(&tq->flushed, true);
1905    }
1906 }
1907 
1908 static void
tc_call_flush(struct pipe_context * pipe,union tc_payload * payload)1909 tc_call_flush(struct pipe_context *pipe, union tc_payload *payload)
1910 {
1911    struct tc_flush_payload *p = (struct tc_flush_payload *)payload;
1912    struct pipe_screen *screen = pipe->screen;
1913 
1914    pipe->flush(pipe, p->fence ? &p->fence : NULL, p->flags);
1915    screen->fence_reference(screen, &p->fence, NULL);
1916 
1917    if (!(p->flags & PIPE_FLUSH_DEFERRED))
1918       tc_flush_queries(p->tc);
1919 }
1920 
1921 static void
tc_flush(struct pipe_context * _pipe,struct pipe_fence_handle ** fence,unsigned flags)1922 tc_flush(struct pipe_context *_pipe, struct pipe_fence_handle **fence,
1923          unsigned flags)
1924 {
1925    struct threaded_context *tc = threaded_context(_pipe);
1926    struct pipe_context *pipe = tc->pipe;
1927    struct pipe_screen *screen = pipe->screen;
1928    bool async = flags & PIPE_FLUSH_DEFERRED;
1929 
1930    if (flags & PIPE_FLUSH_ASYNC) {
1931       struct tc_batch *last = &tc->batch_slots[tc->last];
1932 
1933       /* Prefer to do the flush in the driver thread, but avoid the inter-thread
1934        * communication overhead if the driver thread is currently idle and the
1935        * caller is going to wait for the fence immediately anyway.
1936        */
1937       if (!(util_queue_fence_is_signalled(&last->fence) &&
1938             (flags & PIPE_FLUSH_HINT_FINISH)))
1939          async = true;
1940    }
1941 
1942    if (async && tc->create_fence) {
1943       if (fence) {
1944          struct tc_batch *next = &tc->batch_slots[tc->next];
1945 
1946          if (!next->token) {
1947             next->token = malloc(sizeof(*next->token));
1948             if (!next->token)
1949                goto out_of_memory;
1950 
1951             pipe_reference_init(&next->token->ref, 1);
1952             next->token->tc = tc;
1953          }
1954 
1955          screen->fence_reference(screen, fence, tc->create_fence(pipe, next->token));
1956          if (!*fence)
1957             goto out_of_memory;
1958       }
1959 
1960       struct tc_flush_payload *p =
1961          tc_add_struct_typed_call(tc, TC_CALL_flush, tc_flush_payload);
1962       p->tc = tc;
1963       p->fence = fence ? *fence : NULL;
1964       p->flags = flags | TC_FLUSH_ASYNC;
1965 
1966       if (!(flags & PIPE_FLUSH_DEFERRED))
1967          tc_batch_flush(tc);
1968       return;
1969    }
1970 
1971 out_of_memory:
1972    tc_sync_msg(tc, flags & PIPE_FLUSH_END_OF_FRAME ? "end of frame" :
1973                    flags & PIPE_FLUSH_DEFERRED ? "deferred fence" : "normal");
1974 
1975    if (!(flags & PIPE_FLUSH_DEFERRED))
1976       tc_flush_queries(tc);
1977    pipe->flush(pipe, fence, flags);
1978 }
1979 
1980 /* This is actually variable-sized, because indirect isn't allocated if it's
1981  * not needed. */
1982 struct tc_full_draw_info {
1983    struct pipe_draw_info draw;
1984    struct pipe_draw_indirect_info indirect;
1985 };
1986 
1987 static void
tc_call_draw_vbo(struct pipe_context * pipe,union tc_payload * payload)1988 tc_call_draw_vbo(struct pipe_context *pipe, union tc_payload *payload)
1989 {
1990    struct tc_full_draw_info *info = (struct tc_full_draw_info*)payload;
1991 
1992    pipe->draw_vbo(pipe, &info->draw);
1993    pipe_so_target_reference(&info->draw.count_from_stream_output, NULL);
1994    if (info->draw.index_size)
1995       pipe_resource_reference(&info->draw.index.resource, NULL);
1996    if (info->draw.indirect) {
1997       pipe_resource_reference(&info->indirect.buffer, NULL);
1998       pipe_resource_reference(&info->indirect.indirect_draw_count, NULL);
1999    }
2000 }
2001 
2002 static struct tc_full_draw_info *
tc_add_draw_vbo(struct pipe_context * _pipe,bool indirect)2003 tc_add_draw_vbo(struct pipe_context *_pipe, bool indirect)
2004 {
2005    return (struct tc_full_draw_info*)
2006           tc_add_sized_call(threaded_context(_pipe), TC_CALL_draw_vbo,
2007                             indirect ? sizeof(struct tc_full_draw_info) :
2008                                        sizeof(struct pipe_draw_info));
2009 }
2010 
2011 static void
tc_draw_vbo(struct pipe_context * _pipe,const struct pipe_draw_info * info)2012 tc_draw_vbo(struct pipe_context *_pipe, const struct pipe_draw_info *info)
2013 {
2014    struct threaded_context *tc = threaded_context(_pipe);
2015    struct pipe_draw_indirect_info *indirect = info->indirect;
2016    unsigned index_size = info->index_size;
2017    bool has_user_indices = info->has_user_indices;
2018 
2019    if (index_size && has_user_indices) {
2020       unsigned size = info->count * index_size;
2021       struct pipe_resource *buffer = NULL;
2022       unsigned offset;
2023 
2024       tc_assert(!indirect);
2025 
2026       /* This must be done before adding draw_vbo, because it could generate
2027        * e.g. transfer_unmap and flush partially-uninitialized draw_vbo
2028        * to the driver if it was done afterwards.
2029        */
2030       u_upload_data(tc->base.stream_uploader, 0, size, 4, info->index.user,
2031                     &offset, &buffer);
2032       if (unlikely(!buffer))
2033          return;
2034 
2035       struct tc_full_draw_info *p = tc_add_draw_vbo(_pipe, false);
2036       p->draw.count_from_stream_output = NULL;
2037       pipe_so_target_reference(&p->draw.count_from_stream_output,
2038                                info->count_from_stream_output);
2039       memcpy(&p->draw, info, sizeof(*info));
2040       p->draw.has_user_indices = false;
2041       p->draw.index.resource = buffer;
2042       p->draw.start = offset / index_size;
2043    } else {
2044       /* Non-indexed call or indexed with a real index buffer. */
2045       struct tc_full_draw_info *p = tc_add_draw_vbo(_pipe, indirect != NULL);
2046       p->draw.count_from_stream_output = NULL;
2047       pipe_so_target_reference(&p->draw.count_from_stream_output,
2048                                info->count_from_stream_output);
2049       if (index_size) {
2050          tc_set_resource_reference(&p->draw.index.resource,
2051                                    info->index.resource);
2052       }
2053       memcpy(&p->draw, info, sizeof(*info));
2054 
2055       if (indirect) {
2056          tc_set_resource_reference(&p->draw.indirect->buffer, indirect->buffer);
2057          tc_set_resource_reference(&p->indirect.indirect_draw_count,
2058                                    indirect->indirect_draw_count);
2059          memcpy(&p->indirect, indirect, sizeof(*indirect));
2060          p->draw.indirect = &p->indirect;
2061       }
2062    }
2063 }
2064 
2065 static void
tc_call_launch_grid(struct pipe_context * pipe,union tc_payload * payload)2066 tc_call_launch_grid(struct pipe_context *pipe, union tc_payload *payload)
2067 {
2068    struct pipe_grid_info *p = (struct pipe_grid_info *)payload;
2069 
2070    pipe->launch_grid(pipe, p);
2071    pipe_resource_reference(&p->indirect, NULL);
2072 }
2073 
2074 static void
tc_launch_grid(struct pipe_context * _pipe,const struct pipe_grid_info * info)2075 tc_launch_grid(struct pipe_context *_pipe,
2076                const struct pipe_grid_info *info)
2077 {
2078    struct threaded_context *tc = threaded_context(_pipe);
2079    struct pipe_grid_info *p = tc_add_struct_typed_call(tc, TC_CALL_launch_grid,
2080                                                        pipe_grid_info);
2081    assert(info->input == NULL);
2082 
2083    tc_set_resource_reference(&p->indirect, info->indirect);
2084    memcpy(p, info, sizeof(*info));
2085 }
2086 
2087 static void
tc_call_resource_copy_region(struct pipe_context * pipe,union tc_payload * payload)2088 tc_call_resource_copy_region(struct pipe_context *pipe, union tc_payload *payload)
2089 {
2090    struct tc_resource_copy_region *p = (struct tc_resource_copy_region *)payload;
2091 
2092    pipe->resource_copy_region(pipe, p->dst, p->dst_level, p->dstx, p->dsty,
2093                               p->dstz, p->src, p->src_level, &p->src_box);
2094    pipe_resource_reference(&p->dst, NULL);
2095    pipe_resource_reference(&p->src, NULL);
2096 }
2097 
2098 static void
tc_resource_copy_region(struct pipe_context * _pipe,struct pipe_resource * dst,unsigned dst_level,unsigned dstx,unsigned dsty,unsigned dstz,struct pipe_resource * src,unsigned src_level,const struct pipe_box * src_box)2099 tc_resource_copy_region(struct pipe_context *_pipe,
2100                         struct pipe_resource *dst, unsigned dst_level,
2101                         unsigned dstx, unsigned dsty, unsigned dstz,
2102                         struct pipe_resource *src, unsigned src_level,
2103                         const struct pipe_box *src_box)
2104 {
2105    struct threaded_context *tc = threaded_context(_pipe);
2106    struct threaded_resource *tdst = threaded_resource(dst);
2107    struct tc_resource_copy_region *p =
2108       tc_add_struct_typed_call(tc, TC_CALL_resource_copy_region,
2109                                tc_resource_copy_region);
2110 
2111    tc_set_resource_reference(&p->dst, dst);
2112    p->dst_level = dst_level;
2113    p->dstx = dstx;
2114    p->dsty = dsty;
2115    p->dstz = dstz;
2116    tc_set_resource_reference(&p->src, src);
2117    p->src_level = src_level;
2118    p->src_box = *src_box;
2119 
2120    if (dst->target == PIPE_BUFFER)
2121       util_range_add(&tdst->valid_buffer_range, dstx, dstx + src_box->width);
2122 }
2123 
2124 static void
tc_call_blit(struct pipe_context * pipe,union tc_payload * payload)2125 tc_call_blit(struct pipe_context *pipe, union tc_payload *payload)
2126 {
2127    struct pipe_blit_info *blit = (struct pipe_blit_info*)payload;
2128 
2129    pipe->blit(pipe, blit);
2130    pipe_resource_reference(&blit->dst.resource, NULL);
2131    pipe_resource_reference(&blit->src.resource, NULL);
2132 }
2133 
2134 static void
tc_blit(struct pipe_context * _pipe,const struct pipe_blit_info * info)2135 tc_blit(struct pipe_context *_pipe, const struct pipe_blit_info *info)
2136 {
2137    struct threaded_context *tc = threaded_context(_pipe);
2138    struct pipe_blit_info *blit =
2139       tc_add_struct_typed_call(tc, TC_CALL_blit, pipe_blit_info);
2140 
2141    tc_set_resource_reference(&blit->dst.resource, info->dst.resource);
2142    tc_set_resource_reference(&blit->src.resource, info->src.resource);
2143    memcpy(blit, info, sizeof(*info));
2144 }
2145 
2146 struct tc_generate_mipmap {
2147    struct pipe_resource *res;
2148    enum pipe_format format;
2149    unsigned base_level;
2150    unsigned last_level;
2151    unsigned first_layer;
2152    unsigned last_layer;
2153 };
2154 
2155 static void
tc_call_generate_mipmap(struct pipe_context * pipe,union tc_payload * payload)2156 tc_call_generate_mipmap(struct pipe_context *pipe, union tc_payload *payload)
2157 {
2158    struct tc_generate_mipmap *p = (struct tc_generate_mipmap *)payload;
2159    MAYBE_UNUSED bool result = pipe->generate_mipmap(pipe, p->res, p->format,
2160                                                     p->base_level,
2161                                                     p->last_level,
2162                                                     p->first_layer,
2163                                                     p->last_layer);
2164    assert(result);
2165    pipe_resource_reference(&p->res, NULL);
2166 }
2167 
2168 static boolean
tc_generate_mipmap(struct pipe_context * _pipe,struct pipe_resource * res,enum pipe_format format,unsigned base_level,unsigned last_level,unsigned first_layer,unsigned last_layer)2169 tc_generate_mipmap(struct pipe_context *_pipe,
2170                    struct pipe_resource *res,
2171                    enum pipe_format format,
2172                    unsigned base_level,
2173                    unsigned last_level,
2174                    unsigned first_layer,
2175                    unsigned last_layer)
2176 {
2177    struct threaded_context *tc = threaded_context(_pipe);
2178    struct pipe_context *pipe = tc->pipe;
2179    struct pipe_screen *screen = pipe->screen;
2180    unsigned bind = PIPE_BIND_SAMPLER_VIEW;
2181 
2182    if (util_format_is_depth_or_stencil(format))
2183       bind = PIPE_BIND_DEPTH_STENCIL;
2184    else
2185       bind = PIPE_BIND_RENDER_TARGET;
2186 
2187    if (!screen->is_format_supported(screen, format, res->target,
2188                                     res->nr_samples, bind))
2189       return false;
2190 
2191    struct tc_generate_mipmap *p =
2192       tc_add_struct_typed_call(tc, TC_CALL_generate_mipmap, tc_generate_mipmap);
2193 
2194    tc_set_resource_reference(&p->res, res);
2195    p->format = format;
2196    p->base_level = base_level;
2197    p->last_level = last_level;
2198    p->first_layer = first_layer;
2199    p->last_layer = last_layer;
2200    return true;
2201 }
2202 
2203 static void
tc_call_flush_resource(struct pipe_context * pipe,union tc_payload * payload)2204 tc_call_flush_resource(struct pipe_context *pipe, union tc_payload *payload)
2205 {
2206    pipe->flush_resource(pipe, payload->resource);
2207    pipe_resource_reference(&payload->resource, NULL);
2208 }
2209 
2210 static void
tc_flush_resource(struct pipe_context * _pipe,struct pipe_resource * resource)2211 tc_flush_resource(struct pipe_context *_pipe,
2212                   struct pipe_resource *resource)
2213 {
2214    struct threaded_context *tc = threaded_context(_pipe);
2215    union tc_payload *payload = tc_add_small_call(tc, TC_CALL_flush_resource);
2216 
2217    tc_set_resource_reference(&payload->resource, resource);
2218 }
2219 
2220 static void
tc_call_invalidate_resource(struct pipe_context * pipe,union tc_payload * payload)2221 tc_call_invalidate_resource(struct pipe_context *pipe, union tc_payload *payload)
2222 {
2223    pipe->invalidate_resource(pipe, payload->resource);
2224    pipe_resource_reference(&payload->resource, NULL);
2225 }
2226 
2227 static void
tc_invalidate_resource(struct pipe_context * _pipe,struct pipe_resource * resource)2228 tc_invalidate_resource(struct pipe_context *_pipe,
2229                        struct pipe_resource *resource)
2230 {
2231    struct threaded_context *tc = threaded_context(_pipe);
2232 
2233    if (resource->target == PIPE_BUFFER) {
2234       tc_invalidate_buffer(tc, threaded_resource(resource));
2235       return;
2236    }
2237 
2238    union tc_payload *payload = tc_add_small_call(tc, TC_CALL_invalidate_resource);
2239    tc_set_resource_reference(&payload->resource, resource);
2240 }
2241 
2242 struct tc_clear {
2243    unsigned buffers;
2244    union pipe_color_union color;
2245    double depth;
2246    unsigned stencil;
2247 };
2248 
2249 static void
tc_call_clear(struct pipe_context * pipe,union tc_payload * payload)2250 tc_call_clear(struct pipe_context *pipe, union tc_payload *payload)
2251 {
2252    struct tc_clear *p = (struct tc_clear *)payload;
2253    pipe->clear(pipe, p->buffers, &p->color, p->depth, p->stencil);
2254 }
2255 
2256 static void
tc_clear(struct pipe_context * _pipe,unsigned buffers,const union pipe_color_union * color,double depth,unsigned stencil)2257 tc_clear(struct pipe_context *_pipe, unsigned buffers,
2258          const union pipe_color_union *color, double depth,
2259          unsigned stencil)
2260 {
2261    struct threaded_context *tc = threaded_context(_pipe);
2262    struct tc_clear *p = tc_add_struct_typed_call(tc, TC_CALL_clear, tc_clear);
2263 
2264    p->buffers = buffers;
2265    p->color = *color;
2266    p->depth = depth;
2267    p->stencil = stencil;
2268 }
2269 
2270 static void
tc_clear_render_target(struct pipe_context * _pipe,struct pipe_surface * dst,const union pipe_color_union * color,unsigned dstx,unsigned dsty,unsigned width,unsigned height,bool render_condition_enabled)2271 tc_clear_render_target(struct pipe_context *_pipe,
2272                        struct pipe_surface *dst,
2273                        const union pipe_color_union *color,
2274                        unsigned dstx, unsigned dsty,
2275                        unsigned width, unsigned height,
2276                        bool render_condition_enabled)
2277 {
2278    struct threaded_context *tc = threaded_context(_pipe);
2279    struct pipe_context *pipe = tc->pipe;
2280 
2281    tc_sync(tc);
2282    pipe->clear_render_target(pipe, dst, color, dstx, dsty, width, height,
2283                              render_condition_enabled);
2284 }
2285 
2286 static void
tc_clear_depth_stencil(struct pipe_context * _pipe,struct pipe_surface * dst,unsigned clear_flags,double depth,unsigned stencil,unsigned dstx,unsigned dsty,unsigned width,unsigned height,bool render_condition_enabled)2287 tc_clear_depth_stencil(struct pipe_context *_pipe,
2288                        struct pipe_surface *dst, unsigned clear_flags,
2289                        double depth, unsigned stencil, unsigned dstx,
2290                        unsigned dsty, unsigned width, unsigned height,
2291                        bool render_condition_enabled)
2292 {
2293    struct threaded_context *tc = threaded_context(_pipe);
2294    struct pipe_context *pipe = tc->pipe;
2295 
2296    tc_sync(tc);
2297    pipe->clear_depth_stencil(pipe, dst, clear_flags, depth, stencil,
2298                              dstx, dsty, width, height,
2299                              render_condition_enabled);
2300 }
2301 
2302 struct tc_clear_buffer {
2303    struct pipe_resource *res;
2304    unsigned offset;
2305    unsigned size;
2306    char clear_value[16];
2307    int clear_value_size;
2308 };
2309 
2310 static void
tc_call_clear_buffer(struct pipe_context * pipe,union tc_payload * payload)2311 tc_call_clear_buffer(struct pipe_context *pipe, union tc_payload *payload)
2312 {
2313    struct tc_clear_buffer *p = (struct tc_clear_buffer *)payload;
2314 
2315    pipe->clear_buffer(pipe, p->res, p->offset, p->size, p->clear_value,
2316                       p->clear_value_size);
2317    pipe_resource_reference(&p->res, NULL);
2318 }
2319 
2320 static void
tc_clear_buffer(struct pipe_context * _pipe,struct pipe_resource * res,unsigned offset,unsigned size,const void * clear_value,int clear_value_size)2321 tc_clear_buffer(struct pipe_context *_pipe, struct pipe_resource *res,
2322                 unsigned offset, unsigned size,
2323                 const void *clear_value, int clear_value_size)
2324 {
2325    struct threaded_context *tc = threaded_context(_pipe);
2326    struct threaded_resource *tres = threaded_resource(res);
2327    struct tc_clear_buffer *p =
2328       tc_add_struct_typed_call(tc, TC_CALL_clear_buffer, tc_clear_buffer);
2329 
2330    tc_set_resource_reference(&p->res, res);
2331    p->offset = offset;
2332    p->size = size;
2333    memcpy(p->clear_value, clear_value, clear_value_size);
2334    p->clear_value_size = clear_value_size;
2335 
2336    util_range_add(&tres->valid_buffer_range, offset, offset + size);
2337 }
2338 
2339 struct tc_clear_texture {
2340    struct pipe_resource *res;
2341    unsigned level;
2342    struct pipe_box box;
2343    char data[16];
2344 };
2345 
2346 static void
tc_call_clear_texture(struct pipe_context * pipe,union tc_payload * payload)2347 tc_call_clear_texture(struct pipe_context *pipe, union tc_payload *payload)
2348 {
2349    struct tc_clear_texture *p = (struct tc_clear_texture *)payload;
2350 
2351    pipe->clear_texture(pipe, p->res, p->level, &p->box, p->data);
2352    pipe_resource_reference(&p->res, NULL);
2353 }
2354 
2355 static void
tc_clear_texture(struct pipe_context * _pipe,struct pipe_resource * res,unsigned level,const struct pipe_box * box,const void * data)2356 tc_clear_texture(struct pipe_context *_pipe, struct pipe_resource *res,
2357                  unsigned level, const struct pipe_box *box, const void *data)
2358 {
2359    struct threaded_context *tc = threaded_context(_pipe);
2360    struct tc_clear_texture *p =
2361       tc_add_struct_typed_call(tc, TC_CALL_clear_texture, tc_clear_texture);
2362 
2363    tc_set_resource_reference(&p->res, res);
2364    p->level = level;
2365    p->box = *box;
2366    memcpy(p->data, data,
2367           util_format_get_blocksize(res->format));
2368 }
2369 
2370 struct tc_resource_commit {
2371    struct pipe_resource *res;
2372    unsigned level;
2373    struct pipe_box box;
2374    bool commit;
2375 };
2376 
2377 static void
tc_call_resource_commit(struct pipe_context * pipe,union tc_payload * payload)2378 tc_call_resource_commit(struct pipe_context *pipe, union tc_payload *payload)
2379 {
2380    struct tc_resource_commit *p = (struct tc_resource_commit *)payload;
2381 
2382    pipe->resource_commit(pipe, p->res, p->level, &p->box, p->commit);
2383    pipe_resource_reference(&p->res, NULL);
2384 }
2385 
2386 static bool
tc_resource_commit(struct pipe_context * _pipe,struct pipe_resource * res,unsigned level,struct pipe_box * box,bool commit)2387 tc_resource_commit(struct pipe_context *_pipe, struct pipe_resource *res,
2388                    unsigned level, struct pipe_box *box, bool commit)
2389 {
2390    struct threaded_context *tc = threaded_context(_pipe);
2391    struct tc_resource_commit *p =
2392       tc_add_struct_typed_call(tc, TC_CALL_resource_commit, tc_resource_commit);
2393 
2394    tc_set_resource_reference(&p->res, res);
2395    p->level = level;
2396    p->box = *box;
2397    p->commit = commit;
2398    return true; /* we don't care about the return value for this call */
2399 }
2400 
2401 
2402 /********************************************************************
2403  * callback
2404  */
2405 
2406 struct tc_callback_payload {
2407    void (*fn)(void *data);
2408    void *data;
2409 };
2410 
2411 static void
tc_call_callback(UNUSED struct pipe_context * pipe,union tc_payload * payload)2412 tc_call_callback(UNUSED struct pipe_context *pipe, union tc_payload *payload)
2413 {
2414    struct tc_callback_payload *p = (struct tc_callback_payload *)payload;
2415 
2416    p->fn(p->data);
2417 }
2418 
2419 static void
tc_callback(struct pipe_context * _pipe,void (* fn)(void *),void * data,bool asap)2420 tc_callback(struct pipe_context *_pipe, void (*fn)(void *), void *data,
2421             bool asap)
2422 {
2423    struct threaded_context *tc = threaded_context(_pipe);
2424 
2425    if (asap && tc_is_sync(tc)) {
2426       fn(data);
2427       return;
2428    }
2429 
2430    struct tc_callback_payload *p =
2431       tc_add_struct_typed_call(tc, TC_CALL_callback, tc_callback_payload);
2432    p->fn = fn;
2433    p->data = data;
2434 }
2435 
2436 
2437 /********************************************************************
2438  * create & destroy
2439  */
2440 
2441 static void
tc_destroy(struct pipe_context * _pipe)2442 tc_destroy(struct pipe_context *_pipe)
2443 {
2444    struct threaded_context *tc = threaded_context(_pipe);
2445    struct pipe_context *pipe = tc->pipe;
2446 
2447    if (tc->base.const_uploader &&
2448        tc->base.stream_uploader != tc->base.const_uploader)
2449       u_upload_destroy(tc->base.const_uploader);
2450 
2451    if (tc->base.stream_uploader)
2452       u_upload_destroy(tc->base.stream_uploader);
2453 
2454    tc_sync(tc);
2455 
2456    if (util_queue_is_initialized(&tc->queue)) {
2457       util_queue_destroy(&tc->queue);
2458 
2459       for (unsigned i = 0; i < TC_MAX_BATCHES; i++) {
2460          util_queue_fence_destroy(&tc->batch_slots[i].fence);
2461          assert(!tc->batch_slots[i].token);
2462       }
2463    }
2464 
2465    slab_destroy_child(&tc->pool_transfers);
2466    assert(tc->batch_slots[tc->next].num_total_call_slots == 0);
2467    pipe->destroy(pipe);
2468    os_free_aligned(tc);
2469 }
2470 
2471 static const tc_execute execute_func[TC_NUM_CALLS] = {
2472 #define CALL(name) tc_call_##name,
2473 #include "u_threaded_context_calls.h"
2474 #undef CALL
2475 };
2476 
2477 /**
2478  * Wrap an existing pipe_context into a threaded_context.
2479  *
2480  * \param pipe                 pipe_context to wrap
2481  * \param parent_transfer_pool parent slab pool set up for creating pipe_-
2482  *                             transfer objects; the driver should have one
2483  *                             in pipe_screen.
2484  * \param replace_buffer  callback for replacing a pipe_resource's storage
2485  *                        with another pipe_resource's storage.
2486  * \param out  if successful, the threaded_context will be returned here in
2487  *             addition to the return value if "out" != NULL
2488  */
2489 struct pipe_context *
threaded_context_create(struct pipe_context * pipe,struct slab_parent_pool * parent_transfer_pool,tc_replace_buffer_storage_func replace_buffer,tc_create_fence_func create_fence,struct threaded_context ** out)2490 threaded_context_create(struct pipe_context *pipe,
2491                         struct slab_parent_pool *parent_transfer_pool,
2492                         tc_replace_buffer_storage_func replace_buffer,
2493                         tc_create_fence_func create_fence,
2494                         struct threaded_context **out)
2495 {
2496    struct threaded_context *tc;
2497 
2498    STATIC_ASSERT(sizeof(union tc_payload) <= 8);
2499    STATIC_ASSERT(sizeof(struct tc_call) <= 16);
2500 
2501    if (!pipe)
2502       return NULL;
2503 
2504    util_cpu_detect();
2505 
2506    if (!debug_get_bool_option("GALLIUM_THREAD", util_cpu_caps.nr_cpus > 1))
2507       return pipe;
2508 
2509    tc = os_malloc_aligned(sizeof(struct threaded_context), 16);
2510    if (!tc) {
2511       pipe->destroy(pipe);
2512       return NULL;
2513    }
2514    memset(tc, 0, sizeof(*tc));
2515 
2516    assert((uintptr_t)tc % 16 == 0);
2517    /* These should be static asserts, but they don't work with MSVC */
2518    assert(offsetof(struct threaded_context, batch_slots) % 16 == 0);
2519    assert(offsetof(struct threaded_context, batch_slots[0].call) % 16 == 0);
2520    assert(offsetof(struct threaded_context, batch_slots[0].call[1]) % 16 == 0);
2521    assert(offsetof(struct threaded_context, batch_slots[1].call) % 16 == 0);
2522 
2523    /* The driver context isn't wrapped, so set its "priv" to NULL. */
2524    pipe->priv = NULL;
2525 
2526    tc->pipe = pipe;
2527    tc->replace_buffer_storage = replace_buffer;
2528    tc->create_fence = create_fence;
2529    tc->map_buffer_alignment =
2530       pipe->screen->get_param(pipe->screen, PIPE_CAP_MIN_MAP_BUFFER_ALIGNMENT);
2531    tc->base.priv = pipe; /* priv points to the wrapped driver context */
2532    tc->base.screen = pipe->screen;
2533    tc->base.destroy = tc_destroy;
2534    tc->base.callback = tc_callback;
2535 
2536    tc->base.stream_uploader = u_upload_clone(&tc->base, pipe->stream_uploader);
2537    if (pipe->stream_uploader == pipe->const_uploader)
2538       tc->base.const_uploader = tc->base.stream_uploader;
2539    else
2540       tc->base.const_uploader = u_upload_clone(&tc->base, pipe->const_uploader);
2541 
2542    if (!tc->base.stream_uploader || !tc->base.const_uploader)
2543       goto fail;
2544 
2545    /* The queue size is the number of batches "waiting". Batches are removed
2546     * from the queue before being executed, so keep one tc_batch slot for that
2547     * execution. Also, keep one unused slot for an unflushed batch.
2548     */
2549    if (!util_queue_init(&tc->queue, "gallium_drv", TC_MAX_BATCHES - 2, 1, 0))
2550       goto fail;
2551 
2552    for (unsigned i = 0; i < TC_MAX_BATCHES; i++) {
2553       tc->batch_slots[i].sentinel = TC_SENTINEL;
2554       tc->batch_slots[i].pipe = pipe;
2555       util_queue_fence_init(&tc->batch_slots[i].fence);
2556    }
2557 
2558    LIST_INITHEAD(&tc->unflushed_queries);
2559 
2560    slab_create_child(&tc->pool_transfers, parent_transfer_pool);
2561 
2562 #define CTX_INIT(_member) \
2563    tc->base._member = tc->pipe->_member ? tc_##_member : NULL
2564 
2565    CTX_INIT(flush);
2566    CTX_INIT(draw_vbo);
2567    CTX_INIT(launch_grid);
2568    CTX_INIT(resource_copy_region);
2569    CTX_INIT(blit);
2570    CTX_INIT(clear);
2571    CTX_INIT(clear_render_target);
2572    CTX_INIT(clear_depth_stencil);
2573    CTX_INIT(clear_buffer);
2574    CTX_INIT(clear_texture);
2575    CTX_INIT(flush_resource);
2576    CTX_INIT(generate_mipmap);
2577    CTX_INIT(render_condition);
2578    CTX_INIT(create_query);
2579    CTX_INIT(create_batch_query);
2580    CTX_INIT(destroy_query);
2581    CTX_INIT(begin_query);
2582    CTX_INIT(end_query);
2583    CTX_INIT(get_query_result);
2584    CTX_INIT(get_query_result_resource);
2585    CTX_INIT(set_active_query_state);
2586    CTX_INIT(create_blend_state);
2587    CTX_INIT(bind_blend_state);
2588    CTX_INIT(delete_blend_state);
2589    CTX_INIT(create_sampler_state);
2590    CTX_INIT(bind_sampler_states);
2591    CTX_INIT(delete_sampler_state);
2592    CTX_INIT(create_rasterizer_state);
2593    CTX_INIT(bind_rasterizer_state);
2594    CTX_INIT(delete_rasterizer_state);
2595    CTX_INIT(create_depth_stencil_alpha_state);
2596    CTX_INIT(bind_depth_stencil_alpha_state);
2597    CTX_INIT(delete_depth_stencil_alpha_state);
2598    CTX_INIT(create_fs_state);
2599    CTX_INIT(bind_fs_state);
2600    CTX_INIT(delete_fs_state);
2601    CTX_INIT(create_vs_state);
2602    CTX_INIT(bind_vs_state);
2603    CTX_INIT(delete_vs_state);
2604    CTX_INIT(create_gs_state);
2605    CTX_INIT(bind_gs_state);
2606    CTX_INIT(delete_gs_state);
2607    CTX_INIT(create_tcs_state);
2608    CTX_INIT(bind_tcs_state);
2609    CTX_INIT(delete_tcs_state);
2610    CTX_INIT(create_tes_state);
2611    CTX_INIT(bind_tes_state);
2612    CTX_INIT(delete_tes_state);
2613    CTX_INIT(create_compute_state);
2614    CTX_INIT(bind_compute_state);
2615    CTX_INIT(delete_compute_state);
2616    CTX_INIT(create_vertex_elements_state);
2617    CTX_INIT(bind_vertex_elements_state);
2618    CTX_INIT(delete_vertex_elements_state);
2619    CTX_INIT(set_blend_color);
2620    CTX_INIT(set_stencil_ref);
2621    CTX_INIT(set_sample_mask);
2622    CTX_INIT(set_min_samples);
2623    CTX_INIT(set_clip_state);
2624    CTX_INIT(set_constant_buffer);
2625    CTX_INIT(set_framebuffer_state);
2626    CTX_INIT(set_polygon_stipple);
2627    CTX_INIT(set_scissor_states);
2628    CTX_INIT(set_viewport_states);
2629    CTX_INIT(set_window_rectangles);
2630    CTX_INIT(set_sampler_views);
2631    CTX_INIT(set_tess_state);
2632    CTX_INIT(set_shader_buffers);
2633    CTX_INIT(set_shader_images);
2634    CTX_INIT(set_vertex_buffers);
2635    CTX_INIT(create_stream_output_target);
2636    CTX_INIT(stream_output_target_destroy);
2637    CTX_INIT(set_stream_output_targets);
2638    CTX_INIT(create_sampler_view);
2639    CTX_INIT(sampler_view_destroy);
2640    CTX_INIT(create_surface);
2641    CTX_INIT(surface_destroy);
2642    CTX_INIT(transfer_map);
2643    CTX_INIT(transfer_flush_region);
2644    CTX_INIT(transfer_unmap);
2645    CTX_INIT(buffer_subdata);
2646    CTX_INIT(texture_subdata);
2647    CTX_INIT(texture_barrier);
2648    CTX_INIT(memory_barrier);
2649    CTX_INIT(resource_commit);
2650    CTX_INIT(create_video_codec);
2651    CTX_INIT(create_video_buffer);
2652    CTX_INIT(set_compute_resources);
2653    CTX_INIT(set_global_binding);
2654    CTX_INIT(get_sample_position);
2655    CTX_INIT(invalidate_resource);
2656    CTX_INIT(get_device_reset_status);
2657    CTX_INIT(set_device_reset_callback);
2658    CTX_INIT(dump_debug_state);
2659    CTX_INIT(set_log_context);
2660    CTX_INIT(emit_string_marker);
2661    CTX_INIT(set_debug_callback);
2662    CTX_INIT(create_fence_fd);
2663    CTX_INIT(fence_server_sync);
2664    CTX_INIT(get_timestamp);
2665    CTX_INIT(create_texture_handle);
2666    CTX_INIT(delete_texture_handle);
2667    CTX_INIT(make_texture_handle_resident);
2668    CTX_INIT(create_image_handle);
2669    CTX_INIT(delete_image_handle);
2670    CTX_INIT(make_image_handle_resident);
2671 #undef CTX_INIT
2672 
2673    if (out)
2674       *out = tc;
2675 
2676    return &tc->base;
2677 
2678 fail:
2679    tc_destroy(&tc->base);
2680    return NULL;
2681 }
2682