Программирование

Q: "OpenGL на CPU"?

Преамбула

Несмотря на долбанутость OpenGL-ного API (и, как следствие, огромное количество глупых ньюбских ошибок, которые я допустил), сам OpenGL мне очень понравился.

Вот, к примеру, код в RawDigger, который занимается визуализацией, это 500+ строк довольно нетривиального кода которые делают:

  • Raw Composite
  • Поканальный показ
  • Overexposure/Underexposure
На OpenGL шейдер, который делает ровно то же самое (ну, да, немножко поменьше, в RD есть всякие режимы 2x2 pixels) - это 11 строк кода, несколько строк определения переменных, ну и, да, еще строк 10 для формирования матриц-векторов на которые мы множим и с которыми сравниваем. Ну и работает "немножко" побыстрее.

К сожалению, выяснилось что полноценный OpenGL есть не везде и в новом проекте таки придется делать софтверный рендеринг.

Амбула

Вопрос, собственно, такой: а есть какой-то code generator, который питался бы чем-то вроде кода OpenGL шейдеров и порождал бы код на SSE+треды. И был бы заточен именно под Imaging.

Ну если быть точным, то я знаю уже про

  • ISPC, который я нежно люблю, но он все-таки не про Imaging (4 рядом лежащих компонента пикселя), а больше про скалярное. С пикселями там приходится чудовищно извращаться.
  • Halide - ровно про это, вот прямо таки заточен, но мне очень не хочется таскать с собой llvm runtime, а хотелось бы генерировать статический код при сборке проекта. Кроме того: Windows support is technically feasible, but we have not yet built or tested on Windows, а мне оно нужно исключительно под Винду, у маков и так все хорошо (даже софтверный рендеринг в виртуальной машине - работает и быстро).
  • llvmpipe - даже совсем OpenGL, но есть серия но:
    • Очень не хочется таскать с собой здоровенный llvm runtime
    • Судя по обсуждению в багзилле мозиллы, прикручивание llvmpipe в качестве software renderer есть процесс весьма сексуальный.
Вопрос мой: может быть есть, все-таки, какие-то оффлайновые кодогенераторы, которые сочетали бы оффлайновость ISPC и пикселе-заточенность Halide/Mesa3D?

Q: mmap() ?

А я вот извиняюсь, а Windows умеет mmap()-ать файлы с сетевого диска?

А макос?

Ну то есть у меня какое-то ощущение из прошлого, что нет, нельзя, но в доках такого ограничения не нашел.

Про Qt5 и VisualStudio 2012

Если в двух словах, то со связкой указанной в заголовке - счастья не получил, откатился на VS2010.

Если подробно:

  • Qt - собирается без проблем, работает.
  • qmake делает прекрасные работоспособные Makefiles
  • qmake -tp vc - делает .vcxproj которые зовут компилятор от 2010-й версии (нет, я не туп, пути стоят нормально, QMAKESPEC=win32-msvc2012) и проекты не собираются, линкер ругается что у меня мои объектники от 2010, а библиотеки - от 2012.
  • Предыдущую проблему поборол: QMAKESPEC=win32-msvc2010 qmake -tp vc, при первом открытии проекта его апгрейдим на 2012. Достает, но уже привык.
  • Макросы для отладчика (показ Q-types по человечески) - установились, но не заработали.
  • Последняя капля: при попытке прикрутить иконку к .exe (обычным способом: RC_FILE=resource.rc в .pro) - все сломалось с ошибкой "VTRES : fatal error CVT1100: duplicate resource. type:ICON, name:1, language:0x0409". Судя по гуглению, это привет от конверсии проекта из 2010 в 2012, этот самый .rc оказывается в двух местах прописан.
Короче, поживу с 2010-м вижуалом до Qt 5.0.1. Хотя 2012-й мне нравится больше.

Опять о современных CPU

Продолжаю набирать материал к вот этой презентации

Вот такой вот код (это автобаланс белого из dcraw в моем вольном изложении, слегка сокращенный, только для 4-компонентных а не байеровских изображений):

