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