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 /* Authors:
29  *  Brian Paul
30  */
31 
32 #include "util/u_memory.h"
33 #include "util/u_inlines.h"
34 
35 #include "draw/draw_context.h"
36 
37 #include "sp_context.h"
38 #include "sp_state.h"
39 #include "sp_texture.h"
40 #include "sp_tex_sample.h"
41 #include "sp_tex_tile_cache.h"
42 
43 
44 struct sp_sampler {
45    struct pipe_sampler_state base;
46    struct sp_sampler_variant *variants;
47    struct sp_sampler_variant *current;
48 };
49 
sp_sampler(struct pipe_sampler_state * sampler)50 static struct sp_sampler *sp_sampler( struct pipe_sampler_state *sampler )
51 {
52    return (struct sp_sampler *)sampler;
53 }
54 
55 
56 static void *
softpipe_create_sampler_state(struct pipe_context * pipe,const struct pipe_sampler_state * sampler)57 softpipe_create_sampler_state(struct pipe_context *pipe,
58                               const struct pipe_sampler_state *sampler)
59 {
60    struct sp_sampler *sp_sampler = CALLOC_STRUCT(sp_sampler);
61 
62    sp_sampler->base = *sampler;
63    sp_sampler->variants = NULL;
64 
65    return (void *)sp_sampler;
66 }
67 
68 
69 /**
70  * Bind a range [start, start+num-1] of samplers for a shader stage.
71  */
72 static void
softpipe_bind_sampler_states(struct pipe_context * pipe,unsigned shader,unsigned start,unsigned num,void ** samplers)73 softpipe_bind_sampler_states(struct pipe_context *pipe,
74                              unsigned shader,
75                              unsigned start,
76                              unsigned num,
77                              void **samplers)
78 {
79    struct softpipe_context *softpipe = softpipe_context(pipe);
80    unsigned i;
81 
82    assert(shader < PIPE_SHADER_TYPES);
83    assert(start + num <= Elements(softpipe->samplers[shader]));
84 
85    /* Check for no-op */
86    if (start + num <= softpipe->num_samplers[shader] &&
87        !memcmp(softpipe->samplers[shader] + start, samplers,
88                num * sizeof(void *))) {
89       return;
90    }
91 
92    draw_flush(softpipe->draw);
93 
94    /* set the new samplers */
95    for (i = 0; i < num; i++) {
96       softpipe->samplers[shader][start + i] = samplers[i];
97    }
98 
99    /* find highest non-null samplers[] entry */
100    {
101       unsigned j = MAX2(softpipe->num_samplers[shader], start + num);
102       while (j > 0 && softpipe->samplers[shader][j - 1] == NULL)
103          j--;
104       softpipe->num_samplers[shader] = j;
105    }
106 
107    if (shader == PIPE_SHADER_VERTEX || shader == PIPE_SHADER_GEOMETRY) {
108       draw_set_samplers(softpipe->draw,
109                         shader,
110                         softpipe->samplers[shader],
111                         softpipe->num_samplers[shader]);
112    }
113 
114    softpipe->dirty |= SP_NEW_SAMPLER;
115 }
116 
117 
118 
119 static void
softpipe_bind_fragment_sampler_states(struct pipe_context * pipe,unsigned num,void ** samplers)120 softpipe_bind_fragment_sampler_states(struct pipe_context *pipe,
121                                       unsigned num, void **samplers)
122 {
123    softpipe_bind_sampler_states(pipe, PIPE_SHADER_FRAGMENT, 0, num, samplers);
124 }
125 
126 
127 static void
softpipe_bind_vertex_sampler_states(struct pipe_context * pipe,unsigned num,void ** samplers)128 softpipe_bind_vertex_sampler_states(struct pipe_context *pipe,
129                                     unsigned num,
130                                     void **samplers)
131 {
132    softpipe_bind_sampler_states(pipe, PIPE_SHADER_VERTEX, 0, num, samplers);
133 }
134 
135 
136 static void
softpipe_bind_geometry_sampler_states(struct pipe_context * pipe,unsigned num,void ** samplers)137 softpipe_bind_geometry_sampler_states(struct pipe_context *pipe,
138                                       unsigned num,
139                                       void **samplers)
140 {
141    softpipe_bind_sampler_states(pipe, PIPE_SHADER_GEOMETRY, 0, num, samplers);
142 }
143 
144 
145 static struct pipe_sampler_view *
softpipe_create_sampler_view(struct pipe_context * pipe,struct pipe_resource * resource,const struct pipe_sampler_view * templ)146 softpipe_create_sampler_view(struct pipe_context *pipe,
147                              struct pipe_resource *resource,
148                              const struct pipe_sampler_view *templ)
149 {
150    struct pipe_sampler_view *view = CALLOC_STRUCT(pipe_sampler_view);
151 
152    if (view) {
153       *view = *templ;
154       view->reference.count = 1;
155       view->texture = NULL;
156       pipe_resource_reference(&view->texture, resource);
157       view->context = pipe;
158    }
159 
160    return view;
161 }
162 
163 
164 static void
softpipe_sampler_view_destroy(struct pipe_context * pipe,struct pipe_sampler_view * view)165 softpipe_sampler_view_destroy(struct pipe_context *pipe,
166                               struct pipe_sampler_view *view)
167 {
168    pipe_resource_reference(&view->texture, NULL);
169    FREE(view);
170 }
171 
172 
173 static void
softpipe_set_sampler_views(struct pipe_context * pipe,unsigned shader,unsigned start,unsigned num,struct pipe_sampler_view ** views)174 softpipe_set_sampler_views(struct pipe_context *pipe,
175                            unsigned shader,
176                            unsigned start,
177                            unsigned num,
178                            struct pipe_sampler_view **views)
179 {
180    struct softpipe_context *softpipe = softpipe_context(pipe);
181    uint i;
182 
183    assert(shader < PIPE_SHADER_TYPES);
184    assert(start + num <= Elements(softpipe->sampler_views[shader]));
185 
186    /* Check for no-op */
187    if (start + num <= softpipe->num_sampler_views[shader] &&
188        !memcmp(softpipe->sampler_views[shader] + start, views,
189                num * sizeof(struct pipe_sampler_view *))) {
190       return;
191    }
192 
193    draw_flush(softpipe->draw);
194 
195    /* set the new sampler views */
196    for (i = 0; i < num; i++) {
197       pipe_sampler_view_reference(&softpipe->sampler_views[shader][start + i],
198                                   views[i]);
199       sp_tex_tile_cache_set_sampler_view(softpipe->tex_cache[shader][start + i],
200                                          views[i]);
201    }
202 
203    /* find highest non-null sampler_views[] entry */
204    {
205       unsigned j = MAX2(softpipe->num_sampler_views[shader], start + num);
206       while (j > 0 && softpipe->sampler_views[shader][j - 1] == NULL)
207          j--;
208       softpipe->num_sampler_views[shader] = j;
209    }
210 
211    if (shader == PIPE_SHADER_VERTEX || shader == PIPE_SHADER_GEOMETRY) {
212       draw_set_sampler_views(softpipe->draw,
213                              shader,
214                              softpipe->sampler_views[shader],
215                              softpipe->num_sampler_views[shader]);
216    }
217 
218    softpipe->dirty |= SP_NEW_TEXTURE;
219 }
220 
221 
222 static void
softpipe_set_fragment_sampler_views(struct pipe_context * pipe,unsigned num,struct pipe_sampler_view ** views)223 softpipe_set_fragment_sampler_views(struct pipe_context *pipe,
224                                     unsigned num,
225                                     struct pipe_sampler_view **views)
226 {
227    softpipe_set_sampler_views(pipe, PIPE_SHADER_FRAGMENT, 0, num, views);
228 }
229 
230 
231 static void
softpipe_set_vertex_sampler_views(struct pipe_context * pipe,unsigned num,struct pipe_sampler_view ** views)232 softpipe_set_vertex_sampler_views(struct pipe_context *pipe,
233                                   unsigned num,
234                                   struct pipe_sampler_view **views)
235 {
236    softpipe_set_sampler_views(pipe, PIPE_SHADER_VERTEX, 0, num, views);
237 }
238 
239 
240 static void
softpipe_set_geometry_sampler_views(struct pipe_context * pipe,unsigned num,struct pipe_sampler_view ** views)241 softpipe_set_geometry_sampler_views(struct pipe_context *pipe,
242                                     unsigned num,
243                                     struct pipe_sampler_view **views)
244 {
245    softpipe_set_sampler_views(pipe, PIPE_SHADER_GEOMETRY, 0, num, views);
246 }
247 
248 
249 /**
250  * Find/create an sp_sampler_variant object for sampling the given texture,
251  * sampler and tex unit.
252  *
253  * Note that the tex unit is significant.  We can't re-use a sampler
254  * variant for multiple texture units because the sampler variant contains
255  * the texture object pointer.  If the texture object pointer were stored
256  * somewhere outside the sampler variant, we could re-use samplers for
257  * multiple texture units.
258  */
259 static struct sp_sampler_variant *
get_sampler_variant(unsigned unit,struct sp_sampler * sampler,struct pipe_sampler_view * view,unsigned processor)260 get_sampler_variant( unsigned unit,
261                      struct sp_sampler *sampler,
262                      struct pipe_sampler_view *view,
263                      unsigned processor )
264 {
265    struct softpipe_resource *sp_texture = softpipe_resource(view->texture);
266    struct sp_sampler_variant *v = NULL;
267    union sp_sampler_key key;
268 
269    /* if this fails, widen the key.unit field and update this assertion */
270    assert(PIPE_MAX_SAMPLERS <= 16);
271 
272    key.bits.target = sp_texture->base.target;
273    key.bits.is_pot = sp_texture->pot;
274    key.bits.processor = processor;
275    key.bits.unit = unit;
276    key.bits.swizzle_r = view->swizzle_r;
277    key.bits.swizzle_g = view->swizzle_g;
278    key.bits.swizzle_b = view->swizzle_b;
279    key.bits.swizzle_a = view->swizzle_a;
280    key.bits.pad = 0;
281 
282    if (sampler->current &&
283        key.value == sampler->current->key.value) {
284       v = sampler->current;
285    }
286 
287    if (v == NULL) {
288       for (v = sampler->variants; v; v = v->next)
289          if (v->key.value == key.value)
290             break;
291 
292       if (v == NULL) {
293          v = sp_create_sampler_variant( &sampler->base, key );
294          v->next = sampler->variants;
295          sampler->variants = v;
296       }
297    }
298 
299    sampler->current = v;
300    return v;
301 }
302 
303 
304 /**
305  * Reset the sampler variants for a shader stage (vert, frag, geom).
306  */
307 static void
reset_sampler_variants(struct softpipe_context * softpipe,unsigned shader,unsigned tgsi_shader,int max_sampler)308 reset_sampler_variants(struct softpipe_context *softpipe,
309                        unsigned shader,
310                        unsigned tgsi_shader,
311                        int max_sampler)
312 {
313    int i;
314 
315    for (i = 0; i <= max_sampler; i++) {
316       if (softpipe->samplers[shader][i]) {
317          softpipe->tgsi.samplers_list[shader][i] =
318             get_sampler_variant(i,
319                                 sp_sampler(softpipe->samplers[shader][i]),
320                                 softpipe->sampler_views[shader][i],
321                                 tgsi_shader);
322 
323          sp_sampler_variant_bind_view(softpipe->tgsi.samplers_list[shader][i],
324                                       softpipe->tex_cache[shader][i],
325                                       softpipe->sampler_views[shader][i]);
326       }
327    }
328 }
329 
330 
331 void
softpipe_reset_sampler_variants(struct softpipe_context * softpipe)332 softpipe_reset_sampler_variants(struct softpipe_context *softpipe)
333 {
334    /* It's a bit hard to build these samplers ahead of time -- don't
335     * really know which samplers are going to be used for vertex and
336     * fragment programs.
337     */
338 
339    /* XXX note: PIPE_SHADER_x != TGSI_PROCESSOR_x (fix that someday) */
340    reset_sampler_variants(softpipe,
341                           PIPE_SHADER_VERTEX,
342                           TGSI_PROCESSOR_VERTEX,
343                           softpipe->vs->max_sampler);
344 
345    reset_sampler_variants(softpipe,
346                           PIPE_SHADER_FRAGMENT,
347                           TGSI_PROCESSOR_FRAGMENT,
348                           softpipe->fs_variant->info.file_max[TGSI_FILE_SAMPLER]);
349 
350    if (softpipe->gs) {
351       reset_sampler_variants(softpipe,
352                              PIPE_SHADER_GEOMETRY,
353                              TGSI_PROCESSOR_GEOMETRY,
354                              softpipe->gs->max_sampler);
355    }
356 }
357 
358 
359 static void
softpipe_delete_sampler_state(struct pipe_context * pipe,void * sampler)360 softpipe_delete_sampler_state(struct pipe_context *pipe,
361                               void *sampler)
362 {
363    struct sp_sampler *sp_sampler = (struct sp_sampler *)sampler;
364    struct sp_sampler_variant *v, *tmp;
365 
366    for (v = sp_sampler->variants; v; v = tmp) {
367       tmp = v->next;
368       sp_sampler_variant_destroy(v);
369    }
370 
371    FREE( sampler );
372 }
373 
374 
375 void
softpipe_init_sampler_funcs(struct pipe_context * pipe)376 softpipe_init_sampler_funcs(struct pipe_context *pipe)
377 {
378    pipe->create_sampler_state = softpipe_create_sampler_state;
379    pipe->bind_fragment_sampler_states  = softpipe_bind_fragment_sampler_states;
380    pipe->bind_vertex_sampler_states = softpipe_bind_vertex_sampler_states;
381    pipe->bind_geometry_sampler_states = softpipe_bind_geometry_sampler_states;
382    pipe->delete_sampler_state = softpipe_delete_sampler_state;
383 
384    pipe->set_fragment_sampler_views = softpipe_set_fragment_sampler_views;
385    pipe->set_vertex_sampler_views = softpipe_set_vertex_sampler_views;
386    pipe->set_geometry_sampler_views = softpipe_set_geometry_sampler_views;
387 
388    pipe->create_sampler_view = softpipe_create_sampler_view;
389    pipe->sampler_view_destroy = softpipe_sampler_view_destroy;
390 }
391 
392