c08ec7c2e8cf92f52b8d64257da0ed8911c9bcc2
[profile/ivi/mesa.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_screen_texture.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_texture_reference( &view->texture, NULL );
49
50       view->dirty = 1;
51    }
52 }
53
54
55 static int
56 update_tss_binding(struct svga_context *svga, 
57                    unsigned dirty )
58 {
59    unsigned i;
60    unsigned count = MAX2( svga->curr.num_sampler_views,
61                           svga->state.hw_draw.num_views );
62    unsigned min_lod;
63    unsigned max_lod;
64
65
66    struct {
67       struct {
68          unsigned unit;
69          struct svga_hw_view_state *view;
70       } bind[PIPE_MAX_SAMPLERS];
71
72       unsigned bind_count;
73    } queue;
74
75    queue.bind_count = 0;
76    
77    for (i = 0; i < count; i++) {
78       const struct svga_sampler_state *s = svga->curr.sampler[i];
79       struct svga_hw_view_state *view = &svga->state.hw_draw.views[i];
80       struct pipe_texture *texture = NULL;
81
82       /* get min max lod */
83       if (svga->curr.sampler_views[i]) {
84          min_lod = MAX2(s->view_min_lod, 0);
85          max_lod = MIN2(s->view_max_lod, svga->curr.sampler_views[i]->texture->last_level);
86          texture = svga->curr.sampler_views[i]->texture;
87       } else {
88          min_lod = 0;
89          max_lod = 0;
90       }
91
92       if (view->texture != texture ||
93           view->min_lod != min_lod ||
94           view->max_lod != max_lod) {
95
96          svga_sampler_view_reference(&view->v, NULL);
97          pipe_texture_reference( &view->texture, texture );
98
99          view->dirty = TRUE;
100          view->min_lod = min_lod;
101          view->max_lod = max_lod;
102
103          if (texture)
104             view->v = svga_get_tex_sampler_view(&svga->pipe, 
105                                                 texture, 
106                                                 min_lod,
107                                                 max_lod);
108       }
109
110       if (view->dirty) {
111          queue.bind[queue.bind_count].unit = i;
112          queue.bind[queue.bind_count].view = view;
113          queue.bind_count++;
114       } 
115       else if (view->v) {
116          svga_validate_sampler_view(svga, view->v);
117       }
118    }
119
120    svga->state.hw_draw.num_views = svga->curr.num_sampler_views;
121
122    if (queue.bind_count) {
123       SVGA3dTextureState *ts;
124
125       if (SVGA3D_BeginSetTextureState( svga->swc,
126                                        &ts,
127                                        queue.bind_count ) != PIPE_OK)
128          goto fail;
129
130       for (i = 0; i < queue.bind_count; i++) {
131          ts[i].stage = queue.bind[i].unit;
132          ts[i].name = SVGA3D_TS_BIND_TEXTURE;
133
134          if (queue.bind[i].view->v) {
135             svga->swc->surface_relocation(svga->swc,
136                                           &ts[i].value,
137                                           queue.bind[i].view->v->handle,
138                                           PIPE_BUFFER_USAGE_GPU_READ);
139          }
140          else {
141             ts[i].value = SVGA3D_INVALID_ID;
142          }
143          
144          queue.bind[i].view->dirty = FALSE;
145       }
146
147       SVGA_FIFOCommitAll( svga->swc );
148    }
149
150    return 0;
151
152 fail:
153    return PIPE_ERROR_OUT_OF_MEMORY;
154 }
155
156
157 struct svga_tracked_state svga_hw_tss_binding = {
158    "texture binding emit",
159    SVGA_NEW_TEXTURE_BINDING |
160    SVGA_NEW_SAMPLER,
161    update_tss_binding
162 };
163
164
165 /***********************************************************************
166  */
167
168 struct ts_queue {
169    unsigned ts_count;
170    SVGA3dTextureState ts[PIPE_MAX_SAMPLERS*SVGA3D_TS_MAX];
171 };
172
173
174 #define EMIT_TS(svga, unit, val, token, fail)                           \
175 do {                                                                    \
176    if (svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] != val) {        \
177       svga_queue_tss( &queue, unit, SVGA3D_TS_##token, val );           \
178       svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] = val;            \
179    }                                                                    \
180 } while (0)
181
182 #define EMIT_TS_FLOAT(svga, unit, fvalue, token, fail)                  \
183 do {                                                                    \
184    unsigned val = fui(fvalue);                                          \
185    if (svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] != val) {        \
186       svga_queue_tss( &queue, unit, SVGA3D_TS_##token, val );           \
187       svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] = val;            \
188    }                                                                    \
189 } while (0)
190
191
192 static INLINE void 
193 svga_queue_tss( struct ts_queue *q,
194                 unsigned unit,
195                 unsigned tss,
196                 unsigned value )
197 {
198    assert(q->ts_count < sizeof(q->ts)/sizeof(q->ts[0]));
199    q->ts[q->ts_count].stage = unit;
200    q->ts[q->ts_count].name = tss;
201    q->ts[q->ts_count].value = value;
202    q->ts_count++;
203 }
204
205
206 static int
207 update_tss(struct svga_context *svga, 
208            unsigned dirty )
209 {
210    unsigned i;
211    struct ts_queue queue;
212
213    queue.ts_count = 0;
214    for (i = 0; i < svga->curr.num_samplers; i++) {
215       if (svga->curr.sampler[i]) {
216          const struct svga_sampler_state *curr = svga->curr.sampler[i];
217
218          EMIT_TS(svga, i, curr->mipfilter, MIPFILTER, fail);
219          EMIT_TS(svga, i, curr->min_lod, TEXTURE_MIPMAP_LEVEL, fail);
220          EMIT_TS(svga, i, curr->magfilter, MAGFILTER, fail);
221          EMIT_TS(svga, i, curr->minfilter, MINFILTER, fail);
222          EMIT_TS(svga, i, curr->aniso_level, TEXTURE_ANISOTROPIC_LEVEL, fail);
223          EMIT_TS_FLOAT(svga, i, curr->lod_bias, TEXTURE_LOD_BIAS, fail);
224          EMIT_TS(svga, i, curr->addressu, ADDRESSU, fail);
225          EMIT_TS(svga, i, curr->addressw, ADDRESSW, fail);
226          EMIT_TS(svga, i, curr->bordercolor, BORDERCOLOR, fail);
227          // TEXCOORDINDEX -- hopefully not needed
228
229          if (svga->curr.tex_flags.flag_1d & (1 << i)) {
230             debug_printf("wrap 1d tex %d\n", i);
231             EMIT_TS(svga, i, SVGA3D_TEX_ADDRESS_WRAP, ADDRESSV, fail);
232          }
233          else
234             EMIT_TS(svga, i, curr->addressv, ADDRESSV, fail);
235
236          if (svga->curr.tex_flags.flag_srgb & (1 << i))
237             EMIT_TS_FLOAT(svga, i, 2.2f, GAMMA, fail);
238          else
239             EMIT_TS_FLOAT(svga, i, 1.0f, GAMMA, fail);
240
241       }
242    }
243  
244    if (queue.ts_count) {
245       SVGA3dTextureState *ts;
246
247       if (SVGA3D_BeginSetTextureState( svga->swc,
248                                        &ts,
249                                        queue.ts_count ) != PIPE_OK)
250          goto fail;
251
252       memcpy( ts,
253               queue.ts,
254               queue.ts_count * sizeof queue.ts[0]);
255       
256       SVGA_FIFOCommitAll( svga->swc );
257    }
258
259    return 0;
260
261 fail:
262    /* XXX: need to poison cached hardware state on failure to ensure
263     * dirty state gets re-emitted.  Fix this by re-instating partial
264     * FIFOCommit command and only updating cached hw state once the
265     * initial allocation has succeeded.
266     */
267    memset(svga->state.hw_draw.ts, 0xcd, sizeof(svga->state.hw_draw.ts));
268
269    return PIPE_ERROR_OUT_OF_MEMORY;
270 }
271
272
273 struct svga_tracked_state svga_hw_tss = {
274    "texture state emit",
275    (SVGA_NEW_SAMPLER |
276     SVGA_NEW_TEXTURE_FLAGS),
277    update_tss
278 };
279