[Bf-blender-cvs] [93e26cb770a] blender2.8: DRW: Fix/refactor UBO & Texture binding.

Clément Foucault noreply at git.blender.org
Fri Mar 16 08:50:35 CET 2018


Commit: 93e26cb770ab052ce06f7a1248d636a068b45edf
Author: Clément Foucault
Date:   Fri Mar 16 08:43:52 2018 +0100
Branches: blender2.8
https://developer.blender.org/rB93e26cb770ab052ce06f7a1248d636a068b45edf

DRW: Fix/refactor UBO & Texture binding.

Previous approach was not clear enough and caused problems.
UBOs were taking slots and not release them after a shading group even
if this UBO was only for this Shading Group (notably the nodetree ubo,
since we now share the same GPUShader for identical trees).

So I choose to have a better defined approach:
- Standard texture and ubo calls are assured to be valid for the shgrp
they are called from.
- (new) Persistent texture and ubo calls are assured to be valid accross
shgrps unless the shader changes.

The standards calls are still valids for the next shgrp but are not assured
to be so if this new shgrp binds a new texture.

This enables some optimisations by not adding redundant texture and ubo
binds.

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

M	source/blender/draw/intern/DRW_render.h
M	source/blender/draw/intern/draw_manager.c
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

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

diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index b4321e5790f..791d38ff62f 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -382,7 +382,9 @@ void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state);
 void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, unsigned int mask);
 
 void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const struct GPUTexture *tex);
+void DRW_shgroup_uniform_texture_persistent(DRWShadingGroup *shgroup, const char *name, const struct GPUTexture *tex);
 void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, const char *name, const struct GPUUniformBuffer *ubo);
