diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2017-01-31 04:12:24 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2017-01-31 13:44:40 +0300 |
commit | c4c3951c4f294a4c543a81cb6b06a68fda8e970a (patch) | |
tree | 91342d8534810f0272ec27fe18e0c8f616dbe5ea | |
parent | 75d6a30cc2fc25c43f77259822853161d19418ac (diff) |
Initial implementation of instancing
-rw-r--r-- | source/blender/draw/intern/DRW_render.h | 1 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_manager.c | 101 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_mode_pass.c | 15 | ||||
-rw-r--r-- | source/blender/gpu/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/gpu/GPU_shader.h | 1 | ||||
-rw-r--r-- | source/blender/gpu/gawain/batch.c | 51 | ||||
-rw-r--r-- | source/blender/gpu/gawain/batch.h | 1 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_shader.c | 2 | ||||
-rw-r--r-- | source/blender/gpu/shaders/gpu_shader_3D_instance_vert.glsl | 10 |
9 files changed, 167 insertions, 16 deletions
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 6d26f7b8b7e..8bd3cabf8de 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -160,6 +160,7 @@ typedef enum { /* Used by DRWShadingGroup.dyntype */ #define DRW_DYN_POINTS 1 #define DRW_DYN_LINES 2 +#define DRW_DYN_INSTANCE 3 DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass); void DRW_shgroup_free(struct DRWShadingGroup *shgroup); diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 45c8b911df1..9fc020885da 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -90,6 +90,7 @@ struct DRWInterface { int modelview; int projection; int modelviewprojection; + int viewprojection; int normal; int eye; }; @@ -114,6 +115,8 @@ struct DRWShadingGroup { int state; /* State changes for this batch only */ short dyntype; /* Dynamic Batch type, 0 is normal */ Batch *dyngeom; /* Dynamic batch */ + GLuint instance_vbo; /* Dynamic batch VBO storing Model Matrices */ + int instance_count; /* Dynamic batch Number of instance to render */ }; /* Render State */ @@ -277,6 +280,7 @@ static DRWInterface *DRW_interface_create(GPUShader *shader) interface->modelview = GPU_shader_get_uniform(shader, "ModelViewMatrix"); interface->projection = GPU_shader_get_uniform(shader, "ProjectionMatrix"); + interface->viewprojection = GPU_shader_get_uniform(shader, "ViewProjectionMatrix"); interface->modelviewprojection = GPU_shader_get_uniform(shader, "ModelViewProjectionMatrix"); interface->normal = GPU_shader_get_uniform(shader, "NormalMatrix"); interface->eye = GPU_shader_get_uniform(shader, "eye"); @@ -440,16 +444,13 @@ void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const DRW_interface_uniform(shgroup, name, DRW_UNIFORM_MAT4, value, 16, 1, 0); } -static void shgroup_dynamic_batch_from_calls(DRWShadingGroup *shgroup) +/* Creates OGL primitives based on DRWCall.obmat position list */ +static void shgroup_dynamic_batch_primitives(DRWShadingGroup *shgroup) { int i = 0; int nbr = BLI_listbase_count(&shgroup->calls); GLenum type; -#ifdef WITH_VIEWPORT_CACHE_TEST - if (shgroup->dyngeom) return; -#endif - if (nbr == 0) { if (shgroup->dyngeom) { Batch_discard(shgroup->dyngeom); @@ -491,6 +492,67 @@ static void shgroup_dynamic_batch_from_calls(DRWShadingGroup *shgroup) MEM_freeN(data); } +static void shgroup_dynamic_batch_instance(DRWShadingGroup *shgroup) +{ + int i = 0; + int nbr = BLI_listbase_count(&shgroup->calls); + + shgroup->instance_count = nbr; + + if (nbr == 0) { + if (shgroup->instance_vbo) { + glDeleteBuffers(1, &shgroup->instance_vbo); + shgroup->instance_vbo = 0; + } + return; + } + + /* Gather Data */ + float *data = MEM_mallocN(sizeof(float) * 4 * 4 * nbr , "Instance Model Matrix"); + + for (DRWCall *call = shgroup->calls.first; call; call = call->next, i++) { + copy_m4_m4(&data[i*16], call->obmat); + } + + /* Upload Data */ + static VertexFormat format = { 0 }; + static unsigned mat_id; + if (format.attrib_ct == 0) { + mat_id = add_attrib(&format, "InstanceModelMatrix", GL_FLOAT, 4, KEEP_FLOAT); + } + + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, nbr); + + fillAttrib(vbo, mat_id, data); + + /* TODO poke mike to add this to gawain */ + if (shgroup->instance_vbo) { + glDeleteBuffers(1, &shgroup->instance_vbo); + shgroup->instance_vbo = 0; + } + + glGenBuffers(1, &shgroup->instance_vbo); + glBindBuffer(GL_ARRAY_BUFFER, shgroup->instance_vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 4 * 4 * nbr, data, GL_STATIC_DRAW); + + MEM_freeN(data); +} + +static void shgroup_dynamic_batch_from_calls(DRWShadingGroup *shgroup) +{ +#ifdef WITH_VIEWPORT_CACHE_TEST + if (shgroup->dyngeom) return; +#endif + + if (shgroup->dyntype == DRW_DYN_INSTANCE) { + shgroup_dynamic_batch_instance(shgroup); + } + else { + shgroup_dynamic_batch_primitives(shgroup); + } +} + /* ***************************************** PASSES ******************************************/ DRWPass *DRW_pass_create(const char *name, DRWState state) @@ -593,7 +655,8 @@ typedef struct DRWBoundTexture { GPUTexture *tex; } DRWBoundTexture; -static void draw_geometry(DRWShadingGroup *shgroup, DRWInterface *interface, Batch *geom, const float (*obmat)[4]) +static void draw_geometry(DRWShadingGroup *shgroup, DRWInterface *interface, Batch *geom, + unsigned int instance_vbo, int instance_count, const float (*obmat)[4]) { RegionView3D *rv3d = CTX_wm_region_view3d(DST.context); @@ -629,6 +692,9 @@ static void draw_geometry(DRWShadingGroup *shgroup, DRWInterface *interface, Bat if (interface->modelviewprojection != -1) { GPU_shader_uniform_vector(shgroup->shader, interface->modelviewprojection, 16, 1, (float *)mvp); } + if (interface->viewprojection != -1) { + GPU_shader_uniform_vector(shgroup->shader, interface->viewprojection, 16, 1, (float *)rv3d->persmat); + } if (interface->projection != -1) { GPU_shader_uniform_vector(shgroup->shader, interface->projection, 16, 1, (float *)rv3d->winmat); } @@ -644,7 +710,12 @@ static void draw_geometry(DRWShadingGroup *shgroup, DRWInterface *interface, Bat /* step 2 : bind vertex array & draw */ Batch_set_program(geom, GPU_shader_get_program(shgroup->shader)); - Batch_draw_stupid(geom); + if (instance_vbo) { + Batch_draw_stupid_instanced(geom, instance_vbo, instance_count); + } + else { + Batch_draw_stupid(geom); + } } static void draw_shgroup(DRWShadingGroup *shgroup) @@ -714,13 +785,21 @@ static void draw_shgroup(DRWShadingGroup *shgroup) /* Replacing multiple calls with only one */ float obmat[4][4]; unit_m4(obmat); - /* Some dynamic batch can have no geom (no call to aggregate) */ - if (shgroup->dyngeom) - draw_geometry(shgroup, interface, shgroup->dyngeom, obmat); + + if (shgroup->dyntype == DRW_DYN_INSTANCE) { + DRWCall *call = shgroup->calls.first; + draw_geometry(shgroup, interface, call->geometry, shgroup->instance_vbo, shgroup->instance_count, obmat); + } + else { + /* Some dynamic batch can have no geom (no call to aggregate) */ + if (shgroup->dyngeom) { + draw_geometry(shgroup, interface, shgroup->dyngeom, 0, 1, obmat); + } + } } else { for (DRWCall *call = shgroup->calls.first; call; call = call->next) { - draw_geometry(shgroup, interface, call->geometry, call->obmat); + draw_geometry(shgroup, interface, call->geometry, 0, 1, call->obmat); } } } diff --git a/source/blender/draw/intern/draw_mode_pass.c b/source/blender/draw/intern/draw_mode_pass.c index 202921437c0..d8db13925fc 100644 --- a/source/blender/draw/intern/draw_mode_pass.c +++ b/source/blender/draw/intern/draw_mode_pass.c @@ -60,6 +60,7 @@ void DRW_pass_setup_common(DRWPass **wire_overlay, DRWPass **wire_outline, DRWPa *non_meshes = DRW_pass_create("Non Meshes Pass", state); GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR); + GPUShader *sh_inst = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR_INSTANCE); /* Solid Wires */ grp = DRW_shgroup_create(sh, *non_meshes); @@ -67,8 +68,15 @@ void DRW_pass_setup_common(DRWPass **wire_overlay, DRWPass **wire_outline, DRWPa /* Points */ grp = DRW_shgroup_create(sh, *non_meshes); + /* Empties */ + static float frontcol[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + grp = DRW_shgroup_create(sh_inst, *non_meshes); + DRW_shgroup_uniform_vec4(grp, "color", frontcol, 1); + DRW_shgroup_dyntype_set(grp, DRW_DYN_INSTANCE); + /* Stipple Wires */ grp = DRW_shgroup_create(sh, *non_meshes); + DRW_shgroup_uniform_vec4(grp, "color", frontcol, 1); DRW_shgroup_state_set(grp, DRW_STATE_STIPPLE_2); grp = DRW_shgroup_create(sh, *non_meshes); @@ -214,8 +222,6 @@ void DRW_draw_lamp(DRWPass *non_meshes, Object *ob) void DRW_shgroup_non_meshes(DRWPass *non_meshes, Object *ob) { struct Batch *geom; - static float frontcol[4] = {0.0f, 0.0f, 0.0f, 1.0f}; - GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR); switch (ob->type) { case OB_LAMP: @@ -223,8 +229,7 @@ void DRW_shgroup_non_meshes(DRWPass *non_meshes, Object *ob) case OB_EMPTY: default: geom = DRW_cache_plain_axes_get(); - DRWShadingGroup *grp = DRW_pass_nth_shgroup_get(non_meshes, 0); - DRW_shgroup_uniform_vec4(grp, "color", frontcol, 1); + DRWShadingGroup *grp = DRW_pass_nth_shgroup_get(non_meshes, 2); DRW_shgroup_call_add(grp, geom, ob->obmat); break; } @@ -234,7 +239,7 @@ void DRW_shgroup_relationship_lines(DRWPass *non_meshes, Object *ob) { if (ob->parent) { struct Batch *geom = DRW_cache_single_vert_get(); - DRWShadingGroup *grp = DRW_pass_nth_shgroup_get(non_meshes, 5); + DRWShadingGroup *grp = DRW_pass_nth_shgroup_get(non_meshes, 6); DRW_shgroup_call_add(grp, geom, ob->obmat); DRW_shgroup_call_add(grp, geom, ob->parent->obmat); } diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 0f2e4360263..7aeb67a224d 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -148,6 +148,7 @@ data_to_c_simple(shaders/gpu_shader_image_depth_linear_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_image_interlace_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_image_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_instance_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_flat_color_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_smooth_color_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_smooth_color_frag.glsl SRC) diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index dcd9b0fa9c8..8cc9433c6ab 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -108,6 +108,7 @@ typedef enum GPUBuiltinShader { GPU_SHADER_2D_IMAGE_COLOR, /* for simple 3D drawing */ GPU_SHADER_3D_UNIFORM_COLOR, + GPU_SHADER_3D_UNIFORM_COLOR_INSTANCE, GPU_SHADER_3D_FLAT_COLOR, GPU_SHADER_3D_SMOOTH_COLOR, GPU_SHADER_3D_DEPTH_ONLY, diff --git a/source/blender/gpu/gawain/batch.c b/source/blender/gpu/gawain/batch.c index df7733d70dc..99c13301177 100644 --- a/source/blender/gpu/gawain/batch.c +++ b/source/blender/gpu/gawain/batch.c @@ -282,3 +282,54 @@ void Batch_draw_stupid(Batch* batch) // Batch_done_using_program(batch); glBindVertexArray(0); } + +/* clement : temp stuff */ +void Batch_draw_stupid_instanced(Batch* batch, unsigned int instance_vbo, int instance_count) +{ + if (batch->vao_id) + glBindVertexArray(batch->vao_id); + else + Batch_prime(batch); + + if (batch->program_dirty) + Batch_update_program_bindings(batch); + + const GLint loc = glGetAttribLocation(batch->program, "InstanceModelMatrix"); + +#if TRUST_NO_ONE + assert(loc != -1); +#endif + + glBindBuffer(GL_ARRAY_BUFFER, instance_vbo); + glEnableVertexAttribArray(loc); + glVertexAttribPointer(loc + 0, 4, GL_FLOAT, GL_FALSE, sizeof(float)*4*4, (GLvoid*)0); + glEnableVertexAttribArray(loc + 1); + glVertexAttribPointer(loc + 1, 4, GL_FLOAT, GL_FALSE, sizeof(float)*4*4, (GLvoid*)(sizeof(float)*4)); + glEnableVertexAttribArray(loc + 2); + glVertexAttribPointer(loc + 2, 4, GL_FLOAT, GL_FALSE, sizeof(float)*4*4, (GLvoid*)(2 * sizeof(float)*4)); + glEnableVertexAttribArray(loc + 3); + glVertexAttribPointer(loc + 3, 4, GL_FLOAT, GL_FALSE, sizeof(float)*4*4, (GLvoid*)(3 * sizeof(float)*4)); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glVertexAttribDivisor(loc + 0, 1); + glVertexAttribDivisor(loc + 1, 1); + glVertexAttribDivisor(loc + 2, 1); + glVertexAttribDivisor(loc + 3, 1); + + // Batch_use_program(batch); + + //gpuBindMatrices(batch->program); + + if (batch->elem) + { + const ElementList* el = batch->elem; + + glDrawElementsInstanced(batch->prim_type, el->index_ct, GL_UNSIGNED_INT, 0, instance_count); + } + else + glDrawArraysInstanced(batch->prim_type, 0, batch->verts->vertex_ct, instance_count); + + // Batch_done_using_program(batch); + glBindVertexArray(0); +} + diff --git a/source/blender/gpu/gawain/batch.h b/source/blender/gpu/gawain/batch.h index 3db910151d9..8b5c48cca79 100644 --- a/source/blender/gpu/gawain/batch.h +++ b/source/blender/gpu/gawain/batch.h @@ -58,6 +58,7 @@ void Batch_Uniform4fv(Batch*, const char* name, const float data[4]); void Batch_draw(Batch*); void Batch_draw_stupid(Batch* batch); +void Batch_draw_stupid_instanced(Batch* batch, unsigned int instance_vbo, int instance_count); diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index 7dcb3796f75..6370e4f7f8c 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -65,6 +65,7 @@ extern char datatoc_gpu_shader_image_modulate_alpha_frag_glsl[]; extern char datatoc_gpu_shader_image_rect_modulate_alpha_frag_glsl[]; extern char datatoc_gpu_shader_image_depth_linear_frag_glsl[]; extern char datatoc_gpu_shader_3D_vert_glsl[]; +extern char datatoc_gpu_shader_3D_instance_vert_glsl[]; extern char datatoc_gpu_shader_3D_flat_color_vert_glsl[]; extern char datatoc_gpu_shader_3D_smooth_color_vert_glsl[]; extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[]; @@ -670,6 +671,7 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) [GPU_SHADER_2D_IMAGE_COLOR] = { datatoc_gpu_shader_2D_image_vert_glsl, datatoc_gpu_shader_image_color_frag_glsl }, [GPU_SHADER_3D_UNIFORM_COLOR] = { datatoc_gpu_shader_3D_vert_glsl, datatoc_gpu_shader_uniform_color_frag_glsl }, + [GPU_SHADER_3D_UNIFORM_COLOR_INSTANCE] = { datatoc_gpu_shader_3D_instance_vert_glsl, datatoc_gpu_shader_uniform_color_frag_glsl }, [GPU_SHADER_3D_FLAT_COLOR] = { datatoc_gpu_shader_3D_flat_color_vert_glsl, datatoc_gpu_shader_flat_color_frag_glsl }, [GPU_SHADER_3D_SMOOTH_COLOR] = { datatoc_gpu_shader_3D_smooth_color_vert_glsl, diff --git a/source/blender/gpu/shaders/gpu_shader_3D_instance_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_instance_vert.glsl new file mode 100644 index 00000000000..7eb321f2996 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_instance_vert.glsl @@ -0,0 +1,10 @@ + +uniform mat4 ViewProjectionMatrix; + +in vec3 pos; +in mat4 InstanceModelMatrix; + +void main() +{ + gl_Position = ViewProjectionMatrix * InstanceModelMatrix * vec4(pos, 1.0); +} |