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 "util/u_inlines.h"
     27 #include "util/u_memory.h"
     28 #include "pipe/p_defines.h"
     29 #include "util/u_math.h"
     30 
     31 #include "svga_sampler_view.h"
     32 #include "svga_winsys.h"
     33 #include "svga_context.h"
     34 #include "svga_shader.h"
     35 #include "svga_state.h"
     36 #include "svga_cmd.h"
     37 
     38 
     39 /**
     40  * Called when tearing down a context to free resources and samplers.
     41  */
     42 void svga_cleanup_tss_binding(struct svga_context *svga)
     43 {
     44    const enum pipe_shader_type shader = PIPE_SHADER_FRAGMENT;
     45    unsigned i;
     46 
     47    for (i = 0; i < ARRAY_SIZE(svga->state.hw_draw.views); i++) {
     48       struct svga_hw_view_state *view = &svga->state.hw_draw.views[i];
     49       if (view) {
     50          svga_sampler_view_reference(&view->v, NULL);
     51          pipe_sampler_view_release(&svga->pipe,
     52                                    &svga->curr.sampler_views[shader][i]);
     53          pipe_resource_reference(&view->texture, NULL);
     54          view->dirty = TRUE;
     55       }
     56    }
     57 }
     58 
     59 
     60 struct bind_queue {
     61    struct {
     62       unsigned unit;
     63       struct svga_hw_view_state *view;
     64    } bind[PIPE_MAX_SAMPLERS];
     65 
     66    unsigned bind_count;
     67 };
     68 
     69 
     70 /**
     71  * Update the texture binding for one texture unit.
     72  */
     73 static void
     74 emit_tex_binding_unit(struct svga_context *svga,
     75                       unsigned unit,
     76                       const struct svga_sampler_state *s,
     77                       const struct pipe_sampler_view *sv,
     78                       struct svga_hw_view_state *view,
     79                       boolean reemit,
     80                       struct bind_queue *queue)
     81 {
     82    struct pipe_resource *texture = NULL;
     83    unsigned last_level, min_lod, max_lod;
     84 
     85    /* get min max lod */
     86    if (sv && s) {
     87       if (s->mipfilter == SVGA3D_TEX_FILTER_NONE) {
     88          /* just use the base level image */
     89          min_lod = max_lod = sv->u.tex.first_level;
     90       }
     91       else {
     92          last_level = MIN2(sv->u.tex.last_level, sv->texture->last_level);
     93          min_lod = s->view_min_lod + sv->u.tex.first_level;
     94          min_lod = MIN2(min_lod, last_level);
     95          max_lod = MIN2(s->view_max_lod + sv->u.tex.first_level, last_level);
     96       }
     97       texture = sv->texture;
     98    }
     99    else {
    100       min_lod = 0;
    101       max_lod = 0;
    102    }
    103 
    104    if (view->texture != texture ||
    105        view->min_lod != min_lod ||
    106        view->max_lod != max_lod) {
    107 
    108       svga_sampler_view_reference(&view->v, NULL);
    109       pipe_resource_reference( &view->texture, texture );
    110 
    111       view->dirty = TRUE;
    112       view->min_lod = min_lod;
    113       view->max_lod = max_lod;
    114 
    115       if (texture) {
    116          view->v = svga_get_tex_sampler_view(&svga->pipe,
    117                                              texture,
    118                                              min_lod,
    119                                              max_lod);
    120       }
    121    }
    122 
    123    /*
    124     * We need to reemit non-null texture bindings, even when they are not
    125     * dirty, to ensure that the resources are paged in.
    126     */
    127    if (view->dirty || (reemit && view->v)) {
    128       queue->bind[queue->bind_count].unit = unit;
    129       queue->bind[queue->bind_count].view = view;
    130       queue->bind_count++;
    131    }
    132 
    133    if (!view->dirty && view->v) {
    134       svga_validate_sampler_view(svga, view->v);
    135    }
    136 }
    137 
    138 
    139 static enum pipe_error
    140 update_tss_binding(struct svga_context *svga,
    141                    unsigned dirty )
    142 {
    143    const enum pipe_shader_type shader = PIPE_SHADER_FRAGMENT;
    144    boolean reemit = svga->rebind.flags.texture_samplers;
    145    unsigned i;
    146    unsigned count = MAX2( svga->curr.num_sampler_views[shader],
    147                           svga->state.hw_draw.num_views );
    148 
    149    struct bind_queue queue;
    150 
    151    if (svga_have_vgpu10(svga))
    152       return PIPE_OK;
    153 
    154    queue.bind_count = 0;
    155 
    156    for (i = 0; i < count; i++) {
    157       emit_tex_binding_unit(svga, i,
    158                             svga->curr.sampler[shader][i],
    159                             svga->curr.sampler_views[shader][i],
    160                             &svga->state.hw_draw.views[i],
    161                             reemit,
    162                             &queue);
    163    }
    164 
    165    svga->state.hw_draw.num_views = svga->curr.num_sampler_views[shader];
    166 
    167    /* Polygon stipple */
    168    if (svga->curr.rast->templ.poly_stipple_enable) {
    169       const unsigned unit = svga->state.hw_draw.fs->pstipple_sampler_unit;
    170       emit_tex_binding_unit(svga, unit,
    171                             svga->polygon_stipple.sampler,
    172                             &svga->polygon_stipple.sampler_view->base,
    173                             &svga->state.hw_draw.views[unit],
    174                             reemit,
    175                             &queue);
    176    }
    177 
    178    if (queue.bind_count) {
    179       SVGA3dTextureState *ts;
    180 
    181       if (SVGA3D_BeginSetTextureState( svga->swc,
    182                                        &ts,
    183                                        queue.bind_count ) != PIPE_OK)
    184          goto fail;
    185 
    186       for (i = 0; i < queue.bind_count; i++) {
    187          struct svga_winsys_surface *handle;
    188 
    189          ts[i].stage = queue.bind[i].unit;
    190          ts[i].name = SVGA3D_TS_BIND_TEXTURE;
    191 
    192          if (queue.bind[i].view->v) {
    193             handle = queue.bind[i].view->v->handle;
    194          }
    195          else {
    196             handle = NULL;
    197          }
    198          svga->swc->surface_relocation(svga->swc,
    199                                        &ts[i].value,
    200                                        NULL,
    201                                        handle,
    202                                        SVGA_RELOC_READ);
    203 
    204          queue.bind[i].view->dirty = FALSE;
    205       }
    206 
    207       SVGA_FIFOCommitAll( svga->swc );
    208    }
    209 
    210    svga->rebind.flags.texture_samplers = FALSE;
    211 
    212    return PIPE_OK;
    213 
    214 fail:
    215    return PIPE_ERROR_OUT_OF_MEMORY;
    216 }
    217 
    218 
    219 /*
    220  * Rebind textures.
    221  *
    222  * Similar to update_tss_binding, but without any state checking/update.
    223  *
    224  * Called at the beginning of every new command buffer to ensure that
    225  * non-dirty textures are properly paged-in.
    226  */
    227 enum pipe_error
    228 svga_reemit_tss_bindings(struct svga_context *svga)
    229 {
    230    unsigned i;
    231    enum pipe_error ret;
    232    struct bind_queue queue;
    233 
    234    assert(!svga_have_vgpu10(svga));
    235    assert(svga->rebind.flags.texture_samplers);
    236 
    237    queue.bind_count = 0;
    238 
    239    for (i = 0; i < svga->state.hw_draw.num_views; i++) {
    240       struct svga_hw_view_state *view = &svga->state.hw_draw.views[i];
    241 
    242       if (view->v) {
    243          queue.bind[queue.bind_count].unit = i;
    244          queue.bind[queue.bind_count].view = view;
    245          queue.bind_count++;
    246       }
    247    }
    248 
    249    /* Polygon stipple */
    250    if (svga->curr.rast->templ.poly_stipple_enable) {
    251       const unsigned unit = svga->state.hw_draw.fs->pstipple_sampler_unit;
    252       struct svga_hw_view_state *view = &svga->state.hw_draw.views[unit];
    253 
    254       if (view->v) {
    255          queue.bind[queue.bind_count].unit = unit;
    256          queue.bind[queue.bind_count].view = view;
    257          queue.bind_count++;
    258       }
    259    }
    260 
    261    if (queue.bind_count) {
    262       SVGA3dTextureState *ts;
    263 
    264       ret = SVGA3D_BeginSetTextureState(svga->swc,
    265                                         &ts,
    266                                         queue.bind_count);
    267       if (ret != PIPE_OK) {
    268          return ret;
    269       }
    270 
    271       for (i = 0; i < queue.bind_count; i++) {
    272          struct svga_winsys_surface *handle;
    273 
    274          ts[i].stage = queue.bind[i].unit;
    275          ts[i].name = SVGA3D_TS_BIND_TEXTURE;
    276 
    277          assert(queue.bind[i].view->v);
    278          handle = queue.bind[i].view->v->handle;
    279          svga->swc->surface_relocation(svga->swc,
    280                                        &ts[i].value,
    281                                        NULL,
    282                                        handle,
    283                                        SVGA_RELOC_READ);
    284       }
    285 
    286       SVGA_FIFOCommitAll(svga->swc);
    287    }
    288 
    289    svga->rebind.flags.texture_samplers = FALSE;
    290 
    291    return PIPE_OK;
    292 }
    293 
    294 
    295 struct svga_tracked_state svga_hw_tss_binding = {
    296    "texture binding emit",
    297    SVGA_NEW_FRAME_BUFFER |
    298    SVGA_NEW_TEXTURE_BINDING |
    299    SVGA_NEW_STIPPLE |
    300    SVGA_NEW_SAMPLER,
    301    update_tss_binding
    302 };
    303 
    304 
    305 /***********************************************************************
    306  */
    307 
    308 struct ts_queue {
    309    unsigned ts_count;
    310    SVGA3dTextureState ts[PIPE_MAX_SAMPLERS*SVGA3D_TS_MAX];
    311 };
    312 
    313 
    314 static inline void
    315 svga_queue_tss( struct ts_queue *q,
    316                 unsigned unit,
    317                 unsigned tss,
    318                 unsigned value )
    319 {
    320    assert(q->ts_count < ARRAY_SIZE(q->ts));
    321    q->ts[q->ts_count].stage = unit;
    322    q->ts[q->ts_count].name = tss;
    323    q->ts[q->ts_count].value = value;
    324    q->ts_count++;
    325 }
    326 
    327 
    328 #define EMIT_TS(svga, unit, val, token)                                 \
    329 do {                                                                    \
    330    assert(unit < ARRAY_SIZE(svga->state.hw_draw.ts));                     \
    331    STATIC_ASSERT(SVGA3D_TS_##token < ARRAY_SIZE(svga->state.hw_draw.ts[unit])); \
    332    if (svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] != val) {        \
    333       svga_queue_tss( queue, unit, SVGA3D_TS_##token, val );            \
    334       svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] = val;            \
    335    }                                                                    \
    336 } while (0)
    337 
    338 #define EMIT_TS_FLOAT(svga, unit, fvalue, token)                        \
    339 do {                                                                    \
    340    unsigned val = fui(fvalue);                                          \
    341    assert(unit < ARRAY_SIZE(svga->state.hw_draw.ts));                     \
    342    STATIC_ASSERT(SVGA3D_TS_##token < ARRAY_SIZE(svga->state.hw_draw.ts[unit])); \
    343    if (svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] != val) {        \
    344       svga_queue_tss( queue, unit, SVGA3D_TS_##token, val );            \
    345       svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] = val;            \
    346    }                                                                    \
    347 } while (0)
    348 
    349 
    350 /**
    351  * Emit texture sampler state (tss) for one texture unit.
    352  */
    353 static void
    354 emit_tss_unit(struct svga_context *svga, unsigned unit,
    355               const struct svga_sampler_state *state,
    356               struct ts_queue *queue)
    357 {
    358    EMIT_TS(svga, unit, state->mipfilter, MIPFILTER);
    359    EMIT_TS(svga, unit, state->min_lod, TEXTURE_MIPMAP_LEVEL);
    360    EMIT_TS(svga, unit, state->magfilter, MAGFILTER);
    361    EMIT_TS(svga, unit, state->minfilter, MINFILTER);
    362    EMIT_TS(svga, unit, state->aniso_level, TEXTURE_ANISOTROPIC_LEVEL);
    363    EMIT_TS_FLOAT(svga, unit, state->lod_bias, TEXTURE_LOD_BIAS);
    364    EMIT_TS(svga, unit, state->addressu, ADDRESSU);
    365    EMIT_TS(svga, unit, state->addressw, ADDRESSW);
    366    EMIT_TS(svga, unit, state->bordercolor, BORDERCOLOR);
    367    // TEXCOORDINDEX -- hopefully not needed
    368 
    369    if (svga->curr.tex_flags.flag_1d & (1 << unit))
    370       EMIT_TS(svga, unit, SVGA3D_TEX_ADDRESS_WRAP, ADDRESSV);
    371    else
    372       EMIT_TS(svga, unit, state->addressv, ADDRESSV);
    373 
    374    if (svga->curr.tex_flags.flag_srgb & (1 << unit))
    375       EMIT_TS_FLOAT(svga, unit, 2.2f, GAMMA);
    376    else
    377       EMIT_TS_FLOAT(svga, unit, 1.0f, GAMMA);
    378 }
    379 
    380 static enum pipe_error
    381 update_tss(struct svga_context *svga,
    382            unsigned dirty )
    383 {
    384    const enum pipe_shader_type shader = PIPE_SHADER_FRAGMENT;
    385    unsigned i;
    386    struct ts_queue queue;
    387 
    388    if (svga_have_vgpu10(svga))
    389       return PIPE_OK;
    390 
    391    queue.ts_count = 0;
    392    for (i = 0; i < svga->curr.num_samplers[shader]; i++) {
    393       if (svga->curr.sampler[shader][i]) {
    394          const struct svga_sampler_state *curr = svga->curr.sampler[shader][i];
    395          emit_tss_unit(svga, i, curr, &queue);
    396       }
    397    }
    398 
    399    /* polygon stipple sampler */
    400    if (svga->curr.rast->templ.poly_stipple_enable) {
    401       emit_tss_unit(svga,
    402                     svga->state.hw_draw.fs->pstipple_sampler_unit,
    403                     svga->polygon_stipple.sampler,
    404                     &queue);
    405    }
    406 
    407    if (queue.ts_count) {
    408       SVGA3dTextureState *ts;
    409 
    410       if (SVGA3D_BeginSetTextureState( svga->swc,
    411                                        &ts,
    412                                        queue.ts_count ) != PIPE_OK)
    413          goto fail;
    414 
    415       memcpy( ts,
    416               queue.ts,
    417               queue.ts_count * sizeof queue.ts[0]);
    418 
    419       SVGA_FIFOCommitAll( svga->swc );
    420    }
    421 
    422    return PIPE_OK;
    423 
    424 fail:
    425    /* XXX: need to poison cached hardware state on failure to ensure
    426     * dirty state gets re-emitted.  Fix this by re-instating partial
    427     * FIFOCommit command and only updating cached hw state once the
    428     * initial allocation has succeeded.
    429     */
    430    memset(svga->state.hw_draw.ts, 0xcd, sizeof(svga->state.hw_draw.ts));
    431 
    432    return PIPE_ERROR_OUT_OF_MEMORY;
    433 }
    434 
    435 
    436 struct svga_tracked_state svga_hw_tss = {
    437    "texture state emit",
    438    (SVGA_NEW_SAMPLER |
    439     SVGA_NEW_STIPPLE |
    440     SVGA_NEW_TEXTURE_FLAGS),
    441    update_tss
    442 };
    443 
    444