GLSL в то время как производительность цикла не зависит от работы внутри нее - PullRequest
1 голос
/ 01 июля 2019

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

Код пересечения BVH основан на следующей идее:

bool BVHintersects( Ray ray ) {

    Object closestObject;

    vec2 toVisit[100]; // using a stack to keep track which node should be tested against the current ray
    int stackPointer = 1;
    toVisit[0] = vec2(0.0, 0.0);  // coordinates of the root node in the BVH hierarcy    



    while(stackPointer > 0) {
        stackPointer--;  // pop the BVH node to examine

        if(!leaf) {
            // examine the BVH node and eventually update the stackPointer and toVisit
        }

        if(leaf) {
            // examine the leaf and eventually update the closestObject entry
        }
    }
}

Проблема с приведенным выше кодом состоит в том, что при втором отскоке света происходит нечто очень странное, если предположить, что я рассчитываю отскок света следующим образом:

vec3 color  = vec3(0.0);
vec3 normal = vec3(0.0);
// first light bounce
bool intersects = BVHintersect(ro, rd, color, normal);

vec3 lightPos = vec3(5, 15, 0);

// updating ray origin & direction
ro = ro + rd * (t - 0.01);
rd = normalize(lightPos - ro);

// second light bounce used only to calculate shadows
bool shadowIntersects = BVHintersect(ro, rd, color, normal);

Второй вызов BVHintersect будет выполняться бесконечно,потому что цикл while никогда не завершается, но из многих тестов, которые я сделал для этого второго вызова, я уверен, что stackPointer в конечном итоге успешно возвращается к 0, фактически, если я помещаю следующий код сразу под циклом while:

int iterationsMade = 0;
while(stackPointer > 0) {
    iterationsMade++;
    if(iterationsMade > 100) {
        break;
    }
    // the rest of the loop
    // after the functions ends it also returns "iterationsMade"

переменная "iterationsMade" всегда меньше 100, цикл while не работает бесконечно, но с точки зрения производительности это похоже на то, как если бы я делал "100" итераций, даже если "iterationsMade" никогда не больше, чем, скажем, 10 или20. Увеличение жестко закодированного значения «100» до большего значения может линейно ухудшить производительность

Что может бытьвозможные причины такого поведения?Какова возможная причина для того, чтобы второй вызов BVHIntersect застрял внутри цикла while, если он никогда не выполняет более 10-20 итераций?

Источник для функции BVHintersect: https://pastebin.com/60SYRQAZ

1 Ответ

1 голос
/ 01 июля 2019

Итак, в шейдерах (или в большинстве SIMD-обстоятельств) есть забавная вещь:

Вся волна будет исполняться как минимум медленнее. Таким образом, если одному потоку необходимо выполнить ~ 100 итераций, тогда они ВСЕ будут использовать 100 итераций. В зависимости от вашей платформы и компилятора цикл может быть развернут до 100 итераций (или любой другой верхней границы, которую вы выберете). Что-нибудь после break не повлияет на конечный результат, но остальная часть развернутого цикла все равно должна быть обработана. Ранний выход не всегда возможен.

Есть несколько способов обойти это, но, возможно, самый простой - это сделать это в несколько проходов с меньшим значением max итераций.

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

См. Этот ответ для получения дополнительной информации.

...