float sum[8],dsum[8]={0,0,0,0,0,0,0,0};
for (row=0; row < bottom; row += 8)
   for (col=0; col < right; col += 8) {
      for(i=0;i<8;i++) sum[i]=0.f;
      for (y=row; y < row+8 && y < bottom; y++)
        for (x=col; x < col+8 && x < right; x++)
          for(i=0; i<4; i++) {
            val = image[y*width+x][i];
            if (val > maximum-25) goto skip_block;
            sum[i] += val;
            sum[i+4]++;
           }
       for(i=0;i<8;i++) dsum[i] += sum[i];
skip_block: ;
   }
То есть, если простыми словами: берем блоки 8x8, если в этом блоке все пиксели имеют значения меньшие (maximum-25), то значения пикселов усредняем, если хоть один пиксел вылетает за указанный лимит - блок выбрасываем.

На моей тестовой 9-Mpix картинке (Nikon D800 "интерполированный в half") этот код работает 45-50 миллисекунд. Что для автобаланса белого как-то неприлично много.

Перепишем его тупо на SSE2:

Хозяйке на заметку: Qt, OpenGL и PBO

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

Вот есть QGraphicsView, направленный в QGLWidget. Есть еще QGraphicsScene, у которой с помощью drawBackground() рисуем нужное нам (картинку).

Этот самый drawBackground() использует текстуры, одну или много, текстуры залиты через PBO.

Дальше - пытаюсь вывести на эту Scene другие объекты. Ну, как в документации написано, к примеру так:

QLabel *label = new QLabel("Bla-Bla");
scene->addWidget(label);
(ну чуть побольше кода, потому что прозрачность, возможность двигать, но смысл именно такой)

Результат:

  • Если объекты выводятся, окно открывается и т.п. до создания "моих" текстур (которые рисуются на фоне) - то все отлично.
  • Если все разлеглось так, что свои текстуры и PBO я создал до первого показа (даже не создания) объекта на Scene, то жопа, при добавлении элемента к сцене получаем такое:
    texture upload failed, error code 0x502
    
И так пробовал, и сяк и об косяк, потерял не меньше двух дней (ну то есть - не работает, пытаемся создать свой пример, там работает, из примера переносим код к себе - не работает и так с десяток раз). И, внезапно, ответ нашелся:

Если вы работали с QOpenGLBuffer, то прежде чем отдать управление в Qt - сделайте ему release(). Иначе будет нехорошо.

И ведь натыкался я уже на подобное, но с VBO: если не отцепить их, то вообще ничего не работает.

О процессинге RAW: плавучка или целое

Обработка RAW в плавучке позволяет избавиться от артефактов вылета за диапазон, да и вообще получить более качественную картинку.

Тем интереснее обратные случаи.

Возьмем вот такой вот кадр:

Это D800 с его приколами в светах, вот на света и посмотрим.

Если обработать картинку dcraw (или LibRaw, которая дает побитово такой же процессинг, если автоматическое определение максимума отключить), то в светах в "середине верха кадра" мы увидим такое вот:

Про Mac и 32 бита

Ваяю потихоньку новый варез для фотографов (пока не скажу какой). Делаю его на Qt5, вот так вот решил.

В связи с этим встает вот такой вот вопрос:

  • Qt5 не билдится как Universal Binary, обещают починить, но там есть препятствие в лице v8 (насколько понял из чтения мейлинг-листов).
  • Qt5 поддерживает Mac OS X начиная с 10.6. Эта самая 10.6 вроде бы требует 64-bit capable CPU (это по комментариям в Qt-шном багтрекере, где обсуждают отсутствие UB). Хотя в Википедии пишут, что 64-bit only - только с 10.7
  • Посмотрел в статистике RawDigger: 32-битных Маков 1%. Не от числа вообще компьютеров а от числа маков. У меня, понятно, статистика смещенная и кривая, но какая уж есть.
Собственно, вопрос: а что будет, если я в мак-версии дропну 32-битность? Целевая аудитория вареза - фотографы, как обычно. Теоретически, это заденет модели 2006-го года и некоторые макмини 2007, но их же должен быть вот тот самый 1%?

По-моему, этот вопрос мы уже обсуждали в этом бложике "вообще", но может у кого есть объемная статистика?

LibRaw 0.15.0-Beta2

