cso_context.c revision fd4aa4f32365a5f054e7fc36b558680dcac66d1b
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
46struct 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
97static void
98free_framebuffer_state(struct pipe_framebuffer_state *fb);
99
100
101static 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
114static 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
128static 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
137static 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
149static 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
160static 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
172static 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
201static 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
226struct 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
246out:
247   cso_destroy_context( ctx );
248   return NULL;
249}
250
251
252/**
253 * Prior to context destruction, this function unbinds all state objects.
254 */
255void 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      ctx->pipe->bind_vertex_sampler_states(ctx->pipe, 0, NULL);
264      ctx->pipe->bind_depth_stencil_alpha_state( ctx->pipe, NULL );
265      ctx->pipe->bind_fs_state( ctx->pipe, NULL );
266      ctx->pipe->bind_vs_state( ctx->pipe, NULL );
267   }
268
269   for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
270      pipe_texture_reference(&ctx->textures[i], NULL);
271      pipe_texture_reference(&ctx->textures_saved[i], NULL);
272   }
273
274   for (i = 0; i < PIPE_MAX_VERTEX_SAMPLERS; i++) {
275      pipe_texture_reference(&ctx->vertex_textures[i], NULL);
276      pipe_texture_reference(&ctx->vertex_textures_saved[i], NULL);
277   }
278
279   free_framebuffer_state(&ctx->fb);
280   free_framebuffer_state(&ctx->fb_saved);
281
282   if (ctx->cache) {
283      cso_cache_delete( ctx->cache );
284      ctx->cache = NULL;
285   }
286}
287
288
289void cso_destroy_context( struct cso_context *ctx )
290{
291   if (ctx) {
292      /*cso_release_all( ctx );*/
293      FREE( ctx );
294   }
295}
296
297
298/* Those function will either find the state of the given template
299 * in the cache or they will create a new state from the given
300 * template, insert it in the cache and return it.
301 */
302
303/*
304 * If the driver returns 0 from the create method then they will assign
305 * the data member of the cso to be the template itself.
306 */
307
308enum pipe_error cso_set_blend(struct cso_context *ctx,
309                              const struct pipe_blend_state *templ)
310{
311   unsigned hash_key = cso_construct_key((void*)templ, sizeof(struct pipe_blend_state));
312   struct cso_hash_iter iter = cso_find_state_template(ctx->cache,
313                                                       hash_key, CSO_BLEND,
314                                                       (void*)templ);
315   void *handle;
316
317   if (cso_hash_iter_is_null(iter)) {
318      struct cso_blend *cso = MALLOC(sizeof(struct cso_blend));
319      if (!cso)
320         return PIPE_ERROR_OUT_OF_MEMORY;
321
322      memcpy(&cso->state, templ, sizeof(*templ));
323      cso->data = ctx->pipe->create_blend_state(ctx->pipe, &cso->state);
324      cso->delete_state = (cso_state_callback)ctx->pipe->delete_blend_state;
325      cso->context = ctx->pipe;
326
327      iter = cso_insert_state(ctx->cache, hash_key, CSO_BLEND, cso);
328      if (cso_hash_iter_is_null(iter)) {
329         FREE(cso);
330         return PIPE_ERROR_OUT_OF_MEMORY;
331      }
332
333      handle = cso->data;
334   }
335   else {
336      handle = ((struct cso_blend *)cso_hash_iter_data(iter))->data;
337   }
338
339   if (ctx->blend != handle) {
340      ctx->blend = handle;
341      ctx->pipe->bind_blend_state(ctx->pipe, handle);
342   }
343   return PIPE_OK;
344}
345
346void cso_save_blend(struct cso_context *ctx)
347{
348   assert(!ctx->blend_saved);
349   ctx->blend_saved = ctx->blend;
350}
351
352void cso_restore_blend(struct cso_context *ctx)
353{
354   if (ctx->blend != ctx->blend_saved) {
355      ctx->blend = ctx->blend_saved;
356      ctx->pipe->bind_blend_state(ctx->pipe, ctx->blend_saved);
357   }
358   ctx->blend_saved = NULL;
359}
360
361
362
363enum pipe_error cso_single_sampler(struct cso_context *ctx,
364                                   unsigned idx,
365                                   const struct pipe_sampler_state *templ)
366{
367   void *handle = NULL;
368
369   if (templ != NULL) {
370      unsigned hash_key = cso_construct_key((void*)templ, sizeof(struct pipe_sampler_state));
371      struct cso_hash_iter iter = cso_find_state_template(ctx->cache,
372                                                          hash_key, CSO_SAMPLER,
373                                                          (void*)templ);
374
375      if (cso_hash_iter_is_null(iter)) {
376         struct cso_sampler *cso = MALLOC(sizeof(struct cso_sampler));
377         if (!cso)
378            return PIPE_ERROR_OUT_OF_MEMORY;
379
380         memcpy(&cso->state, templ, sizeof(*templ));
381         cso->data = ctx->pipe->create_sampler_state(ctx->pipe, &cso->state);
382         cso->delete_state = (cso_state_callback)ctx->pipe->delete_sampler_state;
383         cso->context = ctx->pipe;
384
385         iter = cso_insert_state(ctx->cache, hash_key, CSO_SAMPLER, cso);
386         if (cso_hash_iter_is_null(iter)) {
387            FREE(cso);
388            return PIPE_ERROR_OUT_OF_MEMORY;
389         }
390
391         handle = cso->data;
392      }
393      else {
394         handle = ((struct cso_sampler *)cso_hash_iter_data(iter))->data;
395      }
396   }
397
398   ctx->samplers[idx] = handle;
399   return PIPE_OK;
400}
401
402enum pipe_error
403cso_single_vertex_sampler(struct cso_context *ctx,
404                          unsigned idx,
405                          const struct pipe_sampler_state *templ)
406{
407   void *handle = NULL;
408
409   if (templ != NULL) {
410      unsigned hash_key = cso_construct_key((void*)templ, sizeof(struct pipe_sampler_state));
411      struct cso_hash_iter iter = cso_find_state_template(ctx->cache,
412                                                          hash_key, CSO_SAMPLER,
413                                                          (void*)templ);
414
415      if (cso_hash_iter_is_null(iter)) {
416         struct cso_sampler *cso = MALLOC(sizeof(struct cso_sampler));
417         if (!cso)
418            return PIPE_ERROR_OUT_OF_MEMORY;
419
420         memcpy(&cso->state, templ, sizeof(*templ));
421         cso->data = ctx->pipe->create_sampler_state(ctx->pipe, &cso->state);
422         cso->delete_state = (cso_state_callback)ctx->pipe->delete_sampler_state;
423         cso->context = ctx->pipe;
424
425         iter = cso_insert_state(ctx->cache, hash_key, CSO_SAMPLER, cso);
426         if (cso_hash_iter_is_null(iter)) {
427            FREE(cso);
428            return PIPE_ERROR_OUT_OF_MEMORY;
429         }
430
431         handle = cso->data;
432      }
433      else {
434         handle = ((struct cso_sampler *)cso_hash_iter_data(iter))->data;
435      }
436   }
437
438   ctx->vertex_samplers[idx] = handle;
439   return PIPE_OK;
440}
441
442void cso_single_sampler_done( struct cso_context *ctx )
443{
444   unsigned i;
445
446   /* find highest non-null sampler */
447   for (i = PIPE_MAX_SAMPLERS; i > 0; i--) {
448      if (ctx->samplers[i - 1] != NULL)
449         break;
450   }
451
452   ctx->nr_samplers = i;
453
454   if (ctx->hw.nr_samplers != ctx->nr_samplers ||
455       memcmp(ctx->hw.samplers,
456              ctx->samplers,
457              ctx->nr_samplers * sizeof(void *)) != 0)
458   {
459      memcpy(ctx->hw.samplers, ctx->samplers, ctx->nr_samplers * sizeof(void *));
460      ctx->hw.nr_samplers = ctx->nr_samplers;
461
462      ctx->pipe->bind_fragment_sampler_states(ctx->pipe, ctx->nr_samplers, ctx->samplers);
463   }
464}
465
466void
467cso_single_vertex_sampler_done(struct cso_context *ctx)
468{
469   unsigned i;
470
471   /* find highest non-null sampler */
472   for (i = PIPE_MAX_VERTEX_SAMPLERS; i > 0; i--) {
473      if (ctx->vertex_samplers[i - 1] != NULL)
474         break;
475   }
476
477   ctx->nr_vertex_samplers = i;
478
479   if (ctx->hw.nr_vertex_samplers != ctx->nr_vertex_samplers ||
480       memcmp(ctx->hw.vertex_samplers,
481              ctx->vertex_samplers,
482              ctx->nr_vertex_samplers * sizeof(void *)) != 0)
483   {
484      memcpy(ctx->hw.vertex_samplers,
485             ctx->vertex_samplers,
486             ctx->nr_vertex_samplers * sizeof(void *));
487      ctx->hw.nr_vertex_samplers = ctx->nr_vertex_samplers;
488
489      ctx->pipe->bind_vertex_sampler_states(ctx->pipe,
490                                            ctx->nr_vertex_samplers,
491                                            ctx->vertex_samplers);
492   }
493}
494
495/*
496 * If the function encouters any errors it will return the
497 * last one. Done to always try to set as many samplers
498 * as possible.
499 */
500enum pipe_error cso_set_samplers( struct cso_context *ctx,
501                                  unsigned nr,
502                                  const struct pipe_sampler_state **templates )
503{
504   unsigned i;
505   enum pipe_error temp, error = PIPE_OK;
506
507   /* TODO: fastpath
508    */
509
510   for (i = 0; i < nr; i++) {
511      temp = cso_single_sampler( ctx, i, templates[i] );
512      if (temp != PIPE_OK)
513         error = temp;
514   }
515
516   for ( ; i < ctx->nr_samplers; i++) {
517      temp = cso_single_sampler( ctx, i, NULL );
518      if (temp != PIPE_OK)
519         error = temp;
520   }
521
522   cso_single_sampler_done( ctx );
523
524   return error;
525}
526
527void cso_save_samplers(struct cso_context *ctx)
528{
529   ctx->nr_samplers_saved = ctx->nr_samplers;
530   memcpy(ctx->samplers_saved, ctx->samplers, sizeof(ctx->samplers));
531}
532
533void cso_restore_samplers(struct cso_context *ctx)
534{
535   ctx->nr_samplers = ctx->nr_samplers_saved;
536   memcpy(ctx->samplers, ctx->samplers_saved, sizeof(ctx->samplers));
537   cso_single_sampler_done( ctx );
538}
539
540void
541cso_save_vertex_samplers(struct cso_context *ctx)
542{
543   ctx->nr_vertex_samplers_saved = ctx->nr_vertex_samplers;
544   memcpy(ctx->vertex_samplers_saved, ctx->vertex_samplers, sizeof(ctx->vertex_samplers));
545}
546
547void
548cso_restore_vertex_samplers(struct cso_context *ctx)
549{
550   ctx->nr_vertex_samplers = ctx->nr_vertex_samplers_saved;
551   memcpy(ctx->vertex_samplers, ctx->vertex_samplers_saved, sizeof(ctx->vertex_samplers));
552   cso_single_vertex_sampler_done(ctx);
553}
554
555
556enum pipe_error cso_set_sampler_textures( struct cso_context *ctx,
557                                          uint count,
558                                          struct pipe_texture **textures )
559{
560   uint i;
561
562   ctx->nr_textures = count;
563
564   for (i = 0; i < count; i++)
565      pipe_texture_reference(&ctx->textures[i], textures[i]);
566   for ( ; i < PIPE_MAX_SAMPLERS; i++)
567      pipe_texture_reference(&ctx->textures[i], NULL);
568
569   ctx->pipe->set_fragment_sampler_textures(ctx->pipe, count, textures);
570
571   return PIPE_OK;
572}
573
574void cso_save_sampler_textures( struct cso_context *ctx )
575{
576   uint i;
577
578   ctx->nr_textures_saved = ctx->nr_textures;
579   for (i = 0; i < ctx->nr_textures; i++) {
580      assert(!ctx->textures_saved[i]);
581      pipe_texture_reference(&ctx->textures_saved[i], ctx->textures[i]);
582   }
583}
584
585void cso_restore_sampler_textures( struct cso_context *ctx )
586{
587   uint i;
588
589   ctx->nr_textures = ctx->nr_textures_saved;
590
591   for (i = 0; i < ctx->nr_textures; i++) {
592      pipe_texture_reference(&ctx->textures[i], NULL);
593      ctx->textures[i] = ctx->textures_saved[i];
594      ctx->textures_saved[i] = NULL;
595   }
596   for ( ; i < PIPE_MAX_SAMPLERS; i++)
597      pipe_texture_reference(&ctx->textures[i], NULL);
598
599   ctx->pipe->set_fragment_sampler_textures(ctx->pipe, ctx->nr_textures, ctx->textures);
600
601   ctx->nr_textures_saved = 0;
602}
603
604
605
606enum pipe_error
607cso_set_vertex_sampler_textures(struct cso_context *ctx,
608                                uint count,
609                                struct pipe_texture **textures)
610{
611   uint i;
612
613   ctx->nr_vertex_textures = count;
614
615   for (i = 0; i < count; i++) {
616      pipe_texture_reference(&ctx->vertex_textures[i], textures[i]);
617   }
618   for ( ; i < PIPE_MAX_VERTEX_SAMPLERS; i++) {
619      pipe_texture_reference(&ctx->vertex_textures[i], NULL);
620   }
621
622   ctx->pipe->set_vertex_sampler_textures(ctx->pipe, count, textures);
623
624   return PIPE_OK;
625}
626
627void
628cso_save_vertex_sampler_textures(struct cso_context *ctx)
629{
630   uint i;
631
632   ctx->nr_vertex_textures_saved = ctx->nr_vertex_textures;
633   for (i = 0; i < ctx->nr_vertex_textures; i++) {
634      assert(!ctx->vertex_textures_saved[i]);
635      pipe_texture_reference(&ctx->vertex_textures_saved[i], ctx->vertex_textures[i]);
636   }
637}
638
639void
640cso_restore_vertex_sampler_textures(struct cso_context *ctx)
641{
642   uint i;
643
644   ctx->nr_vertex_textures = ctx->nr_vertex_textures_saved;
645
646   for (i = 0; i < ctx->nr_vertex_textures; i++) {
647      pipe_texture_reference(&ctx->vertex_textures[i], NULL);
648      ctx->vertex_textures[i] = ctx->vertex_textures_saved[i];
649      ctx->vertex_textures_saved[i] = NULL;
650   }
651   for ( ; i < PIPE_MAX_VERTEX_SAMPLERS; i++) {
652      pipe_texture_reference(&ctx->vertex_textures[i], NULL);
653   }
654
655   ctx->pipe->set_vertex_sampler_textures(ctx->pipe,
656                                          ctx->nr_vertex_textures,
657                                          ctx->vertex_textures);
658
659   ctx->nr_vertex_textures_saved = 0;
660}
661
662
663
664enum pipe_error cso_set_depth_stencil_alpha(struct cso_context *ctx,
665                                            const struct pipe_depth_stencil_alpha_state *templ)
666{
667   unsigned hash_key = cso_construct_key((void*)templ,
668                                         sizeof(struct pipe_depth_stencil_alpha_state));
669   struct cso_hash_iter iter = cso_find_state_template(ctx->cache,
670                                                       hash_key,
671						       CSO_DEPTH_STENCIL_ALPHA,
672                                                       (void*)templ);
673   void *handle;
674
675   if (cso_hash_iter_is_null(iter)) {
676      struct cso_depth_stencil_alpha *cso = MALLOC(sizeof(struct cso_depth_stencil_alpha));
677      if (!cso)
678         return PIPE_ERROR_OUT_OF_MEMORY;
679
680      memcpy(&cso->state, templ, sizeof(*templ));
681      cso->data = ctx->pipe->create_depth_stencil_alpha_state(ctx->pipe, &cso->state);
682      cso->delete_state = (cso_state_callback)ctx->pipe->delete_depth_stencil_alpha_state;
683      cso->context = ctx->pipe;
684
685      iter = cso_insert_state(ctx->cache, hash_key, CSO_DEPTH_STENCIL_ALPHA, cso);
686      if (cso_hash_iter_is_null(iter)) {
687         FREE(cso);
688         return PIPE_ERROR_OUT_OF_MEMORY;
689      }
690
691      handle = cso->data;
692   }
693   else {
694      handle = ((struct cso_depth_stencil_alpha *)cso_hash_iter_data(iter))->data;
695   }
696
697   if (ctx->depth_stencil != handle) {
698      ctx->depth_stencil = handle;
699      ctx->pipe->bind_depth_stencil_alpha_state(ctx->pipe, handle);
700   }
701   return PIPE_OK;
702}
703
704void cso_save_depth_stencil_alpha(struct cso_context *ctx)
705{
706   assert(!ctx->depth_stencil_saved);
707   ctx->depth_stencil_saved = ctx->depth_stencil;
708}
709
710void cso_restore_depth_stencil_alpha(struct cso_context *ctx)
711{
712   if (ctx->depth_stencil != ctx->depth_stencil_saved) {
713      ctx->depth_stencil = ctx->depth_stencil_saved;
714      ctx->pipe->bind_depth_stencil_alpha_state(ctx->pipe, ctx->depth_stencil_saved);
715   }
716   ctx->depth_stencil_saved = NULL;
717}
718
719
720
721enum pipe_error cso_set_rasterizer(struct cso_context *ctx,
722                                   const struct pipe_rasterizer_state *templ)
723{
724   unsigned hash_key = cso_construct_key((void*)templ,
725                                         sizeof(struct pipe_rasterizer_state));
726   struct cso_hash_iter iter = cso_find_state_template(ctx->cache,
727                                                       hash_key, CSO_RASTERIZER,
728                                                       (void*)templ);
729   void *handle = NULL;
730
731   if (cso_hash_iter_is_null(iter)) {
732      struct cso_rasterizer *cso = MALLOC(sizeof(struct cso_rasterizer));
733      if (!cso)
734         return PIPE_ERROR_OUT_OF_MEMORY;
735
736      memcpy(&cso->state, templ, sizeof(*templ));
737      cso->data = ctx->pipe->create_rasterizer_state(ctx->pipe, &cso->state);
738      cso->delete_state = (cso_state_callback)ctx->pipe->delete_rasterizer_state;
739      cso->context = ctx->pipe;
740
741      iter = cso_insert_state(ctx->cache, hash_key, CSO_RASTERIZER, cso);
742      if (cso_hash_iter_is_null(iter)) {
743         FREE(cso);
744         return PIPE_ERROR_OUT_OF_MEMORY;
745      }
746
747      handle = cso->data;
748   }
749   else {
750      handle = ((struct cso_rasterizer *)cso_hash_iter_data(iter))->data;
751   }
752
753   if (ctx->rasterizer != handle) {
754      ctx->rasterizer = handle;
755      ctx->pipe->bind_rasterizer_state(ctx->pipe, handle);
756   }
757   return PIPE_OK;
758}
759
760void cso_save_rasterizer(struct cso_context *ctx)
761{
762   assert(!ctx->rasterizer_saved);
763   ctx->rasterizer_saved = ctx->rasterizer;
764}
765
766void cso_restore_rasterizer(struct cso_context *ctx)
767{
768   if (ctx->rasterizer != ctx->rasterizer_saved) {
769      ctx->rasterizer = ctx->rasterizer_saved;
770      ctx->pipe->bind_rasterizer_state(ctx->pipe, ctx->rasterizer_saved);
771   }
772   ctx->rasterizer_saved = NULL;
773}
774
775
776
777enum pipe_error cso_set_fragment_shader_handle(struct cso_context *ctx,
778                                               void *handle )
779{
780   if (ctx->fragment_shader != handle) {
781      ctx->fragment_shader = handle;
782      ctx->pipe->bind_fs_state(ctx->pipe, handle);
783   }
784   return PIPE_OK;
785}
786
787void cso_delete_fragment_shader(struct cso_context *ctx, void *handle )
788{
789   if (handle == ctx->fragment_shader) {
790      /* unbind before deleting */
791      ctx->pipe->bind_fs_state(ctx->pipe, NULL);
792      ctx->fragment_shader = NULL;
793   }
794   ctx->pipe->delete_fs_state(ctx->pipe, handle);
795}
796
797/* Not really working:
798 */
799#if 0
800enum pipe_error cso_set_fragment_shader(struct cso_context *ctx,
801                                        const struct pipe_shader_state *templ)
802{
803   const struct tgsi_token *tokens = templ->tokens;
804   unsigned num_tokens = tgsi_num_tokens(tokens);
805   size_t tokens_size = num_tokens*sizeof(struct tgsi_token);
806   unsigned hash_key = cso_construct_key((void*)tokens, tokens_size);
807   struct cso_hash_iter iter = cso_find_state_template(ctx->cache,
808                                                       hash_key,
809                                                       CSO_FRAGMENT_SHADER,
810                                                       (void*)tokens);
811   void *handle = NULL;
812
813   if (cso_hash_iter_is_null(iter)) {
814      struct cso_fragment_shader *cso = MALLOC(sizeof(struct cso_fragment_shader) + tokens_size);
815      struct tgsi_token *cso_tokens = (struct tgsi_token *)((char *)cso + sizeof(*cso));
816
817      if (!cso)
818         return PIPE_ERROR_OUT_OF_MEMORY;
819
820      memcpy(cso_tokens, tokens, tokens_size);
821      cso->state.tokens = cso_tokens;
822      cso->data = ctx->pipe->create_fs_state(ctx->pipe, &cso->state);
823      cso->delete_state = (cso_state_callback)ctx->pipe->delete_fs_state;
824      cso->context = ctx->pipe;
825
826      iter = cso_insert_state(ctx->cache, hash_key, CSO_FRAGMENT_SHADER, cso);
827      if (cso_hash_iter_is_null(iter)) {
828         FREE(cso);
829         return PIPE_ERROR_OUT_OF_MEMORY;
830      }
831
832      handle = cso->data;
833   }
834   else {
835      handle = ((struct cso_fragment_shader *)cso_hash_iter_data(iter))->data;
836   }
837
838   return cso_set_fragment_shader_handle( ctx, handle );
839}
840#endif
841
842void cso_save_fragment_shader(struct cso_context *ctx)
843{
844   assert(!ctx->fragment_shader_saved);
845   ctx->fragment_shader_saved = ctx->fragment_shader;
846}
847
848void cso_restore_fragment_shader(struct cso_context *ctx)
849{
850   if (ctx->fragment_shader_saved != ctx->fragment_shader) {
851      ctx->pipe->bind_fs_state(ctx->pipe, ctx->fragment_shader_saved);
852      ctx->fragment_shader = ctx->fragment_shader_saved;
853   }
854   ctx->fragment_shader_saved = NULL;
855}
856
857
858enum pipe_error cso_set_vertex_shader_handle(struct cso_context *ctx,
859                                             void *handle )
860{
861   if (ctx->vertex_shader != handle) {
862      ctx->vertex_shader = handle;
863      ctx->pipe->bind_vs_state(ctx->pipe, handle);
864   }
865   return PIPE_OK;
866}
867
868void cso_delete_vertex_shader(struct cso_context *ctx, void *handle )
869{
870   if (handle == ctx->vertex_shader) {
871      /* unbind before deleting */
872      ctx->pipe->bind_vs_state(ctx->pipe, NULL);
873      ctx->vertex_shader = NULL;
874   }
875   ctx->pipe->delete_vs_state(ctx->pipe, handle);
876}
877
878
879/* Not really working:
880 */
881#if 0
882enum pipe_error cso_set_vertex_shader(struct cso_context *ctx,
883                                      const struct pipe_shader_state *templ)
884{
885   unsigned hash_key = cso_construct_key((void*)templ,
886                                         sizeof(struct pipe_shader_state));
887   struct cso_hash_iter iter = cso_find_state_template(ctx->cache,
888                                                       hash_key, CSO_VERTEX_SHADER,
889                                                       (void*)templ);
890   void *handle = NULL;
891
892   if (cso_hash_iter_is_null(iter)) {
893      struct cso_vertex_shader *cso = MALLOC(sizeof(struct cso_vertex_shader));
894
895      if (!cso)
896         return PIPE_ERROR_OUT_OF_MEMORY;
897
898      memcpy(cso->state, templ, sizeof(*templ));
899      cso->data = ctx->pipe->create_vs_state(ctx->pipe, &cso->state);
900      cso->delete_state = (cso_state_callback)ctx->pipe->delete_vs_state;
901      cso->context = ctx->pipe;
902
903      iter = cso_insert_state(ctx->cache, hash_key, CSO_VERTEX_SHADER, cso);
904      if (cso_hash_iter_is_null(iter)) {
905         FREE(cso);
906         return PIPE_ERROR_OUT_OF_MEMORY;
907      }
908
909      handle = cso->data;
910   }
911   else {
912      handle = ((struct cso_vertex_shader *)cso_hash_iter_data(iter))->data;
913   }
914
915   return cso_set_vertex_shader_handle( ctx, handle );
916}
917#endif
918
919
920
921void cso_save_vertex_shader(struct cso_context *ctx)
922{
923   assert(!ctx->vertex_shader_saved);
924   ctx->vertex_shader_saved = ctx->vertex_shader;
925}
926
927void cso_restore_vertex_shader(struct cso_context *ctx)
928{
929   if (ctx->vertex_shader_saved != ctx->vertex_shader) {
930      ctx->pipe->bind_vs_state(ctx->pipe, ctx->vertex_shader_saved);
931      ctx->vertex_shader = ctx->vertex_shader_saved;
932   }
933   ctx->vertex_shader_saved = NULL;
934}
935
936
937/**
938 * Copy framebuffer state from src to dst with refcounting of surfaces.
939 */
940static void
941copy_framebuffer_state(struct pipe_framebuffer_state *dst,
942                       const struct pipe_framebuffer_state *src)
943{
944   uint i;
945
946   dst->width = src->width;
947   dst->height = src->height;
948   dst->nr_cbufs = src->nr_cbufs;
949   for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) {
950      pipe_surface_reference(&dst->cbufs[i], src->cbufs[i]);
951   }
952   pipe_surface_reference(&dst->zsbuf, src->zsbuf);
953}
954
955
956static void
957free_framebuffer_state(struct pipe_framebuffer_state *fb)
958{
959   uint i;
960
961   for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) {
962      pipe_surface_reference(&fb->cbufs[i], NULL);
963   }
964   pipe_surface_reference(&fb->zsbuf, NULL);
965}
966
967
968enum pipe_error cso_set_framebuffer(struct cso_context *ctx,
969                                    const struct pipe_framebuffer_state *fb)
970{
971   if (memcmp(&ctx->fb, fb, sizeof(*fb)) != 0) {
972      copy_framebuffer_state(&ctx->fb, fb);
973      ctx->pipe->set_framebuffer_state(ctx->pipe, fb);
974   }
975   return PIPE_OK;
976}
977
978void cso_save_framebuffer(struct cso_context *ctx)
979{
980   copy_framebuffer_state(&ctx->fb_saved, &ctx->fb);
981}
982
983void cso_restore_framebuffer(struct cso_context *ctx)
984{
985   if (memcmp(&ctx->fb, &ctx->fb_saved, sizeof(ctx->fb))) {
986      copy_framebuffer_state(&ctx->fb, &ctx->fb_saved);
987      ctx->pipe->set_framebuffer_state(ctx->pipe, &ctx->fb);
988      free_framebuffer_state(&ctx->fb_saved);
989   }
990}
991
992
993enum pipe_error cso_set_viewport(struct cso_context *ctx,
994                                 const struct pipe_viewport_state *vp)
995{
996   if (memcmp(&ctx->vp, vp, sizeof(*vp))) {
997      ctx->vp = *vp;
998      ctx->pipe->set_viewport_state(ctx->pipe, vp);
999   }
1000   return PIPE_OK;
1001}
1002
1003void cso_save_viewport(struct cso_context *ctx)
1004{
1005   ctx->vp_saved = ctx->vp;
1006}
1007
1008
1009void cso_restore_viewport(struct cso_context *ctx)
1010{
1011   if (memcmp(&ctx->vp, &ctx->vp_saved, sizeof(ctx->vp))) {
1012      ctx->vp = ctx->vp_saved;
1013      ctx->pipe->set_viewport_state(ctx->pipe, &ctx->vp);
1014   }
1015}
1016
1017
1018
1019
1020enum pipe_error cso_set_blend_color(struct cso_context *ctx,
1021                                    const struct pipe_blend_color *bc)
1022{
1023   if (memcmp(&ctx->blend_color, bc, sizeof(ctx->blend_color))) {
1024      ctx->blend_color = *bc;
1025      ctx->pipe->set_blend_color(ctx->pipe, bc);
1026   }
1027   return PIPE_OK;
1028}
1029