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_state.h"
     35 #include "svga_cmd.h"
     36 
     37 
     38 void svga_cleanup_tss_binding(struct svga_context *svga)
     39 {
     40    int i;
     41    unsigned count = MAX2( svga->curr.num_sampler_views,
     42                           svga->state.hw_draw.num_views );
     43 
     44    for (i = 0; i < count; i++) {
     45       struct svga_hw_view_state *view = &svga->state.hw_draw.views[i];
     46 
     47       svga_sampler_view_reference(&view->v, NULL);
     48       pipe_sampler_view_reference( &svga->curr.sampler_views[i], NULL );
     49       pipe_resource_reference( &view->texture, NULL );
     50 
     51       view->dirty = 1;
     52    }
     53 }
     54 
     55 
     56 struct bind_queue {
     57    struct {
     58       unsigned unit;
     59       struct svga_hw_view_state *view;
     60    } bind[PIPE_MAX_SAMPLERS];
     61 
     62    unsigned bind_count;
     63 };
     64 
     65 
     66 static enum pipe_error
     67 update_tss_binding(struct svga_context *svga,
     68                    unsigned dirty )
     69 {
     70    boolean reemit = svga->rebind.texture_samplers;
     71    unsigned i;
     72    unsigned count = MAX2( svga->curr.num_sampler_views,
     73                           svga->state.hw_draw.num_views );
     74    unsigned min_lod;
     75    unsigned max_lod;
     76 
     77    struct bind_queue queue;
     78 
     79    queue.bind_count = 0;
     80 
     81    for (i = 0; i < count; i++) {
     82       const struct svga_sampler_state *s = svga->curr.sampler[i];
     83       struct svga_hw_view_state *view = &svga->state.hw_draw.views[i];
     84       struct pipe_resource *texture = NULL;
     85       struct pipe_sampler_view *sv = svga->curr.sampler_views[i];
     86 
     87       /* get min max lod */
     88       if (sv) {
     89          min_lod = MAX2(0, (s->view_min_lod + sv->u.tex.first_level));
     90          max_lod = MIN2(s->view_max_lod + sv->u.tex.first_level,
     91                         sv->texture->last_level);
     92          texture = sv->texture;
     93       } else {
     94          min_lod = 0;
     95          max_lod = 0;
     96       }
     97 
     98       if (view->texture != texture ||
     99           view->min_lod != min_lod ||
    100           view->max_lod != max_lod) {
    101 
    102          svga_sampler_view_reference(&view->v, NULL);
    103          pipe_resource_reference( &view->texture, texture );
    104 
    105          view->dirty = TRUE;
    106          view->min_lod = min_lod;
    107          view->max_lod = max_lod;
    108 
    109          if (texture)
    110             view->v = svga_get_tex_sampler_view(&svga->pipe,
    111                                                 texture,
    112                                                 min_lod,
    113                                                 max_lod);
    114       }
    115 
    116       /*
    117        * We need to reemit non-null texture bindings, even when they are not
    118        * dirty, to ensure that the resources are paged in.
    119        */
    120 
    121       if (view->dirty ||
    122           (reemit && view->v)) {
    123          queue.bind[queue.bind_count].unit = i;
    124          queue.bind[queue.bind_count].view = view;
    125          queue.bind_count++;
    126       }
    127       if (!view->dirty && view->v) {
    128          svga_validate_sampler_view(svga, view->v);
    129       }
    130    }
    131 
    132    svga->state.hw_draw.num_views = svga->curr.num_sampler_views;
    133 
    134    if (queue.bind_count) {
    135       SVGA3dTextureState *ts;
    136 
    137       if (SVGA3D_BeginSetTextureState( svga->swc,
    138                                        &ts,
    139                                        queue.bind_count ) != PIPE_OK)
    140          goto fail;
    141 
    142       for (i = 0; i < queue.bind_count; i++) {
    143          struct svga_winsys_surface *handle;
    144 
    145          ts[i].stage = queue.bind[i].unit;
    146          ts[i].name = SVGA3D_TS_BIND_TEXTURE;
    147 
    148          if (queue.bind[i].view->v) {
    149             handle = queue.bind[i].view->v->handle;
    150          }
    151          else {
    152             handle = NULL;
    153          }
    154          svga->swc->surface_relocation(svga->swc,
    155                                        &ts[i].value,
    156                                        handle,
    157                                        SVGA_RELOC_READ);
    158 
    159          queue.bind[i].view->dirty = FALSE;
    160       }
    161 
    162       SVGA_FIFOCommitAll( svga->swc );
    163    }
    164 
    165    svga->rebind.texture_samplers = FALSE;
    166 
    167    return 0;
    168 
    169 fail:
    170    return PIPE_ERROR_OUT_OF_MEMORY;
    171 }
    172 
    173 
    174 /*
    175  * Rebind textures.
    176  *
    177  * Similar to update_tss_binding, but without any state checking/update.
    178  *
    179  * Called at the beginning of every new command buffer to ensure that
    180  * non-dirty textures are properly paged-in.
    181  */
    182 enum pipe_error
    183 svga_reemit_tss_bindings(struct svga_context *svga)
    184 {
    185    unsigned i;
    186    enum pipe_error ret;
    187    struct bind_queue queue;
    188 
    189    assert(svga->rebind.texture_samplers);
    190 
    191    queue.bind_count = 0;
    192 
    193    for (i = 0; i < svga->state.hw_draw.num_views; i++) {
    194       struct svga_hw_view_state *view = &svga->state.hw_draw.views[i];
    195 
    196       if (view->v) {
    197          queue.bind[queue.bind_count].unit = i;
    198          queue.bind[queue.bind_count].view = view;
    199          queue.bind_count++;
    200       }
    201    }
    202 
    203    if (queue.bind_count) {
    204       SVGA3dTextureState *ts;
    205 
    206       ret = SVGA3D_BeginSetTextureState(svga->swc,
    207                                         &ts,
    208                                         queue.bind_count);
    209       if (ret != PIPE_OK) {
    210          return ret;
    211       }
    212 
    213       for (i = 0; i < queue.bind_count; i++) {
    214          struct svga_winsys_surface *handle;
    215 
    216          ts[i].stage = queue.bind[i].unit;
    217          ts[i].name = SVGA3D_TS_BIND_TEXTURE;
    218 
    219          assert(queue.bind[i].view->v);
    220          handle = queue.bind[i].view->v->handle;
    221          svga->swc->surface_relocation(svga->swc,
    222                                        &ts[i].value,
    223                                        handle,
    224                                        SVGA_RELOC_READ);
    225       }
    226 
    227       SVGA_FIFOCommitAll(svga->swc);
    228    }
    229 
    230    svga->rebind.texture_samplers = FALSE;
    231 
    232    return PIPE_OK;
    233 }
    234 
    235 
    236 struct svga_tracked_state svga_hw_tss_binding = {
    237    "texture binding emit",
    238    SVGA_NEW_TEXTURE_BINDING |
    239    SVGA_NEW_SAMPLER,
    240    update_tss_binding
    241 };
    242 
    243 
    244 /***********************************************************************
    245  */
    246 
    247 struct ts_queue {
    248    unsigned ts_count;
    249    SVGA3dTextureState ts[PIPE_MAX_SAMPLERS*SVGA3D_TS_MAX];
    250 };
    251 
    252 
    253 #define EMIT_TS(svga, unit, val, token, fail)                           \
    254 do {                                                                    \
    255    assert(unit < Elements(svga->state.hw_draw.ts));                     \
    256    assert(SVGA3D_TS_##token < Elements(svga->state.hw_draw.ts[unit]));  \
    257    if (svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] != val) {        \
    258       svga_queue_tss( &queue, unit, SVGA3D_TS_##token, val );           \
    259       svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] = val;            \
    260    }                                                                    \
    261 } while (0)
    262 
    263 #define EMIT_TS_FLOAT(svga, unit, fvalue, token, fail)                  \
    264 do {                                                                    \
    265    unsigned val = fui(fvalue);                                          \
    266    assert(unit < Elements(svga->state.hw_draw.ts));                     \
    267    assert(SVGA3D_TS_##token < Elements(svga->state.hw_draw.ts[unit]));  \
    268    if (svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] != val) {        \
    269       svga_queue_tss( &queue, unit, SVGA3D_TS_##token, val );           \
    270       svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] = val;            \
    271    }                                                                    \
    272 } while (0)
    273 
    274 
    275 static INLINE void
    276 svga_queue_tss( struct ts_queue *q,
    277                 unsigned unit,
    278                 unsigned tss,
    279                 unsigned value )
    280 {
    281    assert(q->ts_count < sizeof(q->ts)/sizeof(q->ts[0]));
    282    q->ts[q->ts_count].stage = unit;
    283    q->ts[q->ts_count].name = tss;
    284    q->ts[q->ts_count].value = value;
    285    q->ts_count++;
    286 }
    287 
    288 
    289 static enum pipe_error
    290 update_tss(struct svga_context *svga,
    291            unsigned dirty )
    292 {
    293    unsigned i;
    294    struct ts_queue queue;
    295 
    296    queue.ts_count = 0;
    297    for (i = 0; i < svga->curr.num_samplers; i++) {
    298       if (svga->curr.sampler[i]) {
    299          const struct svga_sampler_state *curr = svga->curr.sampler[i];
    300 
    301          EMIT_TS(svga, i, curr->mipfilter, MIPFILTER, fail);
    302          EMIT_TS(svga, i, curr->min_lod, TEXTURE_MIPMAP_LEVEL, fail);
    303          EMIT_TS(svga, i, curr->magfilter, MAGFILTER, fail);
    304          EMIT_TS(svga, i, curr->minfilter, MINFILTER, fail);
    305          EMIT_TS(svga, i, curr->aniso_level, TEXTURE_ANISOTROPIC_LEVEL, fail);
    306          EMIT_TS_FLOAT(svga, i, curr->lod_bias, TEXTURE_LOD_BIAS, fail);
    307          EMIT_TS(svga, i, curr->addressu, ADDRESSU, fail);
    308          EMIT_TS(svga, i, curr->addressw, ADDRESSW, fail);
    309          EMIT_TS(svga, i, curr->bordercolor, BORDERCOLOR, fail);
    310          // TEXCOORDINDEX -- hopefully not needed
    311 
    312          if (svga->curr.tex_flags.flag_1d & (1 << i)) {
    313             EMIT_TS(svga, i, SVGA3D_TEX_ADDRESS_WRAP, ADDRESSV, fail);
    314          }
    315          else
    316             EMIT_TS(svga, i, curr->addressv, ADDRESSV, fail);
    317 
    318          if (svga->curr.tex_flags.flag_srgb & (1 << i))
    319             EMIT_TS_FLOAT(svga, i, 2.2f, GAMMA, fail);
    320          else
    321             EMIT_TS_FLOAT(svga, i, 1.0f, GAMMA, fail);
    322 
    323       }
    324    }
    325 
    326    if (queue.ts_count) {
    327       SVGA3dTextureState *ts;
    328 
    329       if (SVGA3D_BeginSetTextureState( svga->swc,
    330                                        &ts,
    331                                        queue.ts_count ) != PIPE_OK)
    332          goto fail;
    333 
    334       memcpy( ts,
    335               queue.ts,
    336               queue.ts_count * sizeof queue.ts[0]);
    337 
    338       SVGA_FIFOCommitAll( svga->swc );
    339    }
    340 
    341    return PIPE_OK;
    342 
    343 fail:
    344    /* XXX: need to poison cached hardware state on failure to ensure
    345     * dirty state gets re-emitted.  Fix this by re-instating partial
    346     * FIFOCommit command and only updating cached hw state once the
    347     * initial allocation has succeeded.
    348     */
    349    memset(svga->state.hw_draw.ts, 0xcd, sizeof(svga->state.hw_draw.ts));
    350 
    351    return PIPE_ERROR_OUT_OF_MEMORY;
    352 }
    353 
    354 
    355 struct svga_tracked_state svga_hw_tss = {
    356    "texture state emit",
    357    (SVGA_NEW_SAMPLER |
    358     SVGA_NEW_TEXTURE_FLAGS),
    359    update_tss
    360 };
    361 
    362