LINUX.ORG.RU

Обработка изображений при помощи OpenGL и шейдеров

 , ,


8

1

При помощи технологии OpenGL и библиотеки GLUT вы можете ускорить процесс обработки изображений, используя всю мощь видеоадаптера вашей системы.

>>> Подробности

★★★

Проверено: Shaman007 ()

Ответ на: комментарий от imtw

Да это любой графический движок в общем-то. Конкретно это был псевдокод на lua (основанный на реальном, конечно:)

А по поводу куда - все примеры состоят из какого-то леденящего душу индокода, который с непривычки читать крайне трудно. Я обычно сначала пишу шейдр glsl а потом уже пытаюсь переложить на апи этих GPGPU-обёрток.

RPG ()
Ответ на: комментарий от Eddy_Em

Типичный шейдр - выделение края по лапласу. Костыли, такие костыли:) Обратите внимание, что достаточно сделать всего лишь пять текстурных выборок для фильтра размером 5х5.

uniform sampler2D tex;
uniform vec2 texel;
varying vec2 TexCoord;
void main() {
	vec4 color = texture2D(tex, TexCoord);
	
	//5x5 kernel, using sampler ability to mixing
	vec2 t = texel * 1.5;
	vec3 c = color.rgb * 8.0
	- 2.0 * (texture2D(tex, TexCoord + vec2(-t.x, -t.y)).rgb
	+        texture2D(tex, TexCoord + vec2(t.x, -t.y)).rgb
	+        texture2D(tex, TexCoord + vec2(t.x, t.y)).rgb
	+        texture2D(tex, TexCoord + vec2(-t.x, t.y)).rgb);
	gl_FragColor = vec4(c, color.a);
}

В шейдрах ничего сложного. Вот о CUDA с их пятью видами памяти мозг сломаешь.

RPG ()
Последнее исправление: RPG (всего исправлений: 1)
Ответ на: комментарий от RPG

Да это любой графический движок в общем-то

Давно мечтал найти, где бы так можно было сделать, да вот не нашёл.

псевдокод

То-то я и вижу.

imtw ()
Ответ на: комментарий от Eddy_Em

Как насчет БПФ?

Как будто это на CPU очень просто:) Но оно таки было сделано в каком-то GPU Gems

RPG ()
Ответ на: комментарий от RPG

Ладно. Назначение шейдеров простое — делать элементарную обработку 2D/3D-картины перед выводом на экран. Для серьезных действий они не годятся.

Eddy_Em ☆☆☆☆☆ ()
Ответ на: комментарий от Eddy_Em

Назначение шейдров - позволять программистам считать на них эффекты освещения текстур для получения рельефа/света в играх. Потом кто-то в 2004 году додумался на них обсчитывать системы частиц и тут понеслось...

RPG ()
Ответ на: комментарий от lucentcode

В Gimp и ImageMagic не скоро подобное запилят?

С разморозкой :)

AP ★★★★★ ()
Ответ на: комментарий от RPG

и тут понеслось...

Понёсся костыль через костыль,

видит костыль - костыль костыль.

Сунул костыль в костыль костыль,

Костыль костыль костыль костыль!

Как-то так. Я сам баловался с сеточными методами и редукцией на шейдерах, так что достаточно хорошо представляю масштаб проблемы.

imtw ()
Ответ на: комментарий от imtw

При условии прямых рук - фильтры обработки изображений быстрее CPU на порядки, есть и ещё области применения - то же БПФ, например, считать, физику и прочие симуляции. Многие алгоритмы переносятся просто на раз.

Большую проблему представляют собой в основном алгоритмы, где чтение и запись должно осуществляться в один и тот же массив.

RPG ()
Ответ на: комментарий от RPG

Главное, что-бы Gimp использовал GPU. Для меня это важно. ImageMagic может не спешить, он для пакетной обработки больше заточен. Я могу скрипт и на ночь оставить, это не проблема. А вот когда Gimp тормозит, это печально. К чести данного редактора, после последнего апрейда железа, и перехода на 2.8 он стал работать очень быстро. Видно, не зря я 6Гб и дискретную видюху прикупил.

lucentcode ★★★★★ ()

на многих видеокартах есть opengl но нет opencl т.к. по маркетинговым соображениям соответствующая поддержка не реализована в драйверах. например intel 3000 в sandy bridge. (в 4000 который в ivy bridge вроде заявлена но точно не знаю, у меня есть только 3000).

