Merge remote branch 'origin/master' into nv50-compiler
[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 static int
56 update_tss_binding(struct svga_context *svga,
57 unsigned dirty )
58 {
59 boolean reemit = !!(dirty & SVGA_NEW_COMMAND_BUFFER);
60 unsigned i;
61 unsigned count = MAX2( svga->curr.num_sampler_views,
62 svga->state.hw_draw.num_views );
63 unsigned min_lod;
64 unsigned max_lod;
65
66
67 struct {
68 struct {
69 unsigned unit;
70 struct svga_hw_view_state *view;
71 } bind[PIPE_MAX_SAMPLERS];
72
73 unsigned bind_count;
74 } queue;
75
76 queue.bind_count = 0;
77
78 for (i = 0; i < count; i++) {
79 const struct svga_sampler_state *s = svga->curr.sampler[i];
80 struct svga_hw_view_state *view = &svga->state.hw_draw.views[i];
81 struct pipe_resource *texture = NULL;
82
83 /* get min max lod */
84 if (svga->curr.sampler_views[i]) {
85 min_lod = MAX2(s->view_min_lod, 0);
86 max_lod = MIN2(s->view_max_lod, svga->curr.sampler_views[i]->texture->last_level);
87 texture = svga->curr.sampler_views[i]->texture;
88 } else {
89 min_lod = 0;
90 max_lod = 0;
91 }
92
93 if (view->texture != texture ||
94 view->min_lod != min_lod ||
95 view->max_lod != max_lod) {
96
97 svga_sampler_view_reference(&view->v, NULL);
98 pipe_resource_reference( &view->texture, texture );
99
100 view->dirty = TRUE;
101 view->min_lod = min_lod;
102 view->max_lod = max_lod;
103
104 if (texture)
105 view->v = svga_get_tex_sampler_view(&svga->pipe,
106 texture,
107 min_lod,
108 max_lod);
109 }
110
111 /*
112 * We need to reemit non-null texture bindings, even when they are not
113 * dirty, to ensure that the resources are paged in.
114 */
115
116 if (view->dirty ||
117 (reemit && view->v)) {
118 queue.bind[queue.bind_count].unit = i;
119 queue.bind[queue.bind_count].view = view;
120 queue.bind_count++;
121 }
122 if (!view->dirty && view->v) {
123 svga_validate_sampler_view(svga, view->v);
124 }
125 }
126
127 svga->state.hw_draw.num_views = svga->curr.num_sampler_views;
128
129 if (queue.bind_count) {
130 SVGA3dTextureState *ts;
131
132 if (SVGA3D_BeginSetTextureState( svga->swc,
133 &ts,
134 queue.bind_count ) != PIPE_OK)
135 goto fail;
136
137 for (i = 0; i < queue.bind_count; i++) {
138 struct svga_winsys_surface *handle;
139
140 ts[i].stage = queue.bind[i].unit;
141 ts[i].name = SVGA3D_TS_BIND_TEXTURE;
142
143 if (queue.bind[i].view->v) {
144 handle = queue.bind[i].view->v->handle;
145 }
146 else {
147 handle = NULL;
148 }
149 svga->swc->surface_relocation(svga->swc,
150 &ts[i].value,
151 handle,
152 SVGA_RELOC_READ);
153
154 queue.bind[i].view->dirty = FALSE;
155 }
156
157 SVGA_FIFOCommitAll( svga->swc );
158 }
159
160 return 0;
161
162 fail:
163 return PIPE_ERROR_OUT_OF_MEMORY;
164 }
165
166
167 struct svga_tracked_state svga_hw_tss_binding = {
168 "texture binding emit",
169 SVGA_NEW_TEXTURE_BINDING |
170 SVGA_NEW_SAMPLER |
171 SVGA_NEW_COMMAND_BUFFER,
172 update_tss_binding
173 };
174
175
176 /***********************************************************************
177 */
178
179 struct ts_queue {
180 unsigned ts_count;
181 SVGA3dTextureState ts[PIPE_MAX_SAMPLERS*SVGA3D_TS_MAX];
182 };
183
184
185 #define EMIT_TS(svga, unit, val, token, fail) \
186 do { \
187 if (svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] != val) { \
188 svga_queue_tss( &queue, unit, SVGA3D_TS_##token, val ); \
189 svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] = val; \
190 } \
191 } while (0)
192
193 #define EMIT_TS_FLOAT(svga, unit, fvalue, token, fail) \
194 do { \
195 unsigned val = fui(fvalue); \
196 if (svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] != val) { \
197 svga_queue_tss( &queue, unit, SVGA3D_TS_##token, val ); \
198 svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] = val; \
199 } \
200 } while (0)
201
202
203 static INLINE void
204 svga_queue_tss( struct ts_queue *q,
205 unsigned unit,
206 unsigned tss,
207 unsigned value )
208 {
209 assert(q->ts_count < sizeof(q->ts)/sizeof(q->ts[0]));
210 q->ts[q->ts_count].stage = unit;
211 q->ts[q->ts_count].name = tss;
212 q->ts[q->ts_count].value = value;
213 q->ts_count++;
214 }
215
216
217 static int
218 update_tss(struct svga_context *svga,
219 unsigned dirty )
220 {
221 unsigned i;
222 struct ts_queue queue;
223
224 queue.ts_count = 0;
225 for (i = 0; i < svga->curr.num_samplers; i++) {
226 if (svga->curr.sampler[i]) {
227 const struct svga_sampler_state *curr = svga->curr.sampler[i];
228
229 EMIT_TS(svga, i, curr->mipfilter, MIPFILTER, fail);
230 EMIT_TS(svga, i, curr->min_lod, TEXTURE_MIPMAP_LEVEL, fail);
231 EMIT_TS(svga, i, curr->magfilter, MAGFILTER, fail);
232 EMIT_TS(svga, i, curr->minfilter, MINFILTER, fail);
233 EMIT_TS(svga, i, curr->aniso_level, TEXTURE_ANISOTROPIC_LEVEL, fail);
234 EMIT_TS_FLOAT(svga, i, curr->lod_bias, TEXTURE_LOD_BIAS, fail);
235 EMIT_TS(svga, i, curr->addressu, ADDRESSU, fail);
236 EMIT_TS(svga, i, curr->addressw, ADDRESSW, fail);
237 EMIT_TS(svga, i, curr->bordercolor, BORDERCOLOR, fail);
238 // TEXCOORDINDEX -- hopefully not needed
239
240 if (svga->curr.tex_flags.flag_1d & (1 << i)) {
241 debug_printf("wrap 1d tex %d\n", i);
242 EMIT_TS(svga, i, SVGA3D_TEX_ADDRESS_WRAP, ADDRESSV, fail);
243 }
244 else
245 EMIT_TS(svga, i, curr->addressv, ADDRESSV, fail);
246
247 if (svga->curr.tex_flags.flag_srgb & (1 << i))
248 EMIT_TS_FLOAT(svga, i, 2.2f, GAMMA, fail);
249 else
250 EMIT_TS_FLOAT(svga, i, 1.0f, GAMMA, fail);
251
252 }
253 }
254
255 if (queue.ts_count) {
256 SVGA3dTextureState *ts;
257
258 if (SVGA3D_BeginSetTextureState( svga->swc,
259 &ts,
260 queue.ts_count ) != PIPE_OK)
261 goto fail;
262
263 memcpy( ts,
264 queue.ts,
265 queue.ts_count * sizeof queue.ts[0]);
266
267 SVGA_FIFOCommitAll( svga->swc );
268 }
269
270 return 0;
271
272 fail:
273 /* XXX: need to poison cached hardware state on failure to ensure
274 * dirty state gets re-emitted. Fix this by re-instating partial
275 * FIFOCommit command and only updating cached hw state once the
276 * initial allocation has succeeded.
277 */
278 memset(svga->state.hw_draw.ts, 0xcd, sizeof(svga->state.hw_draw.ts));
279
280 return PIPE_ERROR_OUT_OF_MEMORY;
281 }
282
283
284 struct svga_tracked_state svga_hw_tss = {
285 "texture state emit",
286 (SVGA_NEW_SAMPLER |
287 SVGA_NEW_TEXTURE_FLAGS),
288 update_tss
289 };
290