Uniform Buffer Objects: More complete padding solution
authorDalai Felinto <dfelinto@gmail.com>
Fri, 18 Aug 2017 14:42:58 +0000 (16:42 +0200)
committerDalai Felinto <dfelinto@gmail.com>
Fri, 18 Aug 2017 14:42:58 +0000 (16:42 +0200)
Move floats around when needed to accomodate vec3 arrays efficiently.

With this we use slightly less memory when possible. Basically vec3s are not
treated as vec4 unless we have no float to use for padding).

Reviewers: fclem, sergey

Differential Revision: https://developer.blender.org/D2800

source/blender/gpu/intern/gpu_uniformbuffer.c

index affff54d4072e9bac8cd3c513c989bc2914aa366..46cf9d19a47b725a9862b34f56088c2f60ba55d2 100644 (file)
@@ -82,6 +82,10 @@ static void gpu_uniformbuffer_inputs_sort(struct ListBase *inputs);
 static GPUUniformBufferDynamicItem *gpu_uniformbuffer_populate(
         GPUUniformBufferDynamic *ubo, const GPUType gputype, float *num);
 
+/* Only support up to this type, if you want to extend it, make sure the
+ * padding logic is correct for the new types. */
+#define MAX_UBO_GPU_TYPE GPU_VEC4
+
 static void gpu_uniformbuffer_initialize(GPUUniformBuffer *ubo, const void *data)
 {
        glBindBuffer(GL_UNIFORM_BUFFER, ubo->bindcode);
@@ -263,7 +267,51 @@ static int inputs_cmp(const void *a, const void *b)
  */
 static void gpu_uniformbuffer_inputs_sort(ListBase *inputs)
 {
+       /* Order them as vec4, vec3, vec2, float. */
        BLI_listbase_sort(inputs, inputs_cmp);
+
+       /* Creates a lookup table for the different types; */
+       LinkData *inputs_lookup[MAX_UBO_GPU_TYPE + 1] = {NULL};
+       GPUType cur_type = MAX_UBO_GPU_TYPE + 1;
+
+       for (LinkData *link = inputs->first; link; link = link->next) {
+               GPUInput *input = link->data;
+               if (input->type == cur_type) {
+                       continue;
+               }
+               else {
+                       inputs_lookup[input->type] = link;
+                       cur_type = input->type;
+               }
+       }
+
+       /* If there is no GPU_VEC3 there is no need for alignment. */
+       if (inputs_lookup[GPU_VEC3] == NULL) {
+               return;
+       }
+
+       LinkData *link = inputs_lookup[GPU_VEC3];
+       while (link != NULL && ((GPUInput *)link->data)->type == GPU_VEC3) {
+               LinkData *link_next = link->next;
+
+               /* If GPU_VEC3 is followed by nothing or a GPU_FLOAT, no need for aligment. */
+               if ((link_next == NULL) ||
+                   ((GPUInput *)link_next->data)->type == GPU_FLOAT)
+               {
+                       break;
+               }
+
+               /* If there is a float, move it next to current vec3. */
+               if (inputs_lookup[GPU_FLOAT] != NULL) {
+                       LinkData *float_input = inputs_lookup[GPU_FLOAT];
+                       inputs_lookup[GPU_FLOAT] = float_input->next;
+
+                       BLI_remlink(inputs, float_input);
+                       BLI_insertlinkafter(inputs, link, float_input);
+               }
+
+               link = link_next;
+       }
 }
 
 /**
@@ -273,7 +321,7 @@ static void gpu_uniformbuffer_inputs_sort(ListBase *inputs)
 static GPUUniformBufferDynamicItem *gpu_uniformbuffer_populate(
         GPUUniformBufferDynamic *ubo, const GPUType gputype, float *num)
 {
-       BLI_assert(gputype <= GPU_VEC4);
+       BLI_assert(gputype <= MAX_UBO_GPU_TYPE);
        GPUUniformBufferDynamicItem *item = MEM_callocN(sizeof(GPUUniformBufferDynamicItem), __func__);
 
        item->gputype = gputype;
@@ -318,3 +366,5 @@ void GPU_uniformbuffer_tag_dirty(GPUUniformBuffer *ubo_) {
        GPUUniformBufferDynamic *ubo = (GPUUniformBufferDynamic *)ubo_;
        ubo->flag |= GPU_UBO_FLAG_DIRTY;
 }
+
+#undef MAX_UBO_GPU_TYPE