Войти
ПрограммированиеФорумГрафика

OpenGL Вопросы (5 стр)

Страницы: 14 5 6 756 Следующая »
#60
13:15, 10 ноя 2014

Блин. Тестил в дебаге))
Перевел в релиз с -O2

dirty прямая
0.203168
0.201715
0.206481

без dirty прямая
0.516027
0.514201
0.512298

MrShoor
Я уже думаю как организовать классы для такого рендеринга. Детально с ними не разбирался, так что это скорее всего надолго.

Update.
Не там убирал проверку. Разница двукратная.

#61
13:20, 10 ноя 2014

Dampire
> Короче что с dirty, что без разница незначительная на самом деле.
Твой тест не совсем корректен. У тебя по дефолту dirty сброшен, так что ты всегда считаешь

Вернее не так. 1 цикл ты считаешь всегда, а остальные 2 ты просто скипаешь если флаг dirty.

Я же говорю на таком тесте ты не проверишь. И как я сказал у тебя тяжелый апдейт.

1. Тебе лучше иметь два флага 1 для мировой матрицы, 2й для инверсной.
2. Инверсную считать только по запросу.

const glm::mat4 & Transform::GetMatrix()
{
    if(dirtyInverse)
    {
        inverse = matrix.Inverse();
     }

    return inverse;
}

Эта функция будет вызываться только в случае если тебе действительно нужна инверсная матрица.

3. Если посмотреть внимательно на твой код:

matrix = glm::translate(glm::mat4(1.f), position); // glm::vec3 position
    matrix = matrix * glm::toMat4(rotation);  // glm::quaternion rotation
    matrix = glm::scale(matrix, scale); // glm::vec3 scale
    matrixInverse = glm::inverse(matrix);

    if(parent)
    {
        matrix = parent->GetWorldMatrix() * matrix;
        matrixInverse = parent->GetWorldMatrixInv() * matrixInverse;
    }

первые 3 строчки тебе вообще не нужны. Передавай в объект локальную матрицу а все трансформации с ней делай снаружи.

matrixInverse = glm::inverse(matrix);

тоже не нужна поскольку операция очень дорогая, а эта матрица нужна не так часто.

    if(parent)
    {
        matrix = parent->GetWorldMatrix() * matrix;
        matrixInverse = parent->GetWorldMatrixInv() * matrixInverse;
    }

Собственно у тебя тут останется только  matrix = parent->GetWorldMatrix() * matrix;
В данном случае лучше хранить две матрицы:

local = это собственно локальная матрица объекта
world = parent->matrix * matrix;

для корневого объекта local == world

#62
13:27, 10 ноя 2014

Стас
Ну? А в реальной ситуации как? Что не так то?
dirty/без dirty означает что проверка на условие запилена или выпилена соответственно, а не то, что, я предполагаю, ты подумал. Когда проверка на dirty присутствует оно быстрее в 2.5 - 3 раза.

#63
13:41, 10 ноя 2014

Dampire
У тебя неправильный тест. Вот, смотри:

+ Бенчмарк

Выводит:

Test_OO_no_dirty: 1.13998
Test_OO_dirty: 0.629987
Test_DO_dirty: 0.249995
Test_DO_no_dirty: 0.269995

Какие из этого можно сделать выводы?
1. Data driven в 2 раза эффективнее, чем object-oriended с dirty флагом
2. Test_DO_dirty просчитывает в 2 раза _меньше_ матриц, чем Test_DO_no_dirty, при этом по времени выполнения они почти не отличаются. То есть стоимость кэш-мисса == 2 апдейта матриц.

Где кешмисс?

        Test_DO_dirty* item = &data[i + j];
        if (!item->dirty) {
          item->dirty = !item->dirty;
          continue;
        }

        if (item->dirty) {
          item->matrix = XMMatrixIdentity();
          item->matrix = XMMatrixMultiply(item->matrix, item->matrix);
          item->matrix = XMMatrixMultiply(item->matrix, item->matrix);
          item->matrix = XMMatrixMultiply(item->matrix, item->matrix);
        }

Вот тут кешмисс - проверка на dirty флаг и ранний выход из цикла. Как видишь, нифига это не оптимизация :)

Ну и нужно также помнить, что это очень синтетический пример и в реальном мире кешмисс будет намного дороже.

#64
13:50, 10 ноя 2014

