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