Merge remote branch 'origin/master' into gallium_draw_llvm
[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_inlines.h"
40 #include "util/u_memory.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 #include "cso_context.h"
47
48 struct cso_context {
49 struct pipe_context *pipe;
50 struct cso_cache *cache;
51
52 struct {
53 void *samplers[PIPE_MAX_SAMPLERS];
54 unsigned nr_samplers;
55
56 void *vertex_samplers[PIPE_MAX_VERTEX_SAMPLERS];
57 unsigned nr_vertex_samplers;
58 } hw;
59
60 void *samplers[PIPE_MAX_SAMPLERS];
61 unsigned nr_samplers;
62
63 void *vertex_samplers[PIPE_MAX_VERTEX_SAMPLERS];
64 unsigned nr_vertex_samplers;
65
66 unsigned nr_samplers_saved;
67 void *samplers_saved[PIPE_MAX_SAMPLERS];
68
69 unsigned nr_vertex_samplers_saved;
70 void *vertex_samplers_saved[PIPE_MAX_VERTEX_SAMPLERS];
71
72 struct pipe_texture *textures[PIPE_MAX_SAMPLERS];
73 uint nr_textures;
74
75 struct pipe_texture *vertex_textures[PIPE_MAX_VERTEX_SAMPLERS];
76 uint nr_vertex_textures;
77
78 uint nr_textures_saved;
79 struct pipe_texture *textures_saved[PIPE_MAX_SAMPLERS];
80
81 uint nr_vertex_textures_saved;
82 struct pipe_texture *vertex_textures_saved[PIPE_MAX_SAMPLERS];
83
84 /** Current and saved state.
85 * The saved state is used as a 1-deep stack.
86 */
87 void *blend, *blend_saved;
88 void *depth_stencil, *depth_stencil_saved;
89 void *rasterizer, *rasterizer_saved;
90 void *fragment_shader, *fragment_shader_saved, *geometry_shader;
91 void *vertex_shader, *vertex_shader_saved, *geometry_shader_saved;
92 void *velements, *velements_saved;
93
94 struct pipe_clip_state clip;
95 struct pipe_clip_state clip_saved;
96
97 struct pipe_framebuffer_state fb, fb_saved;
98 struct pipe_viewport_state vp, vp_saved;
99 struct pipe_blend_color blend_color;
100 struct pipe_stencil_ref stencil_ref, stencil_ref_saved;
101 };
102
103
104 static void
105 free_framebuffer_state(struct pipe_framebuffer_state *fb);
106
107
108 static boolean delete_blend_state(struct cso_context *ctx, void *state)
109 {
110 struct cso_blend *cso = (struct cso_blend *)state;
111
112 if (ctx->blend == cso->data)
113 return FALSE;
114
115 if (cso->delete_state)
116 cso->delete_state(cso->context, cso->data);
117 FREE(state);
118 return TRUE;
119 }
120
121 static boolean delete_depth_stencil_state(struct cso_context *ctx, void *state)
122 {
123 struct cso_depth_stencil_alpha *cso = (struct cso_depth_stencil_alpha *)state;
124
125 if (ctx->depth_stencil == cso->data)
126 return FALSE;
127
128 if (cso->delete_state)
129 cso->delete_state(cso->context, cso->data);
130 FREE(state);
131
132 return TRUE;
133 }
134
135 static boolean delete_sampler_state(struct cso_context *ctx, void *state)
136 {
137 struct cso_sampler *cso = (struct cso_sampler *)state;
138 if (cso->delete_state)
139 cso->delete_state(cso->context, cso->data);
140 FREE(state);
141 return TRUE;
142 }
143
144 static boolean delete_rasterizer_state(struct cso_context *ctx, void *state)
145 {
146 struct cso_rasterizer *cso = (struct cso_rasterizer *)state;
147
148 if (ctx->rasterizer == cso->data)
149 return FALSE;
150 if (cso->delete_state)
151 cso->delete_state(cso->context, cso->data);
152 FREE(state);
153 return TRUE;
154 }
155
156 static boolean delete_fs_state(struct cso_context *ctx, void *state)
157 {
158 struct cso_fragment_shader *cso = (struct cso_fragment_shader *)state;
159 if (ctx->fragment_shader == cso->data)
160 return FALSE;
161 if (cso->delete_state)
162 cso->delete_state(cso->context, cso->data);
163 FREE(state);
164 return TRUE;
165 }
166
167 static boolean delete_vs_state(struct cso_context *ctx, void *state)
168 {
169 struct cso_vertex_shader *cso = (struct cso_vertex_shader *)state;
170 if (ctx->vertex_shader == cso->data)
171 return TRUE;
172 if (cso->delete_state)
173 cso->delete_state(cso->context, cso->data);
174 FREE(state);
175 return FALSE;
176 }
177
178 static boolean delete_vertex_elements(struct cso_context *ctx,
179 void *state)
180 {
181 struct cso_velements *cso = (struct cso_velements *)state;
182
183 if (ctx->velements == cso->data)
184 return FALSE;
185
186 if (cso->delete_state)
187 cso->delete_state(cso->context, cso->data);
188 FREE(state);
189 return TRUE;
190 }
191
192
193 static INLINE boolean delete_cso(struct cso_context *ctx,
194 void *state, enum cso_cache_type type)
195 {
196 switch (type) {
197 case CSO_BLEND:
198 return delete_blend_state(ctx, state);
199 break;
200 case CSO_SAMPLER:
201 return delete_sampler_state(ctx, state);
202 break;
203 case CSO_DEPTH_STENCIL_ALPHA:
204 return delete_depth_stencil_state(ctx, state);
205 break;
206 case CSO_RASTERIZER:
207 return delete_rasterizer_state(ctx, state);
208 break;
209 case CSO_FRAGMENT_SHADER:
210 return delete_fs_state(ctx, state);
211 break;
212 case CSO_VERTEX_SHADER:
213 return delete_vs_state(ctx, state);
214 break;
215 case CSO_VELEMENTS:
216 return delete_vertex_elements(ctx, state);
217 break;
218 default:
219 assert(0);
220 FREE(state);
221 }
222 return FALSE;
223 }
224
225 static INLINE void sanitize_hash(struct cso_hash *hash, enum cso_cache_type type,
226 int max_size, void *user_data)
227 {
228 struct cso_context *ctx = (struct cso_context *)user_data;
229 /* if we're approach the maximum size, remove fourth of the entries
230 * otherwise every subsequent call will go through the same */
231 int hash_size = cso_hash_size(hash);
232 int max_entries = (max_size > hash_size) ? max_size : hash_size;
233 int to_remove = (max_size < max_entries) * max_entries/4;
234 struct cso_hash_iter iter = cso_hash_first_node(hash);
235 if (hash_size > max_size)
236 to_remove += hash_size - max_size;
237 while (to_remove) {
238 /*remove elements until we're good */
239 /*fixme: currently we pick the nodes to remove at random*/
240 void *cso = cso_hash_iter_data(iter);
241 if (delete_cso(ctx, cso, type)) {
242 iter = cso_hash_erase(hash, iter);
243 --to_remove;
244 } else
245 iter = cso_hash_iter_next(iter);
246 }
247 }
248
249
250 struct cso_context *cso_create_context( struct pipe_context *pipe )
251 {
252 struct cso_context *ctx = CALLOC_STRUCT(cso_context);
253 if (ctx == NULL)
254 goto out;
255
256 ctx->cache = cso_cache_create();
257 if (ctx->cache == NULL)
258 goto out;
259 cso_cache_set_sanitize_callback(ctx->cache,
260 sanitize_hash,
261 ctx);
262
263 ctx->pipe = pipe;
264
265 /* Enable for testing: */
266 if (0) cso_set_maximum_cache_size( ctx->cache, 4 );
267
268 return ctx;
269
270 out:
271 cso_destroy_context( ctx );
272 return NULL;
273 }
274
275
276 /**
277 * Prior to context destruction, this function unbinds all state objects.
278 */
279 void cso_release_all( struct cso_context *ctx )
280 {
281 unsigned i;
282
283 if (ctx->pipe) {
284 ctx->pipe->bind_blend_state( ctx->pipe, NULL );
285 ctx->pipe->bind_rasterizer_state( ctx->pipe, NULL );
286 ctx->pipe->bind_fragment_sampler_states( ctx->pipe, 0, NULL );
287 if (ctx->pipe->bind_vertex_sampler_states)
288 ctx->pipe->bind_vertex_sampler_states(ctx->pipe, 0, NULL);
289 ctx->pipe->bind_depth_stencil_alpha_state( ctx->pipe, NULL );
290 ctx->pipe->bind_fs_state( ctx->pipe, NULL );
291 ctx->pipe->bind_vs_state( ctx->pipe, NULL );
292 ctx->pipe->bind_vertex_elements_state( ctx->pipe, NULL );
293 }
294
295 for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
296 pipe_texture_reference(&ctx->textures[i], NULL);
297 pipe_texture_reference(&ctx->textures_saved[i], NULL);
298 }
299
300 for (i = 0; i < PIPE_MAX_VERTEX_SAMPLERS; i++) {
301 pipe_texture_reference(&ctx->vertex_textures[i], NULL);
302 pipe_texture_reference(&ctx->vertex_textures_saved[i], NULL);
303 }
304
305 free_framebuffer_state(&ctx->fb);
306 free_framebuffer_state(&ctx->fb_saved);
307
308 if (ctx->cache) {
309 cso_cache_delete( ctx->cache );
310 ctx->cache = NULL;
311 }
312 }
313
314
315 void cso_destroy_context( struct cso_context *ctx )
316 {
317 if (ctx) {
318 /*cso_release_all( ctx );*/
319 FREE( ctx );
320 }
321 }
322
323
324 /* Those function will either find the state of the given template
325 * in the cache or they will create a new state from the given
326 * template, insert it in the cache and return it.
327 */
328
329 /*
330 * If the driver returns 0 from the create method then they will assign
331 * the data member of the cso to be the template itself.
332 */
333
334 enum pipe_error cso_set_blend(struct cso_context *ctx,
335 const struct pipe_blend_state *templ)
336 {
337 unsigned key_size, hash_key;
338 struct cso_hash_iter iter;
339 void *handle;
340
341 key_size = templ->independent_blend_enable ? sizeof(struct pipe_blend_state) :
342 (char *)&(templ->rt[1]) - (char *)templ;
343 hash_key = cso_construct_key((void*)templ, key_size);
344 iter = cso_find_state_template(ctx->cache, hash_key, CSO_BLEND, (void*)templ, key_size);
345
346 if (cso_hash_iter_is_null(iter)) {
347 struct cso_blend *cso = MALLOC(sizeof(struct cso_blend));
348 if (!cso)
349 return PIPE_ERROR_OUT_OF_MEMORY;
350
351 memcpy(&cso->state, templ, key_size);
352 cso->data = ctx->pipe->create_blend_state(ctx->pipe, &cso->state);
353 cso->delete_state = (cso_state_callback)ctx->pipe->delete_blend_state;
354 cso->context = ctx->pipe;
355
356 iter = cso_insert_state(ctx->cache, hash_key, CSO_BLEND, cso);
357 if (cso_hash_iter_is_null(iter)) {
358 FREE(cso);
359 return PIPE_ERROR_OUT_OF_MEMORY;
360 }
361
362 handle = cso->data;
363 }
364 else {
365 handle = ((struct cso_blend *)cso_hash_iter_data(iter))->data;
366 }
367
368 if (ctx->blend != handle) {
369 ctx->blend = handle;
370 ctx->pipe->bind_blend_state(ctx->pipe, handle);
371 }
372 return PIPE_OK;
373 }
374
375 void cso_save_blend(struct cso_context *ctx)
376 {
377 assert(!ctx->blend_saved);
378 ctx->blend_saved = ctx->blend;
379 }
380
381 void cso_restore_blend(struct cso_context *ctx)
382 {
383 if (ctx->blend != ctx->blend_saved) {
384 ctx->blend = ctx->blend_saved;
385 ctx->pipe->bind_blend_state(ctx->pipe, ctx->blend_saved);
386 }
387 ctx->blend_saved = NULL;
388 }
389
390
391
392 enum pipe_error cso_single_sampler(struct cso_context *ctx,
393 unsigned idx,
394 const struct pipe_sampler_state *templ)
395 {
396 void *handle = NULL;
397
398 if (templ != NULL) {
399 unsigned key_size = sizeof(struct pipe_sampler_state);
400 unsigned hash_key = cso_construct_key((void*)templ, key_size);
401 struct cso_hash_iter iter = cso_find_state_template(ctx->cache,
402 hash_key, CSO_SAMPLER,
403 (void*)templ, key_size);
404
405 if (cso_hash_iter_is_null(iter)) {
406 struct cso_sampler *cso = MALLOC(sizeof(struct cso_sampler));
407 if (!cso)
408 return PIPE_ERROR_OUT_OF_MEMORY;
409
410 memcpy(&cso->state, templ, sizeof(*templ));
411 cso->data = ctx->pipe->create_sampler_state(ctx->pipe, &cso->state);
412 cso->delete_state = (cso_state_callback)ctx->pipe->delete_sampler_state;
413 cso->context = ctx->pipe;
414
415 iter = cso_insert_state(ctx->cache, hash_key, CSO_SAMPLER, cso);
416 if (cso_hash_iter_is_null(iter)) {
417 FREE(cso);
418 return PIPE_ERROR_OUT_OF_MEMORY;
419 }
420
421 handle = cso->data;
422 }
423 else {
424 handle = ((struct cso_sampler *)cso_hash_iter_data(iter))->data;
425 }
426 }
427
428 ctx->samplers[idx] = handle;
429 return PIPE_OK;
430 }
431
432 enum pipe_error
433 cso_single_vertex_sampler(struct cso_context *ctx,
434 unsigned idx,
435 const struct pipe_sampler_state *templ)
436 {
437 void *handle = NULL;
438
439 if (templ != NULL) {
440 unsigned key_size = sizeof(struct pipe_sampler_state);
441 unsigned hash_key = cso_construct_key((void*)templ, key_size);
442 struct cso_hash_iter iter = cso_find_state_template(ctx->cache,
443 hash_key, CSO_SAMPLER,
444 (void*)templ, key_size);
445
446 if (cso_hash_iter_is_null(iter)) {
447 struct cso_sampler *cso = MALLOC(sizeof(struct cso_sampler));
448 if (!cso)
449 return PIPE_ERROR_OUT_OF_MEMORY;
450
451 memcpy(&cso->state, templ, sizeof(*templ));
452 cso->data = ctx->pipe->create_sampler_state(ctx->pipe, &cso->state);
453 cso->delete_state = (cso_state_callback)ctx->pipe->delete_sampler_state;
454 cso->context = ctx->pipe;
455
456 iter = cso_insert_state(ctx->cache, hash_key, CSO_SAMPLER, cso);
457 if (cso_hash_iter_is_null(iter)) {
458 FREE(cso);
459 return PIPE_ERROR_OUT_OF_MEMORY;
460 }
461
462 handle = cso->data;
463 }
464 else {
465 handle = ((struct cso_sampler *)cso_hash_iter_data(iter))->data;
466 }
467 }
468
469 ctx->vertex_samplers[idx] = handle;
470 return PIPE_OK;
471 }
472
473 void cso_single_sampler_done( struct cso_context *ctx )
474 {
475 unsigned i;
476
477 /* find highest non-null sampler */
478 for (i = PIPE_MAX_SAMPLERS; i > 0; i--) {
479 if (ctx->samplers[i - 1] != NULL)
480 break;
481 }
482
483 ctx->nr_samplers = i;
484
485 if (ctx->hw.nr_samplers != ctx->nr_samplers ||
486 memcmp(ctx->hw.samplers,
487 ctx->samplers,
488 ctx->nr_samplers * sizeof(void *)) != 0)
489 {
490 memcpy(ctx->hw.samplers, ctx->samplers, ctx->nr_samplers * sizeof(void *));
491 ctx->hw.nr_samplers = ctx->nr_samplers;
492
493 ctx->pipe->bind_fragment_sampler_states(ctx->pipe, ctx->nr_samplers, ctx->samplers);
494 }
495 }
496
497 void
498 cso_single_vertex_sampler_done(struct cso_context *ctx)
499 {
500 unsigned i;
501
502 /* find highest non-null sampler */
503 for (i = PIPE_MAX_VERTEX_SAMPLERS; i > 0; i--) {
504 if (ctx->vertex_samplers[i - 1] != NULL)
505 break;
506 }
507
508 ctx->nr_vertex_samplers = i;
509
510 if (ctx->hw.nr_vertex_samplers != ctx->nr_vertex_samplers ||
511 memcmp(ctx->hw.vertex_samplers,
512 ctx->vertex_samplers,
513 ctx->nr_vertex_samplers * sizeof(void *)) != 0)
514 {
515 memcpy(ctx->hw.vertex_samplers,
516 ctx->vertex_samplers,
517 ctx->nr_vertex_samplers * sizeof(void *));
518 ctx->hw.nr_vertex_samplers = ctx->nr_vertex_samplers;
519
520 ctx->pipe->bind_vertex_sampler_states(ctx->pipe,
521 ctx->nr_vertex_samplers,
522 ctx->vertex_samplers);
523 }
524 }
525
526 /*
527 * If the function encouters any errors it will return the
528 * last one. Done to always try to set as many samplers
529 * as possible.
530 */
531 enum pipe_error cso_set_samplers( struct cso_context *ctx,
532 unsigned nr,
533 const struct pipe_sampler_state **templates )
534 {
535 unsigned i;
536 enum pipe_error temp, error = PIPE_OK;
537
538 /* TODO: fastpath
539 */
540
541 for (i = 0; i < nr; i++) {
542 temp = cso_single_sampler( ctx, i, templates[i] );
543 if (temp != PIPE_OK)
544 error = temp;
545 }
546
547 for ( ; i < ctx->nr_samplers; i++) {
548 temp = cso_single_sampler( ctx, i, NULL );
549 if (temp != PIPE_OK)
550 error = temp;
551 }
552
553 cso_single_sampler_done( ctx );
554
555 return error;
556 }
557
558 void cso_save_samplers(struct cso_context *ctx)
559 {
560 ctx->nr_samplers_saved = ctx->nr_samplers;
561 memcpy(ctx->samplers_saved, ctx->samplers, sizeof(ctx->samplers));
562 }
563
564 void cso_restore_samplers(struct cso_context *ctx)
565 {
566 ctx->nr_samplers = ctx->nr_samplers_saved;
567 memcpy(ctx->samplers, ctx->samplers_saved, sizeof(ctx->samplers));
568 cso_single_sampler_done( ctx );
569 }
570
571 /*
572 * If the function encouters any errors it will return the
573 * last one. Done to always try to set as many samplers
574 * as possible.
575 */
576 enum pipe_error cso_set_vertex_samplers(struct cso_context *ctx,
577 unsigned nr,
578 const struct pipe_sampler_state **templates)
579 {
580 unsigned i;
581 enum pipe_error temp, error = PIPE_OK;
582
583 /* TODO: fastpath
584 */
585
586 for (i = 0; i < nr; i++) {
587 temp = cso_single_vertex_sampler( ctx, i, templates[i] );
588 if (temp != PIPE_OK)
589 error = temp;
590 }
591
592 for ( ; i < ctx->nr_samplers; i++) {
593 temp = cso_single_vertex_sampler( ctx, i, NULL );
594 if (temp != PIPE_OK)
595 error = temp;
596 }
597
598 cso_single_vertex_sampler_done( ctx );
599
600 return error;
601 }
602
603 void
604 cso_save_vertex_samplers(struct cso_context *ctx)
605 {
606 ctx->nr_vertex_samplers_saved = ctx->nr_vertex_samplers;
607 memcpy(ctx->vertex_samplers_saved, ctx->vertex_samplers, sizeof(ctx->vertex_samplers));
608 }
609
610 void
611 cso_restore_vertex_samplers(struct cso_context *ctx)
612 {
613 ctx->nr_vertex_samplers = ctx->nr_vertex_samplers_saved;
614 memcpy(ctx->vertex_samplers, ctx->vertex_samplers_saved, sizeof(ctx->vertex_samplers));
615 cso_single_vertex_sampler_done(ctx);
616 }
617
618
619 enum pipe_error cso_set_sampler_textures( struct cso_context *ctx,
620 uint count,
621 struct pipe_texture **textures )
622 {
623 uint i;
624
625 ctx->nr_textures = count;
626
627 for (i = 0; i < count; i++)
628 pipe_texture_reference(&ctx->textures[i], textures[i]);
629 for ( ; i < PIPE_MAX_SAMPLERS; i++)
630 pipe_texture_reference(&ctx->textures[i], NULL);
631
632 ctx->pipe->set_fragment_sampler_textures(ctx->pipe, count, textures);
633
634 return PIPE_OK;
635 }
636
637 void cso_save_sampler_textures( struct cso_context *ctx )
638 {
639 uint i;
640
641 ctx->nr_textures_saved = ctx->nr_textures;
642 for (i = 0; i < ctx->nr_textures; i++) {
643 assert(!ctx->textures_saved[i]);
644 pipe_texture_reference(&ctx->textures_saved[i], ctx->textures[i]);
645 }
646 }
647
648 void cso_restore_sampler_textures( struct cso_context *ctx )
649 {
650 uint i;
651
652 ctx->nr_textures = ctx->nr_textures_saved;
653
654 for (i = 0; i < ctx->nr_textures; i++) {
655 pipe_texture_reference(&ctx->textures[i], NULL);
656 ctx->textures[i] = ctx->textures_saved[i];
657 ctx->textures_saved[i] = NULL;
658 }
659 for ( ; i < PIPE_MAX_SAMPLERS; i++)
660 pipe_texture_reference(&ctx->textures[i], NULL);
661
662 ctx->pipe->set_fragment_sampler_textures(ctx->pipe, ctx->nr_textures, ctx->textures);
663
664 ctx->nr_textures_saved = 0;
665 }
666
667
668
669 enum pipe_error
670 cso_set_vertex_sampler_textures(struct cso_context *ctx,
671 uint count,
672 struct pipe_texture **textures)
673 {
674 uint i;
675
676 ctx->nr_vertex_textures = count;
677
678 for (i = 0; i < count; i++) {
679 pipe_texture_reference(&ctx->vertex_textures[i], textures[i]);
680 }
681 for ( ; i < PIPE_MAX_VERTEX_SAMPLERS; i++) {
682 pipe_texture_reference(&ctx->vertex_textures[i], NULL);
683 }
684
685 ctx->pipe->set_vertex_sampler_textures(ctx->pipe, count, textures);
686
687 return PIPE_OK;
688 }
689
690 void
691 cso_save_vertex_sampler_textures(struct cso_context *ctx)
692 {
693 uint i;
694
695 ctx->nr_vertex_textures_saved = ctx->nr_vertex_textures;
696 for (i = 0; i < ctx->nr_vertex_textures; i++) {
697 assert(!ctx->vertex_textures_saved[i]);
698 pipe_texture_reference(&ctx->vertex_textures_saved[i], ctx->vertex_textures[i]);
699 }
700 }
701
702 void
703 cso_restore_vertex_sampler_textures(struct cso_context *ctx)
704 {
705 uint i;
706
707 ctx->nr_vertex_textures = ctx->nr_vertex_textures_saved;
708
709 for (i = 0; i < ctx->nr_vertex_textures; i++) {
710 pipe_texture_reference(&ctx->vertex_textures[i], NULL);
711 ctx->vertex_textures[i] = ctx->vertex_textures_saved[i];
712 ctx->vertex_textures_saved[i] = NULL;
713 }
714 for ( ; i < PIPE_MAX_VERTEX_SAMPLERS; i++) {
715 pipe_texture_reference(&ctx->vertex_textures[i], NULL);
716 }
717
718 ctx->pipe->set_vertex_sampler_textures(ctx->pipe,
719 ctx->nr_vertex_textures,
720 ctx->vertex_textures);
721
722 ctx->nr_vertex_textures_saved = 0;
723 }
724
725
726
727 enum pipe_error cso_set_depth_stencil_alpha(struct cso_context *ctx,
728 const struct pipe_depth_stencil_alpha_state *templ)
729 {
730 unsigned key_size = sizeof(struct pipe_depth_stencil_alpha_state);
731 unsigned hash_key = cso_construct_key((void*)templ, key_size);
732 struct cso_hash_iter iter = cso_find_state_template(ctx->cache,
733 hash_key,
734 CSO_DEPTH_STENCIL_ALPHA,
735 (void*)templ, key_size);
736 void *handle;
737
738 if (cso_hash_iter_is_null(iter)) {
739 struct cso_depth_stencil_alpha *cso = MALLOC(sizeof(struct cso_depth_stencil_alpha));
740 if (!cso)
741 return PIPE_ERROR_OUT_OF_MEMORY;
742
743 memcpy(&cso->state, templ, sizeof(*templ));
744 cso->data = ctx->pipe->create_depth_stencil_alpha_state(ctx->pipe, &cso->state);
745 cso->delete_state = (cso_state_callback)ctx->pipe->delete_depth_stencil_alpha_state;
746 cso->context = ctx->pipe;
747
748 iter = cso_insert_state(ctx->cache, hash_key, CSO_DEPTH_STENCIL_ALPHA, cso);
749 if (cso_hash_iter_is_null(iter)) {
750 FREE(cso);
751 return PIPE_ERROR_OUT_OF_MEMORY;
752 }
753
754 handle = cso->data;
755 }
756 else {
757 handle = ((struct cso_depth_stencil_alpha *)cso_hash_iter_data(iter))->data;
758 }
759
760 if (ctx->depth_stencil != handle) {
761 ctx->depth_stencil = handle;
762 ctx->pipe->bind_depth_stencil_alpha_state(ctx->pipe, handle);
763 }
764 return PIPE_OK;
765 }
766
767 void cso_save_depth_stencil_alpha(struct cso_context *ctx)
768 {
769 assert(!ctx->depth_stencil_saved);
770 ctx->depth_stencil_saved = ctx->depth_stencil;
771 }
772
773 void cso_restore_depth_stencil_alpha(struct cso_context *ctx)
774 {
775 if (ctx->depth_stencil != ctx->depth_stencil_saved) {
776 ctx->depth_stencil = ctx->depth_stencil_saved;
777 ctx->pipe->bind_depth_stencil_alpha_state(ctx->pipe, ctx->depth_stencil_saved);
778 }
779 ctx->depth_stencil_saved = NULL;
780 }
781
782
783
784 enum pipe_error cso_set_rasterizer(struct cso_context *ctx,
785 const struct pipe_rasterizer_state *templ)
786 {
787 unsigned key_size = sizeof(struct pipe_rasterizer_state);
788 unsigned hash_key = cso_construct_key((void*)templ, key_size);
789 struct cso_hash_iter iter = cso_find_state_template(ctx->cache,
790 hash_key, CSO_RASTERIZER,
791 (void*)templ, key_size);
792 void *handle = NULL;
793
794 if (cso_hash_iter_is_null(iter)) {
795 struct cso_rasterizer *cso = MALLOC(sizeof(struct cso_rasterizer));
796 if (!cso)
797 return PIPE_ERROR_OUT_OF_MEMORY;
798
799 memcpy(&cso->state, templ, sizeof(*templ));
800 cso->data = ctx->pipe->create_rasterizer_state(ctx->pipe, &cso->state);
801 cso->delete_state = (cso_state_callback)ctx->pipe->delete_rasterizer_state;
802 cso->context = ctx->pipe;
803
804 iter = cso_insert_state(ctx->cache, hash_key, CSO_RASTERIZER, cso);
805 if (cso_hash_iter_is_null(iter)) {
806 FREE(cso);
807 return PIPE_ERROR_OUT_OF_MEMORY;
808 }
809
810 handle = cso->data;
811 }
812 else {
813 handle = ((struct cso_rasterizer *)cso_hash_iter_data(iter))->data;
814 }
815
816 if (ctx->rasterizer != handle) {
817 ctx->rasterizer = handle;
818 ctx->pipe->bind_rasterizer_state(ctx->pipe, handle);
819 }
820 return PIPE_OK;
821 }
822
823 void cso_save_rasterizer(struct cso_context *ctx)
824 {
825 assert(!ctx->rasterizer_saved);
826 ctx->rasterizer_saved = ctx->rasterizer;
827 }
828
829 void cso_restore_rasterizer(struct cso_context *ctx)
830 {
831 if (ctx->rasterizer != ctx->rasterizer_saved) {
832 ctx->rasterizer = ctx->rasterizer_saved;
833 ctx->pipe->bind_rasterizer_state(ctx->pipe, ctx->rasterizer_saved);
834 }
835 ctx->rasterizer_saved = NULL;
836 }
837
838
839
840 enum pipe_error cso_set_fragment_shader_handle(struct cso_context *ctx,
841 void *handle )
842 {
843 if (ctx->fragment_shader != handle) {
844 ctx->fragment_shader = handle;
845 ctx->pipe->bind_fs_state(ctx->pipe, handle);
846 }
847 return PIPE_OK;
848 }
849
850 void cso_delete_fragment_shader(struct cso_context *ctx, void *handle )
851 {
852 if (handle == ctx->fragment_shader) {
853 /* unbind before deleting */
854 ctx->pipe->bind_fs_state(ctx->pipe, NULL);
855 ctx->fragment_shader = NULL;
856 }
857 ctx->pipe->delete_fs_state(ctx->pipe, handle);
858 }
859
860 /* Not really working:
861 */
862 #if 0
863 enum pipe_error cso_set_fragment_shader(struct cso_context *ctx,
864 const struct pipe_shader_state *templ)
865 {
866 const struct tgsi_token *tokens = templ->tokens;
867 unsigned num_tokens = tgsi_num_tokens(tokens);
868 size_t tokens_size = num_tokens*sizeof(struct tgsi_token);
869 unsigned hash_key = cso_construct_key((void*)tokens, tokens_size);
870 struct cso_hash_iter iter = cso_find_state_template(ctx->cache,
871 hash_key,
872 CSO_FRAGMENT_SHADER,
873 (void*)tokens,
874 sizeof(*templ)); /* XXX correct? tokens_size? */
875 void *handle = NULL;
876
877 if (cso_hash_iter_is_null(iter)) {
878 struct cso_fragment_shader *cso = MALLOC(sizeof(struct cso_fragment_shader) + tokens_size);
879 struct tgsi_token *cso_tokens = (struct tgsi_token *)((char *)cso + sizeof(*cso));
880
881 if (!cso)
882 return PIPE_ERROR_OUT_OF_MEMORY;
883
884 memcpy(cso_tokens, tokens, tokens_size);
885 cso->state.tokens = cso_tokens;
886 cso->data = ctx->pipe->create_fs_state(ctx->pipe, &cso->state);
887 cso->delete_state = (cso_state_callback)ctx->pipe->delete_fs_state;
888 cso->context = ctx->pipe;
889
890 iter = cso_insert_state(ctx->cache, hash_key, CSO_FRAGMENT_SHADER, cso);
891 if (cso_hash_iter_is_null(iter)) {
892 FREE(cso);
893 return PIPE_ERROR_OUT_OF_MEMORY;
894 }
895
896 handle = cso->data;
897 }
898 else {
899 handle = ((struct cso_fragment_shader *)cso_hash_iter_data(iter))->data;
900 }
901
902 return cso_set_fragment_shader_handle( ctx, handle );
903 }
904 #endif
905
906 void cso_save_fragment_shader(struct cso_context *ctx)
907 {
908 assert(!ctx->fragment_shader_saved);
909 ctx->fragment_shader_saved = ctx->fragment_shader;
910 }
911
912 void cso_restore_fragment_shader(struct cso_context *ctx)
913 {
914 if (ctx->fragment_shader_saved != ctx->fragment_shader) {
915 ctx->pipe->bind_fs_state(ctx->pipe, ctx->fragment_shader_saved);
916 ctx->fragment_shader = ctx->fragment_shader_saved;
917 }
918 ctx->fragment_shader_saved = NULL;
919 }
920
921
922 enum pipe_error cso_set_vertex_shader_handle(struct cso_context *ctx,
923 void *handle )
924 {
925 if (ctx->vertex_shader != handle) {
926 ctx->vertex_shader = handle;
927 ctx->pipe->bind_vs_state(ctx->pipe, handle);
928 }
929 return PIPE_OK;
930 }
931
932 void cso_delete_vertex_shader(struct cso_context *ctx, void *handle )
933 {
934 if (handle == ctx->vertex_shader) {
935 /* unbind before deleting */
936 ctx->pipe->bind_vs_state(ctx->pipe, NULL);
937 ctx->vertex_shader = NULL;
938 }
939 ctx->pipe->delete_vs_state(ctx->pipe, handle);
940 }
941
942
943 /* Not really working:
944 */
945 #if 0
946 enum pipe_error cso_set_vertex_shader(struct cso_context *ctx,
947 const struct pipe_shader_state *templ)
948 {
949 unsigned hash_key = cso_construct_key((void*)templ,
950 sizeof(struct pipe_shader_state));
951 struct cso_hash_iter iter = cso_find_state_template(ctx->cache,
952 hash_key, CSO_VERTEX_SHADER,
953 (void*)templ,
954 sizeof(*templ));
955 void *handle = NULL;
956
957 if (cso_hash_iter_is_null(iter)) {
958 struct cso_vertex_shader *cso = MALLOC(sizeof(struct cso_vertex_shader));
959
960 if (!cso)
961 return PIPE_ERROR_OUT_OF_MEMORY;
962
963 memcpy(cso->state, templ, sizeof(*templ));
964 cso->data = ctx->pipe->create_vs_state(ctx->pipe, &cso->state);
965 cso->delete_state = (cso_state_callback)ctx->pipe->delete_vs_state;
966 cso->context = ctx->pipe;
967
968 iter = cso_insert_state(ctx->cache, hash_key, CSO_VERTEX_SHADER, cso);
969 if (cso_hash_iter_is_null(iter)) {
970 FREE(cso);
971 return PIPE_ERROR_OUT_OF_MEMORY;
972 }
973
974 handle = cso->data;
975 }
976 else {
977 handle = ((struct cso_vertex_shader *)cso_hash_iter_data(iter))->data;
978 }
979
980 return cso_set_vertex_shader_handle( ctx, handle );
981 }
982 #endif
983
984
985
986 void cso_save_vertex_shader(struct cso_context *ctx)
987 {
988 assert(!ctx->vertex_shader_saved);
989 ctx->vertex_shader_saved = ctx->vertex_shader;
990 }
991
992 void cso_restore_vertex_shader(struct cso_context *ctx)
993 {
994 if (ctx->vertex_shader_saved != ctx->vertex_shader) {
995 ctx->pipe->bind_vs_state(ctx->pipe, ctx->vertex_shader_saved);
996 ctx->vertex_shader = ctx->vertex_shader_saved;
997 }
998 ctx->vertex_shader_saved = NULL;
999 }
1000
1001
1002 /**
1003 * Copy framebuffer state from src to dst with refcounting of surfaces.
1004 */
1005 static void
1006 copy_framebuffer_state(struct pipe_framebuffer_state *dst,
1007 const struct pipe_framebuffer_state *src)
1008 {
1009 uint i;
1010
1011 dst->width = src->width;
1012 dst->height = src->height;
1013 dst->nr_cbufs = src->nr_cbufs;
1014 for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) {
1015 pipe_surface_reference(&dst->cbufs[i], src->cbufs[i]);
1016 }
1017 pipe_surface_reference(&dst->zsbuf, src->zsbuf);
1018 }
1019
1020
1021 static void
1022 free_framebuffer_state(struct pipe_framebuffer_state *fb)
1023 {
1024 uint i;
1025
1026 for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) {
1027 pipe_surface_reference(&fb->cbufs[i], NULL);
1028 }
1029 pipe_surface_reference(&fb->zsbuf, NULL);
1030 }
1031
1032
1033 enum pipe_error cso_set_framebuffer(struct cso_context *ctx,
1034 const struct pipe_framebuffer_state *fb)
1035 {
1036 if (memcmp(&ctx->fb, fb, sizeof(*fb)) != 0) {
1037 copy_framebuffer_state(&ctx->fb, fb);
1038 ctx->pipe->set_framebuffer_state(ctx->pipe, fb);
1039 }
1040 return PIPE_OK;
1041 }
1042
1043 void cso_save_framebuffer(struct cso_context *ctx)
1044 {
1045 copy_framebuffer_state(&ctx->fb_saved, &ctx->fb);
1046 }
1047
1048 void cso_restore_framebuffer(struct cso_context *ctx)
1049 {
1050 if (memcmp(&ctx->fb, &ctx->fb_saved, sizeof(ctx->fb))) {
1051 copy_framebuffer_state(&ctx->fb, &ctx->fb_saved);
1052 ctx->pipe->set_framebuffer_state(ctx->pipe, &ctx->fb);
1053 free_framebuffer_state(&ctx->fb_saved);
1054 }
1055 }
1056
1057
1058 enum pipe_error cso_set_viewport(struct cso_context *ctx,
1059 const struct pipe_viewport_state *vp)
1060 {
1061 if (memcmp(&ctx->vp, vp, sizeof(*vp))) {
1062 ctx->vp = *vp;
1063 ctx->pipe->set_viewport_state(ctx->pipe, vp);
1064 }
1065 return PIPE_OK;
1066 }
1067
1068 void cso_save_viewport(struct cso_context *ctx)
1069 {
1070 ctx->vp_saved = ctx->vp;
1071 }
1072
1073
1074 void cso_restore_viewport(struct cso_context *ctx)
1075 {
1076 if (memcmp(&ctx->vp, &ctx->vp_saved, sizeof(ctx->vp))) {
1077 ctx->vp = ctx->vp_saved;
1078 ctx->pipe->set_viewport_state(ctx->pipe, &ctx->vp);
1079 }
1080 }
1081
1082
1083 enum pipe_error cso_set_blend_color(struct cso_context *ctx,
1084 const struct pipe_blend_color *bc)
1085 {
1086 if (memcmp(&ctx->blend_color, bc, sizeof(ctx->blend_color))) {
1087 ctx->blend_color = *bc;
1088 ctx->pipe->set_blend_color(ctx->pipe, bc);
1089 }
1090 return PIPE_OK;
1091 }
1092
1093 enum pipe_error cso_set_stencil_ref(struct cso_context *ctx,
1094 const struct pipe_stencil_ref *sr)
1095 {
1096 if (memcmp(&ctx->stencil_ref, sr, sizeof(ctx->stencil_ref))) {
1097 ctx->stencil_ref = *sr;
1098 ctx->pipe->set_stencil_ref(ctx->pipe, sr);
1099 }
1100 return PIPE_OK;
1101 }
1102
1103 void cso_save_stencil_ref(struct cso_context *ctx)
1104 {
1105 ctx->stencil_ref_saved = ctx->stencil_ref;
1106 }
1107
1108
1109 void cso_restore_stencil_ref(struct cso_context *ctx)
1110 {
1111 if (memcmp(&ctx->stencil_ref, &ctx->stencil_ref_saved, sizeof(ctx->stencil_ref))) {
1112 ctx->stencil_ref = ctx->stencil_ref_saved;
1113 ctx->pipe->set_stencil_ref(ctx->pipe, &ctx->stencil_ref);
1114 }
1115 }
1116
1117 enum pipe_error cso_set_geometry_shader_handle(struct cso_context *ctx,
1118 void *handle)
1119 {
1120 if (ctx->geometry_shader != handle) {
1121 ctx->geometry_shader = handle;
1122 ctx->pipe->bind_gs_state(ctx->pipe, handle);
1123 }
1124 return PIPE_OK;
1125 }
1126
1127 void cso_delete_geometry_shader(struct cso_context *ctx, void *handle)
1128 {
1129 if (handle == ctx->geometry_shader) {
1130 /* unbind before deleting */
1131 ctx->pipe->bind_gs_state(ctx->pipe, NULL);
1132 ctx->geometry_shader = NULL;
1133 }
1134 ctx->pipe->delete_gs_state(ctx->pipe, handle);
1135 }
1136
1137 void cso_save_geometry_shader(struct cso_context *ctx)
1138 {
1139 assert(!ctx->geometry_shader_saved);
1140 ctx->geometry_shader_saved = ctx->geometry_shader;
1141 }
1142
1143 void cso_restore_geometry_shader(struct cso_context *ctx)
1144 {
1145 if (ctx->geometry_shader_saved != ctx->geometry_shader) {
1146 ctx->pipe->bind_gs_state(ctx->pipe, ctx->geometry_shader_saved);
1147 ctx->geometry_shader = ctx->geometry_shader_saved;
1148 }
1149 ctx->geometry_shader_saved = NULL;
1150 }
1151
1152 /* clip state */
1153
1154 static INLINE void
1155 clip_state_cpy(struct pipe_clip_state *dst,
1156 const struct pipe_clip_state *src)
1157 {
1158 dst->nr = src->nr;
1159 if (src->nr) {
1160 memcpy(dst->ucp, src->ucp, src->nr * sizeof(src->ucp[0]));
1161 }
1162 }
1163
1164 static INLINE int
1165 clip_state_cmp(const struct pipe_clip_state *a,
1166 const struct pipe_clip_state *b)
1167 {
1168 if (a->nr != b->nr) {
1169 return 1;
1170 }
1171 if (a->nr) {
1172 return memcmp(a->ucp, b->ucp, a->nr * sizeof(a->ucp[0]));
1173 }
1174 return 0;
1175 }
1176
1177 void
1178 cso_set_clip(struct cso_context *ctx,
1179 const struct pipe_clip_state *clip)
1180 {
1181 if (clip_state_cmp(&ctx->clip, clip)) {
1182 clip_state_cpy(&ctx->clip, clip);
1183 ctx->pipe->set_clip_state(ctx->pipe, clip);
1184 }
1185 }
1186
1187 void
1188 cso_save_clip(struct cso_context *ctx)
1189 {
1190 clip_state_cpy(&ctx->clip_saved, &ctx->clip);
1191 }
1192
1193 void
1194 cso_restore_clip(struct cso_context *ctx)
1195 {
1196 if (clip_state_cmp(&ctx->clip, &ctx->clip_saved)) {
1197 clip_state_cpy(&ctx->clip, &ctx->clip_saved);
1198 ctx->pipe->set_clip_state(ctx->pipe, &ctx->clip_saved);
1199 }
1200 }
1201
1202 enum pipe_error cso_set_vertex_elements(struct cso_context *ctx,
1203 unsigned count,
1204 const struct pipe_vertex_element *states)
1205 {
1206 unsigned key_size, hash_key;
1207 struct cso_hash_iter iter;
1208 void *handle;
1209 struct cso_velems_state velems_state;
1210
1211 /* need to include the count into the stored state data too.
1212 Otherwise first few count pipe_vertex_elements could be identical even if count
1213 is different, and there's no guarantee the hash would be different in that
1214 case neither */
1215 key_size = sizeof(struct pipe_vertex_element) * count + sizeof(unsigned);
1216 velems_state.count = count;
1217 memcpy(velems_state.velems, states, sizeof(struct pipe_vertex_element) * count);
1218 hash_key = cso_construct_key((void*)&velems_state, key_size);
1219 iter = cso_find_state_template(ctx->cache, hash_key, CSO_VELEMENTS, (void*)&velems_state, key_size);
1220
1221 if (cso_hash_iter_is_null(iter)) {
1222 struct cso_velements *cso = MALLOC(sizeof(struct cso_velements));
1223 if (!cso)
1224 return PIPE_ERROR_OUT_OF_MEMORY;
1225
1226 memcpy(&cso->state, &velems_state, key_size);
1227 cso->data = ctx->pipe->create_vertex_elements_state(ctx->pipe, count, &cso->state.velems[0]);
1228 cso->delete_state = (cso_state_callback)ctx->pipe->delete_vertex_elements_state;
1229 cso->context = ctx->pipe;
1230
1231 iter = cso_insert_state(ctx->cache, hash_key, CSO_VELEMENTS, cso);
1232 if (cso_hash_iter_is_null(iter)) {
1233 FREE(cso);
1234 return PIPE_ERROR_OUT_OF_MEMORY;
1235 }
1236
1237 handle = cso->data;
1238 }
1239 else {
1240 handle = ((struct cso_velements *)cso_hash_iter_data(iter))->data;
1241 }
1242
1243 if (ctx->velements != handle) {
1244 ctx->velements = handle;
1245 ctx->pipe->bind_vertex_elements_state(ctx->pipe, handle);
1246 }
1247 return PIPE_OK;
1248 }
1249
1250 void cso_save_vertex_elements(struct cso_context *ctx)
1251 {
1252 assert(!ctx->velements_saved);
1253 ctx->velements_saved = ctx->velements;
1254 }
1255
1256 void cso_restore_vertex_elements(struct cso_context *ctx)
1257 {
1258 if (ctx->velements != ctx->velements_saved) {
1259 ctx->velements = ctx->velements_saved;
1260 ctx->pipe->bind_vertex_elements_state(ctx->pipe, ctx->velements_saved);
1261 }
1262 ctx->velements_saved = NULL;
1263 }