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