Home | History | Annotate | Line # | Download | only in llvmpipe
      1 /**************************************************************************
      2  *
      3  * Copyright 2010-2021 VMware, Inc.
      4  * All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the
      8  * "Software"), to deal in the Software without restriction, including
      9  * without limitation the rights to use, copy, modify, merge, publish,
     10  * distribute, sub license, and/or sell copies of the Software, and to
     11  * permit persons to whom the Software is furnished to do so, subject to
     12  * the following conditions:
     13  *
     14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
     17  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
     18  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
     19  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
     20  * USE OR OTHER DEALINGS IN THE SOFTWARE.
     21  *
     22  * The above copyright notice and this permission notice (including the
     23  * next paragraph) shall be included in all copies or substantial portions
     24  * of the Software.
     25  *
     26  **************************************************************************/
     27 
     28 
     29 #include "pipe/p_config.h"
     30 
     31 #include "util/u_math.h"
     32 #include "util/u_cpu_detect.h"
     33 #include "util/u_pack_color.h"
     34 #include "util/u_rect.h"
     35 #include "util/u_sse.h"
     36 
     37 #include "lp_jit.h"
     38 #include "lp_debug.h"
     39 #include "lp_state_fs.h"
     40 #include "lp_linear_priv.h"
     41 
     42 #if defined(PIPE_ARCH_SSE)
     43 
     44 #define FIXED16_SHIFT  16
     45 #define FIXED16_ONE    (1<<16)
     46 #define FIXED16_HALF   (1<<15)
     47 
     48 /*
     49  * Color tolerance.  Allow 1 bit of error in 8 bit unorm colors.
     50  */
     51 #define FIXED16_TOL (FIXED16_ONE >> 7)
     52 
     53 /*
     54  * Tolerance for texture coordinate derivatives when doing linear filtering.
     55  *
     56  * (Note that extra care needs to be taken when doing linear filtering as
     57  * coordinates may snap up to neighbour texels inside the tile).
     58  */
     59 #define FIXED16_TOL_DERIV (FIXED16_TOL / TILE_SIZE)
     60 
     61 static inline int
     62 float_to_fixed16(float f)
     63 {
     64    return f * (float)FIXED16_ONE;
     65 }
     66 
     67 static inline int
     68 fixed16_frac(int x)
     69 {
     70    return x & (FIXED16_ONE - 1);
     71 }
     72 
     73 static inline int
     74 fixed16_approx(int x, int y, int tol)
     75 {
     76    return y - tol <= x && x <= y + tol;
     77 }
     78 
     79 
     80 /*
     81  * Unstretched blit of a bgra texture.
     82  */
     83 static const uint32_t *
     84 fetch_bgra_memcpy(struct lp_linear_elem *elem)
     85 {
     86    struct lp_linear_sampler *samp = (struct lp_linear_sampler *)elem;
     87    const struct lp_jit_texture *texture = samp->texture;
     88    const uint32_t *src_row =
     89       (const uint32_t *)((const uint8_t *)texture->base +
     90                          (samp->t >> FIXED16_SHIFT) * texture->row_stride[0]);
     91    const int s     = samp->s;
     92    const int width = samp->width;
     93    const uint32_t *row;
     94 
     95    src_row = &src_row[s >> FIXED16_SHIFT];
     96 
     97    if (((uintptr_t)src_row & 0xf) == 0) {
     98       /* The source texels are already aligned. Return them */
     99       row = src_row;
    100    } else {
    101       memcpy(samp->row, src_row, width * sizeof *row);
    102       row = samp->row;
    103    }
    104 
    105    samp->t += samp->dtdy;
    106    return row;
    107 }
    108 
    109 
    110 /*
    111  * Unstretched blit of a bgrx texture.
    112  */
    113 static const uint32_t *
    114 fetch_bgrx_memcpy(struct lp_linear_elem *elem)
    115 {
    116    struct lp_linear_sampler *samp = (struct lp_linear_sampler *)elem;
    117    const struct lp_jit_texture *texture = samp->texture;
    118    const uint32_t *src_row =
    119       (const uint32_t *)((const uint8_t *)texture->base +
    120                          (samp->t >> FIXED16_SHIFT) * texture->row_stride[0]);
    121    const int s     = samp->s;
    122    const int width = samp->width;
    123    uint32_t *row   = samp->row;
    124    int i;
    125 
    126    src_row = &src_row[s >> FIXED16_SHIFT];
    127 
    128    for (i = 0; i < width; i++) {
    129       row[i] = src_row[i] | 0xff000000;
    130    }
    131 
    132    samp->t += samp->dtdy;
    133    return row;
    134 }
    135 
    136 
    137 /*
    138  * Perform nearest filtered lookup of a row of texels.  Texture lookup
    139  * is assumed to be axis aligned but with arbitrary scaling.
    140  *
    141  * Texture coordinate interpolation is performed in 16.16 fixed point,
    142  * not to be confused with the 1.15 format used by the interpolants.
    143  *
    144  * After 64 pixels (ie. in the next tile), the starting point will be
    145  * recalculated with floating point arithmetic.
    146  */
    147 static const uint32_t *
    148 fetch_bgra_axis_aligned(struct lp_linear_elem *elem)
    149 {
    150    struct lp_linear_sampler *samp = (struct lp_linear_sampler *)elem;
    151    const struct lp_jit_texture *texture = samp->texture;
    152    const uint32_t *src_row =
    153       (const uint32_t *)((const uint8_t *)texture->base +
    154                          (samp->t >> FIXED16_SHIFT) * texture->row_stride[0]);
    155    const int dsdx  = samp->dsdx;
    156    const int width = samp->width;
    157    uint32_t *row   = samp->row;
    158    int s = samp->s;
    159    int i;
    160 
    161    for (i = 0; i < width; i++) {
    162       row[i] = src_row[s>>FIXED16_SHIFT];
    163       s += dsdx;
    164    }
    165 
    166    samp->t += samp->dtdy;
    167    return row;
    168 }
    169 
    170 static const uint32_t *
    171 fetch_bgrx_axis_aligned(struct lp_linear_elem *elem)
    172 {
    173    struct lp_linear_sampler *samp = (struct lp_linear_sampler *)elem;
    174    const struct lp_jit_texture *texture = samp->texture;
    175    const uint32_t *src_row =
    176       (const uint32_t *)((const uint8_t *)texture->base +
    177                          (samp->t >> FIXED16_SHIFT) * texture->row_stride[0]);
    178    const int dsdx  = samp->dsdx;
    179    const int width = samp->width;
    180    uint32_t *row   = samp->row;
    181    int s = samp->s;
    182    int i;
    183 
    184    for (i = 0; i < width; i++) {
    185       row[i] = src_row[s>>FIXED16_SHIFT] | 0xff000000;
    186       s += dsdx;
    187    }
    188 
    189    samp->t += samp->dtdy;
    190    return row;
    191 }
    192 
    193 /* Non-axis aligned, but no clamping or wrapping required
    194  */
    195 static const uint32_t *
    196 fetch_bgra(struct lp_linear_elem *elem)
    197 {
    198    struct lp_linear_sampler *samp = (struct lp_linear_sampler *)elem;
    199    const struct lp_jit_texture *texture = samp->texture;
    200    const uint8_t *src = texture->base;
    201    const int stride = texture->row_stride[0];
    202    const int dsdx  = samp->dsdx;
    203    const int dtdx  = samp->dtdx;
    204    const int width = samp->width;
    205    uint32_t *row   = samp->row;
    206    int s = samp->s;
    207    int t = samp->t;
    208    int i;
    209 
    210    for (i = 0; i < width; i++) {
    211       const uint8_t *texel = (src +
    212                               (t>>FIXED16_SHIFT) * stride +
    213                               (s>>FIXED16_SHIFT) * 4);
    214 
    215       row[i] = *(const uint32_t *)texel;
    216 
    217       s += dsdx;
    218       t += dtdx;
    219    }
    220 
    221    samp->s += samp->dsdy;
    222    samp->t += samp->dtdy;
    223    return row;
    224 }
    225 
    226 
    227 static const uint32_t *
    228 fetch_bgrx(struct lp_linear_elem *elem)
    229 {
    230    struct lp_linear_sampler *samp = (struct lp_linear_sampler *)elem;
    231    const struct lp_jit_texture *texture = samp->texture;
    232    const uint8_t *src = texture->base;
    233    const int stride = texture->row_stride[0];
    234    const int dsdx  = samp->dsdx;
    235    const int dtdx  = samp->dtdx;
    236    const int width = samp->width;
    237    uint32_t *row   = samp->row;
    238    int s = samp->s;
    239    int t = samp->t;
    240    int i;
    241 
    242    for (i = 0; i < width; i++) {
    243       const uint8_t *texel = (src +
    244                               (t>>FIXED16_SHIFT) * stride +
    245                               (s>>FIXED16_SHIFT) * 4);
    246 
    247       row[i] = (*(const uint32_t *)texel) | 0xff000000;
    248 
    249       s += dsdx;
    250       t += dtdx;
    251    }
    252 
    253    samp->s += samp->dsdy;
    254    samp->t += samp->dtdy;
    255    return row;
    256 }
    257 
    258 /* Non-axis aligned, clamped.
    259  */
    260 static const uint32_t *
    261 fetch_bgra_clamp(struct lp_linear_elem *elem)
    262 {
    263    struct lp_linear_sampler *samp = (struct lp_linear_sampler *)elem;
    264    const struct lp_jit_texture *texture = samp->texture;
    265    const uint8_t *src   = texture->base;
    266    const int stride     = texture->row_stride[0];
    267    const int tex_height = texture->height - 1;
    268    const int tex_width  = texture->width - 1;
    269    const int dsdx  = samp->dsdx;
    270    const int dtdx  = samp->dtdx;
    271    const int width = samp->width;
    272    uint32_t *row   = samp->row;
    273    int s = samp->s;
    274    int t = samp->t;
    275    int i;
    276 
    277    for (i = 0; i < width; i++) {
    278       int ct = CLAMP(t>>FIXED16_SHIFT, 0, tex_height);
    279       int cs = CLAMP(s>>FIXED16_SHIFT, 0, tex_width);
    280 
    281       const uint8_t *texel = (src +
    282                               ct * stride +
    283                               cs * 4);
    284 
    285       row[i] = *(const uint32_t *)texel;
    286 
    287       s += dsdx;
    288       t += dtdx;
    289    }
    290 
    291    samp->s += samp->dsdy;
    292    samp->t += samp->dtdy;
    293    return row;
    294 }
    295 
    296 static const uint32_t *
    297 fetch_bgrx_clamp(struct lp_linear_elem *elem)
    298 {
    299    struct lp_linear_sampler *samp = (struct lp_linear_sampler *)elem;
    300    const struct lp_jit_texture *texture = samp->texture;
    301    const uint8_t *src   = texture->base;
    302    const int stride     = texture->row_stride[0];
    303    const int tex_height = texture->height - 1;
    304    const int tex_width  = texture->width - 1;
    305    const int dsdx  = samp->dsdx;
    306    const int dtdx  = samp->dtdx;
    307    const int width = samp->width;
    308    uint32_t *row   = samp->row;
    309    int s = samp->s;
    310    int t = samp->t;
    311    int i;
    312 
    313    for (i = 0; i < width; i++) {
    314       int ct = CLAMP(t>>FIXED16_SHIFT, 0, tex_height);
    315       int cs = CLAMP(s>>FIXED16_SHIFT, 0, tex_width);
    316 
    317       const uint8_t *texel = (src +
    318                               ct * stride +
    319                               cs * 4);
    320 
    321       row[i] = (*(const uint32_t *)texel) | 0xff000000;
    322 
    323       s += dsdx;
    324       t += dtdx;
    325    }
    326 
    327    samp->s += samp->dsdy;
    328    samp->t += samp->dtdy;
    329    return row;
    330 }
    331 
    332 /**
    333  * Fetch and stretch one row.
    334  */
    335 static inline const uint32_t *
    336 fetch_and_stretch_bgra_row(struct lp_linear_sampler *samp,
    337                            int y)
    338 {
    339    const struct lp_jit_texture *texture = samp->texture;
    340    const uint32_t *data = (const uint32_t *)texture->base;
    341    const int stride = texture->row_stride[0] / sizeof(uint32_t);
    342    const uint32_t * restrict src_row;
    343    uint32_t * restrict dst_row;
    344    const int width = samp->width;
    345 
    346    /*
    347     * Search the stretched row cache first.
    348     */
    349 
    350    if (y == samp->stretched_row_y[0]) {
    351       samp->stretched_row_index = 1;
    352       return samp->stretched_row[0];
    353    }
    354 
    355    if (y == samp->stretched_row_y[1]) {
    356       samp->stretched_row_index = 0;
    357       return samp->stretched_row[1];
    358    }
    359 
    360    /*
    361     * Replace one entry.
    362     */
    363 
    364    src_row = data + y * stride;
    365 
    366    dst_row = samp->stretched_row[samp->stretched_row_index];
    367 
    368    if (fixed16_frac(samp->s) == 0 &&
    369        samp->dsdx == FIXED16_ONE) { // TODO: could be relaxed
    370       /*
    371        * 1:1 blit on the x direction.
    372        */
    373 
    374       unsigned i;
    375 
    376       src_row += samp->s >> FIXED16_SHIFT;
    377 
    378       if (((uintptr_t)src_row & 0xf) == 0) {
    379          /* The source texture is already aligned. Return it */
    380          return src_row;
    381       }
    382 
    383       /* Copy the source texture */
    384       for (i = 0; i < width; i += 4) {
    385          __m128i src = _mm_loadu_si128((const __m128i *)&src_row[i]);
    386          *(__m128i *)&dst_row[i] = src;
    387       }
    388    }
    389    else {
    390       util_sse2_stretch_row_8unorm((__m128i *)dst_row,
    391                                    align(width, 4),
    392                                    src_row, samp->s, samp->dsdx);
    393    }
    394 
    395    samp->stretched_row_y[samp->stretched_row_index] = y;
    396    samp->stretched_row_index ^= 1;
    397 
    398    return dst_row;
    399 }
    400 
    401 /* Maximise only as we fetch unscaled pixels linearly into a size-64
    402  * temporary.  For minimise, we will want to either have a bigger
    403  * temporary or fetch sparsely.
    404  */
    405 static const uint32_t *
    406 fetch_bgra_axis_aligned_linear(struct lp_linear_elem *elem)
    407 {
    408    struct lp_linear_sampler *samp = (struct lp_linear_sampler *)elem;
    409    const int width = samp->width;
    410    const uint32_t * restrict src_row0;
    411    const uint32_t * restrict src_row1;
    412    uint32_t * restrict row = samp->row;
    413    int y = samp->t >> FIXED16_SHIFT;
    414    int w = (samp->t >> 8) & 0xff;
    415    int i;
    416    __m128i wt;
    417 
    418    samp->t += samp->dtdy;
    419 
    420    src_row0 = fetch_and_stretch_bgra_row(samp, y);
    421 
    422    if (w == 0) {
    423       return src_row0;
    424    }
    425 
    426    src_row1 = fetch_and_stretch_bgra_row(samp, y + 1);
    427 
    428    wt = _mm_set1_epi16(w);
    429 
    430    /* Combine the two rows using a constant weight.
    431     */
    432    for (i = 0; i < width; i += 4) {
    433       __m128i srca = _mm_load_si128((const __m128i *)&src_row0[i]);
    434       __m128i srcb = _mm_load_si128((const __m128i *)&src_row1[i]);
    435 
    436       *(__m128i *)&row[i] = util_sse2_lerp_epi8_fixed88(srca, srcb, &wt, &wt);
    437    }
    438 
    439    return row;
    440 }
    441 
    442 /* Non-axis-aligned version.  Don't try to take advantage of
    443  * maximize.
    444  */
    445 static const uint32_t *
    446 fetch_bgra_linear(struct lp_linear_elem *elem)
    447 {
    448    struct lp_linear_sampler *samp = (struct lp_linear_sampler *)elem;
    449    const struct lp_jit_texture *texture = samp->texture;
    450    const int stride     = texture->row_stride[0] / sizeof(uint32_t);
    451    const uint32_t *data  = (const uint32_t *)texture->base;
    452    const int dsdx  = samp->dsdx;
    453    const int dtdx  = samp->dtdx;
    454    const int width = samp->width;
    455    uint32_t *row   = samp->row;
    456    int s = samp->s;
    457    int t = samp->t;
    458    int i, j;
    459 
    460    for (i = 0; i < width; i += 4) {
    461       union m128i si0, si1, si2, si3, ws, wt;
    462       __m128i si02, si13;
    463 
    464       for (j = 0; j < 4; j++) {
    465          const uint32_t *src = data + (t >> 16) * stride + (s>>16);
    466 
    467          si0.ui[j] = src[0];
    468          si1.ui[j] = src[1];
    469          si2.ui[j] = src[stride + 0];
    470          si3.ui[j] = src[stride + 1];
    471 
    472          ws.ui[j] = (s>>8) & 0xff;
    473          wt.ui[j] = (t>>8) & 0xff;
    474 
    475          s += dsdx;
    476          t += dtdx;
    477       }
    478 
    479       ws.m = _mm_or_si128(ws.m, _mm_slli_epi32(ws.m, 16));
    480       ws.m = _mm_or_si128(ws.m, _mm_slli_epi32(ws.m, 8));
    481 
    482       wt.m = _mm_or_si128(wt.m, _mm_slli_epi32(wt.m, 16));
    483       wt.m = _mm_or_si128(wt.m, _mm_slli_epi32(wt.m, 8));
    484 
    485       si02 = util_sse2_lerp_epi8_fixed08(si0.m, si2.m, wt.m);
    486       si13 = util_sse2_lerp_epi8_fixed08(si1.m, si3.m, wt.m);
    487 
    488       *(__m128i *)&row[i] = util_sse2_lerp_epi8_fixed08(si02, si13, ws.m);
    489    }
    490 
    491    samp->s += samp->dsdy;
    492    samp->t += samp->dtdy;
    493    return row;
    494 }
    495 
    496 
    497 /* Clamped, non-axis-aligned version.  Don't try to take advantage of
    498  * maximize.
    499  */
    500 static const uint32_t *
    501 fetch_bgra_clamp_linear(struct lp_linear_elem *elem)
    502 {
    503    struct lp_linear_sampler *samp = (struct lp_linear_sampler *)elem;
    504    const struct lp_jit_texture *texture = samp->texture;
    505    const uint32_t *data  = (const uint32_t *)texture->base;
    506    const int stride     = texture->row_stride[0] / sizeof(uint32_t);
    507    const int tex_height = texture->height - 1;
    508    const int tex_width  = texture->width - 1;
    509    const int dsdx  = samp->dsdx;
    510    const int dtdx  = samp->dtdx;
    511    const int width = samp->width;
    512    uint32_t *row   = samp->row;
    513    int s = samp->s;
    514    int t = samp->t;
    515    int i, j;
    516    /* width, height, stride (in pixels) must be smaller than 32768 */
    517    __m128i dsdx4, dtdx4, s4, t4, stride4, w4, h4, zero, one;
    518    s4 = _mm_set1_epi32(s);
    519    t4 = _mm_set1_epi32(t);
    520    s4 = _mm_add_epi32(s4, _mm_set_epi32(3*dsdx, 2*dsdx, dsdx, 0));
    521    t4 =  _mm_add_epi32(t4, _mm_set_epi32(3*dtdx, 2*dtdx, dtdx, 0));
    522    dsdx4 = _mm_set1_epi32(4*dsdx);
    523    dtdx4 = _mm_set1_epi32(4*dtdx);
    524    stride4 = _mm_set1_epi32(stride);
    525    w4 = _mm_set1_epi32(tex_width);
    526    h4 = _mm_set1_epi32(tex_height);
    527    zero = _mm_setzero_si128();
    528    one = _mm_set1_epi32(1);
    529 
    530    for (i = 0; i < width; i += 4) {
    531       union m128i addr[4];
    532       __m128i ws, wt, wsl, wsh, wtl, wth;
    533       __m128i s4s, t4s, cs0, cs1, ct0, ct1, tmp, si[4];
    534 
    535       s4s = _mm_srli_epi32(s4, 16);
    536       t4s = _mm_srli_epi32(t4, 16);
    537       cs0 = _mm_min_epi16(_mm_max_epi16(s4s, zero), w4);
    538       cs1 = _mm_add_epi16(s4s, one);
    539       cs1 = _mm_min_epi16(_mm_max_epi16(cs1, zero), w4);
    540       ct0 = _mm_min_epi16(_mm_max_epi16(t4s, zero), h4);
    541       ct1 = _mm_add_epi16(t4s, one);
    542       ct1 = _mm_min_epi16(_mm_max_epi16(ct1, zero), h4);
    543       tmp = _mm_madd_epi16(ct0, stride4);
    544       addr[0].m = _mm_add_epi32(tmp, cs0);
    545       addr[1].m = _mm_add_epi32(tmp, cs1);
    546       tmp = _mm_madd_epi16(ct1, stride4);
    547       addr[2].m = _mm_add_epi32(tmp, cs0);
    548       addr[3].m = _mm_add_epi32(tmp, cs1);
    549 
    550       for (j = 0; j < 4; j++) {
    551          __m128i ld1, ld2, ld3;
    552          si[j] = _mm_cvtsi32_si128(data[addr[j].ui[0]]);
    553          ld1 = _mm_cvtsi32_si128(data[addr[j].ui[1]]);
    554          si[j] = _mm_unpacklo_epi32(si[j], ld1);
    555          ld2 = _mm_cvtsi32_si128(data[addr[j].ui[2]]);
    556          ld3 = _mm_cvtsi32_si128(data[addr[j].ui[3]]);
    557          ld2 = _mm_unpacklo_epi32(ld2, ld3);
    558          si[j] =  _mm_unpacklo_epi64(si[j], ld2);
    559       }
    560 
    561       ws = _mm_srli_epi32(s4, 8);
    562       ws = _mm_and_si128(ws, _mm_set1_epi32(0xFF));
    563       wt = _mm_srli_epi32(t4, 8);
    564       wt = _mm_and_si128(wt, _mm_set1_epi32(0xFF));
    565 
    566       s4 = _mm_add_epi32(s4, dsdx4);
    567       t4 = _mm_add_epi32(t4, dtdx4);
    568 
    569 #if 0
    570 /* scalar code for reference */
    571       for (j = 0; j < 4; j++) {
    572          int s0 = s >> FIXED16_SHIFT;
    573          int t0 = t >> FIXED16_SHIFT;
    574          int cs0 = CLAMP(s0    , 0, tex_width);
    575          int cs1 = CLAMP(s0 + 1, 0, tex_width);
    576          int ct0 = CLAMP(t0    , 0, tex_height);
    577          int ct1 = CLAMP(t0 + 1, 0, tex_height);
    578 
    579          si0.ui[j] = data[ct0 * stride + cs0];
    580          si1.ui[j] = data[ct0 * stride + cs1];
    581          si2.ui[j] = data[ct1 * stride + cs0];
    582          si3.ui[j] = data[ct1 * stride + cs1];
    583 
    584          ws.ui[j] = (s>>8) & 0xff;
    585          wt.ui[j] = (t>>8) & 0xff;
    586 
    587          s += dsdx;
    588          t += dtdx;
    589       }
    590 #endif
    591 
    592       ws = _mm_or_si128(ws, _mm_slli_epi32(ws, 16));
    593       wsl = _mm_shuffle_epi32(ws, _MM_SHUFFLE(1,1,0,0));
    594       wsh = _mm_shuffle_epi32(ws, _MM_SHUFFLE(3,3,2,2));
    595 
    596       wt = _mm_or_si128(wt, _mm_slli_epi32(wt, 16));
    597       wtl = _mm_shuffle_epi32(wt, _MM_SHUFFLE(1,1,0,0));
    598       wth = _mm_shuffle_epi32(wt, _MM_SHUFFLE(3,3,2,2));
    599 
    600       *(__m128i *)&row[i] = util_sse2_lerp_2d_epi8_fixed88(si[0], si[2],
    601                                                            &si[1], &si[3],
    602                                                            &wtl, &wth,
    603                                                            &wsl, &wsh);
    604    }
    605 
    606    samp->s += samp->dsdy;
    607    samp->t += samp->dtdy;
    608    return row;
    609 }
    610 
    611 static const uint32_t *
    612 fetch_bgrx_axis_aligned_linear(struct lp_linear_elem *elem)
    613 {
    614    struct lp_linear_sampler *samp = (struct lp_linear_sampler *)elem;
    615    const __m128i mask = _mm_set1_epi32(0xff000000);
    616    uint32_t *dst_row = samp->row;
    617    const uint32_t *src_row;
    618    int width = samp->width;
    619    int i;
    620 
    621    src_row = fetch_bgra_axis_aligned_linear(&samp->base);
    622 
    623    for (i = 0; i < width; i += 4) {
    624       __m128i bgra = *(__m128i *)&src_row[i];
    625       __m128i bgrx = _mm_or_si128(bgra, mask);
    626       *(__m128i *)&dst_row[i] = bgrx;
    627    }
    628 
    629    return dst_row;
    630 }
    631 
    632 
    633 static const uint32_t *
    634 fetch_bgrx_clamp_linear(struct lp_linear_elem *elem)
    635 {
    636    struct lp_linear_sampler *samp = (struct lp_linear_sampler *)elem;
    637    const __m128i mask = _mm_set1_epi32(0xff000000);
    638    uint32_t *row   = samp->row;
    639    int width = samp->width;
    640    int i;
    641 
    642    fetch_bgra_clamp_linear(&samp->base);
    643 
    644    for (i = 0; i < width; i += 4) {
    645       __m128i bgra = *(__m128i *)&row[i];
    646       __m128i bgrx = _mm_or_si128(bgra, mask);
    647       *(__m128i *)&row[i] = bgrx;
    648    }
    649 
    650    return row;
    651 }
    652 
    653 
    654 static const uint32_t *
    655 fetch_bgrx_linear(struct lp_linear_elem *elem)
    656 {
    657    struct lp_linear_sampler *samp = (struct lp_linear_sampler *)elem;
    658    const __m128i mask = _mm_set1_epi32(0xff000000);
    659    uint32_t *row   = samp->row;
    660    int width = samp->width;
    661    int i;
    662 
    663    fetch_bgra_linear(&samp->base);
    664 
    665    for (i = 0; i < width; i += 4) {
    666       __m128i bgra = *(__m128i *)&row[i];
    667       __m128i bgrx = _mm_or_si128(bgra, mask);
    668       *(__m128i *)&row[i] = bgrx;
    669    }
    670 
    671    return row;
    672 }
    673 
    674 
    675 static boolean
    676 sampler_is_nearest(const struct lp_linear_sampler *samp,
    677                    const struct lp_sampler_static_state *sampler_state,
    678                    boolean minify)
    679 {
    680    unsigned img_filter;
    681 
    682    if (minify)
    683       img_filter = sampler_state->sampler_state.min_img_filter;
    684    else
    685       img_filter = sampler_state->sampler_state.mag_img_filter;
    686 
    687    /* Is it obviously nearest?
    688     */
    689    if (img_filter == PIPE_TEX_FILTER_NEAREST)
    690       return TRUE;
    691 
    692    /* Otherwise look for linear samplers which devolve to nearest.
    693     */
    694 
    695    /* Needs to be axis aligned.
    696     */
    697    if (!samp->axis_aligned)
    698       return FALSE;
    699 
    700    if (0) {
    701       /* For maximizing shaders, revert to nearest
    702        */
    703       if (samp->dsdx < -FIXED16_HALF && samp->dsdx < FIXED16_HALF &&
    704           samp->dtdy < -FIXED16_HALF && samp->dtdy < FIXED16_HALF)
    705          return TRUE;
    706 
    707       /* For severely minimising shaders, revert to nearest:
    708        */
    709       if ((samp->dsdx < 2 * FIXED16_ONE || samp->dsdx > 2 * FIXED16_ONE) &&
    710           (samp->dtdy < 2 * FIXED16_ONE || samp->dtdy > 2 * FIXED16_ONE))
    711          return TRUE;
    712    }
    713 
    714    /*
    715     * Must be near a pixel center:
    716     */
    717    if (!fixed16_approx(fixed16_frac(samp->s), FIXED16_HALF, FIXED16_TOL) ||
    718        !fixed16_approx(fixed16_frac(samp->t), FIXED16_HALF, FIXED16_TOL))
    719       return FALSE;
    720 
    721    /*
    722     * Must make a full step between pixels:
    723     */
    724    if (!fixed16_approx(samp->dsdx, FIXED16_ONE, FIXED16_TOL_DERIV) ||
    725        !fixed16_approx(samp->dtdy, FIXED16_ONE, FIXED16_TOL_DERIV))
    726       return FALSE;
    727 
    728    /* Treat it as nearest!
    729     */
    730    return TRUE;
    731 }
    732 
    733 /* XXX: Lots of static-state parameters being passed in here but very
    734  * little info is extracted from each one.  Consolidate it all down to
    735  * something succinct in the prepare phase?
    736  */
    737 boolean
    738 lp_linear_init_sampler(struct lp_linear_sampler *samp,
    739                        const struct lp_tgsi_texture_info *info,
    740                        const struct lp_sampler_static_state *sampler_state,
    741                        const struct lp_jit_texture *texture,
    742                        int x0, int y0, int width, int height,
    743                        const float (*a0)[4],
    744                        const float (*dadx)[4],
    745                        const float (*dady)[4])
    746 {
    747    const struct lp_tgsi_channel_info *schan = &info->coord[0];
    748    const struct lp_tgsi_channel_info *tchan = &info->coord[1];
    749 
    750    float w0   =   a0[0][3];
    751 
    752    float s0   =   a0[schan->u.index+1][schan->swizzle];
    753    float dsdx = dadx[schan->u.index+1][schan->swizzle];
    754    float dsdy = dady[schan->u.index+1][schan->swizzle];
    755 
    756    float t0   =   a0[tchan->u.index+1][tchan->swizzle];
    757    float dtdx = dadx[tchan->u.index+1][tchan->swizzle];
    758    float dtdy = dady[tchan->u.index+1][tchan->swizzle];
    759 
    760    int mins, mint, maxs, maxt;
    761    float oow = 1.0f / w0;
    762    float width_oow = texture->width * oow;
    763    float height_oow = texture->height * oow;
    764    float fdsdx = dsdx * width_oow;
    765    float fdsdy = dsdy * width_oow;
    766    float fdtdx = dtdx * height_oow;
    767    float fdtdy = dtdy * height_oow;
    768    int fetch_width;
    769    int fetch_height;
    770    boolean minify;
    771    boolean need_wrap;
    772    boolean is_nearest;
    773 
    774    samp->texture = texture;
    775    samp->width = width;
    776 
    777    samp->s = float_to_fixed16(fdsdx * x0 +
    778                               fdsdy * y0 +
    779                               s0 * width_oow);
    780 
    781    samp->t = float_to_fixed16(fdtdx * x0 +
    782                               fdtdy * y0 +
    783                               t0 * height_oow);
    784 
    785    samp->dsdx = float_to_fixed16(fdsdx);
    786    samp->dsdy = float_to_fixed16(fdsdy);
    787    samp->dtdx = float_to_fixed16(fdtdx);
    788    samp->dtdy = float_to_fixed16(fdtdy);
    789 
    790 
    791    samp->axis_aligned = (samp->dsdy == 0 &&
    792                          samp->dtdx == 0); // TODO: could be relaxed
    793 
    794    {
    795       int dsdx = samp->dsdx >= 0 ? samp->dsdx : -samp->dsdx;
    796       int dsdy = samp->dsdy >= 0 ? samp->dsdy : -samp->dsdy;
    797       int dtdx = samp->dtdx >= 0 ? samp->dtdx : -samp->dtdx;
    798       int dtdy = samp->dtdy >= 0 ? samp->dtdy : -samp->dtdy;
    799       int rho = MAX4(dsdx, dsdy, dtdx, dtdy);
    800 
    801       minify = (rho > FIXED16_ONE);
    802    }
    803 
    804    is_nearest = sampler_is_nearest(samp, sampler_state, minify);
    805 
    806    if (!is_nearest) {
    807       samp->s -= FIXED16_HALF;
    808       samp->t -= FIXED16_HALF;
    809    }
    810 
    811    /* Check for clamping.  This rarely happens as we're rejecting interpolants
    812     * which fall outside the 0..1 range.
    813     */
    814 
    815    if (is_nearest) {
    816       /* Nearest fetch routines don't employ SSE and always operate one pixel
    817        * at a time.
    818        */
    819       fetch_width = width - 1;
    820    }
    821    else {
    822       /* Linear fetch routines employ SSE, and always fetch groups of four
    823        * texels.
    824        */
    825       fetch_width = align(width, 4) - 1;
    826    }
    827    fetch_height = height - 1;
    828 
    829    if (samp->axis_aligned) {
    830       int s0 = samp->s;
    831       int s1 = samp->s + fetch_width  * samp->dsdx;
    832       int t0 = samp->t;
    833       int t1 = samp->t + fetch_height * samp->dtdy;
    834 
    835       mins = MIN2(s0, s1);
    836       mint = MIN2(t0, t1);
    837       maxs = MAX2(s0, s1);
    838       maxt = MAX2(t0, t1);
    839    }
    840    else {
    841       int s0 = samp->s;
    842       int s1 = samp->s + fetch_width  * samp->dsdx;
    843       int s2 = samp->s + fetch_height * samp->dsdy;
    844       int s3 = samp->s + fetch_width  * samp->dsdx + fetch_height * samp->dsdy;
    845       int t0 = samp->t;
    846       int t1 = samp->t + fetch_width  * samp->dtdx;
    847       int t2 = samp->t + fetch_height * samp->dtdy;
    848       int t3 = samp->t + fetch_width  * samp->dtdx + fetch_height * samp->dtdy;
    849 
    850       mins = MIN4(s0, s1, s2, s3);
    851       mint = MIN4(t0, t1, t2, t3);
    852       maxs = MAX4(s0, s1, s2, s3);
    853       maxt = MAX4(t0, t1, t2, t3);
    854    }
    855 
    856    if (is_nearest) {
    857       need_wrap = (mins < 0 ||
    858                    mint < 0 ||
    859                    maxs >= (texture->width  << FIXED16_SHIFT) ||
    860                    maxt >= (texture->height << FIXED16_SHIFT));
    861    } else {
    862       need_wrap = (mins < 0 ||
    863                    mint < 0 ||
    864                    maxs + FIXED16_ONE >= (texture->width  << FIXED16_SHIFT) ||
    865                    maxt + FIXED16_ONE >= (texture->height << FIXED16_SHIFT));
    866    }
    867 
    868    if (0 && need_wrap) {
    869       debug_printf("%u x %u %s\n",
    870                    texture->width, texture->height,
    871                    is_nearest ? "nearest" : "linear");
    872       debug_printf("mins = %f\n", mins*1.0f/FIXED16_ONE);
    873       debug_printf("mint = %f\n", mint*1.0f/FIXED16_ONE);
    874       debug_printf("maxs = %f\n", maxs*1.0f/FIXED16_ONE);
    875       debug_printf("maxt = %f\n", maxt*1.0f/FIXED16_ONE);
    876       debug_printf("\n");
    877    }
    878 
    879    /* We accept any mode below, but we only implement clamping.
    880     */
    881    if (need_wrap &&
    882        (sampler_state->sampler_state.wrap_s != PIPE_TEX_WRAP_CLAMP_TO_EDGE ||
    883         sampler_state->sampler_state.wrap_t != PIPE_TEX_WRAP_CLAMP_TO_EDGE)) {
    884        return FALSE;
    885    }
    886 
    887    if (is_nearest) {
    888       switch (sampler_state->texture_state.format) {
    889       case PIPE_FORMAT_B8G8R8A8_UNORM:
    890          if (need_wrap)
    891             samp->base.fetch = fetch_bgra_clamp;
    892          else if (!samp->axis_aligned)
    893             samp->base.fetch = fetch_bgra;
    894          else if (samp->dsdx != FIXED16_ONE) // TODO: could be relaxed
    895             samp->base.fetch = fetch_bgra_axis_aligned;
    896          else
    897             samp->base.fetch = fetch_bgra_memcpy;
    898 
    899          return TRUE;
    900 
    901       case PIPE_FORMAT_B8G8R8X8_UNORM:
    902          if (need_wrap)
    903             samp->base.fetch = fetch_bgrx_clamp;
    904          else if (!samp->axis_aligned)
    905             samp->base.fetch = fetch_bgrx;
    906          else if (samp->dsdx != FIXED16_ONE) // TODO: could be relaxed
    907             samp->base.fetch = fetch_bgrx_axis_aligned;
    908          else
    909             samp->base.fetch = fetch_bgrx_memcpy;
    910 
    911          return TRUE;
    912 
    913       default:
    914          break;
    915       }
    916 
    917       FAIL("unknown format for nearest");
    918    }
    919    else {
    920       samp->stretched_row_y[0] = -1;
    921       samp->stretched_row_y[1] = -1;
    922       samp->stretched_row_index = 0;
    923 
    924       switch (sampler_state->texture_state.format) {
    925       case PIPE_FORMAT_B8G8R8A8_UNORM:
    926          if (need_wrap)
    927             samp->base.fetch = fetch_bgra_clamp_linear;
    928          else if (!samp->axis_aligned)
    929             samp->base.fetch = fetch_bgra_linear;
    930          else
    931             samp->base.fetch = fetch_bgra_axis_aligned_linear;
    932 
    933          return TRUE;
    934 
    935       case PIPE_FORMAT_B8G8R8X8_UNORM:
    936          if (need_wrap)
    937             samp->base.fetch = fetch_bgrx_clamp_linear;
    938          else if (!samp->axis_aligned)
    939             samp->base.fetch = fetch_bgrx_linear;
    940          else
    941             samp->base.fetch = fetch_bgrx_axis_aligned_linear;
    942          return TRUE;
    943 
    944       default:
    945          break;
    946       }
    947 
    948       FAIL("unknown format");
    949    }
    950 }
    951 
    952 
    953 static const uint32_t *
    954 fetch_noop(struct lp_linear_elem *elem)
    955 {
    956    struct lp_linear_sampler *samp = (struct lp_linear_sampler *)elem;
    957    return samp->row;
    958 }
    959 
    960 
    961 void
    962 lp_linear_init_noop_sampler(struct lp_linear_sampler *samp)
    963 {
    964    samp->base.fetch = fetch_noop;
    965 }
    966 
    967 /* Check the variant for linear path compatibility.
    968  */
    969 boolean
    970 lp_linear_check_sampler(const struct lp_sampler_static_state *sampler,
    971                         const struct lp_tgsi_texture_info *tex)
    972 {
    973    if (tex->modifier != LP_BLD_TEX_MODIFIER_NONE)
    974       return FALSE;
    975 
    976    if (tex->target != TGSI_TEXTURE_2D)
    977       return FALSE;
    978 
    979    if (tex->coord[0].file != TGSI_FILE_INPUT ||
    980        tex->coord[1].file != TGSI_FILE_INPUT)
    981       return FALSE;
    982 
    983    /* These are the only sampling modes we support at the moment.
    984     *
    985     * Actually we'll accept any mode as we're failing on any
    986     * interpolant which exceeds 0..1.  Clamping is applied only to
    987     * avoid invalid reads.
    988     */
    989    if (!is_nearest_sampler(sampler) &&
    990        !is_linear_sampler(sampler))
    991       return FALSE;
    992 
    993    /* These are the only texture formats we support at the moment
    994     */
    995    if (sampler->texture_state.format != PIPE_FORMAT_B8G8R8A8_UNORM &&
    996        sampler->texture_state.format != PIPE_FORMAT_B8G8R8X8_UNORM)
    997       return FALSE;
    998 
    999    return TRUE;
   1000 }
   1001 
   1002 #else
   1003 boolean
   1004 lp_linear_check_sampler(const struct lp_sampler_static_state *sampler,
   1005                         const struct lp_tgsi_texture_info *tex)
   1006 {
   1007    return FALSE;
   1008 }
   1009 #endif
   1010