2013-11-02 11 views
7

Họ suggest:Tại sao Apple đề xuất gửi các lệnh OpenGL trong hàng đợi nền nối tiếp khi điều này chắc chắn dẫn đến sự cố?

Khi sử dụng GCD, sử dụng một hàng đợi nối tiếp chuyên dụng để gửi lệnh để OpenGL ES; điều này có thể được sử dụng để thay thế mô hình mutex thông thường.

Tôi không hiểu đề xuất này. Có xung đột mà tôi không thể giải quyết:

Khi ứng dụng ủy nhiệm ứng dụng nhận được cuộc gọi -applicationWillResignActive, điện thoại phải ngay lập tức ngừng gọi bất kỳ chức năng OpenGL nào.

Nếu ứng dụng tiếp tục gọi hàm OpenGL sau khi -applicationWillResignActive trả về, ứng dụng sẽ gặp sự cố.

Nếu tôi làm theo khuyến cáo của Apple để gọi chức năng OpenGL trong một hàng đợi nền sê-ri, tôi đang phải đối mặt với vấn đề dường như không thể giải quyết này:

1) Sau khi tôi nhận -applicationWillResignActive tôi phải ngay ngừng kêu gọi bất kỳ chức năng OpenGL thêm.

2) Nhưng vì hàng đợi nối tiếp đang ở giữa xử lý một khối mã trong nền, đôi khi khối mã sẽ hoàn thành việc thực hiện after-applicationWillResignActive trả về và ứng dụng gặp sự cố.

Dưới đây là hình minh họa cho thấy "các khối" đồng thời. Các chủ đề chính nhận được một tin nhắn dừng lại đầy đủ và phải ngăn chặn các cuộc gọi hơn nữa để OpenGL ES. Nhưng tiếc là những xảy ra trong một hàng đợi nền mà không thể dừng lại trong chuyến bay của làm việc trên một khối:

|_____main thread: "STOP calling OpenGL ES!"_____| 
_____|_____drawing queue: "Draw!"_____|_____drawing queue: "Draw!"_____| 

Về mặt kỹ thuật tôi thấy không có cách nào để ngăn chặn hàng đợi nền ngay lập tức và tránh các cuộc gọi hơn nữa để OpenGL ở chế độ nền. Một khối mã đã gửi một lần chạy tiếp tục chạy.

Giải pháp duy nhất tôi tìm thấy là NOT gọi hàm OpenGL ES ở chế độ nền. Thay vào đó, hãy gọi chúng trên chuỗi chính để đảm bảo rằng chúng sẽ không bao giờ được gọi sau khi ứng dụng mất quyền truy cập vào GPU.

Vì vậy nếu nó không quan trọng để gọi chức năng OpenGL ES ở chế độ nền, cách nào bạn đảm bảo rằng họ không bao giờ được gọi sau khi ứng dụng từ chức đang hoạt động?

Trả lời

7

Chỉ cần chờ trong applicationWillResignActive cho hàng đợi để hoàn thành tất cả các hoạt động được cung cấp bằng cách sử dụng nhóm công văn hoặc cơ chế tương tự.

Bạn có thể tìm thấy một ví dụ trong documentation:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
dispatch_group_t group = dispatch_group_create(); 

// Add a task to the group 
dispatch_group_async(group, queue, ^{ 
    // Some asynchronous work 
}); 

// Do some other work while the tasks execute. 

// When you cannot make any more forward progress, 
// wait on the group to block the current thread. 
dispatch_group_wait(group, DISPATCH_TIME_FOREVER); 

// Release the group when it is no longer needed. 
dispatch_release(group); 
+0

Nhóm công việc có khiến nguyên tắc chính phải đợi cho đến khi khối enqueued hoàn thành thực thi không? Có một liên kết hữu ích/ví dụ như thế nào điều này được thực hiện? – openfrog

4

đề nghị sử dụng một nhóm văn Ngoài Sven, tôi đã đi một con đường đơn giản hơn trong quá khứ bằng cách sử dụng một công văn đồng bộ vào hàng đợi serial render của bạn trong vòng -applicationWillResignActive:

// Tell whatever is generating rendering operations to pause 

dispatch_sync(openGLESSerialQueue, ^{ 
    [EAGLContext setCurrentContext:context]; 
    glFinish(); 

    // Whatever other cleanup is required 
}); 

Công văn đồng bộ ở đây sẽ chặn cho đến khi tất cả các hành động trong hàng đợi đã hoàn tất, nó sẽ chạy mã của bạn trong khối đó. Nếu bạn có bộ hẹn giờ hoặc một số nguồn khác đang kích hoạt các khối hiển thị mới, tôi sẽ tạm dừng lần đầu tiên đó, trong trường hợp nó đặt một khối cuối cùng trên hàng đợi.

Là biện pháp an toàn bổ sung, tôi sử dụng glFinish() sẽ chặn cho đến khi tất cả hiển thị kết thúc trên GPU (GPU PowerVR như trì hoãn hiển thị nhiều nhất có thể). Đối với các khung hình kết xuất cực kỳ dài, tôi đã từng gặp sự cố do hiển thị khung vẫn còn ngay cả sau khi tất cả các cuộc gọi OpenGL ES có trách nhiệm đã kết thúc. Điều này ngăn cản điều đó.

Tôi sử dụng tính năng này trong một vài ứng dụng khác nhau và loại bỏ rất nhiều sự cố do hiển thị khi chuyển sang nền. Tôi biết những người khác sử dụng một cái gì đó tương tự với thư viện GPUImage của tôi (mà cũng sử dụng một hàng đợi công văn nối tiếp cho dựng hình của nó) và nó có vẻ làm việc tốt cho họ.

Một điều bạn phải thận trọng, với giải pháp này hoặc bất kỳ cách nào khác chặn cho đến khi quá trình nền được thực hiện, là bạn mở bản thân lên đến deadlocks nếu bạn không cẩn thận. Nếu bạn có bất kỳ công văn đồng bộ nào quay trở lại hàng đợi chính trong các khối trên hàng đợi nền của bạn, bạn sẽ muốn loại bỏ chúng hoặc cố gắng làm cho chúng không đồng bộ. Nếu họ đang chờ đợi trên hàng đợi chính, và hàng đợi chính đang chờ đợi trên hàng đợi nền, bạn sẽ đóng băng khá độc đáo. Thông thường, nó khá đơn giản để tránh điều đó.

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