[Bf-blender-cvs] [a25856f2a80] blender2.8: GPUShader/DRW: Add Transform Feedback support.

Clément Foucault noreply at git.blender.org
Wed May 16 16:58:44 CEST 2018


Commit: a25856f2a802dae4e2c4c01e9b74d8c8a1769933
Author: Clément Foucault
Date:   Wed May 16 12:47:15 2018 +0200
Branches: blender2.8
https://developer.blender.org/rBa25856f2a802dae4e2c4c01e9b74d8c8a1769933

GPUShader/DRW: Add Transform Feedback support.

This is a usefull feature that can be used to do a lot of precomputation on
the GPU instead of the CPU.

Implementation is simple and only covers the most usefull case.

How to use:
- Create shader with transform feedback.
- Create a pass with DRW_STATE_TRANS_FEEDBACK.
- Create a target Gwn_VertBuf (make sure it's big enough).
- Create a shading group with DRW_shgroup_transform_feedback_create().
- Add your draw calls to the shading group.
- Render your pass normaly.

Current limitation:
- Only one output buffer.
- Cannot pause/resume tfb rendering to interleave with normal drawcalls.
- Cannot get the number of verts drawn.

===================================================================

M	source/blender/draw/intern/DRW_render.h
M	source/blender/draw/intern/draw_manager.h
M	source/blender/draw/intern/draw_manager_data.c
M	source/blender/draw/intern/draw_manager_exec.c
M	source/blender/draw/intern/draw_manager_shader.c
M	source/blender/gpu/GPU_shader.h
M	source/blender/gpu/intern/gpu_shader.c
M	source/blender/gpu/intern/gpu_shader_private.h

===================================================================

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_

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list