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