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 "svga_cmd.h"
     27 
     28 #include "util/u_format.h"
     29 #include "util/u_inlines.h"
     30 #include "util/u_prim.h"
     31 #include "util/u_time.h"
     32 #include "indices/u_indices.h"
     33 
     34 #include "svga_hw_reg.h"
     35 #include "svga_context.h"
     36 #include "svga_screen.h"
     37 #include "svga_draw.h"
     38 #include "svga_state.h"
     39 #include "svga_swtnl.h"
     40 #include "svga_debug.h"
     41 #include "svga_resource_buffer.h"
     42 #include "util/u_upload_mgr.h"
     43 
     44 /**
     45  * Determine the ranges to upload for the user-buffers referenced
     46  * by the next draw command.
     47  *
     48  * TODO: It might be beneficial to support multiple ranges. In that case,
     49  * the struct svga_buffer::uploaded member should be made an array or a
     50  * list, since we need to account for the possibility that different ranges
     51  * may be uploaded to different hardware buffers chosen by the utility
     52  * upload manager.
     53  */
     54 
     55 static void
     56 svga_user_buffer_range(struct svga_context *svga,
     57                        unsigned start,
     58                        unsigned count,
     59                        unsigned instance_count)
     60 {
     61    const struct pipe_vertex_element *ve = svga->curr.velems->velem;
     62    int i;
     63 
     64    /*
     65     * Release old uploaded range (if not done already) and
     66     * initialize new ranges.
     67     */
     68 
     69    for (i=0; i < svga->curr.velems->count; i++) {
     70       struct pipe_vertex_buffer *vb =
     71          &svga->curr.vb[ve[i].vertex_buffer_index];
     72 
     73       if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) {
     74          struct svga_buffer *buffer = svga_buffer(vb->buffer);
     75 
     76          pipe_resource_reference(&buffer->uploaded.buffer, NULL);
     77          buffer->uploaded.start = ~0;
     78          buffer->uploaded.end = 0;
     79       }
     80    }
     81 
     82    for (i=0; i < svga->curr.velems->count; i++) {
     83       struct pipe_vertex_buffer *vb =
     84          &svga->curr.vb[ve[i].vertex_buffer_index];
     85 
     86       if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) {
     87          struct svga_buffer *buffer = svga_buffer(vb->buffer);
     88          unsigned first, size;
     89          unsigned instance_div = ve[i].instance_divisor;
     90          unsigned elemSize = util_format_get_blocksize(ve[i].src_format);
     91 
     92          svga->dirty |= SVGA_NEW_VBUFFER;
     93 
     94          if (instance_div) {
     95             first = ve[i].src_offset;
     96             count = (instance_count + instance_div - 1) / instance_div;
     97             size = vb->stride * (count - 1) + elemSize;
     98          } else {
     99             first = vb->stride * start + ve[i].src_offset;
    100             size = vb->stride * (count - 1) + elemSize;
    101          }
    102 
    103          buffer->uploaded.start = MIN2(buffer->uploaded.start, first);
    104          buffer->uploaded.end = MAX2(buffer->uploaded.end, first + size);
    105       }
    106    }
    107 }
    108 
    109 /**
    110  * svga_upload_user_buffers - upload parts of user buffers
    111  *
    112  * This function streams a part of a user buffer to hw and fills
    113  * svga_buffer::uploaded with information on the upload.
    114  */
    115 
    116 static int
    117 svga_upload_user_buffers(struct svga_context *svga,
    118                          unsigned start,
    119                          unsigned count,
    120                          unsigned instance_count)
    121 {
    122    const struct pipe_vertex_element *ve = svga->curr.velems->velem;
    123    unsigned i;
    124    int ret;
    125 
    126    svga_user_buffer_range(svga, start, count, instance_count);
    127 
    128    for (i=0; i < svga->curr.velems->count; i++) {
    129       struct pipe_vertex_buffer *vb =
    130          &svga->curr.vb[ve[i].vertex_buffer_index];
    131 
    132       if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) {
    133          struct svga_buffer *buffer = svga_buffer(vb->buffer);
    134 
    135          /*
    136           * Check if already uploaded. Otherwise go ahead and upload.
    137           */
    138 
    139          if (buffer->uploaded.buffer)
    140             continue;
    141 
    142          ret = u_upload_buffer( svga->upload_vb,
    143                                 0,
    144                                 buffer->uploaded.start,
    145                                 buffer->uploaded.end - buffer->uploaded.start,
    146                                 &buffer->b.b,
    147                                 &buffer->uploaded.offset,
    148                                 &buffer->uploaded.buffer);
    149 
    150          if (ret)
    151             return ret;
    152 
    153          if (0)
    154             debug_printf("%s: %d: orig buf %p upl buf %p ofs %d sofs %d"
    155                          " sz %d\n",
    156                          __FUNCTION__,
    157                          i,
    158                          buffer,
    159                          buffer->uploaded.buffer,
    160                          buffer->uploaded.offset,
    161                          buffer->uploaded.start,
    162                          buffer->uploaded.end - buffer->uploaded.start);
    163 
    164          vb->buffer_offset = buffer->uploaded.offset;
    165       }
    166    }
    167 
    168    return PIPE_OK;
    169 }
    170 
    171 /**
    172  * svga_release_user_upl_buffers - release uploaded parts of user buffers
    173  *
    174  * This function releases the hw copy of the uploaded fraction of the
    175  * user-buffer. It's important to do this as soon as all draw calls
    176  * affecting the uploaded fraction are issued, as this allows for
    177  * efficient reuse of the hardware surface backing the uploaded fraction.
    178  *
    179  * svga_buffer::source_offset is set to 0, and svga_buffer::uploaded::buffer
    180  * is set to 0.
    181  */
    182 
    183 static void
    184 svga_release_user_upl_buffers(struct svga_context *svga)
    185 {
    186    unsigned i;
    187    unsigned nr;
    188 
    189    nr = svga->curr.num_vertex_buffers;
    190 
    191    for (i = 0; i < nr; ++i) {
    192       struct pipe_vertex_buffer *vb = &svga->curr.vb[i];
    193 
    194       if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) {
    195          struct svga_buffer *buffer = svga_buffer(vb->buffer);
    196 
    197          /* The buffer_offset is relative to the uploaded buffer.
    198           * Since we're discarding that buffer we need to reset this offset
    199           * so it's not inadvertantly applied to a subsequent draw.
    200           *
    201           * XXX a root problem here is that the svga->curr.vb[] information
    202           * is getting set both by gallium API calls and by code in
    203           * svga_upload_user_buffers().  We should instead have two copies
    204           * of the vertex buffer information and choose between as needed.
    205           */
    206          vb->buffer_offset = 0;
    207 
    208          buffer->uploaded.start = ~0;
    209          buffer->uploaded.end = 0;
    210          if (buffer->uploaded.buffer)
    211             pipe_resource_reference(&buffer->uploaded.buffer, NULL);
    212       }
    213    }
    214 }
    215 
    216 
    217 
    218 static enum pipe_error
    219 retry_draw_range_elements( struct svga_context *svga,
    220                            struct pipe_resource *index_buffer,
    221                            unsigned index_size,
    222                            int index_bias,
    223                            unsigned min_index,
    224                            unsigned max_index,
    225                            unsigned prim,
    226                            unsigned start,
    227                            unsigned count,
    228                            unsigned instance_count,
    229                            boolean do_retry )
    230 {
    231    enum pipe_error ret = PIPE_OK;
    232 
    233    svga_hwtnl_set_unfilled( svga->hwtnl,
    234                             svga->curr.rast->hw_unfilled );
    235 
    236    svga_hwtnl_set_flatshade( svga->hwtnl,
    237                              svga->curr.rast->templ.flatshade,
    238                              svga->curr.rast->templ.flatshade_first );
    239 
    240    ret = svga_upload_user_buffers( svga, min_index + index_bias,
    241                                    max_index - min_index + 1, instance_count );
    242    if (ret != PIPE_OK)
    243       goto retry;
    244 
    245    ret = svga_update_state( svga, SVGA_STATE_HW_DRAW );
    246    if (ret != PIPE_OK)
    247       goto retry;
    248 
    249    ret = svga_hwtnl_draw_range_elements( svga->hwtnl,
    250                                          index_buffer, index_size, index_bias,
    251                                          min_index, max_index,
    252                                          prim, start, count );
    253    if (ret != PIPE_OK)
    254       goto retry;
    255 
    256    return PIPE_OK;
    257 
    258 retry:
    259    svga_context_flush( svga, NULL );
    260 
    261    if (do_retry)
    262    {
    263       return retry_draw_range_elements( svga,
    264                                         index_buffer, index_size, index_bias,
    265                                         min_index, max_index,
    266                                         prim, start, count,
    267                                         instance_count, FALSE );
    268    }
    269 
    270    return ret;
    271 }
    272 
    273 
    274 static enum pipe_error
    275 retry_draw_arrays( struct svga_context *svga,
    276                    unsigned prim,
    277                    unsigned start,
    278                    unsigned count,
    279                    unsigned instance_count,
    280                    boolean do_retry )
    281 {
    282    enum pipe_error ret;
    283 
    284    svga_hwtnl_set_unfilled( svga->hwtnl,
    285                             svga->curr.rast->hw_unfilled );
    286 
    287    svga_hwtnl_set_flatshade( svga->hwtnl,
    288                              svga->curr.rast->templ.flatshade,
    289                              svga->curr.rast->templ.flatshade_first );
    290 
    291    ret = svga_upload_user_buffers( svga, start, count, instance_count );
    292 
    293    if (ret != PIPE_OK)
    294       goto retry;
    295 
    296    ret = svga_update_state( svga, SVGA_STATE_HW_DRAW );
    297    if (ret != PIPE_OK)
    298       goto retry;
    299 
    300    ret = svga_hwtnl_draw_arrays( svga->hwtnl, prim,
    301                                  start, count );
    302    if (ret != PIPE_OK)
    303       goto retry;
    304 
    305    return PIPE_OK;
    306 
    307 retry:
    308    if (ret == PIPE_ERROR_OUT_OF_MEMORY && do_retry)
    309    {
    310       svga_context_flush( svga, NULL );
    311 
    312       return retry_draw_arrays( svga,
    313                                 prim,
    314                                 start,
    315                                 count,
    316                                 instance_count,
    317                                 FALSE );
    318    }
    319 
    320    return ret;
    321 }
    322 
    323 
    324 static void
    325 svga_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
    326 {
    327    struct svga_context *svga = svga_context( pipe );
    328    unsigned reduced_prim = u_reduced_prim( info->mode );
    329    unsigned count = info->count;
    330    enum pipe_error ret = 0;
    331    boolean needed_swtnl;
    332 
    333    if (!u_trim_pipe_prim( info->mode, &count ))
    334       return;
    335 
    336    /*
    337     * Mark currently bound target surfaces as dirty
    338     * doesn't really matter if it is done before drawing.
    339     *
    340     * TODO If we ever normaly return something other then
    341     * true we should not mark it as dirty then.
    342     */
    343    svga_mark_surfaces_dirty(svga_context(pipe));
    344 
    345    if (svga->curr.reduced_prim != reduced_prim) {
    346       svga->curr.reduced_prim = reduced_prim;
    347       svga->dirty |= SVGA_NEW_REDUCED_PRIMITIVE;
    348    }
    349 
    350    needed_swtnl = svga->state.sw.need_swtnl;
    351 
    352    svga_update_state_retry( svga, SVGA_STATE_NEED_SWTNL );
    353 
    354 #ifdef DEBUG
    355    if (svga->curr.vs->base.id == svga->debug.disable_shader ||
    356        svga->curr.fs->base.id == svga->debug.disable_shader)
    357       return;
    358 #endif
    359 
    360    if (svga->state.sw.need_swtnl) {
    361       if (!needed_swtnl) {
    362          /*
    363           * We're switching from HW to SW TNL.  SW TNL will require mapping all
    364           * currently bound vertex buffers, some of which may already be
    365           * referenced in the current command buffer as result of previous HW
    366           * TNL. So flush now, to prevent the context to flush while a referred
    367           * vertex buffer is mapped.
    368           */
    369 
    370          svga_context_flush(svga, NULL);
    371       }
    372 
    373       /* Avoid leaking the previous hwtnl bias to swtnl */
    374       svga_hwtnl_set_index_bias( svga->hwtnl, 0 );
    375       ret = svga_swtnl_draw_vbo( svga, info );
    376    }
    377    else {
    378       if (info->indexed && svga->curr.ib.buffer) {
    379          unsigned offset;
    380 
    381          assert(svga->curr.ib.offset % svga->curr.ib.index_size == 0);
    382          offset = svga->curr.ib.offset / svga->curr.ib.index_size;
    383 
    384          ret = retry_draw_range_elements( svga,
    385                                           svga->curr.ib.buffer,
    386                                           svga->curr.ib.index_size,
    387                                           info->index_bias,
    388                                           info->min_index,
    389                                           info->max_index,
    390                                           info->mode,
    391                                           info->start + offset,
    392                                           info->count,
    393                                           info->instance_count,
    394                                           TRUE );
    395       }
    396       else {
    397          ret = retry_draw_arrays( svga,
    398                                   info->mode,
    399                                   info->start,
    400                                   info->count,
    401                                   info->instance_count,
    402                                   TRUE );
    403       }
    404    }
    405 
    406    /* XXX: Silence warnings, do something sensible here? */
    407    (void)ret;
    408 
    409    svga_release_user_upl_buffers( svga );
    410 
    411    if (SVGA_DEBUG & DEBUG_FLUSH) {
    412       svga_hwtnl_flush_retry( svga );
    413       svga_context_flush(svga, NULL);
    414    }
    415 }
    416 
    417 
    418 void svga_init_draw_functions( struct svga_context *svga )
    419 {
    420    svga->pipe.draw_vbo = svga_draw_vbo;
    421 }
    422