Оптимизация побитовых операций на GPU с GLSL 1.3 - PullRequest
1 голос
/ 01 июня 2019

Я помешан на максимизации производительности и уменьшении занимаемой памяти. Я пишу вершинный шейдер GLSL (нацеленный на OpenGL 3.0, GLSL 1.3 является эквивалентной версией GLSL, если кто-то не уверен) с намерением внедрить скиннинг наиболее экономичным способом.

Я читал, что OpenGL гарантирует не менее 16 КБ памяти Uniform Buffer (в изобилии за то, что я хочу сделать, здесь нет проблем). Поэтому я решил снабдить свой скин-вершинный шейдер преобразованиями костей через единообразные регистры.

Я проиллюстрирую это некоторым кодом:

#version 130

#define NUMBONES 16 /* 16 mat4x4 = 1KiB */
#define FLOATMAXINT 16777216

/* To map from model-space to world-space */
uniform mat4x4 u_mapWorld;

/* To map from model-space straight to screen space(?).
   = projection * view * world (using column-major btw) */
uniform mat4x4 u_mapProj; /* 'Projection' */

/* To map from model-space to light space.
   I use shadow-mapping. */
uniform mat4x4 u_mapLight;

/* For transforming normals */
uniform mat3x3 u_mapNorm;

/* Array of bone transforms for armature animation (skinning).
   This array should total to 1KiB in width? */
uniform mat4x4 u_mapBones [NUMBONES];

/* Array of (corresponding) bone transforms for mapping vertex normals.
   Probably 1KiB in width, in order to honour alignment requirements.
   Desirable width would be 0.56KiB, though. */
uniform mat3x3 u_mapBoneNorms [NUMBONES];

/* Width of two arrays = 2KiB, optimised for speed.
   Fine for what I want to do. */

Я делегирую матричные вычисления ЦПУ, чтобы снять нагрузку с матричной инверсии (для вычисления вершинных нормальных преобразований) с графического процессора, тем более что этот шаг, строго говоря, не нужен и лучше всего избегать. Я не возражаю против дополнительной памяти, которая потребляет это, если это означает более быструю обработку вершин.

Далее у меня есть вершинные входы, которые следующие:

in vec3 v_pos;
in vec3 v_norm;
in vec2 v_uv;
in float v_weights; /* Actually four weights */
in float v_indices; /* Actually four indices */

У меня есть планы по поддержке версий GL начиная с 2.0, и я могу расширить его до 1.4, поэтому v_weights и v_indices являются числами с плавающей точкой, а не упакованными целыми числами. Версии ниже 3.0 указываются как без поддержки для целочисленных входов (и процедуры glVertexAttribIPointer). Я прочитал (и был впечатлен, узнав), числа с плавающей точкой IEEE одинарной (32-битной) точности могут надежно представлять целые числа до диапазона 16 777 216 до того, как точность понизится. Это 24-битная надежная емкость индекса, которую я решил разделить между четырьмя весами (24/4 = 6), что дает каждому весовому индексу 6 битов ширины (индексы варьируются от 0 до 63).

Моя программа передает индексы веса в OpenGL путем построения упакованного целого числа:

std::uint32_t ui_indices =
   ((w0 & 0x3F) <<  0) + ((w1 & 0x3F) <<  6) +
   ((w2 & 0x3F) << 12) + ((w3 & 0x3F) << 18);

и затем преобразует (конвертирует, вы понимаете, что я имею в виду) в число с плавающей точкой, полагая, что точность не теряется :

float f_indices = static_cast<float>(ui_indices);

, который затем передается в OpenGL через glVertexAttribPointer().

В моем вершинном шейдере у меня есть следующий код, который распакует индексы:


/* NONE OF THIS CODE IS YET TESTED */

uint ii; /* Int-converted Index */
uint i[4]; /* Unpacked indices (can we use uint8?) */

/* Extract indices */
fmod(v_indices, ii);

/* Unpack indices.
   I've kept shift-by-zero for presentation. */
i[0] = (ii>> 0) & 0x3F;
i[1] = (ii>> 6) & 0x3F;
i[2] = (ii>>12) & 0x3F;
i[3] = (ii>>18) & 0x3F;

И, наконец, на мой вопрос:

Предполагая, что концепция / реализация не ошибочна (ничего из этого еще не проверено) - будет ли GLSL оптимизировать это утверждение? Кроме того, лучше вместо этого реализовать маскирование в виде серии битовых сдвигов (НЕ БИТОВОЕ ВРАЩЕНИЕ), например:

i[0] = (ii<<18)>>18;
i[1] = (ii<<12)>>18;
i[2] = (ii<< 6)>>18;
i[3] = (ii<< 0)>>18;

P.S. Извиняюсь, если на этот вопрос ответили в другом месте, и я пропустил это. Также извините, если я дал слишком много контекста для небольшого вопроса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...