Home | History | Annotate | Download | only in drm
      1 /**********************************************************
      2  * Copyright 2009-2015 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 
     27 #include "svga_cmd.h"
     28 
     29 #include "util/u_debug.h"
     30 #include "util/u_memory.h"
     31 #include "util/u_debug_stack.h"
     32 #include "util/u_debug_flush.h"
     33 #include "util/u_hash_table.h"
     34 #include "pipebuffer/pb_buffer.h"
     35 #include "pipebuffer/pb_validate.h"
     36 
     37 #include "svga_winsys.h"
     38 #include "vmw_context.h"
     39 #include "vmw_screen.h"
     40 #include "vmw_buffer.h"
     41 #include "vmw_surface.h"
     42 #include "vmw_fence.h"
     43 #include "vmw_shader.h"
     44 #include "vmw_query.h"
     45 
     46 #define VMW_COMMAND_SIZE (64*1024)
     47 #define VMW_SURFACE_RELOCS (1024)
     48 #define VMW_SHADER_RELOCS (1024)
     49 #define VMW_REGION_RELOCS (512)
     50 
     51 #define VMW_MUST_FLUSH_STACK 8
     52 
     53 /*
     54  * A factor applied to the maximum mob memory size to determine
     55  * the optimial time to preemptively flush the command buffer.
     56  * The constant is based on some performance trials with SpecViewperf.
     57  */
     58 #define VMW_MAX_MOB_MEM_FACTOR  2
     59 
     60 /*
     61  * A factor applied to the maximum surface memory size to determine
     62  * the optimial time to preemptively flush the command buffer.
     63  * The constant is based on some performance trials with SpecViewperf.
     64  */
     65 #define VMW_MAX_SURF_MEM_FACTOR 2
     66 
     67 
     68 struct vmw_buffer_relocation
     69 {
     70    struct pb_buffer *buffer;
     71    boolean is_mob;
     72    uint32 offset;
     73 
     74    union {
     75       struct {
     76 	 struct SVGAGuestPtr *where;
     77       } region;
     78       struct {
     79 	 SVGAMobId *id;
     80 	 uint32 *offset_into_mob;
     81       } mob;
     82    };
     83 };
     84 
     85 struct vmw_ctx_validate_item {
     86    union {
     87       struct vmw_svga_winsys_surface *vsurf;
     88       struct vmw_svga_winsys_shader *vshader;
     89    };
     90    boolean referenced;
     91 };
     92 
     93 struct vmw_svga_winsys_context
     94 {
     95    struct svga_winsys_context base;
     96 
     97    struct vmw_winsys_screen *vws;
     98    struct util_hash_table *hash;
     99 
    100 #ifdef DEBUG
    101    boolean must_flush;
    102    struct debug_stack_frame must_flush_stack[VMW_MUST_FLUSH_STACK];
    103    struct debug_flush_ctx *fctx;
    104 #endif
    105 
    106    struct {
    107       uint8_t buffer[VMW_COMMAND_SIZE];
    108       uint32_t size;
    109       uint32_t used;
    110       uint32_t reserved;
    111    } command;
    112 
    113    struct {
    114       struct vmw_ctx_validate_item items[VMW_SURFACE_RELOCS];
    115       uint32_t size;
    116       uint32_t used;
    117       uint32_t staged;
    118       uint32_t reserved;
    119    } surface;
    120 
    121    struct {
    122       struct vmw_buffer_relocation relocs[VMW_REGION_RELOCS];
    123       uint32_t size;
    124       uint32_t used;
    125       uint32_t staged;
    126       uint32_t reserved;
    127    } region;
    128 
    129    struct {
    130       struct vmw_ctx_validate_item items[VMW_SHADER_RELOCS];
    131       uint32_t size;
    132       uint32_t used;
    133       uint32_t staged;
    134       uint32_t reserved;
    135    } shader;
    136 
    137    struct pb_validate *validate;
    138 
    139    /**
    140     * The amount of surface, GMR or MOB memory that is referred by the commands
    141     * currently batched in the context command buffer.
    142     */
    143    uint64_t seen_surfaces;
    144    uint64_t seen_regions;
    145    uint64_t seen_mobs;
    146 
    147    /**
    148     * Whether this context should fail to reserve more commands, not because it
    149     * ran out of command space, but because a substantial ammount of GMR was
    150     * referred.
    151     */
    152    boolean preemptive_flush;
    153 };
    154 
    155 
    156 static inline struct vmw_svga_winsys_context *
    157 vmw_svga_winsys_context(struct svga_winsys_context *swc)
    158 {
    159    assert(swc);
    160    return (struct vmw_svga_winsys_context *)swc;
    161 }
    162 
    163 
    164 static inline unsigned
    165 vmw_translate_to_pb_flags(unsigned flags)
    166 {
    167    unsigned f = 0;
    168    if (flags & SVGA_RELOC_READ)
    169       f |= PB_USAGE_GPU_READ;
    170 
    171    if (flags & SVGA_RELOC_WRITE)
    172       f |= PB_USAGE_GPU_WRITE;
    173 
    174    return f;
    175 }
    176 
    177 static enum pipe_error
    178 vmw_swc_flush(struct svga_winsys_context *swc,
    179               struct pipe_fence_handle **pfence)
    180 {
    181    struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
    182    struct pipe_fence_handle *fence = NULL;
    183    unsigned i;
    184    enum pipe_error ret;
    185 
    186    ret = pb_validate_validate(vswc->validate);
    187    assert(ret == PIPE_OK);
    188    if(ret == PIPE_OK) {
    189 
    190       /* Apply relocations */
    191       for(i = 0; i < vswc->region.used; ++i) {
    192          struct vmw_buffer_relocation *reloc = &vswc->region.relocs[i];
    193          struct SVGAGuestPtr ptr;
    194 
    195          if(!vmw_gmr_bufmgr_region_ptr(reloc->buffer, &ptr))
    196             assert(0);
    197 
    198          ptr.offset += reloc->offset;
    199 
    200 	 if (reloc->is_mob) {
    201 	    if (reloc->mob.id)
    202 	       *reloc->mob.id = ptr.gmrId;
    203 	    if (reloc->mob.offset_into_mob)
    204 	       *reloc->mob.offset_into_mob = ptr.offset;
    205 	    else {
    206 	       assert(ptr.offset == 0);
    207 	    }
    208 	 } else
    209 	    *reloc->region.where = ptr;
    210       }
    211 
    212       if (vswc->command.used || pfence != NULL)
    213          vmw_ioctl_command(vswc->vws,
    214 			   vswc->base.cid,
    215 			   0,
    216                            vswc->command.buffer,
    217                            vswc->command.used,
    218                            &fence);
    219 
    220       pb_validate_fence(vswc->validate, fence);
    221    }
    222 
    223    vswc->command.used = 0;
    224    vswc->command.reserved = 0;
    225 
    226    for(i = 0; i < vswc->surface.used + vswc->surface.staged; ++i) {
    227       struct vmw_ctx_validate_item *isurf = &vswc->surface.items[i];
    228       if (isurf->referenced)
    229          p_atomic_dec(&isurf->vsurf->validated);
    230       vmw_svga_winsys_surface_reference(&isurf->vsurf, NULL);
    231    }
    232 
    233    util_hash_table_clear(vswc->hash);
    234    vswc->surface.used = 0;
    235    vswc->surface.reserved = 0;
    236 
    237    for(i = 0; i < vswc->shader.used + vswc->shader.staged; ++i) {
    238       struct vmw_ctx_validate_item *ishader = &vswc->shader.items[i];
    239       if (ishader->referenced)
    240          p_atomic_dec(&ishader->vshader->validated);
    241       vmw_svga_winsys_shader_reference(&ishader->vshader, NULL);
    242    }
    243 
    244    vswc->shader.used = 0;
    245    vswc->shader.reserved = 0;
    246 
    247    vswc->region.used = 0;
    248    vswc->region.reserved = 0;
    249 
    250 #ifdef DEBUG
    251    vswc->must_flush = FALSE;
    252    debug_flush_flush(vswc->fctx);
    253 #endif
    254    swc->hints &= ~SVGA_HINT_FLAG_CAN_PRE_FLUSH;
    255    vswc->preemptive_flush = FALSE;
    256    vswc->seen_surfaces = 0;
    257    vswc->seen_regions = 0;
    258    vswc->seen_mobs = 0;
    259 
    260    if(pfence)
    261       vmw_fence_reference(vswc->vws, pfence, fence);
    262 
    263    vmw_fence_reference(vswc->vws, &fence, NULL);
    264 
    265    return ret;
    266 }
    267 
    268 
    269 static void *
    270 vmw_swc_reserve(struct svga_winsys_context *swc,
    271                 uint32_t nr_bytes, uint32_t nr_relocs )
    272 {
    273    struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
    274 
    275 #ifdef DEBUG
    276    /* Check if somebody forgot to check the previous failure */
    277    if(vswc->must_flush) {
    278       debug_printf("Forgot to flush:\n");
    279       debug_backtrace_dump(vswc->must_flush_stack, VMW_MUST_FLUSH_STACK);
    280       assert(!vswc->must_flush);
    281    }
    282    debug_flush_might_flush(vswc->fctx);
    283 #endif
    284 
    285    assert(nr_bytes <= vswc->command.size);
    286    if(nr_bytes > vswc->command.size)
    287       return NULL;
    288 
    289    if(vswc->preemptive_flush ||
    290       vswc->command.used + nr_bytes > vswc->command.size ||
    291       vswc->surface.used + nr_relocs > vswc->surface.size ||
    292       vswc->shader.used + nr_relocs > vswc->shader.size ||
    293       vswc->region.used + nr_relocs > vswc->region.size) {
    294 #ifdef DEBUG
    295       vswc->must_flush = TRUE;
    296       debug_backtrace_capture(vswc->must_flush_stack, 1,
    297                               VMW_MUST_FLUSH_STACK);
    298 #endif
    299       return NULL;
    300    }
    301 
    302    assert(vswc->command.used + nr_bytes <= vswc->command.size);
    303    assert(vswc->surface.used + nr_relocs <= vswc->surface.size);
    304    assert(vswc->shader.used + nr_relocs <= vswc->shader.size);
    305    assert(vswc->region.used + nr_relocs <= vswc->region.size);
    306 
    307    vswc->command.reserved = nr_bytes;
    308    vswc->surface.reserved = nr_relocs;
    309    vswc->surface.staged = 0;
    310    vswc->shader.reserved = nr_relocs;
    311    vswc->shader.staged = 0;
    312    vswc->region.reserved = nr_relocs;
    313    vswc->region.staged = 0;
    314 
    315    return vswc->command.buffer + vswc->command.used;
    316 }
    317 
    318 static unsigned
    319 vmw_swc_get_command_buffer_size(struct svga_winsys_context *swc)
    320 {
    321    const struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
    322    return vswc->command.used;
    323 }
    324 
    325 static void
    326 vmw_swc_context_relocation(struct svga_winsys_context *swc,
    327 			   uint32 *cid)
    328 {
    329    *cid = swc->cid;
    330 }
    331 
    332 static boolean
    333 vmw_swc_add_validate_buffer(struct vmw_svga_winsys_context *vswc,
    334 			    struct pb_buffer *pb_buf,
    335 			    unsigned flags)
    336 {
    337    enum pipe_error ret;
    338    unsigned translated_flags;
    339 
    340    /*
    341     * TODO: Update pb_validate to provide a similar functionality
    342     * (Check buffer already present before adding)
    343     */
    344    if (util_hash_table_get(vswc->hash, pb_buf) != pb_buf) {
    345       translated_flags = vmw_translate_to_pb_flags(flags);
    346       ret = pb_validate_add_buffer(vswc->validate, pb_buf, translated_flags);
    347       /* TODO: Update pipebuffer to reserve buffers and not fail here */
    348       assert(ret == PIPE_OK);
    349       (void)ret;
    350       (void)util_hash_table_set(vswc->hash, pb_buf, pb_buf);
    351       return TRUE;
    352    }
    353 
    354    return FALSE;
    355 }
    356 
    357 static void
    358 vmw_swc_region_relocation(struct svga_winsys_context *swc,
    359                           struct SVGAGuestPtr *where,
    360                           struct svga_winsys_buffer *buffer,
    361                           uint32 offset,
    362                           unsigned flags)
    363 {
    364    struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
    365    struct vmw_buffer_relocation *reloc;
    366 
    367    assert(vswc->region.staged < vswc->region.reserved);
    368 
    369    reloc = &vswc->region.relocs[vswc->region.used + vswc->region.staged];
    370    reloc->region.where = where;
    371 
    372    /*
    373     * pb_validate holds a refcount to the buffer, so no need to
    374     * refcount it again in the relocation.
    375     */
    376    reloc->buffer = vmw_pb_buffer(buffer);
    377    reloc->offset = offset;
    378    reloc->is_mob = FALSE;
    379    ++vswc->region.staged;
    380 
    381    if (vmw_swc_add_validate_buffer(vswc, reloc->buffer, flags)) {
    382       vswc->seen_regions += reloc->buffer->size;
    383       if ((swc->hints & SVGA_HINT_FLAG_CAN_PRE_FLUSH) &&
    384           vswc->seen_regions >= VMW_GMR_POOL_SIZE/5)
    385          vswc->preemptive_flush = TRUE;
    386    }
    387 
    388 #ifdef DEBUG
    389    if (!(flags & SVGA_RELOC_INTERNAL))
    390       debug_flush_cb_reference(vswc->fctx, vmw_debug_flush_buf(buffer));
    391 #endif
    392 }
    393 
    394 static void
    395 vmw_swc_mob_relocation(struct svga_winsys_context *swc,
    396 		       SVGAMobId *id,
    397 		       uint32 *offset_into_mob,
    398 		       struct svga_winsys_buffer *buffer,
    399 		       uint32 offset,
    400 		       unsigned flags)
    401 {
    402    struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
    403    struct vmw_buffer_relocation *reloc;
    404    struct pb_buffer *pb_buffer = vmw_pb_buffer(buffer);
    405 
    406    if (id) {
    407       assert(vswc->region.staged < vswc->region.reserved);
    408 
    409       reloc = &vswc->region.relocs[vswc->region.used + vswc->region.staged];
    410       reloc->mob.id = id;
    411       reloc->mob.offset_into_mob = offset_into_mob;
    412 
    413       /*
    414        * pb_validate holds a refcount to the buffer, so no need to
    415        * refcount it again in the relocation.
    416        */
    417       reloc->buffer = pb_buffer;
    418       reloc->offset = offset;
    419       reloc->is_mob = TRUE;
    420       ++vswc->region.staged;
    421    }
    422 
    423    if (vmw_swc_add_validate_buffer(vswc, pb_buffer, flags)) {
    424       vswc->seen_mobs += pb_buffer->size;
    425 
    426       if ((swc->hints & SVGA_HINT_FLAG_CAN_PRE_FLUSH) &&
    427           vswc->seen_mobs >=
    428             vswc->vws->ioctl.max_mob_memory / VMW_MAX_MOB_MEM_FACTOR)
    429          vswc->preemptive_flush = TRUE;
    430    }
    431 
    432 #ifdef DEBUG
    433    if (!(flags & SVGA_RELOC_INTERNAL))
    434       debug_flush_cb_reference(vswc->fctx, vmw_debug_flush_buf(buffer));
    435 #endif
    436 }
    437 
    438 
    439 /**
    440  * vmw_swc_surface_clear_reference - Clear referenced info for a surface
    441  *
    442  * @swc:   Pointer to an svga_winsys_context
    443  * @vsurf: Pointer to a vmw_svga_winsys_surface, the referenced info of which
    444  *         we want to clear
    445  *
    446  * This is primarily used by a discard surface map to indicate that the
    447  * surface data is no longer referenced by a draw call, and mapping it
    448  * should therefore no longer cause a flush.
    449  */
    450 void
    451 vmw_swc_surface_clear_reference(struct svga_winsys_context *swc,
    452                                 struct vmw_svga_winsys_surface *vsurf)
    453 {
    454    struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
    455    struct vmw_ctx_validate_item *isrf =
    456       util_hash_table_get(vswc->hash, vsurf);
    457 
    458    if (isrf && isrf->referenced) {
    459       isrf->referenced = FALSE;
    460       p_atomic_dec(&vsurf->validated);
    461    }
    462 }
    463 
    464 static void
    465 vmw_swc_surface_only_relocation(struct svga_winsys_context *swc,
    466 				uint32 *where,
    467 				struct vmw_svga_winsys_surface *vsurf,
    468 				unsigned flags)
    469 {
    470    struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
    471    struct vmw_ctx_validate_item *isrf;
    472 
    473    assert(vswc->surface.staged < vswc->surface.reserved);
    474    isrf = util_hash_table_get(vswc->hash, vsurf);
    475 
    476    if (isrf == NULL) {
    477       isrf = &vswc->surface.items[vswc->surface.used + vswc->surface.staged];
    478       vmw_svga_winsys_surface_reference(&isrf->vsurf, vsurf);
    479       isrf->referenced = FALSE;
    480       /*
    481        * Note that a failure here may just fall back to unhashed behavior
    482        * and potentially cause unnecessary flushing, so ignore the
    483        * return code.
    484        */
    485       (void) util_hash_table_set(vswc->hash, vsurf, isrf);
    486       ++vswc->surface.staged;
    487 
    488       vswc->seen_surfaces += vsurf->size;
    489       if ((swc->hints & SVGA_HINT_FLAG_CAN_PRE_FLUSH) &&
    490           vswc->seen_surfaces >=
    491             vswc->vws->ioctl.max_surface_memory / VMW_MAX_SURF_MEM_FACTOR)
    492          vswc->preemptive_flush = TRUE;
    493    }
    494 
    495    if (!(flags & SVGA_RELOC_INTERNAL) && !isrf->referenced) {
    496       isrf->referenced = TRUE;
    497       p_atomic_inc(&vsurf->validated);
    498    }
    499 
    500    if (where)
    501       *where = vsurf->sid;
    502 }
    503 
    504 static void
    505 vmw_swc_surface_relocation(struct svga_winsys_context *swc,
    506                            uint32 *where,
    507                            uint32 *mobid,
    508                            struct svga_winsys_surface *surface,
    509                            unsigned flags)
    510 {
    511    struct vmw_svga_winsys_surface *vsurf;
    512 
    513    assert(swc->have_gb_objects || mobid == NULL);
    514 
    515    if (!surface) {
    516       *where = SVGA3D_INVALID_ID;
    517       if (mobid)
    518          *mobid = SVGA3D_INVALID_ID;
    519       return;
    520    }
    521 
    522    vsurf = vmw_svga_winsys_surface(surface);
    523    vmw_swc_surface_only_relocation(swc, where, vsurf, flags);
    524 
    525    if (swc->have_gb_objects && vsurf->buf != NULL) {
    526 
    527       /*
    528        * Make sure backup buffer ends up fenced.
    529        */
    530 
    531       pipe_mutex_lock(vsurf->mutex);
    532       assert(vsurf->buf != NULL);
    533 
    534       vmw_swc_mob_relocation(swc, mobid, NULL, (struct svga_winsys_buffer *)
    535                              vsurf->buf, 0, flags);
    536       pipe_mutex_unlock(vsurf->mutex);
    537    }
    538 }
    539 
    540 static void
    541 vmw_swc_shader_relocation(struct svga_winsys_context *swc,
    542 			  uint32 *shid,
    543 			  uint32 *mobid,
    544 			  uint32 *offset,
    545 			  struct svga_winsys_gb_shader *shader,
    546                           unsigned flags)
    547 {
    548    struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
    549    struct vmw_winsys_screen *vws = vswc->vws;
    550    struct vmw_svga_winsys_shader *vshader;
    551    struct vmw_ctx_validate_item *ishader;
    552 
    553    if(!shader) {
    554       *shid = SVGA3D_INVALID_ID;
    555       return;
    556    }
    557 
    558    vshader = vmw_svga_winsys_shader(shader);
    559 
    560    if (!vws->base.have_vgpu10) {
    561       assert(vswc->shader.staged < vswc->shader.reserved);
    562       ishader = util_hash_table_get(vswc->hash, vshader);
    563 
    564       if (ishader == NULL) {
    565          ishader = &vswc->shader.items[vswc->shader.used + vswc->shader.staged];
    566          vmw_svga_winsys_shader_reference(&ishader->vshader, vshader);
    567          ishader->referenced = FALSE;
    568          /*
    569           * Note that a failure here may just fall back to unhashed behavior
    570           * and potentially cause unnecessary flushing, so ignore the
    571           * return code.
    572           */
    573          (void) util_hash_table_set(vswc->hash, vshader, ishader);
    574          ++vswc->shader.staged;
    575       }
    576 
    577       if (!ishader->referenced) {
    578          ishader->referenced = TRUE;
    579          p_atomic_inc(&vshader->validated);
    580       }
    581    }
    582 
    583    if (shid)
    584       *shid = vshader->shid;
    585 
    586    if (vshader->buf)
    587       vmw_swc_mob_relocation(swc, mobid, offset, vshader->buf,
    588 			     0, SVGA_RELOC_READ);
    589 }
    590 
    591 static void
    592 vmw_swc_query_relocation(struct svga_winsys_context *swc,
    593                          SVGAMobId *id,
    594                          struct svga_winsys_gb_query *query)
    595 {
    596    /* Queries are backed by one big MOB */
    597    vmw_swc_mob_relocation(swc, id, NULL, query->buf, 0,
    598                           SVGA_RELOC_READ | SVGA_RELOC_WRITE);
    599 }
    600 
    601 static void
    602 vmw_swc_commit(struct svga_winsys_context *swc)
    603 {
    604    struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
    605 
    606    assert(vswc->command.used + vswc->command.reserved <= vswc->command.size);
    607    vswc->command.used += vswc->command.reserved;
    608    vswc->command.reserved = 0;
    609 
    610    assert(vswc->surface.staged <= vswc->surface.reserved);
    611    assert(vswc->surface.used + vswc->surface.staged <= vswc->surface.size);
    612    vswc->surface.used += vswc->surface.staged;
    613    vswc->surface.staged = 0;
    614    vswc->surface.reserved = 0;
    615 
    616    assert(vswc->shader.staged <= vswc->shader.reserved);
    617    assert(vswc->shader.used + vswc->shader.staged <= vswc->shader.size);
    618    vswc->shader.used += vswc->shader.staged;
    619    vswc->shader.staged = 0;
    620    vswc->shader.reserved = 0;
    621 
    622    assert(vswc->region.staged <= vswc->region.reserved);
    623    assert(vswc->region.used + vswc->region.staged <= vswc->region.size);
    624    vswc->region.used += vswc->region.staged;
    625    vswc->region.staged = 0;
    626    vswc->region.reserved = 0;
    627 }
    628 
    629 
    630 static void
    631 vmw_swc_destroy(struct svga_winsys_context *swc)
    632 {
    633    struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
    634    unsigned i;
    635 
    636    for(i = 0; i < vswc->surface.used; ++i) {
    637       struct vmw_ctx_validate_item *isurf = &vswc->surface.items[i];
    638       if (isurf->referenced)
    639          p_atomic_dec(&isurf->vsurf->validated);
    640       vmw_svga_winsys_surface_reference(&isurf->vsurf, NULL);
    641    }
    642 
    643    for(i = 0; i < vswc->shader.used; ++i) {
    644       struct vmw_ctx_validate_item *ishader = &vswc->shader.items[i];
    645       if (ishader->referenced)
    646          p_atomic_dec(&ishader->vshader->validated);
    647       vmw_svga_winsys_shader_reference(&ishader->vshader, NULL);
    648    }
    649 
    650    util_hash_table_destroy(vswc->hash);
    651    pb_validate_destroy(vswc->validate);
    652    vmw_ioctl_context_destroy(vswc->vws, swc->cid);
    653 #ifdef DEBUG
    654    debug_flush_ctx_destroy(vswc->fctx);
    655 #endif
    656    FREE(vswc);
    657 }
    658 
    659 static unsigned vmw_hash_ptr(void *p)
    660 {
    661    return (unsigned)(unsigned long)p;
    662 }
    663 
    664 static int vmw_ptr_compare(void *key1, void *key2)
    665 {
    666    return (key1 == key2) ? 0 : 1;
    667 }
    668 
    669 
    670 /**
    671  * vmw_svga_winsys_vgpu10_shader_screate - The winsys shader_crate callback
    672  *
    673  * @swc: The winsys context.
    674  * @shaderId: Previously allocated shader id.
    675  * @shaderType: The shader type.
    676  * @bytecode: The shader bytecode
    677  * @bytecodelen: The length of the bytecode.
    678  *
    679  * Creates an svga_winsys_gb_shader structure and allocates a buffer for the
    680  * shader code and copies the shader code into the buffer. Shader
    681  * resource creation is not done.
    682  */
    683 static struct svga_winsys_gb_shader *
    684 vmw_svga_winsys_vgpu10_shader_create(struct svga_winsys_context *swc,
    685                                      uint32 shaderId,
    686                                      SVGA3dShaderType shaderType,
    687                                      const uint32 *bytecode,
    688                                      uint32 bytecodeLen)
    689 {
    690    struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
    691    struct vmw_svga_winsys_shader *shader;
    692    struct svga_winsys_gb_shader *gb_shader =
    693       vmw_svga_winsys_shader_create(&vswc->vws->base, shaderType, bytecode,
    694                                     bytecodeLen);
    695    if (!gb_shader)
    696       return NULL;
    697 
    698    shader = vmw_svga_winsys_shader(gb_shader);
    699    shader->shid = shaderId;
    700 
    701    return gb_shader;
    702 }
    703 
    704 /**
    705  * vmw_svga_winsys_vgpu10_shader_destroy - The winsys shader_destroy callback.
    706  *
    707  * @swc: The winsys context.
    708  * @shader: A shader structure previously allocated by shader_create.
    709  *
    710  * Frees the shader structure and the buffer holding the shader code.
    711  */
    712 static void
    713 vmw_svga_winsys_vgpu10_shader_destroy(struct svga_winsys_context *swc,
    714                                       struct svga_winsys_gb_shader *shader)
    715 {
    716    struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
    717 
    718    vmw_svga_winsys_shader_destroy(&vswc->vws->base, shader);
    719 }
    720 
    721 /**
    722  * vmw_svga_winsys_resource_rebind - The winsys resource_rebind callback
    723  *
    724  * @swc: The winsys context.
    725  * @surface: The surface to be referenced.
    726  * @shader: The shader to be referenced.
    727  * @flags: Relocation flags.
    728  *
    729  * This callback is needed because shader backing buffers are sub-allocated, and
    730  * hence the kernel fencing is not sufficient. The buffers need to be put on
    731  * the context's validation list and fenced after command submission to avoid
    732  * reuse of busy shader buffers. In addition, surfaces need to be put on the
    733  * validation list in order for the driver to regard them as referenced
    734  * by the command stream.
    735  */
    736 static enum pipe_error
    737 vmw_svga_winsys_resource_rebind(struct svga_winsys_context *swc,
    738                                 struct svga_winsys_surface *surface,
    739                                 struct svga_winsys_gb_shader *shader,
    740                                 unsigned flags)
    741 {
    742    /**
    743     * Need to reserve one validation item for either the surface or
    744     * the shader.
    745     */
    746    if (!vmw_swc_reserve(swc, 0, 1))
    747       return PIPE_ERROR_OUT_OF_MEMORY;
    748 
    749    if (surface)
    750       vmw_swc_surface_relocation(swc, NULL, NULL, surface, flags);
    751    else if (shader)
    752       vmw_swc_shader_relocation(swc, NULL, NULL, NULL, shader, flags);
    753 
    754    vmw_swc_commit(swc);
    755 
    756    return PIPE_OK;
    757 }
    758 
    759 struct svga_winsys_context *
    760 vmw_svga_winsys_context_create(struct svga_winsys_screen *sws)
    761 {
    762    struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
    763    struct vmw_svga_winsys_context *vswc;
    764 
    765    vswc = CALLOC_STRUCT(vmw_svga_winsys_context);
    766    if(!vswc)
    767       return NULL;
    768 
    769    vswc->base.destroy = vmw_swc_destroy;
    770    vswc->base.reserve = vmw_swc_reserve;
    771    vswc->base.get_command_buffer_size = vmw_swc_get_command_buffer_size;
    772    vswc->base.surface_relocation = vmw_swc_surface_relocation;
    773    vswc->base.region_relocation = vmw_swc_region_relocation;
    774    vswc->base.mob_relocation = vmw_swc_mob_relocation;
    775    vswc->base.query_relocation = vmw_swc_query_relocation;
    776    vswc->base.query_bind = vmw_swc_query_bind;
    777    vswc->base.context_relocation = vmw_swc_context_relocation;
    778    vswc->base.shader_relocation = vmw_swc_shader_relocation;
    779    vswc->base.commit = vmw_swc_commit;
    780    vswc->base.flush = vmw_swc_flush;
    781    vswc->base.surface_map = vmw_svga_winsys_surface_map;
    782    vswc->base.surface_unmap = vmw_svga_winsys_surface_unmap;
    783 
    784   vswc->base.shader_create = vmw_svga_winsys_vgpu10_shader_create;
    785   vswc->base.shader_destroy = vmw_svga_winsys_vgpu10_shader_destroy;
    786 
    787   vswc->base.resource_rebind = vmw_svga_winsys_resource_rebind;
    788 
    789    if (sws->have_vgpu10)
    790       vswc->base.cid = vmw_ioctl_extended_context_create(vws, sws->have_vgpu10);
    791    else
    792       vswc->base.cid = vmw_ioctl_context_create(vws);
    793 
    794    if (vswc->base.cid == -1)
    795       goto out_no_context;
    796 
    797    vswc->base.have_gb_objects = sws->have_gb_objects;
    798 
    799    vswc->vws = vws;
    800 
    801    vswc->command.size = VMW_COMMAND_SIZE;
    802    vswc->surface.size = VMW_SURFACE_RELOCS;
    803    vswc->shader.size = VMW_SHADER_RELOCS;
    804    vswc->region.size = VMW_REGION_RELOCS;
    805 
    806    vswc->validate = pb_validate_create();
    807    if(!vswc->validate)
    808       goto out_no_validate;
    809 
    810    vswc->hash = util_hash_table_create(vmw_hash_ptr, vmw_ptr_compare);
    811    if (!vswc->hash)
    812       goto out_no_hash;
    813 
    814 #ifdef DEBUG
    815    vswc->fctx = debug_flush_ctx_create(TRUE, VMW_DEBUG_FLUSH_STACK);
    816 #endif
    817 
    818    return &vswc->base;
    819 
    820 out_no_hash:
    821    pb_validate_destroy(vswc->validate);
    822 out_no_validate:
    823    vmw_ioctl_context_destroy(vws, vswc->base.cid);
    824 out_no_context:
    825    FREE(vswc);
    826    return NULL;
    827 }
    828