1 /*
2 * Copyright © 2014 Rob Clark <[email protected]>
3 * SPDX-License-Identifier: MIT
4 *
5 * Authors:
6 * Rob Clark <[email protected]>
7 */
8
9 #include "pipe/p_state.h"
10 #include "util/format/u_format.h"
11 #include "util/u_inlines.h"
12 #include "util/u_memory.h"
13 #include "util/u_string.h"
14
15 #include "fd4_format.h"
16 #include "fd4_texture.h"
17
18 static enum a4xx_tex_clamp
tex_clamp(unsigned wrap,bool * needs_border)19 tex_clamp(unsigned wrap, bool *needs_border)
20 {
21 switch (wrap) {
22 case PIPE_TEX_WRAP_REPEAT:
23 return A4XX_TEX_REPEAT;
24 case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
25 return A4XX_TEX_CLAMP_TO_EDGE;
26 case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
27 *needs_border = true;
28 return A4XX_TEX_CLAMP_TO_BORDER;
29 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
30 /* only works for PoT.. need to emulate otherwise! */
31 return A4XX_TEX_MIRROR_CLAMP;
32 case PIPE_TEX_WRAP_MIRROR_REPEAT:
33 return A4XX_TEX_MIRROR_REPEAT;
34 case PIPE_TEX_WRAP_MIRROR_CLAMP:
35 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
36 /* these two we could perhaps emulate, but we currently
37 * just don't advertise PIPE_CAP_TEXTURE_MIRROR_CLAMP
38 */
39 default:
40 DBG("invalid wrap: %u", wrap);
41 return 0;
42 }
43 }
44
45 static enum a4xx_tex_filter
tex_filter(unsigned filter,bool aniso)46 tex_filter(unsigned filter, bool aniso)
47 {
48 switch (filter) {
49 case PIPE_TEX_FILTER_NEAREST:
50 return A4XX_TEX_NEAREST;
51 case PIPE_TEX_FILTER_LINEAR:
52 return aniso ? A4XX_TEX_ANISO : A4XX_TEX_LINEAR;
53 default:
54 DBG("invalid filter: %u", filter);
55 return 0;
56 }
57 }
58
59 static void *
fd4_sampler_state_create(struct pipe_context * pctx,const struct pipe_sampler_state * cso)60 fd4_sampler_state_create(struct pipe_context *pctx,
61 const struct pipe_sampler_state *cso)
62 {
63 struct fd4_sampler_stateobj *so = CALLOC_STRUCT(fd4_sampler_stateobj);
64 unsigned aniso = util_last_bit(MIN2(cso->max_anisotropy >> 1, 8));
65 bool miplinear = false;
66
67 if (!so)
68 return NULL;
69
70 if (cso->min_mip_filter == PIPE_TEX_MIPFILTER_LINEAR)
71 miplinear = true;
72
73 so->base = *cso;
74
75 so->needs_border = false;
76 so->texsamp0 =
77 COND(miplinear, A4XX_TEX_SAMP_0_MIPFILTER_LINEAR_NEAR) |
78 A4XX_TEX_SAMP_0_XY_MAG(tex_filter(cso->mag_img_filter, aniso)) |
79 A4XX_TEX_SAMP_0_XY_MIN(tex_filter(cso->min_img_filter, aniso)) |
80 A4XX_TEX_SAMP_0_ANISO(aniso) |
81 A4XX_TEX_SAMP_0_LOD_BIAS(cso->lod_bias) |
82 A4XX_TEX_SAMP_0_WRAP_S(tex_clamp(cso->wrap_s, &so->needs_border)) |
83 A4XX_TEX_SAMP_0_WRAP_T(tex_clamp(cso->wrap_t, &so->needs_border)) |
84 A4XX_TEX_SAMP_0_WRAP_R(tex_clamp(cso->wrap_r, &so->needs_border));
85
86 so->texsamp1 =
87 // COND(miplinear, A4XX_TEX_SAMP_1_MIPFILTER_LINEAR_FAR) |
88 COND(!cso->seamless_cube_map, A4XX_TEX_SAMP_1_CUBEMAPSEAMLESSFILTOFF) |
89 COND(cso->unnormalized_coords, A4XX_TEX_SAMP_1_UNNORM_COORDS);
90
91 if (cso->min_mip_filter != PIPE_TEX_MIPFILTER_NONE) {
92 so->texsamp1 |= A4XX_TEX_SAMP_1_MIN_LOD(cso->min_lod) |
93 A4XX_TEX_SAMP_1_MAX_LOD(cso->max_lod);
94 } else {
95 /* If we're not doing mipmap filtering, we still need a slightly > 0
96 * LOD clamp so the HW can decide between min and mag filtering of
97 * level 0.
98 */
99 so->texsamp1 |= A4XX_TEX_SAMP_1_MIN_LOD(MIN2(cso->min_lod, 0.125f)) |
100 A4XX_TEX_SAMP_1_MAX_LOD(MIN2(cso->max_lod, 0.125f));
101 }
102
103 if (cso->compare_mode)
104 so->texsamp1 |=
105 A4XX_TEX_SAMP_1_COMPARE_FUNC(cso->compare_func); /* maps 1:1 */
106
107 return so;
108 }
109
110 static bool
use_astc_srgb_workaround(struct pipe_context * pctx,enum pipe_format format)111 use_astc_srgb_workaround(struct pipe_context *pctx, enum pipe_format format)
112 {
113 return (fd_screen(pctx->screen)->gpu_id == 420) &&
114 (util_format_description(format)->layout == UTIL_FORMAT_LAYOUT_ASTC);
115 }
116
117 static struct pipe_sampler_view *
fd4_sampler_view_create(struct pipe_context * pctx,struct pipe_resource * prsc,const struct pipe_sampler_view * cso)118 fd4_sampler_view_create(struct pipe_context *pctx, struct pipe_resource *prsc,
119 const struct pipe_sampler_view *cso)
120 {
121 struct fd4_pipe_sampler_view *so = CALLOC_STRUCT(fd4_pipe_sampler_view);
122 struct fd_resource *rsc = fd_resource(prsc);
123 enum pipe_format format = cso->format;
124 unsigned lvl, layers = 0;
125
126 if (!so)
127 return NULL;
128
129 if (format == PIPE_FORMAT_X32_S8X24_UINT) {
130 rsc = rsc->stencil;
131 format = rsc->b.b.format;
132 }
133
134 so->base = *cso;
135 pipe_reference(NULL, &prsc->reference);
136 so->base.texture = prsc;
137 so->base.reference.count = 1;
138 so->base.context = pctx;
139
140 so->swizzle = fd4_tex_swiz(format, cso->swizzle_r, cso->swizzle_g,
141 cso->swizzle_b, cso->swizzle_a);
142
143 so->texconst0 = A4XX_TEX_CONST_0_TYPE(fd4_tex_type(cso->target)) |
144 A4XX_TEX_CONST_0_FMT(fd4_pipe2tex(format)) |
145 so->swizzle;
146
147 if (util_format_is_srgb(format)) {
148 if (use_astc_srgb_workaround(pctx, format))
149 so->astc_srgb = true;
150 so->texconst0 |= A4XX_TEX_CONST_0_SRGB;
151 }
152
153 if (cso->target == PIPE_BUFFER) {
154 unsigned elements = cso->u.buf.size / util_format_get_blocksize(format);
155
156 lvl = 0;
157 so->texconst1 =
158 A4XX_TEX_CONST_1_WIDTH(elements & MASK(15)) |
159 A4XX_TEX_CONST_1_HEIGHT(elements >> 15);
160 so->texconst2 = A4XX_TEX_CONST_2_BUFFER;
161 so->offset = cso->u.buf.offset;
162 } else {
163 unsigned miplevels;
164
165 lvl = fd_sampler_first_level(cso);
166 miplevels = fd_sampler_last_level(cso) - lvl;
167 layers = cso->u.tex.last_layer - cso->u.tex.first_layer + 1;
168
169 so->texconst0 |= A4XX_TEX_CONST_0_MIPLVLS(miplevels);
170 so->texconst1 = A4XX_TEX_CONST_1_WIDTH(u_minify(prsc->width0, lvl)) |
171 A4XX_TEX_CONST_1_HEIGHT(u_minify(prsc->height0, lvl));
172 so->texconst2 = A4XX_TEX_CONST_2_PITCHALIGN(rsc->layout.pitchalign - 5) |
173 A4XX_TEX_CONST_2_PITCH(fd_resource_pitch(rsc, lvl));
174 so->offset = fd_resource_offset(rsc, lvl, cso->u.tex.first_layer);
175 }
176
177 /* NOTE: since we sample z24s8 using 8888_UINT format, the swizzle
178 * we get isn't quite right. Use SWAP(XYZW) as a cheap and cheerful
179 * way to re-arrange things so stencil component is where the swiz
180 * expects.
181 *
182 * Note that gallium expects stencil sampler to return (s,s,s,s)
183 * which isn't quite true. To make that happen we'd have to massage
184 * the swizzle. But in practice only the .x component is used.
185 */
186 if (format == PIPE_FORMAT_X24S8_UINT)
187 so->texconst2 |= A4XX_TEX_CONST_2_SWAP(XYZW);
188
189 switch (cso->target) {
190 case PIPE_TEXTURE_1D_ARRAY:
191 case PIPE_TEXTURE_2D_ARRAY:
192 so->texconst3 = A4XX_TEX_CONST_3_DEPTH(layers) |
193 A4XX_TEX_CONST_3_LAYERSZ(rsc->layout.layer_size);
194 break;
195 case PIPE_TEXTURE_CUBE:
196 case PIPE_TEXTURE_CUBE_ARRAY:
197 so->texconst3 = A4XX_TEX_CONST_3_DEPTH(layers / 6) |
198 A4XX_TEX_CONST_3_LAYERSZ(rsc->layout.layer_size);
199 break;
200 case PIPE_TEXTURE_3D:
201 so->texconst3 =
202 A4XX_TEX_CONST_3_DEPTH(u_minify(prsc->depth0, lvl)) |
203 A4XX_TEX_CONST_3_LAYERSZ(fd_resource_slice(rsc, lvl)->size0);
204 so->texconst4 = A4XX_TEX_CONST_4_LAYERSZ(
205 fd_resource_slice(rsc, prsc->last_level)->size0);
206 break;
207 default:
208 so->texconst3 = 0x00000000;
209 break;
210 }
211
212 return &so->base;
213 }
214
215 static void
fd4_set_sampler_views(struct pipe_context * pctx,enum pipe_shader_type shader,unsigned start,unsigned nr,unsigned unbind_num_trailing_slots,bool take_ownership,struct pipe_sampler_view ** views)216 fd4_set_sampler_views(struct pipe_context *pctx, enum pipe_shader_type shader,
217 unsigned start, unsigned nr,
218 unsigned unbind_num_trailing_slots,
219 bool take_ownership,
220 struct pipe_sampler_view **views)
221 {
222 struct fd_context *ctx = fd_context(pctx);
223 struct fd4_context *fd4_ctx = fd4_context(ctx);
224 uint16_t astc_srgb = 0;
225 uint16_t *sampler_swizzles;
226 unsigned i;
227
228 if (shader == PIPE_SHADER_FRAGMENT) {
229 sampler_swizzles = fd4_ctx->fsampler_swizzles;
230 } else if (shader == PIPE_SHADER_VERTEX) {
231 sampler_swizzles = fd4_ctx->vsampler_swizzles;
232 } else if (shader == PIPE_SHADER_COMPUTE) {
233 sampler_swizzles = fd4_ctx->csampler_swizzles;
234 } else {
235 assert(0);
236 sampler_swizzles = fd4_ctx->csampler_swizzles;
237 }
238
239 for (i = 0; i < nr; i++) {
240 if (views[i]) {
241 struct fd4_pipe_sampler_view *view = fd4_pipe_sampler_view(views[i]);
242 if (view->astc_srgb)
243 astc_srgb |= (1 << (start + i));
244 sampler_swizzles[start + i] = view->swizzle >> 4;
245
246 const struct util_format_description *desc =
247 util_format_description(view->base.format);
248 int c = util_format_get_first_non_void_channel(desc->format);
249 if (c >= 0 && desc->channel[c].pure_integer) {
250 switch (desc->channel[c].size) {
251 case 8:
252 sampler_swizzles[start + i] |= 0x1000;
253 break;
254 case 16:
255 sampler_swizzles[start + i] |= 0x2000;
256 break;
257 case 32:
258 sampler_swizzles[start + i] |= 0x3000;
259 break;
260 case 10:
261 sampler_swizzles[start + i] |= 0x4000;
262 break;
263 default:
264 assert(0);
265 }
266 }
267 }
268 }
269
270 fd_set_sampler_views(pctx, shader, start, nr, unbind_num_trailing_slots,
271 take_ownership, views);
272
273 for (i = 0; i < unbind_num_trailing_slots; i++) {
274 astc_srgb &= ~(1 << (start + nr + i));
275 sampler_swizzles[start + nr + i] = 0x688;
276 }
277
278 if (shader == PIPE_SHADER_FRAGMENT) {
279 fd4_ctx->fastc_srgb = astc_srgb;
280 } else if (shader == PIPE_SHADER_VERTEX) {
281 fd4_ctx->vastc_srgb = astc_srgb;
282 } else if (shader == PIPE_SHADER_COMPUTE) {
283 fd4_ctx->castc_srgb = astc_srgb;
284 }
285 }
286
287 void
fd4_texture_init(struct pipe_context * pctx)288 fd4_texture_init(struct pipe_context *pctx)
289 {
290 pctx->create_sampler_state = fd4_sampler_state_create;
291 pctx->bind_sampler_states = fd_sampler_states_bind;
292 pctx->create_sampler_view = fd4_sampler_view_create;
293 pctx->set_sampler_views = fd4_set_sampler_views;
294 }
295