По традиции, анонсирую LibRaw 0.15-Beta2

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

  • Поддержано 20 новых камер:
    • Canon: G15, S110, SX50
    • Fujifilm: F800EXR, XF1
    • Nikon: 1 J2, 1 V2, D600
    • Olympus: E-PL5, E-PM2
    • Panasonic: FZ200, GH3, LX7
    • Pentax: K-5 II, K-5 IIs, K-30, Q10
    • Sony: SLT-A99, NEX-5R, NEX-6
  • RawSpeed может использоваться не только для байеровских данных, но и для полноцветных (3-цветные DNG, sRAW).
    Правда если вы захотите использовать эту фишку, то вам придется запатчить RawSpeed. Тот же патч положен в дистрибутив LibRaw (в каталоге RawSpeed).
    Пользы от RawSpeed достаточно много даже для нежатых DNG: к примеру, 60-мегабайтный 3-цветный нежатый DNG распаковывается за 130мс родным кодом LibRaw и за 70мс - при помощи RawSpeed.
  • В API добавились флажки, позволяющие понять - использовалась ли библиотека RawSpeed, а если да, то к чему это привело.
  • В очередной раз перебраны потроха (интересно только тем, кто в них копается, сам LibRaw API не изменился)
    • В 0.15-Alpha-Beta1 в imgdata.rawdata были два указателя: raw_image указывал на буфер с байеровскими данными, а color_image - на буфер с 4-компонентными RGBG. Ну то есть для байеровских RAW первый был не нулевым, а для полноцветных - второй.

      В Beta2 этот самый color_image ращеплен на два: color3_image ненулевой если в буфере (на который он указывает) лежат 3-компонентные данные, а color4_image - если данные надо рассматривать как 4-компонентные.

    • Введенный в Alpha4 параметр imgdata.sizes.raw_pitch (шаг строк в RAW-буфере) теперь в байтах, а не в пикселях. И один и тот же raw_pitch используется для доступа к imgdata.rawdata.raw_image, color3_image, color4_image
    Кому интересно совсем в деталях - читайте исходник LibRaw::raw2image() и понятно будет все.

Qt+OpenGL benchmarking Q

А вот, я извиняюсь, такой вопрос.

Есть QGrahicsScene (унаследованное от нее) в которой я в drawBackround вывожу OpenGL-ем нечто.

В процессе разбирательств с OpenGL я это нечто имплементировал десятком разных способов и хочу теперь померять, какой из них быстрее.

Но как?

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

for(.....){
myview->setZoom(...);
QApplication::processEvents();
}

Но получается вот что:

  • FPS-ов ровно 60 (2000 итераций за 34 секунды), OGLFormat::setSwapInterval(0) не помог.
  • Одно ядро процессора полностью загружено.
  • По профайлеру, загружено оно QWindowsWindow::raise() (~70% по профайлеру), вообще весь прочий код занимает остальные 30% CPU, моего кода вовсе не видно.

Так слона не продать.

Ну то есть понятно, можно в OpenGL-рисовалке рисовать одно и то же 10 (100,1000) раз подряд, но вопрос заключается в том, нет ли более прямого пути, который позволяет Qt-GUI программы побенчмаркать попроще?

Update: если вдруг кому интересно, то проблема решилась глобальным выключением VSync в настройках драйвера (NVidia). FPS-ы сразу сильно выросли, а профайл исполнения стал похож на настоящий.

Про Qt и OpenGL

С помощью профайлера и отладчика узнал прекрасное.

Прекрасное, конечно же, описано в мануале, но кто же их читает:

QGLContext::DefaultBindOption LinearFilteringBindOption | InvertedYBindOption | MipmapBindOption In Qt 4.5 and earlier, bindTexture() would mirror the image and automatically generate mipmaps. This option helps preserve this default behavior.
А я все удивлялся, отчего у меня bindTexture для ~мегапиксельной картинки выполняется миллисекунд 20. Ну конечно, оно переворачивает изображение.

Оторвал. Стало быстрее раз в 10 минимум (на глазок, по профайлеру).

