Насколько способен OpenGL Vertex Shader? Сколько квадов можно нарисовать? - PullRequest
1 голос
/ 06 апреля 2019

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

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

Можем ли мы оптимизировать написанный мной код или это ограничение GPU и OpenGL-ES?

Код:

`

    <script type="vertexShader" id="vertexShader">
    #version 300 es
    in vec3 position;
    in vec4 color;
    out vec4 fcolor;
    void main () {
        gl_Position = vec4(position, 1.0);
        fcolor = color;
    }
</script>

<script type="fragmentShader" id="fragmentShader">
    #version 300 es
    precision mediump float;
    in vec4 fcolor;
    out vec4 finalColor;
    void main () {
        finalColor = vec4(fcolor);
    }
</script>
    var gl, canvas;
    gl = initWebGLCanvas('canvas');
    var program = getProgram('vertexShader', 'fragmentShader', true);
    document.getElementById('numOfGrids').oninput = function () {
        clearCanvas(gl);
        this.value = this.value || 1;
        this.value = this.value >= 0 ? this.value : 0;
        var gridVertices = createGridVerticesBuffer(this.value || 1);
        enableVerticesToPickBinaryDataWithinGPU(program, 'position', 'color');
        fetchDataFromGPUAndRenderToCanvas({
            positionIndex : gl.positionIndex,
            vertices : gridVertices,
            positionSize : 3,
            stride : 7,
            colorIndex : gl.colorIndex,
            colorSize : 4,
            positionoffset : 0,
            colorOffset : 3,
            startIndexToDraw : 0,
            numOfComponents : 6
        }, gl);
    };

        var r = [1.0, 0.0, 0.0, 1.0];
var g = [0.0, 1.0, 0.0, 1.0];
var b = [0.0, 0.0, 1.0, 1.0];
var z = 0.0;

var createGridVerticesBuffer = (gridsRequested) => {
    var vertices = [
        1.0, -1.0, z, r[0], r[1], r[2], r[3],
    -1.0, 1.0, z, g[0], g[1], g[2], g[3],
    -1.0, -1.0, z, b[0], b[1], b[2], b[3],

    1.0, -1.0, z, r[0], r[1], r[2], r[3],
    -1.0, 1.0, z, g[0], g[1], g[2], g[3],
    1.0, 1.0, z, b[0], b[1], b[2], b[3]];

    var vertexArray = [];
    var factor = 2.0/gridsRequested;
    var areaRequired = -1.0 + factor;
    vertices[21] = vertices[0] = areaRequired;
    vertices[15] = vertices[1] = -areaRequired;

    vertices[22] = -areaRequired;
    vertices[35] = areaRequired;
    vertices[36] = vertices[8];
    vertexArray.push(vertices);
    var lastVertices = vertices.slice();
    var processX = true;
    for (var i = 1; i <= gridsRequested * gridsRequested - 1; i++) {
        var arr = lastVertices.slice();
        if (processX) {
            arr[21] = arr[0] = lastVertices[0] + factor;
            arr[28] = arr[7] = lastVertices[35];
            arr[8] = lastVertices[36];
            arr[14] = lastVertices[0];
            arr[15] = lastVertices[1];
            arr[35] = lastVertices[35] + factor;
        } else {
            arr[22] = arr[1] = lastVertices[1] - factor;
            arr[29] = arr[8] = lastVertices[8] - factor;
            arr[15] = lastVertices[15] - factor;
            arr[36] = lastVertices[36] - factor;
        }
        vertexArray.push(arr);
        if ((i + 1) % gridsRequested === 0) {
            lastVertices = vertexArray[i + 1 - gridsRequested];
            processX = false;
        } else {
            processX = true;
            lastVertices = arr;
        }
    }
    return createBuffers(gl, vertexArray, true);

};

`

1 Ответ

0 голосов
/ 07 апреля 2019

Вы задали не отвечающий вопрос

Сколько квадов можно нарисовать?

О каком устройстве идет речь? А малиновый пи? IPhone 2? ПК с Windows с NVidia 2080 RTX? Какого размера квады? Что делает ваш фрагментный шейдер?

В любом случае проблема, с которой вы сталкиваетесь, - это не проблема вершинного шейдера, это проблема шейдера fragement. Рисование пикселей требует времени. Рисование говорит, что квадратор 1024x1024 рисует 1 миллион пикселей. Рисование сотен квадратов 1024x1024 - 100 миллионов пикселей. Пытаясь сделать это 60 раз в секунду, мы просим нарисовать 6 миллиардов пикселей.

Измените все квадраты на 1x1 пиксель, и он будет работать очень хорошо, потому что тогда вы только просите его рисовать 6000 пикселей в секунду.

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

Я бы предположил, что общее практическое правило заключается в том, что большинство графических процессоров могут рисовать только от 2 до 12 полноэкранных квадроциклов со скоростью 60 кадров в секунду. Я просто вытащил это число из ниоткуда, но, например, оригинальный Android-графический процессор мог рисовать только 1,5 полноэкранных четырехугольника с частотой 60 кадров в секунду. Я думаю, что Raspberry PI это, вероятно, меньше 4. Я знаю, что Intel Graphics 2015 (не знаю, какая модель) может сделать около 7 при 1280x720. Мой MacBook Air 2019 может работать примерно с 3 (его разрешение составляет 2560x1600, что примерно равно 12 экранам при 1280x720.

Что касается сбоя графического процессора, то сбой не произошел, скорее браузер или операционная система перезагрузили графический процессор, потому что это заняло слишком много времени. Большинство графических процессоров (по состоянию на 2019 г.) имеют многозадачность , а не , как ЦП. Процессор может быть прерван и переключен на что-то другое. Таким образом, ваш компьютер может одновременно запускать множество приложений и сервисов. Большинство графических процессоров не могут этого сделать. Они могут делать только одну вещь одновременно. Таким образом, если вы дадите им 30 секунд работы за один раз, они будут выполнять 30 секунд работы без перерывов. Это не очень хорошо для ОС, так как ей нужен графический процессор для обновления окон и запуска других приложений. Итак, ОС (и некоторые браузеры) время каждого вызова отрисовки. Если один вызов отрисовки занимает больше определенного времени, они сбрасывают графический процессор и часто убивают программу или страницу, которые просили графический процессор сделать что-то, что заняло слишком много времени.

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

Если вам действительно нужно нарисовать перекрывающиеся квадраты или выполнить какое-то вычисление, которое занимает много времени, то вам, вероятно, нужно найти способ разбить его на более мелкие операции для каждого вызова отрисовки. Обрабатывайте 5 четырехугольников на каждый вызов отрисовки и используйте 5 вызовов отрисовки вместо одного с 25-ю. Обрабатывайте больше меньших четырехугольников вместо меньшего количества больших четырехугольников и т. Д ...

...