cso_context.c revision ac87bc18359825890a53d4dbfda5c6eecd916afd
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 *blend;
56   void *depth_stencil;
57   void *rasterizer;
58   void *fragment_shader;
59   void *vertex_shader;
60};
61
62
63struct cso_context *cso_create_context( struct pipe_context *pipe )
64{
65   struct cso_context *ctx = CALLOC_STRUCT(cso_context);
66   if (ctx == NULL)
67      goto out;
68
69   ctx->cache = cso_cache_create();
70   if (ctx->cache == NULL)
71      goto out;
72
73   ctx->pipe = pipe;
74
75   return ctx;
76
77out:
78   cso_destroy_context( ctx );
79   return NULL;
80}
81
82
83void cso_destroy_context( struct cso_context *ctx )
84{
85   if (ctx == NULL)
86      return;
87
88/*
89   if (ctx->pipe)
90      ctx->pipe->flush( ctx->pipe, PIPE_FLUSH_UNBIND_ALL );
91*/
92
93   if (ctx->cache)
94      cso_cache_delete( ctx->cache );
95
96   FREE( ctx );
97}
98
99
100/* Those function will either find the state of the given template
101 * in the cache or they will create a new state from the given
102 * template, insert it in the cache and return it.
103 */
104
105/*
106 * If the driver returns 0 from the create method then they will assign
107 * the data member of the cso to be the template itself.
108 */
109
110void cso_set_blend(struct cso_context *ctx,
111                   const struct pipe_blend_state *templ)
112{
113   unsigned hash_key = cso_construct_key((void*)templ, sizeof(struct pipe_blend_state));
114   struct cso_hash_iter iter = cso_find_state_template(ctx->cache,
115                                                       hash_key, CSO_BLEND,
116                                                       (void*)templ);
117   void *handle;
118
119   if (cso_hash_iter_is_null(iter)) {
120      struct cso_blend *cso = MALLOC(sizeof(struct cso_blend));
121
122      cso->state = *templ;
123      cso->data = ctx->pipe->create_blend_state(ctx->pipe, &cso->state);
124      cso->delete_state = (cso_state_callback)ctx->pipe->delete_blend_state;
125      cso->context = ctx->pipe;
126
127      iter = cso_insert_state(ctx->cache, hash_key, CSO_BLEND, cso);
128      handle = cso->data;
129   }
130   else {
131      handle = ((struct cso_blend *)cso_hash_iter_data(iter))->data;
132   }
133
134   if (ctx->blend != handle) {
135      ctx->blend = handle;
136      ctx->pipe->bind_blend_state(ctx->pipe, handle);
137   }
138}
139
140void cso_single_sampler(struct cso_context *ctx,
141                        unsigned idx,
142                        const struct pipe_sampler_state *templ)
143{
144   void *handle = NULL;
145
146   if (templ != NULL) {
147      unsigned hash_key = cso_construct_key((void*)templ, sizeof(struct pipe_sampler_state));
148      struct cso_hash_iter iter = cso_find_state_template(ctx->cache,
149                                                          hash_key, CSO_SAMPLER,
150                                                          (void*)templ);
151
152      if (cso_hash_iter_is_null(iter)) {
153         struct cso_sampler *cso = MALLOC(sizeof(struct cso_sampler));
154
155         cso->state = *templ;
156         cso->data = ctx->pipe->create_sampler_state(ctx->pipe, &cso->state);
157         cso->delete_state = (cso_state_callback)ctx->pipe->delete_sampler_state;
158         cso->context = ctx->pipe;
159
160         iter = cso_insert_state(ctx->cache, hash_key, CSO_SAMPLER, cso);
161         handle = cso->data;
162      }
163      else {
164         handle = ((struct cso_sampler *)cso_hash_iter_data(iter))->data;
165      }
166   }
167
168   ctx->samplers[idx] = handle;
169}
170
171void cso_single_sampler_done( struct cso_context *ctx )
172{
173   unsigned i;
174
175   for (i = 0; i < 8; i++)
176      if (ctx->samplers[i] == NULL)
177         break;
178
179   ctx->nr_samplers = i;
180
181   if (ctx->hw.nr_samplers != ctx->nr_samplers ||
182       memcmp(ctx->hw.samplers,
183              ctx->samplers,
184              ctx->nr_samplers * sizeof(void *)) != 0)
185   {
186      memcpy(ctx->hw.samplers, ctx->samplers, ctx->nr_samplers * sizeof(void *));
187      ctx->hw.nr_samplers = ctx->nr_samplers;
188
189      ctx->pipe->bind_sampler_states(ctx->pipe, ctx->nr_samplers, ctx->samplers);
190   }
191}
192
193void cso_set_samplers( struct cso_context *ctx,
194                       unsigned nr,
195                       const struct pipe_sampler_state **templates )
196{
197   unsigned i;
198
199   /* TODO: fastpath
200    */
201
202   for (i = 0; i < nr; i++)
203      cso_single_sampler( ctx, i, templates[i] );
204
205   for ( ; i < ctx->nr_samplers; i++)
206      cso_single_sampler( ctx, i, NULL );
207
208   cso_single_sampler_done( ctx );
209}
210
211void cso_set_depth_stencil_alpha(struct cso_context *ctx,
212                                 const struct pipe_depth_stencil_alpha_state *templ)
213{
214   unsigned hash_key = cso_construct_key((void*)templ,
215                                         sizeof(struct pipe_depth_stencil_alpha_state));
216   struct cso_hash_iter iter = cso_find_state_template(ctx->cache,
217                                                       hash_key,
218						       CSO_DEPTH_STENCIL_ALPHA,
219                                                       (void*)templ);
220   void *handle;
221
222   if (cso_hash_iter_is_null(iter)) {
223      struct cso_depth_stencil_alpha *cso = MALLOC(sizeof(struct cso_depth_stencil_alpha));
224
225      cso->state = *templ;
226      cso->data = ctx->pipe->create_depth_stencil_alpha_state(ctx->pipe, &cso->state);
227      cso->delete_state = (cso_state_callback)ctx->pipe->delete_depth_stencil_alpha_state;
228      cso->context = ctx->pipe;
229
230      cso_insert_state(ctx->cache, hash_key, CSO_DEPTH_STENCIL_ALPHA, cso);
231      handle = cso->data;
232   }
233   else {
234      handle = ((struct cso_depth_stencil_alpha *)cso_hash_iter_data(iter))->data;
235   }
236
237   if (ctx->depth_stencil != handle) {
238      ctx->depth_stencil = handle;
239      ctx->pipe->bind_depth_stencil_alpha_state(ctx->pipe, handle);
240   }
241}
242
243
244
245void cso_set_rasterizer(struct cso_context *ctx,
246                              const struct pipe_rasterizer_state *templ)
247{
248   unsigned hash_key = cso_construct_key((void*)templ,
249                                         sizeof(struct pipe_rasterizer_state));
250   struct cso_hash_iter iter = cso_find_state_template(ctx->cache,
251                                                       hash_key, CSO_RASTERIZER,
252                                                       (void*)templ);
253   void *handle = NULL;
254
255   if (cso_hash_iter_is_null(iter)) {
256      struct cso_rasterizer *cso = MALLOC(sizeof(struct cso_rasterizer));
257
258      cso->state = *templ;
259      cso->data = ctx->pipe->create_rasterizer_state(ctx->pipe, &cso->state);
260      cso->delete_state = (cso_state_callback)ctx->pipe->delete_rasterizer_state;
261      cso->context = ctx->pipe;
262
263      cso_insert_state(ctx->cache, hash_key, CSO_RASTERIZER, cso);
264      handle = cso->data;
265   }
266   else {
267      handle = ((struct cso_rasterizer *)cso_hash_iter_data(iter))->data;
268   }
269
270   if (ctx->rasterizer != handle) {
271      ctx->rasterizer = handle;
272      ctx->pipe->bind_rasterizer_state(ctx->pipe, handle);
273   }
274}
275
276
277
278
279
280void cso_set_fragment_shader(struct cso_context *ctx,
281                             const struct pipe_shader_state *templ)
282{
283   unsigned hash_key = cso_construct_key((void*)templ,
284                                         sizeof(struct pipe_shader_state));
285   struct cso_hash_iter iter = cso_find_state_template(ctx->cache,
286                                                       hash_key, CSO_FRAGMENT_SHADER,
287                                                       (void*)templ);
288   void *handle = NULL;
289
290   if (cso_hash_iter_is_null(iter)) {
291      struct cso_fragment_shader *cso = MALLOC(sizeof(struct cso_fragment_shader));
292
293      cso->state = *templ;
294      cso->data = ctx->pipe->create_fs_state(ctx->pipe, &cso->state);
295      cso->delete_state = (cso_state_callback)ctx->pipe->delete_fs_state;
296      cso->context = ctx->pipe;
297
298      iter = cso_insert_state(ctx->cache, hash_key, CSO_FRAGMENT_SHADER, cso);
299      handle = cso->data;
300   }
301   else {
302      handle = ((struct cso_fragment_shader *)cso_hash_iter_data(iter))->data;
303   }
304
305   if (ctx->fragment_shader != handle) {
306      ctx->fragment_shader = handle;
307      ctx->pipe->bind_fs_state(ctx->pipe, handle);
308   }
309}
310
311void cso_set_vertex_shader(struct cso_context *ctx,
312                           const struct pipe_shader_state *templ)
313{
314   unsigned hash_key = cso_construct_key((void*)templ,
315                                         sizeof(struct pipe_shader_state));
316   struct cso_hash_iter iter = cso_find_state_template(ctx->cache,
317                                                       hash_key, CSO_VERTEX_SHADER,
318                                                       (void*)templ);
319   void *handle = NULL;
320
321   if (cso_hash_iter_is_null(iter)) {
322      struct cso_vertex_shader *cso = MALLOC(sizeof(struct cso_vertex_shader));
323
324      cso->state = *templ;
325      cso->data = ctx->pipe->create_vs_state(ctx->pipe, &cso->state);
326      cso->delete_state = (cso_state_callback)ctx->pipe->delete_vs_state;
327      cso->context = ctx->pipe;
328
329      iter = cso_insert_state(ctx->cache, hash_key, CSO_VERTEX_SHADER, cso);
330      handle = cso->data;
331   }
332   else {
333      handle = ((struct cso_vertex_shader *)cso_hash_iter_data(iter))->data;
334   }
335
336   if (ctx->vertex_shader != handle) {
337      ctx->vertex_shader = handle;
338      ctx->pipe->bind_fs_state(ctx->pipe, handle);
339   }
340}
341