xref: /aosp_15_r20/external/mesa3d/src/mesa/state_tracker/st_atom_sampler.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /**************************************************************************
2  *
3  * Copyright 2007 VMware, Inc.
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sub license, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial portions
16  * of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  *
26  **************************************************************************/
27 
28  /*
29   * Authors:
30   *   Keith Whitwell <[email protected]>
31   *   Brian Paul
32   */
33 
34 
35 #include "main/macros.h"
36 #include "main/glformats.h"
37 #include "main/samplerobj.h"
38 #include "main/teximage.h"
39 #include "main/texobj.h"
40 
41 #include "st_context.h"
42 #include "st_cb_texture.h"
43 #include "st_format.h"
44 #include "st_atom.h"
45 #include "st_sampler_view.h"
46 #include "st_texture.h"
47 #include "pipe/p_context.h"
48 #include "pipe/p_defines.h"
49 
50 #include "cso_cache/cso_context.h"
51 
52 #include "util/format/u_format.h"
53 #include "program/prog_instruction.h"
54 
55 
56 /**
57  * Convert a gl_sampler_object to a pipe_sampler_state object.
58  */
59 void
st_convert_sampler(const struct st_context * st,const struct gl_texture_object * texobj,const struct gl_sampler_object * msamp,float tex_unit_lod_bias,struct pipe_sampler_state * sampler,bool seamless_cube_map,bool ignore_srgb_decode,bool glsl130_or_later)60 st_convert_sampler(const struct st_context *st,
61                    const struct gl_texture_object *texobj,
62                    const struct gl_sampler_object *msamp,
63                    float tex_unit_lod_bias,
64                    struct pipe_sampler_state *sampler,
65                    bool seamless_cube_map,
66                    bool ignore_srgb_decode,
67                    bool glsl130_or_later)
68 {
69    memcpy(sampler, &msamp->Attrib.state, sizeof(*sampler));
70 
71    sampler->seamless_cube_map |= seamless_cube_map;
72 
73    if (texobj->_IsIntegerFormat ||
74        (texobj->_IsFloat && st->ctx->Const.ForceFloat32TexNearest)) {
75       sampler->min_img_filter = PIPE_TEX_FILTER_NEAREST;
76       sampler->min_mip_filter = PIPE_TEX_FILTER_NEAREST;
77       sampler->mag_img_filter = PIPE_TEX_FILTER_NEAREST;
78    }
79 
80    if (texobj->Target == GL_TEXTURE_RECTANGLE_ARB && !st->lower_rect_tex)
81       sampler->unnormalized_coords = 1;
82 
83    /*
84     * The spec says that "texture wrap modes are ignored" for seamless cube
85     * maps, so normalize the CSO. This works around Apple hardware which honours
86     * REPEAT modes even for seamless cube maps.
87     */
88    if ((texobj->Target == GL_TEXTURE_CUBE_MAP ||
89         texobj->Target == GL_TEXTURE_CUBE_MAP_ARRAY) &&
90        sampler->seamless_cube_map) {
91 
92       sampler->wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
93       sampler->wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
94       sampler->wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
95    }
96 
97    sampler->lod_bias += tex_unit_lod_bias;
98 
99    /* Check that only wrap modes using the border color have the first bit
100     * set.
101     */
102    STATIC_ASSERT(PIPE_TEX_WRAP_CLAMP & 0x1);
103    STATIC_ASSERT(PIPE_TEX_WRAP_CLAMP_TO_BORDER & 0x1);
104    STATIC_ASSERT(PIPE_TEX_WRAP_MIRROR_CLAMP & 0x1);
105    STATIC_ASSERT(PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER & 0x1);
106    STATIC_ASSERT(((PIPE_TEX_WRAP_REPEAT |
107                    PIPE_TEX_WRAP_CLAMP_TO_EDGE |
108                    PIPE_TEX_WRAP_MIRROR_REPEAT |
109                    PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE) & 0x1) == 0);
110 
111    if (msamp->Attrib.IsBorderColorNonZero &&
112        /* This is true if wrap modes are using the border color: */
113        (sampler->wrap_s | sampler->wrap_t | sampler->wrap_r) & 0x1) {
114       GLenum texBaseFormat = _mesa_base_tex_image(texobj)->_BaseFormat;
115 
116       /* From OpenGL 4.3 spec, "Combined Depth/Stencil Textures":
117        *
118        *    "The DEPTH_STENCIL_TEXTURE_MODE is ignored for non
119        *     depth/stencil textures.
120        */
121       const bool has_combined_ds = texBaseFormat == GL_DEPTH_STENCIL;
122 
123       const GLboolean is_integer =
124          texobj->_IsIntegerFormat ||
125          (texobj->StencilSampling && has_combined_ds) ||
126          texBaseFormat == GL_STENCIL_INDEX;
127 
128       if (texobj->StencilSampling && has_combined_ds)
129          texBaseFormat = GL_STENCIL_INDEX;
130 
131       if (st->apply_texture_swizzle_to_border_color ||
132           st->alpha_border_color_is_not_w || st->use_format_with_border_color) {
133          if (st->apply_texture_swizzle_to_border_color) {
134             const unsigned swizzle = glsl130_or_later ? texobj->SwizzleGLSL130 : texobj->Swizzle;
135 
136             union pipe_color_union tmp = sampler->border_color;
137             const unsigned char swz[4] =
138             {
139                GET_SWZ(swizzle, 0),
140                GET_SWZ(swizzle, 1),
141                GET_SWZ(swizzle, 2),
142                GET_SWZ(swizzle, 3),
143             };
144 
145             st_translate_color(&tmp, texBaseFormat, is_integer);
146 
147             util_format_apply_color_swizzle(&sampler->border_color,
148                                             &tmp, swz, is_integer);
149          } else {
150             bool srgb_skip_decode = false;
151 
152             if (!ignore_srgb_decode && msamp->Attrib.sRGBDecode == GL_SKIP_DECODE_EXT)
153                srgb_skip_decode = true;
154             enum pipe_format format = st_get_sampler_view_format(st, texobj, srgb_skip_decode);
155             if (st->use_format_with_border_color)
156                sampler->border_color_format = format;
157             /* alpha is not w, so set it to the first available component: */
158             if (st->alpha_border_color_is_not_w && util_format_is_alpha(format)) {
159                /* use x component */
160                sampler->border_color.ui[0] = sampler->border_color.ui[3];
161             } else if (st->alpha_border_color_is_not_w && util_format_is_luminance_alpha(format)) {
162                /* use y component */
163                sampler->border_color.ui[1] = sampler->border_color.ui[3];
164             } else {
165                /* not an alpha format */
166                st_translate_color(&sampler->border_color,
167                                   texBaseFormat, is_integer);
168             }
169          }
170       } else {
171          st_translate_color(&sampler->border_color,
172                             texBaseFormat, is_integer);
173       }
174       sampler->border_color_is_integer = is_integer;
175    }
176 
177    /* If sampling a depth texture and using shadow comparison */
178    if (msamp->Attrib.CompareMode == GL_COMPARE_R_TO_TEXTURE) {
179       GLenum texBaseFormat = _mesa_base_tex_image(texobj)->_BaseFormat;
180 
181       if (texBaseFormat == GL_DEPTH_COMPONENT ||
182           (texBaseFormat == GL_DEPTH_STENCIL && !texobj->StencilSampling))
183          sampler->compare_mode = PIPE_TEX_COMPARE_R_TO_TEXTURE;
184    }
185 }
186 
187 /**
188  * Get a pipe_sampler_state object from a texture unit.
189  */
190 void
st_convert_sampler_from_unit(const struct st_context * st,struct pipe_sampler_state * sampler,GLuint texUnit,bool glsl130_or_later)191 st_convert_sampler_from_unit(const struct st_context *st,
192                              struct pipe_sampler_state *sampler,
193                              GLuint texUnit,
194                              bool glsl130_or_later)
195 {
196    const struct gl_texture_object *texobj;
197    struct gl_context *ctx = st->ctx;
198    const struct gl_sampler_object *msamp;
199 
200    texobj = ctx->Texture.Unit[texUnit]._Current;
201    assert(texobj);
202 
203    msamp = _mesa_get_samplerobj(ctx, texUnit);
204 
205    st_convert_sampler(st, texobj, msamp, ctx->Texture.Unit[texUnit].LodBiasQuantized,
206                       sampler, ctx->Texture.CubeMapSeamless, true, glsl130_or_later);
207 }
208 
209 
210 /**
211  * Update the gallium driver's sampler state for fragment, vertex or
212  * geometry shader stage.
213  */
214 static void
update_shader_samplers(struct st_context * st,enum pipe_shader_type shader_stage,const struct gl_program * prog,struct pipe_sampler_state * samplers,unsigned * out_num_samplers)215 update_shader_samplers(struct st_context *st,
216                        enum pipe_shader_type shader_stage,
217                        const struct gl_program *prog,
218                        struct pipe_sampler_state *samplers,
219                        unsigned *out_num_samplers)
220 {
221    struct gl_context *ctx = st->ctx;
222    GLbitfield samplers_used = prog->SamplersUsed;
223    GLbitfield free_slots = ~prog->SamplersUsed;
224    GLbitfield external_samplers_used = prog->ExternalSamplersUsed;
225    unsigned unit, num_samplers;
226    struct pipe_sampler_state local_samplers[PIPE_MAX_SAMPLERS];
227    const struct pipe_sampler_state *states[PIPE_MAX_SAMPLERS];
228 
229    if (samplers_used == 0x0) {
230       if (out_num_samplers)
231          *out_num_samplers = 0;
232       return;
233    }
234 
235    if (!samplers)
236       samplers = local_samplers;
237 
238    num_samplers = util_last_bit(samplers_used);
239 
240    /* loop over sampler units (aka tex image units) */
241    for (unit = 0; samplers_used; unit++, samplers_used >>= 1) {
242       struct pipe_sampler_state *sampler = samplers + unit;
243       unsigned tex_unit = prog->SamplerUnits[unit];
244 
245       /* Don't update the sampler for TBOs. cso_context will not bind sampler
246        * states that are NULL.
247        */
248       if (samplers_used & 1 &&
249           (ctx->Texture.Unit[tex_unit]._Current->Target != GL_TEXTURE_BUFFER)) {
250          st_convert_sampler_from_unit(
251             st, sampler, tex_unit,
252             prog->shader_program && prog->shader_program->GLSL_Version >= 130);
253          states[unit] = sampler;
254       } else {
255          states[unit] = NULL;
256       }
257    }
258 
259    /* For any external samplers with multiplaner YUV, stuff the additional
260     * sampler states we need at the end.
261     *
262     * Just re-use the existing sampler-state from the primary slot.
263     */
264    while (unlikely(external_samplers_used)) {
265       GLuint unit = u_bit_scan(&external_samplers_used);
266       GLuint extra = 0;
267       struct gl_texture_object *stObj =
268             st_get_texture_object(st->ctx, prog, unit);
269       struct pipe_sampler_state *sampler = samplers + unit;
270 
271       /* if resource format matches then YUV wasn't lowered */
272       if (!stObj || st_get_view_format(stObj) == stObj->pt->format)
273          continue;
274 
275       switch (st_get_view_format(stObj)) {
276       case PIPE_FORMAT_NV12:
277          if (stObj->pt->format == PIPE_FORMAT_R8_G8B8_420_UNORM)
278             /* no additional views needed */
279             break;
280          FALLTHROUGH;
281       case PIPE_FORMAT_NV21:
282          if (stObj->pt->format == PIPE_FORMAT_R8_B8G8_420_UNORM)
283             /* no additional views needed */
284             break;
285          FALLTHROUGH;
286       case PIPE_FORMAT_P010:
287       case PIPE_FORMAT_P012:
288       case PIPE_FORMAT_P016:
289       case PIPE_FORMAT_P030:
290       case PIPE_FORMAT_Y210:
291       case PIPE_FORMAT_Y212:
292       case PIPE_FORMAT_Y216:
293       case PIPE_FORMAT_YUYV:
294       case PIPE_FORMAT_YVYU:
295       case PIPE_FORMAT_UYVY:
296       case PIPE_FORMAT_VYUY:
297          if (stObj->pt->format == PIPE_FORMAT_R8G8_R8B8_UNORM ||
298              stObj->pt->format == PIPE_FORMAT_R8B8_R8G8_UNORM ||
299              stObj->pt->format == PIPE_FORMAT_B8R8_G8R8_UNORM ||
300              stObj->pt->format == PIPE_FORMAT_G8R8_B8R8_UNORM) {
301             /* no additional views needed */
302             break;
303          }
304 
305          /* we need one additional sampler: */
306          extra = u_bit_scan(&free_slots);
307          states[extra] = sampler;
308          break;
309       case PIPE_FORMAT_IYUV:
310          if (stObj->pt->format == PIPE_FORMAT_R8_G8_B8_420_UNORM ||
311              stObj->pt->format == PIPE_FORMAT_R8_B8_G8_420_UNORM) {
312             /* no additional views needed */
313             break;
314          }
315          /* we need two additional samplers: */
316          extra = u_bit_scan(&free_slots);
317          states[extra] = sampler;
318          extra = u_bit_scan(&free_slots);
319          states[extra] = sampler;
320          break;
321       default:
322          break;
323       }
324 
325       num_samplers = MAX2(num_samplers, extra + 1);
326    }
327 
328    cso_set_samplers(st->cso_context, shader_stage, num_samplers, states);
329 
330    if (out_num_samplers)
331       *out_num_samplers = num_samplers;
332 }
333 
334 
335 void
st_update_vertex_samplers(struct st_context * st)336 st_update_vertex_samplers(struct st_context *st)
337 {
338    const struct gl_context *ctx = st->ctx;
339 
340    update_shader_samplers(st,
341                           PIPE_SHADER_VERTEX,
342                           ctx->VertexProgram._Current,
343                           st->state.vert_samplers,
344                           &st->state.num_vert_samplers);
345 }
346 
347 
348 void
st_update_tessctrl_samplers(struct st_context * st)349 st_update_tessctrl_samplers(struct st_context *st)
350 {
351    const struct gl_context *ctx = st->ctx;
352 
353    if (ctx->TessCtrlProgram._Current) {
354       update_shader_samplers(st,
355                              PIPE_SHADER_TESS_CTRL,
356                              ctx->TessCtrlProgram._Current, NULL, NULL);
357    }
358 }
359 
360 
361 void
st_update_tesseval_samplers(struct st_context * st)362 st_update_tesseval_samplers(struct st_context *st)
363 {
364    const struct gl_context *ctx = st->ctx;
365 
366    if (ctx->TessEvalProgram._Current) {
367       update_shader_samplers(st,
368                              PIPE_SHADER_TESS_EVAL,
369                              ctx->TessEvalProgram._Current, NULL, NULL);
370    }
371 }
372 
373 
374 void
st_update_geometry_samplers(struct st_context * st)375 st_update_geometry_samplers(struct st_context *st)
376 {
377    const struct gl_context *ctx = st->ctx;
378 
379    if (ctx->GeometryProgram._Current) {
380       update_shader_samplers(st,
381                              PIPE_SHADER_GEOMETRY,
382                              ctx->GeometryProgram._Current, NULL, NULL);
383    }
384 }
385 
386 
387 void
st_update_fragment_samplers(struct st_context * st)388 st_update_fragment_samplers(struct st_context *st)
389 {
390    const struct gl_context *ctx = st->ctx;
391 
392    update_shader_samplers(st,
393                           PIPE_SHADER_FRAGMENT,
394                           ctx->FragmentProgram._Current,
395                           st->state.frag_samplers,
396                           &st->state.num_frag_samplers);
397 }
398 
399 
400 void
st_update_compute_samplers(struct st_context * st)401 st_update_compute_samplers(struct st_context *st)
402 {
403    const struct gl_context *ctx = st->ctx;
404 
405    if (ctx->ComputeProgram._Current) {
406       update_shader_samplers(st,
407                              PIPE_SHADER_COMPUTE,
408                              ctx->ComputeProgram._Current, NULL, NULL);
409    }
410 }
411