Đối với Vertex Buffer Steaming, Nhiều glBufferSubData VS mồ côi?


8

Tôi đã học OpenGL gần đây. Trong các trò chơi, chúng ta cần cập nhật vị trí của các đối tượng trò chơi thường xuyên và chúng sẽ ra vào & ra khỏi màn hình liên tục. Vì vậy, điều đó có nghĩa là trong kết xuất chúng ta cũng cần cập nhật bộ đệm đỉnh khá thường xuyên.

Trong ngữ cảnh của OpenGL, một cách trực quan là sử dụng glBufferSubData để cập nhật những thay đổi.

Nhưng tôi cũng đọc trực tuyến một mẹo gọi là Orphaning tạo ra dữ liệu bộ đệm mới và tải toàn bộ dữ liệu đỉnh lên nó.

Ngoài ra do chi phí chagnes nhà nước và chi phí tải lên, nhiều glBufferSubData cũng có thể có giá cao hơn.

Đây là câu hỏi của tôi,

  1. Phương pháp nào tốt hơn?
  2. Là quầy hàng thực sự quan trọng trong trường hợp này?
  3. Là thay đổi trạng thái và chi phí tải lên thực sự quan trọng trong trường hợp này?

Cảm ơn!


Tại sao bạn muốn tải lên lại hình học khi bạn thực sự chỉ có thể cập nhật ma trận? nói cách khác, bạn không cần phải tải lên lại các đỉnh khi chỉ các biến đổi cần thay đổi.
Concept3d

@ Concept3d Vâng, bạn đã đúng! Tôi đã làm sai khi viết mô tả vấn đề. Cảm ơn bạn đã nhắc nhở tôi về điều đó! Tôi đã cập nhật các mô tả rồi.
YiFeng

Câu trả lời:


9

Đây là một câu hỏi phức tạp với rất nhiều chi tiết nhỏ thực sự quan trọng, hiệu suất sẽ thay đổi dựa trên nền tảng và ứng dụng. Vì vậy, bạn nên lập hồ sơ cho các tắc nghẽn có thể có trước khi đầu tư vào tối ưu hóa.

Điều đó nói rằng, trước tiên, tôi giả sử bạn nên giảm tải lên và cập nhật càng nhiều càng tốt, ví dụ như sử dụng inst instaging.

Thứ hai, lưu ý rằng GPU không thể chuyển bộ đệm và kết xuất cùng một lúc, vì vậy tất cả các lệnh OpenGL trong hàng đợi lệnh được thiết bị xử lý tuần tự. Có nhiều cách khác nhau để sao chép dữ liệu và / hoặc làm cho nó được sử dụng bởi GPU.

Có nhiều cách khác nhau để truyền dữ liệu tới GPU

1- glBufferDatahoặc glBufferSubDataphương pháp

Sử dụng glBufferDatahoặc glBufferSubDatagiống như memcpy. bạn truyền con trỏ và thao tác DMA có thể được thực hiện, tôi nói có thể vì bộ nhớ có thể được ghim trong bộ nhớ CPU và được GPU sử dụng trực tiếp mà không thực sự chuyển bộ nhớ sang GPU, tùy thuộc vào cờ sử dụng (GL_STREAM). Theo ý kiến ​​ban đầu, bạn nên thử điều này vì nó đơn giản hơn để thực hiện.

2- nhận được một con trỏ đến bộ nhớ trong bằng cách sử dụng glMapBuffer

Nếu những điều trên không đủ tốt để bạn có thể sử dụng glMapBuffer, bạn có một con trỏ vào bộ nhớ trong và bạn có thể sử dụng con trỏ này để điền trực tiếp vào bộ đệm, điều này tốt với các thao tác đọc và ghi tệp, vì bạn có thể ánh xạ trực tiếp dữ liệu tệp vào bộ nhớ GPU thay vì sao chép vào bộ đệm tạm thời trước. Nếu bạn không muốn ánh xạ toàn bộ bộ đệm, bạn có thể sử dụngglMapBufferRange dụng để ánh xạ một phần của bộ đệm.

Một mẹo nhỏ là tạo một bộ đệm lớn, sử dụng nửa đầu để kết xuất và nửa sau để cập nhật.

3- Bộ đệm mồ côi

Về bộ đệm mồ côi, điều này có thể được thực hiện bằng cách sử dụng glBufferData với null và các tham số tương tự như nó có. Trình điều khiển sẽ trả về khối bộ nhớ khi nó không được sử dụng. Và sẽ được sử dụng bởi lệnh gọi glBufferData tiếp theo (không có bộ nhớ mới nào được phân bổ).

Tất cả các phương pháp được đề cập gây ra rất nhiều đồng bộ hóa đắt tiền, một lần nữa GPU không thể chuyển bộ đệm và kết xuất cùng một lúc.

4- Unsynchronized Buffers

Phương pháp nhanh nhất (và khó nhất để có quyền) là sử dụng bộ đệm mà không cần đồng bộ hóa mà bạn có thể sử dụng GL_MAP_UNSYNCHRONIZED_BITcờ glMapBufferRange, vấn đề là không thực hiện đồng bộ hóa, vì vậy chúng tôi có thể tải dữ liệu lên bộ đệm bắt đầu được sử dụng và do đó làm hỏng mọi thứ. Bạn có thể sử dụng nhiều bộ đệm với bit không đồng bộ để làm cho mọi thứ dễ dàng hơn một chút.


0

Tôi làm theo cách khác. Có thể có một cái gì đó sai ở đó. Một số điều nguy hiểm tiềm ẩn.

(Tôi sử dụng C # + OpenTK.GameWindow)

Để kích hoạt đối tượng, tôi sử dụng một đối tượng bộ đệm Array riêng biệt cho tập hợp các ma trận mô hình cho mọi trường hợp. Trong đỉnh chia sẻ:

#version 400
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
layout (location = 2) in vec2 texcoord;
layout (location = 4) in mat4 model_matrix;

uniform mat4 proj_matrix, view_matrix;

Trong ma trận mã C # của tôi được lưu trữ trong một mảng float float[] mat4_array

Sau đó, tôi liên kết mảng với Array Buffer Object:

public void bind_data_instances()
{
    GL.BindBuffer(BufferTarget.ArrayBuffer, id_InstanceBO);
    GL.BufferData(BufferTarget.ArrayBuffer, mat4_array.Length * sizeof(float), mat4_array, BufferUsageHint.DynamicDraw);
}

Mỗi khung ma trận mô hình được cập nhật. Để cập nhật mat4_arraytôi chỉ cần gọi:

Buffer.BlockCopy(mat4_array_new, 0, mat4_array, 0, sizeof(float) * mat4_models.Length);

và dựng cảnh. sử dụng GL.DrawElementsInstanced.

Không có cuộc gọi OpenGL bổ sung và nó hoạt động hoàn hảo.


Mục đích của việc có ma trận mô hình là thuộc tính đỉnh là gì?
Anton Duzenko

Đó là cho đối tượng vẽ. Và nó nhanh hơn một mảng được truyền dưới dạng một biến thống nhất.
Dennis
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.