Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
3770 | Serge | 1 | /************************************************************************** |
2 | * |
||
3 | * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. |
||
4 | * All Rights Reserved. |
||
5 | * Copyright 2008-2010 VMware, Inc. All rights reserved. |
||
6 | * |
||
7 | * Permission is hereby granted, free of charge, to any person obtaining a |
||
8 | * copy of this software and associated documentation files (the |
||
9 | * "Software"), to deal in the Software without restriction, including |
||
10 | * without limitation the rights to use, copy, modify, merge, publish, |
||
11 | * distribute, sub license, and/or sell copies of the Software, and to |
||
12 | * permit persons to whom the Software is furnished to do so, subject to |
||
13 | * the following conditions: |
||
14 | * |
||
15 | * The above copyright notice and this permission notice (including the |
||
16 | * next paragraph) shall be included in all copies or substantial portions |
||
17 | * of the Software. |
||
18 | * |
||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
||
20 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||
21 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. |
||
22 | * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR |
||
23 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
||
24 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
||
25 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||
26 | * |
||
27 | **************************************************************************/ |
||
28 | |||
29 | /** |
||
30 | * Texture sampling |
||
31 | * |
||
32 | * Authors: |
||
33 | * Brian Paul |
||
34 | * Keith Whitwell |
||
35 | */ |
||
36 | |||
37 | #include "pipe/p_context.h" |
||
38 | #include "pipe/p_defines.h" |
||
39 | #include "pipe/p_shader_tokens.h" |
||
40 | #include "util/u_math.h" |
||
41 | #include "util/u_format.h" |
||
42 | #include "util/u_memory.h" |
||
43 | #include "util/u_inlines.h" |
||
44 | #include "sp_quad.h" /* only for #define QUAD_* tokens */ |
||
45 | #include "sp_tex_sample.h" |
||
46 | #include "sp_texture.h" |
||
47 | #include "sp_tex_tile_cache.h" |
||
48 | |||
49 | |||
50 | /** Set to one to help debug texture sampling */ |
||
51 | #define DEBUG_TEX 0 |
||
52 | |||
53 | |||
54 | /* |
||
55 | * Return fractional part of 'f'. Used for computing interpolation weights. |
||
56 | * Need to be careful with negative values. |
||
57 | * Note, if this function isn't perfect you'll sometimes see 1-pixel bands |
||
58 | * of improperly weighted linear-filtered textures. |
||
59 | * The tests/texwrap.c demo is a good test. |
||
60 | */ |
||
61 | static INLINE float |
||
62 | frac(float f) |
||
63 | { |
||
64 | return f - floorf(f); |
||
65 | } |
||
66 | |||
67 | |||
68 | |||
69 | /** |
||
70 | * Linear interpolation macro |
||
71 | */ |
||
72 | static INLINE float |
||
73 | lerp(float a, float v0, float v1) |
||
74 | { |
||
75 | return v0 + a * (v1 - v0); |
||
76 | } |
||
77 | |||
78 | |||
79 | /** |
||
80 | * Do 2D/bilinear interpolation of float values. |
||
81 | * v00, v10, v01 and v11 are typically four texture samples in a square/box. |
||
82 | * a and b are the horizontal and vertical interpolants. |
||
83 | * It's important that this function is inlined when compiled with |
||
84 | * optimization! If we find that's not true on some systems, convert |
||
85 | * to a macro. |
||
86 | */ |
||
87 | static INLINE float |
||
88 | lerp_2d(float a, float b, |
||
89 | float v00, float v10, float v01, float v11) |
||
90 | { |
||
91 | const float temp0 = lerp(a, v00, v10); |
||
92 | const float temp1 = lerp(a, v01, v11); |
||
93 | return lerp(b, temp0, temp1); |
||
94 | } |
||
95 | |||
96 | |||
97 | /** |
||
98 | * As above, but 3D interpolation of 8 values. |
||
99 | */ |
||
100 | static INLINE float |
||
101 | lerp_3d(float a, float b, float c, |
||
102 | float v000, float v100, float v010, float v110, |
||
103 | float v001, float v101, float v011, float v111) |
||
104 | { |
||
105 | const float temp0 = lerp_2d(a, b, v000, v100, v010, v110); |
||
106 | const float temp1 = lerp_2d(a, b, v001, v101, v011, v111); |
||
107 | return lerp(c, temp0, temp1); |
||
108 | } |
||
109 | |||
110 | |||
111 | |||
112 | /** |
||
113 | * Compute coord % size for repeat wrap modes. |
||
114 | * Note that if coord is negative, coord % size doesn't give the right |
||
115 | * value. To avoid that problem we add a large multiple of the size |
||
116 | * (rather than using a conditional). |
||
117 | */ |
||
118 | static INLINE int |
||
119 | repeat(int coord, unsigned size) |
||
120 | { |
||
121 | return (coord + size * 1024) % size; |
||
122 | } |
||
123 | |||
124 | |||
125 | /** |
||
126 | * Apply texture coord wrapping mode and return integer texture indexes |
||
127 | * for a vector of four texcoords (S or T or P). |
||
128 | * \param wrapMode PIPE_TEX_WRAP_x |
||
129 | * \param s the incoming texcoords |
||
130 | * \param size the texture image size |
||
131 | * \param icoord returns the integer texcoords |
||
132 | */ |
||
133 | static void |
||
134 | wrap_nearest_repeat(float s, unsigned size, int *icoord) |
||
135 | { |
||
136 | /* s limited to [0,1) */ |
||
137 | /* i limited to [0,size-1] */ |
||
138 | int i = util_ifloor(s * size); |
||
139 | *icoord = repeat(i, size); |
||
140 | } |
||
141 | |||
142 | |||
143 | static void |
||
144 | wrap_nearest_clamp(float s, unsigned size, int *icoord) |
||
145 | { |
||
146 | /* s limited to [0,1] */ |
||
147 | /* i limited to [0,size-1] */ |
||
148 | if (s <= 0.0F) |
||
149 | *icoord = 0; |
||
150 | else if (s >= 1.0F) |
||
151 | *icoord = size - 1; |
||
152 | else |
||
153 | *icoord = util_ifloor(s * size); |
||
154 | } |
||
155 | |||
156 | |||
157 | static void |
||
158 | wrap_nearest_clamp_to_edge(float s, unsigned size, int *icoord) |
||
159 | { |
||
160 | /* s limited to [min,max] */ |
||
161 | /* i limited to [0, size-1] */ |
||
162 | const float min = 1.0F / (2.0F * size); |
||
163 | const float max = 1.0F - min; |
||
164 | if (s < min) |
||
165 | *icoord = 0; |
||
166 | else if (s > max) |
||
167 | *icoord = size - 1; |
||
168 | else |
||
169 | *icoord = util_ifloor(s * size); |
||
170 | } |
||
171 | |||
172 | |||
173 | static void |
||
174 | wrap_nearest_clamp_to_border(float s, unsigned size, int *icoord) |
||
175 | { |
||
176 | /* s limited to [min,max] */ |
||
177 | /* i limited to [-1, size] */ |
||
178 | const float min = -1.0F / (2.0F * size); |
||
179 | const float max = 1.0F - min; |
||
180 | if (s <= min) |
||
181 | *icoord = -1; |
||
182 | else if (s >= max) |
||
183 | *icoord = size; |
||
184 | else |
||
185 | *icoord = util_ifloor(s * size); |
||
186 | } |
||
187 | |||
188 | |||
189 | static void |
||
190 | wrap_nearest_mirror_repeat(float s, unsigned size, int *icoord) |
||
191 | { |
||
192 | const float min = 1.0F / (2.0F * size); |
||
193 | const float max = 1.0F - min; |
||
194 | const int flr = util_ifloor(s); |
||
195 | float u = frac(s); |
||
196 | if (flr & 1) |
||
197 | u = 1.0F - u; |
||
198 | if (u < min) |
||
199 | *icoord = 0; |
||
200 | else if (u > max) |
||
201 | *icoord = size - 1; |
||
202 | else |
||
203 | *icoord = util_ifloor(u * size); |
||
204 | } |
||
205 | |||
206 | |||
207 | static void |
||
208 | wrap_nearest_mirror_clamp(float s, unsigned size, int *icoord) |
||
209 | { |
||
210 | /* s limited to [0,1] */ |
||
211 | /* i limited to [0,size-1] */ |
||
212 | const float u = fabsf(s); |
||
213 | if (u <= 0.0F) |
||
214 | *icoord = 0; |
||
215 | else if (u >= 1.0F) |
||
216 | *icoord = size - 1; |
||
217 | else |
||
218 | *icoord = util_ifloor(u * size); |
||
219 | } |
||
220 | |||
221 | |||
222 | static void |
||
223 | wrap_nearest_mirror_clamp_to_edge(float s, unsigned size, int *icoord) |
||
224 | { |
||
225 | /* s limited to [min,max] */ |
||
226 | /* i limited to [0, size-1] */ |
||
227 | const float min = 1.0F / (2.0F * size); |
||
228 | const float max = 1.0F - min; |
||
229 | const float u = fabsf(s); |
||
230 | if (u < min) |
||
231 | *icoord = 0; |
||
232 | else if (u > max) |
||
233 | *icoord = size - 1; |
||
234 | else |
||
235 | *icoord = util_ifloor(u * size); |
||
236 | } |
||
237 | |||
238 | |||
239 | static void |
||
240 | wrap_nearest_mirror_clamp_to_border(float s, unsigned size, int *icoord) |
||
241 | { |
||
242 | /* s limited to [min,max] */ |
||
243 | /* i limited to [0, size-1] */ |
||
244 | const float min = -1.0F / (2.0F * size); |
||
245 | const float max = 1.0F - min; |
||
246 | const float u = fabsf(s); |
||
247 | if (u < min) |
||
248 | *icoord = -1; |
||
249 | else if (u > max) |
||
250 | *icoord = size; |
||
251 | else |
||
252 | *icoord = util_ifloor(u * size); |
||
253 | } |
||
254 | |||
255 | |||
256 | /** |
||
257 | * Used to compute texel locations for linear sampling |
||
258 | * \param wrapMode PIPE_TEX_WRAP_x |
||
259 | * \param s the texcoord |
||
260 | * \param size the texture image size |
||
261 | * \param icoord0 returns first texture index |
||
262 | * \param icoord1 returns second texture index (usually icoord0 + 1) |
||
263 | * \param w returns blend factor/weight between texture indices |
||
264 | * \param icoord returns the computed integer texture coord |
||
265 | */ |
||
266 | static void |
||
267 | wrap_linear_repeat(float s, unsigned size, |
||
268 | int *icoord0, int *icoord1, float *w) |
||
269 | { |
||
270 | float u = s * size - 0.5F; |
||
271 | *icoord0 = repeat(util_ifloor(u), size); |
||
272 | *icoord1 = repeat(*icoord0 + 1, size); |
||
273 | *w = frac(u); |
||
274 | } |
||
275 | |||
276 | |||
277 | static void |
||
278 | wrap_linear_clamp(float s, unsigned size, |
||
279 | int *icoord0, int *icoord1, float *w) |
||
280 | { |
||
281 | float u = CLAMP(s, 0.0F, 1.0F); |
||
282 | u = u * size - 0.5f; |
||
283 | *icoord0 = util_ifloor(u); |
||
284 | *icoord1 = *icoord0 + 1; |
||
285 | *w = frac(u); |
||
286 | } |
||
287 | |||
288 | |||
289 | static void |
||
290 | wrap_linear_clamp_to_edge(float s, unsigned size, |
||
291 | int *icoord0, int *icoord1, float *w) |
||
292 | { |
||
293 | float u = CLAMP(s, 0.0F, 1.0F); |
||
294 | u = u * size - 0.5f; |
||
295 | *icoord0 = util_ifloor(u); |
||
296 | *icoord1 = *icoord0 + 1; |
||
297 | if (*icoord0 < 0) |
||
298 | *icoord0 = 0; |
||
299 | if (*icoord1 >= (int) size) |
||
300 | *icoord1 = size - 1; |
||
301 | *w = frac(u); |
||
302 | } |
||
303 | |||
304 | |||
305 | static void |
||
306 | wrap_linear_clamp_to_border(float s, unsigned size, |
||
307 | int *icoord0, int *icoord1, float *w) |
||
308 | { |
||
309 | const float min = -1.0F / (2.0F * size); |
||
310 | const float max = 1.0F - min; |
||
311 | float u = CLAMP(s, min, max); |
||
312 | u = u * size - 0.5f; |
||
313 | *icoord0 = util_ifloor(u); |
||
314 | *icoord1 = *icoord0 + 1; |
||
315 | *w = frac(u); |
||
316 | } |
||
317 | |||
318 | |||
319 | static void |
||
320 | wrap_linear_mirror_repeat(float s, unsigned size, |
||
321 | int *icoord0, int *icoord1, float *w) |
||
322 | { |
||
323 | const int flr = util_ifloor(s); |
||
324 | float u = frac(s); |
||
325 | if (flr & 1) |
||
326 | u = 1.0F - u; |
||
327 | u = u * size - 0.5F; |
||
328 | *icoord0 = util_ifloor(u); |
||
329 | *icoord1 = *icoord0 + 1; |
||
330 | if (*icoord0 < 0) |
||
331 | *icoord0 = 0; |
||
332 | if (*icoord1 >= (int) size) |
||
333 | *icoord1 = size - 1; |
||
334 | *w = frac(u); |
||
335 | } |
||
336 | |||
337 | |||
338 | static void |
||
339 | wrap_linear_mirror_clamp(float s, unsigned size, |
||
340 | int *icoord0, int *icoord1, float *w) |
||
341 | { |
||
342 | float u = fabsf(s); |
||
343 | if (u >= 1.0F) |
||
344 | u = (float) size; |
||
345 | else |
||
346 | u *= size; |
||
347 | u -= 0.5F; |
||
348 | *icoord0 = util_ifloor(u); |
||
349 | *icoord1 = *icoord0 + 1; |
||
350 | *w = frac(u); |
||
351 | } |
||
352 | |||
353 | |||
354 | static void |
||
355 | wrap_linear_mirror_clamp_to_edge(float s, unsigned size, |
||
356 | int *icoord0, int *icoord1, float *w) |
||
357 | { |
||
358 | float u = fabsf(s); |
||
359 | if (u >= 1.0F) |
||
360 | u = (float) size; |
||
361 | else |
||
362 | u *= size; |
||
363 | u -= 0.5F; |
||
364 | *icoord0 = util_ifloor(u); |
||
365 | *icoord1 = *icoord0 + 1; |
||
366 | if (*icoord0 < 0) |
||
367 | *icoord0 = 0; |
||
368 | if (*icoord1 >= (int) size) |
||
369 | *icoord1 = size - 1; |
||
370 | *w = frac(u); |
||
371 | } |
||
372 | |||
373 | |||
374 | static void |
||
375 | wrap_linear_mirror_clamp_to_border(float s, unsigned size, |
||
376 | int *icoord0, int *icoord1, float *w) |
||
377 | { |
||
378 | const float min = -1.0F / (2.0F * size); |
||
379 | const float max = 1.0F - min; |
||
380 | float u = fabsf(s); |
||
381 | if (u <= min) |
||
382 | u = min * size; |
||
383 | else if (u >= max) |
||
384 | u = max * size; |
||
385 | else |
||
386 | u *= size; |
||
387 | u -= 0.5F; |
||
388 | *icoord0 = util_ifloor(u); |
||
389 | *icoord1 = *icoord0 + 1; |
||
390 | *w = frac(u); |
||
391 | } |
||
392 | |||
393 | |||
394 | /** |
||
395 | * PIPE_TEX_WRAP_CLAMP for nearest sampling, unnormalized coords. |
||
396 | */ |
||
397 | static void |
||
398 | wrap_nearest_unorm_clamp(float s, unsigned size, int *icoord) |
||
399 | { |
||
400 | int i = util_ifloor(s); |
||
401 | *icoord = CLAMP(i, 0, (int) size-1); |
||
402 | } |
||
403 | |||
404 | |||
405 | /** |
||
406 | * PIPE_TEX_WRAP_CLAMP_TO_BORDER for nearest sampling, unnormalized coords. |
||
407 | */ |
||
408 | static void |
||
409 | wrap_nearest_unorm_clamp_to_border(float s, unsigned size, int *icoord) |
||
410 | { |
||
411 | *icoord = util_ifloor( CLAMP(s, -0.5F, (float) size + 0.5F) ); |
||
412 | } |
||
413 | |||
414 | |||
415 | /** |
||
416 | * PIPE_TEX_WRAP_CLAMP_TO_EDGE for nearest sampling, unnormalized coords. |
||
417 | */ |
||
418 | static void |
||
419 | wrap_nearest_unorm_clamp_to_edge(float s, unsigned size, int *icoord) |
||
420 | { |
||
421 | *icoord = util_ifloor( CLAMP(s, 0.5F, (float) size - 0.5F) ); |
||
422 | } |
||
423 | |||
424 | |||
425 | /** |
||
426 | * PIPE_TEX_WRAP_CLAMP for linear sampling, unnormalized coords. |
||
427 | */ |
||
428 | static void |
||
429 | wrap_linear_unorm_clamp(float s, unsigned size, |
||
430 | int *icoord0, int *icoord1, float *w) |
||
431 | { |
||
432 | /* Not exactly what the spec says, but it matches NVIDIA output */ |
||
433 | float u = CLAMP(s - 0.5F, 0.0f, (float) size - 1.0f); |
||
434 | *icoord0 = util_ifloor(u); |
||
435 | *icoord1 = *icoord0 + 1; |
||
436 | *w = frac(u); |
||
437 | } |
||
438 | |||
439 | |||
440 | /** |
||
441 | * PIPE_TEX_WRAP_CLAMP_TO_BORDER for linear sampling, unnormalized coords. |
||
442 | */ |
||
443 | static void |
||
444 | wrap_linear_unorm_clamp_to_border(float s, unsigned size, |
||
445 | int *icoord0, int *icoord1, float *w) |
||
446 | { |
||
447 | float u = CLAMP(s, -0.5F, (float) size + 0.5F); |
||
448 | u -= 0.5F; |
||
449 | *icoord0 = util_ifloor(u); |
||
450 | *icoord1 = *icoord0 + 1; |
||
451 | if (*icoord1 > (int) size - 1) |
||
452 | *icoord1 = size - 1; |
||
453 | *w = frac(u); |
||
454 | } |
||
455 | |||
456 | |||
457 | /** |
||
458 | * PIPE_TEX_WRAP_CLAMP_TO_EDGE for linear sampling, unnormalized coords. |
||
459 | */ |
||
460 | static void |
||
461 | wrap_linear_unorm_clamp_to_edge(float s, unsigned size, |
||
462 | int *icoord0, int *icoord1, float *w) |
||
463 | { |
||
464 | float u = CLAMP(s, +0.5F, (float) size - 0.5F); |
||
465 | u -= 0.5F; |
||
466 | *icoord0 = util_ifloor(u); |
||
467 | *icoord1 = *icoord0 + 1; |
||
468 | if (*icoord1 > (int) size - 1) |
||
469 | *icoord1 = size - 1; |
||
470 | *w = frac(u); |
||
471 | } |
||
472 | |||
473 | |||
474 | /** |
||
475 | * Do coordinate to array index conversion. For array textures. |
||
476 | */ |
||
477 | static INLINE void |
||
478 | wrap_array_layer(float coord, unsigned size, int *layer) |
||
479 | { |
||
480 | int c = util_ifloor(coord + 0.5F); |
||
481 | *layer = CLAMP(c, 0, (int) size - 1); |
||
482 | } |
||
483 | |||
484 | |||
485 | /** |
||
486 | * Examine the quad's texture coordinates to compute the partial |
||
487 | * derivatives w.r.t X and Y, then compute lambda (level of detail). |
||
488 | */ |
||
489 | static float |
||
490 | compute_lambda_1d(const struct sp_sampler_view *sview, |
||
491 | const float s[TGSI_QUAD_SIZE], |
||
492 | const float t[TGSI_QUAD_SIZE], |
||
493 | const float p[TGSI_QUAD_SIZE]) |
||
494 | { |
||
495 | const struct pipe_resource *texture = sview->base.texture; |
||
496 | float dsdx = fabsf(s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT]); |
||
497 | float dsdy = fabsf(s[QUAD_TOP_LEFT] - s[QUAD_BOTTOM_LEFT]); |
||
498 | float rho = MAX2(dsdx, dsdy) * u_minify(texture->width0, sview->base.u.tex.first_level); |
||
499 | |||
500 | return util_fast_log2(rho); |
||
501 | } |
||
502 | |||
503 | |||
504 | static float |
||
505 | compute_lambda_2d(const struct sp_sampler_view *sview, |
||
506 | const float s[TGSI_QUAD_SIZE], |
||
507 | const float t[TGSI_QUAD_SIZE], |
||
508 | const float p[TGSI_QUAD_SIZE]) |
||
509 | { |
||
510 | const struct pipe_resource *texture = sview->base.texture; |
||
511 | float dsdx = fabsf(s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT]); |
||
512 | float dsdy = fabsf(s[QUAD_TOP_LEFT] - s[QUAD_BOTTOM_LEFT]); |
||
513 | float dtdx = fabsf(t[QUAD_BOTTOM_RIGHT] - t[QUAD_BOTTOM_LEFT]); |
||
514 | float dtdy = fabsf(t[QUAD_TOP_LEFT] - t[QUAD_BOTTOM_LEFT]); |
||
515 | float maxx = MAX2(dsdx, dsdy) * u_minify(texture->width0, sview->base.u.tex.first_level); |
||
516 | float maxy = MAX2(dtdx, dtdy) * u_minify(texture->height0, sview->base.u.tex.first_level); |
||
517 | float rho = MAX2(maxx, maxy); |
||
518 | |||
519 | return util_fast_log2(rho); |
||
520 | } |
||
521 | |||
522 | |||
523 | static float |
||
524 | compute_lambda_3d(const struct sp_sampler_view *sview, |
||
525 | const float s[TGSI_QUAD_SIZE], |
||
526 | const float t[TGSI_QUAD_SIZE], |
||
527 | const float p[TGSI_QUAD_SIZE]) |
||
528 | { |
||
529 | const struct pipe_resource *texture = sview->base.texture; |
||
530 | float dsdx = fabsf(s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT]); |
||
531 | float dsdy = fabsf(s[QUAD_TOP_LEFT] - s[QUAD_BOTTOM_LEFT]); |
||
532 | float dtdx = fabsf(t[QUAD_BOTTOM_RIGHT] - t[QUAD_BOTTOM_LEFT]); |
||
533 | float dtdy = fabsf(t[QUAD_TOP_LEFT] - t[QUAD_BOTTOM_LEFT]); |
||
534 | float dpdx = fabsf(p[QUAD_BOTTOM_RIGHT] - p[QUAD_BOTTOM_LEFT]); |
||
535 | float dpdy = fabsf(p[QUAD_TOP_LEFT] - p[QUAD_BOTTOM_LEFT]); |
||
536 | float maxx = MAX2(dsdx, dsdy) * u_minify(texture->width0, sview->base.u.tex.first_level); |
||
537 | float maxy = MAX2(dtdx, dtdy) * u_minify(texture->height0, sview->base.u.tex.first_level); |
||
538 | float maxz = MAX2(dpdx, dpdy) * u_minify(texture->depth0, sview->base.u.tex.first_level); |
||
539 | float rho; |
||
540 | |||
541 | rho = MAX2(maxx, maxy); |
||
542 | rho = MAX2(rho, maxz); |
||
543 | |||
544 | return util_fast_log2(rho); |
||
545 | } |
||
546 | |||
547 | |||
548 | /** |
||
549 | * Compute lambda for a vertex texture sampler. |
||
550 | * Since there aren't derivatives to use, just return 0. |
||
551 | */ |
||
552 | static float |
||
553 | compute_lambda_vert(const struct sp_sampler_view *sview, |
||
554 | const float s[TGSI_QUAD_SIZE], |
||
555 | const float t[TGSI_QUAD_SIZE], |
||
556 | const float p[TGSI_QUAD_SIZE]) |
||
557 | { |
||
558 | return 0.0f; |
||
559 | } |
||
560 | |||
561 | |||
562 | |||
563 | /** |
||
564 | * Get a texel from a texture, using the texture tile cache. |
||
565 | * |
||
566 | * \param addr the template tex address containing cube, z, face info. |
||
567 | * \param x the x coord of texel within 2D image |
||
568 | * \param y the y coord of texel within 2D image |
||
569 | * \param rgba the quad to put the texel/color into |
||
570 | * |
||
571 | * XXX maybe move this into sp_tex_tile_cache.c and merge with the |
||
572 | * sp_get_cached_tile_tex() function. |
||
573 | */ |
||
574 | |||
575 | |||
576 | |||
577 | |||
578 | static INLINE const float * |
||
579 | get_texel_2d_no_border(const struct sp_sampler_view *sp_sview, |
||
580 | union tex_tile_address addr, int x, int y) |
||
581 | { |
||
582 | const struct softpipe_tex_cached_tile *tile; |
||
583 | addr.bits.x = x / TEX_TILE_SIZE; |
||
584 | addr.bits.y = y / TEX_TILE_SIZE; |
||
585 | y %= TEX_TILE_SIZE; |
||
586 | x %= TEX_TILE_SIZE; |
||
587 | |||
588 | tile = sp_get_cached_tile_tex(sp_sview->cache, addr); |
||
589 | |||
590 | return &tile->data.color[y][x][0]; |
||
591 | } |
||
592 | |||
593 | |||
594 | static INLINE const float * |
||
595 | get_texel_2d(const struct sp_sampler_view *sp_sview, |
||
596 | const struct sp_sampler *sp_samp, |
||
597 | union tex_tile_address addr, int x, int y) |
||
598 | { |
||
599 | const struct pipe_resource *texture = sp_sview->base.texture; |
||
600 | unsigned level = addr.bits.level; |
||
601 | |||
602 | if (x < 0 || x >= (int) u_minify(texture->width0, level) || |
||
603 | y < 0 || y >= (int) u_minify(texture->height0, level)) { |
||
604 | return sp_samp->base.border_color.f; |
||
605 | } |
||
606 | else { |
||
607 | return get_texel_2d_no_border( sp_sview, addr, x, y ); |
||
608 | } |
||
609 | } |
||
610 | |||
611 | /* |
||
612 | * seamless cubemap neighbour array. |
||
613 | * this array is used to find the adjacent face in each of 4 directions, |
||
614 | * left, right, up, down. (or -x, +x, -y, +y). |
||
615 | */ |
||
616 | static const unsigned face_array[PIPE_TEX_FACE_MAX][4] = { |
||
617 | /* pos X first then neg X is Z different, Y the same */ |
||
618 | /* PIPE_TEX_FACE_POS_X,*/ |
||
619 | { PIPE_TEX_FACE_POS_Z, PIPE_TEX_FACE_NEG_Z, |
||
620 | PIPE_TEX_FACE_NEG_Y, PIPE_TEX_FACE_POS_Y }, |
||
621 | /* PIPE_TEX_FACE_NEG_X */ |
||
622 | { PIPE_TEX_FACE_NEG_Z, PIPE_TEX_FACE_POS_Z, |
||
623 | PIPE_TEX_FACE_NEG_Y, PIPE_TEX_FACE_POS_Y }, |
||
624 | |||
625 | /* pos Y first then neg Y is X different, X the same */ |
||
626 | /* PIPE_TEX_FACE_POS_Y */ |
||
627 | { PIPE_TEX_FACE_NEG_X, PIPE_TEX_FACE_POS_X, |
||
628 | PIPE_TEX_FACE_POS_Z, PIPE_TEX_FACE_NEG_Z }, |
||
629 | |||
630 | /* PIPE_TEX_FACE_NEG_Y */ |
||
631 | { PIPE_TEX_FACE_NEG_X, PIPE_TEX_FACE_POS_X, |
||
632 | PIPE_TEX_FACE_NEG_Z, PIPE_TEX_FACE_POS_Z }, |
||
633 | |||
634 | /* pos Z first then neg Y is X different, X the same */ |
||
635 | /* PIPE_TEX_FACE_POS_Z */ |
||
636 | { PIPE_TEX_FACE_NEG_X, PIPE_TEX_FACE_POS_X, |
||
637 | PIPE_TEX_FACE_NEG_Y, PIPE_TEX_FACE_POS_Y }, |
||
638 | |||
639 | /* PIPE_TEX_FACE_NEG_Z */ |
||
640 | { PIPE_TEX_FACE_POS_X, PIPE_TEX_FACE_NEG_X, |
||
641 | PIPE_TEX_FACE_NEG_Y, PIPE_TEX_FACE_POS_Y } |
||
642 | }; |
||
643 | |||
644 | static INLINE unsigned |
||
645 | get_next_face(unsigned face, int x, int y) |
||
646 | { |
||
647 | int idx = 0; |
||
648 | |||
649 | if (x == 0 && y == 0) |
||
650 | return face; |
||
651 | if (x == -1) |
||
652 | idx = 0; |
||
653 | else if (x == 1) |
||
654 | idx = 1; |
||
655 | else if (y == -1) |
||
656 | idx = 2; |
||
657 | else if (y == 1) |
||
658 | idx = 3; |
||
659 | |||
660 | return face_array[face][idx]; |
||
661 | } |
||
662 | |||
663 | static INLINE const float * |
||
664 | get_texel_cube_seamless(const struct sp_sampler_view *sp_sview, |
||
665 | union tex_tile_address addr, int x, int y, |
||
666 | float *corner) |
||
667 | { |
||
668 | const struct pipe_resource *texture = sp_sview->base.texture; |
||
669 | unsigned level = addr.bits.level; |
||
670 | unsigned face = addr.bits.face; |
||
671 | int new_x, new_y; |
||
672 | int max_x, max_y; |
||
673 | int c; |
||
674 | |||
675 | max_x = (int) u_minify(texture->width0, level); |
||
676 | max_y = (int) u_minify(texture->height0, level); |
||
677 | new_x = x; |
||
678 | new_y = y; |
||
679 | |||
680 | /* the corner case */ |
||
681 | if ((x < 0 || x >= max_x) && |
||
682 | (y < 0 || y >= max_y)) { |
||
683 | const float *c1, *c2, *c3; |
||
684 | int fx = x < 0 ? 0 : max_x - 1; |
||
685 | int fy = y < 0 ? 0 : max_y - 1; |
||
686 | c1 = get_texel_2d_no_border( sp_sview, addr, fx, fy); |
||
687 | addr.bits.face = get_next_face(face, (x < 0) ? -1 : 1, 0); |
||
688 | c2 = get_texel_2d_no_border( sp_sview, addr, (x < 0) ? max_x - 1 : 0, fy); |
||
689 | addr.bits.face = get_next_face(face, 0, (y < 0) ? -1 : 1); |
||
690 | c3 = get_texel_2d_no_border( sp_sview, addr, fx, (y < 0) ? max_y - 1 : 0); |
||
691 | for (c = 0; c < TGSI_QUAD_SIZE; c++) |
||
692 | corner[c] = CLAMP((c1[c] + c2[c] + c3[c]), 0.0F, 1.0F) / 3; |
||
693 | |||
694 | return corner; |
||
695 | } |
||
696 | /* change the face */ |
||
697 | if (x < 0) { |
||
698 | new_x = max_x - 1; |
||
699 | face = get_next_face(face, -1, 0); |
||
700 | } else if (x >= max_x) { |
||
701 | new_x = 0; |
||
702 | face = get_next_face(face, 1, 0); |
||
703 | } else if (y < 0) { |
||
704 | new_y = max_y - 1; |
||
705 | face = get_next_face(face, 0, -1); |
||
706 | } else if (y >= max_y) { |
||
707 | new_y = 0; |
||
708 | face = get_next_face(face, 0, 1); |
||
709 | } |
||
710 | |||
711 | addr.bits.face = face; |
||
712 | return get_texel_2d_no_border( sp_sview, addr, new_x, new_y ); |
||
713 | } |
||
714 | |||
715 | /* Gather a quad of adjacent texels within a tile: |
||
716 | */ |
||
717 | static INLINE void |
||
718 | get_texel_quad_2d_no_border_single_tile(const struct sp_sampler_view *sp_sview, |
||
719 | union tex_tile_address addr, |
||
720 | unsigned x, unsigned y, |
||
721 | const float *out[4]) |
||
722 | { |
||
723 | const struct softpipe_tex_cached_tile *tile; |
||
724 | |||
725 | addr.bits.x = x / TEX_TILE_SIZE; |
||
726 | addr.bits.y = y / TEX_TILE_SIZE; |
||
727 | y %= TEX_TILE_SIZE; |
||
728 | x %= TEX_TILE_SIZE; |
||
729 | |||
730 | tile = sp_get_cached_tile_tex(sp_sview->cache, addr); |
||
731 | |||
732 | out[0] = &tile->data.color[y ][x ][0]; |
||
733 | out[1] = &tile->data.color[y ][x+1][0]; |
||
734 | out[2] = &tile->data.color[y+1][x ][0]; |
||
735 | out[3] = &tile->data.color[y+1][x+1][0]; |
||
736 | } |
||
737 | |||
738 | |||
739 | /* Gather a quad of potentially non-adjacent texels: |
||
740 | */ |
||
741 | static INLINE void |
||
742 | get_texel_quad_2d_no_border(const struct sp_sampler_view *sp_sview, |
||
743 | union tex_tile_address addr, |
||
744 | int x0, int y0, |
||
745 | int x1, int y1, |
||
746 | const float *out[4]) |
||
747 | { |
||
748 | out[0] = get_texel_2d_no_border( sp_sview, addr, x0, y0 ); |
||
749 | out[1] = get_texel_2d_no_border( sp_sview, addr, x1, y0 ); |
||
750 | out[2] = get_texel_2d_no_border( sp_sview, addr, x0, y1 ); |
||
751 | out[3] = get_texel_2d_no_border( sp_sview, addr, x1, y1 ); |
||
752 | } |
||
753 | |||
754 | /* Can involve a lot of unnecessary checks for border color: |
||
755 | */ |
||
756 | static INLINE void |
||
757 | get_texel_quad_2d(const struct sp_sampler_view *sp_sview, |
||
758 | const struct sp_sampler *sp_samp, |
||
759 | union tex_tile_address addr, |
||
760 | int x0, int y0, |
||
761 | int x1, int y1, |
||
762 | const float *out[4]) |
||
763 | { |
||
764 | out[0] = get_texel_2d( sp_sview, sp_samp, addr, x0, y0 ); |
||
765 | out[1] = get_texel_2d( sp_sview, sp_samp, addr, x1, y0 ); |
||
766 | out[3] = get_texel_2d( sp_sview, sp_samp, addr, x1, y1 ); |
||
767 | out[2] = get_texel_2d( sp_sview, sp_samp, addr, x0, y1 ); |
||
768 | } |
||
769 | |||
770 | |||
771 | |||
772 | /* 3d variants: |
||
773 | */ |
||
774 | static INLINE const float * |
||
775 | get_texel_3d_no_border(const struct sp_sampler_view *sp_sview, |
||
776 | union tex_tile_address addr, int x, int y, int z) |
||
777 | { |
||
778 | const struct softpipe_tex_cached_tile *tile; |
||
779 | |||
780 | addr.bits.x = x / TEX_TILE_SIZE; |
||
781 | addr.bits.y = y / TEX_TILE_SIZE; |
||
782 | addr.bits.z = z; |
||
783 | y %= TEX_TILE_SIZE; |
||
784 | x %= TEX_TILE_SIZE; |
||
785 | |||
786 | tile = sp_get_cached_tile_tex(sp_sview->cache, addr); |
||
787 | |||
788 | return &tile->data.color[y][x][0]; |
||
789 | } |
||
790 | |||
791 | |||
792 | static INLINE const float * |
||
793 | get_texel_3d(const struct sp_sampler_view *sp_sview, |
||
794 | const struct sp_sampler *sp_samp, |
||
795 | union tex_tile_address addr, int x, int y, int z) |
||
796 | { |
||
797 | const struct pipe_resource *texture = sp_sview->base.texture; |
||
798 | unsigned level = addr.bits.level; |
||
799 | |||
800 | if (x < 0 || x >= (int) u_minify(texture->width0, level) || |
||
801 | y < 0 || y >= (int) u_minify(texture->height0, level) || |
||
802 | z < 0 || z >= (int) u_minify(texture->depth0, level)) { |
||
803 | return sp_samp->base.border_color.f; |
||
804 | } |
||
805 | else { |
||
806 | return get_texel_3d_no_border( sp_sview, addr, x, y, z ); |
||
807 | } |
||
808 | } |
||
809 | |||
810 | |||
811 | /* Get texel pointer for 1D array texture */ |
||
812 | static INLINE const float * |
||
813 | get_texel_1d_array(const struct sp_sampler_view *sp_sview, |
||
814 | const struct sp_sampler *sp_samp, |
||
815 | union tex_tile_address addr, int x, int y) |
||
816 | { |
||
817 | const struct pipe_resource *texture = sp_sview->base.texture; |
||
818 | unsigned level = addr.bits.level; |
||
819 | |||
820 | if (x < 0 || x >= (int) u_minify(texture->width0, level)) { |
||
821 | return sp_samp->base.border_color.f; |
||
822 | } |
||
823 | else { |
||
824 | return get_texel_2d_no_border(sp_sview, addr, x, y); |
||
825 | } |
||
826 | } |
||
827 | |||
828 | |||
829 | /* Get texel pointer for 2D array texture */ |
||
830 | static INLINE const float * |
||
831 | get_texel_2d_array(const struct sp_sampler_view *sp_sview, |
||
832 | const struct sp_sampler *sp_samp, |
||
833 | union tex_tile_address addr, int x, int y, int layer) |
||
834 | { |
||
835 | const struct pipe_resource *texture = sp_sview->base.texture; |
||
836 | unsigned level = addr.bits.level; |
||
837 | |||
838 | assert(layer < (int) texture->array_size); |
||
839 | assert(layer >= 0); |
||
840 | |||
841 | if (x < 0 || x >= (int) u_minify(texture->width0, level) || |
||
842 | y < 0 || y >= (int) u_minify(texture->height0, level)) { |
||
843 | return sp_samp->base.border_color.f; |
||
844 | } |
||
845 | else { |
||
846 | return get_texel_3d_no_border(sp_sview, addr, x, y, layer); |
||
847 | } |
||
848 | } |
||
849 | |||
850 | |||
851 | /* Get texel pointer for cube array texture */ |
||
852 | static INLINE const float * |
||
853 | get_texel_cube_array(const struct sp_sampler_view *sp_sview, |
||
854 | const struct sp_sampler *sp_samp, |
||
855 | union tex_tile_address addr, int x, int y, int layer) |
||
856 | { |
||
857 | const struct pipe_resource *texture = sp_sview->base.texture; |
||
858 | unsigned level = addr.bits.level; |
||
859 | |||
860 | assert(layer < (int) texture->array_size); |
||
861 | assert(layer >= 0); |
||
862 | |||
863 | if (x < 0 || x >= (int) u_minify(texture->width0, level) || |
||
864 | y < 0 || y >= (int) u_minify(texture->height0, level)) { |
||
865 | return sp_samp->base.border_color.f; |
||
866 | } |
||
867 | else { |
||
868 | return get_texel_3d_no_border(sp_sview, addr, x, y, layer); |
||
869 | } |
||
870 | } |
||
871 | /** |
||
872 | * Given the logbase2 of a mipmap's base level size and a mipmap level, |
||
873 | * return the size (in texels) of that mipmap level. |
||
874 | * For example, if level[0].width = 256 then base_pot will be 8. |
||
875 | * If level = 2, then we'll return 64 (the width at level=2). |
||
876 | * Return 1 if level > base_pot. |
||
877 | */ |
||
878 | static INLINE unsigned |
||
879 | pot_level_size(unsigned base_pot, unsigned level) |
||
880 | { |
||
881 | return (base_pot >= level) ? (1 << (base_pot - level)) : 1; |
||
882 | } |
||
883 | |||
884 | |||
885 | static void |
||
886 | print_sample(const char *function, const float *rgba) |
||
887 | { |
||
888 | debug_printf("%s %g %g %g %g\n", |
||
889 | function, |
||
890 | rgba[0], rgba[TGSI_NUM_CHANNELS], rgba[2*TGSI_NUM_CHANNELS], rgba[3*TGSI_NUM_CHANNELS]); |
||
891 | } |
||
892 | |||
893 | |||
894 | static void |
||
895 | print_sample_4(const char *function, float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) |
||
896 | { |
||
897 | debug_printf("%s %g %g %g %g, %g %g %g %g, %g %g %g %g, %g %g %g %g\n", |
||
898 | function, |
||
899 | rgba[0][0], rgba[1][0], rgba[2][0], rgba[3][0], |
||
900 | rgba[0][1], rgba[1][1], rgba[2][1], rgba[3][1], |
||
901 | rgba[0][2], rgba[1][2], rgba[2][2], rgba[3][2], |
||
902 | rgba[0][3], rgba[1][3], rgba[2][3], rgba[3][3]); |
||
903 | } |
||
904 | |||
905 | |||
906 | /* Some image-filter fastpaths: |
||
907 | */ |
||
908 | static INLINE void |
||
909 | img_filter_2d_linear_repeat_POT(struct sp_sampler_view *sp_sview, |
||
910 | struct sp_sampler *sp_samp, |
||
911 | float s, |
||
912 | float t, |
||
913 | float p, |
||
914 | unsigned level, |
||
915 | unsigned face_id, |
||
916 | float *rgba) |
||
917 | { |
||
918 | unsigned xpot = pot_level_size(sp_sview->xpot, level); |
||
919 | unsigned ypot = pot_level_size(sp_sview->ypot, level); |
||
920 | unsigned xmax = (xpot - 1) & (TEX_TILE_SIZE - 1); /* MIN2(TEX_TILE_SIZE, xpot) - 1; */ |
||
921 | unsigned ymax = (ypot - 1) & (TEX_TILE_SIZE - 1); /* MIN2(TEX_TILE_SIZE, ypot) - 1; */ |
||
922 | union tex_tile_address addr; |
||
923 | int c; |
||
924 | |||
925 | float u = s * xpot - 0.5F; |
||
926 | float v = t * ypot - 0.5F; |
||
927 | |||
928 | int uflr = util_ifloor(u); |
||
929 | int vflr = util_ifloor(v); |
||
930 | |||
931 | float xw = u - (float)uflr; |
||
932 | float yw = v - (float)vflr; |
||
933 | |||
934 | int x0 = uflr & (xpot - 1); |
||
935 | int y0 = vflr & (ypot - 1); |
||
936 | |||
937 | const float *tx[4]; |
||
938 | |||
939 | addr.value = 0; |
||
940 | addr.bits.level = level; |
||
941 | |||
942 | /* Can we fetch all four at once: |
||
943 | */ |
||
944 | if (x0 < xmax && y0 < ymax) { |
||
945 | get_texel_quad_2d_no_border_single_tile(sp_sview, addr, x0, y0, tx); |
||
946 | } |
||
947 | else { |
||
948 | unsigned x1 = (x0 + 1) & (xpot - 1); |
||
949 | unsigned y1 = (y0 + 1) & (ypot - 1); |
||
950 | get_texel_quad_2d_no_border(sp_sview, addr, x0, y0, x1, y1, tx); |
||
951 | } |
||
952 | |||
953 | /* interpolate R, G, B, A */ |
||
954 | for (c = 0; c < TGSI_QUAD_SIZE; c++) { |
||
955 | rgba[TGSI_NUM_CHANNELS*c] = lerp_2d(xw, yw, |
||
956 | tx[0][c], tx[1][c], |
||
957 | tx[2][c], tx[3][c]); |
||
958 | } |
||
959 | |||
960 | if (DEBUG_TEX) { |
||
961 | print_sample(__FUNCTION__, rgba); |
||
962 | } |
||
963 | } |
||
964 | |||
965 | |||
966 | static INLINE void |
||
967 | img_filter_2d_nearest_repeat_POT(struct sp_sampler_view *sp_sview, |
||
968 | struct sp_sampler *sp_samp, |
||
969 | float s, |
||
970 | float t, |
||
971 | float p, |
||
972 | unsigned level, |
||
973 | unsigned face_id, |
||
974 | float rgba[TGSI_QUAD_SIZE]) |
||
975 | { |
||
976 | unsigned xpot = pot_level_size(sp_sview->xpot, level); |
||
977 | unsigned ypot = pot_level_size(sp_sview->ypot, level); |
||
978 | const float *out; |
||
979 | union tex_tile_address addr; |
||
980 | int c; |
||
981 | |||
982 | float u = s * xpot; |
||
983 | float v = t * ypot; |
||
984 | |||
985 | int uflr = util_ifloor(u); |
||
986 | int vflr = util_ifloor(v); |
||
987 | |||
988 | int x0 = uflr & (xpot - 1); |
||
989 | int y0 = vflr & (ypot - 1); |
||
990 | |||
991 | addr.value = 0; |
||
992 | addr.bits.level = level; |
||
993 | |||
994 | out = get_texel_2d_no_border(sp_sview, addr, x0, y0); |
||
995 | for (c = 0; c < TGSI_QUAD_SIZE; c++) |
||
996 | rgba[TGSI_NUM_CHANNELS*c] = out[c]; |
||
997 | |||
998 | if (DEBUG_TEX) { |
||
999 | print_sample(__FUNCTION__, rgba); |
||
1000 | } |
||
1001 | } |
||
1002 | |||
1003 | |||
1004 | static INLINE void |
||
1005 | img_filter_2d_nearest_clamp_POT(struct sp_sampler_view *sp_sview, |
||
1006 | struct sp_sampler *sp_samp, |
||
1007 | float s, |
||
1008 | float t, |
||
1009 | float p, |
||
1010 | unsigned level, |
||
1011 | unsigned face_id, |
||
1012 | float rgba[TGSI_QUAD_SIZE]) |
||
1013 | { |
||
1014 | unsigned xpot = pot_level_size(sp_sview->xpot, level); |
||
1015 | unsigned ypot = pot_level_size(sp_sview->ypot, level); |
||
1016 | union tex_tile_address addr; |
||
1017 | int c; |
||
1018 | |||
1019 | float u = s * xpot; |
||
1020 | float v = t * ypot; |
||
1021 | |||
1022 | int x0, y0; |
||
1023 | const float *out; |
||
1024 | |||
1025 | addr.value = 0; |
||
1026 | addr.bits.level = level; |
||
1027 | |||
1028 | x0 = util_ifloor(u); |
||
1029 | if (x0 < 0) |
||
1030 | x0 = 0; |
||
1031 | else if (x0 > xpot - 1) |
||
1032 | x0 = xpot - 1; |
||
1033 | |||
1034 | y0 = util_ifloor(v); |
||
1035 | if (y0 < 0) |
||
1036 | y0 = 0; |
||
1037 | else if (y0 > ypot - 1) |
||
1038 | y0 = ypot - 1; |
||
1039 | |||
1040 | out = get_texel_2d_no_border(sp_sview, addr, x0, y0); |
||
1041 | for (c = 0; c < TGSI_QUAD_SIZE; c++) |
||
1042 | rgba[TGSI_NUM_CHANNELS*c] = out[c]; |
||
1043 | |||
1044 | if (DEBUG_TEX) { |
||
1045 | print_sample(__FUNCTION__, rgba); |
||
1046 | } |
||
1047 | } |
||
1048 | |||
1049 | |||
1050 | static void |
||
1051 | img_filter_1d_nearest(struct sp_sampler_view *sp_sview, |
||
1052 | struct sp_sampler *sp_samp, |
||
1053 | float s, |
||
1054 | float t, |
||
1055 | float p, |
||
1056 | unsigned level, |
||
1057 | unsigned face_id, |
||
1058 | float rgba[TGSI_QUAD_SIZE]) |
||
1059 | { |
||
1060 | const struct pipe_resource *texture = sp_sview->base.texture; |
||
1061 | int width; |
||
1062 | int x; |
||
1063 | union tex_tile_address addr; |
||
1064 | const float *out; |
||
1065 | int c; |
||
1066 | |||
1067 | width = u_minify(texture->width0, level); |
||
1068 | |||
1069 | assert(width > 0); |
||
1070 | |||
1071 | addr.value = 0; |
||
1072 | addr.bits.level = level; |
||
1073 | |||
1074 | sp_samp->nearest_texcoord_s(s, width, &x); |
||
1075 | |||
1076 | out = get_texel_2d(sp_sview, sp_samp, addr, x, 0); |
||
1077 | for (c = 0; c < TGSI_QUAD_SIZE; c++) |
||
1078 | rgba[TGSI_NUM_CHANNELS*c] = out[c]; |
||
1079 | |||
1080 | if (DEBUG_TEX) { |
||
1081 | print_sample(__FUNCTION__, rgba); |
||
1082 | } |
||
1083 | } |
||
1084 | |||
1085 | |||
1086 | static void |
||
1087 | img_filter_1d_array_nearest(struct sp_sampler_view *sp_sview, |
||
1088 | struct sp_sampler *sp_samp, |
||
1089 | float s, |
||
1090 | float t, |
||
1091 | float p, |
||
1092 | unsigned level, |
||
1093 | unsigned face_id, |
||
1094 | float *rgba) |
||
1095 | { |
||
1096 | const struct pipe_resource *texture = sp_sview->base.texture; |
||
1097 | int width; |
||
1098 | int x, layer; |
||
1099 | union tex_tile_address addr; |
||
1100 | const float *out; |
||
1101 | int c; |
||
1102 | |||
1103 | width = u_minify(texture->width0, level); |
||
1104 | |||
1105 | assert(width > 0); |
||
1106 | |||
1107 | addr.value = 0; |
||
1108 | addr.bits.level = level; |
||
1109 | |||
1110 | sp_samp->nearest_texcoord_s(s, width, &x); |
||
1111 | wrap_array_layer(t, texture->array_size, &layer); |
||
1112 | |||
1113 | out = get_texel_1d_array(sp_sview, sp_samp, addr, x, layer); |
||
1114 | for (c = 0; c < TGSI_QUAD_SIZE; c++) |
||
1115 | rgba[TGSI_NUM_CHANNELS*c] = out[c]; |
||
1116 | |||
1117 | if (DEBUG_TEX) { |
||
1118 | print_sample(__FUNCTION__, rgba); |
||
1119 | } |
||
1120 | } |
||
1121 | |||
1122 | |||
1123 | static void |
||
1124 | img_filter_2d_nearest(struct sp_sampler_view *sp_sview, |
||
1125 | struct sp_sampler *sp_samp, |
||
1126 | float s, |
||
1127 | float t, |
||
1128 | float p, |
||
1129 | unsigned level, |
||
1130 | unsigned face_id, |
||
1131 | float *rgba) |
||
1132 | { |
||
1133 | const struct pipe_resource *texture = sp_sview->base.texture; |
||
1134 | int width, height; |
||
1135 | int x, y; |
||
1136 | union tex_tile_address addr; |
||
1137 | const float *out; |
||
1138 | int c; |
||
1139 | |||
1140 | width = u_minify(texture->width0, level); |
||
1141 | height = u_minify(texture->height0, level); |
||
1142 | |||
1143 | assert(width > 0); |
||
1144 | assert(height > 0); |
||
1145 | |||
1146 | addr.value = 0; |
||
1147 | addr.bits.level = level; |
||
1148 | |||
1149 | sp_samp->nearest_texcoord_s(s, width, &x); |
||
1150 | sp_samp->nearest_texcoord_t(t, height, &y); |
||
1151 | |||
1152 | out = get_texel_2d(sp_sview, sp_samp, addr, x, y); |
||
1153 | for (c = 0; c < TGSI_QUAD_SIZE; c++) |
||
1154 | rgba[TGSI_NUM_CHANNELS*c] = out[c]; |
||
1155 | |||
1156 | if (DEBUG_TEX) { |
||
1157 | print_sample(__FUNCTION__, rgba); |
||
1158 | } |
||
1159 | } |
||
1160 | |||
1161 | |||
1162 | static void |
||
1163 | img_filter_2d_array_nearest(struct sp_sampler_view *sp_sview, |
||
1164 | struct sp_sampler *sp_samp, |
||
1165 | float s, |
||
1166 | float t, |
||
1167 | float p, |
||
1168 | unsigned level, |
||
1169 | unsigned face_id, |
||
1170 | float *rgba) |
||
1171 | { |
||
1172 | const struct pipe_resource *texture = sp_sview->base.texture; |
||
1173 | int width, height; |
||
1174 | int x, y, layer; |
||
1175 | union tex_tile_address addr; |
||
1176 | const float *out; |
||
1177 | int c; |
||
1178 | |||
1179 | width = u_minify(texture->width0, level); |
||
1180 | height = u_minify(texture->height0, level); |
||
1181 | |||
1182 | assert(width > 0); |
||
1183 | assert(height > 0); |
||
1184 | |||
1185 | addr.value = 0; |
||
1186 | addr.bits.level = level; |
||
1187 | |||
1188 | sp_samp->nearest_texcoord_s(s, width, &x); |
||
1189 | sp_samp->nearest_texcoord_t(t, height, &y); |
||
1190 | wrap_array_layer(p, texture->array_size, &layer); |
||
1191 | |||
1192 | out = get_texel_2d_array(sp_sview, sp_samp, addr, x, y, layer); |
||
1193 | for (c = 0; c < TGSI_QUAD_SIZE; c++) |
||
1194 | rgba[TGSI_NUM_CHANNELS*c] = out[c]; |
||
1195 | |||
1196 | if (DEBUG_TEX) { |
||
1197 | print_sample(__FUNCTION__, rgba); |
||
1198 | } |
||
1199 | } |
||
1200 | |||
1201 | |||
1202 | static INLINE union tex_tile_address |
||
1203 | face(union tex_tile_address addr, unsigned face ) |
||
1204 | { |
||
1205 | addr.bits.face = face; |
||
1206 | return addr; |
||
1207 | } |
||
1208 | |||
1209 | |||
1210 | static void |
||
1211 | img_filter_cube_nearest(struct sp_sampler_view *sp_sview, |
||
1212 | struct sp_sampler *sp_samp, |
||
1213 | float s, |
||
1214 | float t, |
||
1215 | float p, |
||
1216 | unsigned level, |
||
1217 | unsigned face_id, |
||
1218 | float *rgba) |
||
1219 | { |
||
1220 | const struct pipe_resource *texture = sp_sview->base.texture; |
||
1221 | int width, height; |
||
1222 | int x, y; |
||
1223 | union tex_tile_address addr; |
||
1224 | const float *out; |
||
1225 | int c; |
||
1226 | |||
1227 | width = u_minify(texture->width0, level); |
||
1228 | height = u_minify(texture->height0, level); |
||
1229 | |||
1230 | assert(width > 0); |
||
1231 | assert(height > 0); |
||
1232 | |||
1233 | addr.value = 0; |
||
1234 | addr.bits.level = level; |
||
1235 | |||
1236 | /* |
||
1237 | * If NEAREST filtering is done within a miplevel, always apply wrap |
||
1238 | * mode CLAMP_TO_EDGE. |
||
1239 | */ |
||
1240 | if (sp_samp->base.seamless_cube_map) { |
||
1241 | wrap_nearest_clamp_to_edge(s, width, &x); |
||
1242 | wrap_nearest_clamp_to_edge(t, height, &y); |
||
1243 | } else { |
||
1244 | sp_samp->nearest_texcoord_s(s, width, &x); |
||
1245 | sp_samp->nearest_texcoord_t(t, height, &y); |
||
1246 | } |
||
1247 | |||
1248 | out = get_texel_2d(sp_sview, sp_samp, face(addr, face_id), x, y); |
||
1249 | for (c = 0; c < TGSI_QUAD_SIZE; c++) |
||
1250 | rgba[TGSI_NUM_CHANNELS*c] = out[c]; |
||
1251 | |||
1252 | if (DEBUG_TEX) { |
||
1253 | print_sample(__FUNCTION__, rgba); |
||
1254 | } |
||
1255 | } |
||
1256 | |||
1257 | static void |
||
1258 | img_filter_cube_array_nearest(struct sp_sampler_view *sp_sview, |
||
1259 | struct sp_sampler *sp_samp, |
||
1260 | float s, |
||
1261 | float t, |
||
1262 | float p, |
||
1263 | unsigned level, |
||
1264 | unsigned face_id, |
||
1265 | float *rgba) |
||
1266 | { |
||
1267 | const struct pipe_resource *texture = sp_sview->base.texture; |
||
1268 | int width, height; |
||
1269 | int x, y, layer; |
||
1270 | union tex_tile_address addr; |
||
1271 | const float *out; |
||
1272 | int c; |
||
1273 | |||
1274 | width = u_minify(texture->width0, level); |
||
1275 | height = u_minify(texture->height0, level); |
||
1276 | |||
1277 | assert(width > 0); |
||
1278 | assert(height > 0); |
||
1279 | |||
1280 | addr.value = 0; |
||
1281 | addr.bits.level = level; |
||
1282 | |||
1283 | sp_samp->nearest_texcoord_s(s, width, &x); |
||
1284 | sp_samp->nearest_texcoord_t(t, height, &y); |
||
1285 | wrap_array_layer(p, texture->array_size, &layer); |
||
1286 | |||
1287 | out = get_texel_cube_array(sp_sview, sp_samp, addr, x, y, layer * 6 + face_id); |
||
1288 | for (c = 0; c < TGSI_QUAD_SIZE; c++) |
||
1289 | rgba[TGSI_NUM_CHANNELS*c] = out[c]; |
||
1290 | |||
1291 | if (DEBUG_TEX) { |
||
1292 | print_sample(__FUNCTION__, rgba); |
||
1293 | } |
||
1294 | } |
||
1295 | |||
1296 | static void |
||
1297 | img_filter_3d_nearest(struct sp_sampler_view *sp_sview, |
||
1298 | struct sp_sampler *sp_samp, |
||
1299 | float s, |
||
1300 | float t, |
||
1301 | float p, |
||
1302 | unsigned level, |
||
1303 | unsigned face_id, |
||
1304 | float *rgba) |
||
1305 | { |
||
1306 | const struct pipe_resource *texture = sp_sview->base.texture; |
||
1307 | int width, height, depth; |
||
1308 | int x, y, z; |
||
1309 | union tex_tile_address addr; |
||
1310 | const float *out; |
||
1311 | int c; |
||
1312 | |||
1313 | width = u_minify(texture->width0, level); |
||
1314 | height = u_minify(texture->height0, level); |
||
1315 | depth = u_minify(texture->depth0, level); |
||
1316 | |||
1317 | assert(width > 0); |
||
1318 | assert(height > 0); |
||
1319 | assert(depth > 0); |
||
1320 | |||
1321 | sp_samp->nearest_texcoord_s(s, width, &x); |
||
1322 | sp_samp->nearest_texcoord_t(t, height, &y); |
||
1323 | sp_samp->nearest_texcoord_p(p, depth, &z); |
||
1324 | |||
1325 | addr.value = 0; |
||
1326 | addr.bits.level = level; |
||
1327 | |||
1328 | out = get_texel_3d(sp_sview, sp_samp, addr, x, y, z); |
||
1329 | for (c = 0; c < TGSI_QUAD_SIZE; c++) |
||
1330 | rgba[TGSI_NUM_CHANNELS*c] = out[c]; |
||
1331 | } |
||
1332 | |||
1333 | |||
1334 | static void |
||
1335 | img_filter_1d_linear(struct sp_sampler_view *sp_sview, |
||
1336 | struct sp_sampler *sp_samp, |
||
1337 | float s, |
||
1338 | float t, |
||
1339 | float p, |
||
1340 | unsigned level, |
||
1341 | unsigned face_id, |
||
1342 | float *rgba) |
||
1343 | { |
||
1344 | const struct pipe_resource *texture = sp_sview->base.texture; |
||
1345 | int width; |
||
1346 | int x0, x1; |
||
1347 | float xw; /* weights */ |
||
1348 | union tex_tile_address addr; |
||
1349 | const float *tx0, *tx1; |
||
1350 | int c; |
||
1351 | |||
1352 | width = u_minify(texture->width0, level); |
||
1353 | |||
1354 | assert(width > 0); |
||
1355 | |||
1356 | addr.value = 0; |
||
1357 | addr.bits.level = level; |
||
1358 | |||
1359 | sp_samp->linear_texcoord_s(s, width, &x0, &x1, &xw); |
||
1360 | |||
1361 | tx0 = get_texel_2d(sp_sview, sp_samp, addr, x0, 0); |
||
1362 | tx1 = get_texel_2d(sp_sview, sp_samp, addr, x1, 0); |
||
1363 | |||
1364 | /* interpolate R, G, B, A */ |
||
1365 | for (c = 0; c < TGSI_QUAD_SIZE; c++) |
||
1366 | rgba[TGSI_NUM_CHANNELS*c] = lerp(xw, tx0[c], tx1[c]); |
||
1367 | } |
||
1368 | |||
1369 | |||
1370 | static void |
||
1371 | img_filter_1d_array_linear(struct sp_sampler_view *sp_sview, |
||
1372 | struct sp_sampler *sp_samp, |
||
1373 | float s, |
||
1374 | float t, |
||
1375 | float p, |
||
1376 | unsigned level, |
||
1377 | unsigned face_id, |
||
1378 | float *rgba) |
||
1379 | { |
||
1380 | const struct pipe_resource *texture = sp_sview->base.texture; |
||
1381 | int width; |
||
1382 | int x0, x1, layer; |
||
1383 | float xw; /* weights */ |
||
1384 | union tex_tile_address addr; |
||
1385 | const float *tx0, *tx1; |
||
1386 | int c; |
||
1387 | |||
1388 | width = u_minify(texture->width0, level); |
||
1389 | |||
1390 | assert(width > 0); |
||
1391 | |||
1392 | addr.value = 0; |
||
1393 | addr.bits.level = level; |
||
1394 | |||
1395 | sp_samp->linear_texcoord_s(s, width, &x0, &x1, &xw); |
||
1396 | wrap_array_layer(t, texture->array_size, &layer); |
||
1397 | |||
1398 | tx0 = get_texel_1d_array(sp_sview, sp_samp, addr, x0, layer); |
||
1399 | tx1 = get_texel_1d_array(sp_sview, sp_samp, addr, x1, layer); |
||
1400 | |||
1401 | /* interpolate R, G, B, A */ |
||
1402 | for (c = 0; c < TGSI_QUAD_SIZE; c++) |
||
1403 | rgba[TGSI_NUM_CHANNELS*c] = lerp(xw, tx0[c], tx1[c]); |
||
1404 | } |
||
1405 | |||
1406 | |||
1407 | static void |
||
1408 | img_filter_2d_linear(struct sp_sampler_view *sp_sview, |
||
1409 | struct sp_sampler *sp_samp, |
||
1410 | float s, |
||
1411 | float t, |
||
1412 | float p, |
||
1413 | unsigned level, |
||
1414 | unsigned face_id, |
||
1415 | float *rgba) |
||
1416 | { |
||
1417 | const struct pipe_resource *texture = sp_sview->base.texture; |
||
1418 | int width, height; |
||
1419 | int x0, y0, x1, y1; |
||
1420 | float xw, yw; /* weights */ |
||
1421 | union tex_tile_address addr; |
||
1422 | const float *tx0, *tx1, *tx2, *tx3; |
||
1423 | int c; |
||
1424 | |||
1425 | width = u_minify(texture->width0, level); |
||
1426 | height = u_minify(texture->height0, level); |
||
1427 | |||
1428 | assert(width > 0); |
||
1429 | assert(height > 0); |
||
1430 | |||
1431 | addr.value = 0; |
||
1432 | addr.bits.level = level; |
||
1433 | |||
1434 | sp_samp->linear_texcoord_s(s, width, &x0, &x1, &xw); |
||
1435 | sp_samp->linear_texcoord_t(t, height, &y0, &y1, &yw); |
||
1436 | |||
1437 | tx0 = get_texel_2d(sp_sview, sp_samp, addr, x0, y0); |
||
1438 | tx1 = get_texel_2d(sp_sview, sp_samp, addr, x1, y0); |
||
1439 | tx2 = get_texel_2d(sp_sview, sp_samp, addr, x0, y1); |
||
1440 | tx3 = get_texel_2d(sp_sview, sp_samp, addr, x1, y1); |
||
1441 | |||
1442 | /* interpolate R, G, B, A */ |
||
1443 | for (c = 0; c < TGSI_QUAD_SIZE; c++) |
||
1444 | rgba[TGSI_NUM_CHANNELS*c] = lerp_2d(xw, yw, |
||
1445 | tx0[c], tx1[c], |
||
1446 | tx2[c], tx3[c]); |
||
1447 | } |
||
1448 | |||
1449 | |||
1450 | static void |
||
1451 | img_filter_2d_array_linear(struct sp_sampler_view *sp_sview, |
||
1452 | struct sp_sampler *sp_samp, |
||
1453 | float s, |
||
1454 | float t, |
||
1455 | float p, |
||
1456 | unsigned level, |
||
1457 | unsigned face_id, |
||
1458 | float *rgba) |
||
1459 | { |
||
1460 | const struct pipe_resource *texture = sp_sview->base.texture; |
||
1461 | int width, height; |
||
1462 | int x0, y0, x1, y1, layer; |
||
1463 | float xw, yw; /* weights */ |
||
1464 | union tex_tile_address addr; |
||
1465 | const float *tx0, *tx1, *tx2, *tx3; |
||
1466 | int c; |
||
1467 | |||
1468 | width = u_minify(texture->width0, level); |
||
1469 | height = u_minify(texture->height0, level); |
||
1470 | |||
1471 | assert(width > 0); |
||
1472 | assert(height > 0); |
||
1473 | |||
1474 | addr.value = 0; |
||
1475 | addr.bits.level = level; |
||
1476 | |||
1477 | sp_samp->linear_texcoord_s(s, width, &x0, &x1, &xw); |
||
1478 | sp_samp->linear_texcoord_t(t, height, &y0, &y1, &yw); |
||
1479 | wrap_array_layer(p, texture->array_size, &layer); |
||
1480 | |||
1481 | tx0 = get_texel_2d_array(sp_sview, sp_samp, addr, x0, y0, layer); |
||
1482 | tx1 = get_texel_2d_array(sp_sview, sp_samp, addr, x1, y0, layer); |
||
1483 | tx2 = get_texel_2d_array(sp_sview, sp_samp, addr, x0, y1, layer); |
||
1484 | tx3 = get_texel_2d_array(sp_sview, sp_samp, addr, x1, y1, layer); |
||
1485 | |||
1486 | /* interpolate R, G, B, A */ |
||
1487 | for (c = 0; c < TGSI_QUAD_SIZE; c++) |
||
1488 | rgba[TGSI_NUM_CHANNELS*c] = lerp_2d(xw, yw, |
||
1489 | tx0[c], tx1[c], |
||
1490 | tx2[c], tx3[c]); |
||
1491 | } |
||
1492 | |||
1493 | |||
1494 | static void |
||
1495 | img_filter_cube_linear(struct sp_sampler_view *sp_sview, |
||
1496 | struct sp_sampler *sp_samp, |
||
1497 | float s, |
||
1498 | float t, |
||
1499 | float p, |
||
1500 | unsigned level, |
||
1501 | unsigned face_id, |
||
1502 | float *rgba) |
||
1503 | { |
||
1504 | const struct pipe_resource *texture = sp_sview->base.texture; |
||
1505 | int width, height; |
||
1506 | int x0, y0, x1, y1; |
||
1507 | float xw, yw; /* weights */ |
||
1508 | union tex_tile_address addr, addrj; |
||
1509 | const float *tx0, *tx1, *tx2, *tx3; |
||
1510 | float corner0[TGSI_QUAD_SIZE], corner1[TGSI_QUAD_SIZE], |
||
1511 | corner2[TGSI_QUAD_SIZE], corner3[TGSI_QUAD_SIZE]; |
||
1512 | int c; |
||
1513 | |||
1514 | width = u_minify(texture->width0, level); |
||
1515 | height = u_minify(texture->height0, level); |
||
1516 | |||
1517 | assert(width > 0); |
||
1518 | assert(height > 0); |
||
1519 | |||
1520 | addr.value = 0; |
||
1521 | addr.bits.level = level; |
||
1522 | |||
1523 | /* |
||
1524 | * For seamless if LINEAR filtering is done within a miplevel, |
||
1525 | * always apply wrap mode CLAMP_TO_BORDER. |
||
1526 | */ |
||
1527 | if (sp_samp->base.seamless_cube_map) { |
||
1528 | wrap_linear_clamp_to_border(s, width, &x0, &x1, &xw); |
||
1529 | wrap_linear_clamp_to_border(t, height, &y0, &y1, &yw); |
||
1530 | } else { |
||
1531 | sp_samp->linear_texcoord_s(s, width, &x0, &x1, &xw); |
||
1532 | sp_samp->linear_texcoord_t(t, height, &y0, &y1, &yw); |
||
1533 | } |
||
1534 | |||
1535 | addrj = face(addr, face_id); |
||
1536 | |||
1537 | if (sp_samp->base.seamless_cube_map) { |
||
1538 | tx0 = get_texel_cube_seamless(sp_sview, addrj, x0, y0, corner0); |
||
1539 | tx1 = get_texel_cube_seamless(sp_sview, addrj, x1, y0, corner1); |
||
1540 | tx2 = get_texel_cube_seamless(sp_sview, addrj, x0, y1, corner2); |
||
1541 | tx3 = get_texel_cube_seamless(sp_sview, addrj, x1, y1, corner3); |
||
1542 | } else { |
||
1543 | tx0 = get_texel_2d(sp_sview, sp_samp, addrj, x0, y0); |
||
1544 | tx1 = get_texel_2d(sp_sview, sp_samp, addrj, x1, y0); |
||
1545 | tx2 = get_texel_2d(sp_sview, sp_samp, addrj, x0, y1); |
||
1546 | tx3 = get_texel_2d(sp_sview, sp_samp, addrj, x1, y1); |
||
1547 | } |
||
1548 | /* interpolate R, G, B, A */ |
||
1549 | for (c = 0; c < TGSI_QUAD_SIZE; c++) |
||
1550 | rgba[TGSI_NUM_CHANNELS*c] = lerp_2d(xw, yw, |
||
1551 | tx0[c], tx1[c], |
||
1552 | tx2[c], tx3[c]); |
||
1553 | } |
||
1554 | |||
1555 | |||
1556 | static void |
||
1557 | img_filter_cube_array_linear(struct sp_sampler_view *sp_sview, |
||
1558 | struct sp_sampler *sp_samp, |
||
1559 | float s, |
||
1560 | float t, |
||
1561 | float p, |
||
1562 | unsigned level, |
||
1563 | unsigned face_id, |
||
1564 | float *rgba) |
||
1565 | { |
||
1566 | const struct pipe_resource *texture = sp_sview->base.texture; |
||
1567 | int width, height; |
||
1568 | int x0, y0, x1, y1, layer; |
||
1569 | float xw, yw; /* weights */ |
||
1570 | union tex_tile_address addr; |
||
1571 | const float *tx0, *tx1, *tx2, *tx3; |
||
1572 | int c; |
||
1573 | |||
1574 | width = u_minify(texture->width0, level); |
||
1575 | height = u_minify(texture->height0, level); |
||
1576 | |||
1577 | assert(width > 0); |
||
1578 | assert(height > 0); |
||
1579 | |||
1580 | addr.value = 0; |
||
1581 | addr.bits.level = level; |
||
1582 | |||
1583 | sp_samp->linear_texcoord_s(s, width, &x0, &x1, &xw); |
||
1584 | sp_samp->linear_texcoord_t(t, height, &y0, &y1, &yw); |
||
1585 | wrap_array_layer(p, texture->array_size, &layer); |
||
1586 | |||
1587 | tx0 = get_texel_cube_array(sp_sview, sp_samp, addr, x0, y0, layer * 6 + face_id); |
||
1588 | tx1 = get_texel_cube_array(sp_sview, sp_samp, addr, x1, y0, layer * 6 + face_id); |
||
1589 | tx2 = get_texel_cube_array(sp_sview, sp_samp, addr, x0, y1, layer * 6 + face_id); |
||
1590 | tx3 = get_texel_cube_array(sp_sview, sp_samp, addr, x1, y1, layer * 6 + face_id); |
||
1591 | |||
1592 | /* interpolate R, G, B, A */ |
||
1593 | for (c = 0; c < TGSI_QUAD_SIZE; c++) |
||
1594 | rgba[TGSI_NUM_CHANNELS*c] = lerp_2d(xw, yw, |
||
1595 | tx0[c], tx1[c], |
||
1596 | tx2[c], tx3[c]); |
||
1597 | } |
||
1598 | |||
1599 | static void |
||
1600 | img_filter_3d_linear(struct sp_sampler_view *sp_sview, |
||
1601 | struct sp_sampler *sp_samp, |
||
1602 | float s, |
||
1603 | float t, |
||
1604 | float p, |
||
1605 | unsigned level, |
||
1606 | unsigned face_id, |
||
1607 | float *rgba) |
||
1608 | { |
||
1609 | const struct pipe_resource *texture = sp_sview->base.texture; |
||
1610 | int width, height, depth; |
||
1611 | int x0, x1, y0, y1, z0, z1; |
||
1612 | float xw, yw, zw; /* interpolation weights */ |
||
1613 | union tex_tile_address addr; |
||
1614 | const float *tx00, *tx01, *tx02, *tx03, *tx10, *tx11, *tx12, *tx13; |
||
1615 | int c; |
||
1616 | |||
1617 | width = u_minify(texture->width0, level); |
||
1618 | height = u_minify(texture->height0, level); |
||
1619 | depth = u_minify(texture->depth0, level); |
||
1620 | |||
1621 | addr.value = 0; |
||
1622 | addr.bits.level = level; |
||
1623 | |||
1624 | assert(width > 0); |
||
1625 | assert(height > 0); |
||
1626 | assert(depth > 0); |
||
1627 | |||
1628 | sp_samp->linear_texcoord_s(s, width, &x0, &x1, &xw); |
||
1629 | sp_samp->linear_texcoord_t(t, height, &y0, &y1, &yw); |
||
1630 | sp_samp->linear_texcoord_p(p, depth, &z0, &z1, &zw); |
||
1631 | |||
1632 | |||
1633 | tx00 = get_texel_3d(sp_sview, sp_samp, addr, x0, y0, z0); |
||
1634 | tx01 = get_texel_3d(sp_sview, sp_samp, addr, x1, y0, z0); |
||
1635 | tx02 = get_texel_3d(sp_sview, sp_samp, addr, x0, y1, z0); |
||
1636 | tx03 = get_texel_3d(sp_sview, sp_samp, addr, x1, y1, z0); |
||
1637 | |||
1638 | tx10 = get_texel_3d(sp_sview, sp_samp, addr, x0, y0, z1); |
||
1639 | tx11 = get_texel_3d(sp_sview, sp_samp, addr, x1, y0, z1); |
||
1640 | tx12 = get_texel_3d(sp_sview, sp_samp, addr, x0, y1, z1); |
||
1641 | tx13 = get_texel_3d(sp_sview, sp_samp, addr, x1, y1, z1); |
||
1642 | |||
1643 | /* interpolate R, G, B, A */ |
||
1644 | for (c = 0; c < TGSI_QUAD_SIZE; c++) |
||
1645 | rgba[TGSI_NUM_CHANNELS*c] = lerp_3d(xw, yw, zw, |
||
1646 | tx00[c], tx01[c], |
||
1647 | tx02[c], tx03[c], |
||
1648 | tx10[c], tx11[c], |
||
1649 | tx12[c], tx13[c]); |
||
1650 | } |
||
1651 | |||
1652 | |||
1653 | /* Calculate level of detail for every fragment, |
||
1654 | * with lambda already computed. |
||
1655 | * Note that lambda has already been biased by global LOD bias. |
||
1656 | * \param biased_lambda per-quad lambda. |
||
1657 | * \param lod_in per-fragment lod_bias or explicit_lod. |
||
1658 | * \param lod returns the per-fragment lod. |
||
1659 | */ |
||
1660 | static INLINE void |
||
1661 | compute_lod(const struct pipe_sampler_state *sampler, |
||
1662 | enum tgsi_sampler_control control, |
||
1663 | const float biased_lambda, |
||
1664 | const float lod_in[TGSI_QUAD_SIZE], |
||
1665 | float lod[TGSI_QUAD_SIZE]) |
||
1666 | { |
||
1667 | float min_lod = sampler->min_lod; |
||
1668 | float max_lod = sampler->max_lod; |
||
1669 | uint i; |
||
1670 | |||
1671 | switch (control) { |
||
1672 | case tgsi_sampler_lod_none: |
||
1673 | case tgsi_sampler_lod_zero: |
||
1674 | /* XXX FIXME */ |
||
1675 | case tgsi_sampler_derivs_explicit: |
||
1676 | lod[0] = lod[1] = lod[2] = lod[3] = CLAMP(biased_lambda, min_lod, max_lod); |
||
1677 | break; |
||
1678 | case tgsi_sampler_lod_bias: |
||
1679 | for (i = 0; i < TGSI_QUAD_SIZE; i++) { |
||
1680 | lod[i] = biased_lambda + lod_in[i]; |
||
1681 | lod[i] = CLAMP(lod[i], min_lod, max_lod); |
||
1682 | } |
||
1683 | break; |
||
1684 | case tgsi_sampler_lod_explicit: |
||
1685 | for (i = 0; i < TGSI_QUAD_SIZE; i++) { |
||
1686 | lod[i] = CLAMP(lod_in[i], min_lod, max_lod); |
||
1687 | } |
||
1688 | break; |
||
1689 | default: |
||
1690 | assert(0); |
||
1691 | lod[0] = lod[1] = lod[2] = lod[3] = 0.0f; |
||
1692 | } |
||
1693 | } |
||
1694 | |||
1695 | |||
1696 | /* Calculate level of detail for every fragment. |
||
1697 | * \param lod_in per-fragment lod_bias or explicit_lod. |
||
1698 | * \param lod results per-fragment lod. |
||
1699 | */ |
||
1700 | static INLINE void |
||
1701 | compute_lambda_lod(struct sp_sampler_view *sp_sview, |
||
1702 | struct sp_sampler *sp_samp, |
||
1703 | const float s[TGSI_QUAD_SIZE], |
||
1704 | const float t[TGSI_QUAD_SIZE], |
||
1705 | const float p[TGSI_QUAD_SIZE], |
||
1706 | const float lod_in[TGSI_QUAD_SIZE], |
||
1707 | enum tgsi_sampler_control control, |
||
1708 | float lod[TGSI_QUAD_SIZE]) |
||
1709 | { |
||
1710 | const struct pipe_sampler_state *sampler = &sp_samp->base; |
||
1711 | float lod_bias = sampler->lod_bias; |
||
1712 | float min_lod = sampler->min_lod; |
||
1713 | float max_lod = sampler->max_lod; |
||
1714 | float lambda; |
||
1715 | uint i; |
||
1716 | |||
1717 | switch (control) { |
||
1718 | case tgsi_sampler_lod_none: |
||
1719 | /* XXX FIXME */ |
||
1720 | case tgsi_sampler_derivs_explicit: |
||
1721 | lambda = sp_sview->compute_lambda(sp_sview, s, t, p) + lod_bias; |
||
1722 | lod[0] = lod[1] = lod[2] = lod[3] = CLAMP(lambda, min_lod, max_lod); |
||
1723 | break; |
||
1724 | case tgsi_sampler_lod_bias: |
||
1725 | lambda = sp_sview->compute_lambda(sp_sview, s, t, p) + lod_bias; |
||
1726 | for (i = 0; i < TGSI_QUAD_SIZE; i++) { |
||
1727 | lod[i] = lambda + lod_in[i]; |
||
1728 | lod[i] = CLAMP(lod[i], min_lod, max_lod); |
||
1729 | } |
||
1730 | break; |
||
1731 | case tgsi_sampler_lod_explicit: |
||
1732 | for (i = 0; i < TGSI_QUAD_SIZE; i++) { |
||
1733 | lod[i] = CLAMP(lod_in[i], min_lod, max_lod); |
||
1734 | } |
||
1735 | break; |
||
1736 | case tgsi_sampler_lod_zero: |
||
1737 | /* this is all static state in the sampler really need clamp here? */ |
||
1738 | lod[0] = lod[1] = lod[2] = lod[3] = CLAMP(lod_bias, min_lod, max_lod); |
||
1739 | break; |
||
1740 | default: |
||
1741 | assert(0); |
||
1742 | lod[0] = lod[1] = lod[2] = lod[3] = 0.0f; |
||
1743 | } |
||
1744 | } |
||
1745 | |||
1746 | |||
1747 | static void |
||
1748 | mip_filter_linear(struct sp_sampler_view *sp_sview, |
||
1749 | struct sp_sampler *sp_samp, |
||
1750 | img_filter_func min_filter, |
||
1751 | img_filter_func mag_filter, |
||
1752 | const float s[TGSI_QUAD_SIZE], |
||
1753 | const float t[TGSI_QUAD_SIZE], |
||
1754 | const float p[TGSI_QUAD_SIZE], |
||
1755 | const float c0[TGSI_QUAD_SIZE], |
||
1756 | const float lod_in[TGSI_QUAD_SIZE], |
||
1757 | enum tgsi_sampler_control control, |
||
1758 | float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) |
||
1759 | { |
||
1760 | const struct pipe_resource *texture = sp_sview->base.texture; |
||
1761 | int j; |
||
1762 | float lod[TGSI_QUAD_SIZE]; |
||
1763 | |||
1764 | compute_lambda_lod(sp_sview, sp_samp, s, t, p, lod_in, control, lod); |
||
1765 | |||
1766 | for (j = 0; j < TGSI_QUAD_SIZE; j++) { |
||
1767 | int level0 = sp_sview->base.u.tex.first_level + (int)lod[j]; |
||
1768 | |||
1769 | if (lod[j] < 0.0) |
||
1770 | mag_filter(sp_sview, sp_samp, s[j], t[j], p[j], |
||
1771 | sp_sview->base.u.tex.first_level, |
||
1772 | sp_sview->faces[j], &rgba[0][j]); |
||
1773 | |||
1774 | else if (level0 >= texture->last_level) |
||
1775 | min_filter(sp_sview, sp_samp, s[j], t[j], p[j], texture->last_level, |
||
1776 | sp_sview->faces[j], &rgba[0][j]); |
||
1777 | |||
1778 | else { |
||
1779 | float levelBlend = frac(lod[j]); |
||
1780 | float rgbax[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]; |
||
1781 | int c; |
||
1782 | |||
1783 | min_filter(sp_sview, sp_samp, s[j], t[j], p[j], level0, |
||
1784 | sp_sview->faces[j], &rgbax[0][0]); |
||
1785 | min_filter(sp_sview, sp_samp, s[j], t[j], p[j], level0+1, |
||
1786 | sp_sview->faces[j], &rgbax[0][1]); |
||
1787 | |||
1788 | for (c = 0; c < 4; c++) { |
||
1789 | rgba[c][j] = lerp(levelBlend, rgbax[c][0], rgbax[c][1]); |
||
1790 | } |
||
1791 | } |
||
1792 | } |
||
1793 | |||
1794 | if (DEBUG_TEX) { |
||
1795 | print_sample_4(__FUNCTION__, rgba); |
||
1796 | } |
||
1797 | } |
||
1798 | |||
1799 | |||
1800 | /** |
||
1801 | * Compute nearest mipmap level from texcoords. |
||
1802 | * Then sample the texture level for four elements of a quad. |
||
1803 | * \param c0 the LOD bias factors, or absolute LODs (depending on control) |
||
1804 | */ |
||
1805 | static void |
||
1806 | mip_filter_nearest(struct sp_sampler_view *sp_sview, |
||
1807 | struct sp_sampler *sp_samp, |
||
1808 | img_filter_func min_filter, |
||
1809 | img_filter_func mag_filter, |
||
1810 | const float s[TGSI_QUAD_SIZE], |
||
1811 | const float t[TGSI_QUAD_SIZE], |
||
1812 | const float p[TGSI_QUAD_SIZE], |
||
1813 | const float c0[TGSI_QUAD_SIZE], |
||
1814 | const float lod_in[TGSI_QUAD_SIZE], |
||
1815 | enum tgsi_sampler_control control, |
||
1816 | float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) |
||
1817 | { |
||
1818 | const struct pipe_resource *texture = sp_sview->base.texture; |
||
1819 | float lod[TGSI_QUAD_SIZE]; |
||
1820 | int j; |
||
1821 | |||
1822 | compute_lambda_lod(sp_sview, sp_samp, s, t, p, lod_in, control, lod); |
||
1823 | |||
1824 | for (j = 0; j < TGSI_QUAD_SIZE; j++) { |
||
1825 | if (lod[j] < 0.0) |
||
1826 | mag_filter(sp_sview, sp_samp, s[j], t[j], p[j], |
||
1827 | sp_sview->base.u.tex.first_level, |
||
1828 | sp_sview->faces[j], &rgba[0][j]); |
||
1829 | else { |
||
1830 | float level = sp_sview->base.u.tex.first_level + (int)(lod[j] + 0.5F) ; |
||
1831 | level = MIN2(level, (int)texture->last_level); |
||
1832 | min_filter(sp_sview, sp_samp, s[j], t[j], p[j], |
||
1833 | level, sp_sview->faces[j], &rgba[0][j]); |
||
1834 | } |
||
1835 | } |
||
1836 | |||
1837 | if (DEBUG_TEX) { |
||
1838 | print_sample_4(__FUNCTION__, rgba); |
||
1839 | } |
||
1840 | } |
||
1841 | |||
1842 | |||
1843 | static void |
||
1844 | mip_filter_none(struct sp_sampler_view *sp_sview, |
||
1845 | struct sp_sampler *sp_samp, |
||
1846 | img_filter_func min_filter, |
||
1847 | img_filter_func mag_filter, |
||
1848 | const float s[TGSI_QUAD_SIZE], |
||
1849 | const float t[TGSI_QUAD_SIZE], |
||
1850 | const float p[TGSI_QUAD_SIZE], |
||
1851 | const float c0[TGSI_QUAD_SIZE], |
||
1852 | const float lod_in[TGSI_QUAD_SIZE], |
||
1853 | enum tgsi_sampler_control control, |
||
1854 | float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) |
||
1855 | { |
||
1856 | float lod[TGSI_QUAD_SIZE]; |
||
1857 | int j; |
||
1858 | |||
1859 | compute_lambda_lod(sp_sview, sp_samp, s, t, p, lod_in, control, lod); |
||
1860 | |||
1861 | for (j = 0; j < TGSI_QUAD_SIZE; j++) { |
||
1862 | if (lod[j] < 0.0) { |
||
1863 | mag_filter(sp_sview, sp_samp, s[j], t[j], p[j], |
||
1864 | sp_sview->base.u.tex.first_level, |
||
1865 | sp_sview->faces[j], &rgba[0][j]); |
||
1866 | } |
||
1867 | else { |
||
1868 | min_filter(sp_sview, sp_samp, s[j], t[j], p[j], |
||
1869 | sp_sview->base.u.tex.first_level, |
||
1870 | sp_sview->faces[j], &rgba[0][j]); |
||
1871 | } |
||
1872 | } |
||
1873 | } |
||
1874 | |||
1875 | |||
1876 | static void |
||
1877 | mip_filter_none_no_filter_select(struct sp_sampler_view *sp_sview, |
||
1878 | struct sp_sampler *sp_samp, |
||
1879 | img_filter_func min_filter, |
||
1880 | img_filter_func mag_filter, |
||
1881 | const float s[TGSI_QUAD_SIZE], |
||
1882 | const float t[TGSI_QUAD_SIZE], |
||
1883 | const float p[TGSI_QUAD_SIZE], |
||
1884 | const float c0[TGSI_QUAD_SIZE], |
||
1885 | const float lod_in[TGSI_QUAD_SIZE], |
||
1886 | enum tgsi_sampler_control control, |
||
1887 | float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) |
||
1888 | { |
||
1889 | int j; |
||
1890 | |||
1891 | for (j = 0; j < TGSI_QUAD_SIZE; j++) |
||
1892 | mag_filter(sp_sview, sp_samp, s[j], t[j], p[j], |
||
1893 | sp_sview->base.u.tex.first_level, |
||
1894 | sp_sview->faces[j], &rgba[0][j]); |
||
1895 | } |
||
1896 | |||
1897 | |||
1898 | /* For anisotropic filtering */ |
||
1899 | #define WEIGHT_LUT_SIZE 1024 |
||
1900 | |||
1901 | static float *weightLut = NULL; |
||
1902 | |||
1903 | /** |
||
1904 | * Creates the look-up table used to speed-up EWA sampling |
||
1905 | */ |
||
1906 | static void |
||
1907 | create_filter_table(void) |
||
1908 | { |
||
1909 | unsigned i; |
||
1910 | if (!weightLut) { |
||
1911 | weightLut = (float *) MALLOC(WEIGHT_LUT_SIZE * sizeof(float)); |
||
1912 | |||
1913 | for (i = 0; i < WEIGHT_LUT_SIZE; ++i) { |
||
1914 | float alpha = 2; |
||
1915 | float r2 = (float) i / (float) (WEIGHT_LUT_SIZE - 1); |
||
1916 | float weight = (float) exp(-alpha * r2); |
||
1917 | weightLut[i] = weight; |
||
1918 | } |
||
1919 | } |
||
1920 | } |
||
1921 | |||
1922 | |||
1923 | /** |
||
1924 | * Elliptical weighted average (EWA) filter for producing high quality |
||
1925 | * anisotropic filtered results. |
||
1926 | * Based on the Higher Quality Elliptical Weighted Average Filter |
||
1927 | * published by Paul S. Heckbert in his Master's Thesis |
||
1928 | * "Fundamentals of Texture Mapping and Image Warping" (1989) |
||
1929 | */ |
||
1930 | static void |
||
1931 | img_filter_2d_ewa(struct sp_sampler_view *sp_sview, |
||
1932 | struct sp_sampler *sp_samp, |
||
1933 | img_filter_func min_filter, |
||
1934 | img_filter_func mag_filter, |
||
1935 | const float s[TGSI_QUAD_SIZE], |
||
1936 | const float t[TGSI_QUAD_SIZE], |
||
1937 | const float p[TGSI_QUAD_SIZE], |
||
1938 | unsigned level, |
||
1939 | const float dudx, const float dvdx, |
||
1940 | const float dudy, const float dvdy, |
||
1941 | float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) |
||
1942 | { |
||
1943 | const struct pipe_resource *texture = sp_sview->base.texture; |
||
1944 | |||
1945 | // ??? Won't the image filters blow up if level is negative? |
||
1946 | unsigned level0 = level > 0 ? level : 0; |
||
1947 | float scaling = 1.0f / (1 << level0); |
||
1948 | int width = u_minify(texture->width0, level0); |
||
1949 | int height = u_minify(texture->height0, level0); |
||
1950 | |||
1951 | float ux = dudx * scaling; |
||
1952 | float vx = dvdx * scaling; |
||
1953 | float uy = dudy * scaling; |
||
1954 | float vy = dvdy * scaling; |
||
1955 | |||
1956 | /* compute ellipse coefficients to bound the region: |
||
1957 | * A*x*x + B*x*y + C*y*y = F. |
||
1958 | */ |
||
1959 | float A = vx*vx+vy*vy+1; |
||
1960 | float B = -2*(ux*vx+uy*vy); |
||
1961 | float C = ux*ux+uy*uy+1; |
||
1962 | float F = A*C-B*B/4.0f; |
||
1963 | |||
1964 | /* check if it is an ellipse */ |
||
1965 | /* ASSERT(F > 0.0); */ |
||
1966 | |||
1967 | /* Compute the ellipse's (u,v) bounding box in texture space */ |
||
1968 | float d = -B*B+4.0f*C*A; |
||
1969 | float box_u = 2.0f / d * sqrt(d*C*F); /* box_u -> half of bbox with */ |
||
1970 | float box_v = 2.0f / d * sqrt(A*d*F); /* box_v -> half of bbox height */ |
||
1971 | |||
1972 | float rgba_temp[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]; |
||
1973 | float s_buffer[TGSI_QUAD_SIZE]; |
||
1974 | float t_buffer[TGSI_QUAD_SIZE]; |
||
1975 | float weight_buffer[TGSI_QUAD_SIZE]; |
||
1976 | unsigned buffer_next; |
||
1977 | int j; |
||
1978 | float den; /* = 0.0F; */ |
||
1979 | float ddq; |
||
1980 | float U; /* = u0 - tex_u; */ |
||
1981 | int v; |
||
1982 | |||
1983 | /* Scale ellipse formula to directly index the Filter Lookup Table. |
||
1984 | * i.e. scale so that F = WEIGHT_LUT_SIZE-1 |
||
1985 | */ |
||
1986 | double formScale = (double) (WEIGHT_LUT_SIZE - 1) / F; |
||
1987 | A *= formScale; |
||
1988 | B *= formScale; |
||
1989 | C *= formScale; |
||
1990 | /* F *= formScale; */ /* no need to scale F as we don't use it below here */ |
||
1991 | |||
1992 | /* For each quad, the du and dx values are the same and so the ellipse is |
||
1993 | * also the same. Note that texel/image access can only be performed using |
||
1994 | * a quad, i.e. it is not possible to get the pixel value for a single |
||
1995 | * tex coord. In order to have a better performance, the access is buffered |
||
1996 | * using the s_buffer/t_buffer and weight_buffer. Only when the buffer is |
||
1997 | * full, then the pixel values are read from the image. |
||
1998 | */ |
||
1999 | ddq = 2 * A; |
||
2000 | |||
2001 | for (j = 0; j < TGSI_QUAD_SIZE; j++) { |
||
2002 | /* Heckbert MS thesis, p. 59; scan over the bounding box of the ellipse |
||
2003 | * and incrementally update the value of Ax^2+Bxy*Cy^2; when this |
||
2004 | * value, q, is less than F, we're inside the ellipse |
||
2005 | */ |
||
2006 | float tex_u = -0.5F + s[j] * texture->width0 * scaling; |
||
2007 | float tex_v = -0.5F + t[j] * texture->height0 * scaling; |
||
2008 | |||
2009 | int u0 = (int) floorf(tex_u - box_u); |
||
2010 | int u1 = (int) ceilf(tex_u + box_u); |
||
2011 | int v0 = (int) floorf(tex_v - box_v); |
||
2012 | int v1 = (int) ceilf(tex_v + box_v); |
||
2013 | |||
2014 | float num[4] = {0.0F, 0.0F, 0.0F, 0.0F}; |
||
2015 | buffer_next = 0; |
||
2016 | den = 0; |
||
2017 | U = u0 - tex_u; |
||
2018 | for (v = v0; v <= v1; ++v) { |
||
2019 | float V = v - tex_v; |
||
2020 | float dq = A * (2 * U + 1) + B * V; |
||
2021 | float q = (C * V + B * U) * V + A * U * U; |
||
2022 | |||
2023 | int u; |
||
2024 | for (u = u0; u <= u1; ++u) { |
||
2025 | /* Note that the ellipse has been pre-scaled so F = |
||
2026 | * WEIGHT_LUT_SIZE - 1 |
||
2027 | */ |
||
2028 | if (q < WEIGHT_LUT_SIZE) { |
||
2029 | /* as a LUT is used, q must never be negative; |
||
2030 | * should not happen, though |
||
2031 | */ |
||
2032 | const int qClamped = q >= 0.0F ? q : 0; |
||
2033 | float weight = weightLut[qClamped]; |
||
2034 | |||
2035 | weight_buffer[buffer_next] = weight; |
||
2036 | s_buffer[buffer_next] = u / ((float) width); |
||
2037 | t_buffer[buffer_next] = v / ((float) height); |
||
2038 | |||
2039 | buffer_next++; |
||
2040 | if (buffer_next == TGSI_QUAD_SIZE) { |
||
2041 | /* 4 texel coords are in the buffer -> read it now */ |
||
2042 | unsigned jj; |
||
2043 | /* it is assumed that samp->min_img_filter is set to |
||
2044 | * img_filter_2d_nearest or one of the |
||
2045 | * accelerated img_filter_2d_nearest_XXX functions. |
||
2046 | */ |
||
2047 | for (jj = 0; jj < buffer_next; jj++) { |
||
2048 | min_filter(sp_sview, sp_samp, s_buffer[jj], t_buffer[jj], p[jj], |
||
2049 | level, sp_sview->faces[j], &rgba_temp[0][jj]); |
||
2050 | num[0] += weight_buffer[jj] * rgba_temp[0][jj]; |
||
2051 | num[1] += weight_buffer[jj] * rgba_temp[1][jj]; |
||
2052 | num[2] += weight_buffer[jj] * rgba_temp[2][jj]; |
||
2053 | num[3] += weight_buffer[jj] * rgba_temp[3][jj]; |
||
2054 | } |
||
2055 | |||
2056 | buffer_next = 0; |
||
2057 | } |
||
2058 | |||
2059 | den += weight; |
||
2060 | } |
||
2061 | q += dq; |
||
2062 | dq += ddq; |
||
2063 | } |
||
2064 | } |
||
2065 | |||
2066 | /* if the tex coord buffer contains unread values, we will read |
||
2067 | * them now. |
||
2068 | */ |
||
2069 | if (buffer_next > 0) { |
||
2070 | unsigned jj; |
||
2071 | /* it is assumed that samp->min_img_filter is set to |
||
2072 | * img_filter_2d_nearest or one of the |
||
2073 | * accelerated img_filter_2d_nearest_XXX functions. |
||
2074 | */ |
||
2075 | for (jj = 0; jj < buffer_next; jj++) { |
||
2076 | min_filter(sp_sview, sp_samp, s_buffer[jj], t_buffer[jj], p[jj], |
||
2077 | level, sp_sview->faces[j], &rgba_temp[0][jj]); |
||
2078 | num[0] += weight_buffer[jj] * rgba_temp[0][jj]; |
||
2079 | num[1] += weight_buffer[jj] * rgba_temp[1][jj]; |
||
2080 | num[2] += weight_buffer[jj] * rgba_temp[2][jj]; |
||
2081 | num[3] += weight_buffer[jj] * rgba_temp[3][jj]; |
||
2082 | } |
||
2083 | } |
||
2084 | |||
2085 | if (den <= 0.0F) { |
||
2086 | /* Reaching this place would mean that no pixels intersected |
||
2087 | * the ellipse. This should never happen because the filter |
||
2088 | * we use always intersects at least one pixel. |
||
2089 | */ |
||
2090 | |||
2091 | /*rgba[0]=0; |
||
2092 | rgba[1]=0; |
||
2093 | rgba[2]=0; |
||
2094 | rgba[3]=0;*/ |
||
2095 | /* not enough pixels in resampling, resort to direct interpolation */ |
||
2096 | min_filter(sp_sview, sp_samp, s[j], t[j], p[j], level, |
||
2097 | sp_sview->faces[j], &rgba_temp[0][j]); |
||
2098 | den = 1; |
||
2099 | num[0] = rgba_temp[0][j]; |
||
2100 | num[1] = rgba_temp[1][j]; |
||
2101 | num[2] = rgba_temp[2][j]; |
||
2102 | num[3] = rgba_temp[3][j]; |
||
2103 | } |
||
2104 | |||
2105 | rgba[0][j] = num[0] / den; |
||
2106 | rgba[1][j] = num[1] / den; |
||
2107 | rgba[2][j] = num[2] / den; |
||
2108 | rgba[3][j] = num[3] / den; |
||
2109 | } |
||
2110 | } |
||
2111 | |||
2112 | |||
2113 | /** |
||
2114 | * Sample 2D texture using an anisotropic filter. |
||
2115 | */ |
||
2116 | static void |
||
2117 | mip_filter_linear_aniso(struct sp_sampler_view *sp_sview, |
||
2118 | struct sp_sampler *sp_samp, |
||
2119 | img_filter_func min_filter, |
||
2120 | img_filter_func mag_filter, |
||
2121 | const float s[TGSI_QUAD_SIZE], |
||
2122 | const float t[TGSI_QUAD_SIZE], |
||
2123 | const float p[TGSI_QUAD_SIZE], |
||
2124 | const float c0[TGSI_QUAD_SIZE], |
||
2125 | const float lod_in[TGSI_QUAD_SIZE], |
||
2126 | enum tgsi_sampler_control control, |
||
2127 | float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) |
||
2128 | { |
||
2129 | const struct pipe_resource *texture = sp_sview->base.texture; |
||
2130 | int level0; |
||
2131 | float lambda; |
||
2132 | float lod[TGSI_QUAD_SIZE]; |
||
2133 | |||
2134 | float s_to_u = u_minify(texture->width0, sp_sview->base.u.tex.first_level); |
||
2135 | float t_to_v = u_minify(texture->height0, sp_sview->base.u.tex.first_level); |
||
2136 | float dudx = (s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT]) * s_to_u; |
||
2137 | float dudy = (s[QUAD_TOP_LEFT] - s[QUAD_BOTTOM_LEFT]) * s_to_u; |
||
2138 | float dvdx = (t[QUAD_BOTTOM_RIGHT] - t[QUAD_BOTTOM_LEFT]) * t_to_v; |
||
2139 | float dvdy = (t[QUAD_TOP_LEFT] - t[QUAD_BOTTOM_LEFT]) * t_to_v; |
||
2140 | |||
2141 | if (control == tgsi_sampler_lod_bias || |
||
2142 | control == tgsi_sampler_lod_none || |
||
2143 | /* XXX FIXME */ |
||
2144 | control == tgsi_sampler_derivs_explicit) { |
||
2145 | /* note: instead of working with Px and Py, we will use the |
||
2146 | * squared length instead, to avoid sqrt. |
||
2147 | */ |
||
2148 | float Px2 = dudx * dudx + dvdx * dvdx; |
||
2149 | float Py2 = dudy * dudy + dvdy * dvdy; |
||
2150 | |||
2151 | float Pmax2; |
||
2152 | float Pmin2; |
||
2153 | float e; |
||
2154 | const float maxEccentricity = sp_samp->base.max_anisotropy * sp_samp->base.max_anisotropy; |
||
2155 | |||
2156 | if (Px2 < Py2) { |
||
2157 | Pmax2 = Py2; |
||
2158 | Pmin2 = Px2; |
||
2159 | } |
||
2160 | else { |
||
2161 | Pmax2 = Px2; |
||
2162 | Pmin2 = Py2; |
||
2163 | } |
||
2164 | |||
2165 | /* if the eccentricity of the ellipse is too big, scale up the shorter |
||
2166 | * of the two vectors to limit the maximum amount of work per pixel |
||
2167 | */ |
||
2168 | e = Pmax2 / Pmin2; |
||
2169 | if (e > maxEccentricity) { |
||
2170 | /* float s=e / maxEccentricity; |
||
2171 | minor[0] *= s; |
||
2172 | minor[1] *= s; |
||
2173 | Pmin2 *= s; */ |
||
2174 | Pmin2 = Pmax2 / maxEccentricity; |
||
2175 | } |
||
2176 | |||
2177 | /* note: we need to have Pmin=sqrt(Pmin2) here, but we can avoid |
||
2178 | * this since 0.5*log(x) = log(sqrt(x)) |
||
2179 | */ |
||
2180 | lambda = 0.5F * util_fast_log2(Pmin2) + sp_samp->base.lod_bias; |
||
2181 | compute_lod(&sp_samp->base, control, lambda, lod_in, lod); |
||
2182 | } |
||
2183 | else { |
||
2184 | assert(control == tgsi_sampler_lod_explicit || |
||
2185 | control == tgsi_sampler_lod_zero); |
||
2186 | compute_lod(&sp_samp->base, control, sp_samp->base.lod_bias, lod_in, lod); |
||
2187 | } |
||
2188 | |||
2189 | /* XXX: Take into account all lod values. |
||
2190 | */ |
||
2191 | lambda = lod[0]; |
||
2192 | level0 = sp_sview->base.u.tex.first_level + (int)lambda; |
||
2193 | |||
2194 | /* If the ellipse covers the whole image, we can |
||
2195 | * simply return the average of the whole image. |
||
2196 | */ |
||
2197 | if (level0 >= (int) texture->last_level) { |
||
2198 | int j; |
||
2199 | for (j = 0; j < TGSI_QUAD_SIZE; j++) |
||
2200 | min_filter(sp_sview, sp_samp, s[j], t[j], p[j], texture->last_level, |
||
2201 | sp_sview->faces[j], &rgba[0][j]); |
||
2202 | } |
||
2203 | else { |
||
2204 | /* don't bother interpolating between multiple LODs; it doesn't |
||
2205 | * seem to be worth the extra running time. |
||
2206 | */ |
||
2207 | img_filter_2d_ewa(sp_sview, sp_samp, min_filter, mag_filter, |
||
2208 | s, t, p, level0, |
||
2209 | dudx, dvdx, dudy, dvdy, rgba); |
||
2210 | } |
||
2211 | |||
2212 | if (DEBUG_TEX) { |
||
2213 | print_sample_4(__FUNCTION__, rgba); |
||
2214 | } |
||
2215 | } |
||
2216 | |||
2217 | |||
2218 | /** |
||
2219 | * Specialized version of mip_filter_linear with hard-wired calls to |
||
2220 | * 2d lambda calculation and 2d_linear_repeat_POT img filters. |
||
2221 | */ |
||
2222 | static void |
||
2223 | mip_filter_linear_2d_linear_repeat_POT( |
||
2224 | struct sp_sampler_view *sp_sview, |
||
2225 | struct sp_sampler *sp_samp, |
||
2226 | img_filter_func min_filter, |
||
2227 | img_filter_func mag_filter, |
||
2228 | const float s[TGSI_QUAD_SIZE], |
||
2229 | const float t[TGSI_QUAD_SIZE], |
||
2230 | const float p[TGSI_QUAD_SIZE], |
||
2231 | const float c0[TGSI_QUAD_SIZE], |
||
2232 | const float lod_in[TGSI_QUAD_SIZE], |
||
2233 | enum tgsi_sampler_control control, |
||
2234 | float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) |
||
2235 | { |
||
2236 | const struct pipe_resource *texture = sp_sview->base.texture; |
||
2237 | int j; |
||
2238 | float lod[TGSI_QUAD_SIZE]; |
||
2239 | |||
2240 | compute_lambda_lod(sp_sview, sp_samp, s, t, p, lod_in, control, lod); |
||
2241 | |||
2242 | for (j = 0; j < TGSI_QUAD_SIZE; j++) { |
||
2243 | int level0 = sp_sview->base.u.tex.first_level + (int)lod[j]; |
||
2244 | |||
2245 | /* Catches both negative and large values of level0: |
||
2246 | */ |
||
2247 | if ((unsigned)level0 >= texture->last_level) { |
||
2248 | if (level0 < 0) |
||
2249 | img_filter_2d_linear_repeat_POT(sp_sview, sp_samp, s[j], t[j], p[j], |
||
2250 | sp_sview->base.u.tex.first_level, |
||
2251 | sp_sview->faces[j], &rgba[0][j]); |
||
2252 | else |
||
2253 | img_filter_2d_linear_repeat_POT(sp_sview, sp_samp, s[j], t[j], p[j], |
||
2254 | sp_sview->base.texture->last_level, |
||
2255 | sp_sview->faces[j], &rgba[0][j]); |
||
2256 | |||
2257 | } |
||
2258 | else { |
||
2259 | float levelBlend = frac(lod[j]); |
||
2260 | float rgbax[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]; |
||
2261 | int c; |
||
2262 | |||
2263 | img_filter_2d_linear_repeat_POT(sp_sview, sp_samp, s[j], t[j], p[j], level0, |
||
2264 | sp_sview->faces[j], &rgbax[0][0]); |
||
2265 | img_filter_2d_linear_repeat_POT(sp_sview, sp_samp, s[j], t[j], p[j], level0+1, |
||
2266 | sp_sview->faces[j], &rgbax[0][1]); |
||
2267 | |||
2268 | for (c = 0; c < TGSI_NUM_CHANNELS; c++) |
||
2269 | rgba[c][j] = lerp(levelBlend, rgbax[c][0], rgbax[c][1]); |
||
2270 | } |
||
2271 | } |
||
2272 | |||
2273 | if (DEBUG_TEX) { |
||
2274 | print_sample_4(__FUNCTION__, rgba); |
||
2275 | } |
||
2276 | } |
||
2277 | |||
2278 | |||
2279 | /** |
||
2280 | * Do shadow/depth comparisons. |
||
2281 | */ |
||
2282 | static void |
||
2283 | sample_compare(struct sp_sampler_view *sp_sview, |
||
2284 | struct sp_sampler *sp_samp, |
||
2285 | const float s[TGSI_QUAD_SIZE], |
||
2286 | const float t[TGSI_QUAD_SIZE], |
||
2287 | const float p[TGSI_QUAD_SIZE], |
||
2288 | const float c0[TGSI_QUAD_SIZE], |
||
2289 | const float c1[TGSI_QUAD_SIZE], |
||
2290 | enum tgsi_sampler_control control, |
||
2291 | float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) |
||
2292 | { |
||
2293 | const struct pipe_sampler_state *sampler = &sp_samp->base; |
||
2294 | int j, k0, k1, k2, k3; |
||
2295 | float val; |
||
2296 | float pc0, pc1, pc2, pc3; |
||
2297 | |||
2298 | /** |
||
2299 | * Compare texcoord 'p' (aka R) against texture value 'rgba[0]' |
||
2300 | * for 2D Array texture we need to use the 'c0' (aka Q). |
||
2301 | * When we sampled the depth texture, the depth value was put into all |
||
2302 | * RGBA channels. We look at the red channel here. |
||
2303 | */ |
||
2304 | |||
2305 | if (sp_sview->base.texture->target == PIPE_TEXTURE_2D_ARRAY || |
||
2306 | sp_sview->base.texture->target == PIPE_TEXTURE_CUBE) { |
||
2307 | pc0 = CLAMP(c0[0], 0.0F, 1.0F); |
||
2308 | pc1 = CLAMP(c0[1], 0.0F, 1.0F); |
||
2309 | pc2 = CLAMP(c0[2], 0.0F, 1.0F); |
||
2310 | pc3 = CLAMP(c0[3], 0.0F, 1.0F); |
||
2311 | } else if (sp_sview->base.texture->target == PIPE_TEXTURE_CUBE_ARRAY) { |
||
2312 | pc0 = CLAMP(c1[0], 0.0F, 1.0F); |
||
2313 | pc1 = CLAMP(c1[1], 0.0F, 1.0F); |
||
2314 | pc2 = CLAMP(c1[2], 0.0F, 1.0F); |
||
2315 | pc3 = CLAMP(c1[3], 0.0F, 1.0F); |
||
2316 | } else { |
||
2317 | pc0 = CLAMP(p[0], 0.0F, 1.0F); |
||
2318 | pc1 = CLAMP(p[1], 0.0F, 1.0F); |
||
2319 | pc2 = CLAMP(p[2], 0.0F, 1.0F); |
||
2320 | pc3 = CLAMP(p[3], 0.0F, 1.0F); |
||
2321 | } |
||
2322 | /* compare four texcoords vs. four texture samples */ |
||
2323 | switch (sampler->compare_func) { |
||
2324 | case PIPE_FUNC_LESS: |
||
2325 | k0 = pc0 < rgba[0][0]; |
||
2326 | k1 = pc1 < rgba[0][1]; |
||
2327 | k2 = pc2 < rgba[0][2]; |
||
2328 | k3 = pc3 < rgba[0][3]; |
||
2329 | break; |
||
2330 | case PIPE_FUNC_LEQUAL: |
||
2331 | k0 = pc0 <= rgba[0][0]; |
||
2332 | k1 = pc1 <= rgba[0][1]; |
||
2333 | k2 = pc2 <= rgba[0][2]; |
||
2334 | k3 = pc3 <= rgba[0][3]; |
||
2335 | break; |
||
2336 | case PIPE_FUNC_GREATER: |
||
2337 | k0 = pc0 > rgba[0][0]; |
||
2338 | k1 = pc1 > rgba[0][1]; |
||
2339 | k2 = pc2 > rgba[0][2]; |
||
2340 | k3 = pc3 > rgba[0][3]; |
||
2341 | break; |
||
2342 | case PIPE_FUNC_GEQUAL: |
||
2343 | k0 = pc0 >= rgba[0][0]; |
||
2344 | k1 = pc1 >= rgba[0][1]; |
||
2345 | k2 = pc2 >= rgba[0][2]; |
||
2346 | k3 = pc3 >= rgba[0][3]; |
||
2347 | break; |
||
2348 | case PIPE_FUNC_EQUAL: |
||
2349 | k0 = pc0 == rgba[0][0]; |
||
2350 | k1 = pc1 == rgba[0][1]; |
||
2351 | k2 = pc2 == rgba[0][2]; |
||
2352 | k3 = pc3 == rgba[0][3]; |
||
2353 | break; |
||
2354 | case PIPE_FUNC_NOTEQUAL: |
||
2355 | k0 = pc0 != rgba[0][0]; |
||
2356 | k1 = pc1 != rgba[0][1]; |
||
2357 | k2 = pc2 != rgba[0][2]; |
||
2358 | k3 = pc3 != rgba[0][3]; |
||
2359 | break; |
||
2360 | case PIPE_FUNC_ALWAYS: |
||
2361 | k0 = k1 = k2 = k3 = 1; |
||
2362 | break; |
||
2363 | case PIPE_FUNC_NEVER: |
||
2364 | k0 = k1 = k2 = k3 = 0; |
||
2365 | break; |
||
2366 | default: |
||
2367 | k0 = k1 = k2 = k3 = 0; |
||
2368 | assert(0); |
||
2369 | break; |
||
2370 | } |
||
2371 | |||
2372 | if (sampler->mag_img_filter == PIPE_TEX_FILTER_LINEAR) { |
||
2373 | /* convert four pass/fail values to an intensity in [0,1] */ |
||
2374 | /* |
||
2375 | * XXX this doesn't actually make much sense. |
||
2376 | * We just average the result of four _pixels_ and output the same |
||
2377 | * value for all of the four pixels of the quad. |
||
2378 | * This really needs to work on the _samples_ i.e. inside the img filter. |
||
2379 | */ |
||
2380 | val = 0.25F * (k0 + k1 + k2 + k3); |
||
2381 | |||
2382 | /* XXX returning result for default GL_DEPTH_TEXTURE_MODE = GL_LUMINANCE */ |
||
2383 | for (j = 0; j < 4; j++) { |
||
2384 | rgba[0][j] = rgba[1][j] = rgba[2][j] = val; |
||
2385 | rgba[3][j] = 1.0F; |
||
2386 | } |
||
2387 | } else { |
||
2388 | for (j = 0; j < 4; j++) { |
||
2389 | rgba[0][j] = k0; |
||
2390 | rgba[1][j] = k1; |
||
2391 | rgba[2][j] = k2; |
||
2392 | rgba[3][j] = 1.0F; |
||
2393 | } |
||
2394 | } |
||
2395 | } |
||
2396 | |||
2397 | |||
2398 | static void |
||
2399 | do_swizzling(const struct pipe_sampler_view *sview, |
||
2400 | float in[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE], |
||
2401 | float out[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) |
||
2402 | { |
||
2403 | int j; |
||
2404 | const unsigned swizzle_r = sview->swizzle_r; |
||
2405 | const unsigned swizzle_g = sview->swizzle_g; |
||
2406 | const unsigned swizzle_b = sview->swizzle_b; |
||
2407 | const unsigned swizzle_a = sview->swizzle_a; |
||
2408 | |||
2409 | switch (swizzle_r) { |
||
2410 | case PIPE_SWIZZLE_ZERO: |
||
2411 | for (j = 0; j < 4; j++) |
||
2412 | out[0][j] = 0.0f; |
||
2413 | break; |
||
2414 | case PIPE_SWIZZLE_ONE: |
||
2415 | for (j = 0; j < 4; j++) |
||
2416 | out[0][j] = 1.0f; |
||
2417 | break; |
||
2418 | default: |
||
2419 | assert(swizzle_r < 4); |
||
2420 | for (j = 0; j < 4; j++) |
||
2421 | out[0][j] = in[swizzle_r][j]; |
||
2422 | } |
||
2423 | |||
2424 | switch (swizzle_g) { |
||
2425 | case PIPE_SWIZZLE_ZERO: |
||
2426 | for (j = 0; j < 4; j++) |
||
2427 | out[1][j] = 0.0f; |
||
2428 | break; |
||
2429 | case PIPE_SWIZZLE_ONE: |
||
2430 | for (j = 0; j < 4; j++) |
||
2431 | out[1][j] = 1.0f; |
||
2432 | break; |
||
2433 | default: |
||
2434 | assert(swizzle_g < 4); |
||
2435 | for (j = 0; j < 4; j++) |
||
2436 | out[1][j] = in[swizzle_g][j]; |
||
2437 | } |
||
2438 | |||
2439 | switch (swizzle_b) { |
||
2440 | case PIPE_SWIZZLE_ZERO: |
||
2441 | for (j = 0; j < 4; j++) |
||
2442 | out[2][j] = 0.0f; |
||
2443 | break; |
||
2444 | case PIPE_SWIZZLE_ONE: |
||
2445 | for (j = 0; j < 4; j++) |
||
2446 | out[2][j] = 1.0f; |
||
2447 | break; |
||
2448 | default: |
||
2449 | assert(swizzle_b < 4); |
||
2450 | for (j = 0; j < 4; j++) |
||
2451 | out[2][j] = in[swizzle_b][j]; |
||
2452 | } |
||
2453 | |||
2454 | switch (swizzle_a) { |
||
2455 | case PIPE_SWIZZLE_ZERO: |
||
2456 | for (j = 0; j < 4; j++) |
||
2457 | out[3][j] = 0.0f; |
||
2458 | break; |
||
2459 | case PIPE_SWIZZLE_ONE: |
||
2460 | for (j = 0; j < 4; j++) |
||
2461 | out[3][j] = 1.0f; |
||
2462 | break; |
||
2463 | default: |
||
2464 | assert(swizzle_a < 4); |
||
2465 | for (j = 0; j < 4; j++) |
||
2466 | out[3][j] = in[swizzle_a][j]; |
||
2467 | } |
||
2468 | } |
||
2469 | |||
2470 | |||
2471 | static wrap_nearest_func |
||
2472 | get_nearest_unorm_wrap(unsigned mode) |
||
2473 | { |
||
2474 | switch (mode) { |
||
2475 | case PIPE_TEX_WRAP_CLAMP: |
||
2476 | return wrap_nearest_unorm_clamp; |
||
2477 | case PIPE_TEX_WRAP_CLAMP_TO_EDGE: |
||
2478 | return wrap_nearest_unorm_clamp_to_edge; |
||
2479 | case PIPE_TEX_WRAP_CLAMP_TO_BORDER: |
||
2480 | return wrap_nearest_unorm_clamp_to_border; |
||
2481 | default: |
||
2482 | assert(0); |
||
2483 | return wrap_nearest_unorm_clamp; |
||
2484 | } |
||
2485 | } |
||
2486 | |||
2487 | |||
2488 | static wrap_nearest_func |
||
2489 | get_nearest_wrap(unsigned mode) |
||
2490 | { |
||
2491 | switch (mode) { |
||
2492 | case PIPE_TEX_WRAP_REPEAT: |
||
2493 | return wrap_nearest_repeat; |
||
2494 | case PIPE_TEX_WRAP_CLAMP: |
||
2495 | return wrap_nearest_clamp; |
||
2496 | case PIPE_TEX_WRAP_CLAMP_TO_EDGE: |
||
2497 | return wrap_nearest_clamp_to_edge; |
||
2498 | case PIPE_TEX_WRAP_CLAMP_TO_BORDER: |
||
2499 | return wrap_nearest_clamp_to_border; |
||
2500 | case PIPE_TEX_WRAP_MIRROR_REPEAT: |
||
2501 | return wrap_nearest_mirror_repeat; |
||
2502 | case PIPE_TEX_WRAP_MIRROR_CLAMP: |
||
2503 | return wrap_nearest_mirror_clamp; |
||
2504 | case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: |
||
2505 | return wrap_nearest_mirror_clamp_to_edge; |
||
2506 | case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: |
||
2507 | return wrap_nearest_mirror_clamp_to_border; |
||
2508 | default: |
||
2509 | assert(0); |
||
2510 | return wrap_nearest_repeat; |
||
2511 | } |
||
2512 | } |
||
2513 | |||
2514 | |||
2515 | static wrap_linear_func |
||
2516 | get_linear_unorm_wrap(unsigned mode) |
||
2517 | { |
||
2518 | switch (mode) { |
||
2519 | case PIPE_TEX_WRAP_CLAMP: |
||
2520 | return wrap_linear_unorm_clamp; |
||
2521 | case PIPE_TEX_WRAP_CLAMP_TO_EDGE: |
||
2522 | return wrap_linear_unorm_clamp_to_edge; |
||
2523 | case PIPE_TEX_WRAP_CLAMP_TO_BORDER: |
||
2524 | return wrap_linear_unorm_clamp_to_border; |
||
2525 | default: |
||
2526 | assert(0); |
||
2527 | return wrap_linear_unorm_clamp; |
||
2528 | } |
||
2529 | } |
||
2530 | |||
2531 | |||
2532 | static wrap_linear_func |
||
2533 | get_linear_wrap(unsigned mode) |
||
2534 | { |
||
2535 | switch (mode) { |
||
2536 | case PIPE_TEX_WRAP_REPEAT: |
||
2537 | return wrap_linear_repeat; |
||
2538 | case PIPE_TEX_WRAP_CLAMP: |
||
2539 | return wrap_linear_clamp; |
||
2540 | case PIPE_TEX_WRAP_CLAMP_TO_EDGE: |
||
2541 | return wrap_linear_clamp_to_edge; |
||
2542 | case PIPE_TEX_WRAP_CLAMP_TO_BORDER: |
||
2543 | return wrap_linear_clamp_to_border; |
||
2544 | case PIPE_TEX_WRAP_MIRROR_REPEAT: |
||
2545 | return wrap_linear_mirror_repeat; |
||
2546 | case PIPE_TEX_WRAP_MIRROR_CLAMP: |
||
2547 | return wrap_linear_mirror_clamp; |
||
2548 | case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: |
||
2549 | return wrap_linear_mirror_clamp_to_edge; |
||
2550 | case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: |
||
2551 | return wrap_linear_mirror_clamp_to_border; |
||
2552 | default: |
||
2553 | assert(0); |
||
2554 | return wrap_linear_repeat; |
||
2555 | } |
||
2556 | } |
||
2557 | |||
2558 | |||
2559 | /** |
||
2560 | * Is swizzling needed for the given state key? |
||
2561 | */ |
||
2562 | static INLINE bool |
||
2563 | any_swizzle(const struct pipe_sampler_view *view) |
||
2564 | { |
||
2565 | return (view->swizzle_r != PIPE_SWIZZLE_RED || |
||
2566 | view->swizzle_g != PIPE_SWIZZLE_GREEN || |
||
2567 | view->swizzle_b != PIPE_SWIZZLE_BLUE || |
||
2568 | view->swizzle_a != PIPE_SWIZZLE_ALPHA); |
||
2569 | } |
||
2570 | |||
2571 | |||
2572 | static img_filter_func |
||
2573 | get_img_filter(const struct sp_sampler_view *sp_sview, |
||
2574 | const struct pipe_sampler_state *sampler, |
||
2575 | unsigned filter) |
||
2576 | { |
||
2577 | switch (sp_sview->base.texture->target) { |
||
2578 | case PIPE_BUFFER: |
||
2579 | case PIPE_TEXTURE_1D: |
||
2580 | if (filter == PIPE_TEX_FILTER_NEAREST) |
||
2581 | return img_filter_1d_nearest; |
||
2582 | else |
||
2583 | return img_filter_1d_linear; |
||
2584 | break; |
||
2585 | case PIPE_TEXTURE_1D_ARRAY: |
||
2586 | if (filter == PIPE_TEX_FILTER_NEAREST) |
||
2587 | return img_filter_1d_array_nearest; |
||
2588 | else |
||
2589 | return img_filter_1d_array_linear; |
||
2590 | break; |
||
2591 | case PIPE_TEXTURE_2D: |
||
2592 | case PIPE_TEXTURE_RECT: |
||
2593 | /* Try for fast path: |
||
2594 | */ |
||
2595 | if (sp_sview->pot2d && |
||
2596 | sampler->wrap_s == sampler->wrap_t && |
||
2597 | sampler->normalized_coords) |
||
2598 | { |
||
2599 | switch (sampler->wrap_s) { |
||
2600 | case PIPE_TEX_WRAP_REPEAT: |
||
2601 | switch (filter) { |
||
2602 | case PIPE_TEX_FILTER_NEAREST: |
||
2603 | return img_filter_2d_nearest_repeat_POT; |
||
2604 | case PIPE_TEX_FILTER_LINEAR: |
||
2605 | return img_filter_2d_linear_repeat_POT; |
||
2606 | default: |
||
2607 | break; |
||
2608 | } |
||
2609 | break; |
||
2610 | case PIPE_TEX_WRAP_CLAMP: |
||
2611 | switch (filter) { |
||
2612 | case PIPE_TEX_FILTER_NEAREST: |
||
2613 | return img_filter_2d_nearest_clamp_POT; |
||
2614 | default: |
||
2615 | break; |
||
2616 | } |
||
2617 | } |
||
2618 | } |
||
2619 | /* Otherwise use default versions: |
||
2620 | */ |
||
2621 | if (filter == PIPE_TEX_FILTER_NEAREST) |
||
2622 | return img_filter_2d_nearest; |
||
2623 | else |
||
2624 | return img_filter_2d_linear; |
||
2625 | break; |
||
2626 | case PIPE_TEXTURE_2D_ARRAY: |
||
2627 | if (filter == PIPE_TEX_FILTER_NEAREST) |
||
2628 | return img_filter_2d_array_nearest; |
||
2629 | else |
||
2630 | return img_filter_2d_array_linear; |
||
2631 | break; |
||
2632 | case PIPE_TEXTURE_CUBE: |
||
2633 | if (filter == PIPE_TEX_FILTER_NEAREST) |
||
2634 | return img_filter_cube_nearest; |
||
2635 | else |
||
2636 | return img_filter_cube_linear; |
||
2637 | break; |
||
2638 | case PIPE_TEXTURE_CUBE_ARRAY: |
||
2639 | if (filter == PIPE_TEX_FILTER_NEAREST) |
||
2640 | return img_filter_cube_array_nearest; |
||
2641 | else |
||
2642 | return img_filter_cube_array_linear; |
||
2643 | break; |
||
2644 | case PIPE_TEXTURE_3D: |
||
2645 | if (filter == PIPE_TEX_FILTER_NEAREST) |
||
2646 | return img_filter_3d_nearest; |
||
2647 | else |
||
2648 | return img_filter_3d_linear; |
||
2649 | break; |
||
2650 | default: |
||
2651 | assert(0); |
||
2652 | return img_filter_1d_nearest; |
||
2653 | } |
||
2654 | } |
||
2655 | |||
2656 | |||
2657 | static void |
||
2658 | sample_mip(struct sp_sampler_view *sp_sview, |
||
2659 | struct sp_sampler *sp_samp, |
||
2660 | const float s[TGSI_QUAD_SIZE], |
||
2661 | const float t[TGSI_QUAD_SIZE], |
||
2662 | const float p[TGSI_QUAD_SIZE], |
||
2663 | const float c0[TGSI_QUAD_SIZE], |
||
2664 | const float lod[TGSI_QUAD_SIZE], |
||
2665 | enum tgsi_sampler_control control, |
||
2666 | float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) |
||
2667 | { |
||
2668 | mip_filter_func mip_filter; |
||
2669 | img_filter_func min_img_filter = NULL; |
||
2670 | img_filter_func mag_img_filter = NULL; |
||
2671 | |||
2672 | if (sp_sview->pot2d & sp_samp->min_mag_equal_repeat_linear) { |
||
2673 | mip_filter = mip_filter_linear_2d_linear_repeat_POT; |
||
2674 | } |
||
2675 | else { |
||
2676 | mip_filter = sp_samp->mip_filter; |
||
2677 | min_img_filter = get_img_filter(sp_sview, &sp_samp->base, sp_samp->min_img_filter); |
||
2678 | if (sp_samp->min_mag_equal) { |
||
2679 | mag_img_filter = min_img_filter; |
||
2680 | } |
||
2681 | else { |
||
2682 | mag_img_filter = get_img_filter(sp_sview, &sp_samp->base, sp_samp->base.mag_img_filter); |
||
2683 | } |
||
2684 | } |
||
2685 | |||
2686 | mip_filter(sp_sview, sp_samp, min_img_filter, mag_img_filter, |
||
2687 | s, t, p, c0, lod, control, rgba); |
||
2688 | |||
2689 | if (sp_samp->base.compare_mode != PIPE_TEX_COMPARE_NONE) { |
||
2690 | sample_compare(sp_sview, sp_samp, s, t, p, c0, lod, control, rgba); |
||
2691 | } |
||
2692 | |||
2693 | if (sp_sview->need_swizzle) { |
||
2694 | float rgba_temp[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]; |
||
2695 | memcpy(rgba_temp, rgba, sizeof(rgba_temp)); |
||
2696 | do_swizzling(&sp_sview->base, rgba_temp, rgba); |
||
2697 | } |
||
2698 | |||
2699 | } |
||
2700 | |||
2701 | |||
2702 | /** |
||
2703 | * Use 3D texcoords to choose a cube face, then sample the 2D cube faces. |
||
2704 | * Put face info into the sampler faces[] array. |
||
2705 | */ |
||
2706 | static void |
||
2707 | sample_cube(struct sp_sampler_view *sp_sview, |
||
2708 | struct sp_sampler *sp_samp, |
||
2709 | const float s[TGSI_QUAD_SIZE], |
||
2710 | const float t[TGSI_QUAD_SIZE], |
||
2711 | const float p[TGSI_QUAD_SIZE], |
||
2712 | const float c0[TGSI_QUAD_SIZE], |
||
2713 | const float c1[TGSI_QUAD_SIZE], |
||
2714 | enum tgsi_sampler_control control, |
||
2715 | float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) |
||
2716 | { |
||
2717 | unsigned j; |
||
2718 | float ssss[4], tttt[4]; |
||
2719 | |||
2720 | /* Not actually used, but the intermediate steps that do the |
||
2721 | * dereferencing don't know it. |
||
2722 | */ |
||
2723 | static float pppp[4] = { 0, 0, 0, 0 }; |
||
2724 | |||
2725 | pppp[0] = c0[0]; |
||
2726 | pppp[1] = c0[1]; |
||
2727 | pppp[2] = c0[2]; |
||
2728 | pppp[3] = c0[3]; |
||
2729 | /* |
||
2730 | major axis |
||
2731 | direction target sc tc ma |
||
2732 | ---------- ------------------------------- --- --- --- |
||
2733 | +rx TEXTURE_CUBE_MAP_POSITIVE_X_EXT -rz -ry rx |
||
2734 | -rx TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +rz -ry rx |
||
2735 | +ry TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +rx +rz ry |
||
2736 | -ry TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +rx -rz ry |
||
2737 | +rz TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +rx -ry rz |
||
2738 | -rz TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT -rx -ry rz |
||
2739 | */ |
||
2740 | |||
2741 | /* Choose the cube face and compute new s/t coords for the 2D face. |
||
2742 | * |
||
2743 | * Use the same cube face for all four pixels in the quad. |
||
2744 | * |
||
2745 | * This isn't ideal, but if we want to use a different cube face |
||
2746 | * per pixel in the quad, we'd have to also compute the per-face |
||
2747 | * LOD here too. That's because the four post-face-selection |
||
2748 | * texcoords are no longer related to each other (they're |
||
2749 | * per-face!) so we can't use subtraction to compute the partial |
||
2750 | * deriviates to compute the LOD. Doing so (near cube edges |
||
2751 | * anyway) gives us pretty much random values. |
||
2752 | */ |
||
2753 | { |
||
2754 | /* use the average of the four pixel's texcoords to choose the face */ |
||
2755 | const float rx = 0.25F * (s[0] + s[1] + s[2] + s[3]); |
||
2756 | const float ry = 0.25F * (t[0] + t[1] + t[2] + t[3]); |
||
2757 | const float rz = 0.25F * (p[0] + p[1] + p[2] + p[3]); |
||
2758 | const float arx = fabsf(rx), ary = fabsf(ry), arz = fabsf(rz); |
||
2759 | |||
2760 | if (arx >= ary && arx >= arz) { |
||
2761 | float sign = (rx >= 0.0F) ? 1.0F : -1.0F; |
||
2762 | uint face = (rx >= 0.0F) ? PIPE_TEX_FACE_POS_X : PIPE_TEX_FACE_NEG_X; |
||
2763 | for (j = 0; j < TGSI_QUAD_SIZE; j++) { |
||
2764 | const float ima = -0.5F / fabsf(s[j]); |
||
2765 | ssss[j] = sign * p[j] * ima + 0.5F; |
||
2766 | tttt[j] = t[j] * ima + 0.5F; |
||
2767 | sp_sview->faces[j] = face; |
||
2768 | } |
||
2769 | } |
||
2770 | else if (ary >= arx && ary >= arz) { |
||
2771 | float sign = (ry >= 0.0F) ? 1.0F : -1.0F; |
||
2772 | uint face = (ry >= 0.0F) ? PIPE_TEX_FACE_POS_Y : PIPE_TEX_FACE_NEG_Y; |
||
2773 | for (j = 0; j < TGSI_QUAD_SIZE; j++) { |
||
2774 | const float ima = -0.5F / fabsf(t[j]); |
||
2775 | ssss[j] = -s[j] * ima + 0.5F; |
||
2776 | tttt[j] = sign * -p[j] * ima + 0.5F; |
||
2777 | sp_sview->faces[j] = face; |
||
2778 | } |
||
2779 | } |
||
2780 | else { |
||
2781 | float sign = (rz >= 0.0F) ? 1.0F : -1.0F; |
||
2782 | uint face = (rz >= 0.0F) ? PIPE_TEX_FACE_POS_Z : PIPE_TEX_FACE_NEG_Z; |
||
2783 | for (j = 0; j < TGSI_QUAD_SIZE; j++) { |
||
2784 | const float ima = -0.5F / fabsf(p[j]); |
||
2785 | ssss[j] = sign * -s[j] * ima + 0.5F; |
||
2786 | tttt[j] = t[j] * ima + 0.5F; |
||
2787 | sp_sview->faces[j] = face; |
||
2788 | } |
||
2789 | } |
||
2790 | } |
||
2791 | |||
2792 | sample_mip(sp_sview, sp_samp, ssss, tttt, pppp, c0, c1, control, rgba); |
||
2793 | } |
||
2794 | |||
2795 | |||
2796 | static void |
||
2797 | sp_get_dims(struct sp_sampler_view *sp_sview, int level, |
||
2798 | int dims[4]) |
||
2799 | { |
||
2800 | const struct pipe_sampler_view *view = &sp_sview->base; |
||
2801 | const struct pipe_resource *texture = view->texture; |
||
2802 | |||
2803 | /* undefined according to EXT_gpu_program */ |
||
2804 | level += view->u.tex.first_level; |
||
2805 | if (level > view->u.tex.last_level) |
||
2806 | return; |
||
2807 | |||
2808 | dims[0] = u_minify(texture->width0, level); |
||
2809 | |||
2810 | switch(texture->target) { |
||
2811 | case PIPE_TEXTURE_1D_ARRAY: |
||
2812 | dims[1] = view->u.tex.last_layer - view->u.tex.first_layer + 1; |
||
2813 | /* fallthrough */ |
||
2814 | case PIPE_TEXTURE_1D: |
||
2815 | return; |
||
2816 | case PIPE_TEXTURE_2D_ARRAY: |
||
2817 | dims[2] = view->u.tex.last_layer - view->u.tex.first_layer + 1; |
||
2818 | /* fallthrough */ |
||
2819 | case PIPE_TEXTURE_2D: |
||
2820 | case PIPE_TEXTURE_CUBE: |
||
2821 | case PIPE_TEXTURE_RECT: |
||
2822 | dims[1] = u_minify(texture->height0, level); |
||
2823 | return; |
||
2824 | case PIPE_TEXTURE_3D: |
||
2825 | dims[1] = u_minify(texture->height0, level); |
||
2826 | dims[2] = u_minify(texture->depth0, level); |
||
2827 | return; |
||
2828 | case PIPE_TEXTURE_CUBE_ARRAY: |
||
2829 | dims[1] = u_minify(texture->height0, level); |
||
2830 | dims[2] = (view->u.tex.last_layer - view->u.tex.first_layer + 1) / 6; |
||
2831 | break; |
||
2832 | case PIPE_BUFFER: |
||
2833 | dims[0] /= util_format_get_blocksize(view->format); |
||
2834 | return; |
||
2835 | default: |
||
2836 | assert(!"unexpected texture target in sp_get_dims()"); |
||
2837 | return; |
||
2838 | } |
||
2839 | } |
||
2840 | |||
2841 | /** |
||
2842 | * This function is only used for getting unfiltered texels via the |
||
2843 | * TXF opcode. The GL spec says that out-of-bounds texel fetches |
||
2844 | * produce undefined results. Instead of crashing, lets just clamp |
||
2845 | * coords to the texture image size. |
||
2846 | */ |
||
2847 | static void |
||
2848 | sp_get_texels(struct sp_sampler_view *sp_sview, |
||
2849 | const int v_i[TGSI_QUAD_SIZE], |
||
2850 | const int v_j[TGSI_QUAD_SIZE], |
||
2851 | const int v_k[TGSI_QUAD_SIZE], |
||
2852 | const int lod[TGSI_QUAD_SIZE], |
||
2853 | const int8_t offset[3], |
||
2854 | float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) |
||
2855 | { |
||
2856 | union tex_tile_address addr; |
||
2857 | const struct pipe_resource *texture = sp_sview->base.texture; |
||
2858 | int j, c; |
||
2859 | const float *tx; |
||
2860 | int width, height, depth; |
||
2861 | |||
2862 | addr.value = 0; |
||
2863 | /* TODO write a better test for LOD */ |
||
2864 | addr.bits.level = lod[0]; |
||
2865 | |||
2866 | width = u_minify(texture->width0, addr.bits.level); |
||
2867 | height = u_minify(texture->height0, addr.bits.level); |
||
2868 | depth = u_minify(texture->depth0, addr.bits.level); |
||
2869 | |||
2870 | switch(texture->target) { |
||
2871 | case PIPE_BUFFER: |
||
2872 | case PIPE_TEXTURE_1D: |
||
2873 | for (j = 0; j < TGSI_QUAD_SIZE; j++) { |
||
2874 | int x = CLAMP(v_i[j] + offset[0], 0, width - 1); |
||
2875 | tx = get_texel_2d_no_border(sp_sview, addr, x, 0); |
||
2876 | for (c = 0; c < 4; c++) { |
||
2877 | rgba[c][j] = tx[c]; |
||
2878 | } |
||
2879 | } |
||
2880 | break; |
||
2881 | case PIPE_TEXTURE_1D_ARRAY: |
||
2882 | for (j = 0; j < TGSI_QUAD_SIZE; j++) { |
||
2883 | int x = CLAMP(v_i[j] + offset[0], 0, width - 1); |
||
2884 | int y = CLAMP(v_j[j], sp_sview->base.u.tex.first_layer, sp_sview->base.u.tex.last_layer); |
||
2885 | tx = get_texel_2d_no_border(sp_sview, addr, x, y); |
||
2886 | for (c = 0; c < 4; c++) { |
||
2887 | rgba[c][j] = tx[c]; |
||
2888 | } |
||
2889 | } |
||
2890 | break; |
||
2891 | case PIPE_TEXTURE_2D: |
||
2892 | case PIPE_TEXTURE_RECT: |
||
2893 | for (j = 0; j < TGSI_QUAD_SIZE; j++) { |
||
2894 | int x = CLAMP(v_i[j] + offset[0], 0, width - 1); |
||
2895 | int y = CLAMP(v_j[j] + offset[1], 0, height - 1); |
||
2896 | tx = get_texel_2d_no_border(sp_sview, addr, x, y); |
||
2897 | for (c = 0; c < 4; c++) { |
||
2898 | rgba[c][j] = tx[c]; |
||
2899 | } |
||
2900 | } |
||
2901 | break; |
||
2902 | case PIPE_TEXTURE_2D_ARRAY: |
||
2903 | for (j = 0; j < TGSI_QUAD_SIZE; j++) { |
||
2904 | int x = CLAMP(v_i[j] + offset[0], 0, width - 1); |
||
2905 | int y = CLAMP(v_j[j] + offset[1], 0, height - 1); |
||
2906 | int layer = CLAMP(v_k[j], sp_sview->base.u.tex.first_layer, sp_sview->base.u.tex.last_layer); |
||
2907 | tx = get_texel_3d_no_border(sp_sview, addr, x, y, layer); |
||
2908 | for (c = 0; c < 4; c++) { |
||
2909 | rgba[c][j] = tx[c]; |
||
2910 | } |
||
2911 | } |
||
2912 | break; |
||
2913 | case PIPE_TEXTURE_3D: |
||
2914 | for (j = 0; j < TGSI_QUAD_SIZE; j++) { |
||
2915 | int x = CLAMP(v_i[j] + offset[0], 0, width - 1); |
||
2916 | int y = CLAMP(v_j[j] + offset[1], 0, height - 1); |
||
2917 | int z = CLAMP(v_k[j] + offset[2], 0, depth - 1); |
||
2918 | tx = get_texel_3d_no_border(sp_sview, addr, x, y, z); |
||
2919 | for (c = 0; c < 4; c++) { |
||
2920 | rgba[c][j] = tx[c]; |
||
2921 | } |
||
2922 | } |
||
2923 | break; |
||
2924 | case PIPE_TEXTURE_CUBE: /* TXF can't work on CUBE according to spec */ |
||
2925 | default: |
||
2926 | assert(!"Unknown or CUBE texture type in TXF processing\n"); |
||
2927 | break; |
||
2928 | } |
||
2929 | |||
2930 | if (sp_sview->need_swizzle) { |
||
2931 | float rgba_temp[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]; |
||
2932 | memcpy(rgba_temp, rgba, sizeof(rgba_temp)); |
||
2933 | do_swizzling(&sp_sview->base, rgba_temp, rgba); |
||
2934 | } |
||
2935 | } |
||
2936 | |||
2937 | |||
2938 | void * |
||
2939 | softpipe_create_sampler_state(struct pipe_context *pipe, |
||
2940 | const struct pipe_sampler_state *sampler) |
||
2941 | { |
||
2942 | struct sp_sampler *samp = CALLOC_STRUCT(sp_sampler); |
||
2943 | |||
2944 | samp->base = *sampler; |
||
2945 | |||
2946 | /* Note that (for instance) linear_texcoord_s and |
||
2947 | * nearest_texcoord_s may be active at the same time, if the |
||
2948 | * sampler min_img_filter differs from its mag_img_filter. |
||
2949 | */ |
||
2950 | if (sampler->normalized_coords) { |
||
2951 | samp->linear_texcoord_s = get_linear_wrap( sampler->wrap_s ); |
||
2952 | samp->linear_texcoord_t = get_linear_wrap( sampler->wrap_t ); |
||
2953 | samp->linear_texcoord_p = get_linear_wrap( sampler->wrap_r ); |
||
2954 | |||
2955 | samp->nearest_texcoord_s = get_nearest_wrap( sampler->wrap_s ); |
||
2956 | samp->nearest_texcoord_t = get_nearest_wrap( sampler->wrap_t ); |
||
2957 | samp->nearest_texcoord_p = get_nearest_wrap( sampler->wrap_r ); |
||
2958 | } |
||
2959 | else { |
||
2960 | samp->linear_texcoord_s = get_linear_unorm_wrap( sampler->wrap_s ); |
||
2961 | samp->linear_texcoord_t = get_linear_unorm_wrap( sampler->wrap_t ); |
||
2962 | samp->linear_texcoord_p = get_linear_unorm_wrap( sampler->wrap_r ); |
||
2963 | |||
2964 | samp->nearest_texcoord_s = get_nearest_unorm_wrap( sampler->wrap_s ); |
||
2965 | samp->nearest_texcoord_t = get_nearest_unorm_wrap( sampler->wrap_t ); |
||
2966 | samp->nearest_texcoord_p = get_nearest_unorm_wrap( sampler->wrap_r ); |
||
2967 | } |
||
2968 | |||
2969 | samp->min_img_filter = sampler->min_img_filter; |
||
2970 | |||
2971 | switch (sampler->min_mip_filter) { |
||
2972 | case PIPE_TEX_MIPFILTER_NONE: |
||
2973 | if (sampler->min_img_filter == sampler->mag_img_filter) |
||
2974 | samp->mip_filter = mip_filter_none_no_filter_select; |
||
2975 | else |
||
2976 | samp->mip_filter = mip_filter_none; |
||
2977 | break; |
||
2978 | |||
2979 | case PIPE_TEX_MIPFILTER_NEAREST: |
||
2980 | samp->mip_filter = mip_filter_nearest; |
||
2981 | break; |
||
2982 | |||
2983 | case PIPE_TEX_MIPFILTER_LINEAR: |
||
2984 | if (sampler->min_img_filter == sampler->mag_img_filter && |
||
2985 | sampler->normalized_coords && |
||
2986 | sampler->wrap_s == PIPE_TEX_WRAP_REPEAT && |
||
2987 | sampler->wrap_t == PIPE_TEX_WRAP_REPEAT && |
||
2988 | sampler->min_img_filter == PIPE_TEX_FILTER_LINEAR && |
||
2989 | sampler->max_anisotropy <= 1) { |
||
2990 | samp->min_mag_equal_repeat_linear = TRUE; |
||
2991 | } |
||
2992 | samp->mip_filter = mip_filter_linear; |
||
2993 | |||
2994 | /* Anisotropic filtering extension. */ |
||
2995 | if (sampler->max_anisotropy > 1) { |
||
2996 | samp->mip_filter = mip_filter_linear_aniso; |
||
2997 | |||
2998 | /* Override min_img_filter: |
||
2999 | * min_img_filter needs to be set to NEAREST since we need to access |
||
3000 | * each texture pixel as it is and weight it later; using linear |
||
3001 | * filters will have incorrect results. |
||
3002 | * By setting the filter to NEAREST here, we can avoid calling the |
||
3003 | * generic img_filter_2d_nearest in the anisotropic filter function, |
||
3004 | * making it possible to use one of the accelerated implementations |
||
3005 | */ |
||
3006 | samp->min_img_filter = PIPE_TEX_FILTER_NEAREST; |
||
3007 | |||
3008 | /* on first access create the lookup table containing the filter weights. */ |
||
3009 | if (!weightLut) { |
||
3010 | create_filter_table(); |
||
3011 | } |
||
3012 | } |
||
3013 | break; |
||
3014 | } |
||
3015 | if (samp->min_img_filter == sampler->mag_img_filter) { |
||
3016 | samp->min_mag_equal = TRUE; |
||
3017 | } |
||
3018 | |||
3019 | return (void *)samp; |
||
3020 | } |
||
3021 | |||
3022 | |||
3023 | compute_lambda_func |
||
3024 | softpipe_get_lambda_func(const struct pipe_sampler_view *view, unsigned shader) |
||
3025 | { |
||
3026 | if (shader != PIPE_SHADER_FRAGMENT) |
||
3027 | return compute_lambda_vert; |
||
3028 | |||
3029 | switch (view->texture->target) { |
||
3030 | case PIPE_BUFFER: |
||
3031 | case PIPE_TEXTURE_1D: |
||
3032 | case PIPE_TEXTURE_1D_ARRAY: |
||
3033 | return compute_lambda_1d; |
||
3034 | case PIPE_TEXTURE_2D: |
||
3035 | case PIPE_TEXTURE_2D_ARRAY: |
||
3036 | case PIPE_TEXTURE_RECT: |
||
3037 | case PIPE_TEXTURE_CUBE: |
||
3038 | case PIPE_TEXTURE_CUBE_ARRAY: |
||
3039 | return compute_lambda_2d; |
||
3040 | case PIPE_TEXTURE_3D: |
||
3041 | return compute_lambda_3d; |
||
3042 | default: |
||
3043 | assert(0); |
||
3044 | return compute_lambda_1d; |
||
3045 | } |
||
3046 | } |
||
3047 | |||
3048 | |||
3049 | struct pipe_sampler_view * |
||
3050 | softpipe_create_sampler_view(struct pipe_context *pipe, |
||
3051 | struct pipe_resource *resource, |
||
3052 | const struct pipe_sampler_view *templ) |
||
3053 | { |
||
3054 | struct sp_sampler_view *sview = CALLOC_STRUCT(sp_sampler_view); |
||
3055 | struct softpipe_resource *spr = (struct softpipe_resource *)resource; |
||
3056 | |||
3057 | if (sview) { |
||
3058 | struct pipe_sampler_view *view = &sview->base; |
||
3059 | *view = *templ; |
||
3060 | view->reference.count = 1; |
||
3061 | view->texture = NULL; |
||
3062 | pipe_resource_reference(&view->texture, resource); |
||
3063 | view->context = pipe; |
||
3064 | |||
3065 | if (any_swizzle(view)) { |
||
3066 | sview->need_swizzle = TRUE; |
||
3067 | } |
||
3068 | |||
3069 | if (resource->target == PIPE_TEXTURE_CUBE || |
||
3070 | resource->target == PIPE_TEXTURE_CUBE_ARRAY) |
||
3071 | sview->get_samples = sample_cube; |
||
3072 | else { |
||
3073 | sview->get_samples = sample_mip; |
||
3074 | } |
||
3075 | sview->pot2d = spr->pot && |
||
3076 | (resource->target == PIPE_TEXTURE_2D || |
||
3077 | resource->target == PIPE_TEXTURE_RECT); |
||
3078 | |||
3079 | sview->xpot = util_logbase2( resource->width0 ); |
||
3080 | sview->ypot = util_logbase2( resource->height0 ); |
||
3081 | } |
||
3082 | |||
3083 | return (struct pipe_sampler_view *) sview; |
||
3084 | } |
||
3085 | |||
3086 | |||
3087 | static void |
||
3088 | sp_tgsi_get_dims(struct tgsi_sampler *tgsi_sampler, |
||
3089 | const unsigned sview_index, |
||
3090 | int level, int dims[4]) |
||
3091 | { |
||
3092 | struct sp_tgsi_sampler *sp_samp = (struct sp_tgsi_sampler *)tgsi_sampler; |
||
3093 | |||
3094 | assert(sview_index < PIPE_MAX_SHADER_SAMPLER_VIEWS); |
||
3095 | /* TODO should have defined behavior if no texture is bound. */ |
||
3096 | sp_get_dims(&sp_samp->sp_sview[sview_index], level, dims); |
||
3097 | } |
||
3098 | |||
3099 | |||
3100 | static void |
||
3101 | sp_tgsi_get_samples(struct tgsi_sampler *tgsi_sampler, |
||
3102 | const unsigned sview_index, |
||
3103 | const unsigned sampler_index, |
||
3104 | const float s[TGSI_QUAD_SIZE], |
||
3105 | const float t[TGSI_QUAD_SIZE], |
||
3106 | const float p[TGSI_QUAD_SIZE], |
||
3107 | const float c0[TGSI_QUAD_SIZE], |
||
3108 | const float lod[TGSI_QUAD_SIZE], |
||
3109 | float derivs[3][2][TGSI_QUAD_SIZE], |
||
3110 | const int8_t offset[3], |
||
3111 | enum tgsi_sampler_control control, |
||
3112 | float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) |
||
3113 | { |
||
3114 | struct sp_tgsi_sampler *sp_samp = (struct sp_tgsi_sampler *)tgsi_sampler; |
||
3115 | |||
3116 | assert(sview_index < PIPE_MAX_SHADER_SAMPLER_VIEWS); |
||
3117 | assert(sampler_index < PIPE_MAX_SAMPLERS); |
||
3118 | assert(sp_samp->sp_sampler[sampler_index]); |
||
3119 | /* FIXME should have defined behavior if no texture is bound. */ |
||
3120 | assert(sp_samp->sp_sview[sview_index].get_samples); |
||
3121 | sp_samp->sp_sview[sview_index].get_samples(&sp_samp->sp_sview[sview_index], |
||
3122 | sp_samp->sp_sampler[sampler_index], |
||
3123 | s, t, p, c0, lod, control, rgba); |
||
3124 | } |
||
3125 | |||
3126 | |||
3127 | static void |
||
3128 | sp_tgsi_get_texel(struct tgsi_sampler *tgsi_sampler, |
||
3129 | const unsigned sview_index, |
||
3130 | const int i[TGSI_QUAD_SIZE], |
||
3131 | const int j[TGSI_QUAD_SIZE], const int k[TGSI_QUAD_SIZE], |
||
3132 | const int lod[TGSI_QUAD_SIZE], const int8_t offset[3], |
||
3133 | float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) |
||
3134 | { |
||
3135 | struct sp_tgsi_sampler *sp_samp = (struct sp_tgsi_sampler *)tgsi_sampler; |
||
3136 | |||
3137 | assert(sview_index < PIPE_MAX_SHADER_SAMPLER_VIEWS); |
||
3138 | /* FIXME should have defined behavior if no texture is bound. */ |
||
3139 | assert(sp_samp->sp_sview[sview_index].base.texture); |
||
3140 | sp_get_texels(&sp_samp->sp_sview[sview_index], i, j, k, lod, offset, rgba); |
||
3141 | } |
||
3142 | |||
3143 | |||
3144 | struct sp_tgsi_sampler * |
||
3145 | sp_create_tgsi_sampler(void) |
||
3146 | { |
||
3147 | struct sp_tgsi_sampler *samp = CALLOC_STRUCT(sp_tgsi_sampler); |
||
3148 | if (!samp) |
||
3149 | return NULL; |
||
3150 | |||
3151 | samp->base.get_dims = sp_tgsi_get_dims; |
||
3152 | samp->base.get_samples = sp_tgsi_get_samples; |
||
3153 | samp->base.get_texel = sp_tgsi_get_texel; |
||
3154 | |||
3155 | return samp; |
||
3156 | }>>>>=>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>=>=>=>=>>>>>>>>>>=>>>>=>=>>><>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><>>>>>>>>>>>>>>>>>>>>>>>>=>>>>>>=>>=>>=> |
||
3157 |