Как расширить возможности вершинного шейдера для GPGPU
Я пытаюсь реализовать Scrypt hasher (для LTC miner) на GLSL (не спрашивайте меня, почему).
И, на самом деле, я застрял с алгоритмом HMAC SHA-256. Несмотря на то, что я реализовал SHA-256 правильно (он повторно использует хэш corrent для ввода), шейдер фрагментов перестает компилироваться, когда я добавляю последний шаг (хэширование предыдущего хэша, согласованное с oKey).
Шейдер не может выполнить более трех раундов SHA-256. Он просто перестает компилироваться. Каковы же эти пределы? Он не использует много памяти, 174 объекта vec2 в итоге. Похоже, это не связано с памятью, потому что любой дополнительный раунд SHA256 не требует новой памяти. И, похоже, это никак не связано с размером видового экрана. Он перестает работать как на 1x1, так и на 1x128 видовых экранах.Я начал делать майнер на WebGL, но после появления limit я попытался запустить тот же шейдер в Qt на полнофункциональном OpenGL. В результате рабочий стол OpenGL позволяет один раунд SHA256 меньше, чем OpenGL ES в WebGL (почему?).
Забыл упомянуть . Шейдер не работает на стадии сцепления. Шейдер хорошо компилируется сам, но связывание программы не удается.
Я не использую никаких текстур, никаких расширений, медленных вещей и т. д. Просто квадрат (4 vec2 вершин) и несколько форм для фрагментного шейдера. Входные данные составляют всего 80 байт, результат шейдера фрагментов-двоичный (черный или белый), поэтому задача идеально подходит для GLSL-принципов.
Моя видеокарта Radeon HD7970 с большим количеством VRAM, которая способна вместить сотни потоков scrypt (scrypt использует 128 кб за хэш, но я не могу достичь только HMAC-SHA-256). Моя карта поддерживает OpenGL 4.4.
Я новичок в OpenGL и могу понять что-то не так. Я понимаю, что шейдер фрагментов работает для каждого пикселя отдельно, но если у меня есть видовой экран 1x128, то используется только 128x348 байт. Где находится предел фрагментного шейдера. Вот общий код, который я использую, чтобы вы поняли, как я пытаюсь решить эту проблему.uniform vec2 base_nonce[2];
uniform vec2 header[20]; /* Header of the block */
uniform vec2 H[8];
uniform vec2 K[64];
void sha256_round(inout vec2 w[64], inout vec2 t[8], inout vec2 hash[8]) {
for (int i = 0; i < 64; i++) {
if( i > 15 ) {
w[i] = blend(w[i-16], w[i-15], w[i-7], w[i-2]);
}
_s0 = e0(t[0]);
_maj = maj(t[0],t[1],t[2]);
_t2 = safe_add(_s0, _maj);
_s1 = e1(t[4]);
_ch = ch(t[4], t[5], t[6]);
_t1 = safe_add(safe_add(safe_add(safe_add(t[7], _s1), _ch), K[i]), w[i]);
t[7] = t[6]; t[6] = t[5]; t[5] = t[4];
t[4] = safe_add(t[3], _t1);
t[3] = t[2]; t[2] = t[1]; t[1] = t[0];
t[0] = safe_add(_t1, _t2);
}
for (int i = 0; i < 8; i++) {
hash[i] = safe_add(t[i], hash[i]);
t[i] = hash[i];
}
}
void main () {
vec2 key_hash[8]; /* Our SHA-256 hash */
vec2 i_key[16];
vec2 i_key_hash[8];
vec2 o_key[16];
vec2 nonced_header[20]; /* Header with nonce */
set_nonce_to_header(nonced_header);
vec2 P[32]; /* Padded SHA-256 message */
pad_the_header(P, nonced_header);
/* Hash HMAC secret key */
sha256(P, key_hash);
/* Make iKey and oKey */
for(int i = 0; i < 16; i++) {
if (i < 8) {
i_key[i] = xor(key_hash[i], vec2(Ox3636, Ox3636));
o_key[i] = xor(key_hash[i], vec2(Ox5c5c, Ox5c5c));
} else {
i_key[i] = vec2(Ox3636, Ox3636);
o_key[i] = vec2(Ox5c5c, Ox5c5c);
}
}
/* SHA256 hash of iKey */
for (int i = 0; i < 8; i++) {
i_key_hash[i] = H[i];
t[i] = i_key_hash[i];
}
for (int i = 0; i < 16; i++) { w[i] = i_key[i]; }
sha256_round(w, t, i_key_hash);
gl_FragColor = toRGBA(i_key_hash[0]);
}
Какие решения я могу использовать для улучшения ситуации? Есть что-то крутое в OpenGL 4.4, в OpenGL ES 3.1? Возможно ли вообще сделать такие вычисления и сохранить так много (128 кб) в шейдере фрагментов? Каковы ограничения для вершинного шейдера? Могу ли я сделать то же самое с вершинным шейдером вместо фрагмента?
1 ответ:
Я пытаюсь ответить на свой собственный вопрос.
Шейдер-это небольшой процессор с ограниченными регистрами и кэш-памятью. Кроме того, существуют ограничения на выполнение инструкций. Итак, вся архитектура, чтобы вместить все в один фрагмент шейдера, неверна.С другой стороны, вы можете изменять свои шейдерные программы во время рендеринга десятки или сотни раз. Это нормальная практика.
Необходимо разделить большие вычисления на меньшие части и представить их отдельно. Использование рендеринга в текстуру сохранить вашу работу.
Благодаря статистике webgl, 96,5% клиентов имеют MAX_TEXTURE_SIZE eq 4096. Это дает вам 32 мегабайта памяти. Он может содержать черновик данных для 256 потоков вычисления scrypt.