где-нибудь можно почитиать об ограничениях при использовании произвольных вычислений в шейдерах? для тех кто не знаком с openGL. не знаю, стоит ли его осваивать, если графика не особо нужна, а вычисления могут пригодиться...

anonymous ()
Ответ на: комментарий от Artificial_Thought

Ембедеры должны страдать.

anonymous ()
Ответ на: комментарий от lucentcode

Сам GIMP конечно может и не будет, а фильтры gegl многие уже портированы на GPU, можно пробовать запуская 2.8 с GEGL_USE_OPENCL=yes через инструменты - операция gegl.

RPG ()

Осторожно, слоупоки слоупочнее чем кажутся! Статья хорошая, но это все же не новость.

anonymous ()
Ответ на: комментарий от ckotinko

вот мне очень хочется понять, как наиболее полно загрузить именно амд-шное GPU (конкретно 58хх), но из твоего суперкраткого объяснения я только *слова* понял

начнем с того, где лежат доки именно по архитектуре GPU? интересно, кстати, и избыточно сложное нвидийное, и слишком простое амд-шное

почему-то они не гуглятся у меня! че мне пока удалось нагуглить — это не доки, а презентации (хотя и по архитектуре), из которых я не понял даже, есть и какое пенальти в случае неверного предсказания ветвления

хочется чтобы было ясно:

1. откуда и куда передаются данные (pipeline?)

2. каковы ограничения по скорости и по латентности в шинах/точках_передачи/че-там

3. какое пенальти в случае неверного предсказания ветвления

4. как возможно избежать пенальти в п.3 вроде conditional move

5. специфичные фенечки, вроде же в gpu имеются некие sorting networks? или это тоже реализуется программно?

если влом все это писать, то накатай хотя бы список *вопросов*, аналогичных 1-4, но существенно точнее и поподробнее, чем я тут

меня интересует все это с чисто вычислительной точки зрения, т.е. без приложения к рендерингу графики (хотя, если приложение поможет понять структуру gpu, оно полезно)

вот, скажем, конкретная задача:

есть возрастающая последовательность целых чисел (несколько миллиардов — в память на видяхе не влезут (но на это можно пока забить))

шаг алгоритма: из каждого из них (довольно просто — несколькими последовательными циклами фиксированной длины почти без if-ов) генерится возрастающая последовательность (до 100 штук) целых чисел; эти маленькие последовательности надо слить (отсортировать слиянием) в такую же последовательность и выбросить дубликаты (и может выбросить еще кое-что)

этот шаг повторяется скажем до 100 раз

как это быстро делать на cpu — я представляю; на gpu — полностью без понятия

www_linux_org_ru ★★★★★ ()
Последнее исправление: www_linux_org_ru (всего исправлений: 1)
Ответ на: комментарий от www_linux_org_ru

доки находятся на сайте x.org/docs/AMD

вам стоит обратить внимание на файл AMD_Evergreen-Family-Instructio-Set-Architecture.pdf.

Каждый считающий блок(stream processor - темный квадратик на схеме) обрабатывает до 10 разных потоков. В каждом потоке обрабатывается 64 workitemов.

Workitemы обрабатываются группами по 16, чередуясь каждый цикл. Сперва 0-15, затем 16-31, затем 32-47, потом 48-63, затем снова 0-15... Причем в течении этих 4х циклов первые 4 цикла читаются регистры GPR, на 4й происходит подстановка PV и его запись в GPR, на 5й стартует само ALU и работает 4 цикла(внутри него тоже конвейер). Т.е. полная итерация занимает 8 циклов, за которые на конвейере в разных стадиях оказываются все 64workitemа по два раза. Конвейер можно тормознуть, если создать конфликт при чтении или записи.

Stream processor содержит 16 блоков(далее «блок»), в каждом из которых есть 5 ALU. они называются ALU.X, ALU.Y, ALU.Z, ALU.W, ALU.T. Каждый блок содержит банк регистров(четыре памяти 256 х 32 бита) для каждого workitemа. Всего, напомню, на блок приходится 4 workitemа. Т.е. всего банков 16(4*4 по 256х32бита), но workitemы видят только свою четверку.

