Tôi nghĩ rằng tôi nhận được những gì bạn đang cố gắng hỏi. Tôi giả sử mối quan tâm chính của bạn là các biến không đồng nhất được xác định bên ngoài main()
:
float left;
float right;
float mscaled;
float xn;
float xm;
Chúng ta hãy xem cách GPU và GLSL hoạt động. GPU không có ngăn xếp hoặc hồ sơ kích hoạt cuộc gọi. Không có cách nào để mô phỏng phạm vi hoặc các biến động cục bộ trong GLSL như trình biên dịch C có thể thực hiện trên hầu hết các CPU. Tất cả những gì tồn tại là các thanh ghi, là các thanh ghi thống nhất, đầu vào giai đoạn đổ bóng, đầu ra và tệp thanh ghi cục bộ duy nhất cho lệnh gọi shader đó.
Nói cách khác, vì không có thứ gọi là hàm hoặc ngăn xếp hay heap, tất cả các biến được khai báo ở bất cứ đâu sống trong một thanh ghi. Cho dù chúng là cục bộ đối với một số phạm vi trong GLSL hoặc toàn cầu đối với toàn bộ tệp, không có sự khác biệt. Họ chỉ là đăng ký.
Tuy nhiên, bộ cấp phát đăng ký không phải là một phần của tiêu chuẩn GLSL. Các triển khai OpenGL khác nhau có thể có các mức chất lượng khác nhau khi chuyển đổi mã GLSL cấp cao thành mã máy cấp thấp mà GPU hiểu. Một trong những phần phức tạp hơn của trình biên dịch (GLSL hay nói cách khác) là cấp phát đăng ký . Đây là một phần của trình biên dịch xác định đăng ký một biến đã cho. C khó hơn một chút vì nó thường phải xử lý các tệp đăng ký rất nhỏ (đặc biệt là trên x86) và nó phải xử lý việc tràn thanh ghi (di chuyển biến vào ngăn xếp) và bí danh (lưu biến trở lại RAM trước khi gọi hàm) và hướng dẫn lẻ yêu cầu đầu ra phải ở trong một thanh ghi cụ thể (x86'sidiv
ví dụ). GPU có tệp đăng ký ish lớn trên tài khoản không có stack hoặc heap, vì vậy việc cấp phát có thể đơn giản hơn.
Tuy nhiên, tập tin đăng ký không phải là vô hạn. Nếu bạn có nhiều biến hơn các thanh ghi được hỗ trợ bởi phần cứng của bạn, trình biên dịch sẽ phải thử phù hợp với tất cả các biến của bạn trong các thanh ghi. Điều này thường đòi hỏi một số hình thức kiểm tra phạm vi sống . Nghĩa là, nếu bạn sử dụng một biến xn
cho một phép tính sau đó không bao giờ sử dụng lại nó, trình biên dịch có thể xác định điều này và sau đó biết rằng thanh ghi bị chiếm dụng xn
có thể được sử dụng bởi một biến khác sau này, do đó cho phép nhiều biến hơn so với thanh ghi (rất lâu vì không có quá nhiều biến số sống cùng một lúc).
Trình biên dịch có thể không làm điều này, tuy nhiên. Nó không có. Hoặc nó có thể làm điều đó chỉ trong một số trường hợp. Phạm vi đưa ra trình biên dịch đơn giản hơn một vấn đề dễ dàng hơn để giải quyết. Tất cả các thanh ghi được phân bổ cho các biến chức năng cục bộ có thể được sử dụng lại sau khi hàm đó thoát vì nó biết các biến đã chết. Biến toàn cầu không có đảm bảo dễ dàng như vậy. Do đó, một số trình biên dịch có khả năng kém hơn cũng có thể không tối ưu hóa tuổi thọ của chúng và các biến toàn cục sẽ luôn ăn hết một thanh ghi. Điều này sẽ không làm cho mọi thứ chậm hơn nhưng có thể trên một số trình điều khiển giới hạn kích thước của trình đổ bóng bạn có thể viết.
Nói chung, tôi rất khuyên bạn nên giữ tất cả các biến cục bộ. Giữ định nghĩa càng gần với việc sử dụng biến càng có ý nghĩa. Điều này áp dụng cho tất cả các ngôn ngữ lập trình, không chỉ GLSL. Tôi cũng khuyên bạn nên tạo mọi "biến" const trong mọi trường hợp bạn có thể. Một lần nữa nó có thể là một gợi ý cho một số trình biên dịch có khả năng kém hơn mà tối ưu hóa nhất định là có thể, và quan trọng hơn, nó làm cho mã của bạn trở nên tự viết tài liệu hơn và dễ bảo trì.
Và tất nhiên, đây là lời khuyên "chỉ cần kiểm tra và tìm hiểu chắc chắn" của bạn. Viết shader của bạn có và không có toàn cầu của bạn và hồ sơ nó. Bất kỳ và tất cả các lời khuyên về hiệu suất trực tuyến nên được tin tưởng và được cho là bị chìm trong giả định hoặc lỗi thời.
main()
chức năng? Giá trị của bạn có thực sự là biến toàn cục (đồng phục hoặc thuộc tính theo cách nói GLSL) hoặc giá trị không đổi?