2012-05-18 7 views
8

Tôi đã có trước đây đã là vấn đề mà tôi muốn để pha trộn các giá trị màu trong một đơn vị hình ảnh bằng cách làm một cái gì đó như:GLSL, semaphores?

vec4 texelCol = imageLoad(myImage, myTexel); 
imageStore(myImage, myTexel, texelCol+newCol); 

Trong một kịch bản mà nhiều mảnh vỡ có thể có cùng giá trị cho 'myTexel', điều này aparently là không thể bởi vì người ta không thể tạo ra nguyên tử giữa các lệnh imageLoad và imageStore và các shaderinvocations khác có thể thay đổi màu texel ở giữa.

Bây giờ ai đó đã nói với tôi rằng nhà thơ đang làm việc vất vả vấn đề này bằng cách tạo ra các semaphores bằng cách sử dụng các nguyên tử nguyên tử trên kết cấu uint, như vậy trình đổ bóng sẽ chờ đợi bằng cách nào đó trong một vòng lặp trước khi truy cập vào Texel và ngay sau khi nó miễn phí viết itno kết cấu số nguyên để chặn các lời gọi đổ bóng khác, xử lý màu texel và khi hoàn thành nguyên tử miễn phí số nguyên texel một lần nữa.

Nhưng tôi không thể có được bộ não của tôi arround như thế nào điều này thực sự có thể làm việc và làm thế nào mã như vậy sẽ như thế nào?

Thực sự có thể thực hiện việc này không? có thể đặt trình đổ bóng đoạn GLSL để đợi trong một vòng lặp while? Nếu có thể, ai đó có thể đưa ra một ví dụ?

+0

Từ [đặc tả mở rộng] (http://www.opengl.org/registry/specs/EXT/shader_image_load_store.txt) có vẻ như bạn sẽ cần sắp xếp các rào cản bộ nhớ phù hợp, hoặc với 'MemoryBarrierEXT()' hoặc 'memoryBarrier()' trong chính trình tự đổ bóng. – Flexo

+0

@awoodland: Các rào cản bộ nhớ không thể cho phép các trình đổ bóng khác chạy ở cùng một giai đoạn để đọc bộ nhớ. –

+0

Xem câu trả lời của tôi cho http://stackoverflow.com/a/16802075/1388799 cho giải pháp hiện đang hoạt động đối với vấn đề semaphore GLSL trên thẻ Nvidia Kepler. –

Trả lời

6

Có, bạn có thể làm điều này, nhưng chỉ miễn là đơn đặt hàng trong đó mọi thứ được pha trộn không liên quan. Nếu không, bạn cần phải sử dụng các kỹ thuật thông thường.

Về cơ bản, bạn chỉ đang triển khai spinlock. Chỉ thay vì một biến khóa, bạn có toàn bộ giá trị của khóa.

Trước tiên, bạn cần một hình ảnh có kích thước của hình ảnh khác mà bạn sẽ sử dụng cho các hoạt động nguyên tử. Nó cần phải là một kết cấu số nguyên với GL_R32UI và định dạng uimage của r32ui để khớp. Nó phải được khởi tạo với 0. Cả hình ảnh nguyên tử và hình ảnh "trộn" phải được khai báo "mạch lạc".

  1. Thực hiện thao tác imageAtomicCompSwap tại vị trí trên hình ảnh nguyên nguyên. Bạn đang so sánh nó với 0 và giá trị bạn đặt giá trị là 1.

  2. Nếu # 1 trả về 1, điều này có nghĩa là ai đó có khóa. Quay lại bướC# 1.

  3. Nếu # 1 trả về 0, bây giờ bạn có quyền truy cập độc quyền vào texel (vì texel hiện có 1 trong đó, nhờ hoạt động so sánh/hoán đổi). Tiếp tục.

  4. Thực hiện thao tác trộn của bạn. Phát ra một memoryBarrier sau khi thao tác trộn.

  5. Thực hiện imageAtomicExchange, với giá trị bằng 0. Điều này mở khóa spinlock.

Lý do hoạt động này là do nguyên tử. GLSL đảm bảo rằng nguyên tử là nguyên tử. imageAtomicCompareSwap thực hiện thao tác đọc/điều chỉnh/ghi có điều kiện như một chuỗi nguyên tử. Và bởi vì nó là nguyên tử, nó là không thể cho các lời gọi trình đổ bóng khác để ngăn chặn hoặc làm gián đoạn hoạt động. Điều này có nghĩa là không quan trọng có bao nhiêu luồng của trình đổ bóng đang chạy: nếu 100 chuỗi trong số đó gọi là imageAtomicCompareSwap(..., 0, 1), chính xác một trong số chúng sẽ nhận 1 là giá trị trả lại và phần còn lại sẽ là 0 (cho cùng một texel)).

Vì vậy, chỉ một chuỗi sẽ có khóa; phần còn lại phải đợi.

Việc sử dụng chức năng memoryBarrier() sẽ đảm bảo rằng các luồng khác đang đợi sẽ nhận dữ liệu đã sửa đổi khi chúng đọc. Một lần nữa, bạn cần sử dụng bộ định tính coherent cho hình ảnh bạn đang thực hiện việc này.

+0

Tôi không hiểu tại sao kết cấu số nguyên phải bằng kích thước của màn hình. Điều đó có nghĩa là một giá trị khóa trên mỗi mảnh. nhưng không nên có một giá trị khóa cho mỗi texel của hình ảnh được viết? – Mat

+1

@Mat: Có nhiều ô của hình ảnh hơn pixel của màn hình không? Nó sẽ giúp để biết những điều này trước. –

+0

đôi khi nhiều hơn, thường ít hơn. nó phụ thuộc vào vụ án. Vì vậy, các shader mảnh sẽ ở lại trong vòng lặp while cho đến khi điều kiện thực sự được đáp ứng? là GLSL không bằng cách nào đó đảm bảo rằng các shaders trở lại và do đó giết một lời gọi shader nếu nó quay quá lâu? – Mat