cso_context.c revision 7d95efde0a0e13e13c59444703bc47eb13926385
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 /* Wrap the cso cache & hash mechanisms in a simplified
29  * pipe-driver-specific interface.
30  *
31  * Authors:
32  *   Zack Rusin <zack@tungstengraphics.com>
33  *   Keith Whitwell <keith@tungstengraphics.com>
34  */
35
36#include "pipe/p_state.h"
37#include "pipe/p_util.h"
38
39#include "cso_cache/cso_context.h"
40#include "cso_cache/cso_cache.h"
41#include "cso_cache/cso_hash.h"
42
43struct cso_context {
44   struct pipe_context *pipe;
45   struct cso_cache *cache;
46
47   struct {
48      void *samplers[PIPE_MAX_SAMPLERS];
49      unsigned nr_samplers;
50   } hw;
51
52   void *samplers[PIPE_MAX_SAMPLERS];
53   unsigned nr_samplers;
54
55   void *samplers_saved[PIPE_MAX_SAMPLERS];
56   unsigned nr_samplers_saved;
57
58   struct pipe_texture *textures[PIPE_MAX_SAMPLERS];
59   uint nr_textures;
60
61   struct pipe_texture *textures_saved[PIPE_MAX_SAMPLERS];
62   uint nr_textures_saved;
63
64   /** Current and saved state.
65    * The saved state is used as a 1-deep stack.
66    */
67   void *blend, *blend_saved;
68   void *depth_stencil, *depth_stencil_saved;
69   void *rasterizer, *rasterizer_saved;
70   void *fragment_shader, *fragment_shader_saved;
71   void *vertex_shader, *vertex_shader_saved;
72
73   struct pipe_framebuffer_state fb, fb_saved;
74   struct pipe_viewport_state vp, vp_saved;
75   struct pipe_blend_color blend_color;
76};
77
78
79struct cso_context *cso_create_context( struct pipe_context *pipe )
80{
81   struct cso_context *ctx = CALLOC_STRUCT(cso_context);
82   if (ctx == NULL)
83      goto out;
84
85   ctx->cache = cso_cache_create();
86   if (ctx->cache == NULL)
87      goto out;
88
89   ctx->pipe = pipe;
90
91   /* Enable for testing: */
92   if (0) cso_set_maximum_cache_size( ctx->cache, 4 );
93
94   return ctx;
95
96out:
97   cso_destroy_context( ctx );
98   return NULL;
99}
100
101static void cso_release_all( struct cso_context *ctx )
102{
103   if (ctx->pipe) {
104      ctx->pipe->bind_blend_state( ctx->pipe, NULL );
105      ctx->pipe->bind_rasterizer_state( ctx->pipe, NULL );
106      ctx->pipe->bind_sampler_states( ctx->pipe, 0, NULL );
107      ctx->pipe->bind_depth_stencil_alpha_state( ctx->pipe, NULL );
108      ctx->pipe->bind_fs_state( ctx->pipe, NULL );
109      ctx->pipe->bind_vs_state( ctx->pipe, NULL );
110   }
111
112   if (ctx->cache) {
113      cso_cache_delete( ctx->cache );
114      ctx->cache = NULL;
115   }
116}
117
118
119void cso_destroy_context( struct cso_context *ctx )
120{
121   if (ctx)
122      cso_release_all( ctx );
123
124   FREE( ctx );
125}
126
127
128/* Those function will either find the state of the given template
129 * in the cache or they will create a new state from the given
130 * template, insert it in the cache and return it.
131 */
132
133/*
134 * If the driver returns 0 from the create method then they will assign
135 * the data member of the cso to be the template itself.
136 */
137
138void cso_set_blend(struct cso_context *ctx,
139                   const struct pipe_blend_state *templ)
140{
141   unsigned hash_key = cso_construct_key((void*)templ, sizeof(struct pipe_blend_state));
142   struct cso_hash_iter iter = cso_find_state_template(ctx->cache,
143                                                       hash_key, CSO_BLEND,
144                                                       (void*)templ);
145   void *handle;
146
147   if (cso_hash_iter_is_null(iter)) {
148      struct cso_blend *cso = MALLOC(sizeof(struct cso_blend));
149
150      cso->state = *templ;
151      cso->data = ctx->pipe->create_blend_state(ctx->pipe, &cso->state);
152      cso->delete_state = (cso_state_callback)ctx->pipe->delete_blend_state;
153      cso->context = ctx->pipe;
154
155      iter = cso_insert_state(ctx->cache, hash_key, CSO_BLEND, cso);
156      handle = cso->data;
157   }
158   else {
159      handle = ((struct cso_blend *)cso_hash_iter_data(iter))->data;
160   }
161
162   if (ctx->blend != handle) {
163      ctx->blend = handle;
164      ctx->pipe->bind_blend_state(ctx->pipe, handle);
165   }
166}
167
168void cso_save_blend(struct cso_context *ctx)
169{
170   assert(!ctx->blend_saved);
171   ctx->blend_saved = ctx->blend;
172}
173
174void cso_restore_blend(struct cso_context *ctx)
175{
176   if (ctx->blend != ctx->blend_saved) {
177      ctx->blend = ctx->blend_saved;
178      ctx->pipe->bind_blend_state(ctx->pipe, ctx->blend_saved);
179   }
180   ctx->blend_saved = NULL;
181}
182
183
184
185void cso_single_sampler(struct cso_context *ctx,
186                        unsigned idx,
187                        const struct pipe_sampler_state *templ)
188{
189   void *handle = NULL;
190
191   if (templ != NULL) {
192      unsigned hash_key = cso_construct_key((void*)templ, sizeof(struct pipe_sampler_state));
193      struct cso_hash_iter iter = cso_find_state_template(ctx->cache,
194                                                          hash_key, CSO_SAMPLER,
195                                                          (void*)templ);
196
197      if (cso_hash_iter_is_null(iter)) {
198         struct cso_sampler *cso = MALLOC(sizeof(struct cso_sampler));
199
200         cso->state = *templ;
201         cso->data = ctx->pipe->create_sampler_state(ctx->pipe, &cso->state);
202         cso->delete_state = (cso_state_callback)ctx->pipe->delete_sampler_state;
203         cso->context = ctx->pipe;
204
205         iter = cso_insert_state(ctx->cache, hash_key, CSO_SAMPLER, cso);
206         handle = cso->data;
207      }
208      else {
209         handle = ((struct cso_sampler *)cso_hash_iter_data(iter))->data;
210      }
211   }
212
213   ctx->samplers[idx] = handle;
214}
215
216void cso_single_sampler_done( struct cso_context *ctx )
217{
218   unsigned i;
219
220   for (i = 0; i < 8; i++)
221      if (ctx->samplers[i] == NULL)
222         break;
223
224   ctx->nr_samplers = i;
225
226   if (ctx->hw.nr_samplers != ctx->nr_samplers ||
227       memcmp(ctx->hw.samplers,
228              ctx->samplers,
229              ctx->nr_samplers * sizeof(void *)) != 0)
230   {
231      memcpy(ctx->hw.samplers, ctx->samplers, ctx->nr_samplers * sizeof(void *));
232      ctx->hw.nr_samplers = ctx->nr_samplers;
233
234      ctx->pipe->bind_sampler_states(ctx->pipe, ctx->nr_samplers, ctx->samplers);
235   }
236}
237
238void cso_set_samplers( struct cso_context *ctx,
239                       unsigned nr,
240                       const struct pipe_sampler_state **templates )
241{
242   unsigned i;
243
244   /* TODO: fastpath
245    */
246
247   for (i = 0; i < nr; i++)
248      cso_single_sampler( ctx, i, templates[i] );
249
250   for ( ; i < ctx->nr_samplers; i++)
251      cso_single_sampler( ctx, i, NULL );
252
253   cso_single_sampler_done( ctx );
254}
255
256void cso_save_samplers(struct cso_context *ctx)
257{
258   ctx->nr_samplers_saved = ctx->nr_samplers;
259   memcpy(ctx->samplers_saved, ctx->samplers, sizeof(ctx->samplers));
260}
261
262void cso_restore_samplers(struct cso_context *ctx)
263{
264   cso_set_samplers(ctx, ctx->nr_samplers_saved,
265                    (const struct pipe_sampler_state **) ctx->samplers_saved);
266}
267
268
269void cso_set_sampler_textures( struct cso_context *ctx,
270                               uint count,
271                               struct pipe_texture **textures )
272{
273   uint i;
274
275   ctx->nr_textures = count;
276
277   for (i = 0; i < count; i++)
278      ctx->textures[i] = textures[i];
279   for ( ; i < PIPE_MAX_SAMPLERS; i++)
280      ctx->textures[i] = NULL;
281
282   ctx->pipe->set_sampler_textures(ctx->pipe, count, textures);
283}
284
285void cso_save_sampler_textures( struct cso_context *ctx )
286{
287   ctx->nr_textures_saved = ctx->nr_textures;
288   memcpy(ctx->textures_saved, ctx->textures, sizeof(ctx->textures));
289}
290
291void cso_restore_sampler_textures( struct cso_context *ctx )
292{
293   cso_set_sampler_textures(ctx, ctx->nr_textures_saved, ctx->textures_saved);
294   ctx->nr_textures_saved = 0;
295}
296
297
298
299
300void cso_set_depth_stencil_alpha(struct cso_context *ctx,
301                                 const struct pipe_depth_stencil_alpha_state *templ)
302{
303   unsigned hash_key = cso_construct_key((void*)templ,
304                                         sizeof(struct pipe_depth_stencil_alpha_state));
305   struct cso_hash_iter iter = cso_find_state_template(ctx->cache,
306                                                       hash_key,
307						       CSO_DEPTH_STENCIL_ALPHA,
308                                                       (void*)templ);
309   void *handle;
310
311   if (cso_hash_iter_is_null(iter)) {
312      struct cso_depth_stencil_alpha *cso = MALLOC(sizeof(struct cso_depth_stencil_alpha));
313
314      cso->state = *templ;
315      cso->data = ctx->pipe->create_depth_stencil_alpha_state(ctx->pipe, &cso->state);
316      cso->delete_state = (cso_state_callback)ctx->pipe->delete_depth_stencil_alpha_state;
317      cso->context = ctx->pipe;
318
319      cso_insert_state(ctx->cache, hash_key, CSO_DEPTH_STENCIL_ALPHA, cso);
320      handle = cso->data;
321   }
322   else {
323      handle = ((struct cso_depth_stencil_alpha *)cso_hash_iter_data(iter))->data;
324   }
325
326   if (ctx->depth_stencil != handle) {
327      ctx->depth_stencil = handle;
328      ctx->pipe->bind_depth_stencil_alpha_state(ctx->pipe, handle);
329   }
330}
331
332void cso_save_depth_stencil_alpha(struct cso_context *ctx)
333{
334   assert(!ctx->depth_stencil_saved);
335   ctx->depth_stencil_saved = ctx->depth_stencil;
336}
337
338void cso_restore_depth_stencil_alpha(struct cso_context *ctx)
339{
340   if (ctx->depth_stencil != ctx->depth_stencil_saved) {
341      ctx->depth_stencil = ctx->depth_stencil_saved;
342      ctx->pipe->bind_depth_stencil_alpha_state(ctx->pipe, ctx->depth_stencil_saved);
343   }
344   ctx->depth_stencil_saved = NULL;
345}
346
347
348
349void cso_set_rasterizer(struct cso_context *ctx,
350                        const struct pipe_rasterizer_state *templ)
351{
352   unsigned hash_key = cso_construct_key((void*)templ,
353                                         sizeof(struct pipe_rasterizer_state));
354   struct cso_hash_iter iter = cso_find_state_template(ctx->cache,
355                                                       hash_key, CSO_RASTERIZER,
356                                                       (void*)templ);
357   void *handle = NULL;
358
359   if (cso_hash_iter_is_null(iter)) {
360      struct cso_rasterizer *cso = MALLOC(sizeof(struct cso_rasterizer));
361
362      cso->state = *templ;
363      cso->data = ctx->pipe->create_rasterizer_state(ctx->pipe, &cso->state);
364      cso->delete_state = (cso_state_callback)ctx->pipe->delete_rasterizer_state;
365      cso->context = ctx->pipe;
366
367      cso_insert_state(ctx->cache, hash_key, CSO_RASTERIZER, cso);
368      handle = cso->data;
369   }
370   else {
371      handle = ((struct cso_rasterizer *)cso_hash_iter_data(iter))->data;
372   }
373
374   if (ctx->rasterizer != handle) {
375      ctx->rasterizer = handle;
376      ctx->pipe->bind_rasterizer_state(ctx->pipe, handle);
377   }
378}
379
380void cso_save_rasterizer(struct cso_context *ctx)
381{
382   assert(!ctx->rasterizer_saved);
383   ctx->rasterizer_saved = ctx->rasterizer;
384}
385
386void cso_restore_rasterizer(struct cso_context *ctx)
387{
388   if (ctx->rasterizer != ctx->rasterizer_saved) {
389      ctx->rasterizer = ctx->rasterizer_saved;
390      ctx->pipe->bind_rasterizer_state(ctx->pipe, ctx->rasterizer_saved);
391   }
392   ctx->rasterizer_saved = NULL;
393}
394
395
396void cso_set_fragment_shader(struct cso_context *ctx,
397                             const struct pipe_shader_state *templ)
398{
399   unsigned hash_key = cso_construct_key((void*)templ,
400                                         sizeof(struct pipe_shader_state));
401   struct cso_hash_iter iter = cso_find_state_template(ctx->cache,
402                                                       hash_key, CSO_FRAGMENT_SHADER,
403                                                       (void*)templ);
404   void *handle = NULL;
405
406   if (cso_hash_iter_is_null(iter)) {
407      struct cso_fragment_shader *cso = MALLOC(sizeof(struct cso_fragment_shader));
408
409      cso->state = *templ;
410      cso->data = ctx->pipe->create_fs_state(ctx->pipe, &cso->state);
411      cso->delete_state = (cso_state_callback)ctx->pipe->delete_fs_state;
412      cso->context = ctx->pipe;
413
414      iter = cso_insert_state(ctx->cache, hash_key, CSO_FRAGMENT_SHADER, cso);
415      handle = cso->data;
416   }
417   else {
418      handle = ((struct cso_fragment_shader *)cso_hash_iter_data(iter))->data;
419   }
420
421   if (ctx->fragment_shader != handle) {
422      ctx->fragment_shader = handle;
423      ctx->pipe->bind_fs_state(ctx->pipe, handle);
424   }
425}
426
427void cso_save_fragment_shader(struct cso_context *ctx)
428{
429   assert(!ctx->fragment_shader_saved);
430   ctx->fragment_shader_saved = ctx->fragment_shader;
431}
432
433void cso_restore_fragment_shader(struct cso_context *ctx)
434{
435   assert(ctx->fragment_shader_saved);
436   if (ctx->fragment_shader_saved != ctx->fragment_shader) {
437      ctx->pipe->bind_fs_state(ctx->pipe, ctx->fragment_shader_saved);
438      ctx->fragment_shader = ctx->fragment_shader_saved;
439   }
440   ctx->fragment_shader_saved = NULL;
441}
442
443
444
445void cso_set_vertex_shader(struct cso_context *ctx,
446                           const struct pipe_shader_state *templ)
447{
448   unsigned hash_key = cso_construct_key((void*)templ,
449                                         sizeof(struct pipe_shader_state));
450   struct cso_hash_iter iter = cso_find_state_template(ctx->cache,
451                                                       hash_key, CSO_VERTEX_SHADER,
452                                                       (void*)templ);
453   void *handle = NULL;
454
455   if (cso_hash_iter_is_null(iter)) {
456      struct cso_vertex_shader *cso = MALLOC(sizeof(struct cso_vertex_shader));
457
458      cso->state = *templ;
459      cso->data = ctx->pipe->create_vs_state(ctx->pipe, &cso->state);
460      cso->delete_state = (cso_state_callback)ctx->pipe->delete_vs_state;
461      cso->context = ctx->pipe;
462
463      iter = cso_insert_state(ctx->cache, hash_key, CSO_VERTEX_SHADER, cso);
464      handle = cso->data;
465   }
466   else {
467      handle = ((struct cso_vertex_shader *)cso_hash_iter_data(iter))->data;
468   }
469
470   if (ctx->vertex_shader != handle) {
471      ctx->vertex_shader = handle;
472      ctx->pipe->bind_vs_state(ctx->pipe, handle);
473   }
474}
475
476void cso_save_vertex_shader(struct cso_context *ctx)
477{
478   assert(!ctx->vertex_shader_saved);
479   ctx->vertex_shader_saved = ctx->vertex_shader;
480}
481
482void cso_restore_vertex_shader(struct cso_context *ctx)
483{
484   assert(ctx->vertex_shader_saved);
485   if (ctx->vertex_shader_saved != ctx->vertex_shader) {
486      ctx->pipe->bind_fs_state(ctx->pipe, ctx->vertex_shader_saved);
487      ctx->vertex_shader = ctx->vertex_shader_saved;
488   }
489   ctx->vertex_shader_saved = NULL;
490}
491
492
493
494void cso_set_framebuffer(struct cso_context *ctx,
495                         const struct pipe_framebuffer_state *fb)
496{
497   if (memcmp(&ctx->fb, fb, sizeof(*fb))) {
498      ctx->fb = *fb;
499      ctx->pipe->set_framebuffer_state(ctx->pipe, fb);
500   }
501}
502
503void cso_save_framebuffer(struct cso_context *ctx)
504{
505   ctx->fb_saved = ctx->fb;
506}
507
508void cso_restore_framebuffer(struct cso_context *ctx)
509{
510   if (memcmp(&ctx->fb, &ctx->fb_saved, sizeof(ctx->fb))) {
511      ctx->fb = ctx->fb_saved;
512      ctx->pipe->set_framebuffer_state(ctx->pipe, &ctx->fb);
513   }
514}
515
516
517void cso_set_viewport(struct cso_context *ctx,
518                      const struct pipe_viewport_state *vp)
519{
520   if (memcmp(&ctx->vp, vp, sizeof(*vp))) {
521      ctx->vp = *vp;
522      ctx->pipe->set_viewport_state(ctx->pipe, vp);
523   }
524}
525
526void cso_save_viewport(struct cso_context *ctx)
527{
528   ctx->vp_saved = ctx->vp;
529}
530
531
532void cso_restore_viewport(struct cso_context *ctx)
533{
534   if (memcmp(&ctx->vp, &ctx->vp_saved, sizeof(ctx->vp))) {
535      ctx->vp = ctx->vp_saved;
536      ctx->pipe->set_viewport_state(ctx->pipe, &ctx->vp);
537   }
538}
539
540
541
542
543void cso_set_blend_color(struct cso_context *ctx,
544                         const struct pipe_blend_color *bc)
545{
546   if (memcmp(&ctx->blend_color, bc, sizeof(ctx->blend_color))) {
547      ctx->blend_color = *bc;
548      ctx->pipe->set_blend_color(ctx->pipe, bc);
549   }
550}
551