cso_context.c revision d2ec02f44026244130b4e6f9d87eac6a03a9c6c1
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 "pipe/p_util.h"
40#include "pipe/p_inlines.h"
41#include "tgsi/util/tgsi_parse.h"
42
43#include "cso_cache/cso_context.h"
44#include "cso_cache/cso_cache.h"
45#include "cso_cache/cso_hash.h"
46
47struct cso_context {
48   struct pipe_context *pipe;
49   struct cso_cache *cache;
50
51   struct {
52      void *samplers[PIPE_MAX_SAMPLERS];
53      unsigned nr_samplers;
54   } hw;
55
56   void *samplers[PIPE_MAX_SAMPLERS];
57   unsigned nr_samplers;
58
59   void *samplers_saved[PIPE_MAX_SAMPLERS];
60   unsigned nr_samplers_saved;
61
62   struct pipe_texture *textures[PIPE_MAX_SAMPLERS];
63   uint nr_textures;
64
65   struct pipe_texture *textures_saved[PIPE_MAX_SAMPLERS];
66   uint nr_textures_saved;
67
68   /** Current and saved state.
69    * The saved state is used as a 1-deep stack.
70    */
71   void *blend, *blend_saved;
72   void *depth_stencil, *depth_stencil_saved;
73   void *rasterizer, *rasterizer_saved;
74   void *fragment_shader, *fragment_shader_saved;
75   void *vertex_shader, *vertex_shader_saved;
76
77   struct pipe_framebuffer_state fb, fb_saved;
78   struct pipe_viewport_state vp, vp_saved;
79   struct pipe_blend_color blend_color;
80};
81
82
83static boolean delete_blend_state(struct cso_context *ctx, void *state)
84{
85   struct cso_blend *cso = (struct cso_blend *)state;
86
87   if (ctx->blend == cso->data)
88      return FALSE;
89
90   if (cso->delete_state)
91      cso->delete_state(cso->context, cso->data);
92   FREE(state);
93   return TRUE;
94}
95
96static boolean delete_depth_stencil_state(struct cso_context *ctx, void *state)
97{
98   struct cso_depth_stencil_alpha *cso = (struct cso_depth_stencil_alpha *)state;
99
100   if (ctx->depth_stencil == cso->data)
101      return FALSE;
102
103   if (cso->delete_state)
104      cso->delete_state(cso->context, cso->data);
105   FREE(state);
106
107   return TRUE;
108}
109
110static boolean delete_sampler_state(struct cso_context *ctx, void *state)
111{
112   struct cso_sampler *cso = (struct cso_sampler *)state;
113   if (cso->delete_state)
114      cso->delete_state(cso->context, cso->data);
115   FREE(state);
116   return TRUE;
117}
118
119static boolean delete_rasterizer_state(struct cso_context *ctx, void *state)
120{
121   struct cso_rasterizer *cso = (struct cso_rasterizer *)state;
122
123   if (ctx->rasterizer == cso->data)
124      return FALSE;
125   if (cso->delete_state)
126      cso->delete_state(cso->context, cso->data);
127   FREE(state);
128   return TRUE;
129}
130
131static boolean delete_fs_state(struct cso_context *ctx, void *state)
132{
133   struct cso_fragment_shader *cso = (struct cso_fragment_shader *)state;
134   if (ctx->fragment_shader == cso->data)
135      return FALSE;
136   if (cso->delete_state)
137      cso->delete_state(cso->context, cso->data);
138   FREE(state);
139   return TRUE;
140}
141
142static boolean delete_vs_state(struct cso_context *ctx, void *state)
143{
144   struct cso_vertex_shader *cso = (struct cso_vertex_shader *)state;
145   if (ctx->vertex_shader == cso->data)
146      return TRUE;
147   if (cso->delete_state)
148      cso->delete_state(cso->context, cso->data);
149   FREE(state);
150   return FALSE;
151}
152
153
154static INLINE boolean delete_cso(struct cso_context *ctx,
155                                 void *state, enum cso_cache_type type)
156{
157   switch (type) {
158   case CSO_BLEND:
159      return delete_blend_state(ctx, state);
160      break;
161   case CSO_SAMPLER:
162      return delete_sampler_state(ctx, state);
163      break;
164   case CSO_DEPTH_STENCIL_ALPHA:
165      return delete_depth_stencil_state(ctx, state);
166      break;
167   case CSO_RASTERIZER:
168      return delete_rasterizer_state(ctx, state);
169      break;
170   case CSO_FRAGMENT_SHADER:
171      return delete_fs_state(ctx, state);
172      break;
173   case CSO_VERTEX_SHADER:
174      return delete_vs_state(ctx, state);
175      break;
176   default:
177      assert(0);
178      FREE(state);
179   }
180   return FALSE;
181}
182
183static INLINE void sanitize_hash(struct cso_hash *hash, enum cso_cache_type type,
184                                 int max_size, void *user_data)
185{
186   struct cso_context *ctx = (struct cso_context *)user_data;
187   /* if we're approach the maximum size, remove fourth of the entries
188    * otherwise every subsequent call will go through the same */
189   int hash_size = cso_hash_size(hash);
190   int max_entries = (max_size > hash_size) ? max_size : hash_size;
191   int to_remove =  (max_size < max_entries) * max_entries/4;
192   struct cso_hash_iter iter = cso_hash_first_node(hash);
193   if (hash_size > max_size)
194      to_remove += hash_size - max_size;
195   while (to_remove) {
196      /*remove elements until we're good */
197      /*fixme: currently we pick the nodes to remove at random*/
198      void *cso = cso_hash_iter_data(iter);
199      if (delete_cso(ctx, cso, type)) {
200         iter = cso_hash_erase(hash, iter);
201         --to_remove;
202      } else
203         iter = cso_hash_iter_next(iter);
204   }
205}
206
207
208struct cso_context *cso_create_context( struct pipe_context *pipe )
209{
210   struct cso_context *ctx = CALLOC_STRUCT(cso_context);
211   if (ctx == NULL)
212      goto out;
213
214   ctx->cache = cso_cache_create();
215   if (ctx->cache == NULL)
216      goto out;
217   cso_cache_set_sanitize_callback(ctx->cache,
218                                   sanitize_hash,
219                                   ctx);
220
221   ctx->pipe = pipe;
222
223   /* Enable for testing: */
224   if (0) cso_set_maximum_cache_size( ctx->cache, 4 );
225
226   return ctx;
227
228out:
229   cso_destroy_context( ctx );
230   return NULL;
231}
232
233
234/**
235 * Prior to context destruction, this function unbinds all state objects.
236 */
237void cso_release_all( struct cso_context *ctx )
238{
239   unsigned i;
240
241   if (ctx->pipe) {
242      ctx->pipe->bind_blend_state( ctx->pipe, NULL );
243      ctx->pipe->bind_rasterizer_state( ctx->pipe, NULL );
244      ctx->pipe->bind_sampler_states( ctx->pipe, 0, NULL );
245      ctx->pipe->bind_depth_stencil_alpha_state( ctx->pipe, NULL );
246      ctx->pipe->bind_fs_state( ctx->pipe, NULL );
247      ctx->pipe->bind_vs_state( ctx->pipe, NULL );
248   }
249
250   for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
251      pipe_texture_reference(&ctx->textures[i], NULL);
252      pipe_texture_reference(&ctx->textures_saved[i], NULL);
253   }
254
255   if (ctx->cache) {
256      cso_cache_delete( ctx->cache );
257      ctx->cache = NULL;
258   }
259}
260
261
262void cso_destroy_context( struct cso_context *ctx )
263{
264   if (ctx) {
265      //cso_release_all( ctx );
266      FREE( ctx );
267   }
268}
269
270
271/* Those function will either find the state of the given template
272 * in the cache or they will create a new state from the given
273 * template, insert it in the cache and return it.
274 */
275
276/*
277 * If the driver returns 0 from the create method then they will assign
278 * the data member of the cso to be the template itself.
279 */
280
281enum pipe_error cso_set_blend(struct cso_context *ctx,
282                              const struct pipe_blend_state *templ)
283{
284   unsigned hash_key = cso_construct_key((void*)templ, sizeof(struct pipe_blend_state));
285   struct cso_hash_iter iter = cso_find_state_template(ctx->cache,
286                                                       hash_key, CSO_BLEND,
287                                                       (void*)templ);
288   void *handle;
289
290   if (cso_hash_iter_is_null(iter)) {
291      struct cso_blend *cso = MALLOC(sizeof(struct cso_blend));
292      if (!cso)
293         return PIPE_ERROR_OUT_OF_MEMORY;
294
295      cso->state = *templ;
296      cso->data = ctx->pipe->create_blend_state(ctx->pipe, &cso->state);
297      cso->delete_state = (cso_state_callback)ctx->pipe->delete_blend_state;
298      cso->context = ctx->pipe;
299
300      iter = cso_insert_state(ctx->cache, hash_key, CSO_BLEND, cso);
301      if (cso_hash_iter_is_null(iter)) {
302         FREE(cso);
303         return PIPE_ERROR_OUT_OF_MEMORY;
304      }
305
306      handle = cso->data;
307   }
308   else {
309      handle = ((struct cso_blend *)cso_hash_iter_data(iter))->data;
310   }
311
312   if (ctx->blend != handle) {
313      ctx->blend = handle;
314      ctx->pipe->bind_blend_state(ctx->pipe, handle);
315   }
316   return PIPE_OK;
317}
318
319void cso_save_blend(struct cso_context *ctx)
320{
321   assert(!ctx->blend_saved);
322   ctx->blend_saved = ctx->blend;
323}
324
325void cso_restore_blend(struct cso_context *ctx)
326{
327   if (ctx->blend != ctx->blend_saved) {
328      ctx->blend = ctx->blend_saved;
329      ctx->pipe->bind_blend_state(ctx->pipe, ctx->blend_saved);
330   }
331   ctx->blend_saved = NULL;
332}
333
334
335
336enum pipe_error cso_single_sampler(struct cso_context *ctx,
337                                   unsigned idx,
338                                   const struct pipe_sampler_state *templ)
339{
340   void *handle = NULL;
341
342   if (templ != NULL) {
343      unsigned hash_key = cso_construct_key((void*)templ, sizeof(struct pipe_sampler_state));
344      struct cso_hash_iter iter = cso_find_state_template(ctx->cache,
345                                                          hash_key, CSO_SAMPLER,
346                                                          (void*)templ);
347
348      if (cso_hash_iter_is_null(iter)) {
349         struct cso_sampler *cso = MALLOC(sizeof(struct cso_sampler));
350         if (!cso)
351            return PIPE_ERROR_OUT_OF_MEMORY;
352
353         cso->state = *templ;
354         cso->data = ctx->pipe->create_sampler_state(ctx->pipe, &cso->state);
355         cso->delete_state = (cso_state_callback)ctx->pipe->delete_sampler_state;
356         cso->context = ctx->pipe;
357
358         iter = cso_insert_state(ctx->cache, hash_key, CSO_SAMPLER, cso);
359         if (cso_hash_iter_is_null(iter)) {
360            FREE(cso);
361            return PIPE_ERROR_OUT_OF_MEMORY;
362         }
363
364         handle = cso->data;
365      }
366      else {
367         handle = ((struct cso_sampler *)cso_hash_iter_data(iter))->data;
368      }
369   }
370
371   ctx->samplers[idx] = handle;
372   return PIPE_OK;
373}
374
375void cso_single_sampler_done( struct cso_context *ctx )
376{
377   unsigned i;
378
379   /* find highest non-null sampler */
380   for (i = PIPE_MAX_SAMPLERS; i > 0; i--) {
381      if (ctx->samplers[i - 1] != NULL)
382         break;
383   }
384
385   ctx->nr_samplers = i;
386
387   if (ctx->hw.nr_samplers != ctx->nr_samplers ||
388       memcmp(ctx->hw.samplers,
389              ctx->samplers,
390              ctx->nr_samplers * sizeof(void *)) != 0)
391   {
392      memcpy(ctx->hw.samplers, ctx->samplers, ctx->nr_samplers * sizeof(void *));
393      ctx->hw.nr_samplers = ctx->nr_samplers;
394
395      ctx->pipe->bind_sampler_states(ctx->pipe, ctx->nr_samplers, ctx->samplers);
396   }
397}
398
399/*
400 * If the function encouters any errors it will return the
401 * last one. Done to always try to set as many samplers
402 * as possible.
403 */
404enum pipe_error cso_set_samplers( struct cso_context *ctx,
405                                  unsigned nr,
406                                  const struct pipe_sampler_state **templates )
407{
408   unsigned i;
409   enum pipe_error temp, error = PIPE_OK;
410
411   /* TODO: fastpath
412    */
413
414   for (i = 0; i < nr; i++) {
415      temp = cso_single_sampler( ctx, i, templates[i] );
416      if (temp != PIPE_OK)
417         error = temp;
418   }
419
420   for ( ; i < ctx->nr_samplers; i++) {
421      temp = cso_single_sampler( ctx, i, NULL );
422      if (temp != PIPE_OK)
423         error = temp;
424   }
425
426   cso_single_sampler_done( ctx );
427
428   return error;
429}
430
431void cso_save_samplers(struct cso_context *ctx)
432{
433   ctx->nr_samplers_saved = ctx->nr_samplers;
434   memcpy(ctx->samplers_saved, ctx->samplers, sizeof(ctx->samplers));
435}
436
437void cso_restore_samplers(struct cso_context *ctx)
438{
439   ctx->nr_samplers = ctx->nr_samplers_saved;
440   memcpy(ctx->samplers, ctx->samplers_saved, sizeof(ctx->samplers));
441   cso_single_sampler_done( ctx );
442}
443
444
445enum pipe_error cso_set_sampler_textures( struct cso_context *ctx,
446                                          uint count,
447                                          struct pipe_texture **textures )
448{
449   uint i;
450
451   ctx->nr_textures = count;
452
453   for (i = 0; i < count; i++)
454      pipe_texture_reference(&ctx->textures[i], textures[i]);
455   for ( ; i < PIPE_MAX_SAMPLERS; i++)
456      pipe_texture_reference(&ctx->textures[i], NULL);
457
458   ctx->pipe->set_sampler_textures(ctx->pipe, count, textures);
459
460   return PIPE_OK;
461}
462
463void cso_save_sampler_textures( struct cso_context *ctx )
464{
465   uint i;
466
467   ctx->nr_textures_saved = ctx->nr_textures;
468   for (i = 0; i < ctx->nr_textures; i++) {
469      assert(!ctx->textures_saved[i]);
470      pipe_texture_reference(&ctx->textures_saved[i], ctx->textures[i]);
471   }
472}
473
474void cso_restore_sampler_textures( struct cso_context *ctx )
475{
476   uint i;
477
478   ctx->nr_textures = ctx->nr_textures_saved;
479
480   for (i = 0; i < ctx->nr_textures; i++) {
481      pipe_texture_reference(&ctx->textures[i], NULL);
482      ctx->textures[i] = ctx->textures_saved[i];
483      ctx->textures_saved[i] = NULL;
484   }
485   for ( ; i < PIPE_MAX_SAMPLERS; i++)
486      pipe_texture_reference(&ctx->textures[i], NULL);
487
488   ctx->pipe->set_sampler_textures(ctx->pipe, ctx->nr_textures, ctx->textures);
489
490   ctx->nr_textures_saved = 0;
491}
492
493
494
495enum pipe_error cso_set_depth_stencil_alpha(struct cso_context *ctx,
496                                            const struct pipe_depth_stencil_alpha_state *templ)
497{
498   unsigned hash_key = cso_construct_key((void*)templ,
499                                         sizeof(struct pipe_depth_stencil_alpha_state));
500   struct cso_hash_iter iter = cso_find_state_template(ctx->cache,
501                                                       hash_key,
502						       CSO_DEPTH_STENCIL_ALPHA,
503                                                       (void*)templ);
504   void *handle;
505
506   if (cso_hash_iter_is_null(iter)) {
507      struct cso_depth_stencil_alpha *cso = MALLOC(sizeof(struct cso_depth_stencil_alpha));
508      if (!cso)
509         return PIPE_ERROR_OUT_OF_MEMORY;
510
511      cso->state = *templ;
512      cso->data = ctx->pipe->create_depth_stencil_alpha_state(ctx->pipe, &cso->state);
513      cso->delete_state = (cso_state_callback)ctx->pipe->delete_depth_stencil_alpha_state;
514      cso->context = ctx->pipe;
515
516      iter = cso_insert_state(ctx->cache, hash_key, CSO_DEPTH_STENCIL_ALPHA, cso);
517      if (cso_hash_iter_is_null(iter)) {
518         FREE(cso);
519         return PIPE_ERROR_OUT_OF_MEMORY;
520      }
521
522      handle = cso->data;
523   }
524   else {
525      handle = ((struct cso_depth_stencil_alpha *)cso_hash_iter_data(iter))->data;
526   }
527
528   if (ctx->depth_stencil != handle) {
529      ctx->depth_stencil = handle;
530      ctx->pipe->bind_depth_stencil_alpha_state(ctx->pipe, handle);
531   }
532   return PIPE_OK;
533}
534
535void cso_save_depth_stencil_alpha(struct cso_context *ctx)
536{
537   assert(!ctx->depth_stencil_saved);
538   ctx->depth_stencil_saved = ctx->depth_stencil;
539}
540
541void cso_restore_depth_stencil_alpha(struct cso_context *ctx)
542{
543   if (ctx->depth_stencil != ctx->depth_stencil_saved) {
544      ctx->depth_stencil = ctx->depth_stencil_saved;
545      ctx->pipe->bind_depth_stencil_alpha_state(ctx->pipe, ctx->depth_stencil_saved);
546   }
547   ctx->depth_stencil_saved = NULL;
548}
549
550
551
552enum pipe_error cso_set_rasterizer(struct cso_context *ctx,
553                                   const struct pipe_rasterizer_state *templ)
554{
555   unsigned hash_key = cso_construct_key((void*)templ,
556                                         sizeof(struct pipe_rasterizer_state));
557   struct cso_hash_iter iter = cso_find_state_template(ctx->cache,
558                                                       hash_key, CSO_RASTERIZER,
559                                                       (void*)templ);
560   void *handle = NULL;
561
562   if (cso_hash_iter_is_null(iter)) {
563      struct cso_rasterizer *cso = MALLOC(sizeof(struct cso_rasterizer));
564      if (!cso)
565         return PIPE_ERROR_OUT_OF_MEMORY;
566
567      cso->state = *templ;
568      cso->data = ctx->pipe->create_rasterizer_state(ctx->pipe, &cso->state);
569      cso->delete_state = (cso_state_callback)ctx->pipe->delete_rasterizer_state;
570      cso->context = ctx->pipe;
571
572      iter = cso_insert_state(ctx->cache, hash_key, CSO_RASTERIZER, cso);
573      if (cso_hash_iter_is_null(iter)) {
574         FREE(cso);
575         return PIPE_ERROR_OUT_OF_MEMORY;
576      }
577
578      handle = cso->data;
579   }
580   else {
581      handle = ((struct cso_rasterizer *)cso_hash_iter_data(iter))->data;
582   }
583
584   if (ctx->rasterizer != handle) {
585      ctx->rasterizer = handle;
586      ctx->pipe->bind_rasterizer_state(ctx->pipe, handle);
587   }
588   return PIPE_OK;
589}
590
591void cso_save_rasterizer(struct cso_context *ctx)
592{
593   assert(!ctx->rasterizer_saved);
594   ctx->rasterizer_saved = ctx->rasterizer;
595}
596
597void cso_restore_rasterizer(struct cso_context *ctx)
598{
599   if (ctx->rasterizer != ctx->rasterizer_saved) {
600      ctx->rasterizer = ctx->rasterizer_saved;
601      ctx->pipe->bind_rasterizer_state(ctx->pipe, ctx->rasterizer_saved);
602   }
603   ctx->rasterizer_saved = NULL;
604}
605
606
607
608enum pipe_error cso_set_fragment_shader_handle(struct cso_context *ctx,
609                                               void *handle )
610{
611   if (ctx->fragment_shader != handle) {
612      ctx->fragment_shader = handle;
613      ctx->pipe->bind_fs_state(ctx->pipe, handle);
614   }
615   return PIPE_OK;
616}
617
618void cso_delete_fragment_shader(struct cso_context *ctx, void *handle )
619{
620   if (handle == ctx->fragment_shader) {
621      /* unbind before deleting */
622      ctx->pipe->bind_fs_state(ctx->pipe, NULL);
623      ctx->fragment_shader = NULL;
624   }
625   ctx->pipe->delete_fs_state(ctx->pipe, handle);
626}
627
628/* Not really working:
629 */
630#if 0
631enum pipe_error cso_set_fragment_shader(struct cso_context *ctx,
632                                        const struct pipe_shader_state *templ)
633{
634   const struct tgsi_token *tokens = templ->tokens;
635   unsigned num_tokens = tgsi_num_tokens(tokens);
636   size_t tokens_size = num_tokens*sizeof(struct tgsi_token);
637   unsigned hash_key = cso_construct_key((void*)tokens, tokens_size);
638   struct cso_hash_iter iter = cso_find_state_template(ctx->cache,
639                                                       hash_key,
640                                                       CSO_FRAGMENT_SHADER,
641                                                       (void*)tokens);
642   void *handle = NULL;
643
644   if (cso_hash_iter_is_null(iter)) {
645      struct cso_fragment_shader *cso = MALLOC(sizeof(struct cso_fragment_shader) + tokens_size);
646      struct tgsi_token *cso_tokens = (struct tgsi_token *)((char *)cso + sizeof(*cso));
647
648      if (!cso)
649         return PIPE_ERROR_OUT_OF_MEMORY;
650
651      memcpy(cso_tokens, tokens, tokens_size);
652      cso->state.tokens = cso_tokens;
653      cso->data = ctx->pipe->create_fs_state(ctx->pipe, &cso->state);
654      cso->delete_state = (cso_state_callback)ctx->pipe->delete_fs_state;
655      cso->context = ctx->pipe;
656
657      iter = cso_insert_state(ctx->cache, hash_key, CSO_FRAGMENT_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_fragment_shader *)cso_hash_iter_data(iter))->data;
667   }
668
669   return cso_set_fragment_shader_handle( ctx, handle );
670}
671#endif
672
673void cso_save_fragment_shader(struct cso_context *ctx)
674{
675   assert(!ctx->fragment_shader_saved);
676   ctx->fragment_shader_saved = ctx->fragment_shader;
677}
678
679void cso_restore_fragment_shader(struct cso_context *ctx)
680{
681   if (ctx->fragment_shader_saved != ctx->fragment_shader) {
682      ctx->pipe->bind_fs_state(ctx->pipe, ctx->fragment_shader_saved);
683      ctx->fragment_shader = ctx->fragment_shader_saved;
684   }
685   ctx->fragment_shader_saved = NULL;
686}
687
688
689enum pipe_error cso_set_vertex_shader_handle(struct cso_context *ctx,
690                                             void *handle )
691{
692   if (ctx->vertex_shader != handle) {
693      ctx->vertex_shader = handle;
694      ctx->pipe->bind_vs_state(ctx->pipe, handle);
695   }
696   return PIPE_OK;
697}
698
699void cso_delete_vertex_shader(struct cso_context *ctx, void *handle )
700{
701   if (handle == ctx->vertex_shader) {
702      /* unbind before deleting */
703      ctx->pipe->bind_vs_state(ctx->pipe, NULL);
704      ctx->vertex_shader = NULL;
705   }
706   ctx->pipe->delete_vs_state(ctx->pipe, handle);
707}
708
709
710/* Not really working:
711 */
712#if 0
713enum pipe_error cso_set_vertex_shader(struct cso_context *ctx,
714                                      const struct pipe_shader_state *templ)
715{
716   unsigned hash_key = cso_construct_key((void*)templ,
717                                         sizeof(struct pipe_shader_state));
718   struct cso_hash_iter iter = cso_find_state_template(ctx->cache,
719                                                       hash_key, CSO_VERTEX_SHADER,
720                                                       (void*)templ);
721   void *handle = NULL;
722
723   if (cso_hash_iter_is_null(iter)) {
724      struct cso_vertex_shader *cso = MALLOC(sizeof(struct cso_vertex_shader));
725
726      if (!cso)
727         return PIPE_ERROR_OUT_OF_MEMORY;
728
729      cso->state = *templ;
730      cso->data = ctx->pipe->create_vs_state(ctx->pipe, &cso->state);
731      cso->delete_state = (cso_state_callback)ctx->pipe->delete_vs_state;
732      cso->context = ctx->pipe;
733
734      iter = cso_insert_state(ctx->cache, hash_key, CSO_VERTEX_SHADER, cso);
735      if (cso_hash_iter_is_null(iter)) {
736         FREE(cso);
737         return PIPE_ERROR_OUT_OF_MEMORY;
738      }
739
740      handle = cso->data;
741   }
742   else {
743      handle = ((struct cso_vertex_shader *)cso_hash_iter_data(iter))->data;
744   }
745
746   return cso_set_vertex_shader_handle( ctx, handle );
747}
748#endif
749
750
751
752void cso_save_vertex_shader(struct cso_context *ctx)
753{
754   assert(!ctx->vertex_shader_saved);
755   ctx->vertex_shader_saved = ctx->vertex_shader;
756}
757
758void cso_restore_vertex_shader(struct cso_context *ctx)
759{
760   if (ctx->vertex_shader_saved != ctx->vertex_shader) {
761      ctx->pipe->bind_vs_state(ctx->pipe, ctx->vertex_shader_saved);
762      ctx->vertex_shader = ctx->vertex_shader_saved;
763   }
764   ctx->vertex_shader_saved = NULL;
765}
766
767
768
769enum pipe_error cso_set_framebuffer(struct cso_context *ctx,
770                                    const struct pipe_framebuffer_state *fb)
771{
772   if (memcmp(&ctx->fb, fb, sizeof(*fb)) != 0) {
773      ctx->fb = *fb;
774      ctx->pipe->set_framebuffer_state(ctx->pipe, fb);
775   }
776   return PIPE_OK;
777}
778
779void cso_save_framebuffer(struct cso_context *ctx)
780{
781   ctx->fb_saved = ctx->fb;
782}
783
784void cso_restore_framebuffer(struct cso_context *ctx)
785{
786   if (memcmp(&ctx->fb, &ctx->fb_saved, sizeof(ctx->fb))) {
787      ctx->fb = ctx->fb_saved;
788      ctx->pipe->set_framebuffer_state(ctx->pipe, &ctx->fb);
789   }
790}
791
792
793enum pipe_error cso_set_viewport(struct cso_context *ctx,
794                                 const struct pipe_viewport_state *vp)
795{
796   if (memcmp(&ctx->vp, vp, sizeof(*vp))) {
797      ctx->vp = *vp;
798      ctx->pipe->set_viewport_state(ctx->pipe, vp);
799   }
800   return PIPE_OK;
801}
802
803void cso_save_viewport(struct cso_context *ctx)
804{
805   ctx->vp_saved = ctx->vp;
806}
807
808
809void cso_restore_viewport(struct cso_context *ctx)
810{
811   if (memcmp(&ctx->vp, &ctx->vp_saved, sizeof(ctx->vp))) {
812      ctx->vp = ctx->vp_saved;
813      ctx->pipe->set_viewport_state(ctx->pipe, &ctx->vp);
814   }
815}
816
817
818
819
820enum pipe_error cso_set_blend_color(struct cso_context *ctx,
821                                    const struct pipe_blend_color *bc)
822{
823   if (memcmp(&ctx->blend_color, bc, sizeof(ctx->blend_color))) {
824      ctx->blend_color = *bc;
825      ctx->pipe->set_blend_color(ctx->pipe, bc);
826   }
827   return PIPE_OK;
828}
829