Multires sculpting drawing optimization:

Use OpenGL 3.2 extension ARB_draw_elements_base_vertex, which allows us
to add offset in index buffer indices automatically. This should reduce
the number of draw calls significantly.

We may have some errors on the Mac with VBO setting off.
OSX OpenGL extensions don't play well with vertex arrays.
Will test that more later.

We might also use a full element buffer here, like we do when hiding
some quads, but this approach keeps the memory savings intended
originally.
This commit is contained in:
Antonis Ryakiotakis 2015-08-03 19:08:50 +02:00
parent 7667ad2d4e
commit 2411027a79
1 changed files with 46 additions and 8 deletions

View File

@ -1121,6 +1121,9 @@ struct GPU_PBVH_Buffers {
GPUBuffer *vert_buf, *index_buf, *index_buf_fast;
GLenum index_type;
int *baseelemarray;
void **baseindex;
/* mesh pointers in case buffer allocation fails */
const MPoly *mpoly;
const MLoop *mloop;
@ -1681,6 +1684,18 @@ GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(int *grid_indices, int totgrid,
if (buffers->index_buf)
buffers->vert_buf = GPU_buffer_alloc(sizeof(VertexBufferFormat) * totgrid * key->grid_area, false);
if (GLEW_ARB_draw_elements_base_vertex) {
int i;
buffers->baseelemarray = MEM_mallocN(sizeof(int) * totgrid * 2, "GPU_PBVH_Buffers.baseelemarray");
buffers->baseindex = MEM_mallocN(sizeof(void *) * totgrid, "GPU_PBVH_Buffers.baseindex");
for (i = 0; i < totgrid; i++) {
buffers->baseelemarray[i] = buffers->tot_quad * 6;
buffers->baseelemarray[i + totgrid] = i * key->grid_area;
buffers->baseindex[i] = buffers->index_buf && !buffers->index_buf->use_vbo ?
buffers->index_buf->pointer : NULL;
}
}
return buffers;
}
@ -2012,21 +2027,40 @@ void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial,
if (buffers->tot_quad) {
const char *offset = base;
int i, last = (buffers->has_hidden || do_fast) ? 1 : buffers->totgrid;
for (i = 0; i < last; i++) {
const bool drawall = !(buffers->has_hidden || do_fast);
if (GLEW_ARB_draw_elements_base_vertex && drawall) {
glVertexPointer(3, GL_FLOAT, sizeof(VertexBufferFormat),
offset + offsetof(VertexBufferFormat, co));
glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat),
offset + offsetof(VertexBufferFormat, no));
glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VertexBufferFormat),
offset + offsetof(VertexBufferFormat, color));
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);
glMultiDrawElementsBaseVertex(GL_TRIANGLES, buffers->baseelemarray, buffers->index_type,
(const void * const *)buffers->baseindex,
buffers->totgrid, &buffers->baseelemarray[buffers->totgrid]);
}
else {
int i, last = drawall ? buffers->totgrid : 1;
/* we could optimize this to one draw call, but it would need more memory */
for (i = 0; i < last; i++) {
glVertexPointer(3, GL_FLOAT, sizeof(VertexBufferFormat),
offset + offsetof(VertexBufferFormat, co));
glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat),
offset + offsetof(VertexBufferFormat, no));
glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VertexBufferFormat),
offset + offsetof(VertexBufferFormat, color));
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);
}
}
}
else if (buffers->tot_tri) {
@ -2112,6 +2146,10 @@ void GPU_free_pbvh_buffers(GPU_PBVH_Buffers *buffers)
GPU_buffer_free(buffers->index_buf);
if (buffers->index_buf_fast)
GPU_buffer_free(buffers->index_buf_fast);
if (buffers->baseelemarray)
MEM_freeN(buffers->baseelemarray);
if (buffers->baseindex)
MEM_freeN(buffers->baseindex);
MEM_freeN(buffers);
}