Я думаю, я отримую те, що ти намагаєшся запитати. Я припускаю, що ваша основна проблема - це неоднорідні змінні, визначені поза main()
:
float left;
float right;
float mscaled;
float xn;
float xm;
Давайте подивимось, як працюють GPU та GLSL. У GPU немає стека або записів активації виклику. Не існує способу імітувати область чи локальні змінні в GLSL, як це може зробити компілятор C для більшості процесорів. Все, що існує, - це регістри, які є або однорідними регістрами, входами, виходами на етапі шейдерів, і локальним файлом регістрів, унікальним для виклику шейдера.
Іншими словами, оскільки не існує такого поняття, як функція, стек чи купа, усі змінні, заявлені де-небудь, містяться в реєстрі. Незалежно від того, чи є вони локальними для певного обсягу в GLSL або глобальними для всього файлу, це не має ніякого значення. Вони просто регістри.
Однак розподільник регістра не є частиною стандарту GLSL. Різні реалізації OpenGL можуть мати різний рівень якості, що стосується перетворення високого рівня GLSL-коду в машинний код низького рівня, який розуміє GPU. Однією з найбільш складних частин компілятора (GLSL або іншим способом) є розподіл регістрів . Це та частина компілятора, яка визначає, які регістри займає дана змінна. У C це трохи складніше, оскільки, як правило, доводиться мати справу з дуже крихітними файлами реєстру (особливо на x86), і йому доводиться мати справу з розливом реєстру (переміщення змінних в стек) і згладжуванням (збереження змінних назад в ОЗУ перед викликом функцій) і непарні інструкції, які вимагають, щоб вихід був у певному реєстрі (x86)idiv
наприклад). У графічних процесорах є великий реєстр-файл через відсутність стека чи купи, тож розподільник може бути простішим.
Однак файл реєстру не є нескінченним. Якщо у вас більше змінних, ніж регістри, що підтримуються вашим обладнанням, компілятору доведеться спробувати помістити всі ваші змінні в регістри. Зазвичай для цього потрібна певна форма перевірки діапазону життєдіяльності . Тобто, якщо ви використовуєте змінну xn
для одного обчислення, то ніколи не використовуйте її знову, компілятор може визначити це, а потім знати, що реєстр, зайнятий, xn
може бути використаний згодом іншою змінною, таким чином дозволяючи отримати більше змінних, ніж є регістри (так довго оскільки одразу не так вже й багато живих змінних).
Однак компілятор цього не може зробити. Цього не має. Або це може зробити це лише в деяких випадках. Області застосування спрощують компілятори набагато простіше вирішити проблему. Усі регістри, призначені місцевим змінним функцій, можна повторно використовувати після того, як ця функція вийде, оскільки вона знає, що змінні є мертвими. Глобальні змінні не мають такої легкої гарантії. Отже, деякі менш здібні компілятори можуть також не оптимізувати своє життя, і глобальні змінні завжди з'їдають реєстр. Це не зробить нічого повільніше, але на деяких драйверах це може обмежити розмір шейдера, який ви можете записати.
Загалом, я б дуже рекомендував зберігати всі змінні локалізованими. Тримайте визначення максимально наближеним до використання змінної, наскільки це має сенс. Це стосується всіх мов програмування, а не лише GLSL. Я також рекомендую робити кожен "змінний" const у кожному можливому випадку. Знову це може бути натяком на деякі менш здатні компілятори, що можливі певні оптимізації, і що ще важливіше, це робить ваш код більш самодокументованим та легким у обслуговуванні.
І звичайно, ось ваша обов'язкова порада "просто перевірити та дізнатися точно". Напишіть свій шейдер із і без глобалістів та профіліруйте його. Будь-які поради щодо ефективності роботи в Інтернеті повинні бути недовірливими та вважати, що вони можуть бути вичерпані у припущеннях або застарілих.
main()
функцію? Чи є ваші значення насправді глобальними змінними (обмундирування чи атрибути в мові GLSL) або постійними значеннями?