diff options
author | Julian Eisel <eiseljulian@gmail.com> | 2015-08-01 22:06:58 +0300 |
---|---|---|
committer | Julian Eisel <eiseljulian@gmail.com> | 2015-08-01 22:06:58 +0300 |
commit | 4ade467fc6adfc13ce9e21d7e50b366fce70ea5f (patch) | |
tree | 968418721b08baacd47bab95877bc08812f3046a /source/blender/gpu/intern/gpu_buffers.c | |
parent | 7759782ee7c4e654641c9f7abb51631c86e3f29c (diff) | |
parent | a3c5de3e3ca82d8ad5a28029f3ee9207929318a1 (diff) |
Merge branch 'master' into UI-graphical-redesign
Conflicts:
source/blender/blenkernel/BKE_blender.h
source/blender/blenloader/intern/versioning_270.c
source/blender/editors/interface/resources.c
source/blender/makesdna/DNA_userdef_types.h
Diffstat (limited to 'source/blender/gpu/intern/gpu_buffers.c')
-rw-r--r-- | source/blender/gpu/intern/gpu_buffers.c | 1585 |
1 files changed, 458 insertions, 1127 deletions
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index 62843f0905f..2e1b866a160 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -51,6 +51,7 @@ #include "BKE_ccg.h" #include "BKE_DerivedMesh.h" #include "BKE_paint.h" +#include "BKE_mesh.h" #include "BKE_pbvh.h" #include "DNA_userdef_types.h" @@ -69,6 +70,35 @@ typedef enum { GPU_BUFFER_ELEMENT_STATE = (1 << 5), } GPUBufferState; +typedef struct { + GLenum gl_buffer_type; + int num_components; /* number of data components for one vertex */ +} GPUBufferTypeSettings; + + +static size_t gpu_buffer_size_from_type(DerivedMesh *dm, GPUBufferType type); + +const GPUBufferTypeSettings gpu_buffer_type_settings[] = { + /* vertex */ + {GL_ARRAY_BUFFER_ARB, 3}, + /* normal */ + {GL_ARRAY_BUFFER_ARB, 4}, /* we copy 3 shorts per normal but we add a fourth for alignment */ + /* mcol */ + {GL_ARRAY_BUFFER_ARB, 3}, + /* uv */ + {GL_ARRAY_BUFFER_ARB, 2}, + /* uv for texpaint */ + {GL_ARRAY_BUFFER_ARB, 4}, + /* edge */ + {GL_ELEMENT_ARRAY_BUFFER_ARB, 2}, + /* uv edge */ + {GL_ELEMENT_ARRAY_BUFFER_ARB, 4}, + /* triangles, 1 point since we are allocating from tottriangle points, which account for all points */ + {GL_ELEMENT_ARRAY_BUFFER_ARB, 1}, + /* fast triangles */ + {GL_ELEMENT_ARRAY_BUFFER_ARB, 1}, +}; + #define MAX_GPU_ATTRIB_DATA 32 #define BUFFER_OFFSET(n) ((GLubyte *)NULL + (n)) @@ -79,6 +109,43 @@ static GPUAttrib attribData[MAX_GPU_ATTRIB_DATA] = { { -1, 0, 0 } }; static ThreadMutex buffer_mutex = BLI_MUTEX_INITIALIZER; +/* multires global buffer, can be used for many grids having the same grid size */ +static GPUBuffer *mres_glob_buffer = NULL; +static int mres_prev_gridsize = -1; +static GLenum mres_prev_index_type = 0; +static unsigned mres_prev_totquad = 0; + +void GPU_buffer_material_finalize(GPUDrawObject *gdo, GPUBufferMaterial *matinfo, int totmat) +{ + int i, curmat, curelement; + + /* count the number of materials used by this DerivedMesh */ + for (i = 0; i < totmat; i++) { + if (matinfo[i].totelements > 0) + gdo->totmaterial++; + } + + /* allocate an array of materials used by this DerivedMesh */ + gdo->materials = MEM_mallocN(sizeof(GPUBufferMaterial) * gdo->totmaterial, + "GPUDrawObject.materials"); + + /* initialize the materials array */ + for (i = 0, curmat = 0, curelement = 0; i < totmat; i++) { + if (matinfo[i].totelements > 0) { + gdo->materials[curmat] = matinfo[i]; + gdo->materials[curmat].start = curelement; + gdo->materials[curmat].mat_nr = i; + gdo->materials[curmat].polys = MEM_mallocN(sizeof(int) * matinfo[i].totpolys, "GPUBufferMaterial.polys"); + + curelement += matinfo[i].totelements; + curmat++; + } + } + + MEM_freeN(matinfo); +} + + /* stores recently-deleted buffers so that new buffers won't have to * be recreated as often * @@ -93,15 +160,11 @@ static ThreadMutex buffer_mutex = BLI_MUTEX_INITIALIZER; typedef struct GPUBufferPool { /* number of allocated buffers stored */ int totbuf; - int totpbvhbufids; /* actual allocated length of the arrays */ int maxsize; - int maxpbvhsize; GPUBuffer **buffers; - GLuint *pbvhbufids; } GPUBufferPool; #define MAX_FREE_GPU_BUFFERS 8 -#define MAX_FREE_GPU_BUFF_IDS 100 /* create a new GPUBufferPool */ static GPUBufferPool *gpu_buffer_pool_new(void) @@ -111,11 +174,8 @@ static GPUBufferPool *gpu_buffer_pool_new(void) pool = MEM_callocN(sizeof(GPUBufferPool), "GPUBuffer_Pool"); pool->maxsize = MAX_FREE_GPU_BUFFERS; - pool->maxpbvhsize = MAX_FREE_GPU_BUFF_IDS; pool->buffers = MEM_mallocN(sizeof(*pool->buffers) * pool->maxsize, "GPUBufferPool.buffers"); - pool->pbvhbufids = MEM_mallocN(sizeof(*pool->pbvhbufids) * pool->maxpbvhsize, - "GPUBufferPool.pbvhbuffers"); return pool; } @@ -173,7 +233,6 @@ static void gpu_buffer_pool_free(GPUBufferPool *pool) gpu_buffer_pool_delete_last(pool); MEM_freeN(pool->buffers); - MEM_freeN(pool->pbvhbufids); MEM_freeN(pool); } @@ -187,11 +246,6 @@ static void gpu_buffer_pool_free_unused(GPUBufferPool *pool) while (pool->totbuf) gpu_buffer_pool_delete_last(pool); - if (pool->totpbvhbufids > 0) { - glDeleteBuffersARB(pool->totpbvhbufids, pool->pbvhbufids); - pool->totpbvhbufids = 0; - } - BLI_mutex_unlock(&buffer_mutex); } @@ -221,11 +275,12 @@ void GPU_global_buffer_pool_free_unused(void) * * Thread-unsafe version for internal usage only. */ -static GPUBuffer *gpu_buffer_alloc_intern(int size, bool use_VBO) +static GPUBuffer *gpu_buffer_alloc_intern(size_t size, bool use_VBO) { GPUBufferPool *pool; GPUBuffer *buf; - int i, bufsize, bestfit = -1; + int i, bestfit = -1; + size_t bufsize; /* bad case, leads to leak of buf since buf->pointer will allocate * NULL, leading to return without cleanup. In any case better detect early @@ -290,8 +345,11 @@ static GPUBuffer *gpu_buffer_alloc_intern(int size, bool use_VBO) glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); } else { + static int time = 0; + buf->pointer = MEM_mallocN(size, "GPUBuffer.pointer"); - + + time++; /* purpose of this seems to be dealing with * out-of-memory errors? looks a bit iffy to me * though, at least on Linux I expect malloc() would @@ -300,15 +358,17 @@ static GPUBuffer *gpu_buffer_alloc_intern(int size, bool use_VBO) gpu_buffer_pool_delete_last(pool); buf->pointer = MEM_mallocN(size, "GPUBuffer.pointer"); } - if (!buf->pointer) + if (!buf->pointer) { + MEM_freeN(buf); return NULL; + } } return buf; } /* Same as above, but safe for threading. */ -GPUBuffer *GPU_buffer_alloc(int size, bool force_vertex_arrays) +GPUBuffer *GPU_buffer_alloc(size_t size, bool force_vertex_arrays) { GPUBuffer *buffer; bool use_VBOs = (GLEW_ARB_vertex_buffer_object) && !(U.gameflags & USER_DISABLE_VBO) && !force_vertex_arrays; @@ -383,197 +443,51 @@ void GPU_buffer_free(GPUBuffer *buffer) BLI_mutex_unlock(&buffer_mutex); } -#if 0 /* currently unused */ -# define USE_GPU_POINT_LINK -#endif - -typedef struct GPUVertPointLink { -#ifdef USE_GPU_POINT_LINK - struct GPUVertPointLink *next; -#endif - /* -1 means uninitialized */ - int point_index; -} GPUVertPointLink; - - -/* add a new point to the list of points related to a particular - * vertex */ -#ifdef USE_GPU_POINT_LINK - -static void gpu_drawobject_add_vert_point(GPUDrawObject *gdo, int vert_index, int point_index) -{ - GPUVertPointLink *lnk; - - lnk = &gdo->vert_points[vert_index]; - - /* if first link is in use, add a new link at the end */ - if (lnk->point_index != -1) { - /* get last link */ - for (; lnk->next; lnk = lnk->next) ; - - /* add a new link from the pool */ - lnk = lnk->next = &gdo->vert_points_mem[gdo->vert_points_usage]; - gdo->vert_points_usage++; - } - - lnk->point_index = point_index; -} - -#else - -static void gpu_drawobject_add_vert_point(GPUDrawObject *gdo, int vert_index, int point_index) -{ - GPUVertPointLink *lnk; - lnk = &gdo->vert_points[vert_index]; - if (lnk->point_index == -1) { - lnk->point_index = point_index; - } -} - -#endif /* USE_GPU_POINT_LINK */ - -/* update the vert_points and triangle_to_mface fields with a new - * triangle */ -static void gpu_drawobject_add_triangle(GPUDrawObject *gdo, - int base_point_index, - int face_index, - int v1, int v2, int v3) -{ - int i, v[3] = {v1, v2, v3}; - for (i = 0; i < 3; i++) - gpu_drawobject_add_vert_point(gdo, v[i], base_point_index + i); - gdo->triangle_to_mface[base_point_index / 3] = face_index; -} - -/* for each vertex, build a list of points related to it; these lists - * are stored in an array sized to the number of vertices */ -static void gpu_drawobject_init_vert_points(GPUDrawObject *gdo, MFace *f, int totface, int totmat) +void GPU_buffer_multires_free(bool force) { - GPUBufferMaterial *mat; - int i, *mat_orig_to_new; - - mat_orig_to_new = MEM_callocN(sizeof(*mat_orig_to_new) * totmat, - "GPUDrawObject.mat_orig_to_new"); - /* allocate the array and space for links */ - gdo->vert_points = MEM_mallocN(sizeof(GPUVertPointLink) * gdo->totvert, - "GPUDrawObject.vert_points"); -#ifdef USE_GPU_POINT_LINK - gdo->vert_points_mem = MEM_callocN(sizeof(GPUVertPointLink) * gdo->tot_triangle_point, - "GPUDrawObject.vert_points_mem"); - gdo->vert_points_usage = 0; -#endif - - /* build a map from the original material indices to the new - * GPUBufferMaterial indices */ - for (i = 0; i < gdo->totmaterial; i++) - mat_orig_to_new[gdo->materials[i].mat_nr] = i; - - /* -1 indicates the link is not yet used */ - for (i = 0; i < gdo->totvert; i++) { -#ifdef USE_GPU_POINT_LINK - gdo->vert_points[i].link = NULL; -#endif - gdo->vert_points[i].point_index = -1; + if (!mres_glob_buffer) { + /* Early output, no need to lock in this case, */ + return; } - for (i = 0; i < totface; i++, f++) { - mat = &gdo->materials[mat_orig_to_new[f->mat_nr]]; - - /* add triangle */ - gpu_drawobject_add_triangle(gdo, mat->start + mat->totpoint, - i, f->v1, f->v2, f->v3); - mat->totpoint += 3; - - /* add second triangle for quads */ - if (f->v4) { - gpu_drawobject_add_triangle(gdo, mat->start + mat->totpoint, - i, f->v3, f->v4, f->v1); - mat->totpoint += 3; + if (force && BLI_thread_is_main()) { + if (mres_glob_buffer) { + if (mres_glob_buffer->id) + glDeleteBuffersARB(1, &mres_glob_buffer->id); + else if (mres_glob_buffer->pointer) + MEM_freeN(mres_glob_buffer->pointer); + MEM_freeN(mres_glob_buffer); } } - - /* map any unused vertices to loose points */ - for (i = 0; i < gdo->totvert; i++) { - if (gdo->vert_points[i].point_index == -1) { - gdo->vert_points[i].point_index = gdo->tot_triangle_point + gdo->tot_loose_point; - gdo->tot_loose_point++; - } + else { + BLI_mutex_lock(&buffer_mutex); + gpu_buffer_free_intern(mres_glob_buffer); + BLI_mutex_unlock(&buffer_mutex); } - MEM_freeN(mat_orig_to_new); + mres_glob_buffer = NULL; + mres_prev_gridsize = -1; + mres_prev_index_type = 0; + mres_prev_totquad = 0; } -/* see GPUDrawObject's structure definition for a description of the - * data being initialized here */ -GPUDrawObject *GPU_drawobject_new(DerivedMesh *dm) -{ - GPUDrawObject *gdo; - MFace *mface; - int totmat = dm->totmat; - int *points_per_mat; - int i, curmat, curpoint, totface; - - /* object contains at least one material (default included) so zero means uninitialized dm */ - BLI_assert(totmat != 0); - - mface = dm->getTessFaceArray(dm); - totface = dm->getNumTessFaces(dm); - - /* get the number of points used by each material, treating - * each quad as two triangles */ - points_per_mat = MEM_callocN(sizeof(*points_per_mat) * totmat, "GPU_drawobject_new.mat_orig_to_new"); - for (i = 0; i < totface; i++) - points_per_mat[mface[i].mat_nr] += mface[i].v4 ? 6 : 3; - - /* create the GPUDrawObject */ - gdo = MEM_callocN(sizeof(GPUDrawObject), "GPUDrawObject"); - gdo->totvert = dm->getNumVerts(dm); - gdo->totedge = dm->getNumEdges(dm); - - /* count the number of materials used by this DerivedMesh */ - for (i = 0; i < totmat; i++) { - if (points_per_mat[i] > 0) - gdo->totmaterial++; - } - - /* allocate an array of materials used by this DerivedMesh */ - gdo->materials = MEM_mallocN(sizeof(GPUBufferMaterial) * gdo->totmaterial, - "GPUDrawObject.materials"); - - /* initialize the materials array */ - for (i = 0, curmat = 0, curpoint = 0; i < totmat; i++) { - if (points_per_mat[i] > 0) { - gdo->materials[curmat].start = curpoint; - gdo->materials[curmat].totpoint = 0; - gdo->materials[curmat].mat_nr = i; - - curpoint += points_per_mat[i]; - curmat++; - } - } - - /* store total number of points used for triangles */ - gdo->tot_triangle_point = curpoint; - - gdo->triangle_to_mface = MEM_mallocN(sizeof(int) * (gdo->tot_triangle_point / 3), - "GPUDrawObject.triangle_to_mface"); - - gpu_drawobject_init_vert_points(gdo, mface, totface, totmat); - MEM_freeN(points_per_mat); - - return gdo; -} void GPU_drawobject_free(DerivedMesh *dm) { GPUDrawObject *gdo; + int i; if (!dm || !(gdo = dm->drawObject)) return; + for (i = 0; i < gdo->totmaterial; i++) { + if (gdo->materials[i].polys) + MEM_freeN(gdo->materials[i].polys); + } + MEM_freeN(gdo->materials); - MEM_freeN(gdo->triangle_to_mface); - MEM_freeN(gdo->vert_points); + if (gdo->vert_points) + MEM_freeN(gdo->vert_points); #ifdef USE_GPU_POINT_LINK MEM_freeN(gdo->vert_points_mem); #endif @@ -584,40 +498,39 @@ void GPU_drawobject_free(DerivedMesh *dm) GPU_buffer_free(gdo->colors); GPU_buffer_free(gdo->edges); GPU_buffer_free(gdo->uvedges); + GPU_buffer_free(gdo->triangles); MEM_freeN(gdo); dm->drawObject = NULL; } -static GPUBuffer *gpu_try_realloc(GPUBufferPool *pool, GPUBuffer *buffer, int size, bool use_VBOs) +static GPUBuffer *gpu_try_realloc(GPUBufferPool *pool, GPUBuffer *buffer, size_t size, bool use_VBOs) { - gpu_buffer_free_intern(buffer); - gpu_buffer_pool_delete_last(pool); - buffer = NULL; - /* try freeing an entry from the pool * and reallocating the buffer */ - if (pool->totbuf > 0) { + gpu_buffer_free_intern(buffer); + + buffer = NULL; + + while (pool->totbuf && !buffer) { gpu_buffer_pool_delete_last(pool); buffer = gpu_buffer_alloc_intern(size, use_VBOs); } - + return buffer; } -typedef void (*GPUBufferCopyFunc)(DerivedMesh *dm, float *varray, int *index, - int *mat_orig_to_new, void *user_data); - static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object, - int vector_size, int size, GLenum target, - void *user, GPUBufferCopyFunc copy_f) + int type, void *user) { GPUBufferPool *pool; GPUBuffer *buffer; float *varray; int *mat_orig_to_new; - int *cur_index_per_mat; int i; + const GPUBufferTypeSettings *ts = &gpu_buffer_type_settings[type]; + GLenum target = ts->gl_buffer_type; + size_t size = gpu_buffer_size_from_type(dm, type); bool use_VBOs = (GLEW_ARB_vertex_buffer_object) && !(U.gameflags & USER_DISABLE_VBO); GLboolean uploaded; @@ -633,12 +546,7 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object, mat_orig_to_new = MEM_mallocN(sizeof(*mat_orig_to_new) * dm->totmat, "GPU_buffer_setup.mat_orig_to_new"); - cur_index_per_mat = MEM_mallocN(sizeof(int) * object->totmaterial, - "GPU_buffer_setup.cur_index_per_mat"); for (i = 0; i < object->totmaterial; i++) { - /* for each material, the current index to copy data to */ - cur_index_per_mat[i] = object->materials[i].start * vector_size; - /* map from original material index to new * GPUBufferMaterial index */ mat_orig_to_new[object->materials[i].mat_nr] = i; @@ -659,7 +567,7 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object, /* allocation still failed; fall back * to legacy mode */ - if (!buffer) { + if (!(buffer && (varray = glMapBufferARB(target, GL_WRITE_ONLY_ARB)))) { use_VBOs = false; success = true; } @@ -674,7 +582,7 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object, uploaded = GL_FALSE; /* attempt to upload the data to the VBO */ while (uploaded == GL_FALSE) { - (*copy_f)(dm, varray, cur_index_per_mat, mat_orig_to_new, user); + dm->copy_gpu_data(dm, type, varray, mat_orig_to_new, user); /* glUnmapBuffer returns GL_FALSE if * the data store is corrupted; retry * in that case */ @@ -691,11 +599,10 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object, if (buffer) { varray = buffer->pointer; - (*copy_f)(dm, varray, cur_index_per_mat, mat_orig_to_new, user); + dm->copy_gpu_data(dm, type, varray, mat_orig_to_new, user); } } - MEM_freeN(cur_index_per_mat); MEM_freeN(mat_orig_to_new); BLI_mutex_unlock(&buffer_mutex); @@ -703,361 +610,6 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object, return buffer; } -static void GPU_buffer_copy_vertex(DerivedMesh *dm, float *varray, int *index, int *mat_orig_to_new, void *UNUSED(user)) -{ - MVert *mvert; - MFace *f; - int i, j, start, totface; - - mvert = dm->getVertArray(dm); - f = dm->getTessFaceArray(dm); - - totface = dm->getNumTessFaces(dm); - for (i = 0; i < totface; i++, f++) { - start = index[mat_orig_to_new[f->mat_nr]]; - - /* v1 v2 v3 */ - copy_v3_v3(&varray[start], mvert[f->v1].co); - copy_v3_v3(&varray[start + 3], mvert[f->v2].co); - copy_v3_v3(&varray[start + 6], mvert[f->v3].co); - index[mat_orig_to_new[f->mat_nr]] += 9; - - if (f->v4) { - /* v3 v4 v1 */ - copy_v3_v3(&varray[start + 9], mvert[f->v3].co); - copy_v3_v3(&varray[start + 12], mvert[f->v4].co); - copy_v3_v3(&varray[start + 15], mvert[f->v1].co); - index[mat_orig_to_new[f->mat_nr]] += 9; - } - } - - /* copy loose points */ - j = dm->drawObject->tot_triangle_point * 3; - for (i = 0; i < dm->drawObject->totvert; i++) { - if (dm->drawObject->vert_points[i].point_index >= dm->drawObject->tot_triangle_point) { - copy_v3_v3(&varray[j], mvert[i].co); - j += 3; - } - } -} - -static void GPU_buffer_copy_normal(DerivedMesh *dm, float *varray, int *index, int *mat_orig_to_new, void *UNUSED(user)) -{ - int i, totface; - int start; - float f_no[3]; - - const float *nors = dm->getTessFaceDataArray(dm, CD_NORMAL); - short (*tlnors)[4][3] = dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL); - MVert *mvert = dm->getVertArray(dm); - MFace *f = dm->getTessFaceArray(dm); - - totface = dm->getNumTessFaces(dm); - for (i = 0; i < totface; i++, f++) { - const int smoothnormal = (f->flag & ME_SMOOTH); - - start = index[mat_orig_to_new[f->mat_nr]]; - index[mat_orig_to_new[f->mat_nr]] += f->v4 ? 18 : 9; - - if (tlnors) { - short (*tlnor)[3] = tlnors[i]; - /* Copy loop normals */ - normal_short_to_float_v3(&varray[start], tlnor[0]); - normal_short_to_float_v3(&varray[start + 3], tlnor[1]); - normal_short_to_float_v3(&varray[start + 6], tlnor[2]); - - if (f->v4) { - normal_short_to_float_v3(&varray[start + 9], tlnor[2]); - normal_short_to_float_v3(&varray[start + 12], tlnor[3]); - normal_short_to_float_v3(&varray[start + 15], tlnor[0]); - } - } - else if (smoothnormal) { - /* copy vertex normal */ - normal_short_to_float_v3(&varray[start], mvert[f->v1].no); - normal_short_to_float_v3(&varray[start + 3], mvert[f->v2].no); - normal_short_to_float_v3(&varray[start + 6], mvert[f->v3].no); - - if (f->v4) { - normal_short_to_float_v3(&varray[start + 9], mvert[f->v3].no); - normal_short_to_float_v3(&varray[start + 12], mvert[f->v4].no); - normal_short_to_float_v3(&varray[start + 15], mvert[f->v1].no); - } - } - else if (nors) { - /* copy cached face normal */ - copy_v3_v3(&varray[start], &nors[i * 3]); - copy_v3_v3(&varray[start + 3], &nors[i * 3]); - copy_v3_v3(&varray[start + 6], &nors[i * 3]); - - if (f->v4) { - copy_v3_v3(&varray[start + 9], &nors[i * 3]); - copy_v3_v3(&varray[start + 12], &nors[i * 3]); - copy_v3_v3(&varray[start + 15], &nors[i * 3]); - } - } - else { - /* calculate face normal */ - if (f->v4) - normal_quad_v3(f_no, mvert[f->v1].co, mvert[f->v2].co, mvert[f->v3].co, mvert[f->v4].co); - else - normal_tri_v3(f_no, mvert[f->v1].co, mvert[f->v2].co, mvert[f->v3].co); - - copy_v3_v3(&varray[start], f_no); - copy_v3_v3(&varray[start + 3], f_no); - copy_v3_v3(&varray[start + 6], f_no); - - if (f->v4) { - copy_v3_v3(&varray[start + 9], f_no); - copy_v3_v3(&varray[start + 12], f_no); - copy_v3_v3(&varray[start + 15], f_no); - } - } - } -} - -static void GPU_buffer_copy_uv(DerivedMesh *dm, float *varray, int *index, int *mat_orig_to_new, void *UNUSED(user)) -{ - int start; - int i, totface; - - MTFace *mtface; - MFace *f; - - if (!(mtface = DM_get_tessface_data_layer(dm, CD_MTFACE))) - return; - f = dm->getTessFaceArray(dm); - - totface = dm->getNumTessFaces(dm); - for (i = 0; i < totface; i++, f++) { - start = index[mat_orig_to_new[f->mat_nr]]; - - /* v1 v2 v3 */ - copy_v2_v2(&varray[start], mtface[i].uv[0]); - copy_v2_v2(&varray[start + 2], mtface[i].uv[1]); - copy_v2_v2(&varray[start + 4], mtface[i].uv[2]); - index[mat_orig_to_new[f->mat_nr]] += 6; - - if (f->v4) { - /* v3 v4 v1 */ - copy_v2_v2(&varray[start + 6], mtface[i].uv[2]); - copy_v2_v2(&varray[start + 8], mtface[i].uv[3]); - copy_v2_v2(&varray[start + 10], mtface[i].uv[0]); - index[mat_orig_to_new[f->mat_nr]] += 6; - } - } -} - - -static void GPU_buffer_copy_uv_texpaint(DerivedMesh *dm, float *varray, int *index, int *mat_orig_to_new, void *UNUSED(user)) -{ - int start; - int i, totface; - - int totmaterial = dm->totmat; - MTFace **mtface_base; - MTFace *stencil_base; - int stencil; - MFace *mf; - - /* should have been checked for before, reassert */ - BLI_assert(DM_get_tessface_data_layer(dm, CD_MTFACE)); - mf = dm->getTessFaceArray(dm); - mtface_base = MEM_mallocN(totmaterial * sizeof(*mtface_base), "texslots"); - - for (i = 0; i < totmaterial; i++) { - mtface_base[i] = DM_paint_uvlayer_active_get(dm, i); - } - - stencil = CustomData_get_stencil_layer(&dm->faceData, CD_MTFACE); - stencil_base = CustomData_get_layer_n(&dm->faceData, CD_MTFACE, stencil); - - totface = dm->getNumTessFaces(dm); - - for (i = 0; i < totface; i++, mf++) { - int mat_i = mf->mat_nr; - start = index[mat_orig_to_new[mat_i]]; - - /* v1 v2 v3 */ - copy_v2_v2(&varray[start], mtface_base[mat_i][i].uv[0]); - copy_v2_v2(&varray[start + 2], stencil_base[i].uv[0]); - copy_v2_v2(&varray[start + 4], mtface_base[mat_i][i].uv[1]); - copy_v2_v2(&varray[start + 6], stencil_base[i].uv[1]); - copy_v2_v2(&varray[start + 8], mtface_base[mat_i][i].uv[2]); - copy_v2_v2(&varray[start + 10], stencil_base[i].uv[2]); - index[mat_orig_to_new[mat_i]] += 12; - - if (mf->v4) { - /* v3 v4 v1 */ - copy_v2_v2(&varray[start + 12], mtface_base[mat_i][i].uv[2]); - copy_v2_v2(&varray[start + 14], stencil_base[i].uv[2]); - copy_v2_v2(&varray[start + 16], mtface_base[mat_i][i].uv[3]); - copy_v2_v2(&varray[start + 18], stencil_base[i].uv[3]); - copy_v2_v2(&varray[start + 20], mtface_base[mat_i][i].uv[0]); - copy_v2_v2(&varray[start + 22], stencil_base[i].uv[0]); - index[mat_orig_to_new[mat_i]] += 12; - } - } - - MEM_freeN(mtface_base); -} - - -static void copy_mcol_uc3(unsigned char *v, unsigned char *col) -{ - v[0] = col[3]; - v[1] = col[2]; - v[2] = col[1]; -} - -/* treat varray_ as an array of MCol, four MCol's per face */ -static void GPU_buffer_copy_mcol(DerivedMesh *dm, float *varray_, int *index, int *mat_orig_to_new, void *user) -{ - int i, totface; - unsigned char *varray = (unsigned char *)varray_; - unsigned char *mcol = (unsigned char *)user; - MFace *f = dm->getTessFaceArray(dm); - - totface = dm->getNumTessFaces(dm); - for (i = 0; i < totface; i++, f++) { - int start = index[mat_orig_to_new[f->mat_nr]]; - - /* v1 v2 v3 */ - copy_mcol_uc3(&varray[start], &mcol[i * 16]); - copy_mcol_uc3(&varray[start + 3], &mcol[i * 16 + 4]); - copy_mcol_uc3(&varray[start + 6], &mcol[i * 16 + 8]); - index[mat_orig_to_new[f->mat_nr]] += 9; - - if (f->v4) { - /* v3 v4 v1 */ - copy_mcol_uc3(&varray[start + 9], &mcol[i * 16 + 8]); - copy_mcol_uc3(&varray[start + 12], &mcol[i * 16 + 12]); - copy_mcol_uc3(&varray[start + 15], &mcol[i * 16]); - index[mat_orig_to_new[f->mat_nr]] += 9; - } - } -} - -static void GPU_buffer_copy_edge(DerivedMesh *dm, float *varray_, int *UNUSED(index), int *UNUSED(mat_orig_to_new), void *UNUSED(user)) -{ - MEdge *medge, *medge_base; - unsigned int *varray = (unsigned int *)varray_; - int i, totedge, iloose, inorm, iloosehidden, inormhidden; - int tot_loose_hidden = 0, tot_loose = 0; - int tot_hidden = 0, tot = 0; - - medge_base = medge = dm->getEdgeArray(dm); - totedge = dm->getNumEdges(dm); - - for (i = 0; i < totedge; i++, medge++) { - if (medge->flag & ME_EDGEDRAW) { - if (medge->flag & ME_LOOSEEDGE) tot_loose++; - else tot++; - } - else { - if (medge->flag & ME_LOOSEEDGE) tot_loose_hidden++; - else tot_hidden++; - } - } - - inorm = 0; - inormhidden = tot; - iloose = tot + tot_hidden; - iloosehidden = iloose + tot_loose; - - medge = medge_base; - for (i = 0; i < totedge; i++, medge++) { - if (medge->flag & ME_EDGEDRAW) { - if (medge->flag & ME_LOOSEEDGE) { - varray[iloose * 2] = dm->drawObject->vert_points[medge->v1].point_index; - varray[iloose * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index; - iloose++; - } - else { - varray[inorm * 2] = dm->drawObject->vert_points[medge->v1].point_index; - varray[inorm * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index; - inorm++; - } - } - else { - if (medge->flag & ME_LOOSEEDGE) { - varray[iloosehidden * 2] = dm->drawObject->vert_points[medge->v1].point_index; - varray[iloosehidden * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index; - iloosehidden++; - } - else { - varray[inormhidden * 2] = dm->drawObject->vert_points[medge->v1].point_index; - varray[inormhidden * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index; - inormhidden++; - } - } - } - - dm->drawObject->tot_loose_edge_drawn = tot_loose; - dm->drawObject->loose_edge_offset = tot + tot_hidden; - dm->drawObject->tot_edge_drawn = tot; -} - -static void GPU_buffer_copy_uvedge(DerivedMesh *dm, float *varray, int *UNUSED(index), int *UNUSED(mat_orig_to_new), void *UNUSED(user)) -{ - MTFace *tf = DM_get_tessface_data_layer(dm, CD_MTFACE); - int i, j = 0; - - if (!tf) - return; - - for (i = 0; i < dm->numTessFaceData; i++, tf++) { - MFace mf; - dm->getTessFace(dm, i, &mf); - - copy_v2_v2(&varray[j], tf->uv[0]); - copy_v2_v2(&varray[j + 2], tf->uv[1]); - - copy_v2_v2(&varray[j + 4], tf->uv[1]); - copy_v2_v2(&varray[j + 6], tf->uv[2]); - - if (!mf.v4) { - copy_v2_v2(&varray[j + 8], tf->uv[2]); - copy_v2_v2(&varray[j + 10], tf->uv[0]); - j += 12; - } - else { - copy_v2_v2(&varray[j + 8], tf->uv[2]); - copy_v2_v2(&varray[j + 10], tf->uv[3]); - - copy_v2_v2(&varray[j + 12], tf->uv[3]); - copy_v2_v2(&varray[j + 14], tf->uv[0]); - j += 16; - } - } -} - -typedef enum { - GPU_BUFFER_VERTEX = 0, - GPU_BUFFER_NORMAL, - GPU_BUFFER_COLOR, - GPU_BUFFER_UV, - GPU_BUFFER_UV_TEXPAINT, - GPU_BUFFER_EDGE, - GPU_BUFFER_UVEDGE, -} GPUBufferType; - -typedef struct { - GPUBufferCopyFunc copy; - GLenum gl_buffer_type; - int vector_size; -} GPUBufferTypeSettings; - -const GPUBufferTypeSettings gpu_buffer_type_settings[] = { - {GPU_buffer_copy_vertex, GL_ARRAY_BUFFER_ARB, 3}, - {GPU_buffer_copy_normal, GL_ARRAY_BUFFER_ARB, 3}, - {GPU_buffer_copy_mcol, GL_ARRAY_BUFFER_ARB, 3}, - {GPU_buffer_copy_uv, GL_ARRAY_BUFFER_ARB, 2}, - {GPU_buffer_copy_uv_texpaint, GL_ARRAY_BUFFER_ARB, 4}, - {GPU_buffer_copy_edge, GL_ELEMENT_ARRAY_BUFFER_ARB, 2}, - {GPU_buffer_copy_uvedge, GL_ELEMENT_ARRAY_BUFFER_ARB, 4} -}; - /* get the GPUDrawObject buffer associated with a type */ static GPUBuffer **gpu_drawobject_buffer_from_type(GPUDrawObject *gdo, GPUBufferType type) { @@ -1076,34 +628,33 @@ static GPUBuffer **gpu_drawobject_buffer_from_type(GPUDrawObject *gdo, GPUBuffer return &gdo->edges; case GPU_BUFFER_UVEDGE: return &gdo->uvedges; + case GPU_BUFFER_TRIANGLES: + return &gdo->triangles; default: return NULL; } } /* get the amount of space to allocate for a buffer of a particular type */ -static int gpu_buffer_size_from_type(DerivedMesh *dm, GPUBufferType type) +static size_t gpu_buffer_size_from_type(DerivedMesh *dm, GPUBufferType type) { switch (type) { case GPU_BUFFER_VERTEX: - return sizeof(float) * 3 * (dm->drawObject->tot_triangle_point + dm->drawObject->tot_loose_point); + return sizeof(float) * gpu_buffer_type_settings[type].num_components * (dm->drawObject->tot_loop_verts + dm->drawObject->tot_loose_point); case GPU_BUFFER_NORMAL: - return sizeof(float) * 3 * dm->drawObject->tot_triangle_point; + return sizeof(short) * gpu_buffer_type_settings[type].num_components * dm->drawObject->tot_loop_verts; case GPU_BUFFER_COLOR: - return sizeof(char) * 3 * dm->drawObject->tot_triangle_point; + return sizeof(char) * gpu_buffer_type_settings[type].num_components * dm->drawObject->tot_loop_verts; case GPU_BUFFER_UV: - return sizeof(float) * 2 * dm->drawObject->tot_triangle_point; + return sizeof(float) * gpu_buffer_type_settings[type].num_components * dm->drawObject->tot_loop_verts; case GPU_BUFFER_UV_TEXPAINT: - return sizeof(float) * 4 * dm->drawObject->tot_triangle_point; + return sizeof(float) * gpu_buffer_type_settings[type].num_components * dm->drawObject->tot_loop_verts; case GPU_BUFFER_EDGE: - return sizeof(int) * 2 * dm->drawObject->totedge; + return sizeof(int) * gpu_buffer_type_settings[type].num_components * dm->drawObject->totedge; case GPU_BUFFER_UVEDGE: - /* each face gets 3 points, 3 edges per triangle, and - * each edge has its own, non-shared coords, so each - * tri corner needs minimum of 4 floats, quads used - * less so here we can over allocate and assume all - * tris. */ - return sizeof(float) * 4 * dm->drawObject->tot_triangle_point; + return sizeof(int) * gpu_buffer_type_settings[type].num_components * dm->drawObject->tot_loop_verts; + case GPU_BUFFER_TRIANGLES: + return sizeof(int) * gpu_buffer_type_settings[type].num_components * dm->drawObject->tot_triangle_point; default: return -1; } @@ -1112,25 +663,20 @@ static int gpu_buffer_size_from_type(DerivedMesh *dm, GPUBufferType type) /* call gpu_buffer_setup with settings for a particular type of buffer */ static GPUBuffer *gpu_buffer_setup_type(DerivedMesh *dm, GPUBufferType type) { - const GPUBufferTypeSettings *ts; void *user_data = NULL; GPUBuffer *buf; - ts = &gpu_buffer_type_settings[type]; - /* special handling for MCol and UV buffers */ if (type == GPU_BUFFER_COLOR) { - if (!(user_data = DM_get_tessface_data_layer(dm, dm->drawObject->colType))) + if (!(user_data = DM_get_loop_data_layer(dm, dm->drawObject->colType))) return NULL; } else if (ELEM(type, GPU_BUFFER_UV, GPU_BUFFER_UV_TEXPAINT)) { - if (!DM_get_tessface_data_layer(dm, CD_MTFACE)) + if (!DM_get_loop_data_layer(dm, CD_MLOOPUV)) return NULL; } - buf = gpu_buffer_setup(dm, dm->drawObject, ts->vector_size, - gpu_buffer_size_from_type(dm, type), - ts->gl_buffer_type, user_data, ts->copy); + buf = gpu_buffer_setup(dm, dm->drawObject, type, user_data); return buf; } @@ -1142,7 +688,7 @@ static GPUBuffer *gpu_buffer_setup_common(DerivedMesh *dm, GPUBufferType type) GPUBuffer **buf; if (!dm->drawObject) - dm->drawObject = GPU_drawobject_new(dm); + dm->drawObject = dm->gpuObjectNew(dm); buf = gpu_drawobject_buffer_from_type(dm->drawObject, type); if (!(*buf)) @@ -1176,10 +722,10 @@ void GPU_normal_setup(DerivedMesh *dm) glEnableClientState(GL_NORMAL_ARRAY); if (dm->drawObject->normals->use_vbo) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->normals->id); - glNormalPointer(GL_FLOAT, 0, 0); + glNormalPointer(GL_SHORT, 4 * sizeof(short), 0); } else { - glNormalPointer(GL_FLOAT, 0, dm->drawObject->normals->pointer); + glNormalPointer(GL_SHORT, 4 * sizeof(short), dm->drawObject->normals->pointer); } GLStates |= GPU_BUFFER_NORMAL_STATE; @@ -1233,7 +779,7 @@ void GPU_color_setup(DerivedMesh *dm, int colType) if (!dm->drawObject) { /* XXX Not really nice, but we need a valid gpu draw object to set the colType... * Else we would have to add a new param to gpu_buffer_setup_common. */ - dm->drawObject = GPU_drawobject_new(dm); + dm->drawObject = dm->gpuObjectNew(dm); dm->dirty &= ~DM_DIRTY_MCOL_UPDATE_DRAW; dm->drawObject->colType = colType; } @@ -1265,6 +811,21 @@ void GPU_color_setup(DerivedMesh *dm, int colType) GLStates |= GPU_BUFFER_COLOR_STATE; } +void GPU_buffer_bind_as_color(GPUBuffer *buffer) +{ + glEnableClientState(GL_COLOR_ARRAY); + if (buffer->use_vbo) { + glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer->id); + glColorPointer(4, GL_UNSIGNED_BYTE, 0, 0); + } + else { + glColorPointer(4, GL_UNSIGNED_BYTE, 0, buffer->pointer); + } + + GLStates |= GPU_BUFFER_COLOR_STATE; +} + + void GPU_edge_setup(DerivedMesh *dm) { if (!gpu_buffer_setup_common(dm, GPU_BUFFER_EDGE)) @@ -1307,6 +868,18 @@ void GPU_uvedge_setup(DerivedMesh *dm) GLStates |= GPU_BUFFER_VERTEX_STATE; } +void GPU_triangle_setup(struct DerivedMesh *dm) +{ + if (!gpu_buffer_setup_common(dm, GPU_BUFFER_TRIANGLES)) + return; + + if (dm->drawObject->triangles->use_vbo) { + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, dm->drawObject->triangles->id); + } + + GLStates |= GPU_BUFFER_ELEMENT_STATE; +} + static int GPU_typesize(int type) { switch (type) { @@ -1337,7 +910,7 @@ int GPU_attrib_element_size(GPUAttrib data[], int numdata) return elementsize; } -void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numdata) +void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numdata, int element_size) { int i; int elementsize; @@ -1351,7 +924,10 @@ void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numda else break; } - elementsize = GPU_attrib_element_size(data, numdata); + if (element_size == 0) + elementsize = GPU_attrib_element_size(data, numdata); + else + elementsize = element_size; if (buffer->use_vbo) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer->id); @@ -1375,8 +951,20 @@ void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numda attribData[numdata].index = -1; } +void GPU_interleaved_attrib_unbind(void) +{ + int i; + for (i = 0; i < MAX_GPU_ATTRIB_DATA; i++) { + if (attribData[i].index != -1) { + glDisableVertexAttribArrayARB(attribData[i].index); + } + else + break; + } + attribData[0].index = -1; +} -void GPU_buffer_unbind(void) +void GPU_buffers_unbind(void) { int i; @@ -1431,7 +1019,13 @@ void GPU_color_switch(int mode) } } -void *GPU_buffer_lock(GPUBuffer *buffer) +static int gpu_binding_type_gl[] = +{ + GL_ARRAY_BUFFER_ARB, + GL_ELEMENT_ARRAY_BUFFER_ARB +}; + +void *GPU_buffer_lock(GPUBuffer *buffer, GPUBindingType binding) { float *varray; @@ -1439,8 +1033,9 @@ void *GPU_buffer_lock(GPUBuffer *buffer) return 0; if (buffer->use_vbo) { - glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer->id); - varray = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + int bindtypegl = gpu_binding_type_gl[binding]; + glBindBufferARB(bindtypegl, buffer->id); + varray = glMapBufferARB(bindtypegl, GL_WRITE_ONLY_ARB); return varray; } else { @@ -1448,7 +1043,7 @@ void *GPU_buffer_lock(GPUBuffer *buffer) } } -void *GPU_buffer_lock_stream(GPUBuffer *buffer) +void *GPU_buffer_lock_stream(GPUBuffer *buffer, GPUBindingType binding) { float *varray; @@ -1456,10 +1051,11 @@ void *GPU_buffer_lock_stream(GPUBuffer *buffer) return 0; if (buffer->use_vbo) { - glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer->id); + int bindtypegl = gpu_binding_type_gl[binding]; + glBindBufferARB(bindtypegl, buffer->id); /* discard previous data, avoid stalling gpu */ - glBufferDataARB(GL_ARRAY_BUFFER_ARB, buffer->size, 0, GL_STREAM_DRAW_ARB); - varray = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + glBufferDataARB(bindtypegl, buffer->size, 0, GL_STREAM_DRAW_ARB); + varray = glMapBufferARB(bindtypegl, GL_WRITE_ONLY_ARB); return varray; } else { @@ -1467,13 +1063,30 @@ void *GPU_buffer_lock_stream(GPUBuffer *buffer) } } -void GPU_buffer_unlock(GPUBuffer *buffer) +void GPU_buffer_unlock(GPUBuffer *buffer, GPUBindingType binding) { if (buffer->use_vbo) { + int bindtypegl = gpu_binding_type_gl[binding]; /* note: this operation can fail, could return * an error code from this function? */ - glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); + glUnmapBufferARB(bindtypegl); + glBindBufferARB(bindtypegl, 0); + } +} + +void GPU_buffer_bind(GPUBuffer *buffer, GPUBindingType binding) +{ + if (buffer->use_vbo) { + int bindtypegl = gpu_binding_type_gl[binding]; + glBindBufferARB(bindtypegl, buffer->id); + } +} + +void GPU_buffer_unbind(GPUBuffer *buffer, GPUBindingType binding) +{ + if (buffer->use_vbo) { + int bindtypegl = gpu_binding_type_gl[binding]; + glBindBufferARB(bindtypegl, 0); } } @@ -1490,14 +1103,6 @@ void GPU_buffer_draw_elements(GPUBuffer *elements, unsigned int mode, int start, /* XXX: the rest of the code in this file is used for optimized PBVH * drawing and doesn't interact at all with the buffer code above */ -/* Return false if VBO is either unavailable or disabled by the user, - * true otherwise */ -static int gpu_vbo_enabled(void) -{ - return (GLEW_ARB_vertex_buffer_object && - !(U.gameflags & USER_DISABLE_VBO)); -} - /* Convenience struct for building the VBO. */ typedef struct { float co[3]; @@ -1513,14 +1118,17 @@ typedef struct { struct GPU_PBVH_Buffers { /* opengl buffer handles */ - GLuint vert_buf, index_buf; + GPUBuffer *vert_buf, *index_buf, *index_buf_fast; GLenum index_type; /* mesh pointers in case buffer allocation fails */ - MFace *mface; - MVert *mvert; + const MPoly *mpoly; + const MLoop *mloop; + const MLoopTri *looptri; + const MVert *mvert; + const int *face_indices; - int totface; + int face_indices_len; const float *vmask; /* grid pointers */ @@ -1581,22 +1189,6 @@ static void gpu_color_from_mask_copy(float mask, const float diffuse_color[4], u out[2] = diffuse_color[2] * mask_color; } -static void gpu_color_from_mask_set(float mask, float diffuse_color[4]) -{ - float color = gpu_color_from_mask(mask); - glColor3f(diffuse_color[0] * color, diffuse_color[1] * color, diffuse_color[2] * color); -} - -static float gpu_color_from_mask_quad(const CCGKey *key, - CCGElem *a, CCGElem *b, - CCGElem *c, CCGElem *d) -{ - return gpu_color_from_mask((*CCG_elem_mask(key, a) + - *CCG_elem_mask(key, b) + - *CCG_elem_mask(key, c) + - *CCG_elem_mask(key, d)) * 0.25f); -} - static void gpu_color_from_mask_quad_copy(const CCGKey *key, CCGElem *a, CCGElem *b, CCGElem *c, CCGElem *d, @@ -1614,47 +1206,38 @@ static void gpu_color_from_mask_quad_copy(const CCGKey *key, out[2] = diffuse_color[2] * mask_color; } -static void gpu_color_from_mask_quad_set(const CCGKey *key, - CCGElem *a, CCGElem *b, - CCGElem *c, CCGElem *d, - const float diffuse_color[4]) -{ - float color = gpu_color_from_mask_quad(key, a, b, c, d); - glColor3f(diffuse_color[0] * color, diffuse_color[1] * color, diffuse_color[2] * color); -} - -void GPU_update_mesh_pbvh_buffers(GPU_PBVH_Buffers *buffers, MVert *mvert, - int *vert_indices, int totvert, const float *vmask, - int (*face_vert_indices)[4], bool show_diffuse_color) +void GPU_update_mesh_pbvh_buffers( + GPU_PBVH_Buffers *buffers, const MVert *mvert, + const int *vert_indices, int totvert, const float *vmask, + const int (*face_vert_indices)[4], bool show_diffuse_color) { VertexBufferFormat *vert_data; - int i, j, k; + int i, j; buffers->vmask = vmask; buffers->show_diffuse_color = show_diffuse_color; buffers->use_matcaps = GPU_material_use_matcaps_get(); - if (buffers->vert_buf) { + { int totelem = (buffers->smooth ? totvert : (buffers->tot_tri * 3)); float diffuse_color[4] = {0.8f, 0.8f, 0.8f, 0.8f}; if (buffers->use_matcaps) diffuse_color[0] = diffuse_color[1] = diffuse_color[2] = 1.0; else if (show_diffuse_color) { - MFace *f = buffers->mface + buffers->face_indices[0]; + const MLoopTri *lt = &buffers->looptri[buffers->face_indices[0]]; + const MPoly *mp = &buffers->mpoly[lt->poly]; - GPU_material_diffuse_get(f->mat_nr + 1, diffuse_color); + GPU_material_diffuse_get(mp->mat_nr + 1, diffuse_color); } copy_v4_v4(buffers->diffuse_color, diffuse_color); /* Build VBO */ - glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf); - glBufferDataARB(GL_ARRAY_BUFFER_ARB, - sizeof(VertexBufferFormat) * totelem, - NULL, GL_STATIC_DRAW_ARB); - - vert_data = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + if (buffers->vert_buf) + GPU_buffer_free(buffers->vert_buf); + buffers->vert_buf = GPU_buffer_alloc(sizeof(VertexBufferFormat) * totelem, false); + vert_data = GPU_buffer_lock(buffers->vert_buf, GPU_BINDING_ARRAY); if (vert_data) { /* Vertex data is shared if smooth-shaded, but separate @@ -1662,7 +1245,7 @@ void GPU_update_mesh_pbvh_buffers(GPU_PBVH_Buffers *buffers, MVert *mvert, * shouldn't be shared. */ if (buffers->smooth) { for (i = 0; i < totvert; ++i) { - MVert *v = mvert + vert_indices[i]; + const MVert *v = &mvert[vert_indices[i]]; VertexBufferFormat *out = vert_data + i; copy_v3_v3(out->co, v->co); @@ -1678,118 +1261,114 @@ void GPU_update_mesh_pbvh_buffers(GPU_PBVH_Buffers *buffers, MVert *mvert, rgb_float_to_uchar(out->color, diffuse_color); \ } (void)0 - for (i = 0; i < buffers->totface; i++) { - MFace *f = buffers->mface + buffers->face_indices[i]; + for (i = 0; i < buffers->face_indices_len; i++) { + const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]]; + const unsigned int vtri[3] = { + buffers->mloop[lt->tri[0]].v, + buffers->mloop[lt->tri[1]].v, + buffers->mloop[lt->tri[2]].v, + }; - UPDATE_VERTEX(i, f->v1, 0, diffuse_color); - UPDATE_VERTEX(i, f->v2, 1, diffuse_color); - UPDATE_VERTEX(i, f->v3, 2, diffuse_color); - if (f->v4) - UPDATE_VERTEX(i, f->v4, 3, diffuse_color); + UPDATE_VERTEX(i, vtri[0], 0, diffuse_color); + UPDATE_VERTEX(i, vtri[1], 1, diffuse_color); + UPDATE_VERTEX(i, vtri[2], 2, diffuse_color); } #undef UPDATE_VERTEX } else { - for (i = 0; i < buffers->totface; ++i) { - const MFace *f = &buffers->mface[buffers->face_indices[i]]; - const unsigned int *fv = &f->v1; - const int vi[2][3] = {{0, 1, 2}, {3, 0, 2}}; - float fno[3]; - short no[3]; + /* calculate normal for each polygon only once */ + unsigned int mpoly_prev = UINT_MAX; + short no[3]; + + for (i = 0; i < buffers->face_indices_len; ++i) { + const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]]; + const unsigned int vtri[3] = { + buffers->mloop[lt->tri[0]].v, + buffers->mloop[lt->tri[1]].v, + buffers->mloop[lt->tri[2]].v, + }; float fmask; - if (paint_is_face_hidden(f, mvert)) + if (paint_is_face_hidden(lt, mvert, buffers->mloop)) continue; /* Face normal and mask */ - if (f->v4) { - normal_quad_v3(fno, - mvert[fv[0]].co, - mvert[fv[1]].co, - mvert[fv[2]].co, - mvert[fv[3]].co); - if (vmask) { - fmask = (vmask[fv[0]] + - vmask[fv[1]] + - vmask[fv[2]] + - vmask[fv[3]]) * 0.25f; - } + if (lt->poly != mpoly_prev) { + const MPoly *mp = &buffers->mpoly[lt->poly]; + float fno[3]; + BKE_mesh_calc_poly_normal(mp, &buffers->mloop[mp->loopstart], mvert, fno); + normal_float_to_short_v3(no, fno); + mpoly_prev = lt->poly; } - else { - normal_tri_v3(fno, - mvert[fv[0]].co, - mvert[fv[1]].co, - mvert[fv[2]].co); - if (vmask) { - fmask = (vmask[fv[0]] + - vmask[fv[1]] + - vmask[fv[2]]) / 3.0f; - } + + if (vmask) { + fmask = (vmask[vtri[0]] + + vmask[vtri[1]] + + vmask[vtri[2]]) / 3.0f; } - normal_float_to_short_v3(no, fno); - for (j = 0; j < (f->v4 ? 2 : 1); j++) { - for (k = 0; k < 3; k++) { - const MVert *v = &mvert[fv[vi[j][k]]]; - VertexBufferFormat *out = vert_data; + for (j = 0; j < 3; j++) { + const MVert *v = &mvert[vtri[j]]; + VertexBufferFormat *out = vert_data; - copy_v3_v3(out->co, v->co); - memcpy(out->no, no, sizeof(short) * 3); + copy_v3_v3(out->co, v->co); + copy_v3_v3_short(out->no, no); - if (vmask) - gpu_color_from_mask_copy(fmask, diffuse_color, out->color); - else - rgb_float_to_uchar(out->color, diffuse_color); + if (vmask) + gpu_color_from_mask_copy(fmask, diffuse_color, out->color); + else + rgb_float_to_uchar(out->color, diffuse_color); - vert_data++; - } + vert_data++; } } } - glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); + GPU_buffer_unlock(buffers->vert_buf, GPU_BINDING_ARRAY); } else { - glDeleteBuffersARB(1, &buffers->vert_buf); - buffers->vert_buf = 0; + GPU_buffer_free(buffers->vert_buf); + buffers->vert_buf = NULL; } - - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); } buffers->mvert = mvert; } -GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers(int (*face_vert_indices)[4], - MFace *mface, MVert *mvert, - int *face_indices, - int totface) +GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers( + const int (*face_vert_indices)[4], + const MPoly *mpoly, const MLoop *mloop, const MLoopTri *looptri, + const MVert *mvert, + const int *face_indices, + const int face_indices_len) { GPU_PBVH_Buffers *buffers; unsigned short *tri_data; - int i, j, k, tottri; + int i, j, tottri; buffers = MEM_callocN(sizeof(GPU_PBVH_Buffers), "GPU_Buffers"); buffers->index_type = GL_UNSIGNED_SHORT; - buffers->smooth = mface[face_indices[0]].flag & ME_SMOOTH; + buffers->smooth = mpoly[looptri[face_indices[0]].poly].flag & ME_SMOOTH; buffers->show_diffuse_color = false; buffers->use_matcaps = false; /* Count the number of visible triangles */ - for (i = 0, tottri = 0; i < totface; ++i) { - const MFace *f = &mface[face_indices[i]]; - if (!paint_is_face_hidden(f, mvert)) - tottri += f->v4 ? 2 : 1; + for (i = 0, tottri = 0; i < face_indices_len; ++i) { + const MLoopTri *lt = &looptri[face_indices[i]]; + if (!paint_is_face_hidden(lt, mvert, mloop)) + tottri++; } if (tottri == 0) { buffers->tot_tri = 0; - buffers->mface = mface; + buffers->mpoly = mpoly; + buffers->mloop = mloop; + buffers->looptri = looptri; buffers->face_indices = face_indices; - buffers->totface = 0; + buffers->face_indices_len = 0; return buffers; } @@ -1797,58 +1376,41 @@ GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers(int (*face_vert_indices)[4], /* An element index buffer is used for smooth shading, but flat * shading requires separate vertex normals so an index buffer is * can't be used there. */ - if (gpu_vbo_enabled() && buffers->smooth) - glGenBuffersARB(1, &buffers->index_buf); + if (buffers->smooth) + buffers->index_buf = GPU_buffer_alloc(sizeof(unsigned short) * tottri * 3, false); if (buffers->index_buf) { - /* Generate index buffer object */ - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf); - glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, - sizeof(unsigned short) * tottri * 3, NULL, GL_STATIC_DRAW_ARB); - /* Fill the triangle buffer */ - tri_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + tri_data = GPU_buffer_lock(buffers->index_buf, GPU_BINDING_INDEX); if (tri_data) { - for (i = 0; i < totface; ++i) { - const MFace *f = mface + face_indices[i]; - int v[3]; + for (i = 0; i < face_indices_len; ++i) { + const MLoopTri *lt = &looptri[face_indices[i]]; /* Skip hidden faces */ - if (paint_is_face_hidden(f, mvert)) + if (paint_is_face_hidden(lt, mvert, mloop)) continue; - v[0] = 0; - v[1] = 1; - v[2] = 2; - - for (j = 0; j < (f->v4 ? 2 : 1); ++j) { - for (k = 0; k < 3; ++k) { - *tri_data = face_vert_indices[i][v[k]]; - tri_data++; - } - v[0] = 3; - v[1] = 0; - v[2] = 2; + for (j = 0; j < 3; ++j) { + *tri_data = face_vert_indices[i][j]; + tri_data++; } } - glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB); + GPU_buffer_unlock(buffers->index_buf, GPU_BINDING_INDEX); } else { - glDeleteBuffersARB(1, &buffers->index_buf); - buffers->index_buf = 0; + GPU_buffer_free(buffers->index_buf); + buffers->index_buf = NULL; } - - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); } - if (gpu_vbo_enabled() && (buffers->index_buf || !buffers->smooth)) - glGenBuffersARB(1, &buffers->vert_buf); - buffers->tot_tri = tottri; - buffers->mface = mface; + buffers->mpoly = mpoly; + buffers->mloop = mloop; + buffers->looptri = looptri; + buffers->face_indices = face_indices; - buffers->totface = totface; + buffers->face_indices_len = face_indices_len; return buffers; } @@ -1865,7 +1427,6 @@ void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, CCGElem **grids, /* Build VBO */ if (buffers->vert_buf) { - int totvert = key->grid_area * totgrid; int smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH; const int has_mask = key->has_mask; float diffuse_color[4] = {0.8f, 0.8f, 0.8f, 1.0f}; @@ -1880,11 +1441,7 @@ void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, CCGElem **grids, copy_v4_v4(buffers->diffuse_color, diffuse_color); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf); - glBufferDataARB(GL_ARRAY_BUFFER_ARB, - sizeof(VertexBufferFormat) * totvert, - NULL, GL_STATIC_DRAW_ARB); - vert_data = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + vert_data = GPU_buffer_lock_stream(buffers->vert_buf, GPU_BINDING_ARRAY); if (vert_data) { for (i = 0; i < totgrid; ++i) { VertexBufferFormat *vd = vert_data; @@ -1945,13 +1502,13 @@ void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, CCGElem **grids, vert_data += key->grid_area; } - glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); + + GPU_buffer_unlock(buffers->vert_buf, GPU_BINDING_ARRAY); } else { - glDeleteBuffersARB(1, &buffers->vert_buf); - buffers->vert_buf = 0; + GPU_buffer_free(buffers->vert_buf); + buffers->vert_buf = NULL; } - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); } buffers->grids = grids; @@ -1972,14 +1529,11 @@ void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, CCGElem **grids, type_ *tri_data; \ int offset = 0; \ int i, j, k; \ - \ - glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, \ - sizeof(type_) * (tot_quad_) * 6, NULL, \ - GL_STATIC_DRAW_ARB); \ + buffer_ = GPU_buffer_alloc(sizeof(type_) * (tot_quad_) * 6, \ + false); \ \ /* Fill the buffer */ \ - tri_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, \ - GL_WRITE_ONLY_ARB); \ + tri_data = GPU_buffer_lock(buffer_, GPU_BINDING_INDEX); \ if (tri_data) { \ for (i = 0; i < totgrid; ++i) { \ BLI_bitmap *gh = NULL; \ @@ -2006,69 +1560,77 @@ void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, CCGElem **grids, \ offset += gridsize * gridsize; \ } \ - glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB); \ + GPU_buffer_unlock(buffer_, GPU_BINDING_INDEX); \ } \ else { \ - glDeleteBuffersARB(1, &(buffer_)); \ - (buffer_) = 0; \ + GPU_buffer_free(buffer_); \ + (buffer_) = NULL; \ } \ } (void)0 /* end FILL_QUAD_BUFFER */ -static GLuint gpu_get_grid_buffer(int gridsize, GLenum *index_type, unsigned *totquad) +static GPUBuffer *gpu_get_grid_buffer(int gridsize, GLenum *index_type, unsigned *totquad) { - static int prev_gridsize = -1; - static GLenum prev_index_type = 0; - static GLuint buffer = 0; - static unsigned prev_totquad; - /* used in the FILL_QUAD_BUFFER macro */ BLI_bitmap * const *grid_hidden = NULL; const int *grid_indices = NULL; int totgrid = 1; - /* VBO is disabled; delete the previous buffer (if it exists) and - * return an invalid handle */ - if (!gpu_vbo_enabled()) { - if (buffer) - glDeleteBuffersARB(1, &buffer); - return 0; - } - /* VBO is already built */ - if (buffer && prev_gridsize == gridsize) { - *index_type = prev_index_type; - *totquad = prev_totquad; - return buffer; + if (mres_glob_buffer && mres_prev_gridsize == gridsize) { + *index_type = mres_prev_index_type; + *totquad = mres_prev_totquad; + return mres_glob_buffer; + } + /* we can't reuse old, delete the existing buffer */ + else if (mres_glob_buffer) { + GPU_buffer_free(mres_glob_buffer); } /* Build new VBO */ - glGenBuffersARB(1, &buffer); - if (buffer) { - *totquad = (gridsize - 1) * (gridsize - 1); - - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffer); + *totquad = (gridsize - 1) * (gridsize - 1); - if (gridsize * gridsize < USHRT_MAX) { - *index_type = GL_UNSIGNED_SHORT; - FILL_QUAD_BUFFER(unsigned short, *totquad, buffer); - } - else { - *index_type = GL_UNSIGNED_INT; - FILL_QUAD_BUFFER(unsigned int, *totquad, buffer); - } - - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + if (gridsize * gridsize < USHRT_MAX) { + *index_type = GL_UNSIGNED_SHORT; + FILL_QUAD_BUFFER(unsigned short, *totquad, mres_glob_buffer); } - - prev_gridsize = gridsize; - prev_index_type = *index_type; - prev_totquad = *totquad; - return buffer; -} + else { + *index_type = GL_UNSIGNED_INT; + FILL_QUAD_BUFFER(unsigned int, *totquad, mres_glob_buffer); + } + + mres_prev_gridsize = gridsize; + mres_prev_index_type = *index_type; + mres_prev_totquad = *totquad; + return mres_glob_buffer; +} + +#define FILL_FAST_BUFFER(type_) \ +{ \ + type_ *buffer; \ + buffers->index_buf_fast = GPU_buffer_alloc(sizeof(type_) * 6 * totgrid, false); \ + buffer = GPU_buffer_lock(buffers->index_buf_fast, GPU_BINDING_INDEX); \ + if (buffer) { \ + int i; \ + for (i = 0; i < totgrid; i++) { \ + int currentquad = i * 6; \ + buffer[currentquad] = i * gridsize * gridsize; \ + buffer[currentquad + 1] = i * gridsize * gridsize + gridsize - 1; \ + buffer[currentquad + 2] = (i + 1) * gridsize * gridsize - gridsize; \ + buffer[currentquad + 3] = (i + 1) * gridsize * gridsize - 1; \ + buffer[currentquad + 4] = i * gridsize * gridsize + gridsize - 1; \ + buffer[currentquad + 5] = (i + 1) * gridsize * gridsize - gridsize; \ + } \ + GPU_buffer_unlock(buffers->index_buf_fast, GPU_BINDING_INDEX); \ + } \ + else { \ + GPU_buffer_free(buffers->index_buf_fast); \ + buffers->index_buf_fast = NULL; \ + } \ +} (void)0 GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(int *grid_indices, int totgrid, - BLI_bitmap **grid_hidden, int gridsize) + BLI_bitmap **grid_hidden, int gridsize, const CCGKey *key) { GPU_PBVH_Buffers *buffers; int totquad; @@ -2088,28 +1650,28 @@ GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(int *grid_indices, int totgrid, if (totquad == 0) return buffers; + /* create and fill indices of the fast buffer too */ + if (totgrid * gridsize * gridsize < USHRT_MAX) { + FILL_FAST_BUFFER(unsigned short); + } + else { + FILL_FAST_BUFFER(unsigned int); + } + if (totquad == fully_visible_totquad) { buffers->index_buf = gpu_get_grid_buffer(gridsize, &buffers->index_type, &buffers->tot_quad); buffers->has_hidden = 0; } - else if (GLEW_ARB_vertex_buffer_object && !(U.gameflags & USER_DISABLE_VBO)) { - /* Build new VBO */ - glGenBuffersARB(1, &buffers->index_buf); - if (buffers->index_buf) { - buffers->tot_quad = totquad; - - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf); - - if (totgrid * gridsize * gridsize < USHRT_MAX) { - buffers->index_type = GL_UNSIGNED_SHORT; - FILL_QUAD_BUFFER(unsigned short, totquad, buffers->index_buf); - } - else { - buffers->index_type = GL_UNSIGNED_INT; - FILL_QUAD_BUFFER(unsigned int, totquad, buffers->index_buf); - } + else { + buffers->tot_quad = totquad; - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + if (totgrid * gridsize * gridsize < USHRT_MAX) { + buffers->index_type = GL_UNSIGNED_SHORT; + FILL_QUAD_BUFFER(unsigned short, totquad, buffers->index_buf); + } + else { + buffers->index_type = GL_UNSIGNED_INT; + FILL_QUAD_BUFFER(unsigned int, totquad, buffers->index_buf); } buffers->has_hidden = 1; @@ -2117,7 +1679,7 @@ GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(int *grid_indices, int totgrid, /* Build coord/normal VBO */ if (buffers->index_buf) - glGenBuffersARB(1, &buffers->vert_buf); + buffers->vert_buf = GPU_buffer_alloc(sizeof(VertexBufferFormat) * totgrid * key->grid_area, false); return buffers; } @@ -2216,9 +1778,6 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers, buffers->show_diffuse_color = show_diffuse_color; buffers->use_matcaps = GPU_material_use_matcaps_get(); - if (!buffers->vert_buf || (buffers->smooth && !buffers->index_buf)) - return; - /* Count visible triangles */ tottri = gpu_bmesh_face_visible_count(bm_faces); @@ -2248,13 +1807,12 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers, copy_v4_v4(buffers->diffuse_color, diffuse_color); /* Initialize vertex buffer */ - glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf); - glBufferDataARB(GL_ARRAY_BUFFER_ARB, - sizeof(VertexBufferFormat) * totvert, - NULL, GL_STATIC_DRAW_ARB); + if (buffers->vert_buf) + GPU_buffer_free(buffers->vert_buf); + buffers->vert_buf = GPU_buffer_alloc(sizeof(VertexBufferFormat) * totvert, false); /* Fill vertex buffer */ - vert_data = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + vert_data = GPU_buffer_lock(buffers->vert_buf, GPU_BINDING_ARRAY); if (vert_data) { int v_index = 0; @@ -2314,15 +1872,15 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers, buffers->tot_tri = tottri; } - glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); + GPU_buffer_unlock(buffers->vert_buf, GPU_BINDING_ARRAY); /* gpu_bmesh_vert_to_buffer_copy sets dirty index values */ bm->elem_index_dirty |= BM_VERT; } else { /* Memory map failed */ - glDeleteBuffersARB(1, &buffers->vert_buf); - buffers->vert_buf = 0; + GPU_buffer_free(buffers->vert_buf); + buffers->vert_buf = NULL; return; } @@ -2330,15 +1888,14 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers, const int use_short = (maxvert < USHRT_MAX); /* Initialize triangle index buffer */ - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf); - glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, - (use_short ? - sizeof(unsigned short) : - sizeof(unsigned int)) * 3 * tottri, - NULL, GL_STATIC_DRAW_ARB); + if (buffers->index_buf) + GPU_buffer_free(buffers->index_buf); + buffers->index_buf = GPU_buffer_alloc((use_short ? + sizeof(unsigned short) : + sizeof(unsigned int)) * 3 * tottri, false); /* Fill triangle index buffer */ - tri_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + tri_data = GPU_buffer_lock(buffers->index_buf, GPU_BINDING_INDEX); if (tri_data) { GSetIterator gs_iter; @@ -2368,7 +1925,7 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers, } } - glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB); + GPU_buffer_unlock(buffers->index_buf, GPU_BINDING_INDEX); buffers->tot_tri = tottri; buffers->index_type = (use_short ? @@ -2377,10 +1934,13 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers, } else { /* Memory map failed */ - glDeleteBuffersARB(1, &buffers->index_buf); - buffers->index_buf = 0; + GPU_buffer_free(buffers->index_buf); + buffers->index_buf = NULL; } } + else if (buffers->index_buf) { + GPU_buffer_free(buffers->index_buf); + } } GPU_PBVH_Buffers *GPU_build_bmesh_pbvh_buffers(int smooth_shading) @@ -2388,9 +1948,6 @@ GPU_PBVH_Buffers *GPU_build_bmesh_pbvh_buffers(int smooth_shading) GPU_PBVH_Buffers *buffers; buffers = MEM_callocN(sizeof(GPU_PBVH_Buffers), "GPU_Buffers"); - if (smooth_shading) - glGenBuffersARB(1, &buffers->index_buf); - glGenBuffersARB(1, &buffers->vert_buf); buffers->use_bmesh = true; buffers->smooth = smooth_shading; buffers->show_diffuse_color = false; @@ -2399,217 +1956,17 @@ GPU_PBVH_Buffers *GPU_build_bmesh_pbvh_buffers(int smooth_shading) return buffers; } -static void gpu_draw_buffers_legacy_mesh(GPU_PBVH_Buffers *buffers) -{ - const MVert *mvert = buffers->mvert; - int i, j; - const int has_mask = (buffers->vmask != NULL); - const MFace *face = &buffers->mface[buffers->face_indices[0]]; - float diffuse_color[4] = {0.8f, 0.8f, 0.8f, 1.0f}; - - if (buffers->use_matcaps) - diffuse_color[0] = diffuse_color[1] = diffuse_color[2] = 1.0; - else if (buffers->show_diffuse_color) - GPU_material_diffuse_get(face->mat_nr + 1, diffuse_color); - - if (has_mask) { - gpu_colors_enable(VBO_DISABLED); - } - - for (i = 0; i < buffers->totface; ++i) { - MFace *f = buffers->mface + buffers->face_indices[i]; - int S = f->v4 ? 4 : 3; - unsigned int *fv = &f->v1; - - if (paint_is_face_hidden(f, buffers->mvert)) - continue; - - glBegin((f->v4) ? GL_QUADS : GL_TRIANGLES); - - if (buffers->smooth) { - for (j = 0; j < S; j++) { - if (has_mask) { - gpu_color_from_mask_set(buffers->vmask[fv[j]], diffuse_color); - } - glNormal3sv(mvert[fv[j]].no); - glVertex3fv(mvert[fv[j]].co); - } - } - else { - float fno[3]; - - /* calculate face normal */ - if (f->v4) { - normal_quad_v3(fno, mvert[fv[0]].co, mvert[fv[1]].co, - mvert[fv[2]].co, mvert[fv[3]].co); - } - else - normal_tri_v3(fno, mvert[fv[0]].co, mvert[fv[1]].co, mvert[fv[2]].co); - glNormal3fv(fno); - - if (has_mask) { - float fmask; - - /* calculate face mask color */ - fmask = (buffers->vmask[fv[0]] + - buffers->vmask[fv[1]] + - buffers->vmask[fv[2]]); - if (f->v4) - fmask = (fmask + buffers->vmask[fv[3]]) * 0.25f; - else - fmask /= 3.0f; - gpu_color_from_mask_set(fmask, diffuse_color); - } - - for (j = 0; j < S; j++) - glVertex3fv(mvert[fv[j]].co); - } - - glEnd(); - } - - if (has_mask) { - gpu_colors_disable(VBO_DISABLED); - } -} - -static void gpu_draw_buffers_legacy_grids(GPU_PBVH_Buffers *buffers) -{ - const CCGKey *key = &buffers->gridkey; - int i, j, x, y, gridsize = buffers->gridkey.grid_size; - const int has_mask = key->has_mask; - const DMFlagMat *flags = &buffers->grid_flag_mats[buffers->grid_indices[0]]; - float diffuse_color[4] = {0.8f, 0.8f, 0.8f, 1.0f}; - - if (buffers->use_matcaps) - diffuse_color[0] = diffuse_color[1] = diffuse_color[2] = 1.0; - else if (buffers->show_diffuse_color) - GPU_material_diffuse_get(flags->mat_nr + 1, diffuse_color); - - if (has_mask) { - gpu_colors_enable(VBO_DISABLED); - } - - for (i = 0; i < buffers->totgrid; ++i) { - int g = buffers->grid_indices[i]; - CCGElem *grid = buffers->grids[g]; - BLI_bitmap *gh = buffers->grid_hidden[g]; - - /* TODO: could use strips with hiding as well */ - - if (gh) { - glBegin(GL_QUADS); - - for (y = 0; y < gridsize - 1; y++) { - for (x = 0; x < gridsize - 1; x++) { - CCGElem *e[4] = { - CCG_grid_elem(key, grid, x + 1, y + 1), - CCG_grid_elem(key, grid, x + 1, y), - CCG_grid_elem(key, grid, x, y), - CCG_grid_elem(key, grid, x, y + 1) - }; - - /* skip face if any of its corners are hidden */ - if (paint_is_grid_face_hidden(gh, gridsize, x, y)) - continue; - - if (buffers->smooth) { - for (j = 0; j < 4; j++) { - if (has_mask) { - gpu_color_from_mask_set(*CCG_elem_mask(key, e[j]), diffuse_color); - } - glNormal3fv(CCG_elem_no(key, e[j])); - glVertex3fv(CCG_elem_co(key, e[j])); - } - } - else { - float fno[3]; - normal_quad_v3(fno, - CCG_elem_co(key, e[0]), - CCG_elem_co(key, e[1]), - CCG_elem_co(key, e[2]), - CCG_elem_co(key, e[3])); - glNormal3fv(fno); - - if (has_mask) { - gpu_color_from_mask_quad_set(key, e[0], e[1], e[2], e[3], diffuse_color); - } - - for (j = 0; j < 4; j++) - glVertex3fv(CCG_elem_co(key, e[j])); - } - } - } - - glEnd(); - } - else if (buffers->smooth) { - for (y = 0; y < gridsize - 1; y++) { - glBegin(GL_QUAD_STRIP); - for (x = 0; x < gridsize; x++) { - CCGElem *a = CCG_grid_elem(key, grid, x, y); - CCGElem *b = CCG_grid_elem(key, grid, x, y + 1); - - if (has_mask) { - gpu_color_from_mask_set(*CCG_elem_mask(key, a), diffuse_color); - } - glNormal3fv(CCG_elem_no(key, a)); - glVertex3fv(CCG_elem_co(key, a)); - if (has_mask) { - gpu_color_from_mask_set(*CCG_elem_mask(key, b), diffuse_color); - } - glNormal3fv(CCG_elem_no(key, b)); - glVertex3fv(CCG_elem_co(key, b)); - } - glEnd(); - } - } - else { - for (y = 0; y < gridsize - 1; y++) { - glBegin(GL_QUAD_STRIP); - for (x = 0; x < gridsize; x++) { - CCGElem *a = CCG_grid_elem(key, grid, x, y); - CCGElem *b = CCG_grid_elem(key, grid, x, y + 1); - - if (x > 0) { - CCGElem *c = CCG_grid_elem(key, grid, x - 1, y); - CCGElem *d = CCG_grid_elem(key, grid, x - 1, y + 1); - - float fno[3]; - normal_quad_v3(fno, - CCG_elem_co(key, d), - CCG_elem_co(key, b), - CCG_elem_co(key, a), - CCG_elem_co(key, c)); - glNormal3fv(fno); - - if (has_mask) { - gpu_color_from_mask_quad_set(key, a, b, c, d, diffuse_color); - } - } - - glVertex3fv(CCG_elem_co(key, a)); - glVertex3fv(CCG_elem_co(key, b)); - } - glEnd(); - } - } - } - - if (has_mask) { - gpu_colors_disable(VBO_DISABLED); - } -} - void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial, - bool wireframe) + bool wireframe, bool fast) { + bool do_fast = fast && buffers->index_buf_fast; /* sets material from the first face, to solve properly face would need to * be sorted in buckets by materials */ if (setMaterial) { - if (buffers->totface) { - const MFace *f = &buffers->mface[buffers->face_indices[0]]; - if (!setMaterial(f->mat_nr + 1, NULL)) + if (buffers->face_indices_len) { + const MLoopTri *lt = &buffers->looptri[buffers->face_indices[0]]; + const MPoly *mp = &buffers->mpoly[lt->poly]; + if (!setMaterial(mp->mat_nr + 1, NULL)) return; } else if (buffers->totgrid) { @@ -2623,25 +1980,38 @@ void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial, } } - glShadeModel((buffers->smooth || buffers->totface) ? GL_SMOOTH : GL_FLAT); + glShadeModel((buffers->smooth || buffers->face_indices_len) ? GL_SMOOTH : GL_FLAT); if (buffers->vert_buf) { + char *base = NULL; + char *index_base = NULL; glEnableClientState(GL_VERTEX_ARRAY); if (!wireframe) { glEnableClientState(GL_NORMAL_ARRAY); gpu_colors_enable(VBO_ENABLED); } - glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf); + GPU_buffer_bind(buffers->vert_buf, GPU_BINDING_ARRAY); - if (buffers->index_buf) - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf); + if (!buffers->vert_buf->use_vbo) + base = (char *)buffers->vert_buf->pointer; + + if (do_fast) { + GPU_buffer_bind(buffers->index_buf_fast, GPU_BINDING_INDEX); + if (!buffers->index_buf_fast->use_vbo) + index_base = buffers->index_buf_fast->pointer; + } + else if (buffers->index_buf) { + GPU_buffer_bind(buffers->index_buf, GPU_BINDING_INDEX); + if (!buffers->index_buf->use_vbo) + index_base = buffers->index_buf->pointer; + } if (wireframe) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); if (buffers->tot_quad) { - const char *offset = 0; + const char *offset = base; int i, last = buffers->has_hidden ? 1 : buffers->totgrid; for (i = 0; i < last; i++) { glVertexPointer(3, GL_FLOAT, sizeof(VertexBufferFormat), @@ -2651,7 +2021,10 @@ void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial, glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VertexBufferFormat), offset + offsetof(VertexBufferFormat, color)); - glDrawElements(GL_TRIANGLES, buffers->tot_quad * 6, buffers->index_type, 0); + if (do_fast) + glDrawElements(GL_TRIANGLES, buffers->totgrid * 6, buffers->index_type, index_base); + else + glDrawElements(GL_TRIANGLES, buffers->tot_quad * 6, buffers->index_type, index_base); offset += buffers->gridkey.grid_area * sizeof(VertexBufferFormat); } @@ -2660,14 +2033,14 @@ void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial, int totelem = buffers->tot_tri * 3; glVertexPointer(3, GL_FLOAT, sizeof(VertexBufferFormat), - (void *)offsetof(VertexBufferFormat, co)); + (void *)(base + offsetof(VertexBufferFormat, co))); glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat), - (void *)offsetof(VertexBufferFormat, no)); + (void *)(base + offsetof(VertexBufferFormat, no))); glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VertexBufferFormat), - (void *)offsetof(VertexBufferFormat, color)); + (void *)(base + offsetof(VertexBufferFormat, color))); if (buffers->index_buf) - glDrawElements(GL_TRIANGLES, totelem, buffers->index_type, 0); + glDrawElements(GL_TRIANGLES, totelem, buffers->index_type, index_base); else glDrawArrays(GL_TRIANGLES, 0, totelem); } @@ -2675,9 +2048,9 @@ void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial, if (wireframe) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - if (buffers->index_buf) - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + GPU_buffer_unbind(buffers->vert_buf, GPU_BINDING_ARRAY); + if (buffers->index_buf || do_fast) + GPU_buffer_unbind(do_fast ? buffers->index_buf_fast : buffers->index_buf, GPU_BINDING_INDEX); glDisableClientState(GL_VERTEX_ARRAY); if (!wireframe) { @@ -2685,13 +2058,6 @@ void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial, gpu_colors_disable(VBO_ENABLED); } } - /* fallbacks if we are out of memory or VBO is disabled */ - else if (buffers->totface) { - gpu_draw_buffers_legacy_mesh(buffers); - } - else if (buffers->totgrid) { - gpu_draw_buffers_legacy_grids(buffers); - } } bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, GSet *bm_faces, bool show_diffuse_color) @@ -2708,10 +2074,11 @@ bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, GSet *bm_faces, if ((buffers->show_diffuse_color == false) || use_matcaps) return false; - if (buffers->mface) { - MFace *f = buffers->mface + buffers->face_indices[0]; + if (buffers->looptri) { + const MLoopTri *lt = &buffers->looptri[buffers->face_indices[0]]; + const MPoly *mp = &buffers->mpoly[lt->poly]; - GPU_material_diffuse_get(f->mat_nr + 1, diffuse_color); + GPU_material_diffuse_get(mp->mat_nr + 1, diffuse_color); } else if (buffers->use_bmesh) { /* due to dynamic nature of dyntopo, only get first material */ @@ -2736,50 +2103,15 @@ bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, GSet *bm_faces, return !equals_v3v3(diffuse_color, buffers->diffuse_color); } -/* release a GPU_PBVH_Buffers id; - * - * Thread-unsafe version for internal usage only. - */ -static void gpu_pbvh_buffer_free_intern(GLuint id) -{ - GPUBufferPool *pool; - - /* zero id is vertex buffers off */ - if (!id) - return; - - pool = gpu_get_global_buffer_pool(); - - /* free the buffers immediately if we are on main thread */ - if (BLI_thread_is_main()) { - glDeleteBuffersARB(1, &id); - - if (pool->totpbvhbufids > 0) { - glDeleteBuffersARB(pool->totpbvhbufids, pool->pbvhbufids); - pool->totpbvhbufids = 0; - } - return; - } - /* outside of main thread, can't safely delete the - * buffer, so increase pool size */ - if (pool->maxpbvhsize == pool->totpbvhbufids) { - pool->maxpbvhsize += MAX_FREE_GPU_BUFF_IDS; - pool->pbvhbufids = MEM_reallocN(pool->pbvhbufids, - sizeof(*pool->pbvhbufids) * pool->maxpbvhsize); - } - - /* insert the buffer into the beginning of the pool */ - pool->pbvhbufids[pool->totpbvhbufids++] = id; -} - - void GPU_free_pbvh_buffers(GPU_PBVH_Buffers *buffers) { if (buffers) { if (buffers->vert_buf) - gpu_pbvh_buffer_free_intern(buffers->vert_buf); + GPU_buffer_free(buffers->vert_buf); if (buffers->index_buf && (buffers->tot_tri || buffers->has_hidden)) - gpu_pbvh_buffer_free_intern(buffers->index_buf); + GPU_buffer_free(buffers->index_buf); + if (buffers->index_buf_fast) + GPU_buffer_free(buffers->index_buf_fast); MEM_freeN(buffers); } @@ -2838,7 +2170,6 @@ void GPU_init_draw_pbvh_BB(void) glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); glEnable(GL_BLEND); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); } void GPU_end_draw_pbvh_BB(void) |