etnaviv: increment the resource seqno in resource_changed
[mesa.git] / src / gallium / drivers / svga / svga_state_tss.c
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 */
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
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
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
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
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
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
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