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