svga: update driver for version 10 GPU interface
[mesa.git] / src / gallium / drivers / svga / svga_pipe_sampler.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_defines.h"
27 #include "util/u_bitmask.h"
28 #include "util/u_format.h"
29 #include "util/u_inlines.h"
30 #include "util/u_math.h"
31 #include "util/u_memory.h"
32 #include "tgsi/tgsi_parse.h"
33
34 #include "svga_context.h"
35 #include "svga_cmd.h"
36 #include "svga_debug.h"
37 #include "svga_resource_texture.h"
38
39
40 static inline unsigned
41 translate_wrap_mode(unsigned wrap)
42 {
43 switch (wrap) {
44 case PIPE_TEX_WRAP_REPEAT:
45 return SVGA3D_TEX_ADDRESS_WRAP;
46
47 case PIPE_TEX_WRAP_CLAMP:
48 return SVGA3D_TEX_ADDRESS_CLAMP;
49
50 case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
51 /* Unfortunately SVGA3D_TEX_ADDRESS_EDGE not respected by
52 * hardware.
53 */
54 return SVGA3D_TEX_ADDRESS_CLAMP;
55
56 case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
57 return SVGA3D_TEX_ADDRESS_BORDER;
58
59 case PIPE_TEX_WRAP_MIRROR_REPEAT:
60 return SVGA3D_TEX_ADDRESS_MIRROR;
61
62 case PIPE_TEX_WRAP_MIRROR_CLAMP:
63 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
64 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
65 return SVGA3D_TEX_ADDRESS_MIRRORONCE;
66
67 default:
68 assert(0);
69 return SVGA3D_TEX_ADDRESS_WRAP;
70 }
71 }
72
73 static inline unsigned translate_img_filter( unsigned filter )
74 {
75 switch (filter) {
76 case PIPE_TEX_FILTER_NEAREST: return SVGA3D_TEX_FILTER_NEAREST;
77 case PIPE_TEX_FILTER_LINEAR: return SVGA3D_TEX_FILTER_LINEAR;
78 default:
79 assert(0);
80 return SVGA3D_TEX_FILTER_NEAREST;
81 }
82 }
83
84 static inline unsigned translate_mip_filter( unsigned filter )
85 {
86 switch (filter) {
87 case PIPE_TEX_MIPFILTER_NONE: return SVGA3D_TEX_FILTER_NONE;
88 case PIPE_TEX_MIPFILTER_NEAREST: return SVGA3D_TEX_FILTER_NEAREST;
89 case PIPE_TEX_MIPFILTER_LINEAR: return SVGA3D_TEX_FILTER_LINEAR;
90 default:
91 assert(0);
92 return SVGA3D_TEX_FILTER_NONE;
93 }
94 }
95
96
97 static uint8
98 translate_comparison_func(unsigned func)
99 {
100 switch (func) {
101 case PIPE_FUNC_NEVER:
102 return SVGA3D_COMPARISON_NEVER;
103 case PIPE_FUNC_LESS:
104 return SVGA3D_COMPARISON_LESS;
105 case PIPE_FUNC_EQUAL:
106 return SVGA3D_COMPARISON_EQUAL;
107 case PIPE_FUNC_LEQUAL:
108 return SVGA3D_COMPARISON_LESS_EQUAL;
109 case PIPE_FUNC_GREATER:
110 return SVGA3D_COMPARISON_GREATER;
111 case PIPE_FUNC_NOTEQUAL:
112 return SVGA3D_COMPARISON_NOT_EQUAL;
113 case PIPE_FUNC_GEQUAL:
114 return SVGA3D_COMPARISON_GREATER_EQUAL;
115 case PIPE_FUNC_ALWAYS:
116 return SVGA3D_COMPARISON_ALWAYS;
117 default:
118 assert(!"Invalid comparison function");
119 return SVGA3D_COMPARISON_ALWAYS;
120 }
121 }
122
123
124 /**
125 * Translate filtering state to vgpu10 format.
126 */
127 static SVGA3dFilter
128 translate_filter_mode(unsigned img_filter,
129 unsigned min_filter,
130 unsigned mag_filter,
131 boolean anisotropic,
132 boolean compare)
133 {
134 SVGA3dFilter mode = 0;
135
136 if (img_filter == PIPE_TEX_FILTER_LINEAR)
137 mode |= SVGA3D_FILTER_MIP_LINEAR;
138 if (min_filter == PIPE_TEX_FILTER_LINEAR)
139 mode |= SVGA3D_FILTER_MIN_LINEAR;
140 if (mag_filter == PIPE_TEX_FILTER_LINEAR)
141 mode |= SVGA3D_FILTER_MAG_LINEAR;
142 if (anisotropic)
143 mode |= SVGA3D_FILTER_ANISOTROPIC;
144 if (compare)
145 mode |= SVGA3D_FILTER_COMPARE;
146
147 return mode;
148 }
149
150
151 /**
152 * Define a vgpu10 sampler state.
153 */
154 static void
155 define_sampler_state_object(struct svga_context *svga,
156 struct svga_sampler_state *ss,
157 const struct pipe_sampler_state *ps)
158 {
159 uint8_t max_aniso = (uint8_t) 255; /* XXX fix me */
160 boolean anisotropic;
161 uint8 compare_func;
162 SVGA3dFilter filter;
163 SVGA3dRGBAFloat bcolor;
164 unsigned try;
165 float min_lod, max_lod;
166
167 assert(svga_have_vgpu10(svga));
168
169 anisotropic = ss->aniso_level > 1.0f;
170
171 filter = translate_filter_mode(ps->min_mip_filter,
172 ps->min_img_filter,
173 ps->mag_img_filter,
174 anisotropic,
175 ss->compare_mode);
176
177 compare_func = translate_comparison_func(ss->compare_func);
178
179 COPY_4V(bcolor.value, ps->border_color.f);
180
181 ss->id = util_bitmask_add(svga->sampler_object_id_bm);
182
183 assert(ps->min_lod <= ps->max_lod);
184
185 if (ps->min_mip_filter == PIPE_TEX_MIPFILTER_NONE) {
186 /* just use the base level image */
187 min_lod = max_lod = 0.0f;
188 }
189 else {
190 min_lod = ps->min_lod;
191 max_lod = ps->max_lod;
192 }
193
194 /* Loop in case command buffer is full and we need to flush and retry */
195 for (try = 0; try < 2; try++) {
196 enum pipe_error ret =
197 SVGA3D_vgpu10_DefineSamplerState(svga->swc,
198 ss->id,
199 filter,
200 ss->addressu,
201 ss->addressv,
202 ss->addressw,
203 ss->lod_bias, /* float */
204 max_aniso,
205 compare_func,
206 bcolor,
207 min_lod, /* float */
208 max_lod); /* float */
209 if (ret == PIPE_OK)
210 return;
211 svga_context_flush(svga, NULL);
212 }
213 }
214
215
216 static void *
217 svga_create_sampler_state(struct pipe_context *pipe,
218 const struct pipe_sampler_state *sampler)
219 {
220 struct svga_context *svga = svga_context(pipe);
221 struct svga_sampler_state *cso = CALLOC_STRUCT( svga_sampler_state );
222
223 if (!cso)
224 return NULL;
225
226 cso->mipfilter = translate_mip_filter(sampler->min_mip_filter);
227 cso->magfilter = translate_img_filter( sampler->mag_img_filter );
228 cso->minfilter = translate_img_filter( sampler->min_img_filter );
229 cso->aniso_level = MAX2( sampler->max_anisotropy, 1 );
230 if(sampler->max_anisotropy)
231 cso->magfilter = cso->minfilter = SVGA3D_TEX_FILTER_ANISOTROPIC;
232 cso->lod_bias = sampler->lod_bias;
233 cso->addressu = translate_wrap_mode(sampler->wrap_s);
234 cso->addressv = translate_wrap_mode(sampler->wrap_t);
235 cso->addressw = translate_wrap_mode(sampler->wrap_r);
236 cso->normalized_coords = sampler->normalized_coords;
237 cso->compare_mode = sampler->compare_mode;
238 cso->compare_func = sampler->compare_func;
239
240 {
241 uint32 r = float_to_ubyte(sampler->border_color.f[0]);
242 uint32 g = float_to_ubyte(sampler->border_color.f[1]);
243 uint32 b = float_to_ubyte(sampler->border_color.f[2]);
244 uint32 a = float_to_ubyte(sampler->border_color.f[3]);
245
246 cso->bordercolor = (a << 24) | (r << 16) | (g << 8) | b;
247 }
248
249 /* No SVGA3D support for:
250 * - min/max LOD clamping
251 */
252 cso->min_lod = 0;
253 cso->view_min_lod = MAX2((int) (sampler->min_lod + 0.5), 0);
254 cso->view_max_lod = MAX2((int) (sampler->max_lod + 0.5), 0);
255
256 /* Use min_mipmap */
257 if (svga->debug.use_min_mipmap) {
258 if (cso->view_min_lod == cso->view_max_lod) {
259 cso->min_lod = cso->view_min_lod;
260 cso->view_min_lod = 0;
261 cso->view_max_lod = 1000; /* Just a high number */
262 cso->mipfilter = SVGA3D_TEX_FILTER_NONE;
263 }
264 }
265
266 if (svga_have_vgpu10(svga)) {
267 define_sampler_state_object(svga, cso, sampler);
268 }
269
270 SVGA_DBG(DEBUG_VIEWS, "min %u, view(min %u, max %u) lod, mipfilter %s\n",
271 cso->min_lod, cso->view_min_lod, cso->view_max_lod,
272 cso->mipfilter == SVGA3D_TEX_FILTER_NONE ? "SVGA3D_TEX_FILTER_NONE" : "SOMETHING");
273
274 return cso;
275 }
276
277 static void
278 svga_bind_sampler_states(struct pipe_context *pipe,
279 unsigned shader,
280 unsigned start,
281 unsigned num,
282 void **samplers)
283 {
284 struct svga_context *svga = svga_context(pipe);
285 unsigned i;
286
287 assert(shader < PIPE_SHADER_TYPES);
288 assert(start + num <= PIPE_MAX_SAMPLERS);
289
290 /* Pre-VGPU10 only supports FS textures */
291 if (!svga_have_vgpu10(svga) && shader != PIPE_SHADER_FRAGMENT)
292 return;
293
294 for (i = 0; i < num; i++)
295 svga->curr.sampler[shader][start + i] = samplers[i];
296
297 /* find highest non-null sampler[] entry */
298 {
299 unsigned j = MAX2(svga->curr.num_samplers[shader], start + num);
300 while (j > 0 && svga->curr.sampler[shader][j - 1] == NULL)
301 j--;
302 svga->curr.num_samplers[shader] = j;
303 }
304
305 svga->dirty |= SVGA_NEW_SAMPLER;
306 }
307
308
309 static void svga_delete_sampler_state(struct pipe_context *pipe,
310 void *sampler)
311 {
312 struct svga_sampler_state *ss = (struct svga_sampler_state *) sampler;
313 struct svga_context *svga = svga_context(pipe);
314
315 if (svga_have_vgpu10(svga)) {
316 enum pipe_error ret;
317
318 svga_hwtnl_flush_retry(svga);
319
320 ret = SVGA3D_vgpu10_DestroySamplerState(svga->swc, ss->id);
321 if (ret != PIPE_OK) {
322 svga_context_flush(svga, NULL);
323 ret = SVGA3D_vgpu10_DestroySamplerState(svga->swc, ss->id);
324 }
325 util_bitmask_clear(svga->sampler_object_id_bm, ss->id);
326 }
327
328 FREE(sampler);
329 }
330
331
332 static struct pipe_sampler_view *
333 svga_create_sampler_view(struct pipe_context *pipe,
334 struct pipe_resource *texture,
335 const struct pipe_sampler_view *templ)
336 {
337 struct svga_pipe_sampler_view *sv = CALLOC_STRUCT(svga_pipe_sampler_view);
338
339 if (!sv) {
340 return NULL;
341 }
342
343 sv->base = *templ;
344 sv->base.reference.count = 1;
345 sv->base.texture = NULL;
346 pipe_resource_reference(&sv->base.texture, texture);
347
348 sv->base.context = pipe;
349 sv->id = SVGA3D_INVALID_ID;
350
351 return &sv->base;
352 }
353
354
355 static void
356 svga_sampler_view_destroy(struct pipe_context *pipe,
357 struct pipe_sampler_view *view)
358 {
359 struct svga_context *svga = svga_context(pipe);
360 struct svga_pipe_sampler_view *sv = svga_pipe_sampler_view(view);
361
362 if (svga_have_vgpu10(svga) && sv->id != SVGA3D_INVALID_ID) {
363 if (view->context != pipe) {
364 /* The SVGA3D device will generate an error (and on Linux, cause
365 * us to abort) if we try to destroy a shader resource view from
366 * a context other than the one it was created with. Skip the
367 * SVGA3D_vgpu10_DestroyShaderResourceView() and leak the sampler
368 * view for now. This should only sometimes happen when a shared
369 * texture is deleted.
370 */
371 _debug_printf("context mismatch in %s\n", __func__);
372 }
373 else {
374 enum pipe_error ret;
375
376 svga_hwtnl_flush_retry(svga); /* XXX is this needed? */
377
378 ret = SVGA3D_vgpu10_DestroyShaderResourceView(svga->swc, sv->id);
379 if (ret != PIPE_OK) {
380 svga_context_flush(svga, NULL);
381 ret = SVGA3D_vgpu10_DestroyShaderResourceView(svga->swc, sv->id);
382 }
383 util_bitmask_clear(svga->sampler_view_id_bm, sv->id);
384 }
385 }
386
387 pipe_resource_reference(&sv->base.texture, NULL);
388
389 FREE(sv);
390 }
391
392 static void
393 svga_set_sampler_views(struct pipe_context *pipe,
394 unsigned shader,
395 unsigned start,
396 unsigned num,
397 struct pipe_sampler_view **views)
398 {
399 struct svga_context *svga = svga_context(pipe);
400 unsigned flag_1d = 0;
401 unsigned flag_srgb = 0;
402 uint i;
403
404 assert(shader < PIPE_SHADER_TYPES);
405 assert(start + num <= Elements(svga->curr.sampler_views[shader]));
406
407 /* Pre-VGPU10 only supports FS textures */
408 if (!svga_have_vgpu10(svga) && shader != PIPE_SHADER_FRAGMENT)
409 return;
410
411 for (i = 0; i < num; i++) {
412 if (svga->curr.sampler_views[shader][start + i] != views[i]) {
413 /* Note: we're using pipe_sampler_view_release() here to work around
414 * a possible crash when the old view belongs to another context that
415 * was already destroyed.
416 */
417 pipe_sampler_view_release(pipe, &svga->curr.sampler_views[shader][start + i]);
418 pipe_sampler_view_reference(&svga->curr.sampler_views[shader][start + i],
419 views[i]);
420 }
421
422 if (!views[i])
423 continue;
424
425 if (util_format_is_srgb(views[i]->format))
426 flag_srgb |= 1 << (start + i);
427
428 if (views[i]->texture->target == PIPE_TEXTURE_1D)
429 flag_1d |= 1 << (start + i);
430 }
431
432 /* find highest non-null sampler_views[] entry */
433 {
434 unsigned j = MAX2(svga->curr.num_sampler_views[shader], start + num);
435 while (j > 0 && svga->curr.sampler_views[shader][j - 1] == NULL)
436 j--;
437 svga->curr.num_sampler_views[shader] = j;
438 }
439
440 svga->dirty |= SVGA_NEW_TEXTURE_BINDING;
441
442 if (flag_srgb != svga->curr.tex_flags.flag_srgb ||
443 flag_1d != svga->curr.tex_flags.flag_1d)
444 {
445 svga->dirty |= SVGA_NEW_TEXTURE_FLAGS;
446 svga->curr.tex_flags.flag_1d = flag_1d;
447 svga->curr.tex_flags.flag_srgb = flag_srgb;
448 }
449 }
450
451
452 void svga_init_sampler_functions( struct svga_context *svga )
453 {
454 svga->pipe.create_sampler_state = svga_create_sampler_state;
455 svga->pipe.bind_sampler_states = svga_bind_sampler_states;
456 svga->pipe.delete_sampler_state = svga_delete_sampler_state;
457 svga->pipe.set_sampler_views = svga_set_sampler_views;
458 svga->pipe.create_sampler_view = svga_create_sampler_view;
459 svga->pipe.sampler_view_destroy = svga_sampler_view_destroy;
460 }
461
462
463