Home | History | Annotate | Download | only in nvc0
      1 /*
      2  * Copyright 2008 Ben Skeggs
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice shall be included in
     12  * all copies or substantial portions of the Software.
     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 NONINFRINGEMENT.  IN NO EVENT SHALL
     17  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
     18  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
     19  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     20  * SOFTWARE.
     21  */
     22 
     23 #include "nvc0_context.h"
     24 #include "nvc0_resource.h"
     25 #include "nv50/nv50_texture.xml.h"
     26 
     27 #include "util/u_format.h"
     28 
     29 #define NVE4_TIC_ENTRY_INVALID 0x000fffff
     30 #define NVE4_TSC_ENTRY_INVALID 0xfff00000
     31 
     32 #define NV50_TIC_0_SWIZZLE__MASK                      \
     33    (NV50_TIC_0_MAPA__MASK | NV50_TIC_0_MAPB__MASK |   \
     34     NV50_TIC_0_MAPG__MASK | NV50_TIC_0_MAPR__MASK)
     35 
     36 static INLINE uint32_t
     37 nv50_tic_swizzle(uint32_t tc, unsigned swz, boolean tex_int)
     38 {
     39    switch (swz) {
     40    case PIPE_SWIZZLE_RED:
     41       return (tc & NV50_TIC_0_MAPR__MASK) >> NV50_TIC_0_MAPR__SHIFT;
     42    case PIPE_SWIZZLE_GREEN:
     43       return (tc & NV50_TIC_0_MAPG__MASK) >> NV50_TIC_0_MAPG__SHIFT;
     44    case PIPE_SWIZZLE_BLUE:
     45       return (tc & NV50_TIC_0_MAPB__MASK) >> NV50_TIC_0_MAPB__SHIFT;
     46    case PIPE_SWIZZLE_ALPHA:
     47       return (tc & NV50_TIC_0_MAPA__MASK) >> NV50_TIC_0_MAPA__SHIFT;
     48    case PIPE_SWIZZLE_ONE:
     49       return tex_int ? NV50_TIC_MAP_ONE_INT : NV50_TIC_MAP_ONE_FLOAT;
     50    case PIPE_SWIZZLE_ZERO:
     51    default:
     52       return NV50_TIC_MAP_ZERO;
     53    }
     54 }
     55 
     56 struct pipe_sampler_view *
     57 nvc0_create_sampler_view(struct pipe_context *pipe,
     58                          struct pipe_resource *texture,
     59                          const struct pipe_sampler_view *templ)
     60 {
     61    const struct util_format_description *desc;
     62    uint64_t address;
     63    uint32_t *tic;
     64    uint32_t swz[4];
     65    uint32_t depth;
     66    struct nv50_tic_entry *view;
     67    struct nv50_miptree *mt;
     68    boolean tex_int;
     69 
     70    view = MALLOC_STRUCT(nv50_tic_entry);
     71    if (!view)
     72       return NULL;
     73    mt = nv50_miptree(texture);
     74 
     75    view->pipe = *templ;
     76    view->pipe.reference.count = 1;
     77    view->pipe.texture = NULL;
     78    view->pipe.context = pipe;
     79 
     80    view->id = -1;
     81 
     82    pipe_resource_reference(&view->pipe.texture, texture);
     83 
     84    tic = &view->tic[0];
     85 
     86    desc = util_format_description(view->pipe.format);
     87 
     88    tic[0] = nvc0_format_table[view->pipe.format].tic;
     89 
     90    tex_int = util_format_is_pure_integer(view->pipe.format);
     91 
     92    swz[0] = nv50_tic_swizzle(tic[0], view->pipe.swizzle_r, tex_int);
     93    swz[1] = nv50_tic_swizzle(tic[0], view->pipe.swizzle_g, tex_int);
     94    swz[2] = nv50_tic_swizzle(tic[0], view->pipe.swizzle_b, tex_int);
     95    swz[3] = nv50_tic_swizzle(tic[0], view->pipe.swizzle_a, tex_int);
     96    tic[0] = (tic[0] & ~NV50_TIC_0_SWIZZLE__MASK) |
     97       (swz[0] << NV50_TIC_0_MAPR__SHIFT) |
     98       (swz[1] << NV50_TIC_0_MAPG__SHIFT) |
     99       (swz[2] << NV50_TIC_0_MAPB__SHIFT) |
    100       (swz[3] << NV50_TIC_0_MAPA__SHIFT);
    101 
    102    address = mt->base.address;
    103 
    104    tic[2] = 0x10001000 | NV50_TIC_2_NO_BORDER;
    105 
    106    if (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB)
    107       tic[2] |= NV50_TIC_2_COLORSPACE_SRGB;
    108 
    109    /* check for linear storage type */
    110    if (unlikely(!nouveau_bo_memtype(nv04_resource(texture)->bo))) {
    111       if (texture->target == PIPE_BUFFER) {
    112          address +=
    113             view->pipe.u.buf.first_element * desc->block.bits / 8;
    114          tic[2] |= NV50_TIC_2_LINEAR | NV50_TIC_2_TARGET_BUFFER;
    115          tic[3] = 0;
    116          tic[4] = /* width */
    117             view->pipe.u.buf.last_element - view->pipe.u.buf.first_element + 1;
    118          tic[5] = 0;
    119       } else {
    120          /* must be 2D texture without mip maps */
    121          tic[2] |= NV50_TIC_2_LINEAR | NV50_TIC_2_TARGET_RECT;
    122          if (texture->target != PIPE_TEXTURE_RECT)
    123             tic[2] |= NV50_TIC_2_NORMALIZED_COORDS;
    124          tic[3] = mt->level[0].pitch;
    125          tic[4] = mt->base.base.width0;
    126          tic[5] = (1 << 16) | mt->base.base.height0;
    127       }
    128       tic[6] =
    129       tic[7] = 0;
    130       tic[1] = address;
    131       tic[2] |= address >> 32;
    132       return &view->pipe;
    133    }
    134 
    135    if (mt->base.base.target != PIPE_TEXTURE_RECT)
    136       tic[2] |= NV50_TIC_2_NORMALIZED_COORDS;
    137 
    138    tic[2] |=
    139       ((mt->level[0].tile_mode & 0x0f0) << (22 - 4)) |
    140       ((mt->level[0].tile_mode & 0xf00) << (25 - 8));
    141 
    142    depth = MAX2(mt->base.base.array_size, mt->base.base.depth0);
    143 
    144    if (mt->base.base.array_size > 1) {
    145       /* there doesn't seem to be a base layer field in TIC */
    146       address += view->pipe.u.tex.first_layer * mt->layer_stride;
    147       depth = view->pipe.u.tex.last_layer - view->pipe.u.tex.first_layer + 1;
    148    }
    149    tic[1] = address;
    150    tic[2] |= address >> 32;
    151 
    152    switch (mt->base.base.target) {
    153    case PIPE_TEXTURE_1D:
    154       tic[2] |= NV50_TIC_2_TARGET_1D;
    155       break;
    156 /* case PIPE_TEXTURE_2D_MS: */
    157    case PIPE_TEXTURE_2D:
    158       tic[2] |= NV50_TIC_2_TARGET_2D;
    159       break;
    160    case PIPE_TEXTURE_RECT:
    161       tic[2] |= NV50_TIC_2_TARGET_RECT;
    162       break;
    163    case PIPE_TEXTURE_3D:
    164       tic[2] |= NV50_TIC_2_TARGET_3D;
    165       break;
    166    case PIPE_TEXTURE_CUBE:
    167       depth /= 6;
    168       if (depth > 1)
    169          tic[2] |= NV50_TIC_2_TARGET_CUBE_ARRAY;
    170       else
    171          tic[2] |= NV50_TIC_2_TARGET_CUBE;
    172       break;
    173    case PIPE_TEXTURE_1D_ARRAY:
    174       tic[2] |= NV50_TIC_2_TARGET_1D_ARRAY;
    175       break;
    176 /* case PIPE_TEXTURE_2D_ARRAY_MS: */
    177    case PIPE_TEXTURE_2D_ARRAY:
    178       tic[2] |= NV50_TIC_2_TARGET_2D_ARRAY;
    179       break;
    180    default:
    181       NOUVEAU_ERR("invalid texture target: %d\n", mt->base.base.target);
    182       return FALSE;
    183    }
    184 
    185    if (mt->base.base.target == PIPE_BUFFER)
    186       tic[3] = mt->base.base.width0;
    187    else
    188       tic[3] = 0x00300000;
    189 
    190    tic[4] = (1 << 31) | (mt->base.base.width0 << mt->ms_x);
    191 
    192    tic[5] = (mt->base.base.height0 << mt->ms_y) & 0xffff;
    193    tic[5] |= depth << 16;
    194    tic[5] |= mt->base.base.last_level << 28;
    195 
    196    tic[6] = (mt->ms_x > 1) ? 0x88000000 : 0x03000000; /* sampling points */
    197 
    198    tic[7] = (view->pipe.u.tex.last_level << 4) | view->pipe.u.tex.first_level;
    199 
    200    /*
    201    if (mt->base.base.target == PIPE_TEXTURE_2D_MS ||
    202        mt->base.base.target == PIPE_TEXTURE_2D_ARRAY_MS)
    203       tic[7] |= mt->ms_mode << 12;
    204    */
    205 
    206    return &view->pipe;
    207 }
    208 
    209 static boolean
    210 nvc0_validate_tic(struct nvc0_context *nvc0, int s)
    211 {
    212    uint32_t commands[32];
    213    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    214    struct nouveau_bo *txc = nvc0->screen->txc;
    215    unsigned i;
    216    unsigned n = 0;
    217    boolean need_flush = FALSE;
    218 
    219    for (i = 0; i < nvc0->num_textures[s]; ++i) {
    220       struct nv50_tic_entry *tic = nv50_tic_entry(nvc0->textures[s][i]);
    221       struct nv04_resource *res;
    222       const boolean dirty = !!(nvc0->textures_dirty[s] & (1 << i));
    223 
    224       if (!tic) {
    225          if (dirty)
    226             commands[n++] = (i << 1) | 0;
    227          continue;
    228       }
    229       res = nv04_resource(tic->pipe.texture);
    230 
    231       if (tic->id < 0) {
    232          tic->id = nvc0_screen_tic_alloc(nvc0->screen, tic);
    233 
    234          PUSH_SPACE(push, 17);
    235          BEGIN_NVC0(push, NVC0_M2MF(OFFSET_OUT_HIGH), 2);
    236          PUSH_DATAh(push, txc->offset + (tic->id * 32));
    237          PUSH_DATA (push, txc->offset + (tic->id * 32));
    238          BEGIN_NVC0(push, NVC0_M2MF(LINE_LENGTH_IN), 2);
    239          PUSH_DATA (push, 32);
    240          PUSH_DATA (push, 1);
    241          BEGIN_NVC0(push, NVC0_M2MF(EXEC), 1);
    242          PUSH_DATA (push, 0x100111);
    243          BEGIN_NIC0(push, NVC0_M2MF(DATA), 8);
    244          PUSH_DATAp(push, &tic->tic[0], 8);
    245 
    246          need_flush = TRUE;
    247       } else
    248       if (res->status & NOUVEAU_BUFFER_STATUS_GPU_WRITING) {
    249          BEGIN_NVC0(push, NVC0_3D(TEX_CACHE_CTL), 1);
    250          PUSH_DATA (push, (tic->id << 4) | 1);
    251       }
    252       nvc0->screen->tic.lock[tic->id / 32] |= 1 << (tic->id % 32);
    253 
    254       res->status &= ~NOUVEAU_BUFFER_STATUS_GPU_WRITING;
    255       res->status |=  NOUVEAU_BUFFER_STATUS_GPU_READING;
    256 
    257       if (!dirty)
    258          continue;
    259       commands[n++] = (tic->id << 9) | (i << 1) | 1;
    260 
    261       BCTX_REFN(nvc0->bufctx_3d, TEX(s, i), res, RD);
    262    }
    263    for (; i < nvc0->state.num_textures[s]; ++i)
    264       commands[n++] = (i << 1) | 0;
    265 
    266    nvc0->state.num_textures[s] = nvc0->num_textures[s];
    267 
    268    if (n) {
    269       BEGIN_NIC0(push, NVC0_3D(BIND_TIC(s)), n);
    270       PUSH_DATAp(push, commands, n);
    271    }
    272    nvc0->textures_dirty[s] = 0;
    273 
    274    return need_flush;
    275 }
    276 
    277 static boolean
    278 nve4_validate_tic(struct nvc0_context *nvc0, unsigned s)
    279 {
    280    struct nouveau_bo *txc = nvc0->screen->txc;
    281    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    282    unsigned i;
    283    boolean need_flush = FALSE;
    284 
    285    for (i = 0; i < nvc0->num_textures[s]; ++i) {
    286       struct nv50_tic_entry *tic = nv50_tic_entry(nvc0->textures[s][i]);
    287       struct nv04_resource *res;
    288       const boolean dirty = !!(nvc0->textures_dirty[s] & (1 << i));
    289 
    290       if (!tic) {
    291          nvc0->tex_handles[s][i] |= NVE4_TIC_ENTRY_INVALID;
    292          continue;
    293       }
    294       res = nv04_resource(tic->pipe.texture);
    295 
    296       if (tic->id < 0) {
    297          tic->id = nvc0_screen_tic_alloc(nvc0->screen, tic);
    298 
    299          PUSH_SPACE(push, 16);
    300          BEGIN_NVC0(push, NVE4_P2MF(DST_ADDRESS_HIGH), 2);
    301          PUSH_DATAh(push, txc->offset + (tic->id * 32));
    302          PUSH_DATA (push, txc->offset + (tic->id * 32));
    303          BEGIN_NVC0(push, NVE4_P2MF(LINE_LENGTH_IN), 2);
    304          PUSH_DATA (push, 32);
    305          PUSH_DATA (push, 1);
    306          BEGIN_1IC0(push, NVE4_P2MF(EXEC), 9);
    307          PUSH_DATA (push, 0x1001);
    308          PUSH_DATAp(push, &tic->tic[0], 8);
    309 
    310          need_flush = TRUE;
    311       } else
    312       if (res->status & NOUVEAU_BUFFER_STATUS_GPU_WRITING) {
    313          BEGIN_NVC0(push, NVC0_3D(TEX_CACHE_CTL), 1);
    314          PUSH_DATA (push, (tic->id << 4) | 1);
    315       }
    316       nvc0->screen->tic.lock[tic->id / 32] |= 1 << (tic->id % 32);
    317 
    318       res->status &= ~NOUVEAU_BUFFER_STATUS_GPU_WRITING;
    319       res->status |=  NOUVEAU_BUFFER_STATUS_GPU_READING;
    320 
    321       nvc0->tex_handles[s][i] &= ~NVE4_TIC_ENTRY_INVALID;
    322       nvc0->tex_handles[s][i] |= tic->id;
    323       if (dirty)
    324          BCTX_REFN(nvc0->bufctx_3d, TEX(s, i), res, RD);
    325    }
    326    for (; i < nvc0->state.num_textures[s]; ++i)
    327       nvc0->tex_handles[s][i] |= NVE4_TIC_ENTRY_INVALID;
    328 
    329    nvc0->state.num_textures[s] = nvc0->num_textures[s];
    330 
    331    return need_flush;
    332 }
    333 
    334 void nvc0_validate_textures(struct nvc0_context *nvc0)
    335 {
    336    boolean need_flush;
    337 
    338    if (nvc0->screen->base.class_3d >= NVE4_3D_CLASS) {
    339       need_flush  = nve4_validate_tic(nvc0, 0);
    340       need_flush |= nve4_validate_tic(nvc0, 3);
    341       need_flush |= nve4_validate_tic(nvc0, 4);
    342    } else {
    343       need_flush  = nvc0_validate_tic(nvc0, 0);
    344       need_flush |= nvc0_validate_tic(nvc0, 3);
    345       need_flush |= nvc0_validate_tic(nvc0, 4);
    346    }
    347 
    348    if (need_flush) {
    349       BEGIN_NVC0(nvc0->base.pushbuf, NVC0_3D(TIC_FLUSH), 1);
    350       PUSH_DATA (nvc0->base.pushbuf, 0);
    351    }
    352 }
    353 
    354 static boolean
    355 nvc0_validate_tsc(struct nvc0_context *nvc0, int s)
    356 {
    357    uint32_t commands[16];
    358    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    359    unsigned i;
    360    unsigned n = 0;
    361    boolean need_flush = FALSE;
    362 
    363    for (i = 0; i < nvc0->num_samplers[s]; ++i) {
    364       struct nv50_tsc_entry *tsc = nv50_tsc_entry(nvc0->samplers[s][i]);
    365 
    366       if (!(nvc0->samplers_dirty[s] & (1 << i)))
    367          continue;
    368       if (!tsc) {
    369          commands[n++] = (i << 4) | 0;
    370          continue;
    371       }
    372       if (tsc->id < 0) {
    373          tsc->id = nvc0_screen_tsc_alloc(nvc0->screen, tsc);
    374 
    375          nvc0_m2mf_push_linear(&nvc0->base, nvc0->screen->txc,
    376                                65536 + tsc->id * 32, NOUVEAU_BO_VRAM,
    377                                32, tsc->tsc);
    378          need_flush = TRUE;
    379       }
    380       nvc0->screen->tsc.lock[tsc->id / 32] |= 1 << (tsc->id % 32);
    381 
    382       commands[n++] = (tsc->id << 12) | (i << 4) | 1;
    383    }
    384    for (; i < nvc0->state.num_samplers[s]; ++i)
    385       commands[n++] = (i << 4) | 0;
    386 
    387    nvc0->state.num_samplers[s] = nvc0->num_samplers[s];
    388 
    389    if (n) {
    390       BEGIN_NIC0(push, NVC0_3D(BIND_TSC(s)), n);
    391       PUSH_DATAp(push, commands, n);
    392    }
    393    nvc0->samplers_dirty[s] = 0;
    394 
    395    return need_flush;
    396 }
    397 
    398 static boolean
    399 nve4_validate_tsc(struct nvc0_context *nvc0, int s)
    400 {
    401    struct nouveau_bo *txc = nvc0->screen->txc;
    402    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    403    unsigned i;
    404    boolean need_flush = FALSE;
    405 
    406    for (i = 0; i < nvc0->num_samplers[s]; ++i) {
    407       struct nv50_tsc_entry *tsc = nv50_tsc_entry(nvc0->samplers[s][i]);
    408 
    409       if (!tsc) {
    410          nvc0->tex_handles[s][i] |= NVE4_TSC_ENTRY_INVALID;
    411          continue;
    412       }
    413       if (tsc->id < 0) {
    414          tsc->id = nvc0_screen_tsc_alloc(nvc0->screen, tsc);
    415 
    416          PUSH_SPACE(push, 16);
    417          BEGIN_NVC0(push, NVE4_P2MF(DST_ADDRESS_HIGH), 2);
    418          PUSH_DATAh(push, txc->offset + 65536 + (tsc->id * 32));
    419          PUSH_DATA (push, txc->offset + 65536 + (tsc->id * 32));
    420          BEGIN_NVC0(push, NVE4_P2MF(LINE_LENGTH_IN), 2);
    421          PUSH_DATA (push, 32);
    422          PUSH_DATA (push, 1);
    423          BEGIN_1IC0(push, NVE4_P2MF(EXEC), 9);
    424          PUSH_DATA (push, 0x1001);
    425          PUSH_DATAp(push, &tsc->tsc[0], 8);
    426 
    427          need_flush = TRUE;
    428       }
    429       nvc0->screen->tsc.lock[tsc->id / 32] |= 1 << (tsc->id % 32);
    430 
    431       nvc0->tex_handles[s][i] &= ~NVE4_TSC_ENTRY_INVALID;
    432       nvc0->tex_handles[s][i] |= tsc->id << 20;
    433    }
    434    for (; i < nvc0->state.num_samplers[s]; ++i)
    435       nvc0->tex_handles[s][i] |= NVE4_TSC_ENTRY_INVALID;
    436 
    437    nvc0->state.num_samplers[s] = nvc0->num_samplers[s];
    438 
    439    return need_flush;
    440 }
    441 
    442 void nvc0_validate_samplers(struct nvc0_context *nvc0)
    443 {
    444    boolean need_flush;
    445 
    446    if (nvc0->screen->base.class_3d >= NVE4_3D_CLASS) {
    447       need_flush  = nve4_validate_tsc(nvc0, 0);
    448       need_flush |= nve4_validate_tsc(nvc0, 3);
    449       need_flush |= nve4_validate_tsc(nvc0, 4);
    450    } else {
    451       need_flush  = nvc0_validate_tsc(nvc0, 0);
    452       need_flush |= nvc0_validate_tsc(nvc0, 3);
    453       need_flush |= nvc0_validate_tsc(nvc0, 4);
    454    }
    455 
    456    if (need_flush) {
    457       BEGIN_NVC0(nvc0->base.pushbuf, NVC0_3D(TSC_FLUSH), 1);
    458       PUSH_DATA (nvc0->base.pushbuf, 0);
    459    }
    460 }
    461 
    462 /* Upload the "diagonal" entries for the possible texture sources ($t == $s).
    463  * At some point we might want to get a list of the combinations used by a
    464  * shader and fill in those entries instead of having it extract the handles.
    465  */
    466 void
    467 nve4_set_tex_handles(struct nvc0_context *nvc0)
    468 {
    469    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    470    uint64_t address;
    471    unsigned s;
    472 
    473    if (nvc0->screen->base.class_3d < NVE4_3D_CLASS)
    474       return;
    475    address = nvc0->screen->uniform_bo->offset + (5 << 16);
    476 
    477    for (s = 0; s < 5; ++s, address += (1 << 9)) {
    478       uint32_t dirty = nvc0->textures_dirty[s] | nvc0->samplers_dirty[s];
    479       if (!dirty)
    480          continue;
    481       BEGIN_NVC0(push, NVC0_3D(CB_SIZE), 3);
    482       PUSH_DATA (push, 512);
    483       PUSH_DATAh(push, address);
    484       PUSH_DATA (push, address);
    485       do {
    486          int i = ffs(dirty) - 1;
    487          dirty &= ~(1 << i);
    488 
    489          BEGIN_NVC0(push, NVC0_3D(CB_POS), 2);
    490          PUSH_DATA (push, (8 + i) * 4);
    491          PUSH_DATA (push, nvc0->tex_handles[s][i]);
    492       } while (dirty);
    493 
    494       nvc0->textures_dirty[s] = 0;
    495       nvc0->samplers_dirty[s] = 0;
    496    }
    497 }
    498