Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2018-03-16 10:43:52 +0300
committerClément Foucault <foucault.clem@gmail.com>2018-03-16 10:50:31 +0300
commit93e26cb770ab052ce06f7a1248d636a068b45edf (patch)
tree0d6a1804ee78e5dec404d09d1e74943b1812d64f /source/blender/draw/intern
parent43d0943141cb745d69d36eb1cf177c22663def61 (diff)
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.
Diffstat (limited to 'source/blender/draw/intern')
-rw-r--r--source/blender/draw/intern/DRW_render.h2
-rw-r--r--source/blender/draw/intern/draw_manager.c4
-rw-r--r--source/blender/draw/intern/draw_manager.h8
-rw-r--r--source/blender/draw/intern/draw_manager_data.c18
-rw-r--r--source/blender/draw/intern/draw_manager_exec.c104
5 files changed, 95 insertions, 41 deletions
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_changed = (DST.shader != shgroup->shader);
- if (DST.shader != shgroup->shader) {
+ if (shader_changed) {
if (DST.shader) GPU_shader_unbind();
GPU_shader_bind(shgroup->shader);
DST.shader = shgroup->shader;
-
- release_texture_slots();
- release_ubo_slots();
}
+ release_ubo_slots(shader_changed);
+ release_texture_slots(shader_changed);
+
drw_state_set((pass_state & shgroup->state_extra_disable) | shgroup->state_extra);
drw_stencil_set(shgroup->stencil_mask);
@@ -810,7 +835,13 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
case DRW_UNIFORM_TEXTURE:
tex = (GPUTexture *)uni->value;
BLI_assert(tex);
- bind_texture(tex);
+ bind_texture(tex, BIND_TEMP);
+ GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
+ break;
+ case DRW_UNIFORM_TEXTURE_PERSIST:
+ tex = (GPUTexture *)uni->value;
+ BLI_assert(tex);
+ bind_texture(tex, BIND_PERSIST);
GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
break;
case DRW_UNIFORM_BUFFER:
@@ -819,12 +850,17 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
}
tex = *((GPUTexture **)uni->value);
BLI_assert(tex);
- bind_texture(tex);
+ bind_texture(tex, BIND_TEMP);
GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
break;
case DRW_UNIFORM_BLOCK:
ubo = (GPUUniformBuffer *)uni->value;
- bind_ubo(ubo);
+ bind_ubo(ubo, BIND_TEMP);
+ GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
+ break;
+ case DRW_UNIFORM_BLOCK_PERSIST:
+ ubo = (GPUUniformBuffer *)uni->value;
+ bind_ubo(ubo, BIND_PERSIST);
GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
break;
}