2009-04-29 29 views
15

Tần suất tôi nên gọi các chức năng OpenGL như glEnable() hoặc glEnableClientState() và các đối tác tương ứng glDisable của chúng? Có phải chúng được gọi một lần ở đầu ứng dụng hay tôi nên giữ chúng bị vô hiệu hóa và chỉ bật những tính năng mà tôi cần ngay lập tức để vẽ một cái gì đó? Có sự khác biệt về hiệu suất không?Tôi có nên gọi glEnable và glDisable mỗi khi tôi vẽ thứ gì đó không?

Trả lời

12

"Điều đó phụ thuộc".

Nếu toàn bộ ứng dụng của bạn chỉ sử dụng một kết hợp trạng thái bật/tắt, thì tất cả chỉ có nghĩa là thiết lập nó ở đầu và đi.

Hầu hết các ứng dụng trong thế giới thực cần trộn và sau đó bạn buộc phải gọi glEnable() để bật một số trạng thái cụ thể, thực hiện cuộc gọi vẽ, sau đó glDisable() lại khi bạn hoàn thành "xóa giai đoạn ".

Đề án phân loại nhà nước, theo dõi trạng thái và tối ưu hóa nhiều xuất phát từ điều này, vì chuyển đổi trạng thái đôi khi rất tốn kém.

15

Nếu bạn thấy rằng bạn đang kiểm tra giá trị của biến trạng thái thường xuyên và sau đó gọi glEnable/glDisable bạn có thể làm sạch mọi thứ một chút bằng cách sử dụng ngăn xếp thuộc tính (glPushAttrib/glPopAttrib).

Ngăn xếp thuộc tính cho phép bạn tách biệt các khu vực mã của bạn và những thay đổi thành thuộc tính trong một phần không ảnh hưởng đến trạng thái thuộc tính trong các phần khác.

void drawObject1(){ 
    glPushAttrib(GL_ENABLE_BIT); 

    glEnable(GL_DEPTH_TEST); 
    glEnable(GL_LIGHTING);  

    /* Isolated Region 1 */ 

    glPopAttrib(); 
}   

void drawObject2(){ 
    glPushAttrib(GL_ENABLE_BIT); 

    glEnable(GL_FOG); 
    glEnable(GL_GL_POINT_SMOOTH);  

    /* Isolated Region 2 */ 

    glPopAttrib(); 
}  

void drawScene(){ 
    drawObject1(); 
    drawObject2(); 
} 

Mặc dù GL_LIGHTINGGL_DEPTH_TEST được thiết lập trong drawObject1 nhà nước của họ không được bảo quản để drawObject2. Trong trường hợp không có glPushAttrib, điều này sẽ không xảy ra. Ngoài ra - lưu ý rằng không cần phải gọi glDisable ở cuối các cuộc gọi hàm, glPopAttrib thực hiện công việc.

Theo như hiệu suất, phí trên do các hàm gọi riêng lẻ đến glEnable/glDisable là tối thiểu. Nếu bạn cần xử lý nhiều trạng thái, có thể bạn sẽ cần tạo trình quản lý trạng thái của riêng bạn hoặc thực hiện nhiều cuộc gọi đến glGetInteger ... và sau đó hành động tương ứng. Máy móc và luồng điều khiển bổ sung có thể làm cho mã ít minh bạch hơn, khó gỡ lỗi hơn và khó bảo trì hơn. Những vấn đề này có thể làm cho những thứ khác, hiệu quả hơn, tối ưu hóa khó khăn hơn.

Ngăn xếp phân bổ có thể hỗ trợ trong việc duy trì các lớp trừu tượng và tạo các vùng cách ly.

glPushAttrib manpage

+0

.. và đối tác khách hàng của nó glPush/PopClientAttrib –

+1

Các chức năng này không được chấp nhận trong đường ống có thể lập trình. – andrewrk

0

Một nguyên tắc của ngón tay cái mà tôi được dạy cho biết rằng đó là hầu như luôn luôn rẻ hơn để chỉ bật/tắt tại sẽ chứ không phải là kiểm tra trạng thái hiện tại và chỉ thay đổi nếu cần thiết.

Điều đó nói rằng, câu trả lời của Marc là điều chắc chắn nên hoạt động.

8

Trước hết, bạn sử dụng phiên bản OpenGL nào? Và thế hệ phần cứng đồ họa nào mà nhóm mục tiêu của bạn có? Biết điều này sẽ làm cho nó dễ dàng hơn để đưa ra một câu trả lời đúng hơn. Câu trả lời của tôi giả định OpenGL 2.1.

