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