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