OpenGL là một máy nhà nước, có nghĩa là bất cứ khi nào một nhà nước được thay đổi, trạng thái đó được làm "hiện tại" cho đến khi thay đổi một lần nữa một cách rõ ràng bởi các lập trình viên với một cuộc gọi OpenGL API mới. Ngoại lệ cho quy tắc này tồn tại, giống như các cuộc gọi mảng trạng thái máy khách làm cho màu đỉnh hiện tại không được xác định. Nhưng đó là những ngoại lệ xác định quy tắc.

"một lần ở đầu ứng dụng" không có ý nghĩa nhiều, bởi vì có những lúc bạn cần phá hủy ngữ cảnh OpenGL khi ứng dụng vẫn đang chạy. Tôi cho rằng bạn có nghĩa là chỉ sau mỗi lần tạo cửa sổ. Điều đó làm việc cho nhà nước bạn không cần phải thay đổi sau này. Ví dụ: Nếu tất cả các lệnh gọi vẽ của bạn sử dụng cùng một dữ liệu mảng đỉnh, bạn không cần phải vô hiệu hóa chúng bằng glDisableClientState sau đó.

Có rất nhiều trạng thái bật/tắt được liên kết với đường ống chức năng cố định cũ. Việc mua lại dễ dàng cho việc này là: Sử dụng trình đổ bóng! Nếu bạn nhắm mục tiêu một thế hệ thẻ nhiều nhất là năm tuổi, có thể nó bắt chước đường ống chức năng cố định với trình đổ bóng. Bằng cách sử dụng shaders, bạn có ít nhiều quyền kiểm soát những gì đang xảy ra trong giai đoạn chuyển đổi và rasterization, và bạn có thể tạo ra "trạng thái" của riêng mình với đồng phục, rất rẻ để thay đổi/cập nhật.

Biết rằng OpenGL là một máy nhà nước như tôi đã nói ở trên nên làm rõ rằng người ta nên cố gắng giữ cho trạng thái thay đổi ở mức tối thiểu, miễn là có thể. Tuy nhiên, có lẽ hầu hết những thứ khác tác động đến hiệu năng nhiều hơn là bật/tắt các cuộc gọi trạng thái. Nếu bạn muốn biết về chúng, hãy đọc xuống.


Chi phí của nhà nước không gắn liền với các cuộc gọi quốc fixed-function cũ và đó là không đơn giản cho phép/vô hiệu hóa nhà nước có thể khác nhau rất nhiều chi phí. Đáng chú ý là liên kết các shader và các tên liên kết, ("tên" của kết cấu, chương trình, đối tượng đệm) thường khá đắt. Đây là lý do tại sao rất nhiều trò chơi và ứng dụng được sử dụng để sắp xếp thứ tự vẽ của mắt lưới của chúng theo kết cấu. Bằng cách đó, họ không phải gắn kết cùng một kết cấu hai lần. Ngày nay, điều tương tự cũng áp dụng cho các chương trình đổ bóng. Bạn không muốn liên kết cùng một chương trình đổ bóng hai lần nếu bạn không phải làm như vậy. Ngoài ra, không phải tất cả các tính năng trong một phiên bản OpenGL cụ thể đều được tăng tốc phần cứng trên tất cả các thẻ, ngay cả khi các nhà cung cấp thẻ đó tuyên bố rằng chúng tuân thủ OpenGL. Việc tuân thủ có nghĩa là họ tuân theo đặc điểm kỹ thuật, không phải là họ nhất thiết phải chạy tất cả các chiến công một cách hiệu quả. Một số chức năng như glHistogram và glMinMax từ GL__ ARB __imaging nên được ghi nhớ trong vấn đề này.


Kết luận: Trừ khi có lý do rõ ràng không sử dụng trình đổ bóng! Nó giúp bạn tiết kiệm từ rất nhiều cuộc gọi nhà nước không cần thiết vì bạn có thể sử dụng đồng phục để thay thế. OpenGL shaders đã được chỉ trong khoảng sáu năm bạn biết. Ngoài ra, chi phí thay đổi trạng thái bật/tắt có thể là là một vấn đề, nhưng thường có nhiều thứ để đạt được từ việc tối ưu hóa các thay đổi trạng thái đắt tiền khác, như glUseProgram, glCompileShader, glLinkprogram, glBindBuffer và glBindTexture.

P.S: OpenGL 3.0 đã xóa các cuộc gọi bật/tắt trạng thái ứng dụng khách. Chúng được ngầm sử dụng như mảng vẽ là cách duy nhất để vẽ trong phiên bản này. Chế độ ngay lập tức đã bị xóa. gl .. Các cuộc gọi con trỏ đã bị xóa là tốt, vì thực sự chỉ cần glVertexAttribPointer.

Các vấn đề liên quan