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/format/u_format.h"
29 #include "util/u_inlines.h"
30 #include "util/u_math.h"
31 #include "util/u_memory.h"
32
33 #include "svga_context.h"
34 #include "svga_cmd.h"
35 #include "svga_debug.h"
36 #include "svga_resource_texture.h"
37 #include "svga_surface.h"
38 #include "svga_sampler_view.h"
39
40
41 static inline unsigned
translate_wrap_mode(unsigned wrap)42 translate_wrap_mode(unsigned wrap)
43 {
44 switch (wrap) {
45 case PIPE_TEX_WRAP_REPEAT:
46 return SVGA3D_TEX_ADDRESS_WRAP;
47 case PIPE_TEX_WRAP_CLAMP:
48 return SVGA3D_TEX_ADDRESS_CLAMP;
49 case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
50 /* Unfortunately SVGA3D_TEX_ADDRESS_EDGE not respected by
51 * hardware.
52 */
53 return SVGA3D_TEX_ADDRESS_CLAMP;
54 case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
55 return SVGA3D_TEX_ADDRESS_BORDER;
56 case PIPE_TEX_WRAP_MIRROR_REPEAT:
57 return SVGA3D_TEX_ADDRESS_MIRROR;
58 case PIPE_TEX_WRAP_MIRROR_CLAMP:
59 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
60 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
61 return SVGA3D_TEX_ADDRESS_MIRRORONCE;
62 default:
63 assert(0);
64 return SVGA3D_TEX_ADDRESS_WRAP;
65 }
66 }
67
68
69 static inline unsigned
translate_img_filter(unsigned filter)70 translate_img_filter(unsigned filter)
71 {
72 switch (filter) {
73 case PIPE_TEX_FILTER_NEAREST:
74 return SVGA3D_TEX_FILTER_NEAREST;
75 case PIPE_TEX_FILTER_LINEAR:
76 return SVGA3D_TEX_FILTER_LINEAR;
77 default:
78 assert(0);
79 return SVGA3D_TEX_FILTER_NEAREST;
80 }
81 }
82
83
84 static inline unsigned
translate_mip_filter(unsigned filter)85 translate_mip_filter(unsigned filter)
86 {
87 switch (filter) {
88 case PIPE_TEX_MIPFILTER_NONE:
89 return SVGA3D_TEX_FILTER_NONE;
90 case PIPE_TEX_MIPFILTER_NEAREST:
91 return SVGA3D_TEX_FILTER_NEAREST;
92 case PIPE_TEX_MIPFILTER_LINEAR:
93 return SVGA3D_TEX_FILTER_LINEAR;
94 default:
95 assert(0);
96 return SVGA3D_TEX_FILTER_NONE;
97 }
98 }
99
100
101 static uint8
translate_comparison_func(unsigned func)102 translate_comparison_func(unsigned func)
103 {
104 switch (func) {
105 case PIPE_FUNC_NEVER:
106 return SVGA3D_COMPARISON_NEVER;
107 case PIPE_FUNC_LESS:
108 return SVGA3D_COMPARISON_LESS;
109 case PIPE_FUNC_EQUAL:
110 return SVGA3D_COMPARISON_EQUAL;
111 case PIPE_FUNC_LEQUAL:
112 return SVGA3D_COMPARISON_LESS_EQUAL;
113 case PIPE_FUNC_GREATER:
114 return SVGA3D_COMPARISON_GREATER;
115 case PIPE_FUNC_NOTEQUAL:
116 return SVGA3D_COMPARISON_NOT_EQUAL;
117 case PIPE_FUNC_GEQUAL:
118 return SVGA3D_COMPARISON_GREATER_EQUAL;
119 case PIPE_FUNC_ALWAYS:
120 return SVGA3D_COMPARISON_ALWAYS;
121 default:
122 assert(!"Invalid comparison function");
123 return SVGA3D_COMPARISON_ALWAYS;
124 }
125 }
126
127
128 /**
129 * Translate filtering state to vgpu10 format.
130 */
131 static SVGA3dFilter
translate_filter_mode(unsigned img_filter,unsigned min_filter,unsigned mag_filter,bool anisotropic,bool compare)132 translate_filter_mode(unsigned img_filter,
133 unsigned min_filter,
134 unsigned mag_filter,
135 bool anisotropic,
136 bool compare)
137 {
138 SVGA3dFilter mode = 0;
139
140 if (img_filter == PIPE_TEX_FILTER_LINEAR)
141 mode |= SVGA3D_FILTER_MIP_LINEAR;
142 if (min_filter == PIPE_TEX_FILTER_LINEAR)
143 mode |= SVGA3D_FILTER_MIN_LINEAR;
144 if (mag_filter == PIPE_TEX_FILTER_LINEAR)
145 mode |= SVGA3D_FILTER_MAG_LINEAR;
146 if (anisotropic)
147 mode |= SVGA3D_FILTER_ANISOTROPIC;
148 if (compare)
149 mode |= SVGA3D_FILTER_COMPARE;
150
151 return mode;
152 }
153
154
155 /**
156 * Define a vgpu10 sampler state.
157 */
158 static void
define_sampler_state_object(struct svga_context * svga,struct svga_sampler_state * ss,const struct pipe_sampler_state * ps)159 define_sampler_state_object(struct svga_context *svga,
160 struct svga_sampler_state *ss,
161 const struct pipe_sampler_state *ps)
162 {
163 uint8_t max_aniso = (uint8_t) 255; /* XXX fix me */
164 bool anisotropic;
165 uint8 compare_func;
166 SVGA3dFilter filter;
167 SVGA3dRGBAFloat bcolor;
168 float min_lod, max_lod;
169
170 assert(svga_have_vgpu10(svga));
171
172 anisotropic = ss->aniso_level > 1.0f;
173
174 filter = translate_filter_mode(ps->min_mip_filter,
175 ps->min_img_filter,
176 ps->mag_img_filter,
177 anisotropic,
178 ss->compare_mode);
179
180 compare_func = translate_comparison_func(ss->compare_func);
181
182 COPY_4V(bcolor.value, ps->border_color.f);
183
184 assert(ps->min_lod <= ps->max_lod);
185
186 if (ps->min_mip_filter == PIPE_TEX_MIPFILTER_NONE) {
187 /* just use the base level image */
188 min_lod = max_lod = 0.0f;
189 }
190 else {
191 min_lod = ps->min_lod;
192 max_lod = ps->max_lod;
193 }
194
195 /* If shadow comparisons are enabled, create two sampler states: one
196 * with the given shadow compare mode, another with shadow comparison off.
197 * We need the later because in some cases, we have to do the shadow
198 * compare in the shader. So, we don't want to do it twice.
199 */
200 STATIC_ASSERT(PIPE_TEX_COMPARE_NONE == 0);
201 STATIC_ASSERT(PIPE_TEX_COMPARE_R_TO_TEXTURE == 1);
202 ss->id[1] = SVGA3D_INVALID_ID;
203
204 unsigned i;
205 for (i = 0; i <= ss->compare_mode; i++) {
206 ss->id[i] = util_bitmask_add(svga->sampler_object_id_bm);
207
208 SVGA_RETRY(svga, SVGA3D_vgpu10_DefineSamplerState
209 (svga->swc,
210 ss->id[i],
211 filter,
212 ss->addressu,
213 ss->addressv,
214 ss->addressw,
215 ss->lod_bias, /* float */
216 max_aniso,
217 compare_func,
218 bcolor,
219 min_lod, /* float */
220 max_lod)); /* float */
221
222 /* turn off the shadow compare option for second iteration */
223 filter &= ~SVGA3D_FILTER_COMPARE;
224 }
225 }
226
227
228 static void *
svga_create_sampler_state(struct pipe_context * pipe,const struct pipe_sampler_state * sampler)229 svga_create_sampler_state(struct pipe_context *pipe,
230 const struct pipe_sampler_state *sampler)
231 {
232 struct svga_context *svga = svga_context(pipe);
233 struct svga_sampler_state *cso = CALLOC_STRUCT( svga_sampler_state );
234
235 if (!cso)
236 return NULL;
237
238 cso->mipfilter = translate_mip_filter(sampler->min_mip_filter);
239 cso->magfilter = translate_img_filter( sampler->mag_img_filter );
240 cso->minfilter = translate_img_filter( sampler->min_img_filter );
241 cso->aniso_level = MAX2( sampler->max_anisotropy, 1 );
242 if (sampler->max_anisotropy)
243 cso->magfilter = cso->minfilter = SVGA3D_TEX_FILTER_ANISOTROPIC;
244 cso->lod_bias = sampler->lod_bias;
245 cso->addressu = translate_wrap_mode(sampler->wrap_s);
246 cso->addressv = translate_wrap_mode(sampler->wrap_t);
247 cso->addressw = translate_wrap_mode(sampler->wrap_r);
248 cso->normalized_coords = !sampler->unnormalized_coords;
249 cso->compare_mode = sampler->compare_mode;
250 cso->compare_func = sampler->compare_func;
251
252 {
253 uint32 r = float_to_ubyte(sampler->border_color.f[0]);
254 uint32 g = float_to_ubyte(sampler->border_color.f[1]);
255 uint32 b = float_to_ubyte(sampler->border_color.f[2]);
256 uint32 a = float_to_ubyte(sampler->border_color.f[3]);
257
258 cso->bordercolor = (a << 24) | (r << 16) | (g << 8) | b;
259 }
260
261 /* No SVGA3D support for:
262 * - min/max LOD clamping
263 */
264 cso->min_lod = 0;
265 cso->view_min_lod = MAX2((int) (sampler->min_lod + 0.5), 0);
266 cso->view_max_lod = MAX2((int) (sampler->max_lod + 0.5), 0);
267
268 /* Use min_mipmap */
269 if (svga->debug.use_min_mipmap) {
270 if (cso->view_min_lod == cso->view_max_lod) {
271 cso->min_lod = cso->view_min_lod;
272 cso->view_min_lod = 0;
273 cso->view_max_lod = 1000; /* Just a high number */
274 cso->mipfilter = SVGA3D_TEX_FILTER_NONE;
275 }
276 }
277
278 if (svga_have_vgpu10(svga)) {
279 define_sampler_state_object(svga, cso, sampler);
280 }
281
282 SVGA_DBG(DEBUG_SAMPLERS,
283 "New sampler: min %u, view(min %u, max %u) lod, mipfilter %s\n",
284 cso->min_lod, cso->view_min_lod, cso->view_max_lod,
285 cso->mipfilter == SVGA3D_TEX_FILTER_NONE ? "SVGA3D_TEX_FILTER_NONE" : "SOMETHING");
286
287 svga->hud.num_sampler_objects++;
288 SVGA_STATS_COUNT_INC(svga_screen(svga->pipe.screen)->sws,
289 SVGA_STATS_COUNT_SAMPLER);
290
291 return cso;
292 }
293
294
295 static void
svga_bind_sampler_states(struct pipe_context * pipe,enum pipe_shader_type shader,unsigned start,unsigned num,void ** samplers)296 svga_bind_sampler_states(struct pipe_context *pipe,
297 enum pipe_shader_type shader,
298 unsigned start,
299 unsigned num,
300 void **samplers)
301 {
302 struct svga_context *svga = svga_context(pipe);
303 unsigned i;
304 bool any_change = false;
305
306 assert(shader < PIPE_SHADER_TYPES);
307 assert(start + num <= PIPE_MAX_SAMPLERS);
308
309 /* Pre-VGPU10 only supports FS textures */
310 if (!svga_have_vgpu10(svga) && shader != PIPE_SHADER_FRAGMENT)
311 return;
312
313 for (i = 0; i < num; i++) {
314 if (svga->curr.sampler[shader][start + i] != samplers[i])
315 any_change = true;
316 svga->curr.sampler[shader][start + i] = samplers[i];
317 }
318
319 if (!any_change) {
320 return;
321 }
322
323 /* find highest non-null sampler[] entry */
324 {
325 unsigned j = MAX2(svga->curr.num_samplers[shader], start + num);
326 while (j > 0 && svga->curr.sampler[shader][j - 1] == NULL)
327 j--;
328 svga->curr.num_samplers[shader] = j;
329 }
330
331 svga->dirty |= SVGA_NEW_SAMPLER;
332 }
333
334
335 static void
svga_delete_sampler_state(struct pipe_context * pipe,void * sampler)336 svga_delete_sampler_state(struct pipe_context *pipe, void *sampler)
337 {
338 struct svga_sampler_state *ss = (struct svga_sampler_state *) sampler;
339 struct svga_context *svga = svga_context(pipe);
340
341 if (svga_have_vgpu10(svga)) {
342 unsigned i;
343 for (i = 0; i < ARRAY_SIZE(ss->id); i++) {
344 if (ss->id[i] != SVGA3D_INVALID_ID) {
345 svga_hwtnl_flush_retry(svga);
346
347 SVGA_RETRY(svga, SVGA3D_vgpu10_DestroySamplerState(svga->swc,
348 ss->id[i]));
349 util_bitmask_clear(svga->sampler_object_id_bm, ss->id[i]);
350 }
351 }
352 }
353
354 FREE(sampler);
355 svga->hud.num_sampler_objects--;
356 }
357
358
359 static struct pipe_sampler_view *
svga_create_sampler_view(struct pipe_context * pipe,struct pipe_resource * texture,const struct pipe_sampler_view * templ)360 svga_create_sampler_view(struct pipe_context *pipe,
361 struct pipe_resource *texture,
362 const struct pipe_sampler_view *templ)
363 {
364 struct svga_context *svga = svga_context(pipe);
365 struct svga_pipe_sampler_view *sv = CALLOC_STRUCT(svga_pipe_sampler_view);
366
367 if (!sv) {
368 return NULL;
369 }
370
371 sv->base = *templ;
372 sv->base.reference.count = 1;
373 sv->base.texture = NULL;
374 pipe_resource_reference(&sv->base.texture, texture);
375
376 sv->base.context = pipe;
377 sv->id = SVGA3D_INVALID_ID;
378
379 svga->hud.num_samplerview_objects++;
380 SVGA_STATS_COUNT_INC(svga_screen(svga->pipe.screen)->sws,
381 SVGA_STATS_COUNT_SAMPLERVIEW);
382
383 return &sv->base;
384 }
385
386
387 static void
svga_sampler_view_destroy(struct pipe_context * pipe,struct pipe_sampler_view * view)388 svga_sampler_view_destroy(struct pipe_context *pipe,
389 struct pipe_sampler_view *view)
390 {
391 struct svga_context *svga = svga_context(pipe);
392 struct svga_pipe_sampler_view *sv = svga_pipe_sampler_view(view);
393
394 if (svga_have_vgpu10(svga) && sv->id != SVGA3D_INVALID_ID) {
395 assert(view->context == pipe);
396
397 svga_hwtnl_flush_retry(svga);
398
399 SVGA_RETRY(svga, SVGA3D_vgpu10_DestroyShaderResourceView(svga->swc,
400 sv->id));
401 util_bitmask_clear(svga->sampler_view_id_bm, sv->id);
402 }
403
404 pipe_resource_reference(&sv->base.texture, NULL);
405
406 FREE(sv);
407 svga->hud.num_samplerview_objects--;
408 }
409
410
411 static void
svga_set_sampler_views(struct pipe_context * pipe,enum pipe_shader_type shader,unsigned start,unsigned num,unsigned unbind_num_trailing_slots,bool take_ownership,struct pipe_sampler_view ** views)412 svga_set_sampler_views(struct pipe_context *pipe,
413 enum pipe_shader_type shader,
414 unsigned start,
415 unsigned num,
416 unsigned unbind_num_trailing_slots,
417 bool take_ownership,
418 struct pipe_sampler_view **views)
419 {
420 struct svga_context *svga = svga_context(pipe);
421 unsigned flag_1d = 0;
422 unsigned flag_srgb = 0;
423 uint i;
424 bool any_change = false;
425
426 assert(shader < PIPE_SHADER_TYPES);
427 assert(start + num <= ARRAY_SIZE(svga->curr.sampler_views[shader]));
428
429 /* Pre-VGPU10 only supports FS textures */
430 if (!svga_have_vgpu10(svga) && shader != PIPE_SHADER_FRAGMENT) {
431 for (unsigned i = 0; i < num; i++) {
432 struct pipe_sampler_view *view = views[i];
433 pipe_sampler_view_reference(&view, NULL);
434 }
435 return;
436 }
437
438 SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_SETSAMPLERVIEWS);
439
440 /* This bit of code works around a quirk in the CSO module.
441 * If start=num=0 it means all sampler views should be released.
442 * Note that the CSO module treats sampler views for fragment shaders
443 * differently than other shader types.
444 */
445 if (start == 0 && num == 0 && svga->curr.num_sampler_views[shader] > 0) {
446 for (i = 0; i < svga->curr.num_sampler_views[shader]; i++) {
447 pipe_sampler_view_reference(&svga->curr.sampler_views[shader][i],
448 NULL);
449 }
450 any_change = true;
451 }
452
453 for (i = 0; i < num; i++) {
454 enum pipe_texture_target target;
455
456 any_change |= svga->curr.sampler_views[shader][start + i] != views[i];
457
458 if (take_ownership) {
459 pipe_sampler_view_reference(&svga->curr.sampler_views[shader][start + i],
460 NULL);
461 svga->curr.sampler_views[shader][start + i] = views[i];
462 } else if (svga->curr.sampler_views[shader][start + i] != views[i]) {
463 pipe_sampler_view_reference(&svga->curr.sampler_views[shader][start + i],
464 views[i]);
465 }
466
467 if (!views[i])
468 continue;
469
470 if (util_format_is_srgb(views[i]->format))
471 flag_srgb |= 1 << (start + i);
472
473 target = views[i]->target;
474 if (target == PIPE_TEXTURE_1D) {
475 flag_1d |= 1 << (start + i);
476 } else if (target == PIPE_TEXTURE_RECT) {
477 /* If the size of the bound texture changes, we need to emit new
478 * const buffer values.
479 */
480 svga->dirty |= SVGA_NEW_TEXTURE_CONSTS;
481 } else if (target == PIPE_BUFFER) {
482 /* If the size of the bound buffer changes, we need to emit new
483 * const buffer values.
484 */
485 svga->dirty |= SVGA_NEW_TEXTURE_CONSTS;
486 }
487 }
488
489 for (; i < num + unbind_num_trailing_slots; i++) {
490 if (svga->curr.sampler_views[shader][start + i]) {
491 pipe_sampler_view_reference(&svga->curr.sampler_views[shader][start + i],
492 NULL);
493 any_change = true;
494 }
495 }
496
497 if (!any_change) {
498 goto done;
499 }
500
501 /* find highest non-null sampler_views[] entry */
502 {
503 unsigned j = MAX2(svga->curr.num_sampler_views[shader], start + num);
504 while (j > 0 && svga->curr.sampler_views[shader][j - 1] == NULL)
505 j--;
506 svga->curr.num_sampler_views[shader] = j;
507 }
508
509 svga->dirty |= SVGA_NEW_TEXTURE_BINDING;
510
511 if (flag_srgb != svga->curr.tex_flags.flag_srgb ||
512 flag_1d != svga->curr.tex_flags.flag_1d) {
513 svga->dirty |= SVGA_NEW_TEXTURE_FLAGS;
514 svga->curr.tex_flags.flag_1d = flag_1d;
515 svga->curr.tex_flags.flag_srgb = flag_srgb;
516 }
517
518 /* Check if any of the sampler view resources collide with the framebuffer
519 * color buffers or depth stencil resource. If so, set the NEW_FRAME_BUFFER
520 * dirty bit so that emit_framebuffer can be invoked to create backed view
521 * for the conflicted surface view.
522 */
523 if (svga_check_sampler_framebuffer_resource_collision(svga, shader)) {
524 svga->dirty |= SVGA_NEW_FRAME_BUFFER;
525 }
526
527 done:
528 SVGA_STATS_TIME_POP(svga_sws(svga));
529 }
530
531 /**
532 * Clean up sampler, sampler view state at context destruction time
533 */
534 void
svga_cleanup_sampler_state(struct svga_context * svga)535 svga_cleanup_sampler_state(struct svga_context *svga)
536 {
537 enum pipe_shader_type shader;
538
539 for (shader = 0; shader <= PIPE_SHADER_COMPUTE; shader++) {
540 unsigned i;
541
542 for (i = 0; i < svga->state.hw_draw.num_sampler_views[shader]; i++) {
543 pipe_sampler_view_reference(&svga->state.hw_draw.sampler_views[shader][i],
544 NULL);
545 }
546 }
547
548 /* free polygon stipple state */
549 if (svga->polygon_stipple.sampler) {
550 svga->pipe.delete_sampler_state(&svga->pipe, svga->polygon_stipple.sampler);
551 }
552
553 if (svga->polygon_stipple.sampler_view) {
554 svga->pipe.sampler_view_destroy(&svga->pipe,
555 &svga->polygon_stipple.sampler_view->base);
556 }
557 pipe_resource_reference(&svga->polygon_stipple.texture, NULL);
558 }
559
560 void
svga_init_sampler_functions(struct svga_context * svga)561 svga_init_sampler_functions( struct svga_context *svga )
562 {
563 svga->pipe.create_sampler_state = svga_create_sampler_state;
564 svga->pipe.bind_sampler_states = svga_bind_sampler_states;
565 svga->pipe.delete_sampler_state = svga_delete_sampler_state;
566 svga->pipe.set_sampler_views = svga_set_sampler_views;
567 svga->pipe.create_sampler_view = svga_create_sampler_view;
568 svga->pipe.sampler_view_destroy = svga_sampler_view_destroy;
569 }
570