Chi phí thực tế của bất kỳ thay đổi trạng thái cụ thể nào khác nhau với rất nhiều yếu tố mà một câu trả lời chung là không thể thực hiện được.
Đầu tiên, mọi thay đổi trạng thái có thể có khả năng có cả chi phí phía CPU và chi phí phía GPU. Chi phí CPU có thể, tùy thuộc vào trình điều khiển và API đồ họa của bạn, được thanh toán hoàn toàn trên luồng chính hoặc một phần trên luồng nền.
Thứ hai, chi phí GPU có thể phụ thuộc vào số lượng công việc trong chuyến bay. Các GPU hiện đại rất tinh vi và thích có nhiều công việc trong chuyến bay cùng một lúc, và sự chậm lại lớn nhất bạn có thể nhận được là từ việc trì hoãn đường ống để mọi thứ hiện đang trong chuyến bay phải nghỉ hưu trước khi trạng thái thay đổi. Điều gì có thể gây ra một gian hàng đường ống? Vâng, nó phụ thuộc vào GPU của bạn!
Điều bạn thực sự cần biết để hiểu hiệu suất ở đây là: trình điều khiển và GPU cần làm gì để xử lý thay đổi trạng thái của bạn? Điều này tất nhiên phụ thuộc vào GPU của bạn và cũng phụ thuộc vào chi tiết mà ISV thường không chia sẻ công khai. Tuy nhiên, có một số nguyên tắc chung .
GPU thường được chia thành một frontend và một phụ trợ. Frontend xử lý một luồng các lệnh được tạo bởi trình điều khiển, trong khi phần phụ trợ thực hiện tất cả công việc thực sự. Như tôi đã nói trước đây, phần phụ trợ rất thích có nhiều công việc trong chuyến bay, nhưng nó cần một số thông tin để lưu trữ thông tin về công việc đó (có lẽ được điền bởi frontend). Nếu bạn đá đủ số lượng nhỏ và sử dụng hết silicon theo dõi công việc, thì frontend sẽ phải chững lại ngay cả khi có rất nhiều mã lực không sử dụng đang ngồi xung quanh. Vì vậy, một nguyên tắc ở đây: càng thay đổi trạng thái (và rút ra nhỏ), bạn càng có khả năng bỏ đói phần phụ trợ GPU .
Mặc dù bản vẽ đang thực sự được xử lý, nhưng về cơ bản, bạn chỉ đang chạy các chương trình đổ bóng, đang thực hiện truy cập bộ nhớ để lấy đồng phục, dữ liệu bộ đệm đỉnh, kết cấu của bạn, mà cả các cấu trúc điều khiển cho các đơn vị đổ bóng nơi bộ đệm đỉnh của bạn và kết cấu của bạn là. Và GPU cũng có bộ nhớ đệm trước các truy cập bộ nhớ đó. Vì vậy, bất cứ khi nào bạn ném đồng phục mới hoặc các ràng buộc kết cấu / bộ đệm mới vào GPU, nó sẽ có khả năng bị mất bộ nhớ cache trong lần đầu tiên nó phải đọc chúng. Một nguyên tắc khác: hầu hết các thay đổi trạng thái sẽ gây ra lỗi bộ nhớ cache GPU. (Điều này có ý nghĩa nhất khi bạn tự quản lý bộ đệm liên tục: nếu bạn giữ bộ đệm liên tục giống nhau giữa các lần rút, thì nhiều khả năng chúng sẽ nằm trong bộ nhớ cache trên GPU.)
Một phần lớn chi phí cho các thay đổi trạng thái đối với tài nguyên đổ bóng là phía CPU. Bất cứ khi nào bạn đặt bộ đệm liên tục mới, trình điều khiển rất có thể sao chép nội dung của bộ đệm liên tục đó vào luồng lệnh cho GPU. Nếu bạn đặt một đồng phục duy nhất, trình điều khiển rất có thể biến nó thành một bộ đệm lớn liên tục phía sau lưng của bạn, vì vậy nó phải tìm kiếm phần bù cho đồng phục đó trong bộ đệm không đổi, sao chép giá trị vào, sau đó đánh dấu bộ đệm không đổi như bẩn để nó có thể được sao chép vào luồng lệnh trước lệnh gọi tiếp theo. Nếu bạn liên kết một kết cấu mới hoặc bộ đệm đỉnh, trình điều khiển có thể đang sao chép cấu trúc điều khiển cho tài nguyên đó xung quanh. Ngoài ra, nếu bạn đang sử dụng GPU rời trên HĐH đa nhiệm, trình điều khiển cần theo dõi mọi tài nguyên bạn sử dụng và khi bạn bắt đầu sử dụng nó để nhân ' Trình quản lý bộ nhớ GPU có thể đảm bảo rằng bộ nhớ cho tài nguyên đó nằm trong VRAM của GPU khi việc rút thăm xảy ra. Nguyên tắc:thay đổi trạng thái làm cho trình điều khiển xáo trộn bộ nhớ xung quanh để tạo ra một luồng lệnh tối thiểu cho GPU.
Khi bạn thay đổi trình đổ bóng hiện tại, có thể bạn đang gây ra lỗi bộ đệm GPU (chúng cũng có bộ đệm hướng dẫn!). Về nguyên tắc, công việc của CPU nên được giới hạn trong việc đưa một lệnh mới vào luồng lệnh có nội dung "sử dụng trình đổ bóng". Trong thực tế, mặc dù, có một mớ hỗn độn của trình biên dịch shader để giải quyết. Trình điều khiển GPU rất thường xuyên biên dịch các shader, ngay cả khi bạn đã tạo shader trước thời hạn. Mặc dù có liên quan nhiều hơn đến chủ đề này, một số trạng thái không được hỗ trợ bởi phần cứng GPU và thay vào đó được biên dịch vào chương trình đổ bóng. Một ví dụ phổ biến là các định dạng đỉnh: chúng có thể được biên dịch thành shader đỉnh thay vì ở trạng thái riêng biệt trên chip. Vì vậy, nếu bạn sử dụng các định dạng đỉnh mà bạn chưa từng sử dụng với trình tạo bóng đỉnh cụ thể trước đó, thì bây giờ bạn có thể phải trả một loạt chi phí CPU để vá shader và sao chép chương trình shader lên tới GPU. Ngoài ra, trình điều khiển và trình biên dịch shader có thể âm mưu làm tất cả các loại để tối ưu hóa việc thực hiện chương trình đổ bóng. Điều này có thể có nghĩa là tối ưu hóa bố cục bộ nhớ của đồng phục và cấu trúc kiểm soát tài nguyên của bạn để chúng được đóng gói độc đáo vào các thanh ghi bộ nhớ hoặc shader liền kề. Vì vậy, khi bạn thay đổi shader, nó có thể khiến trình điều khiển nhìn vào mọi thứ bạn đã ràng buộc với đường ống và đóng gói lại thành một định dạng hoàn toàn khác cho shader mới, sau đó sao chép nó vào luồng lệnh. Nguyên tắc: Điều này có thể có nghĩa là tối ưu hóa bố cục bộ nhớ của đồng phục và cấu trúc kiểm soát tài nguyên của bạn để chúng được đóng gói độc đáo vào các thanh ghi bộ nhớ hoặc shader liền kề. Vì vậy, khi bạn thay đổi shader, nó có thể khiến trình điều khiển nhìn vào mọi thứ bạn đã ràng buộc với đường ống và đóng gói lại thành một định dạng hoàn toàn khác cho shader mới, sau đó sao chép nó vào luồng lệnh. Nguyên tắc: Điều này có thể có nghĩa là tối ưu hóa bố cục bộ nhớ của đồng phục và cấu trúc kiểm soát tài nguyên của bạn để chúng được đóng gói độc đáo vào các thanh ghi bộ nhớ hoặc shader liền kề. Vì vậy, khi bạn thay đổi shader, nó có thể khiến trình điều khiển nhìn vào mọi thứ bạn đã ràng buộc với đường ống và đóng gói lại thành một định dạng hoàn toàn khác cho shader mới, sau đó sao chép nó vào luồng lệnh. Nguyên tắc:thay đổi shader có thể gây xáo trộn bộ nhớ CPU.
Thay đổi bộ đệm khung có thể phụ thuộc nhiều nhất vào việc triển khai, nhưng thường khá đắt trên GPU. GPU của bạn có thể không thể xử lý nhiều lệnh gọi rút thăm tới các mục tiêu kết xuất khác nhau cùng một lúc, do đó, nó có thể cần phải trì hoãn đường ống giữa hai cuộc gọi rút thăm đó. Nó có thể cần phải xóa bộ đệm để có thể đọc mục tiêu kết xuất sau. Nó có thể cần phải giải quyết công việc mà nó đã hoãn lại trong bản vẽ. (Rất phổ biến khi tích lũy cấu trúc dữ liệu riêng biệt cùng với bộ đệm độ sâu, mục tiêu kết xuất MSAA và hơn thế nữa. Điều này có thể cần được hoàn thiện khi bạn chuyển khỏi mục tiêu kết xuất đó. Nếu bạn đang sử dụng GPU dựa trên gạch , giống như nhiều GPU di động, một lượng công việc tạo bóng thực tế khá lớn có thể cần phải được xóa khi bạn chuyển khỏi bộ đệm khung.) Nguyên tắc:thay đổi mục tiêu kết xuất là tốn kém trên GPU.
Tôi chắc chắn rằng điều đó rất khó hiểu, và thật không may, thật khó để nói quá cụ thể vì các chi tiết thường không công khai, nhưng tôi hy vọng đó là một cái nhìn tổng quan nửa vời về một số điều thực sự đang diễn ra khi bạn gọi một số trạng thái thay đổi chức năng trong API đồ họa yêu thích của bạn.