Что, если какую-либо операцию я могу использовать для проверки точности GLSL int на заявленную точность? - PullRequest
0 голосов
/ 26 апреля 2020

У меня есть приложение OpenGL ES 2.0, которое получает разные результаты для mediump против highp. Имеет общий смысл.

За исключением того, что если я запрашиваю

int range[2], precision;
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_HIGH_FLOAT, range, &precision);
printf("Fragment shader high precision float range: %d %d precision: %d\n", range[0], range[1], precision);
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT, range, &precision);
printf("Fragment shader medium precision float range: %d %d precision: %d\n", range[0], range[1], precision);

Оба печатают одно и то же

Fragment shader high precision float range: 127 127 precision: 23
Fragment shader medium precision float range: 127 127 precision: 23

Это похоже на ошибку в драйвере, которая отстой, и я Я отправлю сообщение об ошибке (при условии, что это ошибка в драйвере)

Для mediump float я смог сделать тест.

int range[2], precision;
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_HIGH_FLOAT, range, &precision);

float value = sqrtf(powf(2.0f, precision) - 1.0f);

Я загружаю это через mediump равномерно в шейдер как в

glUniform3f(vLocation, value, value, value);

для этого шейдера

    precision mediump float;
    uniform mediump vec3 v;
    void main() {
      gl_FragColor = vec4(normalize(v) * 0.5 + 0.5, 1);
    }

и glReadPixels результат. Результат должен быть 0,577, что составляет около 146 при преобразовании в 8-битный цвет, поэтому я проверяю на ~ 146

И тестирование работает. Устройство не проходит тест, потому что сообщает о неверной точности, но другие устройства сообщают о правильной прохождении.

На самом деле понадобилось время, чтобы найти тест, который не прошел, и я не уверен, почему. Мой первоначальный тест был просто

precision mediump float;
uniform mediump vec2 v;
void () {
  gl_FragColor = vec4(v.x / v.y);
}

И я бы прошел

float value = powf(2.0f, precision) - 1.0f;
glUniform2f(vLocation, value / 2, value);

Я думал, что если внутренне это действительно 16-битный медиум, тогда vx будет 4194303, а vy будет 8388607, что даст неправильный результат, но это не так. Я понимаю, что драйвер не обязан использовать самую низкую точность в любом месте, но все же, ... То, что заставило меня заметить ошибку драйвера, в первую очередь, было зеркальным результатом, отличающимся, поэтому я переключился на использование normalize для моего test, который выявил проблему.

Во всяком случае, теперь я хочу сделать аналогичный тест для mediump int , но я не могу найти тест, который не проходит. Вы не можете вызвать normalize для ivec3, например.

Моя первая попытка была получить наибольшее значение int на основе указанного диапазона [1], разделить на 2, 4, 8 и 16 в дюймах , загрузить в шейдер через форму, в шейдере умножить на 2, 4, 8, 16. Результатом каждого должно быть значение, разделенное на значение * 2, 4, 8, 16. Если драйвер сообщает неправильный range[1] для mediump (что это, он сообщает 31, но я знаю, что это 15), тогда он должен переполниться и получить неправильный результат.

    precision mediump float;
    uniform mediump ivec4 v;
    uniform mediump ivec4 expected;

    ivec4 iabs(ivec4 v) {
      return ivec4(
        v.x < 0 ? -v.x : v.x,
        v.y < 0 ? -v.y : v.y,
        v.z < 0 ? -v.z : v.z,
        v.w < 0 ? -v.w : v.w);
    }

    void main() {
      mediump ivec4 t = ivec4(2, 4, 8, 16);
      mediump ivec4 m = v * t;
      mediump ivec4 diff = iabs(m - expected);
      mediump ivec4 maxDiff = ivec4(4);
      bvec4 pass = lessThan(diff, maxDiff);
      gl_FragColor = pass;
    }

Но это проходит, хотя я знаю, что GPU использует только 16 бит для mediump и эти значения передаются в тест, потому что rangeMax неверен из драйвера

v = 536870910, 268435454, 134217726, 67108862
expected = 1073741820, 1073741816, 1073741808, 1073741792

Любая идея, какой другой тест я могу использовать, чтобы проверить фактическую точность mediump int> = сообщенную точность mediump int?

...