Из другого прекрасного:

  • Если использовать QOpenGLBuffer::bind() и потом, после рисования или заполнения, не сказать ему QOpenGLBuffer::release(), то в QGraphicsView/Scene отваливается отображение элементов, нарисованных стандартным путем (через addItem).
  • Если генерировать структуры руками (glBindTexture/glTexImage2D), но забыть про установку фильтрации, то текстура вовсе не отображается.
Как я уже писал, сколько же есть вещей, которые я предпочел бы не знать.

День прошел не зря.

OpenGL Qs

Сразу предупреждаю: с OpenGL я пытаюсь работать всего неделю (был еще подход к снаряду, но началось лето и я переключился на МонголиеКарелии), поэтому вопросы у меня, вероятно, глупые и вообще про разное.

Вопросов, собственно, три:

1. Допустим, у меня очень простая сцена, два треугольника, образуют прямоугольник, на них натягиваю текстуру (собственно, картинку, которую хочу показать).

Вопрос: есть ли смысл связываться с VBO или 6 пар вызовов glTexCoord2f()/glVertex2f() не будут заметно медленнее? А если прямоугольник не один, а, к примеру, 64 (картинка 8000x8000, а на предельный размер текстуры я заложусь как 1024x1024), будет ли заметный выигрыш, если загнать все в буфер(ы) и дергать рисование меняя только индексы?

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

2. В Qt5 есть (старые) QGL*-объекты, есть новые QOpenGL*.

Кто бы рассказал, в чем разница....

3. Ну и вообще, Qt-шные примеры, что из комплекта, что найденные в сети, какие-то частично безумные. То слишком простые, то вроде простой - а шейдеры там внезапно "#version 330", то - очень хороший пример boxes из поставки - но переусложненный, начинаешь от него куски отпиливать и все разваливается.

Нет ли каких-то Qt-OpenGL tutorials, которые бы с одной стороны были бы "современными" (в смысле используемых Qt-интерфейсов), интересными (не банальный QGLWidget::paintGL()), но и не слишком сложными.

Про Nvidia

Если кто вдруг не видел. На Supercomputers 2012 у Nvidia был свой уголок, NVidia Technology Theater. Где выступали всякие интересные люди со всякими интересными презентациями.

Если кто не видел, рекомендую пойти на архив записей и повтыкать. Там дурацкий интерфейс, надо в правом блоке (где "чат") ткнуть в закладку "видео" и пораскрывать ее. Скажем, про CARMA мне было весьма интересно.

Чтобы два раза не вставать: утро понедельника - время для общефилософских рассуждений

Мне ужасно не нравится, то что сейчас происходит в GPGPU-мире:

  • Есть Nvidia с CUDA и с аккуратно спрятанным под ковер OpenCL. То есть OpenCL 1.1 в драйверах есть, но компания делает вид, что никакого OpenCL в природе не существует. Где, к примеру, OpenCL 1.2? При этом, в HPC-области NVidia очевидный лидер, если кто-то делает HPC-софт, то делает он его в первую очередь под CUDA (ну, насколько я вижу).
  • Есть OpenCL, в который кинулся весь остальной мир. И на CPU и на GPU и на x86 и на ARM и на прочих архитектурах. Если писать что-то для более-менее массового юзера, то очевидно что на OpenCL, ибо рынок куда шире.
Душераздирающее зрелище.

Про Qt5: книжки? примеры? руководства?

По случаю выхода Qt5 Beta2, хочу ею овладеть.

Причем, овладеть по-взрослому, по-мужски!

Ну то есть вот в RawDigger я утомился рисовать собственно GUI на C++, очень хочу делать это декларативно, в грубой форме, на Javascript-е. Особенно это касается всяких форм с большим количеством элементов, но и всего остального гуя - тоже.

Проблема только в том, что я совершенно не представляю себе, как это сделать. Ну то есть этот язык у меня в состоянии "читаю, что-то понимаю, сам написать не могу". При этом, понятно, одним QML+JS у меня никак не обойдется, какие-то core-вещи всяко на C++, а дальше как-то с ними интегрироваться.

Вопрос: а есть ли какие-то систематические источники информации. В свое время пара книжек по Qt4 мне очень помогли. Я их не читал, но пролистал и многое - осознал. Хочу такого же, но для Qt5+QML2. Или не такого же, другого. Каких-то писучих блоггеров, которые про Qt5 пишут, может быть какие-то живые проекты, не знаю. Посоветуйте.