Эта четверка называются X,Y,Z,W. Напомню, что за итерацию происходит максимум 3 чтения и 1 запись. Если вы будете писать-читать из каждого банка больше, начнутся остановки конвейера.

За одну итерацию вы можете выполнить до 5 alu команд, либо одну* команду для работы с любой памятью. Назовем это «пятеркой». В пятерке может быть от 1 до 5 команд. Команды про память могут продолжить работать после итерации(начать жить своей жизнью), при этом поток может быть заблокирован или продолжить работать с ALU. Если поток блокировался, может начать работу другой поток.

Команды для всех workitemов в «блоке» выполняются строго одновременно, т.е. все 64 workitemа получат одну команду за одну итерацию. 4 раза по 16 workitemов паралельно выполнят в точности одно и тоже. ALU-команды выполняются паралельно всей пятеркой. Процессор не может «отложить» несколько команд на потом или выполнить заранее. Процессор не может выполнить 2 команды из «пятерки» сейчас, а еще 1 потом. Задача компилятора - распихать ваши «элементарные операции» по реальным итерациям так, чтоб выполнить их за минимальное колво итераций, по возможности до упора заполнив каждую пятерку команд.

ckotinko ☆☆☆ ()
Ответ на: комментарий от www_linux_org_ru

У каждого workitemа есть стек предикатов, куда можно поместить предикат, заменить верхний предикат на новый, совершить операцию если верхний предикат в стеке равен «пофиг чему», «true», «false», а также выполнить команду если он = true и тут же изъять его из стека.

Условно выполнить можно как отдельную операцию ALU, так и __блок__ однотипных операций. Это делает за вас компилятор. Ваша задача - следить, чтоб код вашего «ядра» не содержал конструкций вида:

if(x){
  if(y){ok!
  }
  if(!y){ok!
  }
}//if(y) удаляется
if(!y){//предикат надо заново считать!
}

У каждого блока есть 32Кб локальной памяти. Ее видят только workitemы из одной пачки в 64 itemа. Она тоже поделена на кусочки по 32бита. + есть глобальная память + обычная. Локальную память за пределами stream processor не видно!

Если вы хотите считать оттуда побайтно, читайте сразу int4 в переменную(128бит сразу), а потом спецкомандами от амд добывайте оттуда байтики. Это быстрее. Атомарные операции можно проводить прямо в локальной памяти и в глобальной памяти. Локальная память тоже поделена на банки с шагом в 128 байт, так что если будут конфликты при доступе, будут паузы(их закроют другие потоки если есть или тот же поток, если ему не надо читаемые данные прям щас).

И да, компилятор довольно тупой а АМД рукожопы. Поэтому если ваши ядра считаются как-то ну очень медленно, используйте типы float4 и ручками дергайте отдельные его компоненты. Иногда компилятор просто неэффективно использует регистры.

ckotinko ☆☆☆ ()
Ответ на: комментарий от www_linux_org_ru

И вот еще что - чем больше переменных в ядре вы использовали на 1 workitem тем меньше будет потоков ,и дыры в ожидании чтения-записи нечем будет закрыть.

Алсо, с точки зрения одного workitemа, частота видяхи в 4 раза меньше заявленной.

Алсо, если у вас есть код вида: if(x){workworkworkA;} else{workworkworkB;}

учтите что все workitemы выполняют один и тот же код! т.е. если у кого-то из них условие не выполнено, они не будут выполнять код, но потратят на него время как если бы выполняли.

Вы можете в принципе читать одно и то-же значение из __local памяти во всю группу workitemов в пределах одного stream processor.

Это можно использовать для распределения задач в случаях когда надо условно выполнить какой-то сложный код. Попозже напишу как, задолбался

ckotinko ☆☆☆ ()
Ответ на: комментарий от ckotinko

Это можно использовать для распределения задач в случаях когда надо условно выполнить какой-то сложный код. Попозже напишу как, задолбался

предлагаю отложить «сложный код внутри if» на то время, когда я прочту внимательно доку и осмыслю, что ты написал

у меня есть вопрос вида «интересен ответ, но можно не особо объяснять почему так»

