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