Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  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_time.h"
  31. #include "util/u_upload_mgr.h"
  32. #include "indices/u_indices.h"
  33.  
  34. #include "svga_hw_reg.h"
  35. #include "svga_cmd.h"
  36. #include "svga_context.h"
  37. #include "svga_screen.h"
  38. #include "svga_draw.h"
  39. #include "svga_state.h"
  40. #include "svga_swtnl.h"
  41. #include "svga_debug.h"
  42. #include "svga_resource_buffer.h"
  43.  
  44.  
  45. /**
  46.  * Determine the ranges to upload for the user-buffers referenced
  47.  * by the next draw command.
  48.  *
  49.  * TODO: It might be beneficial to support multiple ranges. In that case,
  50.  * the struct svga_buffer::uploaded member should be made an array or a
  51.  * list, since we need to account for the possibility that different ranges
  52.  * may be uploaded to different hardware buffers chosen by the utility
  53.  * upload manager.
  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.    unsigned 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. /**
  111.  * svga_upload_user_buffers - upload parts of user buffers
  112.  *
  113.  * This function streams a part of a user buffer to hw and fills
  114.  * svga_buffer::uploaded with information on the upload.
  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. /**
  173.  * svga_release_user_upl_buffers - release uploaded parts of user buffers
  174.  *
  175.  * This function releases the hw copy of the uploaded fraction of the
  176.  * user-buffer. It's important to do this as soon as all draw calls
  177.  * affecting the uploaded fraction are issued, as this allows for
  178.  * efficient reuse of the hardware surface backing the uploaded fraction.
  179.  *
  180.  * svga_buffer::source_offset is set to 0, and svga_buffer::uploaded::buffer
  181.  * is set to 0.
  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.    svga->num_draw_calls++;  /* for SVGA_QUERY_DRAW_CALLS */
  334.  
  335.    if (!u_trim_pipe_prim( info->mode, &count ))
  336.       return;
  337.  
  338.    /*
  339.     * Mark currently bound target surfaces as dirty
  340.     * doesn't really matter if it is done before drawing.
  341.     *
  342.     * TODO If we ever normaly return something other then
  343.     * true we should not mark it as dirty then.
  344.     */
  345.    svga_mark_surfaces_dirty(svga_context(pipe));
  346.  
  347.    if (svga->curr.reduced_prim != reduced_prim) {
  348.       svga->curr.reduced_prim = reduced_prim;
  349.       svga->dirty |= SVGA_NEW_REDUCED_PRIMITIVE;
  350.    }
  351.  
  352.    needed_swtnl = svga->state.sw.need_swtnl;
  353.  
  354.    svga_update_state_retry( svga, SVGA_STATE_NEED_SWTNL );
  355.  
  356. #ifdef DEBUG
  357.    if (svga->curr.vs->base.id == svga->debug.disable_shader ||
  358.        svga->curr.fs->base.id == svga->debug.disable_shader)
  359.       return;
  360. #endif
  361.  
  362.    if (svga->state.sw.need_swtnl) {
  363.       svga->num_fallbacks++;  /* for SVGA_QUERY_FALLBACKS */
  364.       if (!needed_swtnl) {
  365.          /*
  366.           * We're switching from HW to SW TNL.  SW TNL will require mapping all
  367.           * currently bound vertex buffers, some of which may already be
  368.           * referenced in the current command buffer as result of previous HW
  369.           * TNL. So flush now, to prevent the context to flush while a referred
  370.           * vertex buffer is mapped.
  371.           */
  372.  
  373.          svga_context_flush(svga, NULL);
  374.       }
  375.  
  376.       /* Avoid leaking the previous hwtnl bias to swtnl */
  377.       svga_hwtnl_set_index_bias( svga->hwtnl, 0 );
  378.       ret = svga_swtnl_draw_vbo( svga, info );
  379.    }
  380.    else {
  381.       if (info->indexed && svga->curr.ib.buffer) {
  382.          unsigned offset;
  383.  
  384.          assert(svga->curr.ib.offset % svga->curr.ib.index_size == 0);
  385.          offset = svga->curr.ib.offset / svga->curr.ib.index_size;
  386.  
  387.          ret = retry_draw_range_elements( svga,
  388.                                           svga->curr.ib.buffer,
  389.                                           svga->curr.ib.index_size,
  390.                                           info->index_bias,
  391.                                           info->min_index,
  392.                                           info->max_index,
  393.                                           info->mode,
  394.                                           info->start + offset,
  395.                                           info->count,
  396.                                           info->instance_count,
  397.                                           TRUE );
  398.       }
  399.       else {
  400.          ret = retry_draw_arrays( svga,
  401.                                   info->mode,
  402.                                   info->start,
  403.                                   info->count,
  404.                                   info->instance_count,
  405.                                   TRUE );
  406.       }
  407.    }
  408.  
  409.    /* XXX: Silence warnings, do something sensible here? */
  410.    (void)ret;
  411.  
  412.    svga_release_user_upl_buffers( svga );
  413.  
  414.    if (SVGA_DEBUG & DEBUG_FLUSH) {
  415.       svga_hwtnl_flush_retry( svga );
  416.       svga_context_flush(svga, NULL);
  417.    }
  418. }
  419.  
  420.  
  421. void svga_init_draw_functions( struct svga_context *svga )
  422. {
  423.    svga->pipe.draw_vbo = svga_draw_vbo;
  424. }
  425.