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