• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_shader.h"
35 #include "svga_state.h"
36 #include "svga_cmd.h"
37 
38 
39 /**
40  * Called when tearing down a context to free resources and samplers.
41  */
svga_cleanup_tss_binding(struct svga_context * svga)42 void svga_cleanup_tss_binding(struct svga_context *svga)
43 {
44    const enum pipe_shader_type shader = PIPE_SHADER_FRAGMENT;
45    unsigned i;
46 
47    for (i = 0; i < ARRAY_SIZE(svga->state.hw_draw.views); i++) {
48       struct svga_hw_view_state *view = &svga->state.hw_draw.views[i];
49       if (view) {
50          svga_sampler_view_reference(&view->v, NULL);
51          pipe_sampler_view_release(&svga->pipe,
52                                    &svga->curr.sampler_views[shader][i]);
53          pipe_resource_reference(&view->texture, NULL);
54          view->dirty = TRUE;
55       }
56    }
57 }
58 
59 
60 struct bind_queue {
61    struct {
62       unsigned unit;
63       struct svga_hw_view_state *view;
64    } bind[PIPE_MAX_SAMPLERS];
65 
66    unsigned bind_count;
67 };
68 
69 
70 /**
71  * Update the texture binding for one texture unit.
72  */
73 static void
emit_tex_binding_unit(struct svga_context * svga,unsigned unit,const struct svga_sampler_state * s,const struct pipe_sampler_view * sv,struct svga_hw_view_state * view,boolean reemit,struct bind_queue * queue)74 emit_tex_binding_unit(struct svga_context *svga,
75                       unsigned unit,
76                       const struct svga_sampler_state *s,
77                       const struct pipe_sampler_view *sv,
78                       struct svga_hw_view_state *view,
79                       boolean reemit,
80                       struct bind_queue *queue)
81 {
82    struct pipe_resource *texture = NULL;
83    unsigned last_level, min_lod, max_lod;
84 
85    /* get min max lod */
86    if (sv && s) {
87       if (s->mipfilter == SVGA3D_TEX_FILTER_NONE) {
88          /* just use the base level image */
89          min_lod = max_lod = sv->u.tex.first_level;
90       }
91       else {
92          last_level = MIN2(sv->u.tex.last_level, sv->texture->last_level);
93          min_lod = s->view_min_lod + sv->u.tex.first_level;
94          min_lod = MIN2(min_lod, last_level);
95          max_lod = MIN2(s->view_max_lod + sv->u.tex.first_level, last_level);
96       }
97       texture = sv->texture;
98    }
99    else {
100       min_lod = 0;
101       max_lod = 0;
102    }
103 
104    if (view->texture != texture ||
105        view->min_lod != min_lod ||
106        view->max_lod != max_lod) {
107 
108       svga_sampler_view_reference(&view->v, NULL);
109       pipe_resource_reference( &view->texture, texture );
110 
111       view->dirty = TRUE;
112       view->min_lod = min_lod;
113       view->max_lod = max_lod;
114 
115       if (texture) {
116          view->v = svga_get_tex_sampler_view(&svga->pipe,
117                                              texture,
118                                              min_lod,
119                                              max_lod);
120       }
121    }
122 
123    /*
124     * We need to reemit non-null texture bindings, even when they are not
125     * dirty, to ensure that the resources are paged in.
126     */
127    if (view->dirty || (reemit && view->v)) {
128       queue->bind[queue->bind_count].unit = unit;
129       queue->bind[queue->bind_count].view = view;
130       queue->bind_count++;
131    }
132 
133    if (!view->dirty && view->v) {
134       svga_validate_sampler_view(svga, view->v);
135    }
136 }
137 
138 
139 static enum pipe_error
update_tss_binding(struct svga_context * svga,unsigned dirty)140 update_tss_binding(struct svga_context *svga,
141                    unsigned dirty )
142 {
143    const enum pipe_shader_type shader = PIPE_SHADER_FRAGMENT;
144    boolean reemit = svga->rebind.flags.texture_samplers;
145    unsigned i;
146    unsigned count = MAX2( svga->curr.num_sampler_views[shader],
147                           svga->state.hw_draw.num_views );
148 
149    struct bind_queue queue;
150 
151    if (svga_have_vgpu10(svga))
152       return PIPE_OK;
153 
154    queue.bind_count = 0;
155 
156    for (i = 0; i < count; i++) {
157       emit_tex_binding_unit(svga, i,
158                             svga->curr.sampler[shader][i],
159                             svga->curr.sampler_views[shader][i],
160                             &svga->state.hw_draw.views[i],
161                             reemit,
162                             &queue);
163    }
164 
165    svga->state.hw_draw.num_views = svga->curr.num_sampler_views[shader];
166 
167    /* Polygon stipple */
168    if (svga->curr.rast->templ.poly_stipple_enable) {
169       const unsigned unit = svga->state.hw_draw.fs->pstipple_sampler_unit;
170       emit_tex_binding_unit(svga, unit,
171                             svga->polygon_stipple.sampler,
172                             &svga->polygon_stipple.sampler_view->base,
173                             &svga->state.hw_draw.views[unit],
174                             reemit,
175                             &queue);
176    }
177 
178    if (queue.bind_count) {
179       SVGA3dTextureState *ts;
180 
181       if (SVGA3D_BeginSetTextureState( svga->swc,
182                                        &ts,
183                                        queue.bind_count ) != PIPE_OK)
184          goto fail;
185 
186       for (i = 0; i < queue.bind_count; i++) {
187          struct svga_winsys_surface *handle;
188 
189          ts[i].stage = queue.bind[i].unit;
190          ts[i].name = SVGA3D_TS_BIND_TEXTURE;
191 
192          if (queue.bind[i].view->v) {
193             handle = queue.bind[i].view->v->handle;
194          }
195          else {
196             handle = NULL;
197          }
198          svga->swc->surface_relocation(svga->swc,
199                                        &ts[i].value,
200                                        NULL,
201                                        handle,
202                                        SVGA_RELOC_READ);
203 
204          queue.bind[i].view->dirty = FALSE;
205       }
206 
207       SVGA_FIFOCommitAll( svga->swc );
208    }
209 
210    svga->rebind.flags.texture_samplers = FALSE;
211 
212    return PIPE_OK;
213 
214 fail:
215    return PIPE_ERROR_OUT_OF_MEMORY;
216 }
217 
218 
219 /*
220  * Rebind textures.
221  *
222  * Similar to update_tss_binding, but without any state checking/update.
223  *
224  * Called at the beginning of every new command buffer to ensure that
225  * non-dirty textures are properly paged-in.
226  */
227 enum pipe_error
svga_reemit_tss_bindings(struct svga_context * svga)228 svga_reemit_tss_bindings(struct svga_context *svga)
229 {
230    unsigned i;
231    enum pipe_error ret;
232    struct bind_queue queue;
233 
234    assert(!svga_have_vgpu10(svga));
235    assert(svga->rebind.flags.texture_samplers);
236 
237    queue.bind_count = 0;
238 
239    for (i = 0; i < svga->state.hw_draw.num_views; i++) {
240       struct svga_hw_view_state *view = &svga->state.hw_draw.views[i];
241 
242       if (view->v) {
243          queue.bind[queue.bind_count].unit = i;
244          queue.bind[queue.bind_count].view = view;
245          queue.bind_count++;
246       }
247    }
248 
249    /* Polygon stipple */
250    if (svga->curr.rast->templ.poly_stipple_enable) {
251       const unsigned unit = svga->state.hw_draw.fs->pstipple_sampler_unit;
252       struct svga_hw_view_state *view = &svga->state.hw_draw.views[unit];
253 
254       if (view->v) {
255          queue.bind[queue.bind_count].unit = unit;
256          queue.bind[queue.bind_count].view = view;
257          queue.bind_count++;
258       }
259    }
260 
261    if (queue.bind_count) {
262       SVGA3dTextureState *ts;
263 
264       ret = SVGA3D_BeginSetTextureState(svga->swc,
265                                         &ts,
266                                         queue.bind_count);
267       if (ret != PIPE_OK) {
268          return ret;
269       }
270 
271       for (i = 0; i < queue.bind_count; i++) {
272          struct svga_winsys_surface *handle;
273 
274          ts[i].stage = queue.bind[i].unit;
275          ts[i].name = SVGA3D_TS_BIND_TEXTURE;
276 
277          assert(queue.bind[i].view->v);
278          handle = queue.bind[i].view->v->handle;
279          svga->swc->surface_relocation(svga->swc,
280                                        &ts[i].value,
281                                        NULL,
282                                        handle,
283                                        SVGA_RELOC_READ);
284       }
285 
286       SVGA_FIFOCommitAll(svga->swc);
287    }
288 
289    svga->rebind.flags.texture_samplers = FALSE;
290 
291    return PIPE_OK;
292 }
293 
294 
295 struct svga_tracked_state svga_hw_tss_binding = {
296    "texture binding emit",
297    SVGA_NEW_FRAME_BUFFER |
298    SVGA_NEW_TEXTURE_BINDING |
299    SVGA_NEW_STIPPLE |
300    SVGA_NEW_SAMPLER,
301    update_tss_binding
302 };
303 
304 
305 /***********************************************************************
306  */
307 
308 struct ts_queue {
309    unsigned ts_count;
310    SVGA3dTextureState ts[PIPE_MAX_SAMPLERS*SVGA3D_TS_MAX];
311 };
312 
313 
314 static inline void
svga_queue_tss(struct ts_queue * q,unsigned unit,unsigned tss,unsigned value)315 svga_queue_tss( struct ts_queue *q,
316                 unsigned unit,
317                 unsigned tss,
318                 unsigned value )
319 {
320    assert(q->ts_count < ARRAY_SIZE(q->ts));
321    q->ts[q->ts_count].stage = unit;
322    q->ts[q->ts_count].name = tss;
323    q->ts[q->ts_count].value = value;
324    q->ts_count++;
325 }
326 
327 
328 #define EMIT_TS(svga, unit, val, token)                                 \
329 do {                                                                    \
330    assert(unit < ARRAY_SIZE(svga->state.hw_draw.ts));                     \
331    STATIC_ASSERT(SVGA3D_TS_##token < ARRAY_SIZE(svga->state.hw_draw.ts[unit])); \
332    if (svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] != val) {        \
333       svga_queue_tss( queue, unit, SVGA3D_TS_##token, val );            \
334       svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] = val;            \
335    }                                                                    \
336 } while (0)
337 
338 #define EMIT_TS_FLOAT(svga, unit, fvalue, token)                        \
339 do {                                                                    \
340    unsigned val = fui(fvalue);                                          \
341    assert(unit < ARRAY_SIZE(svga->state.hw_draw.ts));                     \
342    STATIC_ASSERT(SVGA3D_TS_##token < ARRAY_SIZE(svga->state.hw_draw.ts[unit])); \
343    if (svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] != val) {        \
344       svga_queue_tss( queue, unit, SVGA3D_TS_##token, val );            \
345       svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] = val;            \
346    }                                                                    \
347 } while (0)
348 
349 
350 /**
351  * Emit texture sampler state (tss) for one texture unit.
352  */
353 static void
emit_tss_unit(struct svga_context * svga,unsigned unit,const struct svga_sampler_state * state,struct ts_queue * queue)354 emit_tss_unit(struct svga_context *svga, unsigned unit,
355               const struct svga_sampler_state *state,
356               struct ts_queue *queue)
357 {
358    EMIT_TS(svga, unit, state->mipfilter, MIPFILTER);
359    EMIT_TS(svga, unit, state->min_lod, TEXTURE_MIPMAP_LEVEL);
360    EMIT_TS(svga, unit, state->magfilter, MAGFILTER);
361    EMIT_TS(svga, unit, state->minfilter, MINFILTER);
362    EMIT_TS(svga, unit, state->aniso_level, TEXTURE_ANISOTROPIC_LEVEL);
363    EMIT_TS_FLOAT(svga, unit, state->lod_bias, TEXTURE_LOD_BIAS);
364    EMIT_TS(svga, unit, state->addressu, ADDRESSU);
365    EMIT_TS(svga, unit, state->addressw, ADDRESSW);
366    EMIT_TS(svga, unit, state->bordercolor, BORDERCOLOR);
367    // TEXCOORDINDEX -- hopefully not needed
368 
369    if (svga->curr.tex_flags.flag_1d & (1 << unit))
370       EMIT_TS(svga, unit, SVGA3D_TEX_ADDRESS_WRAP, ADDRESSV);
371    else
372       EMIT_TS(svga, unit, state->addressv, ADDRESSV);
373 
374    if (svga->curr.tex_flags.flag_srgb & (1 << unit))
375       EMIT_TS_FLOAT(svga, unit, 2.2f, GAMMA);
376    else
377       EMIT_TS_FLOAT(svga, unit, 1.0f, GAMMA);
378 }
379 
380 static enum pipe_error
update_tss(struct svga_context * svga,unsigned dirty)381 update_tss(struct svga_context *svga,
382            unsigned dirty )
383 {
384    const enum pipe_shader_type shader = PIPE_SHADER_FRAGMENT;
385    unsigned i;
386    struct ts_queue queue;
387 
388    if (svga_have_vgpu10(svga))
389       return PIPE_OK;
390 
391    queue.ts_count = 0;
392    for (i = 0; i < svga->curr.num_samplers[shader]; i++) {
393       if (svga->curr.sampler[shader][i]) {
394          const struct svga_sampler_state *curr = svga->curr.sampler[shader][i];
395          emit_tss_unit(svga, i, curr, &queue);
396       }
397    }
398 
399    /* polygon stipple sampler */
400    if (svga->curr.rast->templ.poly_stipple_enable) {
401       emit_tss_unit(svga,
402                     svga->state.hw_draw.fs->pstipple_sampler_unit,
403                     svga->polygon_stipple.sampler,
404                     &queue);
405    }
406 
407    if (queue.ts_count) {
408       SVGA3dTextureState *ts;
409 
410       if (SVGA3D_BeginSetTextureState( svga->swc,
411                                        &ts,
412                                        queue.ts_count ) != PIPE_OK)
413          goto fail;
414 
415       memcpy( ts,
416               queue.ts,
417               queue.ts_count * sizeof queue.ts[0]);
418 
419       SVGA_FIFOCommitAll( svga->swc );
420    }
421 
422    return PIPE_OK;
423 
424 fail:
425    /* XXX: need to poison cached hardware state on failure to ensure
426     * dirty state gets re-emitted.  Fix this by re-instating partial
427     * FIFOCommit command and only updating cached hw state once the
428     * initial allocation has succeeded.
429     */
430    memset(svga->state.hw_draw.ts, 0xcd, sizeof(svga->state.hw_draw.ts));
431 
432    return PIPE_ERROR_OUT_OF_MEMORY;
433 }
434 
435 
436 struct svga_tracked_state svga_hw_tss = {
437    "texture state emit",
438    (SVGA_NEW_SAMPLER |
439     SVGA_NEW_STIPPLE |
440     SVGA_NEW_TEXTURE_FLAGS),
441    update_tss
442 };
443 
444