RawDigger 0.9.13 - второй релиз-кандидат

Кто скачал "RC1" (т.е. по ссылкам из предыдущего поста до 22:10 10.11.12 время Московское) - возьмите теперь RC2. Исправления:
  • 'Next File' не работала на первом файле каталога (да, я так тестирую :) - у меня в тестовом каталоге, так уж совпало, первый файл лежит неподдерживаемого формата и на него я никогда не попадал).
  • Если Next или Prev - запрещена т.к. мы дошли до одного из краев, то при смене порядка сортировки в Preferences - это запрещение сбрасывается.

RawDigger 0.9.13 (RC3)

Граждане фотографы!

Вашему вниманию предлагается RawDigger 0.9.13 Release Candidate 1 2 3:

Update: В RC2 исправлена бага с "залипанием" на первом файле каталога: на нем не работало "Next file".

Часть из этих изменений уже была показана изумленной публике, а часть - совсем свежая.

Документация пока не обновлена, остается от версии 0.9.12, поэтому привожу

Changelog с комментариями

О современных процессорах и несовременных алгоритмах

В продолжение разговора, который кратко звучал на highload (в вопросах и ответах) и чуть подробнее - когда я с той же презентацией был в Mail.ru.

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

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

   for x in data:
        n = n + 1
        delta = x - mean
        mean = mean + delta/n
        M2 = M2 + delta*(x - mean)
 
    variance = M2/(n - 1)
    return variance
Плохо тут сразу два места: деления (все еще медленные) и зависимость между инструкциями (которая мешает локально векторизовать, впрочем векторизацию в общем случае тут вообще трудно применить т.к. каналы в данных перемежаются "произвольно". Ну то есть не вполне произвольно, но паттернов возможных много). Ну и в лоб не параллелится (на крупном уровне), впрочем для дисперсии объединения есть простая формула и это несущественно.

Индикация пересветов в RawDigger: версия для Mac и обновление виндовой.

Если кто скачал версию "OE1" из предыдущего поста, то самое время ее стереть и взять новую. Если кто хотел маковскую версию, то вот она: Изменения (в виндовой версии) касаются тех режимов, которые я сам не использую, а потому и не тестировал:
  • На "черной рамке" не рисуется область недодержки.
  • При показе RAW в режиме "1 пиксель на пиксель" (а не размазывание пиксела на 2x2) - нет противного серого фона.

RawDigger: индикация пересветов (и челубеев)

Индикация выбитых светов (и недодержаных теней) - сделана.

Пока - в виде беты, нужно тестировать, смотреть что удобно, что неудобно, что не работает и так далее. Ну и оптимизировать скорость отрисовки. Но пробовать уже можно.

Выглядит это так:

В окошке Display появились пимпы OvExp и UnExp, если их включить, то отрисовываются выбитые пикселы (красным, как в ACR) и недодержаные (синим).

В окошке OvExp/UnExp Stats - показывается статистика по пикселам по всему изображению. Сколько выбито в штуках и в процентах (от общего количества пикселов данного цвета).

На удивление, оказалось что даже отрисовка одним цветом позволяет отличить места, где выбит один канал - от выбитых двух и трех каналов. При просмотре одного канала (RawChannel) - показываются выбитые/недодержаные пикселы только в том канале, который просматривается.

Естественно, уровни отсечки сверху и снизу - настраиваются. Мануал пока не правился, поэтому опишу настройки прямо тут.

Презентация с Highload

По просьбам трудящихся масс, моя презентация с Хайлоада:

Никаких откровений нет, задача была - показать что multicore/simd - это очень просто и стоит того. Читатели моего уютненького легко узнают примеры 1.5-2-летней давности.

Анимированность Slideshare порезала, но вроде накрывающих друг друга картинок у меня нет.

Временная девиртуализация

В понедельник (с обеда и до вечера) и во вторник (весь день, плюс-минус) буду на Highload. Кому нужен - ловите там.

Я там даже выступаю в этот раз но на данную секунду - не знаю даже в какой день, что уж говорить о времени, в понедельник в 17:45 в третьем зале.

Pages

Subscribe to Программирование