gallium/util: add threaded_context as a pipe_context wrapper
[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 tc_sync(tc);
1596 pipe->set_debug_callback(pipe, cb);
1597 }
1598
1599 static void
1600 tc_create_fence_fd(struct pipe_context *_pipe,
1601 struct pipe_fence_handle **fence, int fd)
1602 {
1603 struct threaded_context *tc = threaded_context(_pipe);
1604 struct pipe_context *pipe = tc->pipe;
1605
1606 tc_sync(tc);
1607 pipe->create_fence_fd(pipe, fence, fd);
1608 }
1609
1610 static void
1611 tc_fence_server_sync(struct pipe_context *_pipe,
1612 struct pipe_fence_handle *fence)
1613 {
1614 struct threaded_context *tc = threaded_context(_pipe);
1615 struct pipe_context *pipe = tc->pipe;
1616
1617 tc_sync(tc);
1618 pipe->fence_server_sync(pipe, fence);
1619 }
1620
1621 static struct pipe_video_codec *
1622 tc_create_video_codec(struct pipe_context *_pipe,
1623 const struct pipe_video_codec *templ)
1624 {
1625 unreachable("Threaded context should not be enabled for video APIs");
1626 return NULL;
1627 }
1628
1629 static struct pipe_video_buffer *
1630 tc_create_video_buffer(struct pipe_context *_pipe,
1631 const struct pipe_video_buffer *templ)
1632 {
1633 unreachable("Threaded context should not be enabled for video APIs");
1634 return NULL;
1635 }
1636
1637
1638 /********************************************************************
1639 * draw, launch, clear, blit, copy, flush
1640 */
1641
1642 static void
1643 tc_flush(struct pipe_context *_pipe, struct pipe_fence_handle **fence,
1644 unsigned flags)
1645 {
1646 struct threaded_context *tc = threaded_context(_pipe);
1647 struct pipe_context *pipe = tc->pipe;
1648 struct threaded_query *tq, *tmp;
1649
1650 LIST_FOR_EACH_ENTRY_SAFE(tq, tmp, &tc->unflushed_queries, head_unflushed) {
1651 tq->flushed = true;
1652 LIST_DEL(&tq->head_unflushed);
1653 }
1654
1655 /* TODO: deferred flushes? */
1656 tc_sync_msg(tc, flags & PIPE_FLUSH_END_OF_FRAME ? "end of frame" :
1657 flags & PIPE_FLUSH_DEFERRED ? "deferred fence" : "normal");
1658 pipe->flush(pipe, fence, flags);
1659 }
1660
1661 /* This is actually variable-sized, because indirect isn't allocated if it's
1662 * not needed. */
1663 struct tc_full_draw_info {
1664 struct pipe_draw_info draw;
1665 struct pipe_draw_indirect_info indirect;
1666 };
1667
1668 static void
1669 tc_call_draw_vbo(struct pipe_context *pipe, union tc_payload *payload)
1670 {
1671 struct tc_full_draw_info *info = (struct tc_full_draw_info*)payload;
1672
1673 pipe->draw_vbo(pipe, &info->draw);
1674 pipe_so_target_reference(&info->draw.count_from_stream_output, NULL);
1675 if (info->draw.index_size)
1676 pipe_resource_reference(&info->draw.index.resource, NULL);
1677 if (info->draw.indirect) {
1678 pipe_resource_reference(&info->indirect.buffer, NULL);
1679 pipe_resource_reference(&info->indirect.indirect_draw_count, NULL);
1680 }
1681 }
1682
1683 static struct tc_full_draw_info *
1684 tc_add_draw_vbo(struct pipe_context *_pipe, bool indirect)
1685 {
1686 return (struct tc_full_draw_info*)
1687 tc_add_sized_call(threaded_context(_pipe), TC_CALL_draw_vbo,
1688 indirect ? sizeof(struct tc_full_draw_info) :
1689 sizeof(struct pipe_draw_info));
1690 }
1691
1692 static void
1693 tc_draw_vbo(struct pipe_context *_pipe, const struct pipe_draw_info *info)
1694 {
1695 struct threaded_context *tc = threaded_context(_pipe);
1696 struct pipe_draw_indirect_info *indirect = info->indirect;
1697 unsigned index_size = info->index_size;
1698 bool has_user_indices = info->has_user_indices;
1699
1700 if (index_size && has_user_indices) {
1701 unsigned size = info->count * index_size;
1702 struct pipe_resource *buffer = NULL;
1703 unsigned offset;
1704
1705 tc_assert(!indirect);
1706
1707 /* This must be done before adding draw_vbo, because it could generate
1708 * e.g. transfer_unmap and flush partially-uninitialized draw_vbo
1709 * to the driver if it was done afterwards.
1710 */
1711 u_upload_data(tc->base.stream_uploader, 0, size, 4, info->index.user,
1712 &offset, &buffer);
1713 if (unlikely(!buffer))
1714 return;
1715
1716 struct tc_full_draw_info *p = tc_add_draw_vbo(_pipe, false);
1717 p->draw.count_from_stream_output = NULL;
1718 pipe_so_target_reference(&p->draw.count_from_stream_output,
1719 info->count_from_stream_output);
1720 memcpy(&p->draw, info, sizeof(*info));
1721 p->draw.has_user_indices = false;
1722 p->draw.index.resource = buffer;
1723 p->draw.start = offset / index_size;
1724 } else {
1725 /* Non-indexed call or indexed with a real index buffer. */
1726 struct tc_full_draw_info *p = tc_add_draw_vbo(_pipe, indirect != NULL);
1727 p->draw.count_from_stream_output = NULL;
1728 pipe_so_target_reference(&p->draw.count_from_stream_output,
1729 info->count_from_stream_output);
1730 if (index_size) {
1731 tc_set_resource_reference(&p->draw.index.resource,
1732 info->index.resource);
1733 }
1734 memcpy(&p->draw, info, sizeof(*info));
1735
1736 if (indirect) {
1737 tc_set_resource_reference(&p->draw.indirect->buffer, indirect->buffer);
1738 tc_set_resource_reference(&p->indirect.indirect_draw_count,
1739 indirect->indirect_draw_count);
1740 memcpy(&p->indirect, indirect, sizeof(*indirect));
1741 p->draw.indirect = &p->indirect;
1742 }
1743 }
1744 }
1745
1746 static void
1747 tc_call_launch_grid(struct pipe_context *pipe, union tc_payload *payload)
1748 {
1749 struct pipe_grid_info *p = (struct pipe_grid_info *)payload;
1750
1751 pipe->launch_grid(pipe, p);
1752 pipe_resource_reference(&p->indirect, NULL);
1753 }
1754
1755 static void
1756 tc_launch_grid(struct pipe_context *_pipe,
1757 const struct pipe_grid_info *info)
1758 {
1759 struct threaded_context *tc = threaded_context(_pipe);
1760 struct pipe_grid_info *p = tc_add_struct_typed_call(tc, TC_CALL_launch_grid,
1761 pipe_grid_info);
1762 assert(info->input == NULL);
1763
1764 tc_set_resource_reference(&p->indirect, info->indirect);
1765 memcpy(p, info, sizeof(*info));
1766 }
1767
1768 static void
1769 tc_call_resource_copy_region(struct pipe_context *pipe, union tc_payload *payload)
1770 {
1771 struct tc_resource_copy_region *p = (struct tc_resource_copy_region *)payload;
1772
1773 pipe->resource_copy_region(pipe, p->dst, p->dst_level, p->dstx, p->dsty,
1774 p->dstz, p->src, p->src_level, &p->src_box);
1775 pipe_resource_reference(&p->dst, NULL);
1776 pipe_resource_reference(&p->src, NULL);
1777 }
1778
1779 static void
1780 tc_resource_copy_region(struct pipe_context *_pipe,
1781 struct pipe_resource *dst, unsigned dst_level,
1782 unsigned dstx, unsigned dsty, unsigned dstz,
1783 struct pipe_resource *src, unsigned src_level,
1784 const struct pipe_box *src_box)
1785 {
1786 struct threaded_context *tc = threaded_context(_pipe);
1787 struct threaded_resource *tdst = threaded_resource(dst);
1788 struct tc_resource_copy_region *p =
1789 tc_add_struct_typed_call(tc, TC_CALL_resource_copy_region,
1790 tc_resource_copy_region);
1791
1792 tc_set_resource_reference(&p->dst, dst);
1793 p->dst_level = dst_level;
1794 p->dstx = dstx;
1795 p->dsty = dsty;
1796 p->dstz = dstz;
1797 tc_set_resource_reference(&p->src, src);
1798 p->src_level = src_level;
1799 p->src_box = *src_box;
1800
1801 if (dst->target == PIPE_BUFFER)
1802 util_range_add(&tdst->valid_buffer_range, dstx, dstx + src_box->width);
1803 }
1804
1805 static void
1806 tc_call_blit(struct pipe_context *pipe, union tc_payload *payload)
1807 {
1808 struct pipe_blit_info *blit = (struct pipe_blit_info*)payload;
1809
1810 pipe->blit(pipe, blit);
1811 pipe_resource_reference(&blit->dst.resource, NULL);
1812 pipe_resource_reference(&blit->src.resource, NULL);
1813 }
1814
1815 static void
1816 tc_blit(struct pipe_context *_pipe, const struct pipe_blit_info *info)
1817 {
1818 struct threaded_context *tc = threaded_context(_pipe);
1819 struct pipe_blit_info *blit =
1820 tc_add_struct_typed_call(tc, TC_CALL_blit, pipe_blit_info);
1821
1822 tc_set_resource_reference(&blit->dst.resource, info->dst.resource);
1823 tc_set_resource_reference(&blit->src.resource, info->src.resource);
1824 memcpy(blit, info, sizeof(*info));
1825 }
1826
1827 struct tc_generate_mipmap {
1828 struct pipe_resource *res;
1829 enum pipe_format format;
1830 unsigned base_level;
1831 unsigned last_level;
1832 unsigned first_layer;
1833 unsigned last_layer;
1834 };
1835
1836 static void
1837 tc_call_generate_mipmap(struct pipe_context *pipe, union tc_payload *payload)
1838 {
1839 struct tc_generate_mipmap *p = (struct tc_generate_mipmap *)payload;
1840 bool result = pipe->generate_mipmap(pipe, p->res, p->format, p->base_level,
1841 p->last_level, p->first_layer,
1842 p->last_layer);
1843 assert(result);
1844 pipe_resource_reference(&p->res, NULL);
1845 }
1846
1847 static boolean
1848 tc_generate_mipmap(struct pipe_context *_pipe,
1849 struct pipe_resource *res,
1850 enum pipe_format format,
1851 unsigned base_level,
1852 unsigned last_level,
1853 unsigned first_layer,
1854 unsigned last_layer)
1855 {
1856 struct threaded_context *tc = threaded_context(_pipe);
1857 struct pipe_context *pipe = tc->pipe;
1858 struct pipe_screen *screen = pipe->screen;
1859 unsigned bind = PIPE_BIND_SAMPLER_VIEW;
1860
1861 if (util_format_is_depth_or_stencil(format))
1862 bind = PIPE_BIND_DEPTH_STENCIL;
1863 else
1864 bind = PIPE_BIND_RENDER_TARGET;
1865
1866 if (!screen->is_format_supported(screen, format, res->target,
1867 res->nr_samples, bind))
1868 return false;
1869
1870 struct tc_generate_mipmap *p =
1871 tc_add_struct_typed_call(tc, TC_CALL_generate_mipmap, tc_generate_mipmap);
1872
1873 tc_set_resource_reference(&p->res, res);
1874 p->format = format;
1875 p->base_level = base_level;
1876 p->last_level = last_level;
1877 p->first_layer = first_layer;
1878 p->last_layer = last_layer;
1879 return true;
1880 }
1881
1882 static void
1883 tc_call_flush_resource(struct pipe_context *pipe, union tc_payload *payload)
1884 {
1885 pipe->flush_resource(pipe, payload->resource);
1886 pipe_resource_reference(&payload->resource, NULL);
1887 }
1888
1889 static void
1890 tc_flush_resource(struct pipe_context *_pipe,
1891 struct pipe_resource *resource)
1892 {
1893 struct threaded_context *tc = threaded_context(_pipe);
1894 union tc_payload *payload = tc_add_small_call(tc, TC_CALL_flush_resource);
1895
1896 tc_set_resource_reference(&payload->resource, resource);
1897 }
1898
1899 static void
1900 tc_call_invalidate_resource(struct pipe_context *pipe, union tc_payload *payload)
1901 {
1902 pipe->invalidate_resource(pipe, payload->resource);
1903 pipe_resource_reference(&payload->resource, NULL);
1904 }
1905
1906 static void
1907 tc_invalidate_resource(struct pipe_context *_pipe,
1908 struct pipe_resource *resource)
1909 {
1910 struct threaded_context *tc = threaded_context(_pipe);
1911
1912 if (resource->target == PIPE_BUFFER) {
1913 tc_invalidate_buffer(tc, threaded_resource(resource));
1914 return;
1915 }
1916
1917 union tc_payload *payload = tc_add_small_call(tc, TC_CALL_invalidate_resource);
1918 tc_set_resource_reference(&payload->resource, resource);
1919 }
1920
1921 struct tc_clear {
1922 unsigned buffers;
1923 union pipe_color_union color;
1924 double depth;
1925 unsigned stencil;
1926 };
1927
1928 static void
1929 tc_call_clear(struct pipe_context *pipe, union tc_payload *payload)
1930 {
1931 struct tc_clear *p = (struct tc_clear *)payload;
1932 pipe->clear(pipe, p->buffers, &p->color, p->depth, p->stencil);
1933 }
1934
1935 static void
1936 tc_clear(struct pipe_context *_pipe, unsigned buffers,
1937 const union pipe_color_union *color, double depth,
1938 unsigned stencil)
1939 {
1940 struct threaded_context *tc = threaded_context(_pipe);
1941 struct tc_clear *p = tc_add_struct_typed_call(tc, TC_CALL_clear, tc_clear);
1942
1943 p->buffers = buffers;
1944 p->color = *color;
1945 p->depth = depth;
1946 p->stencil = stencil;
1947 }
1948
1949 static void
1950 tc_clear_render_target(struct pipe_context *_pipe,
1951 struct pipe_surface *dst,
1952 const union pipe_color_union *color,
1953 unsigned dstx, unsigned dsty,
1954 unsigned width, unsigned height,
1955 bool render_condition_enabled)
1956 {
1957 struct threaded_context *tc = threaded_context(_pipe);
1958 struct pipe_context *pipe = tc->pipe;
1959
1960 tc_sync(tc);
1961 pipe->clear_render_target(pipe, dst, color, dstx, dsty, width, height,
1962 render_condition_enabled);
1963 }
1964
1965 static void
1966 tc_clear_depth_stencil(struct pipe_context *_pipe,
1967 struct pipe_surface *dst, unsigned clear_flags,
1968 double depth, unsigned stencil, unsigned dstx,
1969 unsigned dsty, unsigned width, unsigned height,
1970 bool render_condition_enabled)
1971 {
1972 struct threaded_context *tc = threaded_context(_pipe);
1973 struct pipe_context *pipe = tc->pipe;
1974
1975 tc_sync(tc);
1976 pipe->clear_depth_stencil(pipe, dst, clear_flags, depth, stencil,
1977 dstx, dsty, width, height,
1978 render_condition_enabled);
1979 }
1980
1981 struct tc_clear_buffer {
1982 struct pipe_resource *res;
1983 unsigned offset;
1984 unsigned size;
1985 char clear_value[16];
1986 int clear_value_size;
1987 };
1988
1989 static void
1990 tc_call_clear_buffer(struct pipe_context *pipe, union tc_payload *payload)
1991 {
1992 struct tc_clear_buffer *p = (struct tc_clear_buffer *)payload;
1993
1994 pipe->clear_buffer(pipe, p->res, p->offset, p->size, p->clear_value,
1995 p->clear_value_size);
1996 pipe_resource_reference(&p->res, NULL);
1997 }
1998
1999 static void
2000 tc_clear_buffer(struct pipe_context *_pipe, struct pipe_resource *res,
2001 unsigned offset, unsigned size,
2002 const void *clear_value, int clear_value_size)
2003 {
2004 struct threaded_context *tc = threaded_context(_pipe);
2005 struct threaded_resource *tres = threaded_resource(res);
2006 struct tc_clear_buffer *p =
2007 tc_add_struct_typed_call(tc, TC_CALL_clear_buffer, tc_clear_buffer);
2008
2009 tc_set_resource_reference(&p->res, res);
2010 p->offset = offset;
2011 p->size = size;
2012 memcpy(p->clear_value, clear_value, clear_value_size);
2013 p->clear_value_size = clear_value_size;
2014
2015 util_range_add(&tres->valid_buffer_range, offset, offset + size);
2016 }
2017
2018 struct tc_clear_texture {
2019 struct pipe_resource *res;
2020 unsigned level;
2021 struct pipe_box box;
2022 char data[16];
2023 };
2024
2025 static void
2026 tc_call_clear_texture(struct pipe_context *pipe, union tc_payload *payload)
2027 {
2028 struct tc_clear_texture *p = (struct tc_clear_texture *)payload;
2029
2030 pipe->clear_texture(pipe, p->res, p->level, &p->box, p->data);
2031 pipe_resource_reference(&p->res, NULL);
2032 }
2033
2034 static void
2035 tc_clear_texture(struct pipe_context *_pipe, struct pipe_resource *res,
2036 unsigned level, const struct pipe_box *box, const void *data)
2037 {
2038 struct threaded_context *tc = threaded_context(_pipe);
2039 struct tc_clear_texture *p =
2040 tc_add_struct_typed_call(tc, TC_CALL_clear_texture, tc_clear_texture);
2041
2042 tc_set_resource_reference(&p->res, res);
2043 p->level = level;
2044 p->box = *box;
2045 memcpy(p->data, data,
2046 util_format_get_blocksize(res->format));
2047 }
2048
2049 struct tc_resource_commit {
2050 struct pipe_resource *res;
2051 unsigned level;
2052 struct pipe_box box;
2053 bool commit;
2054 };
2055
2056 static void
2057 tc_call_resource_commit(struct pipe_context *pipe, union tc_payload *payload)
2058 {
2059 struct tc_resource_commit *p = (struct tc_resource_commit *)payload;
2060
2061 pipe->resource_commit(pipe, p->res, p->level, &p->box, p->commit);
2062 pipe_resource_reference(&p->res, NULL);
2063 }
2064
2065 static bool
2066 tc_resource_commit(struct pipe_context *_pipe, struct pipe_resource *res,
2067 unsigned level, struct pipe_box *box, bool commit)
2068 {
2069 struct threaded_context *tc = threaded_context(_pipe);
2070 struct tc_resource_commit *p =
2071 tc_add_struct_typed_call(tc, TC_CALL_resource_commit, tc_resource_commit);
2072
2073 tc_set_resource_reference(&p->res, res);
2074 p->level = level;
2075 p->box = *box;
2076 p->commit = commit;
2077 return true; /* we don't care about the return value for this call */
2078 }
2079
2080
2081 /********************************************************************
2082 * create & destroy
2083 */
2084
2085 static void
2086 tc_destroy(struct pipe_context *_pipe)
2087 {
2088 struct threaded_context *tc = threaded_context(_pipe);
2089 struct pipe_context *pipe = tc->pipe;
2090
2091 tc_sync(tc);
2092
2093 if (util_queue_is_initialized(&tc->queue)) {
2094 util_queue_destroy(&tc->queue);
2095
2096 for (unsigned i = 0; i < TC_MAX_BATCHES; i++)
2097 util_queue_fence_destroy(&tc->batch_slots[i].fence);
2098 }
2099
2100 if (tc->base.const_uploader &&
2101 tc->base.stream_uploader != tc->base.const_uploader)
2102 u_upload_destroy(tc->base.const_uploader);
2103
2104 if (tc->base.stream_uploader)
2105 u_upload_destroy(tc->base.stream_uploader);
2106
2107 slab_destroy_child(&tc->pool_transfers);
2108 pipe->destroy(pipe);
2109 FREE(tc);
2110 }
2111
2112 static const tc_execute execute_func[TC_NUM_CALLS] = {
2113 #define CALL(name) tc_call_##name,
2114 #include "u_threaded_context_calls.h"
2115 #undef CALL
2116 };
2117
2118 /**
2119 * Wrap an existing pipe_context into a threaded_context.
2120 *
2121 * \param pipe pipe_context to wrap
2122 * \param parent_transfer_pool parent slab pool set up for creating pipe_-
2123 * transfer objects; the driver should have one
2124 * in pipe_screen.
2125 * \param replace_buffer callback for replacing a pipe_resource's storage
2126 * with another pipe_resource's storage.
2127 * \param out if successful, the threaded_context will be returned here in
2128 * addition to the return value if "out" != NULL
2129 */
2130 struct pipe_context *
2131 threaded_context_create(struct pipe_context *pipe,
2132 struct slab_parent_pool *parent_transfer_pool,
2133 tc_replace_buffer_storage_func replace_buffer,
2134 struct threaded_context **out)
2135 {
2136 struct threaded_context *tc;
2137
2138 STATIC_ASSERT(sizeof(union tc_payload) <= 8);
2139 STATIC_ASSERT(sizeof(struct tc_call) <= 16);
2140
2141 if (!pipe)
2142 return NULL;
2143
2144 util_cpu_detect();
2145
2146 if (!debug_get_bool_option("GALLIUM_THREAD", util_cpu_caps.nr_cpus > 1))
2147 return pipe;
2148
2149 tc = CALLOC_STRUCT(threaded_context);
2150 if (!tc) {
2151 pipe->destroy(pipe);
2152 return NULL;
2153 }
2154
2155 /* The driver context isn't wrapped, so set its "priv" to NULL. */
2156 pipe->priv = NULL;
2157
2158 tc->pipe = pipe;
2159 tc->replace_buffer_storage = replace_buffer;
2160 tc->map_buffer_alignment =
2161 pipe->screen->get_param(pipe->screen, PIPE_CAP_MIN_MAP_BUFFER_ALIGNMENT);
2162 tc->base.priv = pipe; /* priv points to the wrapped driver context */
2163 tc->base.screen = pipe->screen;
2164 tc->base.destroy = tc_destroy;
2165
2166 tc->base.stream_uploader = u_upload_clone(&tc->base, pipe->stream_uploader);
2167 if (pipe->stream_uploader == pipe->const_uploader)
2168 tc->base.const_uploader = tc->base.stream_uploader;
2169 else
2170 tc->base.const_uploader = u_upload_clone(&tc->base, pipe->const_uploader);
2171
2172 if (!tc->base.stream_uploader || !tc->base.const_uploader)
2173 goto fail;
2174
2175 /* The queue size is the number of batches "waiting". Batches are removed
2176 * from the queue before being executed, so keep one tc_batch slot for that
2177 * execution. Also, keep one unused slot for an unflushed batch.
2178 */
2179 if (!util_queue_init(&tc->queue, "gallium_drv", TC_MAX_BATCHES - 2, 1))
2180 goto fail;
2181
2182 for (unsigned i = 0; i < TC_MAX_BATCHES; i++) {
2183 tc->batch_slots[i].sentinel = TC_SENTINEL;
2184 tc->batch_slots[i].sentinel2 = TC_SENTINEL;
2185 tc->batch_slots[i].pipe = pipe;
2186 util_queue_fence_init(&tc->batch_slots[i].fence);
2187 }
2188
2189 LIST_INITHEAD(&tc->unflushed_queries);
2190
2191 slab_create_child(&tc->pool_transfers, parent_transfer_pool);
2192
2193 #define CTX_INIT(_member) \
2194 tc->base._member = tc->pipe->_member ? tc_##_member : NULL
2195
2196 CTX_INIT(flush);
2197 CTX_INIT(draw_vbo);
2198 CTX_INIT(launch_grid);
2199 CTX_INIT(resource_copy_region);
2200 CTX_INIT(blit);
2201 CTX_INIT(clear);
2202 CTX_INIT(clear_render_target);
2203 CTX_INIT(clear_depth_stencil);
2204 CTX_INIT(clear_buffer);
2205 CTX_INIT(clear_texture);
2206 CTX_INIT(flush_resource);
2207 CTX_INIT(generate_mipmap);
2208 CTX_INIT(render_condition);
2209 CTX_INIT(create_query);
2210 CTX_INIT(create_batch_query);
2211 CTX_INIT(destroy_query);
2212 CTX_INIT(begin_query);
2213 CTX_INIT(end_query);
2214 CTX_INIT(get_query_result);
2215 CTX_INIT(get_query_result_resource);
2216 CTX_INIT(set_active_query_state);
2217 CTX_INIT(create_blend_state);
2218 CTX_INIT(bind_blend_state);
2219 CTX_INIT(delete_blend_state);
2220 CTX_INIT(create_sampler_state);
2221 CTX_INIT(bind_sampler_states);
2222 CTX_INIT(delete_sampler_state);
2223 CTX_INIT(create_rasterizer_state);
2224 CTX_INIT(bind_rasterizer_state);
2225 CTX_INIT(delete_rasterizer_state);
2226 CTX_INIT(create_depth_stencil_alpha_state);
2227 CTX_INIT(bind_depth_stencil_alpha_state);
2228 CTX_INIT(delete_depth_stencil_alpha_state);
2229 CTX_INIT(create_fs_state);
2230 CTX_INIT(bind_fs_state);
2231 CTX_INIT(delete_fs_state);
2232 CTX_INIT(create_vs_state);
2233 CTX_INIT(bind_vs_state);
2234 CTX_INIT(delete_vs_state);
2235 CTX_INIT(create_gs_state);
2236 CTX_INIT(bind_gs_state);
2237 CTX_INIT(delete_gs_state);
2238 CTX_INIT(create_tcs_state);
2239 CTX_INIT(bind_tcs_state);
2240 CTX_INIT(delete_tcs_state);
2241 CTX_INIT(create_tes_state);
2242 CTX_INIT(bind_tes_state);
2243 CTX_INIT(delete_tes_state);
2244 CTX_INIT(create_compute_state);
2245 CTX_INIT(bind_compute_state);
2246 CTX_INIT(delete_compute_state);
2247 CTX_INIT(create_vertex_elements_state);
2248 CTX_INIT(bind_vertex_elements_state);
2249 CTX_INIT(delete_vertex_elements_state);
2250 CTX_INIT(set_blend_color);
2251 CTX_INIT(set_stencil_ref);
2252 CTX_INIT(set_sample_mask);
2253 CTX_INIT(set_min_samples);
2254 CTX_INIT(set_clip_state);
2255 CTX_INIT(set_constant_buffer);
2256 CTX_INIT(set_framebuffer_state);
2257 CTX_INIT(set_polygon_stipple);
2258 CTX_INIT(set_scissor_states);
2259 CTX_INIT(set_viewport_states);
2260 CTX_INIT(set_window_rectangles);
2261 CTX_INIT(set_sampler_views);
2262 CTX_INIT(set_tess_state);
2263 CTX_INIT(set_shader_buffers);
2264 CTX_INIT(set_shader_images);
2265 CTX_INIT(set_vertex_buffers);
2266 CTX_INIT(create_stream_output_target);
2267 CTX_INIT(stream_output_target_destroy);
2268 CTX_INIT(set_stream_output_targets);
2269 CTX_INIT(create_sampler_view);
2270 CTX_INIT(sampler_view_destroy);
2271 CTX_INIT(create_surface);
2272 CTX_INIT(surface_destroy);
2273 CTX_INIT(transfer_map);
2274 CTX_INIT(transfer_flush_region);
2275 CTX_INIT(transfer_unmap);
2276 CTX_INIT(buffer_subdata);
2277 CTX_INIT(texture_subdata);
2278 CTX_INIT(texture_barrier);
2279 CTX_INIT(memory_barrier);
2280 CTX_INIT(resource_commit);
2281 CTX_INIT(create_video_codec);
2282 CTX_INIT(create_video_buffer);
2283 CTX_INIT(set_compute_resources);
2284 CTX_INIT(set_global_binding);
2285 CTX_INIT(get_sample_position);
2286 CTX_INIT(invalidate_resource);
2287 CTX_INIT(get_device_reset_status);
2288 CTX_INIT(set_device_reset_callback);
2289 CTX_INIT(dump_debug_state);
2290 CTX_INIT(emit_string_marker);
2291 CTX_INIT(set_debug_callback);
2292 CTX_INIT(create_fence_fd);
2293 CTX_INIT(fence_server_sync);
2294 CTX_INIT(get_timestamp);
2295 #undef CTX_INIT
2296
2297 if (out)
2298 *out = tc;
2299
2300 return &tc->base;
2301
2302 fail:
2303 tc_destroy(&tc->base);
2304 return NULL;
2305 }