Merge remote branch 'origin/master' into pipe-video
[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 "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
37 void 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
55 struct 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
65 static int
66 update_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
164 fail:
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 */
177 enum pipe_error
178 svga_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
227 struct 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
239 struct 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) \
246 do { \
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) \
254 do { \
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
263 static INLINE void
264 svga_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
277 static int
278 update_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
331 fail:
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
343 struct svga_tracked_state svga_hw_tss = {
344 "texture state emit",
345 (SVGA_NEW_SAMPLER |
346 SVGA_NEW_TEXTURE_FLAGS),
347 update_tss
348 };
349