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 "util/u_memory.h"
28 #include "pipe/p_defines.h"
29 #include "util/u_math.h"
30 
31 #include "svga_sampler_view.h"
32 #include "svga_winsys.h"
33 #include "svga_context.h"
34 #include "svga_state.h"
35 #include "svga_cmd.h"
36 
37 
svga_cleanup_tss_binding(struct svga_context * svga)38 void svga_cleanup_tss_binding(struct svga_context *svga)
39 {
40    int i;
41    unsigned count = MAX2( svga->curr.num_sampler_views,
42                           svga->state.hw_draw.num_views );
43 
44    for (i = 0; i < count; i++) {
45       struct svga_hw_view_state *view = &svga->state.hw_draw.views[i];
46 
47       svga_sampler_view_reference(&view->v, NULL);
48       pipe_sampler_view_reference( &svga->curr.sampler_views[i], NULL );
49       pipe_resource_reference( &view->texture, NULL );
50 
51       view->dirty = 1;
52    }
53 }
54 
55 
56 struct bind_queue {
57    struct {
58       unsigned unit;
59       struct svga_hw_view_state *view;
60    } bind[PIPE_MAX_SAMPLERS];
61 
62    unsigned bind_count;
63 };
64 
65 
66 static enum pipe_error
update_tss_binding(struct svga_context * svga,unsigned dirty)67 update_tss_binding(struct svga_context *svga,
68                    unsigned dirty )
69 {
70    boolean reemit = svga->rebind.texture_samplers;
71    unsigned i;
72    unsigned count = MAX2( svga->curr.num_sampler_views,
73                           svga->state.hw_draw.num_views );
74    unsigned min_lod;
75    unsigned max_lod;
76 
77    struct bind_queue queue;
78 
79    queue.bind_count = 0;
80 
81    for (i = 0; i < count; i++) {
82       const struct svga_sampler_state *s = svga->curr.sampler[i];
83       struct svga_hw_view_state *view = &svga->state.hw_draw.views[i];
84       struct pipe_resource *texture = NULL;
85       struct pipe_sampler_view *sv = svga->curr.sampler_views[i];
86 
87       /* get min max lod */
88       if (sv) {
89          min_lod = MAX2(0, (s->view_min_lod + sv->u.tex.first_level));
90          max_lod = MIN2(s->view_max_lod + sv->u.tex.first_level,
91                         sv->texture->last_level);
92          texture = sv->texture;
93       } else {
94          min_lod = 0;
95          max_lod = 0;
96       }
97 
98       if (view->texture != texture ||
99           view->min_lod != min_lod ||
100           view->max_lod != max_lod) {
101 
102          svga_sampler_view_reference(&view->v, NULL);
103          pipe_resource_reference( &view->texture, texture );
104 
105          view->dirty = TRUE;
106          view->min_lod = min_lod;
107          view->max_lod = max_lod;
108 
109          if (texture)
110             view->v = svga_get_tex_sampler_view(&svga->pipe,
111                                                 texture,
112                                                 min_lod,
113                                                 max_lod);
114       }
115 
116       /*
117        * We need to reemit non-null texture bindings, even when they are not
118        * dirty, to ensure that the resources are paged in.
119        */
120 
121       if (view->dirty ||
122           (reemit && view->v)) {
123          queue.bind[queue.bind_count].unit = i;
124          queue.bind[queue.bind_count].view = view;
125          queue.bind_count++;
126       }
127       if (!view->dirty && view->v) {
128          svga_validate_sampler_view(svga, view->v);
129       }
130    }
131 
132    svga->state.hw_draw.num_views = svga->curr.num_sampler_views;
133 
134    if (queue.bind_count) {
135       SVGA3dTextureState *ts;
136 
137       if (SVGA3D_BeginSetTextureState( svga->swc,
138                                        &ts,
139                                        queue.bind_count ) != PIPE_OK)
140          goto fail;
141 
142       for (i = 0; i < queue.bind_count; i++) {
143          struct svga_winsys_surface *handle;
144 
145          ts[i].stage = queue.bind[i].unit;
146          ts[i].name = SVGA3D_TS_BIND_TEXTURE;
147 
148          if (queue.bind[i].view->v) {
149             handle = queue.bind[i].view->v->handle;
150          }
151          else {
152             handle = NULL;
153          }
154          svga->swc->surface_relocation(svga->swc,
155                                        &ts[i].value,
156                                        handle,
157                                        SVGA_RELOC_READ);
158 
159          queue.bind[i].view->dirty = FALSE;
160       }
161 
162       SVGA_FIFOCommitAll( svga->swc );
163    }
164 
165    svga->rebind.texture_samplers = FALSE;
166 
167    return 0;
168 
169 fail:
170    return PIPE_ERROR_OUT_OF_MEMORY;
171 }
172 
173 
174 /*
175  * Rebind textures.
176  *
177  * Similar to update_tss_binding, but without any state checking/update.
178  *
179  * Called at the beginning of every new command buffer to ensure that
180  * non-dirty textures are properly paged-in.
181  */
182 enum pipe_error
svga_reemit_tss_bindings(struct svga_context * svga)183 svga_reemit_tss_bindings(struct svga_context *svga)
184 {
185    unsigned i;
186    enum pipe_error ret;
187    struct bind_queue queue;
188 
189    assert(svga->rebind.texture_samplers);
190 
191    queue.bind_count = 0;
192 
193    for (i = 0; i < svga->state.hw_draw.num_views; i++) {
194       struct svga_hw_view_state *view = &svga->state.hw_draw.views[i];
195 
196       if (view->v) {
197          queue.bind[queue.bind_count].unit = i;
198          queue.bind[queue.bind_count].view = view;
199          queue.bind_count++;
200       }
201    }
202 
203    if (queue.bind_count) {
204       SVGA3dTextureState *ts;
205 
206       ret = SVGA3D_BeginSetTextureState(svga->swc,
207                                         &ts,
208                                         queue.bind_count);
209       if (ret != PIPE_OK) {
210          return ret;
211       }
212 
213       for (i = 0; i < queue.bind_count; i++) {
214          struct svga_winsys_surface *handle;
215 
216          ts[i].stage = queue.bind[i].unit;
217          ts[i].name = SVGA3D_TS_BIND_TEXTURE;
218 
219          assert(queue.bind[i].view->v);
220          handle = queue.bind[i].view->v->handle;
221          svga->swc->surface_relocation(svga->swc,
222                                        &ts[i].value,
223                                        handle,
224                                        SVGA_RELOC_READ);
225       }
226 
227       SVGA_FIFOCommitAll(svga->swc);
228    }
229 
230    svga->rebind.texture_samplers = FALSE;
231 
232    return PIPE_OK;
233 }
234 
235 
236 struct svga_tracked_state svga_hw_tss_binding = {
237    "texture binding emit",
238    SVGA_NEW_TEXTURE_BINDING |
239    SVGA_NEW_SAMPLER,
240    update_tss_binding
241 };
242 
243 
244 /***********************************************************************
245  */
246 
247 struct ts_queue {
248    unsigned ts_count;
249    SVGA3dTextureState ts[PIPE_MAX_SAMPLERS*SVGA3D_TS_MAX];
250 };
251 
252 
253 #define EMIT_TS(svga, unit, val, token, fail)                           \
254 do {                                                                    \
255    assert(unit < Elements(svga->state.hw_draw.ts));                     \
256    assert(SVGA3D_TS_##token < Elements(svga->state.hw_draw.ts[unit]));  \
257    if (svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] != val) {        \
258       svga_queue_tss( &queue, unit, SVGA3D_TS_##token, val );           \
259       svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] = val;            \
260    }                                                                    \
261 } while (0)
262 
263 #define EMIT_TS_FLOAT(svga, unit, fvalue, token, fail)                  \
264 do {                                                                    \
265    unsigned val = fui(fvalue);                                          \
266    assert(unit < Elements(svga->state.hw_draw.ts));                     \
267    assert(SVGA3D_TS_##token < Elements(svga->state.hw_draw.ts[unit]));  \
268    if (svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] != val) {        \
269       svga_queue_tss( &queue, unit, SVGA3D_TS_##token, val );           \
270       svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] = val;            \
271    }                                                                    \
272 } while (0)
273 
274 
275 static INLINE void
svga_queue_tss(struct ts_queue * q,unsigned unit,unsigned tss,unsigned value)276 svga_queue_tss( struct ts_queue *q,
277                 unsigned unit,
278                 unsigned tss,
279                 unsigned value )
280 {
281    assert(q->ts_count < sizeof(q->ts)/sizeof(q->ts[0]));
282    q->ts[q->ts_count].stage = unit;
283    q->ts[q->ts_count].name = tss;
284    q->ts[q->ts_count].value = value;
285    q->ts_count++;
286 }
287 
288 
289 static enum pipe_error
update_tss(struct svga_context * svga,unsigned dirty)290 update_tss(struct svga_context *svga,
291            unsigned dirty )
292 {
293    unsigned i;
294    struct ts_queue queue;
295 
296    queue.ts_count = 0;
297    for (i = 0; i < svga->curr.num_samplers; i++) {
298       if (svga->curr.sampler[i]) {
299          const struct svga_sampler_state *curr = svga->curr.sampler[i];
300 
301          EMIT_TS(svga, i, curr->mipfilter, MIPFILTER, fail);
302          EMIT_TS(svga, i, curr->min_lod, TEXTURE_MIPMAP_LEVEL, fail);
303          EMIT_TS(svga, i, curr->magfilter, MAGFILTER, fail);
304          EMIT_TS(svga, i, curr->minfilter, MINFILTER, fail);
305          EMIT_TS(svga, i, curr->aniso_level, TEXTURE_ANISOTROPIC_LEVEL, fail);
306          EMIT_TS_FLOAT(svga, i, curr->lod_bias, TEXTURE_LOD_BIAS, fail);
307          EMIT_TS(svga, i, curr->addressu, ADDRESSU, fail);
308          EMIT_TS(svga, i, curr->addressw, ADDRESSW, fail);
309          EMIT_TS(svga, i, curr->bordercolor, BORDERCOLOR, fail);
310          // TEXCOORDINDEX -- hopefully not needed
311 
312          if (svga->curr.tex_flags.flag_1d & (1 << i)) {
313             EMIT_TS(svga, i, SVGA3D_TEX_ADDRESS_WRAP, ADDRESSV, fail);
314          }
315          else
316             EMIT_TS(svga, i, curr->addressv, ADDRESSV, fail);
317 
318          if (svga->curr.tex_flags.flag_srgb & (1 << i))
319             EMIT_TS_FLOAT(svga, i, 2.2f, GAMMA, fail);
320          else
321             EMIT_TS_FLOAT(svga, i, 1.0f, GAMMA, fail);
322 
323       }
324    }
325 
326    if (queue.ts_count) {
327       SVGA3dTextureState *ts;
328 
329       if (SVGA3D_BeginSetTextureState( svga->swc,
330                                        &ts,
331                                        queue.ts_count ) != PIPE_OK)
332          goto fail;
333 
334       memcpy( ts,
335               queue.ts,
336               queue.ts_count * sizeof queue.ts[0]);
337 
338       SVGA_FIFOCommitAll( svga->swc );
339    }
340 
341    return PIPE_OK;
342 
343 fail:
344    /* XXX: need to poison cached hardware state on failure to ensure
345     * dirty state gets re-emitted.  Fix this by re-instating partial
346     * FIFOCommit command and only updating cached hw state once the
347     * initial allocation has succeeded.
348     */
349    memset(svga->state.hw_draw.ts, 0xcd, sizeof(svga->state.hw_draw.ts));
350 
351    return PIPE_ERROR_OUT_OF_MEMORY;
352 }
353 
354 
355 struct svga_tracked_state svga_hw_tss = {
356    "texture state emit",
357    (SVGA_NEW_SAMPLER |
358     SVGA_NEW_TEXTURE_FLAGS),
359    update_tss
360 };
361 
362