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