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