diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 901f009e7ed..827ac4701e5 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -47,6 +47,7 @@ #include "GPU_framebuffer.h" #include "GPU_texture.h" +#include "GPU_shader.h" #include "draw_common.h" #include "draw_cache.h" @@ -229,6 +230,9 @@ struct GPUShader *DRW_shader_create( const char *vert, const char *geom, const char *frag, const char *defines); struct GPUShader *DRW_shader_create_with_lib( const char *vert, const char *geom, const char *frag, const char *lib, const char *defines); +struct GPUShader *DRW_shader_create_with_transform_feedback( + const char *vert, const char *geom, const char *defines, + const GPUShaderTFBType prim_type, const char **varying_names, const int varying_count); struct GPUShader *DRW_shader_create_2D(const char *frag, const char *defines); struct GPUShader *DRW_shader_create_3D(const char *frag, const char *defines); struct GPUShader *DRW_shader_create_fullscreen(const char *frag, const char *defines); @@ -274,6 +278,7 @@ typedef enum { DRW_STATE_ADDITIVE_FULL = (1 << 19), /* Same as DRW_STATE_ADDITIVE but let alpha accumulate without premult. */ DRW_STATE_BLEND_PREMUL = (1 << 20), /* Use that if color is already premult by alpha. */ DRW_STATE_WIRE_SMOOTH = (1 << 21), + DRW_STATE_TRANS_FEEDBACK = (1 << 22), DRW_STATE_WRITE_STENCIL = (1 << 27), DRW_STATE_WRITE_STENCIL_SHADOW = (1 << 28), @@ -312,6 +317,7 @@ DRWShadingGroup *DRW_shgroup_instance_create( DRWShadingGroup *DRW_shgroup_point_batch_create(struct GPUShader *shader, DRWPass *pass); DRWShadingGroup *DRW_shgroup_line_batch_create(struct GPUShader *shader, DRWPass *pass); DRWShadingGroup *DRW_shgroup_empty_tri_batch_create(struct GPUShader *shader, DRWPass *pass, int size); +DRWShadingGroup *DRW_shgroup_transform_feedback_create(struct GPUShader *shader, DRWPass *pass, struct Gwn_VertBuf *tf_target); typedef void (DRWCallGenerateFn)( DRWShadingGroup *shgroup, diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h index e71da41f118..0f9a68552fe 100644 --- a/source/blender/draw/intern/draw_manager.h +++ b/source/blender/draw/intern/draw_manager.h @@ -193,6 +193,7 @@ typedef enum { DRW_SHG_TRIANGLE_BATCH, DRW_SHG_INSTANCE, DRW_SHG_INSTANCE_EXTERNAL, + DRW_SHG_FEEDBACK_TRANSFORM, } DRWShadingGroupType; struct DRWShadingGroup { @@ -206,6 +207,10 @@ struct DRWShadingGroup { struct { /* DRW_SHG_NORMAL */ DRWCall *first, *last; /* Linked list of DRWCall or DRWCallDynamic depending of type */ } calls; + struct { /* DRW_SHG_FEEDBACK_TRANSFORM */ + DRWCall *first, *last; /* Linked list of DRWCall or DRWCallDynamic depending of type */ + struct Gwn_VertBuf *tfeedback_target; /* Transform Feedback target. */ + }; struct { /* DRW_SHG_***_BATCH */ struct Gwn_Batch *batch_geom; /* Result of call batching */ struct Gwn_VertBuf *batch_vbo; diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index 306ca0c6a3c..6f4de3bb02b 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -353,7 +353,7 @@ static DRWCallState *drw_call_state_object(DRWShadingGroup *shgroup, float (*obm void DRW_shgroup_call_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, float (*obmat)[4]) { BLI_assert(geom != NULL); - BLI_assert(shgroup->type == DRW_SHG_NORMAL); + BLI_assert(ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM)); DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls); call->state = drw_call_state_create(shgroup, obmat, NULL); @@ -828,6 +828,18 @@ DRWShadingGroup *DRW_shgroup_empty_tri_batch_create(struct GPUShader *shader, DR return shgroup; } +DRWShadingGroup *DRW_shgroup_transform_feedback_create(struct GPUShader *shader, DRWPass *pass, Gwn_VertBuf *tf_target) +{ + DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass); + shgroup->type = DRW_SHG_FEEDBACK_TRANSFORM; + + drw_shgroup_init(shgroup, shader); + + shgroup->tfeedback_target = tf_target; + + return shgroup; +} + /* Specify an external batch instead of adding each attrib one by one. */ void DRW_shgroup_instance_batch(DRWShadingGroup *shgroup, struct Gwn_Batch *batch) { diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c index 033168680b8..78ac96e41b2 100644 --- a/source/blender/draw/intern/draw_manager_exec.c +++ b/source/blender/draw/intern/draw_manager_exec.c @@ -102,6 +102,21 @@ void drw_state_set(DRWState state) } } + /* Raster Discard */ + { + if (CHANGED_ANY(DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR | + DRW_STATE_WRITE_STENCIL | DRW_STATE_WRITE_STENCIL_SHADOW)) + { + if ((state & (DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR | + DRW_STATE_WRITE_STENCIL | DRW_STATE_WRITE_STENCIL_SHADOW)) != 0) { + glDisable(GL_RASTERIZER_DISCARD); + } + else { + glEnable(GL_RASTERIZER_DISCARD); + } + } + } + /* Cull */ { DRWState test; @@ -900,6 +915,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) int val; float fval; const bool shader_changed = (DST.shader != shgroup->shader); + bool use_tfeedback = false; if (shader_changed) { if (DST.shader) GPU_shader_unbind(); @@ -907,6 +923,13 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) DST.shader = shgroup->shader; } + if ((pass_state & DRW_STATE_TRANS_FEEDBACK) != 0 && + (shgroup->type == DRW_SHG_FEEDBACK_TRANSFORM)) + { + use_tfeedback = GPU_shader_transform_feedback_enable(shgroup->shader, + shgroup->tfeedback_target->vbo_id); + } + release_ubo_slots(shader_changed); release_texture_slots(shader_changed); @@ -1023,7 +1046,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) #endif /* Rendering Calls */ - if (!ELEM(shgroup->type, DRW_SHG_NORMAL)) { + if (!ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM)) { /* Replacing multiple calls with only one */ if (ELEM(shgroup->type, DRW_SHG_INSTANCE, DRW_SHG_INSTANCE_EXTERNAL)) { if (shgroup->type == DRW_SHG_INSTANCE_EXTERNAL) { @@ -1104,6 +1127,10 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) glFrontFace(DST.frontface); } + if (use_tfeedback) { + GPU_shader_transform_feedback_disable(shgroup->shader); + } + /* TODO: remove, (currently causes alpha issue with sculpt, need to investigate) */ DRW_state_reset(); } diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c index 06a579c2208..77fcb766743 100644 --- a/source/blender/draw/intern/draw_manager_shader.c +++ b/source/blender/draw/intern/draw_manager_shader.c @@ -295,6 +295,14 @@ GPUShader *DRW_shader_create_with_lib( return sh; } +GPUShader *DRW_shader_create_with_transform_feedback( + const char *vert, const char *geom, const char *defines, + const GPUShaderTFBType prim_type, const char **varying_names, const int varying_count) +{ + return GPU_shader_create_ex(vert, NULL, geom, NULL, defines, GPU_SHADER_FLAGS_NONE, + prim_type, varying_names, varying_count); +} + GPUShader *DRW_shader_create_2D(const char *frag, const char *defines) { return GPU_shader_create(datatoc_gpu_shader_2D_vert_glsl, frag, NULL, NULL, defines); diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index 2a672873d86..baaa23c2398 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -50,6 +50,13 @@ enum { GPU_SHADER_FLAGS_NEW_SHADING = (1 << 1), }; +typedef enum GPUShaderTFBType { + GPU_SHADER_TFB_NONE = 0, /* Transform feedback unsupported. */ + GPU_SHADER_TFB_POINTS = 1, + GPU_SHADER_TFB_LINES = 2, + GPU_SHADER_TFB_TRIANGLES = 3, +} GPUShaderTFBType; + GPUShader *GPU_shader_create( const char *vertexcode, const char *fragcode, @@ -62,12 +69,19 @@ GPUShader *GPU_shader_create_ex( const char *geocode, const char *libcode, const char *defines, - const int flags); + const int flags, + const GPUShaderTFBType tf_type, + const char **tf_names, + const int tf_count); void GPU_shader_free(GPUShader *shader); void GPU_shader_bind(GPUShader *shader); void GPU_shader_unbind(void); +/* Returns true if transform feedback was succesfully enabled. */ +bool GPU_shader_transform_feedback_enable(GPUShader *shader, unsigned int vbo_id); +void GPU_shader_transform_feedback_disable(GPUShader *shader); + int GPU_shader_get_program(GPUShader *shader); void *GPU_shader_get_interface(GPUShader *shader); diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index 02baa2e58cb..2068c5a6a75 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -268,7 +268,10 @@ GPUShader *GPU_shader_create(const char *vertexcode, geocode, libcode, defines, - GPU_SHADER_FLAGS_NONE); + GPU_SHADER_FLAGS_NONE, + GPU_SHADER_TFB_NONE, + NULL, + 0); } #define DEBUG_SHADER_NONE "" @@ -323,7 +326,10 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode, const char *geocode, const char *libcode, const char *defines, - const int flags) + const int flags, + const GPUShaderTFBType tf_type, + const char **tf_names, + const int tf_count) { #ifdef WITH_OPENSUBDIV bool use_opensubdiv = (flags & GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV) != 0; @@ -469,6 +475,13 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode, } #endif + if (tf_names != NULL) { + glTransformFeedbackVaryings(shader->program, tf_count, tf_names, GL_INTERLEAVED_ATTRIBS); + /* Primitive type must be setup */ + BLI_assert(tf_type != GPU_SHADER_TFB_NONE); + shader->feedback_transform_type = tf_type; + } + glLinkProgram(shader->program); glGetProgramiv(shader->program, GL_LINK_STATUS, &status); if (!status) { @@ -527,6 +540,27 @@ void GPU_shader_unbind(void) glUseProgram(0); } +bool GPU_shader_transform_feedback_enable(GPUShader *shader, unsigned int vbo_id) +{ + if (shader->feedback_transform_type == GPU_SHADER_TFB_NONE) { + return false; + } + + glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, vbo_id); + + switch (shader->feedback_transform_type) { + case GPU_SHADER_TFB_POINTS: glBeginTransformFeedback(GL_POINTS); return true; + case GPU_SHADER_TFB_LINES: glBeginTransformFeedback(GL_LINES); return true; + case GPU_SHADER_TFB_TRIANGLES: glBeginTransformFeedback(GL_TRIANGLES); return true; + default: return false; + } +} + +void GPU_shader_transform_feedback_disable(GPUShader *UNUSED(shader)) +{ + glEndTransformFeedback(); +} + void GPU_shader_free(GPUShader *shader) { BLI_assert(shader); diff --git a/source/blender/gpu/intern/gpu_shader_private.h b/source/blender/gpu/intern/gpu_shader_private.h index 67d8c6e6213..d8ec6b5d6d1 100644 --- a/source/blender/gpu/intern/gpu_shader_private.h +++ b/source/blender/gpu/intern/gpu_shader_private.h @@ -36,6 +36,8 @@ struct GPUShader { GLuint fragment; /* handle for fragment shader */ Gwn_ShaderInterface *interface; /* cached uniform & attrib interface for shader */ + + int feedback_transform_type; }; #endif /* __GPU_SHADER_PRIVATE_H__ */