Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /**************************************************************************
  2.  *
  3.  * Copyright 2007 VMware, Inc.
  4.  * All Rights Reserved.
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a
  7.  * copy of this software and associated documentation files (the
  8.  * "Software"), to deal in the Software without restriction, including
  9.  * without limitation the rights to use, copy, modify, merge, publish,
  10.  * distribute, sub license, and/or sell copies of the Software, and to
  11.  * permit persons to whom the Software is furnished to do so, subject to
  12.  * the following conditions:
  13.  *
  14.  * The above copyright notice and this permission notice (including the
  15.  * next paragraph) shall be included in all copies or substantial portions
  16.  * of the Software.
  17.  *
  18.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  19.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  20.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
  21.  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
  22.  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  23.  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  24.  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  25.  *
  26.  **************************************************************************/
  27.  
  28.  /*
  29.   * Authors:
  30.   *   Keith Whitwell <keithw@vmware.com>
  31.   */
  32.  
  33. #include "util/u_memory.h"
  34. #include "draw/draw_context.h"
  35. #include "draw/draw_private.h"
  36. #include "draw/draw_vbuf.h"
  37. #include "draw/draw_vertex.h"
  38. #include "draw/draw_pt.h"
  39. #include "draw/draw_gs.h"
  40. #include "translate/translate.h"
  41. #include "translate/translate_cache.h"
  42.  
  43. /* The simplest 'middle end' in the new vertex code.
  44.  *
  45.  * The responsibilities of a middle end are to:
  46.  *  - perform vertex fetch using
  47.  *       - draw vertex element/buffer state
  48.  *       - a list of fetch indices we received as an input
  49.  *  - run the vertex shader
  50.  *  - cliptest,
  51.  *  - clip coord calculation
  52.  *  - viewport transformation
  53.  *  - if necessary, run the primitive pipeline, passing it:
  54.  *       - a linear array of vertex_header vertices constructed here
  55.  *       - a set of draw indices we received as an input
  56.  *  - otherwise, drive the hw backend,
  57.  *       - allocate space for hardware format vertices
  58.  *       - translate the vertex-shader output vertices to hw format
  59.  *       - calling the backend draw functions.
  60.  *
  61.  * For convenience, we provide a helper function to drive the hardware
  62.  * backend given similar inputs to those required to run the pipeline.
  63.  *
  64.  * In the case of passthrough mode, many of these actions are disabled
  65.  * or noops, so we end up doing:
  66.  *
  67.  *  - perform vertex fetch
  68.  *  - drive the hw backend
  69.  *
  70.  * IE, basically just vertex fetch to post-vs-format vertices,
  71.  * followed by a call to the backend helper function.
  72.  */
  73.  
  74.  
  75. struct fetch_emit_middle_end {
  76.    struct draw_pt_middle_end base;
  77.    struct draw_context *draw;
  78.  
  79.    struct translate *translate;
  80.    const struct vertex_info *vinfo;
  81.  
  82.    /* Cache point size somewhere it's address won't change:
  83.     */
  84.    float point_size;
  85.  
  86.    struct translate_cache *cache;
  87. };
  88.  
  89.  
  90. static void fetch_emit_prepare( struct draw_pt_middle_end *middle,
  91.                                 unsigned prim,
  92.                                 unsigned opt,
  93.                                 unsigned *max_vertices )
  94. {
  95.    struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
  96.    struct draw_context *draw = feme->draw;
  97.    const struct vertex_info *vinfo;
  98.    unsigned i, dst_offset;
  99.    struct translate_key key;
  100.    unsigned gs_out_prim = (draw->gs.geometry_shader ?
  101.                            draw->gs.geometry_shader->output_primitive :
  102.                            prim);
  103.  
  104.    draw->render->set_primitive(draw->render, gs_out_prim);
  105.  
  106.    /* Must do this after set_primitive() above:
  107.     */
  108.    vinfo = feme->vinfo = draw->render->get_vertex_info(draw->render);
  109.  
  110.    /* Transform from API vertices to HW vertices, skipping the
  111.     * pipeline_vertex intermediate step.
  112.     */
  113.    dst_offset = 0;
  114.    memset(&key, 0, sizeof(key));
  115.  
  116.    for (i = 0; i < vinfo->num_attribs; i++) {
  117.       const struct pipe_vertex_element *src = &draw->pt.vertex_element[vinfo->attrib[i].src_index];
  118.  
  119.       unsigned emit_sz = 0;
  120.       unsigned input_format = src->src_format;
  121.       unsigned input_buffer = src->vertex_buffer_index;
  122.       unsigned input_offset = src->src_offset;
  123.       unsigned output_format;
  124.  
  125.       output_format = draw_translate_vinfo_format(vinfo->attrib[i].emit);
  126.       emit_sz = draw_translate_vinfo_size(vinfo->attrib[i].emit);
  127.  
  128.       if (vinfo->attrib[i].emit == EMIT_OMIT)
  129.          continue;
  130.  
  131.       if (vinfo->attrib[i].emit == EMIT_1F_PSIZE) {
  132.          input_format = PIPE_FORMAT_R32_FLOAT;
  133.          input_buffer = draw->pt.nr_vertex_buffers;
  134.          input_offset = 0;
  135.       }
  136.  
  137.       key.element[i].type = TRANSLATE_ELEMENT_NORMAL;
  138.       key.element[i].input_format = input_format;
  139.       key.element[i].input_buffer = input_buffer;
  140.       key.element[i].input_offset = input_offset;
  141.       key.element[i].instance_divisor = src->instance_divisor;
  142.       key.element[i].output_format = output_format;
  143.       key.element[i].output_offset = dst_offset;
  144.  
  145.       dst_offset += emit_sz;
  146.    }
  147.  
  148.    key.nr_elements = vinfo->num_attribs;
  149.    key.output_stride = vinfo->size * 4;
  150.  
  151.    /* Don't bother with caching at this stage:
  152.     */
  153.    if (!feme->translate ||
  154.        translate_key_compare(&feme->translate->key, &key) != 0)
  155.    {
  156.       translate_key_sanitize(&key);
  157.       feme->translate = translate_cache_find(feme->cache,
  158.                                              &key);
  159.  
  160.       feme->translate->set_buffer(feme->translate,
  161.                                   draw->pt.nr_vertex_buffers,
  162.                                   &feme->point_size,
  163.                                   0,
  164.                                   ~0);
  165.    }
  166.  
  167.    feme->point_size = draw->rasterizer->point_size;
  168.  
  169.    for (i = 0; i < draw->pt.nr_vertex_buffers; i++) {
  170.       feme->translate->set_buffer(feme->translate,
  171.                                   i,
  172.                                   ((char *)draw->pt.user.vbuffer[i].map +
  173.                                    draw->pt.vertex_buffer[i].buffer_offset),
  174.                                   draw->pt.vertex_buffer[i].stride,
  175.                                   draw->pt.max_index);
  176.    }
  177.  
  178.    *max_vertices = (draw->render->max_vertex_buffer_bytes /
  179.                     (vinfo->size * 4));
  180. }
  181.  
  182.  
  183. static void
  184. fetch_emit_bind_parameters(struct draw_pt_middle_end *middle)
  185. {
  186.    /* No-op? */
  187. }
  188.  
  189.  
  190. static void fetch_emit_run( struct draw_pt_middle_end *middle,
  191.                             const unsigned *fetch_elts,
  192.                             unsigned fetch_count,
  193.                             const ushort *draw_elts,
  194.                             unsigned draw_count,
  195.                             unsigned prim_flags )
  196. {
  197.    struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
  198.    struct draw_context *draw = feme->draw;
  199.    void *hw_verts;
  200.  
  201.    /* XXX: need to flush to get prim_vbuf.c to release its allocation??
  202.     */
  203.    draw_do_flush( draw, DRAW_FLUSH_BACKEND );
  204.  
  205.    draw->render->allocate_vertices( draw->render,
  206.                                     (ushort)feme->translate->key.output_stride,
  207.                                     (ushort)fetch_count );
  208.  
  209.    hw_verts = draw->render->map_vertices( draw->render );
  210.    if (!hw_verts) {
  211.       debug_warn_once("vertex buffer allocation failed (out of memory?)");
  212.       return;
  213.    }
  214.  
  215.    /* Single routine to fetch vertices and emit HW verts.
  216.     */
  217.    feme->translate->run_elts( feme->translate,
  218.                               fetch_elts,
  219.                               fetch_count,
  220.                               draw->start_instance,
  221.                               draw->instance_id,
  222.                               hw_verts );
  223.  
  224.    if (0) {
  225.       unsigned i;
  226.       for (i = 0; i < fetch_count; i++) {
  227.          debug_printf("\n\nvertex %d:\n", i);
  228.          draw_dump_emitted_vertex( feme->vinfo,
  229.                                    (const uint8_t *)hw_verts + feme->vinfo->size * 4 * i );
  230.       }
  231.    }
  232.  
  233.    draw->render->unmap_vertices( draw->render,
  234.                                  0,
  235.                                  (ushort)(fetch_count - 1) );
  236.  
  237.    /* XXX: Draw arrays path to avoid re-emitting index list again and
  238.     * again.
  239.     */
  240.    draw->render->draw_elements( draw->render,
  241.                                 draw_elts,
  242.                                 draw_count );
  243.  
  244.    /* Done -- that was easy, wasn't it:
  245.     */
  246.    draw->render->release_vertices( draw->render );
  247.  
  248. }
  249.  
  250.  
  251. static void fetch_emit_run_linear( struct draw_pt_middle_end *middle,
  252.                                    unsigned start,
  253.                                    unsigned count,
  254.                                    unsigned prim_flags )
  255. {
  256.    struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
  257.    struct draw_context *draw = feme->draw;
  258.    void *hw_verts;
  259.  
  260.    /* XXX: need to flush to get prim_vbuf.c to release its allocation??
  261.     */
  262.    draw_do_flush( draw, DRAW_FLUSH_BACKEND );
  263.  
  264.    if (!draw->render->allocate_vertices( draw->render,
  265.                                          (ushort)feme->translate->key.output_stride,
  266.                                          (ushort)count ))
  267.       goto fail;
  268.  
  269.    hw_verts = draw->render->map_vertices( draw->render );
  270.    if (!hw_verts)
  271.       goto fail;
  272.  
  273.    /* Single routine to fetch vertices and emit HW verts.
  274.     */
  275.    feme->translate->run( feme->translate,
  276.                          start,
  277.                          count,
  278.                          draw->start_instance,
  279.                          draw->instance_id,
  280.                          hw_verts );
  281.  
  282.    if (0) {
  283.       unsigned i;
  284.       for (i = 0; i < count; i++) {
  285.          debug_printf("\n\nvertex %d:\n", i);
  286.          draw_dump_emitted_vertex( feme->vinfo,
  287.                                    (const uint8_t *)hw_verts + feme->vinfo->size * 4 * i );
  288.       }
  289.    }
  290.  
  291.    draw->render->unmap_vertices( draw->render, 0, count - 1 );
  292.  
  293.    /* XXX: Draw arrays path to avoid re-emitting index list again and
  294.     * again.
  295.     */
  296.    draw->render->draw_arrays( draw->render, 0, count );
  297.  
  298.    /* Done -- that was easy, wasn't it:
  299.     */
  300.    draw->render->release_vertices( draw->render );
  301.    return;
  302.  
  303. fail:
  304.    debug_warn_once("allocate or map of vertex buffer failed (out of memory?)");
  305.    return;
  306. }
  307.  
  308.  
  309. static boolean fetch_emit_run_linear_elts( struct draw_pt_middle_end *middle,
  310.                                         unsigned start,
  311.                                         unsigned count,
  312.                                         const ushort *draw_elts,
  313.                                         unsigned draw_count,
  314.                                         unsigned prim_flags )
  315. {
  316.    struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
  317.    struct draw_context *draw = feme->draw;
  318.    void *hw_verts;
  319.  
  320.    /* XXX: need to flush to get prim_vbuf.c to release its allocation??
  321.     */
  322.    draw_do_flush( draw, DRAW_FLUSH_BACKEND );
  323.  
  324.    if (!draw->render->allocate_vertices( draw->render,
  325.                                          (ushort)feme->translate->key.output_stride,
  326.                                          (ushort)count ))
  327.       return FALSE;
  328.  
  329.    hw_verts = draw->render->map_vertices( draw->render );
  330.    if (!hw_verts)
  331.       return FALSE;
  332.  
  333.    /* Single routine to fetch vertices and emit HW verts.
  334.     */
  335.    feme->translate->run( feme->translate,
  336.                          start,
  337.                          count,
  338.                          draw->start_instance,
  339.                          draw->instance_id,
  340.                          hw_verts );
  341.  
  342.    draw->render->unmap_vertices( draw->render, 0, (ushort)(count - 1) );
  343.  
  344.    /* XXX: Draw arrays path to avoid re-emitting index list again and
  345.     * again.
  346.     */
  347.    draw->render->draw_elements( draw->render,
  348.                                 draw_elts,
  349.                                 draw_count );
  350.  
  351.    /* Done -- that was easy, wasn't it:
  352.     */
  353.    draw->render->release_vertices( draw->render );
  354.  
  355.    return TRUE;
  356. }
  357.  
  358.  
  359. static void fetch_emit_finish( struct draw_pt_middle_end *middle )
  360. {
  361.    /* nothing to do */
  362. }
  363.  
  364.  
  365. static void fetch_emit_destroy( struct draw_pt_middle_end *middle )
  366. {
  367.    struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
  368.  
  369.    if (feme->cache)
  370.       translate_cache_destroy(feme->cache);
  371.  
  372.    FREE(middle);
  373. }
  374.  
  375.  
  376. struct draw_pt_middle_end *draw_pt_fetch_emit( struct draw_context *draw )
  377. {
  378.    struct fetch_emit_middle_end *fetch_emit = CALLOC_STRUCT( fetch_emit_middle_end );
  379.    if (fetch_emit == NULL)
  380.       return NULL;
  381.  
  382.    fetch_emit->cache = translate_cache_create();
  383.    if (!fetch_emit->cache) {
  384.       FREE(fetch_emit);
  385.       return NULL;
  386.    }
  387.  
  388.    fetch_emit->base.prepare    = fetch_emit_prepare;
  389.    fetch_emit->base.bind_parameters = fetch_emit_bind_parameters;
  390.    fetch_emit->base.run        = fetch_emit_run;
  391.    fetch_emit->base.run_linear = fetch_emit_run_linear;
  392.    fetch_emit->base.run_linear_elts = fetch_emit_run_linear_elts;
  393.    fetch_emit->base.finish     = fetch_emit_finish;
  394.    fetch_emit->base.destroy    = fetch_emit_destroy;
  395.  
  396.    fetch_emit->draw = draw;
  397.  
  398.    return &fetch_emit->base;
  399. }
  400.  
  401.