ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

vbo_split_copy.c
Go to the documentation of this file.
00001 
00002 /*
00003  * Mesa 3-D graphics library
00004  * Version:  6.5
00005  *
00006  * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
00007  *
00008  * Permission is hereby granted, free of charge, to any person obtaining a
00009  * copy of this software and associated documentation files (the "Software"),
00010  * to deal in the Software without restriction, including without limitation
00011  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
00012  * and/or sell copies of the Software, and to permit persons to whom the
00013  * Software is furnished to do so, subject to the following conditions:
00014  *
00015  * The above copyright notice and this permission notice shall be included
00016  * in all copies or substantial portions 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 MERCHANTABILITY,
00020  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
00021  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00022  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00023  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00024  *
00025  * Authors:
00026  *    Keith Whitwell <keith@tungstengraphics.com>
00027  */
00028 
00029 /* Split indexed primitives with per-vertex copying.
00030  */
00031 
00032 #include "main/glheader.h"
00033 #include "main/imports.h"
00034 #include "main/macros.h"
00035 #include "main/enums.h"
00036 #include "main/mtypes.h"
00037 
00038 #include "vbo_split.h"
00039 #include "vbo.h"
00040 
00041 
00042 #define ELT_TABLE_SIZE 16
00043 
00044 /* Used for vertex-level splitting of indexed buffers.  Note that
00045  * non-indexed primitives may be converted to indexed in some cases
00046  * (eg loops, fans) in order to use this splitting path.
00047  */
00048 struct copy_context {
00049 
00050    GLcontext *ctx;
00051    const struct gl_client_array **array;
00052    const struct _mesa_prim *prim;
00053    GLuint nr_prims;
00054    const struct _mesa_index_buffer *ib;
00055    vbo_draw_func draw;
00056 
00057    const struct split_limits *limits;
00058 
00059    struct {
00060       GLuint attr;
00061       GLuint size;
00062       const struct gl_client_array *array;
00063       const GLubyte *src_ptr;
00064 
00065       struct gl_client_array dstarray;
00066 
00067    } varying[VERT_ATTRIB_MAX];
00068    GLuint nr_varying;
00069 
00070    const struct gl_client_array *dstarray_ptr[VERT_ATTRIB_MAX];
00071    struct _mesa_index_buffer dstib;
00072 
00073    GLuint *translated_elt_buf;
00074    const GLuint *srcelt;
00075 
00076    /* A baby hash table to avoid re-emitting (some) duplicate
00077     * vertices when splitting indexed primitives.
00078     */
00079    struct { 
00080       GLuint in;
00081       GLuint out;
00082    } vert_cache[ELT_TABLE_SIZE];
00083       
00084 
00085    GLuint vertex_size;
00086    GLubyte *dstbuf;
00087    GLubyte *dstptr;     /* dstptr == dstbuf + dstelt_max * vertsize */
00088    GLuint dstbuf_size;  /* in vertices */
00089    GLuint dstbuf_nr;        /* count of emitted vertices, also the
00090                  * largest value in dstelt.  Our
00091                  * MaxIndex.
00092                  */
00093 
00094    GLuint *dstelt;
00095    GLuint dstelt_nr;
00096    GLuint dstelt_size;
00097 
00098 #define MAX_PRIM 32
00099    struct _mesa_prim dstprim[MAX_PRIM];
00100    GLuint dstprim_nr;
00101 
00102 };
00103 
00104 
00105 static GLuint type_size( GLenum type )
00106 {
00107    switch(type) {
00108    case GL_BYTE: return sizeof(GLbyte);
00109    case GL_UNSIGNED_BYTE: return sizeof(GLubyte);
00110    case GL_SHORT: return sizeof(GLshort);
00111    case GL_UNSIGNED_SHORT: return sizeof(GLushort);
00112    case GL_INT: return sizeof(GLint);
00113    case GL_UNSIGNED_INT: return sizeof(GLuint);
00114    case GL_FLOAT: return sizeof(GLfloat);
00115    case GL_DOUBLE: return sizeof(GLdouble);
00116    default: return 0;
00117    }
00118 }
00119 
00120 static GLuint attr_size( const struct gl_client_array *array )
00121 {
00122    return array->Size * type_size(array->Type);
00123 }
00124 
00125 
00126 /* Starts returning true slightly before the buffer fills, to ensure
00127  * that there is sufficient room for any remaining vertices to finish
00128  * off the prim:
00129  */
00130 static GLboolean check_flush( struct copy_context *copy )
00131 {
00132    GLenum mode = copy->dstprim[copy->dstprim_nr].mode; 
00133 
00134    if (GL_TRIANGLE_STRIP == mode &&
00135        copy->dstelt_nr & 1) { /* see bug9962 */
00136        return GL_FALSE;
00137    }
00138 
00139    if (copy->dstbuf_nr + 4 > copy->dstbuf_size)
00140       return GL_TRUE;
00141 
00142    if (copy->dstelt_nr + 4 > copy->dstelt_size)
00143       return GL_TRUE;
00144 
00145    return GL_FALSE;
00146 }
00147 
00148 static void flush( struct copy_context *copy )
00149 {
00150    GLuint i;
00151 
00152    /* Set some counters: 
00153     */
00154    copy->dstib.count = copy->dstelt_nr;
00155 
00156    copy->draw( copy->ctx,
00157            copy->dstarray_ptr,
00158            copy->dstprim,
00159            copy->dstprim_nr,
00160            &copy->dstib,
00161            0,
00162            copy->dstbuf_nr );
00163 
00164    /* Reset all pointers: 
00165     */
00166    copy->dstprim_nr = 0;
00167    copy->dstelt_nr = 0;
00168    copy->dstbuf_nr = 0;
00169    copy->dstptr = copy->dstbuf;
00170 
00171    /* Clear the vertex cache:
00172     */
00173    for (i = 0; i < ELT_TABLE_SIZE; i++)
00174       copy->vert_cache[i].in = ~0;
00175 }
00176 
00177 
00178 
00179 static void begin( struct copy_context *copy, GLenum mode, GLboolean begin_flag )
00180 {
00181    struct _mesa_prim *prim = &copy->dstprim[copy->dstprim_nr];
00182 
00183 /*    _mesa_printf("begin %s (%d)\n", _mesa_lookup_enum_by_nr(mode), begin_flag); */
00184         
00185    prim->mode = mode;
00186    prim->begin = begin_flag;
00187 }
00188 
00189 
00190 /* Use a hashtable to attempt to identify recently-emitted vertices
00191  * and avoid re-emitting them.
00192  */
00193 static GLuint elt(struct copy_context *copy, GLuint elt_idx)
00194 {
00195    GLuint elt = copy->srcelt[elt_idx];
00196    GLuint slot = elt & (ELT_TABLE_SIZE-1);
00197 
00198 /*    _mesa_printf("elt %d\n", elt); */
00199 
00200    /* Look up the incoming element in the vertex cache.  Re-emit if
00201     * necessary.   
00202     */
00203    if (copy->vert_cache[slot].in != elt) {
00204       GLubyte *csr = copy->dstptr;
00205       GLuint i;
00206 
00207 /*       _mesa_printf("  --> emit to dstelt %d\n", copy->dstbuf_nr); */
00208 
00209       for (i = 0; i < copy->nr_varying; i++) {
00210      const struct gl_client_array *srcarray = copy->varying[i].array;
00211      const GLubyte *srcptr = copy->varying[i].src_ptr + elt * srcarray->StrideB;
00212 
00213      memcpy(csr, srcptr, copy->varying[i].size);
00214      csr += copy->varying[i].size;
00215 
00216      if (0) 
00217      {
00218         const GLuint *f = (const GLuint *)srcptr;
00219         GLuint j;
00220         _mesa_printf("  varying %d: ", i);
00221         for(j = 0; j < copy->varying[i].size / 4; j++)
00222            _mesa_printf("%x ", f[j]);
00223         _mesa_printf("\n");
00224      }
00225            
00226       }
00227 
00228       copy->vert_cache[slot].in = elt;
00229       copy->vert_cache[slot].out = copy->dstbuf_nr++;
00230       copy->dstptr += copy->vertex_size;
00231 
00232       assert(csr == copy->dstptr);
00233       assert(copy->dstptr == (copy->dstbuf + 
00234                     copy->dstbuf_nr * 
00235                     copy->vertex_size));
00236    }
00237 /*    else */
00238 /*       _mesa_printf("  --> reuse vertex\n"); */
00239    
00240 /*    _mesa_printf("  --> emit %d\n", copy->vert_cache[slot].out); */
00241    copy->dstelt[copy->dstelt_nr++] = copy->vert_cache[slot].out;
00242    return check_flush(copy);
00243 }
00244 
00245 static void end( struct copy_context *copy, GLboolean end_flag )
00246 {
00247    struct _mesa_prim *prim = &copy->dstprim[copy->dstprim_nr];
00248 
00249 /*    _mesa_printf("end (%d)\n", end_flag); */
00250 
00251    prim->end = end_flag;
00252    prim->count = copy->dstelt_nr - prim->start;
00253 
00254    if (++copy->dstprim_nr == MAX_PRIM ||
00255        check_flush(copy)) 
00256       flush(copy);
00257 }
00258 
00259 
00260 
00261 static void replay_elts( struct copy_context *copy )
00262 {
00263    GLuint i, j, k;
00264    GLboolean split;
00265 
00266    for (i = 0; i < copy->nr_prims; i++) {
00267       const struct _mesa_prim *prim = &copy->prim[i];
00268       const GLuint start = prim->start;
00269       GLuint first, incr;
00270 
00271       switch (prim->mode) {
00272      
00273       case GL_LINE_LOOP:
00274      /* Convert to linestrip and emit the final vertex explicitly,
00275       * but only in the resultant strip that requires it.
00276       */
00277      j = 0;
00278      while (j != prim->count) {
00279         begin(copy, GL_LINE_STRIP, prim->begin && j == 0);
00280 
00281         for (split = GL_FALSE; j != prim->count && !split; j++)
00282            split = elt(copy, start + j);
00283 
00284         if (j == prim->count) {
00285            /* Done, emit final line.  Split doesn't matter as
00286         * it is always raised a bit early so we can emit
00287         * the last verts if necessary!
00288         */
00289            if (prim->end) 
00290           (void)elt(copy, start + 0);
00291 
00292            end(copy, prim->end);
00293         }
00294         else {
00295            /* Wrap
00296         */
00297            assert(split);
00298            end(copy, 0);
00299            j--;
00300         }
00301      }
00302      break;
00303 
00304       case GL_TRIANGLE_FAN:
00305       case GL_POLYGON:
00306      j = 2;
00307      while (j != prim->count) {
00308         begin(copy, prim->mode, prim->begin && j == 0);
00309 
00310         split = elt(copy, start+0); 
00311         assert(!split);
00312 
00313         split = elt(copy, start+j-1); 
00314         assert(!split);
00315 
00316         for (; j != prim->count && !split; j++)
00317            split = elt(copy, start+j);
00318 
00319         end(copy, prim->end && j == prim->count);
00320 
00321         if (j != prim->count) {
00322            /* Wrapped the primitive, need to repeat some vertices:
00323         */
00324            j -= 1;
00325         }
00326      }
00327      break;
00328 
00329       default:
00330      (void)split_prim_inplace(prim->mode, &first, &incr);
00331      
00332      j = 0;
00333      while (j != prim->count) {
00334 
00335         begin(copy, prim->mode, prim->begin && j == 0);
00336 
00337         split = 0;
00338         for (k = 0; k < first; k++, j++)
00339            split |= elt(copy, start+j);
00340 
00341         assert(!split);
00342 
00343         for (; j != prim->count && !split; )
00344            for (k = 0; k < incr; k++, j++)
00345           split |= elt(copy, start+j);
00346 
00347         end(copy, prim->end && j == prim->count);
00348 
00349         if (j != prim->count) {
00350            /* Wrapped the primitive, need to repeat some vertices:
00351         */
00352            assert(j > first - incr);
00353            j -= (first - incr);
00354         }
00355      }
00356      break;
00357       }
00358    }
00359 
00360    if (copy->dstprim_nr)
00361       flush(copy);
00362 }
00363 
00364 
00365 static void replay_init( struct copy_context *copy )
00366 {
00367    GLcontext *ctx = copy->ctx;
00368    GLuint i;
00369    GLuint offset;
00370    const GLvoid *srcptr;
00371 
00372    /* Make a list of varying attributes and their vbo's.  Also
00373     * calculate vertex size.
00374     */
00375    copy->vertex_size = 0;
00376    for (i = 0; i < VERT_ATTRIB_MAX; i++) {
00377       struct gl_buffer_object *vbo = copy->array[i]->BufferObj;
00378 
00379       if (copy->array[i]->StrideB == 0) {
00380      copy->dstarray_ptr[i] = copy->array[i];
00381       }
00382       else {
00383      GLuint j = copy->nr_varying++;
00384      
00385      copy->varying[j].attr = i;
00386      copy->varying[j].array = copy->array[i];
00387      copy->varying[j].size = attr_size(copy->array[i]);
00388      copy->vertex_size += attr_size(copy->array[i]);
00389       
00390      if (vbo->Name && !vbo->Pointer) 
00391         ctx->Driver.MapBuffer(ctx,
00392                   GL_ARRAY_BUFFER_ARB, 
00393                   GL_WRITE_ONLY, /* XXX */
00394                   vbo);
00395 
00396      copy->varying[j].src_ptr = ADD_POINTERS(vbo->Pointer,
00397                          copy->array[i]->Ptr);
00398 
00399      copy->dstarray_ptr[i] = &copy->varying[j].dstarray;
00400       }
00401    }
00402 
00403    /* There must always be an index buffer.  Currently require the
00404     * caller convert non-indexed prims to indexed.  Could alternately
00405     * do it internally.
00406     */
00407    if (copy->ib->obj->Name && !copy->ib->obj->Pointer) 
00408       ctx->Driver.MapBuffer(ctx, 
00409                 GL_ARRAY_BUFFER_ARB, /* XXX */
00410                 GL_WRITE_ONLY, /* XXX */
00411                 copy->ib->obj);
00412 
00413    srcptr = (const GLubyte *)ADD_POINTERS(copy->ib->obj->Pointer, copy->ib->ptr);
00414 
00415    switch (copy->ib->type) {
00416    case GL_UNSIGNED_BYTE:
00417       copy->translated_elt_buf = _mesa_malloc(sizeof(GLuint) * copy->ib->count);
00418       copy->srcelt = copy->translated_elt_buf;
00419 
00420       for (i = 0; i < copy->ib->count; i++)
00421      copy->translated_elt_buf[i] = ((const GLubyte *)srcptr)[i];
00422       break;
00423 
00424    case GL_UNSIGNED_SHORT:
00425       copy->translated_elt_buf = _mesa_malloc(sizeof(GLuint) * copy->ib->count);
00426       copy->srcelt = copy->translated_elt_buf;
00427 
00428       for (i = 0; i < copy->ib->count; i++)
00429      copy->translated_elt_buf[i] = ((const GLushort *)srcptr)[i];
00430       break;
00431 
00432    case GL_UNSIGNED_INT:
00433       copy->translated_elt_buf = NULL;
00434       copy->srcelt = (const GLuint *)srcptr;
00435       break;
00436    }
00437    
00438 
00439    /* Figure out the maximum allowed vertex buffer size:
00440     */
00441    if (copy->vertex_size * copy->limits->max_verts <= copy->limits->max_vb_size) {
00442       copy->dstbuf_size = copy->limits->max_verts;
00443    }
00444    else {
00445       copy->dstbuf_size = copy->limits->max_vb_size / copy->vertex_size;
00446    }
00447 
00448    /* Allocate an output vertex buffer:
00449     *
00450     * XXX:  This should be a VBO!
00451     */
00452    copy->dstbuf = _mesa_malloc(copy->dstbuf_size * 
00453                    copy->vertex_size);   
00454    copy->dstptr = copy->dstbuf;
00455 
00456    /* Setup new vertex arrays to point into the output buffer: 
00457     */
00458    for (offset = 0, i = 0; i < copy->nr_varying; i++) {
00459       const struct gl_client_array *src = copy->varying[i].array;
00460       struct gl_client_array *dst = &copy->varying[i].dstarray;
00461 
00462       dst->Size = src->Size;
00463       dst->Type = src->Type;
00464       dst->Stride = copy->vertex_size;
00465       dst->StrideB = copy->vertex_size;
00466       dst->Ptr = copy->dstbuf + offset;
00467       dst->Enabled = GL_TRUE;
00468       dst->Normalized = src->Normalized; 
00469       dst->BufferObj = ctx->Array.NullBufferObj;
00470       dst->_MaxElement = copy->dstbuf_size; /* may be less! */
00471 
00472       offset += copy->varying[i].size;
00473    }
00474 
00475    /* Allocate an output element list:
00476     */
00477    copy->dstelt_size = MIN2(65536,
00478                 copy->ib->count * 2 + 3);
00479    copy->dstelt_size = MIN2(copy->dstelt_size,
00480                 copy->limits->max_indices);
00481    copy->dstelt = _mesa_malloc(sizeof(GLuint) * copy->dstelt_size);
00482    copy->dstelt_nr = 0;
00483 
00484    /* Setup the new index buffer to point to the allocated element
00485     * list:
00486     */
00487    copy->dstib.count = 0;   /* duplicates dstelt_nr */
00488    copy->dstib.type = GL_UNSIGNED_INT;
00489    copy->dstib.obj = ctx->Array.NullBufferObj;
00490    copy->dstib.ptr = copy->dstelt;
00491 }
00492 
00493 
00494 static void replay_finish( struct copy_context *copy )
00495 {
00496    GLcontext *ctx = copy->ctx;
00497    GLuint i;
00498 
00499    /* Free our vertex and index buffers: 
00500     */
00501    _mesa_free(copy->translated_elt_buf);
00502    _mesa_free(copy->dstbuf);
00503    _mesa_free(copy->dstelt);
00504    
00505    /* Unmap VBO's 
00506     */
00507    for (i = 0; i < copy->nr_varying; i++) {
00508       struct gl_buffer_object *vbo = copy->varying[i].array->BufferObj;
00509 
00510       if (vbo->Name && vbo->Pointer) 
00511      ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER_ARB, vbo);
00512    }
00513 
00514    /* Unmap index buffer:
00515     */
00516    if (copy->ib->obj->Name && copy->ib->obj->Pointer) {
00517       ctx->Driver.UnmapBuffer(ctx, 
00518                   GL_ARRAY_BUFFER_ARB, /* XXX */
00519                   copy->ib->obj);
00520    }
00521 }
00522 
00523 void vbo_split_copy( GLcontext *ctx,
00524              const struct gl_client_array *arrays[],
00525              const struct _mesa_prim *prim,
00526              GLuint nr_prims,
00527              const struct _mesa_index_buffer *ib,
00528              vbo_draw_func draw,
00529              const struct split_limits *limits )
00530 {
00531    struct copy_context copy;
00532    GLuint i;
00533 
00534    memset(&copy, 0, sizeof(copy));
00535 
00536    /* Require indexed primitives:
00537     */
00538    assert(ib);
00539    
00540    copy.ctx = ctx;
00541    copy.array = arrays;
00542    copy.prim = prim;
00543    copy.nr_prims = nr_prims;
00544    copy.ib = ib;
00545    copy.draw = draw;
00546    copy.limits = limits;
00547 
00548 
00549    /* Clear the vertex cache:
00550     */
00551    for (i = 0; i < ELT_TABLE_SIZE; i++)
00552       copy.vert_cache[i].in = ~0;
00553 
00554 
00555    replay_init(&copy);
00556    replay_elts(&copy);
00557    replay_finish(&copy);
00558 }

Generated on Sun May 27 2012 04:20:48 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.