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