Mất bao lâu để OpenGL thực sự cập nhật màn hình?


9

Tôi có một ứng dụng thử nghiệm OpenGL đơn giản trong C, rút ​​ra những điều khác nhau để đáp ứng với đầu vào chính. (Mesa 8.0.4, đã thử với Mesa-EGL và với GLFW, Ubuntu 12.04LTS trên PC với NVIDIA GTX650). Việc vẽ khá đơn giản / nhanh chóng (loại hình tam giác xoay). Mã kiểm tra của tôi không giới hạn tốc độ khung hình một cách có chủ ý theo bất kỳ cách nào, nó chỉ trông như thế này:

while (true)
{
    draw();
    swap_buffers();
}

Tôi đã tính thời gian này rất cẩn thận và tôi thấy rằng thời gian từ một cuộc gọi eglSwapBuffers()(hoặc glfwSwapBuffers, điều tương tự) đến cuộc gọi tiếp theo là ~ 16,6 mili giây. Thời gian từ sau cuộc gọi đến eglSwapBuffers()ngay trước cuộc gọi tiếp theo chỉ ít hơn thế một chút, mặc dù những gì được rút ra rất đơn giản. Thời gian mà bộ đệm trao đổi cuộc gọi mất dưới 1ms.

Tuy nhiên, thời gian từ ứng dụng thay đổi những gì nó vẽ để phản hồi với phím bấm đến thay đổi thực sự hiển thị trên màn hình là> 150ms (giá trị khoảng 8-9 khung hình). Điều này được đo bằng camera ghi lại màn hình và bàn phím ở tốc độ 60fps.

Do đó, các câu hỏi:

  1. Trường hợp rút thăm được đệm giữa một lệnh gọi để trao đổi bộ đệm và thực sự hiển thị trên màn hình? Tại sao lại có sự chậm trễ? Có vẻ như ứng dụng đang vẽ nhiều khung hình phía trước màn hình mọi lúc.

  2. Ứng dụng OpenGL có thể làm gì để thu hút màn hình ngay lập tức? (tức là: không có bộ đệm, chỉ chặn cho đến khi vẽ xong; tôi không cần thông lượng cao, tôi cần độ trễ thấp)

  3. Ứng dụng có thể làm gì để rút thăm ngay lập tức ở trên nhanh nhất có thể?

  4. Làm thế nào một ứng dụng có thể biết những gì thực sự trên màn hình ngay bây giờ? (Hoặc, độ trễ của bộ đệm hiện tại là bao lâu / bao nhiêu khung hình?)


Bạn có thể phân tách thời gian mà bàn phím cần để thông báo cho ứng dụng của bạn với thời gian cần thiết để thực sự kết xuất nó không?
ThorinII

@ThorinII: Điểm công bằng. Tôi có thể có thể thiết lập một cái gì đó hacky bằng cách sử dụng đèn LED trên một cổng song song, v.v. để có được dấu hiệu khi nào ứng dụng thực sự nhấn phím. Tuy nhiên, đó chỉ là fgetc (stdin), nó có thể chậm đến mức nào? : /
Alex I

Tôi có ấn tượng rằng glFlush đã được sử dụng để gây ra tất cả các lệnh ngay lập tức.
Chương trình

1
@AlexI kiểm tra gamedev.stackexchange.com/questions/66543/ này có thể giúp bạn
concept3d

1
@ concept3d: Vâng, về cơ bản nó đã được trả lời, chỉ cần nghĩ rằng bạn muốn có thêm đại diện :) Rõ ràng tôi phải đợi một ngày để trao giải mặc dù.
Alex I

Câu trả lời:


6

Bất kỳ chức năng API vẽ nào được gọi từ CPU sẽ được gửi tới bộ đệm vòng lệnh GPU để được GPU thực hiện sau đó. Điều này có nghĩa là các chức năng OpenGL chủ yếu là các chức năng không chặn. Vì vậy, CPU và GPU sẽ hoạt động song song.

