Недавно столкнулся с весьма неприятным багом в движке The Great Tribes.
После обновления драйвера AMD игра начала намертво зависать при перемещении камеры, особенно когда на карте открывалась большая территория. Иногда зависал графический драйвер, иногда JVM падала внутри atio6axx.dll.
Самое интересное — на старом драйвере и других видеокартах всё работало нормально!
Начались поиски. Под подозрение попало практически всё: многопоточность OpenGL, VAO, VBO, индексные буферы, тени, модели юнитов и даже glfwSwapBuffers().
Постепенно удалось выяснить, что зависание вызывает отрисовка поверхности карты. А затем внимание переключилось на фрагментный шейдер.
В нём обнаружилась вот такая конструкция:
int segment = (3 - int(min(3, outTexCoord.y * 4.0))) * 4 + int(min(3, outTexCoord.x * 4.0));
Переменная segment использовалась для обращения к массивам из 16 элементов. Проблема заключалась в том, что координаты ограничивались сверху, но не снизу. При отрицательных текстурных координатах индекс мог выходить за пределы массива.
Исправление оказалось удивительно простым:
ivec2 cell = clamp(ivec2(floor(outTexCoord * 4.0)), ivec2(0), ivec2(3));int segment = (3 - cell.y) * 4 + cell.x;
И зависания исчезли!
Получилась отличная иллюстрация неопределённого поведения в GLSL. Старый драйвер каким-то образом справлялся с некорректным обращением к массиву, другие видеокарты тоже не показывали проблемы, а новая версия драйвера AMD превратила его в настоящий кошмар.
Мораль истории: если ваш шейдер прекрасно работает на одной видеокарте, это ещё не означает, что в нём нет ошибок.
А иногда за многочасовой отладкой собственного 3D-движка скрываются всего две строчки кода. 😁
P. S. Я уже десять лет разрабатываю собственный игровой движок на Java, LWJGL и OpenGL для стратегии The Great Tribes. За это время накопилось немало интересных историй — от многопоточности рендеринга до оптимизации огромных игровых карт и работы с графическими драйверами.
Если вам интересна внутренняя кухня разработки собственного 3D-движка без Unity и Unreal, напишите в комментариях. Возможно, стоит сделать из этого небольшую серию технических статей. 🙂
ссылка на оригинал статьи https://habr.com/ru/articles/1100744/