У меня есть приложение 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?