Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / gallium / drivers / svga / svga_state_tss.c
1 /**********************************************************
2  * Copyright 2008-2009 VMware, Inc.  All rights reserved.
3  *
4  * Permission is hereby granted, free of charge, to any person
5  * obtaining a copy of this software and associated documentation
6  * files (the "Software"), to deal in the Software without
7  * restriction, including without limitation the rights to use, copy,
8  * modify, merge, publish, distribute, sublicense, and/or sell copies
9  * of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  *
24  **********************************************************/
25
26 #include "util/u_inlines.h"
27 #include "pipe/p_defines.h"
28 #include "util/u_math.h"
29
30 #include "svga_sampler_view.h"
31 #include "svga_winsys.h"
32 #include "svga_context.h"
33 #include "svga_state.h"
34 #include "svga_cmd.h"
35
36
37 void svga_cleanup_tss_binding(struct svga_context *svga)
38 {
39    int i;
40    unsigned count = MAX2( svga->curr.num_sampler_views,
41                           svga->state.hw_draw.num_views );
42
43    for (i = 0; i < count; i++) {
44       struct svga_hw_view_state *view = &svga->state.hw_draw.views[i];
45
46       svga_sampler_view_reference(&view->v, NULL);
47       pipe_sampler_view_reference( &svga->curr.sampler_views[i], NULL );
48       pipe_resource_reference( &view->texture, NULL );
49
50       view->dirty = 1;
51    }
52 }
53
54
55 struct bind_queue {
56    struct {
57       unsigned unit;
58       struct svga_hw_view_state *view;
59    } bind[PIPE_MAX_SAMPLERS];
60
61    unsigned bind_count;
62 };
63
64
65 static int
66 update_tss_binding(struct svga_context *svga, 
67                    unsigned dirty )
68 {
69    boolean reemit = svga->rebind.texture_samplers;
70    unsigned i;
71    unsigned count = MAX2( svga->curr.num_sampler_views,
72                           svga->state.hw_draw.num_views );
73    unsigned min_lod;
74    unsigned max_lod;
75
76    struct bind_queue queue;
77
78    queue.bind_count = 0;
79    
80    for (i = 0; i < count; i++) {
81       const struct svga_sampler_state *s = svga->curr.sampler[i];
82       struct svga_hw_view_state *view = &svga->state.hw_draw.views[i];
83       struct pipe_resource *texture = NULL;
84
85       /* get min max lod */
86       if (svga->curr.sampler_views[i]) {
87          min_lod = MAX2(s->view_min_lod, 0);
88          max_lod = MIN2(s->view_max_lod, svga->curr.sampler_views[i]->texture->last_level);
89          texture = svga->curr.sampler_views[i]->texture;
90       } else {
91          min_lod = 0;
92          max_lod = 0;
93       }
94
95       if (view->texture != texture ||
96           view->min_lod != min_lod ||
97           view->max_lod != max_lod) {
98
99          svga_sampler_view_reference(&view->v, NULL);
100          pipe_resource_reference( &view->texture, texture );
101
102          view->dirty = TRUE;
103          view->min_lod = min_lod;
104          view->max_lod = max_lod;
105
106          if (texture)
107             view->v = svga_get_tex_sampler_view(&svga->pipe, 
108                                                 texture, 
109                                                 min_lod,
110                                                 max_lod);
111       }
112
113       /*
114        * We need to reemit non-null texture bindings, even when they are not
115        * dirty, to ensure that the resources are paged in.
116        */
117
118       if (view->dirty ||
119           (reemit && view->v)) {
120          queue.bind[queue.bind_count].unit = i;
121          queue.bind[queue.bind_count].view = view;
122          queue.bind_count++;
123       } 
124       if (!view->dirty && view->v) {
125          svga_validate_sampler_view(svga, view->v);
126       }
127    }
128
129    svga->state.hw_draw.num_views = svga->curr.num_sampler_views;
130
131    if (queue.bind_count) {
132       SVGA3dTextureState *ts;
133
134       if (SVGA3D_BeginSetTextureState( svga->swc,
135                                        &ts,
136                                        queue.bind_count ) != PIPE_OK)
137          goto fail;
138
139       for (i = 0; i < queue.bind_count; i++) {
140          struct svga_winsys_surface *handle;
141
142          ts[i].stage = queue.bind[i].unit;
143          ts[i].name = SVGA3D_TS_BIND_TEXTURE;
144
145          if (queue.bind[i].view->v) {
146             handle = queue.bind[i].view->v->handle;
147          }
148          else {
149             handle = NULL;
150          }
151          svga->swc->surface_relocation(svga->swc,
152                                        &ts[i].value,
153                                        handle,
154                                        SVGA_RELOC_READ);
155          
156          queue.bind[i].view->dirty = FALSE;
157       }
158
159       SVGA_FIFOCommitAll( svga->swc );
160    }
161
162    svga->rebind.texture_samplers = FALSE;
163
164    return 0;
165
166 fail:
167    return PIPE_ERROR_OUT_OF_MEMORY;
168 }
169
170
171 /*
172  * Rebind textures.
173  *
174  * Similar to update_tss_binding, but without any state checking/update.
175  *
176  * Called at the beginning of every new command buffer to ensure that
177  * non-dirty textures are properly paged-in.
178  */
179 enum pipe_error
180 svga_reemit_tss_bindings(struct svga_context *svga)
181 {
182    unsigned i;
183    enum pipe_error ret;
184    struct bind_queue queue;
185
186    assert(svga->rebind.texture_samplers);
187
188    queue.bind_count = 0;
189
190    for (i = 0; i < svga->state.hw_draw.num_views; i++) {
191       struct svga_hw_view_state *view = &svga->state.hw_draw.views[i];
192
193       if (view->v) {
194          queue.bind[queue.bind_count].unit = i;
195          queue.bind[queue.bind_count].view = view;
196          queue.bind_count++;
197       }
198    }
199
200    if (queue.bind_count) {
201       SVGA3dTextureState *ts;
202
203       ret = SVGA3D_BeginSetTextureState(svga->swc,
204                                         &ts,
205                                         queue.bind_count);
206       if (ret != PIPE_OK) {
207          return ret;
208       }
209
210       for (i = 0; i < queue.bind_count; i++) {
211          struct svga_winsys_surface *handle;
212
213          ts[i].stage = queue.bind[i].unit;
214          ts[i].name = SVGA3D_TS_BIND_TEXTURE;
215
216          assert(queue.bind[i].view->v);
217          handle = queue.bind[i].view->v->handle;
218          svga->swc->surface_relocation(svga->swc,
219                                        &ts[i].value,
220                                        handle,
221                                        SVGA_RELOC_READ);
222       }
223
224       SVGA_FIFOCommitAll(svga->swc);
225    }
226
227    svga->rebind.texture_samplers = FALSE;
228
229    return PIPE_OK;
230 }
231
232
233 struct svga_tracked_state svga_hw_tss_binding = {
234    "texture binding emit",
235    SVGA_NEW_TEXTURE_BINDING |
236    SVGA_NEW_SAMPLER,
237    update_tss_binding
238 };
239
240
241 /***********************************************************************
242  */
243
244 struct ts_queue {
245    unsigned ts_count;
246    SVGA3dTextureState ts[PIPE_MAX_SAMPLERS*SVGA3D_TS_MAX];
247 };
248
249
250 #define EMIT_TS(svga, unit, val, token, fail)                           \
251 do {                                                                    \
252    if (svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] != val) {        \
253       svga_queue_tss( &queue, unit, SVGA3D_TS_##token, val );           \
254       svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] = val;            \
255    }                                                                    \
256 } while (0)
257
258 #define EMIT_TS_FLOAT(svga, unit, fvalue, token, fail)                  \
259 do {                                                                    \
260    unsigned val = fui(fvalue);                                          \
261    if (svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] != val) {        \
262       svga_queue_tss( &queue, unit, SVGA3D_TS_##token, val );           \
263       svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] = val;            \
264    }                                                                    \
265 } while (0)
266
267
268 static INLINE void 
269 svga_queue_tss( struct ts_queue *q,
270                 unsigned unit,
271                 unsigned tss,
272                 unsigned value )
273 {
274    assert(q->ts_count < sizeof(q->ts)/sizeof(q->ts[0]));
275    q->ts[q->ts_count].stage = unit;
276    q->ts[q->ts_count].name = tss;
277    q->ts[q->ts_count].value = value;
278    q->ts_count++;
279 }
280
281
282 static int
283 update_tss(struct svga_context *svga, 
284            unsigned dirty )
285 {
286    unsigned i;
287    struct ts_queue queue;
288
289    queue.ts_count = 0;
290    for (i = 0; i < svga->curr.num_samplers; i++) {
291       if (svga->curr.sampler[i]) {
292          const struct svga_sampler_state *curr = svga->curr.sampler[i];
293
294          EMIT_TS(svga, i, curr->mipfilter, MIPFILTER, fail);
295          EMIT_TS(svga, i, curr->min_lod, TEXTURE_MIPMAP_LEVEL, fail);
296          EMIT_TS(svga, i, curr->magfilter, MAGFILTER, fail);
297          EMIT_TS(svga, i, curr->minfilter, MINFILTER, fail);
298          EMIT_TS(svga, i, curr->aniso_level, TEXTURE_ANISOTROPIC_LEVEL, fail);
299          EMIT_TS_FLOAT(svga, i, curr->lod_bias, TEXTURE_LOD_BIAS, fail);
300          EMIT_TS(svga, i, curr->addressu, ADDRESSU, fail);
301          EMIT_TS(svga, i, curr->addressw, ADDRESSW, fail);
302          EMIT_TS(svga, i, curr->bordercolor, BORDERCOLOR, fail);
303          // TEXCOORDINDEX -- hopefully not needed
304
305          if (svga->curr.tex_flags.flag_1d & (1 << i)) {
306             EMIT_TS(svga, i, SVGA3D_TEX_ADDRESS_WRAP, ADDRESSV, fail);
307          }
308          else
309             EMIT_TS(svga, i, curr->addressv, ADDRESSV, fail);
310
311          if (svga->curr.tex_flags.flag_srgb & (1 << i))
312             EMIT_TS_FLOAT(svga, i, 2.2f, GAMMA, fail);
313          else
314             EMIT_TS_FLOAT(svga, i, 1.0f, GAMMA, fail);
315
316       }
317    }
318  
319    if (queue.ts_count) {
320       SVGA3dTextureState *ts;
321
322       if (SVGA3D_BeginSetTextureState( svga->swc,
323                                        &ts,
324                                        queue.ts_count ) != PIPE_OK)
325          goto fail;
326
327       memcpy( ts,
328               queue.ts,
329               queue.ts_count * sizeof queue.ts[0]);
330       
331       SVGA_FIFOCommitAll( svga->swc );
332    }
333
334    return 0;
335
336 fail:
337    /* XXX: need to poison cached hardware state on failure to ensure
338     * dirty state gets re-emitted.  Fix this by re-instating partial
339     * FIFOCommit command and only updating cached hw state once the
340     * initial allocation has succeeded.
341     */
342    memset(svga->state.hw_draw.ts, 0xcd, sizeof(svga->state.hw_draw.ts));
343
344    return PIPE_ERROR_OUT_OF_MEMORY;
345 }
346
347
348 struct svga_tracked_state svga_hw_tss = {
349    "texture state emit",
350    (SVGA_NEW_SAMPLER |
351     SVGA_NEW_TEXTURE_FLAGS),
352    update_tss
353 };
354