1. сколько максимум можно выжать в секунду из карточки 5850 или 5870 (вот кстати http://en.wikipedia.org/wiki/Comparison_of_AMD_graphics_processing_units) если все сделать правильно и параллельно — сколько целочисленных, ну скажем 128 или 64-битных операций (типа и, или, не, сдвиг) и сколько простых if-ов? («простые if-ы» для того, чтобы скажем выбрасывать все нули из последовательности)

2. они еще выпускаться вроде?

3. в чем разница с 68хх и 78хх? глядя на википедию вижу только техпроцесс получше и не вижу профита по цифрам: http://en.wikipedia.org/wiki/Comparison_of_AMD_graphics_processing_units — ладно, хрен с профитом, но хуже они не будут опять с точки зрения целочисленных операций и простых if-ов?

www_linux_org_ru ★★★★★ ()
Последнее исправление: www_linux_org_ru (всего исправлений: 1)
Ответ на: комментарий от www_linux_org_ru

по поводу ветвлений: на gpu выгоднее не ветвиться, если ветки стоят дорого, а рассортировывать задачи по корзинам и жрать их из корзин охапками по 64. если ветка недорогая, ветвиться быстрее.

для этого очень удобно читерское чтение во все workitemы. ведь вы можете узнать, какие itemы в 64ке активны(т.е. в условном выражении зохавать 64битное целое, состоящее из всех 64 последних предикатов.


__local struct foo data[128];
int count=0;//в регистре
int pcount=128;//в регистре-колво мест в fifo
if(условие){
   x=bitcount64(active_mask);
   y=bitcount64(active_mask & (MAX_UINT64<<workitem_id));
   data[count+y]=parameters;
   pcount-=x;
   сount=127 & (count+x);
   if(pcount<64){
      pcount+=64;
      int index=((count+64)&127) +workitemid;
      workworkwork1(data[index]);
   }
}

в чем разница с 68хх и 78хх?

6800 - вместо пятерки команд у вас четверка. причем sin/cos/foo/bla короче сложные команды остались, но они превращают «четверку» в двойку, занимая в ней сразу 3 места. В остальном то же самое.

78хх - все команды последовательно. нет больше четверок-пятерок. есть однерки. плюс дополнительный целочисленный проц 1 на 64 итема. можно в любой workitem насрать в любой регистр из него и читать также. в память читать-писать из него низя.плюс для всяких счетчиков можно его использовать

ckotinko ☆☆☆ ()
Ответ на: комментарий от www_linux_org_ru

Я отправил feature request челу который отвечает за OpenGL.

будет что-то вроде deferred functions

ckotinko ☆☆☆ ()
Ответ на: комментарий от www_linux_org_ru

2. они еще выпускаться вроде?

мобильная дешевятина(6250, 6310, 6320, 6800М, 7130М, 7470М), SOCи-все они evergreenы

ckotinko ☆☆☆ ()

ну как бы и что? на швабре больше 9к таких статей
стопицот статей как получить оконтуренное изображение
где статья вида «есть оконтуренное изображения, как запилить распознавание на этом изображении руки\ноги\дорожного знака»

TERRANZ ★★★★ ()
Ответ на: комментарий от ckotinko

Я отправил feature request челу который отвечает за OpenGL. будет что-то вроде deferred functions

о! тогда сделай фича реквест на сортировку!

Q: When will Thrust support OpenCL?
A: The primary barrier to OpenCL support is the lack of an OpenCL compiler and runtime with support for C++ templates (e.g., something similar to nvcc and the CUDA Runtime). These features are necessary to achieve close coupling of host and device codes.

я правильно понимаю, что у амд нет *НИКАКОЙ* сортировки на openCL?! хрен с ним с красивым интерфейсом в стиле stl, была бы хоть какая-то сортировка!

как я вижу сортировку *без шаблонов*:

1. 8ГБ/с по pci-e 2.0 (и даже 16ГБ/с по 3.0) это *очень* медленно; поэтому данные для сортировки должны быть минимизированы — вместо struct Bad { int key; Payload payload; } очевидно надо слать struct Good { int key; Payload* payload_ptr; }

2. т.е. приходим к тому, что в gpu сортировать надо 4 и 8-байтные entities (т.е. sizeof(Good)=4 и 8); если же у нас скажем 6-байтный key и 2-байтный Payload/Payload*, то 8-байтная сортировка все равно сработает нормально; 4-байтные entities тоже нужны, особенно если хочется «sort -u»

это голодный минимум; дальше можно придумывать например битовую маску, которая из 8-байтной entity выделяет key, сортировку 3,5,6,7-байтных entities и т.п.

www_linux_org_ru ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.