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