Subversion Repositories Kolibri OS

Rev

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

  1. /**************************************************************************
  2.  *
  3.  * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
  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 TUNGSTEN GRAPHICS 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 <keith@tungstengraphics.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 fetch_emit_run( struct draw_pt_middle_end *middle,
  184.                             const unsigned *fetch_elts,
  185.                             unsigned fetch_count,
  186.                             const ushort *draw_elts,
  187.                             unsigned draw_count,
  188.                             unsigned prim_flags )
  189. {
  190.    struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
  191.    struct draw_context *draw = feme->draw;
  192.    void *hw_verts;
  193.  
  194.    /* XXX: need to flush to get prim_vbuf.c to release its allocation??
  195.     */
  196.    draw_do_flush( draw, DRAW_FLUSH_BACKEND );
  197.  
  198.    draw->render->allocate_vertices( draw->render,
  199.                                     (ushort)feme->translate->key.output_stride,
  200.                                     (ushort)fetch_count );
  201.  
  202.    hw_verts = draw->render->map_vertices( draw->render );
  203.    if (!hw_verts) {
  204.       debug_warn_once("vertex buffer allocation failed (out of memory?)");
  205.       return;
  206.    }
  207.  
  208.    /* Single routine to fetch vertices and emit HW verts.
  209.     */
  210.    feme->translate->run_elts( feme->translate,
  211.                               fetch_elts,
  212.                               fetch_count,
  213.                               draw->start_instance,
  214.                               draw->instance_id,
  215.                               hw_verts );
  216.  
  217.    if (0) {
  218.       unsigned i;
  219.       for (i = 0; i < fetch_count; i++) {
  220.          debug_printf("\n\nvertex %d:\n", i);
  221.          draw_dump_emitted_vertex( feme->vinfo,
  222.                                    (const uint8_t *)hw_verts + feme->vinfo->size * 4 * i );
  223.       }
  224.    }
  225.  
  226.    draw->render->unmap_vertices( draw->render,
  227.                                  0,
  228.                                  (ushort)(fetch_count - 1) );
  229.  
  230.    /* XXX: Draw arrays path to avoid re-emitting index list again and
  231.     * again.
  232.     */
  233.    draw->render->draw_elements( draw->render,
  234.                                 draw_elts,
  235.                                 draw_count );
  236.  
  237.    /* Done -- that was easy, wasn't it:
  238.     */
  239.    draw->render->release_vertices( draw->render );
  240.  
  241. }
  242.  
  243.  
  244. static void fetch_emit_run_linear( struct draw_pt_middle_end *middle,
  245.                                    unsigned start,
  246.                                    unsigned count,
  247.                                    unsigned prim_flags )
  248. {
  249.    struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
  250.    struct draw_context *draw = feme->draw;
  251.    void *hw_verts;
  252.  
  253.    /* XXX: need to flush to get prim_vbuf.c to release its allocation??
  254.     */
  255.    draw_do_flush( draw, DRAW_FLUSH_BACKEND );
  256.  
  257.    if (!draw->render->allocate_vertices( draw->render,
  258.                                          (ushort)feme->translate->key.output_stride,
  259.                                          (ushort)count ))
  260.       goto fail;
  261.  
  262.    hw_verts = draw->render->map_vertices( draw->render );
  263.    if (!hw_verts)
  264.       goto fail;
  265.  
  266.    /* Single routine to fetch vertices and emit HW verts.
  267.     */
  268.    feme->translate->run( feme->translate,
  269.                          start,
  270.                          count,
  271.                          draw->start_instance,
  272.                          draw->instance_id,
  273.                          hw_verts );
  274.  
  275.    if (0) {
  276.       unsigned i;
  277.       for (i = 0; i < count; i++) {
  278.          debug_printf("\n\nvertex %d:\n", i);
  279.          draw_dump_emitted_vertex( feme->vinfo,
  280.                                    (const uint8_t *)hw_verts + feme->vinfo->size * 4 * i );
  281.       }
  282.    }
  283.  
  284.    draw->render->unmap_vertices( draw->render, 0, count - 1 );
  285.  
  286.    /* XXX: Draw arrays path to avoid re-emitting index list again and
  287.     * again.
  288.     */
  289.    draw->render->draw_arrays( draw->render, 0, count );
  290.  
  291.    /* Done -- that was easy, wasn't it:
  292.     */
  293.    draw->render->release_vertices( draw->render );
  294.    return;
  295.  
  296. fail:
  297.    debug_warn_once("allocate or map of vertex buffer failed (out of memory?)");
  298.    return;
  299. }
  300.  
  301.  
  302. static boolean fetch_emit_run_linear_elts( struct draw_pt_middle_end *middle,
  303.                                         unsigned start,
  304.                                         unsigned count,
  305.                                         const ushort *draw_elts,
  306.                                         unsigned draw_count,
  307.                                         unsigned prim_flags )
  308. {
  309.    struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
  310.    struct draw_context *draw = feme->draw;
  311.    void *hw_verts;
  312.  
  313.    /* XXX: need to flush to get prim_vbuf.c to release its allocation??
  314.     */
  315.    draw_do_flush( draw, DRAW_FLUSH_BACKEND );
  316.  
  317.    if (!draw->render->allocate_vertices( draw->render,
  318.                                          (ushort)feme->translate->key.output_stride,
  319.                                          (ushort)count ))
  320.       return FALSE;
  321.  
  322.    hw_verts = draw->render->map_vertices( draw->render );
  323.    if (!hw_verts)
  324.       return FALSE;
  325.  
  326.    /* Single routine to fetch vertices and emit HW verts.
  327.     */
  328.    feme->translate->run( feme->translate,
  329.                          start,
  330.                          count,
  331.                          draw->start_instance,
  332.                          draw->instance_id,
  333.                          hw_verts );
  334.  
  335.    draw->render->unmap_vertices( draw->render, 0, (ushort)(count - 1) );
  336.  
  337.    /* XXX: Draw arrays path to avoid re-emitting index list again and
  338.     * again.
  339.     */
  340.    draw->render->draw_elements( draw->render,
  341.                                 draw_elts,
  342.                                 draw_count );
  343.  
  344.    /* Done -- that was easy, wasn't it:
  345.     */
  346.    draw->render->release_vertices( draw->render );
  347.  
  348.    return TRUE;
  349. }
  350.  
  351.  
  352. static void fetch_emit_finish( struct draw_pt_middle_end *middle )
  353. {
  354.    /* nothing to do */
  355. }
  356.  
  357.  
  358. static void fetch_emit_destroy( struct draw_pt_middle_end *middle )
  359. {
  360.    struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
  361.  
  362.    if (feme->cache)
  363.       translate_cache_destroy(feme->cache);
  364.  
  365.    FREE(middle);
  366. }
  367.  
  368.  
  369. struct draw_pt_middle_end *draw_pt_fetch_emit( struct draw_context *draw )
  370. {
  371.    struct fetch_emit_middle_end *fetch_emit = CALLOC_STRUCT( fetch_emit_middle_end );
  372.    if (fetch_emit == NULL)
  373.       return NULL;
  374.  
  375.    fetch_emit->cache = translate_cache_create();
  376.    if (!fetch_emit->cache) {
  377.       FREE(fetch_emit);
  378.       return NULL;
  379.    }
  380.  
  381.    fetch_emit->base.prepare    = fetch_emit_prepare;
  382.    fetch_emit->base.run        = fetch_emit_run;
  383.    fetch_emit->base.run_linear = fetch_emit_run_linear;
  384.    fetch_emit->base.run_linear_elts = fetch_emit_run_linear_elts;
  385.    fetch_emit->base.finish     = fetch_emit_finish;
  386.    fetch_emit->base.destroy    = fetch_emit_destroy;
  387.  
  388.    fetch_emit->draw = draw;
  389.  
  390.    return &fetch_emit->base;
  391. }
  392.  
  393.