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 
     27 #include "util/u_format.h"
     28 #include "util/u_inlines.h"
     29 #include "util/u_prim.h"
     30 #include "util/u_prim_restart.h"
     31 #include "util/u_time.h"
     32 #include "util/u_upload_mgr.h"
     33 #include "indices/u_indices.h"
     34 
     35 #include "svga_hw_reg.h"
     36 #include "svga_cmd.h"
     37 #include "svga_context.h"
     38 #include "svga_screen.h"
     39 #include "svga_draw.h"
     40 #include "svga_shader.h"
     41 #include "svga_state.h"
     42 #include "svga_surface.h"
     43 #include "svga_swtnl.h"
     44 #include "svga_debug.h"
     45 #include "svga_resource_buffer.h"
     46 
     47 static enum pipe_error
     48 retry_draw_range_elements( struct svga_context *svga,
     49                            struct pipe_resource *index_buffer,
     50                            unsigned index_size,
     51                            int index_bias,
     52                            unsigned min_index,
     53                            unsigned max_index,
     54                            enum pipe_prim_type prim,
     55                            unsigned start,
     56                            unsigned count,
     57                            unsigned start_instance,
     58                            unsigned instance_count,
     59                            boolean do_retry )
     60 {
     61    enum pipe_error ret = PIPE_OK;
     62 
     63    SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_DRAWELEMENTS);
     64 
     65    svga_hwtnl_set_fillmode(svga->hwtnl, svga->curr.rast->hw_fillmode);
     66 
     67    ret = svga_update_state( svga, SVGA_STATE_HW_DRAW );
     68    if (ret != PIPE_OK)
     69       goto retry;
     70 
     71    /** determine if flatshade is to be used after svga_update_state()
     72     *  in case the fragment shader is changed.
     73     */
     74    svga_hwtnl_set_flatshade(svga->hwtnl,
     75                             svga->curr.rast->templ.flatshade ||
     76                             svga->state.hw_draw.fs->uses_flat_interp,
     77                             svga->curr.rast->templ.flatshade_first);
     78 
     79    ret = svga_hwtnl_draw_range_elements( svga->hwtnl,
     80                                          index_buffer, index_size, index_bias,
     81                                          min_index, max_index,
     82                                          prim, start, count,
     83                                          start_instance, instance_count);
     84    if (ret != PIPE_OK)
     85       goto retry;
     86 
     87    goto done;
     88 
     89 retry:
     90    svga_context_flush( svga, NULL );
     91 
     92    if (do_retry)
     93    {
     94       ret = retry_draw_range_elements(svga,
     95                                       index_buffer, index_size, index_bias,
     96                                       min_index, max_index,
     97                                       prim, start, count,
     98                                       start_instance, instance_count, FALSE);
     99    }
    100 
    101 done:
    102    SVGA_STATS_TIME_POP(svga_sws(svga));
    103    return ret;
    104 }
    105 
    106 
    107 static enum pipe_error
    108 retry_draw_arrays( struct svga_context *svga,
    109                    enum pipe_prim_type prim, unsigned start, unsigned count,
    110                    unsigned start_instance, unsigned instance_count,
    111                    boolean do_retry )
    112 {
    113    enum pipe_error ret;
    114 
    115    SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_DRAWARRAYS);
    116 
    117    svga_hwtnl_set_fillmode(svga->hwtnl, svga->curr.rast->hw_fillmode);
    118 
    119    ret = svga_update_state( svga, SVGA_STATE_HW_DRAW );
    120    if (ret != PIPE_OK)
    121       goto retry;
    122 
    123    /** determine if flatshade is to be used after svga_update_state()
    124     *  in case the fragment shader is changed.
    125     */
    126    svga_hwtnl_set_flatshade(svga->hwtnl,
    127                             svga->curr.rast->templ.flatshade ||
    128                             svga->state.hw_draw.fs->uses_flat_interp,
    129                             svga->curr.rast->templ.flatshade_first);
    130 
    131    ret = svga_hwtnl_draw_arrays(svga->hwtnl, prim, start, count,
    132                                 start_instance, instance_count);
    133    if (ret != PIPE_OK)
    134       goto retry;
    135 
    136    goto done;
    137 
    138 retry:
    139    if (ret == PIPE_ERROR_OUT_OF_MEMORY && do_retry)
    140    {
    141       svga_context_flush( svga, NULL );
    142 
    143       ret = retry_draw_arrays(svga, prim, start, count,
    144                               start_instance, instance_count,
    145                               FALSE);
    146    }
    147 
    148 done:
    149    SVGA_STATS_TIME_POP(svga_sws(svga));
    150    return ret;
    151 }
    152 
    153 
    154 /**
    155  * Determine if we need to implement primitive restart with a fallback
    156  * path which breaks the original primitive into sub-primitive at the
    157  * restart indexes.
    158  */
    159 static boolean
    160 need_fallback_prim_restart(const struct svga_context *svga,
    161                            const struct pipe_draw_info *info)
    162 {
    163    if (info->primitive_restart && info->indexed) {
    164       if (!svga_have_vgpu10(svga))
    165          return TRUE;
    166       else if (!svga->state.sw.need_swtnl) {
    167          if (svga->curr.ib.index_size == 1)
    168             return TRUE; /* no device support for 1-byte indexes */
    169          else if (svga->curr.ib.index_size == 2)
    170             return info->restart_index != 0xffff;
    171          else
    172             return info->restart_index != 0xffffffff;
    173       }
    174    }
    175 
    176    return FALSE;
    177 }
    178 
    179 
    180 static void
    181 svga_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
    182 {
    183    struct svga_context *svga = svga_context( pipe );
    184    unsigned reduced_prim = u_reduced_prim( info->mode );
    185    unsigned count = info->count;
    186    enum pipe_error ret = 0;
    187    boolean needed_swtnl;
    188 
    189    SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_DRAWVBO);
    190 
    191    svga->hud.num_draw_calls++;  /* for SVGA_QUERY_NUM_DRAW_CALLS */
    192 
    193    if (u_reduced_prim(info->mode) == PIPE_PRIM_TRIANGLES &&
    194        svga->curr.rast->templ.cull_face == PIPE_FACE_FRONT_AND_BACK)
    195       goto done;
    196 
    197    /*
    198     * Mark currently bound target surfaces as dirty
    199     * doesn't really matter if it is done before drawing.
    200     *
    201     * TODO If we ever normaly return something other then
    202     * true we should not mark it as dirty then.
    203     */
    204    svga_mark_surfaces_dirty(svga_context(pipe));
    205 
    206    if (svga->curr.reduced_prim != reduced_prim) {
    207       svga->curr.reduced_prim = reduced_prim;
    208       svga->dirty |= SVGA_NEW_REDUCED_PRIMITIVE;
    209    }
    210 
    211    if (need_fallback_prim_restart(svga, info)) {
    212       enum pipe_error r;
    213       r = util_draw_vbo_without_prim_restart(pipe, &svga->curr.ib, info);
    214       assert(r == PIPE_OK);
    215       (void) r;
    216       goto done;
    217    }
    218 
    219    if (!u_trim_pipe_prim( info->mode, &count ))
    220       goto done;
    221 
    222    needed_swtnl = svga->state.sw.need_swtnl;
    223 
    224    svga_update_state_retry( svga, SVGA_STATE_NEED_SWTNL );
    225 
    226    if (svga->state.sw.need_swtnl) {
    227       svga->hud.num_fallbacks++;  /* for SVGA_QUERY_NUM_FALLBACKS */
    228       if (!needed_swtnl) {
    229          /*
    230           * We're switching from HW to SW TNL.  SW TNL will require mapping all
    231           * currently bound vertex buffers, some of which may already be
    232           * referenced in the current command buffer as result of previous HW
    233           * TNL. So flush now, to prevent the context to flush while a referred
    234           * vertex buffer is mapped.
    235           */
    236 
    237          svga_context_flush(svga, NULL);
    238       }
    239 
    240       /* Avoid leaking the previous hwtnl bias to swtnl */
    241       svga_hwtnl_set_index_bias( svga->hwtnl, 0 );
    242       ret = svga_swtnl_draw_vbo( svga, info );
    243    }
    244    else {
    245       if (info->indexed && svga->curr.ib.buffer) {
    246          unsigned offset;
    247 
    248          assert(svga->curr.ib.offset % svga->curr.ib.index_size == 0);
    249          offset = svga->curr.ib.offset / svga->curr.ib.index_size;
    250 
    251          ret = retry_draw_range_elements( svga,
    252                                           svga->curr.ib.buffer,
    253                                           svga->curr.ib.index_size,
    254                                           info->index_bias,
    255                                           info->min_index,
    256                                           info->max_index,
    257                                           info->mode,
    258                                           info->start + offset,
    259                                           count,
    260                                           info->start_instance,
    261                                           info->instance_count,
    262                                           TRUE );
    263       }
    264       else {
    265          ret = retry_draw_arrays(svga, info->mode, info->start, count,
    266                                  info->start_instance, info->instance_count,
    267                                  TRUE);
    268       }
    269    }
    270 
    271    /* XXX: Silence warnings, do something sensible here? */
    272    (void)ret;
    273 
    274    if (SVGA_DEBUG & DEBUG_FLUSH) {
    275       svga_hwtnl_flush_retry( svga );
    276       svga_context_flush(svga, NULL);
    277    }
    278 
    279 done:
    280    SVGA_STATS_TIME_POP(svga_sws(svga));
    281 ;
    282 }
    283 
    284 
    285 void svga_init_draw_functions( struct svga_context *svga )
    286 {
    287    svga->pipe.draw_vbo = svga_draw_vbo;
    288 }
    289