+void DRW_shgroup_uniform_block_persistent(DRWShadingGroup *shgroup, const char *name, const struct GPUUniformBuffer *ubo);
 void DRW_shgroup_uniform_buffer(DRWShadingGroup *shgroup, const char *name, struct GPUTexture **tex);
 void DRW_shgroup_uniform_float(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize);
 void DRW_shgroup_uniform_vec2(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize);
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index fe91a8d5aae..3c21acd3a02 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -446,13 +446,13 @@ static void drw_viewport_var_init(void)
 		DST.RST.bound_texs = MEM_callocN(sizeof(GPUTexture *) * GPU_max_textures(), "Bound GPUTexture refs");
 	}
 	if (DST.RST.bound_tex_slots == NULL) {
-		DST.RST.bound_tex_slots = MEM_callocN(sizeof(bool) * GPU_max_textures(), "Bound Texture Slots");
+		DST.RST.bound_tex_slots = MEM_callocN(sizeof(char) * GPU_max_textures(), "Bound Texture Slots");
 	}
 	if (DST.RST.bound_ubos == NULL) {
 		DST.RST.bound_ubos = MEM_callocN(sizeof(GPUUniformBuffer *) * GPU_max_ubo_binds(), "Bound GPUUniformBuffer refs");
 	}
 	if (DST.RST.bound_ubo_slots == NULL) {
-		DST.RST.bound_ubo_slots = MEM_callocN(sizeof(bool) * GPU_max_textures(), "Bound Ubo Slots");
+		DST.RST.bound_ubo_slots = MEM_callocN(sizeof(char) * GPU_max_textures(), "Bound Ubo Slots");
 	}
 
 	if (view_ubo == NULL) {
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
index 529166b5792..6d4eee08ad6 100644
--- a/source/blender/draw/intern/draw_manager.h
+++ b/source/blender/draw/intern/draw_manager.h
@@ -159,8 +159,10 @@ typedef enum {
 	DRW_UNIFORM_INT,
 	DRW_UNIFORM_FLOAT,
 	DRW_UNIFORM_TEXTURE,
+	DRW_UNIFORM_TEXTURE_PERSIST,
 	DRW_UNIFORM_BUFFER,
-	DRW_UNIFORM_BLOCK
+	DRW_UNIFORM_BLOCK,
+	DRW_UNIFORM_BLOCK_PERSIST
 } DRWUniformType;
 
 struct DRWUniform {
@@ -335,10 +337,10 @@ typedef struct DRWManager {
 	/** GPU Resource State: Memory storage between drawing. */
 	struct {
 		GPUTexture **bound_texs;
-		bool *bound_tex_slots;
+		char *bound_tex_slots;
 		int bind_tex_inc;
 		GPUUniformBuffer **bound_ubos;
-		bool *bound_ubo_slots;
+		char *bound_ubo_slots;
 		int bind_ubo_inc;
 	} RST;
 } DRWManager;
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index 4648c321f26..b1db3b63777 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -99,7 +99,7 @@ static void drw_interface_uniform(DRWShadingGroup *shgroup, const char *name,
                                   DRWUniformType type, const void *value, int length, int arraysize)
 {
 	int location;
-	if (type == DRW_UNIFORM_BLOCK) {
+	if (ELEM(type, DRW_UNIFORM_BLOCK, DRW_UNIFORM_BLOCK_PERSIST)) {
 		location = GPU_shader_get_uniform_block(shgroup->shader, name);
 	}
 	else {
@@ -126,12 +126,26 @@ void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, con
 	drw_interface_uniform(shgroup, name, DRW_UNIFORM_TEXTURE, tex, 0, 1);
 }
 
+/* Same as DRW_shgroup_uniform_texture but is garanteed to be bound if shader does not change between shgrp. */
+void DRW_shgroup_uniform_texture_persistent(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex)
+{
+	BLI_assert(tex != NULL);
+	drw_interface_uniform(shgroup, name, DRW_UNIFORM_TEXTURE_PERSIST, tex, 0, 1);
+}
+
 void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, const char *name, const GPUUniformBuffer *ubo)
 {
 	BLI_assert(ubo != NULL);
 	drw_interface_uniform(shgroup, name, DRW_UNIFORM_BLOCK, ubo, 0, 1);
 }
 
+/* Same as DRW_shgroup_uniform_block but is garanteed to be bound if shader does not change between shgrp. */
+void DRW_shgroup_uniform_block_persistent(DRWShadingGroup *shgroup, const char *name, const GPUUniformBuffer *ubo)
+{
+	BLI_assert(ubo != NULL);
+	drw_interface_uniform(shgroup, name, DRW_UNIFORM_BLOCK_PERSIST, ubo, 0, 1);
+}
+
 void DRW_shgroup_uniform_buffer(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex)
 {
 	drw_interface_uniform(shgroup, name, DRW_UNIFORM_BUFFER, tex, 0, 1);
@@ -461,7 +475,7 @@ static void drw_interface_init(DRWShadingGroup *shgroup, GPUShader *shader)
 	int view_ubo_location = GPU_shader_get_uniform_block(shader, "viewBlock");
 
 	if (view_ubo_location != -1) {
-		drw_interface_uniform_create_ex(shgroup, view_ubo_location, DRW_UNIFORM_BLOCK, view_ubo, 0, 1);
+		drw_interface_uniform_create_ex(shgroup, view_ubo_location, DRW_UNIFORM_BLOCK_PERSIST, view_ubo, 0, 1);
 	}
 	else {
 		/* Only here to support builtin shaders. This should not be used by engines. */
diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c
index 19b55190e6c..cf9521fece4 100644
--- a/source/blender/draw/intern/draw_manager_exec.c
+++ b/source/blender/draw/intern/draw_manager_exec.c
@@ -704,63 +704,87 @@ static void draw_geometry_execute(DRWShadingGroup *shgroup, Gwn_Batch *geom)
 	draw_geometry_execute_ex(shgroup, geom, 0, 0, false);
 }
 
-static void bind_texture(GPUTexture *tex)
+enum {
+	BIND_NONE = 0,
+	BIND_TEMP = 1,         /* Release slot after this shading group. */
+	BIND_PERSIST = 2,      /* Release slot only after the next shader change. */
+};
+
+static void bind_texture(GPUTexture *tex, char bind_type)
 {
+	int index;
+	char *slot_flags = DST.RST.bound_tex_slots;
 	int bind_num = GPU_texture_bound_number(tex);
 	if (bind_num == -1) {
 		for (int i = 0; i < GPU_max_textures(); ++i) {
-			DST.RST.bind_tex_inc = (DST.RST.bind_tex_inc + 1) % GPU_max_textures();
-			if (DST.RST.bound_tex_slots[DST.RST.bind_tex_inc] == false) {
-				if (DST.RST.bound_texs[DST.RST.bind_tex_inc] != NULL) {
-					GPU_texture_unbind(DST.RST.bound_texs[DST.RST.bind_tex_inc]);
+			index = DST.RST.bind_tex_inc = (DST.RST.bind_tex_inc + 1) % GPU_max_textures();
+			if (slot_flags[index] == BIND_NONE) {
+				if (DST.RST.bound_texs[index] != NULL) {
+					GPU_texture_unbind(DST.RST.bound_texs[index]);
 				}
-				GPU_texture_bind(tex, DST.RST.bind_tex_inc);
-				DST.RST.bound_texs[DST.RST.bind_tex_inc] = tex;
-				DST.RST.bound_tex_slots[DST.RST.bind_tex_inc] = true;
+				GPU_texture_bind(tex, index);
+				DST.RST.bound_texs[index] = tex;
+				slot_flags[index] = bind_type;
 				// printf("Binds Texture %d %p\n", DST.RST.bind_tex_inc, tex);
 				return;
 			}
 		}
-
 		printf("Not enough texture slots! Reduce number of textures used by your shader.\n");
 	}
-	DST.RST.bound_tex_slots[bind_num] = true;
+	slot_flags[bind_num] = bind_type;
 }
 
-static void bind_ubo(GPUUniformBuffer *ubo)
+static void bind_ubo(GPUUniformBuffer *ubo, char bind_type)
 {
+	int index;
+	char *slot_flags = DST.RST.bound_ubo_slots;
 	int bind_num = GPU_uniformbuffer_bindpoint(ubo);
 	if (bind_num == -1) {
 		for (int i = 0; i < GPU_max_ubo_binds(); ++i) {
-			DST.RST.bind_ubo_inc = (DST.RST.bind_ubo_inc + 1) % GPU_max_ubo_binds();
-			if (DST.RST.bound_ubo_slots[DST.RST.bind_ubo_inc] == false) {
-				if (DST.RST.bound_ubos[DST.RST.bind_ubo_inc] != NULL) {
-					GPU_uniformbuffer_unbind(DST.RST.bound_ubos[DST.RST.bind_ubo_inc]);
+			index = DST.RST.bind_ubo_inc = (DST.RST.bind_ubo_inc + 1) % GPU_max_ubo_binds();
+			if (slot_flags[index] == BIND_NONE) {
+				if (DST.RST.bound_ubos[index] != NULL) {
+					GPU_uniformbuffer_unbind(DST.RST.bound_ubos[index]);
 				}
-				GPU_uniformbuffer_bind(ubo, DST.RST.bind_ubo_inc);
-				DST.RST.bound_ubos[DST.RST.bind_ubo_inc] = ubo;
-				DST.RST.bound_ubo_slots[DST.RST.bind_ubo_inc] = true;
+				GPU_uniformbuffer_bind(ubo, index);
+				DST.RST.bound_ubos[index] = ubo;
+				slot_flags[bind_num] = bind_type;
 				return;
 			}
 		}
-		/* This is not depending on user input.
-		 * It is our responsability to make sure there enough slots. */
-		BLI_assert(0 && "Not enough ubo slots! This should not happen!\n");
-
 		/* printf so user can report bad behaviour */
 		printf("Not enough ubo slots! This should not happen!\n");
+		/* This is not depending on user input.
+		 * It is our responsability to make sure there is enough slots. */
+		BLI_assert(0);
 	}
-	DST.RST.bound_ubo_slots[bind_num] = true;
+	slot_flags[bind_num] = bind_type;
 }
 
-static void release_texture_slots(void)
+static void release_texture_slots(bool with_persist)
 {
-	memset(DST.RST.bound_tex_slots, 0x0, sizeof(bool) * GPU_max_textures());
+	if (with_persist) {
+		memset(DST.RST.bound_tex_slots, 0x0, sizeof(*DST.RST.bound_tex_slots) * GPU_max_ubo_binds());
+	}
+	else {
+		for (int i = 0; i < GPU_max_ubo_binds(); ++i) {
+			if (DST.RST.bound_tex_slots[i] != BIND_PERSIST)
+				DST.RST.bound_tex_slots[i] = BIND_NONE;
+		}
+	}
 }
 
-static void release_ubo_slots(void)
+static void release_ubo_slots(bool with_persist)
 {
-	memset(DST.RST.bound_ubo_slots, 0x0, sizeof(bool) * GPU_max_textures());
+	if (with_persist) {
+		memset(DST.RST.bound_ubo_slots, 0x0, sizeof(*DST.RST.bound_ubo_slots) * GPU_max_ubo_binds());
+	}
+	else {
+		for (int i = 0; i < GPU_max_ubo_binds(); ++i) {
+			if (DST.RST.bound_ubo_slots[i] != BIND_PERSIST)
+				DST.RST.bound_ubo_slots[i] = BIND_NONE;
+		}
+	}
 }
 
 static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
@@ -771,16 +795,17 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
 	GPUUniformBuffer *ubo;
 	int val;
 	float fval;
+	const bool shader_chang

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list