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