Home | History | Annotate | Download | only in svga
      1 /**********************************************************
      2  * Copyright 2008-2009 VMware, Inc.  All rights reserved.
      3  *
      4  * Permission is hereby granted, free of charge, to any person
      5  * obtaining a copy of this software and associated documentation
      6  * files (the "Software"), to deal in the Software without
      7  * restriction, including without limitation the rights to use, copy,
      8  * modify, merge, publish, distribute, sublicense, and/or sell copies
      9  * of the Software, and to permit persons to whom the Software is
     10  * furnished to do so, subject to the following conditions:
     11  *
     12  * The above copyright notice and this permission notice shall be
     13  * included in all copies or substantial portions of the Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     18  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
     19  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
     20  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     22  * SOFTWARE.
     23  *
     24  **********************************************************/
     25 
     26 #include "pipe/p_defines.h"
     27 #include "util/u_bitmask.h"
     28 #include "util/u_format.h"
     29 #include "util/u_inlines.h"
     30 #include "util/u_math.h"
     31 #include "util/u_memory.h"
     32 #include "tgsi/tgsi_parse.h"
     33 
     34 #include "svga_context.h"
     35 #include "svga_cmd.h"
     36 #include "svga_debug.h"
     37 #include "svga_resource_texture.h"
     38 #include "svga_surface.h"
     39 #include "svga_sampler_view.h"
     40 
     41 
     42 static inline unsigned
     43 translate_wrap_mode(unsigned wrap)
     44 {
     45    switch (wrap) {
     46    case PIPE_TEX_WRAP_REPEAT:
     47       return SVGA3D_TEX_ADDRESS_WRAP;
     48    case PIPE_TEX_WRAP_CLAMP:
     49       return SVGA3D_TEX_ADDRESS_CLAMP;
     50    case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
     51       /* Unfortunately SVGA3D_TEX_ADDRESS_EDGE not respected by
     52        * hardware.
     53        */
     54       return SVGA3D_TEX_ADDRESS_CLAMP;
     55    case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
     56       return SVGA3D_TEX_ADDRESS_BORDER;
     57    case PIPE_TEX_WRAP_MIRROR_REPEAT:
     58       return SVGA3D_TEX_ADDRESS_MIRROR;
     59    case PIPE_TEX_WRAP_MIRROR_CLAMP:
     60    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
     61    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
     62       return SVGA3D_TEX_ADDRESS_MIRRORONCE;
     63    default:
     64       assert(0);
     65       return SVGA3D_TEX_ADDRESS_WRAP;
     66    }
     67 }
     68 
     69 
     70 static inline unsigned
     71 translate_img_filter(unsigned filter)
     72 {
     73    switch (filter) {
     74    case PIPE_TEX_FILTER_NEAREST:
     75       return SVGA3D_TEX_FILTER_NEAREST;
     76    case PIPE_TEX_FILTER_LINEAR:
     77       return SVGA3D_TEX_FILTER_LINEAR;
     78    default:
     79       assert(0);
     80       return SVGA3D_TEX_FILTER_NEAREST;
     81    }
     82 }
     83 
     84 
     85 static inline unsigned
     86 translate_mip_filter(unsigned filter)
     87 {
     88    switch (filter) {
     89    case PIPE_TEX_MIPFILTER_NONE:
     90       return SVGA3D_TEX_FILTER_NONE;
     91    case PIPE_TEX_MIPFILTER_NEAREST:
     92       return SVGA3D_TEX_FILTER_NEAREST;
     93    case PIPE_TEX_MIPFILTER_LINEAR:
     94       return SVGA3D_TEX_FILTER_LINEAR;
     95    default:
     96       assert(0);
     97       return SVGA3D_TEX_FILTER_NONE;
     98    }
     99 }
    100 
    101 
    102 static uint8
    103 translate_comparison_func(unsigned func)
    104 {
    105    switch (func) {
    106    case PIPE_FUNC_NEVER:
    107       return SVGA3D_COMPARISON_NEVER;
    108    case PIPE_FUNC_LESS:
    109       return SVGA3D_COMPARISON_LESS;
    110    case PIPE_FUNC_EQUAL:
    111       return SVGA3D_COMPARISON_EQUAL;
    112    case PIPE_FUNC_LEQUAL:
    113       return SVGA3D_COMPARISON_LESS_EQUAL;
    114    case PIPE_FUNC_GREATER:
    115       return SVGA3D_COMPARISON_GREATER;
    116    case PIPE_FUNC_NOTEQUAL:
    117       return SVGA3D_COMPARISON_NOT_EQUAL;
    118    case PIPE_FUNC_GEQUAL:
    119       return SVGA3D_COMPARISON_GREATER_EQUAL;
    120    case PIPE_FUNC_ALWAYS:
    121       return SVGA3D_COMPARISON_ALWAYS;
    122    default:
    123       assert(!"Invalid comparison function");
    124       return SVGA3D_COMPARISON_ALWAYS;
    125    }
    126 }
    127 
    128 
    129 /**
    130  * Translate filtering state to vgpu10 format.
    131  */
    132 static SVGA3dFilter
    133 translate_filter_mode(unsigned img_filter,
    134                       unsigned min_filter,
    135                       unsigned mag_filter,
    136                       boolean anisotropic,
    137                       boolean compare)
    138 {
    139    SVGA3dFilter mode = 0;
    140 
    141    if (img_filter == PIPE_TEX_FILTER_LINEAR)
    142       mode |= SVGA3D_FILTER_MIP_LINEAR;
    143    if (min_filter == PIPE_TEX_FILTER_LINEAR)
    144       mode |= SVGA3D_FILTER_MIN_LINEAR;
    145    if (mag_filter == PIPE_TEX_FILTER_LINEAR)
    146       mode |= SVGA3D_FILTER_MAG_LINEAR;
    147    if (anisotropic)
    148       mode |= SVGA3D_FILTER_ANISOTROPIC;
    149    if (compare)
    150       mode |= SVGA3D_FILTER_COMPARE;
    151 
    152    return mode;
    153 }
    154 
    155 
    156 /**
    157  * Define a vgpu10 sampler state.
    158  */
    159 static void
    160 define_sampler_state_object(struct svga_context *svga,
    161                             struct svga_sampler_state *ss,
    162                             const struct pipe_sampler_state *ps)
    163 {
    164    uint8_t max_aniso = (uint8_t) 255; /* XXX fix me */
    165    boolean anisotropic;
    166    uint8 compare_func;
    167    SVGA3dFilter filter;
    168    SVGA3dRGBAFloat bcolor;
    169    unsigned try;
    170    float min_lod, max_lod;
    171 
    172    assert(svga_have_vgpu10(svga));
    173 
    174    anisotropic = ss->aniso_level > 1.0f;
    175 
    176    filter = translate_filter_mode(ps->min_mip_filter,
    177                                   ps->min_img_filter,
    178                                   ps->mag_img_filter,
    179                                   anisotropic,
    180                                   ss->compare_mode);
    181 
    182    compare_func = translate_comparison_func(ss->compare_func);
    183 
    184    COPY_4V(bcolor.value, ps->border_color.f);
    185 
    186    ss->id = util_bitmask_add(svga->sampler_object_id_bm);
    187 
    188    assert(ps->min_lod <= ps->max_lod);
    189 
    190    if (ps->min_mip_filter == PIPE_TEX_MIPFILTER_NONE) {
    191       /* just use the base level image */
    192       min_lod = max_lod = 0.0f;
    193    }
    194    else {
    195       min_lod = ps->min_lod;
    196       max_lod = ps->max_lod;
    197    }
    198 
    199    /* Loop in case command buffer is full and we need to flush and retry */
    200    for (try = 0; try < 2; try++) {
    201       enum pipe_error ret =
    202          SVGA3D_vgpu10_DefineSamplerState(svga->swc,
    203                                           ss->id,
    204                                           filter,
    205                                           ss->addressu,
    206                                           ss->addressv,
    207                                           ss->addressw,
    208                                           ss->lod_bias, /* float */
    209                                           max_aniso,
    210                                           compare_func,
    211                                           bcolor,
    212                                           min_lod,       /* float */
    213                                           max_lod);      /* float */
    214       if (ret == PIPE_OK)
    215          return;
    216       svga_context_flush(svga, NULL);
    217    }
    218 }
    219 
    220 
    221 static void *
    222 svga_create_sampler_state(struct pipe_context *pipe,
    223                           const struct pipe_sampler_state *sampler)
    224 {
    225    struct svga_context *svga = svga_context(pipe);
    226    struct svga_sampler_state *cso = CALLOC_STRUCT( svga_sampler_state );
    227 
    228    if (!cso)
    229       return NULL;
    230 
    231    cso->mipfilter = translate_mip_filter(sampler->min_mip_filter);
    232    cso->magfilter = translate_img_filter( sampler->mag_img_filter );
    233    cso->minfilter = translate_img_filter( sampler->min_img_filter );
    234    cso->aniso_level = MAX2( sampler->max_anisotropy, 1 );
    235    if (sampler->max_anisotropy)
    236       cso->magfilter = cso->minfilter = SVGA3D_TEX_FILTER_ANISOTROPIC;
    237    cso->lod_bias = sampler->lod_bias;
    238    cso->addressu = translate_wrap_mode(sampler->wrap_s);
    239    cso->addressv = translate_wrap_mode(sampler->wrap_t);
    240    cso->addressw = translate_wrap_mode(sampler->wrap_r);
    241    cso->normalized_coords = sampler->normalized_coords;
    242    cso->compare_mode = sampler->compare_mode;
    243    cso->compare_func = sampler->compare_func;
    244 
    245    {
    246       uint32 r = float_to_ubyte(sampler->border_color.f[0]);
    247       uint32 g = float_to_ubyte(sampler->border_color.f[1]);
    248       uint32 b = float_to_ubyte(sampler->border_color.f[2]);
    249       uint32 a = float_to_ubyte(sampler->border_color.f[3]);
    250 
    251       cso->bordercolor = (a << 24) | (r << 16) | (g << 8) | b;
    252    }
    253 
    254    /* No SVGA3D support for:
    255     *    - min/max LOD clamping
    256     */
    257    cso->min_lod = 0;
    258    cso->view_min_lod = MAX2((int) (sampler->min_lod + 0.5), 0);
    259    cso->view_max_lod = MAX2((int) (sampler->max_lod + 0.5), 0);
    260 
    261    /* Use min_mipmap */
    262    if (svga->debug.use_min_mipmap) {
    263       if (cso->view_min_lod == cso->view_max_lod) {
    264          cso->min_lod = cso->view_min_lod;
    265          cso->view_min_lod = 0;
    266          cso->view_max_lod = 1000; /* Just a high number */
    267          cso->mipfilter = SVGA3D_TEX_FILTER_NONE;
    268       }
    269    }
    270 
    271    if (svga_have_vgpu10(svga)) {
    272       define_sampler_state_object(svga, cso, sampler);
    273    }
    274 
    275    SVGA_DBG(DEBUG_VIEWS, "min %u, view(min %u, max %u) lod, mipfilter %s\n",
    276             cso->min_lod, cso->view_min_lod, cso->view_max_lod,
    277             cso->mipfilter == SVGA3D_TEX_FILTER_NONE ? "SVGA3D_TEX_FILTER_NONE" : "SOMETHING");
    278 
    279    svga->hud.num_sampler_objects++;
    280    SVGA_STATS_COUNT_INC(svga_screen(svga->pipe.screen)->sws,
    281                         SVGA_STATS_COUNT_SAMPLER);
    282 
    283    return cso;
    284 }
    285 
    286 
    287 static void
    288 svga_bind_sampler_states(struct pipe_context *pipe,
    289                          enum pipe_shader_type shader,
    290                          unsigned start,
    291                          unsigned num,
    292                          void **samplers)
    293 {
    294    struct svga_context *svga = svga_context(pipe);
    295    unsigned i;
    296    boolean any_change = FALSE;
    297 
    298    assert(shader < PIPE_SHADER_TYPES);
    299    assert(start + num <= PIPE_MAX_SAMPLERS);
    300 
    301    /* Pre-VGPU10 only supports FS textures */
    302    if (!svga_have_vgpu10(svga) && shader != PIPE_SHADER_FRAGMENT)
    303       return;
    304 
    305    for (i = 0; i < num; i++) {
    306       if (svga->curr.sampler[shader][start + i] != samplers[i])
    307          any_change = TRUE;
    308       svga->curr.sampler[shader][start + i] = samplers[i];
    309    }
    310 
    311    if (!any_change) {
    312       return;
    313    }
    314 
    315    /* find highest non-null sampler[] entry */
    316    {
    317       unsigned j = MAX2(svga->curr.num_samplers[shader], start + num);
    318       while (j > 0 && svga->curr.sampler[shader][j - 1] == NULL)
    319          j--;
    320       svga->curr.num_samplers[shader] = j;
    321    }
    322 
    323    svga->dirty |= SVGA_NEW_SAMPLER;
    324 }
    325 
    326 
    327 static void
    328 svga_delete_sampler_state(struct pipe_context *pipe, void *sampler)
    329 {
    330    struct svga_sampler_state *ss = (struct svga_sampler_state *) sampler;
    331    struct svga_context *svga = svga_context(pipe);
    332 
    333    if (svga_have_vgpu10(svga)) {
    334       enum pipe_error ret;
    335 
    336       svga_hwtnl_flush_retry(svga);
    337 
    338       ret = SVGA3D_vgpu10_DestroySamplerState(svga->swc, ss->id);
    339       if (ret != PIPE_OK) {
    340          svga_context_flush(svga, NULL);
    341          ret = SVGA3D_vgpu10_DestroySamplerState(svga->swc, ss->id);
    342       }
    343       util_bitmask_clear(svga->sampler_object_id_bm, ss->id);
    344    }
    345 
    346    FREE(sampler);
    347    svga->hud.num_sampler_objects--;
    348 }
    349 
    350 
    351 static struct pipe_sampler_view *
    352 svga_create_sampler_view(struct pipe_context *pipe,
    353                          struct pipe_resource *texture,
    354                          const struct pipe_sampler_view *templ)
    355 {
    356    struct svga_context *svga = svga_context(pipe);
    357    struct svga_pipe_sampler_view *sv = CALLOC_STRUCT(svga_pipe_sampler_view);
    358 
    359    if (!sv) {
    360       return NULL;
    361    }
    362 
    363    sv->base = *templ;
    364    sv->base.reference.count = 1;
    365    sv->base.texture = NULL;
    366    pipe_resource_reference(&sv->base.texture, texture);
    367 
    368    sv->base.context = pipe;
    369    sv->id = SVGA3D_INVALID_ID;
    370 
    371    svga->hud.num_samplerview_objects++;
    372    SVGA_STATS_COUNT_INC(svga_screen(svga->pipe.screen)->sws,
    373                         SVGA_STATS_COUNT_SAMPLERVIEW);
    374 
    375    return &sv->base;
    376 }
    377 
    378 
    379 static void
    380 svga_sampler_view_destroy(struct pipe_context *pipe,
    381                           struct pipe_sampler_view *view)
    382 {
    383    struct svga_context *svga = svga_context(pipe);
    384    struct svga_pipe_sampler_view *sv = svga_pipe_sampler_view(view);
    385 
    386    if (svga_have_vgpu10(svga) && sv->id != SVGA3D_INVALID_ID) {
    387       if (view->context != pipe) {
    388          /* The SVGA3D device will generate an error (and on Linux, cause
    389           * us to abort) if we try to destroy a shader resource view from
    390           * a context other than the one it was created with.  Skip the
    391           * SVGA3D_vgpu10_DestroyShaderResourceView() and leak the sampler
    392           * view for now.  This should only sometimes happen when a shared
    393           * texture is deleted.
    394           */
    395          _debug_printf("context mismatch in %s\n", __func__);
    396       }
    397       else {
    398          enum pipe_error ret;
    399 
    400          svga_hwtnl_flush_retry(svga); /* XXX is this needed? */
    401 
    402          ret = SVGA3D_vgpu10_DestroyShaderResourceView(svga->swc, sv->id);
    403          if (ret != PIPE_OK) {
    404             svga_context_flush(svga, NULL);
    405             ret = SVGA3D_vgpu10_DestroyShaderResourceView(svga->swc, sv->id);
    406          }
    407          util_bitmask_clear(svga->sampler_view_id_bm, sv->id);
    408       }
    409    }
    410 
    411    pipe_resource_reference(&sv->base.texture, NULL);
    412 
    413    FREE(sv);
    414    svga->hud.num_samplerview_objects--;
    415 }
    416 
    417 
    418 static void
    419 svga_set_sampler_views(struct pipe_context *pipe,
    420                        enum pipe_shader_type shader,
    421                        unsigned start,
    422                        unsigned num,
    423                        struct pipe_sampler_view **views)
    424 {
    425    struct svga_context *svga = svga_context(pipe);
    426    unsigned flag_1d = 0;
    427    unsigned flag_srgb = 0;
    428    unsigned flag_rect = 0;
    429    unsigned flag_buf = 0;
    430    uint i;
    431    boolean any_change = FALSE;
    432 
    433    assert(shader < PIPE_SHADER_TYPES);
    434    assert(start + num <= ARRAY_SIZE(svga->curr.sampler_views[shader]));
    435 
    436    /* Pre-VGPU10 only supports FS textures */
    437    if (!svga_have_vgpu10(svga) && shader != PIPE_SHADER_FRAGMENT)
    438       return;
    439 
    440    SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_SETSAMPLERVIEWS);
    441 
    442    /* This bit of code works around a quirk in the CSO module.
    443     * If start=num=0 it means all sampler views should be released.
    444     * Note that the CSO module treats sampler views for fragment shaders
    445     * differently than other shader types.
    446     */
    447    if (start == 0 && num == 0 && svga->curr.num_sampler_views[shader] > 0) {
    448       for (i = 0; i < svga->curr.num_sampler_views[shader]; i++) {
    449          pipe_sampler_view_release(pipe, &svga->curr.sampler_views[shader][i]);
    450       }
    451       any_change = TRUE;
    452    }
    453 
    454    for (i = 0; i < num; i++) {
    455       enum pipe_texture_target target;
    456 
    457       if (svga->curr.sampler_views[shader][start + i] != views[i]) {
    458          /* Note: we're using pipe_sampler_view_release() here to work around
    459           * a possible crash when the old view belongs to another context that
    460           * was already destroyed.
    461           */
    462          pipe_sampler_view_release(pipe, &svga->curr.sampler_views[shader][start + i]);
    463          pipe_sampler_view_reference(&svga->curr.sampler_views[shader][start + i],
    464                                      views[i]);
    465          any_change = TRUE;
    466       }
    467 
    468       if (!views[i])
    469          continue;
    470 
    471       if (util_format_is_srgb(views[i]->format))
    472          flag_srgb |= 1 << (start + i);
    473 
    474       target = views[i]->texture->target;
    475       if (target == PIPE_TEXTURE_1D)
    476          flag_1d |= 1 << (start + i);
    477       else if (target == PIPE_TEXTURE_RECT)
    478          flag_rect |= 1 << (start + i);
    479       else if (target == PIPE_BUFFER)
    480          flag_buf |= 1 << (start + i);
    481    }
    482 
    483    if (!any_change) {
    484       goto done;
    485    }
    486 
    487    /* find highest non-null sampler_views[] entry */
    488    {
    489       unsigned j = MAX2(svga->curr.num_sampler_views[shader], start + num);
    490       while (j > 0 && svga->curr.sampler_views[shader][j - 1] == NULL)
    491          j--;
    492       svga->curr.num_sampler_views[shader] = j;
    493    }
    494 
    495    svga->dirty |= SVGA_NEW_TEXTURE_BINDING;
    496 
    497    if (flag_srgb != svga->curr.tex_flags.flag_srgb ||
    498        flag_1d != svga->curr.tex_flags.flag_1d) {
    499       svga->dirty |= SVGA_NEW_TEXTURE_FLAGS;
    500       svga->curr.tex_flags.flag_1d = flag_1d;
    501       svga->curr.tex_flags.flag_srgb = flag_srgb;
    502    }
    503 
    504    if (flag_rect != svga->curr.tex_flags.flag_rect ||
    505        flag_buf != svga->curr.tex_flags.flag_buf)
    506    {
    507       /* Need to re-emit texture constants */
    508       svga->dirty |= SVGA_NEW_TEXTURE_CONSTS;
    509       svga->curr.tex_flags.flag_rect = flag_rect;
    510       svga->curr.tex_flags.flag_buf = flag_buf;
    511    }
    512 
    513    /* Check if any of the sampler view resources collide with the framebuffer
    514     * color buffers or depth stencil resource. If so, set the NEW_FRAME_BUFFER
    515     * dirty bit so that emit_framebuffer can be invoked to create backed view
    516     * for the conflicted surface view.
    517     */
    518    if (svga_check_sampler_framebuffer_resource_collision(svga, shader)) {
    519       svga->dirty |= SVGA_NEW_FRAME_BUFFER;
    520    }
    521 
    522 done:
    523    SVGA_STATS_TIME_POP(svga_sws(svga));
    524 }
    525 
    526 /**
    527  * Clean up sampler, sampler view state at context destruction time
    528  */
    529 void
    530 svga_cleanup_sampler_state(struct svga_context *svga)
    531 {
    532    enum pipe_shader_type shader;
    533 
    534    for (shader = 0; shader <= PIPE_SHADER_GEOMETRY; shader++) {
    535       unsigned i;
    536 
    537       for (i = 0; i < svga->state.hw_draw.num_sampler_views[shader]; i++) {
    538          pipe_sampler_view_release(&svga->pipe,
    539                                    &svga->state.hw_draw.sampler_views[shader][i]);
    540       }
    541    }
    542 
    543    /* free polygon stipple state */
    544    if (svga->polygon_stipple.sampler) {
    545       svga->pipe.delete_sampler_state(&svga->pipe, svga->polygon_stipple.sampler);
    546    }
    547 
    548    if (svga->polygon_stipple.sampler_view) {
    549       svga->pipe.sampler_view_destroy(&svga->pipe,
    550                                       &svga->polygon_stipple.sampler_view->base);
    551    }
    552    pipe_resource_reference(&svga->polygon_stipple.texture, NULL);
    553 }
    554 
    555 void
    556 svga_init_sampler_functions( struct svga_context *svga )
    557 {
    558    svga->pipe.create_sampler_state = svga_create_sampler_state;
    559    svga->pipe.bind_sampler_states = svga_bind_sampler_states;
    560    svga->pipe.delete_sampler_state = svga_delete_sampler_state;
    561    svga->pipe.set_sampler_views = svga_set_sampler_views;
    562    svga->pipe.create_sampler_view = svga_create_sampler_view;
    563    svga->pipe.sampler_view_destroy = svga_sampler_view_destroy;
    564 }
    565