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