Как две строки GLSL едва не свели меня с ума 😁
Недавно столкнулся с весьма неприятным багом в движке The Great Tribes.
После обновления драйвера AMD игра начала намертво зависать при перемещении камеры, особенно когда на карте открывалась большая территория. Иногда зависал графический драйвер, иногда JVM падала внутри atio6axx.dll.
Самое интересное — на старом драйвере и других видеокартах всё работало нормально!
Начались поиски. Под подозрение попало практически всё: многопоточность OpenGL, VAO, VBO, индексные буферы, тени, модели юнитов и даже glfwSwapBuffers().
Постепенно удалось выяснить, что зависание вызывает отрисовка поверхности карты. А затем внимание переключилось на фрагментный шейдер.
В нём обнаружилась вот такая конструкция:
Переменная segment использовалась для обращения к массивам из 16 элементов. Проблема заключалась в том, что координаты ограничивались сверху, но не снизу. При отрицательных текстурных координатах индекс мог выходить за пределы массива.
Исправление оказалось удивительно простым:
И зависания исчезли!
Получилась отличная иллюстрация неопределённого поведения в GLSL. Старый драйвер каким-то образом справлялся с некорректным обращением к массиву, другие видеокарты тоже не показывали проблемы, а новая версия драйвера AMD превратила его в настоящий кошмар.
Мораль истории: если ваш шейдер прекрасно работает на одной видеокарте, это ещё не означает, что в нём нет ошибок.
А иногда за многочасовой отладкой собственного 3D-движка скрываются всего две строчки кода. 😁