Да бесполезно это обьяснять, когда чел размахивает пейпером как флагом... Хотел я написать сразу же, да в лом было. Там прям какая то идеальная ситуайия) и обьекты выровнены, и transform занимает 12 тактов, ппичем код трасформа не указан, красота. 12 тактов, жто допустим 12 сложений, при условии что данныкюе УЖЕ в регистрах, а их то надо еще грузить и чтение со второго кеша ну нифига не однотактовое. Да и лишний jmp к функции transform стоит тактов.

#65
13:51, 10 ноя 2014

Zloten
Я вот привёл тест. Что в нём не так?

#66
13:57, 10 ноя 2014

bazhenovc
Не понял, а зачем два раза проверять флаг?

#67
14:00, 10 ноя 2014

bazhenovc
> Ну и нужно также помнить, что это очень синтетический пример и в реальном мире
> кешмисс будет намного дороже.

Ну пример и правда уж очень синтетический. Ты просто показываешь вычисление матрицы. А у него в апдейте как минимум штук 5 умножений + инверсия... так что в его случае dirty флаг как раз дает прирост,
И то что ты показываешь крайне сложно показать синтетическими тестами

#68
14:00, 10 ноя 2014

Zloten
Вторая проверка не вызывает кешмисс и ни на что не влияет. Я его убрал - результаты не изменились.

        Test_DO_dirty* item = &data[i + j];
        if (!item->dirty) {
          item->dirty = !item->dirty;
          continue;
        }
        
        item->matrix = XMMatrixIdentity();
        item->matrix = XMMatrixMultiply(item->matrix, item->matrix);
        item->matrix = XMMatrixMultiply(item->matrix, item->matrix);
        item->matrix = XMMatrixMultiply(item->matrix, item->matrix);
#69
14:02, 10 ноя 2014

bazhenovc
Это неправильные пчелы и они делают неправильный мед. Я понял твою позицию. И я сделаю с проверкой флага, просто потому-что в моем коде оно работает быстрее. Когда перестанет - уберу.

#70
14:02, 10 ноя 2014

Хм, чтение item->dirty, здесь ту уже по любому получаешь кеш-мисс, ту УЖЕ залез в обьект. Поэтому и разницы нет.

#71
14:08, 10 ноя 2014

Стас
> Ну пример и правда уж очень синтетический. Ты просто показываешь вычисление
> матрицы. А у него в апдейте как минимум штук 5 умножений + инверсия...
Применение data driven подхода будет давать прирост перформанса в любом случае, независимо от количества умножений.

С dirty флагом сложнее - он действительно не всегда выгоден, поэтому нужно профилировать и смотреть следующие вещи:
1. Будет ли dirty флаг дороже, чем тупо посчитать лишнее?
2. Если dirty флаг даёт серьёзный прирост, может попробовать переписать/оптимизировать математику?
3. Окупается ли выигрыш по перформансу, достигнутый такими оптимизациями? (имеется в виду затраченное программерское время на написание и будущую поддержку этого кода)

#72
14:10, 10 ноя 2014

Zloten
> Хм, чтение item->dirty, здесь ту уже по любому получаешь кеш-мисс, ту УЖЕ залез
> в обьект. Поэтому и разницы нет.
Нет, объект уже находится в кеше, потому что я его туда префетчил. Кешмисс возникает на следующей итерации цикла, когда в кеше внезапно оказывается не тот объект.

#73
14:12, 10 ноя 2014

Стас
Я уже переделал под инверсию/прямую. Есть 2 флага и 2 функции апдейта матрицы. Хранить локальную и глобальную я не хочу, потому-что я пока не вижу примеров использования локальной матрицы. Позиция/вращение/размер у меня всегда относительно родителя, матрица же всегда мировая.

#74
14:37, 10 ноя 2014

А зачем его префетчить? если он ВОЗМОЖНО не понадобиться? Как пример хранить дерти флаг в младшем бите указателя на обьект:

struct UObject {
  Matrix4 data1;
  Matrix4 data2;
};

void transform( UObject* objects, Matrix4* matrix ) {
  // do something
}

void update( UObject** objects, Matrix4* matrix ) {
  uint32 num = 1000;
  do {
    uint32 addr = (uint32) *objects;
    if ( UNLIKELY( addr & 1 ) ) {
      transform( *objects = (UObject*) ( addr & ~1 ), matrix );
    }
    objects++;
  } while ( --num );
}

ЗЫ И если ты заранее префетчишь то все возможные кеш-мисы ты уже словил.

Страницы: 14 5 6 756 Следующая »
ПрограммированиеФорумГрафика