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