cso_context.c revision 389021220d27c376b81a6221a31d0ee33c24e67f
1/************************************************************************** 2 * 3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. 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 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28 /** 29 * @file 30 * 31 * Wrap the cso cache & hash mechanisms in a simplified 32 * pipe-driver-specific interface. 33 * 34 * @author Zack Rusin <zack@tungstengraphics.com> 35 * @author Keith Whitwell <keith@tungstengraphics.com> 36 */ 37 38#include "pipe/p_state.h" 39#include "util/u_memory.h" 40#include "tgsi/tgsi_parse.h" 41 42#include "cso_cache/cso_context.h" 43#include "cso_cache/cso_cache.h" 44#include "cso_cache/cso_hash.h" 45 46struct cso_context { 47 struct pipe_context *pipe; 48 struct cso_cache *cache; 49 50 struct { 51 void *samplers[PIPE_MAX_SAMPLERS]; 52 unsigned nr_samplers; 53 } hw; 54 55 void *samplers[PIPE_MAX_SAMPLERS]; 56 unsigned nr_samplers; 57 58 unsigned nr_samplers_saved; 59 void *samplers_saved[PIPE_MAX_SAMPLERS]; 60 61 struct pipe_texture *textures[PIPE_MAX_SAMPLERS]; 62 uint nr_textures; 63 64 uint nr_textures_saved; 65 struct pipe_texture *textures_saved[PIPE_MAX_SAMPLERS]; 66 67 /** Current and saved state. 68 * The saved state is used as a 1-deep stack. 69 */ 70 void *blend, *blend_saved; 71 void *depth_stencil, *depth_stencil_saved; 72 void *rasterizer, *rasterizer_saved; 73 void *fragment_shader, *fragment_shader_saved; 74 void *vertex_shader, *vertex_shader_saved; 75 76 struct pipe_framebuffer_state fb, fb_saved; 77 struct pipe_viewport_state vp, vp_saved; 78 struct pipe_blend_color blend_color; 79}; 80 81 82static void 83free_framebuffer_state(struct pipe_framebuffer_state *fb); 84 85 86static boolean delete_blend_state(struct cso_context *ctx, void *state) 87{ 88 struct cso_blend *cso = (struct cso_blend *)state; 89 90 if (ctx->blend == cso->data) 91 return FALSE; 92 93 if (cso->delete_state) 94 cso->delete_state(cso->context, cso->data); 95 FREE(state); 96 return TRUE; 97} 98 99static boolean delete_depth_stencil_state(struct cso_context *ctx, void *state) 100{ 101 struct cso_depth_stencil_alpha *cso = (struct cso_depth_stencil_alpha *)state; 102 103 if (ctx->depth_stencil == cso->data) 104 return FALSE; 105 106 if (cso->delete_state) 107 cso->delete_state(cso->context, cso->data); 108 FREE(state); 109 110 return TRUE; 111} 112 113static boolean delete_sampler_state(struct cso_context *ctx, void *state) 114{ 115 struct cso_sampler *cso = (struct cso_sampler *)state; 116 if (cso->delete_state) 117 cso->delete_state(cso->context, cso->data); 118 FREE(state); 119 return TRUE; 120} 121 122static boolean delete_rasterizer_state(struct cso_context *ctx, void *state) 123{ 124 struct cso_rasterizer *cso = (struct cso_rasterizer *)state; 125 126 if (ctx->rasterizer == cso->data) 127 return FALSE; 128 if (cso->delete_state) 129 cso->delete_state(cso->context, cso->data); 130 FREE(state); 131 return TRUE; 132} 133 134static boolean delete_fs_state(struct cso_context *ctx, void *state) 135{ 136 struct cso_fragment_shader *cso = (struct cso_fragment_shader *)state; 137 if (ctx->fragment_shader == cso->data) 138 return FALSE; 139 if (cso->delete_state) 140 cso->delete_state(cso->context, cso->data); 141 FREE(state); 142 return TRUE; 143} 144 145static boolean delete_vs_state(struct cso_context *ctx, void *state) 146{ 147 struct cso_vertex_shader *cso = (struct cso_vertex_shader *)state; 148 if (ctx->vertex_shader == cso->data) 149 return TRUE; 150 if (cso->delete_state) 151 cso->delete_state(cso->context, cso->data); 152 FREE(state); 153 return FALSE; 154} 155 156 157static INLINE boolean delete_cso(struct cso_context *ctx, 158 void *state, enum cso_cache_type type) 159{ 160 switch (type) { 161 case CSO_BLEND: 162 return delete_blend_state(ctx, state); 163 break; 164 case CSO_SAMPLER: 165 return delete_sampler_state(ctx, state); 166 break; 167 case CSO_DEPTH_STENCIL_ALPHA: 168 return delete_depth_stencil_state(ctx, state); 169 break; 170 case CSO_RASTERIZER: 171 return delete_rasterizer_state(ctx, state); 172 break; 173 case CSO_FRAGMENT_SHADER: 174 return delete_fs_state(ctx, state); 175 break; 176 case CSO_VERTEX_SHADER: 177 return delete_vs_state(ctx, state); 178 break; 179 default: 180 assert(0); 181 FREE(state); 182 } 183 return FALSE; 184} 185 186static INLINE void sanitize_hash(struct cso_hash *hash, enum cso_cache_type type, 187 int max_size, void *user_data) 188{ 189 struct cso_context *ctx = (struct cso_context *)user_data; 190 /* if we're approach the maximum size, remove fourth of the entries 191 * otherwise every subsequent call will go through the same */ 192 int hash_size = cso_hash_size(hash); 193 int max_entries = (max_size > hash_size) ? max_size : hash_size; 194 int to_remove = (max_size < max_entries) * max_entries/4; 195 struct cso_hash_iter iter = cso_hash_first_node(hash); 196 if (hash_size > max_size) 197 to_remove += hash_size - max_size; 198 while (to_remove) { 199 /*remove elements until we're good */ 200 /*fixme: currently we pick the nodes to remove at random*/ 201 void *cso = cso_hash_iter_data(iter); 202 if (delete_cso(ctx, cso, type)) { 203 iter = cso_hash_erase(hash, iter); 204 --to_remove; 205 } else 206 iter = cso_hash_iter_next(iter); 207 } 208} 209 210 211struct cso_context *cso_create_context( struct pipe_context *pipe ) 212{ 213 struct cso_context *ctx = CALLOC_STRUCT(cso_context); 214 if (ctx == NULL) 215 goto out; 216 217 ctx->cache = cso_cache_create(); 218 if (ctx->cache == NULL) 219 goto out; 220 cso_cache_set_sanitize_callback(ctx->cache, 221 sanitize_hash, 222 ctx); 223 224 ctx->pipe = pipe; 225 226 /* Enable for testing: */ 227 if (0) cso_set_maximum_cache_size( ctx->cache, 4 ); 228 229 return ctx; 230 231out: 232 cso_destroy_context( ctx ); 233 return NULL; 234} 235 236 237/** 238 * Prior to context destruction, this function unbinds all state objects. 239 */ 240void cso_release_all( struct cso_context *ctx ) 241{ 242 unsigned i; 243 244 if (ctx->pipe) { 245 ctx->pipe->bind_blend_state( ctx->pipe, NULL ); 246 ctx->pipe->bind_rasterizer_state( ctx->pipe, NULL ); 247 ctx->pipe->bind_sampler_states( ctx->pipe, 0, NULL ); 248 ctx->pipe->bind_depth_stencil_alpha_state( ctx->pipe, NULL ); 249 ctx->pipe->bind_fs_state( ctx->pipe, NULL ); 250 ctx->pipe->bind_vs_state( ctx->pipe, NULL ); 251 } 252 253 for (i = 0; i < PIPE_MAX_SAMPLERS; i++) { 254 pipe_texture_reference(&ctx->textures[i], NULL); 255 pipe_texture_reference(&ctx->textures_saved[i], NULL); 256 } 257 258 free_framebuffer_state(&ctx->fb); 259 free_framebuffer_state(&ctx->fb_saved); 260 261 if (ctx->cache) { 262 cso_cache_delete( ctx->cache ); 263 ctx->cache = NULL; 264 } 265} 266 267 268void cso_destroy_context( struct cso_context *ctx ) 269{ 270 if (ctx) { 271 /*cso_release_all( ctx );*/ 272 FREE( ctx ); 273 } 274} 275 276 277/* Those function will either find the state of the given template 278 * in the cache or they will create a new state from the given 279 * template, insert it in the cache and return it. 280 */ 281 282/* 283 * If the driver returns 0 from the create method then they will assign 284 * the data member of the cso to be the template itself. 285 */ 286 287enum pipe_error cso_set_blend(struct cso_context *ctx, 288 const struct pipe_blend_state *templ) 289{ 290 unsigned hash_key = cso_construct_key((void*)templ, sizeof(struct pipe_blend_state)); 291 struct cso_hash_iter iter = cso_find_state_template(ctx->cache, 292 hash_key, CSO_BLEND, 293 (void*)templ); 294 void *handle; 295 296 if (cso_hash_iter_is_null(iter)) { 297 struct cso_blend *cso = MALLOC(sizeof(struct cso_blend)); 298 if (!cso) 299 return PIPE_ERROR_OUT_OF_MEMORY; 300 301 memcpy(&cso->state, templ, sizeof(*templ)); 302 cso->data = ctx->pipe->create_blend_state(ctx->pipe, &cso->state); 303 cso->delete_state = (cso_state_callback)ctx->pipe->delete_blend_state; 304 cso->context = ctx->pipe; 305 306 iter = cso_insert_state(ctx->cache, hash_key, CSO_BLEND, cso); 307 if (cso_hash_iter_is_null(iter)) { 308 FREE(cso); 309 return PIPE_ERROR_OUT_OF_MEMORY; 310 } 311 312 handle = cso->data; 313 } 314 else { 315 handle = ((struct cso_blend *)cso_hash_iter_data(iter))->data; 316 } 317 318 if (ctx->blend != handle) { 319 ctx->blend = handle; 320 ctx->pipe->bind_blend_state(ctx->pipe, handle); 321 } 322 return PIPE_OK; 323} 324 325void cso_save_blend(struct cso_context *ctx) 326{ 327 assert(!ctx->blend_saved); 328 ctx->blend_saved = ctx->blend; 329} 330 331void cso_restore_blend(struct cso_context *ctx) 332{ 333 if (ctx->blend != ctx->blend_saved) { 334 ctx->blend = ctx->blend_saved; 335 ctx->pipe->bind_blend_state(ctx->pipe, ctx->blend_saved); 336 } 337 ctx->blend_saved = NULL; 338} 339 340 341 342enum pipe_error cso_single_sampler(struct cso_context *ctx, 343 unsigned idx, 344 const struct pipe_sampler_state *templ) 345{ 346 void *handle = NULL; 347 348 if (templ != NULL) { 349 unsigned hash_key = cso_construct_key((void*)templ, sizeof(struct pipe_sampler_state)); 350 struct cso_hash_iter iter = cso_find_state_template(ctx->cache, 351 hash_key, CSO_SAMPLER, 352 (void*)templ); 353 354 if (cso_hash_iter_is_null(iter)) { 355 struct cso_sampler *cso = MALLOC(sizeof(struct cso_sampler)); 356 if (!cso) 357 return PIPE_ERROR_OUT_OF_MEMORY; 358 359 memcpy(&cso->state, templ, sizeof(*templ)); 360 cso->data = ctx->pipe->create_sampler_state(ctx->pipe, &cso->state); 361 cso->delete_state = (cso_state_callback)ctx->pipe->delete_sampler_state; 362 cso->context = ctx->pipe; 363 364 iter = cso_insert_state(ctx->cache, hash_key, CSO_SAMPLER, cso); 365 if (cso_hash_iter_is_null(iter)) { 366 FREE(cso); 367 return PIPE_ERROR_OUT_OF_MEMORY; 368 } 369 370 handle = cso->data; 371 } 372 else { 373 handle = ((struct cso_sampler *)cso_hash_iter_data(iter))->data; 374 } 375 } 376 377 ctx->samplers[idx] = handle; 378 return PIPE_OK; 379} 380 381void cso_single_sampler_done( struct cso_context *ctx ) 382{ 383 unsigned i; 384 385 /* find highest non-null sampler */ 386 for (i = PIPE_MAX_SAMPLERS; i > 0; i--) { 387 if (ctx->samplers[i - 1] != NULL) 388 break; 389 } 390 391 ctx->nr_samplers = i; 392 393 if (ctx->hw.nr_samplers != ctx->nr_samplers || 394 memcmp(ctx->hw.samplers, 395 ctx->samplers, 396 ctx->nr_samplers * sizeof(void *)) != 0) 397 { 398 memcpy(ctx->hw.samplers, ctx->samplers, ctx->nr_samplers * sizeof(void *)); 399 ctx->hw.nr_samplers = ctx->nr_samplers; 400 401 ctx->pipe->bind_sampler_states(ctx->pipe, ctx->nr_samplers, ctx->samplers); 402 } 403} 404 405/* 406 * If the function encouters any errors it will return the 407 * last one. Done to always try to set as many samplers 408 * as possible. 409 */ 410enum pipe_error cso_set_samplers( struct cso_context *ctx, 411 unsigned nr, 412 const struct pipe_sampler_state **templates ) 413{ 414 unsigned i; 415 enum pipe_error temp, error = PIPE_OK; 416 417 /* TODO: fastpath 418 */ 419 420 for (i = 0; i < nr; i++) { 421 temp = cso_single_sampler( ctx, i, templates[i] ); 422 if (temp != PIPE_OK) 423 error = temp; 424 } 425 426 for ( ; i < ctx->nr_samplers; i++) { 427 temp = cso_single_sampler( ctx, i, NULL ); 428 if (temp != PIPE_OK) 429 error = temp; 430 } 431 432 cso_single_sampler_done( ctx ); 433 434 return error; 435} 436 437void cso_save_samplers(struct cso_context *ctx) 438{ 439 ctx->nr_samplers_saved = ctx->nr_samplers; 440 memcpy(ctx->samplers_saved, ctx->samplers, sizeof(ctx->samplers)); 441} 442 443void cso_restore_samplers(struct cso_context *ctx) 444{ 445 ctx->nr_samplers = ctx->nr_samplers_saved; 446 memcpy(ctx->samplers, ctx->samplers_saved, sizeof(ctx->samplers)); 447 cso_single_sampler_done( ctx ); 448} 449 450 451enum pipe_error cso_set_sampler_textures( struct cso_context *ctx, 452 uint count, 453 struct pipe_texture **textures ) 454{ 455 uint i; 456 457 ctx->nr_textures = count; 458 459 for (i = 0; i < count; i++) 460 pipe_texture_reference(&ctx->textures[i], textures[i]); 461 for ( ; i < PIPE_MAX_SAMPLERS; i++) 462 pipe_texture_reference(&ctx->textures[i], NULL); 463 464 ctx->pipe->set_sampler_textures(ctx->pipe, count, textures); 465 466 return PIPE_OK; 467} 468 469void cso_save_sampler_textures( struct cso_context *ctx ) 470{ 471 uint i; 472 473 ctx->nr_textures_saved = ctx->nr_textures; 474 for (i = 0; i < ctx->nr_textures; i++) { 475 assert(!ctx->textures_saved[i]); 476 pipe_texture_reference(&ctx->textures_saved[i], ctx->textures[i]); 477 } 478} 479 480void cso_restore_sampler_textures( struct cso_context *ctx ) 481{ 482 uint i; 483 484 ctx->nr_textures = ctx->nr_textures_saved; 485 486 for (i = 0; i < ctx->nr_textures; i++) { 487 pipe_texture_reference(&ctx->textures[i], NULL); 488 ctx->textures[i] = ctx->textures_saved[i]; 489 ctx->textures_saved[i] = NULL; 490 } 491 for ( ; i < PIPE_MAX_SAMPLERS; i++) 492 pipe_texture_reference(&ctx->textures[i], NULL); 493 494 ctx->pipe->set_sampler_textures(ctx->pipe, ctx->nr_textures, ctx->textures); 495 496 ctx->nr_textures_saved = 0; 497} 498 499 500 501enum pipe_error cso_set_depth_stencil_alpha(struct cso_context *ctx, 502 const struct pipe_depth_stencil_alpha_state *templ) 503{ 504 unsigned hash_key = cso_construct_key((void*)templ, 505 sizeof(struct pipe_depth_stencil_alpha_state)); 506 struct cso_hash_iter iter = cso_find_state_template(ctx->cache, 507 hash_key, 508 CSO_DEPTH_STENCIL_ALPHA, 509 (void*)templ); 510 void *handle; 511 512 if (cso_hash_iter_is_null(iter)) { 513 struct cso_depth_stencil_alpha *cso = MALLOC(sizeof(struct cso_depth_stencil_alpha)); 514 if (!cso) 515 return PIPE_ERROR_OUT_OF_MEMORY; 516 517 memcpy(&cso->state, templ, sizeof(*templ)); 518 cso->data = ctx->pipe->create_depth_stencil_alpha_state(ctx->pipe, &cso->state); 519 cso->delete_state = (cso_state_callback)ctx->pipe->delete_depth_stencil_alpha_state; 520 cso->context = ctx->pipe; 521 522 iter = cso_insert_state(ctx->cache, hash_key, CSO_DEPTH_STENCIL_ALPHA, cso); 523 if (cso_hash_iter_is_null(iter)) { 524 FREE(cso); 525 return PIPE_ERROR_OUT_OF_MEMORY; 526 } 527 528 handle = cso->data; 529 } 530 else { 531 handle = ((struct cso_depth_stencil_alpha *)cso_hash_iter_data(iter))->data; 532 } 533 534 if (ctx->depth_stencil != handle) { 535 ctx->depth_stencil = handle; 536 ctx->pipe->bind_depth_stencil_alpha_state(ctx->pipe, handle); 537 } 538 return PIPE_OK; 539} 540 541void cso_save_depth_stencil_alpha(struct cso_context *ctx) 542{ 543 assert(!ctx->depth_stencil_saved); 544 ctx->depth_stencil_saved = ctx->depth_stencil; 545} 546 547void cso_restore_depth_stencil_alpha(struct cso_context *ctx) 548{ 549 if (ctx->depth_stencil != ctx->depth_stencil_saved) { 550 ctx->depth_stencil = ctx->depth_stencil_saved; 551 ctx->pipe->bind_depth_stencil_alpha_state(ctx->pipe, ctx->depth_stencil_saved); 552 } 553 ctx->depth_stencil_saved = NULL; 554} 555 556 557 558enum pipe_error cso_set_rasterizer(struct cso_context *ctx, 559 const struct pipe_rasterizer_state *templ) 560{ 561 unsigned hash_key = cso_construct_key((void*)templ, 562 sizeof(struct pipe_rasterizer_state)); 563 struct cso_hash_iter iter = cso_find_state_template(ctx->cache, 564 hash_key, CSO_RASTERIZER, 565 (void*)templ); 566 void *handle = NULL; 567 568 if (cso_hash_iter_is_null(iter)) { 569 struct cso_rasterizer *cso = MALLOC(sizeof(struct cso_rasterizer)); 570 if (!cso) 571 return PIPE_ERROR_OUT_OF_MEMORY; 572 573 memcpy(&cso->state, templ, sizeof(*templ)); 574 cso->data = ctx->pipe->create_rasterizer_state(ctx->pipe, &cso->state); 575 cso->delete_state = (cso_state_callback)ctx->pipe->delete_rasterizer_state; 576 cso->context = ctx->pipe; 577 578 iter = cso_insert_state(ctx->cache, hash_key, CSO_RASTERIZER, cso); 579 if (cso_hash_iter_is_null(iter)) { 580 FREE(cso); 581 return PIPE_ERROR_OUT_OF_MEMORY; 582 } 583 584 handle = cso->data; 585 } 586 else { 587 handle = ((struct cso_rasterizer *)cso_hash_iter_data(iter))->data; 588 } 589 590 if (ctx->rasterizer != handle) { 591 ctx->rasterizer = handle; 592 ctx->pipe->bind_rasterizer_state(ctx->pipe, handle); 593 } 594 return PIPE_OK; 595} 596 597void cso_save_rasterizer(struct cso_context *ctx) 598{ 599 assert(!ctx->rasterizer_saved); 600 ctx->rasterizer_saved = ctx->rasterizer; 601} 602 603void cso_restore_rasterizer(struct cso_context *ctx) 604{ 605 if (ctx->rasterizer != ctx->rasterizer_saved) { 606 ctx->rasterizer = ctx->rasterizer_saved; 607 ctx->pipe->bind_rasterizer_state(ctx->pipe, ctx->rasterizer_saved); 608 } 609 ctx->rasterizer_saved = NULL; 610} 611 612 613 614enum pipe_error cso_set_fragment_shader_handle(struct cso_context *ctx, 615 void *handle ) 616{ 617 if (ctx->fragment_shader != handle) { 618 ctx->fragment_shader = handle; 619 ctx->pipe->bind_fs_state(ctx->pipe, handle); 620 } 621 return PIPE_OK; 622} 623 624void cso_delete_fragment_shader(struct cso_context *ctx, void *handle ) 625{ 626 if (handle == ctx->fragment_shader) { 627 /* unbind before deleting */ 628 ctx->pipe->bind_fs_state(ctx->pipe, NULL); 629 ctx->fragment_shader = NULL; 630 } 631 ctx->pipe->delete_fs_state(ctx->pipe, handle); 632} 633 634/* Not really working: 635 */ 636#if 0 637enum pipe_error cso_set_fragment_shader(struct cso_context *ctx, 638 const struct pipe_shader_state *templ) 639{ 640 const struct tgsi_token *tokens = templ->tokens; 641 unsigned num_tokens = tgsi_num_tokens(tokens); 642 size_t tokens_size = num_tokens*sizeof(struct tgsi_token); 643 unsigned hash_key = cso_construct_key((void*)tokens, tokens_size); 644 struct cso_hash_iter iter = cso_find_state_template(ctx->cache, 645 hash_key, 646 CSO_FRAGMENT_SHADER, 647 (void*)tokens); 648 void *handle = NULL; 649 650 if (cso_hash_iter_is_null(iter)) { 651 struct cso_fragment_shader *cso = MALLOC(sizeof(struct cso_fragment_shader) + tokens_size); 652 struct tgsi_token *cso_tokens = (struct tgsi_token *)((char *)cso + sizeof(*cso)); 653 654 if (!cso) 655 return PIPE_ERROR_OUT_OF_MEMORY; 656 657 memcpy(cso_tokens, tokens, tokens_size); 658 cso->state.tokens = cso_tokens; 659 cso->data = ctx->pipe->create_fs_state(ctx->pipe, &cso->state); 660 cso->delete_state = (cso_state_callback)ctx->pipe->delete_fs_state; 661 cso->context = ctx->pipe; 662 663 iter = cso_insert_state(ctx->cache, hash_key, CSO_FRAGMENT_SHADER, cso); 664 if (cso_hash_iter_is_null(iter)) { 665 FREE(cso); 666 return PIPE_ERROR_OUT_OF_MEMORY; 667 } 668 669 handle = cso->data; 670 } 671 else { 672 handle = ((struct cso_fragment_shader *)cso_hash_iter_data(iter))->data; 673 } 674 675 return cso_set_fragment_shader_handle( ctx, handle ); 676} 677#endif 678 679void cso_save_fragment_shader(struct cso_context *ctx) 680{ 681 assert(!ctx->fragment_shader_saved); 682 ctx->fragment_shader_saved = ctx->fragment_shader; 683} 684 685void cso_restore_fragment_shader(struct cso_context *ctx) 686{ 687 if (ctx->fragment_shader_saved != ctx->fragment_shader) { 688 ctx->pipe->bind_fs_state(ctx->pipe, ctx->fragment_shader_saved); 689 ctx->fragment_shader = ctx->fragment_shader_saved; 690 } 691 ctx->fragment_shader_saved = NULL; 692} 693 694 695enum pipe_error cso_set_vertex_shader_handle(struct cso_context *ctx, 696 void *handle ) 697{ 698 if (ctx->vertex_shader != handle) { 699 ctx->vertex_shader = handle; 700 ctx->pipe->bind_vs_state(ctx->pipe, handle); 701 } 702 return PIPE_OK; 703} 704 705void cso_delete_vertex_shader(struct cso_context *ctx, void *handle ) 706{ 707 if (handle == ctx->vertex_shader) { 708 /* unbind before deleting */ 709 ctx->pipe->bind_vs_state(ctx->pipe, NULL); 710 ctx->vertex_shader = NULL; 711 } 712 ctx->pipe->delete_vs_state(ctx->pipe, handle); 713} 714 715 716/* Not really working: 717 */ 718#if 0 719enum pipe_error cso_set_vertex_shader(struct cso_context *ctx, 720 const struct pipe_shader_state *templ) 721{ 722 unsigned hash_key = cso_construct_key((void*)templ, 723 sizeof(struct pipe_shader_state)); 724 struct cso_hash_iter iter = cso_find_state_template(ctx->cache, 725 hash_key, CSO_VERTEX_SHADER, 726 (void*)templ); 727 void *handle = NULL; 728 729 if (cso_hash_iter_is_null(iter)) { 730 struct cso_vertex_shader *cso = MALLOC(sizeof(struct cso_vertex_shader)); 731 732 if (!cso) 733 return PIPE_ERROR_OUT_OF_MEMORY; 734 735 memcpy(cso->state, templ, sizeof(*templ)); 736 cso->data = ctx->pipe->create_vs_state(ctx->pipe, &cso->state); 737 cso->delete_state = (cso_state_callback)ctx->pipe->delete_vs_state; 738 cso->context = ctx->pipe; 739 740 iter = cso_insert_state(ctx->cache, hash_key, CSO_VERTEX_SHADER, cso); 741 if (cso_hash_iter_is_null(iter)) { 742 FREE(cso); 743 return PIPE_ERROR_OUT_OF_MEMORY; 744 } 745 746 handle = cso->data; 747 } 748 else { 749 handle = ((struct cso_vertex_shader *)cso_hash_iter_data(iter))->data; 750 } 751 752 return cso_set_vertex_shader_handle( ctx, handle ); 753} 754#endif 755 756 757 758void cso_save_vertex_shader(struct cso_context *ctx) 759{ 760 assert(!ctx->vertex_shader_saved); 761 ctx->vertex_shader_saved = ctx->vertex_shader; 762} 763 764void cso_restore_vertex_shader(struct cso_context *ctx) 765{ 766 if (ctx->vertex_shader_saved != ctx->vertex_shader) { 767 ctx->pipe->bind_vs_state(ctx->pipe, ctx->vertex_shader_saved); 768 ctx->vertex_shader = ctx->vertex_shader_saved; 769 } 770 ctx->vertex_shader_saved = NULL; 771} 772 773 774/** 775 * Copy framebuffer state from src to dst with refcounting of surfaces. 776 */ 777static void 778copy_framebuffer_state(struct pipe_framebuffer_state *dst, 779 const struct pipe_framebuffer_state *src) 780{ 781 uint i; 782 783 dst->width = src->width; 784 dst->height = src->height; 785 dst->nr_cbufs = src->nr_cbufs; 786 for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) { 787 pipe_surface_reference(&dst->cbufs[i], src->cbufs[i]); 788 } 789 pipe_surface_reference(&dst->zsbuf, src->zsbuf); 790} 791 792 793static void 794free_framebuffer_state(struct pipe_framebuffer_state *fb) 795{ 796 uint i; 797 798 for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) { 799 pipe_surface_reference(&fb->cbufs[i], NULL); 800 } 801 pipe_surface_reference(&fb->zsbuf, NULL); 802} 803 804 805enum pipe_error cso_set_framebuffer(struct cso_context *ctx, 806 const struct pipe_framebuffer_state *fb) 807{ 808 if (memcmp(&ctx->fb, fb, sizeof(*fb)) != 0) { 809 copy_framebuffer_state(&ctx->fb, fb); 810 ctx->pipe->set_framebuffer_state(ctx->pipe, fb); 811 } 812 return PIPE_OK; 813} 814 815void cso_save_framebuffer(struct cso_context *ctx) 816{ 817 copy_framebuffer_state(&ctx->fb_saved, &ctx->fb); 818} 819 820void cso_restore_framebuffer(struct cso_context *ctx) 821{ 822 if (memcmp(&ctx->fb, &ctx->fb_saved, sizeof(ctx->fb))) { 823 copy_framebuffer_state(&ctx->fb, &ctx->fb_saved); 824 ctx->pipe->set_framebuffer_state(ctx->pipe, &ctx->fb); 825 free_framebuffer_state(&ctx->fb_saved); 826 } 827} 828 829 830enum pipe_error cso_set_viewport(struct cso_context *ctx, 831 const struct pipe_viewport_state *vp) 832{ 833 if (memcmp(&ctx->vp, vp, sizeof(*vp))) { 834 ctx->vp = *vp; 835 ctx->pipe->set_viewport_state(ctx->pipe, vp); 836 } 837 return PIPE_OK; 838} 839 840void cso_save_viewport(struct cso_context *ctx) 841{ 842 ctx->vp_saved = ctx->vp; 843} 844 845 846void cso_restore_viewport(struct cso_context *ctx) 847{ 848 if (memcmp(&ctx->vp, &ctx->vp_saved, sizeof(ctx->vp))) { 849 ctx->vp = ctx->vp_saved; 850 ctx->pipe->set_viewport_state(ctx->pipe, &ctx->vp); 851 } 852} 853 854 855 856 857enum pipe_error cso_set_blend_color(struct cso_context *ctx, 858 const struct pipe_blend_color *bc) 859{ 860 if (memcmp(&ctx->blend_color, bc, sizeof(ctx->blend_color))) { 861 ctx->blend_color = *bc; 862 ctx->pipe->set_blend_color(ctx->pipe, bc); 863 } 864 return PIPE_OK; 865} 866