draw_pt_fetch_shade_pipeline.c

Go to the documentation of this file.
00001 /**************************************************************************
00002  *
00003  * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
00004  * All Rights Reserved.
00005  *
00006  * Permission is hereby granted, free of charge, to any person obtaining a
00007  * copy of this software and associated documentation files (the
00008  * "Software"), to deal in the Software without restriction, including
00009  * without limitation the rights to use, copy, modify, merge, publish,
00010  * distribute, sub license, and/or sell copies of the Software, and to
00011  * permit persons to whom the Software is furnished to do so, subject to
00012  * the following conditions:
00013  *
00014  * The above copyright notice and this permission notice (including the
00015  * next paragraph) shall be included in all copies or substantial portions
00016  * of the Software.
00017  *
00018  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00019  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00020  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
00021  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
00022  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
00023  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
00024  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00025  *
00026  **************************************************************************/
00027 
00028 #include "util/u_math.h"
00029 #include "util/u_memory.h"
00030 #include "draw/draw_context.h"
00031 #include "draw/draw_vbuf.h"
00032 #include "draw/draw_vertex.h"
00033 #include "draw/draw_pt.h"
00034 #include "draw/draw_vs.h"
00035 #include "translate/translate.h"
00036 
00037 
00038 struct fetch_pipeline_middle_end {
00039    struct draw_pt_middle_end base;
00040    struct draw_context *draw;
00041 
00042    struct pt_emit *emit;
00043    struct pt_fetch *fetch;
00044    struct pt_post_vs *post_vs;
00045 
00046    unsigned vertex_data_offset;
00047    unsigned vertex_size;
00048    unsigned prim;
00049    unsigned opt;
00050 };
00051 
00052 
00053 static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle,
00054                                     unsigned prim,
00055                                     unsigned opt,
00056                                     unsigned *max_vertices )
00057 {
00058    struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
00059    struct draw_context *draw = fpme->draw;
00060    struct draw_vertex_shader *vs = draw->vs.vertex_shader;
00061 
00062    /* Add one to num_outputs because the pipeline occasionally tags on
00063     * an additional texcoord, eg for AA lines.
00064     */
00065    unsigned nr = MAX2( vs->info.num_inputs,
00066                        vs->info.num_outputs + 1 );
00067 
00068    fpme->prim = prim;
00069    fpme->opt = opt;
00070 
00071    /* Always leave room for the vertex header whether we need it or
00072     * not.  It's hard to get rid of it in particular because of the
00073     * viewport code in draw_pt_post_vs.c.  
00074     */
00075    fpme->vertex_size = sizeof(struct vertex_header) + nr * 4 * sizeof(float);
00076 
00077    
00078 
00079    draw_pt_fetch_prepare( fpme->fetch, 
00080                           fpme->vertex_size );
00081 
00082    /* XXX: it's not really gl rasterization rules we care about here,
00083     * but gl vs dx9 clip spaces.
00084     */
00085    draw_pt_post_vs_prepare( fpme->post_vs,
00086                             (boolean)draw->bypass_clipping,
00087                             (boolean)draw->identity_viewport,
00088                             (boolean)draw->rasterizer->gl_rasterization_rules );
00089                             
00090 
00091    if (!(opt & PT_PIPELINE)) {
00092       draw_pt_emit_prepare( fpme->emit, 
00093                             prim,
00094                             max_vertices );
00095 
00096       *max_vertices = MAX2( *max_vertices,
00097                             DRAW_PIPE_MAX_VERTICES );
00098    }
00099    else {
00100       *max_vertices = DRAW_PIPE_MAX_VERTICES; 
00101    }
00102 
00103    /* return even number */
00104    *max_vertices = *max_vertices & ~1;
00105 
00106    /* No need to prepare the shader.
00107     */
00108    vs->prepare(vs, draw);
00109 }
00110 
00111 
00112 
00113 static void fetch_pipeline_run( struct draw_pt_middle_end *middle,
00114                                 const unsigned *fetch_elts,
00115                                 unsigned fetch_count,
00116                                 const ushort *draw_elts,
00117                                 unsigned draw_count )
00118 {
00119    struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
00120    struct draw_context *draw = fpme->draw;
00121    struct draw_vertex_shader *shader = draw->vs.vertex_shader;
00122    unsigned opt = fpme->opt;
00123    unsigned alloc_count = align( fetch_count, 4 );
00124 
00125    struct vertex_header *pipeline_verts = 
00126       (struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count);
00127 
00128    if (!pipeline_verts) {
00129       /* Not much we can do here - just skip the rendering.
00130        */
00131       assert(0);
00132       return;
00133    }
00134 
00135    /* Fetch into our vertex buffer
00136     */
00137    draw_pt_fetch_run( fpme->fetch,
00138                       fetch_elts, 
00139                       fetch_count,
00140                       (char *)pipeline_verts );
00141 
00142    /* Run the shader, note that this overwrites the data[] parts of
00143     * the pipeline verts.  If there is no shader, ie a bypass shader,
00144     * then the inputs == outputs, and are already in the correct
00145     * place.
00146     */
00147    if (opt & PT_SHADE)
00148    {
00149       shader->run_linear(shader, 
00150                          (const float (*)[4])pipeline_verts->data,
00151                          (      float (*)[4])pipeline_verts->data,
00152                          (const float (*)[4])draw->pt.user.constants,
00153                          fetch_count,
00154                          fpme->vertex_size,
00155                          fpme->vertex_size);
00156    }
00157 
00158    if (draw_pt_post_vs_run( fpme->post_vs,
00159                             pipeline_verts,
00160                             fetch_count,
00161                             fpme->vertex_size ))
00162    {
00163       opt |= PT_PIPELINE;
00164    }
00165 
00166    /* Do we need to run the pipeline?
00167     */
00168    if (opt & PT_PIPELINE) {
00169       draw_pipeline_run( fpme->draw,
00170                          fpme->prim,
00171                          pipeline_verts,
00172                          fetch_count,
00173                          fpme->vertex_size,
00174                          draw_elts,
00175                          draw_count );
00176    }
00177    else {
00178       draw_pt_emit( fpme->emit,
00179                     (const float (*)[4])pipeline_verts->data,
00180                     fetch_count,
00181                     fpme->vertex_size,
00182                     draw_elts,
00183                     draw_count );
00184    }
00185 
00186 
00187    FREE(pipeline_verts);
00188 }
00189 
00190 
00191 static void fetch_pipeline_linear_run( struct draw_pt_middle_end *middle,
00192                                        unsigned start,
00193                                        unsigned count)
00194 {
00195    struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
00196    struct draw_context *draw = fpme->draw;
00197    struct draw_vertex_shader *shader = draw->vs.vertex_shader;
00198    unsigned opt = fpme->opt;
00199    unsigned alloc_count = align( count, 4 );
00200 
00201    struct vertex_header *pipeline_verts =
00202       (struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count);
00203 
00204    if (!pipeline_verts) {
00205       /* Not much we can do here - just skip the rendering.
00206        */
00207       assert(0);
00208       return;
00209    }
00210 
00211    /* Fetch into our vertex buffer
00212     */
00213    draw_pt_fetch_run_linear( fpme->fetch,
00214                              start,
00215                              count,
00216                              (char *)pipeline_verts );
00217 
00218    /* Run the shader, note that this overwrites the data[] parts of
00219     * the pipeline verts.  If there is no shader, ie a bypass shader,
00220     * then the inputs == outputs, and are already in the correct
00221     * place.
00222     */
00223    if (opt & PT_SHADE)
00224    {
00225       shader->run_linear(shader,
00226                          (const float (*)[4])pipeline_verts->data,
00227                          (      float (*)[4])pipeline_verts->data,
00228                          (const float (*)[4])draw->pt.user.constants,
00229                          count,
00230                          fpme->vertex_size,
00231                          fpme->vertex_size);
00232    }
00233 
00234    if (draw_pt_post_vs_run( fpme->post_vs,
00235                             pipeline_verts,
00236                             count,
00237                             fpme->vertex_size ))
00238    {
00239       opt |= PT_PIPELINE;
00240    }
00241 
00242    /* Do we need to run the pipeline?
00243     */
00244    if (opt & PT_PIPELINE) {
00245       draw_pipeline_run_linear( fpme->draw,
00246                                 fpme->prim,
00247                                 pipeline_verts,
00248                                 count,
00249                                 fpme->vertex_size);
00250    }
00251    else {
00252       draw_pt_emit_linear( fpme->emit,
00253                            (const float (*)[4])pipeline_verts->data,
00254                            count,
00255                            fpme->vertex_size,
00256                            0, /*start*/
00257                            count );
00258    }
00259 
00260    FREE(pipeline_verts);
00261 }
00262 
00263 
00264 
00265 static boolean fetch_pipeline_linear_run_elts( struct draw_pt_middle_end *middle,
00266                                             unsigned start,
00267                                             unsigned count,
00268                                             const ushort *draw_elts,
00269                                             unsigned draw_count )
00270 {
00271    struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
00272    struct draw_context *draw = fpme->draw;
00273    struct draw_vertex_shader *shader = draw->vs.vertex_shader;
00274    unsigned opt = fpme->opt;
00275    unsigned alloc_count = align( count, 4 );
00276 
00277    struct vertex_header *pipeline_verts =
00278       (struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count);
00279 
00280    if (!pipeline_verts) 
00281       return FALSE;
00282 
00283    /* Fetch into our vertex buffer
00284     */
00285    draw_pt_fetch_run_linear( fpme->fetch,
00286                              start,
00287                              count,
00288                              (char *)pipeline_verts );
00289 
00290    /* Run the shader, note that this overwrites the data[] parts of
00291     * the pipeline verts.  If there is no shader, ie a bypass shader,
00292     * then the inputs == outputs, and are already in the correct
00293     * place.
00294     */
00295    if (opt & PT_SHADE)
00296    {
00297       shader->run_linear(shader,
00298                          (const float (*)[4])pipeline_verts->data,
00299                          (      float (*)[4])pipeline_verts->data,
00300                          (const float (*)[4])draw->pt.user.constants,
00301                          count,
00302                          fpme->vertex_size,
00303                          fpme->vertex_size);
00304    }
00305 
00306    if (draw_pt_post_vs_run( fpme->post_vs,
00307                             pipeline_verts,
00308                             count,
00309                             fpme->vertex_size ))
00310    {
00311       opt |= PT_PIPELINE;
00312    }
00313 
00314    /* Do we need to run the pipeline?
00315     */
00316    if (opt & PT_PIPELINE) {
00317       draw_pipeline_run( fpme->draw,
00318                          fpme->prim,
00319                          pipeline_verts,
00320                          count,
00321                          fpme->vertex_size,
00322                          draw_elts,
00323                          draw_count );
00324    }
00325    else {
00326       draw_pt_emit( fpme->emit,
00327                     (const float (*)[4])pipeline_verts->data,
00328                     count,
00329                     fpme->vertex_size,
00330                     draw_elts,
00331                     draw_count );
00332    }
00333 
00334    FREE(pipeline_verts);
00335    return TRUE;
00336 }
00337 
00338 
00339 
00340 static void fetch_pipeline_finish( struct draw_pt_middle_end *middle )
00341 {
00342    /* nothing to do */
00343 }
00344 
00345 static void fetch_pipeline_destroy( struct draw_pt_middle_end *middle )
00346 {
00347    struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
00348 
00349    if (fpme->fetch)
00350       draw_pt_fetch_destroy( fpme->fetch );
00351 
00352    if (fpme->emit)
00353       draw_pt_emit_destroy( fpme->emit );
00354 
00355    if (fpme->post_vs)
00356       draw_pt_post_vs_destroy( fpme->post_vs );
00357 
00358    FREE(middle);
00359 }
00360 
00361 
00362 struct draw_pt_middle_end *draw_pt_fetch_pipeline_or_emit( struct draw_context *draw )
00363 {
00364    struct fetch_pipeline_middle_end *fpme = CALLOC_STRUCT( fetch_pipeline_middle_end );
00365    if (!fpme)
00366       goto fail;
00367 
00368    fpme->base.prepare        = fetch_pipeline_prepare;
00369    fpme->base.run            = fetch_pipeline_run;
00370    fpme->base.run_linear     = fetch_pipeline_linear_run;
00371    fpme->base.run_linear_elts = fetch_pipeline_linear_run_elts;
00372    fpme->base.finish         = fetch_pipeline_finish;
00373    fpme->base.destroy        = fetch_pipeline_destroy;
00374 
00375    fpme->draw = draw;
00376 
00377    fpme->fetch = draw_pt_fetch_create( draw );
00378    if (!fpme->fetch)
00379       goto fail;
00380 
00381    fpme->post_vs = draw_pt_post_vs_create( draw );
00382    if (!fpme->post_vs)
00383       goto fail;
00384 
00385    fpme->emit = draw_pt_emit_create( draw );
00386    if (!fpme->emit) 
00387       goto fail;
00388 
00389    return &fpme->base;
00390 
00391  fail:
00392    if (fpme)
00393       fetch_pipeline_destroy( &fpme->base );
00394 
00395    return NULL;
00396 }

Generated on Tue Sep 29 06:25:14 2009 for Gallium3D by  doxygen 1.5.4