2014-10-02 22 views
14

Tôi đang vẽ một hoạt ảnh bằng cách sử dụng GDI đệm đôi trên cửa sổ, trên một hệ thống trong đó chế độ DWM được bật và nhìn thấy rõ ràng tearing trên màn hình. Có cách nào để ngăn chặn điều này?Có thể ngăn chặn hiện vật rách khi vẽ bằng GDI trên cửa sổ có thành phần DWM không?

Chi tiết

Hoạt ảnh có cùng hình ảnh và di chuyển sang phải sang trái trên màn hình; số lượng điểm ảnh trên được xác định bởi sự chênh lệch giữa thời gian hiện tại và thời gian hoạt ảnh bắt đầu và thời gian kết thúc, để hoàn thành một phần được áp dụng cho toàn bộ chiều rộng cửa sổ, sử dụng timeGetTime với 1ms resolution. Hoạt ảnh vẽ trong một vòng lặp mà không cần xử lý thông điệp ứng dụng; nó gọi phương thức (thư viện VCL) Repaint mà nội bộ vô hiệu hóa và sau đó gọi UpdateWindow cho cửa sổ được đề cập, trực tiếp gọi vào thủ tục thông báo với WM_PAINT. Việc thực hiện VCL của bộ xử lý sơn sử dụng BeginBufferedPaint. Tranh là chính nó đôi đệm.

Mục đích của việc này là có tỷ lệ khung hình cao nhất có thể để có được hoạt ảnh mượt mà trên màn hình. (Bản vẽ sử dụng bộ đệm đôi để loại bỏ nhấp nháy và đảm bảo toàn bộ hình ảnh hoặc khung hình trên màn hình bất kỳ lúc nào. Nó sẽ làm mất hiệu lực và cập nhật trực tiếp bằng cách gọi vào thủ tục tin nhắn mà không thực hiện xử lý thông báo khác. Trong ví dụ này, bức tranh được thực hiện trong một vài cuộc gọi BitBlt (một ở phía bên trái của hình động, nghĩa là di chuyển ngoài màn hình, và một ở phía bên phải của hình động, tức là di chuyển trên màn hình.)

Khi xem hoạt ảnh, hiển thị rõ ràng tearing. Điều này xảy ra trên Windows Vista, 7 và 8.1 trên nhiều hệ thống với các cạc đồ họa khác nhau.

Cách tiếp cận của tôi để xử lý việc này là giảm tỷ lệ mà bản vẽ đang vẽ hoặc để chờ VSync trước khi vẽ lại. Đây có thể là phương pháp sai, vì vậy câu trả lời cho câu hỏi này có thể là "Làm điều gì khác hoàn toàn: X". Nếu vậy, tuyệt vời :)

(Những gì tôi thực sự muốn là một cách để yêu cầu DWM để soạn/sử dụng khung chỉ đầy đủ sơn cho cửa sổ cụ thể này.)

Tôi đã thử các phương pháp sau đây , không ai trong số đó loại bỏ tất cả các rách nhìn thấy được. Do đó, câu hỏi là, Có thể tránh xé rách khi sử dụng thành phần DWM không và nếu có thì làm cách nào?

phương pháp tiếp cận thử:

  • Bắt tốc độ làm tươi màn hình qua GetDeviceCaps(Application.MainForm.Handle, VREFRESH); ngủ cho 1/tốc độ làm mới mili giây. Hơi được cải thiện trên bức tranh càng nhanh càng tốt, nhưng có thể là suy nghĩ mơ hồ. Tỷ lệ hình ảnh động kém hơn một chút. (Tinh chỉnh: bình thường Sleep và độ chờ đợi có độ phân giải cao sử dụng timeGetTime.)

  • Sử dụng DwmSetPresentParameters để cố gắng giới hạn cập nhật ở cùng tốc độ mà mã rút ra. (Biến thể: rất nhiều bộ đệm (cBuffer = 8) (không có hiệu ứng hiển thị), chỉ định tốc độ làm mới của màn hình/1 và ngủ bằng mã trên (giống như chỉ thử phương pháp ngủ); 1, 10, vv (không có hiệu ứng nhìn thấy được), thay đổi độ bao phủ của khung nguồn (không có hiệu ứng nhìn thấy được).)

  • Sử dụng DwmGetCompositionTimingInfo trong nhiều cách khác nhau:

      • Trong khi cFramesPending> 0, quay;
      • Nhận cFrame (khung soạn) và quay trong khi con số này không thay đổi;
      • Nhận cFrameDisplayed và quay trong khi điều này không thay đổi;
      • Tính toán một thời gian để ngủ để bằng cách thêm qpcVBlank + qpcRefreshPeriod, và sau đó trong khi QueryPerformanceCounter trả về một thời gian ít hơn này, spin
  • Tất cả những phương pháp cũng đã được thay đổi bằng sơn sau đó quay/ngủ trước khi vẽ lại; hoặc ngược lại: ngủ và sau đó vẽ.

Rất ít dường như có hiệu ứng rõ ràng và ảnh hưởng nào khó có thể đạt được và chỉ có thể là kết quả của tốc độ khung hình thấp hơn. Không có ngăn chặn rách, tức là không làm cho DWM soạn cửa sổ với bản sao "toàn bộ" nội dung của DC của cửa sổ.

Tư vấn đánh giá cao :)

+1

GDI cũ và mạnh mẽ và không hoạt hình mượt mà. Có thể thử Direct2D? –

+1

@JonathanPotter Điểm tốt. Một trong những ràng buộc mà tôi đang sử dụng là không sử dụng DX của bất kỳ loại nào - một lý do là số lượng nền tảng và thiếu các yêu cầu, mã cuối cùng cần phải chạy. (Không phải tất cả đều là Windows hiện đại.) Có lẽ helper DX code chỉ khi Aero tồn tại ...? Tuy nhiên, nó sẽ phải liên tục chuyển sang và từ GDI/DX mà không có trục trặc thị giác, vì nó bật/tắt hoạt ảnh. Điều đó có thể không? –

+0

Có lẽ bạn có thể viết một lớp helper vẽ có sử dụng DX nếu có và rơi trở lại GDI nếu không. Nó sẽ là khá hiếm khi tìm thấy một hệ thống không hỗ trợ Direct3D mặc dù ngay cả khi không phải D2D. –

Trả lời

2

Vì bạn đang sử dụng BitBlt, hãy chắc chắn Dibs của bạn là 4-byte/pixel. Với 3 byte/pixel, GDI là chậm khủng khiếp trong khi DWM đang chạy, đó có thể là nguồn gốc của rách của bạn. Một vấn đề khác BitBlt tôi đã chạy vào, nếu DIB của bạn là hơi lớn hơn, so với cuộc gọi BitBlt thực hiện mất một thời gian dài bất ngờ. Nếu bạn chia nhỏ một cuộc gọi thành các cuộc gọi nhỏ hơn chỉ vẽ một phần dữ liệu, thì điều đó có thể hữu ích. Cả hai mục này đều giúp tôi trong trường hợp của tôi, chỉ vì bản thân BitBlt đang chạy quá chậm, do đó dẫn đến hiện vật video.

+0

Chỉ trong trường hợp bổ sung: không quên cập nhật chỉ bẩn rect (GetUpdateRect) thay vì toàn bộ cửa sổ ... – Jurlie

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