Điều quan trọng nhất cần lưu ý là ứng dụng của bạn có thể bị ràng buộc CPU hoặc GPU. Một khi bạn gọi glFinish, CPU sẽ đợi GPU hoàn thành các lệnh vẽ của nó, nếu GPU mất nhiều thời gian hơn và có thể / khiến CPU bị đình trệ thì các ứng dụng của bạn bị ràng buộc GPU. Nếu GPU hoàn thành việc vẽ các lệnh và CPU mất quá nhiều thời gian để glFinish thì ứng dụng của bạn bị ràng buộc CPU.

Và lưu ý rằng có một sự khác biệt giữa glFlushglFinish.

glFlush: chỉ ra rằng tất cả các lệnh đã được gửi tới GL trước đó phải hoàn thành trong thời gian hữu hạn.

glFinish: buộc tất cả các lệnh GL trước đó phải hoàn thành. Kết thúc không trả về cho đến khi tất cả các hiệu ứng từ các lệnh được ban hành trước đó trên trạng thái máy khách và máy chủ GL và bộ đệm khung được thực hiện đầy đủ. "

glXSwapBuffers thực hiện một glFlush ngầm trước khi nó trở lại. Các lệnh OpenGL sau đó có thể được ban hành ngay sau khi gọi glXSwapBuffers, nhưng không được thực thi cho đến khi hoàn thành việc trao đổi bộ đệm.

Thời gian khung hình thực tế rất có thể sẽ được xác định theo đó trong số hai CPU / GPU đang mất nhiều thời gian hơn để hoàn thành công việc của nó.


Điều này rất hữu ích. Một số chỉnh sửa có thể có: opengl.org/sdk/docs/man2/xhtml/glXSwapBuffers.xml "glXSwapBuffers thực hiện một glFlush ngầm trước khi trả về" có vẻ như điều này thực sự không thực hiện được glFinish, vì vậy bộ đệm lệnh có thể có khá nhiều những thứ trong đó khi bộ đệm trao đổi trở lại.
Alex I

... Ngoài ra, tôi nghĩ điểm thú vị nhất là ứng dụng thử nghiệm rất đơn giản của tôi không phải CPU không bị giới hạn GPU - không có nhiều việc phải làm ở đây - nhưng một điều khác, nó bằng cách nào đó kết thúc với cả tốc độ khung hình thấp (giống hệt như màn hình tốc độ làm mới ??) và độ trễ cao (vì bộ đệm lệnh, thực sự bạn đã giải thích phần đó khá tốt).
Alex I

