svga_state_tss.c revision 369ece170257ef687ca609cacd1d66d186274eb3
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
37void 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
55struct 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
65static int
66update_tss_binding(struct svga_context *svga,
67                   unsigned dirty )
68{
69   boolean reemit = !!(dirty & SVGA_NEW_COMMAND_BUFFER);
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   return 0;
163
164fail:
165   return PIPE_ERROR_OUT_OF_MEMORY;
166}
167
168
169/*
170 * Rebind textures.
171 *
172 * Similar to update_tss_binding, but without any state checking/update.
173 *
174 * Called at the beginning of every new command buffer to ensure that
175 * non-dirty textures are properly paged-in.
176 */
177enum pipe_error
178svga_reemit_tss_bindings(struct svga_context *svga)
179{
180   unsigned i;
181   enum pipe_error ret;
182   struct bind_queue queue;
183
184   queue.bind_count = 0;
185
186   for (i = 0; i < svga->state.hw_draw.num_views; i++) {
187      struct svga_hw_view_state *view = &svga->state.hw_draw.views[i];
188
189      if (view->v) {
190         queue.bind[queue.bind_count].unit = i;
191         queue.bind[queue.bind_count].view = view;
192         queue.bind_count++;
193      }
194   }
195
196   if (queue.bind_count) {
197      SVGA3dTextureState *ts;
198
199      ret = SVGA3D_BeginSetTextureState(svga->swc,
200                                        &ts,
201                                        queue.bind_count);
202      if (ret != PIPE_OK) {
203         return ret;
204      }
205
206      for (i = 0; i < queue.bind_count; i++) {
207         struct svga_winsys_surface *handle;
208
209         ts[i].stage = queue.bind[i].unit;
210         ts[i].name = SVGA3D_TS_BIND_TEXTURE;
211
212         assert(queue.bind[i].view->v);
213         handle = queue.bind[i].view->v->handle;
214         svga->swc->surface_relocation(svga->swc,
215                                       &ts[i].value,
216                                       handle,
217                                       SVGA_RELOC_READ);
218      }
219
220      SVGA_FIFOCommitAll(svga->swc);
221   }
222
223   return PIPE_OK;
224}
225
226
227struct svga_tracked_state svga_hw_tss_binding = {
228   "texture binding emit",
229   SVGA_NEW_TEXTURE_BINDING |
230   SVGA_NEW_SAMPLER |
231   SVGA_NEW_COMMAND_BUFFER,
232   update_tss_binding
233};
234
235
236/***********************************************************************
237 */
238
239struct ts_queue {
240   unsigned ts_count;
241   SVGA3dTextureState ts[PIPE_MAX_SAMPLERS*SVGA3D_TS_MAX];
242};
243
244
245#define EMIT_TS(svga, unit, val, token, fail)                           \
246do {                                                                    \
247   if (svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] != val) {        \
248      svga_queue_tss( &queue, unit, SVGA3D_TS_##token, val );           \
249      svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] = val;            \
250   }                                                                    \
251} while (0)
252
253#define EMIT_TS_FLOAT(svga, unit, fvalue, token, fail)                  \
254do {                                                                    \
255   unsigned val = fui(fvalue);                                          \
256   if (svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] != val) {        \
257      svga_queue_tss( &queue, unit, SVGA3D_TS_##token, val );           \
258      svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] = val;            \
259   }                                                                    \
260} while (0)
261
262
263static INLINE void
264svga_queue_tss( struct ts_queue *q,
265                unsigned unit,
266                unsigned tss,
267                unsigned value )
268{
269   assert(q->ts_count < sizeof(q->ts)/sizeof(q->ts[0]));
270   q->ts[q->ts_count].stage = unit;
271   q->ts[q->ts_count].name = tss;
272   q->ts[q->ts_count].value = value;
273   q->ts_count++;
274}
275
276
277static int
278update_tss(struct svga_context *svga,
279           unsigned dirty )
280{
281   unsigned i;
282   struct ts_queue queue;
283
284   queue.ts_count = 0;
285   for (i = 0; i < svga->curr.num_samplers; i++) {
286      if (svga->curr.sampler[i]) {
287         const struct svga_sampler_state *curr = svga->curr.sampler[i];
288
289         EMIT_TS(svga, i, curr->mipfilter, MIPFILTER, fail);
290         EMIT_TS(svga, i, curr->min_lod, TEXTURE_MIPMAP_LEVEL, fail);
291         EMIT_TS(svga, i, curr->magfilter, MAGFILTER, fail);
292         EMIT_TS(svga, i, curr->minfilter, MINFILTER, fail);
293         EMIT_TS(svga, i, curr->aniso_level, TEXTURE_ANISOTROPIC_LEVEL, fail);
294         EMIT_TS_FLOAT(svga, i, curr->lod_bias, TEXTURE_LOD_BIAS, fail);
295         EMIT_TS(svga, i, curr->addressu, ADDRESSU, fail);
296         EMIT_TS(svga, i, curr->addressw, ADDRESSW, fail);
297         EMIT_TS(svga, i, curr->bordercolor, BORDERCOLOR, fail);
298         // TEXCOORDINDEX -- hopefully not needed
299
300         if (svga->curr.tex_flags.flag_1d & (1 << i)) {
301            EMIT_TS(svga, i, SVGA3D_TEX_ADDRESS_WRAP, ADDRESSV, fail);
302         }
303         else
304            EMIT_TS(svga, i, curr->addressv, ADDRESSV, fail);
305
306         if (svga->curr.tex_flags.flag_srgb & (1 << i))
307            EMIT_TS_FLOAT(svga, i, 2.2f, GAMMA, fail);
308         else
309            EMIT_TS_FLOAT(svga, i, 1.0f, GAMMA, fail);
310
311      }
312   }
313
314   if (queue.ts_count) {
315      SVGA3dTextureState *ts;
316
317      if (SVGA3D_BeginSetTextureState( svga->swc,
318                                       &ts,
319                                       queue.ts_count ) != PIPE_OK)
320         goto fail;
321
322      memcpy( ts,
323              queue.ts,
324              queue.ts_count * sizeof queue.ts[0]);
325
326      SVGA_FIFOCommitAll( svga->swc );
327   }
328
329   return 0;
330
331fail:
332   /* XXX: need to poison cached hardware state on failure to ensure
333    * dirty state gets re-emitted.  Fix this by re-instating partial
334    * FIFOCommit command and only updating cached hw state once the
335    * initial allocation has succeeded.
336    */
337   memset(svga->state.hw_draw.ts, 0xcd, sizeof(svga->state.hw_draw.ts));
338
339   return PIPE_ERROR_OUT_OF_MEMORY;
340}
341
342
343struct svga_tracked_state svga_hw_tss = {
344   "texture state emit",
345   (SVGA_NEW_SAMPLER |
346    SVGA_NEW_TEXTURE_FLAGS),
347   update_tss
348};
349
350