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