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