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