@AlexI both low framerate (exactly same as monitor refresh rate??không trừ khi bạn sử dụng VSync một cách rõ ràng.
Concept3d

@AlexI Tôi cũng muốn chỉ ra rằng thời gian khung hình khác với FPS, hãy sử dụng thời gian khung hình để lập hồ sơ cho ứng dụng của bạn vì đó là tuyến tính. Mặt khác, FPS là một phép đo kém mà không tuyến tính.
Concept3d

Tôi không rõ ràng sử dụng vsync. Tôi không làm gì để thay đổi cài đặt mặc định vsync, thậm chí tôi không biết phải thay đổi cài đặt nào trong OpenGL. Tôi chỉ nhận được chính xác 60fps (trong vòng một phần trăm).
Alex I

4

OpenGL không bao giờ cập nhật màn hình, về mặt kỹ thuật.

Có một API hệ thống cửa sổ tách biệt với GL (ví dụ GLX, WGL, CGL, EGL) thực hiện điều này. Bộ đệm hoán đổi bằng cách sử dụng các API này thường ngầm gọi glFlush (...)nhưng trong một số triển khai (ví dụ: trình tạo trình GDI trên Windows), nó thực hiện đầy đủ glFinish (...):

 

    * Ở phía bên trái, là đường dẫn ICD (phần cứng) đi qua SwapBuffers (...). Ở bên phải, đường dẫn GDI (phần mềm).

Nếu bạn có Vsync kích hoạt và đôi đệm, sau đó bất kỳ lệnh đó sẽ sửa đổi bộ đệm trở lại trước khi một swap cấp phát xảy ra phải gian hàng cho đến khi trao đổi. Có một độ sâu giới hạn trong hàng đợi lệnh, vì vậy lệnh bị đình trệ này cuối cùng sẽ gây ra kẹt xe trong đường ống. Điều này có thể có nghĩa là thay vì chặn trên SwapBuffers (...)ứng dụng của bạn thực sự chặn một số lệnh GL không liên quan cho đến khi VBLANK xuất hiện. Những gì nó thực sự sôi nổi là có bao nhiêu bộ đệm trở lại trong chuỗi trao đổi của bạn.

Miễn là tất cả các bộ đệm phía sau có đầy đủ các khung đã hoàn thành chưa được di chuyển ra phía trước, bộ đệm trao đổi sẽ ngầm gây ra chặn. Đáng buồn thay, không có cách nào để kiểm soát rõ ràng số lượng bộ đệm trở lại được sử dụng bởi hầu hết các API hệ thống cửa sổ GL (ngoài 0 bộ đệm đơn hoặc 1 bộ đệm đôi). Trình điều khiển có thể tự do sử dụng 2 bộ đệm trở lại nếu muốn (bộ đệm ba), nhưng bạn không thể yêu cầu điều này ở cấp ứng dụng bằng cách sử dụng cái gì đó như GLX hoặc WGL.


Andon: Thông tin tốt, cảm ơn bạn. Tôi nghĩ những gì tôi đang thấy là một phần đệm đôi, nhưng: "cố gắng sửa đổi bộ đệm trở lại trước khi hoán đổi xảy ra phải chặn" - tại sao? có vẻ như mọi thứ đều có thể được gửi đến bộ đệm lệnh, bao gồm cả trao đổi :)
Alex I

"kiểm soát rõ ràng số lượng bộ đệm trở lại được sử dụng bởi hầu hết các API hệ thống cửa sổ GL (ngoài 0 bộ đệm đơn hoặc 1 bộ đệm đôi)" - làm thế nào để kiểm soát một bộ đệm đơn / đôi?
Alex I

@AlexI: Tôi đã làm rõ ngôn ngữ liên quan đến lý do tại sao lệnh có thể dẫn đến chặn. Trong các API khác, có một khái niệm được gọi là kết xuất trước, đây thực sự là độ sâu của hàng đợi lệnh. Đối với việc kiểm soát bộ đệm đơn / đôi, được điều khiển bởi định dạng pixel bạn chọn khi bạn tạo bối cảnh kết xuất. Trong WGL, bạn có thể chọn bộ đệm đơn hoặc bộ đệm đôi, nhưng nếu bạn chọn bộ đệm đôi, trình điều khiển thực sự có thể tạo 2 bộ đệm trở lại (do đó bộ đệm đôi trở thành bộ đệm ba) nếu người dùng đặt trình điều khiển của họ để thực hiện việc này.
Andon M. Coleman

Bạn thực sự không muốn hiển thị quá nhiều khung hình phía trước bởi vì trong khi điều này sẽ làm giảm việc chặn, nó cũng làm tăng độ trễ. Cách tốt nhất để giảm thiểu độ trễ thực sự là gọi glFinish (...)ngay sau khi hoán đổi bộ đệm. Điều này sẽ xóa hàng đợi lệnh, nhưng điều đó cũng có nghĩa là GPU và CPU sẽ được đồng bộ hóa (điều này không tốt nếu bạn muốn giữ GPU hoạt động mọi lúc).
Andon M. Coleman

1

Tôi cho rằng bạn quen thuộc với thí nghiệm này ?

Về cơ bản, John Carmack đang làm một cái gì đó tương tự, ghi lại màn hình và các pixel thời gian được gửi đến màn hình. Ông thấy rằng rất nhiều độ trễ xuất phát từ màn hình. Các yếu tố khác là độ trễ đầu vào từ bàn phím, trình điều khiển video và hoặc tất nhiên là việc thực hiện chương trình.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.