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