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